3.9.6 Developer's Pre-Audit Checklist

This subsection is the operational checklist version of Section 3.9.2. Where 3.9.2 explains why each preparation item matters, this section gives the team a scannable list to verify the day before the audit begins. Both serve a purpose: 3.9.2 informs the team's preparation philosophy, while this section verifies the preparation is actually complete.

Use this checklist literally. Each item is either done or not done — there is no partial credit. If a checkbox cannot be honestly ticked, the audit's value is reduced. Some items represent multiple hours of work; others are 30-second verifications. All of them save more audit hours than they consume.

The checklist is organized to match the audit's lifecycle: codebase, documentation, threat modeling, tooling, deployment, communication, and the final sweep. Each section is independently scannable; a team that completes a subset before falling behind can pick up where they left off without losing context.

Codebase

  • Codebase is frozen at a specific commit hash
  • The audited commit is tagged in git (e.g., audit-v1.0)
  • Active development for non-audit work happens on a separate branch
  • A dedicated audit-remediation branch has been created off the tagged commit
  • All files in scope compile without errors
  • All files in scope compile without warnings (or accepted warnings are documented)
  • No TODO, FIXME, or XXX comments remain in production code (or those that remain are documented and intentional)
  • No commented-out code blocks in production code
  • No console.log or debug statements in production code
  • No hardcoded test addresses or test private keys
  • All compiler pragmas are pinned to a specific version (e.g., pragma solidity 0.8.20), not floating
  • All third-party dependencies are at pinned versions in package.json / foundry.toml
  • The codebase is in a single repository (or the dependencies between repositories are explicitly documented)

Code Quality

  • All functions have appropriate visibility (external, public, internal, private)
  • State variables use the most restrictive visibility that allows correct behavior
  • Custom errors are used in preference to revert strings where applicable
  • Events are emitted for every state-changing operation
  • Event parameters are indexed appropriately for off-chain filtering
  • Magic numbers have been replaced with named constants
  • Hardcoded addresses are passed in via constructor/initializer rather than baked into source
  • All inheritance chains are explicit (is A, B, C)
  • No unused imports, variables, or functions

NatSpec Documentation

  • Every public/external function has @notice
  • Every public/external function has @dev (where implementation notes are warranted)
  • Every parameter has @param with a meaningful description
  • Every return value has @return with a meaningful description
  • Every public state variable has @notice
  • Every contract has a contract-level @notice describing its purpose
  • @custom:security-contact is set on the main contract(s)
  • NatSpec accurately reflects current code (no stale documentation)
  • forge inspect <Contract> userdoc returns the expected entries

Threat Modeling

  • Threat model document exists and is current
  • Assets and attack surfaces are enumerated
  • Trust boundaries are explicitly identified
  • Attack scenarios for each asset are documented with defenses
  • Specific concerns and known-uncertain areas are flagged for auditor focus
  • Centralization risks are documented honestly (e.g., admin controls, multisig signers)
  • External dependencies are listed with their trust assumptions (oracles, other protocols, etc.)
  • The threat model has been shared with the auditor

Invariants

  • Invariants document exists with each invariant having a unique ID
  • Per-user invariants are explicit (e.g., user collateralization, user state consistency)
  • Global invariants are explicit (e.g., total supply conservation, solvency)
  • Conditional invariants are explicit (e.g., pause-state behavior)
  • Foundry invariant tests exist for the highest-priority invariants
  • All documented invariants currently pass under existing test conditions
  • The invariants document has been shared with the auditor

Internal Audit

  • Peer code review has been performed on all in-scope changes
  • Review comments have been addressed or explicitly deferred with documentation
  • Slither runs cleanly (or findings are triaged and documented as accepted)
  • Mythril analysis has been run against complex contracts (where applicable)
  • Solhint runs without errors
  • Test coverage is at 100% for lines and branches in scope
  • Negative tests exist for every privileged function (unauthorized callers cannot call)
  • Tests exist for every reverting branch (require, revert, custom errors)
  • Adversarial test contracts exist for any function with external calls
  • At least one full read-through of the codebase has been performed by a senior team member with the threat model in hand

Deployment

  • Deployment script exists (Foundry Script or Hardhat task)
  • Constructor / initializer parameters are documented with their meaning
  • The deployment script includes post-deployment assertion checks
  • The deployment script has been tested against a local fork
  • The deployment script has been tested against a testnet
  • All initial role grants and ownership transfers are scripted
  • Multi-sig setup (if applicable) is documented with signer addresses
  • Timelock setup (if applicable) is documented with timing parameters
  • Contract verification on Etherscan/equivalent is part of the deployment workflow
  • The deployment script has been shared with the auditor

