This commit is contained in:
Noah Zinsmeister
2019-10-31 17:46:25 -04:00
parent 88b63ccee0
commit 8cb70d07b2
9 changed files with 74 additions and 46 deletions

View File

@ -2,64 +2,85 @@ pragma solidity 0.5.12;
import "../interfaces/IUniswapV2.sol";
import "../libraries/Math.sol";
contract Oracle {
using Math for uint256;
struct TokenData {
uint128 token0;
uint128 token1;
}
struct Time {
struct TimeData {
uint64 blockNumber;
uint64 blockTimestamp;
}
address public exchange;
uint128 constant period = 1 days;
bool public initialized;
uint64 constant period = 1 days;
TokenData private reservesCumulative;
Time private lastUpdate;
TimeData private lastUpdate;
TokenData private currentPrice;
constructor(address _exchange) public {
exchange = _exchange;
}
function _updateCurrentPrice(TokenData memory averages, uint128 timestampDelta) private {
function _updateCurrentPrice(TokenData memory averages, uint64 timeElapsed) private {
TokenData memory nextPrice;
if (timestampDelta >= period || (currentPrice.token0 == 0 && currentPrice.token1 == 0)) {
if (timeElapsed >= period || (currentPrice.token0 == 0 && currentPrice.token1 == 0)) {
nextPrice = averages;
} else {
nextPrice = TokenData({
token0: (currentPrice.token0 * (period - timestampDelta) + averages.token0 * timestampDelta) / period,
token1: (currentPrice.token1 * (period - timestampDelta) + averages.token1 * timestampDelta) / period
token0: (currentPrice.token0 * (period - timeElapsed) + averages.token0 * timeElapsed) / period,
token1: (currentPrice.token1 * (period - timeElapsed) + averages.token1 * timeElapsed) / period
});
}
currentPrice = nextPrice;
}
function updateCurrentPrice() external {
IUniswapV2 uniswapV2 = IUniswapV2(exchange);
// TODO handle the case where time has passed (basically, always use the most up-to-date data)
(uint128 reserveCumulativeToken0, uint128 reserveCumulativeToken1) = uniswapV2.getReservesCumulative();
(uint64 blockNumber, uint64 blockTimestamp) = uniswapV2.getLastUpdate();
function initialize() external {
require(!initialized, "Oracle: ALREADY_INITIALIZED");
IUniswapV2 uniswapV2 = IUniswapV2(exchange);
(uint128 reserveCumulativeToken0, uint128 reserveCumulativeToken1) = uniswapV2.getReservesCumulative();
reservesCumulative.token0 = reserveCumulativeToken0;
reservesCumulative.token1 = reserveCumulativeToken1;
lastUpdate.blockNumber = block.number.downcastTo64();
lastUpdate.blockTimestamp = block.timestamp.downcastTo64();
initialized = true;
}
function updateCurrentPrice() external {
require(initialized, "Oracle: UNINITIALIZED");
uint64 blockNumber = block.number.downcastTo64();
// if we haven't updated this block yet...
if (blockNumber > lastUpdate.blockNumber) {
IUniswapV2 uniswapV2 = IUniswapV2(exchange);
(uint128 reserveCumulativeToken0, uint128 reserveCumulativeToken1) = uniswapV2.getReservesCumulative();
uint128 blocksElapsed = blockNumber - lastUpdate.blockNumber;
if (lastUpdate.blockNumber != 0) {
TokenData memory deltas = TokenData({
token0: reserveCumulativeToken0 - reservesCumulative.token0,
token1: reserveCumulativeToken1 - reservesCumulative.token1
});
TokenData memory deltas = TokenData({
token0: reserveCumulativeToken0 - reservesCumulative.token0,
token1: reserveCumulativeToken1 - reservesCumulative.token1
});
TokenData memory averages = TokenData({
token0: deltas.token0 / blocksElapsed,
token1: deltas.token1 / blocksElapsed
});
TokenData memory averages = TokenData({
token0: deltas.token0 / blocksElapsed,
token1: deltas.token1 / blocksElapsed
});
uint128 timeElapsed = blockTimestamp - lastUpdate.blockTimestamp;
_updateCurrentPrice(averages, timeElapsed);
}
uint64 blockTimestamp = block.timestamp.downcastTo64();
uint64 timeElapsed = blockTimestamp - lastUpdate.blockTimestamp;
_updateCurrentPrice(averages, timeElapsed);
reservesCumulative.token0 = reserveCumulativeToken0;
reservesCumulative.token1 = reserveCumulativeToken1;