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/AddressError.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title Library for address related errors.\n */\nlibrary AddressError {\n    /**\n     * @dev Thrown when a zero address was passed as a function parameter (0x0000000000000000000000000000000000000000).\n     */\n    error ZeroAddress();\n\n    /**\n     * @dev Thrown when an address representing a contract is expected, but no code is found at the address.\n     * @param contr The address that was expected to be a contract.\n     */\n    error NotAContract(address contr);\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/token/ERC20Helper.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"../interfaces/IERC20.sol\";\n\nlibrary ERC20Helper {\n    error FailedTransfer(address from, address to, uint value);\n\n    function safeTransfer(address token, address to, uint value) internal {\n        (bool success, bytes memory data) = token.call(\n            abi.encodeWithSelector(IERC20.transfer.selector, to, value)\n        );\n        if (!success || (data.length != 0 && !abi.decode(data, (bool)))) {\n            revert FailedTransfer(address(this), to, value);\n        }\n    }\n\n    function safeTransferFrom(address token, address from, address to, uint value) internal {\n        (bool success, bytes memory data) = token.call(\n            abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value)\n        );\n        if (!success || (data.length != 0 && !abi.decode(data, (bool)))) {\n            revert FailedTransfer(from, to, value);\n        }\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/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/IRewardDistributor.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 a reward distributor.\ninterface IRewardDistributor is IERC165 {\n    /// @notice Returns a human-readable name for the reward distributor\n    function name() external returns (string memory);\n\n    /// @notice This function should revert if ERC2771Context._msgSender() is not the Synthetix CoreProxy address.\n    /// @return whether or not the payout was executed\n    function payout(\n        uint128 accountId,\n        uint128 poolId,\n        address collateralType,\n        address sender,\n        uint256 amount\n    ) external returns (bool);\n\n    /// @notice This function is called by the Synthetix Core Proxy whenever\n    /// a position is updated on a pool which this distributor is registered\n    function onPositionUpdated(\n        uint128 accountId,\n        uint128 poolId,\n        address collateralType,\n        uint256 newShares\n    ) external;\n\n    /// @notice Address to ERC-20 token distributed by this distributor, for display purposes only\n    /// @dev Return address(0) if providing non ERC-20 rewards\n    function token() external returns (address);\n}\n"
      },
      "contracts/interfaces/IAssociateDebtModule.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title Module for associating debt with the system.\n * @notice Allows a market to associate debt to a user's existing position.\n * E.g. when migrating a position from v2 into v3's legacy market, the market first scales up everyone's debt, and then associates it to a position using this module.\n */\ninterface IAssociateDebtModule {\n    /**\n     * @notice Thrown when the specified market is not connected to the specified pool in debt association.\n     */\n    error NotFundedByPool(uint256 marketId, uint256 poolId);\n\n    /**\n     * @notice Thrown when a debt association would shift a position below the liquidation ratio.\n     */\n    error InsufficientCollateralRatio(\n        uint256 collateralValue,\n        uint256 debt,\n        uint256 ratio,\n        uint256 minRatio\n    );\n\n    /**\n     * @notice Emitted when `associateDebt` is called.\n     * @param marketId The id of the market to which debt was associated.\n     * @param poolId The id of the pool associated to the target market.\n     * @param collateralType The address of the collateral type that acts as collateral in the corresponding pool.\n     * @param accountId The id of the account whose debt is being associated.\n     * @param amount The amount of debt being associated with the specified account, denominated with 18 decimals of precision.\n     * @param updatedDebt The total updated debt of the account, denominated with 18 decimals of precision\n     */\n    event DebtAssociated(\n        uint128 indexed marketId,\n        uint128 indexed poolId,\n        address indexed collateralType,\n        uint128 accountId,\n        uint256 amount,\n        int256 updatedDebt\n    );\n\n    /**\n     * @notice Allows a market to associate debt with a specific position.\n     * The specified debt will be removed from all vault participants pro-rata. After removing the debt, the amount will\n     * be allocated directly to the specified account.\n     * **NOTE**: if the specified account is an existing staker on the vault, their position will be included in the pro-rata\n     * reduction. Ex: if there are 10 users staking 10 USD of debt on a pool, and associate debt is called with 10 USD on one of those users,\n     * their debt after the operation is complete will be 19 USD. This might seem unusual, but its actually ideal behavior when\n     * your market has incurred some new debt, and it wants to allocate this amount directly to a specific user. In this case, the user's\n     * debt balance would increase pro rata, but then get decreased pro-rata, and then increased to the full amount on their account. All\n     * other accounts would be left with no change to their debt, however.\n     * @param marketId The id of the market to which debt was associated.\n     * @param poolId The id of the pool associated to the target market.\n     * @param collateralType The address of the collateral type that acts as collateral in the corresponding pool.\n     * @param accountId The id of the account whose debt is being associated.\n     * @param amount The amount of debt being associated with the specified account, denominated with 18 decimals of precision.\n     * @return debtAmount The updated debt of the position, denominated with 18 decimals of precision.\n     */\n    function associateDebt(\n        uint128 marketId,\n        uint128 poolId,\n        address collateralType,\n        uint128 accountId,\n        uint256 amount\n    ) external returns (int256 debtAmount);\n}\n"
      },
      "contracts/modules/core/AssociateDebtModule.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"../../interfaces/IAssociateDebtModule.sol\";\n\nimport \"@synthetixio/core-contracts/contracts/utils/DecimalMath.sol\";\nimport \"@synthetixio/core-contracts/contracts/utils/SafeCast.sol\";\nimport \"@synthetixio/core-contracts/contracts/token/ERC20Helper.sol\";\nimport \"@synthetixio/core-contracts/contracts/errors/AccessError.sol\";\nimport \"@synthetixio/core-contracts/contracts/utils/ERC2771Context.sol\";\nimport \"@synthetixio/core-modules/contracts/storage/FeatureFlag.sol\";\n\nimport \"../../storage/Account.sol\";\nimport \"../../storage/Pool.sol\";\n\n/**\n * @title Module for associating debt with the system.\n * @dev See IAssociateDebtModule.\n */\ncontract AssociateDebtModule is IAssociateDebtModule {\n    using DecimalMath for uint256;\n    using SafeCastU128 for uint128;\n    using SafeCastU256 for uint256;\n    using SafeCastI128 for int128;\n    using SafeCastI256 for int256;\n    using ERC20Helper for address;\n    using Distribution for Distribution.Data;\n    using Pool for Pool.Data;\n    using Vault for Vault.Data;\n    using VaultEpoch for VaultEpoch.Data;\n    using CollateralConfiguration for CollateralConfiguration.Data;\n    using ScalableMapping for ScalableMapping.Data;\n\n    bytes32 private constant _USD_TOKEN = \"USDToken\";\n    bytes32 private constant _ASSOCIATE_DEBT_FEATURE_FLAG = \"associateDebt\";\n\n    /**\n     * @inheritdoc IAssociateDebtModule\n     */\n    function associateDebt(\n        uint128 marketId,\n        uint128 poolId,\n        address collateralType,\n        uint128 accountId,\n        uint256 amount\n    ) external returns (int256) {\n        FeatureFlag.ensureAccessToFeature(_ASSOCIATE_DEBT_FEATURE_FLAG);\n        Account.exists(accountId);\n\n        Pool.Data storage poolData = Pool.load(poolId);\n        VaultEpoch.Data storage epochData = poolData.vaults[collateralType].currentEpoch();\n        Market.Data storage marketData = Market.load(marketId);\n\n        if (ERC2771Context._msgSender() != marketData.marketAddress) {\n            revert AccessError.Unauthorized(ERC2771Context._msgSender());\n        }\n\n        // The market must appear in pool configuration of the specified position\n        if (!poolData.hasMarket(marketId)) {\n            revert NotFundedByPool(marketId, poolId);\n        }\n\n        // Refresh latest account debt\n        poolData.updateAccountDebt(collateralType, accountId);\n\n        // rebalance here because this is a good opporitunity to do so, and because its required for correct debt accounting after account debt update\n        poolData.rebalanceMarketsInPool();\n\n        // Remove the debt we're about to assign to a specific position, pro-rata\n        epochData.distributeDebtToAccounts(-amount.toInt());\n\n        // Assign this debt to the specified position\n        int256 updatedDebt = epochData.assignDebtToAccount(accountId, amount.toInt());\n\n        (, uint256 actorCollateralValue) = poolData.currentAccountCollateral(\n            collateralType,\n            accountId\n        );\n\n        // Reverts if this debt increase would make the position liquidatable\n        _verifyCollateralRatio(\n            collateralType,\n            updatedDebt > 0 ? updatedDebt.toUint() : 0,\n            actorCollateralValue\n        );\n\n        emit DebtAssociated(marketId, poolId, collateralType, accountId, amount, updatedDebt);\n\n        return updatedDebt;\n    }\n\n    /**\n     * @dev Reverts if a collateral ratio would be liquidatable.\n     */\n    function _verifyCollateralRatio(\n        address collateralType,\n        uint256 debt,\n        uint256 collateralValue\n    ) internal view {\n        uint256 liquidationRatio = CollateralConfiguration.load(collateralType).liquidationRatioD18;\n        if (debt != 0 && collateralValue.divDecimal(debt) < liquidationRatio) {\n            revert InsufficientCollateralRatio(\n                collateralValue,\n                debt,\n                collateralValue.divDecimal(debt),\n                liquidationRatio\n            );\n        }\n    }\n}\n"
      },
      "contracts/storage/Account.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"./AccountRBAC.sol\";\nimport \"./Collateral.sol\";\nimport \"./Pool.sol\";\n\nimport \"@synthetixio/core-contracts/contracts/utils/SafeCast.sol\";\nimport \"@synthetixio/core-contracts/contracts/utils/ERC2771Context.sol\";\n\n/**\n * @title Object for tracking accounts with access control and collateral tracking.\n */\nlibrary Account {\n    using AccountRBAC for AccountRBAC.Data;\n    using Pool for Pool.Data;\n    using Collateral for Collateral.Data;\n    using SetUtil for SetUtil.UintSet;\n    using SafeCastU128 for uint128;\n    using SafeCastU256 for uint256;\n    using SafeCastI128 for int128;\n    using SafeCastI256 for int256;\n\n    /**\n     * @dev Thrown when the given target address does not have the given permission with the given account.\n     */\n    error PermissionDenied(uint128 accountId, bytes32 permission, address target);\n\n    /**\n     * @dev Thrown when an account cannot be found.\n     */\n    error AccountNotFound(uint128 accountId);\n\n    /**\n     * @dev Thrown when an account does not have sufficient collateral for a particular operation in the system.\n     */\n    error InsufficientAccountCollateral(uint256 requestedAmount);\n\n    /**\n     * @dev Thrown when the requested operation requires an activity timeout before the\n     */\n    error AccountActivityTimeoutPending(\n        uint128 accountId,\n        uint256 currentTime,\n        uint256 requiredTime\n    );\n\n    struct Data {\n        /**\n         * @dev Numeric identifier for the account. Must be unique.\n         * @dev There cannot be an account with id zero (See ERC721._mint()).\n         */\n        uint128 id;\n        /**\n         * @dev Role based access control data for the account.\n         */\n        AccountRBAC.Data rbac;\n        uint64 lastInteraction;\n        uint64 __slotAvailableForFutureUse;\n        uint128 __slot2AvailableForFutureUse;\n        /**\n         * @dev Address set of collaterals that are being used in the system by this account.\n         */\n        mapping(address => Collateral.Data) collaterals;\n    }\n\n    /**\n     * @dev Returns the account stored at the specified account id.\n     */\n    function load(uint128 id) internal pure returns (Data storage account) {\n        bytes32 s = keccak256(abi.encode(\"io.synthetix.synthetix.Account\", id));\n        assembly {\n            account.slot := s\n        }\n    }\n\n    /**\n     * @dev Creates an account for the given id, and associates it to the given owner.\n     *\n     * Note: Will not fail if the account already exists, and if so, will overwrite the existing owner. Whatever calls this internal function must first check that the account doesn't exist before re-creating it.\n     */\n    function create(uint128 id, address owner) internal returns (Data storage account) {\n        account = load(id);\n\n        account.id = id;\n        account.rbac.owner = owner;\n    }\n\n    /**\n     * @dev Reverts if the account does not exist with appropriate error. Otherwise, returns the account.\n     */\n    function exists(uint128 id) internal view returns (Data storage account) {\n        Data storage a = load(id);\n        if (a.rbac.owner == address(0)) {\n            revert AccountNotFound(id);\n        }\n\n        return a;\n    }\n\n    /**\n     * @dev Given a collateral type, returns information about the total collateral assigned, deposited, and locked by the account\n     */\n    function getCollateralTotals(\n        Data storage self,\n        address collateralType\n    )\n        internal\n        view\n        returns (uint256 totalDepositedD18, uint256 totalAssignedD18, uint256 totalLockedD18)\n    {\n        totalAssignedD18 = getAssignedCollateral(self, collateralType);\n        totalDepositedD18 =\n            totalAssignedD18 +\n            self.collaterals[collateralType].amountAvailableForDelegationD18;\n        totalLockedD18 = self.collaterals[collateralType].getTotalLocked();\n\n        return (totalDepositedD18, totalAssignedD18, totalLockedD18);\n    }\n\n    /**\n     * @dev Returns the total amount of collateral that has been delegated to pools by the account, for the given collateral type.\n     */\n    function getAssignedCollateral(\n        Data storage self,\n        address collateralType\n    ) internal view returns (uint256) {\n        uint256 totalAssignedD18 = 0;\n\n        SetUtil.UintSet storage pools = self.collaterals[collateralType].pools;\n\n        for (uint256 i = 1; i <= pools.length(); i++) {\n            uint128 poolIdx = pools.valueAt(i).to128();\n\n            Pool.Data storage pool = Pool.load(poolIdx);\n\n            (uint256 collateralAmountD18, ) = pool.currentAccountCollateral(\n                collateralType,\n                self.id\n            );\n            totalAssignedD18 += collateralAmountD18;\n        }\n\n        return totalAssignedD18;\n    }\n\n    function recordInteraction(Data storage self) internal {\n        // solhint-disable-next-line numcast/safe-cast\n        self.lastInteraction = uint64(block.timestamp);\n    }\n\n    /**\n     * @dev Loads the Account object for the specified accountId,\n     * and validates that sender has the specified permission. It also resets\n     * the interaction timeout. These\n     * are different actions but they are merged in a single function\n     * because loading an account and checking for a permission is a very\n     * common use case in other parts of the code.\n     */\n    function loadAccountAndValidatePermission(\n        uint128 accountId,\n        bytes32 permission\n    ) internal returns (Data storage account) {\n        account = Account.load(accountId);\n\n        if (!account.rbac.authorized(permission, ERC2771Context._msgSender())) {\n            revert PermissionDenied(accountId, permission, ERC2771Context._msgSender());\n        }\n\n        recordInteraction(account);\n    }\n\n    /**\n     * @dev Loads the Account object for the specified accountId,\n     * and validates that sender has the specified permission. It also resets\n     * the interaction timeout. These\n     * are different actions but they are merged in a single function\n     * because loading an account and checking for a permission is a very\n     * common use case in other parts of the code.\n     */\n    function loadAccountAndValidatePermissionAndTimeout(\n        uint128 accountId,\n        bytes32 permission,\n        uint256 timeout\n    ) internal view returns (Data storage account) {\n        account = Account.load(accountId);\n\n        if (!account.rbac.authorized(permission, ERC2771Context._msgSender())) {\n            revert PermissionDenied(accountId, permission, ERC2771Context._msgSender());\n        }\n\n        uint256 endWaitingPeriod = account.lastInteraction + timeout;\n        if (block.timestamp < endWaitingPeriod) {\n            revert AccountActivityTimeoutPending(accountId, block.timestamp, endWaitingPeriod);\n        }\n    }\n\n    /**\n     * @dev Ensure that the account has the required amount of collateral funds remaining\n     */\n    function requireSufficientCollateral(\n        uint128 accountId,\n        address collateralType,\n        uint256 amountD18\n    ) internal view {\n        if (\n            Account.load(accountId).collaterals[collateralType].amountAvailableForDelegationD18 <\n            amountD18\n        ) {\n            revert InsufficientAccountCollateral(amountD18);\n        }\n    }\n}\n"
      },
      "contracts/storage/AccountRBAC.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/errors/AddressError.sol\";\n\n/**\n * @title Object for tracking an accounts permissions (role based access control).\n */\nlibrary AccountRBAC {\n    using SetUtil for SetUtil.Bytes32Set;\n    using SetUtil for SetUtil.AddressSet;\n\n    /**\n     * @dev All permissions used by the system\n     * need to be hardcoded here.\n     */\n    bytes32 internal constant _ADMIN_PERMISSION = \"ADMIN\";\n    bytes32 internal constant _WITHDRAW_PERMISSION = \"WITHDRAW\";\n    bytes32 internal constant _DELEGATE_PERMISSION = \"DELEGATE\";\n    bytes32 internal constant _MINT_PERMISSION = \"MINT\";\n    bytes32 internal constant _REWARDS_PERMISSION = \"REWARDS\";\n    bytes32 internal constant _PERPS_MODIFY_COLLATERAL_PERMISSION = \"PERPS_MODIFY_COLLATERAL\";\n    bytes32 internal constant _PERPS_COMMIT_ASYNC_ORDER_PERMISSION = \"PERPS_COMMIT_ASYNC_ORDER\";\n    bytes32 internal constant _BURN_PERMISSION = \"BURN\";\n\n    /**\n     * @dev Thrown when a permission specified by a user does not exist or is invalid.\n     */\n    error InvalidPermission(bytes32 permission);\n\n    struct Data {\n        /**\n         * @dev The owner of the account and admin of all permissions.\n         */\n        address owner;\n        /**\n         * @dev Set of permissions for each address enabled by the account.\n         */\n        mapping(address => SetUtil.Bytes32Set) permissions;\n        /**\n         * @dev Array of addresses that this account has given permissions to.\n         */\n        SetUtil.AddressSet permissionAddresses;\n    }\n\n    /**\n     * @dev Reverts if the specified permission is unknown to the account RBAC system.\n     */\n    function isPermissionValid(bytes32 permission) internal pure {\n        if (\n            permission != AccountRBAC._WITHDRAW_PERMISSION &&\n            permission != AccountRBAC._DELEGATE_PERMISSION &&\n            permission != AccountRBAC._MINT_PERMISSION &&\n            permission != AccountRBAC._ADMIN_PERMISSION &&\n            permission != AccountRBAC._REWARDS_PERMISSION &&\n            permission != AccountRBAC._PERPS_MODIFY_COLLATERAL_PERMISSION &&\n            permission != AccountRBAC._PERPS_COMMIT_ASYNC_ORDER_PERMISSION &&\n            permission != AccountRBAC._BURN_PERMISSION\n        ) {\n            revert InvalidPermission(permission);\n        }\n    }\n\n    /**\n     * @dev Sets the owner of the account.\n     */\n    function setOwner(Data storage self, address owner) internal {\n        self.owner = owner;\n    }\n\n    /**\n     * @dev Grants a particular permission to the specified target address.\n     */\n    function grantPermission(Data storage self, bytes32 permission, address target) internal {\n        if (target == address(0)) {\n            revert AddressError.ZeroAddress();\n        }\n\n        if (permission == \"\") {\n            revert InvalidPermission(\"\");\n        }\n\n        if (!self.permissionAddresses.contains(target)) {\n            self.permissionAddresses.add(target);\n        }\n\n        self.permissions[target].add(permission);\n    }\n\n    /**\n     * @dev Revokes a particular permission from the specified target address.\n     */\n    function revokePermission(Data storage self, bytes32 permission, address target) internal {\n        self.permissions[target].remove(permission);\n\n        if (self.permissions[target].length() == 0) {\n            self.permissionAddresses.remove(target);\n        }\n    }\n\n    /**\n     * @dev Revokes all permissions for the specified target address.\n     * @notice only removes permissions for the given address, not for the entire account\n     */\n    function revokeAllPermissions(Data storage self, address target) internal {\n        bytes32[] memory permissions = self.permissions[target].values();\n\n        if (permissions.length == 0) {\n            return;\n        }\n\n        for (uint256 i = 0; i < permissions.length; i++) {\n            self.permissions[target].remove(permissions[i]);\n        }\n\n        self.permissionAddresses.remove(target);\n    }\n\n    /**\n     * @dev Returns wether the specified address has the given permission.\n     */\n    function hasPermission(\n        Data storage self,\n        bytes32 permission,\n        address target\n    ) internal view returns (bool) {\n        return target != address(0) && self.permissions[target].contains(permission);\n    }\n\n    /**\n     * @dev Returns wether the specified target address has the given permission, or has the high level admin permission.\n     */\n    function authorized(\n        Data storage self,\n        bytes32 permission,\n        address target\n    ) internal view returns (bool) {\n        return ((target == self.owner) ||\n            hasPermission(self, _ADMIN_PERMISSION, target) ||\n            hasPermission(self, permission, target));\n    }\n}\n"
      },
      "contracts/storage/Collateral.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/SafeCast.sol\";\n\nimport \"./CollateralLock.sol\";\n\n/**\n * @title Stores information about a deposited asset for a given account.\n *\n * Each account will have one of these objects for each type of collateral it deposited in the system.\n */\nlibrary Collateral {\n    using SafeCastU256 for uint256;\n\n    /**\n     * @dev Thrown when a specified market is not found.\n     */\n    error InsufficentAvailableCollateral(\n        uint256 amountAvailableForDelegationD18,\n        uint256 amountD18\n    );\n\n    struct Data {\n        /**\n         * @dev The amount that can be withdrawn or delegated in this collateral.\n         */\n        uint256 amountAvailableForDelegationD18;\n        /**\n         * @dev The pools to which this collateral delegates to.\n         */\n        SetUtil.UintSet pools;\n        /**\n         * @dev Marks portions of the collateral as locked,\n         * until a given unlock date.\n         *\n         * Note: Locks apply to delegated collateral and to collateral not\n         * assigned or delegated to a pool (see ICollateralModule).\n         */\n        CollateralLock.Data[] locks;\n    }\n\n    /**\n     * @dev Increments the entry's availableCollateral.\n     */\n    function increaseAvailableCollateral(Data storage self, uint256 amountD18) internal {\n        self.amountAvailableForDelegationD18 += amountD18;\n    }\n\n    /**\n     * @dev Decrements the entry's availableCollateral.\n     */\n    function decreaseAvailableCollateral(Data storage self, uint256 amountD18) internal {\n        if (self.amountAvailableForDelegationD18 < amountD18) {\n            revert InsufficentAvailableCollateral(self.amountAvailableForDelegationD18, amountD18);\n        }\n        self.amountAvailableForDelegationD18 -= amountD18;\n    }\n\n    /**\n     * @dev Returns the total amount in this collateral entry that is locked.\n     *\n     * Sweeps through all existing locks and accumulates their amount,\n     * if their unlock date is in the future.\n     */\n    function getTotalLocked(Data storage self) internal view returns (uint256) {\n        uint64 currentTime = block.timestamp.to64();\n\n        uint256 lockedD18;\n        for (uint256 i = 0; i < self.locks.length; i++) {\n            CollateralLock.Data storage lock = self.locks[i];\n\n            if (lock.lockExpirationTime > currentTime) {\n                lockedD18 += lock.amountD18;\n            }\n        }\n\n        return lockedD18;\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/CollateralLock.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title Represents a given amount of collateral locked until a given date.\n */\nlibrary CollateralLock {\n    struct Data {\n        /**\n         * @dev The amount of collateral that has been locked.\n         */\n        uint128 amountD18;\n        /**\n         * @dev The date when the locked amount becomes unlocked.\n         */\n        uint64 lockExpirationTime;\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/MarketConfiguration.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title Tracks a market's weight within a Pool, and its maximum debt.\n *\n * Each pool has an array of these, with one entry per market managed by the pool.\n *\n * A market's weight determines how much liquidity the pool provides to the market, and how much debt exposure the market gives the pool.\n *\n * Weights are used to calculate percentages by adding all the weights in the pool and dividing the market's weight by the total weights.\n *\n * A market's maximum debt in a pool is indicated with a maximum debt value per share.\n */\nlibrary MarketConfiguration {\n    struct Data {\n        /**\n         * @dev Numeric identifier for the market.\n         *\n         * Must be unique, and in a list of `MarketConfiguration[]`, must be increasing.\n         */\n        uint128 marketId;\n        /**\n         * @dev The ratio of each market's `weight` to the pool's `totalWeights` determines the pro-rata share of the market to the pool's total liquidity.\n         */\n        uint128 weightD18;\n        /**\n         * @dev Maximum value per share that a pool will tolerate for this market.\n         *\n         * If the the limit is met, the markets exceeding debt will be distributed, and it will be disconnected from the pool that no longer provides credit to it.\n         *\n         * Note: This value will have no effect if the system wide limit is hit first. See `PoolConfiguration.minLiquidityRatioD18`.\n         */\n        int128 maxDebtShareValueD18;\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"
      },
      "contracts/storage/Pool.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"./Config.sol\";\nimport \"./Distribution.sol\";\nimport \"./MarketConfiguration.sol\";\nimport \"./Vault.sol\";\nimport \"./Market.sol\";\nimport \"./PoolCollateralConfiguration.sol\";\nimport \"./SystemPoolConfiguration.sol\";\nimport \"./PoolCollateralConfiguration.sol\";\n\nimport \"@synthetixio/core-contracts/contracts/errors/AccessError.sol\";\nimport \"@synthetixio/core-contracts/contracts/utils/SafeCast.sol\";\nimport {DecimalMath} from \"@synthetixio/core-contracts/contracts/utils/DecimalMath.sol\";\n\n/**\n * @title Aggregates collateral from multiple users in order to provide liquidity to a configurable set of markets.\n *\n * The set of markets is configured as an array of MarketConfiguration objects, where the weight of the market can be specified. This weight, and the aggregated total weight of all the configured markets, determines how much collateral from the pool each market has, as well as in what proportion the market passes on debt to the pool and thus to all its users.\n *\n * The pool tracks the collateral provided by users using an array of Vaults objects, for which there will be one per collateral type. Each vault tracks how much collateral each user has delegated to this pool, how much debt the user has because of minting USD, as well as how much corresponding debt the pool has passed on to the user.\n */\nlibrary Pool {\n    using CollateralConfiguration for CollateralConfiguration.Data;\n    using Market for Market.Data;\n    using Vault for Vault.Data;\n    using VaultEpoch for VaultEpoch.Data;\n    using Distribution for Distribution.Data;\n    using DecimalMath for uint256;\n    using DecimalMath for int256;\n    using DecimalMath for int128;\n    using SafeCastAddress for address;\n    using SafeCastU128 for uint128;\n    using SafeCastU256 for uint256;\n    using SafeCastI128 for int128;\n    using SafeCastI256 for int256;\n\n    /**\n     * @dev Thrown when the specified pool is not found.\n     */\n    error PoolNotFound(uint128 poolId);\n\n    /**\n     * @dev Thrown when attempting to create a pool that already exists.\n     */\n    error PoolAlreadyExists(uint128 poolId);\n\n    /**\n     * @dev Thrown when min delegation time for a market connected to the pool has not elapsed\n     */\n    error MinDelegationTimeoutPending(uint128 poolId, uint32 timeRemaining);\n\n    /**\n     * @dev Thrown when pool has surpassed max collateral deposit\n     */\n    error PoolCollateralLimitExceeded(\n        uint128 poolId,\n        address collateralType,\n        uint256 currentCollateral,\n        uint256 maxCollateral\n    );\n\n    bytes32 private constant _CONFIG_SET_MARKET_MIN_DELEGATE_MAX = \"setMarketMinDelegateTime_max\";\n\n    struct Data {\n        /**\n         * @dev Numeric identifier for the pool. Must be unique.\n         * @dev A pool with id zero exists! (See Pool.loadExisting()). Users can delegate to this pool to be able to mint USD without being exposed to fluctuating debt.\n         */\n        uint128 id;\n        /**\n         * @dev Text identifier for the pool.\n         *\n         * Not required to be unique.\n         */\n        string name;\n        /**\n         * @dev Creator of the pool, which has configuration access rights for the pool.\n         *\n         * See onlyPoolOwner.\n         */\n        address owner;\n        /**\n         * @dev Allows the current pool owner to nominate a new owner, and thus transfer pool configuration credentials.\n         */\n        address nominatedOwner;\n        /**\n         * @dev Sum of all market weights.\n         *\n         * Market weights are tracked in `MarketConfiguration.weight`, one for each market. The ratio of each market's `weight` to the pool's `totalWeights` determines the pro-rata share of the market to the pool's total liquidity.\n         *\n         * Reciprocally, this pro-rata share also determines how much the pool is exposed to each market's debt.\n         */\n        uint128 totalWeightsD18;\n        /**\n         * @dev Accumulated cache value of all vault collateral debts\n         */\n        int128 totalVaultDebtsD18;\n        /**\n         * @dev Array of markets connected to this pool, and their configurations. I.e. weight, etc.\n         *\n         * See totalWeights.\n         */\n        MarketConfiguration.Data[] marketConfigurations;\n        /**\n         * @dev A pool's debt distribution connects pools to the debt distribution chain, i.e. vaults and markets. Vaults are actors in the pool's debt distribution, where the amount of shares they possess depends on the amount of collateral each vault delegates to the pool.\n         *\n         * The debt distribution chain will move debt from markets into this pools, and then from pools to vaults.\n         *\n         * Actors: Vaults.\n         * Shares: USD value, proportional to the amount of collateral that the vault delegates to the pool.\n         * Value per share: Debt per dollar of collateral. Depends on aggregated debt of connected markets.\n         *\n         */\n        Distribution.Data vaultsDebtDistribution;\n        /**\n         * @dev Reference to all the vaults that provide liquidity to this pool.\n         *\n         * Each collateral type will have its own vault, specific to this pool. I.e. if two pools both use SNX collateral, each will have its own SNX vault.\n         *\n         * Vaults track user collateral and debt using a debt distribution, which is connected to the debt distribution chain.\n         */\n        mapping(address => Vault.Data) vaults;\n        uint64 lastConfigurationTime;\n        uint64 __reserved1;\n        uint64 __reserved2;\n        uint64 __reserved3;\n        mapping(address => PoolCollateralConfiguration.Data) collateralConfigurations;\n        /**\n         * @dev A switch to make the pool opt-in for new collateral\n         *\n         * By default it's set to false, which means any new collateral accepeted by the system will be accpeted by the pool.\n         *\n         * If the pool owner sets this value to true, then new collaterals will be disabled for the pool unless a maxDeposit is set for a that collateral.\n         */\n        bool collateralDisabledByDefault;\n    }\n\n    /**\n     * @dev Returns the pool stored at the specified pool id.\n     */\n    function load(uint128 id) internal pure returns (Data storage pool) {\n        bytes32 s = keccak256(abi.encode(\"io.synthetix.synthetix.Pool\", id));\n        assembly {\n            pool.slot := s\n        }\n    }\n\n    /**\n     * @dev Creates a pool for the given pool id, and assigns the caller as its owner.\n     *\n     * Reverts if the specified pool already exists.\n     */\n    function create(uint128 id, address owner) internal returns (Pool.Data storage pool) {\n        if (id == 0 || load(id).id == id) {\n            revert PoolAlreadyExists(id);\n        }\n\n        pool = load(id);\n\n        pool.id = id;\n        pool.owner = owner;\n    }\n\n    /**\n     * @dev Ticker function that updates the debt distribution chain downwards, from markets into the pool, according to each market's weight.\n     * IMPORTANT: debt must be distributed downstream before invoking this function.\n     *\n     * It updates the chain by performing these actions:\n     * - Splits the pool's total liquidity of the pool into each market, pro-rata. The amount of shares that the pool has on each market depends on how much liquidity the pool provides to the market.\n     * - Accumulates the change in debt value from each market into the pools own vault debt distribution's value per share.\n     */\n    function rebalanceMarketsInPool(Data storage self) internal {\n        uint256 totalWeightsD18 = self.totalWeightsD18;\n\n        if (totalWeightsD18 == 0) {\n            return; // Nothing to rebalance.\n        }\n\n        // Read from storage once, before entering the loop below.\n        // These values should not change while iterating through each market.\n        uint256 totalCreditCapacityD18 = self.vaultsDebtDistribution.totalSharesD18;\n        int128 debtPerShareD18 = totalCreditCapacityD18 > 0 // solhint-disable-next-line numcast/safe-cast\n            ? int(self.totalVaultDebtsD18).divDecimal(totalCreditCapacityD18.toInt()).to128() // solhint-disable-next-line numcast/safe-cast\n            : int128(0);\n\n        uint256 systemMinLiquidityRatioD18 = SystemPoolConfiguration.load().minLiquidityRatioD18;\n\n        // Loop through the pool's markets, applying market weights, and tracking how this changes the amount of debt that this pool is responsible for.\n        // This debt extracted from markets is then applied to the pool's vault debt distribution, which thus exposes debt to the pool's vaults.\n        for (uint256 i = 0; i < self.marketConfigurations.length; i++) {\n            MarketConfiguration.Data storage marketConfiguration = self.marketConfigurations[i];\n\n            uint256 weightD18 = marketConfiguration.weightD18;\n\n            // Calculate each market's pro-rata USD liquidity.\n            // Note: the factor `(weight / totalWeights)` is not deduped in the operations below to maintain numeric precision.\n\n            uint256 marketCreditCapacityD18 = (totalCreditCapacityD18 * weightD18) /\n                totalWeightsD18;\n\n            Market.Data storage marketData = Market.load(marketConfiguration.marketId);\n\n            // Use market-specific minimum liquidity ratio if set, otherwise use system default.\n            uint256 minLiquidityRatioD18 = marketData.minLiquidityRatioD18 > 0\n                ? marketData.minLiquidityRatioD18\n                : systemMinLiquidityRatioD18;\n\n            // Contain the pool imposed market's maximum debt share value.\n            // Imposed by system.\n            int256 effectiveMaxShareValueD18 = getSystemMaxValuePerShare(\n                marketData.id,\n                minLiquidityRatioD18,\n                debtPerShareD18\n            );\n            // Imposed by pool.\n            int256 configuredMaxShareValueD18 = marketConfiguration.maxDebtShareValueD18;\n            effectiveMaxShareValueD18 = effectiveMaxShareValueD18 < configuredMaxShareValueD18\n                ? effectiveMaxShareValueD18\n                : configuredMaxShareValueD18;\n\n            // Update each market's corresponding credit capacity.\n            // The returned value represents how much the market's debt changed after changing the shares of this pool actor, which is aggregated to later be passed on the pools debt distribution.\n            Market.rebalancePools(\n                marketConfiguration.marketId,\n                self.id,\n                effectiveMaxShareValueD18,\n                marketCreditCapacityD18\n            );\n        }\n    }\n\n    /**\n     * @dev Determines the resulting maximum value per share for a market, according to a system-wide minimum liquidity ratio. This prevents markets from assigning more debt to pools than they have collateral to cover.\n     *\n     * Note: There is a market-wide fail safe for each market at `MarketConfiguration.maxDebtShareValue`. The lower of the two values should be used.\n     *\n     * See `SystemPoolConfiguration.minLiquidityRatio`.\n     */\n    function getSystemMaxValuePerShare(\n        uint128 marketId,\n        uint256 minLiquidityRatioD18,\n        int256 debtPerShareD18\n    ) internal view returns (int256) {\n        // Retrieve the current value per share of the market.\n        Market.Data storage marketData = Market.load(marketId);\n        int256 valuePerShareD18 = marketData.poolsDebtDistribution.getValuePerShare();\n\n        // Calculate the margin of debt that the market would incur if it hit the system wide limit.\n        uint256 marginD18 = minLiquidityRatioD18 == 0\n            ? DecimalMath.UNIT\n            : DecimalMath.UNIT.divDecimal(minLiquidityRatioD18);\n\n        // The resulting maximum value per share is the distribution's value per share,\n        // plus the margin to hit the limit, minus the current debt per share.\n        return valuePerShareD18 + marginD18.toInt() - debtPerShareD18;\n    }\n\n    /**\n     * @dev Reverts if the pool does not exist with appropriate error. Otherwise, returns the pool.\n     */\n    function loadExisting(uint128 id) internal view returns (Data storage) {\n        Data storage p = load(id);\n        if (id != 0 && p.id != id) {\n            revert PoolNotFound(id);\n        }\n\n        return p;\n    }\n\n    /**\n     * @dev Returns true if the pool is exposed to the specified market.\n     */\n    function hasMarket(Data storage self, uint128 marketId) internal view returns (bool) {\n        for (uint256 i = 0; i < self.marketConfigurations.length; i++) {\n            if (self.marketConfigurations[i].marketId == marketId) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * IMPORTANT: after this function, you should accumulateVaultDebt\n     */\n    function distributeDebtToVaults(\n        Data storage self,\n        address optionalCollateralType\n    ) internal returns (int256 cumulativeDebtChange) {\n        // Update each market's pro-rata liquidity and collect accumulated debt into the pool's debt distribution.\n        uint128 myPoolId = self.id;\n        for (uint256 i = 0; i < self.marketConfigurations.length; i++) {\n            Market.Data storage market = Market.load(self.marketConfigurations[i].marketId);\n\n            market.distributeDebtToPools(9999999999);\n            cumulativeDebtChange += market.accumulateDebtChange(myPoolId);\n        }\n\n        assignDebt(self, cumulativeDebtChange);\n\n        // Transfer the debt change from the pool into the vault.\n        if (optionalCollateralType != address(0)) {\n            bytes32 actorId = optionalCollateralType.toBytes32();\n            self.vaults[optionalCollateralType].distributeDebtToAccounts(\n                self.vaultsDebtDistribution.accumulateActor(actorId)\n            );\n        }\n    }\n\n    function assignDebt(Data storage self, int256 debtAmountD18) internal {\n        // Accumulate the change in total liquidity, from the vault, into the pool.\n        self.totalVaultDebtsD18 = self.totalVaultDebtsD18 + debtAmountD18.to128();\n\n        self.vaultsDebtDistribution.distributeValue(debtAmountD18);\n    }\n\n    function assignDebtToAccount(\n        Data storage self,\n        address collateralType,\n        uint128 accountId,\n        int256 debtAmountD18\n    ) internal {\n        self.totalVaultDebtsD18 = self.totalVaultDebtsD18 + debtAmountD18.to128();\n\n        self.vaults[collateralType].currentEpoch().assignDebtToAccount(accountId, debtAmountD18);\n    }\n\n    /**\n     * @dev Ticker function that updates the debt distribution chain for a specific collateral type downwards, from the pool into the corresponding the vault, according to changes in the collateral's price.\n     * IMPORTANT: *should* call distributeDebtToVaults() to ensure that deltaDebtD18 is referencing the latest\n     *\n     * It updates the chain by performing these actions:\n     * - Collects the latest price of the corresponding collateral and updates the vault's liquidity.\n     * - Updates the vaults shares in the pool's debt distribution, according to the collateral provided by the vault.\n     * - Updates the value per share of the vault's debt distribution.\n     */\n    function recalculateVaultCollateral(\n        Data storage self,\n        address collateralType\n    ) internal returns (uint256 collateralPriceD18) {\n        // Get the latest collateral price.\n        collateralPriceD18 = CollateralConfiguration.load(collateralType).getCollateralPrice(\n            DecimalMath.UNIT\n        );\n\n        // Changes in price update the corresponding vault's total collateral value as well as its liquidity (collateral - debt).\n        (uint256 usdWeightD18, ) = self.vaults[collateralType].updateCreditCapacity(\n            collateralPriceD18\n        );\n\n        // Update the vault's shares in the pool's debt distribution, according to the value of its collateral.\n        self.vaultsDebtDistribution.setActorShares(collateralType.toBytes32(), usdWeightD18);\n\n        // now that available vault collateral has been recalculated, we should also rebalance the pool markets\n        rebalanceMarketsInPool(self);\n    }\n\n    /**\n     * @dev Updates the debt distribution chain for this pool, and consolidates the given account's debt.\n     */\n    function updateAccountDebt(\n        Data storage self,\n        address collateralType,\n        uint128 accountId\n    ) internal returns (int256 debtD18) {\n        distributeDebtToVaults(self, collateralType);\n        return self.vaults[collateralType].consolidateAccountDebt(accountId);\n    }\n\n    /**\n     * @dev Clears all vault data for the specified collateral type.\n     */\n    function resetVault(Data storage self, address collateralType) internal {\n        // Creates a new epoch in the vault, effectively zeroing out all values.\n        self.vaults[collateralType].reset();\n\n        // Ensure that the vault's values update the debt distribution chain.\n        recalculateVaultCollateral(self, collateralType);\n    }\n\n    /**\n     * @dev Calculates the collateralization ratio of the vault that tracks the given collateral type.\n     *\n     * The c-ratio is the vault's share of the total debt of the pool, divided by the collateral it delegates to the pool.\n     *\n     * Note: This is not a view function. It updates the debt distribution chain before performing any calculations.\n     */\n    function currentVaultCollateralRatio(\n        Data storage self,\n        address collateralType\n    ) internal returns (uint256) {\n        int256 vaultDebtD18 = currentVaultDebt(self, collateralType);\n        (, uint256 collateralValueD18) = currentVaultCollateral(self, collateralType);\n\n        return vaultDebtD18 > 0 ? collateralValueD18.divDecimal(vaultDebtD18.toUint()) : 0;\n    }\n\n    /**\n     * @dev Finds a connected market whose credit capacity has reached its locked limit.\n     *\n     * Note: Returns market zero (null market) if none is found.\n     */\n    function findMarketWithCapacityLocked(\n        Data storage self\n    ) internal view returns (Market.Data storage lockedMarket) {\n        for (uint256 i = 0; i < self.marketConfigurations.length; i++) {\n            Market.Data storage market = Market.load(self.marketConfigurations[i].marketId);\n\n            if (market.isCapacityLocked()) {\n                return market;\n            }\n        }\n\n        // Market zero = null market.\n        return Market.load(0);\n    }\n\n    function getRequiredMinDelegationTime(\n        Data storage self\n    ) internal view returns (uint32 requiredMinDelegateTime) {\n        for (uint256 i = 0; i < self.marketConfigurations.length; i++) {\n            uint32 marketMinDelegateTime = Market\n                .load(self.marketConfigurations[i].marketId)\n                .minDelegateTime;\n\n            if (marketMinDelegateTime > requiredMinDelegateTime) {\n                requiredMinDelegateTime = marketMinDelegateTime;\n            }\n        }\n\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        return\n            maxMinDelegateTime < requiredMinDelegateTime\n                ? maxMinDelegateTime\n                : requiredMinDelegateTime;\n    }\n\n    /**\n     * @dev Returns the debt of the vault that tracks the given collateral type.\n     *\n     * The vault's debt is the vault's share of the total debt of the pool, or its share of the total debt of the markets connected to the pool. The size of this share depends on how much collateral the pool provides to the pool.\n     *\n     * Note: This is not a view function. It updates the debt distribution chain before performing any calculations.\n     */\n    function currentVaultDebt(Data storage self, address collateralType) internal returns (int256) {\n        // TODO: assert that all debts have been paid, otherwise vault cant be reset (its so critical here)\n        distributeDebtToVaults(self, collateralType);\n        rebalanceMarketsInPool(self);\n        return self.vaults[collateralType].currentDebt();\n    }\n\n    /**\n     * @dev Returns the total amount and value of the specified collateral delegated to this pool.\n     */\n    function currentVaultCollateral(\n        Data storage self,\n        address collateralType\n    ) internal view returns (uint256 collateralAmountD18, uint256 collateralValueD18) {\n        uint256 collateralPriceD18 = CollateralConfiguration\n            .load(collateralType)\n            .getCollateralPrice(collateralAmountD18);\n\n        collateralAmountD18 = self.vaults[collateralType].currentCollateral();\n        collateralValueD18 = collateralPriceD18.mulDecimal(collateralAmountD18);\n    }\n\n    /**\n     * @dev Returns the amount and value of collateral that the specified account has delegated to this pool.\n     */\n    function currentAccountCollateral(\n        Data storage self,\n        address collateralType,\n        uint128 accountId\n    ) internal view returns (uint256 collateralAmountD18, uint256 collateralValueD18) {\n        collateralAmountD18 = self.vaults[collateralType].currentAccountCollateral(accountId);\n        uint256 collateralPriceD18 = CollateralConfiguration\n            .load(collateralType)\n            .getCollateralPrice(collateralAmountD18);\n        collateralValueD18 = collateralPriceD18.mulDecimal(collateralAmountD18);\n    }\n\n    /**\n     * @dev Returns the specified account's collateralization ratio (collateral / debt).\n     * @dev If the account's debt is negative or zero, returns an \"infinite\" c-ratio.\n     */\n    function currentAccountCollateralRatio(\n        Data storage self,\n        address collateralType,\n        uint128 accountId\n    ) internal returns (uint256) {\n        int256 positionDebtD18 = updateAccountDebt(self, collateralType, accountId);\n        rebalanceMarketsInPool(self);\n        if (positionDebtD18 <= 0) {\n            return type(uint256).max;\n        }\n\n        (, uint256 positionCollateralValueD18) = currentAccountCollateral(\n            self,\n            collateralType,\n            accountId\n        );\n\n        return positionCollateralValueD18.divDecimal(positionDebtD18.toUint());\n    }\n\n    /**\n     * @dev Reverts if the caller is not the owner of the specified pool.\n     */\n    function onlyPoolOwner(uint128 poolId, address caller) internal view {\n        if (Pool.load(poolId).owner != caller) {\n            revert AccessError.Unauthorized(caller);\n        }\n    }\n\n    function requireMinDelegationTimeElapsed(\n        Data storage self,\n        uint64 lastDelegationTime\n    ) internal view {\n        uint32 requiredMinDelegationTime = getRequiredMinDelegationTime(self);\n        if (block.timestamp < lastDelegationTime + requiredMinDelegationTime) {\n            revert MinDelegationTimeoutPending(\n                self.id,\n                // solhint-disable-next-line numcast/safe-cast\n                uint32(lastDelegationTime + requiredMinDelegationTime - block.timestamp)\n            );\n        }\n    }\n\n    function checkPoolCollateralLimit(\n        Data storage self,\n        address collateralType,\n        uint256 collateralAmountD18\n    ) internal view {\n        uint256 collateralLimitD18 = self\n            .collateralConfigurations[collateralType]\n            .collateralLimitD18;\n        uint256 currentCollateral = self.vaults[collateralType].currentCollateral();\n\n        if (\n            (self.collateralDisabledByDefault && collateralLimitD18 == 0) ||\n            (collateralLimitD18 > 0 && currentCollateral + collateralAmountD18 > collateralLimitD18)\n        ) {\n            revert PoolCollateralLimitExceeded(\n                self.id,\n                collateralType,\n                currentCollateral + collateralAmountD18,\n                collateralLimitD18\n            );\n        }\n    }\n}\n"
      },
      "contracts/storage/PoolCollateralConfiguration.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nlibrary PoolCollateralConfiguration {\n    bytes32 private constant _SLOT =\n        keccak256(abi.encode(\"io.synthetix.synthetix.PoolCollateralConfiguration\"));\n\n    struct Data {\n        uint256 collateralLimitD18;\n        uint256 issuanceRatioD18;\n    }\n}\n"
      },
      "contracts/storage/RewardDistribution.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/errors/ParameterError.sol\";\nimport \"@synthetixio/core-contracts/contracts/utils/SafeCast.sol\";\n\nimport \"../interfaces/external/IRewardDistributor.sol\";\n\nimport \"./Distribution.sol\";\nimport \"./RewardDistributionClaimStatus.sol\";\n\n/**\n * @title Used by vaults to track rewards for its participants. There will be one of these for each pool, collateral type, and distributor combination.\n */\nlibrary RewardDistribution {\n    using DecimalMath for int256;\n    using SafeCastU128 for uint128;\n    using SafeCastU256 for uint256;\n    using SafeCastI128 for int128;\n    using SafeCastI256 for int256;\n    using SafeCastU64 for uint64;\n    using SafeCastU32 for uint32;\n    using SafeCastI32 for int32;\n\n    struct Data {\n        /**\n         * @dev The 3rd party smart contract which holds/mints tokens for distributing rewards to vault participants.\n         */\n        IRewardDistributor distributor;\n        /**\n         * @dev Available slot.\n         */\n        uint128 __slotAvailableForFutureUse;\n        /**\n         * @dev The value of the rewards in this entry.\n         */\n        uint128 rewardPerShareD18;\n        /**\n         * @dev The status for each actor, regarding this distribution's entry.\n         */\n        mapping(uint256 => RewardDistributionClaimStatus.Data) claimStatus;\n        /**\n         * @dev Value to be distributed as rewards in a scheduled form.\n         */\n        int128 scheduledValueD18;\n        /**\n         * @dev Date at which the entry's rewards will begin to be claimable.\n         *\n         * Note: Set to <= block.timestamp to distribute immediately to currently participating users.\n         */\n        uint64 start;\n        /**\n         * @dev Time span after the start date, in which the whole of the entry's rewards will become claimable.\n         */\n        uint32 duration;\n        /**\n         * @dev Date on which this distribution entry was last updated.\n         */\n        uint32 lastUpdate;\n    }\n\n    /**\n     * @dev Distributes rewards into a new rewards distribution entry.\n     *\n     * Note: this function allows for more special cases such as distributing at a future date or distributing over time.\n     * If you want to apply the distribution to the pool, call `distribute` with the return value. Otherwise, you can\n     * record this independently as well.\n     */\n    function distribute(\n        Data storage self,\n        Distribution.Data storage dist,\n        int256 amountD18,\n        uint64 start,\n        uint32 duration\n    ) internal returns (int256 diffD18) {\n        uint256 totalSharesD18 = dist.totalSharesD18;\n\n        if (totalSharesD18 == 0) {\n            revert ParameterError.InvalidParameter(\n                \"amount\",\n                \"can't distribute to empty distribution\"\n            );\n        }\n\n        uint256 curTime = block.timestamp;\n\n        // Unlocks the entry's distributed amount into its value per share.\n        diffD18 += updateEntry(self, totalSharesD18);\n\n        // If the current time is past the end of the entry's duration,\n        // update any rewards which may have accrued since last run.\n        // (instant distribution--immediately disperse amount).\n        if (start + duration <= curTime) {\n            diffD18 += amountD18.divDecimal(totalSharesD18.toInt());\n\n            self.lastUpdate = 0;\n            self.start = 0;\n            self.duration = 0;\n            self.scheduledValueD18 = 0;\n            // Else, schedule the amount to distribute.\n        } else {\n            self.scheduledValueD18 = amountD18.to128();\n\n            self.start = start;\n            self.duration = duration;\n\n            // The amount is actually the amount distributed already *plus* whatever has been specified now.\n            self.lastUpdate = 0;\n\n            diffD18 += updateEntry(self, totalSharesD18);\n        }\n    }\n\n    /**\n     * @dev Gets the total shares of a reward distribution entry.\n     */\n    function getEntry(\n        Data storage self,\n        uint256 totalSharesAmountD18\n    ) internal view returns (int256) {\n        // No balance if a pool is empty or if it has no rewards\n        if (self.scheduledValueD18 == 0 || totalSharesAmountD18 == 0) {\n            return 0;\n        }\n\n        uint256 curTime = block.timestamp;\n\n        int256 valuePerShareChangeD18 = 0;\n\n        // No balance if current time is before start time\n        if (curTime < self.start) {\n            return 0;\n        }\n\n        // If the entry's duration is zero and its last update was before the start time,\n        // consider the entry to be an instant distribution.\n        if (self.duration == 0 && self.lastUpdate < self.start) {\n            // Simply update the value per share to the total value divided by the total shares.\n            valuePerShareChangeD18 = self.scheduledValueD18.to256().divDecimal(\n                totalSharesAmountD18.toInt()\n            );\n            // Else, if the last update was before the end of the duration.\n        } else if (self.lastUpdate < self.start + self.duration) {\n            // Determine how much was previously distributed.\n            // If the last update is zero, then nothing was distributed,\n            // otherwise the amount is proportional to the time elapsed since the start.\n            int256 lastUpdateDistributedD18 = self.lastUpdate < self.start\n                ? SafeCastI128.zero()\n                : (self.scheduledValueD18 * (self.lastUpdate - self.start).toInt()) /\n                    self.duration.toInt();\n\n            // If the current time is beyond the duration, then consider all scheduled value to be distributed.\n            // Else, the amount distributed is proportional to the elapsed time.\n            int256 curUpdateDistributedD18 = self.scheduledValueD18;\n            if (curTime < self.start + self.duration) {\n                // Note: Not using an intermediate time ratio variable\n                // in the following calculation to maintain precision.\n                curUpdateDistributedD18 =\n                    (curUpdateDistributedD18 * (curTime - self.start).toInt()) /\n                    self.duration.toInt();\n            }\n\n            // The final value per share change is the difference between what is to be distributed and what was distributed.\n            valuePerShareChangeD18 = (curUpdateDistributedD18 - lastUpdateDistributedD18)\n                .divDecimal(totalSharesAmountD18.toInt());\n        }\n\n        return valuePerShareChangeD18;\n    }\n\n    /**\n     * @dev Updates the total shares of a reward distribution entry, and releases its unlocked value into its value per share, depending on the time elapsed since the start of the distribution's entry.\n     *\n     * Note: call every time before `totalShares` changes.\n     */\n    function updateEntry(\n        Data storage self,\n        uint256 totalSharesAmountD18\n    ) internal returns (int256) {\n        // Cannot process distributed rewards if a pool is empty or if it has no rewards.\n        if (self.scheduledValueD18 == 0 || totalSharesAmountD18 == 0) {\n            return 0;\n        }\n\n        uint256 curTime = block.timestamp;\n\n        int256 valuePerShareChangeD18 = 0;\n\n        // Cannot update an entry whose start date has not being reached.\n        if (curTime < self.start) {\n            return 0;\n        }\n\n        // If the entry's duration is zero and its last update was before the start time,\n        // consider the entry to be an instant distribution.\n        if (self.duration == 0 && self.lastUpdate < self.start) {\n            // Simply update the value per share to the total value divided by the total shares.\n            valuePerShareChangeD18 = self.scheduledValueD18.to256().divDecimal(\n                totalSharesAmountD18.toInt()\n            );\n            // Else, if the last update was before the end of the duration.\n        } else if (self.lastUpdate < self.start + self.duration) {\n            // Determine how much was previously distributed.\n            // If the last update is zero, then nothing was distributed,\n            // otherwise the amount is proportional to the time elapsed since the start.\n            int256 lastUpdateDistributedD18 = 0;\n\n            if (self.lastUpdate >= self.start) {\n                // solhint-disable numcast/safe-cast\n                lastUpdateDistributedD18 =\n                    (int256(self.scheduledValueD18) * (self.lastUpdate - self.start).toInt()) /\n                    self.duration.toInt();\n                // solhint-enable numcast/safe-cast\n            }\n\n            // If the current time is beyond the duration, then consider all scheduled value to be distributed.\n            // Else, the amount distributed is proportional to the elapsed time.\n            int256 curUpdateDistributedD18 = self.scheduledValueD18;\n            if (curTime < self.start + self.duration) {\n                // Note: Not using an intermediate time ratio variable\n                // in the following calculation to maintain precision.\n                curUpdateDistributedD18 =\n                    (curUpdateDistributedD18 * (curTime - self.start).toInt()) /\n                    self.duration.toInt();\n            }\n\n            // The final value per share change is the difference between what is to be distributed and what was distributed.\n            valuePerShareChangeD18 = (curUpdateDistributedD18 - lastUpdateDistributedD18)\n                .divDecimal(totalSharesAmountD18.toInt());\n        }\n\n        self.lastUpdate = curTime.to32();\n\n        return valuePerShareChangeD18;\n    }\n}\n"
      },
      "contracts/storage/RewardDistributionClaimStatus.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\n/**\n * @title Tracks information per actor within a RewardDistribution.\n */\nlibrary RewardDistributionClaimStatus {\n    struct Data {\n        /**\n         * @dev The last known reward per share for this actor.\n         */\n        uint128 lastRewardPerShareD18;\n        /**\n         * @dev The amount of rewards pending to be claimed by this actor.\n         */\n        uint128 pendingSendD18;\n    }\n}\n"
      },
      "contracts/storage/ScalableMapping.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\n/**\n * @title Data structure that wraps a mapping with a scalar multiplier.\n *\n * If you wanted to modify all the values in a mapping by the same amount, you would normally have to loop through each entry in the mapping. This object allows you to modify all of them at once, by simply modifying the scalar multiplier.\n *\n * I.e. a regular mapping represents values like this:\n * value = mapping[id]\n *\n * And a scalable mapping represents values like this:\n * value = mapping[id] * scalar\n *\n * This reduces the number of computations needed for modifying the balances of N users from O(n) to O(1).\n\n * Note: Notice how users are tracked by a generic bytes32 id instead of an address. This allows the actors of the mapping not just to be addresses. They can be anything, for example a pool id, an account id, etc.\n *\n * *********************\n * Conceptual Examples\n * *********************\n *\n * 1) Socialization of collateral during a liquidation.\n *\n * Scalable mappings are very useful for \"socialization\" of collateral, that is, the re-distribution of collateral when an account is liquidated. Suppose 1000 ETH are liquidated, and would need to be distributed amongst 1000 depositors. With a regular mapping, every depositor's balance would have to be modified in a loop that iterates through every single one of them. With a scalable mapping, the scalar would simply need to be incremented so that the total value of the mapping increases by 1000 ETH.\n *\n * 2) Socialization of debt during a liquidation.\n *\n * Similar to the socialization of collateral during a liquidation, the debt of the position that is being liquidated can be re-allocated using a scalable mapping with a single action. Supposing a scalable mapping tracks each user's debt in the system, and that 1000 sUSD has to be distributed amongst 1000 depositors, the debt data structure's scalar would simply need to be incremented so that the total value or debt of the distribution increments by 1000 sUSD.\n *\n */\nlibrary ScalableMapping {\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    using DecimalMath for uint256;\n\n    /**\n     * @dev Thrown when attempting to scale a mapping with an amount that is lower than its resolution.\n     */\n    error InsufficientMappedAmount();\n\n    /**\n     * @dev Thrown when attempting to scale a mapping with no shares.\n     */\n    error CannotScaleEmptyMapping();\n\n    struct Data {\n        uint128 totalSharesD18;\n        int128 scaleModifierD27;\n        mapping(bytes32 => uint256) sharesD18;\n    }\n\n    /**\n     * @dev Inflates or deflates the total value of the distribution by the given value.\n     * @dev The incoming value is split per share, and used as a delta that is *added* to the existing scale modifier. The resulting scale modifier must be in the range [-1, type(int128).max).\n     */\n    function scale(Data storage self, int256 valueD18) internal {\n        if (valueD18 == 0) {\n            return;\n        }\n\n        uint256 totalSharesD18 = self.totalSharesD18;\n        if (totalSharesD18 == 0) {\n            revert CannotScaleEmptyMapping();\n        }\n\n        int256 valueD45 = valueD18 * DecimalMath.UNIT_PRECISE_INT;\n        int256 deltaScaleModifierD27 = valueD45 / totalSharesD18.toInt();\n\n        self.scaleModifierD27 += deltaScaleModifierD27.to128();\n\n        if (self.scaleModifierD27 < -DecimalMath.UNIT_PRECISE_INT) {\n            revert InsufficientMappedAmount();\n        }\n    }\n\n    /**\n     * @dev Updates an actor's individual value in the distribution to the specified amount.\n     *\n     * The change in value is manifested in the distribution by changing the actor's number of shares in it, and thus the distribution's total number of shares.\n     *\n     * Returns the resulting amount of shares that the actor has after this change in value.\n     */\n    function set(\n        Data storage self,\n        bytes32 actorId,\n        uint256 newActorValueD18\n    ) internal returns (uint256 resultingSharesD18) {\n        // Represent the actor's change in value by changing the actor's number of shares,\n        // and keeping the distribution's scaleModifier constant.\n\n        resultingSharesD18 = getSharesForAmount(self, newActorValueD18);\n\n        // Modify the total shares with the actor's change in shares.\n        self.totalSharesD18 = (self.totalSharesD18 + resultingSharesD18 - self.sharesD18[actorId])\n            .to128();\n\n        self.sharesD18[actorId] = resultingSharesD18.to128();\n    }\n\n    /**\n     * @dev Returns the value owned by the actor in the distribution.\n     *\n     * i.e. actor.shares * scaleModifier\n     */\n    function get(Data storage self, bytes32 actorId) internal view returns (uint256 valueD18) {\n        uint256 totalSharesD18 = self.totalSharesD18;\n        if (totalSharesD18 == 0) {\n            return 0;\n        }\n\n        return (self.sharesD18[actorId] * totalAmount(self)) / totalSharesD18;\n    }\n\n    /**\n     * @dev Returns the total value held in the distribution.\n     *\n     * i.e. totalShares * scaleModifier\n     */\n    function totalAmount(Data storage self) internal view returns (uint256 valueD18) {\n        return\n            ((self.scaleModifierD27 + DecimalMath.UNIT_PRECISE_INT).toUint() *\n                self.totalSharesD18) / DecimalMath.UNIT_PRECISE;\n    }\n\n    function getSharesForAmount(\n        Data storage self,\n        uint256 amountD18\n    ) internal view returns (uint256 sharesD18) {\n        sharesD18 =\n            (amountD18 * DecimalMath.UNIT_PRECISE) /\n            (self.scaleModifierD27 + DecimalMath.UNIT_PRECISE_INT128).toUint();\n    }\n}\n"
      },
      "contracts/storage/SystemPoolConfiguration.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"@synthetixio/core-contracts/contracts/utils/SetUtil.sol\";\n\n/**\n * @title System wide configuration for pools.\n */\nlibrary SystemPoolConfiguration {\n    bytes32 private constant _SLOT_SYSTEM_POOL_CONFIGURATION =\n        keccak256(abi.encode(\"io.synthetix.synthetix.SystemPoolConfiguration\"));\n\n    struct Data {\n        /**\n         * @dev Owner specified system-wide limiting factor that prevents markets from minting too much debt, similar to the issuance ratio to a collateral type.\n         *\n         * Note: If zero, then this value defaults to 100%.\n         */\n        uint256 minLiquidityRatioD18;\n        uint128 __reservedForFutureUse;\n        /**\n         * @dev Id of the main pool set by the system owner.\n         */\n        uint128 preferredPool;\n        /**\n         * @dev List of pools approved by the system owner.\n         */\n        SetUtil.UintSet approvedPools;\n    }\n\n    /**\n     * @dev Returns the configuration singleton.\n     */\n    function load() internal pure returns (Data storage systemPoolConfiguration) {\n        bytes32 s = _SLOT_SYSTEM_POOL_CONFIGURATION;\n        assembly {\n            systemPoolConfiguration.slot := s\n        }\n    }\n}\n"
      },
      "contracts/storage/Vault.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"./VaultEpoch.sol\";\nimport \"./RewardDistribution.sol\";\n\nimport \"@synthetixio/core-contracts/contracts/utils/SetUtil.sol\";\nimport \"@synthetixio/core-contracts/contracts/utils/SafeCast.sol\";\n\n/**\n * @title Tracks collateral and debt distributions in a pool, for a specific collateral type.\n *\n * I.e. if a pool supports SNX and ETH collaterals, it will have an SNX Vault, and an ETH Vault.\n *\n * The Vault data structure is itself split into VaultEpoch sub-structures. This facilitates liquidations,\n * so that whenever one occurs, a clean state of all data is achieved by simply incrementing the epoch index.\n *\n * It is recommended to understand VaultEpoch before understanding this object.\n */\nlibrary Vault {\n    using VaultEpoch for VaultEpoch.Data;\n    using Distribution for Distribution.Data;\n    using RewardDistribution for RewardDistribution.Data;\n    using ScalableMapping for ScalableMapping.Data;\n    using DecimalMath for uint256;\n    using DecimalMath for int128;\n    using DecimalMath for int256;\n    using SafeCastU128 for uint128;\n    using SafeCastU256 for uint256;\n    using SafeCastI128 for int128;\n    using SafeCastI256 for int256;\n    using SetUtil for SetUtil.Bytes32Set;\n\n    /**\n     * @dev Thrown when a non-existent reward distributor is referenced\n     */\n    error RewardDistributorNotFound();\n\n    struct Data {\n        /**\n         * @dev The vault's current epoch number.\n         *\n         * Vault data is divided into epochs. An epoch changes when an entire vault is liquidated.\n         */\n        uint256 epoch;\n        /**\n         * @dev Unused property, maintained for backwards compatibility in storage layout.\n         */\n        // solhint-disable-next-line private-vars-leading-underscore\n        bytes32 __slotAvailableForFutureUse;\n        /**\n         * @dev The previous debt of the vault, when `updateCreditCapacity` was last called by the Pool.\n         */\n        // solhint-disable-next-line var-name-mixedcase\n        int128 _unused_prevTotalDebtD18;\n        /**\n         * @dev Vault data for all the liquidation cycles divided into epochs.\n         */\n        mapping(uint256 => VaultEpoch.Data) epochData;\n        /**\n         * @dev Tracks available rewards, per user, for this vault.\n         */\n        mapping(bytes32 => RewardDistribution.Data) rewards;\n        /**\n         * @dev Tracks reward ids, for this vault.\n         */\n        SetUtil.Bytes32Set rewardIds;\n    }\n\n    /**\n     * @dev Return's the VaultEpoch data for the current epoch.\n     */\n    function currentEpoch(Data storage self) internal view returns (VaultEpoch.Data storage) {\n        return self.epochData[self.epoch];\n    }\n\n    /**\n     * @dev Updates the vault's credit capacity as the value of its collateral minus its debt.\n     *\n     * Called as a ticker when users interact with pools, allowing pools to set\n     * vaults' credit capacity shares within them.\n     *\n     * Returns the amount of collateral that this vault is providing in net USD terms.\n     */\n    function updateCreditCapacity(\n        Data storage self,\n        uint256 collateralPriceD18\n    ) internal view returns (uint256 usdWeightD18, int256 totalDebtD18) {\n        VaultEpoch.Data storage epochData = currentEpoch(self);\n\n        usdWeightD18 = (epochData.collateralAmounts.totalAmount()).mulDecimal(collateralPriceD18);\n\n        totalDebtD18 = epochData.totalDebt();\n\n        //self.prevTotalDebtD18 = totalDebtD18.to128();\n    }\n\n    /**\n     * @dev Updated the value per share of the current epoch's incoming debt distribution.\n     */\n    function distributeDebtToAccounts(Data storage self, int256 debtChangeD18) internal {\n        currentEpoch(self).distributeDebtToAccounts(debtChangeD18);\n    }\n\n    /**\n     * @dev Consolidates an accounts debt.\n     */\n    function consolidateAccountDebt(\n        Data storage self,\n        uint128 accountId\n    ) internal returns (int256) {\n        return currentEpoch(self).consolidateAccountDebt(accountId);\n    }\n\n    /**\n     * @dev Traverses available rewards for this vault, and updates an accounts\n     * claim on them according to the amount of debt shares they have.\n     */\n    function updateRewards(\n        Data storage self,\n        uint128 accountId,\n        uint128 poolId,\n        address collateralType\n    ) internal returns (uint256[] memory rewards, address[] memory distributors) {\n        rewards = new uint256[](self.rewardIds.length());\n        distributors = new address[](self.rewardIds.length());\n\n        uint256 numRewards = self.rewardIds.length();\n        for (uint256 i = 0; i < numRewards; i++) {\n            RewardDistribution.Data storage dist = self.rewards[self.rewardIds.valueAt(i + 1)];\n\n            if (address(dist.distributor) == address(0)) {\n                continue;\n            }\n\n            distributors[i] = address(dist.distributor);\n            rewards[i] = updateReward(\n                self,\n                accountId,\n                poolId,\n                collateralType,\n                self.rewardIds.valueAt(i + 1)\n            );\n        }\n    }\n\n    /**\n     * @dev Traverses available rewards for this vault and the reward id, and returns an accounts\n     * pending claim on them according to the amount of debt shares they have.\n     */\n    function getReward(\n        Data storage self,\n        uint128 accountId,\n        bytes32 rewardId\n    ) internal view returns (uint256) {\n        uint256 totalSharesD18 = currentEpoch(self).accountsDebtDistribution.totalSharesD18;\n        uint256 actorSharesD18 = currentEpoch(self).accountsDebtDistribution.getActorShares(\n            accountId.toBytes32()\n        );\n\n        RewardDistribution.Data storage dist = self.rewards[rewardId];\n\n        if (address(dist.distributor) == address(0)) {\n            revert RewardDistributorNotFound();\n        }\n\n        uint256 currentRewardPerShare = dist.rewardPerShareD18;\n\n        currentRewardPerShare += dist.getEntry(totalSharesD18).toUint().to128();\n\n        uint256 currentPending = dist.claimStatus[accountId].pendingSendD18 +\n            actorSharesD18.mulDecimal(\n                currentRewardPerShare - dist.claimStatus[accountId].lastRewardPerShareD18\n            );\n\n        return currentPending;\n    }\n\n    /**\n     * @dev Traverses available rewards for this vault and the reward id, and updates an accounts\n     * claim on them according to the amount of debt shares they have.\n     */\n    function updateReward(\n        Data storage self,\n        uint128 accountId,\n        uint128 poolId,\n        address collateralType,\n        bytes32 rewardId\n    ) internal returns (uint256) {\n        uint256 totalSharesD18 = currentEpoch(self).accountsDebtDistribution.totalSharesD18;\n        uint256 actorSharesD18 = currentEpoch(self).accountsDebtDistribution.getActorShares(\n            accountId.toBytes32()\n        );\n\n        RewardDistribution.Data storage dist = self.rewards[rewardId];\n\n        if (address(dist.distributor) == address(0)) {\n            revert RewardDistributorNotFound();\n        }\n\n        dist.distributor.onPositionUpdated(accountId, poolId, collateralType, actorSharesD18);\n\n        dist.rewardPerShareD18 += dist.updateEntry(totalSharesD18).toUint().to128();\n\n        dist.claimStatus[accountId].pendingSendD18 += actorSharesD18\n            .mulDecimal(dist.rewardPerShareD18 - dist.claimStatus[accountId].lastRewardPerShareD18)\n            .to128();\n\n        dist.claimStatus[accountId].lastRewardPerShareD18 = dist.rewardPerShareD18;\n\n        return dist.claimStatus[accountId].pendingSendD18;\n    }\n\n    /**\n     * @dev Increments the current epoch index, effectively producing a\n     * completely blank new VaultEpoch data structure in the vault.\n     */\n    function reset(Data storage self) internal {\n        self.epoch++;\n    }\n\n    /**\n     * @dev Returns the vault's combined debt (consolidated and unconsolidated),\n     * for the current epoch.\n     */\n    function currentDebt(Data storage self) internal view returns (int256) {\n        return currentEpoch(self).totalDebt();\n    }\n\n    /**\n     * @dev Returns the total value in the Vault's collateral distribution, for the current epoch.\n     */\n    function currentCollateral(Data storage self) internal view returns (uint256) {\n        return currentEpoch(self).collateralAmounts.totalAmount();\n    }\n\n    /**\n     * @dev Returns an account's collateral value in this vault's current epoch.\n     */\n    function currentAccountCollateral(\n        Data storage self,\n        uint128 accountId\n    ) internal view returns (uint256) {\n        return currentEpoch(self).getAccountCollateral(accountId);\n    }\n}\n"
      },
      "contracts/storage/VaultEpoch.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.11 <0.9.0;\n\nimport \"./Distribution.sol\";\nimport \"./ScalableMapping.sol\";\n\nimport \"@synthetixio/core-contracts/contracts/utils/SafeCast.sol\";\n\n/**\n * @title Tracks collateral and debt distributions in a pool, for a specific collateral type, in a given epoch.\n *\n * Collateral is tracked with a distribution as opposed to a regular mapping because liquidations cause collateral to be socialized. If collateral was tracked using a regular mapping, such socialization would be difficult and require looping through individual balances, or some other sort of complex and expensive mechanism. Distributions make socialization easy.\n *\n * Debt is also tracked in a distribution for the same reason, but it is additionally split in two distributions: incoming and consolidated debt.\n *\n * Incoming debt is modified when a liquidations occurs.\n * Consolidated debt is updated when users interact with the system.\n */\nlibrary VaultEpoch {\n    using Distribution for Distribution.Data;\n    using DecimalMath for uint256;\n    using SafeCastU128 for uint128;\n    using SafeCastU256 for uint256;\n    using SafeCastI128 for int128;\n    using SafeCastI256 for int256;\n    using ScalableMapping for ScalableMapping.Data;\n\n    struct Data {\n        /**\n         * @dev Amount of debt in this Vault that is yet to be consolidated.\n         *\n         * E.g. when a given amount of debt is socialized during a liquidation, but it yet hasn't been rolled into\n         * the consolidated debt distribution.\n         */\n        int128 unconsolidatedDebtD18;\n        /**\n         * @dev Amount of debt in this Vault that has been consolidated.\n         */\n        int128 totalConsolidatedDebtD18;\n        /**\n         * @dev Tracks incoming debt for each user.\n         *\n         * The value of shares in this distribution change as the associate market changes, i.e. price changes in an asset in\n         * a spot market.\n         *\n         * Also, when debt is socialized in a liquidation, it is done onto this distribution. As users\n         * interact with the system, their independent debt is consolidated or rolled into consolidatedDebtDist.\n         */\n        Distribution.Data accountsDebtDistribution;\n        /**\n         * @dev Tracks collateral delegated to this vault, for each user.\n         *\n         * Uses a distribution instead of a regular market because of the way collateral is socialized during liquidations.\n         *\n         * A regular mapping would require looping over the mapping of each account's collateral, or moving the liquidated\n         * collateral into a place where it could later be claimed. With a distribution, liquidated collateral can be\n         * socialized very easily.\n         */\n        ScalableMapping.Data collateralAmounts;\n        /**\n         * @dev Tracks consolidated debt for each user.\n         *\n         * Updated when users interact with the system, consolidating changes from the fluctuating accountsDebtDistribution,\n         * and directly when users mint or burn USD, or repay debt.\n         */\n        mapping(uint256 => int256) consolidatedDebtAmountsD18;\n        /**\n         * @dev Tracks last time a user delegated to this vault.\n         *\n         * Needed to validate min delegation time compliance to prevent small scale debt pool frontrunning\n         */\n        mapping(uint128 => uint64) lastDelegationTime;\n    }\n\n    /**\n     * @dev Updates the value per share of the incoming debt distribution.\n     * Used for socialization during liquidations, and to bake in market changes.\n     *\n     * Called from:\n     * - LiquidationModule.liquidate\n     * - Pool.recalculateVaultCollateral (ticker)\n     */\n    function distributeDebtToAccounts(Data storage self, int256 debtChangeD18) internal {\n        self.accountsDebtDistribution.distributeValue(debtChangeD18);\n\n        // Cache total debt here.\n        // Will roll over to individual users as they interact with the system.\n        self.unconsolidatedDebtD18 += debtChangeD18.to128();\n    }\n\n    /**\n     * @dev Adjusts the debt associated with `accountId` by `amountD18`.\n     * Used to add or remove debt from/to a specific account, instead of all accounts at once (use distributeDebtToAccounts for that)\n     */\n    function assignDebtToAccount(\n        Data storage self,\n        uint128 accountId,\n        int256 amountD18\n    ) internal returns (int256 newDebtD18) {\n        int256 currentDebtD18 = self.consolidatedDebtAmountsD18[accountId];\n        self.consolidatedDebtAmountsD18[accountId] += amountD18;\n        self.totalConsolidatedDebtD18 += amountD18.to128();\n        return currentDebtD18 + amountD18;\n    }\n\n    /**\n     * @dev Consolidates user debt as they interact with the system.\n     *\n     * Fluctuating debt is moved from incoming to consolidated debt.\n     *\n     * Called as a ticker from various parts of the system, usually whenever the\n     * real debt of a user needs to be known.\n     */\n    function consolidateAccountDebt(\n        Data storage self,\n        uint128 accountId\n    ) internal returns (int256 currentDebtD18) {\n        int256 newDebtD18 = self.accountsDebtDistribution.accumulateActor(accountId.toBytes32());\n\n        currentDebtD18 = assignDebtToAccount(self, accountId, newDebtD18);\n        self.unconsolidatedDebtD18 -= newDebtD18.to128();\n    }\n\n    /**\n     * @dev Updates a user's collateral value, and sets their exposure to debt\n     * according to the collateral they delegated and the leverage used.\n     *\n     * Called whenever a user's collateral changes.\n     */\n    function updateAccountPosition(\n        Data storage self,\n        uint128 accountId,\n        uint256 collateralAmountD18,\n        uint256 leverageD18\n    ) internal {\n        bytes32 actorId = accountId.toBytes32();\n\n        // Ensure account debt is consolidated before we do next things.\n        consolidateAccountDebt(self, accountId);\n\n        self.collateralAmounts.set(actorId, collateralAmountD18);\n        self.accountsDebtDistribution.setActorShares(\n            actorId,\n            self.collateralAmounts.sharesD18[actorId].mulDecimal(leverageD18)\n        );\n    }\n\n    /**\n     * @dev Returns the vault's total debt in this epoch, including the debt\n     * that hasn't yet been consolidated into individual accounts.\n     */\n    function totalDebt(Data storage self) internal view returns (int256) {\n        return self.unconsolidatedDebtD18 + self.totalConsolidatedDebtD18;\n    }\n\n    /**\n     * @dev Returns an account's value in the Vault's collateral distribution.\n     */\n    function getAccountCollateral(\n        Data storage self,\n        uint128 accountId\n    ) internal view returns (uint256 amountD18) {\n        return self.collateralAmounts.get(accountId.toBytes32());\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}