Skip to content

PDA Derivation - Automatic Program Derived Address Calculation

Program Derived Addresses (PDAs) are a fundamental concept in Solana programming, but calculating them manually during testing is tedious and error-prone. Testship automatically derives PDAs for you in real-time, handling simple seeds, complex account-based patterns, and even nested derivations that depend on on-chain data.

PDAs are deterministic addresses derived from:

  • A program ID
  • One or more seeds (strings, public keys, or other data)
  • A bump seed (to ensure the address is off the ed25519 curve)

For basic PDA patterns like:

#[account(
seeds = [b"user", authority.key().as_ref()],
bump
)]

Testship automatically:

  1. ✅ Identifies seeds from your program’s IDL
  2. ✅ Creates input fields only for variable seeds
  3. ✅ Auto-fills constant seeds (e.g., b"user")
  4. ✅ Calculates PDA when all dependencies are met
  5. ✅ Shows live derivation status with loading indicator

Testship’s real power is handling advanced patterns:

Multiple Seeds with Mixed Types

seeds = [b"vault", token_mint.key().as_ref(), owner.key().as_ref()]

✅ Auto-derives when token_mint and owner are provided

Numeric Argument Seeds

seeds = [b"order", order_id.to_le_bytes().as_ref()]

✅ Converts numbers to proper byte arrays (u8, u16, u32, u64, i8, i16, i32, i64)

Account Field Seeds (The Hard Part)

// Uses a field FROM another account as a seed
#[account(
seeds = [b"escrow", vault.authority.as_ref()],
bump
)]

Fetches the vault account from on-chain
Decodes it using the IDL
Extracts the authority field
Uses it as a seed

This is where Testship truly shines - no other tool handles this automatically!

Watch PDAs being derived in real-time with clear visual feedback:

  • 🟡 Idle - Waiting for dependencies (shows what’s missing)
  • 🟠 Deriving - Currently calculating (with spinner animation)
  • 🟢 Ready - Successfully derived (address auto-filled)
  • 🔴 Error - Derivation failed (with detailed error message)

PDA accounts are clearly marked:

  • 🔑 PDA Badge - Yellow badge on PDA accounts
  • Auto-PDA Badge - Green badge when successfully derived
  • ⚠️ Loading Badge - Orange badge while deriving
  • Error Badge - Red badge if derivation fails

Testship shows exactly what’s needed:

Waiting for dependencies:
• argument: order_id
• account: vault

Fill in the dependencies, and derivation happens automatically!

  • Auto-clears when dependencies change
  • Refresh button to manually re-derive
  • Preserves manual overrides if needed
  • Debounced to avoid excessive calculations (500ms delay)

For complex account-based seeds, Testship:

  1. Detects the account field pattern in IDL
  2. Fetches the account from the blockchain
  3. Decodes using BorshAccountsCoder
  4. Extracts the specific field (handles camelCase/snake_case)
  5. Converts to proper seed buffer
  6. Uses in PDA derivation

Testship automatically:

  • Uses findProgramAddressSync for canonical bump
  • No need to specify bump manually
  • Ensures PDAs are valid and secure
#[account(
seeds = [b"user", authority.key().as_ref()],
bump
)]
pub user: Account<'info, User>,

What Testship does:

  1. Sees you connected your wallet (authority auto-filled)
  2. Derives [b"user", wallet_pubkey]
  3. Shows green “Auto-PDA” badge
  4. Address appears instantly ✨
#[account(
seeds = [b"escrow", vault.authority.as_ref(), vault.nonce.to_le_bytes().as_ref()],
bump
)]
pub escrow: Account<'info, Escrow>,

What Testship does:

  1. You fill in the vault address
  2. Testship fetches vault account from blockchain 🌐
  3. Decodes it using your IDL 📖
  4. Extracts vault.authority and vault.nonce 🔍
  5. Converts nonce to bytes
  6. Derives the PDA
  7. Shows green “Auto-PDA” badge ✅

This complex derivation happens automatically in ~1 second!

For instructions with dependent PDAs:

  1. Fill in initial account (e.g., mint address)
  2. First PDA derives automatically (e.g., vault)
  3. Second PDA uses first PDA as seed (e.g., vault_authority)
  4. All addresses populate in sequence
  5. Ready to execute! 🚀
  • Zero Manual Calculation - Never compute PDAs by hand again
  • Error Prevention - No more typos or wrong seed order
  • Lightning Fast - Even complex derivations in <1 second
  • Visual Feedback - Always know what’s happening
  • Learning Tool - Understand PDA patterns in your program
  • Battle Tested - Handles the most complex Solana programs
Seed KindDescriptionExample
constStatic bytesb"user"
argInstruction argumentsorder_id
accountSimple account pubkeyauthority.key()
account.fieldField from accountvault.authority

Testship uses:

  • @solana/web3.js for PDA derivation
  • @coral-xyz/anchor for IDL parsing
  • BorshAccountsCoder for account decoding
  • React hooks for reactive updates
  • 500ms debouncing to avoid excessive calls

Current limitations (to be improved):

  • ⚠️ String seeds must be UTF-8 encoded
  • ⚠️ Nested struct fields (e.g., account.data.field) not yet supported
  • ⚠️ Array/Vec seeds require manual specification

Most Anchor programs use simpler patterns that work perfectly!

Learn how Testship remembers your frequently used accounts in Account Suggestions.