Contract API
Versioned public interfaces. Machine-readable schemas live in schemas/; tests/contract_api/test_contract_api.py checks a live node against them and writes bench/results/contract_api.json. Captured fixtures are in schemas/fixtures/.
1. ZeroFlux node JSON-RPC (API v1, consensus v2)
Transport: POST /rpc, JSON-RPC 2.0. params is an object or a one-element array holding the object. Schema: schemas/zfx-node-rpc-v1.json (every method's params, result and listed error codes).
| method | purpose | notes |
|---|---|---|
zfx_node_get_tip |
height, hash, state root, target, chain id, consensus version | deterministic |
zfx_node_get_block |
by hash (64 hex) or height |
a 64-char key is always a hash |
zfx_node_get_transaction |
tx, status, block, confirmations, receipt | receipt includes the header and a Merkle inclusion proof against tx_root |
zfx_get_account, zfx_get_address_history |
balance, immature, nonce, pending; history | |
zfx_estimate_fee |
median fee of recent blocks, floor 1000 | |
zfx_submit_transaction |
full validation, then mempool | idempotent: an identical resubmission returns the same txid with duplicate: true |
zfx_bridge_lock |
a transaction to the lockbox; memo = NEAR recipient | deposit_id = txid |
zfx_get_mining_work, zfx_submit_mining_result |
mining | stale work returns 1002 |
zfx_bridge_info |
committee, epoch, admin nonce, paused, totals, trust model text | |
zfx_bridge_deposit_status |
unknown, mempool, awaiting_confirmations, final |
final includes block, height, Merkle inclusion proof |
zfx_bridge_redeem_status |
unknown, mempool, released_awaiting_confirmations, final |
|
zfx_bridge_submit_op |
2-of-3 release or admin op | consensus enforces quorum, nonce, replay, timelock |
zfx_bridge_list_deposits, zfx_bridge_list_releases |
indexes used by relayers and reconciliation | |
zfx_faucet |
testnet only, rate limited | |
zfx_admin_* |
peer add, snapshot export/verify, shutdown | Authorization: Bearer <token>, compared in constant time |
Error codes: -32700 parse, -32600 invalid request, -32601 unknown method, -32602 invalid params (missing field, bad hex, bad address checksum), 1001 tx rejected, 1002 stale work, 1003 not found, 1004 unauthorized, 1005 rate limited, 1006 bridge rejected, 1007 faucet, 1099 internal.
Chain identity: chain_id u32 (testnet 0x5a460002); consensus_version 2; header magic ZFX2, 164 bytes.
Signing bytes
Transaction (wallet, SLH-DSA, FIPS 205 context ZFX-v0.1):
core = chain_id u32le | from[32] | to[32] | amount u64le | fee u64le | nonce u64le
[| 0x01 | memo_len u8 | memo utf8] (only when a memo is set; <= 64 bytes)
signed = "ZFX-tx-v0.1" | core
txid = sha256("ZFX-txid-v0.1" | core)
Bridge release and admin approvals (relayer SLH-DSA-SHA2-128s, context ZFX-bridge-v1), put_str = u16le length + bytes:
release = sha256("ZFX-bridge-release-v1" | chain_id u32le | put_str(asset_id) | epoch u32le
| withdrawal_id[32] | recipient[32] | amount u64le | expiry_height u64le | sha256(near_burn_ref))
admin = sha256("ZFX-bridge-admin-v1" | chain_id u32le | epoch u32le | op_nonce u64le | action)
action = 0x01 pause | 0x02 unpause | 0x03 (put_str(member_pubkey_hex) x3 | activate_height u64le)
Golden vectors for all of these: tests/vectors/consensus_v2.json, recomputed by cargo test -p zfx-verify.
2. wZFX contract on NEAR
NEP-141 (fungible token), NEP-145 (storage), NEP-148 (metadata: symbol wZFX, decimals 8). Source bridge/near/wzfx/src/lib.rs.
| method | caller | effect / checks |
|---|---|---|
ft_metadata, ft_total_supply, ft_balance_of, ft_transfer, ft_transfer_call, storage_* |
standard | NEP-141/145/148 behavior from near-contract-standards |
bridge_mint(attestation, approvals) |
anyone (relay) | not paused; attestation.epoch == epoch; block_timestamp <= expiry_ns; amount > 0; deposit_id 32 bytes and never minted; >= 2 distinct valid committee signatures; recipient registered |
bridge_burn(amount, native_recipient) |
holder, 1 yoctoNEAR | not paused; valid zfx1 checksum; burns and records BurnRecord with withdrawal_id = sha256("ZFX-near-burn-v1" \| put_str(contract) \| nonce u64le) |
bridge_pause(approvals?) |
owner, or anyone with 1 committee signature | sets paused |
bridge_unpause(approvals) |
anyone with 2 committee signatures | clears paused |
propose_rotation(committee, approvals) / apply_rotation() |
2 signatures / anyone after the timelock | new ed25519 keys, epoch + 1 |
stage_upgrade(code_hash) / deploy_upgrade() (raw WASM input) |
owner | deploy only after the timelock and only the staged sha256; then migrate |
| views | anyone | bridge_state, version, is_minted, get_burn, burns_since |
NEAR-side put_str is a u32le length + bytes. Committee signatures are ed25519 over:
mint = sha256("ZFX-near-mint-v1" | put_str(contract) | native_chain_id u32le | put_str(native_asset_id) | epoch u32le
| deposit_id[32] | put_str(recipient) | amount u128le | native_height u64le | expiry_ns u64le)
admin = sha256("ZFX-near-admin-v1" | put_str(contract) | epoch u32le | admin_nonce u64le | action)
action = 0x01 pause | 0x02 unpause | 0x03 put_str(key_hex) x3
The relayer computes the same bytes in bridge/relayers/src/digest.rs. Golden-vector tests in both crates (digests_match_golden_vectors, digests_match_relayer_golden_vectors) pin them to identical values.
Events (EVENT_JSON: logs): NEP-141 ft_mint (memo zfx-deposit:<deposit_id>) and ft_burn (memo zfx-withdrawal:<withdrawal_id>); bridge events with standard: "zfx-bridge", version: "1.0.0": mint, burn, pause, unpause, rotation_proposed, rotation_applied, upgrade_staged, upgrade_deployed, refund_burned.
Panic messages are the error codes on NEAR. Examples asserted by tests: insufficient committee approvals, invalid committee signature, deposit already minted (replay), attestation expired, attestation for wrong committee epoch, bridge paused, unpause needs threshold approvals, rotation timelock not elapsed, owner only, upgrade timelock not elapsed, WASM does not match the staged code hash.
3. Intents adapter (bridge/intents/zfx_intents/adapter.py)
| operation | maps to | terminal states |
|---|---|---|
intents.quote(token_in, token_out, exact_amount_in \| exact_amount_out, min_deadline_ms) |
Message Bus quote |
list of solver quotes (empty when no liquidity or stale price) |
intents.submit(quote, signer, key, verifier, salt) |
signs a NEP-413 token_diff mirroring the quote; Message Bus publish_intent |
returns intent_hash |
intents.status(intent_hash) |
Message Bus get_status |
SETTLED (with NEAR tx hash) or NOT_FOUND_OR_NOT_VALID |
Token ids are nep141:<contract>. Nonces follow Verifier defuse/v0.4.2: 5628f6c6 | 0x00 | salt[4] | deadline_ns i64le | random[15], base64. Payload: {"standard":"nep413","payload":{"recipient","nonce","message"},"public_key","signature"}. See docs/INTENTS_INTEGRATION.md.