All articles
Smart Contracts·July 8, 2026·6 min read

What a Smart Contract Audit Actually Checks, Step by Step

What does a smart contract audit check? Slither and Echidna passes, manual invariant review, access control, and upgrade paths, explained.

What A Smart Contract Audit Actually Checks, Step By Step

A real audit is not someone reading your Solidity files top to bottom and nodding. It's a sequence of specific passes, each catching a different class of bug, run in an order that front-loads the cheap checks before the expensive ones. If you've never sat next to an auditor doing this work, here's the actual checklist, not the marketing version.

Pass 1: Static Analysis (Slither, and Why It's First)

Slither runs in under a minute on most codebases and flags roughly 90 detector categories: reentrancy patterns, uninitialized storage pointers, incorrect ERC20 return handling, shadowed state variables, unprotected selfdestruct, tx.origin misuse, and delegatecall to untrusted addresses. It's cheap, so it goes first. A competent auditor runs it, then spends 30-60 minutes triaging: maybe 40 findings come out, 30 are noise (Slither is noisy about low-severity style issues), and 10 are worth a closer look.

We also run Mythril or Semgrep with custom rules for project-specific patterns, but Slither is the baseline every serious shop uses. If a firm quotes you an audit and can't tell you which static tools they run, that's a red flag worth asking about directly.

slither ./contracts --exclude-informational --exclude-low \
  --filter-paths "node_modules|test"

That command alone won't find your business-logic bugs. It finds the mechanical ones — the stuff a human reviewer might miss on hour six of reading code.

Pass 2: Fuzzing With Echidna Or Foundry

Static analysis reads code structurally. Fuzzing executes it against thousands of randomized inputs looking for invariant violations. This is where you catch the bugs that only show up under specific numeric edge cases — integer overflow in a fee calculation that only triggers above a certain deposit size, a rounding error that lets someone drain dust from a vault over 10,000 transactions.

A typical Echidna setup defines invariants as properties the contract must never violate, regardless of call sequence:

function echidna_total_supply_matches_balances() public view returns (bool) {
    return totalSupply() == sumOfAllBalances();
}

Echidna then hammers the contract with random call sequences — mint, transfer, burn, in any order, with any amounts — trying to break that property. Foundry's invariant testing (forge test --match-test invariant) does something similar with a faster iteration loop, which is why a lot of teams now run both: Echidna for deep campaigns overnight, Foundry invariants for fast feedback during development. On a real audit we typically budget 12-48 hours of fuzz campaign time per contract, more for anything handling AMM math or interest accrual.

Pass 3: Manual Invariant Review

Tools verify properties you already thought to write down. They don't tell you which properties matter. This is the part that actually requires a senior engineer and can't be automated away.

The auditor works through: what should always be true about this system's state, and does every function preserve it? For a lending protocol: collateral value should never drop below the borrow threshold without triggering liquidation. For a staking contract: rewards distributed should never exceed rewards funded. For an AMM: the constant product (or whatever curve you're using) should hold after every swap, including ones that hit fee-on-transfer tokens or contracts with hooks.

This pass is where most high-severity findings actually come from in our experience, not the automated tools. A classic example: a vesting contract that computes unlocked tokens as (block.timestamp - start) * rate, where rate was computed with integer division and rounds down, meaning the last claimant in a batch loses dust, and over enough claimants the contract ends up holding orphaned tokens forever. Nothing crashes. Nothing reverts. It's just quietly wrong, and only a human tracing the math catches it.

Pass 4: Access Control Mapping

Every function gets classified: who can call it, under what state, and what happens if that assumption is wrong. We build this as an actual table — function name, modifier, expected caller, what breaks if the modifier is missing or misconfigured.

Common findings here: an onlyOwner function that should be onlyOwner but a refactor accidentally dropped the modifier; a multisig threshold that's technically 2-of-3 but two of those three keys are held by the same person; an emergency pause function with no corresponding unpause path, meaning a false-positive trigger permanently bricks the contract. Ownership transfer functions get special attention — a two-step transfer (propose, then accept) is safer than a one-step transfer because a typo'd address in a one-step transfer means permanent loss of control, no recovery.

Pass 5: Upgrade Path Review

If the contract is upgradeable — UUPS, Transparent Proxy, or a custom pattern — this pass checks storage layout collisions between versions, whether initialize() can be called twice or by anyone, and whether the proxy admin is a timelock or an EOA. An EOA-controlled proxy admin on a contract holding real value is one of the most common findings we flag as high severity, because it means one compromised key equals total control over the logic, regardless of how clean the implementation contract is.

We also check whether upgrades pass through a timelock long enough for users to exit if they disagree with a change — 24 hours is common, some protocols run 48-72.

Pass 6: The Written Report And Fix Verification

Findings get severity-ranked (critical, high, medium, low, informational), each with a proof of concept where relevant. The team fixes what needs fixing, and the auditor does a second pass specifically on the diff — not a full re-audit, but a targeted check that the fix doesn't introduce a new problem, which happens more often than you'd think.

If you're comparing quotes, ask directly which of these six passes each firm includes and how many hours are budgeted for the fuzzing campaign specifically — that line item is where corners get cut. For chain-specific mechanics beyond EVM, the checklist shifts; see our TON audit checklist for FunC and Tact contracts for how that differs. If you're still scoping budget, we break down real pricing by chain in our audit cost guide for EVM, Solana, and TON, and if you're wondering whether you need this at all before launch, we cover that directly in do you need an audit before mainnet launch.

We run all six passes as standard on every smart contract audit engagement, and offer lighter-weight code review for pre-audit cleanup or internal PRs. If you're building the contract from scratch rather than auditing an existing one, our smart contract development team builds with these checks in mind from day one, and the same applies to full dApp development where the frontend and contract need to be reviewed as one system.

If you have a contract heading toward mainnet, get it in front of an auditor before the deploy date is fixed, not after — talk to us about a smart contract audit while there's still time to fix what we find.

Need a bot like this built?

We design, build and run trading bots on Solana, Hyperliquid and Polymarket.

Start a project
#smart contract audit#Slither#Echidna#security#Solidity