creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@openzeppelin/contracts/access/Ownable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/math/SafeMath.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n    /**\n     * @dev Returns the addition of two unsigned integers, with an overflow flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            uint256 c = a + b;\n            if (c < a) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n     *\n     * _Available since v3.4._\n     */\n    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b > a) return (false, 0);\n            return (true, a - b);\n        }\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n            // benefit is lost if 'b' is also tested.\n            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n            if (a == 0) return (true, 0);\n            uint256 c = a * b;\n            if (c / a != b) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the division of two unsigned integers, with a division by zero flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a / b);\n        }\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a % b);\n        }\n    }\n\n    /**\n     * @dev Returns the addition of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `+` operator.\n     *\n     * Requirements:\n     *\n     * - Addition cannot overflow.\n     */\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a + b;\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, reverting on\n     * overflow (when the result is negative).\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     *\n     * - Subtraction cannot overflow.\n     */\n    function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a - b;\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `*` operator.\n     *\n     * Requirements:\n     *\n     * - Multiplication cannot overflow.\n     */\n    function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a * b;\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers, reverting on\n     * division by zero. The result is rounded towards zero.\n     *\n     * Counterpart to Solidity's `/` operator.\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function div(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a / b;\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * reverting when dividing by zero.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a % b;\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n     * overflow (when the result is negative).\n     *\n     * CAUTION: This function is deprecated because it requires allocating memory for the error\n     * message unnecessarily. For custom revert reasons use {trySub}.\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     *\n     * - Subtraction cannot overflow.\n     */\n    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        unchecked {\n            require(b <= a, errorMessage);\n            return a - b;\n        }\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n     * division by zero. The result is rounded towards zero.\n     *\n     * Counterpart to Solidity's `/` operator. Note: this function uses a\n     * `revert` opcode (which leaves remaining gas untouched) while Solidity\n     * uses an invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        unchecked {\n            require(b > 0, errorMessage);\n            return a / b;\n        }\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * reverting with custom message when dividing by zero.\n     *\n     * CAUTION: This function is deprecated because it requires allocating memory for the error\n     * message unnecessarily. For custom revert reasons use {tryMod}.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        unchecked {\n            require(b > 0, errorMessage);\n            return a % b;\n        }\n    }\n}\n"
      },
      "contracts/interfaces/IOracle.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\ninterface IOracle {\n    function viewPriceInUSD() external view returns (uint256);\n}\n"
      },
      "contracts/interfaces/IPriceOracleAggregator.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nimport {IOracle} from './IOracle.sol';\n\ninterface IPriceOracleAggregator {\n    event UpdateOracle(address token, IOracle oracle);\n\n    function updateOracleForAsset(address _asset, IOracle _oracle) external;\n\n    function viewPriceInUSD(address _token) external view returns (uint256);\n}\n"
      },
      "contracts/interfaces/IUniswapV2Factory.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\ninterface IUniswapV2Factory {\n    function getPair(\n        address tokenA,\n        address tokenB\n    ) external view returns (address pair);\n}\n"
      },
      "contracts/interfaces/IUniswapV2Pair.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\ninterface IUniswapV2Pair {\n    event Approval(address indexed owner, address indexed spender, uint value);\n    event Transfer(address indexed from, address indexed to, uint value);\n\n    function name() external pure returns (string memory);\n\n    function symbol() external pure returns (string memory);\n\n    function decimals() external pure returns (uint8);\n\n    function totalSupply() external view returns (uint);\n\n    function balanceOf(address owner) external view returns (uint);\n\n    function allowance(\n        address owner,\n        address spender\n    ) external view returns (uint);\n\n    function approve(address spender, uint value) external returns (bool);\n\n    function transfer(address to, uint value) external returns (bool);\n\n    function transferFrom(\n        address from,\n        address to,\n        uint value\n    ) external returns (bool);\n\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n    function PERMIT_TYPEHASH() external pure returns (bytes32);\n\n    function nonces(address owner) external view returns (uint);\n\n    function permit(\n        address owner,\n        address spender,\n        uint value,\n        uint deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    event Mint(address indexed sender, uint amount0, uint amount1);\n    event Burn(\n        address indexed sender,\n        uint amount0,\n        uint amount1,\n        address indexed to\n    );\n    event Swap(\n        address indexed sender,\n        uint amount0In,\n        uint amount1In,\n        uint amount0Out,\n        uint amount1Out,\n        address indexed to\n    );\n    event Sync(uint112 reserve0, uint112 reserve1);\n\n    function MINIMUM_LIQUIDITY() external pure returns (uint);\n\n    function factory() external view returns (address);\n\n    function token0() external view returns (address);\n\n    function token1() external view returns (address);\n\n    function getReserves()\n        external\n        view\n        returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);\n\n    function price0CumulativeLast() external view returns (uint);\n\n    function price1CumulativeLast() external view returns (uint);\n\n    function kLast() external view returns (uint);\n\n    function mint(address to) external returns (uint liquidity);\n\n    function burn(address to) external returns (uint amount0, uint amount1);\n\n    function swap(\n        uint amount0Out,\n        uint amount1Out,\n        address to,\n        bytes calldata data\n    ) external;\n\n    function skim(address to) external;\n\n    function sync() external;\n\n    function initialize(address, address) external;\n}\n"
      },
      "contracts/libraries/Babylonian.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nlibrary Babylonian {\n    function sqrt(uint256 y) internal pure returns (uint256 z) {\n        if (y > 3) {\n            z = y;\n            uint256 x = y / 2 + 1;\n            while (x < z) {\n                z = x;\n                x = (y / x + x) / 2;\n            }\n        } else if (y != 0) {\n            z = 1;\n        }\n        // else z = 0\n    }\n}\n"
      },
      "contracts/libraries/FixedPoint.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nimport './Babylonian.sol';\n\n// a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))\nlibrary FixedPoint {\n    // range: [0, 2**112 - 1]\n    // resolution: 1 / 2**112\n    struct uq112x112 {\n        uint224 _x;\n    }\n\n    // range: [0, 2**144 - 1]\n    // resolution: 1 / 2**112\n    struct uq144x112 {\n        uint256 _x;\n    }\n\n    uint8 private constant RESOLUTION = 112;\n    uint256 private constant Q112 = uint256(1) << RESOLUTION;\n    uint256 private constant Q224 = Q112 << RESOLUTION;\n\n    // encode a uint112 as a UQ112x112\n    function encode(uint112 x) internal pure returns (uq112x112 memory) {\n        return uq112x112(uint224(x) << RESOLUTION);\n    }\n\n    // encodes a uint144 as a UQ144x112\n    function encode144(uint144 x) internal pure returns (uq144x112 memory) {\n        return uq144x112(uint256(x) << RESOLUTION);\n    }\n\n    // divide a UQ112x112 by a uint112, returning a UQ112x112\n    function div(\n        uq112x112 memory self,\n        uint112 x\n    ) internal pure returns (uq112x112 memory) {\n        require(x != 0, 'FixedPoint: DIV_BY_ZERO');\n        return uq112x112(self._x / uint224(x));\n    }\n\n    // multiply a UQ112x112 by a uint, returning a UQ144x112\n    // reverts on overflow\n    function mul(\n        uq112x112 memory self,\n        uint256 y\n    ) internal pure returns (uq144x112 memory) {\n        uint256 z;\n        require(\n            y == 0 || (z = uint256(self._x) * y) / y == uint256(self._x),\n            'FixedPoint: MULTIPLICATION_OVERFLOW'\n        );\n        return uq144x112(z);\n    }\n\n    // returns a UQ112x112 which represents the ratio of the numerator to the denominator\n    // equivalent to encode(numerator).div(denominator)\n    function fraction(\n        uint112 numerator,\n        uint112 denominator\n    ) internal pure returns (uq112x112 memory) {\n        require(denominator > 0, 'FixedPoint: DIV_BY_ZERO');\n        return uq112x112((uint224(numerator) << RESOLUTION) / denominator);\n    }\n\n    // decode a UQ112x112 into a uint112 by truncating after the radix point\n    function decode(uq112x112 memory self) internal pure returns (uint112) {\n        return uint112(self._x >> RESOLUTION);\n    }\n\n    // decode a UQ144x112 into a uint144 by truncating after the radix point\n    function decode144(uq144x112 memory self) internal pure returns (uint144) {\n        return uint144(self._x >> RESOLUTION);\n    }\n\n    // take the reciprocal of a UQ112x112\n    function reciprocal(\n        uq112x112 memory self\n    ) internal pure returns (uq112x112 memory) {\n        require(self._x != 0, 'FixedPoint: ZERO_RECIPROCAL');\n        return uq112x112(uint224(Q224 / self._x));\n    }\n\n    // square root of a UQ112x112\n    function sqrt(\n        uq112x112 memory self\n    ) internal pure returns (uq112x112 memory) {\n        return uq112x112(uint224(Babylonian.sqrt(uint256(self._x)) << 56));\n    }\n}\n"
      },
      "contracts/oracle/UniswapV2Oracle.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nimport '@openzeppelin/contracts/utils/math/SafeMath.sol';\nimport '@openzeppelin/contracts/access/Ownable.sol';\n\nimport '../libraries/FixedPoint.sol';\nimport '../interfaces/IPriceOracleAggregator.sol';\nimport '../interfaces/IUniswapV2Pair.sol';\nimport '../interfaces/IUniswapV2Factory.sol';\n\ninterface IERC20Metadata {\n    function decimals() external view returns (uint8);\n}\n\nlibrary UniswapV2Library {\n    using SafeMath for uint256;\n\n    // returns sorted token addresses, used to handle return values from pairs sorted in this order\n    function sortTokens(\n        address tokenA,\n        address tokenB\n    ) internal pure returns (address token0, address token1) {\n        require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES');\n        (token0, token1) = tokenA < tokenB\n            ? (tokenA, tokenB)\n            : (tokenB, tokenA);\n        require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS');\n    }\n\n    // Less efficient than the CREATE2 method below\n    function pairFor(\n        address factory,\n        address tokenA,\n        address tokenB\n    ) internal view returns (address pair) {\n        (address token0, address token1) = sortTokens(tokenA, tokenB);\n        pair = IUniswapV2Factory(factory).getPair(token0, token1);\n    }\n\n    // calculates the CREATE2 address for a pair without making any external calls\n    function pairForCreate2(\n        address factory,\n        address tokenA,\n        address tokenB\n    ) internal pure returns (address pair) {\n        (address token0, address token1) = sortTokens(tokenA, tokenB);\n        pair = address(\n            uint160(\n                bytes20(\n                    keccak256(\n                        abi.encodePacked(\n                            hex'ff',\n                            factory,\n                            keccak256(abi.encodePacked(token0, token1)),\n                            hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash\n                        )\n                    )\n                )\n            )\n        ); // this matches the CREATE2 in UniswapV2Factory.createPair\n    }\n\n    // fetches and sorts the reserves for a pair\n    function getReserves(\n        address factory,\n        address tokenA,\n        address tokenB\n    ) internal view returns (uint256 reserveA, uint256 reserveB) {\n        (address token0, ) = sortTokens(tokenA, tokenB);\n        (uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair(\n            pairFor(factory, tokenA, tokenB)\n        ).getReserves();\n        (reserveA, reserveB) = tokenA == token0\n            ? (reserve0, reserve1)\n            : (reserve1, reserve0);\n    }\n\n    // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset\n    function quote(\n        uint256 amountA,\n        uint256 reserveA,\n        uint256 reserveB\n    ) internal pure returns (uint256 amountB) {\n        require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT');\n        require(\n            reserveA > 0 && reserveB > 0,\n            'UniswapV2Library: INSUFFICIENT_LIQUIDITY'\n        );\n        amountB = amountA.mul(reserveB) / reserveA;\n    }\n\n    // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset\n    function getAmountOut(\n        uint256 amountIn,\n        uint256 reserveIn,\n        uint256 reserveOut\n    ) internal pure returns (uint256 amountOut) {\n        require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT');\n        require(\n            reserveIn > 0 && reserveOut > 0,\n            'UniswapV2Library: INSUFFICIENT_LIQUIDITY'\n        );\n        uint256 amountInWithFee = amountIn.mul(997);\n        uint256 numerator = amountInWithFee.mul(reserveOut);\n        uint256 denominator = reserveIn.mul(1000).add(amountInWithFee);\n        amountOut = numerator / denominator;\n    }\n\n    // given an output amount of an asset and pair reserves, returns a required input amount of the other asset\n    function getAmountIn(\n        uint256 amountOut,\n        uint256 reserveIn,\n        uint256 reserveOut\n    ) internal pure returns (uint256 amountIn) {\n        require(amountOut > 0, 'UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT');\n        require(\n            reserveIn > 0 && reserveOut > 0,\n            'UniswapV2Library: INSUFFICIENT_LIQUIDITY'\n        );\n        uint256 numerator = reserveIn.mul(amountOut).mul(1000);\n        uint256 denominator = reserveOut.sub(amountOut).mul(997);\n        amountIn = (numerator / denominator).add(1);\n    }\n\n    // performs chained getAmountOut calculations on any number of pairs\n    function getAmountsOut(\n        address factory,\n        uint256 amountIn,\n        address[] memory path\n    ) internal view returns (uint256[] memory amounts) {\n        require(path.length >= 2, 'UniswapV2Library: INVALID_PATH');\n        amounts = new uint256[](path.length);\n        amounts[0] = amountIn;\n        for (uint256 i = 0; i < path.length - 1; i++) {\n            (uint256 reserveIn, uint256 reserveOut) = getReserves(\n                factory,\n                path[i],\n                path[i + 1]\n            );\n            amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut);\n        }\n    }\n\n    // performs chained getAmountIn calculations on any number of pairs\n    function getAmountsIn(\n        address factory,\n        uint256 amountOut,\n        address[] memory path\n    ) internal view returns (uint256[] memory amounts) {\n        require(path.length >= 2, 'UniswapV2Library: INVALID_PATH');\n        amounts = new uint256[](path.length);\n        amounts[amounts.length - 1] = amountOut;\n        for (uint256 i = path.length - 1; i > 0; i--) {\n            (uint256 reserveIn, uint256 reserveOut) = getReserves(\n                factory,\n                path[i - 1],\n                path[i]\n            );\n            amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut);\n        }\n    }\n}\n\nlibrary UniswapV2OracleLibrary {\n    using FixedPoint for *;\n\n    // helper function that returns the current block timestamp within the range of uint32, i.e. [0, 2**32 - 1]\n    function currentBlockTimestamp() internal view returns (uint32) {\n        return uint32(block.timestamp % 2 ** 32);\n    }\n\n    // produces the cumulative price using counterfactuals to save gas and avoid a call to sync.\n    function currentCumulativePrices(\n        address pair\n    )\n        internal\n        view\n        returns (\n            uint256 price0Cumulative,\n            uint256 price1Cumulative,\n            uint32 blockTimestamp\n        )\n    {\n        blockTimestamp = currentBlockTimestamp();\n        price0Cumulative = IUniswapV2Pair(pair).price0CumulativeLast();\n        price1Cumulative = IUniswapV2Pair(pair).price1CumulativeLast();\n\n        // if time has elapsed since the last update on the pair, mock the accumulated price values\n        (\n            uint112 reserve0,\n            uint112 reserve1,\n            uint32 blockTimestampLast\n        ) = IUniswapV2Pair(pair).getReserves();\n        if (blockTimestampLast != blockTimestamp) {\n            // subtraction overflow is desired\n            uint32 timeElapsed = blockTimestamp - blockTimestampLast;\n            // addition overflow is desired\n            // counterfactual\n            price0Cumulative +=\n                uint256(FixedPoint.fraction(reserve1, reserve0)._x) *\n                timeElapsed;\n            // counterfactual\n            price1Cumulative +=\n                uint256(FixedPoint.fraction(reserve0, reserve1)._x) *\n                timeElapsed;\n        }\n    }\n}\n\ncontract UniswapV2Oracle is IOracle, Ownable {\n    using FixedPoint for *;\n\n    /// @notice oracle that returns price in USD\n    IPriceOracleAggregator public immutable aggregator;\n\n    uint256 public PERIOD = 1; // 1 hour TWAP (time-weighted average price)\n    uint256 public CONSULT_LENIENCY = 120; // Used for being able to consult past the period end\n    bool public ALLOW_STALE_CONSULTS = false; // If false, consult() will fail if the TWAP is stale\n\n    IUniswapV2Pair public immutable pair;\n    bool public isFirstToken;\n    address public immutable token0;\n    address public immutable token1;\n\n    uint256 public price0CumulativeLast;\n    uint256 public price1CumulativeLast;\n    uint32 public blockTimestampLast;\n\n    FixedPoint.uq112x112 public price0Average;\n    FixedPoint.uq112x112 public price1Average;\n\n    constructor(\n        address _factory,\n        address _tokenA,\n        address _tokenB,\n        address _priceOracleAggregator\n    ) {\n        require(\n            _priceOracleAggregator != address(0),\n            'UNIV2: Invalid Aggregator'\n        );\n        require(_factory != address(0), 'UNIV2: Invalid factory');\n        require(_tokenA != address(0), 'UNIV2: Invalid tokenA');\n        require(_tokenB != address(0), 'UNIV2: Invalid tokenB');\n\n        aggregator = IPriceOracleAggregator(_priceOracleAggregator);\n\n        IUniswapV2Pair _pair = IUniswapV2Pair(\n            UniswapV2Library.pairFor(_factory, _tokenA, _tokenB)\n        );\n        require(address(_pair) != address(0), 'UNIV2: Invalid Pair');\n\n        pair = _pair;\n        token0 = _pair.token0();\n        token1 = _pair.token1();\n\n        price0CumulativeLast = _pair.price0CumulativeLast(); // fetch the current accumulated price value (1 / 0)\n        price1CumulativeLast = _pair.price1CumulativeLast(); // fetch the current accumulated price value (0 / 1)\n        uint112 reserve0;\n        uint112 reserve1;\n        (reserve0, reserve1, blockTimestampLast) = _pair.getReserves();\n        require(reserve0 != 0 && reserve1 != 0, 'UNIV2: NO_RESERVES'); // ensure that there's liquidity in the pair\n\n        if (_tokenA == _pair.token0()) {\n            isFirstToken = true;\n        } else {\n            isFirstToken = false;\n        }\n    }\n\n    function setPeriod(uint256 _period) external onlyOwner {\n        PERIOD = _period;\n    }\n\n    function setConsultLeniency(uint256 _consult_leniency) external onlyOwner {\n        CONSULT_LENIENCY = _consult_leniency;\n    }\n\n    function setAllowStaleConsults(\n        bool _allow_stale_consults\n    ) external onlyOwner {\n        ALLOW_STALE_CONSULTS = _allow_stale_consults;\n    }\n\n    // Check if update() can be called instead of wasting gas calling it\n    function canUpdate() public view returns (bool) {\n        uint32 blockTimestamp = UniswapV2OracleLibrary.currentBlockTimestamp();\n        uint32 timeElapsed = blockTimestamp - blockTimestampLast; // Overflow is desired\n        return (timeElapsed >= PERIOD);\n    }\n\n    function update() external {\n        (\n            uint256 price0Cumulative,\n            uint256 price1Cumulative,\n            uint32 blockTimestamp\n        ) = UniswapV2OracleLibrary.currentCumulativePrices(address(pair));\n\n        // overflow is desired\n        uint256 timeElapsed = blockTimestamp > blockTimestampLast\n            ? blockTimestamp - blockTimestampLast\n            : uint256(blockTimestamp) + 2 ** 32 - uint256(blockTimestampLast);\n\n        // Ensure that at least one full period has passed since the last update\n        require(timeElapsed >= PERIOD, 'UniswapPairOracle: PERIOD_NOT_ELAPSED');\n\n        // Overflow is desired, casting never truncates\n        // Cumulative price is in (uq112x112 price * seconds) units so we simply wrap it after division by time elapsed\n        price0Average = FixedPoint.uq112x112(\n            uint224((price0Cumulative - price0CumulativeLast) / timeElapsed)\n        );\n        price1Average = FixedPoint.uq112x112(\n            uint224((price1Cumulative - price1CumulativeLast) / timeElapsed)\n        );\n\n        price0CumulativeLast = price0Cumulative;\n        price1CumulativeLast = price1Cumulative;\n        blockTimestampLast = blockTimestamp;\n    }\n\n    /// @dev returns the latest price of asset\n    function viewPriceInUSD() external view override returns (uint256 price) {\n        uint32 blockTimestamp = UniswapV2OracleLibrary.currentBlockTimestamp();\n        uint32 timeElapsed = blockTimestamp - blockTimestampLast; // Overflow is desired\n\n        // Ensure that the price is not stale\n        require(\n            (timeElapsed < (PERIOD + CONSULT_LENIENCY)) || ALLOW_STALE_CONSULTS,\n            'UniswapPairOracle: PRICE_IS_STALE_NEED_TO_CALL_UPDATE'\n        );\n\n        if (isFirstToken) {\n            price =\n                (aggregator.viewPriceInUSD(token1) *\n                    (10 ** IERC20Metadata(token0).decimals())) /\n                (\n                    price1Average\n                        .mul(10 ** IERC20Metadata(token1).decimals())\n                        .decode144()\n                );\n        } else {\n            price =\n                (aggregator.viewPriceInUSD(token0) *\n                    (10 ** IERC20Metadata(token1).decimals())) /\n                (\n                    price0Average\n                        .mul(10 ** IERC20Metadata(token0).decimals())\n                        .decode144()\n                );\n        }\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "metadata": {
        "useLiteralContent": true
      },
      "libraries": {}
    }
  }}