Instruction Handlers
Instruction handlers são funções públicas dentro de #[program]. Elas recebem Context<T>, onde T é a struct de contas validada, além de argumentos deserializados com Borsh.
Receita
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
require!(amount > 0, VaultError::InvalidAmount);
// business logic
Ok(())
}Quando usar: Você implementa a lógica de negócio de uma instrução on-chain.
Exemplo Prático
#[program]
pub mod vault {
use super::*;
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
let vault = &mut ctx.accounts.vault;
vault.total = vault.total.checked_add(amount).ok_or(VaultError::Overflow)?;
emit!(Deposited { amount, vault: vault.key() });
Ok(())
}
}
#[derive(Accounts)]
pub struct Deposit<'info> {
#[account(mut, seeds = [b"vault"], bump = vault.bump)]
pub vault: Account<'info, VaultState>,
#[account(mut)]
pub depositor: Signer<'info>,
}O que isso demonstra:
Context<Deposit>encapsula contas e program_id- Args de instrução deserializam após validação de contas
- Retornar
Result<()>propaga erros customizados ctx.bumpsexpõe bumps canônicos a partir de seeds
Aprofundamento
Campos do Context
| Campo | Uso |
|---|---|
ctx.accounts | Contas validadas mutáveis/imutáveis |
ctx.program_id | Pubkey do programa atual |
ctx.bumps | Mapa de bump seeds a partir de constraints |
ctx.remaining_accounts | Contas extras fora da struct |
Mantenha handlers pequenos; delegue lógica complexa para funções de módulo.
Erros comuns
- Trabalho pesado no handler - Limites de CU excedidos.. Correção: Extraia helpers; evite deserializações redundantes.
- Ignorar ctx.bumps - Re-buscar bumps em CPI.. Correção: Use
ctx.bumps.vaulta partir do nome em seeds. - Mutar sem intenção de persistir - Esqueceu que a conta é Account<T>.. Correção: Mudanças serializam no drop se mut.
- Tipo Result errado - Handlers devem retornar Result em caminhos que podem falhar.. Correção: Use
Result<()>ou APIs de retorno de dados. - Usar remaining_accounts às cegas - Ataques de substituição de conta.. Correção: Valide owner e discriminator.
Alternativas
| Alternativa | Use quando | Não use quando |
|---|---|---|
| Helpers de módulo | Lógica compartilhada entre handlers | Inline em programas pequenos |
| APIs return_data | Retornar bytes ao caller | A maioria das instruções usa contas para saída |
| Arms de match de instrução nativa | Sem Anchor | Ergonomia do Context do Anchor |
FAQs
Qual versão do Anchor é assumida?
0.32.1 em toda esta seção.
Uma PDA pode ser Signer na struct de contas?
Não. Use constraints de seeds e assinatura em CPI.
Onde o bump é armazenado?
No campo da struct de conta, definido na inicialização.
Como os clientes derivam PDAs?
Use @solana/kit 7.0.0 com os mesmos bytes de seed.
Qual program id é usado para PDAs?
O endereço declare_id do seu programa Anchor.
Seeds incluem bump?
Não no array de seeds; bump é parâmetro separado em find_program_address.
Como depurar falhas de PDA?
Compare chaves logadas; verifique seeds e program id no client-side.
PDAs são rent-exempt?
Sim quando mantêm dados; financie com payer no init.
Uma PDA pode assinar múltiplos CPIs em uma ix?
Sim, com as mesmas signer seeds em cada CPI.
O que ler em seguida?
Veja os links em Relacionados para tópicos mais profundos sobre handlers.
Relacionados
- Instruction Arguments - entradas tipadas
- Accessing Accounts - detalhes de ctx.accounts
- The #[program] Module - macro de módulo
Versões da 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.