DEV Community

VerKron
VerKron

Posted on

I Built a White-Hat MEV Rescue Bot in Paper Mode. Here's What It Actually Proved.

Most MEV bots are built to extract. This one was built to rescue: watch the mempool, spot an exploit in flight, confirm it on a fork, and — in theory — frontrun the attacker with the same profitable plan, sweeping the value to a vault instead of the attacker's wallet.

Theory is the operative word. The bot has never sent a live transaction. It runs in paper mode only, on replayed transactions and fork simulations. That constraint turned out to be the most useful design decision in the project, because paper mode forces a question live trading lets you dodge: what do you actually know, versus what are you assuming?

The pipeline: four modules, one rule

The bot is four modules with a strict separation:

  1. Watcher — mempool intake, either a live read-only websocket or deterministic replay from JSONL. Every transaction is normalized and run through the detector.
  2. Detector — pure-function rules. Each finding carries a human-readable reason explaining why it flagged. A failing rule is isolated, never fatal.
  3. Simulator — an Anvil fork harness with impersonation and snapshot/revert. It errors on a bad RPC instead of hanging.
  4. Rescue — two paper strategies: frontrun_replay (replay the attacker's plan pre-attack, value to the vault) and circuit_breaker (automated pause/blacklist, measured against the dump schedule).

The governing rule: a filter that cannot be evaluated is reported as unevaluated, never silently passed. In security tooling, a silent pass is a false negative wearing a lab coat.

The honest finding: the detector did not generalize

I started with a rule set derived from BiFi. It caught BiFi, not the next three incidents. Each new case forced a new rule — and that failure to generalize is the project's most important result.

BiFi (Ethereum, ~$165.6K). Flagged by a combination of flash-loan, lending-loop, and oracle-manipulation signals, scoring 170 — a confirmed finding. The paper rescue replayed the inflated-interest plan on a pre-attack snapshot.

TIP (BSC, ~$68.5K). The Mango-markets shape: three or more DEX swaps plus a lending borrow in one atomic transaction. No oracle is manipulated, so the oracle rule stays silent. That forced R8, pump-and-borrow: count the swaps, check for the borrow, flag the combination.

Cysic (BSC, ~$727K). No flash loan, no lending loop. The vector was forged off-chain message-processing authorization — indistinguishable on-chain from a legitimate bridge mint. You cannot detect it by call path, because the call path looks normal. That forced R7, anomalous mint: flag when one transaction mints 5% or more of supply to one address. Detect the anomaly, not the mechanism.

# R7 in spirit: anomaly, not call-path matching
if minted_to_one_address / total_supply >= 0.05:
    flag("anomalous mint", severity="high")
    # A legit bridge mint can look identical on-chain.
    # This is a triage signal, not proof of an attack.
Enter fullscreen mode Exit fullscreen mode

GoldPesa (Base, ~$114.4K). A Uniswap v4 hook bug: the hook withdrew the whole unlock's net delta without checking its own deltas were isolated, and the attacker planted phantom debt in their own unlock in the same transaction. That forced R11, v4-hook shared-unlock accounting: the trigger is the combination — own unlock, attacker-side position, hook burn/re-mint — and the red flags are the hook's delta netting down against its expected credit, plus a position minted with zero payment in.

Case Chain Loss What flagged it
BiFi ETH ~$165.6K Flash-loan + lending + oracle signals
TIP BSC ~$68.5K R8: swaps + borrow in one tx
Cysic BSC ~$727K R7: anomalous mint
GoldPesa Base ~$114.4K R11: v4 hook unlock accounting

Eleven rules, 27 tests, all passing — but the real lesson is that the case library is the detector. Every new incident becomes a fixture and a test. A rescue bot that stops learning after its first incident is a museum piece.

The Cysic math: why automation matters more than cleverness

Cysic justifies the whole project — and limits it.

In the real incident, the human response was a blacklist after about 76 minutes, containing 2.8M CYS (~$283K) of the 7.2M CYS (~$727K) moved. In paper simulation, an automated pause() at T+30 seconds freezes the full amount.

That 76-minutes-to-30-seconds gap is a latency gap, and latency is automatable. But a third-party white-hat cannot pause someone else's token: the Cysic circuit-breaker only works for the protocol itself or a delegated pauser. For everyone else, only the frontrun-replay shape applies.

So the honest pitch is narrower, and better: this bot is most valuable to protocols, as a delegated pauser and pre-deployed rescue plan, not as a lone wolf racing attackers in the public mempool.

What paper mode does not prove

Paper mode proves the patterns are detectable and the rescue mechanics work in simulation. It does not prove six things live operation needs:

  1. Speed. Paper has no latency budget. Live needs mempool-to-flag-to-simulation-to-bundle in roughly one block: 12 seconds on Ethereum, 1.5 seconds on BSC. That means colocated infrastructure and a paid mempool feed, not a public websocket.
  2. Adversarial ordering. Paper assumes the white-hat lands first. Live competes with other searchers. Winning needs private relays — Flashbots on Ethereum, 48 Club or BloXroute on BSC — and bribes, typically 10–50% of rescue value. The simulator's rule is to abort unless profit is at least twice gas plus bribe.
  3. Archive state. Free RPCs do not serve the archive state a fork simulation needs. Live needs paid archive access or a self-hosted Erigon node.
  4. Authorization. As above: pausing requires the protocol's permission. Without it, half the playbook does not exist.
  5. Bounty negotiation. Rescue is not revenue. Protocols typically offer 10–20%, negotiated after the fact. In BiFi's case, a white-hat returned 159,103 USDC. The bot needs a human operator who can do that negotiation; code cannot.
  6. Capital. Gas float plus bribe budget. Attack capital itself can come from flash loans, but the float cannot. A realistic BSC-first minimum viable live setup is under $100 plus a $50 BNB float.

None of this is a reason not to build. It is a reason to build in the right order: case library first, live watcher in read-only mode for two weeks to measure flag rate and false positives, and no bundle submitted until the profit gate and a human in the loop are in place for the first ten rescues.

The takeaway

If you are building detection tooling, do not ask whether your rules generalize. Assume they do not, and build the system that makes adding the next rule cheap: replayable fixtures, isolated rules, unevaluated-never-passed discipline, and a fork harness that fails loudly instead of hanging.

The exploits will keep inventing new shapes. The Cysic mint looked legitimate. The GoldPesa hook bug lived in accounting most auditors would skim past. Your detector will miss the next one too — unless the pipeline learns from it in hours, not rewrites.

That is what paper mode bought me: not a proven money machine, but a learning machine with receipts.

Paper mode only. No live transactions, no real funds. Figures are from post-mortems and fork simulations, not live rescues.

Top comments (1)

Collapse
 
bloqarl profile image
Carlos (Bloqarl) •

Nice write-up, and "the case library is the detector" is an honest result. One thing that might help with the latency problem: a lot of exploits deploy the attack contract in its own tx first, sometimes blocks before the attack. That's a window you can watch, and since you have the bytecode you can run it on your fork before it fires. The other thing paper mode can hide: attackers often gate the exploit function on msg.sender or tx.origin so nobody can copy the call, so a frontrun replay usually means rebuilding the plan in your own contract. In your four cases, was the attack contract deployed separately before the exploit tx?