Fuzz Testing Explained in Detail
Fuzz testing is automated testing with generated inputs. Instead of checking one hand-written value, the test runner tries many values and reports inputs that break an assertion, trigger an unexpected revert, or violate expected behavior.
In smart contracts, fuzzing is useful because dangerous inputs are often not obvious. They may involve zero values, maximum integers, unusual addresses, repeated calls, strange token behavior, or boundary conditions around time and balances.
Smart contract example
A unit test might check one transfer amount:
function test_transfer() public {
token.transfer(alice, 100);
assertEq(token.balanceOf(alice), 100);
}
A fuzz test checks many amounts:
function testFuzz_transfer(uint256 amount) public {
amount = bound(amount, 1, token.balanceOf(address(this)));
token.transfer(alice, amount);
assertEq(token.balanceOf(alice), amount);
}
The test checks whether transfer logic holds for tiny amounts, large amounts, and values near the sender balance.
Fuzz Testing in Auditing
Fuzzing catches bugs that fixed examples miss, especially in arithmetic, accounting, access checks, token transfers, pricing math, and state transitions.
A good fuzz test can turn an auditor's suspicion into a reproducible failing case. It also pairs well with invariant testing when the risk depends on sequences of calls.
Red flags in code
-
Arithmetic that depends on user-controlled amounts.
-
Branches that handle zero, max, or near-max values differently.
-
Token accounting split across several mappings.
-
External calls mixed with balance updates.
-
Tests that only use round numbers like
1 etheror1000. -
Fuzz tests that discard most inputs with broad
assumefilters.
How to test or review it
-
Start with the property the code should preserve.
-
Vary user-controlled inputs first.
-
Use
boundor targeted input generation to keep values meaningful. -
Avoid filtering so heavily that the fuzzer cannot explore the code.
-
Review failing cases carefully. A revert is only a bug if the protocol expected the call to succeed.
-
Add arithmetic boundary cases when reviewing integer overflow or rounding-sensitive code.
-
Use the smart contract audit checklist to decide which flows deserve fuzz coverage.