creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n  function decimals() external view returns (uint8);\n\n  function description() external view returns (string memory);\n\n  function version() external view returns (uint256);\n\n  function getRoundData(uint80 _roundId)\n    external\n    view\n    returns (\n      uint80 roundId,\n      int256 answer,\n      uint256 startedAt,\n      uint256 updatedAt,\n      uint80 answeredInRound\n    );\n\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"
      },
      "@openzeppelin/contracts-upgradeable/access/IAccessControlUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControlUpgradeable {\n    /**\n     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n     *\n     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n     * {RoleAdminChanged} not being emitted signaling this.\n     *\n     * _Available since v3.1._\n     */\n    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n    /**\n     * @dev Emitted when `account` is granted `role`.\n     *\n     * `sender` is the account that originated the contract call, an admin role\n     * bearer except when using {AccessControl-_setupRole}.\n     */\n    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Emitted when `account` is revoked `role`.\n     *\n     * `sender` is the account that originated the contract call:\n     *   - if using `revokeRole`, it is the admin role bearer\n     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)\n     */\n    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) external view returns (bool);\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function grantRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function revokeRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been granted `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `account`.\n     */\n    function renounceRole(bytes32 role, address account) external;\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n// EIP-2612 is Final as of 2022-11-01. This file is deprecated.\n\nimport \"./IERC20PermitUpgradeable.sol\";\n"
      },
      "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20MetadataUpgradeable is IERC20Upgradeable {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20PermitUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n *     doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n *     token.safeTransferFrom(msg.sender, address(this), value);\n *     ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20PermitUpgradeable {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     *\n     * CAUTION: See Security Considerations above.\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20Upgradeable {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/utils/math/Math.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds up instead\n     * of rounding down.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct 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(x, y, not(0))\n                prod0 := mul(x, y)\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                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1, \"Math: mulDiv overflow\");\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n            // in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10 ** 64) {\n                value /= 10 ** 64;\n                result += 64;\n            }\n            if (value >= 10 ** 32) {\n                value /= 10 ** 32;\n                result += 32;\n            }\n            if (value >= 10 ** 16) {\n                value /= 10 ** 16;\n                result += 16;\n            }\n            if (value >= 10 ** 8) {\n                value /= 10 ** 8;\n                result += 8;\n            }\n            if (value >= 10 ** 4) {\n                value /= 10 ** 4;\n                result += 4;\n            }\n            if (value >= 10 ** 2) {\n                value /= 10 ** 2;\n                result += 2;\n            }\n            if (value >= 10 ** 1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\n        }\n    }\n}\n"
      },
      "contracts/interfaces/IAsset.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"../libraries/Fixed.sol\";\nimport \"./IMain.sol\";\nimport \"./IRewardable.sol\";\n\n// Not used directly in the IAsset interface, but used by many consumers to save stack space\nstruct Price {\n    uint192 low; // {UoA/tok}\n    uint192 high; // {UoA/tok}\n}\n\n/**\n * @title IAsset\n * @notice Supertype. Any token that interacts with our system must be wrapped in an asset,\n * whether it is used as RToken backing or not. Any token that can report a price in the UoA\n * is eligible to be an asset.\n */\ninterface IAsset is IRewardable {\n    /// Refresh saved price\n    /// The Reserve protocol calls this at least once per transaction, before relying on\n    /// the Asset's other functions.\n    /// @dev Called immediately after deployment, before use\n    function refresh() external;\n\n    /// Should not revert\n    /// low should be nonzero if the asset could be worth selling\n    /// @return low {UoA/tok} The lower end of the price estimate\n    /// @return high {UoA/tok} The upper end of the price estimate\n    function price() external view returns (uint192 low, uint192 high);\n\n    /// Should not revert\n    /// lotLow should be nonzero when the asset might be worth selling\n    /// @dev Deprecated. Phased out in 3.1.0, but left on interface for backwards compatibility\n    /// @return lotLow {UoA/tok} The lower end of the lot price estimate\n    /// @return lotHigh {UoA/tok} The upper end of the lot price estimate\n    function lotPrice() external view returns (uint192 lotLow, uint192 lotHigh);\n\n    /// @return {tok} The balance of the ERC20 in whole tokens\n    function bal(address account) external view returns (uint192);\n\n    /// @return The ERC20 contract of the token with decimals() available\n    function erc20() external view returns (IERC20Metadata);\n\n    /// @return The number of decimals in the ERC20; just for gas optimization\n    function erc20Decimals() external view returns (uint8);\n\n    /// @return If the asset is an instance of ICollateral or not\n    function isCollateral() external view returns (bool);\n\n    /// @return {UoA} The max trade volume, in UoA\n    function maxTradeVolume() external view returns (uint192);\n\n    /// @return {s} The timestamp of the last refresh() that saved prices\n    function lastSave() external view returns (uint48);\n}\n\n// Used only in Testing. Strictly speaking an Asset does not need to adhere to this interface\ninterface TestIAsset is IAsset {\n    /// @return The address of the chainlink feed\n    function chainlinkFeed() external view returns (AggregatorV3Interface);\n\n    /// {1} The max % deviation allowed by the oracle\n    function oracleError() external view returns (uint192);\n\n    /// @return {s} Seconds that an oracle value is considered valid\n    function oracleTimeout() external view returns (uint48);\n\n    /// @return {s} The maximum of all oracle timeouts on the plugin\n    function maxOracleTimeout() external view returns (uint48);\n\n    /// @return {s} Seconds that the price() should decay over, after stale price\n    function priceTimeout() external view returns (uint48);\n\n    /// @return {UoA/tok} The last saved low price\n    function savedLowPrice() external view returns (uint192);\n\n    /// @return {UoA/tok} The last saved high price\n    function savedHighPrice() external view returns (uint192);\n}\n\n/// CollateralStatus must obey a linear ordering. That is:\n/// - being DISABLED is worse than being IFFY, or SOUND\n/// - being IFFY is worse than being SOUND.\nenum CollateralStatus {\n    SOUND,\n    IFFY, // When a peg is not holding or a chainlink feed is stale\n    DISABLED // When the collateral has completely defaulted\n}\n\n/// Upgrade-safe maximum operator for CollateralStatus\nlibrary CollateralStatusComparator {\n    /// @return Whether a is worse than b\n    function worseThan(CollateralStatus a, CollateralStatus b) internal pure returns (bool) {\n        return uint256(a) > uint256(b);\n    }\n}\n\n/**\n * @title ICollateral\n * @notice A subtype of Asset that consists of the tokens eligible to back the RToken.\n */\ninterface ICollateral is IAsset {\n    /// Emitted whenever the collateral status is changed\n    /// @param newStatus The old CollateralStatus\n    /// @param newStatus The updated CollateralStatus\n    event CollateralStatusChanged(\n        CollateralStatus indexed oldStatus,\n        CollateralStatus indexed newStatus\n    );\n\n    /// @dev refresh()\n    /// Refresh exchange rates and update default status.\n    /// VERY IMPORTANT: In any valid implemntation, status() MUST become DISABLED in refresh() if\n    /// refPerTok() has ever decreased since last call.\n\n    /// @return The canonical name of this collateral's target unit.\n    function targetName() external view returns (bytes32);\n\n    /// @return The status of this collateral asset. (Is it defaulting? Might it soon?)\n    function status() external view returns (CollateralStatus);\n\n    // ==== Exchange Rates ====\n\n    /// @return {ref/tok} Quantity of whole reference units per whole collateral tokens\n    function refPerTok() external view returns (uint192);\n\n    /// @return {target/ref} Quantity of whole target units per whole reference unit in the peg\n    function targetPerRef() external view returns (uint192);\n}\n\n// Used only in Testing. Strictly speaking a Collateral does not need to adhere to this interface\ninterface TestICollateral is TestIAsset, ICollateral {\n    /// @return The epoch timestamp when the collateral will default from IFFY to DISABLED\n    function whenDefault() external view returns (uint256);\n\n    /// @return The amount of time a collateral must be in IFFY status until being DISABLED\n    function delayUntilDefault() external view returns (uint48);\n\n    /// @return The underlying refPerTok, likely not included in all collaterals however.\n    function underlyingRefPerTok() external view returns (uint192);\n}\n"
      },
      "contracts/interfaces/IAssetRegistry.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./IAsset.sol\";\nimport \"./IComponent.sol\";\n\n/// A serialization of the AssetRegistry to be passed around in the P1 impl for gas optimization\nstruct Registry {\n    IERC20[] erc20s;\n    IAsset[] assets;\n}\n\n/**\n * @title IAssetRegistry\n * @notice The AssetRegistry is in charge of maintaining the ERC20 tokens eligible\n *   to be handled by the rest of the system. If an asset is in the registry, this means:\n *      1. Its ERC20 contract has been vetted\n *      2. The asset is the only asset for that ERC20\n *      3. The asset can be priced in the UoA, usually via an oracle\n */\ninterface IAssetRegistry is IComponent {\n    /// Emitted when an asset is added to the registry\n    /// @param erc20 The ERC20 contract for the asset\n    /// @param asset The asset contract added to the registry\n    event AssetRegistered(IERC20 indexed erc20, IAsset indexed asset);\n\n    /// Emitted when an asset is removed from the registry\n    /// @param erc20 The ERC20 contract for the asset\n    /// @param asset The asset contract removed from the registry\n    event AssetUnregistered(IERC20 indexed erc20, IAsset indexed asset);\n\n    // Initialization\n    function init(IMain main_, IAsset[] memory assets_) external;\n\n    /// Fully refresh all asset state\n    /// @custom:refresher\n    function refresh() external;\n\n    /// Register `asset`\n    /// If either the erc20 address or the asset was already registered, fail\n    /// @return true if the erc20 address was not already registered.\n    /// @custom:governance\n    function register(IAsset asset) external returns (bool);\n\n    /// Register `asset` if and only if its erc20 address is already registered.\n    /// If the erc20 address was not registered, revert.\n    /// @return swapped If the asset was swapped for a previously-registered asset\n    /// @custom:governance\n    function swapRegistered(IAsset asset) external returns (bool swapped);\n\n    /// Unregister an asset, requiring that it is already registered\n    /// @custom:governance\n    function unregister(IAsset asset) external;\n\n    /// @return {s} The timestamp of the last refresh\n    function lastRefresh() external view returns (uint48);\n\n    /// @return The corresponding asset for ERC20, or reverts if not registered\n    function toAsset(IERC20 erc20) external view returns (IAsset);\n\n    /// @return The corresponding collateral, or reverts if unregistered or not collateral\n    function toColl(IERC20 erc20) external view returns (ICollateral);\n\n    /// @return If the ERC20 is registered\n    function isRegistered(IERC20 erc20) external view returns (bool);\n\n    /// @return A list of all registered ERC20s\n    function erc20s() external view returns (IERC20[] memory);\n\n    /// @return reg The list of registered ERC20s and Assets, in the same order\n    function getRegistry() external view returns (Registry memory reg);\n\n    /// @return The number of registered ERC20s\n    function size() external view returns (uint256);\n}\n"
      },
      "contracts/interfaces/IBackingManager.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./IAssetRegistry.sol\";\nimport \"./IBasketHandler.sol\";\nimport \"./IComponent.sol\";\nimport \"./IRToken.sol\";\nimport \"./IStRSR.sol\";\nimport \"./ITrading.sol\";\n\n/// Memory struct for RecollateralizationLibP1 + RTokenAsset\n/// Struct purposes:\n///   1. Configure trading\n///   2. Stay under stack limit with fewer vars\n///   3. Cache information such as component addresses and basket quantities, to save on gas\nstruct TradingContext {\n    BasketRange basketsHeld; // {BU}\n    // basketsHeld.top is the number of partial baskets units held\n    // basketsHeld.bottom is the number of full basket units held\n\n    // Components\n    IBasketHandler bh;\n    IAssetRegistry ar;\n    IStRSR stRSR;\n    IERC20 rsr;\n    IRToken rToken;\n    // Gov Vars\n    uint192 minTradeVolume; // {UoA}\n    uint192 maxTradeSlippage; // {1}\n    // Cached values\n    uint192[] quantities; // {tok/BU} basket quantities\n    uint192[] bals; // {tok} balances in BackingManager + out on trades\n}\n\n/**\n * @title IBackingManager\n * @notice The BackingManager handles changes in the ERC20 balances that back an RToken.\n *   - It computes which trades to perform, if any, and initiates these trades with the Broker.\n *     - rebalance()\n *   - If already collateralized, excess assets are transferred to RevenueTraders.\n *     - forwardRevenue(IERC20[] calldata erc20s)\n */\ninterface IBackingManager is IComponent, ITrading {\n    /// Emitted when the trading delay is changed\n    /// @param oldVal The old trading delay\n    /// @param newVal The new trading delay\n    event TradingDelaySet(uint48 oldVal, uint48 newVal);\n\n    /// Emitted when the backing buffer is changed\n    /// @param oldVal The old backing buffer\n    /// @param newVal The new backing buffer\n    event BackingBufferSet(uint192 oldVal, uint192 newVal);\n\n    // Initialization\n    function init(\n        IMain main_,\n        uint48 tradingDelay_,\n        uint192 backingBuffer_,\n        uint192 maxTradeSlippage_,\n        uint192 minTradeVolume_\n    ) external;\n\n    // Give RToken max allowance over a registered token\n    /// @custom:refresher\n    /// @custom:interaction\n    function grantRTokenAllowance(IERC20) external;\n\n    /// Apply the overall backing policy using the specified TradeKind, taking a haircut if unable\n    /// @param kind TradeKind.DUTCH_AUCTION or TradeKind.BATCH_AUCTION\n    /// @custom:interaction RCEI\n    function rebalance(TradeKind kind) external;\n\n    /// Forward revenue to RevenueTraders; reverts if not fully collateralized\n    /// @param erc20s The tokens to forward\n    /// @custom:interaction RCEI\n    function forwardRevenue(IERC20[] calldata erc20s) external;\n\n    /// Structs for trading\n    /// @param basketsHeld The number of baskets held by the BackingManager\n    /// @return ctx The TradingContext\n    /// @return reg Contents of AssetRegistry.getRegistry()\n    function tradingContext(BasketRange memory basketsHeld)\n        external\n        view\n        returns (TradingContext memory ctx, Registry memory reg);\n}\n\ninterface TestIBackingManager is IBackingManager, TestITrading {\n    function tradingDelay() external view returns (uint48);\n\n    function backingBuffer() external view returns (uint192);\n\n    function setTradingDelay(uint48 val) external;\n\n    function setBackingBuffer(uint192 val) external;\n}\n"
      },
      "contracts/interfaces/IBasketHandler.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../libraries/Fixed.sol\";\nimport \"./IAsset.sol\";\nimport \"./IComponent.sol\";\n\nstruct BasketRange {\n    uint192 bottom; // {BU}\n    uint192 top; // {BU}\n}\n\n/**\n * @title IBasketHandler\n * @notice The BasketHandler aims to maintain a reference basket of constant target unit amounts.\n * When a collateral token defaults, a new reference basket of equal target units is set.\n * When _all_ collateral tokens default for a target unit, only then is the basket allowed to fall\n *   in terms of target unit amounts. The basket is considered defaulted in this case.\n */\ninterface IBasketHandler is IComponent {\n    /// Emitted when the prime basket is set\n    /// @param erc20s The collateral tokens for the prime basket\n    /// @param targetAmts {target/BU} A list of quantities of target unit per basket unit\n    /// @param targetNames Each collateral token's targetName\n    event PrimeBasketSet(IERC20[] erc20s, uint192[] targetAmts, bytes32[] targetNames);\n\n    /// Emitted when the reference basket is set\n    /// @param nonce {basketNonce} The basket nonce\n    /// @param erc20s The list of collateral tokens in the reference basket\n    /// @param refAmts {ref/BU} The reference amounts of the basket collateral tokens\n    /// @param disabled True when the list of erc20s + refAmts may not be correct\n    event BasketSet(uint256 indexed nonce, IERC20[] erc20s, uint192[] refAmts, bool disabled);\n\n    /// Emitted when a backup config is set for a target unit\n    /// @param targetName The name of the target unit as a bytes32\n    /// @param max The max number to use from `erc20s`\n    /// @param erc20s The set of backup collateral tokens\n    event BackupConfigSet(bytes32 indexed targetName, uint256 max, IERC20[] erc20s);\n\n    /// Emitted when the warmup period is changed\n    /// @param oldVal The old warmup period\n    /// @param newVal The new warmup period\n    event WarmupPeriodSet(uint48 oldVal, uint48 newVal);\n\n    /// Emitted when the status of a basket has changed\n    /// @param oldStatus The previous basket status\n    /// @param newStatus The new basket status\n    event BasketStatusChanged(CollateralStatus oldStatus, CollateralStatus newStatus);\n\n    /// Emitted when the last basket nonce available for redemption is changed\n    /// @param oldVal The old value of lastCollateralized\n    /// @param newVal The new value of lastCollateralized\n    event LastCollateralizedChanged(uint48 oldVal, uint48 newVal);\n\n    // Initialization\n    function init(\n        IMain main_,\n        uint48 warmupPeriod_,\n        bool reweightable_\n    ) external;\n\n    /// Set the prime basket\n    /// For an index RToken (reweightable = true), use forceSetPrimeBasket to skip normalization\n    /// @param erc20s The collateral tokens for the new prime basket\n    /// @param targetAmts The target amounts (in) {target/BU} for the new prime basket\n    ///                   required range: 1e9 values; absolute range irrelevant.\n    /// @custom:governance\n    function setPrimeBasket(IERC20[] calldata erc20s, uint192[] calldata targetAmts) external;\n\n    /// Set the prime basket without normalizing targetAmts by the UoA of the current basket\n    /// Works the same as setPrimeBasket for non-index RTokens (reweightable = false)\n    /// @param erc20s The collateral tokens for the new prime basket\n    /// @param targetAmts The target amounts (in) {target/BU} for the new prime basket\n    ///                   required range: 1e9 values; absolute range irrelevant.\n    /// @custom:governance\n    function forceSetPrimeBasket(IERC20[] calldata erc20s, uint192[] calldata targetAmts) external;\n\n    /// Set the backup configuration for a given target\n    /// @param targetName The name of the target as a bytes32\n    /// @param max The maximum number of collateral tokens to use from this target\n    ///            Required range: 1-255\n    /// @param erc20s A list of ordered backup collateral tokens\n    /// @custom:governance\n    function setBackupConfig(\n        bytes32 targetName,\n        uint256 max,\n        IERC20[] calldata erc20s\n    ) external;\n\n    /// Default the basket in order to schedule a basket refresh\n    /// @custom:protected\n    function disableBasket() external;\n\n    /// Governance-controlled setter to cause a basket switch explicitly\n    /// @custom:governance\n    /// @custom:interaction\n    function refreshBasket() external;\n\n    /// Track basket status and collateralization changes\n    /// @custom:refresher\n    function trackStatus() external;\n\n    /// @return If the BackingManager has sufficient collateral to redeem the entire RToken supply\n    function fullyCollateralized() external view returns (bool);\n\n    /// @return status The worst CollateralStatus of all collateral in the basket\n    function status() external view returns (CollateralStatus status);\n\n    /// @return If the basket is ready to issue and trade\n    function isReady() external view returns (bool);\n\n    /// @param erc20 The ERC20 token contract for the asset\n    /// @return {tok/BU} The whole token quantity of token in the reference basket\n    /// Returns 0 if erc20 is not registered or not in the basket\n    /// Returns FIX_MAX (in lieu of +infinity) if Collateral.refPerTok() is 0.\n    /// Otherwise, returns (token's basket.refAmts / token's Collateral.refPerTok())\n    function quantity(IERC20 erc20) external view returns (uint192);\n\n    /// Like quantity(), but unsafe because it DOES NOT CONFIRM THAT THE ASSET IS CORRECT\n    /// @param erc20 The ERC20 token contract for the asset\n    /// @param asset The registered asset plugin contract for the erc20\n    /// @return {tok/BU} The whole token quantity of token in the reference basket\n    /// Returns 0 if erc20 is not registered or not in the basket\n    /// Returns FIX_MAX (in lieu of +infinity) if Collateral.refPerTok() is 0.\n    /// Otherwise, returns (token's basket.refAmts / token's Collateral.refPerTok())\n    function quantityUnsafe(IERC20 erc20, IAsset asset) external view returns (uint192);\n\n    /// @param amount {BU}\n    /// @return erc20s The addresses of the ERC20 tokens in the reference basket\n    /// @return quantities {qTok} The quantity of each ERC20 token to issue `amount` baskets\n    function quote(uint192 amount, RoundingMode rounding)\n        external\n        view\n        returns (address[] memory erc20s, uint256[] memory quantities);\n\n    /// Return the redemption value of `amount` BUs for a linear combination of historical baskets\n    /// @param basketNonces An array of basket nonces to do redemption from\n    /// @param portions {1} An array of Fix quantities that must add up to FIX_ONE\n    /// @param amount {BU}\n    /// @return erc20s The backing collateral erc20s\n    /// @return quantities {qTok} ERC20 token quantities equal to `amount` BUs\n    function quoteCustomRedemption(\n        uint48[] memory basketNonces,\n        uint192[] memory portions,\n        uint192 amount\n    ) external view returns (address[] memory erc20s, uint256[] memory quantities);\n\n    /// @return top {BU} The number of partial basket units: e.g max(coll.map((c) => c.balAsBUs())\n    ///         bottom {BU} The number of whole basket units held by the account\n    function basketsHeldBy(address account) external view returns (BasketRange memory);\n\n    /// Should not revert\n    /// low should be nonzero when BUs are worth selling\n    /// @return low {UoA/BU} The lower end of the price estimate\n    /// @return high {UoA/BU} The upper end of the price estimate\n    function price() external view returns (uint192 low, uint192 high);\n\n    /// Should not revert\n    /// lotLow should be nonzero if a BU could be worth selling\n    /// @dev Deprecated. Phased out in 3.1.0, but left on interface for backwards compatibility\n    /// @return lotLow {UoA/tok} The lower end of the lot price estimate\n    /// @return lotHigh {UoA/tok} The upper end of the lot price estimate\n    function lotPrice() external view returns (uint192 lotLow, uint192 lotHigh);\n\n    /// @return timestamp The timestamp at which the basket was last set\n    function timestamp() external view returns (uint48);\n\n    /// @return The current basket nonce, regardless of status\n    function nonce() external view returns (uint48);\n}\n\ninterface TestIBasketHandler is IBasketHandler {\n    function lastCollateralized() external view returns (uint48);\n\n    function warmupPeriod() external view returns (uint48);\n\n    function setWarmupPeriod(uint48 val) external;\n}\n"
      },
      "contracts/interfaces/IBroker.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"./IAsset.sol\";\nimport \"./IComponent.sol\";\nimport \"./IGnosis.sol\";\nimport \"./ITrade.sol\";\n\nenum TradeKind {\n    DUTCH_AUCTION,\n    BATCH_AUCTION\n}\n\n/// Cache of all prices for a pair to prevent re-lookup\nstruct TradePrices {\n    uint192 sellLow; // {UoA/sellTok} can be 0\n    uint192 sellHigh; // {UoA/sellTok} should not be 0\n    uint192 buyLow; // {UoA/buyTok} should not be 0\n    uint192 buyHigh; // {UoA/buyTok} should not be 0 or FIX_MAX\n}\n\n/// The data format that describes a request for trade with the Broker\nstruct TradeRequest {\n    IAsset sell;\n    IAsset buy;\n    uint256 sellAmount; // {qSellTok}\n    uint256 minBuyAmount; // {qBuyTok}\n}\n\n/**\n * @title IBroker\n * @notice The Broker deploys oneshot Trade contracts for Traders and monitors\n *   the continued proper functioning of trading platforms.\n */\ninterface IBroker is IComponent {\n    event GnosisSet(IGnosis oldVal, IGnosis newVal);\n    event BatchTradeImplementationSet(ITrade oldVal, ITrade newVal);\n    event DutchTradeImplementationSet(ITrade oldVal, ITrade newVal);\n    event BatchAuctionLengthSet(uint48 oldVal, uint48 newVal);\n    event DutchAuctionLengthSet(uint48 oldVal, uint48 newVal);\n    event BatchTradeDisabledSet(bool prevVal, bool newVal);\n    event DutchTradeDisabledSet(IERC20Metadata indexed erc20, bool prevVal, bool newVal);\n\n    // Initialization\n    function init(\n        IMain main_,\n        IGnosis gnosis_,\n        ITrade batchTradeImplemention_,\n        uint48 batchAuctionLength_,\n        ITrade dutchTradeImplemention_,\n        uint48 dutchAuctionLength_\n    ) external;\n\n    /// Request a trade from the broker\n    /// @dev Requires setting an allowance in advance\n    /// @custom:interaction\n    function openTrade(\n        TradeKind kind,\n        TradeRequest memory req,\n        TradePrices memory prices\n    ) external returns (ITrade);\n\n    /// Only callable by one of the trading contracts the broker deploys\n    function reportViolation() external;\n\n    function batchTradeDisabled() external view returns (bool);\n\n    function dutchTradeDisabled(IERC20Metadata erc20) external view returns (bool);\n}\n\ninterface TestIBroker is IBroker {\n    function gnosis() external view returns (IGnosis);\n\n    function batchTradeImplementation() external view returns (ITrade);\n\n    function dutchTradeImplementation() external view returns (ITrade);\n\n    function batchAuctionLength() external view returns (uint48);\n\n    function dutchAuctionLength() external view returns (uint48);\n\n    function setGnosis(IGnosis newGnosis) external;\n\n    function setBatchTradeImplementation(ITrade newTradeImplementation) external;\n\n    function setBatchAuctionLength(uint48 newAuctionLength) external;\n\n    function setDutchTradeImplementation(ITrade newTradeImplementation) external;\n\n    function setDutchAuctionLength(uint48 newAuctionLength) external;\n\n    function enableBatchTrade() external;\n\n    function enableDutchTrade(IERC20Metadata erc20) external;\n\n    // only present on pre-3.0.0 Brokers; used by EasyAuction regression test\n    function disabled() external view returns (bool);\n}\n"
      },
      "contracts/interfaces/IComponent.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"./IMain.sol\";\nimport \"./IVersioned.sol\";\n\n/**\n * @title IComponent\n * @notice A Component is the central building block of all our system contracts. Components\n *   contain important state that must be migrated during upgrades, and they delegate\n *   their ownership to Main's owner.\n */\ninterface IComponent is IVersioned {\n    function main() external view returns (IMain);\n}\n"
      },
      "contracts/interfaces/IDistributor.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./IComponent.sol\";\n\nuint256 constant MAX_DISTRIBUTION = 1e4; // 10,000\nuint8 constant MAX_DESTINATIONS = 100; // maximum number of RevenueShare destinations\n\nstruct RevenueShare {\n    uint16 rTokenDist; // {revShare} A value between [0, 10,000]\n    uint16 rsrDist; // {revShare} A value between [0, 10,000]\n}\n\n/// Assumes no more than 100 independent distributions.\nstruct RevenueTotals {\n    uint24 rTokenTotal; // {revShare}\n    uint24 rsrTotal; // {revShare}\n}\n\n/**\n * @title IDistributor\n * @notice The Distributor Component maintains a revenue distribution table that dictates\n *   how to divide revenue across the Furnace, StRSR, and any other destinations.\n */\ninterface IDistributor is IComponent {\n    /// Emitted when a distribution is set\n    /// @param dest The address set to receive the distribution\n    /// @param rTokenDist The distribution of RToken that should go to `dest`\n    /// @param rsrDist The distribution of RSR that should go to `dest`\n    event DistributionSet(address indexed dest, uint16 rTokenDist, uint16 rsrDist);\n\n    /// Emitted when revenue is distributed\n    /// @param erc20 The token being distributed, either RSR or the RToken itself\n    /// @param source The address providing the revenue\n    /// @param amount The amount of the revenue\n    event RevenueDistributed(IERC20 indexed erc20, address indexed source, uint256 amount);\n\n    // Initialization\n    function init(IMain main_, RevenueShare memory dist) external;\n\n    /// @custom:governance\n    function setDistribution(address dest, RevenueShare memory share) external;\n\n    /// Distribute the `erc20` token across all revenue destinations\n    /// Only callable by RevenueTraders\n    /// @custom:protected\n    function distribute(IERC20 erc20, uint256 amount) external;\n\n    /// @return revTotals The total of all  destinations\n    function totals() external view returns (RevenueTotals memory revTotals);\n}\n\ninterface TestIDistributor is IDistributor {\n    // solhint-disable-next-line func-name-mixedcase\n    function FURNACE() external view returns (address);\n\n    // solhint-disable-next-line func-name-mixedcase\n    function ST_RSR() external view returns (address);\n\n    /// @return rTokenDist The RToken distribution for the address\n    /// @return rsrDist The RSR distribution for the address\n    function distribution(address) external view returns (uint16 rTokenDist, uint16 rsrDist);\n}\n"
      },
      "contracts/interfaces/IFurnace.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"../libraries/Fixed.sol\";\nimport \"./IComponent.sol\";\n\n/**\n * @title IFurnace\n * @notice A helper contract to burn RTokens slowly and permisionlessly.\n */\ninterface IFurnace is IComponent {\n    // Initialization\n    function init(IMain main_, uint192 ratio_) external;\n\n    /// Emitted when the melting ratio is changed\n    /// @param oldRatio The old ratio\n    /// @param newRatio The new ratio\n    event RatioSet(uint192 oldRatio, uint192 newRatio);\n\n    function ratio() external view returns (uint192);\n\n    ///    Needed value range: [0, 1], granularity 1e-9\n    /// @custom:governance\n    function setRatio(uint192) external;\n\n    /// Performs any RToken melting that has vested since the last payout.\n    /// @custom:refresher\n    function melt() external;\n}\n\ninterface TestIFurnace is IFurnace {\n    function lastPayout() external view returns (uint256);\n\n    function lastPayoutBal() external view returns (uint256);\n}\n"
      },
      "contracts/interfaces/IGnosis.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nstruct GnosisAuctionData {\n    IERC20 auctioningToken;\n    IERC20 biddingToken;\n    uint256 orderCancellationEndDate;\n    uint256 auctionEndDate;\n    bytes32 initialAuctionOrder;\n    uint256 minimumBiddingAmountPerOrder;\n    uint256 interimSumBidAmount;\n    bytes32 interimOrder;\n    bytes32 clearingPriceOrder;\n    uint96 volumeClearingPriceOrder;\n    bool minFundingThresholdNotReached;\n    bool isAtomicClosureAllowed;\n    uint256 feeNumerator;\n    uint256 minFundingThreshold;\n}\n\n/// The relevant portion of the interface of the live Gnosis EasyAuction contract\n/// https://github.com/gnosis/ido-contracts/blob/main/contracts/EasyAuction.sol\ninterface IGnosis {\n    function initiateAuction(\n        IERC20 auctioningToken,\n        IERC20 biddingToken,\n        uint256 orderCancellationEndDate,\n        uint256 auctionEndDate,\n        uint96 auctionedSellAmount,\n        uint96 minBuyAmount,\n        uint256 minimumBiddingAmountPerOrder,\n        uint256 minFundingThreshold,\n        bool isAtomicClosureAllowed,\n        address accessManagerContract,\n        bytes memory accessManagerContractData\n    ) external returns (uint256 auctionId);\n\n    function auctionData(uint256 auctionId) external view returns (GnosisAuctionData memory);\n\n    /// @param auctionId The external auction id\n    /// @dev See here for decoding: https://git.io/JMang\n    /// @return encodedOrder The order, encoded in a bytes 32\n    function settleAuction(uint256 auctionId) external returns (bytes32 encodedOrder);\n\n    /// @return The numerator over a 1000-valued denominator\n    function feeNumerator() external returns (uint256);\n}\n"
      },
      "contracts/interfaces/IMain.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"@openzeppelin/contracts-upgradeable/access/IAccessControlUpgradeable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./IAssetRegistry.sol\";\nimport \"./IBasketHandler.sol\";\nimport \"./IBackingManager.sol\";\nimport \"./IBroker.sol\";\nimport \"./IDistributor.sol\";\nimport \"./IFurnace.sol\";\nimport \"./IGnosis.sol\";\nimport \"./IRToken.sol\";\nimport \"./IRevenueTrader.sol\";\nimport \"./IStRSR.sol\";\nimport \"./ITrading.sol\";\nimport \"./IVersioned.sol\";\n\n// === Auth roles ===\n\nbytes32 constant OWNER = bytes32(bytes(\"OWNER\"));\nbytes32 constant SHORT_FREEZER = bytes32(bytes(\"SHORT_FREEZER\"));\nbytes32 constant LONG_FREEZER = bytes32(bytes(\"LONG_FREEZER\"));\nbytes32 constant PAUSER = bytes32(bytes(\"PAUSER\"));\n\n/**\n * Main is a central hub that maintains a list of Component contracts.\n *\n * Components:\n *   - perform a specific function\n *   - defer auth to Main\n *   - usually (but not always) contain sizeable state that require a proxy\n */\nstruct Components {\n    // Definitely need proxy\n    IRToken rToken;\n    IStRSR stRSR;\n    IAssetRegistry assetRegistry;\n    IBasketHandler basketHandler;\n    IBackingManager backingManager;\n    IDistributor distributor;\n    IFurnace furnace;\n    IBroker broker;\n    IRevenueTrader rsrTrader;\n    IRevenueTrader rTokenTrader;\n}\n\ninterface IAuth is IAccessControlUpgradeable {\n    /// Emitted when `unfreezeAt` is changed\n    /// @param oldVal The old value of `unfreezeAt`\n    /// @param newVal The new value of `unfreezeAt`\n    event UnfreezeAtSet(uint48 oldVal, uint48 newVal);\n\n    /// Emitted when the short freeze duration governance param is changed\n    /// @param oldDuration The old short freeze duration\n    /// @param newDuration The new short freeze duration\n    event ShortFreezeDurationSet(uint48 oldDuration, uint48 newDuration);\n\n    /// Emitted when the long freeze duration governance param is changed\n    /// @param oldDuration The old long freeze duration\n    /// @param newDuration The new long freeze duration\n    event LongFreezeDurationSet(uint48 oldDuration, uint48 newDuration);\n\n    /// Emitted when the system is paused or unpaused for trading\n    /// @param oldVal The old value of `tradingPaused`\n    /// @param newVal The new value of `tradingPaused`\n    event TradingPausedSet(bool oldVal, bool newVal);\n\n    /// Emitted when the system is paused or unpaused for issuance\n    /// @param oldVal The old value of `issuancePaused`\n    /// @param newVal The new value of `issuancePaused`\n    event IssuancePausedSet(bool oldVal, bool newVal);\n\n    /**\n     * Trading Paused: Disable everything except for OWNER actions, RToken.issue, RToken.redeem,\n     * StRSR.stake, and StRSR.payoutRewards\n     * Issuance Paused: Disable RToken.issue\n     * Frozen: Disable everything except for OWNER actions + StRSR.stake (for governance)\n     */\n\n    function tradingPausedOrFrozen() external view returns (bool);\n\n    function issuancePausedOrFrozen() external view returns (bool);\n\n    function frozen() external view returns (bool);\n\n    function shortFreeze() external view returns (uint48);\n\n    function longFreeze() external view returns (uint48);\n\n    // ====\n\n    // onlyRole(OWNER)\n    function freezeForever() external;\n\n    // onlyRole(SHORT_FREEZER)\n    function freezeShort() external;\n\n    // onlyRole(LONG_FREEZER)\n    function freezeLong() external;\n\n    // onlyRole(OWNER)\n    function unfreeze() external;\n\n    function pauseTrading() external;\n\n    function unpauseTrading() external;\n\n    function pauseIssuance() external;\n\n    function unpauseIssuance() external;\n}\n\ninterface IComponentRegistry {\n    // === Component setters/getters ===\n\n    event RTokenSet(IRToken indexed oldVal, IRToken indexed newVal);\n\n    function rToken() external view returns (IRToken);\n\n    event StRSRSet(IStRSR oldVal, IStRSR newVal);\n\n    function stRSR() external view returns (IStRSR);\n\n    event AssetRegistrySet(IAssetRegistry oldVal, IAssetRegistry newVal);\n\n    function assetRegistry() external view returns (IAssetRegistry);\n\n    event BasketHandlerSet(IBasketHandler oldVal, IBasketHandler newVal);\n\n    function basketHandler() external view returns (IBasketHandler);\n\n    event BackingManagerSet(IBackingManager oldVal, IBackingManager newVal);\n\n    function backingManager() external view returns (IBackingManager);\n\n    event DistributorSet(IDistributor oldVal, IDistributor newVal);\n\n    function distributor() external view returns (IDistributor);\n\n    event RSRTraderSet(IRevenueTrader oldVal, IRevenueTrader newVal);\n\n    function rsrTrader() external view returns (IRevenueTrader);\n\n    event RTokenTraderSet(IRevenueTrader oldVal, IRevenueTrader newVal);\n\n    function rTokenTrader() external view returns (IRevenueTrader);\n\n    event FurnaceSet(IFurnace oldVal, IFurnace newVal);\n\n    function furnace() external view returns (IFurnace);\n\n    event BrokerSet(IBroker oldVal, IBroker newVal);\n\n    function broker() external view returns (IBroker);\n}\n\n/**\n * @title IMain\n * @notice The central hub for the entire system. Maintains components and an owner singleton role\n */\ninterface IMain is IVersioned, IAuth, IComponentRegistry {\n    function poke() external; // not used in p1\n\n    // === Initialization ===\n\n    event MainInitialized();\n\n    function init(\n        Components memory components,\n        IERC20 rsr_,\n        uint48 shortFreeze_,\n        uint48 longFreeze_\n    ) external;\n\n    function rsr() external view returns (IERC20);\n}\n\ninterface TestIMain is IMain {\n    /// @custom:governance\n    function setShortFreeze(uint48) external;\n\n    /// @custom:governance\n    function setLongFreeze(uint48) external;\n\n    function shortFreeze() external view returns (uint48);\n\n    function longFreeze() external view returns (uint48);\n\n    function longFreezes(address account) external view returns (uint256);\n\n    function tradingPaused() external view returns (bool);\n\n    function issuancePaused() external view returns (bool);\n}\n"
      },
      "contracts/interfaces/IRevenueTrader.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"./IComponent.sol\";\nimport \"./ITrading.sol\";\n\n/**\n * @title IRevenueTrader\n * @notice The RevenueTrader is an extension of the trading mixin that trades all\n *   assets at its address for a single target asset. There are two runtime instances\n *   of the RevenueTrader, 1 for RToken and 1 for RSR.\n */\ninterface IRevenueTrader is IComponent, ITrading {\n    // Initialization\n    function init(\n        IMain main_,\n        IERC20 tokenToBuy_,\n        uint192 maxTradeSlippage_,\n        uint192 minTradeVolume_\n    ) external;\n\n    /// Distribute tokenToBuy to its destinations\n    /// @dev Special-case of manageTokens()\n    /// @custom:interaction\n    function distributeTokenToBuy() external;\n\n    /// Return registered ERC20s to the BackingManager if distribution for tokenToBuy is 0\n    /// @custom:interaction\n    function returnTokens(IERC20[] memory erc20s) external;\n\n    /// Process some number of tokens\n    /// If the tokenToBuy is included in erc20s, RevenueTrader will distribute it at end of the tx\n    /// @param erc20s The ERC20s to manage; can be tokenToBuy or anything registered\n    /// @param kinds The kinds of auctions to launch: DUTCH_AUCTION | BATCH_AUCTION\n    /// @custom:interaction\n    function manageTokens(IERC20[] memory erc20s, TradeKind[] memory kinds) external;\n\n    function tokenToBuy() external view returns (IERC20);\n}\n\n// solhint-disable-next-line no-empty-blocks\ninterface TestIRevenueTrader is IRevenueTrader, TestITrading {\n\n}\n"
      },
      "contracts/interfaces/IRewardable.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title IRewardable\n * @notice A simple interface mixin to support claiming of rewards.\n */\ninterface IRewardable {\n    /// Emitted whenever a reward token balance is claimed\n    /// @param erc20 The ERC20 of the reward token\n    /// @param amount {qTok}\n    event RewardsClaimed(IERC20 indexed erc20, uint256 amount);\n\n    /// Claim rewards earned by holding a balance of the ERC20 token\n    /// Must emit `RewardsClaimed` for each token rewards are claimed for\n    /// @custom:interaction\n    function claimRewards() external;\n}\n\n/**\n * @title IRewardableComponent\n * @notice A simple interface mixin to support claiming of rewards.\n */\ninterface IRewardableComponent is IRewardable {\n    /// Claim rewards for a single ERC20\n    /// Must emit `RewardsClaimed` for each token rewards are claimed for\n    /// @custom:interaction\n    function claimRewardsSingle(IERC20 erc20) external;\n}\n"
      },
      "contracts/interfaces/IRToken.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\";\n// solhint-disable-next-line max-line-length\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../libraries/Fixed.sol\";\nimport \"../libraries/Throttle.sol\";\nimport \"./IComponent.sol\";\n\n/**\n * @title IRToken\n * @notice An RToken is an ERC20 that is permissionlessly issuable/redeemable and tracks an\n *   exchange rate against a single unit: baskets, or {BU} in our type notation.\n */\ninterface IRToken is IComponent, IERC20MetadataUpgradeable, IERC20PermitUpgradeable {\n    /// Emitted when an issuance of RToken occurs, whether it occurs via slow minting or not\n    /// @param issuer The address holding collateral tokens\n    /// @param recipient The address of the recipient of the RTokens\n    /// @param amount The quantity of RToken being issued\n    /// @param baskets The corresponding number of baskets\n    event Issuance(\n        address indexed issuer,\n        address indexed recipient,\n        uint256 amount,\n        uint192 baskets\n    );\n\n    /// Emitted when a redemption of RToken occurs\n    /// @param redeemer The address holding RToken\n    /// @param recipient The address of the account receiving the backing collateral tokens\n    /// @param amount The quantity of RToken being redeemed\n    /// @param baskets The corresponding number of baskets\n    /// @param amount {qRTok} The amount of RTokens canceled\n    event Redemption(\n        address indexed redeemer,\n        address indexed recipient,\n        uint256 amount,\n        uint192 baskets\n    );\n\n    /// Emitted when the number of baskets needed changes\n    /// @param oldBasketsNeeded Previous number of baskets units needed\n    /// @param newBasketsNeeded New number of basket units needed\n    event BasketsNeededChanged(uint192 oldBasketsNeeded, uint192 newBasketsNeeded);\n\n    /// Emitted when RToken is melted, i.e the RToken supply is decreased but basketsNeeded is not\n    /// @param amount {qRTok}\n    event Melted(uint256 amount);\n\n    /// Emitted when issuance SupplyThrottle params are set\n    event IssuanceThrottleSet(ThrottleLib.Params oldVal, ThrottleLib.Params newVal);\n\n    /// Emitted when redemption SupplyThrottle params are set\n    event RedemptionThrottleSet(ThrottleLib.Params oldVal, ThrottleLib.Params newVal);\n\n    // Initialization\n    function init(\n        IMain main_,\n        string memory name_,\n        string memory symbol_,\n        string memory mandate_,\n        ThrottleLib.Params calldata issuanceThrottleParams,\n        ThrottleLib.Params calldata redemptionThrottleParams\n    ) external;\n\n    /// Issue an RToken with basket collateral\n    /// @param amount {qRTok} The quantity of RToken to issue\n    /// @custom:interaction\n    function issue(uint256 amount) external;\n\n    /// Issue an RToken with basket collateral, to a particular recipient\n    /// @param recipient The address to receive the issued RTokens\n    /// @param amount {qRTok} The quantity of RToken to issue\n    /// @custom:interaction\n    function issueTo(address recipient, uint256 amount) external;\n\n    /// Redeem RToken for basket collateral\n    /// @dev Use redeemCustom for non-current baskets\n    /// @param amount {qRTok} The quantity {qRToken} of RToken to redeem\n    /// @custom:interaction\n    function redeem(uint256 amount) external;\n\n    /// Redeem RToken for basket collateral to a particular recipient\n    /// @dev Use redeemCustom for non-current baskets\n    /// @param recipient The address to receive the backing collateral tokens\n    /// @param amount {qRTok} The quantity {qRToken} of RToken to redeem\n    /// @custom:interaction\n    function redeemTo(address recipient, uint256 amount) external;\n\n    /// Redeem RToken for a linear combination of historical baskets, to a particular recipient\n    /// @dev Allows partial redemptions up to the minAmounts\n    /// @param recipient The address to receive the backing collateral tokens\n    /// @param amount {qRTok} The quantity {qRToken} of RToken to redeem\n    /// @param basketNonces An array of basket nonces to do redemption from\n    /// @param portions {1} An array of Fix quantities that must add up to FIX_ONE\n    /// @param expectedERC20sOut An array of ERC20s expected out\n    /// @param minAmounts {qTok} The minimum ERC20 quantities the caller should receive\n    /// @custom:interaction\n    function redeemCustom(\n        address recipient,\n        uint256 amount,\n        uint48[] memory basketNonces,\n        uint192[] memory portions,\n        address[] memory expectedERC20sOut,\n        uint256[] memory minAmounts\n    ) external;\n\n    /// Mint an amount of RToken equivalent to baskets BUs, scaling basketsNeeded up\n    /// Callable only by BackingManager\n    /// @param baskets {BU} The number of baskets to mint RToken for\n    /// @custom:protected\n    function mint(uint192 baskets) external;\n\n    /// Melt a quantity of RToken from the caller's account\n    /// @param amount {qRTok} The amount to be melted\n    /// @custom:protected\n    function melt(uint256 amount) external;\n\n    /// Burn an amount of RToken from caller's account and scale basketsNeeded down\n    /// Callable only by BackingManager\n    /// @custom:protected\n    function dissolve(uint256 amount) external;\n\n    /// Set the number of baskets needed directly, callable only by the BackingManager\n    /// @param basketsNeeded {BU} The number of baskets to target\n    ///                      needed range: pretty interesting\n    /// @custom:protected\n    function setBasketsNeeded(uint192 basketsNeeded) external;\n\n    /// @return {BU} How many baskets are being targeted\n    function basketsNeeded() external view returns (uint192);\n\n    /// @return {qRTok} The maximum issuance that can be performed in the current block\n    function issuanceAvailable() external view returns (uint256);\n\n    /// @return {qRTok} The maximum redemption that can be performed in the current block\n    function redemptionAvailable() external view returns (uint256);\n}\n\ninterface TestIRToken is IRToken {\n    function setIssuanceThrottleParams(ThrottleLib.Params calldata) external;\n\n    function setRedemptionThrottleParams(ThrottleLib.Params calldata) external;\n\n    function issuanceThrottleParams() external view returns (ThrottleLib.Params memory);\n\n    function redemptionThrottleParams() external view returns (ThrottleLib.Params memory);\n\n    function increaseAllowance(address, uint256) external returns (bool);\n\n    function decreaseAllowance(address, uint256) external returns (bool);\n\n    function monetizeDonations(IERC20) external;\n}\n"
      },
      "contracts/interfaces/IStRSR.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\";\n// solhint-disable-next-line max-line-length\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol\";\nimport \"../libraries/Fixed.sol\";\nimport \"./IComponent.sol\";\n\n/**\n * @title IStRSR\n * @notice An ERC20 token representing shares of the RSR over-collateralization pool.\n *\n * StRSR permits the BackingManager to take RSR in times of need. In return, the BackingManager\n * benefits the StRSR pool with RSR rewards purchased with a portion of its revenue.\n *\n * In the absence of collateral default or losses due to slippage, StRSR should have a\n * monotonically increasing exchange rate with respect to RSR, meaning that over time\n * StRSR is redeemable for more RSR. It is non-rebasing.\n */\ninterface IStRSR is IERC20MetadataUpgradeable, IERC20PermitUpgradeable, IComponent {\n    /// Emitted when RSR is staked\n    /// @param era The era at time of staking\n    /// @param staker The address of the staker\n    /// @param rsrAmount {qRSR} How much RSR was staked\n    /// @param stRSRAmount {qStRSR} How much stRSR was minted by this staking\n    event Staked(\n        uint256 indexed era,\n        address indexed staker,\n        uint256 rsrAmount,\n        uint256 stRSRAmount\n    );\n\n    /// Emitted when an unstaking is started\n    /// @param draftId The id of the draft.\n    /// @param draftEra The era of the draft.\n    /// @param staker The address of the unstaker\n    ///   The triple (staker, draftEra, draftId) is a unique ID\n    /// @param rsrAmount {qRSR} How much RSR this unstaking will be worth, absent seizures\n    /// @param stRSRAmount {qStRSR} How much stRSR was burned by this unstaking\n    event UnstakingStarted(\n        uint256 indexed draftId,\n        uint256 indexed draftEra,\n        address indexed staker,\n        uint256 rsrAmount,\n        uint256 stRSRAmount,\n        uint256 availableAt\n    );\n\n    /// Emitted when RSR is unstaked\n    /// @param firstId The beginning of the range of draft IDs withdrawn in this transaction\n    /// @param endId The end of range of draft IDs withdrawn in this transaction\n    ///   (ID i was withdrawn if firstId <= i < endId)\n    /// @param draftEra The era of the draft.\n    ///   The triple (staker, draftEra, id) is a unique ID among drafts\n    /// @param staker The address of the unstaker\n\n    /// @param rsrAmount {qRSR} How much RSR this unstaking was worth\n    event UnstakingCompleted(\n        uint256 indexed firstId,\n        uint256 indexed endId,\n        uint256 draftEra,\n        address indexed staker,\n        uint256 rsrAmount\n    );\n\n    /// Emitted when RSR unstaking is cancelled\n    /// @param firstId The beginning of the range of draft IDs withdrawn in this transaction\n    /// @param endId The end of range of draft IDs withdrawn in this transaction\n    ///   (ID i was withdrawn if firstId <= i < endId)\n    /// @param draftEra The era of the draft.\n    ///   The triple (staker, draftEra, id) is a unique ID among drafts\n    /// @param staker The address of the unstaker\n\n    /// @param rsrAmount {qRSR} How much RSR this unstaking was worth\n    event UnstakingCancelled(\n        uint256 indexed firstId,\n        uint256 indexed endId,\n        uint256 draftEra,\n        address indexed staker,\n        uint256 rsrAmount\n    );\n\n    /// Emitted whenever the exchange rate changes\n    event ExchangeRateSet(uint192 oldVal, uint192 newVal);\n\n    /// Emitted whenever RSR are paids out\n    event RewardsPaid(uint256 rsrAmt);\n\n    /// Emitted if all the RSR in the staking pool is seized and all balances are reset to zero.\n    event AllBalancesReset(uint256 indexed newEra);\n    /// Emitted if all the RSR in the unstakin pool is seized, and all ongoing unstaking is voided.\n    event AllUnstakingReset(uint256 indexed newEra);\n\n    event UnstakingDelaySet(uint48 oldVal, uint48 newVal);\n    event RewardRatioSet(uint192 oldVal, uint192 newVal);\n    event WithdrawalLeakSet(uint192 oldVal, uint192 newVal);\n\n    // Initialization\n    function init(\n        IMain main_,\n        string memory name_,\n        string memory symbol_,\n        uint48 unstakingDelay_,\n        uint192 rewardRatio_,\n        uint192 withdrawalLeak_\n    ) external;\n\n    /// Gather and payout rewards from rsrTrader\n    /// @custom:interaction\n    function payoutRewards() external;\n\n    /// Stakes an RSR `amount` on the corresponding RToken to earn yield and over-collateralized\n    /// the system\n    /// @param amount {qRSR}\n    /// @custom:interaction\n    function stake(uint256 amount) external;\n\n    /// Begins a delayed unstaking for `amount` stRSR\n    /// @param amount {qStRSR}\n    /// @custom:interaction\n    function unstake(uint256 amount) external;\n\n    /// Complete delayed unstaking for the account, up to (but not including!) `endId`\n    /// @custom:interaction\n    function withdraw(address account, uint256 endId) external;\n\n    /// Cancel unstaking for the account, up to (but not including!) `endId`\n    /// @custom:interaction\n    function cancelUnstake(uint256 endId) external;\n\n    /// Seize RSR, only callable by main.backingManager()\n    /// @custom:protected\n    function seizeRSR(uint256 amount) external;\n\n    /// Reset all stakes and advance era\n    /// @custom:governance\n    function resetStakes() external;\n\n    /// Return the maximum valid value of endId such that withdraw(endId) should immediately work\n    function endIdForWithdraw(address account) external view returns (uint256 endId);\n\n    /// @return {qRSR/qStRSR} The exchange rate between RSR and StRSR\n    function exchangeRate() external view returns (uint192);\n}\n\ninterface TestIStRSR is IStRSR {\n    function rewardRatio() external view returns (uint192);\n\n    function setRewardRatio(uint192) external;\n\n    function unstakingDelay() external view returns (uint48);\n\n    function setUnstakingDelay(uint48) external;\n\n    function withdrawalLeak() external view returns (uint192);\n\n    function setWithdrawalLeak(uint192) external;\n\n    function increaseAllowance(address, uint256) external returns (bool);\n\n    function decreaseAllowance(address, uint256) external returns (bool);\n\n    /// @return {qStRSR/qRSR} The exchange rate between StRSR and RSR\n    function exchangeRate() external view returns (uint192);\n}\n"
      },
      "contracts/interfaces/ITrade.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"./IBroker.sol\";\nimport \"./IVersioned.sol\";\n\nenum TradeStatus {\n    NOT_STARTED, // before init()\n    OPEN, // after init() and before settle()\n    CLOSED, // after settle()\n    // === Intermediate-tx state ===\n    PENDING // during init() or settle() (reentrancy protection)\n}\n\n/**\n * Simple generalized trading interface for all Trade contracts to obey\n *\n * Usage: if (canSettle()) settle()\n */\ninterface ITrade is IVersioned {\n    /// Complete the trade and transfer tokens back to the origin trader\n    /// @return soldAmt {qSellTok} The quantity of tokens sold\n    /// @return boughtAmt {qBuyTok} The quantity of tokens bought\n    function settle() external returns (uint256 soldAmt, uint256 boughtAmt);\n\n    function sell() external view returns (IERC20Metadata);\n\n    function buy() external view returns (IERC20Metadata);\n\n    /// @return {tok} The sell amount of the trade, in whole tokens\n    function sellAmount() external view returns (uint192);\n\n    /// @return The timestamp at which the trade is projected to become settle-able\n    function endTime() external view returns (uint48);\n\n    /// @return True if the trade can be settled\n    /// @dev Should be guaranteed to be true eventually as an invariant\n    function canSettle() external view returns (bool);\n\n    /// @return TradeKind.DUTCH_AUCTION or TradeKind.BATCH_AUCTION\n    // solhint-disable-next-line func-name-mixedcase\n    function KIND() external view returns (TradeKind);\n}\n"
      },
      "contracts/interfaces/ITrading.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../libraries/Fixed.sol\";\nimport \"./IComponent.sol\";\nimport \"./ITrade.sol\";\nimport \"./IRewardable.sol\";\n\n/**\n * @title ITrading\n * @notice Common events and refresher function for all Trading contracts\n */\ninterface ITrading is IComponent, IRewardableComponent {\n    event MaxTradeSlippageSet(uint192 oldVal, uint192 newVal);\n    event MinTradeVolumeSet(uint192 oldVal, uint192 newVal);\n\n    /// Emitted when a trade is started\n    /// @param trade The one-time-use trade contract that was just deployed\n    /// @param sell The token to sell\n    /// @param buy The token to buy\n    /// @param sellAmount {qSellTok} The quantity of the selling token\n    /// @param minBuyAmount {qBuyTok} The minimum quantity of the buying token to accept\n    event TradeStarted(\n        ITrade indexed trade,\n        IERC20 indexed sell,\n        IERC20 indexed buy,\n        uint256 sellAmount,\n        uint256 minBuyAmount\n    );\n\n    /// Emitted after a trade ends\n    /// @param trade The one-time-use trade contract\n    /// @param sell The token to sell\n    /// @param buy The token to buy\n    /// @param sellAmount {qSellTok} The quantity of the token sold\n    /// @param buyAmount {qBuyTok} The quantity of the token bought\n    event TradeSettled(\n        ITrade indexed trade,\n        IERC20 indexed sell,\n        IERC20 indexed buy,\n        uint256 sellAmount,\n        uint256 buyAmount\n    );\n\n    /// Settle a single trade, expected to be used with multicall for efficient mass settlement\n    /// @param sell The sell token in the trade\n    /// @return The trade settled\n    /// @custom:refresher\n    function settleTrade(IERC20 sell) external returns (ITrade);\n\n    /// @return {%} The maximum trade slippage acceptable\n    function maxTradeSlippage() external view returns (uint192);\n\n    /// @return {UoA} The minimum trade volume in UoA, applies to all assets\n    function minTradeVolume() external view returns (uint192);\n\n    /// @return The ongoing trade for a sell token, or the zero address\n    function trades(IERC20 sell) external view returns (ITrade);\n\n    /// @return The number of ongoing trades open\n    function tradesOpen() external view returns (uint48);\n\n    /// @return The number of total trades ever opened\n    function tradesNonce() external view returns (uint256);\n}\n\ninterface TestITrading is ITrading {\n    /// @custom:governance\n    function setMaxTradeSlippage(uint192 val) external;\n\n    /// @custom:governance\n    function setMinTradeVolume(uint192 val) external;\n}\n"
      },
      "contracts/interfaces/IVersioned.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\ninterface IVersioned {\n    function version() external view returns (string memory);\n}\n"
      },
      "contracts/libraries/Fixed.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\n// solhint-disable func-name-mixedcase func-visibility\n// slither-disable-start divide-before-multiply\npragma solidity ^0.8.19;\n\n/// @title FixedPoint, a fixed-point arithmetic library defining the custom type uint192\n/// @author Matt Elder <matt.elder@reserve.org> and the Reserve Team <https://reserve.org>\n\n/** The logical type `uint192 ` is a 192 bit value, representing an 18-decimal Fixed-point\n    fractional value.  This is what's described in the Solidity documentation as\n    \"fixed192x18\" -- a value represented by 192 bits, that makes 18 digits available to\n    the right of the decimal point.\n\n    The range of values that uint192 can represent is about [-1.7e20, 1.7e20].\n    Unless a function explicitly says otherwise, it will fail on overflow.\n    To be clear, the following should hold:\n    toFix(0) == 0\n    toFix(1) == 1e18\n*/\n\n// Analysis notes:\n//   Every function should revert iff its result is out of bounds.\n//   Unless otherwise noted, when a rounding mode is given, that mode is applied to\n//     a single division that may happen as the last step in the computation.\n//   Unless otherwise noted, when a rounding mode is *not* given but is needed, it's FLOOR.\n//   For each, we comment:\n//   - @return is the value expressed  in \"value space\", where uint192(1e18) \"is\" 1.0\n//   - as-ints: is the value expressed in \"implementation space\", where uint192(1e18) \"is\" 1e18\n//   The \"@return\" expression is suitable for actually using the library\n//   The \"as-ints\" expression is suitable for testing\n\n// A uint value passed to this library was out of bounds for uint192 operations\nerror UIntOutOfBounds();\nbytes32 constant UIntOutofBoundsHash = keccak256(abi.encodeWithSignature(\"UIntOutOfBounds()\"));\n\n// Used by P1 implementation for easier casting\nuint256 constant FIX_ONE_256 = 1e18;\nuint8 constant FIX_DECIMALS = 18;\n\n// If a particular uint192 is represented by the uint192 n, then the uint192 represents the\n// value n/FIX_SCALE.\nuint64 constant FIX_SCALE = 1e18;\n\n// FIX_SCALE Squared:\nuint128 constant FIX_SCALE_SQ = 1e36;\n\n// The largest integer that can be converted to uint192 .\n// This is a bit bigger than 3.1e39\nuint192 constant FIX_MAX_INT = type(uint192).max / FIX_SCALE;\n\nuint192 constant FIX_ZERO = 0; // The uint192 representation of zero.\nuint192 constant FIX_ONE = FIX_SCALE; // The uint192 representation of one.\nuint192 constant FIX_MAX = type(uint192).max; // The largest uint192. (Not an integer!)\nuint192 constant FIX_MIN = 0; // The smallest uint192.\n\n/// An enum that describes a rounding approach for converting to ints\nenum RoundingMode {\n    FLOOR, // Round towards zero\n    ROUND, // Round to the nearest int\n    CEIL // Round away from zero\n}\n\nRoundingMode constant FLOOR = RoundingMode.FLOOR;\nRoundingMode constant ROUND = RoundingMode.ROUND;\nRoundingMode constant CEIL = RoundingMode.CEIL;\n\n/* @dev Solidity 0.8.x only allows you to change one of type or size per type conversion.\n   Thus, all the tedious-looking double conversions like uint256(uint256 (foo))\n   See: https://docs.soliditylang.org/en/v0.8.17/080-breaking-changes.html#new-restrictions\n */\n\n/// Explicitly convert a uint256 to a uint192. Revert if the input is out of bounds.\nfunction _safeWrap(uint256 x) pure returns (uint192) {\n    if (FIX_MAX < x) revert UIntOutOfBounds();\n    return uint192(x);\n}\n\n/// Convert a uint to its Fix representation.\n/// @return x\n// as-ints: x * 1e18\nfunction toFix(uint256 x) pure returns (uint192) {\n    return _safeWrap(x * FIX_SCALE);\n}\n\n/// Convert a uint to its fixed-point representation, and left-shift its value `shiftLeft`\n/// decimal digits.\n/// @return x * 10**shiftLeft\n// as-ints: x * 10**(shiftLeft + 18)\nfunction shiftl_toFix(uint256 x, int8 shiftLeft) pure returns (uint192) {\n    return shiftl_toFix(x, shiftLeft, FLOOR);\n}\n\n/// @return x * 10**shiftLeft\n// as-ints: x * 10**(shiftLeft + 18)\nfunction shiftl_toFix(\n    uint256 x,\n    int8 shiftLeft,\n    RoundingMode rounding\n) pure returns (uint192) {\n    // conditions for avoiding overflow\n    if (x == 0) return 0;\n    if (shiftLeft <= -96) return (rounding == CEIL ? 1 : 0); // 0 < uint.max / 10**77 < 0.5\n    if (40 <= shiftLeft) revert UIntOutOfBounds(); // 10**56 < FIX_MAX < 10**57\n\n    shiftLeft += 18;\n\n    uint256 coeff = 10**abs(shiftLeft);\n    uint256 shifted = (shiftLeft >= 0) ? x * coeff : _divrnd(x, coeff, rounding);\n\n    return _safeWrap(shifted);\n}\n\n/// Divide a uint by a uint192, yielding a uint192\n/// This may also fail if the result is MIN_uint192! not fixing this for optimization's sake.\n/// @return x / y\n// as-ints: x * 1e36 / y\nfunction divFix(uint256 x, uint192 y) pure returns (uint192) {\n    // If we didn't have to worry about overflow, we'd just do `return x * 1e36 / _y`\n    // If it's safe to do this operation the easy way, do it:\n    if (x < uint256(type(uint256).max / FIX_SCALE_SQ)) {\n        return _safeWrap(uint256(x * FIX_SCALE_SQ) / y);\n    } else {\n        return _safeWrap(mulDiv256(x, FIX_SCALE_SQ, y));\n    }\n}\n\n/// Divide a uint by a uint, yielding a  uint192\n/// @return x / y\n// as-ints: x * 1e18 / y\nfunction divuu(uint256 x, uint256 y) pure returns (uint192) {\n    return _safeWrap(mulDiv256(FIX_SCALE, x, y));\n}\n\n/// @return min(x,y)\n// as-ints: min(x,y)\nfunction fixMin(uint192 x, uint192 y) pure returns (uint192) {\n    return x < y ? x : y;\n}\n\n/// @return max(x,y)\n// as-ints: max(x,y)\nfunction fixMax(uint192 x, uint192 y) pure returns (uint192) {\n    return x > y ? x : y;\n}\n\n/// @return absoluteValue(x,y)\n// as-ints: absoluteValue(x,y)\nfunction abs(int256 x) pure returns (uint256) {\n    return x < 0 ? uint256(-x) : uint256(x);\n}\n\n/// Divide two uints, returning a uint, using rounding mode `rounding`.\n/// @return numerator / divisor\n// as-ints: numerator / divisor\nfunction _divrnd(\n    uint256 numerator,\n    uint256 divisor,\n    RoundingMode rounding\n) pure returns (uint256) {\n    uint256 result = numerator / divisor;\n\n    if (rounding == FLOOR) return result;\n\n    if (rounding == ROUND) {\n        if (numerator % divisor > (divisor - 1) / 2) {\n            result++;\n        }\n    } else {\n        if (numerator % divisor != 0) {\n            result++;\n        }\n    }\n\n    return result;\n}\n\nlibrary FixLib {\n    /// Again, all arithmetic functions fail if and only if the result is out of bounds.\n\n    /// Convert this fixed-point value to a uint. Round towards zero if needed.\n    /// @return x\n    // as-ints: x / 1e18\n    function toUint(uint192 x) internal pure returns (uint136) {\n        return toUint(x, FLOOR);\n    }\n\n    /// Convert this uint192 to a uint\n    /// @return x\n    // as-ints: x / 1e18 with rounding\n    function toUint(uint192 x, RoundingMode rounding) internal pure returns (uint136) {\n        return uint136(_divrnd(uint256(x), FIX_SCALE, rounding));\n    }\n\n    /// Return the uint192 shifted to the left by `decimal` digits\n    /// (Similar to a bitshift but in base 10)\n    /// @return x * 10**decimals\n    // as-ints: x * 10**decimals\n    function shiftl(uint192 x, int8 decimals) internal pure returns (uint192) {\n        return shiftl(x, decimals, FLOOR);\n    }\n\n    /// Return the uint192 shifted to the left by `decimal` digits\n    /// (Similar to a bitshift but in base 10)\n    /// @return x * 10**decimals\n    // as-ints: x * 10**decimals\n    function shiftl(\n        uint192 x,\n        int8 decimals,\n        RoundingMode rounding\n    ) internal pure returns (uint192) {\n        // Handle overflow cases\n        if (x == 0) return 0;\n        if (decimals <= -59) return (rounding == CEIL ? 1 : 0); // 59, because 1e58 > 2**192\n        if (58 <= decimals) revert UIntOutOfBounds(); // 58, because x * 1e58 > 2 ** 192 if x != 0\n\n        uint256 coeff = uint256(10**abs(decimals));\n        return _safeWrap(decimals >= 0 ? x * coeff : _divrnd(x, coeff, rounding));\n    }\n\n    /// Add a uint192 to this uint192\n    /// @return x + y\n    // as-ints: x + y\n    function plus(uint192 x, uint192 y) internal pure returns (uint192) {\n        return x + y;\n    }\n\n    /// Add a uint to this uint192\n    /// @return x + y\n    // as-ints: x + y*1e18\n    function plusu(uint192 x, uint256 y) internal pure returns (uint192) {\n        return _safeWrap(x + y * FIX_SCALE);\n    }\n\n    /// Subtract a uint192 from this uint192\n    /// @return x - y\n    // as-ints: x - y\n    function minus(uint192 x, uint192 y) internal pure returns (uint192) {\n        return x - y;\n    }\n\n    /// Subtract a uint from this uint192\n    /// @return x - y\n    // as-ints: x - y*1e18\n    function minusu(uint192 x, uint256 y) internal pure returns (uint192) {\n        return _safeWrap(uint256(x) - uint256(y * FIX_SCALE));\n    }\n\n    /// Multiply this uint192 by a uint192\n    /// Round truncated values to the nearest available value. 5e-19 rounds away from zero.\n    /// @return x * y\n    // as-ints: x * y/1e18  [division using ROUND, not FLOOR]\n    function mul(uint192 x, uint192 y) internal pure returns (uint192) {\n        return mul(x, y, ROUND);\n    }\n\n    /// Multiply this uint192 by a uint192\n    /// @return x * y\n    // as-ints: x * y/1e18\n    function mul(\n        uint192 x,\n        uint192 y,\n        RoundingMode rounding\n    ) internal pure returns (uint192) {\n        return _safeWrap(_divrnd(uint256(x) * uint256(y), FIX_SCALE, rounding));\n    }\n\n    /// Multiply this uint192 by a uint\n    /// @return x * y\n    // as-ints: x * y\n    function mulu(uint192 x, uint256 y) internal pure returns (uint192) {\n        return _safeWrap(x * y);\n    }\n\n    /// Divide this uint192 by a uint192\n    /// @return x / y\n    // as-ints: x * 1e18 / y\n    function div(uint192 x, uint192 y) internal pure returns (uint192) {\n        return div(x, y, FLOOR);\n    }\n\n    /// Divide this uint192 by a uint192\n    /// @return x / y\n    // as-ints: x * 1e18 / y\n    function div(\n        uint192 x,\n        uint192 y,\n        RoundingMode rounding\n    ) internal pure returns (uint192) {\n        // Multiply-in FIX_SCALE before dividing by y to preserve precision.\n        return _safeWrap(_divrnd(uint256(x) * FIX_SCALE, y, rounding));\n    }\n\n    /// Divide this uint192 by a uint\n    /// @return x / y\n    // as-ints: x / y\n    function divu(uint192 x, uint256 y) internal pure returns (uint192) {\n        return divu(x, y, FLOOR);\n    }\n\n    /// Divide this uint192 by a uint\n    /// @return x / y\n    // as-ints: x / y\n    function divu(\n        uint192 x,\n        uint256 y,\n        RoundingMode rounding\n    ) internal pure returns (uint192) {\n        return _safeWrap(_divrnd(x, y, rounding));\n    }\n\n    uint64 constant FIX_HALF = uint64(FIX_SCALE) / 2;\n\n    /// Raise this uint192 to a nonnegative integer power. Requires that x_ <= FIX_ONE\n    /// Gas cost is O(lg(y)), precision is +- 1e-18.\n    /// @return x_ ** y\n    // as-ints: x_ ** y / 1e18**(y-1)    <- technically correct for y = 0. :D\n    function powu(uint192 x_, uint48 y) internal pure returns (uint192) {\n        require(x_ <= FIX_ONE);\n        if (y == 1) return x_;\n        if (x_ == FIX_ONE || y == 0) return FIX_ONE;\n        uint256 x = uint256(x_) * FIX_SCALE; // x is D36\n        uint256 result = FIX_SCALE_SQ; // result is D36\n        while (true) {\n            if (y & 1 == 1) result = (result * x + FIX_SCALE_SQ / 2) / FIX_SCALE_SQ;\n            if (y <= 1) break;\n            y = (y >> 1);\n            x = (x * x + FIX_SCALE_SQ / 2) / FIX_SCALE_SQ;\n        }\n        return _safeWrap(result / FIX_SCALE);\n    }\n\n    function sqrt(uint192 x) internal pure returns (uint192) {\n        return _safeWrap(sqrt256(x * FIX_ONE_256)); // FLOOR\n    }\n\n    /// Comparison operators...\n    function lt(uint192 x, uint192 y) internal pure returns (bool) {\n        return x < y;\n    }\n\n    function lte(uint192 x, uint192 y) internal pure returns (bool) {\n        return x <= y;\n    }\n\n    function gt(uint192 x, uint192 y) internal pure returns (bool) {\n        return x > y;\n    }\n\n    function gte(uint192 x, uint192 y) internal pure returns (bool) {\n        return x >= y;\n    }\n\n    function eq(uint192 x, uint192 y) internal pure returns (bool) {\n        return x == y;\n    }\n\n    function neq(uint192 x, uint192 y) internal pure returns (bool) {\n        return x != y;\n    }\n\n    /// Return whether or not this uint192 is less than epsilon away from y.\n    /// @return |x - y| < epsilon\n    // as-ints: |x - y| < epsilon\n    function near(\n        uint192 x,\n        uint192 y,\n        uint192 epsilon\n    ) internal pure returns (bool) {\n        uint192 diff = x <= y ? y - x : x - y;\n        return diff < epsilon;\n    }\n\n    // ================ Chained Operations ================\n    // The operation foo_bar() always means:\n    //   Do foo() followed by bar(), and overflow only if the _end_ result doesn't fit in an uint192\n\n    /// Shift this uint192 left by `decimals` digits, and convert to a uint\n    /// @return x * 10**decimals\n    // as-ints: x * 10**(decimals - 18)\n    function shiftl_toUint(uint192 x, int8 decimals) internal pure returns (uint256) {\n        return shiftl_toUint(x, decimals, FLOOR);\n    }\n\n    /// Shift this uint192 left by `decimals` digits, and convert to a uint.\n    /// @return x * 10**decimals\n    // as-ints: x * 10**(decimals - 18)\n    function shiftl_toUint(\n        uint192 x,\n        int8 decimals,\n        RoundingMode rounding\n    ) internal pure returns (uint256) {\n        // Handle overflow cases\n        if (x == 0) return 0; // always computable, no matter what decimals is\n        if (decimals <= -42) return (rounding == CEIL ? 1 : 0);\n        if (96 <= decimals) revert UIntOutOfBounds();\n\n        decimals -= 18; // shift so that toUint happens at the same time.\n\n        uint256 coeff = uint256(10**abs(decimals));\n        return decimals >= 0 ? uint256(x * coeff) : uint256(_divrnd(x, coeff, rounding));\n    }\n\n    /// Multiply this uint192 by a uint, and output the result as a uint\n    /// @return x * y\n    // as-ints: x * y / 1e18\n    function mulu_toUint(uint192 x, uint256 y) internal pure returns (uint256) {\n        return mulDiv256(uint256(x), y, FIX_SCALE);\n    }\n\n    /// Multiply this uint192 by a uint, and output the result as a uint\n    /// @return x * y\n    // as-ints: x * y / 1e18\n    function mulu_toUint(\n        uint192 x,\n        uint256 y,\n        RoundingMode rounding\n    ) internal pure returns (uint256) {\n        return mulDiv256(uint256(x), y, FIX_SCALE, rounding);\n    }\n\n    /// Multiply this uint192 by a uint192 and output the result as a uint\n    /// @return x * y\n    // as-ints: x * y / 1e36\n    function mul_toUint(uint192 x, uint192 y) internal pure returns (uint256) {\n        return mulDiv256(uint256(x), uint256(y), FIX_SCALE_SQ);\n    }\n\n    /// Multiply this uint192 by a uint192 and output the result as a uint\n    /// @return x * y\n    // as-ints: x * y / 1e36\n    function mul_toUint(\n        uint192 x,\n        uint192 y,\n        RoundingMode rounding\n    ) internal pure returns (uint256) {\n        return mulDiv256(uint256(x), uint256(y), FIX_SCALE_SQ, rounding);\n    }\n\n    /// Compute x * y / z avoiding intermediate overflow\n    /// @dev Only use if you need to avoid overflow; costlier than x * y / z\n    /// @return x * y / z\n    // as-ints: x * y / z\n    function muluDivu(\n        uint192 x,\n        uint256 y,\n        uint256 z\n    ) internal pure returns (uint192) {\n        return muluDivu(x, y, z, FLOOR);\n    }\n\n    /// Compute x * y / z, avoiding intermediate overflow\n    /// @dev Only use if you need to avoid overflow; costlier than x * y / z\n    /// @return x * y / z\n    // as-ints: x * y / z\n    function muluDivu(\n        uint192 x,\n        uint256 y,\n        uint256 z,\n        RoundingMode rounding\n    ) internal pure returns (uint192) {\n        return _safeWrap(mulDiv256(x, y, z, rounding));\n    }\n\n    /// Compute x * y / z on Fixes, avoiding intermediate overflow\n    /// @dev Only use if you need to avoid overflow; costlier than x * y / z\n    /// @return x * y / z\n    // as-ints: x * y / z\n    function mulDiv(\n        uint192 x,\n        uint192 y,\n        uint192 z\n    ) internal pure returns (uint192) {\n        return mulDiv(x, y, z, FLOOR);\n    }\n\n    /// Compute x * y / z on Fixes, avoiding intermediate overflow\n    /// @dev Only use if you need to avoid overflow; costlier than x * y / z\n    /// @return x * y / z\n    // as-ints: x * y / z\n    function mulDiv(\n        uint192 x,\n        uint192 y,\n        uint192 z,\n        RoundingMode rounding\n    ) internal pure returns (uint192) {\n        return _safeWrap(mulDiv256(x, y, z, rounding));\n    }\n\n    // === safe*() ===\n\n    /// Multiply two fixes, rounding up to FIX_MAX and down to 0\n    /// @param a First param to multiply\n    /// @param b Second param to multiply\n    function safeMul(\n        uint192 a,\n        uint192 b,\n        RoundingMode rounding\n    ) internal pure returns (uint192) {\n        // untestable:\n        //      a will never = 0 here because of the check in _price()\n        if (a == 0 || b == 0) return 0;\n        // untestable:\n        //      a = FIX_MAX iff b = 0\n        if (a == FIX_MAX || b == FIX_MAX) return FIX_MAX;\n\n        // return FIX_MAX instead of throwing overflow errors.\n        unchecked {\n            // p and mul *are* Fix values, so have 18 decimals (D18)\n            uint256 rawDelta = uint256(b) * a; // {D36} = {D18} * {D18}\n            // if we overflowed, then return FIX_MAX\n            if (rawDelta / b != a) return FIX_MAX;\n            uint256 shiftDelta = rawDelta;\n\n            // add in rounding\n            if (rounding == RoundingMode.ROUND) shiftDelta += (FIX_ONE / 2);\n            else if (rounding == RoundingMode.CEIL) shiftDelta += FIX_ONE - 1;\n\n            // untestable (here there be dragons):\n            // (below explanation is for the ROUND case, but it extends to the FLOOR/CEIL too)\n            //          A)  shiftDelta = rawDelta + (FIX_ONE / 2)\n            //      shiftDelta overflows if:\n            //          B)  shiftDelta = MAX_UINT256 - FIX_ONE/2 + 1\n            //              rawDelta + (FIX_ONE/2) = MAX_UINT256 - FIX_ONE/2 + 1\n            //              b * a = MAX_UINT256 - FIX_ONE + 1\n            //      therefore shiftDelta overflows if:\n            //          C)  b = (MAX_UINT256 - FIX_ONE + 1) / a\n            //      MAX_UINT256 ~= 1e77 , FIX_MAX ~= 6e57 (6e20 difference in magnitude)\n            //      a <= 1e21 (MAX_TARGET_AMT)\n            //      a must be between 1e19 & 1e20 in order for b in (C) to be uint192,\n            //      but a would have to be < 1e18 in order for (A) to overflow\n            if (shiftDelta < rawDelta) return FIX_MAX;\n\n            // return FIX_MAX if return result would truncate\n            if (shiftDelta / FIX_ONE > FIX_MAX) return FIX_MAX;\n\n            // return _div(rawDelta, FIX_ONE, rounding)\n            return uint192(shiftDelta / FIX_ONE); // {D18} = {D36} / {D18}\n        }\n    }\n\n    /// Divide two fixes, rounding up to FIX_MAX and down to 0\n    /// @param a Numerator\n    /// @param b Denominator\n    function safeDiv(\n        uint192 a,\n        uint192 b,\n        RoundingMode rounding\n    ) internal pure returns (uint192) {\n        if (a == 0) return 0;\n        if (b == 0) return FIX_MAX;\n\n        uint256 raw = _divrnd(FIX_ONE_256 * a, uint256(b), rounding);\n        if (raw >= FIX_MAX) return FIX_MAX;\n        return uint192(raw); // don't need _safeWrap\n    }\n\n    /// Multiplies two fixes and divide by a third\n    /// @param a First to multiply\n    /// @param b Second to multiply\n    /// @param c Denominator\n    function safeMulDiv(\n        uint192 a,\n        uint192 b,\n        uint192 c,\n        RoundingMode rounding\n    ) internal pure returns (uint192 result) {\n        if (a == 0 || b == 0) return 0;\n        if (a == FIX_MAX || b == FIX_MAX || c == 0) return FIX_MAX;\n\n        uint256 result_256;\n        unchecked {\n            (uint256 hi, uint256 lo) = fullMul(a, b);\n            if (hi >= c) return FIX_MAX;\n            uint256 mm = mulmod(a, b, c);\n            if (mm > lo) hi -= 1;\n            lo -= mm;\n            uint256 pow2 = c & (0 - c);\n\n            uint256 c_256 = uint256(c);\n            // Warning: Should not access c below this line\n\n            c_256 /= pow2;\n            lo /= pow2;\n            lo += hi * ((0 - pow2) / pow2 + 1);\n            uint256 r = 1;\n            r *= 2 - c_256 * r;\n            r *= 2 - c_256 * r;\n            r *= 2 - c_256 * r;\n            r *= 2 - c_256 * r;\n            r *= 2 - c_256 * r;\n            r *= 2 - c_256 * r;\n            r *= 2 - c_256 * r;\n            r *= 2 - c_256 * r;\n            result_256 = lo * r;\n\n            // Apply rounding\n            if (rounding == CEIL) {\n                if (mm != 0) result_256 += 1;\n            } else if (rounding == ROUND) {\n                if (mm > ((c_256 - 1) / 2)) result_256 += 1;\n            }\n        }\n\n        if (result_256 >= FIX_MAX) return FIX_MAX;\n        return uint192(result_256);\n    }\n}\n\n// ================ a couple pure-uint helpers================\n// as-ints comments are omitted here, because they're the same as @return statements, because\n// these are all pure uint functions\n\n/// Return (x*y/z), avoiding intermediate overflow.\n//  Adapted from sources:\n//    https://medium.com/coinmonks/4db014e080b1, https://medium.com/wicketh/afa55870a65\n//    and quite a few of the other excellent \"Mathemagic\" posts from https://medium.com/wicketh\n/// @dev Only use if you need to avoid overflow; costlier than x * y / z\n/// @return result x * y / z\nfunction mulDiv256(\n    uint256 x,\n    uint256 y,\n    uint256 z\n) pure returns (uint256 result) {\n    unchecked {\n        (uint256 hi, uint256 lo) = fullMul(x, y);\n        if (hi >= z) revert UIntOutOfBounds();\n        uint256 mm = mulmod(x, y, z);\n        if (mm > lo) hi -= 1;\n        lo -= mm;\n        uint256 pow2 = z & (0 - z);\n        z /= pow2;\n        lo /= pow2;\n        lo += hi * ((0 - pow2) / pow2 + 1);\n        uint256 r = 1;\n        r *= 2 - z * r;\n        r *= 2 - z * r;\n        r *= 2 - z * r;\n        r *= 2 - z * r;\n        r *= 2 - z * r;\n        r *= 2 - z * r;\n        r *= 2 - z * r;\n        r *= 2 - z * r;\n        result = lo * r;\n    }\n}\n\n/// Return (x*y/z), avoiding intermediate overflow.\n/// @dev Only use if you need to avoid overflow; costlier than x * y / z\n/// @return x * y / z\nfunction mulDiv256(\n    uint256 x,\n    uint256 y,\n    uint256 z,\n    RoundingMode rounding\n) pure returns (uint256) {\n    uint256 result = mulDiv256(x, y, z);\n    if (rounding == FLOOR) return result;\n\n    uint256 mm = mulmod(x, y, z);\n    if (rounding == CEIL) {\n        if (mm != 0) result += 1;\n    } else {\n        if (mm > ((z - 1) / 2)) result += 1; // z should be z-1\n    }\n    return result;\n}\n\n/// Return (x*y) as a \"virtual uint512\" (lo, hi), representing (hi*2**256 + lo)\n///   Adapted from sources:\n///   https://medium.com/wicketh/27650fec525d, https://medium.com/coinmonks/4db014e080b1\n/// @dev Intended to be internal to this library\n/// @return hi (hi, lo) satisfies  hi*(2**256) + lo == x * y\n/// @return lo (paired with `hi`)\nfunction fullMul(uint256 x, uint256 y) pure returns (uint256 hi, uint256 lo) {\n    unchecked {\n        uint256 mm = mulmod(x, y, uint256(0) - uint256(1));\n        lo = x * y;\n        hi = mm - lo;\n        if (mm < lo) hi -= 1;\n    }\n}\n\n// =============== from prbMath at commit 28055f6cd9a2367f9ad7ab6c8e01c9ac8e9acc61 ===============\n/// @notice Calculates the square root of x using the Babylonian method.\n///\n/// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\n///\n/// Notes:\n/// - If x is not a perfect square, the result is rounded down.\n/// - Credits to OpenZeppelin for the explanations in comments below.\n///\n/// @param x The uint256 number for which to calculate the square root.\n/// @return result The result as a uint256.\nfunction sqrt256(uint256 x) pure returns (uint256 result) {\n    if (x == 0) {\n        return 0;\n    }\n\n    // For our first guess, we calculate the biggest power of 2 which is smaller than the square root of x.\n    //\n    // We know that the \"msb\" (most significant bit) of x is a power of 2 such that we have:\n    //\n    // $$\n    // msb(x) <= x <= 2*msb(x)$\n    // $$\n    //\n    // We write $msb(x)$ as $2^k$, and we get:\n    //\n    // $$\n    // k = log_2(x)\n    // $$\n    //\n    // Thus, we can write the initial inequality as:\n    //\n    // $$\n    // 2^{log_2(x)} <= x <= 2*2^{log_2(x)+1} \\\\\n    // sqrt(2^k) <= sqrt(x) < sqrt(2^{k+1}) \\\\\n    // 2^{k/2} <= sqrt(x) < 2^{(k+1)/2} <= 2^{(k/2)+1}\n    // $$\n    //\n    // Consequently, $2^{log_2(x) /2} is a good first approximation of sqrt(x) with at least one correct bit.\n    uint256 xAux = uint256(x);\n    result = 1;\n    if (xAux >= 2**128) {\n        xAux >>= 128;\n        result <<= 64;\n    }\n    if (xAux >= 2**64) {\n        xAux >>= 64;\n        result <<= 32;\n    }\n    if (xAux >= 2**32) {\n        xAux >>= 32;\n        result <<= 16;\n    }\n    if (xAux >= 2**16) {\n        xAux >>= 16;\n        result <<= 8;\n    }\n    if (xAux >= 2**8) {\n        xAux >>= 8;\n        result <<= 4;\n    }\n    if (xAux >= 2**4) {\n        xAux >>= 4;\n        result <<= 2;\n    }\n    if (xAux >= 2**2) {\n        result <<= 1;\n    }\n\n    // At this point, `result` is an estimation with at least one bit of precision. We know the true value has at\n    // most 128 bits, since it is the square root of a uint256. Newton's method converges quadratically (precision\n    // doubles at every iteration). We thus need at most 7 iteration to turn our partial result with one bit of\n    // precision into the expected uint128 result.\n    unchecked {\n        result = (result + x / result) >> 1;\n        result = (result + x / result) >> 1;\n        result = (result + x / result) >> 1;\n        result = (result + x / result) >> 1;\n        result = (result + x / result) >> 1;\n        result = (result + x / result) >> 1;\n        result = (result + x / result) >> 1;\n\n        // If x is not a perfect square, round the result toward zero.\n        uint256 roundedResult = x / result;\n        if (result >= roundedResult) {\n            result = roundedResult;\n        }\n    }\n}\n// slither-disable-end divide-before-multiply\n"
      },
      "contracts/libraries/Throttle.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"./Fixed.sol\";\n\nuint48 constant ONE_HOUR = 3600; // {seconds/hour}\n\n/**\n * @title ThrottleLib\n * A library that implements a usage throttle that can be used to ensure net issuance\n * or net redemption for an RToken never exceeds some bounds per unit time (hour).\n *\n * It is expected for the RToken to use this library with two instances, one for issuance\n * and one for redemption. Issuance causes the available redemption amount to increase, and\n * visa versa.\n */\nlibrary ThrottleLib {\n    using FixLib for uint192;\n\n    struct Params {\n        uint256 amtRate; // {qRTok/hour} a quantity of RToken hourly; cannot be 0\n        uint192 pctRate; // {1/hour} a fraction of RToken hourly; can be 0\n    }\n\n    struct Throttle {\n        // === Gov params ===\n        Params params;\n        // === Cache ===\n        uint48 lastTimestamp; // {seconds}\n        uint256 lastAvailable; // {qRTok}\n    }\n\n    /// Reverts if usage amount exceeds available amount\n    /// @param supply {qRTok} Total RToken supply beforehand\n    /// @param amount {qRTok} Amount of RToken to use. Should be negative for the issuance\n    ///   throttle during redemption and for the redemption throttle during issuance.\n    function useAvailable(\n        Throttle storage throttle,\n        uint256 supply,\n        int256 amount\n    ) internal {\n        // untestable: amtRate will always be > 0 due to previous validations\n        if (throttle.params.amtRate == 0 && throttle.params.pctRate == 0) return;\n\n        // Calculate hourly limit\n        uint256 limit = hourlyLimit(throttle, supply); // {qRTok}\n\n        // Calculate available amount before supply change\n        uint256 available = currentlyAvailable(throttle, limit);\n\n        // Update throttle.timestamp if available amount changed or at limit\n        if (available != throttle.lastAvailable || available == limit) {\n            throttle.lastTimestamp = uint48(block.timestamp);\n        }\n\n        // Update throttle.lastAvailable\n        if (amount > 0) {\n            require(uint256(amount) <= available, \"supply change throttled\");\n            available -= uint256(amount);\n            // untestable: the final else statement, amount will never be 0\n        } else if (amount < 0) {\n            available += uint256(-amount);\n        }\n        throttle.lastAvailable = available;\n    }\n\n    /// @param limit {qRTok/hour} The hourly limit\n    /// @return available {qRTok} Amount currently available for consumption\n    function currentlyAvailable(Throttle storage throttle, uint256 limit)\n        internal\n        view\n        returns (uint256 available)\n    {\n        uint48 delta = uint48(block.timestamp) - throttle.lastTimestamp; // {seconds}\n        available = throttle.lastAvailable + (limit * delta) / ONE_HOUR;\n        if (available > limit) available = limit;\n    }\n\n    /// @return limit {qRTok} The hourly limit\n    function hourlyLimit(Throttle storage throttle, uint256 supply)\n        internal\n        view\n        returns (uint256 limit)\n    {\n        Params storage params = throttle.params;\n\n        // Calculate hourly limit as: max(params.amtRate, supply.mul(params.pctRate))\n        limit = (supply * params.pctRate) / FIX_ONE_256; // {qRTok}\n        if (params.amtRate > limit) limit = params.amtRate;\n    }\n}\n"
      },
      "contracts/plugins/assets/AppreciatingFiatCollateral.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"../../interfaces/IAsset.sol\";\nimport \"../../libraries/Fixed.sol\";\nimport \"./FiatCollateral.sol\";\nimport \"./Asset.sol\";\nimport \"./OracleLib.sol\";\n\n/**\n * @title AppreciatingFiatCollateral\n * Collateral that may need revenue hiding to become truly \"up only\"\n *\n * For: {tok} != {ref}, {ref} != {target}, {target} == {UoA}\n * Inheritors _must_ implement underlyingRefPerTok()\n * Can be easily extended by (optionally) re-implementing:\n *   - tryPrice()\n *   - refPerTok()\n *   - targetPerRef()\n *   - claimRewards()\n * Should not have to re-implement any other methods.\n * Should also set `oracleTimeout` in constructor if adding a new oracle source with timeout.\n *\n * Can intentionally disable default checks by setting config.defaultThreshold to 0\n * Can intentionally do no revenue hiding by setting revenueHiding to 0\n */\nabstract contract AppreciatingFiatCollateral is FiatCollateral {\n    using FixLib for uint192;\n    using OracleLib for AggregatorV3Interface;\n\n    // revenueShowing = FIX_ONE.minus(revenueHiding)\n    uint192 public immutable revenueShowing; // {1} The maximum fraction of refPerTok to show\n\n    // does not become nonzero until after first refresh()\n    uint192 internal exposedReferencePrice; // {ref/tok} max ref price observed, sub revenue hiding\n\n    /// @param config.chainlinkFeed Feed units: {UoA/ref}\n    /// @param revenueHiding {1} A value like 1e-6 that represents the maximum refPerTok to hide\n    constructor(CollateralConfig memory config, uint192 revenueHiding) FiatCollateral(config) {\n        require(revenueHiding < FIX_ONE, \"revenueHiding out of range\");\n        revenueShowing = FIX_ONE.minus(revenueHiding);\n    }\n\n    /// Can revert, used by other contract functions in order to catch errors\n    /// Should not return FIX_MAX for low\n    /// Should only return FIX_MAX for high if low is 0\n    /// @dev Override this when pricing is more complicated than just a single oracle\n    /// @return low {UoA/tok} The low price estimate\n    /// @return high {UoA/tok} The high price estimate\n    /// @return pegPrice {target/ref} The actual price observed in the peg\n    function tryPrice()\n        external\n        view\n        virtual\n        override\n        returns (\n            uint192 low,\n            uint192 high,\n            uint192 pegPrice\n        )\n    {\n        // {target/ref} = {UoA/ref} / {UoA/target} (1)\n        pegPrice = chainlinkFeed.price(oracleTimeout);\n\n        // {UoA/tok} = {target/ref} * {ref/tok} * {UoA/target} (1)\n        uint192 p = pegPrice.mul(underlyingRefPerTok());\n        uint192 err = p.mul(oracleError, CEIL);\n\n        low = p - err;\n        high = p + err;\n        // assert(low <= high); obviously true just by inspection\n    }\n\n    /// Should not revert\n    /// Refresh exchange rates and update default status.\n    /// @dev Should not need to override: can handle collateral with variable refPerTok()\n    function refresh() public virtual override {\n        CollateralStatus oldStatus = status();\n\n        // Check for hard default\n        // must happen before tryPrice() call since `refPerTok()` returns a stored value\n\n        // revenue hiding: do not DISABLE if drawdown is small\n        try this.underlyingRefPerTok() returns (uint192 underlyingRefPerTok_) {\n            // {ref/tok} = {ref/tok} * {1}\n            uint192 hiddenReferencePrice = underlyingRefPerTok_.mul(revenueShowing);\n\n            // uint192(<) is equivalent to Fix.lt\n            if (underlyingRefPerTok_ < exposedReferencePrice) {\n                exposedReferencePrice = underlyingRefPerTok_;\n                markStatus(CollateralStatus.DISABLED);\n            } else if (hiddenReferencePrice > exposedReferencePrice) {\n                exposedReferencePrice = hiddenReferencePrice;\n            }\n\n            // Check for soft default + save prices\n            try this.tryPrice() returns (uint192 low, uint192 high, uint192 pegPrice) {\n                // {UoA/tok}, {UoA/tok}, {target/ref}\n                // (0, 0) is a valid price; (0, FIX_MAX) is unpriced\n\n                // Save prices if priced\n                if (high != FIX_MAX) {\n                    savedLowPrice = low;\n                    savedHighPrice = high;\n                    lastSave = uint48(block.timestamp);\n                } else {\n                    // must be unpriced\n                    assert(low == 0);\n                }\n\n                // If the price is below the default-threshold price, default eventually\n                // uint192(+/-) is the same as Fix.plus/minus\n                if (pegPrice < pegBottom || pegPrice > pegTop || low == 0) {\n                    markStatus(CollateralStatus.IFFY);\n                } else {\n                    markStatus(CollateralStatus.SOUND);\n                }\n            } catch (bytes memory errData) {\n                // see: docs/solidity-style.md#Catching-Empty-Data\n                if (errData.length == 0) revert(); // solhint-disable-line reason-string\n                markStatus(CollateralStatus.IFFY);\n            }\n        } catch (bytes memory errData) {\n            // see: docs/solidity-style.md#Catching-Empty-Data\n            if (errData.length == 0) revert(); // solhint-disable-line reason-string\n            markStatus(CollateralStatus.DISABLED);\n        }\n\n        CollateralStatus newStatus = status();\n        if (oldStatus != newStatus) {\n            emit CollateralStatusChanged(oldStatus, newStatus);\n        }\n    }\n\n    /// @return {ref/tok} Exposed quantity of whole reference units per whole collateral tokens\n    function refPerTok() public view virtual override returns (uint192) {\n        return exposedReferencePrice;\n    }\n\n    /// Should update in inheritors\n    /// @return {ref/tok} Actual quantity of whole reference units per whole collateral tokens\n    function underlyingRefPerTok() public view virtual returns (uint192);\n}\n"
      },
      "contracts/plugins/assets/Asset.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"../../interfaces/IAsset.sol\";\nimport \"./OracleLib.sol\";\nimport \"./VersionedAsset.sol\";\n\ncontract Asset is IAsset, VersionedAsset {\n    using FixLib for uint192;\n    using OracleLib for AggregatorV3Interface;\n\n    uint192 public constant MAX_HIGH_PRICE_BUFFER = 2 * FIX_ONE; // {UoA/tok} 200%\n\n    AggregatorV3Interface public immutable chainlinkFeed; // {UoA/tok}\n\n    IERC20Metadata public immutable erc20;\n\n    uint8 public immutable erc20Decimals;\n\n    uint192 public immutable override maxTradeVolume; // {UoA}\n\n    uint48 public immutable oracleTimeout; // {s}\n\n    uint192 public immutable oracleError; // {1}\n\n    // === Lot price ===\n\n    uint48 public immutable priceTimeout; // {s} The period over which `savedHighPrice` decays to 0\n\n    uint192 public savedLowPrice; // {UoA/tok} The low price of the token during the last update\n\n    uint48 public lastSave; // {s} The timestamp when prices were last saved\n\n    uint192 public savedHighPrice; // {UoA/tok} The high price of the token during the last update\n\n    uint48 public maxOracleTimeout; // {s} maximum of all the oracle timeouts\n\n    /// @param priceTimeout_ {s} The number of seconds over which savedHighPrice decays to 0\n    /// @param chainlinkFeed_ Feed units: {UoA/tok}\n    /// @param oracleError_ {1} The % the oracle feed can be off by\n    /// @param maxTradeVolume_ {UoA} The max trade volume, in UoA\n    /// @param oracleTimeout_ {s} The number of seconds until the chainlinkFeed becomes invalid\n    constructor(\n        uint48 priceTimeout_,\n        AggregatorV3Interface chainlinkFeed_,\n        uint192 oracleError_,\n        IERC20Metadata erc20_,\n        uint192 maxTradeVolume_,\n        uint48 oracleTimeout_\n    ) {\n        require(priceTimeout_ != 0, \"price timeout zero\");\n        require(address(chainlinkFeed_) != address(0), \"missing chainlink feed\");\n        require(oracleError_ != 0 && oracleError_ < FIX_ONE, \"oracle error out of range\");\n        require(address(erc20_) != address(0), \"missing erc20\");\n        require(maxTradeVolume_ != 0, \"invalid max trade volume\");\n        require(oracleTimeout_ != 0, \"oracleTimeout zero\");\n        priceTimeout = priceTimeout_;\n        chainlinkFeed = chainlinkFeed_;\n        oracleError = oracleError_;\n        erc20 = erc20_;\n        erc20Decimals = erc20.decimals();\n        maxTradeVolume = maxTradeVolume_;\n        oracleTimeout = oracleTimeout_;\n        maxOracleTimeout = oracleTimeout_; // must be kept current by each child class\n    }\n\n    /// Can revert, used by other contract functions in order to catch errors\n    /// Should not return FIX_MAX for low\n    /// Should only return FIX_MAX for high if low is 0\n    /// @dev The third (unused) variable is only here for compatibility with Collateral\n    /// @return low {UoA/tok} The low price estimate\n    /// @return high {UoA/tok} The high price estimate\n    function tryPrice()\n        external\n        view\n        virtual\n        returns (\n            uint192 low,\n            uint192 high,\n            uint192\n        )\n    {\n        uint192 p = chainlinkFeed.price(oracleTimeout); // {UoA/tok}\n        uint192 err = p.mul(oracleError, CEIL);\n        // assert(low <= high); obviously true just by inspection\n        return (p - err, p + err, 0);\n    }\n\n    /// Should not revert\n    /// Refresh saved prices\n    function refresh() public virtual override {\n        try this.tryPrice() returns (uint192 low, uint192 high, uint192) {\n            // {UoA/tok}, {UoA/tok}\n            // (0, 0) is a valid price; (0, FIX_MAX) is unpriced\n\n            // Save prices if priced\n            if (high != FIX_MAX) {\n                savedLowPrice = low;\n                savedHighPrice = high;\n                lastSave = uint48(block.timestamp);\n            } else {\n                // must be unpriced\n                assert(low == 0);\n            }\n        } catch (bytes memory errData) {\n            // see: docs/solidity-style.md#Catching-Empty-Data\n            if (errData.length == 0) revert(); // solhint-disable-line reason-string\n        }\n    }\n\n    /// Should not revert\n    /// low should be nonzero if the asset could be worth selling\n    /// @dev Should be general enough to not need to be overridden\n    /// @return _low {UoA/tok} The lower end of the price estimate\n    /// @return _high {UoA/tok} The upper end of the price estimate\n    /// @notice If the price feed is broken, _low will decay downwards and _high will decay upwards\n    ///     If tryPrice() is broken for `oracleTimeout + priceTimeout + ORACLE_TIMEOUT_BUFFER` ,\n    ///     _low will be 0 and _high will be FIX_MAX.\n    ///     Because the price decay begins at `oracleTimeout + ORACLE_TIMEOUT_BUFFER` seconds,\n    ///     the price feed can be broken for up to `2 * oracleTimeout` seconds without\n    ///     affecting the price estimate.  This could happen if the Asset is refreshed just before\n    ///     the maxOracleTimeout is reached, forcing a second period to pass before\n    ///     the price begins to decay.\n    function price() public view virtual returns (uint192 _low, uint192 _high) {\n        try this.tryPrice() returns (uint192 low, uint192 high, uint192) {\n            // if the price feed is still functioning, use that\n            _low = low;\n            _high = high;\n        } catch (bytes memory errData) {\n            // see: docs/solidity-style.md#Catching-Empty-Data\n            if (errData.length == 0) revert(); // solhint-disable-line reason-string\n\n            // if the price feed is broken, decay _low downwards and _high upwards\n\n            uint48 delta = uint48(block.timestamp) - lastSave; // {s}\n            uint48 decayDelay = maxOracleTimeout + OracleLib.ORACLE_TIMEOUT_BUFFER;\n            if (delta <= decayDelay) {\n                // use saved prices for at least the decayDelay\n                _low = savedLowPrice;\n                _high = savedHighPrice;\n            } else if (delta >= decayDelay + priceTimeout) {\n                // unpriced after a full timeout\n                return (0, FIX_MAX);\n            } else {\n                // decayDelay <= delta <= decayDelay + priceTimeout\n\n                // Decay _high upwards to 3x savedHighPrice\n                // {UoA/tok} = {UoA/tok} * {1}\n                _high = savedHighPrice.safeMul(\n                    FIX_ONE + MAX_HIGH_PRICE_BUFFER.muluDivu(delta - decayDelay, priceTimeout),\n                    ROUND\n                ); // during overflow should not revert\n\n                // if _high is FIX_MAX, leave at UNPRICED\n                if (_high != FIX_MAX) {\n                    // Decay _low downwards from savedLowPrice to 0\n                    // {UoA/tok} = {UoA/tok} * {1}\n                    _low = savedLowPrice.muluDivu(decayDelay + priceTimeout - delta, priceTimeout);\n                    // during overflow should revert since a FIX_MAX _low breaks everything\n                }\n            }\n        }\n        assert(_low <= _high);\n    }\n\n    /// Should not revert\n    /// lotLow should be nonzero when the asset might be worth selling\n    /// @dev Deprecated. Phased out in 3.1.0, but left on interface for backwards compatibility\n    /// @return lotLow {UoA/tok} The lower end of the lot price estimate\n    /// @return lotHigh {UoA/tok} The upper end of the lot price estimate\n    function lotPrice() external view virtual returns (uint192 lotLow, uint192 lotHigh) {\n        return price();\n    }\n\n    /// @return {tok} The balance of the ERC20 in whole tokens\n    function bal(address account) external view virtual returns (uint192) {\n        return shiftl_toFix(erc20.balanceOf(account), -int8(erc20Decimals));\n    }\n\n    /// @return If the asset is an instance of ICollateral or not\n    function isCollateral() external pure virtual returns (bool) {\n        return false;\n    }\n\n    // solhint-disable no-empty-blocks\n\n    /// Claim rewards earned by holding a balance of the ERC20 token\n    /// @custom:delegate-call\n    function claimRewards() external virtual {}\n\n    // solhint-enable no-empty-blocks\n}\n"
      },
      "contracts/plugins/assets/curve/CurveStableCollateral.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport \"contracts/interfaces/IAsset.sol\";\nimport \"contracts/libraries/Fixed.sol\";\nimport \"contracts/plugins/assets/AppreciatingFiatCollateral.sol\";\nimport \"../../../interfaces/IRewardable.sol\";\nimport \"../curve/PoolTokens.sol\";\n\n/**\n * @title CurveStableCollateral\n *  This plugin contract is fully general to any number of (fiat) tokens in a Curve stable pool,\n *  whether this LP token ends up staked in Curve, Convex, Frax, or somewhere else.\n *  Each token in the pool can have between 1 and 2 oracles per each token.\n *  Stable means only like-kind pools.\n *  Works for both CurveGaugeWrapper and ConvexStakingWrapper.\n *\n * tok = ConvexStakingWrapper(stablePlainPool)\n * ref = stablePlainPool pool invariant\n * tar = USD\n * UoA = USD\n *\n * @notice Curve pools with native ETH or ERC777 should be avoided,\n *  see docs/collateral.md for information\n */\ncontract CurveStableCollateral is AppreciatingFiatCollateral, PoolTokens {\n    using OracleLib for AggregatorV3Interface;\n    using FixLib for uint192;\n\n    // I don't love hard-coding these, but I prefer it to dynamically reading from either\n    // a CurveGaugeWrapper or ConvexStakingWrapper. If we ever use this contract\n    // on something other than mainnet we'll have to change this.\n    IERC20 internal constant CRV = IERC20(0xD533a949740bb3306d119CC777fa900bA034cd52);\n    IERC20 internal constant CVX = IERC20(0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B);\n\n    /// @dev config Unused members: chainlinkFeed, oracleError, oracleTimeout\n    /// @dev config.erc20 should be a CurveGaugeWrapper or ConvexStakingWrapper\n    constructor(\n        CollateralConfig memory config,\n        uint192 revenueHiding,\n        PTConfiguration memory ptConfig\n    ) AppreciatingFiatCollateral(config, revenueHiding) PoolTokens(ptConfig) {\n        require(config.defaultThreshold != 0, \"defaultThreshold zero\");\n        maxOracleTimeout = uint48(Math.max(maxOracleTimeout, maxPoolOracleTimeout()));\n    }\n\n    /// Can revert, used by other contract functions in order to catch errors\n    /// Should not return FIX_MAX for low\n    /// Should only return FIX_MAX for high if low is 0\n    /// @dev Override this when pricing is more complicated than just a single pool\n    /// @return low {UoA/tok} The low price estimate\n    /// @return high {UoA/tok} The high price estimate\n    /// @return {target/ref} Unused. Always 0\n    function tryPrice()\n        external\n        view\n        virtual\n        override\n        returns (\n            uint192 low,\n            uint192 high,\n            uint192\n        )\n    {\n        // Assumption: the pool is balanced\n        //\n        // This pricing method returns a MINIMUM when the pool is balanced.\n        // It IS possible to interact with the protocol within a sandwich to manipulate\n        // LP token price upwards.\n        //\n        // However:\n        //    - Lots of manipulation is required;\n        //        (StableSwap pools are not price sensitive until the edge of the curve)\n        //    - The DutchTrade pricing curve accounts for small/medium amounts of manipulation\n        //    - The manipulator is under competition in auctions, so cannot guarantee they\n        //        are the beneficiary of the manipulation.\n        //\n        // To be more MEV-resistant requires not using spot balances at all, which means one-of:\n        //   1. A moving average metric (unavailable in the cases we care about)\n        //   2. Mapping oracle prices to expected pool balances using precise knowledge about\n        //      the shape of the trading curve. (maybe we can do this in the future)\n\n        // {UoA}\n        (uint192 aumLow, uint192 aumHigh) = totalBalancesValue();\n\n        // {tok}\n        uint192 supply = shiftl_toFix(lpToken.totalSupply(), -int8(lpToken.decimals()));\n        // We can always assume that the total supply is non-zero\n\n        // {UoA/tok} = {UoA} / {tok}\n        low = aumLow.div(supply, FLOOR);\n        high = aumHigh.div(supply, CEIL);\n        assert(low <= high); // not obviously true just by inspection\n\n        return (low, high, 0);\n    }\n\n    /// Should not revert\n    /// Refresh exchange rates and update default status.\n    /// Have to override to add custom default checks\n    function refresh() public virtual override {\n        CollateralStatus oldStatus = status();\n\n        // Check for hard default\n        // must happen before tryPrice() call since `refPerTok()` returns a stored value\n\n        // revenue hiding: do not DISABLE if drawdown is small\n        try this.underlyingRefPerTok() returns (uint192 underlyingRefPerTok_) {\n            // {ref/tok} = {ref/tok} * {1}\n            uint192 hiddenReferencePrice = underlyingRefPerTok_.mul(revenueShowing);\n\n            // uint192(<) is equivalent to Fix.lt\n            if (underlyingRefPerTok_ < exposedReferencePrice) {\n                exposedReferencePrice = underlyingRefPerTok_;\n                markStatus(CollateralStatus.DISABLED);\n            } else if (hiddenReferencePrice > exposedReferencePrice) {\n                exposedReferencePrice = hiddenReferencePrice;\n            }\n\n            // Check for soft default + save prices\n            try this.tryPrice() returns (uint192 low, uint192 high, uint192) {\n                // {UoA/tok}, {UoA/tok}, {UoA/tok}\n                // (0, 0) is a valid price; (0, FIX_MAX) is unpriced\n\n                // Save prices if priced\n                if (high != FIX_MAX) {\n                    savedLowPrice = low;\n                    savedHighPrice = high;\n                    lastSave = uint48(block.timestamp);\n                } else {\n                    // must be unpriced\n                    // untested:\n                    //      validated in other plugins, cost to test here is high\n                    assert(low == 0);\n                }\n\n                // If the price is below the default-threshold price, default eventually\n                // uint192(+/-) is the same as Fix.plus/minus\n                if (low == 0 || _anyDepeggedInPool() || _anyDepeggedOutsidePool()) {\n                    markStatus(CollateralStatus.IFFY);\n                } else {\n                    markStatus(CollateralStatus.SOUND);\n                }\n            } catch (bytes memory errData) {\n                // see: docs/solidity-style.md#Catching-Empty-Data\n                if (errData.length == 0) revert(); // solhint-disable-line reason-string\n                markStatus(CollateralStatus.IFFY);\n            }\n        } catch (bytes memory errData) {\n            // see: docs/solidity-style.md#Catching-Empty-Data\n            if (errData.length == 0) revert(); // solhint-disable-line reason-string\n            markStatus(CollateralStatus.DISABLED);\n        }\n\n        CollateralStatus newStatus = status();\n        if (oldStatus != newStatus) {\n            emit CollateralStatusChanged(oldStatus, newStatus);\n        }\n    }\n\n    /// Claim rewards earned by holding a balance of the ERC20 token\n    /// @custom:delegate-call\n    function claimRewards() external virtual override(Asset, IRewardable) {\n        // Plugin can be used with either Curve or Convex wrappers\n        // Here I prefer omitting any wrapper-specific logic at the cost of an additional event\n        uint256 crvBal = CRV.balanceOf(address(this));\n        uint256 cvxBal = CVX.balanceOf(address(this));\n        IRewardable(address(erc20)).claimRewards();\n        emit RewardsClaimed(CRV, CRV.balanceOf(address(this)) - crvBal);\n        emit RewardsClaimed(CVX, CVX.balanceOf(address(this)) - cvxBal);\n    }\n\n    // === Internal ===\n\n    /// @return {ref/tok} Actual quantity of whole reference units per whole collateral tokens\n    function underlyingRefPerTok() public view virtual override returns (uint192) {\n        return _safeWrap(curvePool.get_virtual_price());\n    }\n\n    // Override this later to implement non-stable pools\n    function _anyDepeggedInPool() internal view virtual returns (bool) {\n        // Check reference token oracles\n        for (uint8 i = 0; i < nTokens; ++i) {\n            try this.tokenPrice(i) returns (uint192 low, uint192 high) {\n                // {UoA/tok} = {UoA/tok} + {UoA/tok}\n                uint192 mid = (low + high) / 2;\n\n                // If the price is below the default-threshold price, default eventually\n                // uint192(+/-) is the same as Fix.plus/minus\n                if (mid < pegBottom || mid > pegTop) return true;\n            } catch (bytes memory errData) {\n                // see: docs/solidity-style.md#Catching-Empty-Data\n                // untested:\n                //      pattern validated in other plugins, cost to test is high\n                if (errData.length == 0) revert(); // solhint-disable-line reason-string\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    // Override this in child classes to implement metapools\n    function _anyDepeggedOutsidePool() internal view virtual returns (bool) {\n        return false;\n    }\n}\n"
      },
      "contracts/plugins/assets/curve/PoolTokens.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity 0.8.19;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport \"contracts/plugins/assets/OracleLib.sol\";\nimport \"contracts/libraries/Fixed.sol\";\n\n// solhint-disable func-name-mixedcase\ninterface ICurvePool {\n    // For Curve Plain Pools and V2 Metapools\n    function coins(uint256) external view returns (address);\n\n    // Only exists in Curve Lending Pools; not used currently\n    function underlying_coins(uint256) external view returns (address);\n\n    // Only exists in V1 Curve Metapools; not used currently\n    function base_coins(uint256) external view returns (address);\n\n    function balances(uint256) external view returns (uint256);\n\n    function get_virtual_price() external view returns (uint256);\n\n    function token() external view returns (address);\n}\n\n/// Supports Curve base pools for up to 4 tokens\ncontract PoolTokens {\n    using OracleLib for AggregatorV3Interface;\n    using FixLib for uint192;\n\n    error WrongIndex(uint8 maxLength);\n    error NoToken(uint8 tokenNumber);\n\n    enum CurvePoolType {\n        Plain,\n        Lending, // not supported in this version\n        Metapool // not supported via this class. parent class handles metapool math\n    }\n\n    // === State (Immutable) ===\n\n    ICurvePool public immutable curvePool;\n    IERC20Metadata public immutable lpToken;\n    uint8 internal immutable nTokens;\n\n    IERC20Metadata internal immutable token0;\n    IERC20Metadata internal immutable token1;\n    IERC20Metadata internal immutable token2;\n    IERC20Metadata internal immutable token3;\n\n    // For each token, we maintain up to two feeds/timeouts/errors\n    // The data below would normally be a struct, but we want bytecode substitution\n\n    AggregatorV3Interface internal immutable _t0feed0;\n    AggregatorV3Interface internal immutable _t0feed1;\n    uint48 internal immutable _t0timeout0; // {s}\n    uint48 internal immutable _t0timeout1; // {s}\n    uint192 internal immutable _t0error0; // {1}\n    uint192 internal immutable _t0error1; // {1}\n\n    AggregatorV3Interface internal immutable _t1feed0;\n    AggregatorV3Interface internal immutable _t1feed1;\n    uint48 internal immutable _t1timeout0; // {s}\n    uint48 internal immutable _t1timeout1; // {s}\n    uint192 internal immutable _t1error0; // {1}\n    uint192 internal immutable _t1error1; // {1}\n\n    AggregatorV3Interface internal immutable _t2feed0;\n    AggregatorV3Interface internal immutable _t2feed1;\n    uint48 internal immutable _t2timeout0; // {s}\n    uint48 internal immutable _t2timeout1; // {s}\n    uint192 internal immutable _t2error0; // {1}\n    uint192 internal immutable _t2error1; // {1}\n\n    AggregatorV3Interface internal immutable _t3feed0;\n    AggregatorV3Interface internal immutable _t3feed1;\n    uint48 internal immutable _t3timeout0; // {s}\n    uint48 internal immutable _t3timeout1; // {s}\n    uint192 internal immutable _t3error0; // {1}\n    uint192 internal immutable _t3error1; // {1}\n\n    // === Config ===\n\n    struct PTConfiguration {\n        uint8 nTokens;\n        ICurvePool curvePool;\n        IERC20Metadata lpToken;\n        CurvePoolType poolType;\n        AggregatorV3Interface[][] feeds; // row should multiply to give {UoA/ref}; max columns is 2\n        uint48[][] oracleTimeouts; // {s} same order as feeds\n        uint192[][] oracleErrors; // {1} same order as feeds\n    }\n\n    constructor(PTConfiguration memory config) {\n        require(config.nTokens <= 4, \"up to 4 tokens max\");\n        require(maxFeedsLength(config.feeds) <= 2, \"price feeds limited to 2\");\n        require(\n            config.feeds.length == config.nTokens && minFeedsLength(config.feeds) != 0,\n            \"each token needs at least 1 price feed\"\n        );\n        require(address(config.curvePool) != address(0), \"curvePool address is zero\");\n\n        curvePool = config.curvePool;\n        nTokens = config.nTokens;\n        lpToken = config.lpToken;\n\n        // Solidity does not support immutable arrays. This is a hack to get the equivalent of\n        // an immutable array so we do not have store the token feeds in the blockchain. This is\n        // a gas optimization since it is significantly more expensive to read and write on the\n        // blockchain than it is to use embedded values in the bytecode.\n\n        // === Tokens ===\n\n        IERC20Metadata[] memory tokens = new IERC20Metadata[](nTokens);\n        for (uint8 i = 0; i < nTokens; ++i) {\n            if (config.poolType == CurvePoolType.Plain) {\n                tokens[i] = IERC20Metadata(curvePool.coins(i));\n            } else {\n                revert(\"invalid poolType\");\n            }\n        }\n\n        token0 = tokens[0];\n        token1 = tokens[1];\n        token2 = (nTokens > 2) ? tokens[2] : IERC20Metadata(address(0));\n        token3 = (nTokens > 3) ? tokens[3] : IERC20Metadata(address(0));\n\n        // === Feeds + timeouts ===\n        // I know this section at-first looks verbose and silly, but it's actually well-justified:\n        //   - immutable variables cannot be conditionally written to\n        //   - a struct or an array would not be able to be immutable\n        //   - immutable variables means values get in-lined in the bytecode\n\n        // token0\n        bool more = config.feeds[0].length != 0;\n        // untestable:\n        //     more will always be true based on previous feeds validations\n        _t0feed0 = more ? config.feeds[0][0] : AggregatorV3Interface(address(0));\n        _t0timeout0 = more && config.oracleTimeouts[0].length != 0\n            ? config.oracleTimeouts[0][0]\n            : 0;\n        _t0error0 = more && config.oracleErrors[0].length != 0 ? config.oracleErrors[0][0] : 0;\n        if (more) {\n            require(address(_t0feed0) != address(0), \"t0feed0 empty\");\n            require(_t0timeout0 != 0, \"t0timeout0 zero\");\n            require(_t0error0 < FIX_ONE, \"t0error0 too large\");\n        }\n\n        more = config.feeds[0].length > 1;\n        _t0feed1 = more ? config.feeds[0][1] : AggregatorV3Interface(address(0));\n        _t0timeout1 = more && config.oracleTimeouts[0].length > 1 ? config.oracleTimeouts[0][1] : 0;\n        _t0error1 = more && config.oracleErrors[0].length > 1 ? config.oracleErrors[0][1] : 0;\n        if (more) {\n            require(address(_t0feed1) != address(0), \"t0feed1 empty\");\n            require(_t0timeout1 != 0, \"t0timeout1 zero\");\n            require(_t0error1 < FIX_ONE, \"t0error1 too large\");\n        }\n\n        // token1\n        // untestable:\n        //     more will always be true based on previous feeds validations\n        more = config.feeds[1].length != 0;\n        _t1feed0 = more ? config.feeds[1][0] : AggregatorV3Interface(address(0));\n        _t1timeout0 = more && config.oracleTimeouts[1].length != 0\n            ? config.oracleTimeouts[1][0]\n            : 0;\n        _t1error0 = more && config.oracleErrors[1].length != 0 ? config.oracleErrors[1][0] : 0;\n        if (more) {\n            require(address(_t1feed0) != address(0), \"t1feed0 empty\");\n            require(_t1timeout0 != 0, \"t1timeout0 zero\");\n            require(_t1error0 < FIX_ONE, \"t1error0 too large\");\n        }\n\n        more = config.feeds[1].length > 1;\n        _t1feed1 = more ? config.feeds[1][1] : AggregatorV3Interface(address(0));\n        _t1timeout1 = more && config.oracleTimeouts[1].length > 1 ? config.oracleTimeouts[1][1] : 0;\n        _t1error1 = more && config.oracleErrors[1].length > 1 ? config.oracleErrors[1][1] : 0;\n        if (more) {\n            require(address(_t1feed1) != address(0), \"t1feed1 empty\");\n            require(_t1timeout1 != 0, \"t1timeout1 zero\");\n            require(_t1error1 < FIX_ONE, \"t1error1 too large\");\n        }\n\n        // token2\n        more = config.feeds.length > 2 && config.feeds[2].length != 0;\n        _t2feed0 = more ? config.feeds[2][0] : AggregatorV3Interface(address(0));\n        _t2timeout0 = more && config.oracleTimeouts[2].length != 0\n            ? config.oracleTimeouts[2][0]\n            : 0;\n        _t2error0 = more && config.oracleErrors[2].length != 0 ? config.oracleErrors[2][0] : 0;\n        if (more) {\n            require(address(_t2feed0) != address(0), \"t2feed0 empty\");\n            require(_t2timeout0 != 0, \"t2timeout0 zero\");\n            require(_t2error0 < FIX_ONE, \"t2error0 too large\");\n        }\n\n        more = config.feeds.length > 2 && config.feeds[2].length > 1;\n        _t2feed1 = more ? config.feeds[2][1] : AggregatorV3Interface(address(0));\n        _t2timeout1 = more && config.oracleTimeouts[2].length > 1 ? config.oracleTimeouts[2][1] : 0;\n        _t2error1 = more && config.oracleErrors[2].length > 1 ? config.oracleErrors[2][1] : 0;\n        if (more) {\n            require(address(_t2feed1) != address(0), \"t2feed1 empty\");\n            require(_t2timeout1 != 0, \"t2timeout1 zero\");\n            require(_t2error1 < FIX_ONE, \"t2error1 too large\");\n        }\n\n        // token3\n        more = config.feeds.length > 3 && config.feeds[3].length != 0;\n        _t3feed0 = more ? config.feeds[3][0] : AggregatorV3Interface(address(0));\n        _t3timeout0 = more && config.oracleTimeouts[3].length != 0\n            ? config.oracleTimeouts[3][0]\n            : 0;\n        _t3error0 = more && config.oracleErrors[3].length != 0 ? config.oracleErrors[3][0] : 0;\n        if (more) {\n            require(address(_t3feed0) != address(0), \"t3feed0 empty\");\n            require(_t3timeout0 != 0, \"t3timeout0 zero\");\n            require(_t3error0 < FIX_ONE, \"t3error0 too large\");\n        }\n\n        more = config.feeds.length > 3 && config.feeds[3].length > 1;\n        _t3feed1 = more ? config.feeds[3][1] : AggregatorV3Interface(address(0));\n        _t3timeout1 = more && config.oracleTimeouts[3].length > 1 ? config.oracleTimeouts[3][1] : 0;\n        _t3error1 = more && config.oracleErrors[3].length > 1 ? config.oracleErrors[3][1] : 0;\n        if (more) {\n            require(address(_t3feed1) != address(0), \"t3feed1 empty\");\n            require(_t3timeout1 != 0, \"t3timeout1 zero\");\n            require(_t3error1 < FIX_ONE, \"t3error1 too large\");\n        }\n    }\n\n    /// @dev Warning: Can revert\n    /// @param index The index of the token: 0, 1, 2, or 3\n    /// @return low {UoA/ref_index}\n    /// @return high {UoA/ref_index}\n    function tokenPrice(uint8 index) public view virtual returns (uint192 low, uint192 high) {\n        if (index >= nTokens) revert WrongIndex(nTokens - 1);\n\n        // Use only 1 feed if 2nd feed not defined\n        // otherwise: multiply feeds together, e.g; {UoA/ref} = {UoA/target} * {target/ref}\n        uint192 x;\n        uint192 y = FIX_ONE;\n        uint192 xErr; // {1}\n        uint192 yErr; // {1}\n        // if only 1 feed: `y` is FIX_ONE and `yErr` is 0\n\n        if (index == 0) {\n            x = _t0feed0.price(_t0timeout0);\n            xErr = _t0error0;\n            if (address(_t0feed1) != address(0)) {\n                y = _t0feed1.price(_t0timeout1);\n                yErr = _t0error1;\n            }\n        } else if (index == 1) {\n            x = _t1feed0.price(_t1timeout0);\n            xErr = _t1error0;\n            if (address(_t1feed1) != address(0)) {\n                y = _t1feed1.price(_t1timeout1);\n                yErr = _t1error1;\n            }\n        } else if (index == 2) {\n            x = _t2feed0.price(_t2timeout0);\n            xErr = _t2error0;\n            if (address(_t2feed1) != address(0)) {\n                y = _t2feed1.price(_t2timeout1);\n                yErr = _t2error1;\n            }\n        } else {\n            x = _t3feed0.price(_t3timeout0);\n            xErr = _t3error0;\n            if (address(_t3feed1) != address(0)) {\n                y = _t3feed1.price(_t3timeout1);\n                yErr = _t3error1;\n            }\n        }\n\n        return toRange(x, y, xErr, yErr);\n    }\n\n    // === Internal ===\n\n    /// @dev Warning: Can revert\n    /// @return low {UoA}\n    /// @return high {UoA}\n    function totalBalancesValue() internal view returns (uint192 low, uint192 high) {\n        for (uint8 i = 0; i < nTokens; ++i) {\n            IERC20Metadata token = getToken(i);\n            uint192 balance = shiftl_toFix(curvePool.balances(i), -int8(token.decimals()));\n            (uint192 lowP, uint192 highP) = tokenPrice(i);\n\n            low += balance.mul(lowP, FLOOR);\n            high += balance.mul(highP, CEIL);\n        }\n    }\n\n    /// @return [{tok}]\n    function getBalances() internal view virtual returns (uint192[] memory) {\n        uint192[] memory balances = new uint192[](nTokens);\n\n        for (uint8 i = 0; i < nTokens; ++i) {\n            IERC20Metadata token = getToken(i);\n            uint192 balance = shiftl_toFix(curvePool.balances(i), -int8(token.decimals()));\n            balances[i] = (balance);\n        }\n\n        return balances;\n    }\n\n    function maxPoolOracleTimeout() internal view virtual returns (uint48) {\n        return\n            uint48(\n                Math.max(\n                    Math.max(\n                        Math.max(_t0timeout0, _t1timeout0),\n                        Math.max(_t2timeout0, _t3timeout0)\n                    ),\n                    Math.max(Math.max(_t0timeout1, _t1timeout1), Math.max(_t2timeout1, _t3timeout1))\n                )\n            );\n    }\n\n    // === Private ===\n\n    function getToken(uint8 index) private view returns (IERC20Metadata) {\n        // untestable:\n        //      getToken is always called with a valid index\n        if (index >= nTokens) revert WrongIndex(nTokens - 1);\n        if (index == 0) return token0;\n        if (index == 1) return token1;\n        if (index == 2) return token2;\n        return token3;\n    }\n\n    function minFeedsLength(AggregatorV3Interface[][] memory feeds) private pure returns (uint8) {\n        uint8 minLength = type(uint8).max;\n        for (uint8 i = 0; i < feeds.length; ++i) {\n            minLength = uint8(Math.min(minLength, feeds[i].length));\n        }\n        return minLength;\n    }\n\n    function maxFeedsLength(AggregatorV3Interface[][] memory feeds) private pure returns (uint8) {\n        uint8 maxLength;\n        for (uint8 i = 0; i < feeds.length; ++i) {\n            maxLength = uint8(Math.max(maxLength, feeds[i].length));\n        }\n        return maxLength;\n    }\n\n    /// x and y can be any two fixes that can be multiplied\n    /// @param xErr {1} error associated with x\n    /// @param yErr {1} error associated with y\n    /// returns low and high extremes of x * y, given errors\n    function toRange(\n        uint192 x,\n        uint192 y,\n        uint192 xErr,\n        uint192 yErr\n    ) private pure returns (uint192 low, uint192 high) {\n        low = x.mul(FIX_ONE - xErr).mul(y.mul(FIX_ONE - yErr), FLOOR);\n        high = x.mul(FIX_ONE + xErr).mul(y.mul(FIX_ONE + yErr), CEIL);\n    }\n}\n"
      },
      "contracts/plugins/assets/FiatCollateral.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"../../interfaces/IAsset.sol\";\nimport \"../../libraries/Fixed.sol\";\nimport \"./Asset.sol\";\nimport \"./OracleLib.sol\";\n\nuint48 constant MAX_DELAY_UNTIL_DEFAULT = 1209600; // {s} 2 weeks\n\nstruct CollateralConfig {\n    uint48 priceTimeout; // {s} The number of seconds over which saved prices decay\n    AggregatorV3Interface chainlinkFeed; // Feed units: {target/ref}\n    uint192 oracleError; // {1} The % the oracle feed can be off by\n    IERC20Metadata erc20; // The ERC20 of the collateral token\n    uint192 maxTradeVolume; // {UoA} The max trade volume, in UoA\n    uint48 oracleTimeout; // {s} The number of seconds until a oracle value becomes invalid\n    bytes32 targetName; // The bytes32 representation of the target name\n    uint192 defaultThreshold; // {1} A value like 0.05 that represents a deviation tolerance\n    // set defaultThreshold to zero to create SelfReferentialCollateral\n    uint48 delayUntilDefault; // {s} The number of seconds an oracle can mulfunction\n}\n\n/**\n * @title FiatCollateral\n * Parent class for all collateral. Can be extended to support appreciating collateral\n *\n * For: {tok} == {ref}, {ref} != {target}, {target} == {UoA}\n * Can be easily extended by (optionally) re-implementing:\n *   - tryPrice()\n *   - refPerTok()\n *   - targetPerRef()\n *   - claimRewards()\n * If you have appreciating collateral, then you should use AppreciatingFiatCollateral or\n * override refresh() yourself.\n *\n * Can intentionally disable default checks by setting config.defaultThreshold to 0\n */\ncontract FiatCollateral is ICollateral, Asset {\n    using FixLib for uint192;\n    using OracleLib for AggregatorV3Interface;\n\n    // Default Status:\n    // _whenDefault == NEVER: no risk of default (initial value)\n    // _whenDefault > block.timestamp: delayed default may occur as soon as block.timestamp.\n    //                In this case, the asset may recover, reachiving _whenDefault == NEVER.\n    // _whenDefault <= block.timestamp: default has already happened (permanently)\n    uint48 private constant NEVER = type(uint48).max;\n    uint48 private _whenDefault = NEVER;\n\n    uint48 public immutable delayUntilDefault; // {s} e.g 86400\n\n    // targetName: The canonical name of this collateral's target unit.\n    bytes32 public immutable targetName;\n\n    uint192 public immutable pegBottom; // {target/ref} The bottom of the peg\n\n    uint192 public immutable pegTop; // {target/ref} The top of the peg\n\n    /// @param config.chainlinkFeed Feed units: {UoA/ref}\n    constructor(CollateralConfig memory config)\n        Asset(\n            config.priceTimeout,\n            config.chainlinkFeed,\n            config.oracleError,\n            config.erc20,\n            config.maxTradeVolume,\n            config.oracleTimeout\n        )\n    {\n        require(config.targetName != bytes32(0), \"targetName missing\");\n        if (config.defaultThreshold != 0) {\n            require(config.delayUntilDefault != 0, \"delayUntilDefault zero\");\n        }\n        require(config.delayUntilDefault <= 1209600, \"delayUntilDefault too long\");\n\n        // Note: This contract is designed to allow setting defaultThreshold = 0 to disable\n        // default checks. You can apply the check below to child contracts when required\n        // require(config.defaultThreshold != 0, \"defaultThreshold zero\");\n\n        targetName = config.targetName;\n        delayUntilDefault = config.delayUntilDefault;\n\n        // Cache constants\n        uint192 peg = targetPerRef(); // {target/ref}\n\n        // {target/ref} = {target/ref} * {1}\n        uint192 delta = peg.mul(config.defaultThreshold);\n        pegBottom = peg - delta;\n        pegTop = peg + delta;\n    }\n\n    /// Can revert, used by other contract functions in order to catch errors\n    /// Should not return FIX_MAX for low\n    /// Should only return FIX_MAX for high if low is 0\n    /// @dev Override this when pricing is more complicated than just a single oracle\n    /// @return low {UoA/tok} The low price estimate\n    /// @return high {UoA/tok} The high price estimate\n    /// @return pegPrice {target/ref} The actual price observed in the peg\n    function tryPrice()\n        external\n        view\n        virtual\n        override\n        returns (\n            uint192 low,\n            uint192 high,\n            uint192 pegPrice\n        )\n    {\n        // {target/ref} = {UoA/ref} / {UoA/target} (1)\n        pegPrice = chainlinkFeed.price(oracleTimeout);\n\n        // {target/ref} = {target/ref} * {1}\n        uint192 err = pegPrice.mul(oracleError, CEIL);\n\n        low = pegPrice - err;\n        high = pegPrice + err;\n        // assert(low <= high); obviously true just by inspection\n    }\n\n    /// Should not revert\n    /// Refresh exchange rates and update default status.\n    /// @dev May need to override: limited to handling collateral with refPerTok() = 1\n    function refresh() public virtual override(Asset, IAsset) {\n        CollateralStatus oldStatus = status();\n\n        // Check for soft default + save price\n        try this.tryPrice() returns (uint192 low, uint192 high, uint192 pegPrice) {\n            // {UoA/tok}, {UoA/tok}, {target/ref}\n            // (0, 0) is a valid price; (0, FIX_MAX) is unpriced\n\n            // Save prices if priced\n            if (high != FIX_MAX) {\n                savedLowPrice = low;\n                savedHighPrice = high;\n                lastSave = uint48(block.timestamp);\n            } else {\n                // must be unpriced\n                assert(low == 0);\n            }\n\n            // If the price is below the default-threshold price, default eventually\n            // uint192(+/-) is the same as Fix.plus/minus\n            if (pegPrice < pegBottom || pegPrice > pegTop || low == 0) {\n                markStatus(CollateralStatus.IFFY);\n            } else {\n                markStatus(CollateralStatus.SOUND);\n            }\n        } catch (bytes memory errData) {\n            // see: docs/solidity-style.md#Catching-Empty-Data\n            if (errData.length == 0) revert(); // solhint-disable-line reason-string\n            markStatus(CollateralStatus.IFFY);\n        }\n\n        CollateralStatus newStatus = status();\n        if (oldStatus != newStatus) {\n            emit CollateralStatusChanged(oldStatus, newStatus);\n        }\n    }\n\n    /// @return The collateral's status\n    function status() public view returns (CollateralStatus) {\n        if (_whenDefault == NEVER) {\n            return CollateralStatus.SOUND;\n        } else if (_whenDefault > block.timestamp) {\n            return CollateralStatus.IFFY;\n        } else {\n            return CollateralStatus.DISABLED;\n        }\n    }\n\n    // === Helpers for child classes ===\n\n    function markStatus(CollateralStatus status_) internal {\n        // untestable:\n        //      All calls to markStatus happen exclusively if the collateral is not defaulted\n        if (_whenDefault <= block.timestamp) return; // prevent DISABLED -> SOUND/IFFY\n\n        if (status_ == CollateralStatus.SOUND) {\n            _whenDefault = NEVER;\n        } else if (status_ == CollateralStatus.IFFY) {\n            uint256 sum = block.timestamp + uint256(delayUntilDefault);\n            // untestable:\n            //      constructor enforces max length on delayUntilDefault\n            if (sum >= NEVER) _whenDefault = NEVER;\n            else if (sum < _whenDefault) _whenDefault = uint48(sum);\n            // else: no change to _whenDefault\n            // untested:\n            //      explicit `if` to check DISABLED. else branch will never be hit\n        } else if (status_ == CollateralStatus.DISABLED) {\n            _whenDefault = uint48(block.timestamp);\n        }\n    }\n\n    function whenDefault() external view returns (uint256) {\n        return _whenDefault;\n    }\n\n    // === End child helpers ===\n\n    /// @return {ref/tok} Quantity of whole reference units per whole collateral tokens\n    function refPerTok() public view virtual returns (uint192) {\n        return FIX_ONE;\n    }\n\n    /// @return {target/ref} Quantity of whole target units per whole reference unit in the peg\n    function targetPerRef() public view virtual returns (uint192) {\n        return FIX_ONE;\n    }\n\n    /// @return If the asset is an instance of ICollateral or not\n    function isCollateral() external pure virtual override(Asset, IAsset) returns (bool) {\n        return true;\n    }\n}\n"
      },
      "contracts/plugins/assets/OracleErrors.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\n// 0x19abf40e\nerror StalePrice();\n// 0x4dfba023\nerror InvalidPrice();\n"
      },
      "contracts/plugins/assets/OracleLib.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport \"../../libraries/Fixed.sol\";\nimport \"./OracleErrors.sol\";\n\ninterface EACAggregatorProxy {\n    function aggregator() external view returns (address);\n}\n\n/// Used by asset plugins to price their collateral\nlibrary OracleLib {\n    uint48 internal constant ORACLE_TIMEOUT_BUFFER = 300; // {s} 5 minutes\n\n    /// @dev Use for nested calls that should revert when there is a problem\n    /// @param timeout The number of seconds after which oracle values should be considered stale\n    /// @return {UoA/tok}\n    function price(AggregatorV3Interface chainlinkFeed, uint48 timeout)\n        internal\n        view\n        returns (uint192)\n    {\n        try chainlinkFeed.latestRoundData() returns (\n            uint80 roundId,\n            int256 p,\n            uint256,\n            uint256 updateTime,\n            uint80 answeredInRound\n        ) {\n            if (updateTime == 0 || answeredInRound < roundId) {\n                revert StalePrice();\n            }\n\n            // Downcast is safe: uint256(-) reverts on underflow; block.timestamp assumed < 2^48\n            uint48 secondsSince = uint48(block.timestamp - updateTime);\n            if (secondsSince > timeout + ORACLE_TIMEOUT_BUFFER) revert StalePrice();\n\n            if (p <= 0) revert InvalidPrice();\n\n            // {UoA/tok}\n            return shiftl_toFix(uint256(p), -int8(chainlinkFeed.decimals()));\n        } catch (bytes memory errData) {\n            // Check if the aggregator was not set: if so, the chainlink feed has been deprecated\n            // and a _specific_ error needs to be raised in order to avoid looking like OOG\n            if (errData.length == 0) {\n                if (EACAggregatorProxy(address(chainlinkFeed)).aggregator() == address(0)) {\n                    revert StalePrice();\n                }\n                // solhint-disable-next-line reason-string\n                revert();\n            }\n\n            // Otherwise, preserve the error bytes\n            // solhint-disable-next-line no-inline-assembly\n            assembly {\n                revert(add(32, errData), mload(errData))\n            }\n        }\n    }\n}\n"
      },
      "contracts/plugins/assets/VersionedAsset.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"../../interfaces/IVersioned.sol\";\n\n// This value should be updated on each release\nstring constant ASSET_VERSION = \"3.4.0\";\n\n/**\n * @title VersionedAsset\n * @notice A mix-in to track semantic versioning uniformly across asset plugin contracts.\n */\nabstract contract VersionedAsset is IVersioned {\n    function version() public pure virtual override returns (string memory) {\n        return ASSET_VERSION;\n    }\n}\n"
      },
      "contracts/plugins/assets/yearnv2/YearnV2CurveFiatCollateral.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\nimport \"../curve/CurveStableCollateral.sol\";\n\ninterface IPricePerShareHelper {\n    /// @notice Helper function to convert shares to underlying amount with exact precision\n    /// @param vault The yToken address\n    /// @param shares {qTok}\n    /// @return {qLP Token}\n    function sharesToAmount(address vault, uint256 shares) external view returns (uint256);\n}\n\n/**\n * @title YearnV2 Curve Fiat Collateral\n * @notice Collateral plugin for a Yearn V2 Vault for a fiatcoin curve pool, eg yvCurveUSDCcrvUSD\n * tok = yvCurveUSDCcrvUSD\n * ref = crvUSDUSDC-f's underlying virtual token\n * tar = USD\n * UoA = USD\n *\n * More on the ref token: crvUSDUSDC-f has a virtual price. The ref token to measure is not the\n * balance of crvUSDUSDC-f that the LP token is redeemable for, but the balance of the virtual\n * token that underlies crvUSDUSDC-f. This virtual token is an evolving mix of USDC and crvUSD.\n *\n * Should only be used for Stable pools.\n * No rewards (handled internally by the Yearn vault).\n * Revenue hiding can be kept very small since stable curve pools should be up-only.\n */\ncontract YearnV2CurveFiatCollateral is CurveStableCollateral {\n    using FixLib for uint192;\n\n    IPricePerShareHelper public immutable pricePerShareHelper;\n\n    /// @dev config Unused members: chainlinkFeed, oracleError, oracleTimeout\n    /// @dev config.erc20 should be a RewardableERC20\n    constructor(\n        CollateralConfig memory config,\n        uint192 revenueHiding,\n        PTConfiguration memory ptConfig,\n        IPricePerShareHelper pricePerShareHelper_\n    ) CurveStableCollateral(config, revenueHiding, ptConfig) {\n        pricePerShareHelper = pricePerShareHelper_;\n    }\n\n    /// Can revert, used by other contract functions in order to catch errors\n    /// Should not return FIX_MAX for low\n    /// Should only return FIX_MAX for high if low is 0\n    /// @return low {UoA/tok} The low price estimate\n    /// @return high {UoA/tok} The high price estimate\n    /// @return {target/ref} Unused. Always 0\n    function tryPrice()\n        external\n        view\n        virtual\n        override\n        returns (\n            uint192 low,\n            uint192 high,\n            uint192\n        )\n    {\n        // {UoA}\n        (uint192 aumLow, uint192 aumHigh) = totalBalancesValue();\n\n        // {LP token}\n        uint192 supply = shiftl_toFix(lpToken.totalSupply(), -int8(lpToken.decimals()));\n        // We can always assume that the total supply is non-zero\n\n        // {UoA/LP token} = {UoA} / {LP token}\n        uint192 lpLow = aumLow.div(supply, FLOOR);\n        uint192 lpHigh = aumHigh.div(supply, CEIL);\n\n        // {LP token/tok}\n        uint192 pricePerShare = _pricePerShare();\n\n        // {UoA/tok} = {UoA/LP token} * {LP token/tok}\n        low = lpLow.mul(pricePerShare, FLOOR);\n        high = lpHigh.mul(pricePerShare, CEIL);\n\n        return (low, high, 0);\n    }\n\n    // solhint-disable no-empty-blocks\n\n    /// @custom:delegate-call\n    function claimRewards() external virtual override {\n        // No rewards to claim, everything is part of the pricePerShare\n    }\n\n    // solhint-enable no-empty-blocks\n\n    // === Internal ===\n\n    /// @return {ref/tok} Actual quantity of whole reference units per whole collateral tokens\n    function underlyingRefPerTok() public view virtual override returns (uint192) {\n        // {ref/tok} = {ref/LP token} * {LP token/tok}\n        return _safeWrap(curvePool.get_virtual_price()).mul(_pricePerShare(), FLOOR);\n    }\n\n    /// @return {LP token/tok}\n    function _pricePerShare() internal view returns (uint192) {\n        uint256 supply = erc20.totalSupply(); // {qTok}\n        uint256 amount = pricePerShareHelper.sharesToAmount(address(erc20), supply); // {qLP Token}\n\n        // yvCurve tokens always have the same number of decimals as the underlying curve LP token,\n        // so we can divide the quanta units without converting to whole units\n\n        // {LP token/tok} = {LP token} / {tok}\n        return divuu(amount, supply);\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}