Logo
New RPC users get 35% off their first monthView the offer
OnFinality Learn
Performance & Optimization12 min read

MEV Extraction: Measurement, RPC Infrastructure, and Operational Workflows

A reproducible methodology for measuring MEV exposure, configuring RPC access for searchers and builders, and diagnosing common extraction failures.

TL;DR

MEV (maximal extractable value) is the profit available to block producers and searchers by reordering, inserting, or censoring transactions within a block. This article explains the mechanism, then gives a reproducible procedure for measuring MEV exposure on your own transactions and for configuring RPC access that supports low-latency extraction workflows. It separates documented protocol behavior from recommendations and from measurements you must run yourself. Concrete endpoint and provider choices belong in RPC Assistant, not here.

Scope and the MEV mental model

MEV refers to the maximum value that can be extracted from a block by choosing the order, inclusion, or exclusion of transactions. The term is often written as MEV or maximal extractable value; the physics unit MeV (megaelectronvolt) and unrelated company names share the abbreviation, so context matters when searching. In blockchain contexts, MEV is a property of the mempool and block-building pipeline, not a single product.

The extraction pipeline has four roles. Users submit transactions. Searchers detect profitable opportunities and submit bundles. Builders assemble bundles into blocks. Validators or block producers propose those blocks. Each role depends on fast, consistent access to chain state and pending transactions, which is where RPC infrastructure becomes a first-order concern.

This article covers three things: how to reason about MEV exposure, how to measure it reproducibly, and how to configure RPC access for extraction workflows. It does not recommend a specific provider; use the RPC Assistant for endpoint and provider selection.

  • MEV is a block-level property; measuring it requires block and transaction data, not just mempool snapshots.
  • Searchers and builders have different latency and consistency requirements.
  • Public RPC endpoints are usually unsuitable for competitive extraction because of rate limits and variable latency.

Assumptions and prerequisites

The procedures below assume you have an EVM-compatible chain with a JSON-RPC interface, a funded test account, and permission to run scripts against an RPC endpoint. You need Node.js 18 or later for the JavaScript examples and curl for the shell examples. Replace RPC_URL with your own endpoint; never commit private keys.

You should also have a way to archive or index blocks. Measurement over a single block is rarely meaningful; plan for at least a few thousand blocks or a representative sample. If you operate a validator or builder, coordinate with your infrastructure team before running latency-sensitive workloads against production endpoints.

export RPC_URL="https://your-endpoint.example"
export PRIVATE_KEY="0x..."
node --version
curl --version

Documented behavior versus recommendations

Documented behavior includes JSON-RPC methods such as eth_blockNumber, eth_getBlockByNumber, eth_getTransactionReceipt, and eth_sendBundle where supported by the relay. These methods have defined request and response shapes. What is not standardized is how quickly a given endpoint propagates pending transactions, how it orders them, or whether it exposes a private mempool.

Recommendations in this article are clearly marked. For example, using a dedicated node for latency-sensitive bundle submission is a recommendation, not a protocol rule. Measurements such as bundle inclusion rate, latency percentiles, and reorg frequency must be produced by you against your own infrastructure and chain.

Measuring MEV exposure on your own transactions

A practical first measurement is the difference between the value your transaction expected and the value it realized after inclusion. For swaps, compare the quoted output at submission time with the actual output in the receipt. For liquidations, compare the expected bonus with the realized bonus. This isolates the portion of value captured by reordering or sandwiching.

The script below fetches a block, iterates its transactions, and prints gas used and effective gas price. It is a starting point for building a per-block MEV report. It does not classify MEV; classification requires decoding logs and comparing against a reference price.

Run this against a sample of blocks and record results in a table with columns for block number, transaction hash, expected output, actual output, and delta. Do not fill in numbers you have not measured.

const { ethers } = require("ethers");

async function main() {
  const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
  const blockNumber = await provider.getBlockNumber();
  const block = await provider.getBlock(blockNumber, true);
  console.log(`block ${blockNumber} txs=${block.transactions.length}`);
  for (const tx of block.transactions.slice(0, 5)) {
    const receipt = await provider.getTransactionReceipt(tx);
    console.log(tx, receipt.gasUsed.toString(), receipt.effectiveGasPrice?.toString());
  }
}

main().catch((err) => { console.error(err); process.exit(1); });

Results table procedure for MEV measurement

Record every measurement in a table with fixed columns so results are comparable across runs. A suggested schema is: block number, transaction hash, strategy type, expected value, realized value, delta, inclusion latency in milliseconds, and whether the transaction was included in the target block. Populate the table only with values your script produced.

BlockTx hashStrategyExpectedRealizedDeltaLatency (ms)Included
(measured)(measured)(label)(measured)(measured)(computed)(measured)(yes/no)

