# 70 — The genetic fuzzer

The `fuzz` command is a separate tool from `attack` and a separate mental model. `attack` runs one scenario as written. `fuzz` runs the same scenario thousands of times, mutating its parameters between runs, in search of the parameter combination that maximises adversary profit. This chapter explains how the search works and when to reach for it.

## What "genetic" means here

The fuzzer maintains a population of *individuals*. An individual is a concrete assignment of the parameters declared in `fuzzer_config.search_space`. For example, in the sandwich scenario:

```
individual #5  =  { front_run_amount: 73000, back_run_amount: 81500 }
individual #12 =  { front_run_amount: 12000, back_run_amount: 230000 }
```

Each individual is scored by running the scenario with its parameters and reading off the adversary's profit. The score is the *fitness*. Higher fitness means more profit.

Each generation, the fuzzer keeps the top-scoring fraction of the population, breeds new individuals from those (taking parameters from two parents and mixing), and mutates a configurable fraction of the offspring (perturbing one parameter randomly). The next generation is then scored, and so on, for `generations` rounds.

The output is the best individual found across all generations.

## When to use it

Use `fuzz` when:

* the attack is parameterised over a continuous space — flash-loan size, swap size, LP range width, time delay;
* the optimum is not obvious from first principles, or the obvious optimum is wrong because of a non-linearity (fee tiers, slippage curves);
* you have an overnight CI slot and want to walk in to a worked-out finding in the morning.

Do not use `fuzz` when:

* the scenario is one fixed transaction with no tunable parameters;
* the invariant has not been observed to break under `attack`. The fuzzer amplifies findings; it does not discover them.

## Tuning the search

Three knobs matter, and they trade off against each other.

**`population`** — the number of individuals per generation. Higher means the search explores more of the space per round but each round costs more to run. We default to 30; we have found 50 helpful for high-dimensional searches and rarely benefit from going above 100.

**`generations`** — the number of rounds. Higher means the search has more time to converge but the run takes proportionally longer. We default to 50; we use 200 overnight.

**`mutation_rate`** — the probability that an offspring's parameter is randomly perturbed rather than inherited. Higher means more exploration; lower means faster convergence on a local optimum. We default to 0.15. Below 0.05 the search frequently gets stuck in a local optimum that is far from the global one; above 0.30 the search is essentially random.

The right tuning depends on the shape of the fitness landscape, which we do not know in advance. The honest answer is: start with the defaults, look at the convergence curve, and adjust. A flat curve calls for higher `mutation_rate`; a curve that converges and stops calls for higher `generations`.

## Reproducibility

A `fuzz` run is reproducible when its PRNG seed is fixed. Pass `--seed <int>` to fix the seed; without it, the seed is drawn from the operating system and printed on the first line of output, so an interesting run can always be re-run.

The fitness reported by a reproduced run will match the original *byte-for-byte* if the seed is the same and `economicfuzz` is the same version. If the version has changed, the fitness may shift; the convergence story will not.

## Reading the output

```
genetic fuzzer — sandwich-around-mint
strategy: genetic | pop: 30 | gen: 40
──────────────────────────────────────────────────

results:
══════════════════════════════════════════════════
generations:     40
total attacks:   1200
profitable:      864
best fitness:    1240.50
best params:
    front_run_amount: 67500.00
    back_run_amount: 73000.00
══════════════════════════════════════════════════
```

`profitable` is the count of individuals across all generations whose fitness was strictly positive — i.e., the adversary made any profit. `best fitness` is the maximum profit observed in USD-equivalent. `best params` is the winning individual.

Treat `best params` as the worst-case parameter assignment for the protocol. It is the assignment we recommend pinning into a regression scenario before patching, so that the patch can be verified against the same parameters.

## What a flat search means

If the search converges on `best fitness: 0`, the scenario is not exploitable as written. This is a *clean* result, but it is also a result that should be triple-checked before being trusted: a flat fitness can mean the protocol is hard, or it can mean the scenario was misconfigured. Re-run with a different seed; if both runs return zero, the scenario as written is genuinely clean.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://economicfuzz.gitbook.io/economicfuzz-docs/reference/70-genetic-fuzzer.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
