Crypto OS
Technical Crypto OSStage 4 · DeFi Engineering

T24 · MEV

Who saw your transaction before it entered a block?

Capabilities practiced
BuilderProtocol Literacy
Hands on
Sandwich your own trade in a fork environment and quantify the user's loss.
AI Lab
Have AI list user-side protections and assess, one by one, whether each is feasible in your product.

A Real-World Problem

Two months after your swap interface launches, users repeat one complaint: “The execution price is always a little worse than your quote.”

You check every item from T20. Quotes use current reserves, routing chooses the best path, minimum output is in the user's signature, and there is a deadline. Crucially, trades do not revert. Slippage protection works; users receive at least their signed minimum.

Then you open one trade in a block explorer.

It is transaction 47 in its block. Transactions 46 and 48 have the same sender and touch the same pool: one buys, one sells, and your user is between them.

Replay the three locally and calculate the user's shortfall. The number is familiar: almost exactly the front end's default slippage tolerance.

The user was not tricked. The contract has no bug. Every check passed. Their transaction was simply placed in the middle.

The real question is: who chose the order of those three transactions, and why?

Thought Experiment

Shrink a blockchain to a village.

At its entrance stands a public notice board. Anyone wanting a task done posts a note. Every twelve seconds a packer takes a batch of notes and completes them in whatever order they choose.

Those two rules imply three things.

First, the board is public before the work is done. Your note says what you want to buy, how much, and the worst price you accept. The whole village can read it before execution. This is not a leak; publicity lets others verify the packer followed the rules.

Second, the packer chooses the order and may add their own note. They can put yours at position 47 and their own just ahead.

Third, they do not have to act personally. They can announce: “Whoever pays most gets the first position in the next batch.”

The third rule changes everything. “Who goes first” becomes something with a price, an auction, and willing buyers, not a mere technical detail.

Three businesses appear. For now, leave them unnamed:

A sees the same item sold at different prices on two stalls. They buy at the cheap stall and sell at the expensive one. Prices converge, seemingly without harm, but the price difference came from the people stocking the stalls.

B sees your note announcing a large buy. They buy first, let your order push the price higher, then sell to you. Your visible intention creates their profit.

C sees collateral just cross the seizure threshold from T22 and races everyone else to take the reward.

All three share one important property: none requires an exploit. Every action is permitted and every check passes.

They exploit the structure of the system, not a mistake in its code.

Your Decision

The user has signed. Your code must now send the transaction.

Where do you send it?

What Happens

Each option asks how long and to how many parties the intent is visible, and who may profit from that visibility.

ApproachWho sees the intent?Whom do you trust?Main costFailure mode
Public mempool, tight toleranceEveryoneNo new partyHigh failure rateRepeated failure pressures users to widen it
Public mempool, wide toleranceEveryoneNo new partyInvisible extractionPersistent user loss goes unnoticed
Private channelOne operatorOperator's promiseNew counterpartyBroken promise is hard to verify
Intent and executor auctionGroup of executorsStrength of competitionDelay and concentrationWeak competition quietly worsens prices

The trust column carries the lesson:

MEV cannot simply be eliminated; it can be shifted. Each defense changes who may profit from your transaction's order instead of making that value zero.

Any claim that a particular service makes you “safe” leaves out the new party whose behavior you now depend on.

A second lesson is a calculable threshold for whether an attacker targets a trade:

Attacker gross gain ≈ trade amount × slippage room they can use
Attacker cost ≈ fees on two swaps + gas on two transactions + bid for position

Positive net gain: act. Zero or negative: ignore the trade.

Read this in reverse: your slippage tolerance is the bounty you post. Multiplying tolerance by trade size gives the prize. Once it exceeds attack costs, the trade becomes a target.

Thus, transaction ordering is itself a saleable resource.

No software version can patch that away. Somebody must decide the order. You can only measure its value and identify who receives it.

Build a Model

1. Who has seen your transaction?

  1. Your front end
  2. Wallet
  3. RPC provider
  4. Public mempool
  5. Searchers
  6. Block builder
  7. Block proposer
  8. Block inclusion
