PDAs en Anchor
Las Direcciones Derivadas de Programa (PDAs) no tienen clave privada; tu programa firma por ellas con seeds y bump a través de invoke_signed o CPI with_signer.
Busca en todas las páginas de la documentación
Las Direcciones Derivadas de Programa (PDAs) no tienen clave privada; tu programa firma por ellas con seeds y bump a través de invoke_signed o CPI with_signer.
#[account(
seeds = [b"escrow", maker.key().as_ref()],
bump,
)]
pub escrow: Account<'info, Escrow>,Cuándo usar esto: El programa debe custodiar activos o almacenar estado canónico en una dirección determinista.
use anchor_lang::prelude::*;
#[account]
#[derive(InitSpace)]
pub struct Escrow {
pub maker: Pubkey,
pub escrow_id: u64,
pub bump: u8,
}
// `escrow_id` es un argumento de instrucción, por lo que la estructura de cuentas debe
// declararlo con #[instruction(..)] antes de que las seeds puedan referenciarlo.
#[derive(Accounts)]
#[instruction(escrow_id: u64)]
pub struct InitEscrow<'info> {
#[account(
init,
payer = maker,
space = 8 + Escrow::INIT_SPACE,
seeds = [b"escrow", maker.key().as_ref(), escrow_id.to_le_bytes().as_ref()],
bump,
)]
pub escrow: Account<'info, Escrow>,
#[account(mut)]
pub maker: Signer<'info>,
pub system_program: Program<'info, System>,
}
pub fn init_escrow(ctx: Context<InitEscrow>, escrow_id: u64) -> Result<()> {
let escrow = &mut ctx.accounts.escrow;
escrow.maker = ctx.accounts.maker.key();
escrow.escrow_id = escrow_id;
// Anchor NO persiste el bump por ti; escríbelo tú mismo.
escrow.bump = ctx.bumps.escrow;
Ok(())
}Lo que esto demuestra:
seeds + el ID del programa determinan la dirección de la PDA.bump encuentra el bump canónico fuera de la curva; ctx.bumps.escrow lo expone.Escrow::INIT_SPACE solo existe gracias a #[derive(InitSpace)].seeds que referencian un argumento de instrucción necesitan #[instruction(..)].bump en la cuenta para comprobaciones posteriores más baratas.Signer.Pubkey::find_program_address(seeds, program_id) devuelve (dirección, bump). Anchor envuelve esto en restricciones.
Solo el programa que posee las seeds de la PDA puede firmar, a menos que se use un ID de programa externo en las seeds (avanzado).
bump fuera de la curva no almacenado - CU extra en cada CPI. Solución: Persistir el bump en el estado.seeds - Restricciones máximas de datos de seeds. Solución: Mantener las seeds compactas.seeds entre cliente/servidor - La transacción falla. Solución: Compartir el generador de seeds en el SDK.Signer<'info> - Compila, pero siempre falla en tiempo de ejecución: una PDA no tiene clave para firmar la transacción. Solución: Usar Account con una restricción de seeds y firmar solo dentro de las CPIs.| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
Cuentas propiedad de Keypair | Se necesita firma externa | Custodia del programa |
seeds::program para PDAs externas | CPI a PDAs de programas extranjeros | Estado del propio programa |
0.32.1 en toda esta sección.
No. Usa restricciones de seeds y firma CPI.
En el campo de tu struct de cuenta, establecido en la inicialización.
Usa @solana/kit 7.0.0 con bytes de seeds coincidentes.
La dirección declare_id de tu programa Anchor.
No en el array de seeds; el bump es un parámetro separado para find_program_address.
Compara las claves registradas; verifica las seeds y el ID del programa en el lado del cliente.
Sí, cuando contienen datos; fináncialas con el pagador en la inicialización.
Sí, con las mismas seeds de firmante para cada CPI.
Consulta los enlaces relacionados para temas más profundos sobre PDAs.
Seeds y Bump - validaciónVersiones 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.
Revisado por Chris St. John·Última actualización: 16 jul 2026