Conceptos básicos de Anchor
10 ejemplos para empezar con Anchor en Solana: 7 básicos y 3 intermedios.
Prerrequisitos
- Rust 1.91.1 y Anchor CLI 0.32.1 (
anchor --version) - Solana CLI 3.0.10 (
solana --version) con un par de claves financiado para el despliegue anchor init my_programo un espacio de trabajo existente conAnchor.toml
Ejemplos básicos
1. Crear la estructura de un espacio de trabajo
Anchor crea programas, pruebas y configuración en un solo árbol.
anchor init counter --no-git
cd counter
cat programs/counter/Cargo.tomlprograms/contiene crates de Rust en cadenatests/contiene pruebas de integración de TypeScriptAnchor.tomlfija el clúster, el ID del programa y los scripts- Fija
anchor-lang = "0.32.1"enCargo.toml
Relacionado: Estructura del Proyecto - diseño de carpetas
2. Declarar el ID de tu programa
La dirección del programa debe coincidir con el despliegue en cadena.
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod counter {
use super::*;
pub fn initialize(_ctx: Context<Initialize>) -> Result<()> {
Ok(())
}
}declare_id!establece la clave pública del programa- Ejecuta
anchor keys syncdespués de queanchor deployactualice el ID - La discrepancia causa
DeclaredProgramIdMismatchen tiempo de ejecución
Relacionado: El Módulo #[program]
3. Definir una estructura de cuentas
Anchor valida cada cuenta antes de que se ejecute tu manejador.
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(mut)]
pub payer: Signer<'info>,
pub system_program: Program<'info, System>,
}Signerdemuestra que la cuenta firmó la transacciónProgram<System>comprueba la dirección del programa del sistema- Las restricciones se ejecutan antes de que se ejecute el cuerpo del manejador
Relacionado: La Estructura de Cuentas
4. Escribir un manejador de instrucciones
Los manejadores reciben Context<T> con cuentas validadas.
pub fn increment(ctx: Context<Increment>) -> Result<()> {
ctx.accounts.counter.count += 1;
Ok(())
}- Devuelve
Result<()>para instrucciones que pueden fallar - Modifica cuentas a través de los campos de
ctx.accounts - Usa
require!para comprobaciones personalizadas dentro de los manejadores
Relacionado: Manejadores de Instrucciones
5. Compilar e inspeccionar la IDL
anchor build compila SBF y emite el JSON de la IDL.
anchor build
cat target/idl/counter.json | head- La IDL lista instrucciones, cuentas y tipos para los clientes
- La IDL se encuentra en
target/idl/<program>.json - Regenera después de cada cambio en la API pública
Relacionado: Compilar y Desplegar
6. Ejecutar pruebas locales
Las pruebas de TypeScript ejercitan el programa en un validador local.
anchor test- Inicia Surfpool/validador local, despliega, ejecuta
tests/*.ts - Usa clientes
@coral-xyz/anchoro@solana/kiten las pruebas - Iteración rápida sin gastar SOL de devnet
Relacionado: El Flujo de Trabajo de Anchor
7. Fijar dependencias
Haz coincidir las versiones de la CLI y los crates para evitar la deriva de macros.
[dependencies]
anchor-lang = "0.32.1"
anchor-spl = "0.32.1"- Mantén
anchor-langy Anchor CLI en la misma versión menor Cargo.lockdel espacio de trabajo debe ser confirmado- Actualiza tanto la CLI como los crates juntos
Ejemplos intermedios
8. Inicializar una cuenta respaldada por PDA
Las direcciones derivadas del programa almacenan el estado propiedad del programa.
#[account(
init,
payer = payer,
space = 8 + Counter::INIT_SPACE,
seeds = [b"counter", payer.key().as_ref()],
bump
)]
pub counter: Account<'info, Counter>,
pub payer: Signer<'info>,
pub system_program: Program<'info, System>,initcrea la cuenta en la misma instrucciónseeds+bumpderivan una PDA determinista- Siempre establece
spacepara el tamaño exento de alquiler
Relacionado: PDAs en Anchor
9. Emitir un evento
Los eventos estructurados ayudan a los indexadores a observar los cambios de estado.
#[event]
pub struct CountChanged {
pub new_count: u64,
}
pub fn increment(ctx: Context<Increment>) -> Result<()> {
ctx.accounts.counter.count += 1;
emit!(CountChanged { new_count: ctx.accounts.counter.count });
Ok(())
}#[event]registra un tipo en la IDLemit!escribe una entrada de registro de auto-CPI- Prefiere eventos sobre
msg!para una salida legible por máquina
Relacionado: Eventos con emit!
10. Declarar errores personalizados
Los errores tipados se decodifican limpiamente en los clientes.
#[error_code]
pub enum CounterError {
#[msg("Count cannot exceed maximum")]
CountOverflow,
}
require!(ctx.accounts.counter.count < 100, CounterError::CountOverflow);#[error_code]se mapea a códigos de error de Anchor en la IDLrequire!es la macro de guardia idiomática- Los clientes mapean los códigos de error a mensajes humanos
Relacionado: #[error_code] y require!
Versiones de la pila: 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.