Token-2022 (Token Extensions)
Token-2022 is a separate token program with the same core layout as the original Token Program, plus optional extensions configured when the mint is created: transfer fees, metadata pointers, transfer hooks, non-transferable tokens and more. Code has to pass the right token program ID. Anchor's token_interface lets one instruction accept either program.
Reference: Solana docs: Token Extensions · Solana Program Library: Token-2022
Real code, line by line
3 excerpts from different projects. Each caption links the exact lines at the fork's pinned commit. The notes below each excerpt explain the lines that matter.
lib/src/lib/getMintWithCorrectTokenProgram.ts L1–26 @ 7aa9ddf · MIT · originalimport { PublicKey, type Connection } from "@solana/web3.js";import { Mint, TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID, getMint,} from "@solana/spl-token";import { Vault } from "./program";import { ValhallaVault } from "./models"; export async function getMintWithCorrectTokenProgram( connection: Connection, vault: Partial<Vault | ValhallaVault>): Promise<{ mint: Mint; tokenProgramId: PublicKey }> { try { const mint = new PublicKey(vault.mint || ""); return { mint: await getMint(connection, mint), tokenProgramId: TOKEN_PROGRAM_ID, }; } catch (error) { const mint = new PublicKey(vault.mint || ""); return { mint: await getMint(connection, mint, undefined, TOKEN_2022_PROGRAM_ID), tokenProgramId: TOKEN_2022_PROGRAM_ID, };- Line 4
TOKEN_2022_PROGRAM_ID,: Targets the Token-2022 program instead of the original Token Program.
libs/api/preset/data-access/src/lib/api-preset-minter.service.ts L203–228 @ b87eed9 · MIT · original const minterTokenAccount = getAssociatedTokenAddressSync( mintKeypair.publicKey, minter, true, TOKEN_2022_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID, ) // TODO: Change funder as per needed const funder = authority const funderPaymentTokenAccount = getAssociatedTokenAddressSync( paymentConfig.mint, funder.publicKey, false, TOKEN_2022_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID, ) const { decimals: paymentConfigDecimals } = await getMint( this.solana.connection, paymentConfig.mint, 'confirmed', TOKEN_2022_PROGRAM_ID, ) const { decimals: appPaymentConfigDecimals } = await getMint(- Line 207
TOKEN_2022_PROGRAM_ID,: Targets the Token-2022 program instead of the original Token Program.
warden/src/warden.rs L2–27 @ 09c8df3 · Apache-2.0 · original use std::str::FromStr; use anchor_spl::associated_token;use common_utils::prelude::anchor_spl::token_2022::spl_token_2022;use common_utils::prelude::anchor_spl::token_2022::spl_token_2022::extension::transfer_fee::TransferFeeAmount;use common_utils::prelude::anchor_spl::token_2022::spl_token_2022::extension::{ BaseStateWithExtensions, StateWithExtensions,};use common_utils::prelude::*;use log::{error, info, warn};use nacl::sign::generate_keypair;use player_profile::client::find_key_in_profile;use player_profile::state::{Profile, ProfileKey};use profile_vault::{drain_vault_ix, ProfileVaultPermissions, VaultAuthority};use solana_sdk::bs58;use solana_sdk::commitment_config::CommitmentConfig;use solana_sdk::pubkey::Pubkey; use common::VaultBalance; use crate::{ redis::redis_client::RedisClient, scrambler::Scrambler, HasherTrait, ToRedisKey, WardenError,}; pub const EPOCH_MINT: &str = "EPCHJ3JhGrx2y9NKR5BsmCLwBpFxFheMHDZsmn59BwAi";- Line 6
use common_utils::prelude::anchor_spl::token_2022::spl_token_2022;: Targets the Token-2022 program instead of the original Token Program.
Go further
- valhalla: explore the full project
- tokengator: explore the full project
- epoch: explore the full project
- Next lesson: Escrow patterns