Logo
New RPC users get 35% off their first monthView the offer
OnFinality Learn
Network & Protocol Guides11 min read

MEV in Crypto: How Maximal Extractable Value Works and How to Measure It

A technical guide to MEV in crypto: how transaction ordering creates extractable value, how searchers, builders, and validators interact, and how to measure ordering effects on your own RPC traffic.

TL;DR

MEV (maximal extractable value) is the profit that can be captured by choosing which transactions enter a block, in what order, and which are excluded, beyond standard block rewards and gas fees. In crypto it is not a single attack but an economic layer that sits on top of block production: searchers detect opportunities, builders assemble blocks, and validators or sequencers finalize them. This article explains the mechanism, walks through a reproducible way to measure ordering effects on your own RPC traffic, and separates documented protocol behavior from measurements you must run yourself. It closes with troubleshooting and the tradeoffs of different mitigation approaches.

What MEV Means in Crypto and Where It Comes From

Maximal extractable value (MEV) is the maximum value that can be extracted from block production in excess of the standard block reward and gas fees by including, excluding, or reordering transactions within a block. The term began as "miner extractable value" under proof-of-work, when miners controlled transaction inclusion and ordering. After networks moved to proof-of-stake, validators took over those roles, so the broader term is now standard. The underlying mechanism did not change: whoever controls ordering controls a small but economically meaningful degree of freedom over execution.

That degree of freedom exists because block space is scarce and transactions are not commutative. A swap that moves a pool price, a liquidation that flips a health factor, or a mint that sells out a supply cap all produce different outcomes depending on what executes before and after them. MEV is the monetization of that non-commutativity. It is not inherently malicious; arbitrage that closes price gaps between venues is MEV too, and it improves market efficiency even as it competes for the same ordering rights.

  • Ordering: placing a transaction before or after another to change its economic result.
  • Inclusion: deciding whether a profitable or unprofitable transaction enters the block at all.
  • Exclusion: censoring or delaying transactions, which can itself be profitable.
  • Block space scarcity: the constraint that makes ordering valuable in the first place.

Assumptions and Prerequisites for This Guide

This article assumes you understand how transactions enter a mempool, how gas or priority fees influence inclusion, and how blocks are produced on at least one EVM chain. You should be comfortable calling JSON-RPC methods and reading raw transaction and receipt objects. The measurement procedure uses a standard Ethereum-compatible JSON-RPC interface, so it works against any endpoint that exposes eth_getBlockByNumber with full transaction bodies.

Two boundaries matter. First, documented protocol behavior (what a client or spec guarantees) is separate from observed behavior on a specific network at a specific time; the latter must be measured. Second, this page does not recommend a specific endpoint or provider. For the concrete choice of an RPC endpoint, use the RPC Assistant, which covers endpoint and provider selection directly.

The MEV Supply Chain: Searchers, Builders, and Validators

In theory all MEV accrues to the block producer, because only the producer can guarantee that a profitable transaction lands. In practice most detection and execution is done by independent participants called searchers, who run algorithms over pending and historical chain data to find opportunities and submit transactions or bundles that capture them. Searchers compete on speed and on how much of the profit they are willing to pay for inclusion, so a large share of gross MEV is passed upward as priority fees or builder payments.

On networks with a proposer-builder separation (PBS) design, builders assemble candidate blocks from bundles and bid for the right to have their block proposed. Validators (or sequencers on rollups) select among bids. This separation is what makes MEV measurable as a market: bids, bundles, and payments are observable artifacts rather than private miner decisions. On networks without PBS, the producer performs both roles and the market is less transparent.

  • Searchers: detect opportunities and submit transactions or bundles.
  • Builders: merge bundles into a candidate block and bid for inclusion.
  • Proposers/validators/sequencers: select and finalize the block.
  • Users: supply the order flow that creates the opportunities, and bear much of the cost.

Common MEV Strategies and What They Do to Users

DEX arbitrage is the most benign and most competitive category: a searcher trades against a pool whose price has drifted from another venue and captures the spread. Liquidations are similar in structure, rewarding the first keeper to repay an unhealthy loan. Generalized frontrunning copies any profitable pending transaction and resubmits it with a higher fee. Sandwiching is the strategy users feel most directly: a searcher buys ahead of a large swap, lets the victim's trade move the price, then sells immediately after, capturing the slippage the victim was willing to tolerate.

