Solana 技术训练营 2026

2026年01月09日更新 193 人订阅
课程介绍
C4: Solana 程序开发入门: 简单链上数据存储程序扩展为可交易的代币程序

使用 Anchor 的 SPL 代币

The Token Program

在 Solana 上,所有与代币相关的操作都由 SPL Token Program 和 Token2022 Program 处理:这是 Solana 的原生代币框架,定义了所有代币的创建、管理和转移方式。

这是一个单一的统一程序,处理整个网络中的所有代币操作,确保一致性和互操作性。

⚠️ 在 Solana 上为所有代币提供单一统一接口的决定,创造了一种可以在所有 dApp(去中心化应用程序)和集成(如钱包等)中复制的简单实现。

对于 Anchor,所有与代币相关的内容都可以在 anchor-spl crate 中找到。因此,在初始化了一个 Anchor 工作区后,我们可以这样做:

cargo add anchor-spl

⚠️ 如果您不熟悉 Anchor,我们建议先完成 Anchor 入门 再继续。

铸币账户和代币账户

如果您熟悉 Anchor,您会知道它们有一组宏,可以帮助用户抽象掉与初始化账户相关的许多复杂性。

同样适用于 MintToken 和 Associated Token 账户。

铸币账户

得益于 Anchor 提供的宏,我们可以轻松创建一个 Mint 账户,如下所示:

#[derive(Accounts)]
pub struct CreateMint<'info> {
    #[account(mut)]
    pub signer: Signer<'info>,
    #[account(
        init,
        payer = signer,
        mint::decimals = 6,
        mint::authority = signer.key(),
    )]
    pub mint: Account<'info, Mint>,
    pub system_program: Program<'info, System>,
    pub token_program: Program<'info, Token>,
}

代币账户

同样适用于 Token 账户。通过宏创建 Token 账户的方式如下:

#[derive(Accounts)]
pub struct CreateToken<'info> {
    #[account(mut)]
    pub signer: Signer<'info>,
    pub mint: Account<'info, Mint>,
    #[account(
        mut,
        token::mint = mint,
        token::authority = signer,
    )]
    pub token: Account<'info, TokenAccount>,
    pub system_program: Program<'info, System>,
    pub token_program: Program<'info, Token>,
}

关联代币账户

同样适用于 Associated Token 账户,通过宏创建 Associated Token 账户的方式与创建 Token 账户类似,唯一的区别在于约束条件,具体如下:

#[derive(Accounts)]
pub struct CreateToken<'info> {
    #[account(mut)]
    pub signer: Signer<'info>,
    pub mint: Account<'info, Mint>,
    #[account(
        mut,
        associated_token::mint = mint,
        associated_token::authority = signer,
    )]
    pub token: Account<'info, TokenAccount>,
    pub system_program: Program<'info, System>,
    pub token_program: Program<'info, Token>,
    pub associated_token_program: Program<'info, AssociatedToken>,
}

Mint To 指令

创建新代币并将其存入指定账户。只有铸币权限持有者可以执行此操作。

在我们铸造任何代币之前,我们需要已经完成以下操作:

  • 初始化一个 Mint 账户,并持有 mintAuthority
  • 初始化一个 Token 账户或 Associated Token 账户,用于接收铸造的代币

⚠️ 我们铸造的代币数量是根据小数位数进行“标准化”的。这意味着如果我们想铸造一个具有 6 位小数的代币,我们实际上需要将金额设置为 1_000_000

以下是 CPI 到 mint_to() 指令的示例:

mint_to(
    CpiContext::new(
        ctx.accounts.token_program.to_account_info(),
        MintTo {
            mint: ctx.accounts.mint_account.to_account_info(),
            to: ctx.accounts.to_token_account.to_account_info(),
            authority: ctx.accounts.authority.to_account_info(),
        },
    ),
    &1_000_000,
)?;

转账指令

将代币从一个账户转移到另一个账户。这是用户之间发送代币的基本操作。

在我们可以转移任何代币之前,我们需要已经具备以下条件:

  • 已初始化一个 Mint 账户。
  • 一个源 Token 账户或 Associated Token 账户,并且该账户中至少有我们想要转移的数量。
  • 一个目标 Token 账户或 Associated Token 账户,用于接收来自源 Token 账户的代币。

⚠️ 我们转移的代币数量是根据小数位数进行“标准化”的。这意味着如果我们想要转移一个有 6 位小数的代币,我们实际上需要将 1_000_000 作为数量。

以下是 CPI 到 transfer() 指令的样子:

transfer(
    CpiContext::new(
        ctx.accounts.token_program.to_account_info(),
        Transfer {
            from: ctx.accounts.from_token_account.to_account_info(),
            to: ctx.accounts.to_token_account.to_account_info(),
            authority: ctx.accounts.authority.to_account_info(),
        },
    ),
    &1_000_000,
)?;

销毁指令

通过将代币从流通中移除来永久销毁代币。这将减少代币的总供应量。

在我们销毁任何代币之前,我们需要已经拥有:

  • 一个已初始化的 Mint 账户。
  • 一个 Token 账户或一个 Associated Token 账户,并且该账户中至少有我们想要销毁的数量。

⚠️ 我们销毁的代币数量是根据小数位数进行“标准化”的。这意味着,如果我们想销毁一个有 6 位小数的代币,我们实际上需要将 1_000_000 作为数量输入。

