Anchor
使用 Anchor 的 Token2022

使用 Anchor 的 Token2022

默认账户状态扩展

DefaultAccountState 扩展是一种铸币扩展,允许所有新创建的 Token 账户默认被冻结。然后,铸币的 Freeze Authority 可以解冻(解除冻结)这些 Token 账户,使其可以使用。

初始化铸币账户

由于 Anchor 没有任何用于 default_account_state 扩展的宏,我们将使用原始 CPI 创建一个 Mint 账户。

以下是如何使用默认账户状态扩展创建铸币的方法:

use anchor_lang::prelude::*;
use anchor_lang::system_program::{create_account, CreateAccount};
use anchor_spl::{
    token_2022::{
        initialize_mint2,
        spl_token_2022::{extension::ExtensionType, pod::PodMint, state::AccountState},
        InitializeMint2,
    },
    token_interface::{
        default_account_state_initialize, DefaultAccountStateInitialize, Mint, Token2022,
    },
};
 
#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(mut)]
    pub payer: Signer<'info>,
    #[account(mut)]
    pub mint_account: Signer<'info>,
    pub token_program: Program<'info, Token2022>,
    pub system_program: Program<'info, System>,
}
 
pub fn initialize_default_account_state_(
    ctx: Context<Initialize>,
) -> Result<()> {
    // 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);
 
    // Invoke System Program to create new account with space for mint and extension data
    create_account(
        CpiContext::new(
            ctx.accounts.system_program.to_account_info(),
            CreateAccount {
                from: ctx.accounts.payer.to_account_info(),
                to: ctx.accounts.mint_account.to_account_info(),
            },
        ),
        lamports,                          // Lamports
        mint_size as u64,                  // Space
        &ctx.accounts.token_program.key(), // Owner Program
    )?;
 
    // Initialize the NonTransferable extension
    // This instruction must come before the instruction to initialize the mint data
    default_account_state_initialize(
        CpiContext::new(
            ctx.accounts.token_program.to_account_info(),
            DefaultAccountStateInitialize {
                token_program_id: ctx.accounts.token_program.to_account_info(),
                mint: ctx.accounts.mint_account.to_account_info(),
            },
        ),
        &AccountState::Frozen, // default frozen token accounts
    )?;
 
    // Initialize the standard mint account data
    initialize_mint2(
        CpiContext::new(
            ctx.accounts.token_program.to_account_info(),
            InitializeMint2 {
                mint: ctx.accounts.mint_account.to_account_info(),
            },
        ),
        2,                               // decimals
        &ctx.accounts.payer.key(),       // mint authority
        Some(&ctx.accounts.payer.key()), // freeze authority
    )?;
 
    Ok(())
}

请记住,Freeze AuthorityMint 上对于此扩展是必需的,否则我们将无法在创建时解冻任何 Token 账户。

解冻代币账户

拥有 DefaultAccountState 扩展意味着所有初始化的 Token 账户默认将被 frozen

这意味着如果我们不解冻(解除冻结)这些 Token 账户,就无法 MintTransfer 或几乎无法对这些账户执行任何操作。

我们可以使用 thaw_account() 指令轻松解冻一个 Token 账户,如下所示:

use anchor_lang::prelude::*;
use anchor_spl::{
    token_interface::{thaw_account, ThawAccount, Mint, Token, Token2022}
};
 
#[derive(Accounts)]
pub struct ThawAccount<'info> {
    #[account(mut)]
    pub freeze_authority: Signer<'info>,
    #[account(
        mut,
        mint::freeze_authority = freeze_authority,
    )]
    pub mint_account: InterfaceAccount<'info, Mint>,
    pub token_account: InterfaceAccount<'info, Token>,
    pub token_program: Program<'info, Token2022>,
    pub system_program: Program<'info, System>,
}
 
pub fn thaw_account(
    ctx: Context<UpdateState>,
) -> Result<()> {
    thaw_account(
        CpiContext::new(
            ctx.accounts.token_program.to_account_info(),
            ThawAccount {
                account: ctx.accounts.token_account.to_account_info(),
                mint: ctx.accounts.mint_account.to_account_info(),
                freeze_authority: ctx.accounts.freeze_authority.to_account_info(),
            },
        ),
        &account_state,
    )?;
    Ok(())
}

更改默认账户状态

一旦我们不再需要对代币分发进行更严格的控制,并希望让所有人自由交易代币时,我们可以使用 default_account_state_update() 指令更改默认账户状态,如下所示:

use anchor_lang::prelude::*;
use anchor_spl::{
    token_interface::{default_account_state_update, DeafaultAccountStateUpdate, Mint, Token2022}
    spl_token_2022::state::AccountState,   
};
 
#[derive(Accounts)]
pub struct UpdateState<'info> {
    #[account(mut)]
    pub freeze_authority: Signer<'info>,
    #[account(
        mut,
        mint::freeze_authority = freeze_authority,
    )]
    pub mint_account: InterfaceAccount<'info, Mint>,
    pub token_program: Program<'info, Token2022>,
    pub system_program: Program<'info, System>,
}
 
pub fn update_state(
    ctx: Context<UpdateState>,
    account_state: AnchorAccountState,
) -> Result<()> {
    // Convert AnchorAccountState to spl_token_2022::state::AccountState
    let account_state = account_state.to_spl_account_state();
 
    default_account_state_update(
        CpiContext::new(
            ctx.accounts.token_program.to_account_info(),
            DefaultAccountStateUpdate {
                token_program_id: ctx.accounts.token_program.to_account_info(),
                mint: ctx.accounts.mint_account.to_account_info(),
                freeze_authority: ctx.accounts.freeze_authority.to_account_info(),
            },
        ),
        &account_state,
    )?;
    Ok(())
}
 
// Custom enum to implement AnchorSerialize and AnchorDeserialize
// This is required to pass the enum as an argument to the instruction
#[derive(AnchorSerialize, AnchorDeserialize)]
pub enum AnchorAccountState {
    Uninitialized,
    Initialized,
    Frozen,
}
 
// Implement conversion from AnchorAccountState to spl_token_2022::state::AccountState
impl AnchorAccountState {
    pub fn to_spl_account_state(&self) -> AccountState {
        match self {
            AnchorAccountState::Uninitialized => AccountState::Uninitialized,
            AnchorAccountState::Initialized => AccountState::Initialized,
            AnchorAccountState::Frozen => AccountState::Frozen,
        }
    }
}
Blueshift © 2025Commit: fd080b2