Pre-alphaFollow the build on GitHub

Shake your contract
before someone else does.

Soroquake fuzzes Soroban contracts with thousands of multi-user transaction sequences, checks your invariants after every step, and hands back the shortest sequence that breaks one, as a Rust test.

Calls in a shrunk repro, our target for 9 in 10 failures

Default pull-request campaign, corpus replay included

Ready-made invariant packs for tokens, AMMs, lending, vaults and more

Drained from YieldBlox on Blend V2 in Feb 2026 by a multi-step attack

Engine figures are design targets for v1. The incident figure comes from public post-mortems.

Write what must stay true.Soroquake does the shaking.

  1. 01

    Describe what users can do

    Each handler is a plain Rust function that calls your contract: deposit, swap, liquidate, set a fee. Soroquake picks who calls it and with what.

  2. 02

    Declare what must stay true

    Invariants read state and pass or fail. Solvency, supply equals balances, only the admin changes fees. Import packs for the standard ones.

  3. 03

    Let it shake

    Thousands of sequences across actors, ledger time, oracle moves and TTL expiry, guided by coverage, with every invariant checked after every step.

  4. 04

    Keep the aftershock

    The failure shrinks to the fewest calls that still break it and lands in your repo as a test that stays red until you fix it.

soroquake / vault campaign running
09:41:02[init]cargo soroquake init
09:41:02[init]found 3 handlers: deposit, withdraw, accrue
09:41:03[init]5 actors, recorded auth, ledger time on
>
Handlers
Invariants
Shake
Test

Example: a vault rounding bug found and turned into a test.

Bugs that only show up in the right order.Unit tests check the paths you thought of.

Accounting drift

shares × price ≤ assets

Same-asset swaps

swap(a, a) changes nothing

Free mint

supply == Σ balances

Broken liquidations

liquidate ⇒ health improves

Auth and roles

only admin sets the fee

Overflow at the edges

no panic near i128::MAX

Archival and TTL

restore ⇒ nothing lost

Upgrade regressions

invariants hold after migrate

Replay real Stellar incidents.Then aim the same invariant at your contracts.

YieldBlox on Blend V2

When
…
Loss
…
Cause
…

No borrower takes out more than their collateral is worth at a fair price

Documented by BlockSec, Halborn and Blockaid

Comet BLND-USDC pool

When
…
Loss
…
Cause
…

A same-asset swap is a no-op; reserves never fall without an outflow

Waiting for a primary post-mortem

Your incident next

Every case ships with four parts, and each release must rediscover all of them.

  • Ledger snapshot before the attack
  • Attack sequence
  • Invariant that catches it
  • Fixed contract
cargo soroquake lab apply yieldblox --target my_pool

Every pull request gets shaken.Five minutes on each PR, an hour every night.

soroquakeis shaking #128…

Running 12 invariants for 5 minutes

supply_matches_balancesrunning…
only_admin_sets_feerunning…
solventrunning…
#[test]
fn soroquake_solvent_0x5eed() {
    let s = setup(&Env::default());
    deposit(&mut s, ALICE, 3);
    accrue(&mut s, 1);
    withdraw(&mut s, ALICE, 1);
    assert!(solvent(&s).is_pass());
}
  • One workflow file

    Add soroquake/action@v1 and every PR gets a check and a comment.

  • A corpus that gets smarter

    Sequences that reached new code are cached between runs, keyed by your contract's code hash.

  • Findings where you review code

    SARIF upload puts broken invariants into GitHub code scanning next to the handler.

  • A badge that means something

    invariantsrunning

Everything a Soroban team needs to shake a contractbefore an attacker does.

Follow the build

Find the shortest sequence that breaks it.

fuzz/failures/solvent-0x5eed.seq

withdraw pays more than a fair share

  1. bobdeposit(40)
  2. alicedeposit(3)
  3. carolapprove(bob, 9)
  4. adminaccrue(1)
  5. bobwithdraw(12 shares)
  6. ledgeradvance(17 280)
  7. alicewithdraw(1 share)paid 2, fair 1
  8. +let payout = shares * assets / total;

50 calls · shrinking…

Shrinking and replayable failures

acme/vaultChecking 6 invariant packs…
  • sep41Checking…
  • ammChecking…
  • vaultChecking…
  • lendingChecking…
  • accessChecking…
  • ttlChecking…

Invariant packs

mainnet snapshotledger 58,214,903
vault instancefetching…
persistent: Shares(*)fetching…
USDC balancesfetching…
oracle pricesfetching…
Taking snapshot…read-only

Mainnet fork mode

Replay an incident before it replays you.

YieldBlox, Feb 2026 replay

Attack sequence

  1. 1deposit(USTRY, 50k)
  2. 2swap(thin pool) pushes USTRY price ×100
  3. 3borrow(USDC, max)
  4. 4withdraw collateral

Ledger state

USTRY price
$1.06
collateral value
$0
USDC borrowed
$0
Replaying from the pre-incident snapshot…

Exploit Replay Lab

Read how the lab works

Questions people ask first.

Can I use Soroquake today?

Not yet. The repository holds the spec and a first scaffold. The core engine (handlers, invariants, shrinking) is the first milestone; fork mode, the Replay Lab and the GitHub Action follow.

How is this different from cargo-fuzz?

Stellar's docs show how to hand-write a stateful fuzz harness for one contract. Soroquake is the reusable version: a handler and invariant API, multi-contract sequences, readable shrunk tests, a CI corpus, fork mode and ready-made packs.

What about Komet or Certora Sunbeam?

They prove properties formally and are great for the few that matter most. Soroquake is the fast, everyday loop that runs on every pull request. Use both.

Does it ever touch mainnet?

Fork mode reads a ledger snapshot taken with stellar snapshot create. Soroquake never signs or submits a transaction.

Other people have built Soroban fuzzers. Why another?

soroban-token-fuzzer covers SEP-41 tokens and yarobanza/soroban-fuzz is an early generic MVP. We credit both and focus on what neither has yet: multi-contract harnesses, coverage guidance, fork mode, incident replays and CI.

What does it cost?

Nothing. Everything is Apache-2.0, runs on your machine or your CI, and sends no telemetry by default.