Skip to content

RUST.md: every account the program creates is a PDA unless it cannot be - #64

Merged
mikemaccana merged 1 commit into
mainfrom
claude/confident-keller-2i6eks
Sep 22, 2026
Merged

mikemaccana merged 1 commit into
mainfrom
claude/confident-keller-2i6eks

Conversation

@mikemaccana

Copy link
Copy Markdown
Collaborator

The order-book example created its base, quote, and fee vaults at public keys the client generated, for no reason beyond habit. Each vault cost the client an extra signer, and nothing but the market's record said where it was. quicknode/solana-program-examples#148 made them PDAs of the market. Only the 180 KB order book had a real reason to stay at a generated key, because a program can allocate at most 10 KB when it creates an account through CPI.

This adds the rule to PDA Management in skills/solana/RUST.md, so new programs don't repeat the mistake:

  • Accounts the program creates are PDAs by default. That covers vaults, positions, configs, per-user records, and mints the program creates. Wallets, and the mints and token accounts a user brings, are out of scope.
  • Size is the usual reason an account can't be a PDA. Above 10,240 bytes (MAX_PERMITTED_DATA_INCREASE) the client has to create the account with create_account, and that needs the new account's own signature. Growing a PDA with realloc is named as the alternative. The rule also names three things that are not reasons:
    • copying an example;
    • saving a seed;
    • the client already having a key pair.
  • A justified exception carries a comment and a stored-address check. The comment on the account constraint says why it isn't a PDA, and every instruction checks the account against the address the program recorded. In Anchor, an init without seeds is such an account; in Quasar, an init without address = X::seeds(..) is. Either one without the comment is a finding.
  • Tests derive every PDA the program creates. A Keypair::new() for a program account is correct only for an allowed exception.

🤖 Generated with Claude Code

https://claude.ai/code/session_011VUvZT5384GaSBhhgJwFp3


Generated by Claude Code

The order-book example created its three vaults at public keys the
client generated, for no reason beyond habit: each one cost an extra
signer, and nothing but the market's record said where it was. Only the
180 KB order book had a real reason, since a program can allocate at
most 10 KB when it creates an account through CPI.

PDA Management now says so. Program-created accounts are PDAs by
default. Size is the usual reason one can't be, and copying an example,
saving a seed, or already holding a key pair are not reasons. An account
at a generated public key carries a comment saying why and is bound by a
stored-address check. An Anchor `init` without `seeds`, or a Quasar
`init` without `address = X::seeds(..)`, without that comment is a
finding. Tests derive every PDA the program creates.

Claude-Session: https://claude.ai/code/session_011VUvZT5384GaSBhhgJwFp3
@mikemaccana
mikemaccana merged commit ab61c64 into main Sep 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant