欢迎订阅专栏:10分钟智能合约:进阶实战
三明治攻击(Sandwich Attack):定义、原理与防御
三明治攻击 是 MEV 中最具代表性的攻击形式之一。攻击者将目标交易“夹”在自己的两笔交易中间:先在前置交易中推高价格,等待目标交易以高价执行,最后在后置交易中卖出,赚取差价。因交易顺序形成“夹心”而得名。
三明治攻击 = 前置交易(Front-run) + 目标交易(Victim) + 后置交易(Back-run)。
1. 攻击原理详解
攻击者监听公开交易池(Mempool),发现一笔会对价格产生显著影响的交易(如用 10 ETH 在 Uniswap 购买某代币)。攻击者随即构造两笔交易:
- 前置交易:支付更高 Gas,在目标交易前买入同样的代币,人为抬高价格。
- 后置交易:支付更高 Gas,在目标交易后立即卖出之前买入的代币。
攻击流程示意图
区块交易顺序(按Gas价格排序,高到低):
┌─────────────────────────────────────────────┐
│ 1. 攻击者买入交易(高Gas) ← 前置 │
│ 2. 用户买入交易(中Gas) ← 目标 │
│ 3. 攻击者卖出交易(高Gas) ← 后置 │
└─────────────────────────────────────────────┘
价格变化:
正常价格 → 前置买入推高 → 用户被迫更高价买入 → 后置卖出价格略回落,但攻击者仍获利
简化示例(Uniswap V2 风格)
- 初始池:10 ETH 和 10,000 代币 A,价格 1 ETH = 1,000 A。
- 用户交易:想用 10 ETH 买 A。正常应获得 ≈ 5,000 A(考虑滑点)。
- 攻击者前置:先用 10 ETH 买 A,价格飙升,用户交易时获得更少的 A(比如 2,500 A)。
- 攻击者后置:卖出之前买入的 A(加上用户买入后池子里的 ETH),获利差价。
实际上,攻击者通过两笔交易原子化(通常使用 Flashbots 捆绑)确保要么全成功,要么全失败。
2. 攻击的关键条件
- 目标交易滑点大:大额交易相对池子流动性而言足够大,价格影响明显。
- 低流动性池:越小、越浅的池子越容易被操纵。
- 公开 Mempool:攻击者能提前看到用户交易。
- Gas 竞价自由:攻击者愿意支付比用户更高的 Gas 来插队。
3. 攻击的数学本质
设目标交易前池中 x 个 ETH,y 个代币。用户欲用 Δx ETH 买入 Δy 代币。
在没有前置的情况下,用户获得的代币 Δy = y - (x*y)/(x+Δx)。
攻击者前置交易买入 α ETH 的代币,进一步改变储备,使得用户最终获得的代币远少于无攻击时应得的数量。攻击者随后卖出,赚取差价。
4. 防御与缓解措施
| 策略 | 实现方式 | 有效性 |
|---|---|---|
| 私有交易池 | 使用 Flashbots RPC 提交交易,不进入公开 Mempool。 | 直接避免被侦察,最有效。 |
| 设置滑点容忍度 | 用户设置 0.5%~1% 的滑点上限,超限交易回滚。 | 基本防护,但可能被高滑点需求覆盖。 |
| 使用 TWAP 预言机 | 交易价格基于时间加权平均价,而非瞬时储备。 | 彻底消除三明治,但需要设计。 |
| 批量拍卖 | 如 CowSwap,将所有订单聚合成批量,统一结算。 | 完全消除排序攻击,但流动性受限。 |
| Commit-Reveal | 用户先提交订单哈希,后再揭示订单详情。 | 防侦察,但用户体验复杂。 |
| DEX 层面限制 | 对单笔交易的最大滑点或最大交易量进行限制。 | 增加攻击成本。 |
代码示例:用户侧使用滑点保护
function swapWithProtection(
uint amountIn,
uint minAmountOut, // 最小期望输出,防止三明治
address tokenIn,
address tokenOut
) external {
uint amountOut = dex.swap(amountIn, tokenIn, tokenOut);
require(amountOut >= minAmountOut, "Slipped too much");
}
5. 真实案例
- Jared from Subway bot:以太坊上最著名的三明治攻击机器人,每天获利数十万美元,至今仍活跃。
- Uniswap 早期 MEME 代币:许多低流动性代币上线后,用户大额购买即被三明治攻击。
- MEV-保护聚合器:1inch、CowSwap 等的出现正是为了对抗三明治攻击。
6. 总结
三明治攻击的本质:
- 利用交易排序权和公开 Mempool 狙击对价格敏感的用户。
- 攻击者不创造价值,只是重新分配用户损失。
对普通用户:
- 使用支持 MEV 保护的 DEX 聚合器(如 CowSwap、1inch 的“防护”模式)。
- 设置较小的滑点容忍度。
- 大额交易拆分成小额,或使用 Flashbots RPC。
对协议开发者:
- 避免依赖瞬时储备定价(使用 TWAP)。
- 考虑实施批量拍卖或交易延迟机制。
- 教育用户使用安全的交易工具。
审计三明治风险时,重点关注 DEX 交易对流动性的深度、预言机机制以及是否存在可被轻易操纵的价格计算逻辑。