Token-2022 Basics
9 examples to get you started with Token-2022 (Token Extensions) - 7 basic and 2 intermediate.
Prerequisites
solana config set --url devnet
spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb --versioncargo add anchor-lang@0.32.1 anchor-spl@0.32.1Token-2022 program ID: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb.
Basic Examples
1. Create a Token-2022 Mint
Same CLI flow as classic SPL with explicit program ID.
spl-token create-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb --decimals 6- Mint account is larger when extensions are enabled
- Default mint without extensions behaves like classic Token
- Always pass program ID in client derivation paths
Related: Transfer Fees - fee extension
2. Create ATA for Token-2022 Mint
ATA derivation includes token program ID.
spl-token create-account <MINT> --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb- Wrong program ID in derivation yields wrong ATA address
- Associated Token program is shared with classic Token
- Rent scales with account size when extensions attach to accounts
Related: Associated Token Accounts (ATAs)
3. Inspect Extension Layout
Display shows enabled extensions on mint/account.
spl-token display <MINT> --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb- Extension data appended to base SPL layout
- Immutable extensions cannot be removed after init
- Plan extension set before mainnet mint creation
Related: Metadata & Metadata Pointer
4. Mint and Transfer (No Extensions)
Baseline Token-2022 without extensions mirrors classic behavior.
spl-token mint <MINT> 1000000 --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
spl-token transfer <MINT> 500000 <RECIPIENT> --fund-recipient --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb- Wallets must detect Token-2022 program on mint account owner field
@solana-program/token-2022package provides instruction builders- DEX support varies - verify router compatibility
Related: Migrating from SPL Token
5. Read Mint Owner Program via RPC
Clients branch on token program before building instructions.
import { createSolanaRpc, address } from "@solana/kit";
const TOKEN_2022 = address("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb");
const rpc = createSolanaRpc("https://api.devnet.solana.com");
const { value } = await rpc.getAccountInfo(address("MINT_PUBKEY")).send();
const isToken2022 = value?.owner === TOKEN_2022;
console.log("Token-2022 mint:", isToken2022);- Mint
ownerfield is the token program ID - Use correct package for instruction encoding
- DAS may unify reads; transactions still need correct program
Related: Reading NFTs (DAS API)
6. Enable Transfer Fee Extension (CLI)
Common revenue extension configured at mint init.
# Extension flags vary by spl-token version - see transfer-fees page for full flow
spl-token create-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb --decimals 6 --enable-transfer-fees- Fee basis points and max fee set in extension init data
- Withheld fees accumulate in accounts until harvested
- Wallets should show net received amount
Related: Transfer Fees
7. Use token_interface in Anchor
Single code path for Token and Token-2022 mints.
use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface};
#[derive(Accounts)]
pub struct Deposit<'info> {
pub mint: InterfaceAccount<'info, Mint>,
#[account(mut)]
pub user_token: InterfaceAccount<'info, TokenAccount>,
pub token_program: Interface<'info, TokenInterface>,
}InterfaceAccountdeserializes both program layouts- Pass actual
token_programaccount matching mint owner - Required for protocols accepting arbitrary listed tokens
Related: SPL Token in Programs
Intermediate Examples
8. Transfer Hook Extension Overview
Custom program invoked on every transfer.
// Transfer hook program ID stored in mint extension
// Token-2022 CPIs to hook with extra accounts from remaining_accounts- Hook can enforce allowlists, royalties, or accounting
- Extra accounts must be passed in client transactions
- Advanced CU and failure modes - test on Surfpool 0.12.0
Related: Transfer Hooks
9. Choose Extensions for Product Requirements
| Need | Extension |
|---|---|
| Revenue on transfers | Transfer fee |
| Compliance gating | Default account state + non-transferable |
| On-mint metadata | Metadata pointer |
| Privacy | Confidential transfer |
- Enable only what you need - immutable extensions add permanent complexity
- Document unsupported wallet behavior for users
Related: Token-2022 Best Practices
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.