Advanced· Lesson 2 of 2· 3 min
Program derived addresses
How a program owns and signs for accounts without a private key — the mechanism behind ATAs, metadata, vaults and every trustless escrow.
Programs are stateless and hold no private key. Yet a token locker has to hold tokens in an account only it can release, and a token's metadata has to be findable from its mint alone. Both problems have one answer: program derived addresses.
Derivation
A PDA is a 32-byte address computed from a program id and a list of seeds — arbitrary bytes, usually strings, public keys or numbers — plus a bump. The runtime hashes them together, and the result must not be a valid Ed25519 public key: it has to lie off the curve, so that no private key for it can exist. Roughly half of all hashes land on the curve, so the search starts with a bump of 255 and counts down until the output is off-curve. The first bump that works is the canonical bump; programs store it or re-derive it.
seeds = ["vault", mint, owner]
bump = 255, 254, ... // first value whose result is off the curve
pda = sha256(seeds ‖ bump ‖ program_id ‖ "ProgramDerivedAddress")Same program, same seeds, same address — on every machine, with no lookup. That determinism is the point. Given a mint, anyone can compute where its metadata must be. Given a wallet and a mint, anyone can compute the associated token account.
Signing without a key
Because no key exists, a PDA can never sign a transaction from outside. But the program the address was derived from can sign for it: during a cross-program invocation the program passes the seeds and bump to the runtime (invoke_signed), the runtime checks that they derive to the account's address under the calling program's id, and treats the PDA as a signer for that call. No other program can do it — the same seeds under a different program id derive a different address.
That is the entire security model of an escrow. The Token Locker's vault is a PDA of the locker program; the tokens inside can move only when the locker program signs for the vault, and the program does that only when its own rules — unlock time reached, correct recipient — are satisfied.
PDAs you already use
| Associated token account | [wallet, token_program, mint] under the Associated Token program. Your canonical balance address for every token. |
|---|---|
| Token metadata | ["metadata", metadata_program, mint] under Metaplex Token Metadata. How a name and image are found from a mint. |
| Escrow vault | Seeds chosen by the locker or launchpad program, typically the lock or sale id. Holds tokens no wallet can touch. |
| Pool state | Exchanges derive a pool's state and vaults from its pair of mints, so the pool for (A, B) has one well-known address. |
PDAs as state
Most program state lives in PDAs — user positions, configuration, counters — because a deterministic address doubles as a lookup key. The ownership rules from The account model still apply: the PDA account is owned by the program, only the program writes its data, and its rent has to be funded when it is created, usually by the user's transaction.
Verifying one
Every client library exposes findProgramAddress(seeds, programId). Recompute the expected address, compare it to what a transaction is about to touch, and check the account's owner in Account Inspector. If a “vault” is not a PDA owned by the program that claims it — if some wallet holds its key — the escrow is a promise, not a guarantee. Solstack's Token Lock Verifier and LP Lock Verifier run exactly this check.
What to remember
- A PDA is derived from seeds, a bump and a program id, and is guaranteed to have no private key.
- Only the owning program can sign for its PDA, through invoke_signed, and only with the right seeds.
- Deterministic derivation is what makes ATAs, metadata and pool addresses discoverable from their inputs.
- Escrow is trustless only when the vault is a PDA owned by the program enforcing the rules.
- Verify a PDA by re-deriving it and checking the account's owner.