Skip to main content

Introduction

Anchor provides first-class support for working with tokens on Solana through the anchor-spl crate. This includes support for both the original SPL Token Program and the newer Token-2022 (Token Extensions) Program. The anchor-spl crate provides:
  • Type-safe wrappers for token accounts and operations
  • Simplified account constraints for token-related accounts
  • Cross-program invocation (CPI) helpers for token operations
  • Support for Token-2022 extensions

Token Programs

Solana has two token programs:
  1. Token Program - The original SPL Token program that has been the standard for creating fungible and non-fungible tokens on Solana.
  2. Token-2022 (Token Extensions Program) - A newer program that extends the functionality of the original Token Program with additional features called “extensions”.
Both programs share the same core functionality and account structures, making it easy to write code that works with both.

Key Concepts

Mint Account

A mint account defines the properties of a token type. It contains:
  • The total supply of tokens
  • The number of decimal places
  • The mint authority (who can mint new tokens)
  • The freeze authority (who can freeze token accounts)

Token Account

A token account holds a specific quantity of tokens from a particular mint. Each token account is associated with:
  • A specific mint (the token type)
  • An owner/authority (who can transfer tokens)
  • A balance (amount of tokens held)

Associated Token Account (ATA)

An associated token account is a token account with a deterministic address derived from:
  • The owner’s public key
  • The token mint address
  • The token program ID
ATAs provide a standardized way to find a user’s token account for any given mint.

Using the token_interface Module

The token_interface module provides types and functions that work with both the Token Program and Token-2022 Program. This is the recommended approach for new programs.
use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface};

#[derive(Accounts)]
pub struct MyInstruction<'info> {
    pub mint: InterfaceAccount<'info, Mint>,
    pub token_account: InterfaceAccount<'info, TokenAccount>,
    pub token_program: Interface<'info, TokenInterface>,
}
The InterfaceAccount wrapper automatically handles deserialization for accounts from either token program, and the Interface type accepts either program ID.

Common Token Operations

The most common token operations in Anchor programs are:
  • Creating token accounts - Initialize new token accounts to hold tokens
  • Minting tokens - Create new token supply
  • Transferring tokens - Move tokens between accounts
  • Burning tokens - Destroy tokens to reduce supply
  • Delegating authority - Allow another address to spend tokens
All of these operations are performed through cross-program invocations (CPIs) to the token programs.

Account Constraints

Anchor provides special constraints for working with token accounts:

For Associated Token Accounts:

#[account(
    init,
    payer = payer,
    associated_token::mint = mint,
    associated_token::authority = owner,
    associated_token::token_program = token_program,
)]
pub token_account: InterfaceAccount<'info, TokenAccount>,

For Custom Token Accounts:

#[account(
    init,
    payer = payer,
    token::mint = mint,
    token::authority = owner,
    token::token_program = token_program,
    seeds = [b"vault"],
    bump
)]
pub token_account: InterfaceAccount<'info, TokenAccount>,

For Mint Accounts:

#[account(
    init,
    payer = payer,
    mint::decimals = 9,
    mint::authority = mint_authority,
    mint::freeze_authority = freeze_authority,
    mint::token_program = token_program,
)]
pub mint: InterfaceAccount<'info, Mint>,

Program Derived Addresses (PDAs) as Authorities

A common pattern in Anchor programs is to use PDAs as token authorities. This allows your program to programmatically control token operations:
#[account(
    init,
    payer = payer,
    mint::decimals = 6,
    mint::authority = mint, // PDA is its own authority
    seeds = [b"mint"],
    bump
)]
pub mint: InterfaceAccount<'info, Mint>,
To use a PDA authority in a CPI, you must provide the seeds:
let seeds = &[b"mint".as_ref(), &[ctx.bumps.mint]];
let signer_seeds = &[&seeds[..]];

let cpi_ctx = CpiContext::new_with_signer(
    token_program,
    accounts,
    signer_seeds
);

Next Steps

  • Token Basics - Learn basic token operations like minting, transferring, and managing token accounts
  • Token Extensions - Explore Token-2022 extensions for advanced functionality

Resources

Build docs developers (and LLMs) love