Precompiles
Call native Paxeer capabilities from the EVM with the correct addresses, ABIs, permissions, and token units.
paxeer-network/precompiles/setup.go and each precompile's abi.json and Go implementation.Fixed addresses and interfaces
Paxeer implements precompiles natively in the node. Call them with their matching ABI rather than expecting deployed Solidity bytecode. Match your client bindings to the node revision you use.
| Address | Capability | Current interface |
|---|---|---|
0x1001 | Bank | Native balances, metadata, supply, pointer-authorized sends, native value transfers |
0x1002 | CosmWasm | instantiate, execute, execute_batch, query |
0x1003 | JSON | Extract bytes, byte lists, unsigned integers, and array elements |
0x1004 | Address association | getPaxAddr, getEvmAddr, associate, associatePubKey |
0x1005 | Staking | Delegation and validator transactions, queries, pagination, pool, and parameters |
0x1006 | Governance | vote, voteWeighted, deposit, submitProposal |
0x1007 | Distribution | Reward queries, withdrawals, withdrawal address, and validator commission |
0x1008 | Oracle | Registered, but both price-query methods revert as retired |
0x1009 | IBC transfer | transfer, transferWithDefaultTimeout |
0x100a | Pointer lookup | Native, CW20, CW721, and CW1155 pointer address, version, and existence |
0x100b | Pointer creation | addNativePointer, addCW20Pointer, addCW721Pointer, addCW1155Pointer |
0x100c | Solo asset claims | claim(bytes), claimSpecific(bytes) using signed Cosmos transaction payloads |
0x1011 | P-256 signatures | verify(bytes) |
Addresses in the table are shortened for readability. Pad them to 20 bytes, for example 0x0000000000000000000000000000000000001001. precompiles/common/ supplies shared gas, payment, ABI, and error handling; it is not another callable precompile.
Address association
getPaxAddr(address) resolves an existing EVM-to-Paxeer association. getEvmAddr(string) performs the reverse lookup. Account addresses use pax1; validator operator addresses use paxvaloper1. These lookups can fail when no association exists; they are not interchangeable with a bech32 encoding of the same 20 bytes.
The manual association methods derive both addresses from a public key or signature. Use the key belonging to the account being linked. Creating a new random wallet would associate a different account. Signature construction must match the exact message bytes expected by addr.go; an application timestamp is not a replay-protection mechanism enforced by that method.
Bank balances and transfers
Bank amounts are integers in the supplied base denomination. The native bank denomination is uhpx: one PAX equals 1,000,000 uhpx, while EVM transaction value uses 10^18 wei per PAX. The internal human-unit identifier is hpx; see network parameters for the unit mapping.
// Minimal ABI for a read; use the full bank/abi.json for other methods.
import { Contract, JsonRpcProvider, formatUnits } from 'ethers'
const provider = new JsonRpcProvider(process.env.PAXEER_EVM_RPC_URL)
if ((await provider.getNetwork()).chainId !== 125n) throw new Error('Wrong chain')
const bank = new Contract(
'0x0000000000000000000000000000000000001001',
['function balance(address,string) view returns (uint256)',
'function decimals(string) view returns (uint8)'],
provider,
)
const account = process.env.PAXEER_ACCOUNT_ADDRESS
if (!account) throw new Error('Set PAXEER_ACCOUNT_ADDRESS')
const amount = await bank.balance(account, 'uhpx')
console.log('bank base units:', amount.toString())
console.log('PAX:', formatUnits(amount, 6))
console.log('bank denomination decimals:', await bank.decimals('uhpx')) // 0bank.decimals(denom) returns 0 because the ABI represents base-denomination integers. It does not return the display exponent of PAX. The name and symbol methods require bank denomination metadata.
send(address from, address to, string denom, uint256 amount)is nonpayable and restricted to the registered ERC-20 native pointer for that denomination. An arbitrary wrapper or wallet cannot call it successfully just by supplying a sender.sendNative(string toAddress)is payable, sends EVM value to a Paxeer bech32 recipient, and preserves both wholeuhpxand the smaller wei remainder. The caller must be associated; delegatecall is rejected.all_balances(address)andsupply(string)also expose base-denomination amounts.
Staking and distribution
Staking writes act for the immediate caller's associated account. A contract wrapper therefore controls its own position; querying its deployer's delegation does not inspect that position. Delegatecall is rejected.
| Operation or result | Units and behavior |
|---|---|
delegate / createValidator value | Wei; must be an exact multiple of 10^12. Fractional uhpx is rejected. |
redelegate / undelegate amount | Integer native staking denomination, normally uhpx. |
delegation balance | Integer amount with its denomination; delegation shares have a separate 18-digit fixed-point scale. |
distribution.rewards coin amount | 18-digit fixed-point amount of the returned denomination. For uhpx, divide by 10^18 for uhpx or 10^24 for PAX. |
| Withdrawn reward amount | Native integer denomination. For uhpx, divide by 10^6 for PAX. |
The staking ABI also exposes validator creation and editing; validator, delegation, unbonding, and redelegation queries; historical information; pool; and params. Read current parameters for unbonding time and entry limits. Paginated queries return a bytes cursor: with ethers, an empty cursor is 0x, whose JavaScript string length is two.
Distribution supports setWithdrawAddress, withdrawDelegationRewards, withdrawMultipleDelegationRewards, withdrawValidatorCommission, and rewards. The withdrawal target must be associated. Some validator addresses are indexed strings in EVM events; an indexed string topic is a hash, not the original bech32 text.
Governance transactions
The governance ABI exposes writes only. Use the native module query APIs to inspect proposals and live deposit or voting parameters. voteWeighted takes option/decimal-string tuples; weights must be valid, use distinct options, and sum exactly to one. A new vote can replace the same voter's existing vote while the proposal is active.
deposit and submitProposal receive the native deposit through EVM value, with exact whole-uhpx payment conversion. submitProposal accepts the JSON shape implemented by gov/handler.go and returns a proposal ID in ABI return data. It does not emit a ProposalSubmitted EVM event, so do not search receipt logs for that invented event.
JSON extraction
The JSON ABI provides extractAsBytes(bytes,string), extractAsBytesList(bytes,string), extractAsUint256(bytes,string), and extractAsBytesFromArray(bytes,uint16). Keys select a literal top-level field. To read a nested field, first extract its containing object.
Byte-list results preserve each element's JSON representation, including quotes around strings. Decode returned hex bytes before parsing JSON. Integer extraction accepts decimal integers and quoted integer strings, rejects negative or oversized values, and does not implement floating-point conversion.
// With json connected to the current precompiles/json/abi.json:
const document = toUtf8Bytes(JSON.stringify({ user: { count: '42' }, tags: ['one'] }))
const user = await json.extractAsBytes(document, 'user')
const count = await json.extractAsUint256(user, 'count') // 42n
const tags = await json.extractAsBytesList(document, 'tags')
const firstTag = JSON.parse(toUtf8String(tags[0])) // 'one'The helper functions toUtf8Bytes and toUtf8String above are ethers exports. The implementation charges 100 gas per ABI argument byte, excluding the selector; total transaction gas includes other execution and transaction costs.
P-256 signature verification
At 0x1011, verify(bytes) takes exactly 160 payload bytes: a 32-byte digest followed by 32-byte r, s, public-key x, and public-key y. Valid signatures return ABI-encoded bytes containing a 32-byte word with value one. Invalid signatures return empty low-level call data rather than an ABI-encoded result; handle that case before decoding. Malformed payload length reverts.
This is an ABI call with a dynamic bytes argument. The 160-byte payload occupies 224 argument bytes after its offset and length words, so the precompile charges 224 × 300 = 67,200 precompile execution gas, before other call or transaction costs. P-256 verification is one part of a passkey flow; challenge, origin, authenticator data, and replay handling belong to the complete application ceremony.
Cross-runtime and cross-chain calls
The CosmWasm guide covers matching the native coin list to payable EVM value. WASM bindings expose calls in the other direction. The IBC guide covers the transfer ABI, which does not expose channel queries.
Pointer lookup returns the pointer address, a version, and an existence flag for one supplied native denomination or CosmWasm address. It does not provide a list-all query. Solo claims consume signed Cosmos transaction payloads; they are asset-claim operations rather than a general administrative interface.
Retired Oracle API
getExchangeRates and getOracleTwaps at 0x1008 revert with oracle precompile is retired; oracle data queries are disabled. See the Oracle module guide for native query interfaces.
ABI and failure handling
Use the matching precompiles/<name>/abi.json, simulate the real caller and value, and inspect revert data before sending a transaction. Most module precompiles meter native execution dynamically; sample gas figures are not fixed limits. An off-chain read needs no funded signer, while an on-chain call still consumes gas.
In particular, address lookup is getPaxAddr in this tree. An SDK package targeting another chain can carry different selectors, chain IDs, prefixes, or addresses even when its API looks similar.