creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@synthetixio/core-contracts/contracts/errors/ParameterError.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title Library for errors related with expected function parameters.\n */\nlibrary ParameterError {\n    /**\n     * @dev Thrown when an invalid parameter is used in a function.\n     * @param parameter The name of the parameter.\n     * @param reason The reason why the received parameter is invalid.\n     */\n    error InvalidParameter(string parameter, string reason);\n}\n"
      },
      "@synthetixio/core-contracts/contracts/interfaces/IERC165.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title ERC165 interface for determining if a contract supports a given interface.\n */\ninterface IERC165 {\n    /**\n     * @notice Determines if the contract in question supports the specified interface.\n     * @param interfaceID XOR of all selectors in the contract.\n     * @return True if the contract supports the specified interface.\n     */\n    function supportsInterface(bytes4 interfaceID) external view returns (bool);\n}\n"
      },
      "@synthetixio/core-contracts/contracts/interfaces/IERC20.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title ERC20 token implementation.\n */\ninterface IERC20 {\n    /**\n     * @notice Emitted when tokens have been transferred.\n     * @param from The address that originally owned the tokens.\n     * @param to The address that received the tokens.\n     * @param amount The number of tokens that were transferred.\n     */\n    event Transfer(address indexed from, address indexed to, uint amount);\n\n    /**\n     * @notice Emitted when a user has provided allowance to another user for transferring tokens on its behalf.\n     * @param owner The address that is providing the allowance.\n     * @param spender The address that received the allowance.\n     * @param amount The number of tokens that were added to `spender`'s allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint amount);\n\n    /**\n     * @notice Thrown when the address interacting with the contract does not have sufficient allowance to transfer tokens from another contract.\n     * @param required The necessary allowance.\n     * @param existing The current allowance.\n     */\n    error InsufficientAllowance(uint required, uint existing);\n\n    /**\n     * @notice Thrown when the address interacting with the contract does not have sufficient tokens.\n     * @param required The necessary balance.\n     * @param existing The current balance.\n     */\n    error InsufficientBalance(uint required, uint existing);\n\n    /**\n     * @notice Retrieves the name of the token, e.g. \"Synthetix Network Token\".\n     * @return A string with the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @notice Retrieves the symbol of the token, e.g. \"SNX\".\n     * @return A string with the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @notice Retrieves the number of decimals used by the token. The default is 18.\n     * @return The number of decimals.\n     */\n    function decimals() external view returns (uint8);\n\n    /**\n     * @notice Returns the total number of tokens in circulation (minted - burnt).\n     * @return The total number of tokens.\n     */\n    function totalSupply() external view returns (uint);\n\n    /**\n     * @notice Returns the balance of a user.\n     * @param owner The address whose balance is being retrieved.\n     * @return The number of tokens owned by the user.\n     */\n    function balanceOf(address owner) external view returns (uint);\n\n    /**\n     * @notice Returns how many tokens a user has allowed another user to transfer on its behalf.\n     * @param owner The user who has given the allowance.\n     * @param spender The user who was given the allowance.\n     * @return The amount of tokens `spender` can transfer on `owner`'s behalf.\n     */\n    function allowance(address owner, address spender) external view returns (uint);\n\n    /**\n     * @notice Transfer tokens from one address to another.\n     * @param to The address that will receive the tokens.\n     * @param amount The amount of tokens to be transferred.\n     * @return A boolean which is true if the operation succeeded.\n     */\n    function transfer(address to, uint amount) external returns (bool);\n\n    /**\n     * @notice Allows users to provide allowance to other users so that they can transfer tokens on their behalf.\n     * @param spender The address that is receiving the allowance.\n     * @param amount The amount of tokens that are being added to the allowance.\n     * @return A boolean which is true if the operation succeeded.\n     */\n    function approve(address spender, uint amount) external returns (bool);\n\n    /**\n     * @notice Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) external returns (bool);\n\n    /**\n     * @notice Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);\n\n    /**\n     * @notice Allows a user who has been given allowance to transfer tokens on another user's behalf.\n     * @param from The address that owns the tokens that are being transferred.\n     * @param to The address that will receive the tokens.\n     * @param amount The number of tokens to transfer.\n     * @return A boolean which is true if the operation succeeded.\n     */\n    function transferFrom(address from, address to, uint amount) external returns (bool);\n}\n"
      },
      "@synthetixio/core-contracts/contracts/utils/DecimalMath.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"./SafeCast.sol\";\n\n/**\n * @title Utility library used to represent \"decimals\" (fixed point numbers) with integers, with two different levels of precision.\n *\n * They are represented by N * UNIT, where UNIT is the number of decimals of precision in the representation.\n *\n * Examples:\n * 1) Given UNIT = 100\n * then if A = 50, A represents the decimal 0.50\n * 2) Given UNIT = 1000000000000000000\n * then if A = 500000000000000000, A represents the decimal 0.500000000000000000\n *\n * Note: An accompanying naming convention of the postfix \"D<Precision>\" is helpful with this utility. I.e. if a variable \"myValue\" represents a low resolution decimal, it should be named \"myValueD18\", and if it was a high resolution decimal \"myValueD27\". While scaling, intermediate precision decimals like \"myValue45\" could arise. Non-decimals should have no postfix, i.e. just \"myValue\".\n *\n * Important: Multiplication and division operations are currently not supported for high precision decimals. Using these operations on them will yield incorrect results and fail silently.\n */\nlibrary DecimalMath {\n    using SafeCastU256 for uint256;\n    using SafeCastI256 for int256;\n\n    // solhint-disable numcast/safe-cast\n\n    // Numbers representing 1.0 (low precision).\n    uint256 public constant UNIT = 1e18;\n    int256 public constant UNIT_INT = int256(UNIT);\n    uint128 public constant UNIT_UINT128 = uint128(UNIT);\n    int128 public constant UNIT_INT128 = int128(UNIT_INT);\n\n    // Numbers representing 1.0 (high precision).\n    uint256 public constant UNIT_PRECISE = 1e27;\n    int256 public constant UNIT_PRECISE_INT = int256(UNIT_PRECISE);\n    int128 public constant UNIT_PRECISE_INT128 = int128(UNIT_PRECISE_INT);\n\n    // Precision scaling, (used to scale down/up from one precision to the other).\n    uint256 public constant PRECISION_FACTOR = 9; // 27 - 18 = 9 :)\n\n    // solhint-enable numcast/safe-cast\n\n    // -----------------\n    // uint256\n    // -----------------\n\n    /**\n     * @dev Multiplies two low precision decimals.\n     *\n     * Since the two numbers are assumed to be fixed point numbers,\n     * (x * UNIT) * (y * UNIT) = x * y * UNIT ^ 2,\n     * the result is divided by UNIT to remove double scaling.\n     */\n    function mulDecimal(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        return (x * y) / UNIT;\n    }\n\n    /**\n     * @dev Divides two low precision decimals.\n     *\n     * Since the two numbers are assumed to be fixed point numbers,\n     * (x * UNIT) / (y * UNIT) = x / y (Decimal representation is lost),\n     * x is first scaled up to end up with a decimal representation.\n     */\n    function divDecimal(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        return (x * UNIT) / y;\n    }\n\n    /**\n     * @dev Scales up a value.\n     *\n     * E.g. if value is not a decimal, a scale up by 18 makes it a low precision decimal.\n     * If value is a low precision decimal, a scale up by 9 makes it a high precision decimal.\n     */\n    function upscale(uint x, uint factor) internal pure returns (uint) {\n        return x * 10 ** factor;\n    }\n\n    /**\n     * @dev Scales down a value.\n     *\n     * E.g. if value is a high precision decimal, a scale down by 9 makes it a low precision decimal.\n     * If value is a low precision decimal, a scale down by 9 makes it a regular integer.\n     *\n     * Scaling down a regular integer would not make sense.\n     */\n    function downscale(uint x, uint factor) internal pure returns (uint) {\n        return x / 10 ** factor;\n    }\n\n    // -----------------\n    // uint128\n    // -----------------\n\n    // Note: Overloading doesn't seem to work for similar types, i.e. int256 and int128, uint256 and uint128, etc, so explicitly naming the functions differently here.\n\n    /**\n     * @dev See mulDecimal for uint256.\n     */\n    function mulDecimalUint128(uint128 x, uint128 y) internal pure returns (uint128) {\n        return (x * y) / UNIT_UINT128;\n    }\n\n    /**\n     * @dev See divDecimal for uint256.\n     */\n    function divDecimalUint128(uint128 x, uint128 y) internal pure returns (uint128) {\n        return (x * UNIT_UINT128) / y;\n    }\n\n    /**\n     * @dev See upscale for uint256.\n     */\n    function upscaleUint128(uint128 x, uint factor) internal pure returns (uint128) {\n        return x * (10 ** factor).to128();\n    }\n\n    /**\n     * @dev See downscale for uint256.\n     */\n    function downscaleUint128(uint128 x, uint factor) internal pure returns (uint128) {\n        return x / (10 ** factor).to128();\n    }\n\n    // -----------------\n    // int256\n    // -----------------\n\n    /**\n     * @dev See mulDecimal for uint256.\n     */\n    function mulDecimal(int256 x, int256 y) internal pure returns (int256) {\n        return (x * y) / UNIT_INT;\n    }\n\n    /**\n     * @dev See divDecimal for uint256.\n     */\n    function divDecimal(int256 x, int256 y) internal pure returns (int256) {\n        return (x * UNIT_INT) / y;\n    }\n\n    /**\n     * @dev See upscale for uint256.\n     */\n    function upscale(int x, uint factor) internal pure returns (int) {\n        return x * (10 ** factor).toInt();\n    }\n\n    /**\n     * @dev See downscale for uint256.\n     */\n    function downscale(int x, uint factor) internal pure returns (int) {\n        return x / (10 ** factor).toInt();\n    }\n\n    // -----------------\n    // int128\n    // -----------------\n\n    /**\n     * @dev See mulDecimal for uint256.\n     */\n    function mulDecimalInt128(int128 x, int128 y) internal pure returns (int128) {\n        return (x * y) / UNIT_INT128;\n    }\n\n    /**\n     * @dev See divDecimal for uint256.\n     */\n    function divDecimalInt128(int128 x, int128 y) internal pure returns (int128) {\n        return (x * UNIT_INT128) / y;\n    }\n\n    /**\n     * @dev See upscale for uint256.\n     */\n    function upscaleInt128(int128 x, uint factor) internal pure returns (int128) {\n        return x * ((10 ** factor).toInt()).to128();\n    }\n\n    /**\n     * @dev See downscale for uint256.\n     */\n    function downscaleInt128(int128 x, uint factor) internal pure returns (int128) {\n        return x / ((10 ** factor).toInt().to128());\n    }\n}\n"
      },
      "@synthetixio/core-contracts/contracts/utils/ERC165Helper.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"../interfaces/IERC165.sol\";\n\nlibrary ERC165Helper {\n    function safeSupportsInterface(\n        address candidate,\n        bytes4 interfaceID\n    ) internal returns (bool supportsInterface) {\n        (bool success, bytes memory response) = candidate.call(\n            abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceID)\n        );\n\n        if (!success) {\n            return false;\n        }\n\n        if (response.length == 0) {\n            return false;\n        }\n\n        assembly {\n            supportsInterface := mload(add(response, 32))\n        }\n    }\n}\n"
      },
      "@synthetixio/core-contracts/contracts/utils/SafeCast.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * Utilities that convert numeric types avoiding silent overflows.\n */\nimport \"./SafeCast/SafeCastU32.sol\";\nimport \"./SafeCast/SafeCastI32.sol\";\nimport \"./SafeCast/SafeCastI24.sol\";\nimport \"./SafeCast/SafeCastU56.sol\";\nimport \"./SafeCast/SafeCastI56.sol\";\nimport \"./SafeCast/SafeCastU64.sol\";\nimport \"./SafeCast/SafeCastI64.sol\";\nimport \"./SafeCast/SafeCastI128.sol\";\nimport \"./SafeCast/SafeCastI256.sol\";\nimport \"./SafeCast/SafeCastU128.sol\";\nimport \"./SafeCast/SafeCastU160.sol\";\nimport \"./SafeCast/SafeCastU256.sol\";\nimport \"./SafeCast/SafeCastAddress.sol\";\nimport \"./SafeCast/SafeCastBytes32.sol\";\n"
      },
      "@synthetixio/core-contracts/contracts/utils/SafeCast/SafeCastAddress.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title See SafeCast.sol.\n */\nlibrary SafeCastAddress {\n    function toBytes32(address x) internal pure returns (bytes32) {\n        return bytes32(uint256(uint160(x)));\n    }\n}\n"
      },
      "@synthetixio/core-contracts/contracts/utils/SafeCast/SafeCastBytes32.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title See SafeCast.sol.\n */\nlibrary SafeCastBytes32 {\n    function toAddress(bytes32 x) internal pure returns (address) {\n        return address(uint160(uint256(x)));\n    }\n\n    function toUint(bytes32 x) internal pure returns (uint) {\n        return uint(x);\n    }\n}\n"
      },
      "@synthetixio/core-contracts/contracts/utils/SafeCast/SafeCastI128.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title See SafeCast.sol.\n */\nlibrary SafeCastI128 {\n    error OverflowInt128ToUint128();\n    error OverflowInt128ToInt32();\n\n    function toUint(int128 x) internal pure returns (uint128) {\n        // ----------------<==============o==============>-----------------\n        // ----------------xxxxxxxxxxxxxxxo===============>----------------\n        if (x < 0) {\n            revert OverflowInt128ToUint128();\n        }\n\n        return uint128(x);\n    }\n\n    function to256(int128 x) internal pure returns (int256) {\n        return int256(x);\n    }\n\n    function to32(int128 x) internal pure returns (int32) {\n        // ----------------<==============o==============>-----------------\n        // ----------------xxxxxxxxxxxx<==o==>xxxxxxxxxxxx-----------------\n        if (x < int(type(int32).min) || x > int(type(int32).max)) {\n            revert OverflowInt128ToInt32();\n        }\n\n        return int32(x);\n    }\n\n    function zero() internal pure returns (int128) {\n        return int128(0);\n    }\n}\n"
      },
      "@synthetixio/core-contracts/contracts/utils/SafeCast/SafeCastI24.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title See SafeCast.sol.\n */\nlibrary SafeCastI24 {\n    function to256(int24 x) internal pure returns (int256) {\n        return int256(x);\n    }\n}\n"
      },
      "@synthetixio/core-contracts/contracts/utils/SafeCast/SafeCastI256.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title See SafeCast.sol.\n */\nlibrary SafeCastI256 {\n    error OverflowInt256ToUint256();\n    error OverflowInt256ToInt128();\n    error OverflowInt256ToInt24();\n\n    function to128(int256 x) internal pure returns (int128) {\n        // ----<==========================o===========================>----\n        // ----xxxxxxxxxxxx<==============o==============>xxxxxxxxxxxxx----\n        if (x < int256(type(int128).min) || x > int256(type(int128).max)) {\n            revert OverflowInt256ToInt128();\n        }\n\n        return int128(x);\n    }\n\n    function to24(int256 x) internal pure returns (int24) {\n        // ----<==========================o===========================>----\n        // ----xxxxxxxxxxxxxxxxxxxx<======o=======>xxxxxxxxxxxxxxxxxxxx----\n        if (x < int256(type(int24).min) || x > int256(type(int24).max)) {\n            revert OverflowInt256ToInt24();\n        }\n\n        return int24(x);\n    }\n\n    function toUint(int256 x) internal pure returns (uint256) {\n        // ----<==========================o===========================>----\n        // ----xxxxxxxxxxxxxxxxxxxxxxxxxxxo===============================>\n        if (x < 0) {\n            revert OverflowInt256ToUint256();\n        }\n\n        return uint256(x);\n    }\n\n    function zero() internal pure returns (int256) {\n        return int256(0);\n    }\n}\n"
      },
      "@synthetixio/core-contracts/contracts/utils/SafeCast/SafeCastI32.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title See SafeCast.sol.\n */\nlibrary SafeCastI32 {\n    error OverflowInt32ToUint32();\n\n    function toUint(int32 x) internal pure returns (uint32) {\n        // ----------------------<========o========>----------------------\n        // ----------------------xxxxxxxxxo=========>----------------------\n        if (x < 0) {\n            revert OverflowInt32ToUint32();\n        }\n\n        return uint32(x);\n    }\n}\n"
      },
      "@synthetixio/core-contracts/contracts/utils/SafeCast/SafeCastI56.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title See SafeCast.sol.\n */\nlibrary SafeCastI56 {\n    error OverflowInt56ToInt24();\n\n    function to24(int56 x) internal pure returns (int24) {\n        // ----------------------<========o========>-----------------------\n        // ----------------------xxx<=====o=====>xxx-----------------------\n        if (x < int(type(int24).min) || x > int(type(int24).max)) {\n            revert OverflowInt56ToInt24();\n        }\n\n        return int24(x);\n    }\n}\n"
      },
      "@synthetixio/core-contracts/contracts/utils/SafeCast/SafeCastI64.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title See SafeCast.sol.\n */\nlibrary SafeCastI64 {\n    error OverflowInt64ToUint64();\n\n    function toUint(int64 x) internal pure returns (uint64) {\n        // ----------------------<========o========>----------------------\n        // ----------------------xxxxxxxxxo=========>----------------------\n        if (x < 0) {\n            revert OverflowInt64ToUint64();\n        }\n\n        return uint64(x);\n    }\n}\n"
      },
      "@synthetixio/core-contracts/contracts/utils/SafeCast/SafeCastU128.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title See SafeCast.sol.\n */\nlibrary SafeCastU128 {\n    error OverflowUint128ToInt128();\n\n    function to256(uint128 x) internal pure returns (uint256) {\n        return uint256(x);\n    }\n\n    function toInt(uint128 x) internal pure returns (int128) {\n        // -------------------------------o===============>----------------\n        // ----------------<==============o==============>x----------------\n        if (x > uint128(type(int128).max)) {\n            revert OverflowUint128ToInt128();\n        }\n\n        return int128(x);\n    }\n\n    function toBytes32(uint128 x) internal pure returns (bytes32) {\n        return bytes32(uint256(x));\n    }\n}\n"
      },
      "@synthetixio/core-contracts/contracts/utils/SafeCast/SafeCastU160.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title See SafeCast.sol.\n */\nlibrary SafeCastU160 {\n    function to256(uint160 x) internal pure returns (uint256) {\n        return uint256(x);\n    }\n}\n"
      },
      "@synthetixio/core-contracts/contracts/utils/SafeCast/SafeCastU256.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title See SafeCast.sol.\n */\nlibrary SafeCastU256 {\n    error OverflowUint256ToUint128();\n    error OverflowUint256ToInt256();\n    error OverflowUint256ToUint64();\n    error OverflowUint256ToUint32();\n    error OverflowUint256ToUint160();\n\n    function to128(uint256 x) internal pure returns (uint128) {\n        // -------------------------------o===============================>\n        // -------------------------------o===============>xxxxxxxxxxxxxxxx\n        if (x > type(uint128).max) {\n            revert OverflowUint256ToUint128();\n        }\n\n        return uint128(x);\n    }\n\n    function to64(uint256 x) internal pure returns (uint64) {\n        // -------------------------------o===============================>\n        // -------------------------------o======>xxxxxxxxxxxxxxxxxxxxxxxxx\n        if (x > type(uint64).max) {\n            revert OverflowUint256ToUint64();\n        }\n\n        return uint64(x);\n    }\n\n    function to32(uint256 x) internal pure returns (uint32) {\n        // -------------------------------o===============================>\n        // -------------------------------o===>xxxxxxxxxxxxxxxxxxxxxxxxxxxx\n        if (x > type(uint32).max) {\n            revert OverflowUint256ToUint32();\n        }\n\n        return uint32(x);\n    }\n\n    function to160(uint256 x) internal pure returns (uint160) {\n        // -------------------------------o===============================>\n        // -------------------------------o==================>xxxxxxxxxxxxx\n        if (x > type(uint160).max) {\n            revert OverflowUint256ToUint160();\n        }\n\n        return uint160(x);\n    }\n\n    function toBytes32(uint256 x) internal pure returns (bytes32) {\n        return bytes32(x);\n    }\n\n    function toInt(uint256 x) internal pure returns (int256) {\n        // -------------------------------o===============================>\n        // ----<==========================o===========================>xxxx\n        if (x > uint256(type(int256).max)) {\n            revert OverflowUint256ToInt256();\n        }\n\n        return int256(x);\n    }\n}\n"
      },
      "@synthetixio/core-contracts/contracts/utils/SafeCast/SafeCastU32.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title See SafeCast.sol.\n */\nlibrary SafeCastU32 {\n    error OverflowUint32ToInt32();\n\n    function toInt(uint32 x) internal pure returns (int32) {\n        // -------------------------------o=========>----------------------\n        // ----------------------<========o========>x----------------------\n        if (x > uint32(type(int32).max)) {\n            revert OverflowUint32ToInt32();\n        }\n\n        return int32(x);\n    }\n\n    function to256(uint32 x) internal pure returns (uint256) {\n        return uint256(x);\n    }\n\n    function to56(uint32 x) internal pure returns (uint56) {\n        return uint56(x);\n    }\n}\n"
      },
      "@synthetixio/core-contracts/contracts/utils/SafeCast/SafeCastU56.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title See SafeCast.sol.\n */\nlibrary SafeCastU56 {\n    error OverflowUint56ToInt56();\n\n    function toInt(uint56 x) internal pure returns (int56) {\n        // -------------------------------o=========>----------------------\n        // ----------------------<========o========>x----------------------\n        if (x > uint56(type(int56).max)) {\n            revert OverflowUint56ToInt56();\n        }\n\n        return int56(x);\n    }\n}\n"
      },
      "@synthetixio/core-contracts/contracts/utils/SafeCast/SafeCastU64.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title See SafeCast.sol.\n */\nlibrary SafeCastU64 {\n    error OverflowUint64ToInt64();\n\n    function toInt(uint64 x) internal pure returns (int64) {\n        // -------------------------------o=========>----------------------\n        // ----------------------<========o========>x----------------------\n        if (x > uint64(type(int64).max)) {\n            revert OverflowUint64ToInt64();\n        }\n\n        return int64(x);\n    }\n\n    function to256(uint64 x) internal pure returns (uint256) {\n        return uint256(x);\n    }\n}\n"
      },
      "contracts/interfaces/external/IAggregatorV3Interface.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/// @title Interface an aggregator needs to adhere.\ninterface IAggregatorV3Interface {\n    /// @notice decimals used by the aggregator\n    function decimals() external view returns (uint8);\n\n    /// @notice aggregator's description\n    function description() external view returns (string memory);\n\n    /// @notice aggregator's version\n    function version() external view returns (uint256);\n\n    // getRoundData and latestRoundData should both raise \"No data present\"\n    // if they do not have data to report, instead of returning unset values\n    // which could be misinterpreted as actual reported values.\n    /// @notice get's round data for requested id\n    function getRoundData(\n        uint80 id\n    )\n        external\n        view\n        returns (\n            uint80 roundId,\n            int256 answer,\n            uint256 startedAt,\n            uint256 updatedAt,\n            uint80 answeredInRound\n        );\n\n    /// @notice get's latest round data\n    function latestRoundData()\n        external\n        view\n        returns (\n            uint80 roundId,\n            int256 answer,\n            uint256 startedAt,\n            uint256 updatedAt,\n            uint80 answeredInRound\n        );\n}\n"
      },
      "contracts/interfaces/external/IExternalNode.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/core-contracts/contracts/interfaces/IERC165.sol\";\n\nimport \"../../storage/NodeOutput.sol\";\nimport \"../../storage/NodeDefinition.sol\";\n\n/// @title Interface for an external node\ninterface IExternalNode is IERC165 {\n    function process(\n        NodeOutput.Data[] memory parentNodeOutputs,\n        bytes memory parameters,\n        bytes32[] memory runtimeKeys,\n        bytes32[] memory runtimeValues\n    ) external view returns (NodeOutput.Data memory);\n\n    function isValid(NodeDefinition.Data memory nodeDefinition) external returns (bool);\n}\n"
      },
      "contracts/interfaces/external/IPyth.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity >=0.8.11 <0.9.0;\n\n/// @title Consume prices from the Pyth Network (https://pyth.network/).\n/// @dev Please refer to the guidance at https://docs.pyth.network/consumers/best-practices for how to consume prices safely.\n/// @author Pyth Data Association\ninterface IPyth {\n    /// @dev Emitted when an update for price feed with `id` is processed successfully.\n    /// @param id The Pyth Price Feed ID.\n    /// @param fresh True if the price update is more recent and stored.\n    /// @param chainId ID of the source chain that the batch price update containing this price.\n    /// This value comes from Wormhole, and you can find the corresponding chains at https://docs.wormholenetwork.com/wormhole/contracts.\n    /// @param sequenceNumber Sequence number of the batch price update containing this price.\n    /// @param lastPublishTime Publish time of the previously stored price.\n    /// @param publishTime Publish time of the given price update.\n    /// @param price Price of the given price update.\n    /// @param conf Confidence interval of the given price update.\n    event PriceFeedUpdate(\n        bytes32 indexed id,\n        bool indexed fresh,\n        uint16 chainId,\n        uint64 sequenceNumber,\n        uint lastPublishTime,\n        uint publishTime,\n        int64 price,\n        uint64 conf\n    );\n\n    /// @dev Emitted when a batch price update is processed successfully.\n    /// @param chainId ID of the source chain that the batch price update comes from.\n    /// @param sequenceNumber Sequence number of the batch price update.\n    /// @param batchSize Number of prices within the batch price update.\n    /// @param freshPricesInBatch Number of prices that were more recent and were stored.\n    event BatchPriceFeedUpdate(\n        uint16 chainId,\n        uint64 sequenceNumber,\n        uint batchSize,\n        uint freshPricesInBatch\n    );\n\n    /// @dev Emitted when a call to `updatePriceFeeds` is processed successfully.\n    /// @param sender Sender of the call (`msg.sender`).\n    /// @param batchCount Number of batches that this function processed.\n    /// @param fee Amount of paid fee for updating the prices.\n    event UpdatePriceFeeds(address indexed sender, uint batchCount, uint fee);\n\n    /// @notice Returns the period (in seconds) that a price feed is considered valid since its publish time\n    function getValidTimePeriod() external view returns (uint validTimePeriod);\n\n    /// @notice Returns the price and confidence interval.\n    /// @dev Reverts if the price has not been updated within the last `getValidTimePeriod()` seconds.\n    /// @param id The Pyth Price Feed ID of which to fetch the price and confidence interval.\n    /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.\n    function getPrice(bytes32 id) external view returns (PythStructs.Price memory price);\n\n    /// @notice Returns the exponentially-weighted moving average price and confidence interval.\n    /// @dev Reverts if the EMA price is not available.\n    /// @param id The Pyth Price Feed ID of which to fetch the EMA price and confidence interval.\n    /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.\n    function getEmaPrice(bytes32 id) external view returns (PythStructs.Price memory price);\n\n    /// @notice Returns the price of a price feed without any sanity checks.\n    /// @dev This function returns the most recent price update in this contract without any recency checks.\n    /// This function is unsafe as the returned price update may be arbitrarily far in the past.\n    ///\n    /// Users of this function should check the `publishTime` in the price to ensure that the returned price is\n    /// sufficiently recent for their application. If you are considering using this function, it may be\n    /// safer / easier to use either `getPrice` or `getPriceNoOlderThan`.\n    /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.\n    function getPriceUnsafe(bytes32 id) external view returns (PythStructs.Price memory price);\n\n    /// @notice Returns the price that is no older than `age` seconds of the current time.\n    /// @dev This function is a sanity-checked version of `getPriceUnsafe` which is useful in\n    /// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently\n    /// recently.\n    /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.\n    function getPriceNoOlderThan(\n        bytes32 id,\n        uint age\n    ) external view returns (PythStructs.Price memory price);\n\n    /// @notice Returns the exponentially-weighted moving average price of a price feed without any sanity checks.\n    /// @dev This function returns the same price as `getEmaPrice` in the case where the price is available.\n    /// However, if the price is not recent this function returns the latest available price.\n    ///\n    /// The returned price can be from arbitrarily far in the past; this function makes no guarantees that\n    /// the returned price is recent or useful for any particular application.\n    ///\n    /// Users of this function should check the `publishTime` in the price to ensure that the returned price is\n    /// sufficiently recent for their application. If you are considering using this function, it may be\n    /// safer / easier to use either `getEmaPrice` or `getEmaPriceNoOlderThan`.\n    /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.\n    function getEmaPriceUnsafe(bytes32 id) external view returns (PythStructs.Price memory price);\n\n    /// @notice Returns the exponentially-weighted moving average price that is no older than `age` seconds\n    /// of the current time.\n    /// @dev This function is a sanity-checked version of `getEmaPriceUnsafe` which is useful in\n    /// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently\n    /// recently.\n    /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.\n    function getEmaPriceNoOlderThan(\n        bytes32 id,\n        uint age\n    ) external view returns (PythStructs.Price memory price);\n\n    /// @notice Update price feeds with given update messages.\n    /// This method requires the caller to pay a fee in wei; the required fee can be computed by calling\n    /// `getUpdateFee` with the length of the `updateData` array.\n    /// Prices will be updated if they are more recent than the current stored prices.\n    /// The call will succeed even if the update is not the most recent.\n    /// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid.\n    /// @param updateData Array of price update data.\n    function updatePriceFeeds(bytes[] calldata updateData) external payable;\n\n    /// @notice Wrapper around updatePriceFeeds that rejects fast if a price update is not necessary. A price update is\n    /// necessary if the current on-chain publishTime is older than the given publishTime. It relies solely on the\n    /// given `publishTimes` for the price feeds and does not read the actual price update publish time within `updateData`.\n    ///\n    /// This method requires the caller to pay a fee in wei; the required fee can be computed by calling\n    /// `getUpdateFee` with the length of the `updateData` array.\n    ///\n    /// `priceIds` and `publishTimes` are two arrays with the same size that correspond to senders known publishTime\n    /// of each priceId when calling this method. If all of price feeds within `priceIds` have updated and have\n    /// a newer or equal publish time than the given publish time, it will reject the transaction to save gas.\n    /// Otherwise, it calls updatePriceFeeds method to update the prices.\n    ///\n    /// @dev Reverts if update is not needed or the transferred fee is not sufficient or the updateData is invalid.\n    /// @param updateData Array of price update data.\n    /// @param priceIds Array of price ids.\n    /// @param publishTimes Array of publishTimes. `publishTimes[i]` corresponds to known `publishTime` of `priceIds[i]`\n    function updatePriceFeedsIfNecessary(\n        bytes[] calldata updateData,\n        bytes32[] calldata priceIds,\n        uint64[] calldata publishTimes\n    ) external payable;\n\n    /// @notice Returns the required fee to update an array of price updates.\n    /// @param updateData Array of price update data.\n    /// @return feeAmount The required fee in Wei.\n    function getUpdateFee(bytes[] calldata updateData) external view returns (uint feeAmount);\n\n    /// @notice Similar to `parsePriceFeedUpdates` but ensures the updates returned are\n    /// the first updates published in minPublishTime. That is, if there are multiple updates for a given timestamp,\n    /// this method will return the first update.\n    ///\n    ///\n    /// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid or there is\n    /// no update for any of the given `priceIds` within the given time range and uniqueness condition.\n    /// @param updateData Array of price update data.\n    /// @param priceIds Array of price ids.\n    /// @param minPublishTime minimum acceptable publishTime for the given `priceIds`.\n    /// @param maxPublishTime maximum acceptable publishTime for the given `priceIds`.\n    /// @return priceFeeds Array of the price feeds corresponding to the given `priceIds` (with the same order).\n    function parsePriceFeedUpdatesUnique(\n        bytes[] calldata updateData,\n        bytes32[] calldata priceIds,\n        uint64 minPublishTime,\n        uint64 maxPublishTime\n    ) external payable returns (PythStructs.PriceFeed[] memory priceFeeds);\n}\n\ncontract PythStructs {\n    // A price with a degree of uncertainty, represented as a price +- a confidence interval.\n    //\n    // The confidence interval roughly corresponds to the standard error of a normal distribution.\n    // Both the price and confidence are stored in a fixed-point numeric representation,\n    // `x * (10^expo)`, where `expo` is the exponent.\n    //\n    // Please refer to the documentation at https://docs.pyth.network/consumers/best-practices for how\n    // to how this price safely.\n    struct Price {\n        // Price\n        int64 price;\n        // Confidence interval around the price\n        uint64 conf;\n        // Price exponent\n        int32 expo;\n        // Unix timestamp describing when the price was published\n        uint publishTime;\n    }\n\n    // PriceFeed represents a current aggregate price from pyth publisher feeds.\n    struct PriceFeed {\n        // The price ID.\n        bytes32 id;\n        // Latest available price\n        Price price;\n        // Latest available exponentially-weighted moving average price\n        Price emaPrice;\n    }\n}\n"
      },
      "contracts/interfaces/external/IUniswapV3Pool.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity >=0.8.11 <0.9.0;\n\ninterface IUniswapV3Pool {\n    function observe(\n        uint32[] calldata secondsAgos\n    )\n        external\n        view\n        returns (\n            int56[] memory tickCumulatives,\n            uint160[] memory secondsPerLiquidityCumulativeX128s\n        );\n\n    function token0() external view returns (address);\n\n    function token1() external view returns (address);\n}\n"
      },
      "contracts/interfaces/INodeModule.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"../storage/NodeOutput.sol\";\nimport \"../storage/NodeDefinition.sol\";\n\n/// @title Module for managing nodes\ninterface INodeModule {\n    /**\n     * @notice Thrown when the specified nodeId has not been registered in the system.\n     */\n    error NodeNotRegistered(bytes32 nodeId);\n\n    /**\n     * @notice Thrown when a node is registered without a valid definition.\n     */\n    error InvalidNodeDefinition(NodeDefinition.Data nodeType);\n\n    /**\n     * @notice Emitted when `registerNode` is called.\n     * @param nodeId The id of the registered node.\n     * @param nodeType The nodeType assigned to this node.\n     * @param parameters The parameters assigned to this node.\n     * @param parents The parents assigned to this node.\n     */\n    event NodeRegistered(\n        bytes32 nodeId,\n        NodeDefinition.NodeType nodeType,\n        bytes parameters,\n        bytes32[] parents\n    );\n\n    /**\n     * @notice Registers a node\n     * @param nodeType The nodeType assigned to this node.\n     * @param parameters The parameters assigned to this node.\n     * @param parents The parents assigned to this node.\n     * @return nodeId The id of the registered node.\n     */\n    function registerNode(\n        NodeDefinition.NodeType nodeType,\n        bytes memory parameters,\n        bytes32[] memory parents\n    ) external returns (bytes32 nodeId);\n\n    /**\n     * @notice Returns the ID of a node, whether or not it has been registered.\n     * @param parents The parents assigned to this node.\n     * @param nodeType The nodeType assigned to this node.\n     * @param parameters The parameters assigned to this node.\n     * @return nodeId The id of the node.\n     */\n    function getNodeId(\n        NodeDefinition.NodeType nodeType,\n        bytes memory parameters,\n        bytes32[] memory parents\n    ) external pure returns (bytes32 nodeId);\n\n    /**\n     * @notice Returns a node's definition (type, parameters, and parents)\n     * @param nodeId The node ID\n     * @return node The node's definition data\n     */\n    function getNode(bytes32 nodeId) external pure returns (NodeDefinition.Data memory node);\n\n    /**\n     * @notice Returns a node current output data\n     * @param nodeId The node ID\n     * @return node The node's output data\n     */\n    function process(bytes32 nodeId) external view returns (NodeOutput.Data memory node);\n\n    /**\n     * @notice Returns a node current output data\n     * @param nodeId The node ID\n     * @param runtimeKeys Keys corresponding to runtime values which could be used by the node graph\n     * @param runtimeValues The values used by the node graph\n     * @return node The node's output data\n     */\n    function processWithRuntime(\n        bytes32 nodeId,\n        bytes32[] memory runtimeKeys,\n        bytes32[] memory runtimeValues\n    ) external view returns (NodeOutput.Data memory node);\n}\n"
      },
      "contracts/modules/NodeModule.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"../interfaces/INodeModule.sol\";\nimport \"../nodes/ReducerNode.sol\";\nimport \"../nodes/ExternalNode.sol\";\nimport \"../nodes/pyth/PythNode.sol\";\nimport \"../nodes/pyth/PythOffchainLookupNode.sol\";\nimport \"../nodes/ChainlinkNode.sol\";\nimport \"../nodes/PriceDeviationCircuitBreakerNode.sol\";\nimport \"../nodes/StalenessCircuitBreakerNode.sol\";\nimport \"../nodes/UniswapNode.sol\";\nimport \"../nodes/ConstantNode.sol\";\n\nimport \"../storage/NodeOutput.sol\";\nimport \"../storage/NodeDefinition.sol\";\n\nimport \"@synthetixio/core-contracts/contracts/errors/ParameterError.sol\";\n\n/**\n * @title Module for managing nodes\n * @dev See INodeModule.\n */\ncontract NodeModule is INodeModule {\n    /**\n     * @inheritdoc INodeModule\n     */\n    function registerNode(\n        NodeDefinition.NodeType nodeType,\n        bytes memory parameters,\n        bytes32[] memory parents\n    ) external returns (bytes32 nodeId) {\n        NodeDefinition.Data memory nodeDefinition = NodeDefinition.Data({\n            parents: parents,\n            nodeType: nodeType,\n            parameters: parameters\n        });\n\n        return _registerNode(nodeDefinition);\n    }\n\n    /**\n     * @inheritdoc INodeModule\n     */\n    function getNodeId(\n        NodeDefinition.NodeType nodeType,\n        bytes memory parameters,\n        bytes32[] memory parents\n    ) external pure returns (bytes32 nodeId) {\n        NodeDefinition.Data memory nodeDefinition = NodeDefinition.Data({\n            parents: parents,\n            nodeType: nodeType,\n            parameters: parameters\n        });\n\n        return _getNodeId(nodeDefinition);\n    }\n\n    /**\n     * @inheritdoc INodeModule\n     */\n    function getNode(bytes32 nodeId) external pure returns (NodeDefinition.Data memory node) {\n        return _getNode(nodeId);\n    }\n\n    /**\n     * @inheritdoc INodeModule\n     */\n    function process(bytes32 nodeId) external view returns (NodeOutput.Data memory node) {\n        return NodeDefinition.process(nodeId, new bytes32[](0), new bytes32[](0));\n    }\n\n    /**\n     * @inheritdoc INodeModule\n     */\n    function processWithRuntime(\n        bytes32 nodeId,\n        bytes32[] memory runtimeKeys,\n        bytes32[] memory runtimeValues\n    ) external view returns (NodeOutput.Data memory node) {\n        return NodeDefinition.process(nodeId, runtimeKeys, runtimeValues);\n    }\n\n    /**\n     * @dev Returns node definition data for a given node id.\n     */\n    function _getNode(bytes32 nodeId) internal pure returns (NodeDefinition.Data storage node) {\n        return NodeDefinition.load(nodeId);\n    }\n\n    /**\n     * @dev Returns the ID of a node, whether or not it has been registered.\n     */\n    function _getNodeId(\n        NodeDefinition.Data memory nodeDefinition\n    ) internal pure returns (bytes32 nodeId) {\n        return NodeDefinition.getId(nodeDefinition);\n    }\n\n    /**\n     * @dev Returns the ID of a node after registering it\n     */\n    function _registerNode(\n        NodeDefinition.Data memory nodeDefinition\n    ) internal returns (bytes32 nodeId) {\n        // If the node has already been registered with the system, return its ID.\n        nodeId = _getNodeId(nodeDefinition);\n        if (_isNodeRegistered(nodeId)) {\n            // even though we do nothing else node is considered \"re-registered\" and returns as such\n            emit NodeRegistered(\n                nodeId,\n                nodeDefinition.nodeType,\n                nodeDefinition.parameters,\n                nodeDefinition.parents\n            );\n            return nodeId;\n        }\n\n        // Validate that the node definition\n        if (!_isValidNodeDefinition(nodeDefinition)) {\n            revert InvalidNodeDefinition(nodeDefinition);\n        }\n\n        // Confirm that all of the parent node IDs have been registered.\n        for (uint256 i = 0; i < nodeDefinition.parents.length; i++) {\n            if (!_isNodeRegistered(nodeDefinition.parents[i])) {\n                revert NodeNotRegistered(nodeDefinition.parents[i]);\n            }\n        }\n\n        // Register the node\n        (, nodeId) = NodeDefinition.create(nodeDefinition);\n        emit NodeRegistered(\n            nodeId,\n            nodeDefinition.nodeType,\n            nodeDefinition.parameters,\n            nodeDefinition.parents\n        );\n    }\n\n    /**\n     * @dev Returns whether a given node ID has already been registered.\n     */\n    function _isNodeRegistered(bytes32 nodeId) internal pure returns (bool nodeRegistered) {\n        NodeDefinition.Data memory nodeDefinition = NodeDefinition.load(nodeId);\n        return (nodeDefinition.nodeType != NodeDefinition.NodeType.NONE);\n    }\n\n    /**\n     * @dev Returns the output of a specified node.\n     */\n    function _isValidNodeDefinition(\n        NodeDefinition.Data memory nodeDefinition\n    ) internal returns (bool valid) {\n        if (\n            nodeDefinition.nodeType == NodeDefinition.NodeType.REDUCER ||\n            nodeDefinition.nodeType == NodeDefinition.NodeType.PRICE_DEVIATION_CIRCUIT_BREAKER ||\n            nodeDefinition.nodeType == NodeDefinition.NodeType.STALENESS_CIRCUIT_BREAKER\n        ) {\n            //check if parents are processable\n            _hasValidParentNodeDefinitions(nodeDefinition);\n        }\n\n        if (nodeDefinition.nodeType == NodeDefinition.NodeType.REDUCER) {\n            return ReducerNode.isValid(nodeDefinition);\n        } else if (nodeDefinition.nodeType == NodeDefinition.NodeType.EXTERNAL) {\n            return ExternalNode.isValid(nodeDefinition);\n        } else if (nodeDefinition.nodeType == NodeDefinition.NodeType.CHAINLINK) {\n            return ChainlinkNode.isValid(nodeDefinition);\n        } else if (nodeDefinition.nodeType == NodeDefinition.NodeType.UNISWAP) {\n            return UniswapNode.isValid(nodeDefinition);\n        } else if (nodeDefinition.nodeType == NodeDefinition.NodeType.PYTH) {\n            return PythNode.isValid(nodeDefinition);\n        } else if (nodeDefinition.nodeType == NodeDefinition.NodeType.PYTH_OFFCHAIN_LOOKUP) {\n            return PythOffchainLookupNode.isValid(nodeDefinition);\n        } else if (\n            nodeDefinition.nodeType == NodeDefinition.NodeType.PRICE_DEVIATION_CIRCUIT_BREAKER\n        ) {\n            return PriceDeviationCircuitBreakerNode.isValid(nodeDefinition);\n        } else if (nodeDefinition.nodeType == NodeDefinition.NodeType.STALENESS_CIRCUIT_BREAKER) {\n            return StalenessCircuitBreakerNode.isValid(nodeDefinition);\n        } else if (nodeDefinition.nodeType == NodeDefinition.NodeType.CONSTANT) {\n            return ConstantNode.isValid(nodeDefinition);\n        }\n        return false;\n    }\n\n    function _hasValidParentNodeDefinitions(\n        NodeDefinition.Data memory nodeDefinition\n    ) internal returns (bool valid) {\n        for (uint256 i = 0; i < nodeDefinition.parents.length; i++) {\n            NodeDefinition.Data memory nodeDef = _getNode(nodeDefinition.parents[i]);\n            if (!_isValidNodeDefinition(nodeDef)) {\n                return false;\n            }\n        }\n        return true;\n    }\n}\n"
      },
      "contracts/nodes/ChainlinkNode.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/core-contracts/contracts/utils/SafeCast.sol\";\nimport \"@synthetixio/core-contracts/contracts/utils/DecimalMath.sol\";\n\nimport \"../storage/NodeDefinition.sol\";\nimport \"../storage/NodeOutput.sol\";\nimport \"../interfaces/external/IAggregatorV3Interface.sol\";\n\nlibrary ChainlinkNode {\n    using SafeCastU256 for uint256;\n    using SafeCastI256 for int256;\n    using DecimalMath for int256;\n\n    uint256 public constant PRECISION = 18;\n\n    function process(\n        bytes memory parameters\n    ) internal view returns (NodeOutput.Data memory nodeOutput) {\n        (address chainlinkAddr, uint256 twapTimeInterval, uint8 decimals) = abi.decode(\n            parameters,\n            (address, uint256, uint8)\n        );\n        IAggregatorV3Interface chainlink = IAggregatorV3Interface(chainlinkAddr);\n        (uint80 roundId, int256 price, , uint256 updatedAt, ) = chainlink.latestRoundData();\n\n        int256 finalPrice = twapTimeInterval == 0\n            ? price\n            : getTwapPrice(chainlink, roundId, price, twapTimeInterval);\n\n        finalPrice = decimals > PRECISION\n            ? finalPrice.downscale(decimals - PRECISION)\n            : finalPrice.upscale(PRECISION - decimals);\n\n        return NodeOutput.Data(finalPrice, updatedAt, 0, 0);\n    }\n\n    function getTwapPrice(\n        IAggregatorV3Interface chainlink,\n        uint80 latestRoundId,\n        int256 latestPrice,\n        uint256 twapTimeInterval\n    ) internal view returns (int256 price) {\n        int256 priceSum = latestPrice;\n        uint256 priceCount = 1;\n\n        uint256 startTime = block.timestamp - twapTimeInterval;\n\n        while (latestRoundId > 0) {\n            try chainlink.getRoundData(--latestRoundId) returns (\n                uint80,\n                int256 answer,\n                uint256,\n                uint256 updatedAt,\n                uint80\n            ) {\n                if (updatedAt < startTime) {\n                    break;\n                }\n                priceSum += answer;\n                priceCount++;\n            } catch {\n                break;\n            }\n        }\n\n        return priceSum / priceCount.toInt();\n    }\n\n    function isValid(NodeDefinition.Data memory nodeDefinition) internal view returns (bool valid) {\n        // Must have no parents\n        if (nodeDefinition.parents.length > 0) {\n            return false;\n        }\n\n        // Must have correct length of parameters data\n        if (nodeDefinition.parameters.length != 32 * 3) {\n            return false;\n        }\n\n        (address chainlinkAddr, , uint8 decimals) = abi.decode(\n            nodeDefinition.parameters,\n            (address, uint256, uint8)\n        );\n        IAggregatorV3Interface chainlink = IAggregatorV3Interface(chainlinkAddr);\n\n        // Must return latestRoundData without error\n        chainlink.latestRoundData();\n\n        // Must return decimals that match the definition\n        if (decimals != chainlink.decimals()) {\n            return false;\n        }\n\n        return true;\n    }\n}\n"
      },
      "contracts/nodes/ConstantNode.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"../storage/NodeDefinition.sol\";\nimport \"../storage/NodeOutput.sol\";\n\nlibrary ConstantNode {\n    function process(\n        bytes memory parameters\n    ) internal view returns (NodeOutput.Data memory nodeOutput) {\n        return NodeOutput.Data(abi.decode(parameters, (int256)), block.timestamp, 0, 0);\n    }\n\n    function isValid(NodeDefinition.Data memory nodeDefinition) internal pure returns (bool valid) {\n        // Must have no parents\n        if (nodeDefinition.parents.length > 0) {\n            return false;\n        }\n\n        // Must have correct length of parameters data\n        if (nodeDefinition.parameters.length < 32) {\n            return false;\n        }\n\n        return true;\n    }\n}\n"
      },
      "contracts/nodes/ExternalNode.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/core-contracts/contracts/utils/ERC165Helper.sol\";\n\nimport \"../storage/NodeDefinition.sol\";\nimport \"../storage/NodeOutput.sol\";\nimport \"../interfaces/external/IExternalNode.sol\";\n\nlibrary ExternalNode {\n    function process(\n        NodeOutput.Data[] memory prices,\n        bytes memory parameters,\n        bytes32[] memory runtimeKeys,\n        bytes32[] memory runtimeValues\n    ) internal view returns (NodeOutput.Data memory nodeOutput) {\n        IExternalNode externalNode = IExternalNode(abi.decode(parameters, (address)));\n        return externalNode.process(prices, parameters, runtimeKeys, runtimeValues);\n    }\n\n    function isValid(NodeDefinition.Data memory nodeDefinition) internal returns (bool valid) {\n        // Must have correct length of parameters data\n        if (nodeDefinition.parameters.length < 32) {\n            return false;\n        }\n\n        address externalNode = abi.decode(nodeDefinition.parameters, (address));\n        if (!ERC165Helper.safeSupportsInterface(externalNode, type(IExternalNode).interfaceId)) {\n            return false;\n        }\n\n        if (!IExternalNode(externalNode).isValid(nodeDefinition)) {\n            return false;\n        }\n\n        return true;\n    }\n}\n"
      },
      "contracts/nodes/PriceDeviationCircuitBreakerNode.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/core-contracts/contracts/utils/SafeCast.sol\";\nimport \"@synthetixio/core-contracts/contracts/utils/DecimalMath.sol\";\n\nimport \"../storage/NodeDefinition.sol\";\nimport \"../storage/NodeOutput.sol\";\n\nlibrary PriceDeviationCircuitBreakerNode {\n    using SafeCastU256 for uint256;\n    using DecimalMath for int256;\n\n    error DeviationToleranceExceeded(int256 deviation);\n    error InvalidInputPrice();\n\n    function process(\n        NodeOutput.Data[] memory parentNodeOutputs,\n        bytes memory parameters\n    ) internal pure returns (NodeOutput.Data memory nodeOutput) {\n        uint256 deviationTolerance = abi.decode(parameters, (uint256));\n\n        int256 primaryPrice = parentNodeOutputs[0].price;\n        int256 comparisonPrice = parentNodeOutputs[1].price;\n\n        if (primaryPrice != comparisonPrice) {\n            int256 difference = abs(primaryPrice - comparisonPrice).upscale(18);\n            if (\n                primaryPrice == 0 || deviationTolerance.toInt() < (difference / abs(primaryPrice))\n            ) {\n                if (parentNodeOutputs.length > 2) {\n                    return parentNodeOutputs[2];\n                } else {\n                    if (primaryPrice == 0) {\n                        revert InvalidInputPrice();\n                    } else {\n                        revert DeviationToleranceExceeded(difference / abs(primaryPrice));\n                    }\n                }\n            }\n        }\n\n        return parentNodeOutputs[0];\n    }\n\n    function abs(int256 x) private pure returns (int256 result) {\n        return x >= 0 ? x : -x;\n    }\n\n    function isValid(NodeDefinition.Data memory nodeDefinition) internal pure returns (bool valid) {\n        // Must have 2-3 parents\n        if (!(nodeDefinition.parents.length == 2 || nodeDefinition.parents.length == 3)) {\n            return false;\n        }\n\n        // Must have correct length of parameters data\n        if (nodeDefinition.parameters.length != 32) {\n            return false;\n        }\n\n        return true;\n    }\n}\n"
      },
      "contracts/nodes/pyth/PythNode.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/core-contracts/contracts/utils/DecimalMath.sol\";\nimport \"@synthetixio/core-contracts/contracts/utils/SafeCast.sol\";\n\nimport \"../../storage/NodeDefinition.sol\";\nimport \"../../storage/NodeOutput.sol\";\nimport \"../../interfaces/external/IPyth.sol\";\n\nlibrary PythNode {\n    using DecimalMath for int64;\n    using SafeCastI256 for int256;\n\n    int256 public constant PRECISION = 18;\n\n    function process(\n        bytes memory parameters\n    ) internal view returns (NodeOutput.Data memory nodeOutput) {\n        (address pythAddress, bytes32 priceFeedId, bool useEma) = abi.decode(\n            parameters,\n            (address, bytes32, bool)\n        );\n        IPyth pyth = IPyth(pythAddress);\n        PythStructs.Price memory pythData = useEma\n            ? pyth.getEmaPriceUnsafe(priceFeedId)\n            : pyth.getPriceUnsafe(priceFeedId);\n\n        int256 factor = PRECISION + pythData.expo;\n        int256 price = factor > 0\n            ? pythData.price.upscale(factor.toUint())\n            : pythData.price.downscale((-factor).toUint());\n\n        return NodeOutput.Data(price, pythData.publishTime, 0, 0);\n    }\n\n    function isValid(NodeDefinition.Data memory nodeDefinition) internal view returns (bool valid) {\n        // Must have no parents\n        if (nodeDefinition.parents.length > 0) {\n            return false;\n        }\n\n        // Must have correct length of parameters data\n        if (nodeDefinition.parameters.length != 32 * 3) {\n            return false;\n        }\n\n        (address pythAddress, bytes32 priceFeedId, bool useEma) = abi.decode(\n            nodeDefinition.parameters,\n            (address, bytes32, bool)\n        );\n        IPyth pyth = IPyth(pythAddress);\n\n        // Must return relevant function without error\n        useEma ? pyth.getEmaPriceUnsafe(priceFeedId) : pyth.getPriceUnsafe(priceFeedId);\n\n        return true;\n    }\n}\n"
      },
      "contracts/nodes/pyth/PythOffchainLookupNode.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/core-contracts/contracts/utils/DecimalMath.sol\";\nimport \"@synthetixio/core-contracts/contracts/utils/SafeCast.sol\";\n\nimport \"../../storage/NodeDefinition.sol\";\nimport \"../../storage/NodeOutput.sol\";\n\nlibrary PythOffchainLookupNode {\n    using DecimalMath for int64;\n    using SafeCastI256 for int256;\n\n    error OracleDataRequired(address oracleContract, bytes oracleQuery);\n\n    int256 public constant PRECISION = 18;\n\n    function process(\n        bytes memory parameters,\n        bytes32[] memory runtimeKeys,\n        bytes32[] memory runtimeValues\n    ) internal pure returns (NodeOutput.Data memory) {\n        (address pythAddress, bytes32 priceId, uint256 stalenessTolerance) = abi.decode(\n            parameters,\n            (address, bytes32, uint256)\n        );\n\n        for (uint256 i = 0; i < runtimeKeys.length; i++) {\n            if (runtimeKeys[i] == \"stalenessTolerance\") {\n                // solhint-disable-next-line numcast/safe-cast\n                stalenessTolerance = uint256(runtimeValues[i]);\n            }\n        }\n\n        bytes32[] memory priceIds = new bytes32[](1);\n        priceIds[0] = priceId;\n\n        // In the future Pyth revert data will have the following\n        // Query schema:\n        //\n        // Enum PythQuery {\n        //  Latest = 0 {\n        //    bytes32[] priceIds,\n        //  },\n        //  NoOlderThan = 1 {\n        //    uint64 stalenessTolerance,\n        //    bytes32[] priceIds,\n        //  },\n        //  Benchmark = 2 {\n        //    uint64 publishTime,\n        //    bytes32[] priceIds,\n        //  }\n        // }\n        //\n        // This contract only implements the PythQuery::NoOlderThan\n        revert OracleDataRequired(\n            pythAddress,\n            abi.encode(\n                // solhint-disable-next-line numcast/safe-cast\n                uint8(1), // PythQuery::NoOlderThan tag\n                // solhint-disable-next-line numcast/safe-cast\n                uint64(stalenessTolerance),\n                priceIds\n            )\n        );\n    }\n\n    function isValid(NodeDefinition.Data memory nodeDefinition) internal pure returns (bool valid) {\n        // Must have no parents\n        if (nodeDefinition.parents.length > 0) {\n            return false;\n        }\n\n        // Must have correct length of parameters data\n        if (nodeDefinition.parameters.length != 32 * 3) {\n            return false;\n        }\n\n        abi.decode(nodeDefinition.parameters, (address, bytes32, uint256));\n\n        return true;\n    }\n}\n"
      },
      "contracts/nodes/ReducerNode.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/core-contracts/contracts/utils/SafeCast.sol\";\nimport \"@synthetixio/core-contracts/contracts/utils/DecimalMath.sol\";\n\nimport \"../storage/NodeDefinition.sol\";\nimport \"../storage/NodeOutput.sol\";\n\nlibrary ReducerNode {\n    using SafeCastI256 for int256;\n    using SafeCastU256 for uint256;\n    using DecimalMath for int256;\n\n    error UnsupportedOperation(Operations operation);\n    error InvalidPrice(int256 price);\n\n    enum Operations {\n        RECENT,\n        MIN,\n        MAX,\n        MEAN,\n        MEDIAN,\n        MUL,\n        DIV,\n        MULDECIMAL,\n        DIVDECIMAL\n    }\n\n    function process(\n        NodeOutput.Data[] memory parentNodeOutputs,\n        bytes memory parameters\n    ) internal pure returns (NodeOutput.Data memory nodeOutput) {\n        Operations operation = abi.decode(parameters, (Operations));\n\n        if (operation == Operations.RECENT) {\n            return recent(parentNodeOutputs);\n        }\n        if (operation == Operations.MIN) {\n            return min(parentNodeOutputs);\n        }\n        if (operation == Operations.MAX) {\n            return max(parentNodeOutputs);\n        }\n        if (operation == Operations.MEAN) {\n            return mean(parentNodeOutputs);\n        }\n        if (operation == Operations.MEDIAN) {\n            return median(parentNodeOutputs);\n        }\n        if (operation == Operations.MUL) {\n            return mul(parentNodeOutputs);\n        }\n        if (operation == Operations.DIV) {\n            return div(parentNodeOutputs);\n        }\n        if (operation == Operations.MULDECIMAL) {\n            return mulDecimal(parentNodeOutputs);\n        }\n        if (operation == Operations.DIVDECIMAL) {\n            return divDecimal(parentNodeOutputs);\n        }\n\n        revert UnsupportedOperation(operation);\n    }\n\n    function median(\n        NodeOutput.Data[] memory parentNodeOutputs\n    ) internal pure returns (NodeOutput.Data memory medianPrice) {\n        quickSort(parentNodeOutputs, SafeCastI256.zero(), (parentNodeOutputs.length - 1).toInt());\n        if (parentNodeOutputs.length % 2 == 0) {\n            NodeOutput.Data[] memory middleSet = new NodeOutput.Data[](2);\n            middleSet[0] = parentNodeOutputs[(parentNodeOutputs.length / 2) - 1];\n            middleSet[1] = parentNodeOutputs[(parentNodeOutputs.length / 2)];\n            return mean(middleSet);\n        } else {\n            return parentNodeOutputs[parentNodeOutputs.length / 2];\n        }\n    }\n\n    function mean(\n        NodeOutput.Data[] memory parentNodeOutputs\n    ) internal pure returns (NodeOutput.Data memory meanPrice) {\n        for (uint256 i = 0; i < parentNodeOutputs.length; i++) {\n            meanPrice.price += parentNodeOutputs[i].price;\n            meanPrice.timestamp += parentNodeOutputs[i].timestamp;\n        }\n\n        meanPrice.price = meanPrice.price / parentNodeOutputs.length.toInt();\n        meanPrice.timestamp = meanPrice.timestamp / parentNodeOutputs.length;\n    }\n\n    function recent(\n        NodeOutput.Data[] memory parentNodeOutputs\n    ) internal pure returns (NodeOutput.Data memory recentPrice) {\n        for (uint256 i = 0; i < parentNodeOutputs.length; i++) {\n            if (parentNodeOutputs[i].timestamp > recentPrice.timestamp) {\n                recentPrice = parentNodeOutputs[i];\n            }\n        }\n    }\n\n    function max(\n        NodeOutput.Data[] memory parentNodeOutputs\n    ) internal pure returns (NodeOutput.Data memory maxPrice) {\n        maxPrice = parentNodeOutputs[0];\n        for (uint256 i = 1; i < parentNodeOutputs.length; i++) {\n            if (parentNodeOutputs[i].price > maxPrice.price) {\n                maxPrice = parentNodeOutputs[i];\n            }\n        }\n    }\n\n    function min(\n        NodeOutput.Data[] memory parentNodeOutputs\n    ) internal pure returns (NodeOutput.Data memory minPrice) {\n        minPrice = parentNodeOutputs[0];\n        for (uint256 i = 1; i < parentNodeOutputs.length; i++) {\n            if (parentNodeOutputs[i].price < minPrice.price) {\n                minPrice = parentNodeOutputs[i];\n            }\n        }\n    }\n\n    function mul(\n        NodeOutput.Data[] memory parentNodeOutputs\n    ) internal pure returns (NodeOutput.Data memory mulPrice) {\n        mulPrice.price = parentNodeOutputs[0].price;\n        mulPrice.timestamp = parentNodeOutputs[0].timestamp;\n        for (uint256 i = 1; i < parentNodeOutputs.length; i++) {\n            mulPrice.price *= parentNodeOutputs[i].price;\n            mulPrice.timestamp += parentNodeOutputs[i].timestamp;\n        }\n        mulPrice.timestamp = mulPrice.timestamp / parentNodeOutputs.length;\n    }\n\n    function div(\n        NodeOutput.Data[] memory parentNodeOutputs\n    ) internal pure returns (NodeOutput.Data memory divPrice) {\n        divPrice.price = parentNodeOutputs[0].price;\n        divPrice.timestamp = parentNodeOutputs[0].timestamp;\n        for (uint256 i = 1; i < parentNodeOutputs.length; i++) {\n            if (parentNodeOutputs[i].price == 0) {\n                revert InvalidPrice(parentNodeOutputs[i].price);\n            }\n            divPrice.price /= parentNodeOutputs[i].price;\n            divPrice.timestamp += parentNodeOutputs[i].timestamp;\n        }\n        divPrice.timestamp = divPrice.timestamp / parentNodeOutputs.length;\n    }\n\n    function mulDecimal(\n        NodeOutput.Data[] memory parentNodeOutputs\n    ) internal pure returns (NodeOutput.Data memory mulPrice) {\n        mulPrice.price = parentNodeOutputs[0].price;\n        mulPrice.timestamp = parentNodeOutputs[0].timestamp;\n        for (uint256 i = 1; i < parentNodeOutputs.length; i++) {\n            mulPrice.price = mulPrice.price.mulDecimal(parentNodeOutputs[i].price);\n            mulPrice.timestamp += parentNodeOutputs[i].timestamp;\n        }\n        mulPrice.timestamp = mulPrice.timestamp / parentNodeOutputs.length;\n    }\n\n    function divDecimal(\n        NodeOutput.Data[] memory parentNodeOutputs\n    ) internal pure returns (NodeOutput.Data memory divPrice) {\n        divPrice.price = parentNodeOutputs[0].price;\n        divPrice.timestamp = parentNodeOutputs[0].timestamp;\n        for (uint256 i = 1; i < parentNodeOutputs.length; i++) {\n            if (parentNodeOutputs[i].price == 0) {\n                revert InvalidPrice(parentNodeOutputs[i].price);\n            }\n            divPrice.price = divPrice.price.divDecimal(parentNodeOutputs[i].price);\n            divPrice.timestamp += parentNodeOutputs[i].timestamp;\n        }\n        divPrice.timestamp = divPrice.timestamp / parentNodeOutputs.length;\n    }\n\n    function quickSort(NodeOutput.Data[] memory arr, int256 left, int256 right) internal pure {\n        int256 i = left;\n        int256 j = right;\n        if (i == j) return;\n        int256 pivot = arr[(left + (right - left) / 2).toUint()].price;\n        while (i <= j) {\n            while (arr[i.toUint()].price < pivot) i++;\n            while (pivot < arr[j.toUint()].price) j--;\n            if (i <= j) {\n                (arr[i.toUint()], arr[j.toUint()]) = (arr[j.toUint()], arr[i.toUint()]);\n                i++;\n                j--;\n            }\n        }\n        if (left < j) quickSort(arr, left, j);\n        if (i < right) quickSort(arr, i, right);\n    }\n\n    function isValid(NodeDefinition.Data memory nodeDefinition) internal pure returns (bool valid) {\n        // Must have at least 2 parents\n        if (nodeDefinition.parents.length < 2) {\n            return false;\n        }\n\n        // Must have correct length of parameters data\n        if (nodeDefinition.parameters.length != 32) {\n            return false;\n        }\n\n        // Must have valid operation\n        uint256 operationId = abi.decode(nodeDefinition.parameters, (uint256));\n        if (operationId > 8) {\n            return false;\n        }\n\n        return true;\n    }\n}\n"
      },
      "contracts/nodes/StalenessCircuitBreakerNode.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport {SafeCastBytes32} from \"@synthetixio/core-contracts/contracts/utils/SafeCast.sol\";\nimport {NodeDefinition} from \"../storage/NodeDefinition.sol\";\nimport {NodeOutput} from \"../storage/NodeOutput.sol\";\n\nlibrary StalenessCircuitBreakerNode {\n    using SafeCastBytes32 for bytes32;\n\n    error StalenessToleranceExceeded();\n\n    function process(\n        NodeDefinition.Data memory nodeDefinition,\n        bytes32[] memory runtimeKeys,\n        bytes32[] memory runtimeValues\n    ) internal view returns (NodeOutput.Data memory nodeOutput) {\n        uint256 stalenessTolerance = abi.decode(nodeDefinition.parameters, (uint256));\n\n        for (uint256 i = 0; i < runtimeKeys.length; i++) {\n            if (runtimeKeys[i] == \"stalenessTolerance\") {\n                stalenessTolerance = runtimeValues[i].toUint();\n                break;\n            }\n        }\n\n        bytes32 priceNodeId = nodeDefinition.parents[0];\n        NodeOutput.Data memory priceNodeOutput = NodeDefinition.process(\n            priceNodeId,\n            runtimeKeys,\n            runtimeValues\n        );\n\n        if (block.timestamp - priceNodeOutput.timestamp <= stalenessTolerance) {\n            return priceNodeOutput;\n        } else if (nodeDefinition.parents.length == 1) {\n            revert StalenessToleranceExceeded();\n        }\n        // If there are two parents, return the output of the second parent (which in this case, should revert with OracleDataRequired)\n        return NodeDefinition.process(nodeDefinition.parents[1], runtimeKeys, runtimeValues);\n    }\n\n    function isValid(NodeDefinition.Data memory nodeDefinition) internal pure returns (bool valid) {\n        // Must have 1-2 parents\n        if (!(nodeDefinition.parents.length == 1 || nodeDefinition.parents.length == 2)) {\n            return false;\n        }\n\n        // Must have correct length of parameters data\n        if (nodeDefinition.parameters.length != 32) {\n            return false;\n        }\n\n        return true;\n    }\n}\n"
      },
      "contracts/nodes/UniswapNode.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/core-contracts/contracts/utils/SafeCast.sol\";\nimport \"@synthetixio/core-contracts/contracts/utils/DecimalMath.sol\";\nimport \"@synthetixio/core-contracts/contracts/interfaces/IERC20.sol\";\n\nimport \"../utils/FullMath.sol\";\nimport \"../utils/TickMath.sol\";\n\nimport \"../storage/NodeDefinition.sol\";\nimport \"../storage/NodeOutput.sol\";\nimport \"../interfaces/external/IUniswapV3Pool.sol\";\n\nlibrary UniswapNode {\n    using SafeCastU256 for uint256;\n    using SafeCastU160 for uint160;\n    using SafeCastU56 for uint56;\n    using SafeCastU32 for uint32;\n    using SafeCastI56 for int56;\n    using SafeCastI256 for int256;\n\n    using DecimalMath for int256;\n\n    uint8 public constant PRECISION = 18;\n\n    function process(\n        bytes memory parameters\n    ) internal view returns (NodeOutput.Data memory nodeOutput) {\n        (\n            address token,\n            address stablecoin,\n            uint8 decimalsToken,\n            uint8 decimalsStablecoin,\n            address pool,\n            uint32 secondsAgo\n        ) = abi.decode(parameters, (address, address, uint8, uint8, address, uint32));\n\n        uint32[] memory secondsAgos = new uint32[](2);\n        secondsAgos[0] = secondsAgo;\n        secondsAgos[1] = 0;\n\n        (int56[] memory tickCumulatives, ) = IUniswapV3Pool(pool).observe(secondsAgos);\n\n        int56 tickCumulativesDelta = tickCumulatives[1] - tickCumulatives[0];\n\n        int24 tick = (tickCumulativesDelta / secondsAgo.to56().toInt()).to24();\n\n        if (tickCumulativesDelta < 0 && (tickCumulativesDelta % secondsAgo.to256().toInt() != 0)) {\n            tick--;\n        }\n\n        uint256 baseAmount = 10 ** PRECISION;\n        int256 price = getQuoteAtTick(tick, baseAmount, token, stablecoin).toInt();\n\n        // solhint-disable-next-line numcast/safe-cast\n        int256 scale = uint256(decimalsToken).toInt() - uint256(decimalsStablecoin).toInt();\n\n        int256 finalPrice = scale > 0\n            ? price.upscale(scale.toUint())\n            : price.downscale((-scale).toUint());\n\n        return NodeOutput.Data(finalPrice, block.timestamp, 0, 0);\n    }\n\n    function getQuoteAtTick(\n        int24 tick,\n        uint256 baseAmount,\n        address baseToken,\n        address quoteToken\n    ) internal pure returns (uint256 quoteAmount) {\n        uint160 sqrtRatioX96 = TickMath.getSqrtRatioAtTick(tick);\n\n        // Calculate quoteAmount with better precision if it doesn't overflow when multiplied by itself\n        if (sqrtRatioX96 <= type(uint128).max) {\n            uint256 ratioX192 = sqrtRatioX96.to256() * sqrtRatioX96;\n            quoteAmount = baseToken < quoteToken\n                ? FullMath.mulDiv(ratioX192, baseAmount, 1 << 192)\n                : FullMath.mulDiv(1 << 192, baseAmount, ratioX192);\n        } else {\n            uint256 ratioX128 = FullMath.mulDiv(sqrtRatioX96, sqrtRatioX96, 1 << 64);\n            quoteAmount = baseToken < quoteToken\n                ? FullMath.mulDiv(ratioX128, baseAmount, 1 << 128)\n                : FullMath.mulDiv(1 << 128, baseAmount, ratioX128);\n        }\n    }\n\n    function isValid(NodeDefinition.Data memory nodeDefinition) internal view returns (bool valid) {\n        // Must have no parents\n        if (nodeDefinition.parents.length > 0) {\n            return false;\n        }\n\n        // Must have correct length of parameters data\n        if (nodeDefinition.parameters.length != 192) {\n            return false;\n        }\n\n        (\n            address token,\n            address stablecoin,\n            uint8 decimalsToken,\n            uint8 decimalsStablecoin,\n            address pool,\n            uint32 secondsAgo\n        ) = abi.decode(\n                nodeDefinition.parameters,\n                (address, address, uint8, uint8, address, uint32)\n            );\n\n        if (IERC20(token).decimals() != decimalsToken) {\n            return false;\n        }\n\n        if (IERC20(stablecoin).decimals() != decimalsStablecoin) {\n            return false;\n        }\n\n        address poolToken0 = IUniswapV3Pool(pool).token0();\n        address poolToken1 = IUniswapV3Pool(pool).token1();\n\n        if (\n            !(poolToken0 == token && poolToken1 == stablecoin) &&\n            !(poolToken0 == stablecoin && poolToken1 == token)\n        ) {\n            return false;\n        }\n\n        if (decimalsToken > 18 || decimalsStablecoin > 18) {\n            return false;\n        }\n\n        if (secondsAgo == 0) {\n            return false;\n        }\n\n        // Must call relevant function without error\n        uint32[] memory secondsAgos = new uint32[](2);\n        secondsAgos[0] = secondsAgo;\n        secondsAgos[1] = 0;\n        IUniswapV3Pool(pool).observe(secondsAgos);\n\n        return true;\n    }\n}\n"
      },
      "contracts/storage/NodeDefinition.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport {ParameterError} from \"@synthetixio/core-contracts/contracts/errors/ParameterError.sol\";\nimport {NodeOutput} from \"./NodeOutput.sol\";\n\nimport \"../nodes/ReducerNode.sol\";\nimport \"../nodes/ExternalNode.sol\";\nimport \"../nodes/pyth/PythNode.sol\";\nimport \"../nodes/pyth/PythOffchainLookupNode.sol\";\nimport \"../nodes/ChainlinkNode.sol\";\nimport \"../nodes/PriceDeviationCircuitBreakerNode.sol\";\nimport \"../nodes/StalenessCircuitBreakerNode.sol\";\nimport \"../nodes/UniswapNode.sol\";\nimport \"../nodes/ConstantNode.sol\";\n\nlibrary NodeDefinition {\n    /**\n     * @notice Thrown when a node cannot be processed\n     */\n    error UnprocessableNode(bytes32 nodeId);\n\n    enum NodeType {\n        NONE,\n        REDUCER,\n        EXTERNAL,\n        CHAINLINK,\n        UNISWAP,\n        PYTH,\n        PRICE_DEVIATION_CIRCUIT_BREAKER,\n        STALENESS_CIRCUIT_BREAKER,\n        CONSTANT,\n        PYTH_OFFCHAIN_LOOKUP // works in conjunction with PYTH node\n    }\n\n    struct Data {\n        /**\n         * @dev Oracle node type enum\n         */\n        NodeType nodeType;\n        /**\n         * @dev Node parameters, specific to each node type\n         */\n        bytes parameters;\n        /**\n         * @dev Parent node IDs, if any\n         */\n        bytes32[] parents;\n    }\n\n    /**\n     * @dev Returns the node stored at the specified node ID.\n     */\n    function load(bytes32 id) internal pure returns (Data storage node) {\n        bytes32 s = keccak256(abi.encode(\"io.synthetix.oracle-manager.Node\", id));\n        assembly {\n            node.slot := s\n        }\n    }\n\n    /**\n     * @dev Register a new node for a given node definition. The resulting node is a function of the definition.\n     */\n    function create(\n        Data memory nodeDefinition\n    ) internal returns (NodeDefinition.Data storage node, bytes32 id) {\n        id = getId(nodeDefinition);\n\n        node = load(id);\n\n        node.nodeType = nodeDefinition.nodeType;\n        node.parameters = nodeDefinition.parameters;\n        node.parents = nodeDefinition.parents;\n    }\n\n    /**\n     * @dev Returns a node ID based on its definition\n     */\n    function getId(Data memory nodeDefinition) internal pure returns (bytes32 id) {\n        return\n            keccak256(\n                abi.encode(\n                    nodeDefinition.nodeType,\n                    nodeDefinition.parameters,\n                    nodeDefinition.parents\n                )\n            );\n    }\n\n    /**\n     * @dev Returns the output of a specified node.\n     */\n    function process(\n        bytes32 nodeId,\n        bytes32[] memory runtimeKeys,\n        bytes32[] memory runtimeValues\n    ) internal view returns (NodeOutput.Data memory price) {\n        if (runtimeKeys.length != runtimeValues.length) {\n            revert ParameterError.InvalidParameter(\n                \"runtimeValues\",\n                \"must be same length as runtimeKeys\"\n            );\n        }\n\n        Data storage nodeDefinition = load(nodeId);\n        NodeType nodeType = nodeDefinition.nodeType;\n\n        if (nodeType == NodeType.REDUCER) {\n            return\n                ReducerNode.process(\n                    _processParentNodeOutputs(nodeDefinition, runtimeKeys, runtimeValues),\n                    nodeDefinition.parameters\n                );\n        } else if (nodeType == NodeType.EXTERNAL) {\n            return\n                ExternalNode.process(\n                    _processParentNodeOutputs(nodeDefinition, runtimeKeys, runtimeValues),\n                    nodeDefinition.parameters,\n                    runtimeKeys,\n                    runtimeValues\n                );\n        } else if (nodeType == NodeType.CHAINLINK) {\n            return ChainlinkNode.process(nodeDefinition.parameters);\n        } else if (nodeType == NodeType.UNISWAP) {\n            return UniswapNode.process(nodeDefinition.parameters);\n        } else if (nodeType == NodeType.PYTH) {\n            return PythNode.process(nodeDefinition.parameters);\n        } else if (nodeType == NodeType.PYTH_OFFCHAIN_LOOKUP) {\n            return\n                PythOffchainLookupNode.process(\n                    nodeDefinition.parameters,\n                    runtimeKeys,\n                    runtimeValues\n                );\n        } else if (nodeType == NodeType.PRICE_DEVIATION_CIRCUIT_BREAKER) {\n            return\n                PriceDeviationCircuitBreakerNode.process(\n                    _processParentNodeOutputs(nodeDefinition, runtimeKeys, runtimeValues),\n                    nodeDefinition.parameters\n                );\n        } else if (nodeType == NodeType.STALENESS_CIRCUIT_BREAKER) {\n            return StalenessCircuitBreakerNode.process(nodeDefinition, runtimeKeys, runtimeValues);\n        } else if (nodeType == NodeType.CONSTANT) {\n            return ConstantNode.process(nodeDefinition.parameters);\n        }\n        revert UnprocessableNode(nodeId);\n    }\n\n    /**\n     * @dev helper function that calls process on parent nodes.\n     */\n    function _processParentNodeOutputs(\n        Data storage nodeDefinition,\n        bytes32[] memory runtimeKeys,\n        bytes32[] memory runtimeValues\n    ) private view returns (NodeOutput.Data[] memory parentNodeOutputs) {\n        parentNodeOutputs = new NodeOutput.Data[](nodeDefinition.parents.length);\n        for (uint256 i = 0; i < nodeDefinition.parents.length; i++) {\n            parentNodeOutputs[i] = process(nodeDefinition.parents[i], runtimeKeys, runtimeValues);\n        }\n    }\n}\n"
      },
      "contracts/storage/NodeOutput.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nlibrary NodeOutput {\n    struct Data {\n        /**\n         * @dev Price returned from the oracle node, expressed with 18 decimals of precision\n         */\n        int256 price;\n        /**\n         * @dev Timestamp associated with the price\n         */\n        uint256 timestamp;\n        // solhint-disable-next-line private-vars-leading-underscore\n        uint256 __slotAvailableForFutureUse1;\n        // solhint-disable-next-line private-vars-leading-underscore\n        uint256 __slotAvailableForFutureUse2;\n    }\n}\n"
      },
      "contracts/utils/FullMath.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/core-contracts/contracts/utils/SafeCast.sol\";\n\n/// @title Contains 512-bit math functions\n/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision\n/// @dev Handles \"phantom overflow\" i.e., allows multiplication and division where an intermediate value overflows 256 bits\nlibrary FullMath {\n    using SafeCastU256 for uint256;\n    using SafeCastI256 for int256;\n\n    /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n    /// @param a The multiplicand\n    /// @param b The multiplier\n    /// @param denominator The divisor\n    /// @return result The 256-bit result\n    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv\n    function mulDiv(\n        uint256 a,\n        uint256 b,\n        uint256 denominator\n    ) internal pure returns (uint256 result) {\n        // 512-bit multiply [prod1 prod0] = a * b\n        // Compute the product mod 2**256 and mod 2**256 - 1\n        // then use the Chinese Remainder Theorem to reconstruct\n        // the 512 bit result. The result is stored in two 256\n        // variables such that product = prod1 * 2**256 + prod0\n        uint256 prod0; // Least significant 256 bits of the product\n        uint256 prod1; // Most significant 256 bits of the product\n        assembly {\n            let mm := mulmod(a, b, not(0))\n            prod0 := mul(a, b)\n            prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n        }\n\n        // Handle non-overflow cases, 256 by 256 division\n        if (prod1 == 0) {\n            require(denominator > 0, \"Handle non-overflow cases\");\n            assembly {\n                result := div(prod0, denominator)\n            }\n            return result;\n        }\n\n        // Make sure the result is less than 2**256.\n        // Also prevents denominator == 0\n        require(denominator > prod1, \"prevents denominator == 0\");\n\n        ///////////////////////////////////////////////\n        // 512 by 256 division.\n        ///////////////////////////////////////////////\n\n        // Make division exact by subtracting the remainder from [prod1 prod0]\n        // Compute remainder using mulmod\n        uint256 remainder;\n        assembly {\n            remainder := mulmod(a, b, denominator)\n        }\n        // Subtract 256 bit number from 512 bit number\n        assembly {\n            prod1 := sub(prod1, gt(remainder, prod0))\n            prod0 := sub(prod0, remainder)\n        }\n\n        // Factor powers of two out of denominator\n        // Compute largest power of two divisor of denominator.\n        // Always >= 1.\n        uint256 twos = (-denominator.toInt() & denominator.toInt()).toUint();\n        // Divide denominator by power of two\n        assembly {\n            denominator := div(denominator, twos)\n        }\n\n        // Divide [prod1 prod0] by the factors of two\n        assembly {\n            prod0 := div(prod0, twos)\n        }\n        // Shift in bits from prod1 into prod0. For this we need\n        // to flip `twos` such that it is 2**256 / twos.\n        // If twos is zero, then it becomes one\n        assembly {\n            twos := add(div(sub(0, twos), twos), 1)\n        }\n        prod0 |= prod1 * twos;\n\n        // Invert denominator mod 2**256\n        // Now that denominator is an odd number, it has an inverse\n        // modulo 2**256 such that denominator * inv = 1 mod 2**256.\n        // Compute the inverse by starting with a seed that is correct\n        // correct for four bits. That is, denominator * inv = 1 mod 2**4\n        uint256 inv = (3 * denominator) ^ 2;\n        // Now use Newton-Raphson iteration to improve the precision.\n        // Thanks to Hensel's lifting lemma, this also works in modular\n        // arithmetic, doubling the correct bits in each step.\n        inv *= 2 - denominator * inv; // inverse mod 2**8\n        inv *= 2 - denominator * inv; // inverse mod 2**16\n        inv *= 2 - denominator * inv; // inverse mod 2**32\n        inv *= 2 - denominator * inv; // inverse mod 2**64\n        inv *= 2 - denominator * inv; // inverse mod 2**128\n        inv *= 2 - denominator * inv; // inverse mod 2**256\n\n        // Because the division is now exact we can divide by multiplying\n        // with the modular inverse of denominator. This will give us the\n        // correct result modulo 2**256. Since the precoditions guarantee\n        // that the outcome is less than 2**256, this is the final result.\n        // We don't need to compute the high bits of the result and prod1\n        // is no longer required.\n        result = prod0 * inv;\n        return result;\n    }\n\n    /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n    /// @param a The multiplicand\n    /// @param b The multiplier\n    /// @param denominator The divisor\n    /// @return result The 256-bit result\n    function mulDivRoundingUp(\n        uint256 a,\n        uint256 b,\n        uint256 denominator\n    ) internal pure returns (uint256 result) {\n        result = mulDiv(a, b, denominator);\n        if (mulmod(a, b, denominator) > 0) {\n            require(result < type(uint256).max, \"result more than max\");\n            result++;\n        }\n    }\n}\n"
      },
      "contracts/utils/TickMath.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/core-contracts/contracts/utils/SafeCast.sol\";\n\n/// @title Math library for computing sqrt prices from ticks and vice versa\n/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports\n/// prices between 2**-128 and 2**128\nlibrary TickMath {\n    using SafeCastU256 for uint256;\n    using SafeCastI256 for int256;\n    using SafeCastI24 for int24;\n    using SafeCastU160 for uint160;\n\n    /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128\n    int24 internal constant MIN_TICK = -887272;\n    /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128\n    int24 internal constant MAX_TICK = -MIN_TICK;\n\n    /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)\n    uint160 internal constant MIN_SQRT_RATIO = 4295128739;\n    /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)\n    uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;\n\n    /// @notice Calculates sqrt(1.0001^tick) * 2^96\n    /// @dev Throws if |tick| > max tick\n    /// @param tick The input tick for the above formula\n    /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)\n    /// at the given tick\n    function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {\n        uint256 absTick = tick < 0 ? (-tick.to256()).toUint() : tick.to256().toUint();\n        require(absTick <= MAX_TICK.to256().toUint(), \"T\");\n\n        uint256 ratio = absTick & 0x1 != 0\n            ? 0xfffcb933bd6fad37aa2d162d1a594001\n            : 0x100000000000000000000000000000000;\n        if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;\n        if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;\n        if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;\n        if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;\n        if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;\n        if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;\n        if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;\n        if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;\n        if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;\n        if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;\n        if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;\n        if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;\n        if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;\n        if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;\n        if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;\n        if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;\n        if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;\n        if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;\n        if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;\n\n        if (tick > 0) ratio = type(uint256).max / ratio;\n\n        // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.\n        // we then downcast because we know the result always fits within 160 bits due to our tick input constraint\n        // we round up in the division so getTickAtSqrtRatio of the output price is always consistent\n        sqrtPriceX96 = ((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1)).to160();\n    }\n\n    /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio\n    /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may\n    /// ever return.\n    /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96\n    /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio\n    function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) {\n        // second inequality must be < because the price can never reach the price at the max tick\n        require(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, \"R\");\n        uint256 ratio = sqrtPriceX96.to256() << 32;\n\n        uint256 r = ratio;\n        uint256 msb = 0;\n\n        assembly {\n            let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := shl(5, gt(r, 0xFFFFFFFF))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := shl(4, gt(r, 0xFFFF))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := shl(3, gt(r, 0xFF))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := shl(2, gt(r, 0xF))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := shl(1, gt(r, 0x3))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := gt(r, 0x1)\n            msb := or(msb, f)\n        }\n\n        if (msb >= 128) r = ratio >> (msb - 127);\n        else r = ratio << (127 - msb);\n\n        int256 _log2 = (msb.toInt() - 128) << 64;\n\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            _log2 := or(_log2, shl(63, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            _log2 := or(_log2, shl(62, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            _log2 := or(_log2, shl(61, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            _log2 := or(_log2, shl(60, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            _log2 := or(_log2, shl(59, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            _log2 := or(_log2, shl(58, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            _log2 := or(_log2, shl(57, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            _log2 := or(_log2, shl(56, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            _log2 := or(_log2, shl(55, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            _log2 := or(_log2, shl(54, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            _log2 := or(_log2, shl(53, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            _log2 := or(_log2, shl(52, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            _log2 := or(_log2, shl(51, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            _log2 := or(_log2, shl(50, f))\n        }\n\n        int256 logSqrt10001 = _log2 * 255738958999603826347141; // 128.128 number\n\n        int24 tickLow = (logSqrt10001 - 3402992956809132418596140100660247210).to24() >> 128;\n        int24 tickHi = (logSqrt10001 + 291339464771989622907027621153398088495).to24() >> 128;\n\n        if (tickLow == tickHi) {\n            tick = tickLow;\n        } else {\n            tick = getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow;\n        }\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "evmVersion": "paris",
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}