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
Proof
required
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)
ExtDataMinified
required
Minified external data:
ext_amount: Token amount to deposit (positive) or withdraw (negative)fee: Transaction fee in token base units
Vec<u8>
required
Encrypted data for the first output UTXO.
Vec<u8>
required
Encrypted data for the second output UTXO.
Accounts
AccountLoader<MerkleTreeAccount>
required
Token-specific merkle tree. PDA:
["merkle_tree", mint.key()].- Mutable: Yes
Account<NullifierAccount>
required
First nullifier account. PDA:
["nullifier0", proof.input_nullifiers[0]].- Mutable: Yes
- Initialized: Yes (created by this instruction)
Account<NullifierAccount>
required
Second nullifier account. PDA:
["nullifier1", proof.input_nullifiers[1]].- Mutable: Yes
- Initialized: Yes (created by this instruction)
SystemAccount
required
Cross-check nullifier. PDA:
["nullifier0", proof.input_nullifiers[1]].- Must not exist
SystemAccount
required
Cross-check nullifier. PDA:
["nullifier1", proof.input_nullifiers[0]].- Must not exist
Account<GlobalConfig>
required
Global configuration. PDA:
["global_config"].Signer
required
Transaction signer.
- Mutable: Yes
Account<Mint>
required
SPL token mint account.
Account<TokenAccount>
required
Signer’s token account (source for deposits).
- Mutable: Yes
- Must be owned by signer
- Must have correct mint
UncheckedAccount
required
Recipient wallet account (owner of recipient_token_account).
Account<TokenAccount>
required
Recipient’s token account (destination for withdrawals).
- Mutable: Yes
- Token mint must match
- Token authority must be recipient
Account<TokenAccount>
required
Tree’s associated token account.
- Mutable: Yes
- Auto-created if needed (init_if_needed)
- Authority: global_config PDA
UncheckedAccount
required
Fee recipient’s associated token account.
- Mutable: Yes
- Must already exist for supported tokens
Program<Token>
required
SPL Token program.
Program<AssociatedToken>
required
Associated Token program.
Program<System>
required
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
Error
Token account is not owned by the signer.
Error
Token account mint doesn’t match the provided mint.
Error
Mint address is not in the allowed tokens list.
Error
Merkle root not found in tree history.
Error
External data hash mismatch.
Error
Zero-knowledge proof verification failed.
Error
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