JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

MEV: sandwich attacks, arbitrage, and the dark forest

Every block is a tiny auction for the right to reorder reality. Learn how bots extract value from your trades, work a sandwich attack and an atomic arbitrage by hand, and see how proposer-builder separation reshaped who profits.

A walk through the dark forest

In August 2020, two researchers — Dan Robinson and Georgios Konstantopoulos — published a post titled Ethereum is a Dark Forest. They had found a vulnerable contract holding real money and tried to rescue the funds before a malicious actor could. They wrote a clean rescue transaction and broadcast it. It never landed. A bot they had never heard of, watching the public waiting area where unconfirmed transactions sit, saw their transaction, copied its profitable payload, paid a higher fee, and got mined first. The bot took the money. The forest had eyes.

That waiting area is the mempool — the public set of pending transactions every node gossips around the network. The reason the bot could win is structural: a blockchain processes transactions in an order someone gets to choose, and that order has monetary value. The profit a block producer (or anyone who can influence ordering) can capture by reordering, inserting, or censoring transactions within a block is called maximal extractable value (MEV).

Three classic plays: arbitrage, liquidations, sandwiches

MEV is not one thing; it is a family of strategies run by specialised bots called searchers. Three plays cover most of the value, and they sit on a spectrum from benign to toxic.

  1. Arbitrage — when the same asset trades at different prices on two AMMs, a searcher buys low on one and sells high on the other in a single atomic transaction. This is generally benign: it pushes prices back into line and keeps DEX quotes honest. It builds directly on the constant-product formula you learned earlier.
  2. Liquidation racing — when a borrower's health factor drops below 1, the position becomes liquidatable and the protocol offers a bonus to whoever repays the debt. Searchers race to be the liquidator and pocket that bonus. Also broadly healthy: it keeps lending markets solvent (the topic of the previous guide).
  3. Sandwich attacks — a searcher spots your pending swap, trades just before and just after it to profit from the price your own trade creates, and leaves you a worse fill. This is toxic MEV: it is value taken directly from an ordinary user. We will dissect one next.

Anatomy of a sandwich: a worked example

Take a pool with 10 ETH and 20,000 USDC, so the invariant is k = x·y = 200,000 and the spot price is 2,000 USDC/ETH. A victim wants to buy ETH with 2,000 USDC and — crucially — sets a generous slippage tolerance, say 10%, so their transaction will not revert even at a much worse price. We ignore the 0.3% fee and gas to keep the arithmetic clean.

Baseline (no attacker). The victim's 2,000 USDC raises the reserve to y = 22,000, so x = 200,000 / 22,000 = 9.0909 ETH. They receive 10 − 9.0909 = 0.9091 ETH, an effective price of 2,200 USDC/ETH. Now watch what an attacker does to that fill.

  1. Front-run (buy). The attacker sees the victim's pending swap and inserts their own buy first, also spending 2,000 USDC. Reserves go to y = 22,000, x = 9.0909, and the attacker receives 0.9091 ETH. The pool is now (9.0909 ETH, 22,000 USDC) — price already pushed up to ~2,420.
  2. Victim executes. Their 2,000 USDC now raises y to 24,000, so x = 200,000 / 24,000 = 8.3333. The victim receives 9.0909 − 8.3333 = 0.7576 ETH — an effective price of 2,640 USDC/ETH instead of 2,200. The 10% slippage they allowed is exactly what let this through.
  3. Back-run (sell). The attacker now sells their 0.9091 ETH back. Reserves: x = 8.3333 + 0.9091 = 9.2424, y = 200,000 / 9.2424 = 21,639. They receive 24,000 − 21,639 = 2,361 USDC. Profit = 2,361 − 2,000 = ≈ 361 USDC, risk-free, minus gas. The victim lost roughly that same value.

The attack is only possible because the victim's transaction was visible in the mempool and their slippage tolerance was loose. The attacker even solves an optimisation: it sizes the front-run as large as possible without pushing the victim's price past their minimum-output limit, where the trade would revert and the sandwich would fail. Three transactions — front-run, victim, back-run — that must land adjacent and in that exact order. That ordering requirement is the whole game.

Atomic arbitrage and flash loans

Arbitrage is the benign engine of MEV. Suppose two ETH/USDC pools drift apart: Pool A holds 100 ETH / 200,000 USDC (price 2,000) and Pool B holds 100 ETH / 220,000 USDC (price 2,200). ETH is cheaper in A, so the searcher buys there and sells into B — all within one transaction that either fully succeeds or fully reverts.

