Solidity Uniswap V2 价格预言机

        预言机是连接区块链与链下服务的桥梁,这样就可以从智能合约中查询现实世界的数据。Chainlink 是最大的oracle网络之一,创建于 2017 年,如今已成为许多 DeFi 应用的重要组成部分。https://github.com/XuHugo/solidityproject

        Uniswap 虽然是链上应用,但也可以充当oracle。交易者经常使用的每个 Uniswap pair合约也吸引着套利者,他们通过尽量缩小交易所之间的价格差异来赚钱。套利者使 Uniswap 的价格尽可能接近中心化交易所的价格,这也可以看作是将中心化交易所的价格反馈到区块链上。为什么不利用这一事实将pair合约变成价格oracle呢?Uniswap V2 就是这么做的。

        在 Uniswap V2 中,价格oracle提供的价格被称为时间加权平均价格(TWAP)。它基本上可以获得两个时间点之间的平均价格。为了做到这一点,合约存储了累计价格:在每次交换之前,它都会计算当前的边际价格(不包括费用),然后乘以上次交换后的秒数,再把这个数字加到前一个数字上。

我在上一段提到了边际价格,这只是两个reserve的关系:

        对于价格oracle功能,Uniswap V2 使用边际价格,它不包括滑点和交换费,也不取决于交换量。

        由于 Solidity 不支持浮点除法,计算这种价格可能比较麻烦:例如,如果两个reserve的比率是 2/3, 那么价格是0;在计算边际价格时,我们需要提高精确度,Unsiwap V2 为此使用了 UQ112.112 数字。

        UQ112.112 本质上是一个小数部分使用 112 位,整数部分使用 112 位的数字。选择 112 位是为了使储备状态变量的存储更优化,这也是变量使用 uint112 类型的原因。另一方面,reserve存储为 UQ112.112 数字的整数部分,这就是为什么在计算价格前要乘以 2**112 的原因。详情请查看 UQ112x112.sol,非常简单。

        让我们来实现价格累积。我们只需要添加一个状态变量:

uint32 private blockTimestampLast;

        它将存储最后一次交换的时间戳。然后我们需要修改储备更新函数:

function _update(

    uint256 balance0,

    uint256 balance1,

    uint112 reserve0_,

    uint112 reserve1_

) private {

    ...

    unchecked {

        uint32 timeElapsed = uint32(block.timestamp) - blockTimestampLast;



        if (timeElapsed > 0 && reserve0_ > 0 && reserve1_ > 0) {

            price0CumulativeLast +=

                uint256(UQ112x112.encode(reserve1_).uqdiv(reserve0_)) *

                timeElapsed;

            price1CumulativeLast +=

                uint256(UQ112x112.encode(reserve0_).uqdiv(reserve1_)) *

                timeElapsed;

        }

    }



    reserve0 = uint112(balance0);

    reserve1 = uint112(balance1);

    blockTimestampLast = uint32(block.timestamp);



    ...

}

UQ112x112.encode 将 uint112 值乘以 2**112,使其成为 uint224 值。然后,将其除以其他reserve,再乘以 timeElapsed。结果会与当前存储的值相加,这就是累积值。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0xweb3q

有钱的捧个钱场,没钱的捧个人场

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值