From left to right, each stage has seen the whole transaction. Any stage can withhold it, delay it, or act first.
StageWhat it seesWhat it can doCan you verify?
RPC providerFull transactionDelay forwarding or share itNo
Public mempoolFull transactionMake it globally readableYes; that is its purpose
SearcherFull transactionConstruct sandwiches, frontruns, or arbitrageNo
Block builderFull transaction and bidsChoose final orderingAfterward, not beforehand
Block proposerAssembled blockAccept or replace itAfterward

The first row is often ignored. People assume skipping the public mempool is enough, but an RPC provider sees the transaction first. It is directly configured in your code and rarely examined.

2. Four forms with two different properties

FormWho provides its profit?What if nobody does it?Does the user lose?
ArbitrageLiquidity providersPrices across markets remain differentNo, though LPs lose
LiquidationLiquidated userT22-style bad debtNo; the bonus was already owed
FrontrunningTransaction senderNothing specialYes
SandwichTransaction senderNothing specialYes

The third column divides them:

The first two are work someone needs to do. Without arbitrage, market prices diverge. Without liquidation, lenders accumulate bad debt. They extract value that already exists, though someone captures it.

The last two exist only because your transaction is visible. If nobody acts, the loss does not exist. It is a newly created cost borne entirely by the sender.

Use this distinction when judging an MEV remedy. Moving arbitrage proceeds from A to B does not help the user; reducing frontrunning and sandwiches does.

3. Sandwich arithmetic: your tolerance sets the attack size

You can calculate this section completely. For a constant-product pool from T19, these functions need no external library and can go straight into a test:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// Constant-product quote, with feeBps charged on input; a typical value is 30
function getAmountOut(
    uint256 amountIn,
    uint256 reserveIn,
    uint256 reserveOut,
    uint256 feeBps
) pure returns (uint256) {
    uint256 inAfterFee = amountIn * (10_000 - feeBps);
    return reserveOut * inAfterFee / (reserveIn * 10_000 + inAfterFee);
}

/// Difference in user receipts without and with a sandwich
/// This subtraction is the number you will measure yourself
function sandwichLoss(
    uint256 userIn,
    uint256 attackerIn,        // Amount supplied by attacker's first trade
    uint256 reserveIn,
    uint256 reserveOut,
    uint256 feeBps
) pure returns (uint256) {
    uint256 clean = getAmountOut(userIn, reserveIn, reserveOut, feeBps);

    // Attacker buys first, moving reserves
    uint256 got = getAmountOut(attackerIn, reserveIn, reserveOut, feeBps);
    uint256 newIn = reserveIn + attackerIn;
    uint256 newOut = reserveOut - got;

    // User executes farther along the moved curve
    uint256 sandwiched = getAmountOut(userIn, newIn, newOut, feeBps);
    return clean - sandwiched;
}

How does the attacker choose attackerIn? They face one hard constraint: the minimum output in the user's signature. Push too far and the user's trade reverts; the attacker's trades then cost fees without the intended gain.

The optimal target is clear:

Optimal attackerIn = the amount making sandwiched exactly equal amountOutMin

Therefore:
    Maximum user loss = trade amount × slippage tolerance
    The attacker aims to take precisely that maximum, no more or less

Pause on that point. The attacker need not guess. Your tolerance tells them how much to trade. Moving from 0.5% to 5% multiplies the target gain by ten.

Whether they act depends on costs:

Gross gain ≈ user loss - pool fees on the attacker's own two swaps
Cost ≈ gas for two trades + bids to surround the user

Act only when net profit is positive.
So there is a minimum attackable size; below it, nobody bothers.

The Lab calculates that minimum. It is more useful than a generic defense tip because it identifies which trade sizes are at risk.

4. Three defenses and the authority each grants

MethodWhat it reducesWho gains authority?What cannot you verify?
Tighten toleranceExtractable valueNobody newNothing new; it adds no trust
Private channelExposureChannel operatorWhether it inspected or resold the opportunity
Intent with competing executorsExposure and returns some proceedsExecutor groupWhether competition remains strong

The second column distinguishes reducing the value available to extract from reducing the number of people who see it. The first requires no new trust; the second inevitably adds a counterparty.

