Skip to main content

Overview

Privacy Cash supports both native SOL and a curated list of SPL tokens. Each supported SPL token has its own dedicated Merkle tree for privacy-preserving transactions.

Token Support Configuration

The protocol uses two mechanisms to control which tokens are supported:

Environment-Based Configuration

Token Allowlist

In production and devnet environments, only tokens in the ALLOWED_TOKENS constant are permitted.

Supported SPL Tokens

Mainnet Tokens

The following tokens are supported on Solana mainnet: Code Reference: lib.rs:52-60

Devnet Tokens

The following test tokens are supported on Solana devnet: Code Reference: lib.rs:41-49

Native SOL Support

In addition to SPL tokens, Privacy Cash natively supports SOL transactions. The SOL mint address is represented as:
Code Reference: utils.rs:14

Token Validation

Before processing SPL token transactions, the protocol validates that the token is allowed:

During Tree Initialization

Code Reference: lib.rs:161-163

During Transactions

Code Reference: lib.rs:395-397 If validation fails, the transaction reverts with:
“Invalid mint address: mint address is not allowed”

Adding Support for New Tokens

Mainnet Token Addition

To add a new token to mainnet:
  1. Update the ALLOWED_TOKENS constant in lib.rs:
  1. Initialize a tree for the token using the initialize_tree_account_for_spl_token instruction
  2. Deploy the updated program with the new token list

Devnet Token Addition

Follow the same process for devnet tokens:

Initializing Token Trees

Each supported SPL token requires its own Merkle tree initialization.

Function Signature

Requirements

  • Only the protocol authority can initialize token trees
  • Token mint must be in ALLOWED_TOKENS (unless ALLOW_ALL_SPL_TOKENS is enabled)
  • Each token gets a separate Merkle tree with seed: [b"merkle_tree", mint.key().as_ref()]

Tree Properties

Each SPL token tree is initialized with:
  • Height: 26 (supports 67,108,864 commitments)
  • Root History Size: 100 previous roots
  • Deposit Limit: Configurable per token (specified during initialization)
Code Reference: lib.rs:151-185

Token Account Management

Associated Token Accounts (ATAs)

For each supported token, the protocol manages:
  1. Tree ATA: The protocol’s token account that holds deposited tokens
    • Authority: global_config PDA
    • Created automatically on first deposit
  2. Fee Recipient ATA: Where protocol fees are collected
    • Must exist for supported tokens
    • Validated during transactions
Code Reference: lib.rs:744-756

Token Transfer Operations

Deposits

Tokens are transferred from the user’s token account to the tree’s ATA:
Code Reference: lib.rs:442-452

Withdrawals

Tokens are transferred from the tree’s ATA to the recipient’s token account:
Code Reference: lib.rs:464-476

Testing on Localnet

For local development and testing, all SPL tokens are automatically allowed:
This allows developers to test with any token without modifying the allowlist.

Token Metadata

USDC (USD Coin)

  • Decimals: 6
  • Use Case: Stablecoin pegged to US Dollar
  • Privacy Use: Private payments, remittances

USDT (Tether USD)

  • Decimals: 6
  • Use Case: Stablecoin pegged to US Dollar
  • Privacy Use: Private transfers, trading

ORE (Ore)

  • Use Case: Mining token on Solana
  • Privacy Use: Private mining rewards, transfers

ZEC (Zcash)

  • Use Case: Privacy-focused cryptocurrency bridge
  • Privacy Use: Cross-chain privacy transactions

stORE (Staked Ore)

  • Use Case: Liquid staking derivative of ORE
  • Privacy Use: Private staking positions

jlUSDC (Jupiter USDC)

  • Use Case: Jupiter DEX liquidity token
  • Privacy Use: Private liquidity provision

jlWSOL (Jupiter Wrapped SOL)

  • Use Case: Jupiter DEX liquidity token
  • Privacy Use: Private SOL positions

Security Considerations

Token Validation

  1. Allowlist enforcement: Only approved tokens can be used in production
  2. Mint verification: Every transaction validates the token mint address
  3. Authority control: Only protocol authority can add new token trees

Account Validation

During SPL token transactions, the protocol validates:
Code Reference: lib.rs:376-383

Error Codes

InvalidMintAddress

“Invalid mint address: mint address is not allowed”
Thrown when attempting to use an unsupported token.

InvalidTokenAccount

“Invalid token account: account is not owned by the token program”
Thrown when the provided token account is invalid.

InvalidTokenAccountMintAddress

“Invalid token account mint address”
Thrown when the token account’s mint doesn’t match the expected mint.

Code References

  • Mainnet token list: lib.rs:52-60
  • Devnet token list: lib.rs:41-49
  • Token validation (initialization): lib.rs:161-163
  • Token validation (transactions): lib.rs:395-397
  • SOL address constant: utils.rs:14
  • Tree initialization: lib.rs:151-185
  • SPL token transactions: lib.rs:371-520