creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@synthetixio/core-contracts/contracts/errors/AccessError.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title Library for access related errors.\n */\nlibrary AccessError {\n    /**\n     * @dev Thrown when an address tries to perform an unauthorized action.\n     * @param addr The address that attempts the action.\n     */\n    error Unauthorized(address addr);\n}\n"
      },
      "@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/interfaces/IERC721.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title ERC721 non-fungible token (NFT) contract.\n */\ninterface IERC721 {\n    /**\n     * @notice Thrown when an address attempts to provide allowance to itself.\n     * @param addr The address attempting to provide allowance.\n     */\n    error CannotSelfApprove(address addr);\n\n    /**\n     * @notice Thrown when attempting to transfer a token to an address that does not satisfy IERC721Receiver requirements.\n     * @param addr The address that cannot receive the tokens.\n     */\n    error InvalidTransferRecipient(address addr);\n\n    /**\n     * @notice Thrown when attempting to specify an owner which is not valid (ex. the 0x00000... address)\n     */\n    error InvalidOwner(address addr);\n\n    /**\n     * @notice Thrown when attempting to operate on a token id that does not exist.\n     * @param id The token id that does not exist.\n     */\n    error TokenDoesNotExist(uint256 id);\n\n    /**\n     * @notice Thrown when attempting to mint a token that already exists.\n     * @param id The token id that already exists.\n     */\n    error TokenAlreadyMinted(uint256 id);\n\n    /**\n     * @notice Emitted when `tokenId` token is transferred from `from` to `to`.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n    /**\n     * @notice Emitted when `owner` enables `approved` to manage the `tokenId` token.\n     */\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n    /**\n     * @notice Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n     */\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    /**\n     * @notice Returns the number of tokens in ``owner``'s account.\n     *\n     * Requirements:\n     *\n     * - `holder` must be a valid address\n     */\n    function balanceOf(address holder) external view returns (uint256 balance);\n\n    /**\n     * @notice Returns the owner of the `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function ownerOf(uint256 tokenId) external view returns (address owner);\n\n    /**\n     * @notice Safely transfers `tokenId` token from `from` to `to`.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes calldata data\n    ) external;\n\n    /**\n     * @notice Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n     * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId) external;\n\n    /**\n     * @notice Transfers `tokenId` token from `from` to `to`.\n     *\n     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 tokenId) external;\n\n    /**\n     * @notice Gives permission to `to` to transfer `tokenId` token to another account.\n     * The approval is cleared when the token is transferred.\n     *\n     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n     *\n     * Requirements:\n     *\n     * - The caller must own the token or be an approved operator.\n     * - `tokenId` must exist.\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address to, uint256 tokenId) external;\n\n    /**\n     * @notice Approve or remove `operator` as an operator for the caller.\n     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n     *\n     * Requirements:\n     *\n     * - The `operator` cannot be the caller.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function setApprovalForAll(address operator, bool approved) external;\n\n    /**\n     * @notice Returns the account approved for `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function getApproved(uint256 tokenId) external view returns (address operator);\n\n    /**\n     * @notice Returns if the `operator` is allowed to manage all of the assets of `owner`.\n     *\n     * See {setApprovalForAll}\n     */\n    function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n"
      },
      "@synthetixio/core-contracts/contracts/interfaces/IERC721Enumerable.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"./IERC721.sol\";\n\n/**\n * @title ERC721 extension with helper functions that allow the enumeration of NFT tokens.\n */\ninterface IERC721Enumerable is IERC721 {\n    /**\n     * @notice Thrown calling *ByIndex function with an index greater than the number of tokens existing\n     * @param requestedIndex The index requested by the caller\n     * @param length The length of the list that is being iterated, making the max index queryable length - 1\n     */\n    error IndexOverrun(uint requestedIndex, uint length);\n\n    /**\n     * @dev Returns the total amount of tokens stored by the contract.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.\n     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.\n     *\n     * Requirements:\n     * - `owner` must be a valid address\n     * - `index` must be less than the balance of the tokens for the owner\n     */\n    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);\n\n    /**\n     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.\n     * Use along with {totalSupply} to enumerate all tokens.\n     *\n     * Requirements:\n     * - `index` must be less than the total supply of the tokens\n     */\n    function tokenByIndex(uint256 index) external view returns (uint256);\n}\n"
      },
      "@synthetixio/core-contracts/contracts/ownership/OwnableStorage.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"../errors/AccessError.sol\";\n\nlibrary OwnableStorage {\n    bytes32 private constant _SLOT_OWNABLE_STORAGE =\n        keccak256(abi.encode(\"io.synthetix.core-contracts.Ownable\"));\n\n    struct Data {\n        address owner;\n        address nominatedOwner;\n    }\n\n    function load() internal pure returns (Data storage store) {\n        bytes32 s = _SLOT_OWNABLE_STORAGE;\n        assembly {\n            store.slot := s\n        }\n    }\n\n    function onlyOwner() internal view {\n        if (msg.sender != getOwner()) {\n            revert AccessError.Unauthorized(msg.sender);\n        }\n    }\n\n    function getOwner() internal view returns (address) {\n        return OwnableStorage.load().owner;\n    }\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/ERC2771Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/* solhint-disable meta-transactions/no-msg-sender */\n/* solhint-disable meta-transactions/no-msg-data */\n\nlibrary ERC2771Context {\n    // This is the trusted-multicall-forwarder. The address is constant due to CREATE2.\n    address private constant TRUSTED_FORWARDER = 0xE2C5658cC5C448B48141168f3e475dF8f65A1e3e;\n\n    function _msgSender() internal view returns (address sender) {\n        if (isTrustedForwarder(msg.sender) && msg.data.length >= 20) {\n            // The assembly code is more direct than the Solidity version using `abi.decode`.\n            /// @solidity memory-safe-assembly\n            assembly {\n                sender := shr(96, calldataload(sub(calldatasize(), 20)))\n            }\n        } else {\n            return msg.sender;\n        }\n    }\n\n    function _msgData() internal view returns (bytes calldata) {\n        if (isTrustedForwarder(msg.sender) && msg.data.length >= 20) {\n            return msg.data[:msg.data.length - 20];\n        } else {\n            return msg.data;\n        }\n    }\n\n    function isTrustedForwarder(address forwarder) internal pure returns (bool) {\n        return forwarder == TRUSTED_FORWARDER;\n    }\n\n    function trustedForwarder() internal pure returns (address) {\n        return TRUSTED_FORWARDER;\n    }\n}\n"
      },
      "@synthetixio/core-contracts/contracts/utils/HeapUtil.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n// Eth Heap\n// Author: Zac Mitton\n// License: MIT\n\nlibrary HeapUtil {\n    // default max-heap\n\n    uint private constant _ROOT_INDEX = 1;\n\n    struct Data {\n        uint128 idCount;\n        Node[] nodes; // root is index 1; index 0 not used\n        mapping(uint128 => uint) indices; // unique id => node index\n    }\n    struct Node {\n        uint128 id; //use with another mapping to store arbitrary object types\n        int128 priority;\n    }\n\n    //call init before anything else\n    function init(Data storage self) internal {\n        if (self.nodes.length == 0) self.nodes.push(Node(0, 0));\n    }\n\n    function insert(Data storage self, uint128 id, int128 priority) internal returns (Node memory) {\n        //√\n        if (self.nodes.length == 0) {\n            init(self);\n        } // test on-the-fly-init\n\n        Node memory n;\n\n        // MODIFIED: support updates\n        extractById(self, id);\n\n        self.idCount++;\n        self.nodes.push();\n        n = Node(id, priority);\n        _bubbleUp(self, n, self.nodes.length - 1);\n\n        return n;\n    }\n\n    function extractMax(Data storage self) internal returns (Node memory) {\n        //√\n        return _extract(self, _ROOT_INDEX);\n    }\n\n    function extractById(Data storage self, uint128 id) internal returns (Node memory) {\n        //√\n        return _extract(self, self.indices[id]);\n    }\n\n    //view\n    function dump(Data storage self) internal view returns (Node[] memory) {\n        //note: Empty set will return `[Node(0,0)]`. uninitialized will return `[]`.\n        return self.nodes;\n    }\n\n    function getById(Data storage self, uint128 id) internal view returns (Node memory) {\n        return getByIndex(self, self.indices[id]); //test that all these return the emptyNode\n    }\n\n    function getByIndex(Data storage self, uint i) internal view returns (Node memory) {\n        return self.nodes.length > i ? self.nodes[i] : Node(0, 0);\n    }\n\n    function getMax(Data storage self) internal view returns (Node memory) {\n        return getByIndex(self, _ROOT_INDEX);\n    }\n\n    function size(Data storage self) internal view returns (uint) {\n        return self.nodes.length > 0 ? self.nodes.length - 1 : 0;\n    }\n\n    function isNode(Node memory n) internal pure returns (bool) {\n        return n.id > 0;\n    }\n\n    //private\n    function _extract(Data storage self, uint i) private returns (Node memory) {\n        //√\n        if (self.nodes.length <= i || i <= 0) {\n            return Node(0, 0);\n        }\n\n        Node memory extractedNode = self.nodes[i];\n        delete self.indices[extractedNode.id];\n\n        Node memory tailNode = self.nodes[self.nodes.length - 1];\n        self.nodes.pop();\n\n        if (i < self.nodes.length) {\n            // if extracted node was not tail\n            _bubbleUp(self, tailNode, i);\n            _bubbleDown(self, self.nodes[i], i); // then try bubbling down\n        }\n        return extractedNode;\n    }\n\n    function _bubbleUp(Data storage self, Node memory n, uint i) private {\n        //√\n        if (i == _ROOT_INDEX || n.priority <= self.nodes[i / 2].priority) {\n            _insert(self, n, i);\n        } else {\n            _insert(self, self.nodes[i / 2], i);\n            _bubbleUp(self, n, i / 2);\n        }\n    }\n\n    function _bubbleDown(Data storage self, Node memory n, uint i) private {\n        //\n        uint length = self.nodes.length;\n        uint cIndex = i * 2; // left child index\n\n        if (length <= cIndex) {\n            _insert(self, n, i);\n        } else {\n            Node memory largestChild = self.nodes[cIndex];\n\n            if (length > cIndex + 1 && self.nodes[cIndex + 1].priority > largestChild.priority) {\n                largestChild = self.nodes[++cIndex]; // TEST ++ gets executed first here\n            }\n\n            if (largestChild.priority <= n.priority) {\n                //TEST: priority 0 is valid! negative ints work\n                _insert(self, n, i);\n            } else {\n                _insert(self, largestChild, i);\n                _bubbleDown(self, n, cIndex);\n            }\n        }\n    }\n\n    function _insert(Data storage self, Node memory n, uint i) private {\n        //√\n        self.nodes[i] = n;\n        self.indices[n.id] = i;\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"
      },
      "@synthetixio/core-contracts/contracts/utils/SetUtil.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"./SafeCast.sol\";\n\nlibrary SetUtil {\n    using SafeCastAddress for address;\n    using SafeCastBytes32 for bytes32;\n    using SafeCastU256 for uint256;\n\n    // ----------------------------------------\n    // Uint support\n    // ----------------------------------------\n\n    struct UintSet {\n        Bytes32Set raw;\n    }\n\n    function add(UintSet storage set, uint value) internal {\n        add(set.raw, value.toBytes32());\n    }\n\n    function remove(UintSet storage set, uint value) internal {\n        remove(set.raw, value.toBytes32());\n    }\n\n    function replace(UintSet storage set, uint value, uint newValue) internal {\n        replace(set.raw, value.toBytes32(), newValue.toBytes32());\n    }\n\n    function contains(UintSet storage set, uint value) internal view returns (bool) {\n        return contains(set.raw, value.toBytes32());\n    }\n\n    function length(UintSet storage set) internal view returns (uint) {\n        return length(set.raw);\n    }\n\n    function valueAt(UintSet storage set, uint position) internal view returns (uint) {\n        return valueAt(set.raw, position).toUint();\n    }\n\n    function positionOf(UintSet storage set, uint value) internal view returns (uint) {\n        return positionOf(set.raw, value.toBytes32());\n    }\n\n    function values(UintSet storage set) internal view returns (uint[] memory) {\n        bytes32[] memory store = values(set.raw);\n        uint[] memory result;\n\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // ----------------------------------------\n    // Address support\n    // ----------------------------------------\n\n    struct AddressSet {\n        Bytes32Set raw;\n    }\n\n    function add(AddressSet storage set, address value) internal {\n        add(set.raw, value.toBytes32());\n    }\n\n    function remove(AddressSet storage set, address value) internal {\n        remove(set.raw, value.toBytes32());\n    }\n\n    function replace(AddressSet storage set, address value, address newValue) internal {\n        replace(set.raw, value.toBytes32(), newValue.toBytes32());\n    }\n\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return contains(set.raw, value.toBytes32());\n    }\n\n    function length(AddressSet storage set) internal view returns (uint) {\n        return length(set.raw);\n    }\n\n    function valueAt(AddressSet storage set, uint position) internal view returns (address) {\n        return valueAt(set.raw, position).toAddress();\n    }\n\n    function positionOf(AddressSet storage set, address value) internal view returns (uint) {\n        return positionOf(set.raw, value.toBytes32());\n    }\n\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = values(set.raw);\n        address[] memory result;\n\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // ----------------------------------------\n    // Core bytes32 support\n    // ----------------------------------------\n\n    error PositionOutOfBounds();\n    error ValueNotInSet();\n    error ValueAlreadyInSet();\n\n    struct Bytes32Set {\n        bytes32[] _values;\n        mapping(bytes32 => uint) _positions; // Position zero is never used.\n    }\n\n    function add(Bytes32Set storage set, bytes32 value) internal {\n        if (contains(set, value)) {\n            revert ValueAlreadyInSet();\n        }\n\n        set._values.push(value);\n        set._positions[value] = set._values.length;\n    }\n\n    function remove(Bytes32Set storage set, bytes32 value) internal {\n        uint position = set._positions[value];\n        if (position == 0) {\n            revert ValueNotInSet();\n        }\n\n        uint index = position - 1;\n        uint lastIndex = set._values.length - 1;\n\n        // If the element being deleted is not the last in the values,\n        // move the last element to its position.\n        if (index != lastIndex) {\n            bytes32 lastValue = set._values[lastIndex];\n\n            set._values[index] = lastValue;\n            set._positions[lastValue] = position;\n        }\n\n        // Remove the last element in the values.\n        set._values.pop();\n        delete set._positions[value];\n    }\n\n    function replace(Bytes32Set storage set, bytes32 value, bytes32 newValue) internal {\n        if (!contains(set, value)) {\n            revert ValueNotInSet();\n        }\n\n        if (contains(set, newValue)) {\n            revert ValueAlreadyInSet();\n        }\n\n        uint position = set._positions[value];\n        delete set._positions[value];\n\n        uint index = position - 1;\n\n        set._values[index] = newValue;\n        set._positions[newValue] = position;\n    }\n\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return set._positions[value] != 0;\n    }\n\n    function length(Bytes32Set storage set) internal view returns (uint) {\n        return set._values.length;\n    }\n\n    function valueAt(Bytes32Set storage set, uint position) internal view returns (bytes32) {\n        if (position == 0 || position > set._values.length) {\n            revert PositionOutOfBounds();\n        }\n\n        uint index = position - 1;\n\n        return set._values[index];\n    }\n\n    function positionOf(Bytes32Set storage set, bytes32 value) internal view returns (uint) {\n        if (!contains(set, value)) {\n            revert ValueNotInSet();\n        }\n\n        return set._positions[value];\n    }\n\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return set._values;\n    }\n}\n"
      },
      "@synthetixio/core-modules/contracts/interfaces/INftModule.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/core-contracts/contracts/interfaces/IERC721Enumerable.sol\";\n\n/**\n * @title Module wrapping an ERC721 token implementation.\n */\ninterface INftModule is IERC721Enumerable {\n    /**\n     * @notice Returns whether the token has been initialized.\n     * @return A boolean with the result of the query.\n     */\n    function isInitialized() external view returns (bool);\n\n    /**\n     * @notice Initializes the token with name, symbol, and uri.\n     */\n    function initialize(\n        string memory tokenName,\n        string memory tokenSymbol,\n        string memory uri\n    ) external;\n\n    /**\n     * @notice Allows the owner to mint tokens.\n     * @param to The address to receive the newly minted tokens.\n     * @param tokenId The ID of the newly minted token\n     */\n    function mint(address to, uint tokenId) external;\n\n    /**\n     * @notice Allows the owner to mint tokens. Verifies that the receiver can receive the token\n     * @param to The address to receive the newly minted token.\n     * @param tokenId The ID of the newly minted token\n     * @param data any data which should be sent to the receiver\n     */\n    function safeMint(address to, uint256 tokenId, bytes memory data) external;\n\n    /**\n     * @notice Allows the owner to burn tokens.\n     * @param tokenId The token to burn\n     */\n    function burn(uint tokenId) external;\n\n    /**\n     * @notice Allows an address that holds tokens to provide allowance to another.\n     * @param tokenId The token which should be allowed to spender\n     * @param spender The address that is given allowance.\n     */\n    function setAllowance(uint tokenId, address spender) external;\n\n    /**\n     * @notice Allows the owner to update the base token URI.\n     * @param uri The new base token uri\n     */\n    function setBaseTokenURI(string memory uri) external;\n}\n"
      },
      "@synthetixio/core-modules/contracts/interfaces/ITokenModule.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/core-contracts/contracts/interfaces/IERC20.sol\";\n\n/**\n * @title Module wrapping an ERC20 token implementation.\n */\ninterface ITokenModule is IERC20 {\n    /**\n     * @notice Returns wether the token has been initialized.\n     * @return A boolean with the result of the query.\n     */\n    function isInitialized() external view returns (bool);\n\n    /**\n     * @notice Initializes the token with name, symbol, and decimals.\n     */\n    function initialize(\n        string memory tokenName,\n        string memory tokenSymbol,\n        uint8 tokenDecimals\n    ) external;\n\n    /**\n     * @notice Allows the owner to mint tokens.\n     * @param to The address to receive the newly minted tokens.\n     * @param amount The amount of tokens to mint.\n     */\n    function mint(address to, uint amount) external;\n\n    /**\n     * @notice Allows the owner to burn tokens.\n     * @param from The address whose tokens will be burnt.\n     * @param amount The amount of tokens to burn.\n     */\n    function burn(address from, uint amount) external;\n\n    /**\n     * @notice Allows an address that holds tokens to provide allowance to another.\n     * @param from The address that is providing allowance.\n     * @param spender The address that is given allowance.\n     * @param amount The amount of allowance being given.\n     */\n    function setAllowance(address from, address spender, uint amount) external;\n}\n"
      },
      "@synthetixio/core-modules/contracts/storage/AssociatedSystem.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"../interfaces/ITokenModule.sol\";\nimport \"../interfaces/INftModule.sol\";\n\nlibrary AssociatedSystem {\n    struct Data {\n        address proxy;\n        address impl;\n        bytes32 kind;\n    }\n\n    error MismatchAssociatedSystemKind(bytes32 expected, bytes32 actual);\n\n    bytes32 public constant KIND_ERC20 = \"erc20\";\n    bytes32 public constant KIND_ERC721 = \"erc721\";\n    bytes32 public constant KIND_UNMANAGED = \"unmanaged\";\n\n    function load(bytes32 id) internal pure returns (Data storage store) {\n        bytes32 s = keccak256(abi.encode(\"io.synthetix.core-modules.AssociatedSystem\", id));\n        assembly {\n            store.slot := s\n        }\n    }\n\n    function getAddress(Data storage self) internal view returns (address) {\n        return self.proxy;\n    }\n\n    function asToken(Data storage self) internal view returns (ITokenModule) {\n        expectKind(self, KIND_ERC20);\n        return ITokenModule(self.proxy);\n    }\n\n    function asNft(Data storage self) internal view returns (INftModule) {\n        expectKind(self, KIND_ERC721);\n        return INftModule(self.proxy);\n    }\n\n    function set(Data storage self, address proxy, address impl, bytes32 kind) internal {\n        self.proxy = proxy;\n        self.impl = impl;\n        self.kind = kind;\n    }\n\n    function expectKind(Data storage self, bytes32 kind) internal view {\n        bytes32 actualKind = self.kind;\n\n        if (actualKind != kind && actualKind != KIND_UNMANAGED) {\n            revert MismatchAssociatedSystemKind(kind, actualKind);\n        }\n    }\n}\n"
      },
      "@synthetixio/core-modules/contracts/storage/FeatureFlag.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/core-contracts/contracts/utils/SetUtil.sol\";\nimport \"@synthetixio/core-contracts/contracts/utils/ERC2771Context.sol\";\n\nlibrary FeatureFlag {\n    using SetUtil for SetUtil.AddressSet;\n\n    error FeatureUnavailable(bytes32 which);\n\n    struct Data {\n        bytes32 name;\n        bool allowAll;\n        bool denyAll;\n        SetUtil.AddressSet permissionedAddresses;\n        address[] deniers;\n    }\n\n    function load(bytes32 featureName) internal pure returns (Data storage store) {\n        bytes32 s = keccak256(abi.encode(\"io.synthetix.core-modules.FeatureFlag\", featureName));\n        assembly {\n            store.slot := s\n        }\n    }\n\n    function ensureAccessToFeature(bytes32 feature) internal view {\n        if (!hasAccess(feature, ERC2771Context._msgSender())) {\n            revert FeatureUnavailable(feature);\n        }\n    }\n\n    function hasAccess(bytes32 feature, address value) internal view returns (bool) {\n        Data storage store = FeatureFlag.load(feature);\n\n        if (store.denyAll) {\n            return false;\n        }\n\n        return store.allowAll || store.permissionedAddresses.contains(value);\n    }\n\n    function isDenier(Data storage self, address possibleDenier) internal view returns (bool) {\n        for (uint i = 0; i < self.deniers.length; i++) {\n            if (self.deniers[i] == possibleDenier) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n}\n"
      },
      "@synthetixio/oracle-manager/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"
      },
      "@synthetixio/oracle-manager/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"
      },
      "@synthetixio/oracle-manager/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"
      },
      "@synthetixio/oracle-manager/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"
      },
      "@synthetixio/oracle-manager/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"
      },
      "@synthetixio/oracle-manager/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"
      },
      "@synthetixio/oracle-manager/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"
      },
      "@synthetixio/oracle-manager/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"
      },
      "@synthetixio/oracle-manager/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"
      },
      "@synthetixio/oracle-manager/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"
      },
      "@synthetixio/oracle-manager/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"
      },
      "@synthetixio/oracle-manager/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"
      },
      "@synthetixio/oracle-manager/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"
      },
      "@synthetixio/oracle-manager/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"
      },
      "@synthetixio/oracle-manager/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"
      },
      "@synthetixio/oracle-manager/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"
      },
      "@synthetixio/oracle-manager/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"
      },
      "@synthetixio/oracle-manager/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"
      },
      "contracts/interfaces/external/IMarket.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/core-contracts/contracts/interfaces/IERC165.sol\";\n\n/// @title Interface for markets integrated with Synthetix\ninterface IMarket is IERC165 {\n    /// @notice returns a human-readable name for a given market\n    function name(uint128 marketId) external view returns (string memory);\n\n    /// @notice returns amount of USD that the market would try to mint if everything was withdrawn\n    function reportedDebt(uint128 marketId) external view returns (uint256);\n\n    /// @notice prevents reduction of available credit capacity by specifying this amount, for which withdrawals will be disallowed\n    function minimumCredit(uint128 marketId) external view returns (uint256);\n}\n"
      },
      "contracts/interfaces/external/IOracleManager.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/oracle-manager/contracts/interfaces/INodeModule.sol\";\n\n/// @title Effective interface for the oracle manager\n// solhint-disable-next-line no-empty-blocks\ninterface IOracleManager is INodeModule {\n\n}\n"
      },
      "contracts/interfaces/IMarketManagerModule.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/core-contracts/contracts/interfaces/IERC20.sol\";\nimport \"./external/IOracleManager.sol\";\n\n/**\n * @title System-wide entry point for the management of markets connected to the system.\n */\ninterface IMarketManagerModule {\n    /**\n     * @notice Thrown when a market does not have enough liquidity for a withdrawal.\n     */\n    error NotEnoughLiquidity(uint128 marketId, uint256 amount);\n\n    /**\n     * @notice Thrown when an attempt to register a market that does not conform to the IMarket interface is made.\n     */\n    error IncorrectMarketInterface(address market);\n\n    /**\n     * @notice Emitted when a new market is registered in the system.\n     * @param market The address of the external market that was registered in the system.\n     * @param marketId The id with which the market was registered in the system.\n     * @param sender The account that trigger the registration of the market.\n     */\n    event MarketRegistered(\n        address indexed market,\n        uint128 indexed marketId,\n        address indexed sender\n    );\n\n    /**\n     * @notice Emitted when a market deposits snxUSD in the system.\n     * @param marketId The id of the market that deposited snxUSD in the system.\n     * @param target The address of the account that provided the snxUSD in the deposit.\n     * @param amount The amount of snxUSD deposited in the system, denominated with 18 decimals of precision.\n     * @param market The address of the external market that is depositing.\n     * @param creditCapacity Updated credit capacity of the market after depositing.\n     * @param netIssuance Updated net issuance.\n     * @param depositedCollateralValue Updated deposited collateral value of the market.\n     * @param reportedDebt Updated reported debt of the market after depositing.\n     */\n    event MarketUsdDeposited(\n        uint128 indexed marketId,\n        address indexed target,\n        uint256 amount,\n        address indexed market,\n        int128 creditCapacity,\n        int128 netIssuance,\n        uint256 depositedCollateralValue,\n        uint256 reportedDebt\n    );\n\n    /**\n     * @notice Emitted when a market withdraws snxUSD from the system.\n     * @param marketId The id of the market that withdrew snxUSD from the system.\n     * @param target The address of the account that received the snxUSD in the withdrawal.\n     * @param amount The amount of snxUSD withdrawn from the system, denominated with 18 decimals of precision.\n     * @param market The address of the external market that is withdrawing.\n     * @param creditCapacity Updated credit capacity of the market after withdrawing.\n     * @param netIssuance Updated net issuance.\n     * @param depositedCollateralValue Updated deposited collateral value of the market.\n     * @param reportedDebt Updated reported debt of the market after withdrawal.\n     */\n    event MarketUsdWithdrawn(\n        uint128 indexed marketId,\n        address indexed target,\n        uint256 amount,\n        address indexed market,\n        int128 creditCapacity,\n        int128 netIssuance,\n        uint256 depositedCollateralValue,\n        uint256 reportedDebt\n    );\n\n    event MarketSystemFeePaid(uint128 indexed marketId, uint256 feeAmount);\n\n    /**\n     * @notice Emitted when a market sets an updated minimum delegation time\n     * @param marketId The id of the market that the setting is applied to\n     * @param minDelegateTime The minimum amount of time between delegation changes\n     */\n    event SetMinDelegateTime(uint128 indexed marketId, uint32 minDelegateTime);\n\n    /**\n     * @notice Emitted when a market-specific minimum liquidity ratio is set\n     * @param marketId The id of the market that the setting is applied to\n     * @param minLiquidityRatio The new market-specific minimum liquidity ratio\n     */\n    event SetMarketMinLiquidityRatio(uint128 indexed marketId, uint256 minLiquidityRatio);\n\n    /**\n     * @notice Connects an external market to the system.\n     * @dev Creates a Market object to track the external market, and returns the newly created market id.\n     * @param market The address of the external market that is to be registered in the system.\n     * @return newMarketId The id with which the market will be registered in the system.\n     */\n    function registerMarket(address market) external returns (uint128 newMarketId);\n\n    /**\n     * @notice Allows an external market connected to the system to deposit USD in the system.\n     * @dev The system burns the incoming USD, increases the market's credit capacity, and reduces its issuance.\n     * @dev See `IMarket`.\n     * @param marketId The id of the market in which snxUSD will be deposited.\n     * @param target The address of the account on who's behalf the deposit will be made.\n     * @param amount The amount of snxUSD to be deposited, denominated with 18 decimals of precision.\n     * @return feeAmount the amount of fees paid (billed as additional debt towards liquidity providers)\n     */\n    function depositMarketUsd(\n        uint128 marketId,\n        address target,\n        uint256 amount\n    ) external returns (uint256 feeAmount);\n\n    /**\n     * @notice Allows an external market connected to the system to withdraw snxUSD from the system.\n     * @dev The system mints the requested snxUSD (provided that the market has sufficient credit), reduces the market's credit capacity, and increases its net issuance.\n     * @dev See `IMarket`.\n     * @param marketId The id of the market from which snxUSD will be withdrawn.\n     * @param target The address of the account that will receive the withdrawn snxUSD.\n     * @param amount The amount of snxUSD to be withdraw, denominated with 18 decimals of precision.\n     * @return feeAmount the amount of fees paid (billed as additional debt towards liquidity providers)\n     */\n    function withdrawMarketUsd(\n        uint128 marketId,\n        address target,\n        uint256 amount\n    ) external returns (uint256 feeAmount);\n\n    /**\n     * @notice Get the amount of fees paid in USD for a call to `depositMarketUsd` and `withdrawMarketUsd` for the given market and amount\n     * @param marketId The market to check fees for\n     * @param amount The amount deposited or withdrawn in USD\n     * @return depositFeeAmount the amount of USD paid for a call to `depositMarketUsd`\n     * @return withdrawFeeAmount the amount of USD paid for a call to `withdrawMarketUsd`\n     */\n    function getMarketFees(\n        uint128 marketId,\n        uint256 amount\n    ) external view returns (uint256 depositFeeAmount, uint256 withdrawFeeAmount);\n\n    /**\n     * @notice Returns the total withdrawable snxUSD amount for the specified market.\n     * @param marketId The id of the market whose withdrawable USD amount is being queried.\n     * @return withdrawableD18 The total amount of snxUSD that the market could withdraw at the time of the query, denominated with 18 decimals of precision.\n     */\n    function getWithdrawableMarketUsd(\n        uint128 marketId\n    ) external view returns (uint256 withdrawableD18);\n\n    /**\n     * @notice Returns the contract address for the specified market.\n     * @param marketId The id of the market\n     * @return marketAddress The contract address for the specified market\n     */\n    function getMarketAddress(uint128 marketId) external view returns (address marketAddress);\n\n    /**\n     * @notice Returns the net issuance of the specified market (snxUSD withdrawn - snxUSD deposited).\n     * @param marketId The id of the market whose net issuance is being queried.\n     * @return issuanceD18 The net issuance of the market, denominated with 18 decimals of precision.\n     */\n    function getMarketNetIssuance(uint128 marketId) external view returns (int128 issuanceD18);\n\n    /**\n     * @notice Returns the reported debt of the specified market.\n     * @param marketId The id of the market whose reported debt is being queried.\n     * @return reportedDebtD18 The market's reported debt, denominated with 18 decimals of precision.\n     */\n    function getMarketReportedDebt(\n        uint128 marketId\n    ) external view returns (uint256 reportedDebtD18);\n\n    /**\n     * @notice Returns the total debt of the specified market.\n     * @param marketId The id of the market whose debt is being queried.\n     * @return totalDebtD18 The total debt of the market, denominated with 18 decimals of precision.\n     */\n    function getMarketTotalDebt(uint128 marketId) external view returns (int256 totalDebtD18);\n\n    /**\n     * @notice Returns the total snxUSD value of the collateral for the specified market.\n     * @param marketId The id of the market whose collateral is being queried.\n     * @return valueD18 The market's total snxUSD value of collateral, denominated with 18 decimals of precision.\n     */\n    function getMarketCollateral(uint128 marketId) external view returns (uint256 valueD18);\n\n    /**\n     * @notice Returns the value per share of the debt of the specified market.\n     * @dev This is not a view function, and actually updates the entire debt distribution chain.\n     * @param marketId The id of the market whose debt per share is being queried.\n     * @return debtPerShareD18 The market's debt per share value, denominated with 18 decimals of precision.\n     */\n    function getMarketDebtPerShare(uint128 marketId) external returns (int256 debtPerShareD18);\n\n    /**\n     * @notice Returns whether the capacity of the specified market is locked.\n     * @param marketId The id of the market whose capacity is being queried.\n     * @return isLocked A boolean that is true if the market's capacity is locked at the time of the query.\n     */\n    function isMarketCapacityLocked(uint128 marketId) external view returns (bool isLocked);\n\n    /**\n     * @notice Returns the USD token associated with this synthetix core system\n     */\n    function getUsdToken() external view returns (IERC20);\n\n    /**\n     * @notice Retrieve the systems' configured oracle manager address\n     */\n    function getOracleManager() external view returns (IOracleManager);\n\n    /**\n     * @notice Update a market's current debt registration with the system.\n     * This function is provided as an escape hatch for pool griefing, preventing\n     * overwhelming the system with a series of very small pools and creating high gas\n     * costs to update an account.\n     * @param marketId the id of the market that needs pools bumped\n     * @return finishedDistributing whether or not all bumpable pools have been bumped and target price has been reached\n     */\n    function distributeDebtToPools(\n        uint128 marketId,\n        uint256 maxIter\n    ) external returns (bool finishedDistributing);\n\n    /**\n     * @notice allows for a market to set its minimum delegation time. This is useful for preventing stakers from frontrunning rewards or losses\n     * by limiting the frequency of `delegateCollateral` (or `setPoolConfiguration`) calls. By default, there is no minimum delegation time.\n     * @param marketId the id of the market that wants to set delegation time.\n     * @param minDelegateTime the minimum number of seconds between delegation calls. Note: this value must be less than the globally defined maximum minDelegateTime\n     */\n    function setMarketMinDelegateTime(uint128 marketId, uint32 minDelegateTime) external;\n\n    /**\n     * @notice Retrieve the minimum delegation time of a market\n     * @param marketId the id of the market\n     */\n    function getMarketMinDelegateTime(uint128 marketId) external view returns (uint32);\n\n    /**\n     * @notice Allows the system owner (not the pool owner) to set a market-specific minimum liquidity ratio.\n     * @param marketId the id of the market\n     * @param minLiquidityRatio The new market-specific minimum liquidity ratio, denominated with 18 decimals of precision. (100% is represented by 1 followed by 18 zeros.)\n     */\n    function setMinLiquidityRatio(uint128 marketId, uint256 minLiquidityRatio) external;\n\n    /**\n     * @notice Retrieves the market-specific minimum liquidity ratio.\n     * @param marketId the id of the market\n     * @return minRatioD18 The current market-specific minimum liquidity ratio, denominated with 18 decimals of precision. (100% is represented by 1 followed by 18 zeros.)\n     */\n    function getMinLiquidityRatio(uint128 marketId) external view returns (uint256 minRatioD18);\n\n    function getMarketPools(\n        uint128 marketId\n    ) external returns (uint128[] memory inRangePoolIds, uint128[] memory outRangePoolIds);\n\n    function getMarketPoolDebtDistribution(\n        uint128 marketId,\n        uint128 poolId\n    ) external returns (uint256 sharesD18, uint128 totalSharesD18, int128 valuePerShareD27);\n}\n"
      },
      "contracts/interfaces/IUSDTokenModule.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/core-modules/contracts/interfaces/ITokenModule.sol\";\n\n/**\n * @title Module for managing the snxUSD token as an associated system.\n */\ninterface IUSDTokenModule is ITokenModule {\n    /**\n     * @notice Allows the core system to burn snxUSD held by the `from` address, provided that it has given allowance to `spender`.\n     * @param from The address that holds the snxUSD to be burned.\n     * @param spender The address to which the holder has given allowance to.\n     * @param amount The amount of snxUSD to be burned, denominated with 18 decimals of precision.\n     */\n    function burnWithAllowance(address from, address spender, uint256 amount) external;\n\n    /**\n     * @notice Destroys `amount` of snxUSD tokens from the caller. This is derived from ERC20Burnable.sol and is currently included for testing purposes with CCIP token pools.\n     * @param amount The amount of snxUSD to be burned, denominated with 18 decimals of precision.\n     */\n    function burn(uint256 amount) external;\n}\n"
      },
      "contracts/modules/core/MarketManagerModule.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"../../interfaces/IMarketManagerModule.sol\";\nimport \"../../interfaces/IUSDTokenModule.sol\";\nimport \"../../interfaces/external/IMarket.sol\";\n\nimport \"@synthetixio/core-contracts/contracts/errors/AccessError.sol\";\nimport \"@synthetixio/core-contracts/contracts/ownership/OwnableStorage.sol\";\nimport \"@synthetixio/core-contracts/contracts/utils/SafeCast.sol\";\nimport \"@synthetixio/core-contracts/contracts/utils/ERC165Helper.sol\";\nimport \"@synthetixio/core-contracts/contracts/utils/HeapUtil.sol\";\nimport \"@synthetixio/core-contracts/contracts/utils/ERC2771Context.sol\";\n\nimport \"../../storage/Config.sol\";\nimport \"../../storage/Market.sol\";\nimport \"../../storage/MarketCreator.sol\";\nimport \"../../storage/Distribution.sol\";\n\nimport \"@synthetixio/core-modules/contracts/storage/AssociatedSystem.sol\";\nimport \"@synthetixio/core-modules/contracts/storage/FeatureFlag.sol\";\n\nimport \"@synthetixio/core-contracts/contracts/errors/ParameterError.sol\";\n\n/**\n * @title System-wide entry point for the management of markets connected to the system.\n * @dev See IMarketManagerModule.\n */\ncontract MarketManagerModule is IMarketManagerModule {\n    using SafeCastU128 for uint128;\n    using SafeCastU256 for uint256;\n    using SafeCastI128 for int128;\n    using SafeCastI256 for int256;\n    using Market for Market.Data;\n    using AssociatedSystem for AssociatedSystem.Data;\n    using Distribution for Distribution.Data;\n    using HeapUtil for HeapUtil.Data;\n\n    using DecimalMath for uint256;\n\n    bytes32 private constant _USD_TOKEN = \"USDToken\";\n    bytes32 private constant _MARKET_FEATURE_FLAG = \"registerMarket\";\n    bytes32 private constant _DEPOSIT_MARKET_FEATURE_FLAG = \"depositMarketUsd\";\n    bytes32 private constant _WITHDRAW_MARKET_FEATURE_FLAG = \"withdrawMarketUsd\";\n\n    bytes32 private constant _CONFIG_SET_MARKET_MIN_DELEGATE_MAX = \"setMarketMinDelegateTime_max\";\n    bytes32 private constant _CONFIG_DEPOSIT_MARKET_USD_FEE_RATIO = \"depositMarketUsd_feeRatio\";\n    bytes32 private constant _CONFIG_WITHDRAW_MARKET_USD_FEE_RATIO = \"withdrawMarketUsd_feeRatio\";\n    bytes32 private constant _CONFIG_DEPOSIT_MARKET_USD_FEE_ADDRESS = \"depositMarketUsd_feeAddress\";\n    bytes32 private constant _CONFIG_WITHDRAW_MARKET_USD_FEE_ADDRESS =\n        \"withdrawMarketUsd_feeAddress\";\n\n    /**\n     * @inheritdoc IMarketManagerModule\n     */\n    function registerMarket(address market) external override returns (uint128 marketId) {\n        FeatureFlag.ensureAccessToFeature(_MARKET_FEATURE_FLAG);\n\n        if (!ERC165Helper.safeSupportsInterface(market, type(IMarket).interfaceId)) {\n            revert IncorrectMarketInterface(market);\n        }\n\n        marketId = MarketCreator.create(market).id;\n\n        emit MarketRegistered(market, marketId, ERC2771Context._msgSender());\n\n        return marketId;\n    }\n\n    /**\n     * @inheritdoc IMarketManagerModule\n     */\n    function getWithdrawableMarketUsd(uint128 marketId) public view override returns (uint256) {\n        int256 withdrawable = Market.load(marketId).creditCapacityD18 +\n            Market.load(marketId).getDepositedCollateralValue().toInt();\n\n        return withdrawable < 0 ? 0 : withdrawable.toUint();\n    }\n\n    /**\n     * @inheritdoc IMarketManagerModule\n     */\n    function getMarketAddress(uint128 marketId) external view override returns (address) {\n        return Market.load(marketId).marketAddress;\n    }\n\n    /**\n     * @inheritdoc IMarketManagerModule\n     */\n    function getMarketNetIssuance(uint128 marketId) external view override returns (int128) {\n        return Market.load(marketId).netIssuanceD18;\n    }\n\n    /**\n     * @inheritdoc IMarketManagerModule\n     */\n    function getMarketReportedDebt(uint128 marketId) external view override returns (uint256) {\n        return Market.load(marketId).getReportedDebt();\n    }\n\n    /**\n     * @inheritdoc IMarketManagerModule\n     */\n    function getMarketCollateral(uint128 marketId) external view override returns (uint256) {\n        return Market.load(marketId).poolsDebtDistribution.totalSharesD18;\n    }\n\n    /**\n     * @inheritdoc IMarketManagerModule\n     */\n    function getMarketTotalDebt(uint128 marketId) external view override returns (int256) {\n        return Market.load(marketId).totalDebt();\n    }\n\n    /**\n     * @inheritdoc IMarketManagerModule\n     */\n    function getMarketDebtPerShare(uint128 marketId) external override returns (int256) {\n        Market.Data storage market = Market.load(marketId);\n\n        market.distributeDebtToPools(999999999);\n\n        return market.getDebtPerShare();\n    }\n\n    /**\n     * @inheritdoc IMarketManagerModule\n     */\n    function getMarketPools(\n        uint128 marketId\n    )\n        external\n        override\n        returns (uint128[] memory inRangePoolIds, uint128[] memory outRangePoolIds)\n    {\n        Market.Data storage market = Market.load(marketId);\n        market.distributeDebtToPools(999999999);\n\n        HeapUtil.Data storage inRangePools = market.inRangePools;\n        inRangePoolIds = new uint128[](inRangePools.size());\n        for (uint i = 1; i <= inRangePools.size(); i++) {\n            HeapUtil.Node memory node = inRangePools.getByIndex(i);\n            inRangePoolIds[i - 1] = node.id;\n        }\n\n        HeapUtil.Data storage outRangePools = market.outRangePools;\n        outRangePoolIds = new uint128[](outRangePools.size());\n        for (uint i = 1; i <= outRangePools.size(); i++) {\n            HeapUtil.Node memory node = outRangePools.getByIndex(i);\n            outRangePoolIds[i - 1] = node.id;\n        }\n    }\n\n    /**\n     * @inheritdoc IMarketManagerModule\n     */\n    function getMarketPoolDebtDistribution(\n        uint128 marketId,\n        uint128 poolId\n    )\n        external\n        override\n        returns (uint256 sharesD18, uint128 totalSharesD18, int128 valuePerShareD27)\n    {\n        Market.Data storage market = Market.load(marketId);\n        market.distributeDebtToPools(999999999);\n\n        Distribution.Data storage poolDistribution = market.poolsDebtDistribution;\n        sharesD18 = poolDistribution.getActorShares(poolId.toBytes32());\n\n        totalSharesD18 = market.poolsDebtDistribution.totalSharesD18;\n        valuePerShareD27 = market.poolsDebtDistribution.valuePerShareD27;\n    }\n\n    /**\n     * @inheritdoc IMarketManagerModule\n     */\n    function isMarketCapacityLocked(uint128 marketId) external view override returns (bool) {\n        return Market.load(marketId).isCapacityLocked();\n    }\n\n    function getUsdToken() external view override returns (IERC20) {\n        return AssociatedSystem.load(_USD_TOKEN).asToken();\n    }\n\n    function getOracleManager() external view returns (IOracleManager) {\n        return IOracleManager(OracleManager.load().oracleManagerAddress);\n    }\n\n    /**\n     * @inheritdoc IMarketManagerModule\n     */\n    function depositMarketUsd(\n        uint128 marketId,\n        address target,\n        uint256 amount\n    ) external override returns (uint256 feeAmount) {\n        FeatureFlag.ensureAccessToFeature(_DEPOSIT_MARKET_FEATURE_FLAG);\n        Market.Data storage market = Market.load(marketId);\n\n        // Call must come from the market itself.\n        if (ERC2771Context._msgSender() != market.marketAddress)\n            revert AccessError.Unauthorized(ERC2771Context._msgSender());\n\n        feeAmount = amount.mulDecimal(Config.readUint(_CONFIG_DEPOSIT_MARKET_USD_FEE_RATIO, 0));\n        address feeAddress = address(0);\n        address configFeeAddress = Config.readAddress(\n            _CONFIG_DEPOSIT_MARKET_USD_FEE_ADDRESS,\n            address(0)\n        );\n\n        if (feeAmount > 0 && configFeeAddress != address(0)) {\n            feeAddress = configFeeAddress;\n        }\n        // verify if the market is authorized to burn the USD for the target\n        ITokenModule usdToken = AssociatedSystem.load(_USD_TOKEN).asToken();\n\n        // Adjust accounting.\n        market.creditCapacityD18 += (amount - feeAmount).toInt().to128();\n        market.netIssuanceD18 -= (amount - feeAmount).toInt().to128();\n\n        // Burn the incoming USD.\n        // Note: Instead of burning, we could transfer USD to and from the MarketManager,\n        // but minting and burning takes the USD out of circulation,\n        // which doesn't affect `totalSupply`, thus simplifying accounting.\n        IUSDTokenModule(address(usdToken)).burnWithAllowance(\n            target,\n            ERC2771Context._msgSender(),\n            amount\n        );\n\n        if (feeAmount > 0 && feeAddress != address(0)) {\n            IUSDTokenModule(address(usdToken)).mint(feeAddress, feeAmount);\n\n            emit MarketSystemFeePaid(marketId, feeAmount);\n        }\n\n        emit MarketUsdDeposited(\n            marketId,\n            target,\n            amount,\n            ERC2771Context._msgSender(),\n            market.creditCapacityD18,\n            market.netIssuanceD18,\n            market.getDepositedCollateralValue(),\n            market.getReportedDebt()\n        );\n    }\n\n    /**\n     * @inheritdoc IMarketManagerModule\n     */\n    function withdrawMarketUsd(\n        uint128 marketId,\n        address target,\n        uint256 amount\n    ) external override returns (uint256 feeAmount) {\n        FeatureFlag.ensureAccessToFeature(_WITHDRAW_MARKET_FEATURE_FLAG);\n        Market.Data storage marketData = Market.load(marketId);\n\n        // Call must come from the market itself.\n        if (ERC2771Context._msgSender() != marketData.marketAddress)\n            revert AccessError.Unauthorized(ERC2771Context._msgSender());\n\n        // Ensure that the market's balance allows for this withdrawal.\n        feeAmount = amount.mulDecimal(Config.readUint(_CONFIG_WITHDRAW_MARKET_USD_FEE_RATIO, 0));\n        if (amount + feeAmount > getWithdrawableMarketUsd(marketId))\n            revert NotEnoughLiquidity(marketId, amount);\n\n        address feeAddress = address(0);\n        address configFeeAddress = Config.readAddress(\n            _CONFIG_WITHDRAW_MARKET_USD_FEE_ADDRESS,\n            address(0)\n        );\n\n        if (feeAmount > 0 && configFeeAddress != address(0)) {\n            feeAddress = configFeeAddress;\n        }\n\n        // Adjust accounting.\n        marketData.creditCapacityD18 -= (amount + feeAmount).toInt().to128();\n        marketData.netIssuanceD18 += (amount + feeAmount).toInt().to128();\n\n        // Mint the requested USD.\n        AssociatedSystem.load(_USD_TOKEN).asToken().mint(target, amount);\n\n        if (feeAmount > 0 && feeAddress != address(0)) {\n            AssociatedSystem.load(_USD_TOKEN).asToken().mint(feeAddress, feeAmount);\n\n            emit MarketSystemFeePaid(marketId, feeAmount);\n        }\n\n        emit MarketUsdWithdrawn(\n            marketId,\n            target,\n            amount,\n            ERC2771Context._msgSender(),\n            marketData.creditCapacityD18,\n            marketData.netIssuanceD18,\n            marketData.getDepositedCollateralValue(),\n            marketData.getReportedDebt()\n        );\n    }\n\n    /**\n     * @inheritdoc IMarketManagerModule\n     */\n    function getMarketFees(\n        uint128,\n        uint256 amount\n    ) external view override returns (uint256 depositFeeAmount, uint256 withdrawFeeAmount) {\n        depositFeeAmount = amount.mulDecimal(\n            Config.readUint(_CONFIG_DEPOSIT_MARKET_USD_FEE_RATIO, 0)\n        );\n\n        withdrawFeeAmount = amount.mulDecimal(\n            Config.readUint(_CONFIG_WITHDRAW_MARKET_USD_FEE_RATIO, 0)\n        );\n    }\n\n    /**\n     * @inheritdoc IMarketManagerModule\n     */\n    function distributeDebtToPools(\n        uint128 marketId,\n        uint256 maxIter\n    ) external override returns (bool) {\n        return Market.load(marketId).distributeDebtToPools(maxIter);\n    }\n\n    /**\n     * @inheritdoc IMarketManagerModule\n     */\n    function setMarketMinDelegateTime(uint128 marketId, uint32 minDelegateTime) external override {\n        Market.Data storage market = Market.load(marketId);\n\n        if (ERC2771Context._msgSender() != market.marketAddress)\n            revert AccessError.Unauthorized(ERC2771Context._msgSender());\n\n        // min delegate time should not be unreasonably long\n        uint256 maxMinDelegateTime = Config.readUint(\n            _CONFIG_SET_MARKET_MIN_DELEGATE_MAX,\n            86400 * 30\n        );\n\n        if (minDelegateTime > maxMinDelegateTime) {\n            revert ParameterError.InvalidParameter(\"minDelegateTime\", \"must not be too large\");\n        }\n\n        market.minDelegateTime = minDelegateTime;\n\n        emit SetMinDelegateTime(marketId, minDelegateTime);\n    }\n\n    /**\n     * @inheritdoc IMarketManagerModule\n     */\n    function getMarketMinDelegateTime(uint128 marketId) external view override returns (uint32) {\n        // solhint-disable-next-line numcast/safe-cast\n        uint32 maxMinDelegateTime = uint32(\n            Config.readUint(_CONFIG_SET_MARKET_MIN_DELEGATE_MAX, 86400 * 30)\n        );\n        uint32 marketMinDelegateTime = Market.load(marketId).minDelegateTime;\n        return\n            maxMinDelegateTime < marketMinDelegateTime ? maxMinDelegateTime : marketMinDelegateTime;\n    }\n\n    /**\n     * @inheritdoc IMarketManagerModule\n     */\n    function setMinLiquidityRatio(uint128 marketId, uint256 minLiquidityRatio) external override {\n        OwnableStorage.onlyOwner();\n        Market.Data storage market = Market.load(marketId);\n\n        market.minLiquidityRatioD18 = minLiquidityRatio;\n\n        emit SetMarketMinLiquidityRatio(marketId, minLiquidityRatio);\n    }\n\n    /**\n     * @inheritdoc IMarketManagerModule\n     */\n    function getMinLiquidityRatio(uint128 marketId) external view override returns (uint256) {\n        return Market.load(marketId).minLiquidityRatioD18;\n    }\n}\n"
      },
      "contracts/storage/CollateralConfiguration.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/core-contracts/contracts/utils/SetUtil.sol\";\nimport \"@synthetixio/core-contracts/contracts/utils/DecimalMath.sol\";\nimport \"@synthetixio/core-contracts/contracts/errors/ParameterError.sol\";\nimport \"@synthetixio/oracle-manager/contracts/interfaces/INodeModule.sol\";\nimport \"@synthetixio/oracle-manager/contracts/storage/NodeOutput.sol\";\nimport \"@synthetixio/core-contracts/contracts/interfaces/IERC20.sol\";\nimport \"@synthetixio/core-contracts/contracts/utils/SafeCast.sol\";\n\nimport \"./OracleManager.sol\";\n\n/**\n * @title Tracks system-wide settings for each collateral type, as well as helper functions for it, such as retrieving its current price from the oracle manager.\n */\nlibrary CollateralConfiguration {\n    bytes32 private constant _SLOT_AVAILABLE_COLLATERALS =\n        keccak256(\n            abi.encode(\"io.synthetix.synthetix.CollateralConfiguration_availableCollaterals\")\n        );\n\n    using SetUtil for SetUtil.AddressSet;\n    using DecimalMath for uint256;\n    using SafeCastI256 for int256;\n\n    /**\n     * @dev Thrown when the token address of a collateral cannot be found.\n     */\n    error CollateralNotFound();\n\n    /**\n     * @dev Thrown when deposits are disabled for the given collateral type.\n     * @param collateralType The address of the collateral type for which depositing was disabled.\n     */\n    error CollateralDepositDisabled(address collateralType);\n\n    /**\n     * @dev Thrown when collateral ratio is not sufficient in a given operation in the system.\n     * @param collateralValue The net USD value of the position.\n     * @param debt The net USD debt of the position.\n     * @param ratio The collateralization ratio of the position.\n     * @param minRatio The minimum c-ratio which was not met. Could be issuance ratio or liquidation ratio, depending on the case.\n     */\n    error InsufficientCollateralRatio(\n        uint256 collateralValue,\n        uint256 debt,\n        uint256 ratio,\n        uint256 minRatio\n    );\n\n    /**\n     * @dev Thrown when the amount being delegated is less than the minimum expected amount.\n     * @param minDelegation The current minimum for deposits and delegation set to this collateral type.\n     */\n    error InsufficientDelegation(uint256 minDelegation);\n\n    /**\n     * @dev Thrown when attempting to convert a token to the system amount and the conversion results in a loss of precision.\n     * @param tokenAmount The amount of tokens that were attempted to be converted.\n     * @param decimals The number of decimals of the token that was attempted to be converted.\n     */\n    error PrecisionLost(uint256 tokenAmount, uint8 decimals);\n\n    struct Data {\n        /**\n         * @dev Allows the owner to control deposits and delegation of collateral types.\n         */\n        bool depositingEnabled;\n        /**\n         * @dev System-wide collateralization ratio for issuance of snxUSD.\n         * Accounts will not be able to mint snxUSD if they are below this issuance c-ratio.\n         */\n        uint256 issuanceRatioD18;\n        /**\n         * @dev System-wide collateralization ratio for liquidations of this collateral type.\n         * Accounts below this c-ratio can be immediately liquidated.\n         */\n        uint256 liquidationRatioD18;\n        /**\n         * @dev Amount of tokens to award when an account is liquidated.\n         */\n        uint256 liquidationRewardD18;\n        /**\n         * @dev The oracle manager node id which reports the current price for this collateral type.\n         */\n        bytes32 oracleNodeId;\n        /**\n         * @dev The token address for this collateral type.\n         */\n        address tokenAddress;\n        /**\n         * @dev Minimum amount that accounts can delegate to pools.\n         * Helps prevent spamming on the system.\n         * Note: If zero, liquidationRewardD18 will be used.\n         */\n        uint256 minDelegationD18;\n    }\n\n    /**\n     * @dev Loads the CollateralConfiguration object for the given collateral type.\n     * @param token The address of the collateral type.\n     * @return collateralConfiguration The CollateralConfiguration object.\n     */\n    function load(address token) internal pure returns (Data storage collateralConfiguration) {\n        bytes32 s = keccak256(abi.encode(\"io.synthetix.synthetix.CollateralConfiguration\", token));\n        assembly {\n            collateralConfiguration.slot := s\n        }\n    }\n\n    /**\n     * @dev Loads all available collateral types configured in the system.\n     * @return availableCollaterals An array of addresses, one for each collateral type supported by the system.\n     */\n    function loadAvailableCollaterals()\n        internal\n        pure\n        returns (SetUtil.AddressSet storage availableCollaterals)\n    {\n        bytes32 s = _SLOT_AVAILABLE_COLLATERALS;\n        assembly {\n            availableCollaterals.slot := s\n        }\n    }\n\n    /**\n     * @dev Configures a collateral type.\n     * @param config The CollateralConfiguration object with all the settings for the collateral type being configured.\n     */\n    function set(Data memory config) internal {\n        SetUtil.AddressSet storage collateralTypes = loadAvailableCollaterals();\n\n        if (!collateralTypes.contains(config.tokenAddress)) {\n            collateralTypes.add(config.tokenAddress);\n        }\n\n        if (config.minDelegationD18 < config.liquidationRewardD18) {\n            revert ParameterError.InvalidParameter(\n                \"minDelegation\",\n                \"must be greater than liquidationReward\"\n            );\n        }\n\n        if (config.issuanceRatioD18 <= 1e18) {\n            revert ParameterError.InvalidParameter(\"issuanceRatioD18\", \"must be greater than 100%\");\n        }\n\n        if (config.liquidationRatioD18 <= 1e18) {\n            revert ParameterError.InvalidParameter(\n                \"liquidationRatioD18\",\n                \"must be greater than 100%\"\n            );\n        }\n\n        if (config.issuanceRatioD18 < config.liquidationRatioD18) {\n            revert ParameterError.InvalidParameter(\n                \"issuanceRatioD18\",\n                \"must be greater than liquidationRatioD18\"\n            );\n        }\n\n        Data storage storedConfig = load(config.tokenAddress);\n\n        storedConfig.tokenAddress = config.tokenAddress;\n        storedConfig.issuanceRatioD18 = config.issuanceRatioD18;\n        storedConfig.liquidationRatioD18 = config.liquidationRatioD18;\n        storedConfig.oracleNodeId = config.oracleNodeId;\n        storedConfig.liquidationRewardD18 = config.liquidationRewardD18;\n        storedConfig.minDelegationD18 = config.minDelegationD18;\n        storedConfig.depositingEnabled = config.depositingEnabled;\n    }\n\n    /**\n     * @dev Shows if a given collateral type is enabled for deposits and delegation.\n     * @param token The address of the collateral being queried.\n     */\n    function collateralEnabled(address token) internal view {\n        if (!load(token).depositingEnabled) {\n            revert CollateralDepositDisabled(token);\n        }\n    }\n\n    /**\n     * @dev Reverts if the amount being delegated is insufficient for the system.\n     * @param token The address of the collateral type.\n     * @param amountD18 The amount being checked for sufficient delegation.\n     */\n    function requireSufficientDelegation(address token, uint256 amountD18) internal view {\n        CollateralConfiguration.Data storage config = load(token);\n\n        uint256 minDelegationD18 = config.minDelegationD18;\n\n        if (minDelegationD18 == 0) {\n            minDelegationD18 = config.liquidationRewardD18;\n        }\n\n        if (amountD18 < minDelegationD18) {\n            revert InsufficientDelegation(minDelegationD18);\n        }\n    }\n\n    /**\n     * @dev Returns the price of this collateral configuration object.\n     * @param self The CollateralConfiguration object.\n     * @param collateralAmount The amount of collateral to get the price for.\n     * @return The price of the collateral with 18 decimals of precision.\n     */\n    function getCollateralPrice(\n        Data storage self,\n        uint256 collateralAmount\n    ) internal view returns (uint256) {\n        OracleManager.Data memory oracleManager = OracleManager.load();\n\n        bytes32[] memory runtimeKeys = new bytes32[](1);\n        bytes32[] memory runtimeValues = new bytes32[](1);\n        runtimeKeys[0] = bytes32(\"size\");\n        runtimeValues[0] = bytes32(collateralAmount);\n        NodeOutput.Data memory node = INodeModule(oracleManager.oracleManagerAddress)\n            .processWithRuntime(self.oracleNodeId, runtimeKeys, runtimeValues);\n\n        return node.price.toUint();\n    }\n\n    /**\n     * @dev Reverts if the specified collateral and debt values produce a collateralization ratio which is below the amount required for new issuance of snxUSD.\n     * @param self The CollateralConfiguration object whose collateral and settings are being queried.\n     * @param debtD18 The debt component of the ratio.\n     * @param collateralValueD18 The collateral component of the ratio.\n     */\n    function verifyIssuanceRatio(\n        Data storage self,\n        uint256 debtD18,\n        uint256 collateralValueD18,\n        uint256 minIssuanceRatioD18\n    ) internal view {\n        uint256 issuanceRatioD18 = self.issuanceRatioD18 > minIssuanceRatioD18\n            ? self.issuanceRatioD18\n            : minIssuanceRatioD18;\n\n        if (\n            debtD18 != 0 &&\n            (collateralValueD18 == 0 || collateralValueD18.divDecimal(debtD18) < issuanceRatioD18)\n        ) {\n            revert InsufficientCollateralRatio(\n                collateralValueD18,\n                debtD18,\n                collateralValueD18.divDecimal(debtD18),\n                issuanceRatioD18\n            );\n        }\n    }\n\n    /**\n     * @dev Converts token amounts with non-system decimal precisions, to 18 decimals of precision.\n     * E.g: $TOKEN_A uses 6 decimals of precision, so this would upscale it by 12 decimals.\n     * E.g: $TOKEN_B uses 20 decimals of precision, so this would downscale it by 2 decimals.\n     * @param self The CollateralConfiguration object corresponding to the collateral type being converted.\n     * @param tokenAmount The token amount, denominated in its native decimal precision.\n     * @return amountD18 The converted amount, denominated in the system's 18 decimal precision.\n     */\n    function convertTokenToSystemAmount(\n        Data storage self,\n        uint256 tokenAmount\n    ) internal view returns (uint256 amountD18) {\n        // this extra condition is to prevent potentially malicious untrusted code from being executed on the next statement\n        if (self.tokenAddress == address(0)) {\n            revert CollateralNotFound();\n        }\n\n        /// @dev this try-catch block assumes there is no malicious code in the token's fallback function\n        try IERC20(self.tokenAddress).decimals() returns (uint8 decimals) {\n            if (decimals == 18) {\n                amountD18 = tokenAmount;\n            } else if (decimals < 18) {\n                amountD18 = (tokenAmount * DecimalMath.UNIT) / (10 ** decimals);\n            } else {\n                // ensure no precision is lost when converting to 18 decimals\n                if (tokenAmount % (10 ** (decimals - 18)) != 0) {\n                    revert PrecisionLost(tokenAmount, decimals);\n                }\n\n                // this will scale down the amount by the difference between the token's decimals and 18\n                amountD18 = (tokenAmount * DecimalMath.UNIT) / (10 ** decimals);\n            }\n        } catch {\n            // if the token doesn't have a decimals function, assume it's 18 decimals\n            amountD18 = tokenAmount;\n        }\n    }\n}\n"
      },
      "contracts/storage/Config.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title System wide configuration for anything\n */\nlibrary Config {\n    struct Data {\n        uint256 __unused;\n    }\n\n    /**\n     * @dev Returns a config value\n     */\n    function read(bytes32 k, bytes32 zeroValue) internal view returns (bytes32 v) {\n        bytes32 s = keccak256(abi.encode(\"Config\", k));\n        assembly {\n            v := sload(s)\n        }\n\n        if (v == bytes32(0)) {\n            v = zeroValue;\n        }\n    }\n\n    function readUint(bytes32 k, uint256 zeroValue) internal view returns (uint256 v) {\n        // solhint-disable-next-line numcast/safe-cast\n        return uint(read(k, bytes32(zeroValue)));\n    }\n\n    function readAddress(bytes32 k, address zeroValue) internal view returns (address v) {\n        // solhint-disable-next-line numcast/safe-cast\n        return address(uint160(readUint(k, uint160(zeroValue))));\n    }\n\n    function put(bytes32 k, bytes32 v) internal {\n        bytes32 s = keccak256(abi.encode(\"Config\", k));\n        assembly {\n            sstore(s, v)\n        }\n    }\n}\n"
      },
      "contracts/storage/Distribution.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 \"./DistributionActor.sol\";\n\n/**\n * @title Data structure that allows you to track some global value, distributed amongst a set of actors.\n *\n * The total value can be scaled with a valuePerShare multiplier, and individual actor shares can be calculated as their amount of shares times this multiplier.\n *\n * Furthermore, changes in the value of individual actors can be tracked since their last update, by keeping track of the value of the multiplier, per user, upon each interaction. See DistributionActor.lastValuePerShare.\n *\n * A distribution is similar to a ScalableMapping, but it has the added functionality of being able to remember the previous value of the scalar multiplier for each actor.\n *\n * Whenever the shares of an actor of the distribution is updated, you get information about how the actor's total value changed since it was last updated.\n */\nlibrary Distribution {\n    using SafeCastU128 for uint128;\n    using SafeCastU256 for uint256;\n    using SafeCastI128 for int128;\n    using SafeCastI256 for int256;\n    using DecimalMath for int256;\n\n    /**\n     * @dev Thrown when an attempt is made to distribute value to a distribution\n     * with no shares.\n     */\n    error EmptyDistribution();\n\n    struct Data {\n        /**\n         * @dev The total number of shares in the distribution.\n         */\n        uint128 totalSharesD18;\n        /**\n         * @dev The value per share of the distribution, represented as a high precision decimal.\n         */\n        int128 valuePerShareD27;\n        /**\n         * @dev Tracks individual actor information, such as how many shares an actor has, their lastValuePerShare, etc.\n         */\n        mapping(bytes32 => DistributionActor.Data) actorInfo;\n    }\n\n    /**\n     * @dev Inflates or deflates the total value of the distribution by the given value.\n     *\n     * The value being distributed ultimately modifies the distribution's valuePerShare.\n     */\n    function distributeValue(Data storage self, int256 valueD18) internal {\n        if (valueD18 == 0) {\n            return;\n        }\n\n        uint256 totalSharesD18 = self.totalSharesD18;\n\n        if (totalSharesD18 == 0) {\n            revert EmptyDistribution();\n        }\n\n        int256 valueD45 = valueD18 * DecimalMath.UNIT_PRECISE_INT;\n        int256 deltaValuePerShareD27 = valueD45 / totalSharesD18.toInt();\n\n        self.valuePerShareD27 += deltaValuePerShareD27.to128();\n    }\n\n    /**\n     * @dev Updates an actor's number of shares in the distribution to the specified amount.\n     *\n     * Whenever an actor's shares are changed in this way, we record the distribution's current valuePerShare into the actor's lastValuePerShare record.\n     *\n     * Returns the the amount by which the actors value changed since the last update.\n     */\n    function setActorShares(\n        Data storage self,\n        bytes32 actorId,\n        uint256 newActorSharesD18\n    ) internal returns (int256 valueChangeD18) {\n        valueChangeD18 = getActorValueChange(self, actorId);\n\n        DistributionActor.Data storage actor = self.actorInfo[actorId];\n\n        uint128 sharesUint128D18 = newActorSharesD18.to128();\n        self.totalSharesD18 = self.totalSharesD18 + sharesUint128D18 - actor.sharesD18;\n\n        actor.sharesD18 = sharesUint128D18;\n        _updateLastValuePerShare(self, actor, newActorSharesD18);\n    }\n\n    /**\n     * @dev Updates an actor's lastValuePerShare to the distribution's current valuePerShare, and\n     * returns the change in value for the actor, since their last update.\n     */\n    function accumulateActor(\n        Data storage self,\n        bytes32 actorId\n    ) internal returns (int256 valueChangeD18) {\n        DistributionActor.Data storage actor = self.actorInfo[actorId];\n        return _updateLastValuePerShare(self, actor, actor.sharesD18);\n    }\n\n    /**\n     * @dev Calculates how much an actor's value has changed since its shares were last updated.\n     *\n     * This change is calculated as:\n     * Since `value = valuePerShare * shares`,\n     * then `delta_value = valuePerShare_now * shares - valuePerShare_then * shares`,\n     * which is `(valuePerShare_now - valuePerShare_then) * shares`,\n     * or just `delta_valuePerShare * shares`.\n     */\n    function getActorValueChange(\n        Data storage self,\n        bytes32 actorId\n    ) internal view returns (int256 valueChangeD18) {\n        return _getActorValueChange(self, self.actorInfo[actorId]);\n    }\n\n    /**\n     * @dev Returns the number of shares owned by an actor in the distribution.\n     */\n    function getActorShares(\n        Data storage self,\n        bytes32 actorId\n    ) internal view returns (uint256 sharesD18) {\n        return self.actorInfo[actorId].sharesD18;\n    }\n\n    /**\n     * @dev Returns the distribution's value per share in normal precision (18 decimals).\n     * @param self The distribution whose value per share is being queried.\n     * @return The value per share in 18 decimal precision.\n     */\n    function getValuePerShare(Data storage self) internal view returns (int256) {\n        return self.valuePerShareD27.to256().downscale(DecimalMath.PRECISION_FACTOR);\n    }\n\n    function _updateLastValuePerShare(\n        Data storage self,\n        DistributionActor.Data storage actor,\n        uint256 newActorShares\n    ) private returns (int256 valueChangeD18) {\n        valueChangeD18 = _getActorValueChange(self, actor);\n\n        actor.lastValuePerShareD27 = newActorShares == 0\n            ? SafeCastI128.zero()\n            : self.valuePerShareD27;\n    }\n\n    function _getActorValueChange(\n        Data storage self,\n        DistributionActor.Data storage actor\n    ) private view returns (int256 valueChangeD18) {\n        int256 deltaValuePerShareD27 = self.valuePerShareD27 - actor.lastValuePerShareD27;\n\n        int256 changedValueD45 = deltaValuePerShareD27 * actor.sharesD18.toInt();\n        valueChangeD18 = changedValueD45 / DecimalMath.UNIT_PRECISE_INT;\n    }\n}\n"
      },
      "contracts/storage/DistributionActor.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title Stores information for specific actors in a Distribution.\n */\nlibrary DistributionActor {\n    struct Data {\n        /**\n         * @dev The actor's current number of shares in the associated distribution.\n         */\n        uint128 sharesD18;\n        /**\n         * @dev The value per share that the associated distribution had at the time that the actor's number of shares was last modified.\n         *\n         * Note: This is also a high precision decimal. See Distribution.valuePerShare.\n         */\n        int128 lastValuePerShareD27;\n    }\n}\n"
      },
      "contracts/storage/Market.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/core-contracts/contracts/utils/HeapUtil.sol\";\n\nimport \"./Distribution.sol\";\nimport \"./CollateralConfiguration.sol\";\nimport \"./MarketPoolInfo.sol\";\n\nimport \"../interfaces/external/IMarket.sol\";\n\n/**\n * @title Connects external contracts that implement the `IMarket` interface to the system.\n *\n * Pools provide credit capacity (collateral) to the markets, and are reciprocally exposed to the associated market's debt.\n *\n * The Market object's main responsibility is to track collateral provided by the pools that support it, and to trace their debt back to such pools.\n */\nlibrary Market {\n    using Distribution for Distribution.Data;\n    using HeapUtil for HeapUtil.Data;\n    using DecimalMath for uint256;\n    using DecimalMath for uint128;\n    using DecimalMath for int256;\n    using DecimalMath for int128;\n    using SafeCastU256 for uint256;\n    using SafeCastU128 for uint128;\n    using SafeCastI256 for int256;\n    using SafeCastI128 for int128;\n\n    /**\n     * @dev Thrown when a specified market is not found.\n     */\n    error MarketNotFound(uint128 marketId);\n\n    struct Data {\n        /**\n         * @dev Numeric identifier for the market. Must be unique.\n         * @dev There cannot be a market with id zero (See MarketCreator.create()). Id zero is used as a null market reference.\n         */\n        uint128 id;\n        /**\n         * @dev Address for the external contract that implements the `IMarket` interface, which this Market objects connects to.\n         *\n         * Note: This object is how the system tracks the market. The actual market is external to the system, i.e. its own contract.\n         */\n        address marketAddress;\n        /**\n         * @dev Issuance can be seen as how much USD the Market \"has issued\", printed, or has asked the system to mint on its behalf.\n         *\n         * More precisely it can be seen as the net difference between the USD burnt and the USD minted by the market.\n         *\n         * More issuance means that the market owes more USD to the system.\n         *\n         * A market burns USD when users deposit it in exchange for some asset that the market offers.\n         * The Market object calls `MarketManager.depositUSD()`, which burns the USD, and decreases its issuance.\n         *\n         * A market mints USD when users return the asset that the market offered and thus withdraw their USD.\n         * The Market object calls `MarketManager.withdrawUSD()`, which mints the USD, and increases its issuance.\n         *\n         * Instead of burning, the Market object could transfer USD to and from the MarketManager, but minting and burning takes the USD out of circulation, which doesn't affect `totalSupply`, thus simplifying accounting.\n         *\n         * How much USD a market can mint depends on how much credit capacity is given to the market by the pools that support it, and reflected in `Market.capacity`.\n         *\n         */\n        int128 netIssuanceD18;\n        /**\n         * @dev The total amount of USD that the market could withdraw if it were to immediately unwrap all its positions.\n         *\n         * The Market's credit capacity increases when the market burns USD, i.e. when it deposits USD in the MarketManager.\n         *\n         * It decreases when the market mints USD, i.e. when it withdraws USD from the MarketManager.\n         *\n         * The Market's credit capacity also depends on how much credit is given to it by the pools that support it.\n         *\n         * The Market's credit capacity also has a dependency on the external market reported debt as it will respond to that debt (and hence change the credit capacity if it increases or decreases)\n         *\n         * The credit capacity can go negative if all of the collateral provided by pools is exhausted, and there is market provided collateral available to consume. in this case, the debt is still being\n         * appropriately assigned, but the market has a dynamic cap based on deposited collateral types.\n         *\n         */\n        int128 creditCapacityD18;\n        /**\n         * @dev The total balance that the market had the last time that its debt was distributed.\n         *\n         * A Market's debt is distributed when the reported debt of its associated external market is rolled into the pools that provide credit capacity to it.\n         */\n        int128 lastDistributedMarketBalanceD18;\n        /**\n         * @dev A heap of pools for which the market has not yet hit its maximum credit capacity.\n         *\n         * The heap is ordered according to this market's max value per share setting in the pools that provide credit capacity to it. See `MarketConfiguration.maxDebtShareValue`.\n         *\n         * The heap's getMax() and extractMax() functions allow us to retrieve the pool with the lowest `maxDebtShareValue`, since its elements are inserted and prioritized by negating their `maxDebtShareValue`.\n         *\n         * Lower max values per share are on the top of the heap. I.e. the heap could look like this:\n         *  .    -1\n         *      / \\\n         *     /   \\\n         *    -2    \\\n         *   / \\    -3\n         * -4   -5\n         *\n         * TL;DR: This data structure allows us to easily find the pool with the lowest or \"most vulnerable\" max value per share and process it if its actual value per share goes beyond this limit.\n         */\n        HeapUtil.Data inRangePools;\n        /**\n         * @dev A heap of pools for which the market has hit its maximum credit capacity.\n         *\n         * Used to reconnect pools to the market, when it falls back below its maximum credit capacity.\n         *\n         * See inRangePools for why a heap is used here.\n         */\n        HeapUtil.Data outRangePools;\n        /**\n         * @dev A market's debt distribution connects markets to the debt distribution chain, in this case pools. Pools are actors in the market's debt distribution, where the amount of shares they possess depends on the amount of collateral they provide to the market. The value per share of this distribution depends on the total debt or balance of the market (netIssuance + reportedDebt).\n         *\n         * The debt distribution chain will move debt from the market into its connected pools.\n         *\n         * Actors: Pools.\n         * Shares: The USD denominated credit capacity that the pool provides to the market.\n         * Value per share: Debt per dollar of credit that the associated external market accrues.\n         *\n         */\n        Distribution.Data poolsDebtDistribution;\n        /**\n         * @dev Additional info needed to remember pools when they are removed from the distribution (or subsequently re-added).\n         */\n        mapping(uint128 => MarketPoolInfo.Data) pools;\n        /**\n         * @dev Array of entries of market provided collateral.\n         *\n         * Markets may obtain additional liquidity, beyond that coming from depositors, by providing their own collateral.\n         *\n         */\n        DepositedCollateral[] depositedCollateral;\n        /**\n         * @dev The maximum amount of market provided collateral, per type, that this market can deposit.\n         */\n        mapping(address => uint256) maximumDepositableD18;\n        uint32 minDelegateTime;\n        uint32 __reservedForLater1;\n        uint64 __reservedForLater2;\n        uint64 __reservedForLater3;\n        uint64 __reservedForLater4;\n        /**\n         * @dev Market-specific override of the minimum liquidity ratio\n         */\n        uint256 minLiquidityRatioD18;\n    }\n\n    /**\n     * @dev Data structure that allows the Market to track the amount of market provided collateral, per type.\n     */\n    struct DepositedCollateral {\n        address collateralType;\n        uint256 amountD18;\n    }\n\n    /**\n     * @dev Returns the market stored at the specified market id.\n     */\n    function load(uint128 id) internal pure returns (Data storage market) {\n        bytes32 s = keccak256(abi.encode(\"io.synthetix.synthetix.Market\", id));\n        assembly {\n            market.slot := s\n        }\n    }\n\n    /**\n     * @dev Queries the external market contract for the amount of debt it has issued.\n     *\n     * The reported debt of a market represents the amount of USD that the market would ask the system to mint, if all of its positions were to be immediately closed.\n     *\n     * The reported debt of a market is collateralized by the assets in the pools which back it.\n     *\n     * See the `IMarket` interface.\n     */\n    function getReportedDebt(Data storage self) internal view returns (uint256) {\n        return IMarket(self.marketAddress).reportedDebt(self.id);\n    }\n\n    /**\n     * @dev Queries the market for the amount of collateral which should be prevented from withdrawal.\n     */\n    function getLockedCreditCapacity(Data storage self) internal view returns (uint256) {\n        return IMarket(self.marketAddress).minimumCredit(self.id);\n    }\n\n    /**\n     * @dev Returns the total debt of the market.\n     *\n     * A market's total debt represents its debt plus its issuance, and thus represents the total outstanding debt of the market.\n     *\n     * Note: it also takes into account the deposited collateral value. See note in  getDepositedCollateralValue()\n     *\n     * Example:\n     * (1 EUR = 1.11 USD)\n     * If an Euro market has received 100 USD to mint 90 EUR, its reported debt is 90 EUR or 100 USD, and its issuance is -100 USD.\n     * Thus, its total balance is 100 USD of reported debt minus 100 USD of issuance, which is 0 USD.\n     *\n     * Additionally, the market's totalDebt might be affected by price fluctuations via reportedDebt, or fees.\n     *\n     */\n    function totalDebt(Data storage self) internal view returns (int256) {\n        return\n            getReportedDebt(self).toInt() +\n            self.netIssuanceD18 -\n            getDepositedCollateralValue(self).toInt();\n    }\n\n    /**\n     * @dev Returns the USD value for the total amount of collateral provided by the market itself.\n     *\n     * Note: This is not credit capacity provided by depositors through pools.\n     */\n    function getDepositedCollateralValue(Data storage self) internal view returns (uint256) {\n        uint256 totalDepositedCollateralValueD18 = 0;\n\n        // Sweep all DepositedCollateral entries and aggregate their USD value.\n        for (uint256 i = 0; i < self.depositedCollateral.length; i++) {\n            DepositedCollateral memory entry = self.depositedCollateral[i];\n            CollateralConfiguration.Data storage collateralConfiguration = CollateralConfiguration\n                .load(entry.collateralType);\n\n            if (entry.amountD18 == 0) {\n                continue;\n            }\n\n            uint256 priceD18 = CollateralConfiguration.getCollateralPrice(\n                collateralConfiguration,\n                entry.amountD18\n            );\n\n            totalDepositedCollateralValueD18 += priceD18.mulDecimal(entry.amountD18);\n        }\n\n        return totalDepositedCollateralValueD18;\n    }\n\n    /**\n     * @dev Returns the amount of credit capacity that a certain pool provides to the market.\n\n     * This credit capacity is obtained by reading the amount of shares that the pool has in the market's debt distribution, which represents the amount of USD denominated credit capacity that the pool has provided to the market.\n     */\n    function getPoolCreditCapacity(\n        Data storage self,\n        uint128 poolId\n    ) internal view returns (uint256) {\n        return self.poolsDebtDistribution.getActorShares(poolId.toBytes32());\n    }\n\n    /**\n     * @dev Given an amount of shares that represent USD credit capacity from a pool, and a maximum value per share, returns the potential contribution to credit capacity that these shares could accrue, if their value per share was to hit the maximum.\n     *\n     * The resulting value is calculated multiplying the amount of creditCapacity provided by the pool by the delta between the maxValue per share vs current value.\n     *\n     * This function is used when the Pools are rebalanced to adjust each pool credit capacity based on a change in the amount of shares provided and/or a new maxValue per share\n     *\n     */\n    function getCreditCapacityContribution(\n        Data storage self,\n        uint256 creditCapacitySharesD18,\n        int256 maxShareValueD18\n    ) internal view returns (int256 contributionD18) {\n        // Determine how much the current value per share deviates from the maximum.\n        uint256 deltaValuePerShareD18 = (maxShareValueD18 -\n            self.poolsDebtDistribution.getValuePerShare()).toUint();\n\n        return deltaValuePerShareD18.mulDecimal(creditCapacitySharesD18).toInt();\n    }\n\n    /**\n     * @dev Returns true if the market's current capacity is below the amount of locked capacity.\n     *\n     */\n    function isCapacityLocked(Data storage self) internal view returns (bool) {\n        return self.creditCapacityD18 < getLockedCreditCapacity(self).toInt();\n    }\n\n    /**\n     * @dev Gets any outstanding debt. Do not call this method except in tests\n     *\n     * Note: This function should only be used in tests!\n     */\n    // solhint-disable-next-line private-vars-leading-underscore, func-name-mixedcase\n    function _testOnly_getOutstandingDebt(\n        Data storage self,\n        uint128 poolId\n    ) internal returns (int256 debtChangeD18) {\n        return\n            self.pools[poolId].pendingDebtD18.toInt() +\n            self.poolsDebtDistribution.accumulateActor(poolId.toBytes32());\n    }\n\n    /**\n     * Returns the number of pools currently active in the market\n     *\n     * Note: this is test only\n     */\n    // solhint-disable-next-line private-vars-leading-underscore, func-name-mixedcase\n    function _testOnly_inRangePools(Data storage self) internal view returns (uint256) {\n        return self.inRangePools.size();\n    }\n\n    /**\n     * Returns the number of pools currently active in the market\n     *\n     * Note: this is test only\n     */\n    // solhint-disable-next-line private-vars-leading-underscore, func-name-mixedcase\n    function _testOnly_outRangePools(Data storage self) internal view returns (uint256) {\n        return self.outRangePools.size();\n    }\n\n    /**\n     * @dev Returns the debt value per share\n     */\n    function getDebtPerShare(Data storage self) internal view returns (int256 debtPerShareD18) {\n        return self.poolsDebtDistribution.getValuePerShare();\n    }\n\n    /**\n     * @dev Determine the amount of debt the pool would assume if its lastValue was updated\n     * Needed for optimization.\n     *\n     * Called by a pool when it distributes its debt.\n     *\n     */\n    function accumulateDebtChange(\n        Data storage self,\n        uint128 poolId\n    ) internal returns (int256 debtChangeD18) {\n        int256 changedValueD18 = self.poolsDebtDistribution.accumulateActor(poolId.toBytes32());\n        debtChangeD18 = self.pools[poolId].pendingDebtD18.toInt() + changedValueD18;\n        self.pools[poolId].pendingDebtD18 = 0;\n    }\n\n    /**\n     * @dev Wrapper that adjusts a pool's shares in the market's credit capacity, making sure that the market's outstanding debt is first passed on to its connected pools.\n     *\n     * Called by a pool when it distributes its debt.\n     *\n     */\n    function rebalancePools(\n        uint128 marketId,\n        uint128 poolId,\n        int256 maxDebtShareValueD18, // (in USD)\n        uint256 newCreditCapacityD18 // in collateralValue (USD)\n    ) internal returns (int256 debtChangeD18) {\n        Data storage self = load(marketId);\n\n        if (self.marketAddress == address(0)) {\n            revert MarketNotFound(marketId);\n        }\n\n        return adjustPoolShares(self, poolId, newCreditCapacityD18, maxDebtShareValueD18);\n    }\n\n    /**\n     * @dev Called by pools when they modify the credit capacity provided to the market, as well as the maximum value per share they tolerate for the market.\n     *\n     * These two settings affect the market in the following ways:\n     * - Updates the pool's shares in `poolsDebtDistribution`.\n     * - Moves the pool in and out of inRangePools/outRangePools.\n     * - Updates the market credit capacity property.\n     */\n    function adjustPoolShares(\n        Data storage self,\n        uint128 poolId,\n        uint256 newCreditCapacityD18,\n        int256 newPoolMaxShareValueD18\n    ) internal returns (int256 debtChangeD18) {\n        uint256 oldCreditCapacityD18 = getPoolCreditCapacity(self, poolId);\n        int256 oldPoolMaxShareValueD18 = -self.inRangePools.getById(poolId).priority;\n\n        // Sanity checks\n        // require(oldPoolMaxShareValue == 0, \"value is not 0\");\n        // require(newPoolMaxShareValue == 0, \"new pool max share value is in fact set\");\n\n        self.pools[poolId].creditCapacityAmountD18 = newCreditCapacityD18.to128();\n\n        int128 valuePerShareD18 = self.poolsDebtDistribution.getValuePerShare().to128();\n\n        if (newCreditCapacityD18 == 0) {\n            self.inRangePools.extractById(poolId);\n            self.outRangePools.extractById(poolId);\n        } else if (newPoolMaxShareValueD18 < valuePerShareD18) {\n            // this will ensure calculations below can correctly gauge shares changes\n            newCreditCapacityD18 = 0;\n            self.inRangePools.extractById(poolId);\n            self.outRangePools.insert(poolId, newPoolMaxShareValueD18.to128());\n        } else {\n            self.inRangePools.insert(poolId, -newPoolMaxShareValueD18.to128());\n            self.outRangePools.extractById(poolId);\n        }\n\n        int256 changedValueD18 = self.poolsDebtDistribution.setActorShares(\n            poolId.toBytes32(),\n            newCreditCapacityD18\n        );\n        debtChangeD18 = self.pools[poolId].pendingDebtD18.toInt() + changedValueD18;\n        self.pools[poolId].pendingDebtD18 = 0;\n\n        // recalculate market capacity\n        if (newPoolMaxShareValueD18 > valuePerShareD18) {\n            self.creditCapacityD18 += getCreditCapacityContribution(\n                self,\n                newCreditCapacityD18,\n                newPoolMaxShareValueD18\n            ).to128();\n        }\n\n        if (oldPoolMaxShareValueD18 > valuePerShareD18) {\n            self.creditCapacityD18 -= getCreditCapacityContribution(\n                self,\n                oldCreditCapacityD18,\n                oldPoolMaxShareValueD18\n            ).to128();\n        }\n    }\n\n    /**\n     * @dev Moves debt from the market into the pools that connect to it.\n     *\n     * This function should be called before any of the pools' shares are modified in `poolsDebtDistribution`.\n     *\n     * Note: The parameter `maxIter` is used as an escape hatch to discourage griefing.\n     */\n    function distributeDebtToPools(\n        Data storage self,\n        uint256 maxIter\n    ) internal returns (bool fullyDistributed) {\n        // Get the current and last distributed market balances.\n        // Note: The last distributed balance will be cached within this function's execution.\n        int256 targetBalanceD18 = totalDebt(self);\n        int256 outstandingBalanceD18 = targetBalanceD18 - self.lastDistributedMarketBalanceD18;\n\n        (, bool exhausted) = bumpPools(self, outstandingBalanceD18, maxIter);\n\n        if (!exhausted && self.poolsDebtDistribution.totalSharesD18 > 0) {\n            // cannot use `outstandingBalance` here because `self.lastDistributedMarketBalance`\n            // may have changed after calling the bump functions above\n            self.poolsDebtDistribution.distributeValue(\n                targetBalanceD18 - self.lastDistributedMarketBalanceD18\n            );\n            self.lastDistributedMarketBalanceD18 = targetBalanceD18.to128();\n        }\n\n        return !exhausted;\n    }\n\n    /**\n     * @dev Determine the target valuePerShare of the poolsDebtDistribution, given the value that is yet to be distributed.\n     */\n    function getTargetValuePerShare(\n        Market.Data storage self,\n        int256 valueToDistributeD18\n    ) internal view returns (int256 targetValuePerShareD18) {\n        return\n            self.poolsDebtDistribution.getValuePerShare() +\n            (\n                self.poolsDebtDistribution.totalSharesD18 > 0\n                    ? valueToDistributeD18.divDecimal(\n                        self.poolsDebtDistribution.totalSharesD18.toInt()\n                    ) // solhint-disable-next-line numcast/safe-cast\n                    : int256(0)\n            );\n    }\n\n    /**\n     * @dev Finds pools for which this market's max value per share limit is hit, distributes their debt, and disconnects the market from them.\n     *\n     * The debt is distributed up to the limit of the max value per share that the pool tolerates on the market.\n     */\n    function bumpPools(\n        Data storage self,\n        int256 maxDistributedD18,\n        uint256 maxIter\n    ) internal returns (int256 actuallyDistributedD18, bool exhausted) {\n        if (maxDistributedD18 == 0) {\n            return (0, false);\n        }\n\n        // Determine the direction based on the amount to be distributed.\n        int128 k;\n        HeapUtil.Data storage fromHeap;\n        HeapUtil.Data storage toHeap;\n        if (maxDistributedD18 > 0) {\n            k = 1;\n            fromHeap = self.inRangePools;\n            toHeap = self.outRangePools;\n        } else {\n            k = -1;\n            fromHeap = self.outRangePools;\n            toHeap = self.inRangePools;\n        }\n\n        // Note: This loop should rarely execute its main body. When it does, it only executes once for each pool that exceeds the limit since `distributeValue` is not run for most pools. Thus, market users are not hit with any overhead as a result of this.\n        uint256 iters;\n        for (iters = 0; iters < maxIter; iters++) {\n            // Exit if there are no pools that can be moved\n            if (fromHeap.size() == 0) {\n                break;\n            }\n\n            // Identify the pool with the lowest maximum value per share.\n            HeapUtil.Node memory edgePool = fromHeap.getMax();\n\n            // 2 cases where we want to break out of this loop\n            if (\n                // If there is no pool in range, and we are going down\n                (maxDistributedD18 - actuallyDistributedD18 > 0 &&\n                    self.poolsDebtDistribution.totalSharesD18 == 0) ||\n                // If there is a pool in ragne, and the lowest max value per share does not hit the limit, exit\n                // Note: `-edgePool.priority` is actually the max value per share limit of the pool\n                (self.poolsDebtDistribution.totalSharesD18 > 0 &&\n                    -edgePool.priority >=\n                    k * getTargetValuePerShare(self, (maxDistributedD18 - actuallyDistributedD18)))\n            ) {\n                break;\n            }\n\n            // The pool has hit its maximum value per share and needs to be removed.\n            // Note: No need to update capacity because pool max share value = valuePerShare when this happens.\n            togglePool(fromHeap, toHeap);\n\n            // Distribute the market's debt to the limit, i.e. for that which exceeds the maximum value per share.\n            if (self.poolsDebtDistribution.totalSharesD18 > 0) {\n                int256 debtToLimitD18 = self\n                    .poolsDebtDistribution\n                    .totalSharesD18\n                    .toInt()\n                    .mulDecimal(\n                        -k * edgePool.priority - self.poolsDebtDistribution.getValuePerShare() // Diff between current value and max value per share.\n                    );\n                self.poolsDebtDistribution.distributeValue(debtToLimitD18);\n\n                // Update the global distributed and outstanding balances with the debt that was just distributed.\n                actuallyDistributedD18 += debtToLimitD18;\n            } else {\n                self.poolsDebtDistribution.valuePerShareD27 = (-k * edgePool.priority)\n                    .to256()\n                    .upscale(DecimalMath.PRECISION_FACTOR)\n                    .to128();\n            }\n\n            // Detach the market from this pool by removing the pool's shares from the market.\n            // The pool will remain \"detached\" until the pool manager specifies a new poolsDebtDistribution.\n            if (maxDistributedD18 > 0) {\n                // the below requires are only for sanity\n                require(\n                    self.poolsDebtDistribution.getActorShares(edgePool.id.toBytes32()) > 0,\n                    \"no shares before actor removal\"\n                );\n\n                uint256 newPoolDebtD18 = self\n                    .poolsDebtDistribution\n                    .setActorShares(edgePool.id.toBytes32(), 0)\n                    .toUint();\n                self.pools[edgePool.id].pendingDebtD18 += newPoolDebtD18.to128();\n            } else {\n                require(\n                    self.poolsDebtDistribution.getActorShares(edgePool.id.toBytes32()) == 0,\n                    \"actor has shares before add\"\n                );\n\n                self.poolsDebtDistribution.setActorShares(\n                    edgePool.id.toBytes32(),\n                    self.pools[edgePool.id].creditCapacityAmountD18\n                );\n            }\n        }\n\n        // Record the accumulated distributed balance.\n        self.lastDistributedMarketBalanceD18 += actuallyDistributedD18.to128();\n\n        exhausted = iters == maxIter;\n    }\n\n    /**\n     * @dev Moves a pool from one heap into another.\n     */\n    function togglePool(HeapUtil.Data storage from, HeapUtil.Data storage to) internal {\n        HeapUtil.Node memory node = from.extractMax();\n        to.insert(node.id, -node.priority);\n    }\n}\n"
      },
      "contracts/storage/MarketCreator.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"./Market.sol\";\n\n/**\n * @title Encapsulates market creation logic\n */\nlibrary MarketCreator {\n    bytes32 private constant _SLOT_MARKET_CREATOR =\n        keccak256(abi.encode(\"io.synthetix.synthetix.Markets\"));\n\n    struct Data {\n        /**\n         * @dev Tracks an array of market ids for each external IMarket address.\n         */\n        mapping(address => uint128[]) marketIdsForAddress;\n        /**\n         * @dev Keeps track of the last market id created.\n         * Used for easily creating new markets.\n         */\n        uint128 lastCreatedMarketId;\n    }\n\n    /**\n     * @dev Returns the singleton market store of the system.\n     */\n    function getMarketStore() internal pure returns (Data storage marketStore) {\n        bytes32 s = _SLOT_MARKET_CREATOR;\n        assembly {\n            marketStore.slot := s\n        }\n    }\n\n    /**\n     * @dev Given an external contract address representing an `IMarket`, creates a new id for the market, and tracks it internally in the system.\n     *\n     * The id used to track the market will be automatically assigned by the system according to the last id used.\n     *\n     * Note: If an external `IMarket` contract tracks several market ids, this function should be called for each market it tracks, resulting in multiple ids for the same address.\n     */\n    function create(address marketAddress) internal returns (Market.Data storage market) {\n        Data storage marketStore = getMarketStore();\n\n        uint128 id = marketStore.lastCreatedMarketId;\n        id++;\n\n        market = Market.load(id);\n\n        market.id = id;\n        market.marketAddress = marketAddress;\n\n        marketStore.lastCreatedMarketId = id;\n\n        loadIdsByAddress(marketAddress).push(id);\n    }\n\n    /**\n     * @dev Returns an array of market ids representing the markets linked to the system at a particular external contract address.\n     *\n     * Note: A contract implementing the `IMarket` interface may represent more than just one market, and thus several market ids could be associated to a single external contract address.\n     */\n    function loadIdsByAddress(address marketAddress) internal view returns (uint128[] storage ids) {\n        return getMarketStore().marketIdsForAddress[marketAddress];\n    }\n}\n"
      },
      "contracts/storage/MarketPoolInfo.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title Stores information regarding a pool's relationship to a market, such that it can be added or removed from a distribution\n */\nlibrary MarketPoolInfo {\n    struct Data {\n        /**\n         * @dev The credit capacity that this pool is providing to the relevant market. Needed to re-add the pool to the distribution when going back in range.\n         */\n        uint128 creditCapacityAmountD18;\n        /**\n         * @dev The amount of debt the pool has which hasn't been passed down the debt distribution chain yet.\n         */\n        uint128 pendingDebtD18;\n    }\n}\n"
      },
      "contracts/storage/OracleManager.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title Represents Oracle Manager\n */\nlibrary OracleManager {\n    bytes32 private constant _SLOT_ORACLE_MANAGER =\n        keccak256(abi.encode(\"io.synthetix.synthetix.OracleManager\"));\n\n    struct Data {\n        /**\n         * @dev The oracle manager address.\n         */\n        address oracleManagerAddress;\n    }\n\n    /**\n     * @dev Loads the singleton storage info about the oracle manager.\n     */\n    function load() internal pure returns (Data storage oracleManager) {\n        bytes32 s = _SLOT_ORACLE_MANAGER;\n        assembly {\n            oracleManager.slot := s\n        }\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}