Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
PDAs are addresses that aren't on the ed25519 curve — meaning no private key exists for them. A program can 'sign' on behalf of its own PDAs because the runtime knows which PDA belongs to which program. This is the foundation of every cross-program flow, every escrow, every protocol that needs deterministic state addresses.
Derive a PDA and use it as program-controlled state.
seeds = [b"vault", userPubkey] and confirm the same address is derived on-chain via Anchor's find_program_address.invoke_signed) to release them.use anchor_lang::prelude::*;
#[derive(Accounts)]
pub struct CreateVault<'info> {
#[account(
init,
payer = user,
space = 8 + 8,
// PDA: address derived from seeds + program_id
// Off-chain: PublicKey.findProgramAddressSync(seeds, programId)
// Returns (address, bump). Bump = nonce that pushes off-curve.
seeds = [b"vault", user.key().as_ref()],
bump
)]
pub vault: Account<'info, Vault>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct Deposit<'info> {
#[account(
mut,
seeds = [b"vault", user.key().as_ref()],
bump = vault.bump, // saved at create time
)]
pub vault: Account<'info, Vault>,
pub user: Signer<'info>,
}
#[account]
pub struct Vault {
pub balance: u64,
pub bump: u8,
}
// Off-chain (TS):
// import { PublicKey } from "@solana/web3.js";
// const [vaultPDA, bump] = PublicKey.findProgramAddressSync(
// [Buffer.from("vault"), user.publicKey.toBuffer()],
// PROGRAM_ID,
// );