導入
第6章で学んだ CPI(Cross-Program Invocation) は、まさにトークン操作のために使われます。トークンの発行(ミント)や送金は、あなたのプログラムが自分でロジックを書くのではなく、Token Programという別のプログラムを呼び出して実行してもらいます。
説明
Anchorには anchor_spl::token というクレートがあり、Token ProgramへのCPI呼び出しをラップした関数が用意されています。代表的なのが mint_to(新規発行)と transfer(送金)です。
use anchor_lang::prelude::*;
use anchor_spl::token::{self, Mint, Token, TokenAccount, MintTo};
pub fn mint_reward(ctx: Context<MintReward>, amount: u64) -> Result<()> {
let cpi_accounts = MintTo {
mint: ctx.accounts.mint.to_account_info(),
to: ctx.accounts.destination.to_account_info(),
authority: ctx.accounts.mint_authority.to_account_info(),
};
let cpi_ctx = CpiContext::new(ctx.accounts.token_program.to_account_info(), cpi_accounts);
token::mint_to(cpi_ctx, amount)?;
Ok(())
}
#[derive(Accounts)]
pub struct MintReward<'info> {
#[account(mut)]
pub mint: Account<'info, Mint>,
#[account(mut)]
pub destination: Account<'info, TokenAccount>,
pub mint_authority: Signer<'info>,
pub token_program: Program<'info, Token>,
}
流れを図にすると、あなたのプログラムが「橋渡し役」になっていることが分かります。
sequenceDiagram
participant Client as クライアント
participant Prog as あなたのプログラム
participant Token as Token Program(CPI先)
Client->>Prog: mint_reward(amount) を呼び出す
Prog->>Prog: CpiContextを組み立てる
Prog->>Token: mint_toをCPIで呼び出す
Token->>Token: destinationの残高を増やす
Token-->>Prog: 成功を返す
Prog-->>Client: Ok(())
送金も同じパターンです。Transfer { from, to, authority } を組み立てて token::transfer(cpi_ctx, amount) を呼びます。あなたのプログラムは残高の増減ロジック自体を持たず、「いつ・誰に・いくら」という条件判断だけを担当し、実際の帳簿操作はToken Programに委ねるという役割分担がポイントです。
演習
mint_authority が Signer<'info> として要求されているのはなぜでしょうか。もしこの制約がなかったら、誰でもトークンを無限に発行できてしまう、という視点で考えてみましょう。
ヒント1を見る
Mintアカウントには「誰が新規発行してよいか」を表す mint authority という設定があります。
ヒント2を見る
Signer<'info> によって「そのmint authorityの秘密鍵を持つ本人が署名している」ことをAnchorが検証します。