This is a reusable fuzzer for Soroban contracts
that implement the standard
TokenInterface
.
Soroban contract authors implementing tokens can use it to gain confidence in their code.
At present, this requires a specific commit of rs-soroban-env
and rs-soroban-sdk
to be checked out in directories adjacent to soroban-token-fuzzer
.
This changes over time as the SDK changes.
Install cargo-fuzz
:
cargo install cargo-fuzz
Running the fuzzer against two in-tree tokens:
cargo +nightly fuzz run fuzz_native_token
cargo +nightly fuzz run fuzz_example_token
The main part of this project is the
soroban-token-fuzzer
crate, in the root directory of this repo.
It is a library that implements reusable token fuzzing logic.
Customized token fuzzers are programs that link to soroban-token-fuzzer
and run it with their own configuration.
In this repo, the soroban-token-fuzzer-driver
crate,
in the fuzz
directory, is such a crate. It includes
the fuzz_native_token
and fuzz_example_token
fuzzers.
The easiest way to use this fuzzer is to clone this repo,
and simply add another fuzzer to the soroban-token-fuzzer-driver
crate.
soroban-token-fuzzer-driver
Copy fuzz/fuzz_targets/fuzz_example_token.rs
to
e.g. fuzz_my_token.rs
Edit fuzz/Cargo.toml
to add your contract as a dependency, e.g.
my-token.path = "../tokens/my-token"
my-token.features = ["testutils"]
Make sure your crate has a "testutils" feature and it is activated.
In fuzz/Cargo.toml
, declare fuzz_my_token.rs
as a binary:
[[bin]]
name = "fuzz_my_token"
path = "fuzz_targets/fuzz_my_token.rs"
test = false
doc = false
Adapt fuzz_my_token.rs
to use your token.
Now you can fuzz your token with
cargo +nightly fuzz run fuzz_my_token
The fuzzer generates several addresses, one of which will be an admin. These addresses may be contract addresses or native account addresses.
It uses token-specific code to initialize the contract.
It then executes some number of commands against the contract,
either a method on the TokenInterface
interface,
a token-specific mint
method, or a command to advance time
and begin a new transaction.
For each call it generates auths for a random subset of addresses.
After every step the fuzzer makes general assertions about invariants, and specific assertions related to the executed command.
It maintains independent state about what it expects from the token's internal state, including information about mints, burns, allowances and balances.
After every step various invariants are asserted:
panic_with_error!
).WasmVm
InvalidAction
approve
, transfer
, transfer_from
, burn_from
, burn
,name
, symbol
and decimals
mint
. There is no standardThe most important thing to know about fuzzing soroban contracts:
never call panic!
and related functions to handle errors that may
occur during normal operation: the fuzzer views panics as bugs.
Instead, use the Soroban-specific
panic_with_error!
macro, which the fuzzer can distinguish from a bare panic!
.
For additional tips see the end of this video presentation.
MIT/Apache-2.0