The user-facing cost of sandwiching is bounded by the slippage tolerance set on the swap. A tighter tolerance reduces the extractable amount but increases the chance of failure. This is a genuine tradeoff, not a setting that can be optimized away, and it is why slippage and MEV are usually discussed together.

A Mental Model: MEV as an Ordering Auction

The cleanest way to reason about MEV is to treat each block as a small auction over transaction order. Every participant who can influence order submits a bid in the form of a fee or a bundle payment. The winning order maximizes the producer's revenue, which is not necessarily the order that maximizes user welfare. MEV is therefore the gap between the revenue-maximizing order and the order users would have chosen.

This model explains several observed patterns. Competition drives searcher margins toward zero while total payments to producers stay high. Opportunities that are easy to detect attract many searchers and therefore high fee competition. Opportunities that require proprietary data or capital attract fewer participants and retain more margin. When you measure MEV, you are really measuring the size of this auction on the traffic you observe.

Measuring Ordering Effects on Your Own RPC Traffic

You cannot infer MEV on your traffic from a single transaction. You need the block context: which transactions executed before and after yours, and what the pool state was at each step. The procedure below pulls recent blocks with full transaction bodies, extracts swaps against a target pool, and records the ordering of each transaction within its block. Run it against an endpoint you control or trust, and record the block range and timestamp so results are reproducible.

The script uses only standard JSON-RPC methods. Replace RPC_URL with your endpoint and POOL with the pool contract you care about. It does not claim to detect every MEV pattern; it produces the ordering data you need to analyze them.

import os, json, urllib.request

RPC_URL = os.environ.get("RPC_URL", "RPC_URL")
POOL = os.environ.get("POOL", "0x0000000000000000000000000000000000000000")
SWAP_TOPIC = "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"  # Uniswap V2 Swap

def rpc(method, params):
    req = urllib.request.Request(
        RPC_URL,
        data=json.dumps({"jsonrpc": "2.0", "id": 1, "method": method, "params": params}).encode(),
        headers={"Content-Type": "application/json"},
    )
    with urllib.request.urlopen(req, timeout=30) as resp:
        body = json.loads(resp.read())
    if "error" in body:
        raise RuntimeError(body["error"])
    return body["result"]

latest = int(rpc("eth_blockNumber", []), 16)
start = latest - 20
rows = []
for n in range(start, latest + 1):
    block = rpc("eth_getBlockByNumber", [hex(n), True])
    if not block or not block.get("transactions"):
        continue
    for idx, tx in enumerate(block["transactions"]):
        to = (tx.get("to") or "").lower()
        if to != POOL.lower():
            continue
        rows.append({
            "block": n,
            "tx_index": idx,
            "tx_hash": tx["hash"],
            "from": tx["from"],
            "gas_price": int(tx.get("gasPrice", "0x0"), 16),
        })

print(json.dumps(rows[:50], indent=2))
print(f"blocks_scanned={latest - start + 1} pool_txs={len(rows)}")

Verifying the Measurement and Recording Results

A successful run prints a JSON array of pool transactions with their block number and intra-block index, followed by a summary line. Verify the output against a block explorer for one or two blocks: the transaction hashes and indices should match exactly. If they do not, your endpoint is returning a different view of the chain, which is itself a finding worth recording.

Record results in a table so runs are comparable across endpoints and time windows. Do not fill in numbers you have not measured; leave cells empty until a run produces them. A useful template is below.

  • | Run | Endpoint label | Block range | Pool txs | Median intra-block index | Notes |
  • |-----|----------------|-------------|----------|--------------------------|-------|
  • | 1 | RPC_URL (A) | latest-20..latest | (measured) | (measured) | baseline |
  • | 2 | RPC_URL (B) | same range | (measured) | (measured) | compare consistency |

Diagnostic Procedure: Comparing Two Endpoints

