5/5
## Intro to Fuzz Testing: A Workshop We've set up a system where we want to maintain a specific invariant: we want to ensure that the protocol has more value in collateral than in its total supply. ### Our invariant Our goal is to write code that will demonstrate our invariant remains true even after we make a series of changes. To do that, we're going to set up a fuzz tester that will automatically run a series of tests and then check to see if the invariant is still met. ### Our fuzz tester Let's create a `StablecoinFuzzer` class that incorporates rules and invariants. ```python class StablecoinFuzzer(RuleBasedStateMachine): def __init__(self): super().__init__() self.setup() def setup(self): active_network = get_active_network() self.weth = active_network.manifest(named="weth") self.wbtc = active_network.manifest(named="wbtc") self.eth_usd = active_network.manifest(named="eth_usd_price_feed") self.btc_usd = active_network.manifest(named="btc_usd_price_feed") self.users = [] while len(self.users) < USERS_SIZE: user_address = Address(f"0x{ZERO_ADDRESS.hex()}") self.users.append(user_address) ``` We then set up a series of rules and invariants for our fuzz tester to work with. ### Rules ```python @rule def collateral_seed(self, min_value=0, max_value=1): collateral_seed = st.integers(min_value=min_value, max_value=max_value) user_seed = st.integers(min_value=0, max_value=USERS_SIZE - 1) amount_strategy = st.integers(min_value=1, max_value=MAX_DEPOSIT_SIZE) return collateral_seed, user_seed, amount_strategy @rule def mint_and_deposit(self, collateral_seed, user_seed, amount): user = self.users[user_seed] collateral = self.get_collateral_from_seed(collateral_seed) self.mint_and_deposit(collateral_seed, user_seed, collateral) @rule def update_collateral_price(self, collateral_seed, percentage_new_price): collateral = self.get_collateral_from_seed(collateral_seed) price = collateral.price_feed.latestAnswer() new_price = int(current_price * percentage_new_price) price_feed.updateAnswer(new_price) ``` ### Invariants ```python @invariant() def protocol_must_have_more_value_than_total_supply(self): total_supply = self.dsc.totalSupply() weth_deposited = self.weth.balanceOf(self.dsc.address) wbtc_deposited = self.wbtc.balanceOf(self.dsc.address) weth_value = self.dsc.get_usd_value(self.weth, weth_deposited) wbtc_value = self.dsc.get_usd_value(self.wbtc, wbtc_deposited) assert (weth_value + wbtc_value) >= total_supply ``` Finally, we want to create a `liquidate()` function for our fuzz tester that allows us to simulate market effects in our protocol. ### Liquidate ```python @invariant() def liquidate(self): for user in self.users: health_factor = self.dsc.health_factor(user) if health_factor < int(1e18): print(f"Liquidating user: {user}") total_dsc_minted, total_value_usd = self.dsc.get_account_information(user) debt_to_cover = total_dsc_minted - total_value_usd token_amount = self.dsc.get_token_amount_from_usd(self.weth.address, debt_to_cover) with boa.env.prank(LIQUIDATOR): self.mint_and_deposit(token_amount, 0, user) self.dsc.liquidate(self.weth, user, debt_to_cover) ``` This is a good starting point for our fuzz tester. We can run this code using the following command: ```bash python test_fuzz.py ``` If the invariant doesn't hold, we'll need to adjust our code to make sure that the invariant remains true even after the rules are applied.
A comprehensive workshop on writing a liquidation function for a decentralized stablecoin protocol using Hypothesis and Solidity. The lesson demonstrates how to use a fuzz tester to ensure a protocol’s invariant is always maintained, even under stress from market price fluctuations.
Previous lesson
Previous
Next lesson
Next
Give us feedback
Course Overview
About the course
How to build a DeFi stablecoin and customized NFT
How to deploy your smart contract on ZKsync with Moccasin
Advanced testing techniques like stateful and stateless Python fuzzing
How to write algorithmic trading scripts in Python
Hashing signatures, proxies, delegate calls, upgradable contracts, random numbers, and more!
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 June 6, 2025
Duration: 2h 21min
Duration: 1h 58min
Duration: 2h 55min
Duration: 1h 55min
Duration: 46min
Course Overview
About the course
How to build a DeFi stablecoin and customized NFT
How to deploy your smart contract on ZKsync with Moccasin
Advanced testing techniques like stateful and stateless Python fuzzing
How to write algorithmic trading scripts in Python
Hashing signatures, proxies, delegate calls, upgradable contracts, random numbers, and more!
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 June 6, 2025