Comptes PDA

Résumé

Créez des comptes PDA via invoke_signed avec les seeds du PDA. Seul le programme propriétaire peut signer pour un PDA. La contrainte init d'Anchor automatise la création de comptes PDA.

Signature PDA via invoke_signed

Lorsqu'un programme doit signer au nom d'un PDA lors d'un CPI, il utilise invoke_signed avec les seeds du PDA. Le runtime vérifie que les seeds dérivent le PDA attendu en utilisant l'ID du programme appelant, garantissant que seul le programme propriétaire peut signer. Pour le flux de vérification complet, voir Signature PDA.

Créer un compte PDA

Dériver un PDA et créer un compte à une adresse PDA sont des opérations distinctes. Vous devez explicitement créer le compte après avoir dérivé l'adresse.

Pour créer un compte à une adresse PDA, le programme de dérivation invoque l'instruction create_account du System Program via invoke_signed, en passant les seeds du PDA afin que le runtime puisse vérifier l'autorité du programme sur cette adresse.

L'exemple ci-dessous utilise le framework Anchor pour créer un nouveau compte avec une adresse dérivée du programme. Le programme inclut une seule instruction initialize pour créer le nouveau compte, qui stockera l'adresse utilisateur et le bump seed utilisés pour dériver le PDA.

Program
use anchor_lang::prelude::*;
declare_id!("75GJVCJNhaukaa2vCCqhreY31gaphv7XTScBChmr1ueR");
#[program]
pub mod pda_account {
use super::*;
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
let account_data = &mut ctx.accounts.pda_account;
// store the address of the `user`
account_data.user = *ctx.accounts.user.key;
// store the canonical bump
account_data.bump = ctx.bumps.pda_account;
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(mut)]
pub user: Signer<'info>,
#[account(
init,
// define the seeds to derive the PDA
seeds = [b"data", user.key().as_ref()],
// use the canonical bump
bump,
payer = user,
space = 8 + DataAccount::INIT_SPACE // 8 bytes for Anchor account discriminator
)]
pub pda_account: Account<'info, DataAccount>,
pub system_program: Program<'info, System>,
}
#[account]
#[derive(InitSpace)]
pub struct DataAccount {
pub user: Pubkey,
pub bump: u8,
}

La contrainte init indique à Anchor d'invoquer le System Program pour créer un nouveau compte en utilisant le PDA comme adresse. Les seeds utilisés pour créer le PDA sont :

  • La chaîne fixe : "data"
  • L'adresse du compte utilisateur fournie dans l'instruction
  • Le bump seed canonique

Dans cet exemple, la contrainte bump n'a pas de valeur assignée, donc Anchor utilisera find_program_address pour dériver le PDA et trouver le bump.

pda_account
#[account(
init,
seeds = [b"data", user.key().as_ref()],
bump,
payer = user,
space = 8 + DataAccount::INIT_SPACE // 8 bytes for Anchor account discriminator
)]
pub pda_account: Account<'info, DataAccount>,

Le fichier de test ci-dessous contient une transaction qui invoque l'instruction initialize pour créer un nouveau compte avec une adresse dérivée de programme. Le fichier contient du code pour dériver le PDA.

L'exemple montre également comment récupérer le nouveau compte qui sera créé.

Test
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { PdaAccount } from "../target/types/pda_account";
import { PublicKey } from "@solana/web3.js";
describe("pda-account", () => {
const provider = anchor.AnchorProvider.env();
anchor.setProvider(provider);
const program = anchor.workspace.PdaAccount as Program<PdaAccount>;
const user = provider.wallet as anchor.Wallet;
// Derive the PDA address using the seeds specified on the program
const [PDA] = PublicKey.findProgramAddressSync(
[Buffer.from("data"), user.publicKey.toBuffer()],
program.programId
);
it("Is initialized!", async () => {
const transactionSignature = await program.methods
.initialize()
.accounts({
user: user.publicKey
})
.rpc();
console.log("Transaction Signature:", transactionSignature);
});
it("Fetch Account", async () => {
const pdaAccount = await program.account.dataAccount.fetch(PDA);
console.log(JSON.stringify(pdaAccount, null, 2));
});
});

Si vous invoquez l'instruction initialize à nouveau avec la même seed d'adresse user, la transaction échouera. Cela se produit parce qu'un compte existe déjà à l'adresse dérivée.

Is this page helpful?

Table des matières

Modifier la page

Géré par

© 2026 Fondation Solana.
Tous droits réservés.
Restez connecté