- tags: Solana, Solana 101: 2. Anchor
What is Program Derived Address(PDA)?1
A Program Derived Address is simply an account owned by the program, but has no private key. Instead it’s signature is obtained by a set of seeds and a bump (a nonce which makes sure it’s off curve). “Generating” a Program Address is different from “creating” it.
- Generating One can generate a PDA using
Pubkey::find_program_address
in Rust orPublicKey.findProgramAddressSync
in JavaScript; - Creating a PDA essentially means to initialize the address with space and set the state to it.
#+end_quote
How to Generate a PDA?
In frontend by using @solana/web3.js
:
import * as web3 from "@solana/web3.js";
import { Buffer } from 'buffer';
const keypair = await connectWallet();
const programId = "Cj9VjDrohXuz914FNbaTMmEqYXkLkJKZn9FCq4UGGGwr";
const [pda, dump] = web3.PublicKey.findProgramAddressSync(
[
Buffer.from("seed1"),
keypair.publicKey,
],
new web3.PublicKey(programId),
);
Summary:
- Seeds can be used to distinguish different purpose of PDA for one program;
- Multipe items of
bump
shall be returned, but the firstdump
is called “canonical bump”; bump
is needed when to use PDA sign tx on chain via program.
How the PDA be Created By a Program?2
- Change the owner of PDA to the specific program by AccountInfo.assign;
- Transfer some lamports from funding account to the PDA to pay the rent;
- Allocate data space by AccountInfo.realloc.
// Assessing required lamports and creating transaction instruction let lamports_required = Rent::get()?.minimum_balance(ACCOUNT_DATA_LEN); let create_pda_account_ix = system_instruction::create_account( &funding_account.key, &pda_account.key, lamports_required, ACCOUNT_DATA_LEN.try_into().unwrap(), &program_id, ); // Invoking the instruction but with PDAs as additional signer invoke_signed( &create_pda_account_ix, &[ funding_account.clone(), pda_account.clone(), system_program.clone(), ], &[signers_seeds], )?;
How the PDA be Created By anchor?3
By using #[account(init)]
macro attribute:
#[account]
pub struct UserStats {
level: u16,
name: String,
bump: u8,
}
// validation struct
#[derive(Accounts)]
pub struct CreateUserStats<'info> {
#[account(mut)]
pub user: Signer<'info>,
// space: 8 discriminator + 2 level + 4 name length + 200 name + 1 bump
#[account(
init,
payer = user,
space = 8 + 2 + 4 + 200 + 1, seeds = [b"user-stats", user.key().as_ref()], bump
)]
pub user_stats: Account<'info, UserStats>,
pub system_program: Program<'info, System>,
}