8. Anchor 框架集成
Anchor 是 Solana 上最流行的开发框架,它简化了程序开发流程。本章介绍如何在 Anchor 程序中集成代币操作。
8.1 Anchor 项目结构
创建新的 Anchor 项目:
bashanchor init token-program cd token-program
项目结构:
token-program/ ├── Anchor.toml # 项目配置 ├── Cargo.toml ├── programs/ │ └── token-program/ │ ├── Cargo.toml │ └── src/ │ └── lib.rs # 主程序代码 ├── tests/ │ └── token-program.ts # 测试文件 └── migrations/
8.2 在 Anchor 中创建代币
更新 programs/token-program/Cargo.toml 添加依赖:
toml[dependencies] anchor-lang = "0.30.1" anchor-spl = "0.30.1"
编写程序代码:
rust// programs/token-program/src/lib.rs use anchor_lang::prelude::*; use anchor_spl::{ token_2022::{self, Token2022, MintTo, Transfer}, token_interface::{Mint, TokenAccount, TokenInterface}, associated_token::AssociatedToken, }; declare_id!("YOUR_PROGRAM_ID"); #[program] pub mod token_program { use super::*; /// 创建新代币 pub fn create_token( ctx: Context<CreateToken>, decimals: u8, ) -> Result<()> { msg!("代币创建成功!"); msg!("Mint 地址: {}", ctx.accounts.mint.key()); msg!("精度: {}", decimals); Ok(()) } /// 铸造代币 pub fn mint_tokens( ctx: Context<MintTokens>, amount: u64, ) -> Result<()> { let cpi_accounts = MintTo { mint: ctx.accounts.mint.to_account_info(), to: ctx.accounts.token_account.to_account_info(), authority: ctx.accounts.authority.to_account_info(), }; let cpi_program = ctx.accounts.token_program.to_account_info(); let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts); token_2022::mint_to(cpi_ctx, amount)?; msg!("铸造 {} 代币到 {}", amount, ctx.accounts.token_account.key()); Ok(()) } /// 转账代币 pub fn transfer_tokens( ctx: Context<TransferTokens>, amount: u64, ) -> Result<()> { let cpi_accounts = Transfer { from: ctx.accounts.from.to_account_info(), to: ctx.accounts.to.to_account_info(), authority: ctx.accounts.authority.to_account_info(), }; let cpi_program = ctx.accounts.token_program.to_account_info(); let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts); token_2022::transfer(cpi_ctx, amount)?; msg!("转账 {} 代币", amount); Ok(()) } } #[derive(Accounts)] #[instruction(decimals: u8)] pub struct CreateToken<'info> { #[account( init, payer = payer, mint::decimals = decimals, mint::authority = payer, mint::freeze_authority = payer, mint::token_program = token_program, )] pub mint: InterfaceAccount<'info, Mint>, #[account(mut)] pub payer: Signer<'info>, pub token_program: Interface<'info, TokenInterface>, pub system_program: Program<'info, System>, }
8.3 使用 PDA 作为权限
在实际应用中,常需要让程序自身控制代币的铸造或转账。这通过 PDA(程序派生地址)实现:
rustuse anchor_lang::prelude::*; use anchor_spl::{ token_2022::{self, MintTo}, token_interface::{Mint, TokenAccount, TokenInterface}, }; #[program] pub mod vault { use super::*; /// 程序控制的铸造 pub fn program_mint( ctx: Context<ProgramMint>, amount: u64, ) -> Result<()> { // 构建 PDA seeds let seeds = &[ b"mint_authority", ctx.accounts.mint.to_account_info().key.as_ref(), &[ctx.bumps.mint_authority], ]; let signer_seeds = &[&seeds[..]]; // 使用 PDA 签名进行 CPI 调用 let cpi_accounts = MintTo { mint: ctx.accounts.mint.to_account_info(), to: ctx.accounts.token_account.to_account_info(), authority: ctx.accounts.mint_authority.to_account_info(), }; let cpi_ctx = CpiContext::new_with_signer( ctx.accounts.token_program.to_account_info(), cpi_accounts, signer_seeds, ); token_2022::mint_to(cpi_ctx, amount)?; Ok(()) } }