Skip to main content

Program identifier

  • c1oak6tetxYnNfvXKFkpn1d98FxtK7B68vBQLYQpWKp

Instruction surface

  • User-facing:
    • 0: Transact
    • 1: TransactSwap
  • Relay/ops-facing:
    • 10: Initialize
    • 11: PrepareSwapSol
    • 12: ExecuteSwap
    • 13: CloseSwapState

Public input layout

Transact and TransactSwap both use a 264-byte public input blob:
  • root[32]
  • publicAmount[8] (i64, LE)
  • extDataHash[32]
  • mintAddress[32]
  • inputNullifiers[64] (2 x 32)
  • outputCommitments[64] (2 x 32)
  • chainNoteHash[32]
This matches the transaction circuit constraints and relay-side validators.

Fees and amount semantics

  • FIXED_FEE_LAMPORTS = 5_000_000 (0.005 SOL)
  • Variable fee: amount * 3 / 1000 (0.3%)
  • MIN_DEPOSIT_LAMPORTS = 10_000_000 (0.01 SOL)
Withdrawal and swap math:
  • gross = abs(publicAmount)
  • fee = 5_000_000 + gross * 3 / 1000
  • net = gross - fee
The program enforces sufficient withdrawal amount so net > 0.

Merkle tree and nullifiers

  • Tree height: 32
  • Root history size: 100
  • Nullifiers are PDA-backed for O(1) spent checks
Relevant seeds:
  • Pool: ["pool"]
  • Treasury: ["treasury"]
  • Merkle tree: ["merkle_tree"]
  • Nullifier: ["nullifier", nullifier_hash]
  • Swap state: ["swap_state", pool_pubkey, nullifier]

Execution model

Transact

  • Verifies 256-byte Groth16 proof against transaction verifier key.
  • Validates root exists in root history ring.
  • Creates nullifier PDAs for non-zero input nullifiers (double-spend protection).
  • Appends non-zero output commitments to Merkle tree.
  • Applies external transfer based on publicAmount:
    • positive: deposit from payer to pool
    • negative: withdrawal from pool to recipient + fee to treasury
    • zero: pure shield transfer (no external SOL movement)
  • Deposit path can require risk-oracle quote accounts when configured.

TransactSwap

  • Runs the same proof/nullifier/commitment checks as Transact.
  • Requires negative publicAmount (swap is a withdrawal path).
  • Creates SwapState PDA with output mint, recipient ATA, min output, timeout data.
  • Moves SOL into swap state path for follow-up execution.

PrepareSwapSol + ExecuteSwap

  • Wraps SOL into wSOL context, executes swap CPI route, then settles output.
  • CloseSwapState closes state account once complete/eligible.

Circuit assumptions the program relies on

  • Transaction circuit is fixed to 2 inputs / 2 outputs.
  • Tree depth is fixed to 32 levels.
  • Circuit enforces value conservation: sum(inputs) + publicAmount = sum(outputs).
  • Circuit includes chainNoteHash binding constraints for chain-note integrity.

Error families

  • 0x1000-0x1002: root management
  • 0x1010-0x1013: proof input/proof shape errors
  • 0x1020-0x1026: nullifier and signer checks
  • 0x1030-0x1039: output/conservation/fee constraints
  • 0x1050-0x105D: account validation
  • 0x1070-0x1076: Groth16 verifier failures
  • 0x1080-0x1082: Merkle tree bounds/hash errors
  • 0x10A0-0x10A1: risk-oracle checks
For SDK-side mapping utilities, see ShieldPoolErrors in Error Handling.

Common failure modes

  • 0x1001 RootNotFound: proof used an old root no longer in ring history.
  • 0x1020/nullifier-already-used: input already spent (or reused test nullifier).
  • Invalid instruction data: wrong public input length (must be 264 bytes).