SPL Token en Programas
Los programas on-chain interactúan con SPL Token a través de invocaciones entre programas (CPIs). Anchor 0.32.1 anchor-spl encapsula la validación de cuentas, deserialización y constructores de instrucciones para lógica de tokens de grado de producción.
Receta
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)?;Cuándo usar esto:
- Programas de escrow, bóveda o pagos que mueven tokens SPL.
- Validar ATAs de usuario en instrucciones DeFi.
- Emitir tokens de recompensa desde una autoridad de emisión PDA.
- Aplicar reglas de coincidencia de emisión y firmante en CPIs de tokens.
Ejemplo Funcional
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,
}Qué demuestra esto:
Account<'info, TokenAccount>valida que el propietario sea el programa Token.- Las restricciones
token::mintyassociated_tokenreducen las comprobaciones manuales de pubkey. transfer_checkedincluye los decimales para un manejo más seguro de los activos.
Análisis Profundo
Cómo Funciona
- ID del programa SPL Token:
TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA - CPI pasa la instrucción serializada + metadatos de cuenta al programa Token.
- Requisitos de firmante: propietario para débito, autoridad de emisión para
mint_to, etc. anchor_spl::token_interfacesoporta Token-2022 con el tipoTokenInterface.
Instrucciones Comunes de CPI
| Instrucción | Firmante | Valida |
|---|---|---|
transfer / transfer_checked | Autoridad de origen | Saldo suficiente |
mint_to | Autoridad de emisión | Aumento de suministro |
burn | Propietario de la cuenta | Disminución de saldo |
approve | Propietario | Límite del delegado |
Notas de Rust
use anchor_spl::token_interface::{
TokenAccount as InterfaceTokenAccount,
TokenInterface,
transfer_checked as interface_transfer_checked,
};
// Usa TokenInterface + InterfaceTokenAccount para emisiones Token-2022Errores Comunes
- Falta la comprobación de igualdad de emisión - ATA de bóveda con activo incorrecto. Solución: Restricción
token::mint = minten todas las cuentas de token. - UncheckedAccount como autoridad de bóveda - sin validación de semilla PDA. Solución: Restricciones
seeds+bumpen la PDA de autoridad. - Cuenta
token_programincorrecta - CPI al Token clásico para una emisión Token-2022 falla. Solución: usartoken_interfaceo pasar el ID de programa correcto. - La PDA no puede firmar la transferencia - faltan las semillas
with_signer. Solución:CpiContext::new_with_signercon las semillas de la bóveda. - Reentrada a través de CPI de token - los programas de hook externos (Token-2022) pueden volver a llamar. Solución: proteger el estado; ver la documentación de transfer hook.
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
invoke crudo + crate spl_token | Programa no-Anchor | Proyecto Anchor con anchor-spl disponible |
token_interface | Multi-programa (Token + Token-2022) | Solo Token clásico para siempre |
| Movimientos de token solo en cliente | El usuario firma todas las transferencias | Lógica de bóveda custodial |
Preguntas Frecuentes
¿Qué es anchor-spl?
Crate Anchor que encapsula ayudantes de CPI del programa SPL y tipos de cuenta para Token, ATA, metadatos y más.
¿Debo usar Account<TokenAccount>?
Muy recomendado en Anchor - deserializa y comprueba la propiedad del programa Token.
¿Cómo firman las PDAs las CPIs de token?
CpiContext::new_with_signer con semillas que coincidan con la PDA de autoridad de la bóveda.
¿`transfer` vs `transfer_checked`?
Prefiere transfer_checked en programas - incluye la protección de decimales.
¿Puede una instrucción hacer CPI de múltiples transferencias?
Sí. Agrupa múltiples instrucciones de token en una transacción desde el cliente; el programa puede iterar sobre las CPIs dentro del presupuesto de CU.
¿Cómo soporto Token-2022?
Cambia a tipos token_interface y pasa el programa propietario de la emisión real en las restricciones.
¿Quién paga la creación de ATA en los programas?
init o init_if_needed en ATA con el firmante payer - a menudo la tesorería del protocolo.
¿Puedo cerrar cuentas de token en programas?
Sí, a través de la CPI CloseAccount cuando el saldo es cero y la autoridad de cierre firma.
¿Cómo probar las CPIs de token?
LiteSVM 0.6.x o Surfpool 0.12.0 validador local con el programa Token desplegado por defecto.
¿Qué pasa con las cuentas de token multisig?
El multisig SPL heredado todavía existe - la mayoría de las aplicaciones usan bóvedas PDA en su lugar.
¿Necesito la cuenta `associated_token_program`?
Requerida en la lista de cuentas cuando la instrucción crea ATAs a través de CPI.
¿Cómo se mapean los errores?
Los errores del programa Token se devuelven como errores del programa - mapea a #[error_code] personalizado para la experiencia del usuario.
Relacionado
- Cuentas de Token Asociadas (ATAs) - Restricciones de ATA
- Transferencias y Delegados - Flujos de delegación
- Invocaciones entre Programas (CPI) - Fundamentos de CPI
Versiones de Stack: Esta página fue 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, y LiteSVM 0.6.x.