pragma solidity =0.6.6; import '@eliteswap/v2-core/contracts/interfaces/IEliteswapV2Factory.sol'; import '@eliteswap/v2-core/contracts/interfaces/IEliteswapV2Pair.sol'; import '@eliteswap/lib/contracts/libraries/FixedPoint.sol'; import '../libraries/EliteswapV2OracleLibrary.sol'; import '../libraries/EliteswapV2Library.sol'; // fixed window oracle that recomputes the average price for the entire period once every period // note that the price average is only guaranteed to be over at least 1 period, but may be over a longer period contract ExampleOracleSimple { using FixedPoint for *; uint public constant PERIOD = 24 hours; IEliteswapV2Pair immutable pair; address public immutable token0; address public immutable token1; uint public price0CumulativeLast; uint public price1CumulativeLast; uint32 public blockTimestampLast; FixedPoint.uq112x112 public price0Average; FixedPoint.uq112x112 public price1Average; constructor(address factory, address tokenA, address tokenB) public { IEliteswapV2Pair _pair = IEliteswapV2Pair(EliteswapV2Library.pairFor(factory, tokenA, tokenB)); pair = _pair; token0 = _pair.token0(); token1 = _pair.token1(); price0CumulativeLast = _pair.price0CumulativeLast(); // fetch the current accumulated price value (1 / 0) price1CumulativeLast = _pair.price1CumulativeLast(); // fetch the current accumulated price value (0 / 1) 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 } function update() external { (uint price0Cumulative, uint price1Cumulative, uint32 blockTimestamp) = EliteswapV2OracleLibrary.currentCumulativePrices(address(pair)); uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired // ensure that at least one full period has passed since the last update require(timeElapsed >= PERIOD, 'ExampleOracleSimple: PERIOD_NOT_ELAPSED'); // overflow is desired, casting never truncates // cumulative price is in (uq112x112 price * seconds) units so we simply wrap it after division by time elapsed price0Average = FixedPoint.uq112x112(uint224((price0Cumulative - price0CumulativeLast) / timeElapsed)); price1Average = FixedPoint.uq112x112(uint224((price1Cumulative - price1CumulativeLast) / timeElapsed)); price0CumulativeLast = price0Cumulative; price1CumulativeLast = price1Cumulative; blockTimestampLast = blockTimestamp; } // note this will always return 0 before update has been called successfully for the first time. 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(); } } }