xChar
·9 months ago

什么是价格

Uniswap作为链上的去中心化交易所,承载着价值发现的功能,即用户或其他链上合约可以通过Uniswap来获取代币的价格,Uniswap在这其中承担链上预言机的功能。

假设当前交易池中有1 Ether和2000 USDC,那么以太币的价格就是2000/1=2000 USDC,反之就是USDC的价格,因此价格就是一个比率,由于智能合约尚不支持小数,所以在Uniswap的代码中拓展了新的数据类型来存储价格,关于新的数据类型后面会专门做介绍。

TWAP价格机制

然而仅仅使用瞬时的代币数目之比作为价格是不安全的,存在人为操纵价格预言机的风险,由于Uniswap提供了闪电贷功能,因此在某个闪电贷交易的瞬间,交易对内的代币余额会产生剧烈波动。在UniswapV2中为了解决这个问题,采用了TWAP(Time Weighted Average Price)即时间加权的价格预言机机制。

具体工作原理如下:

  • 假设过去一天,资产在前20个小时的价格为20$,最近4小时的价格为10$,那么TWAP=($20*20+10$*4)/24 = 18.33$
  • 假设过去一天,资产在第一个小时的价格为10$,最近23小时的价格为15$,那么TWAP=($10*1+15$*23)/24 = 14.79$

总结下来,TWAP的公式如下,这里的T是时间段,P是对应时间段的价格

image

在UniswapV2的合约中,只会记录分子部分,即记录每个时间段乘以单价的求和,而分母部分则需要使用方自行维护,交易对内有两个代币,所有有两个值来记录

通常我们只需关心某一时间区间内的代币价格,这是TWAP公式的历史价格公式:

image

假设我们的计价从T4开始,那么实际的计价公式应该如下:

image

前面已经提到,在合约内有一个变量会追踪分子的求和值,以token0的追踪计价变量price0Cumulativelast为例:

image

这个变量是记录了历史以来所有时间段的求和,那么我们只需要从T4开始的部分即可,计算方式也很简单,在T3时间点我们获取一个price0Cumulativelast变量的快照,在最新即T6时间点再获取一次,两次的差值即是T4-最新时间段内token0的计价和

image

我们自己也维护了最近的窗口持续时间和,即:T4+T5+T6

那么这段时间内的TWAP价格即可计算得出:(price0Cumulativelast-UpToTime3)/(T4+T5+T6)

UniswapV2的实现

具体到Uniswap的实现中,对于每个交易对都维护了两个变量price0Cumulativelast和price1Cumulativelast,在之前提到的_update 方法中进行求和,具体的代码如下:

  • 首先获取当前的区块时间戳blockTimestamp
  • 通过与blockTimestampLast相减,计算出距离上次更新过去了多少时间timeElapsed
  • 只有在timeElapsed >0时,即进入下一个区块时,才会累加价格*时间段
  • 注意这里的价格计算用到了UQ112x112 的特殊格式,了解它是为了记录小数即可,后面会专门讲解这里的优化
  • 在处理完累加后,才会更新blockTimestampLast 到最新的区块时间戳
function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private {
    ...
    uint32 blockTimestamp = uint32(block.timestamp % 2**32);
    uint32 timeElapsed = blockTimestamp - blockTimestampLast;
    if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {
      // * never overflows, and + overflow is desired
      price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed;
      price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed;
    }
    blockTimestampLast = blockTimestamp;
    ...
  }

TWAP的潜在问题

  • 基于时间加权的价格计算,会提高攻击者的操纵成本,因为需要连续控制多个区块,这样的攻击成本是很高的。
    当价格产生剧烈波动时,由于有时间作为加权因素,预言机的价格无法在较短时间内反映出价格的波动,反而提供出过时的价格,尤其是在市场发生剧烈动荡时,这样的情况会导致Uniswap中的价格与外部市场产生较大的差异。

  • 使用TWAP预言机仍然依赖链下的定时触发,存在维护成本与中心化问题。

Loading comments...