这是 CPI 到 burn() 指令的样子:

burn(
    CpiContext::new(
        ctx.accounts.token_program.to_account_info(),
        Burn {
            mint: ctx.accounts.mint.to_account_info(),
            from: ctx.accounts.token_account.to_account_info(),
            authority: ctx.accounts.authority.to_account_info(),
        },
    ),
    &1_000_000,
)?;

关闭账户指令

关闭一个 token 账户,并将其剩余的 SOL 租金转移到目标账户。该 token 账户必须余额为零,除非它是一个原生 SOL 账户。

⚠️ 从 Token2022 开始,可以关闭供应量为 0 的 Mint 账户。

在我们关闭任何 token 账户之前,我们需要已经完成以下操作:

  • 初始化一个 Mint 账户
  • 初始化一个 Token 账户或一个没有任何 token 的 Associated Token 账户。

以下是 CPI 到 close_account() 指令的示例:

close_account(
    CpiContext::new(
        ctx.accounts.token_program.to_account_info(),
        CloseAccount {
            account: ctx.accounts.token_account.to_account_info(),
            destination: ctx.accounts.authority.to_account_info(),,
            authority: ctx.accounts.authority.to_account_info(),
        },
    ),
)?;

批准和撤销指令

批准允许代理人代表账户所有者转移特定数量的代币。这使得程序化的代币转移成为可能,而无需授予完整的账户控制权。

⚠️ 我们设置一个“批准”的金额,代理人只能转移不超过该金额的代币

撤销会移除当前代理人对账户的权限,将完整的控制权还给账户所有者。

⚠️ 立即取消任何现有的代理权限,并且只有账户所有者可以撤销代理(代理人本身无法撤销)

在我们可以代理或撤销任何代币账户之前,我们需要已经完成以下操作:

  • 初始化一个 Mint 账户。
  • 初始化一个 Token 账户或 Associated Token 账户,我们将对其进行控制

⚠️ 我们铸造的代币数量是根据小数位数“标准化”的。这意味着如果我们想铸造一个有 6 位小数的代币,我们实际上需要将金额设置为 1_000_000

以下是 CPI 到 approve() 指令的样子:

approve(
    CpiContext::new(
        ctx.accounts.token_program.to_account_info(),
        Approve {
            to: ctx.accounts.token_account.to_account_info(),
            delegate: ctx.accounts.delegate.to_account_info(),
            authority: ctx.accounts.authority.to_account_info(),
        },
    ),
    &1_000_000,
)?;

以下是 CPI 到 revoke() 指令的样子:

revoke(
    CpiContext::new(
        ctx.accounts.token_program.to_account_info(),
        Revoke {
            pub source: ctx.accounts.token_account.to_account_info(),
            authority: ctx.accounts.authority.to_account_info(),
        },
    ),
)?;

冻结和解冻说明

冻结会阻止账户上的所有代币操作,直到账户被解冻。只有代币的冻结权限持有者才能执行此操作。

⚠️ 完全禁用转账、授权和销毁操作,并且仅影响特定被冻结的账户

解冻会重新启用之前被冻结账户上的代币操作。只有代币的冻结权限持有者才能解冻账户。

⚠️ 恢复被冻结账户的全部功能,并且只能由代币的冻结权限持有者执行

在我们冻结或解冻任何代币账户之前,我们需要已经完成以下操作:

  • 初始化了一个我们持有 freezeAuthority 的 Mint 账户
  • 初始化了一个我们想要冻结或解冻的 Token 账户或 Associated Token 账户

以下是 CPI 到 freeze_account() 指令的示例:

freeze_account(
    CpiContext::new(
        ctx.accounts.token_program.to_account_info(),
        FreezeAccount {
            account: ctx.accounts.token_account.to_account_info(),
            mint: ctx.accounts.mint.to_account_info(),,
            authority: ctx.accounts.authority.to_account_info(),
        },
    ),
)?;

以下是 CPI 到 thaw_account() 指令的示例:

thaw_account(
    CpiContext::new(
        ctx.accounts.token_program.to_account_info(),
        ThawAccount {
            account: ctx.accounts.token_account.to_account_info(),
            mint: ctx.accounts.mint.to_account_info(),,
            authority: ctx.accounts.authority.to_account_info(),
        },
    ),
)?;

设置权限说明

更改 mint 或账户的权限。这允许转移所有权或更新特定的权限类型。

在我们设置任何代币或代币账户的权限之前,我们需要已经完成以下操作:

  • 初始化一个我们持有 mintAuthority 或 freezeAuthority 的 Mint 账户
  • 初始化一个我们拥有的 Token 账户或 Associated Token 账户

以下是 CPI 到 set_authority() 指令的示例:

set_authority(
    CpiContext::new(
        ctx.accounts.token_program.to_account_info(),
        SetAuthority {
            account_or_mint: ctx.accounts.mint_account.to_account_info(),
            to: ctx.accounts.to_token_account.to_account_info(),
            current_authority: ctx.accounts.authority.to_account_info(),
        },
    ),
    &spl_token::instruction::AuthorityType::MintTokens, // authority_type
    Some(new_authority.key()) // new_autority
)?;

本节作者:blueshift

点赞 0
收藏 0
分享

0 条评论

请先 登录 后评论