diff --git a/contracts/DelFiPriceWithOnchainData.sol b/contracts/DelFiPriceWithOnchainData.sol new file mode 100644 index 00000000..b2f20b17 --- /dev/null +++ b/contracts/DelFiPriceWithOnchainData.sol @@ -0,0 +1,114 @@ +pragma solidity ^0.5.0; +pragma experimental ABIEncoderV2; + +import "./OpenOraclePriceData.sol"; +import "./OpenOracleView.sol"; +import "./OpenOracleOnChainInterface.sol"; + +/** + * @notice The DelFi Price Feed View + * @author Compound Labs, Inc. + */ +contract DelFiPriceWithOnchainData is OpenOracleView { + /** + * @notice The event emitted when a price is written to storage + */ + event Price(string symbol, uint64 price); + address[] onChainSources; + /** + * @notice The mapping of medianized prices per symbol + */ + mapping(string => uint64) public prices; + + constructor(OpenOraclePriceData data_, address[] memory sources_,address[] memory onChainSources_) public OpenOracleView(data_, sources_) { + onChainSources = onChainSources_; + } + + function getPrice(string memory _symbol) public returns(uint64){ + return prices[_symbol]; + } + + /** + * @notice Primary entry point to post and recalculate prices + * @dev We let anyone pay to post anything, but only sources count for prices. + * @param messages The messages to post to the oracle + * @param signatures The signatures for the corresponding messages + */ + function postPrices(bytes[] calldata messages, bytes[] calldata signatures, string[] calldata symbols) external { + require(messages.length == signatures.length, "messages and signatures must be 1:1"); + + // Post the messages, whatever they are + for (uint i = 0; i < messages.length; i++) { + OpenOraclePriceData(address(data)).put(messages[i], signatures[i]); + } + + // Recalculate the asset prices for the symbols to update + for (uint i = 0; i < symbols.length; i++) { + string memory symbol = symbols[i]; + + // Calculate the median price, write to storage, and emit an event + uint64 price = medianPrice(symbol, sources); + prices[symbol] = price; + emit Price(symbol, price); + } + } + + /** + * @notice Calculates the median price over any set of sources + * @param symbol The symbol to calculate the median price of + * @param sources_ The sources to use when calculating the median price + * @return median The median price over the set of sources + */ + function medianPrice(string memory symbol, address[] memory sources_) public returns (uint64 median) { + require(sources_.length > 0, "sources list must not be empty"); + uint N = sources_.length; + uint64[] memory postedPrices = new uint64[](N); + for (uint i = 0; i < N; i++) { + postedPrices[i] = OpenOraclePriceData(address(data)).getPrice(sources_[i], symbol); + //should you add check that timestamp is within a certain period? + } + + bool _didGet; + uint _retrievedValue; + uint _timestampRetrieved; + uint64[] memory result = new uint64[](onChainSources.length); + uint tookCount = 0; + for(uint i=0; i< onChainSources.length; i++){ + (_didGet,_retrievedValue,_timestampRetrieved) = OpenOracleOnChainInterface(address(onChainSources[i])).getCurrentValue(symbol); + if(_didGet && _timestampRetrieved > now - 1 days){//or a different threshold (or none like Compound) + result[tookCount] = uint64(_retrievedValue); + tookCount++; + } + } + uint64[] memory allPrices = new uint64[](N + tookCount); + for (uint i=0; i < (N + tookCount); i++) { + if(i array[j]) { + uint64 tmp = array[i]; + array[i] = array[j]; + array[j] = tmp; + } + } + } + return array; + } +} \ No newline at end of file diff --git a/contracts/OpenOracleOnChainInterface.sol b/contracts/OpenOracleOnChainInterface.sol new file mode 100644 index 00000000..267daf9e --- /dev/null +++ b/contracts/OpenOracleOnChainInterface.sol @@ -0,0 +1,20 @@ +pragma solidity ^0.5.0; + + +/*This contract is the interface between the OpenOracle and onChain prices. +Examples of onchain price: + ETH/USD - DAI/ETH price on DEXes + BTC/USD - WBTC/DAI on DEX + Onchain oracles: + Tellor + Chainlink + Zap + Maker DAO ETH/USD price + +*/ + + + +interface OpenOracleOnChainInterface{ + function getCurrentValue(string calldata _symbol) external returns(bool,uint,uint); //_didGet,_value,_timestampRetrieved +} \ No newline at end of file