Address Details
contract
0xa9c7211d0201c37fdC9767c196c83736cDb80c4D
- Contract Name
- SlidingWindowOracle
- Creator
- 0xe59f13–f1e2b8 at 0xca1654–683d56
- Balance
- 0 CELO ( )
- Locked CELO Balance
- 0.00 CELO
- Voting CELO Balance
- 0.00 CELO
- Pending Unlocked Gold
- 0.00 CELO
- Tokens
-
Fetching tokens...
- Transactions
- 2,842 Transactions
- Transfers
- 0 Transfers
- Gas Used
- 137,503,851
- Last Balance Update
- 13564788
This contract has been verified via Sourcify.
View contract in Sourcify repository
- Contract name:
- SlidingWindowOracle
- Optimization enabled
- true
- Compiler version
- v0.6.6+commit.6c089d02
- Optimization runs
- 999999
- EVM Version
- istanbul
- Verified at
- 2022-06-14T18:21:22.384216Z
contracts/SlidingWindowOracle.sol
pragma solidity =0.6.6; import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol"; import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol"; import "@uniswap/lib/contracts/libraries/FixedPoint.sol"; import "./libraries/SafeMath.sol"; import "./libraries/UniswapV2Library.sol"; import "./libraries/UniswapV2OracleLibrary.sol"; // sliding window oracle that uses observations collected over a window to provide moving price averages in the past // `windowSize` with a precision of `windowSize / granularity` // note this is a singleton oracle and only needs to be deployed once per desired parameters, which // differs from the simple oracle which must be deployed once per pair. contract SlidingWindowOracle { using FixedPoint for *; using SafeMath for uint256; struct Observation { uint256 timestamp; uint256 price0Cumulative; uint256 price1Cumulative; } address public immutable factory; // the desired amount of time over which the moving average should be computed, e.g. 24 hours uint256 public immutable windowSize; // the number of observations stored for each pair, i.e. how many price observations are stored for the window. // as granularity increases from 1, more frequent updates are needed, but moving averages become more precise. // averages are computed over intervals with sizes in the range: // [windowSize - (windowSize / granularity) * 2, windowSize] // e.g. if the window size is 24 hours, and the granularity is 24, the oracle will return the average price for // the period: // [now - [22 hours, 24 hours], now] uint8 public immutable granularity; // this is redundant with granularity and windowSize, but stored for gas savings & informational purposes. uint256 public immutable periodSize; // mapping from pair address to a list of price observations of that pair mapping(address => Observation[]) public pairObservations; constructor( address factory_, uint256 windowSize_, uint8 granularity_ ) public { require(granularity_ > 1, "SlidingWindowOracle: GRANULARITY"); require( (periodSize = windowSize_ / granularity_) * granularity_ == windowSize_, "SlidingWindowOracle: WINDOW_NOT_EVENLY_DIVISIBLE" ); factory = factory_; windowSize = windowSize_; granularity = granularity_; } // returns the index of the observation corresponding to the given timestamp function observationIndexOf(uint256 timestamp) public view returns (uint8 index) { uint256 epochPeriod = timestamp / periodSize; return uint8(epochPeriod % granularity); } // returns the observation from the oldest epoch (at the beginning of the window) relative to the current time function getFirstObservationInWindow(address pair) private view returns (Observation storage firstObservation) { uint8 observationIndex = observationIndexOf(block.timestamp); // no overflow issue. if observationIndex + 1 overflows, result is still zero. uint8 firstObservationIndex = (observationIndex + 1) % granularity; firstObservation = pairObservations[pair][firstObservationIndex]; } // update the cumulative price for the observation at the current timestamp. each observation is updated at most // once per epoch period. function update(address tokenA, address tokenB) external { address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB); // populate the array with empty observations (first call only) for (uint256 i = pairObservations[pair].length; i < granularity; i++) { pairObservations[pair].push(); } // get the observation for the current period uint8 observationIndex = observationIndexOf(block.timestamp); Observation storage observation = pairObservations[pair][ observationIndex ]; // we only want to commit updates once per period (i.e. windowSize / granularity) uint256 timeElapsed = block.timestamp - observation.timestamp; if (timeElapsed > periodSize) { ( uint256 price0Cumulative, uint256 price1Cumulative, ) = UniswapV2OracleLibrary.currentCumulativePrices(pair); observation.timestamp = block.timestamp; observation.price0Cumulative = price0Cumulative; observation.price1Cumulative = price1Cumulative; } } // given the cumulative prices of the start and end of a period, and the length of the period, compute the average // price in terms of how much amount out is received for the amount in function computeAmountOut( uint256 priceCumulativeStart, uint256 priceCumulativeEnd, uint256 timeElapsed, uint256 amountIn ) private pure returns (uint256 amountOut) { // overflow is desired. FixedPoint.uq112x112 memory priceAverage = FixedPoint.uq112x112( uint224((priceCumulativeEnd - priceCumulativeStart) / timeElapsed) ); amountOut = priceAverage.mul(amountIn).decode144(); } // returns the amount out corresponding to the amount in for a given token using the moving average over the time // range [now - [windowSize, windowSize - periodSize * 2], now] // update must have been called for the bucket corresponding to timestamp `now - windowSize` function consult( address tokenIn, uint256 amountIn, address tokenOut ) external view returns (uint256 amountOut) { address pair = UniswapV2Library.pairFor(factory, tokenIn, tokenOut); Observation storage firstObservation = getFirstObservationInWindow( pair ); uint256 timeElapsed = block.timestamp - firstObservation.timestamp; require( timeElapsed <= windowSize, "SlidingWindowOracle: MISSING_HISTORICAL_OBSERVATION" ); // should never happen. require( timeElapsed >= windowSize - periodSize * 2, "SlidingWindowOracle: UNEXPECTED_TIME_ELAPSED" ); ( uint256 price0Cumulative, uint256 price1Cumulative, ) = UniswapV2OracleLibrary.currentCumulativePrices(pair); (address token0, ) = UniswapV2Library.sortTokens(tokenIn, tokenOut); if (token0 == tokenIn) { return computeAmountOut( firstObservation.price0Cumulative, price0Cumulative, timeElapsed, amountIn ); } else { return computeAmountOut( firstObservation.price1Cumulative, price1Cumulative, timeElapsed, amountIn ); } } }
/_uniswap/lib/contracts/libraries/Babylonian.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.4.0; // computes square roots using the babylonian method // https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method library Babylonian { // credit for this implementation goes to // https://github.com/abdk-consulting/abdk-libraries-solidity/blob/master/ABDKMath64x64.sol#L687 function sqrt(uint256 x) internal pure returns (uint256) { if (x == 0) return 0; // this block is equivalent to r = uint256(1) << (BitMath.mostSignificantBit(x) / 2); // however that code costs significantly more gas uint256 xx = x; uint256 r = 1; if (xx >= 0x100000000000000000000000000000000) { xx >>= 128; r <<= 64; } if (xx >= 0x10000000000000000) { xx >>= 64; r <<= 32; } if (xx >= 0x100000000) { xx >>= 32; r <<= 16; } if (xx >= 0x10000) { xx >>= 16; r <<= 8; } if (xx >= 0x100) { xx >>= 8; r <<= 4; } if (xx >= 0x10) { xx >>= 4; r <<= 2; } if (xx >= 0x8) { r <<= 1; } r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; // Seven iterations should be enough uint256 r1 = x / r; return (r < r1 ? r : r1); } }
/_uniswap/lib/contracts/libraries/BitMath.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.5.0; library BitMath { // returns the 0 indexed position of the most significant bit of the input x // s.t. x >= 2**msb and x < 2**(msb+1) function mostSignificantBit(uint256 x) internal pure returns (uint8 r) { require(x > 0, 'BitMath::mostSignificantBit: zero'); if (x >= 0x100000000000000000000000000000000) { x >>= 128; r += 128; } if (x >= 0x10000000000000000) { x >>= 64; r += 64; } if (x >= 0x100000000) { x >>= 32; r += 32; } if (x >= 0x10000) { x >>= 16; r += 16; } if (x >= 0x100) { x >>= 8; r += 8; } if (x >= 0x10) { x >>= 4; r += 4; } if (x >= 0x4) { x >>= 2; r += 2; } if (x >= 0x2) r += 1; } // returns the 0 indexed position of the least significant bit of the input x // s.t. (x & 2**lsb) != 0 and (x & (2**(lsb) - 1)) == 0) // i.e. the bit at the index is set and the mask of all lower bits is 0 function leastSignificantBit(uint256 x) internal pure returns (uint8 r) { require(x > 0, 'BitMath::leastSignificantBit: zero'); r = 255; if (x & uint128(-1) > 0) { r -= 128; } else { x >>= 128; } if (x & uint64(-1) > 0) { r -= 64; } else { x >>= 64; } if (x & uint32(-1) > 0) { r -= 32; } else { x >>= 32; } if (x & uint16(-1) > 0) { r -= 16; } else { x >>= 16; } if (x & uint8(-1) > 0) { r -= 8; } else { x >>= 8; } if (x & 0xf > 0) { r -= 4; } else { x >>= 4; } if (x & 0x3 > 0) { r -= 2; } else { x >>= 2; } if (x & 0x1 > 0) r -= 1; } }
/_uniswap/lib/contracts/libraries/FixedPoint.sol
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.4.0; import './FullMath.sol'; import './Babylonian.sol'; import './BitMath.sol'; // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format)) library FixedPoint { // range: [0, 2**112 - 1] // resolution: 1 / 2**112 struct uq112x112 { uint224 _x; } // range: [0, 2**144 - 1] // resolution: 1 / 2**112 struct uq144x112 { uint256 _x; } uint8 public constant RESOLUTION = 112; uint256 public constant Q112 = 0x10000000000000000000000000000; // 2**112 uint256 private constant Q224 = 0x100000000000000000000000000000000000000000000000000000000; // 2**224 uint256 private constant LOWER_MASK = 0xffffffffffffffffffffffffffff; // decimal of UQ*x112 (lower 112 bits) // encode a uint112 as a UQ112x112 function encode(uint112 x) internal pure returns (uq112x112 memory) { return uq112x112(uint224(x) << RESOLUTION); } // encodes a uint144 as a UQ144x112 function encode144(uint144 x) internal pure returns (uq144x112 memory) { return uq144x112(uint256(x) << RESOLUTION); } // decode a UQ112x112 into a uint112 by truncating after the radix point function decode(uq112x112 memory self) internal pure returns (uint112) { return uint112(self._x >> RESOLUTION); } // decode a UQ144x112 into a uint144 by truncating after the radix point function decode144(uq144x112 memory self) internal pure returns (uint144) { return uint144(self._x >> RESOLUTION); } // multiply a UQ112x112 by a uint, returning a UQ144x112 // reverts on overflow function mul(uq112x112 memory self, uint256 y) internal pure returns (uq144x112 memory) { uint256 z = 0; require(y == 0 || (z = self._x * y) / y == self._x, 'FixedPoint::mul: overflow'); return uq144x112(z); } // multiply a UQ112x112 by an int and decode, returning an int // reverts on overflow function muli(uq112x112 memory self, int256 y) internal pure returns (int256) { uint256 z = FullMath.mulDiv(self._x, uint256(y < 0 ? -y : y), Q112); require(z < 2**255, 'FixedPoint::muli: overflow'); return y < 0 ? -int256(z) : int256(z); } // multiply a UQ112x112 by a UQ112x112, returning a UQ112x112 // lossy function muluq(uq112x112 memory self, uq112x112 memory other) internal pure returns (uq112x112 memory) { if (self._x == 0 || other._x == 0) { return uq112x112(0); } uint112 upper_self = uint112(self._x >> RESOLUTION); // * 2^0 uint112 lower_self = uint112(self._x & LOWER_MASK); // * 2^-112 uint112 upper_other = uint112(other._x >> RESOLUTION); // * 2^0 uint112 lower_other = uint112(other._x & LOWER_MASK); // * 2^-112 // partial products uint224 upper = uint224(upper_self) * upper_other; // * 2^0 uint224 lower = uint224(lower_self) * lower_other; // * 2^-224 uint224 uppers_lowero = uint224(upper_self) * lower_other; // * 2^-112 uint224 uppero_lowers = uint224(upper_other) * lower_self; // * 2^-112 // so the bit shift does not overflow require(upper <= uint112(-1), 'FixedPoint::muluq: upper overflow'); // this cannot exceed 256 bits, all values are 224 bits uint256 sum = uint256(upper << RESOLUTION) + uppers_lowero + uppero_lowers + (lower >> RESOLUTION); // so the cast does not overflow require(sum <= uint224(-1), 'FixedPoint::muluq: sum overflow'); return uq112x112(uint224(sum)); } // divide a UQ112x112 by a UQ112x112, returning a UQ112x112 function divuq(uq112x112 memory self, uq112x112 memory other) internal pure returns (uq112x112 memory) { require(other._x > 0, 'FixedPoint::divuq: division by zero'); if (self._x == other._x) { return uq112x112(uint224(Q112)); } if (self._x <= uint144(-1)) { uint256 value = (uint256(self._x) << RESOLUTION) / other._x; require(value <= uint224(-1), 'FixedPoint::divuq: overflow'); return uq112x112(uint224(value)); } uint256 result = FullMath.mulDiv(Q112, self._x, other._x); require(result <= uint224(-1), 'FixedPoint::divuq: overflow'); return uq112x112(uint224(result)); } // returns a UQ112x112 which represents the ratio of the numerator to the denominator // can be lossy function fraction(uint256 numerator, uint256 denominator) internal pure returns (uq112x112 memory) { require(denominator > 0, 'FixedPoint::fraction: division by zero'); if (numerator == 0) return FixedPoint.uq112x112(0); if (numerator <= uint144(-1)) { uint256 result = (numerator << RESOLUTION) / denominator; require(result <= uint224(-1), 'FixedPoint::fraction: overflow'); return uq112x112(uint224(result)); } else { uint256 result = FullMath.mulDiv(numerator, Q112, denominator); require(result <= uint224(-1), 'FixedPoint::fraction: overflow'); return uq112x112(uint224(result)); } } // take the reciprocal of a UQ112x112 // reverts on overflow // lossy function reciprocal(uq112x112 memory self) internal pure returns (uq112x112 memory) { require(self._x != 0, 'FixedPoint::reciprocal: reciprocal of zero'); require(self._x != 1, 'FixedPoint::reciprocal: overflow'); return uq112x112(uint224(Q224 / self._x)); } // square root of a UQ112x112 // lossy between 0/1 and 40 bits function sqrt(uq112x112 memory self) internal pure returns (uq112x112 memory) { if (self._x <= uint144(-1)) { return uq112x112(uint224(Babylonian.sqrt(uint256(self._x) << 112))); } uint8 safeShiftBits = 255 - BitMath.mostSignificantBit(self._x); safeShiftBits -= safeShiftBits % 2; return uq112x112(uint224(Babylonian.sqrt(uint256(self._x) << safeShiftBits) << ((112 - safeShiftBits) / 2))); } }
/_uniswap/lib/contracts/libraries/FullMath.sol
// SPDX-License-Identifier: CC-BY-4.0 pragma solidity >=0.4.0; // taken from https://medium.com/coinmonks/math-in-solidity-part-3-percents-and-proportions-4db014e080b1 // license is CC-BY-4.0 library FullMath { function fullMul(uint256 x, uint256 y) internal pure returns (uint256 l, uint256 h) { uint256 mm = mulmod(x, y, uint256(-1)); l = x * y; h = mm - l; if (mm < l) h -= 1; } function fullDiv( uint256 l, uint256 h, uint256 d ) private pure returns (uint256) { uint256 pow2 = d & -d; d /= pow2; l /= pow2; l += h * ((-pow2) / pow2 + 1); uint256 r = 1; r *= 2 - d * r; r *= 2 - d * r; r *= 2 - d * r; r *= 2 - d * r; r *= 2 - d * r; r *= 2 - d * r; r *= 2 - d * r; r *= 2 - d * r; return l * r; } function mulDiv( uint256 x, uint256 y, uint256 d ) internal pure returns (uint256) { (uint256 l, uint256 h) = fullMul(x, y); uint256 mm = mulmod(x, y, d); if (mm > l) h -= 1; l -= mm; if (h == 0) return l / d; require(h < d, 'FullMath: FULLDIV_OVERFLOW'); return fullDiv(l, h, d); } }
/_uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol
pragma solidity >=0.5.0; interface IUniswapV2Factory { event PairCreated(address indexed token0, address indexed token1, address pair, uint); function feeTo() external view returns (address); function feeToSetter() external view returns (address); function getPair(address tokenA, address tokenB) external view returns (address pair); function allPairs(uint) external view returns (address pair); function allPairsLength() external view returns (uint); function createPair(address tokenA, address tokenB) external returns (address pair); function setFeeTo(address) external; function setFeeToSetter(address) external; }
/_uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol
pragma solidity >=0.5.0; interface IUniswapV2Pair { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function price0CumulativeLast() external view returns (uint); function price1CumulativeLast() external view returns (uint); function kLast() external view returns (uint); function mint(address to) external returns (uint liquidity); function burn(address to) external returns (uint amount0, uint amount1); function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; function skim(address to) external; function sync() external; function initialize(address, address) external; }
/contracts/libraries/SafeMath.sol
pragma solidity =0.6.6; // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) library SafeMath { function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x, "ds-math-add-overflow"); } function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x, "ds-math-sub-underflow"); } function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow"); } }
/contracts/libraries/UniswapV2Library.sol
pragma solidity >=0.5.0; import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol"; import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol"; import "./SafeMath.sol"; library UniswapV2Library { using SafeMath for uint256; // returns sorted token addresses, used to handle return values from pairs sorted in this order function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { require(tokenA != tokenB, "UniswapV2Library: IDENTICAL_ADDRESSES"); (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0), "UniswapV2Library: ZERO_ADDRESS"); } function pairFor( address factory, address tokenA, address tokenB ) internal view returns (address pair) { (address token0, address token1) = sortTokens(tokenA, tokenB); pair = IUniswapV2Factory(factory).getPair(token0, token1); } // fetches and sorts the reserves for a pair function getReserves( address factory, address tokenA, address tokenB ) internal view returns (uint256 reserveA, uint256 reserveB) { (address token0, ) = sortTokens(tokenA, tokenB); (uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair( pairFor(factory, tokenA, tokenB) ).getReserves(); (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0); } // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset function quote( uint256 amountA, uint256 reserveA, uint256 reserveB ) internal pure returns (uint256 amountB) { require(amountA > 0, "UniswapV2Library: INSUFFICIENT_AMOUNT"); require( reserveA > 0 && reserveB > 0, "UniswapV2Library: INSUFFICIENT_LIQUIDITY" ); amountB = amountA.mul(reserveB) / reserveA; } // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset function getAmountOut( uint256 amountIn, uint256 reserveIn, uint256 reserveOut ) internal pure returns (uint256 amountOut) { require(amountIn > 0, "UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT"); require( reserveIn > 0 && reserveOut > 0, "UniswapV2Library: INSUFFICIENT_LIQUIDITY" ); uint256 amountInWithFee = amountIn.mul(997); uint256 numerator = amountInWithFee.mul(reserveOut); uint256 denominator = reserveIn.mul(1000).add(amountInWithFee); amountOut = numerator / denominator; } // given an output amount of an asset and pair reserves, returns a required input amount of the other asset function getAmountIn( uint256 amountOut, uint256 reserveIn, uint256 reserveOut ) internal pure returns (uint256 amountIn) { require(amountOut > 0, "UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT"); require( reserveIn > 0 && reserveOut > 0, "UniswapV2Library: INSUFFICIENT_LIQUIDITY" ); uint256 numerator = reserveIn.mul(amountOut).mul(1000); uint256 denominator = reserveOut.sub(amountOut).mul(997); amountIn = (numerator / denominator).add(1); } // performs chained getAmountOut calculations on any number of pairs function getAmountsOut( address factory, uint256 amountIn, address[] memory path ) internal view returns (uint256[] memory amounts) { require(path.length >= 2, "UniswapV2Library: INVALID_PATH"); amounts = new uint256[](path.length); amounts[0] = amountIn; for (uint256 i; i < path.length - 1; i++) { (uint256 reserveIn, uint256 reserveOut) = getReserves( factory, path[i], path[i + 1] ); amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut); } } // performs chained getAmountIn calculations on any number of pairs function getAmountsIn( address factory, uint256 amountOut, address[] memory path ) internal view returns (uint256[] memory amounts) { require(path.length >= 2, "UniswapV2Library: INVALID_PATH"); amounts = new uint256[](path.length); amounts[amounts.length - 1] = amountOut; for (uint256 i = path.length - 1; i > 0; i--) { (uint256 reserveIn, uint256 reserveOut) = getReserves( factory, path[i - 1], path[i] ); amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); } } }
/contracts/libraries/UniswapV2OracleLibrary.sol
pragma solidity >=0.5.0; import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol"; import "@uniswap/lib/contracts/libraries/FixedPoint.sol"; // library with helper methods for oracles that are concerned with computing average prices library UniswapV2OracleLibrary { using FixedPoint for *; // helper function that returns the current block timestamp within the range of uint32, i.e. [0, 2**32 - 1] function currentBlockTimestamp() internal view returns (uint32) { return uint32(block.timestamp % 2**32); } // produces the cumulative price using counterfactuals to save gas and avoid a call to sync. function currentCumulativePrices(address pair) internal view returns ( uint256 price0Cumulative, uint256 price1Cumulative, uint32 blockTimestamp ) { blockTimestamp = currentBlockTimestamp(); price0Cumulative = IUniswapV2Pair(pair).price0CumulativeLast(); price1Cumulative = IUniswapV2Pair(pair).price1CumulativeLast(); // if time has elapsed since the last update on the pair, mock the accumulated price values ( uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast ) = IUniswapV2Pair(pair).getReserves(); if (blockTimestampLast != blockTimestamp) { // subtraction overflow is desired uint32 timeElapsed = blockTimestamp - blockTimestampLast; // addition overflow is desired // counterfactual price0Cumulative += uint256(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed; // counterfactual price1Cumulative += uint256(FixedPoint.fraction(reserve0, reserve1)._x) * timeElapsed; } } }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"factory_","internalType":"address"},{"type":"uint256","name":"windowSize_","internalType":"uint256"},{"type":"uint8","name":"granularity_","internalType":"uint8"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"amountOut","internalType":"uint256"}],"name":"consult","inputs":[{"type":"address","name":"tokenIn","internalType":"address"},{"type":"uint256","name":"amountIn","internalType":"uint256"},{"type":"address","name":"tokenOut","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"factory","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"granularity","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"index","internalType":"uint8"}],"name":"observationIndexOf","inputs":[{"type":"uint256","name":"timestamp","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"timestamp","internalType":"uint256"},{"type":"uint256","name":"price0Cumulative","internalType":"uint256"},{"type":"uint256","name":"price1Cumulative","internalType":"uint256"}],"name":"pairObservations","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"periodSize","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"update","inputs":[{"type":"address","name":"tokenA","internalType":"address"},{"type":"address","name":"tokenB","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"windowSize","inputs":[]}]
Contract Creation Code
0x61010060405234801561001157600080fd5b5060405161136b38038061136b8339818101604052606081101561003457600080fd5b5080516020820151604090920151909190600160ff82161161009d576040805162461bcd60e51b815260206004820181905260248201527f536c6964696e6757696e646f774f7261636c653a204752414e554c4152495459604482015290519081900360640190fd5b8160ff82168082816100ab57fe5b0460e081905202146100ee5760405162461bcd60e51b815260040180806020018281038252603081526020018061133b6030913960400191505060405180910390fd5b606083901b6001600160601b03191660805260a082905260f881901b7fff000000000000000000000000000000000000000000000000000000000000001660c05260e0516001600160a01b039093169260ff9091169061119c61019f600039806102f7528061059452806105e752806106475250806101f452806104d75280610613528061073d525080610218528061027e528061031b525080610242528061045c5280610485525061119c6000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063c45a01551161005b578063c45a01551461015f578063c640752d14610190578063dbaad32f146101cd578063e4463eb2146101ea57610088565b8063556f0dc71461008d5780638a14117a146100ab5780638c86f1e4146100c5578063bfcc8e4214610108575b600080fd5b6100956101f2565b6040805160ff9092168252519081900360200190f35b6100b3610216565b60408051918252519081900360200190f35b6100b3600480360360608110156100db57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040909101351661023a565b6101416004803603604081101561011e57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813516906020013561041b565b60408051938452602084019290925282820152519081900360600190f35b61016761045a565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6101cb600480360360408110156101a657600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602001351661047e565b005b610095600480360360208110156101e357600080fd5b50356105e2565b6100b3610645565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000806102687f00000000000000000000000000000000000000000000000000000000000000008685610669565b905060006102758261072b565b805490915042037f00000000000000000000000000000000000000000000000000000000000000008111156102f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806110bd6033913960400191505060405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006002027f000000000000000000000000000000000000000000000000000000000000000003811015610393576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c8152602001806110f0602c913960400191505060405180910390fd5b60008061039f856107d3565b509150915060006103b08a89610a5a565b5090508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610404576103f7856001015484868c610bad565b9650505050505050610414565b6103f7856002015483868c610bad565b9392505050565b6000602052816000526040600020818154811061043457fe5b600091825260209091206003909102018054600182015460029092015490935090915083565b7f000000000000000000000000000000000000000000000000000000000000000081565b60006104ab7f00000000000000000000000000000000000000000000000000000000000000008484610669565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081905260409020549091505b7f000000000000000000000000000000000000000000000000000000000000000060ff168110156105365773ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604081208054600190810182559152016104d5565b506000610542426105e2565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604081208054929350909160ff841690811061057b57fe5b60009182526020909120600390910201805490915042037f00000000000000000000000000000000000000000000000000000000000000008111156105da576000806105c6866107d3565b504286556001860191909155600285015550505b505050505050565b6000807f0000000000000000000000000000000000000000000000000000000000000000838161060e57fe5b0490507f000000000000000000000000000000000000000000000000000000000000000060ff16818161063d57fe5b069392505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60008060006106788585610a5a565b604080517fe6a4390500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff80851660048301528084166024830152915193955091935088169163e6a4390591604480820192602092909190829003018186803b1580156106f557600080fd5b505afa158015610709573d6000803e3d6000fd5b505050506040513d602081101561071f57600080fd5b50519695505050505050565b600080610737426105e2565b905060007f000000000000000000000000000000000000000000000000000000000000000060ff168260010160ff168161076d57fe5b0690506000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208160ff16815481106107bc57fe5b906000526020600020906003020192505050919050565b60008060006107e0610c20565b90508373ffffffffffffffffffffffffffffffffffffffff16635909c0d56040518163ffffffff1660e01b815260040160206040518083038186803b15801561082857600080fd5b505afa15801561083c573d6000803e3d6000fd5b505050506040513d602081101561085257600080fd5b5051604080517f5a3d5493000000000000000000000000000000000000000000000000000000008152905191945073ffffffffffffffffffffffffffffffffffffffff861691635a3d549391600480820192602092909190829003018186803b1580156108be57600080fd5b505afa1580156108d2573d6000803e3d6000fd5b505050506040513d60208110156108e857600080fd5b5051604080517f0902f1ac00000000000000000000000000000000000000000000000000000000815290519193506000918291829173ffffffffffffffffffffffffffffffffffffffff891691630902f1ac916004808301926060929190829003018186803b15801561095a57600080fd5b505afa15801561096e573d6000803e3d6000fd5b505050506040513d606081101561098457600080fd5b5080516020820151604090920151909450909250905063ffffffff80821690851614610a505780840363ffffffff81166109d16dffffffffffffffffffffffffffff808616908716610c2a565b600001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1602870196508063ffffffff16610a29856dffffffffffffffffffffffffffff16856dffffffffffffffffffffffffffff16610c2a565b517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16029590950194505b5050509193909250565b6000808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415610ae2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602581526020018061111c6025913960400191505060405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1610610b1c578284610b1f565b83835b909250905073ffffffffffffffffffffffffffffffffffffffff8216610ba657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a205a45524f5f414444524553530000604482015290519081900360640190fd5b9250929050565b6000610bb7611097565b60405180602001604052808588880381610bcd57fe5b047bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690529050610c02610bfd8285610e3f565b610f02565b71ffffffffffffffffffffffffffffffffffff169695505050505050565b63ffffffff421690565b610c32611097565b60008211610c8b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806111416026913960400191505060405180910390fd5b82610ca55750604080516020810190915260008152610e39565b71ffffffffffffffffffffffffffffffffffff8311610d9057600082607085901b81610ccd57fe5b0490507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811115610d5b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4669786564506f696e743a3a6672616374696f6e3a206f766572666c6f770000604482015290519081900360640190fd5b6040518060200160405280827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16815250915050610e39565b6000610dac846e01000000000000000000000000000085610f09565b90507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811115610d5b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4669786564506f696e743a3a6672616374696f6e3a206f766572666c6f770000604482015290519081900360640190fd5b92915050565b610e476110a9565b6000821580610e8257505082517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1682810290838281610e7f57fe5b04145b610eed57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4669786564506f696e743a3a6d756c3a206f766572666c6f7700000000000000604482015290519081900360640190fd5b60408051602081019091529081529392505050565b5160701c90565b6000806000610f188686610fdc565b9150915060008480610f2657fe5b868809905082811115610f3a576001820391505b918290039181610f5857848381610f4d57fe5b049350505050610414565b848210610fc657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f46756c6c4d6174683a2046554c4c4449565f4f564552464c4f57000000000000604482015290519081900360640190fd5b610fd1838387611027565b979650505050505050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8486099050838502925082810391508281101561101f576001820391505b509250929050565b6000818103821680838161103757fe5b04925080858161104357fe5b04945080816000038161105257fe5b60028581038087028203028087028203028087028203028087028203028087028203028087028203029586029003909402930460010193909302939093010292915050565b60408051602081019091526000815290565b604051806020016040528060008152509056fe536c6964696e6757696e646f774f7261636c653a204d495353494e475f484953544f524943414c5f4f42534552564154494f4e536c6964696e6757696e646f774f7261636c653a20554e45585045435445445f54494d455f454c4150534544556e697377617056324c6962726172793a204944454e544943414c5f4144445245535345534669786564506f696e743a3a6672616374696f6e3a206469766973696f6e206279207a65726fa2646970667358221220488b0fc6ff36f00947d18ab620c6ce82823b17e4475325b9008e26123d8ab00064736f6c63430006060033536c6964696e6757696e646f774f7261636c653a2057494e444f575f4e4f545f4556454e4c595f444956495349424c4500000000000000000000000062d5b84be28a183abb507e125b384122d2c25fae0000000000000000000000000000000000000000000000000000000000000e10000000000000000000000000000000000000000000000000000000000000003c
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106100885760003560e01c8063c45a01551161005b578063c45a01551461015f578063c640752d14610190578063dbaad32f146101cd578063e4463eb2146101ea57610088565b8063556f0dc71461008d5780638a14117a146100ab5780638c86f1e4146100c5578063bfcc8e4214610108575b600080fd5b6100956101f2565b6040805160ff9092168252519081900360200190f35b6100b3610216565b60408051918252519081900360200190f35b6100b3600480360360608110156100db57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135916040909101351661023a565b6101416004803603604081101561011e57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813516906020013561041b565b60408051938452602084019290925282820152519081900360600190f35b61016761045a565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6101cb600480360360408110156101a657600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602001351661047e565b005b610095600480360360208110156101e357600080fd5b50356105e2565b6100b3610645565b7f000000000000000000000000000000000000000000000000000000000000003c81565b7f0000000000000000000000000000000000000000000000000000000000000e1081565b6000806102687f00000000000000000000000062d5b84be28a183abb507e125b384122d2c25fae8685610669565b905060006102758261072b565b805490915042037f0000000000000000000000000000000000000000000000000000000000000e108111156102f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806110bd6033913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000003c6002027f0000000000000000000000000000000000000000000000000000000000000e1003811015610393576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c8152602001806110f0602c913960400191505060405180910390fd5b60008061039f856107d3565b509150915060006103b08a89610a5a565b5090508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610404576103f7856001015484868c610bad565b9650505050505050610414565b6103f7856002015483868c610bad565b9392505050565b6000602052816000526040600020818154811061043457fe5b600091825260209091206003909102018054600182015460029092015490935090915083565b7f00000000000000000000000062d5b84be28a183abb507e125b384122d2c25fae81565b60006104ab7f00000000000000000000000062d5b84be28a183abb507e125b384122d2c25fae8484610669565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081905260409020549091505b7f000000000000000000000000000000000000000000000000000000000000003c60ff168110156105365773ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604081208054600190810182559152016104d5565b506000610542426105e2565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604081208054929350909160ff841690811061057b57fe5b60009182526020909120600390910201805490915042037f000000000000000000000000000000000000000000000000000000000000003c8111156105da576000806105c6866107d3565b504286556001860191909155600285015550505b505050505050565b6000807f000000000000000000000000000000000000000000000000000000000000003c838161060e57fe5b0490507f000000000000000000000000000000000000000000000000000000000000003c60ff16818161063d57fe5b069392505050565b7f000000000000000000000000000000000000000000000000000000000000003c81565b60008060006106788585610a5a565b604080517fe6a4390500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff80851660048301528084166024830152915193955091935088169163e6a4390591604480820192602092909190829003018186803b1580156106f557600080fd5b505afa158015610709573d6000803e3d6000fd5b505050506040513d602081101561071f57600080fd5b50519695505050505050565b600080610737426105e2565b905060007f000000000000000000000000000000000000000000000000000000000000003c60ff168260010160ff168161076d57fe5b0690506000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208160ff16815481106107bc57fe5b906000526020600020906003020192505050919050565b60008060006107e0610c20565b90508373ffffffffffffffffffffffffffffffffffffffff16635909c0d56040518163ffffffff1660e01b815260040160206040518083038186803b15801561082857600080fd5b505afa15801561083c573d6000803e3d6000fd5b505050506040513d602081101561085257600080fd5b5051604080517f5a3d5493000000000000000000000000000000000000000000000000000000008152905191945073ffffffffffffffffffffffffffffffffffffffff861691635a3d549391600480820192602092909190829003018186803b1580156108be57600080fd5b505afa1580156108d2573d6000803e3d6000fd5b505050506040513d60208110156108e857600080fd5b5051604080517f0902f1ac00000000000000000000000000000000000000000000000000000000815290519193506000918291829173ffffffffffffffffffffffffffffffffffffffff891691630902f1ac916004808301926060929190829003018186803b15801561095a57600080fd5b505afa15801561096e573d6000803e3d6000fd5b505050506040513d606081101561098457600080fd5b5080516020820151604090920151909450909250905063ffffffff80821690851614610a505780840363ffffffff81166109d16dffffffffffffffffffffffffffff808616908716610c2a565b600001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1602870196508063ffffffff16610a29856dffffffffffffffffffffffffffff16856dffffffffffffffffffffffffffff16610c2a565b517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16029590950194505b5050509193909250565b6000808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415610ae2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602581526020018061111c6025913960400191505060405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1610610b1c578284610b1f565b83835b909250905073ffffffffffffffffffffffffffffffffffffffff8216610ba657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a205a45524f5f414444524553530000604482015290519081900360640190fd5b9250929050565b6000610bb7611097565b60405180602001604052808588880381610bcd57fe5b047bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690529050610c02610bfd8285610e3f565b610f02565b71ffffffffffffffffffffffffffffffffffff169695505050505050565b63ffffffff421690565b610c32611097565b60008211610c8b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806111416026913960400191505060405180910390fd5b82610ca55750604080516020810190915260008152610e39565b71ffffffffffffffffffffffffffffffffffff8311610d9057600082607085901b81610ccd57fe5b0490507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811115610d5b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4669786564506f696e743a3a6672616374696f6e3a206f766572666c6f770000604482015290519081900360640190fd5b6040518060200160405280827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16815250915050610e39565b6000610dac846e01000000000000000000000000000085610f09565b90507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811115610d5b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4669786564506f696e743a3a6672616374696f6e3a206f766572666c6f770000604482015290519081900360640190fd5b92915050565b610e476110a9565b6000821580610e8257505082517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1682810290838281610e7f57fe5b04145b610eed57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4669786564506f696e743a3a6d756c3a206f766572666c6f7700000000000000604482015290519081900360640190fd5b60408051602081019091529081529392505050565b5160701c90565b6000806000610f188686610fdc565b9150915060008480610f2657fe5b868809905082811115610f3a576001820391505b918290039181610f5857848381610f4d57fe5b049350505050610414565b848210610fc657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f46756c6c4d6174683a2046554c4c4449565f4f564552464c4f57000000000000604482015290519081900360640190fd5b610fd1838387611027565b979650505050505050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8486099050838502925082810391508281101561101f576001820391505b509250929050565b6000818103821680838161103757fe5b04925080858161104357fe5b04945080816000038161105257fe5b60028581038087028203028087028203028087028203028087028203028087028203028087028203029586029003909402930460010193909302939093010292915050565b60408051602081019091526000815290565b604051806020016040528060008152509056fe536c6964696e6757696e646f774f7261636c653a204d495353494e475f484953544f524943414c5f4f42534552564154494f4e536c6964696e6757696e646f774f7261636c653a20554e45585045435445445f54494d455f454c4150534544556e697377617056324c6962726172793a204944454e544943414c5f4144445245535345534669786564506f696e743a3a6672616374696f6e3a206469766973696f6e206279207a65726fa2646970667358221220488b0fc6ff36f00947d18ab620c6ce82823b17e4475325b9008e26123d8ab00064736f6c63430006060033