Uniswap's UNI should become an oracle token, says Vitalik Buterin
V神說Uniswap本身就是一個預(yù)言機(jī)token纽什,其實(shí)這個說法對于技術(shù)開發(fā)者來說早就是心照不宣的事情。因?yàn)閁niswap也確實(shí)有一個稱之為TWAP的預(yù)言機(jī)模塊傅是,而且是使用量僅次于ChainLink的第二大預(yù)言機(jī)系統(tǒng)。這種預(yù)言機(jī)則稱之為鏈上預(yù)言機(jī)占键。對于開發(fā)者來說,Link太貴,如果有一個非常權(quán)威的dex可以提供查詢價格接口骂蓖,那么其實(shí)完全沒有必要用ChainkLink。(其實(shí)Dex的 發(fā)展本身就可以完全替代Link川尖,Uniswap已經(jīng)非常接近了登下。)
創(chuàng)建Oracle
對于使用Uniswap來做預(yù)言機(jī)的話,我們需要使用到下面幾個庫: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';
構(gòu)造函數(shù)
我們先假設(shè)我們查詢的是:UNI和ETH的交易價格馍悟。那么UNI就是tokenA畔濒,ETH就是tokenB。我們先創(chuàng)建一個工廠類IUniswapV2Pair锣咒,記錄當(dāng)前的價格侵状,為下面的操作做準(zhǔn)備。
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
}
價格更新
價格更新的函數(shù)非常容易理解毅整,就是獲取新的價格趣兄,然后更新price0CumulativeLast和price1CumulativeLast。唯一值得注意的是悼嫉,update是一個external的function艇潭。所以,每一次的調(diào)用都需要耗費(fèi)gas戏蔑。當(dāng)然了蹋凝,等EIP-1559落地之后,這個調(diào)用的成本應(yīng)該會非常便宜辛臊。但目前還是比較貴仙粱,估計(jì)更新一次需要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即可伐割。但要注意轉(zhuǎn)編碼。
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();
}
}
總結(jié)
最近太累了刃唤,簡單記錄一下隔心。