WritingSolidity Pre-Audit Preparation: A Checklist for Web3 Teams — Clixo
5 min readaudit-preparation, solidity, smart-contract-security, web3

Solidity Pre-Audit Preparation: A Checklist for Web3 Teams

Prepare your Solidity codebase before engaging an auditor. This pre-audit preparation checklist reduces cost, improves coverage, and gets better results.

Most teams think about the audit as something that happens after the code is done. The teams that get the most value from their security review treat audit preparation as part of the development process, not a handoff ritual. An auditor reviewing well-prepared code finds more real vulnerabilities. An auditor reviewing unprepared code spends billable time on context-building and documentation that developers should have done themselves.

This checklist covers what to have in order before you open a conversation with a security firm.

Solidity Pre-Audit Preparation Checklist

Code Quality and Documentation

Lock your compiler version

Use a fixed Solidity version in every file (pragma solidity 0.8.24; not ^0.8.0). The caret syntax allows the contract to compile under future compiler versions with potentially different behavior. Auditors want to know exactly what compiler was used.

Write NatSpec comments for every external and public function

NatSpec is Ethereum's documentation standard. Every external and public function should have @notice (what it does for users) and @dev (technical implementation notes). Every parameter should be documented with @param and return values with @return. Auditors who can read what a function is supposed to do can immediately identify whether it actually does that.

Write an architecture overview document

One or two pages covering:

  • What the protocol does and its economic design
  • How the contracts relate to each other (a diagram helps)
  • What external protocols are integrated and why
  • What the key invariants of the system are (e.g., "the sum of all user balances should always equal the total supply token held by the contract")
  • Known trade-offs or design decisions that are intentional

Define scope explicitly

List every file that is in scope and every file that is out of scope, with brief justification. If a library file is an unmodified copy of a previously audited dependency, say so.

Code Cleanliness

Remove all TODO and FIXME comments

If there are unresolved questions or incomplete implementations in the code, resolve them before the audit. Auditors who find TODOs may not know which are genuine planned work and which represent security gaps.

Remove unused imports, variables, and functions

Dead code creates noise and costs auditor time. Run a linter (Solhint or Slither's unused variable checks) and remove everything that is not needed.

Use named constants for magic numbers

Replace inline numbers with named constants that communicate intent. LIQUIDATION_THRESHOLD = 8000 is auditable; 8000 in the middle of a calculation is not.

Consistent error messages

Use custom errors rather than string revert messages where possible (cheaper gas, clearer intent). Custom errors should have descriptive names: InsufficientBalance() is auditable; E1() is not.

Testing

Achieve meaningful unit test coverage

Not necessarily 100%, but every critical path — deposits, withdrawals, liquidations, reward calculations — should have unit tests. Auditors use test suites to understand intended behavior.

Write at least basic invariant tests

Foundry's invariant testing feature and Echidna both let you define properties that should always hold and fuzz the contract looking for violations. Key invariants to cover:

  • Token accounting: total supply equals sum of all balances
  • Fund custody: ETH or tokens held by the contract match what accounting says should be there
  • Authorization: no unauthorized address can trigger a privileged operation

Include negative test cases

Test that unauthorized callers are rejected. Test that operations fail correctly under invalid inputs. These tests document expected behavior under failure conditions and give auditors confidence that error handling is intentional.

Run all tests on the exact codebase being submitted

Do not submit code that does not pass its own test suite. Failing tests during an audit engagement are a red flag and waste auditor time.

Security Self-Review

Run Slither and address output

Slither is a free static analyzer that catches many common vulnerability patterns. Run it against your codebase and triage all findings before the audit. For findings you disagree with or have intentionally accepted, document your reasoning. Auditors who receive a list of pre-triaged Slither findings with explanations spend less time on known patterns and more time on novel issues.

Verify all external calls follow CEI

Check every external call in the codebase — ETH transfers, ERC-20 transfers, calls to external contracts. Confirm that all state updates happen before the external call. This is the Checks-Effects-Interactions pattern. Flag any place where this order is not followed and document why.

Verify access control on every function

Generate a list of all external and public functions and their access modifiers. Every function that should be restricted should have an explicit modifier enforcing that restriction. Functions with no access restriction should be deliberately public — not accidentally so.

Check for hardcoded addresses

Hardcoded addresses for token contracts, oracle feeds, or external protocols should be documented. If these are expected to change, the mechanism for updating them should be access-controlled.

Audit Engagement Logistics

Designate a technical point of contact

The auditing firm will have questions. A single senior developer who can respond within hours rather than days keeps the engagement moving and prevents delays.

Allocate time for remediation

Build calendar time into the release schedule for the remediation phase after the initial audit report. Fixing findings and having them retested takes time. Protocols that rush remediation introduce new bugs.

Budget for a retest

Confirm upfront that the engagement includes retesting of critical and high findings after remediation. A report with no retest is not a complete engagement.

A prepared codebase is a more auditable codebase. The audit result you get reflects the quality of the code and documentation you submit.

Clixo builds Web3 systems with audit-readiness built into delivery. If your team needs a technical partner who treats security as part of engineering — not a final gate — reach out.