使用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;
}
})
运行后,当测试转币成功,说明成功解锁了账户。