// SPDX-License-Identifier: MIXED pragma solidity 0.6.12; pragma experimental ABIEncoderV2; // solhint-disable not-rely-on-time // File contracts/interfaces/IOracle.sol // License-Identifier: MIT interface IOracle { /// @notice Get the latest exchange rate. /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle. /// For example: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256)); /// @return success if no valid (recent) rate is available, return false else true. /// @return rate The rate of the requested asset / pair / pool. function get(bytes calldata data) external returns (bool success, uint256 rate); /// @notice Check the last exchange rate without any state changes. /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle. /// For example: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256)); /// @return success if no valid (recent) rate is available, return false else true. /// @return rate The rate of the requested asset / pair / pool. function peek(bytes calldata data) external view returns (bool success, uint256 rate); /// @notice Check the current spot exchange rate without any state changes. For oracles like TWAP this will be different from peek(). /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle. /// For example: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256)); /// @return rate The rate of the requested asset / pair / pool. function peekSpot(bytes calldata data) external view returns (uint256 rate); /// @notice Returns a human readable (short) name about this oracle. /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle. /// For example: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256)); /// @return (string) A human readable symbol name about this oracle. function symbol(bytes calldata data) external view returns (string memory); /// @notice Returns a human readable name about this oracle. /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle. /// For example: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256)); /// @return (string) A human readable name about this oracle. function name(bytes calldata data) external view returns (string memory); } // File @boringcrypto/boring-solidity/contracts/libraries/BoringMath.sol@v1.2.1 // License-Identifier: MIT /// @notice A library for performing overflow-/underflow-safe math, /// updated with awesomeness from of DappHub (https://github.com/dapphub/ds-math). library BoringMath { function add(uint256 a, uint256 b) internal pure returns (uint256 c) { require((c = a + b) >= b, "BoringMath: Add Overflow"); } function sub(uint256 a, uint256 b) internal pure returns (uint256 c) { require((c = a - b) <= a, "BoringMath: Underflow"); } function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { require(b == 0 || (c = a * b) / b == a, "BoringMath: Mul Overflow"); } function to128(uint256 a) internal pure returns (uint128 c) { require(a <= uint128(-1), "BoringMath: uint128 Overflow"); c = uint128(a); } function to64(uint256 a) internal pure returns (uint64 c) { require(a <= uint64(-1), "BoringMath: uint64 Overflow"); c = uint64(a); } function to32(uint256 a) internal pure returns (uint32 c) { require(a <= uint32(-1), "BoringMath: uint32 Overflow"); c = uint32(a); } } /// @notice A library for performing overflow-/underflow-safe addition and subtraction on uint128. library BoringMath128 { function add(uint128 a, uint128 b) internal pure returns (uint128 c) { require((c = a + b) >= b, "BoringMath: Add Overflow"); } function sub(uint128 a, uint128 b) internal pure returns (uint128 c) { require((c = a - b) <= a, "BoringMath: Underflow"); } } /// @notice A library for performing overflow-/underflow-safe addition and subtraction on uint64. library BoringMath64 { function add(uint64 a, uint64 b) internal pure returns (uint64 c) { require((c = a + b) >= b, "BoringMath: Add Overflow"); } function sub(uint64 a, uint64 b) internal pure returns (uint64 c) { require((c = a - b) <= a, "BoringMath: Underflow"); } } /// @notice A library for performing overflow-/underflow-safe addition and subtraction on uint32. library BoringMath32 { function add(uint32 a, uint32 b) internal pure returns (uint32 c) { require((c = a + b) >= b, "BoringMath: Add Overflow"); } function sub(uint32 a, uint32 b) internal pure returns (uint32 c) { require((c = a - b) <= a, "BoringMath: Underflow"); } } // File @sushiswap/core/contracts/uniswapv2/interfaces/IUniswapV2Factory.sol@v1.4.2 // License-Identifier: GPL-3.0 interface IUniswapV2Factory { event PairCreated(address indexed token0, address indexed token1, address pair, uint256); function feeTo() external view returns (address); function feeToSetter() external view returns (address); function migrator() external view returns (address); function getPair(address tokenA, address tokenB) external view returns (address pair); function allPairs(uint256) external view returns (address pair); function allPairsLength() external view returns (uint256); function createPair(address tokenA, address tokenB) external returns (address pair); function setFeeTo(address) external; function setFeeToSetter(address) external; function setMigrator(address) external; } // File @sushiswap/core/contracts/uniswapv2/interfaces/IUniswapV2Pair.sol@v1.4.2 // License-Identifier: GPL-3.0 interface IUniswapV2Pair { event Approval(address indexed owner, address indexed spender, uint256 value); event Transfer(address indexed from, address indexed to, uint256 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 (uint256); function balanceOf(address owner) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 value) external returns (bool); function transfer(address to, uint256 value) external returns (bool); function transferFrom( address from, address to, uint256 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 (uint256); function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; event Mint(address indexed sender, uint256 amount0, uint256 amount1); event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to); event Swap(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint256); 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 (uint256); function price1CumulativeLast() external view returns (uint256); function kLast() external view returns (uint256); function mint(address to) external returns (uint256 liquidity); function burn(address to) external returns (uint256 amount0, uint256 amount1); function swap( uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data ) external; function skim(address to) external; function sync() external; function initialize(address, address) external; } // File contracts/libraries/FullMath.sol // License-Identifier: CC-BY-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) private 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; require(h < d, "FullMath::mulDiv: overflow"); return fullDiv(l, h, d); } } // File contracts/libraries/FixedPoint.sol // License-Identifier: GPL-3.0-or-later // 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 private constant RESOLUTION = 112; uint256 private constant Q112 = 0x10000000000000000000000000000; uint256 private constant Q224 = 0x100000000000000000000000000000000000000000000000000000000; uint256 private constant LOWER_MASK = 0xffffffffffffffffffffffffffff; // decimal of UQ*x112 (lower 112 bits) // 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 uint256, 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); } // returns a UQ112x112 which represents the ratio of the numerator to the denominator // lossy if either numerator or denominator is greater than 112 bits function fraction(uint256 numerator, uint256 denominator) internal pure returns (uq112x112 memory) { require(denominator > 0, "FixedPoint::fraction: div by 0"); 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)); } } } // File contracts/oracles/SimpleSLPTWAP0Oracle.sol // License-Identifier: AGPL-3.0-only // Using the same Copyleft License as in the original Repository // adapted from https://github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/examples/ExampleSlidingWindowOracle.sol contract SimpleSLPTWAP1OracleV1 is IOracle { using FixedPoint for *; using BoringMath for uint256; uint256 public constant PERIOD = 5 minutes; struct PairInfo { uint256 priceCumulativeLast; uint32 blockTimestampLast; uint144 priceAverage; } mapping(IUniswapV2Pair => PairInfo) public pairs; // Map of pairs and their info mapping(address => IUniswapV2Pair) public callerInfo; // Map of callers to pairs function _get(IUniswapV2Pair pair, uint32 blockTimestamp) public view returns (uint256) { uint256 priceCumulative = 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(); priceCumulative += uint256(FixedPoint.fraction(reserve0, reserve1)._x) * (blockTimestamp - blockTimestampLast); // overflows ok // overflow is desired, casting never truncates // cumulative price is in (uq112x112 price * seconds) units so we simply wrap it after division by time elapsed return priceCumulative; } function getDataParameter(IUniswapV2Pair pair) public pure returns (bytes memory) { return abi.encode(pair); } // Get the latest exchange rate, if no valid (recent) rate is available, return false /// @inheritdoc IOracle function get(bytes calldata data) external override returns (bool, uint256) { IUniswapV2Pair pair = abi.decode(data, (IUniswapV2Pair)); uint32 blockTimestamp = uint32(block.timestamp); if (pairs[pair].blockTimestampLast == 0) { pairs[pair].blockTimestampLast = blockTimestamp; pairs[pair].priceCumulativeLast = _get(pair, blockTimestamp); return (false, 0); } uint32 timeElapsed = blockTimestamp - pairs[pair].blockTimestampLast; // overflow is desired if (timeElapsed < PERIOD) { return (true, pairs[pair].priceAverage); } uint256 priceCumulative = _get(pair, blockTimestamp); pairs[pair].priceAverage = FixedPoint .uq112x112(uint224((priceCumulative - pairs[pair].priceCumulativeLast) / timeElapsed)) .mul(10**18) .decode144(); pairs[pair].blockTimestampLast = blockTimestamp; pairs[pair].priceCumulativeLast = priceCumulative; return (true, pairs[pair].priceAverage); } // Check the last exchange rate without any state changes /// @inheritdoc IOracle function peek(bytes calldata data) public view override returns (bool, uint256) { IUniswapV2Pair pair = abi.decode(data, (IUniswapV2Pair)); uint32 blockTimestamp = uint32(block.timestamp); if (pairs[pair].blockTimestampLast == 0) { return (false, 0); } uint32 timeElapsed = blockTimestamp - pairs[pair].blockTimestampLast; // overflow is desired if (timeElapsed < PERIOD) { return (true, pairs[pair].priceAverage); } uint256 priceCumulative = _get(pair, blockTimestamp); uint144 priceAverage = FixedPoint.uq112x112(uint224((priceCumulative - pairs[pair].priceCumulativeLast) / timeElapsed)).mul(10**18).decode144(); return (true, priceAverage); } // Check the current spot exchange rate without any state changes /// @inheritdoc IOracle function peekSpot(bytes calldata data) external view override returns (uint256 rate) { IUniswapV2Pair pair = abi.decode(data, (IUniswapV2Pair)); (uint256 reserve0, uint256 reserve1, ) = pair.getReserves(); rate = reserve0.mul(1e18) / reserve1; } /// @inheritdoc IOracle function name(bytes calldata) public view override returns (string memory) { return "SushiSwap TWAP"; } /// @inheritdoc IOracle function symbol(bytes calldata) public view override returns (string memory) { return "TWAP"; } }