In practice, combine the three. A reasonable default dynamically sets tolerance from trade size and pool depth, sends large trades through a private channel or competitive execution, and shows estimated price impact clearly to users. The last costs nothing yet many products omit it.

What It Is Called

MEVMaximal extractable value

Extra value obtainable by choosing which transactions enter a block, which are omitted, and their order.

The keyword is ordering, not exploits. No version removes it, because someone must order transactions. Your task is to measure that value and identify who receives it now.

ArbitrageArbitrage

Profit from a price difference between venues.

It is the one form here with a clear positive externality: prices across fragmented markets converge. But its profits come from liquidity providers. Much LP impermanent loss appears in this form.

SandwichSandwich attack

Trades placed before and after a user's transaction to move price to the edge of their tolerance and capture the difference.

Unlike arbitrage, this loss is created, not simply transferred. Without the attack it would not exist. The user's own tolerance determines its ceiling.

OrderingOrdering rights

The power to choose the sequence in which a batch of transactions executes.

It is this chapter's central resource. Once it can be sold, a supply chain appears: searchers find opportunities, builders assemble blocks, and proposers sell positions. Ordering has value, and valuable resources develop markets.

Private MempoolPrivate mempool

A channel delivering transactions to block producers without public broadcast.

It trades “visible to everyone” for “visible to one operator.” That reallocates trust rather than erasing risk. Before using one, ask who operates it, what they promise, what enforces the promise, and whether you would detect a breach.

SolverSolver

A competing participant who finds and executes a way to fulfill a user's intent.

Competition for ordering value can return part of it to the user as better execution. The cost is a naturally concentrated executor layer needing capital, infrastructure, and algorithms. Ask where solver revenue comes from; the answer exists even if documentation omits it.

Hands-on

Hands onSandwich your own trade on a fork and quantify the user's lossFork environment and any contract test frameworkFree, entirely on a local fork

The Lab's output is a number you measured, not merely an explanation. Afterward you should know how much a 10,000-unit swap loses under your product's default settings.

Prepare the environment and align the quote first.

Fork a chain locally, choose a constant-product pool, and record both reserves and its fee rate. Copy getAmountOut above into the test. Compare its result with the pool's actual call. The values must match exactly, down to the last unit. Any mismatch means rounding or fee placement is wrong; revisit T19's rounding table. Every later loss calculation depends on this baseline.

Run a clean baseline, then one sandwich. Have a test address swap 10,000 in pool units and record its actual receipt as clean, the denominator for later comparisons.

Then execute three trades in order within one block:

Trade 1  Attacker buys amount a       ← lifts the price
Trade 2  User swaps                   ← executes on the moved curve
Trade 3  Attacker sells everything bought in Trade 1

Record the user's receipt (sandwiched), the attacker's final receipt, and their profit over input. User loss is clean minus sandwiched. Convert it to a percentage and put it beside your default slippage tolerance.

Scan for the optimal attacker size.

Fix user size and tolerance and sweep a from small to large. Record user loss and attacker net profit at each point. User loss rises with a until the user's minimum-output check fails. Attacker profit first rises and then falls: push too far and the user reverts, leaving the attacker paying fees for nothing.

Find the a that maximizes profit. Check whether the user's output at this a nearly equals the signed minimum. If it does, you have demonstrated directly that user tolerance defines the attacker's profit target.

Fill a two-dimensional table.

Put tolerance on one axis and trade amount on the other. In each cell record user loss as a percentage and attacker net profit.

                0.1%      0.5%       1%        5%
   1,000        ...       ...       ...       ...
  10,000        ...       ...       ...       ...
 100,000        ...       ...       ...       ...

Draw a boundary around cells where attacker profit is positive. Below and to the left is “safe,” not because of a special defense but because the trade is not worth attacking.

Calculate attack cost and the minimum attackable size. This is the chapter's quantitative exercise.

Known: depth D on one side, pool fee f, user tolerance s, gas price g

Step 1: Use optimal a from the scan to calculate gross attacker gain
        Gross gain ≈ user loss - fees on the attacker's two swaps
        (They pay f twice; many estimates omit this.)

