LogoAnchor 中文文档

创建Token Mint

了解如何使用Anchor在Solana程序中创建和初始化token mint账户。涵盖使用生成的密钥对或PDA创建mint账户的代码示例。

什么是Mint账户?

Mint账户是Solana的Token Programs中的一种账户类型,它唯一地代表了网络上的一个token,并存储了该token的全局元数据。

/// Mint数据。
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Mint {
  /// 用于铸造新token的可选权限。mint权限只能在mint创建期间提供。如果没有mint权限,则mint具有固定的供应量,并且无法铸造更多的token。
  pub mint_authority: COption<Pubkey>,
  /// token的总供应量。
  pub supply: u64,
  /// 小数点右侧的十进制位数。
  pub decimals: u8,
  /// 如果此结构已初始化,则为`true`
  pub is_initialized: bool,
  /// 用于冻结token账户的可选权限。
  pub freeze_authority: COption<Pubkey>,
}

请注意,Token ProgramToken Extension Program都拥有相同的Mint账户基础实现。

Solana上的每一个token都由一个mint账户表示,mint账户的地址作为其在网络上的唯一标识符。

例如,Solana上的USDC稳定币由其mint地址EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v标识。这个mint地址在整个Solana生态系统中作为USDC的唯一标识符。你可以在Solana Explorer上查看有关此mint账户的详细信息。

使用方法

使用anchor-spl crate中的token_interface模块来与Token Program和Token Extension Program进行交互。该模块提供了适用于这两种token程序的类型,允许你编写与任一程序兼容的代码。

snippet

use anchor_spl::token_interface::{Mint, TokenInterface};
 
// --snip--
 
#[derive(Accounts)]
pub struct CreateMint<'info> {
    #[account(mut)]
    pub signer: Signer<'info>,
    #[account(
        init,
        payer = signer,
        mint::decimals = 6,
        mint::authority = signer.key(),
        mint::freeze_authority = signer.key(),
    )]


    pub mint: InterfaceAccount<'info, Mint>,


    pub token_program: Interface<'info, TokenInterface>,
    pub system_program: Program<'info, System>,
}

账户类型

InterfaceAccount类型是一个包装器,可以接受来自Token Program或Token Extension Program的账户。

Mint类型代表两种token程序共享的基础Mint数据结构。当传入此类型的账户时,Anchor会自动将账户数据反序列化为mint结构体,无论是由哪个token程序创建的。

账户类型
pub mint: InterfaceAccount<'info, Mint>,

账户约束

以下账户约束组合使用,以创建和初始化一个新的mint账户:

约束描述
init通过向System Program进行跨程序调用(CPI)来创建一个新账户。这会为mint账户分配所需的空间,并将所有权转移到适当的token程序。
payer指定哪个账户将支付创建新账户所需的租金(SOL存款)。
mint::decimals设置token的小数位数。例如,将此值设置为6表示1个token = 1,000,000个基础单位。
mint::authority设置mint权限——有权限铸造新token的账户。(必需)
mint::freeze_authority设置冻结权限——有权限冻结token账户的账户。(可选)冻结一个token账户会阻止token程序处理包含该冻结token账户的指令(例如转账、销毁等)。
账户约束
#[account(
    init,
    payer = <payer>,
    mint::decimals = <decimals>,
    mint::authority = <authority>,
    mint::freeze_authority = <freeze_authority>,
)]
pub mint: InterfaceAccount<'info, Mint>,

或者,你可以添加seedsbump约束,以创建一个mint账户,其中账户的地址是一个程序派生地址(PDA)。使用PDA的好处是,mint地址可以在任何时候从相同的种子派生。

账户约束
#[account(
    init,
    payer = <payer>,
    mint::decimals = <decimals>,
    mint::authority = <authority>,
    mint::freeze_authority = <freeze_authority>,
    seeds = [<seeds>],
    bump
)]
pub mint: InterfaceAccount<'info, Mint>,

注意,你可以使用同一个PDA作为mint::authority和mint账户地址。使用PDA作为mint::authority可以使你的程序能够“签名”CPI指令以铸造新的token单位。这种模式允许为这两种用途使用单个确定性地址。

示例

以下示例演示了如何在Anchor程序中使用两种不同的方法创建mint账户:

  1. 使用生成的Keypair——这是一种生成新密钥对作为mint地址的方法。当你不需要确定性mint地址时,这很有用。

  2. 使用程序派生地址(PDA)——这种方法创建mint账户时,账户地址是从种子派生的PDA。这允许确定性mint地址,并且在需要稍后找到mint地址时非常有用。

这两种方法都可以完全使用账户约束来完成。

使用Keypair创建Mint

使用生成的Keypair创建一个新的mint账户。

lib.rs
use anchor_lang::prelude::*;
use anchor_spl::token_interface::{Mint, TokenInterface};
 
declare_id!("3pX5NKLru1UBDVckynWQxsgnJeUN3N1viy36Gk9TSn8d");
 
#[program]
pub mod token_example {
    use super::*;
 
    pub fn create_mint(ctx: Context<CreateMint>) -> Result<()> {
        msg!("Created Mint Account: {:?}", ctx.accounts.mint.key());
        Ok(())
    }
}
 
#[derive(Accounts)]
pub struct CreateMint<'info> {
    #[account(mut)]
    pub signer: Signer<'info>,
    #[account(

        init,
        payer = signer,
        mint::decimals = 6,
        mint::authority = signer.key(),
        mint::freeze_authority = signer.key(),
    )]
    pub mint: InterfaceAccount<'info, Mint>,
    pub token_program: Interface<'info, TokenInterface>,
    pub system_program: Program<'info, System>,
}

使用PDA创建Mint

使用程序派生地址(PDA)作为mint账户地址创建一个新的mint账户。

lib.rs
use anchor_lang::prelude::*;
use anchor_spl::token_interface::{Mint, TokenInterface};
 
declare_id!("3pX5NKLru1UBDVckynWQxsgnJeUN3N1viy36Gk9TSn8d");
 
#[program]
pub mod token_example {
    use super::*;
 
    pub fn create_mint(ctx: Context<CreateMint>) -> Result<()> {
        msg!("Created Mint Account: {:?}", ctx.accounts.mint.key());
        Ok(())
    }
}
 
#[derive(Accounts)]
pub struct CreateMint<'info> {
    #[account(mut)]
    pub signer: Signer<'info>,
    #[account(



        init,
        payer = signer,
        mint::decimals = 6,
        mint::authority = mint.key(),
        mint::freeze_authority = mint.key(),
        seeds = [b"mint"],
        bump
    )]
    pub mint: InterfaceAccount<'info, Mint>,
    pub token_program: Interface<'info, TokenInterface>,
    pub system_program: Program<'info, System>,
}

On this page

在GitHub上编辑