Assinatura com PDAs
PDAs assinam CPIs por meio de fatias de seeds passadas a CpiContext::new_with_signer. As seeds devem corresponder às constraints de PDA usadas na inicialização.
Receita
let seeds = &[b"vault".as_ref(), &[ctx.bumps.vault]];
let signer = &[&seeds[..]];
token::transfer(
CpiContext::new_with_signer(
ctx.accounts.token_program.to_account_info(),
accounts,
signer,
),
amount,
)?;Quando usar: Uma PDA é authority sobre contas de token ou possui SOL sendo transferido.
Exemplo prático
pub fn vault_withdraw(ctx: Context<VaultWithdraw>, amount: u64) -> Result<()> {
let bump = ctx.bumps.vault;
let authority_key = ctx.accounts.vault.authority;
let seeds: &[&[u8]] = &[b"vault", authority_key.as_ref(), &[bump]];
let signer_seeds = &[seeds];
token::transfer(
CpiContext::new_with_signer(
ctx.accounts.token_program.to_account_info(),
token::Transfer {
from: ctx.accounts.vault_ata.to_account_info(),
to: ctx.accounts.user_ata.to_account_info(),
authority: ctx.accounts.vault.to_account_info(),
},
signer_seeds,
),
amount,
)?;
Ok(())
}O que isso demonstra:
- Signer seeds são fatias aninhadas
&[&[&[u8]]] - Bump deve ser canônico
- Account info da PDA é o meta authority
- Use ctx.bumps quando seeds correspondem ao nome do campo
Aprofundamento
invoke_signed vs CPI do Anchor
Helpers de CPI do Anchor aceitam with_signer com a mesma semântica do invoke_signed nativo.
PDAs com múltiplas seeds
Inclua cada elemento de seed na mesma ordem usada em #[account(seeds = [...])].
Erros comuns
- Bump errado no array signer - Assinatura de CPI falha.. Correção: Use bump armazenado ou ctx.bumps.
- Componente de seed ausente - Mismatch de endereço derivado.. Correção: Copie seeds da constraint exatamente.
- Meta authority não é conta PDA - Token program rejeita.. Correção: Passe vault PDA como authority.
- Reutilizar buffer de seed incorretamente - Problemas de lifetime/borrow.. Correção: Construa array de seeds por chamada de CPI.
- PDA assina sem constraint na conta - Atacante substitui PDA.. Correção: Valide seeds on-chain.
Alternativas
| Alternativa | Use quando | Não use quando |
|---|---|---|
| Delegar a signer humano | Usuário paga taxas diretamente | Custódia pelo programa |
| Padrões de multisig PDA | Authority compartilhada | PDA de seed única |
FAQs
Qual versão do Anchor é assumida?
0.32.1 em toda esta seção.
Uma PDA pode ser Signer na struct accounts?
Não. Use constraints seeds e assinatura em CPI.
Onde o bump é armazenado?
No campo da sua struct de conta, definido na inicialização.
Como os clientes derivam PDAs?
Use @solana/kit 7.0.0 com bytes de seed correspondentes.
Qual program id é usado para PDAs?
O endereço declare_id do seu programa Anchor.
As seeds incluem bump?
Não no array seeds; bump é parâmetro separado para find_program_address.
Como depurar falhas de PDA?
Compare chaves logadas; verifique seeds e program id no client.
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 para cada CPI.
O que ler em seguida?
Veja os links em Relacionados para tópicos mais profundos sobre assinatura com PDAs.
Relacionados
- CPIs assinados - padrões de CPI
- Authorities PDA - mints e vaults
- Armazenamento de bumps - bump canônico
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.