Go to course navigation

9 - Security II.

Tutorial objectives

  • Advanced techniques in security auditing
  • Static analysis tools
  • Fuzz and property-based testing

Tutorial pre-requisites


Computers in the laboratory don’t allow to install programs and save their state between login sessions. Please bring your own hardware for these tutorials.


Solidity static code analysis framework

Whitepaper: https://www.researchgate.net/publication/333700886_Slither_A_Static_Analysis_Framework_For_Smart_Contracts


$ slither .

Useful printers

  • contract-summary - Print a summary of the contracts
  • function-summary - Print a summary of the functions
  • human-summary - Print a human-readable summary of the contracts
  • inheritance - Print the inheritance relations between contracts
  • modifiers - Print the modifiers called by each function
  • require - Print the require and assert calls of each function
  • variable-order - Print the storage order of the state variables


$ slither . --print contract-summary



$ woke detect .

or automatically in the Tools for Solidity VS Code extension.

Property-based fuzz testing

  • multiprocessing implementation
  • can automatically launch ipdb (IPython-enhanced debugger) on exception

Documentation: https://ackeeblockchain.com/woke/docs/1.2.1/fuzzer


Woke fuzzer currently relies on the Brownie testing framework. Brownie is expected to be replaced by the Woke testing framework in Woke 2.0.


  • flow - a single operation (a function) randomly picked from a set of operations by the fuzzer
  • invariant - a function executed after each flow, usually containing assertions
  • sequence - a sequence of flows and invariants; after each sequence, the blockchain state is reset
  • campaign - an object allowing to define number of sequences and number of flows in each sequence; automatically runs flows and invariants

Each flow can be assigned a weight, which determines the probability of the flow being picked. The default weight is 100.


contract Counter {
    uint256 public count;

    function increment() public {
        count += 1;

    function decrement() public {
        count -= 1;
import brownie
from woke.fuzzer.campaign import Campaign
from woke.fuzzer.decorators import flow, invariant, weight
from woke.fuzzer.random import random_account

class Test:
    def __init__(self, contract_type) -> None:
        self.owner = random_account()
        self.contract = contract_type.deploy({"from": self.owner})
        self.counter_value = 0

    def flow_increment(self):
        self.contract.increment({"from": random_account()})
        self.counter_value += 1

    def flow_decrement(self):
        if self.counter_value == 0:
            with brownie.reverts():
                self.contract.decrement({"from": random_account()})
            self.contract.decrement({"from": random_account()})
            self.counter_value -= 1

    def invariant_counter_value(self):
        assert self.contract.count() == self.counter_value

def test_counter(Counter):
    campaign = Campaign(lambda: Test(Counter))
    campaign.run(100, 40)


Haskell program designed for fuzzy testing of Ethereum smart contracts

Whitepaper: https://www.researchgate.net/publication/343048222_Echidna_effective_usable_and_fast_fuzzing_for_smart_contracts


$ echidna-test helloworld.sol --contract TEST --config echidna-config.yaml