No single technique finds every contract bug. Start with unit tests, add fuzzing and static analysis for the cases you did not think of, and use formal verification for the properties that must never break. ethereum.org is explicit that even full coverage can miss edge cases.
Rung one: unit tests
Unit tests check functions in isolation: return values and storage changes. The ethereum.org testing guide recommends happy path tests, negative tests for invalid inputs, and assertions that document your assumptions.
Strength: fast and cheap. Limit: they only cover cases someone thought to write.
Rung two: integration tests
These check how contracts work together, including cross contract calls and inheritance. They can run against a forked chain in tools like Forge or Hardhat, simulating deployed contracts in a sandbox without real funds. Fork tests are where upgrade and oracle assumptions get exercised against real state.
Rung three: fuzzing
Fuzzing feeds functions random or malformed inputs to find error states, which makes it good for input validation. The guide notes that even with 100 percent coverage it is possible to miss edge cases, so coverage is a floor, not a verdict.
Write properties, such as total supply never exceeds a cap, and let the fuzzer try to break them.
Rung four: static analysis
Static analysis reads source without running it, using linters and analyzers. It catches unsafe constructs and style problems cheaply, but the guide says it is generally weaker at deeper vulnerabilities and can produce false positives. ethereum.org names Slither and Aderyn as examples. Run it on every pull request.
Rung five: formal verification
Formal verification checks an implementation against a formal specification, with properties written as invariants that must hold in every circumstance. It gives stronger guarantees than testing but costs more.
Its limits matter. Verification only confirms the contract matches the specification, so a weak specification lets bugs through. State explosion can slow tools down. Some properties cannot be decided automatically. The documentation positions it as a complement to testing and audits, not a replacement.
A sensible adoption order
- Unit tests with negative cases from day one.
- Static analysis in continuous integration.
- Fuzz properties for anything holding value.
- Fork tests before every deploy or upgrade.
- Formal specifications for a small set of core invariants.
- Independent review, covered in our audit preparation post.
Try it yourself
Open the demo and run the code scan. Look at how findings are grouped and which ones come with a location you could act on.
Click through it at your own pace, or open it full screen.
Quick check
Does 100 percent coverage mean the contract is safe?
No. The testing guide says edge cases can be missed even with full coverage.
What is the main limit of formal verification?
It proves the code matches the specification. If the specification is weak or wrong, bugs can pass.
Sources
- ethereum.org: testing smart contracts
- ethereum.org: formal verification
- ethereum.org: smart contract security
Last reviewed: 19 October 2026.