Token SPL em Programas
Os programas on-chain interagem com o token SPL por meio de invocações entre programas (CPIs). Anchor 0.32.1 anchor-spl envolve validação de conta, desserialização e construtores de instruções para lógica de token de nível de produção.
Receita
use anchor_spl::token::{self, Token, TokenAccount, Transfer};
#[account(mut)]
pub from: Account<'info, TokenAccount>,
pub token_program: Program<'info, Token>,
// ...
token::transfer(cpi_ctx, amount)?;
Quando fazer isso:
- Programas de depósito, cofre ou pagamento que movimentam tokens SPL
- Validando ATAs de usuários em instruções DeFi
- Cunhar tokens de recompensa de uma autoridade de cunhagem de PDA
- Aplicação de regras de correspondência e assinante em CPIs de token
Exemplo de trabalho
use anchor_lang::prelude::*;
use anchor_spl::associated_token::AssociatedToken;
use anchor_spl::token::{self, Mint, Token, TokenAccount, Transfer, TransferChecked};
#[derive(Accounts)]
pub struct Deposit<'info> {
pub mint: Account<'info, Mint>,
#[account(
mut,
associated_token::mint = mint,
associated_token::authority = user,
)]
pub user_ata: Account<'info, TokenAccount>,
#[account(
mut,
token::mint = mint,
token::authority = vault_authority,
)]
pub vault_ata: Account<'info, TokenAccount>,
pub user: Signer<'info>,
/// CHECK: PDA authority over vault ATA
pub vault_authority: UncheckedAccount<'info>,
pub token_program: Program<'info, Token>,
pub associated_token_program: Program<'info, AssociatedToken>,
pub system_program: Program<'info, System>,
}
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
require!(amount > 0, ErrorCode::ZeroAmount);
let decimals = ctx.accounts.mint.decimals;
let cpi = CpiContext::new(
ctx.accounts.token_program.to_account_info(),
TransferChecked {
mint: ctx.accounts.mint.to_account_info(),
from: ctx.accounts.user_ata.to_account_info(),
to: ctx.accounts.vault_ata.to_account_info(),
authority: ctx.accounts.user.to_account_info(),
},
);
token::transfer_checked(cpi, amount, decimals)?;
Ok(())
}
#[error_code]
pub enum ErrorCode {
ZeroAmount,
}
O que isso demonstra:
Account<'info, TokenAccount>valida que o proprietário é o programa Token- As restrições
token::minteassociated_tokenreduzem as verificações manuais de pubkey transfer_checkedinclui decimais para manuseio mais seguro de ativos
Aprofundamento
Como funciona
- ID do programa de token SPL:
TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA - CPI passa instrução serializada + metas de conta para o programa Token
- Requisitos do signatário: proprietário para débito, autoridade mint para mint_to, etc.
anchor_spl::token_interfacesuporta Token-2022 com tipoTokenInterface
Instruções comuns de CPI
| Instrução | Signatário | Valida |
|---|---|---|
transfer / transfer_checked | Autoridade de origem | Equilíbrio suficiente |
mint_to | Autoridade da casa da moeda | Aumento da oferta |
burn | Proprietário da conta | Diminuição do saldo |
approve | Proprietário | Teto delegado |
Notas em Rust
use anchor_spl::token_interface::{
TokenAccount as InterfaceTokenAccount,
TokenInterface,
transfer_checked as interface_transfer_checked,
};
// Use TokenInterface + InterfaceTokenAccount for Token-2022 mints
Pegadinhas
- Falta verificação de igualdade do mint - ativo errado do vault ATA. Correção: restrição
token::mint = mintem todas as contas de token. - UncheckedAccount como autoridade do cofre - sem validação de sementes de PDA. Correção: restrições
seeds+bumpno PDA de autoridade. - Conta token_program errada - CPI para Token clássico para Token-2022 mint falha. Correção: use
token_interfaceou passe o ID correto do programa. - PDA não pode assinar transferência - sementes
with_signerfaltando. Correção:CpiContext::new_with_signercom sementes do Vault. - Reentrada via token CPI - programas de gancho externos (Token-2022) podem retornar chamada. Correção: estado de guarda; consulte a documentação do gancho de transferência.
Alternativas
| Alternativa | Usar quando | Não use quando |
|---|---|---|
Caixa invoke + spl_token bruta | Programa Não Anchor | Projeto anchor com anchor-spl disponível |
token_interface | Multiprograma (Token + Token-2022) | Token Clássico apenas para sempre |
| Movimentações de token somente do cliente | Usuário assina todas as transferências | Lógica de cofre de custódia |
Perguntas frequentes
O que é anchor-spl?
Caixa de anchor, ajudantes de CPI do programa SPL e tipos de conta para token, ATA, metadados e muito mais.
Devo usar Account<TokenAccount>?
Fortemente recomendado no Anchor - desserializa e verifica a propriedade do programa Token.
Como os PDAs assinam CPIs de token?
CpiContext::new_with_signer com sementes correspondentes ao PDA de autoridade do vault.
transferência vs transfer_checked?
Prefira transfer_checked em programas - inclui proteção de decimais.
Uma instrução pode fazer múltiplas transferências de CPI?
Sim. Agrupar múltiplas instruções de token em uma transação do cliente; o programa pode fazer um loop de CPIs dentro do orçamento de CU.
Como posso oferecer suporte ao Token-2022?
Mude para os tipos token_interface e passe o programa proprietário do mint real nas restrições.
Quem paga a criação de ATA em programas?
init ou init_if_needed no ATA com assinante payer - geralmente protocolo de tesouraria.
Posso encerrar contas de token em programas?
Sim, via CloseAccount CPI quando o saldo é zero e sinais de autoridade próximos.
Como testar CPIs de token?
Validador local LiteSVM 0.6.x ou Surfpool 0.12.0 com programa Token implantado por padrão.
E as contas de token multisig?
O multisig SPL legado ainda existe - a maioria dos aplicativos usa cofres de PDA.
Preciso de uma conta associada_token_program?
Obrigatório na lista de contas quando a instrução cria ATAs via CPI.
Como os erros são mapeados?
Erros de programa de token retornam como erros de programa - mapeie para #[error_code] personalizado para UX.
Relacionado
- Contas de token associadas (ATAs) - Restrições de ATA
- Transferências e delegados - fluxos de delegados
- Invocações de programas cruzados (CPI) - Fundamentos de CPI
Versões Stack: Esta página foi escrita para Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0 e LiteSVM 0.6.x.