Step 2: Calculate costs
        Gas for two swaps = 2 × gas per swap × g
        Ordering bid = gross gain given up to get before and after the user
                       (conservatively estimate half the gross gain)

Step 3: Net profit = Step 1 - Step 2

Step 4: Set profit to zero and solve for user trade size V
        V is the minimum attackable size in this pool at this tolerance

Calculate V, then make three comparisons:

  1. Multiply gas price by ten and recalculate. Congestion raises V substantially, making small trades safer.
  2. Change tolerance from 5% to 0.5% and see how V changes.
  3. Measure what share of your actual product trades exceed V.

The third turns abstract risk into a percentage you could report to the team.

Try another defense and record its cost.

Simulate a private channel on the fork by omitting Trades 1 and 3 and executing only the user's trade. Loss falls to zero. The useful part is answering:

QuestionYour answer
Who operates this channel?
What exactly do they promise, and where?
What enforces the promise?
Could you detect a breach?
What happens when the channel goes down?

If you cannot fill every row, the defense is incomplete. It introduces a new counterparty rather than merely flipping a switch.

Use only a local fork and attack only your own test address. Never connect real funds. Real funds enter only the capstone after Stage 5 security acceptance.

AI Lab

AI LabAsk AI for user-facing defenses and assess each one against your productLevel 2 · AI Copilot

Ask in three steps; the second and third are most valuable:

Step one:
List user-facing MEV defenses for an onchain swap product. For each, say
whether it reduces extractable value or exposure, its implementation cost,
user experience impact, and the party to whom it transfers trust.
List fully before recommending anything.

Step two:
My product has (fill in): user scale, trade-size distribution, chain,
default slippage tolerance, and RPC source. Assess each option's feasibility
and give measurable expected effects and measurable costs.

Step three:
For your top two recommendations, state when each fails, what signal I can
observe on failure, and the fallback if its provider stops operating.

Models often list the options in step one, but treat “use a private channel” as a complete solution. Ask who operates it and what enforces its promise. In step two, reject vague “significant reduction” claims. Ask how much of your actual trade distribution is covered and how much loss is avoided. Without numbers, this is not an assessment.

Step three gives a general test for any protection: when does it fail, and how will I know? A control whose failure is invisible can be worse than no control if it leads you to relax other safeguards.

Compare every step-two recommendation with your Lab's two-dimensional table. Does it cover the cells where your real trades fall?

Verify these points yourself after using AI

  • For every defense, does it identify who gains authority? Without the new trust party, assessment is incomplete
  • Does it distinguish reducing extractable value from reducing exposure? They are different
  • Is its slippage advice a fixed percentage or a formula responsive to size and pool depth?
  • Does it treat a private channel as a final answer instead of a trust reallocation?
  • For intent and executor auctions, does it say where executors earn revenue?
  • Does it recognize the RPC provider as a party that sees transactions?
  • Did you verify every named service, interface, and parameter it offers rather than trusting memory?

Real-World Case

Sandwiching is a full-time businessOngoingAny chain with a public mempool

On public mempools, sandwiching is an industry: some participants scan for targets, others optimize position bidding, and still others supply capital.

Its scale can be measured directly. This is one of the few parts of the industry whose actions are publicly reconstructable from onchain history.

For a product team, the point is concrete: default tolerance is not just a user-experience setting. It is a public variable read and priced by professionals in real time.

A private-channel promise is broken2023A major public chain

A group of block proposers was expected to include a searcher's submitted content unchanged. After receiving the block, they replaced transactions and captured the opportunity themselves. The sum involved was large.

The useful lesson is not its exact size. Private-channel protection is a promise, not a cryptographic guarantee. It depends on a party following rules even when violating them pays handsomely.

Recall the Lab table's question about enforcement. For many channels, the real answer is reputation. Reputation can be cashed out against one sufficiently large opportunity.

A chain with one sequencerOngoingSeveral layer-two networks

Some layer-two networks let one sequencer determine transaction order. There may be no public mempool and fewer public sandwich opportunities.

But ordering power remains concentrated in one process. It sees every transaction and chooses every order, while users have little ability to verify its internal choices.

