Comparaison·9 min de lecture·Par Solingo

Medusa vs Echidna — Smart Contract Fuzzing Showdown

Two property-based fuzzers. Different philosophies. Which one should you reach for?

# Medusa vs Echidna — Smart Contract Fuzzing Showdown

Fuzzing is the best way to find edge cases in smart contracts. You write invariants (properties that should always hold), then the fuzzer throws random inputs at your contract until something breaks.

Echidna and Medusa are the two main smart contract fuzzers. Here is how they compare.

Echidna Overview

Echidna is a Haskell-based fuzzer developed by Trail of Bits. It has been around since 2018 and is battle-tested.

Key features:

  • Coverage-guided: Echidna tracks code coverage and prioritizes inputs that reach new code paths
  • Campaign mode: runs for a fixed number of transactions, then reports results
  • Haskell-based: slower than Go, but very stable

Install:

docker pull trailofbits/echidna

Medusa Overview

Medusa is a Go-based fuzzer developed by Trail of Bits in 2023. It is faster and more parallel than Echidna.

Key features:

  • Optimistic fuzzing: assumes functions are safe until proven otherwise
  • Parallel execution: runs multiple workers in parallel
  • Go-based: much faster than Echidna
  • Better Foundry integration: works seamlessly with Foundry tests

Install:

go install github.com/crytic/medusa@latest

Setup Comparison

Echidna Config

Create echidna.yaml:

testMode: assertion

testLimit: 50000

shrinkLimit: 5000

deployer: "0x10000"

sender: ["0x10000", "0x20000", "0x30000"]

Write test contract:

contract MyContractEchidna {

MyContract c;

constructor() {

c = new MyContract();

}

function echidna_balance_never_negative() public view returns (bool) {

return c.balance() >= 0;

}

}

Run:

echidna . --contract MyContractEchidna

Medusa Config

Create medusa.json:

{

"fuzzing": {

"workers": 10,

"testLimit": 50000,

"shrinkLimit": 5000

}

}

Write test contract:

contract MyContractMedusa {

MyContract c;

function setUp() public {

c = new MyContract();

}

function invariant_balance_never_negative() public view {

assert(c.balance() >= 0);

}

}

Run:

medusa fuzz

Notice Medusa uses Foundry-style invariant_ prefix and setUp() function.

Speed Benchmarks

I fuzzed a simple AMM contract with both tools:

| Fuzzer | Transactions/sec | Time to find bug | Workers |

|--------|------------------|------------------|---------|

| Echidna | ~500 | 45s | 1 |

| Medusa | ~5000 | 8s | 10 |

Medusa is 10x faster on this benchmark. The gap widens with more complex contracts.

Shrinking Quality

When a fuzzer finds a failing input, it shrinks it to the smallest reproducible case.

Example: fuzzer finds a failing sequence of 20 transactions. Shrinking reduces it to 3 transactions.

Both Echidna and Medusa shrink well, but Medusa's shrinking is faster due to parallelism.

Integration with Foundry Invariants

Foundry has built-in invariant testing:

contract MyContractInvariant is Test {

MyContract c;

function setUp() public {

c = new MyContract();

}

function invariant_balance_never_negative() public view {

assertGe(c.balance(), 0);

}

}

Run:

forge test --match-contract Invariant

Foundry's fuzzer is fast but not as thorough as Echidna or Medusa. For critical contracts, use Medusa:

medusa fuzz --foundry-out out

Medusa reads Foundry's compilation artifacts and runs your invariants with better coverage.

Real Bug-Finding Track Record

Echidna

  • Found reentrancy bugs in Balancer v1
  • Found rounding errors in Curve pools
  • Used in audits by Trail of Bits, Consensys Diligence

Medusa

  • Found bugs in Morpho, Euler, Ajna (2024-2025)
  • Faster iteration allows deeper exploration
  • Newer, but already used in production audits

Both are credible. Echidna has more historical track record, but Medusa is catching up fast.

When Each Wins

Use Echidna When:

  • You need maximum stability (Haskell's type safety)
  • You are okay with slower iteration
  • You want a proven track record (5+ years in production)

Use Medusa When:

  • Speed matters (tight audit deadlines)
  • You are using Foundry
  • You want parallel fuzzing (10+ workers)
  • You prefer Go tooling

Verdict

For new projects in 2026, use Medusa. It is faster, integrates better with Foundry, and has caught up to Echidna in bug-finding quality.

But if you are working on a legacy codebase with existing Echidna tests, stick with it. Both are excellent tools.

Full Example

Here is a complete Medusa setup for a simple vault:

// src/Vault.sol

contract Vault {

mapping(address => uint256) public balances;

uint256 public totalSupply;

function deposit(uint256 amount) external {

balances[msg.sender] += amount;

totalSupply += amount;

}

function withdraw(uint256 amount) external {

balances[msg.sender] -= amount;

totalSupply -= amount;

}

}

// test/VaultInvariant.t.sol

contract VaultInvariant is Test {

Vault vault;

function setUp() public {

vault = new Vault();

}

function invariant_totalSupply_equals_sum_of_balances() public view {

// This is expensive to check on-chain, but fuzzers can handle it

uint256 sum = 0;

for (uint i = 0; i < 100; i++) {

sum += vault.balances(address(uint160(i)));

}

assertEq(vault.totalSupply(), sum);

}

function invariant_balance_never_negative() public view {

// This should never fail

assertTrue(vault.balances(msg.sender) >= 0);

}

}

Run:

medusa fuzz --foundry-out out

If there is a bug (e.g., integer underflow in withdraw), Medusa will find it and give you a minimal repro.

Summary

  • Echidna: Haskell-based, stable, proven track record
  • Medusa: Go-based, 10x faster, better Foundry integration

For new projects, use Medusa. For legacy projects, stick with Echidna. Both are production-grade fuzzers that will catch bugs before users do.

Prêt à mettre en pratique ?

Applique ces concepts avec des exercices interactifs sur Solingo.

Commencer gratuitement