uniswap(v2)创建BlockchainOracle

Uniswap's UNI should become an oracle token, says Vitalik Buterin

V神说Uniswap本身就是一个预言机token,其实这个说法对于技术开发者来说早就是心照不宣的事情。因为Uniswap也确实有一个称之为TWAP的预言机模块,而且是使用量仅次于ChainLink的第二大预言机系统。这种预言机则称之为链上预言机。对于开发者来说,Link太贵,如果有一个非常权威的dex可以提供查询价格接口,那么其实完全没有必要用ChainkLink。(其实Dex的 发展本身就可以完全替代Link,Uniswap已经非常接近了。)

创建Oracle

对于使用Uniswap来做预言机的话,我们需要使用到下面几个库:IUniswapV2Factory,IUniswapV2Pair,UniswapV2OracleLibrary和UniswapV2Library。

import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol';
import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol';
import '@uniswap/lib/contracts/libraries/FixedPoint.sol';

import '@uniswap/v2-periphery/contracts/libraries/UniswapV2OracleLibrary.sol';
import '@uniswap/v2-periphery/contracts/libraries/UniswapV2Library.sol';

构造函数

我们先假设我们查询的是:UNI和ETH的交易价格。那么UNI就是tokenA,ETH就是tokenB。我们先创建一个工厂类IUniswapV2Pair,记录当前的价格,为下面的操作做准备。

    constructor(address factory, address tokenA, address tokenB) public {
        IUniswapV2Pair _pair = IUniswapV2Pair(UniswapV2Library.pairFor(factory, tokenA, tokenB));
        pair = _pair;
        token0 = _pair.token0();
        token1 = _pair.token1();
        price0CumulativeLast = _pair.price0CumulativeLast();
        price1CumulativeLast = _pair.price1CumulativeLast();

        uint112 reserve0;
        uint112 reserve1;

        (reserve0, reserve1, blockTimestampLast) = _pair.getReserves();
        require(reserve0 != 0 && reserve1 != 0, 'ExampleOracleSimple: NO_RESERVES'); // ensure that there's liquidity in the pair
    }

价格更新

价格更新的函数非常容易理解,就是获取新的价格,然后更新price0CumulativeLast和price1CumulativeLast。唯一值得注意的是,update是一个external的function。所以,每一次的调用都需要耗费gas。当然了,等EIP-1559落地之后,这个调用的成本应该会非常便宜。但目前还是比较贵,估计更新一次需要200~300人民币。(2021年5月)

    function update() external {
        (uint price0CumulativeLast, uint price1CumulativeLast, uint32 blockTimestampLast) = UniswapV2OracleLibrary.currentCumulativePrices(address(pair));
        uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired
        require(timeElapsed >= PERIOD, 'ExampleOracleSimple: PERIOD_NOT_ELAPSED');

        price0Average = FixedPoint.uq112x112(uint224((price0Cumulative - price0CumulativeLast) / timeElapsed));
        price1Average = FixedPoint.uq112x112(uint224((price1Cumulative - price1CumulativeLast) / timeElapsed));

        price0CumulativeLast = price0Cumulative;
        price1CumulativeLast = price1Cumulative;
        blockTimestampLast = blockTimestamp;
    }

获取价格

价格的获取非常简单,直接返回amountOut即可。但要注意转编码。

    function consult(address token, uint amountIn) external view returns (uint amountOut) {
        if (token == token0) {
            amountOut = price0Average.mul(amountIn).decode144();
        } else {
            require(token == token1, 'ExampleOracleSimple: INVALID_TOKEN');
            amountOut = price1Average.mul(amountIn).decode144();
        }
    }

总结

最近太累了,简单记录一下。

你可能感兴趣的:(uniswap(v2)创建BlockchainOracle)