Canonical data shape
BothTransact and TransactSwap use:
proof_bytes: 256-byte Groth16 proofpublic_inputs: 264-byte packed blob
root[32]publicAmount[8](signed LE)extDataHash[32]mintAddress[32]nullifiers[64]commitments[64]chainNoteHash[32]
Deposit flow (publicAmount > 0)
- SDK creates output UTXOs and generates proof inputs.
- SDK resolves Merkle data (relay cache first, chain fallback).
- Transaction is submitted (direct signer path for deposit variants).
- Program verifies proof and appends commitments to the tree.
- Relay/SDK resolve commitment index and persist local proof context.
Withdraw/transfer flow (/transact)
- SDK builds 2-in/2-out witness and computes nullifiers.
- SDK optionally ensures viewing-key registration.
- SDK posts proof + public inputs to relay
/transact. - Relay validates sizes/shape and submits on-chain transaction.
- Program rejects reused nullifiers and enforces amount/fee constraints.
- Client polls
/status/:iduntil completed or failed.
Swap flow (/transact_swap)
- SDK generates proof for withdraw-like step with swap params.
- Relay submits
TransactSwap(Tx1) to openSwapState. - Worker executes swap settlement path (Tx2), validates output min amount.
- Status includes
swap_phase, signatures, and error context. - Timeout/close paths can reclaim state if settlement cannot complete.
Reliability behaviors
- Stale root retries: SDK regenerates proofs when root history moved
- Queue recovery: relay resets stuck jobs and requeues retryable failures
- Commitment sync repair: relay can backfill sparse windows and rebuild cursors
- Recovery operations: bots can withdraw indexed historical deposits