Token2022 - 铸造代币
这里,我们给出例子来说明如何从程序中铸造代币。
创建mint_tokens指令
在instructions
中添加mint_tokens.rs
,并粘贴以下代码:
use anchor_lang::prelude::*;
use anchor_spl::token_2022::{
mint_to, spl_token_2022, MintTo,
};
use anchor_spl::{
token_interface::{
Token2022, TokenAccount, Mint
},
associated_token::AssociatedToken,
};
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
)]
pub mint: Box<InterfaceAccount<'info, Mint>>,
#[account(mut)]
pub destination: Box<InterfaceAccount<'info, TokenAccount>>, // ata account for token
#[account(mut)]
pub user: Signer<'info>,
pub rent: Sysvar<'info, Rent>,
pub token_program: Program<'info, Token2022>,
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_2022::ID == ctx.accounts.token_program.key(), ErrorCode::WrongTokenProgram);
// Mint tokens to miner's ATA
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.try_into().unwrap(),
)?;
Ok(())
}
}
在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 tokens by user1!", async () => {
const destinationAta = await getAssociatedTokenAddress(mintAccount, user1Account.publicKey, false, TOKEN_2022_PROGRAM_ID);
const destinationAtaInfo = await provider.connection.getAccountInfo(destinationAta);
const context = {
user: user1Account.publicKey,
mint: mintAccount,
destination: destinationAta,
tokenProgram: TOKEN_2022_PROGRAM_ID,
}
const amount = new anchor.BN(100).mul(new anchor.BN(1000000000)); // mint 100个
const ix = await program.methods
.mintTokens(metadataParams.name, metadataParams.symbol, amount)
.accounts(context)
.instruction();
const tx = new anchor.web3.Transaction();
if (destinationAtaInfo == null) {
// 如果目标账户没有创建Token account,需要先创建
const instructionDestinationAta = createAssociatedTokenAccountInstruction(
user1Account.publicKey,
destinationAta,
user1Account.publicKey,
mintAccount,
TOKEN_2022_PROGRAM_ID,
)
tx.add(instructionDestinationAta);
}
tx.add(ix);
const signature = await provider.sendAndConfirm(tx, [user1Account]);
console.log("Minted token tx:", signature);
})
检查
将上面运行后的tx输入区块链浏览器,如下图:
从前端发送了两个指令(Instruction),一个是用于在目标账户尚未创建Token account,需要先创建,另一个是用于mint tokens。