Solana CookbookAccounts
How to Create a PDA's Account
Accounts found at Program Derived Addresses (PDAs) can only be created on-chain. The accounts have addresses that have an associated off-curve public key, but no secret key.
To generate a PDA, use findProgramAddressSync
with your required seeds.
Generating with the same seeds will always generate the same PDA.
Generating a PDA
generate-pda.ts
import { PublicKey } from "@solana/web3.js";const programId = new PublicKey("G1DCNUQTSGHehwdLCAmRyAG8hf51eCHrLNUqkgGKYASj");let [pda, bump] = PublicKey.findProgramAddressSync([Buffer.from("test")],programId,);console.log(`bump: ${bump}, pubkey: ${pda.toBase58()}`);// you will find the result is different from `createProgramAddress`.// It is expected because the real seed we used to calculate is ["test" + bump]
Create an Account at a PDA
Program
create-pda.rs
use solana_program::{account_info::next_account_info, account_info::AccountInfo, entrypoint,entrypoint::ProgramResult, program::invoke_signed, pubkey::Pubkey, system_instruction, sysvar::{rent::Rent, Sysvar}};entrypoint!(process_instruction);fn process_instruction(program_id: &Pubkey,accounts: &[AccountInfo],instruction_data: &[u8],) -> ProgramResult {let account_info_iter = &mut accounts.iter();let payer_account_info = next_account_info(account_info_iter)?;let pda_account_info = next_account_info(account_info_iter)?;let rent_sysvar_account_info = &Rent::from_account_info(next_account_info(account_info_iter)?)?;// find space and minimum rent required for accountlet space = instruction_data[0];let bump = instruction_data[1];let rent_lamports = rent_sysvar_account_info.minimum_balance(space.into());invoke_signed(&system_instruction::create_account(&payer_account_info.key,&pda_account_info.key,rent_lamports,space.into(),program_id),&[payer_account_info.clone(),pda_account_info.clone()],&[&[&payer_account_info.key.as_ref(), &[bump]]])?;Ok(())}
Client
create-pda.ts
import {clusterApiUrl,Connection,Keypair,Transaction,SystemProgram,PublicKey,TransactionInstruction,LAMPORTS_PER_SOL,SYSVAR_RENT_PUBKEY,} from "@solana/web3.js";(async () => {// program idconst programId = new PublicKey("7ZP42kRwUQ2zgbqXoaXzAFaiQnDyp6swNktTSv8mNQGN",);// connectionconst connection = new Connection(clusterApiUrl("devnet"), "confirmed");// setup fee payerconst feePayer = Keypair.generate();const feePayerAirdropSignature = await connection.requestAirdrop(feePayer.publicKey,LAMPORTS_PER_SOL,);await connection.confirmTransaction(feePayerAirdropSignature);// setup pdalet [pda, bump] = await PublicKey.findProgramAddress([feePayer.publicKey.toBuffer()],programId,);console.log(`bump: ${bump}, pubkey: ${pda.toBase58()}`);const data_size = 0;let tx = new Transaction().add(new TransactionInstruction({keys: [{pubkey: feePayer.publicKey,isSigner: true,isWritable: true,},{pubkey: pda,isSigner: false,isWritable: true,},{pubkey: SYSVAR_RENT_PUBKEY,isSigner: false,isWritable: false,},{pubkey: SystemProgram.programId,isSigner: false,isWritable: false,},],data: Buffer.from(new Uint8Array([data_size, bump])),programId: programId,}),);console.log(`txhash: ${await connection.sendTransaction(tx, [feePayer])}`);})();