In Solana, Program Derived Addresses (PDAs) are special addresses that are derived from a program ID and a set of seeds, but do not lie on the Ed25519 elliptic curve (unlike regular Solana accounts). This means they have no associated private key and can only be controlled by the program that created them.
Key Characteristics of PDAs:

No Private Key: Cannot sign transactions directly.
Controlled by Programs: Only the program that generated the PDA can authorize actions.
Used for Storage & Cross-Program Invocations (CPI): Often store state or allow programs to interact securely.
How PDAs are Generated
A PDA is created by hashing (sha256) a program ID and some seeds (arbitrary bytes). If the resulting public key does not lie on the Ed25519 curve, it is a valid PDA.
Formula:
PDA = findProgramDerivedAddress(seeds, programId)
If the result is not a valid public key (off-curve), it’s a PDA.
If it is on-curve, Solana adjusts the seeds (usually by adding a bump) to find a valid PDA.
Diagram: PDA Generation in Solana
Here’s a simplified flow of how PDAs are generated:
┌───────────────────────┐ │ Program ID │ │ (e.g., "MyProgram") │ └──────────┬────────────┘ │ │ ┌──────────▼────────────┐ │ Seeds │ │ (e.g., "user_account",│ │ "data_v1") │ └──────────┬────────────┘ │ │ ┌──────────▼────────────┐ │ Hash(ProgramID + │ │ Seeds) │ └──────────┬────────────┘ │ │ ┌──────────▼────────────┐ │ Is result a valid │ │ public key? │ │ (Ed25519 curve check)│ └──────────┬────────────┘ │ No ┌─────┴─────┐ Yes │ │ ▼ ▼ ┌─────────┐ ┌─────────┐ │ Valid │ │ Adjust │ │ PDA │ │ Bump & │ │ Created │ │ Retry │ └─────────┘ └─────────┘
Example Use Cases of PDAs
Storing Program State
Instead of using external accounts, programs can store data in PDAs.
Example: A decentralized exchange (DEX) storing user balances in PDAs.
Cross-Program Invocations (CPI)
PDAs allow programs to securely call other programs without requiring a private key.
Signing for Programs
Since PDAs cannot sign normally, Solana allows the creating program to "sign" PDAs in CPIs.
Code Example (Rust - Solana Program)
use solana_program::{
pubkey::Pubkey,
program_error::ProgramError,
program_pack::Pack,
};
pub fn find_pda(seeds: &[&[u8]], program_id: &Pubkey) -> (Pubkey, u8) {
Pubkey::find_program_address(seeds, program_id)
}
// Usage:
let (pda, bump_seed) = find_pda(&[b"my_account"], &program_id);Summary Table: PDA vs. Regular Account
| Feature | PDA | Regular Account |
|---|---|---|
| Private Key | No | Yes |
| Signing | Only via program (CPI) | Yes (with private key) |
| Generation | findProgramDerivedAddress | Keypair.generate() |
| Use Case | Program-controlled storage | User wallets, token accounts |
Conclusion
PDAs are a powerful feature in Solana that enable secure, program-controlled storage and interactions. They are essential for building scalable and secure dApps on Solana.