Buy 2 ETH from A: k = 100·200,000 = 20,000,000; new x = 98, new y = 20,000,000 / 98 = 204,082, so it costs 4,082 USDC. Sell those 2 ETH into B: k = 100·220,000 = 22,000,000; new x = 102, new y = 22,000,000 / 102 = 215,686, so the searcher receives 220,000 − 215,686 = 4,314 USDC. Profit ≈ 4,314 − 4,082 = 232 USDC, risk-free and atomic, minus gas. (A real bot computes the optimal trade size where the two pools' marginal prices meet, capturing the maximum.)

Here is the magic of atomicity: the searcher need not own any capital at all. They can borrow the funds with a flash loan — an uncollateralised loan that must be borrowed and repaid within the same transaction — run the arbitrage, repay the loan, and keep the spread. If any leg fails, the whole transaction reverts and the loan was never really made.

// Atomic two-pool arbitrage funded by a flash loan (Solidity-style pseudocode)
function arb(uint amountUSDC) external {
    // 1. Borrow with no collateral; the lender calls back into this contract.
    flashLender.flashLoan(USDC, amountUSDC, abi.encode(amountUSDC));
}

function onFlashLoan(uint amountUSDC) external {
    require(msg.sender == address(flashLender));
    // 2. Buy ETH cheap on Pool A.
    uint ethOut = poolA.swap(USDC -> ETH, amountUSDC);
    // 3. Sell that ETH dear on Pool B.
    uint usdcBack = poolB.swap(ETH -> USDC, ethOut);
    // 4. Repay principal + fee; the WHOLE tx reverts if we can't.
    uint owed = amountUSDC + flashFee;
    require(usdcBack > owed, "unprofitable: revert, lose only gas");
    USDC.transfer(address(flashLender), owed);
    // 5. Keep the spread.
    USDC.transfer(searcher, usdcBack - owed);
}
Borrow, arbitrage, repay — all or nothing in one transaction. Note that the SAME flash-loan primitive, pointed at a manipulable price oracle instead of an honest arbitrage, becomes a flash-loan attack (the bZx and many oracle-manipulation exploits).

The auction underneath: from gas wars to PBS

If many searchers spot the same opportunity, how does the chain decide who wins? In the early days, brutally: a priority gas auction (PGA). Bots bid against each other by raising the priority fee (the tip to the block producer) in real time, because higher-paying transactions get ordered first. PGAs were loud and wasteful — losing bots still paid gas for reverted transactions, and the bidding spammed the network. The *Flash Boys 2.0* paper documented these auctions in the wild.

Two problems with the public-mempool PGA model. First, it leaks: posting your profitable bundle to the mempool invites others to copy it (the dark-forest problem). Second, it pushes MEV profits toward whoever runs the most sophisticated validator, threatening to centralise block production. The response was Flashbots and an architecture called proposer-builder separation (PBS).

Proposer-builder separation splits the job of making a block into two roles. Builders compete to assemble the most valuable block they can — packing in searchers' bundles — and attach a bid (how much they will pay the proposer). Proposers (the validators chosen to propose a block) simply pick the highest bid. On Ethereum today this runs out of protocol through software called MEV-Boost and trusted relays; an in-protocol version (enshrined PBS) is a future upgrade.

  1. Searchers send sealed bundles (e.g. an arbitrage or sandwich) privately to builders — never to the public mempool, so no one can copy them.
  2. Builders assemble full blocks, simulate them, and submit (block + bid) to relays.
  3. A relay holds the block body, verifies it is valid and pays what it claims, and shows the proposer only the header and the bid.
  4. The proposer signs the highest-bidding header (committing before it sees the body); the relay then reveals the body so it can be published. This commit-reveal stops the proposer from stealing the builder's MEV.

The effect is dramatic: around 90% of Ethereum blocks are now built via MEV-Boost. PBS democratises MEV — a small home validator earns nearly the same MEV-adjusted reward as a giant staking operation, because both just sell their block space to the same competitive builder market. That is a real win for decentralisation of proposing.

Defenses, and the trade-offs nobody escapes

Can you protect yourself? Partly. The honest headline is that MEV is a structural property of a public, ordered, permissionless ledger — you cannot delete it, you can only redistribute it, minimise the toxic forms, or change who captures it. Each defense buys that with a cost.

  1. Tight slippage limits. Setting a low maximum slippage (a strict minimum-output) makes most sandwiches unprofitable, because the attacker cannot move your price far before your trade reverts. Cost: in volatile or thin markets, honest trades fail more often.
  2. Private order flow. Send your transaction straight to builders through a private RPC (e.g. Flashbots Protect, MEV Blocker) instead of the public mempool, so no searcher ever sees it to sandwich. Cost: you now trust those builders, and concentrating order flow into a few private channels weakens the network's neutrality.
  3. Batch auctions. Protocols like CoW Protocol collect many orders and settle them together at one uniform clearing price, chosen by competing solvers. With no in-batch ordering advantage, sandwiching inside a batch is impossible, and matching opposite orders directly (a coincidence of wants) can beat the AMM price. Cost: added latency and reliance on the solver market.
  4. Encrypted mempools. Threshold-encrypt transactions (e.g. Shutter) so their contents are hidden until after ordering is fixed, then decrypted by a committee. A builder cannot reorder what it cannot read. Cost: extra latency and a new liveness assumption — the decryption committee must stay honest and online.

PBS itself has a dark side. Builder and relay markets have centralised: a handful of builders produce most blocks, and a few relays sit on the critical path. Because a relay can choose which transactions to include, OFAC-sanctioned addresses have at times been censored by compliance-filtering relays — a neutrality concern the community is fighting with inclusion lists and proposer-enforced ordering rules. And as Ethereum moves toward faster finality and restaking layers add new ways to bond capital, MEV keeps finding new surfaces — including cross-chain MEV, which is harder still because trades across chains are not atomic.