MEV,即最大可提取价值,是指通过选择哪些交易进入区块、以何种顺序进入以及排除哪些交易而可捕获的利润。它之所以存在,是因为区块生产者控制排序,且待处理交易在被打包前往往可见。本指南解释其机制,梳理主要的提取模式,并提供可复现的流程,用于衡量自身风险敞口并加以降低。它将有据可查的协议行为、建议以及你必须针对自身基础设施运行的测量区分开来。
最大可提取价值的定义与范围
最大可提取价值(MEV)是指通过在一个区块内包含、排除或重新排序交易,在标准区块奖励和交易手续费之外可获得的最高利润。该术语最初在工作量证明下称为“矿工可提取价值”,当时矿工控制区块内容。以太坊转向权益证明后,验证者承担了这一角色,因此社区采用“最大”来描述同一经济面,而不将其与挖矿绑定。
MEV 不是单一攻击。它是一类只要排序有意义就会产生的价值:去中心化交易所套利、清算、三明治攻击、NFT 铸造狙击以及预言机更新后的尾随交易都属于此范畴。其中一些是良性的做市行为,会收紧各场所的价格;另一些则直接将价值从普通用户手中转移走。当你决定要缓解什么时,这一区分很重要。
本文涵盖机制、参与者角色、可针对 RPC 端点执行的可运行诊断,以及常见缓解措施的权衡。它不发布任何提供商的基准数字;在需要测量之处,会给出流程,以便你得出自己的结果。
- MEV 来自排序、包含和排除,而非仅来自持有或质押。
- 它存在于任何由区块生产者控制交易顺序且待处理交易可被观察的链上。
- 风险敞口取决于你的交易类型、滑点设置以及你提交交易的方式。
假设与前提条件
你应当熟悉交易、区块、gas,以及公共内存池与私有交易中继之间的区别。熟悉自动做市商(AMM)会有帮助,因为大多数面向用户的 MEV 示例都涉及价格影响取决于排序的兑换。
你需要一个用于只读诊断的 RPC 端点。任何可靠的端点都可以;如果你正在选择,RPC 端点指南涵盖了应评估的内容,RPC 定价解释了请求量如何映射到成本。对于需要一致延迟的生产工作负载,专用节点可消除可能扭曲时间敏感测量的邻居干扰效应。
心智模型:排序作为稀缺资源
把区块想象成一个容量固定的序列。其中的每笔交易都会对共享状态产生影响,而一笔交易的影响取决于它之前运行了什么。兑换会沿曲线移动池子价格;清算会改变借款人的健康度;预言机更新会改变合约看到的价格。由于顺序改变结果,选择顺序的权利就有价值。
在一个简单模型中,搜索者识别出有利可图的序列,将其作为捆绑包提交,并向区块构建者出价一部分利润以换取包含。构建者组装最有价值的区块,并将出价传递给验证者,由验证者提议。验证者保证的份额来自出价;搜索者保留剩余部分。竞争推高出价,因此在竞争激烈的机会中,大部分价值可能流向构建者和验证者,而非搜索者。
这就是为什么 MEV 有时被称为对用户的隐形税:价值是真实的,但它是通过更差的执行而非明列项目支付的。这项税收的大小取决于你的交易在落地前暴露了多少自身信息。
参与者角色:搜索者、构建者、验证者和中继
搜索者对 pending 和历史数据运行算法以寻找有利可图的排序,然后提交捆绑包。构建者将捆绑包和普通交易聚合成候选区块,以总价值为优化目标。验证者(或提议者)选择一个区块并对其进行证明。中继充当中介,在搜索者和构建者之间传递捆绑包,而不会过早暴露内容。
这种分离并非普遍存在。在某些网络上,角色合并为单一提议者;在另一些网络上,构建者市场则不那么发达。当你在一条新链上推理 MEV 时,首先要问谁控制排序,以及是否存在私有提交路径。网络目录列出了支持的链及其执行环境,这是在假设以太坊式基础设施之前的一个有用起点。
- 搜索者:发现并提交有利可图的交易捆绑包。
- 构建者:从捆绑包和交易组装区块。
- 验证者/提议者:选择并提议区块。
- 中继:在各方之间以有限披露传递捆绑包。
常见提取模式及其用户影响
DEX 套利纠正池子和场所之间的价格差异。它通常是按交易量计最大的类别,对用户大多中性至有害,因为它将价格推向单一市场利率。清算保持借贷协议偿付能力,是 keeper 的合法激励,尽管在波动期间可能很激进。
三明治攻击是用户感受最直接的模式。搜索者观察到一笔将移动池子价格的待处理兑换,在其之前买入,让受害者的交易进一步推高价格,然后卖出。受害者获得更差的汇率。只有当受害者的滑点容忍度留有空间时,该攻击才有利可图,因此滑点设置是用户控制的主要杠杆。
抢跑和尾随是通用原语:在目标之前或之后放置交易。广义抢跑复制一笔有利可图的交易并替换发送者。NFT 狙击和铸造抢跑将相同逻辑应用于稀缺铸造。每种模式都有不同的缓解特征,这就是为什么“使用私有 RPC”之类的笼统建议并不完整。
诊断流程:检查待处理和近期交易
在改变任何东西之前,先确定你的交易从外部看起来是什么样。以下 Python 脚本查询 JSON-RPC 端点以获取最新区块,并打印交易哈希、gas 价格和输入大小。针对你自己的 RPC_URL 运行它;不要硬编码公共端点。将输出视为基线,以便在改变提交行为后进行比较。
该脚本仅使用标准库模块和 eth_getBlockByNumber 方法,每个 EVM 兼容端点都支持该方法。如果你的提供商有速率限制,请减少区块范围或添加退避。
import json, urllib.request
RPC_URL = "RPC_URL"
def rpc(method, params):
payload = json.dumps({"jsonrpc": "2.0", "id": 1, "method": method, "params": params}).encode()
req = urllib.request.Request(RPC_URL, data=payload, headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=20) as resp:
return json.loads(resp.read())["result"]
block = rpc("eth_getBlockByNumber", ["latest", True])
print("block", int(block["number"], 16), "txs", len(block["transactions"]))
for tx in block["transactions"][:20]:
print(tx["hash"], int(tx["gasPrice"], 16) if tx.get("gasPrice") else "n/a", len(tx.get("input", "")))用可复现方法衡量自身风险敞口
你无法减少你看不到的东西。一个实用的风险敞口测试是通过正常路径提交一笔小额兑换,并将执行价格与紧邻其前后获取的参考价格进行比较。在表格中为每次试验记录以下字段:时间戳、池子、报价输出量、执行输出量、滑点容忍度、提交路径(公共内存池或私有中继)以及观察到的价格影响。
每种配置至少运行十次试验,并报告中位数和分布范围,而非单一结果。单笔兑换可能幸运或不幸;分布才能告诉你缓解措施是否有帮助。不要比较在不同时段或不同市场波动性下进行的试验而不加注明,因为 MEV 活动并非平稳。
下面的结果表是模板,不是测量数据。用你自己的观察填充它。
- | 试验 | 路径 | 报价输出 | 执行输出 | 滑点 bps | 价格影响 |
- | 1 | 公共 | (你的值) | (你的值) | (你的值) | (你的值) |
- | 2 | 私有中继 | (你的值) | (你的值) | (你的值) | (你的值) |
- 报告所有试验中执行减报价的中位数,而非单一最佳情况。
实现:以更紧约束提交兑换
用户侧最直接的缓解是减少三明治攻击可获得的利润。降低滑点容忍度、拆分大额订单并设置截止时间。下面的 JavaScript 片段展示了使用 ethers 风格占位符的兑换调用形态。它仅作示意;请替换你的路由 ABI 和代币地址。切勿将 PRIVATE_KEY 提交到源代码管理。
关键参数是 amountOutMin 和 deadline。amountOutMin 应来自最新报价,而非过时报价,并且应足够紧,使三明治攻击在扣除费用后无利可图。将订单拆分为更小的部分可减少每部分产生的价格影响,进而减少搜索者可从任何单笔交易中提取的价值。
import { ethers } from "ethers";
const provider = new ethers.JsonRpcProvider("RPC_URL");
const wallet = new ethers.Wallet("PRIVATE_KEY", provider);
const router = new ethers.Contract("ROUTER_ADDRESS", ROUTER_ABI, wallet);
const amountIn = ethers.parseUnits("1.0", 18);
const quotedOut = await router.getAmountsOut(amountIn, [TOKEN_IN, TOKEN_OUT]);
const minOut = quotedOut[1] * 995n / 1000n; // 0.5% tolerance, adjust deliberately
const deadline = Math.floor(Date.now() / 1000) + 60;
const tx = await router.swapExactTokensForTokens(
amountIn, minOut, [TOKEN_IN, TOKEN_OUT], await wallet.getAddress(), deadline
);
console.log("submitted", tx.hash);
const receipt = await tx.wait();
console.log("status", receipt.status);验证:确认缓解措施生效
在更改滑点或提交路径后,重新运行风险敞口流程并比较分布。成功的缓解表现为报价与执行金额之间的差距更窄,以及具有大负价格影响的交易更少。它不一定显示零 MEV;套利和其他良性活动仍会出现在区块数据中。
使用区块浏览器或你自己的索引器检查你的交易是否在同一区块中被来自不同发送者的同一池子兑换所前置。如果是,且价格对你不利,那就是三明治攻击的证据。记录区块号和两笔交易哈希,以便观察可复现。
排查常见的 MEV 相关失败
因滑点错误而回滚的交易通常意味着价格在报价和执行之间移动了,可能是正常波动或中间交易所致。稍微放宽容忍度或在签名前立即刷新报价。从未落地的交易可能因优先费过低而卡住;通过你的提供商检查内存池状态,并考虑使用相同 nonce 的替换交易。
如果你的私有中继提交未被包含,请确认中继支持你的链和交易类型。并非每个中继都服务每个网络,有些需要特定的捆绑包格式。如果你在紧滑点下仍反复遭遇三明治攻击,请检查你的钱包或前端是否覆盖了你的滑点设置,这是常见的困惑来源。
- 兑换回滚:刷新报价、检查截止时间、验证代币授权。
- 交易卡住:检查 nonce 和优先费,考虑替换。
- 中继拒绝:验证链支持和捆绑包格式。
- 意外滑点:审计钱包和前端默认设置。
局限性、权衡与后续步骤
私有提交减少了对公共内存池三明治攻击的敞口,但并未消除 MEV;构建者仍可在自己的区块内重新排序,且信任假设转移到了中继。更紧的滑点可防止三明治攻击,但会增加失败交易,从而消耗 gas。拆分订单减少了每笔交易的影响,但增加了总费用和操作复杂性。
测量本身也有局限。公共数据显示了什么落地,而非什么被尝试,捆绑包层面的竞争仅部分可见。将任何单一数字视为快照。对于生产系统,持续监控,并在链的构建者市场变化时重新审视假设。
如果你正在围绕这些工作流构建基础设施,请从可靠的端点开始:查看API 服务了解托管访问,比较 RPC 定价进行成本建模,并在假设中继或构建者 API 存在之前检查支持的网路。对于延迟敏感的搜索者或 keeper,在建立基线后,专用节点通常是下一步。