Token & Associated Token Constraints
anchor-spl provides constraint helpers for SPL Token and Associated Token accounts, reducing manual mint/authority checks.
Search across all documentation pages
anchor-spl provides constraint helpers for SPL Token and Associated Token accounts, reducing manual mint/authority checks.
init_if_needed (used by both ATA examples below) is gated behind a cargo feature. Without it neither snippet compiles:
[dependencies]
anchor-lang = { version = "0.32.1", features = ["init-if-needed"] }use anchor_spl::associated_token::AssociatedToken;
use anchor_spl::token::{Mint, Token, TokenAccount};
#[account(
init_if_needed,
payer = payer,
associated_token::mint = mint,
associated_token::authority = owner,
)]
pub ata: Account<'info, TokenAccount>,When to reach for this: Instructions move tokens or create ATAs.
#[derive(Accounts)]
pub struct TransferTokens<'info> {
#[account(mut)]
pub payer: Signer<'info>,
#[account(mut)]
pub from: Account<'info, TokenAccount>,
#[account(
init_if_needed,
payer = payer,
associated_token::mint = mint,
associated_token::authority = recipient,
)]
pub to: Account<'info, TokenAccount>,
pub mint: Account<'info, Mint>,
pub recipient: SystemAccount<'info>,
pub token_program: Program<'info, Token>,
pub associated_token_program: Program<'info, AssociatedToken>,
pub system_program: Program<'info, System>,
}What this demonstrates:
associated_token::mint ties ATA to mintassociated_token::authority sets ownertoken_interface for Token-2022For Token-2022, use InterfaceAccount and TokenInterface. These types come from anchor_spl::token_interface, not anchor_spl::token — anchor_spl::token::Mint is the legacy-Token-only type and its owner check rejects Token-2022 mints:
use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface};
pub token_program: Interface<'info, TokenInterface>,
pub mint: InterfaceAccount<'info, Mint>,
#[account(mut)]
pub token_account: InterfaceAccount<'info, TokenAccount>,anchor_spl::token_interface mirrors anchor_spl::token with interface-aware types; pick one module per program and don't mix the two Mint types.
Interface when supporting both.constraint = from.mint == mint.key().mut.| Alternative | Use When | Don't Use When |
|---|---|---|
| Manual token::accessor checks | Custom programs | Standard SPL flows |
| CPI only without ATA constraint | External ATA creation | Same-instruction ATA init |
| token_interface CPI helpers | Token-2022 transfers | Legacy token only |
0.32.1 for anchor-lang, Anchor CLI, and examples in this section.
Yes. Solana CLI 3.0.10 handles keypairs, airdrops, and solana program inspection.
target/idl/<program>.json in your workspace.
Yes, but every unchecked field needs explicit constraints or handler checks.
Use anchor test with Surfpool 0.12.0 or LiteSVM 0.6.x in CI.
Anchor account discriminator; do not strip it when sizing space.
Yes, or publish on-chain IDL so clients have a canonical source.
Run with logs; Anchor prints constraint name and account index.
Yes. This stack targets Agave validators with Solana CLI 3.0.10.
See sibling articles linked in Related for deeper token constraints topics.
Stack versions: This page was written for Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, and LiteSVM 0.6.x.
Reviewed by Chris St. John·Last updated Jul 19, 2026