Run the same procedure before and after any infrastructure change. If you switch RPC endpoints, keep the block range identical so the comparison is valid. Report percentiles rather than averages for latency, because MEV outcomes are heavy-tailed.

Configuring RPC access for searchers and builders

Searchers need low-latency access to pending transactions and fast state reads. Builders need reliable block submission and consistent state across many concurrent requests. Both benefit from dedicated nodes rather than shared public endpoints, because rate limits and noisy neighbors distort latency measurements.

The curl example below checks basic endpoint health and block height. Use it as a smoke test before running extraction workloads. If the endpoint returns errors or inconsistent heights across repeated calls, do not proceed with latency-sensitive work.

For provider and endpoint selection, consult the RPC Assistant rather than hardcoding a provider here. For broader infrastructure guidance, see the OnFinality Learn guide to blockchain node hosting and the overview of multi-chain RPC endpoints.

curl -s -X POST "$RPC_URL" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'

curl -s -X POST "$RPC_URL" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"eth_getBlockByNumber","params":["latest",false]}'

Bundle submission and verification workflow

Bundle submission is relay-specific. The example below uses the eth_sendBundle shape common to many relays; confirm the exact method and parameters with your relay documentation before running it. The goal is to verify that your bundle is accepted and then confirm inclusion in a subsequent block.

After submission, poll eth_getTransactionReceipt for each transaction hash in the bundle. If the bundle is not included within your target window, log the block range and the relay response. This log is the basis for troubleshooting in the next section.

const { ethers } = require("ethers");

async function sendBundle(provider, signedTxs, targetBlock) {
  const payload = {
    jsonrpc: "2.0",
    id: 1,
    method: "eth_sendBundle",
    params: [{ txs: signedTxs, blockNumber: "0x" + targetBlock.toString(16) }]
  };
  const res = await fetch(process.env.RPC_URL, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(payload)
  });
  const json = await res.json();
  console.log(JSON.stringify(json));
  return json;
}

async function verify(provider, hashes) {
  for (const h of hashes) {
    const r = await provider.getTransactionReceipt(h);
    console.log(h, r ? `included in ${r.blockNumber}` : "not included");
  }
}

module.exports = { sendBundle, verify };

Expected verification results

A healthy endpoint returns a JSON-RPC response with a result field and no error object. Block height should increase monotonically across repeated calls. A submitted bundle should return an accepted response from the relay, and the verification step should eventually show a receipt with a block number inside your target window.

If you are measuring latency, record the time between request send and response receive for at least a few hundred samples. Report p50, p95, and p99. Do not claim a latency figure without the sample size and the endpoint configuration used to produce it.

Troubleshooting common extraction failures

Most failures fall into four categories: stale state, rate limiting, bundle rejection, and reorgs. Stale state appears when your script reads a block height that is behind the chain tip; compare eth_blockNumber across two endpoints to detect it. Rate limiting appears as HTTP 429 or JSON-RPC error codes; reduce request concurrency or move to a dedicated node.

Bundle rejection usually returns a relay error explaining the reason, such as insufficient priority fee or invalid signature. Log the full response. Reorgs invalidate receipts; re-check inclusion after a few blocks before treating a bundle as final.

If you cannot reproduce a failure, capture the request payload, the response, the block height at send time, and the block height at verification time. This record is what makes the failure diagnosable.

  • Stale state: compare block heights across endpoints before each run.
  • Rate limiting: reduce concurrency and check response headers.
  • Bundle rejection: log the relay error verbatim.
  • Reorgs: re-verify receipts after several blocks.

Limitations and tradeoffs

MEV measurement is inherently incomplete. You can measure your own exposure and your own bundle outcomes, but you cannot observe private order flow or other searchers' bundles. Any claim about total MEV on a chain requires assumptions that should be stated explicitly.

Low-latency infrastructure reduces but does not eliminate the risk of being outbid. Dedicated nodes cost more than shared endpoints and still depend on the underlying network path. There is also an ethical and protocol-level debate about MEV that this article does not resolve; the focus here is measurement and operational reliability.

Next steps

Start by running the block-scan script against a small sample and recording results in the table schema above. Then run the endpoint smoke test and compare latency across two configurations. If you need a concrete endpoint or provider recommendation, use the RPC Assistant. For infrastructure planning, review the OnFinality Learn node hosting guide, the multi-chain RPC overview, and the dedicated node documentation. Pricing for RPC services is available on the pricing page, and supported networks are listed on the networks page.

  • Run the measurement script on a fixed block range.
  • Record results in the standard table schema.
  • Compare endpoint configurations with identical workloads.
  • Consult RPC Assistant for endpoint selection.

Never Worry about Infrastructure Again

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

Get Started