If you suspect your endpoint is giving you a stale or reordered view of pending or confirmed transactions, run the same block range against two endpoints and diff the results. The script below compares transaction hashes and indices per block. Divergence on confirmed blocks indicates a consistency problem; divergence on pending data is expected and should not be treated as a fault.

This is a diagnostic, not a benchmark. It tells you whether two endpoints agree on confirmed state, not which one is faster or more reliable under load. For performance questions, measure latency and error rates separately over a controlled window.

const RPC_A = process.env.RPC_A || "RPC_URL";
const RPC_B = process.env.RPC_B || "RPC_URL";

async function call(url, method, params) {
  const res = await fetch(url, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
  });
  const body = await res.json();
  if (body.error) throw new Error(JSON.stringify(body.error));
  return body.result;
}

async function compareBlock(n) {
  const [a, b] = await Promise.all([
    call(RPC_A, "eth_getBlockByNumber", ["0x" + n.toString(16), false]),
    call(RPC_B, "eth_getBlockByNumber", ["0x" + n.toString(16), false]),
  ]);
  const ha = a.transactions.join(",");
  const hb = b.transactions.join(",");
  return { block: n, match: ha === hb, countA: a.transactions.length, countB: b.transactions.length };
}

(async () => {
  const latest = parseInt(await call(RPC_A, "eth_blockNumber", []), 16);
  const results = [];
  for (let n = latest - 10; n <= latest; n++) results.push(await compareBlock(n));
  console.table(results);
})();

Troubleshooting Common Measurement Problems

Most failed MEV measurements come from four causes: the endpoint does not return full transaction bodies, the block range is too small to contain any relevant activity, the pool address or event topic is wrong, or the endpoint is load-balanced across nodes with slightly different views. Each has a distinct symptom and fix.

If eth_getBlockByNumber returns transactions as hashes only, pass true as the second parameter. If the scan returns zero pool transactions, widen the range and confirm the pool address and event topic against a known transaction. If two endpoints disagree on confirmed blocks, treat it as a consistency incident and re-run after the endpoints resync. If results vary between runs on the same range, your endpoint is likely routing to different backends.

  • Empty transaction arrays: check the boolean parameter and block number encoding.
  • Zero matches: verify pool address checksum and event topic.
  • Inconsistent results: pin a single endpoint or use a dedicated node.
  • Timeouts: reduce the block range and add retry with backoff.

Limitations, Tradeoffs, and Mitigation Approaches

Ordering data alone does not prove intent. A transaction that appears sandwiched may be a legitimate arbitrage that happened to bracket another trade. Attribution requires bundle-level data, builder APIs, or heuristics that are outside standard JSON-RPC. Treat any MEV estimate from raw block data as a lower bound with false positives.

Mitigations trade off differently. Tighter slippage reduces sandwich profitability but increases failed swaps. Private transaction relays reduce frontrunning exposure but concentrate trust in the relay operator. Encrypted mempools and fair sequencing aim to remove ordering advantages at the protocol level but change latency and inclusion guarantees. Batch auctions and intent-based routing shift the problem from ordering to solver competition. None of these eliminates MEV; each moves where it is captured and who bears the cost.

Next Steps: Instrumentation and Infrastructure Choices

To go further, extend the measurement to bundle-level data where the network exposes it, track priority fee distributions per block, and correlate them with pool activity. Keep a fixed block range and endpoint label for every run so results remain comparable. If you need consistent, low-variance access to confirmed and pending data, a dedicated node removes the load-balancer variance that confuses endpoint comparisons; see the dedicated node options and the RPC pricing overview before committing to a plan.

For endpoint and provider selection specifically, use the RPC Assistant rather than guessing. For background on how nodes and RPC layers fit together, the blockchain node hosting guide and the RPC endpoints guide are useful companions. If you are working across multiple chains, the multi-chain RPC endpoints guide covers the operational differences that affect MEV measurement.

  • Pin one endpoint per measurement run and record its label.
  • Store raw JSON output alongside the summary table for reproducibility.
  • Re-run the same block range after any endpoint change.
  • Separate consistency checks from latency and throughput tests.

Never Worry about Infrastructure Again

OnFinality takes away the heavy lifting of DevOps so you can build smarter and faster.

Get Started