使用anchor程序铸造代币
前面一篇中,详细介绍了初始化一个Mint铸币厂,在这篇里,我们完成铸造代币。
创建mint token指令
在之前基础上,mint token的指令相对简单,在instructions
目录下创建mint_tokens.rs
,代码如下:
use anchor_lang::prelude::*;
use anchor_spl::associated_token::AssociatedToken;
use anchor_spl::token::{spl_token, Mint, mint_to, MintTo, Token, TokenAccount};
use crate::constants::MINT_SEEDS;
use crate::errors::ErrorCode;
#[derive(Accounts)]
#[instruction(token_name: String, token_symbol: String)]
pub struct MintTokens<'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> MintTokens<'info> {
pub fn mint_tokens(ctx: Context<MintTokens>, token_name: String, token_symbol: String, amount: u64) -> 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[..]];
mint_to(
CpiContext::new_with_signer(
ctx.accounts.token_program.to_account_info(),
MintTo {
mint: ctx.accounts.mint.to_account_info(),
to: ctx.accounts.destination.to_account_info(),
authority: ctx.accounts.mint.to_account_info(),
},
&signer,
),
amount,
).map_err(|e| {
msg!("Mint tokens to miner's ATA failed: {:?}", e);
e
})?;
msg!("Mint tokens to miner's ATA successfully.");
Ok(())
}
}
上面代码比较好理解,要注意的是,destination
是token account账户,也就是ATA账户。
在lib.rs中调用上面的指令
pub fn mint_tokens(ctx: Context<MintTokens>, token_name: String, token_symbol: String, amount: u64) -> Result<()> {
MintTokens::mint_tokens(ctx, token_name, token_symbol, amount)
}
编译部署
anchor build && anchor deploy
编写测试代码
it("mint token", async () => {
// mint tokens to user1
const destinationAta = await getAssociatedTokenAddress(mintAccount, user1Account.publicKey, false, TOKEN_PROGRAM_ID);
const context = {
mint: mintAccount,
destination: destinationAta,
user: user1Account.publicKey,
tokenProgram: TOKEN_PROGRAM_ID,
};
const amount = new anchor.BN(1000).mul(new anchor.BN(1000000000)); // 1000枚代币
const tx = await program.methods.mintTokens(metadataParams.name, metadataParams.symbol, amount).accounts(context).signers([user1Account]).rpc();
console.log("Your transaction signature", tx);
})
上面测试代码中,使用getAssociatedTokenAddress
获取ATA账户。
注意:这个时候是不确定destination是否已经初始化的,所以在程序中用了init_if_needed
。
另一个需要注意的地方是如果要使用init_if_needed
,需要在Cargo.toml
中配置:anchor-lang = {version = "0.30.1", features = ["init-if-needed"]}
运行测试脚本
anchor test --skip-local-validator
得到交易hash,把hash输入区块链浏览器,查看交易是否正常。
上图中显示铸币成功。