Skip to main content

Overview

The compressed token program (cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m) implements SPL Token-compatible operations for compressed tokens. Instructions support both compressed accounts (in Merkle trees) and decompressed CToken accounts (standard Solana accounts). Program ID: cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m
Documentation: Compressed Token Program

Instruction Categories

Token Operations

Transfer2, MintAction, Freeze, Thaw

Account Management

Create, Close token accounts

CToken Operations

Transfer, Approve, Burn, Mint

Discriminator Reference

Compressed Token Operations

InstructionDiscriminatorSPL Compatible
Transfer2101No
MintAction103No
FreezeAnchorNo
ThawAnchorNo

CToken Account Operations

InstructionDiscriminatorSPL Equivalent
CreateTokenAccount18InitializeAccount3
CreateAssociatedTokenAccount100-
CreateAssociatedTokenAccountIdempotent102-
CloseTokenAccount9CloseAccount

CToken Transfer & Approval

InstructionDiscriminatorSPL Equivalent
CTokenTransfer3Transfer
CTokenTransferChecked12TransferChecked
CTokenApprove4Approve
CTokenRevoke5Revoke

CToken Mint & Burn

InstructionDiscriminatorSPL Equivalent
CTokenMintTo7MintTo
CTokenMintToChecked14MintToChecked
CTokenBurn8Burn
CTokenBurnChecked15BurnChecked

CToken Freeze

InstructionDiscriminatorSPL Equivalent
CTokenFreezeAccount10FreezeAccount
CTokenThawAccount11ThawAccount

Rent Management

InstructionDiscriminatorSPL Compatible
Claim104No
WithdrawFundingPool105No

Transfer2

Discriminator: 101
Enum: InstructionType::Transfer2
Batch transfer instruction supporting compress, decompress, and transfer operations.

Instruction Data

pub struct Transfer2InstructionData {
    pub inputs: Vec<CompressedTokenInput>,
    pub output_compressed_accounts: Vec<OutputCompressedAccountData>,
    pub output_state_merkle_tree_account_indices: Vec<u8>,
    pub ctoken_transfers: Vec<CTokenTransfer>,
    pub compress_or_decompress_amounts: Vec<u64>,
    pub compress_or_decompress_token_output_indices: Vec<u8>,
    pub proof: Option<CompressedProof>,
    pub mint: Pubkey,
    pub delegated_transfer: Option<DelegatedTransferData>,
    pub is_compress: bool,
    pub compression_lamports: Option<u64>,
}
inputs
Vec<CompressedTokenInput>
Input compressed token accounts to spend (with Merkle proofs)
output_compressed_accounts
Vec<OutputCompressedAccountData>
Output compressed token accounts to create
ctoken_transfers
Vec<CTokenTransfer>
Transfers between CToken (decompressed) accounts
compress_or_decompress_amounts
Vec<u64>
Amounts to compress or decompress
is_compress
bool
True for compress operations, false for decompress

Operations

Transfer between compressed token accounts.Flow:
  1. Verify inclusion proofs for input accounts
  2. Sum check: inputs = outputs
  3. Insert nullifiers for spent accounts
  4. Insert output account hashes into queue
Convert CToken account to compressed token.Flow:
  1. Verify CToken account ownership
  2. Burn tokens from CToken account
  3. Create compressed token account
  4. Optionally close CToken account
Convert compressed token to CToken account.Flow:
  1. Verify inclusion proof for compressed account
  2. Insert nullifier (spend compressed account)
  3. Mint tokens to CToken account

Example

// Transfer between compressed accounts
let inputs = vec![CompressedTokenInput {
    owner: sender_pubkey,
    amount: 1000,
    delegate_index: None,
    merkle_context: PackedMerkleContext { /* ... */ },
    root_index: 0,
}];

let outputs = vec![OutputCompressedAccountData {
    owner: recipient_pubkey,
    amount: 1000,
    lamports: 0,
}];

let ix_data = Transfer2InstructionData {
    inputs,
    output_compressed_accounts: outputs,
    proof: Some(validity_proof),
    mint: mint_pubkey,
    // ... other fields
};

MintAction

