← Insights
chain

Audit vs Formal Verification: Spending a Fixed Security Budget

You have budget for security review once. The wrong kind leaves the real risk uncovered. Here's what audits catch, what verification proves, and how to spend it

You have one shot at security review before mainnet. The budget is fixed. Spend it wrong — buy the kind of review that doesn't cover your actual risk — and you'll have a clean report, a green checkmark in your docs, and a live exploit waiting in the part of the code nobody scrutinized the right way. The checkmark is not the same as being secure. Teams discover this the expensive way, after the drain, when they re-read the audit and realize it was scoped to find a class of problem that wasn't the problem.

So before you spend, understand what each kind of review actually does. Audits and formal verification are not competing products where one is the premium version of the other. They answer different questions, cover different ground, and miss different things. The decision is how to allocate a finite budget across them — and across the third leg most teams forget entirely.

What an audit actually catches

A smart contract audit is expert humans reading your code adversarially, asking "how do I break this and steal from it." A good audit run by good reviewers is the highest-value security spend for most contracts, because the question it answers — does this code do something it shouldn't — is broad and covers the failure modes that actually drain protocols.

Audits catch the known vulnerability classes: reentrancy, access control gaps, integer issues, unchecked external calls, oracle manipulation. They catch the things automated scanners flag, and more importantly they catch what scanners can't: logic errors specific to your contract, economic attacks that emerge from how your incentives interact, state transitions your design didn't intend, the subtle way two of your functions combine into a drain that neither has alone. A skilled auditor models your contract as a system an adversary will probe, and finds the holes in your logic, not generic patterns.

That breadth is the strength. An audit looks at the whole contract and asks the open-ended question. For the vast majority of production contracts, a strong audit is where the security budget should go first.

What an audit misses

Audits have two structural limits, and both come from the same root: an audit is humans reading code under time pressure.

First, completeness is not guaranteed. An auditor reviews for a bounded number of weeks and finds what they find. A clean report does not mean no bugs exist — it means none were found in the time spent by the people who looked. Coverage depends on the reviewers' skill, their familiarity with your domain, and how much time the budget bought. A rushed audit by junior reviewers on a complex contract is a checkmark, not a guarantee.

Second, audits prove the presence of bugs, not their absence. Finding a vulnerability is proof it exists. Not finding one is the absence of evidence, which is not evidence of absence. For most contracts that's an acceptable risk, because the alternative costs more than the value at stake. For some contracts — the ones holding very large value with a critical, well-defined property that must never be violated — "probably correct" isn't good enough, and that's exactly the gap formal verification fills.

What formal verification actually proves

Formal verification is mathematical proof that a specific property of your code holds for all possible inputs and states, not just the ones a human or a test happened to try. You write a formal specification — a precise statement of an invariant — and a tool (Certora, the symbolic engines, model checkers) proves the code satisfies it across the entire state space, or produces a concrete counterexample showing where it doesn't.

The power: where an audit checks the cases a human considered, verification checks every case. If you can express your critical property formally — "total supply always equals the sum of balances," "no function lets a user withdraw more than they deposited," "only an authorized role can ever change the implementation" — verification proves it holds against the full input space, including the adversarial inputs nobody thought to test. For a defined invariant, it's the strongest assurance available.

The limits are equally important. Verification proves the properties you specified — nothing more. If you forget to specify a property, it's unverified, and the proof says nothing about it. The proof is only as good as the spec, and writing a complete, correct spec for a complex contract is hard, expensive, and itself a place to make mistakes. Verification is narrow and deep: total certainty about specific properties, zero coverage of everything you didn't formalize. It does not replace an audit's broad adversarial read; it complements it on the properties that must never break.

The third leg: monitoring

Here is what the audit-versus-verification framing leaves out and what gets protocols killed anyway. Both audit and verification are pre-deployment. They look at the code before it's live. Neither does anything once your contract is on mainnet, holding value, facing a continuously evolving adversary probing it in real time.

A clean audit and a complete proof both tell you the code was correct against the threats understood at review time. They do not tell you you're being attacked right now. New attack techniques emerge. The ecosystem your contract integrates with changes underneath it. A composition with a contract that didn't exist at audit time opens a path nobody could have reviewed. Security is not a state you reach at deployment; it's a posture you hold over the contract's life.

Monitoring is the third leg of the stool, and skipping it is why teams with clean audits still get drained and learn about it from Twitter. Event monitoring on privileged actions, anomaly detection on outflow velocity, balance reconciliation against your model, admin-action alerts inside the timelock window, and an on-call rotation that can pause fast. Pre-deployment review reduces the probability of a vulnerability. Monitoring reduces the cost of one that gets through anyway — and one always might. A fixed security budget that spends everything on review and nothing on detection is a budget that's bought a clean conscience and no early warning.

We've built production contracts where on-chain provenance and access control had to hold under real adversarial pressure, with monitoring as a first-class part of the system rather than an afterthought. See how we approached Sigil →

How to spend a fixed budget

The allocation depends on value at risk and contract complexity. Some defaults that hold up.

Most production contracts — meaningful value, standard-to-moderate complexity. Put the majority into a strong audit from reviewers who know your domain, leave room to fix what they find and re-review, and carve out a real slice for monitoring so a missed bug surfaces in the first block instead of on someone else's dashboard. Skip formal verification unless there's a specific invariant whose violation is catastrophic.

Very high value, well-defined critical property — a vault, a bridge, anything where one specific invariant must never break and breaking it loses everything. Audit and formal verification, with verification scoped tightly to the handful of properties that matter most. Don't try to verify the whole contract; verify the invariants whose failure is fatal, and let the audit cover the broad surface. Monitoring still non-negotiable.

The constant across both: fix-and-re-review beats a second independent audit on unfixed code, and monitoring is never the line item you cut. The worst allocation is one big audit, no budget left to fix the findings properly, and nothing watching the contract after launch. A clean report on code you didn't have budget to fix is a report on code you're not shipping.

What fixed looks like

You spent the budget against your actual risk, not against whichever review had the best marketing. A strong adversarial audit covered the broad surface, by reviewers who understood your domain, with budget reserved to fix findings and re-review. If a single catastrophic invariant existed, formal verification proved it across the full state space — scoped to the properties that must never break, not sprayed across the whole contract. And monitoring went live with the contract: privileged-action alerts, outflow anomaly detection, balance reconciliation, an on-call who can pause. Security stopped being a checkmark you earned at deployment and became a posture you hold — reduce the probability of a bug before launch, reduce the cost of one after. The first thirty days on mainnet are quiet because the surface was covered three ways, not one.

This is for you if

You're shipping a contract with real value at stake and you have one security budget to allocate before mainnet. Getting the allocation right — the right depth of audit, formal verification scoped to the invariants that warrant it, and monitoring built in rather than skipped — is the difference between a clean report and an actually secure protocol. Proper security review and the monitoring to back it typically runs $50k–$200k+ depending on contract complexity and value at risk, and it's the cheapest insurance a real-money protocol will ever buy relative to the loss it prevents.

This is not for you if you're deploying a memecoin or a testnet toy where there's no value to protect and the security plan is hope. Spend where the value at risk warrants the spend, and not before.