Overview
Thetransact_spl instruction enables private transactions for SPL tokens. It functions identically to the transact instruction but operates on SPL token accounts instead of native SOL.
Each SPL token has its own dedicated merkle tree, initialized via initialize_tree_account_for_spl_token.
Function Signature
Parameters
Zero-knowledge proof containing:
proof_a: First proof component (64 bytes)proof_b: Second proof component (128 bytes)proof_c: Third proof component (64 bytes)root: Merkle tree root (32 bytes)public_amount: Public transaction amount (32 bytes)ext_data_hash: Hash of external data (32 bytes)input_nullifiers: Array of 2 nullifiers (32 bytes each)output_commitments: Array of 2 commitments (32 bytes each)
Minified external data:
ext_amount: Token amount to deposit (positive) or withdraw (negative)fee: Transaction fee in token base units
Encrypted data for the first output UTXO.
Encrypted data for the second output UTXO.
Accounts
Token-specific merkle tree. PDA:
["merkle_tree", mint.key()].- Mutable: Yes
First nullifier account. PDA:
["nullifier0", proof.input_nullifiers[0]].- Mutable: Yes
- Initialized: Yes (created by this instruction)
Second nullifier account. PDA:
["nullifier1", proof.input_nullifiers[1]].- Mutable: Yes
- Initialized: Yes (created by this instruction)
Cross-check nullifier. PDA:
["nullifier0", proof.input_nullifiers[1]].- Must not exist
Cross-check nullifier. PDA:
["nullifier1", proof.input_nullifiers[0]].- Must not exist
Global configuration. PDA:
["global_config"].Transaction signer.
- Mutable: Yes
SPL token mint account.
Signer’s token account (source for deposits).
- Mutable: Yes
- Must be owned by signer
- Must have correct mint
Recipient wallet account (owner of recipient_token_account).
Recipient’s token account (destination for withdrawals).
- Mutable: Yes
- Token mint must match
- Token authority must be recipient
Tree’s associated token account.
- Mutable: Yes
- Auto-created if needed (init_if_needed)
- Authority: global_config PDA
Fee recipient’s associated token account.
- Mutable: Yes
- Must already exist for supported tokens
SPL Token program.
Associated Token program.
Solana system program.
Behavior
Deposits (ext_amount > 0)
- Validates token account ownership and mint
- Checks deposit amount is within limit
- Transfers tokens from signer_token_account to tree_ata
- Validates and transfers deposit fee to fee_recipient_ata
- Verifies zero-knowledge proof
- Appends commitments to token-specific merkle tree
- Emits SPL commitment events
Withdrawals (ext_amount < 0)
- Validates token accounts
- Verifies merkle root and proof
- Transfers tokens from tree_ata to recipient_token_account
- Transfers withdrawal fee to fee_recipient_ata
- Appends commitments to merkle tree
- Emits SPL commitment events
Code Example
Allowed Tokens
- Mainnet
- Devnet
- Localnet
- USDC:
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v - USDT:
Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB - ORE:
oreoU2P8bN6jkk3jbaiVxYnG1dCXcYxwhwyK9jSybcp - ZEC:
A7bdiYdS5GjqGFtxf17ppRHtDKPkkRqbKtR27dxvQXaS - stORE:
sTorERYB6xAZ1SSbwpK3zoK2EEwbBrc7TZAzg1uCGiH - jlUSDC:
9BEcn9aPEmhSPbPQeFGjidRiEKki46fVQDyPpSQXPA2D - jlWSOL:
2uQsyo1fXXQkDtcpXnLofWy88PxcvnfH2L8FPSE62FVU
Events
This instruction emits twoSplCommitmentData events:
Validations
Token Account Ownership
Token Account Ownership
signer_token_account.owner must equal signer.key()Token Account Mint
Token Account Mint
signer_token_account.mint must equal mint.key()Allowed Token
Allowed Token
Mint address must be in the allowed tokens list (unless localnet).
All SOL Validations
All SOL Validations
Same validations as the
transact instruction apply.Errors
Token account is not owned by the signer.
Token account mint doesn’t match the provided mint.
Mint address is not in the allowed tokens list.
Merkle root not found in tree history.
External data hash mismatch.
Zero-knowledge proof verification failed.
Deposit amount exceeds the token’s maximum deposit limit.
See Also
- transact - Transact with SOL
- initialize_spl_tree - Initialize SPL token tree
- update_deposit_limit - Update SPL deposit limits