Free guide

Token-2022 and token extensions, explained

Solana has two token programs. Why the second one exists, what an extension physically is, and which habits from the classic Token program still hold.

Why a second token program

The classic Token program is deliberately frozen. Every wallet, exchange, and DeFi protocol depends on its exact behavior, so adding features to it risks the whole ecosystem; its stability is its value. The feature requests were real anyway: projects kept needing transfer fees, transfer-time logic, richer metadata, confidential amounts, and kept solving them with fragile wrappers around a program that could not help.

The answer was Token-2022, also called the Token Extensions program: a separate deployment at its own well-known address, implementing a superset of the classic program. The core instruction set is the same — mints, token accounts, mint_to, transfer_checked, burn all work identically — plus an extension system for everything new. The classic program stays frozen; innovation moved next door.

One mint, one universe

A mint belongs to exactly one of the two programs. Created under classic Token, forever classic; created under Token-2022, forever Token-2022, and every one of its token accounts lives under the same program. There is no migration instruction: "moving" a token means minting a new one. Even associated token accounts respect the split — the ATA derivation includes the token program's ID, so the same wallet-and-mint pair has different ATA addresses in the two universes. The two programs are parallel worlds that happen to share an interface.

What an extension physically is

An extension is not a separate account. It is extra bytes appended to the mint or token account itself, stored as type-length-value (TLV) entries after the base layout. The base fields keep the classic program's exact byte layout, which is what lets shared tooling read either kind of account. Three consequences follow:

What the size rule looks like in code

From the official default-account-state example, the first two steps of creating a mint with an extension from inside a program:

// Calculate space required for mint and extension data
let mint_size = ExtensionType::try_calculate_account_len::<PodMint>(&[
    ExtensionType::DefaultAccountState,
])?;

// Calculate minimum lamports required for size of mint account with extensions
let lamports = (Rent::get()?).minimum_balance(mint_size);

From solana-foundation/program-examples, MIT licensed, © Solana Foundation, pinned to commit 9389865.

The extension list goes in, the byte count comes out, and rent is computed from that. What follows in the example is a three-CPI recipe with one iron ordering rule: the System Program creates the account, the extension's initializer writes its TLV entry, and only then does initialize_mint2 seal the mint. Extension first, mint second — reverse them and the creation fails.

What Token-2022 retrains

The mental model carries over whole: mints define, token accounts hold, authorities are stored keys, decimals scale raw amounts. What changes is at the edges. Plain transfer is effectively retired, because Token-2022 needs the mint at transfer time — to charge fees, consult hooks, check non-transferability — so everything speaks transfer_checked, which carries the mint. And "create a token account" stops being a fixed-size recipe; creation flows compute the length for the extension set first, as above.

The deepest extension is the transfer hook: a mint that names a program of yours, which the token program calls on every transfer. That single idea covers whitelist gates, per-transfer counters, and transfer switches, and it is where reading Token-2022 code stops being optional for anyone auditing what a mint can and cannot do.