Token-2022 (Token Extensions) banner
solanabr solanabr

Token-2022 (Token Extensions)

Development community intermediate

Description

SPL Token-2022 is the next-generation token program (`TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`). Superset of SPL Token with extensions that add functionality at the mint or account level. **Progra

Installation

This entry records only its repository, not the path inside it, so there is no exact command to give. Open the source below and copy the folder into ~/.claude/skills/, or the file into ~/.claude/agents/.

Repository README

This is the README for solanabr/solana-claude, shared by 5 entries in this directory. It describes the repository, not this entry specifically.


name: token-2022 description: Comprehensive guide to SPL Token-2022 (Token Extensions) — transfer hooks, confidential transfers, metadata, transfer fees, and all extension types with practical Anchor/native patterns.

Token-2022 (Token Extensions)

SPL Token-2022 is the next-generation token program (`TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`). Superset of SPL Token with extensions that add functionality at the mint or account level.

**Program IDs:**

  • Token-2022: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
  • SPL Token (legacy): TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA

1. Transfer Hooks

Execute custom logic on every token transfer via a CPI to your program.

Anchor Transfer Hook Program

use anchor_lang::prelude::*;
use anchor_spl::token_2022;
use spl_transfer_hook_interface::instruction::TransferHookInstruction;

declare_id!("YourHookProgram111111111111111111111111111");

#[program]
pub mod transfer_hook {
    use super::*;

    // Called by Token-2022 on every transfer
    pub fn transfer_hook(ctx: Context, amount: u64) -> Result<()> {
        // Custom logic: logging, royalties, allowlists, etc.
        let counter = &mut ctx.accounts.counter;
        counter.transfers += 1;
        Ok(())
    }

    // Required: tells Token-2022 what extra accounts to include
    pub fn initialize_extra_account_meta_list(
        ctx: Context,
    ) -> Result<()> {
        let extra_metas = &[
            ExtraAccountMeta::new_with_seeds(
                &[Seed::Literal { bytes: b"counter".to_vec() }],
                false, // is_signer
                true,  // is_writable
            )?,
        ];
        ExtraAccountMetaList::init::(
            &mut ctx.accounts.extra_account_meta_list.try_borrow_mut_data()?,
            extra_metas,
        )?;
        Ok(())
    }
}

#[derive(Accounts)]
pub struct TransferHook<'info> {
    #[account(token::mint = mint, token::authority = owner)]
    pub source: InterfaceAccount<'info, token_2022::TokenAccount>,
    pub mint: InterfaceAccount<'info, token_2022::Mint>,
    #[account(token::mint = mint)]
    pub destination: InterfaceAccount<'info, token_2022::TokenAccount>,
    pub owner: UncheckedAccount<'info>,
    /// CHECK: validated by transfer hook interface
    pub extra_account_meta_list: UncheckedAccount<'info>,
    #[account(mut, seeds = [b"counter"], bump)]
    pub counter: Account<'info, TransferCounter>,
}

Client-Side: Adding Extra Accounts

import {
  createTransferCheckedWithTransferHookInstruction,
  getExtraAccountMetaAddress,
  getExtraAccountMetas,
} from "@solana/spl-token";

// Automatically resolves extra accounts from on-chain meta list
const ix = await createTransferCheckedWithTransferHookInstruction(
  connection,
  sourceAta,
  mint,
  destinationAta,
  owner.publicKey,
  amount,
  decimals,
  [],                  // multiSigners
  "confirmed",
  TOKEN_2022_PROGRAM_ID
);