Anchor
Token2022 mit Anchor

Token2022 mit Anchor

Die Default Account State Extension

Die DefaultAccountState Extension ist eine Mint-Erweiterung, die es ermöglicht, dass alle neu erstellten Token Konten für diese spezifische Mint standardmäßig eingefroren werden. Der Freeze Authority der Mint kann dann diese Token Konten auftauen (entsperren), damit sie nutzbar werden.

Initializing the Mint Account

Da Anchor keine Makros für die default_account_state Extension hat, werden wir ein Mint Konto mit den direkten CPIs erstellen.

Hier ist, wie man eine Mint mit der Default Account State Extension erstellt:

rust
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(())
}

Denken Sie daran, dass der Freeze Authority auf der Mint für diese Erweiterung obligatorisch ist, sonst können wir kein Token Konto bei der Erstellung auftauen.

Thawing the Token Account

Mit der DefaultAccountState Extension werden alle Token Konten, die initialisiert werden, standardmäßig frozen.

Das bedeutet, dass es nicht möglich ist, mit diesen Token Konten zu Mint, zu Transfer oder überhaupt irgendetwas zu tun, wenn wir sie nicht auftauen (entsperren).

Wir können ein Token Konto einfach mit der thaw_account() Anweisung wie folgt auftauen:

rust
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(())
}

Changing the Default Account State

Sobald wir keine größere Kontrolle mehr über die Token-Verteilung benötigen und allen erlauben möchten, frei mit unserem Token zu handeln, können wir den Standard-Kontostatus mit der default_account_state_update() Anweisung wie folgt ändern:

rust
use anchor_lang::prelude::*;
use anchor_spl::{
    token_interface::{default_account_state_update, DefaultAccountStateUpdate, 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: e573eab