Program identifier
zh1eLd6rSphLejbFfJEneUwzHRfMKxgzrgkfwA6qRkW
Deployed artifact (since 2026-08-24)
- SBF ELF sha256
d0f68613a08d7e0913aea67d95f04598bc070911a0e84fedd43cc6bfa18e6cf6(239,032 bytes) - Independently audited; the deployed bytecode is built from the audited release
- Upgrade authority: Squads multisig vault
F6HWeX5i2KjYQag6wCtxzQXeGewv6vXZihZR3EWdRL7s(3-of-4, 1-hour time lock) - Verification recipe and circuit hashes: Release notes
Instruction surface
0:Transact(deposit, withdraw, shielded transfer)1:TransactSwap(swap flow entrypoint)2:Initialize(mint-scoped pool bootstrap)3:PrepareSwapSol4:ExecuteSwap5:CloseSwapState6:CollectTreasury
Transact and TransactSwap.
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]
Fees and amount semantics
Fees are read from each pool’s on-chainPoolConfig (fixed amount + variable ratio); the
values below are the deployed defaults.
FIXED_FEE_LAMPORTS = 5_000_000(0.005 SOL, SOL pool)DEFAULT_SPL_FIXED_FEE_RAW_UNITS = 450_000(0.45 USDC / USDT, SPL pools)- Variable fee:
amount * 3 / 1000(0.3%, all pools) MIN_DEPOSIT_LAMPORTS = 10_000_000(0.01 SOL)MIN_DEPOSIT_SPL_BASE_UNITS = 1_000_000(1.00 USDC / USDT)
gross = abs(publicAmount)fee = fixed + gross * 3 / 1000(fixed=5_000_000lamports or450_000base units)net = gross - fee
net > 0.
Merkle tree and nullifiers
- Tree height:
32 - Root history size:
100 - Nullifier PDA seed model:
["nullifier", pool_pubkey, nullifier_hash]
- Pool:
["pool", mint] - Treasury:
["treasury", mint] - Merkle tree:
["merkle_tree", mint]
Execution model
Transact
- Verifies 256-byte Groth16 proof against the embedded transaction verifying key (ceremony
cloak-transaction-0.2.0, sha256d65073d44064ed3be10d79e52d60a06d6be6d6c01afcd5ce52cdfcfc97c5585d). - 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)
- Deposits carry a signed risk quote bound to the deposit, checked on-chain.
- Withdrawals and swaps carry a signed withdraw authorization when a withdraw authorizer is set on the pool.
TransactSwap
- Runs the same proof/nullifier/commitment checks as
Transact. - Requires negative
publicAmount(swap is a withdrawal path). - Creates
SwapStatefor the follow-up settlement path.
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
chainNoteHashbinding constraints for chain-note integrity.
Error mapping
For SDK-side mapping utilities, seeShieldPoolErrors 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).