Upgradeability (if applicable)

  • Proxy pattern is identified (Transparent, UUPS, Beacon, Diamond)
  • Implementation contract's constructor calls _disableInitializers()
  • Storage layout is documented for the implementation contract
  • Storage layout follows append-only or namespaced storage pattern
  • OpenZeppelin Upgrades Plugin (or equivalent) is used to verify storage compatibility
  • Upgrade authorization is documented (who can upgrade, with what timelock)
  • An initial implementation deployment has been performed and verified

Known Issues

  • Known-issues document exists
  • Acknowledged-for-future issues are documented with rationale
  • Centralization risks are documented with mitigations
  • Out-of-scope items are explicitly listed
  • Each known issue has been triaged with the team (not just listed)
  • The known-issues document has been shared with the auditor

Scope and Engagement

  • Scope document exists and has been signed by both parties
  • In-scope files are listed by exact path
  • Lines-of-code count is calculated and matches the auditor's pricing basis
  • Out-of-scope items are explicitly listed
  • Focus areas are identified (matching the threat model's specific concerns)
  • Deliverables are specified (report format, severity classification, fix verification)
  • Timeline is specified (start date, expected delivery, fix verification window)
  • Communication protocol is specified (channels, cadence, response SLAs)
  • Public disclosure terms are specified (when, where, who can publish)

Communication Setup

  • Dedicated Slack/Discord channel has been created
  • Auditors have been invited to the channel
  • Primary point of contact has been designated (and backup if applicable)
  • Weekly status call has been scheduled (recurring calendar invite)
  • Shared document repository has been set up (Notion, Google Docs, etc.)
  • Q&A log document has been created
  • Findings tracking document has been created
  • All documents have been shared with the auditor

Tooling and Environment

  • The audited repository can be cloned and built by someone with no prior context (verified by having a team member try)
  • README.md includes setup instructions
  • README.md includes the command to run the test suite
  • Auditor has been informed of any non-standard tooling required
  • CI configuration is documented or available
  • Local development setup has been verified by a non-author team member

Final Sweep (Day Before Audit Starts)

  • Re-run all automated tools (Slither, Solhint, forge build, forge test, forge coverage)
  • Verify the audited commit hash matches what's in the scope document
  • Verify all documentation links work
  • Verify the auditor can access the repository (or has received it via the agreed-upon mechanism)
  • Verify the communication channels are accessible to the auditor
  • Send a brief "audit starts tomorrow" message to the auditor confirming readiness
  • Make sure the primary point of contact is available during the engagement window
  • Make sure other team members can be reached if the POC is unavailable
  • Bug bounty program has been set up (Immunefi or similar) for post-launch
  • Formal verification specifications have been prepared (if engaging Certora or similar)
  • Prior audit reports (if any) are shared with the auditor as context
  • Test deployment on Sepolia or other testnet has been completed
  • At least one mock attack scenario has been walked through by the team
  • Emergency response plan exists for the deployment (pause keys ready, communication channels prepared)

Items That Should Be False at This Point

Some things should not be true if the codebase is genuinely ready:

  • Recent commits in the last 24 hours touching audit-scope files (should be FALSE)
  • Open pull requests targeting audit-scope code (should be FALSE)
  • Unresolved Slither findings of high or medium severity (should be FALSE — either fix or document as accepted)
  • Tests that are currently failing (should be FALSE)
  • Tests that are marked skip or pending (should be FALSE — either fix or remove)
  • Functions in scope that don't have NatSpec (should be FALSE)
  • Functions in scope without test coverage (should be FALSE)
  • Known critical or high-severity bugs that have not been disclosed to the auditor (should be FALSE)

If any of these are TRUE, the codebase is not actually ready and the audit will be less effective than it should be.

Using This Checklist

For a small audit (single contract, <500 LoC), this checklist takes a senior engineer roughly 2-4 hours to walk through completely. For a large multi-contract engagement, it can take a small team a full week.

The investment is worth it. A team that walks through this checklist and ticks every box reliably gets more value from the audit than a team that skips half the items. The audit cost is the same; the audit's output is substantially better.

For repeat audits, the checklist gets faster — most items remain done across engagements. The first audit is the expensive one in terms of preparation effort; subsequent audits build on the artifacts created the first time.

Cross-References

  • Why each item matters — Section 3.9.2 covers the reasoning behind each preparation deliverable
  • Internal audit — Section 3.9.1 covers the internal review work that should be complete before this checklist begins
  • Selecting an audit path — Section 3.9.3 covers the audit-path decision (this checklist applies regardless of path)
  • During the audit — Section 3.9.4 covers what happens once the checklist is complete and the audit starts
  • Post-audit remediation — Section 3.9.5 covers what to do with the audit's findings
  • Auditor's prerequisites — Section 4.3.2 covers the same checklist from the auditor's side (what they expect to see)