Coding & Program Standards
Consistent standards reduce review time and audit findings: where PDAs live, how errors are named, how clients encode amounts. This page defines team conventions for Anchor and native programs on Agave 4.1.1.
Recipe
Quick-reference recipe card - copy-paste ready.
// programs/<name>/src/constants.rs
pub const JUPITER_PROGRAM_ID: Pubkey = pubkey!("JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4");
// programs/<name>/src/error.rs
#[error_code]
pub enum VaultError {
#[msg("Program is paused")]
Paused,
}When to reach for this:
- New engineer onboarding
- Linter and CI rule authoring
- Audit readiness checklist
- Open-source contributor guide reference
Working Example
// Account naming: <Entity><Role> e.g. UserPosition, PoolConfig
#[account(
init,
payer = user,
space = 8 + UserPosition::INIT_SPACE,
seeds = [b"position", user.key().as_ref(), pool.key().as_ref()],
bump
)]
pub user_position: Account<'info, UserPosition>,
// Arithmetic
let new_total = config.total_deposits
.checked_add(amount)
.ok_or(VaultError::Overflow)?;// packages/clients - amounts as bigint
const amountLamports = parseSolToLamports(userInput); // never Number() for tokensWhat this demonstrates:
- CPI IDs centralized in
constants.rs checked_addmandatory pattern- INIT_SPACE for Anchor 0.32.1 account sizing
- Client integer token policy
Deep Dive
Repo Layout
programs/ Anchor/native crates
tests/litesvm/ Integration tests
app/ Next.js dApp
packages/idl/ Published IDL + codegen
docs/adr/ Architecture decisionsNaming
| Item | Convention |
|---|---|
| Instructions | snake_case verb deposit_sol |
| Accounts | PascalCase UserPosition |
| Errors | PascalCase enum VaultError |
| PDAs | seeds documented above #[account] |
Gotchas
- Magic numbers in seeds - Audit confusion. Fix:
pub const SEED_VAULT: &[u8] = b"vault"; unwrap()in programs - Panic = exploit surface. Fix:?andErrorCode.- Duplicate program ID strings - Client/server drift. Fix: Single constants crate or env from one package.
- Skipping
rustfmtin CI - Review noise. Fix:cargo fmt --checkrequired. - Mixed web3.js and kit - Two RPC stacks. Fix: kit-only for new code per ADR.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
nightly Rust | Unstable feature need | Production programs |
allow clippy wide | Legacy migration | New code |
| Pinocchio subset | Hot path only | Whole team untrained |
FAQs
Anchor vs native standards?
Same security rules; native adds manual validation checklist.
Comment language?
English for audit and open-source consistency.
Public vs pub(crate)?
Minimize public API surface in program crates.
Test naming?
test_<ix>_<scenario> in LiteSVM modules.
IDL check in?
Committed to packages/idl; hash in CI.
Feature flags in Rust?
cfg(feature = "mainnet") rare; prefer on-chain config bool.
Logging?
msg! sparingly; no secret data in logs.
Dependency policy?
See dependency governance page; cargo deny in CI.
License headers?
Required for open-source repos; internal optional.
Enforcement?
CI + PR template checklist + review culture.
Related
- Dependency & Crate Governance - crates policy
- Documentation Conventions - docs alongside code
- Code Review Culture - human enforcement
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.