1/5
## Fuzz Testing: Introduction Fuzz Testing is a technique for finding vulnerabilities in software by feeding it random data. We can use this technique to find bugs and vulnerabilities in smart contracts. Let's start by looking at a simple example: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract MyContract { uint256 public shouldAlwaysBeZero = 0; uint256 private hiddenValue = 0; function doStuff(uint256 data) public { if (data == 2) { shouldAlwaysBeZero = 1; } if (hiddenValue == 7) { shouldAlwaysBeZero = 1; } hiddenValue = data; } } ``` We have a function called `doStuff` which takes an integer as an input parameter. We know that the variable `shouldAlwaysBeZero` should always be zero. This is known as an invariant. The invariant is a property of the system that must always hold. Let's look at a unit test for this code: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {MyContract} from "./MyContract.sol"; contract MyContractTest { MyContract exampleContract; function testAlwaysGetZeroUnit() public { uint256 data = 0; exampleContract.doStuff(data); assert(exampleContract.shouldAlwaysBeZero() == 0); } } ``` We pass in a single data point, call the function, and then check if our invariant is still true. We might think that our code is covered, but if we look closer at the `doStuff` function we see that if our data input is 2, `shouldAlwaysBeZero` will be set to 1. This will break our invariant, since `shouldAlwaysBeZero` will no longer be zero. In order to find this bug, we can write a fuzz test in Foundry. This will allow us to automatically generate random input data and run it through our code to try to find edge cases. Let's write a fuzz test for this example: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {MyContract} from "./MyContract.sol"; import {Test} from "forge-std/Test.sol"; contract MyContractTest is Test { MyContract exampleContract; function testAlwaysGetZeroFuzz(uint256 data) public { // uint256 data = 0; exampleContract.doStuff(data); assert(exampleContract.shouldAlwaysBeZero() == 0); } } ``` In the fuzz test, we will remove the manually selected data and let Foundry automatically randomize the data. We can run this fuzz test from the terminal using this command: ```bash forge test -m testAlwaysGetZeroFuzz ``` Foundry will then automatically run through our code with a ton of different random inputs to try to find a scenario where the invariant is broken. We can see that the fuzz test has successfully identified a counter-example. This allows us to go back to our code and fix the bug. Foundry fuzz tests are known as stateless fuzz tests, which means that the state of the previous run is discarded for the next run. There's another type of fuzz test that we can write in Foundry called a stateful fuzz test. This is where we use the ending state of our previous fuzz run as the starting state of the next fuzz run. To write a stateful fuzz test, we use the `invariant` keyword. Let's write a stateful fuzz test for our example: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {MyContract} from "./MyContract.sol"; import {Test} from "forge-std/Test.sol"; import {StdInvariant} from "forge-std/StdInvariant.sol"; contract MyContractTest is StdInvariant, Test { MyContract exampleContract; function setUp() public { exampleContract = new MyContract(); targetContract(address(exampleContract)); } function invariant_testAlwaysReturnsZero() public { assert(exampleContract.shouldAlwaysBeZero() == 0); } } ``` We first need to import the `StdInvariant` contract and inherit it in our test contract. We then need to tell Foundry which contract to run the fuzz test on. Since we only have one contract, we'll tell Foundry that `exampleContract` should be used as the target contract. Lastly, we will write a function called `invariant_testAlwaysReturnsZero` that asserts that `shouldAlwaysBeZero` is equal to zero. Now when we run this test, Foundry will randomly run through our code, calling our functions in a random order with random data. Since we only have one function `doStuff`, it will call `doStuff` with random data, then call `doStuff` again with random data, then call `doStuff` again with random data, and so on. If it happens to call `doStuff` with an input of 7, it will set `hiddenValue` to 7. The next time it calls `doStuff`, it will set `shouldAlwaysBeZero` to 1. When it runs our invariant test, it will find that our invariant is broken. We can see in the terminal that the invariant test found a failing test with this sequence: ```bash [FAIL. Reason: Assertion violated] [Sequence] sender=0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
A comprehensive introduction to fuzz testing for smart contracts. The lesson introduces fuzzing in the context of Vyper development and explores the concepts of stateless and stateful fuzzing.
Previous lesson
Previous
Next lesson
Next
Give us feedback
Course Overview
About the course
Python basics
Introduction to Web3.py
Introduction to Titanoboa
Introduction to Moccasin
How to create an ERC-20
How to test Python code and Vyper smart contract
How to deploy Vyper smart contracts on ZKsync using Moccasin
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
On-chain Data Analyst
$59,000 - $139,000 (avg. salary)
DeFi Developer
$75,000 - $200,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Last updated on April 21, 2025
Duration: 2h 20min
Duration: 1h 51min
Duration: 58min
Duration: 2h 23min
Duration: 53min
Duration: 2h 24min
Duration: 28min
Duration: 1h 54min
Duration: 11min
Course Overview
About the course
Python basics
Introduction to Web3.py
Introduction to Titanoboa
Introduction to Moccasin
How to create an ERC-20
How to test Python code and Vyper smart contract
How to deploy Vyper smart contracts on ZKsync using Moccasin
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
On-chain Data Analyst
$59,000 - $139,000 (avg. salary)
DeFi Developer
$75,000 - $200,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Last updated on April 21, 2025
Testimonials
Read what our students have to say about this course.
Chainlink
Chainlink
Gustavo Gonzalez
Solutions Engineer at OpenZeppelin
Francesco Andreoli
Lead Devrel at Metamask
Albert Hu
DeForm Founding Engineer
Radek
Senior Developer Advocate at Ceramic
Boidushya
WalletConnect
Idris
Developer Relations Engineer at Axelar