This is a clear case of relocation, not removal: risk changes from “unknown strangers can sandwich me” to “I trust one operator.” Which is preferable depends on the failure you are willing to accept and should be decided explicitly.

Users ultimately pay for liquidation competitionAll onchain lending and perpetual protocolsOnchain

Return to T22's last stage. Ten liquidators discover one opportunity; one wins and nine pay for failed attempts.

Those costs enter each liquidator's calculation. To remain profitable after expected failed attempts, they demand a larger liquidation bonus, paid by the liquidated user.

Thus the cost of competing for order appears indirectly as a harsher liquidation penalty on ordinary users. This path is less visible than a sandwich but still MEV's user impact.

Change One Variable

What ifSend every trade privately and never use the public mempool

Public sandwiches disappear, execution improves, and support complaints may fall.

Record three new risks. First, a new single point of failure: if the channel goes down, the product either stops or silently falls back to the public mempool. Silent fallback is worse because users think protection remains. Second, the operator sees everything, without verifiable limits on its behavior. Third, arbitrageurs also stop seeing the trade, which can slow price discovery in some settings.

Fallback must be explicit, observable, and visible to users. Quietly reverting to an unprotected path is worse than an outright failure.

What ifMove to a chain with 0.4-second blocks

At first glance, exposure time falls thirtyfold.

Two things change. Attackers have less reaction time, favoring faster infrastructure and fewer participants. But those remaining may compete more fiercely, while fewer transactions fit each block and a front position can become scarcer and more valuable.

More importantly, recalculate every time or block-count assumption: expiry, tolerance, and expected inclusion time depend on the chain's cadence. The conclusion matches T21 and T22: derive time-related parameters again after moving chains.

What ifUse batch auctions so all orders in an interval clear at one price

This changes the mechanism itself. Within one batch, there is no before and after, removing a sandwich's prerequisite.

Three costs appear. Latency while waiting for the batch; slower price discovery because one clearing price may be stale during sharp moves; and a valuable batch boundary, where inclusion in this batch versus the next becomes worth competing for.

Mechanism design often works this way: removing one extractable position creates another scarcity elsewhere. Judge the change by whether the new one is materially less valuable.

What ifCalculate tolerance dynamically from trade size and pool depth instead of using a fixed value

Of these methods, this is the only one requiring no new trusted party, and it is inexpensive frontend arithmetic.

Small trades can use looser tolerances because their profit will not cover attack costs. Large trades tighten automatically and, beyond a threshold, prompt splitting or a different execution route.

The hard part is knowing pool depth in real time. That returns you to T17 and T18: use a reliable indexer and real-time channel, not stale cache. A tolerance calculated from stale depth is more dangerous than a fixed one, because it appears intelligent.

Takeaway Questions

5
Who is paying?

The most important cost here is hidden: users pay for transaction ordering through a worse execution price, absent from any invoice. It appears as a slightly poorer rate and usually goes unnoticed.

A useful habit: when you see “zero fees” or “gas-free,” ask who owns the ordering right. Removing visible fees often just moves the cost.

6
Where does revenue come from?

Every layer in the MEV chain has a revenue source: searchers earn spreads, builders collect bids, proposers sell position, private channels earn fees or revenue share, and executors retain auction surplus.

Draw the chain and write “how do they earn?” at each step. Any step you cannot explain is a piece of the proposed solution you do not yet understand.

9
Who bears the risk?

Risk appears in three places with different visibility: users receive worse prices invisibly, LPs lose some value to arbitrage with partial visibility, and protocols lose reputation and users only later.

The first matters most: these losses occur in “successful transactions.” Users report failures, not a 5% extraction hidden inside success. A team relying only on support tickets will miss this category entirely.

10
What is the incentive?

The incentive is plain: if order has value, someone will pay for it. That follows from rational behavior, not necessarily malice.

For any protection depending on people obeying rules, ask: what if a one-time gain from breaking the rule exceeds the future gain from keeping it? The 2023 case supplies an answer.

Chapter Check

Key idea

Transaction order is itself a resource that can be sold.

Finished this chapter’s lab? Mark it completeView all progress

On this page