Account Model Best Practices
Design account layouts that scale, stay safe, and minimize rent and compute costs on Agave 4.1.1.
How to Use This List
- Apply A before writing your first
#[account]struct - Review B before mainnet launch security audit
- Use C when optimizing CU and rent at scale
A - Layout Design
- One logical entity per account. Shard user state across PDAs, not one global map account.
- Use
InitSpace+max_lenfor variable fields. Never guess String/Vec sizes in Anchor 0.32.1. - Include
versionbyte when schema will evolve. Append-only field changes prevent deserialization breakage. - Size accounts to realistic maxima, not infinite. Rent and CU scale with bytes.
B - Security
- Every
mutaccount has owner + authority checks.Account<T>,has_one,seeds, or explicitconstraint. - Avoid
UncheckedAccountwithout constraints. Treat as guilty until proven valid. - Validate signers match stored authorities.
Signer+has_onetogether, not either alone. - Close accounts when lifecycle ends. Return rent to users; prevent orphaned lamport sinks.
- Never accept victim accounts by pubkey alone. Attacker passes others' accounts if constraints are missing.
C - Operations
- Query
getMinimumBalanceForRentExemptionin clients. Do not hardcode rent lamports. - Use
reallocsparingly with migration plan. Prefer new account types for breaking changes. - Emit events on create/close. Indexers depend on lifecycle signals.
- Document PDA seeds in IDL/docs. Client derivation must match on-chain
seedsexactly. - Filter
getProgramAccountsby discriminator. Reduces RPC payload and client decode work.
FAQs
What is the worst account model mistake?
Missing owner/authority validation on writable accounts - leads to drain vulnerabilities.
When should I use zero-copy?
Accounts larger than a few KB read/written frequently. Measure CU before migrating.
How many PDAs per user is normal?
One per logical object (position, order, vault). Avoid dozens per action to limit rent UX cost.
Should protocols subsidize account creation?
Yes for frictionless onboarding when rent exceeds user tolerance - budget treasury accordingly.
How do I audit account constraints?
Map each instruction to every mut account; list runtime checks applied.
Is init_if_needed safe?
Only with strong seeds and authority checks - otherwise attackers initialize on victim's behalf.
What space should I allocate for strings?
#[max_len(N)] on field; InitSpace includes 4 + N in total.
Can I share one account across programs?
One owner program only. Share data via CPI or read-only passing, not dual ownership.
How do I handle account migration?
New PDA + copy instruction + deprecate old type. Never reorder existing Borsh fields.
Should global config be a PDA?
Yes - seeds = [b"config"] singleton is standard for protocol parameters.
What about account compression?
Use for massive low-mutability datasets (cNFTs). Not for hot DeFi state.
How does LiteSVM 0.6.x help account tests?
Fast local tests for init/close/realloc without full validator overhead.
Related
- Account Model Basics - hands-on patterns
- Account Ownership & Permissions - security rules
- Data Accounts & Layout - sizing guidance
Stack versions: This page was written for Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, and LiteSVM 0.6.x.