本文深入探讨了 Uniswap V4 中引入的截断预言机(Truncated Oracle)如何应对 DeFi 借贷协议中传统 TWAP 预言机易受价格操纵的问题。截断预言机通过限制每个区块的价格变动幅度,有效降低了闪电贷攻击的影响,但同时也分析了它固有的时间窗口选择和历史数据依赖等问题,并提出了相应的改进建议。
DeFi 借贷协议严重依赖于精确的价格预言机来确定抵押品价值、借款限额和触发清算。传统的时间加权平均价格(Time-Weighted Average Price, TWAP)预言机虽然被广泛采用,但本质上容易受到价格操纵的影响,导致可能具有破坏性的不公平清算和系统性市场低效。Uniswap V4 引入的截断预言机旨在解决这些关键漏洞。
TWAP 通过累积价格快照来计算资产在定义的时间窗口内的平均价格。虽然旨在平滑短期波动,但它从根本上假设了一个相对稳定的市场环境,但这在 DeFi 中通常不是如此。
考虑一个抵押率为 1.9 倍的借贷市场。一个有 10 ETH 抵押品 (ETH 价格 = $2,200) 的借款人,为了确保 10,000 USDC 的贷款,必须维持至少价值 $19,000 的抵押品 (大约 9 ETH) 以避免清算。
攻击者可以通过 闪电贷 来利用这一点,在一个低流动性交易所执行大规模的市场抛售,暂时将 ETH 价格 砸 到 $500。这种攻击相对便宜,因为唯一的成本是闪电贷费用。由于 TWAP 不加区分地包含所有价格数据,因此它很容易受到这种类型的操纵。
让我们假设 TWAP 基于最近的 5 个区块计算平均值:
| 区块 | ETH 价格 |
| Block 1 | $2200 |
| Block 2 | $2200 |
| Block 3 | $2200 |
| Block 4 | $2200 |
| Block 5 | $500 (攻击) |
这些区块上的 TWAP 价格是:
TWAP = (2200 + 2200 + 2200 + 2200 + 500) / 5 = 1860
由于借贷市场使用 TWAP,该协议错误地将 ETH 报告为 $1,860。
借款人的 10 ETH 抵押品价值 $18,600 (10 ETH * $1860),低于 $19,000,因此,借款人的头寸被不公平地清算。
低流动性资金池特别容易受到 闪电贷攻击,因为较小的闪电贷金额会产生更大的价格波动。
截断预言机是一个 Uniswap V4 Hook(hook),它对流动性池中的价格变化做出反应。与传统的 TWAP 不同,它采用了一种改进的几何平均计算方法,并结合了每个区块的关键价格变动上限。这个上限有效地限制了突然的、人为诱导的价格飙升的影响,防止它们立即扭曲预言机的输出。
为了说明这一点,考虑一个假设的 区块价格上限 为 5% 的场景:
| 区块 | ETH 价格 | 截断预言机价格 |
| Block 1 | $2200 | $2200 |
| Block 2 | $2200 | $2200 |
| Block 3 | $500 (攻击) | $2090 |
截断预言机不会像 TWAP 那样降至 $1860,而是仅降至 $2090。
对于拥有 10 ETH 抵押品的借款人来说,这种差异至关重要。按照截断预言机 $2090 的价格,他们的抵押品价值为 $20,900 (10 ETH * $2090),超过了所需的 $19,000 阈值,从而避免了清算。而价格较低的 TWAP 预言机会导致不应有的清算。
虽然截断预言机可以防止即时价格下跌,但攻击者仍然可以通过在多个区块中逐渐降低价格 5% 来操纵价格。
| 区块 | ETH 价格 | 截断预言机价格 |
| Block 1 | $2200 | $2200 |
| Block 2 | $2200 | $2200 |
| Block 3 | $500 (攻击) | $2090 |
| Block 4 | $500 (攻击) | $1985 |
| Block 5 | $500 (攻击) | $1885 |
借款人的 10 ETH 抵押品为 10 * 1885 = 18850,低于 19,000,因此,借款人的头寸被不公平地清算。
这次攻击持续了 3 个区块,虽然比单区块闪电贷攻击贵得多,但对于拥有大量资金的攻击者来说仍然是可行的。持续的操纵需要维持一个很大的仓位,并反复吸收套利交易,这可能会付出高昂的代价。但是,对于资金充足的攻击者来说,清算目标头寸的潜在收益可能会超过成本。
操纵期间 TWAP 与截断预言机价格行为
TruncatedOracle 库为 Uniswap 的截断预言机提供了核心逻辑,该预言机跟踪并限制预定义的最大区块价格变化。
int24 constant MAX_ABS_TICK_MOVE = 9116;
MAX_ABS_TICK_MOVE = 9116 定义了每个区块的最大价格变动。
任何超过此值的价格变化都会被 截断,以防止极端波动。
transform 函数确保价格更新永远不会超过预定义的上限 (MAX_ABS_TICK_MOVE):
function transform(Observation memory last, uint32 blockTimestamp, int24 tick, uint128 liquidity)
private pure returns (Observation memory)
{
unchecked {
uint32 delta = blockTimestamp - last.blockTimestamp;
// Truncate extreme price movements per block
// **截断**每个区块的极端价格变动
if ((tick - last.prevTick) > MAX_ABS_TICK_MOVE) {
tick = last.prevTick + MAX_ABS_TICK_MOVE;
} else if ((tick - last.prevTick) < -MAX_ABS_TICK_MOVE) {
tick = last.prevTick - MAX_ABS_TICK_MOVE;
}
return Observation({
blockTimestamp: blockTimestamp,
prevTick: tick,
tickCumulative: last.tickCumulative + int48(tick) * int48(uint48(delta)),
secondsPerLiquidityCumulativeX128: last.secondsPerLiquidityCumulativeX128
+ ((uint144(delta) << 128) / (liquidity > 0 ? liquidity : 1)),
initialized: true
});
}
}
这是如何运作的
这种机制确保了价格的逐步变动,使攻击者更难在单个交易中操纵价格预言机。
因此,截断预言机通过限制价格在选定的时间窗口内可以移动的速度,部分缓解了低流动性池操纵的问题。由于预言机仅考虑部分历史价格数据,因此突然的价格飙升或暴跌会减少直接影响,防止估值发生剧烈变化。这使得攻击者更难以利用低流动性池进行闪电抛售或拉升,因为价格无法立即反映极端的市场变动。
虽然截断预言机提供了显着改进,但它继承了传统 TWAP 的基本漏洞,尤其是在时间段选择和处理不充分的历史数据方面。这些问题仍然可以被利用来操纵预言机。
📌 不正确的时间段选择**
TWAP 容易受到 闪崩 和 延迟定价 的影响,这仍然是截断预言机中的一个问题:
建议:
✅ 在考虑预言机价格时,不要使用不可变的周期,而是根据市场情况进行设置。
✅ 确保仔细选择时间窗口,以平衡响应性和稳定性。
📌 零时间窗口和缺乏历史数据
TWAP 的历史依赖性问题也存在于截断预言机中:
建议:
✅ 在认为预言机有效之前,需要最低价格更新历史。
Uniswap V4 的截断预言机代表了链上价格预言机的重大进步,提供了增强的针对闪电贷操纵的弹性。然而,它并不是万能的。时间段选择、处理不充分的历史数据以及多区块操纵的风险等基本挑战仍然存在。开发人员必须极其谨慎,并实施强大的保障措施来减轻这些风险。对预言机行为的系统性监控,以及对时间窗口和价格上限的自适应调整,对于维护依赖协议的完整性至关重要。
- 原文链接: hacken.io/discover/unisw...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!