Jacky Gu

Solana开发笔记: 使用anchor程序解冻代币

01 Jan 2025 Share to

使用anchor程序解冻代币

前面一篇中,详细介绍了如何冻结代币,这篇介绍解冻代币。

因为mint账户的冻结权限(freeze authority)是mint账户自己,所以本操作需要在anchor程序中进行。

创建解冻代币指令

instructions中添加thaw_token_account.rs,并粘贴以下代码:

use anchor_lang::prelude::*;

use anchor_spl::associated_token::AssociatedToken;
use anchor_spl::token::{thaw_account, spl_token, Mint, ThawAccount, Token, TokenAccount};

use crate::constants::MINT_SEEDS;
use crate::errors::ErrorCode;

#[derive(Accounts)]
#[instruction(token_name: String, token_symbol: String)]
pub struct ThawTokenAccount<'info> {
    #[account(
      mut,
      seeds = [MINT_SEEDS.as_bytes(), token_name.as_bytes(), token_symbol.as_bytes()],
      bump,
      mint::authority = mint,
      mint::decimals = 9,
    )]
    pub mint: Box<Account<'info, Mint>>,
    #[account(
      init_if_needed,
      payer = user,
      associated_token::mint = mint,
      associated_token::authority = user, // destination is the ata account and user is the owner
    )]
    pub destination: Box<Account<'info, TokenAccount>>, // ata account
    #[account(mut)]
    pub user: Signer<'info>,
    pub rent: Sysvar<'info, Rent>,
    pub token_program: Program<'info, Token>,
    pub system_program: Program<'info, System>,
    pub associated_token_program: Program<'info, AssociatedToken>,
}

impl<'info> ThawTokenAccount<'info> {
    pub fn thaw_token_account(ctx: Context<ThawTokenAccount>, token_name: String, token_symbol: String) -> Result<()> {
        require!(spl_token::ID == ctx.accounts.token_program.key(), ErrorCode::WrongTokenProgram);
        let seeds = &[MINT_SEEDS.as_bytes(), token_name.as_bytes(), token_symbol.as_bytes(), &[ctx.bumps.mint]];
        let signer = [&seeds[..]];

        let thaw_ctx = CpiContext::new_with_signer(
            ctx.accounts.token_program.to_account_info(),
            ThawAccount {
                account: ctx.accounts.destination.to_account_info(),
                mint: ctx.accounts.mint.to_account_info(),
                authority: ctx.accounts.mint.to_account_info(),
            },
            &signer,
        );
        thaw_account(thaw_ctx)?;
        msg!("Thaw ata successfully.");
        Ok(())
    }
}

在lib.rs中调用上面的指令

    pub fn thaw_token_account(ctx: Context<ThawTokenAccount>, token_name: String, token_symbol: String) -> Result<()> {
        ThawTokenAccount::thaw_token_account(ctx, token_name, token_symbol)
    }

编译部署

anchor build && anchor deploy

编写测试代码

  it("thaw token account", async () => {
    // Get user1's token account (ATA)
    const tokenAccount = await getAssociatedTokenAddress(mintAccount, user1Account.publicKey, false, TOKEN_PROGRAM_ID);

    // Prepare context for thaw instruction
    const context = {
      mint: mintAccount,
      destination: tokenAccount,
      user: user1Account.publicKey,
      tokenProgram: TOKEN_PROGRAM_ID,
    };

    // Call thaw_token_account instruction
    const tx = await program.methods
      .thawTokenAccount(metadataParams.name, metadataParams.symbol)
      .accounts(context)
      .signers([user1Account])
      .rpc();

    console.log("Thaw token account transaction signature:", tx);

    // Verify the token account is thawed by attempting to transfer tokens
    try {
      const sourceAta = await getAssociatedTokenAddress(mintAccount, user1Account.publicKey, false, TOKEN_PROGRAM_ID);
      const destinationAta = await getAssociatedTokenAddress(mintAccount, user2Account.publicKey, false, TOKEN_PROGRAM_ID);

      const transferIx = createTransferInstruction(
        sourceAta,
        destinationAta,
        user1Account.publicKey,
        10 * Math.pow(10, 9)  // 10 tokens
      );

      const transferTx = new anchor.web3.Transaction().add(transferIx);
      const signature = await provider.sendAndConfirm(transferTx, [user1Account]);
      console.log("Transfer from thawed account succeeded:", signature);

      // Get balances after transfer
      const sourceBalance = await provider.connection.getTokenAccountBalance(sourceAta);
      const destBalance = await provider.connection.getTokenAccountBalance(destinationAta);
      console.log("Source balance after transfer:", sourceBalance.value.uiAmount);
      console.log("Destination balance after transfer:", destBalance.value.uiAmount);
    } catch (error) {
      console.error("Transfer from thawed account failed unexpectedly:", error);
      throw error;
    }
  })

运行后,当测试转币成功,说明成功解锁了账户。