Smart contract audits aren’t a box to tick before a token launch. They’re a disciplined process for shrinking blast radius in a system where bugs become irreversible transactions. The best teams treat auditing as a lifecycle: design reviews, implementation hardening, automated checks, manual analysis, and post-deploy monitoring.
Below is a pragmatic checklist we use to pressure-test Solidity/EVM systems (and most items apply to other chains too). Use it as a pre-audit gate and as a way to get more value from an external auditor.
1) Scope and threat model (start here)
Checklist
- Define what’s in-scope: contracts, proxies, libraries, dependencies, deployment scripts, keeper bots, off-chain signers.
- Enumerate assets at risk: user deposits, treasury funds, mint authority, admin roles, upgrade controls.
- Identify trust assumptions: who can pause, who can upgrade, who controls oracles, who sets fees.
- Specify attacker model: EOAs, MEV searchers, compromised admin keys, malicious integrators, oracle manipulation.
- Document invariants: “TVL can only decrease via user withdrawals,” “mint capped at X,” “no one can withdraw another user’s funds.”
Opinionated take: If you can’t write your protocol invariants in plain English, you’re not ready for an audit—you’re asking auditors to reverse-engineer your intent.
2) Architecture and privilege review
Checklist
- Map call graph and state ownership: which contract owns funds, which only computes.
- Identify privileged functions and who can call them (owner, role, multisig, timelock).
- Verify least privilege: separate roles for pausing, parameter updates, upgrades, and treasury actions.
- Confirm admin actions are time-delayed (timelock) when they can move funds or change pricing.
- Ensure emergency controls exist: pause, caps, circuit breakers; document when to use them.
Real example: Many bridge and vault incidents are “audit-complete” code with unsafe admin pathways—single EOA admin, instant upgrade, no timelock, no monitoring.
3) Dependency and supply-chain hygiene
Checklist
- Pin dependency versions (OpenZeppelin, Solmate, Uniswap, Chainlink). No floating tags.
- Audit all custom forks and vendored libraries.
- Review external protocol integrations: token standards, DEX routers, lending markets.
- Validate compiler version and settings (optimizer runs, viaIR) are consistent across environments.
- Confirm no dangerous precompiles/opcodes assumptions across chains (L2 differences, Shanghai/Cancun features).
4) Upgradeability and storage safety
Checklist
- If using proxies (UUPS/Transparent), verify:
- Upgrade authorization is correct and tested.
- Implementation contracts are initialized/locked (disable initializers).
- Storage layout is stable across upgrades (no reordering, reserved gaps).
- Confirm upgrade rollback and emergency freeze plans.
- Ensure immutable assumptions are not violated by upgrades.
Watch-out: A surprising number of “minor” upgrades introduce storage collisions that silently corrupt balances.
5) Core vulnerability checklist (Solidity/EVM)
Checklist
- Reentrancy: external calls before state updates; use checks-effects-interactions or reentrancy guards.
- Access control: missing modifiers, role misconfiguration, privilege escalation.
- Integer/precision errors: rounding, overflow/underflow (still relevant via casting), fixed-point math.
- Price/oracle manipulation: spot price reliance, low-liquidity TWAPs, stale data, missing heartbeat checks.
- MEV and sandwich risk: slippage, predictable swaps, mint/burn pricing.
- Denial of service:
- Unbounded loops over user-controlled arrays.
- Gas griefing on callbacks.
- Blocked withdrawals due to reverting token transfers.
- Unsafe external calls:
- ERC20 non-compliance (no return value).
- Fee-on-transfer tokens.
- Reverting receiver hooks (ERC777, ERC1363).
- Signature and auth issues:
- EIP-712 domain separation mistakes.
- Replay across chains or contracts.
- Missing nonce/deadline.
- Randomness: blockhash/timestamp usage, predictable VRF fallbacks.
- Front-running: commit-reveal absent where needed.
- Selfdestruct/deprecated patterns and chain-specific quirks.
6) Economic and game-theory review (DeFi-specific)
Audits that only look for “code bugs” miss economic exploits.
Checklist
- Model value flows: who profits when parameters change, who bears losses.
- Stress-test edge cases:
- Low liquidity / high volatility.
- Extreme interest rates.
- Liquidation incentives and bad debt.
- Validate fee logic: caps, min/max bounds, and whether fees can be set to confiscatory values.
- Review share accounting in vaults:
- Deposit/withdraw rounding.
- Inflation attacks on first depositor.
- Donation attacks (direct transfers) and how they affect share price.
7) Testing strategy that actually catches bugs
Checklist
- Unit tests for every privileged path and every revert reason that matters.
- Property-based/fuzz tests for invariants (Foundry fuzzing, Echidna).
- Differential tests against a reference model (Python/TypeScript math model).
- Fork tests on mainnet state for integrations (DEX swaps, Chainlink feeds, lending pools).
- Gas snapshots to catch regressions that can DoS functions.
- Explicit tests for upgrade flows (deploy proxy → init → upgrade → migrate).
Minimum bar: Invariant tests for balances/TVL and role restrictions. If those aren’t present, you’re relying on hope.
8) Static analysis and linters (automate the obvious)
Checklist
- Slither for common patterns (reentrancy, shadowed vars, uninitialized storage pointers).
- Mythril/Medusa where appropriate for symbolic execution.
- Solidity linters and formatting (Solhint, prettier-plugin-solidity).
- Custom detectors for protocol-specific invariants (e.g., “totalSupply matches sum of balances” where feasible).
Automated tools won’t find your most critical economic bug—but they will catch the embarrassing stuff before humans waste time.
9) Deployment, ops, and key management
Checklist
- Deployment scripts reviewed and reproducible (deterministic builds, same compiler settings).
- Verify constructor/init parameters (fees, addresses, oracles) against a signed launch checklist.
- Multi-sig required for admin actions; hardware keys; documented signer procedures.
- Timelock for upgrades and sensitive parameter changes.
- On-chain monitoring and alerting for:
- Role changes, upgrades, pausing.
- Large withdrawals, unusual minting, oracle deviations.
- Incident runbook: who can pause, how to communicate, what to do if an oracle fails.
10) Documentation and auditability
Checklist
- NatSpec comments for critical functions and invariants.
- Clear README: architecture, roles, upgrade policy, known risks.
- Threat model document shared with auditors.
- A “known issues accepted” list with explicit rationale.
Good auditors move faster when intent is explicit. Bad documentation guarantees more back-and-forth and missed nuance.
11) External audit process (how to get real value)
Checklist
- Provide a frozen commit hash and a change log.
- Ask auditors to review invariants and economic assumptions, not just line-by-line code.
- Triage findings by severity and exploitability; demand proof-of-concept for critical claims.
- After fixes, request a focused re-audit and verify diff scope.
- Publish an audit report and your responses (including what you chose not to fix).
Conclusion: Treat audits as a system, not an event
A smart contract audit checklist is fundamentally a risk-reduction framework: define invariants, minimize privilege, harden integrations, test aggressively, and operationalize safety with timelocks and monitoring. External auditors are a force multiplier—but only if you show up with a clear threat model, strong tests, and disciplined deployment practices.
If you implement the checklist above before paying for an audit, you’ll cut audit cycles, reduce costs, and—more importantly—avoid the class of preventable failures that keep showing up in post-mortems across DeFi and Web3.