Discriminator: 103
Enum: InstructionType::MintAction
Batch instruction for mint management and minting operations.

Actions

ActionDescription
CreateCompressedMintCreate new compressed mint
MintToMint compressed tokens
UpdateMintAuthorityChange mint authority
UpdateFreezeAuthorityChange freeze authority
MintToCTokenMint to CToken account
UpdateMetadataFieldUpdate token metadata
UpdateMetadataAuthorityChange metadata authority
RemoveMetadataKeyRemove metadata field
DecompressMintConvert to SPL mint
CompressAndCloseCMintCompress and close mint account

Instruction Data

pub struct MintActionInstructionData {
    pub action: MintAction,
    pub amount: Option<u64>,
    pub new_authority: Option<Pubkey>,
    pub metadata_field: Option<TokenMetadataField>,
    pub proof: Option<CompressedProof>,
}

Example: Mint Tokens

let ix_data = MintActionInstructionData {
    action: MintAction::MintTo,
    amount: Some(1_000_000),
    new_authority: None,
    metadata_field: None,
    proof: None,
};

CToken Instructions

CTokenTransfer

Discriminator: 3
SPL Equivalent: Transfer
Transfer tokens between CToken accounts.
pub struct CTokenTransferData {
    pub amount: u64,
}
Accounts:
  1. Source CToken account (mut)
  2. Destination CToken account (mut)
  3. Authority (signer)

CTokenApprove

Discriminator: 4
SPL Equivalent: Approve
Approve delegate for CToken account.
pub struct CTokenApproveData {
    pub amount: u64,
}
Accounts:
  1. CToken account (mut)
  2. Delegate
  3. Owner (signer)

CTokenMintTo

Discriminator: 7
SPL Equivalent: MintTo
Mint tokens to CToken account.
pub struct CTokenMintToData {
    pub amount: u64,
}
Accounts:
  1. Mint
  2. Destination CToken account (mut)
  3. Mint authority (signer)

CTokenBurn

Discriminator: 8
SPL Equivalent: Burn
Burn tokens from CToken account.
pub struct CTokenBurnData {
    pub amount: u64,
}
Accounts:
  1. CToken account (mut)
  2. Mint (mut)
  3. Authority (signer)

Account Management

CreateTokenAccount

Discriminator: 18
SPL Equivalent: InitializeAccount3
Create CToken account.
pub struct CreateTokenAccountData {
    pub owner: Pubkey,
    pub extensions: Option<Vec<ExtensionType>>,
}

CloseTokenAccount

Discriminator: 9
SPL Equivalent: CloseAccount
Close CToken account and reclaim rent. Rent distribution:
  • If compressible: rent → rent recipient
  • Remaining lamports → destination account

Rent Management

Claim

Discriminator: 104
Enum: InstructionType::Claim
Claim rent from expired compressible accounts.
pub struct ClaimInstructionData {
    pub bump: u8,
}
Requirements:
  • Account must be compressible
  • Rentability period expired
  • Rent authority matches

WithdrawFundingPool

Discriminator: 105
Enum: InstructionType::WithdrawFundingPool
Withdraw from rent recipient pool.
pub struct WithdrawFundingPoolData {
    pub amount: u64,
    pub bump: u8,
}

Error Codes

Common error codes (30000+ range):
CodeErrorDescription
30001InsufficientFundsNot enough tokens
30002InvalidMintWrong mint for operation
30003InvalidAuthorityAuthority check failed
30004InvalidDelegateDelegate check failed
30005AccountFrozenAccount is frozen
30006MintHasNoFreezeAuthorityMint cannot freeze
30007SumCheckFailedInputs != outputs
30008InvalidProofZK proof verification failed
30009DecompressionErrorFailed to decompress
30010CompressionErrorFailed to compress

Best Practices

Transfer2 requires valid ZK proofs. Never skip proof validation.
For transfers, verify that total inputs equal total outputs (including fees).
When Merkle trees roll over, update account Merkle context references.
Transfer2 and MintAction support batching. Combine operations for efficiency.

Resources

Program Source

View on GitHub

Instruction Docs

Detailed instruction reference

SDK

TypeScript SDK

Examples

Program examples

Build docs developers (and LLMs) love