前言
2020~2021是一个Defi的时代,很多公链都开始支持EVM,开始搞web3.0。包括,Algorand,BCH,BSC,NEO和Conflux等等等等。很多公链生态应用都是出现爆发式出现,例如Gamefi,多种Defi协议。然而,Defi各种生态里,预言机服务是非常非常重要的一个服务。很多Defi协议都需要一个预言机合约进行报价,为了解决新生公链生态没有预言机的问题,我开源了我在TriangleDAO写的一个中心化区块链预言机。核心团队 or 核心社区人员可以部署到对应的链上,做一个临时的中心化区块链预言机方案。这同样也适合联盟链,联盟链应该是很少或者几乎没有预言机服务的吧。
开源地址:
https://github.com/shanxuanch...
技术架构 ( v1.0)
核心其实是2个合约:一个是TriangleOracle.sol,另外一个PriceFeed.sol。
TriangleOracle.sol继承了IERC2362标准,主要是2个函数:一个是putPirce和ValueFor。有一个定时的进程每5分钟会从Binance和Okex读取价格,然后触发putPrice,把价格写到链上。
pragma solidity 0.6.11;
import "./Ownable.sol";
import "./Interfaces/IERC2362.sol";
contract TriangleOracle is Ownable, IERC2362 {
// 32 + 16 + 16 = 64 bytes
// default 1e+18
struct PriceOracle {
int256 price; // 16 bytes
uint256 timestamp;
uint256 status; // 16 bytes
}
PriceOracle latestPrice;
event PutLatestTokenPrice(int256 price, uint256 timestamp, uint256 status);
function putPrice(bytes32 _id, int256 price, uint256 timestamp) public onlyOwner {
uint256 _status = 200;
latestPrice = PriceOracle ({
price: price,
timestamp: timestamp,
status: _status
});
emit PutLatestTokenPrice(price,timestamp, _status);
}
function valueFor(bytes32 _id) external view override returns(int256,uint256,uint256) {
return (latestPrice.price, latestPrice.timestamp, latestPrice.status);
}
}
PriceFeed合约的职责是读TriangleOracle.sol的价格,然后把价格保存到lastGoodPrice这个变量中,以便其他合约读取这个价格。这里有其他逻辑,例如scale。比较重要的是,这里涉及到可更新和合约交互的逻辑,让我对智能合约的理解提升了一个数量级。
// SPDX-License-Identifier: MIT
pragma solidity 0.6.11;
import "./Dependencies/SafeMath.sol";
import "./Interfaces/IERC2362.sol";
import "./Interfaces/IPriceFeed.sol";
import "./Dependencies/Initializable.sol";
import "./Dependencies/CheckContract.sol";
contract PriceFeed is CheckContract, IPriceFeed, Initializable {
using SafeMath for uint256;
uint constant public TARGET_DIGITS = 18;
// CFX/USDT assertID
bytes32 constant public assetID = bytes32(0x65784185a07d3add5e7a99a6ddd4477e3c8caad717bac3ba3c3361d99a978c29);
struct WitnetResponse {
int256 value;
uint256 _timestamp;
uint256 status;
}
IERC2362 public witnet;
uint public lastGoodPrice;
event LastGoodPriceUpdated(uint _lastGoodPrice);
// --- Dependency setters ---
function initialize(address _IWitnetCFXUSDTAddress) public initializer {
checkContract(_IWitnetCFXUSDTAddress);
witnet = IERC2362(_IWitnetCFXUSDTAddress);
WitnetResponse memory witnetResponse = _getCurrentWitnetResponse(assetID);
_storePrice(witnetResponse);
}
function getPrice() external view returns (uint) {
return lastGoodPrice;
}
function fetchPrice() external override returns (uint) {
WitnetResponse memory witnetResponse = _getCurrentWitnetResponse(assetID);
_storePrice(witnetResponse);
return lastGoodPrice;
}
function _getCurrentWitnetResponse(bytes32 _assetID) internal view returns(WitnetResponse memory response) {
try witnet.valueFor(_assetID) returns (
int256 value,
uint256 _timestamp,
uint256 status
) {
response.value = value;
response._timestamp = _timestamp;
response.status = status;
} catch {
// If call to Chainlink aggregator reverts, return a zero response with success = false
return response;
}
}
function _storePrice(WitnetResponse memory witnetResponse) internal {
require(witnetResponse.status == 200, "witnet Response is not 200. response error.");
uint goodPrice = _scaleWitnetPriceByDigits(uint(witnetResponse.value), 6);
if (goodPrice != lastGoodPrice) {
lastGoodPrice = goodPrice;
emit LastGoodPriceUpdated(lastGoodPrice);
}
}
function _scaleWitnetPriceByDigits(uint _price, uint _answerDigits) internal pure returns (uint) {
/*
* Convert the price returned by the Chainlink oracle to an 18-digit decimal for use by Liquity.
* At date of Liquity launch, Chainlink uses an 8-digit price, but we also handle the possibility of
* future changes.
*
*/
uint price;
if (_answerDigits >= TARGET_DIGITS) {
// Scale the returned price value down to Liquity's target precision
price = _price.div(10 ** (_answerDigits - TARGET_DIGITS));
}
else if (_answerDigits < TARGET_DIGITS) {
// Scale the returned price value up to Liquity's target precision
price = _price.mul(10 ** (TARGET_DIGITS - _answerDigits));
}
return price;
}
}
总结
地址:https://github.com/shanxuanch...
总体而言没有什么技术难度,就是一个定时脚步读写任务而已。中心化的预言机服务是比较简单的,但是去中心化就非常有难度了。现在为止有接近$300W的TVL了,虽然token的价格波动很大,但是我内心非常有信心。原因?可能是我提前知道各种利好吧。如果Token解锁了,我想所有帮助我一路上爬过来的人都分发一部分token,想了想,可能这是我去北京之前唯一能拿得出手的礼物了。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。