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 v4.4.1 (token/ERC20/extensions/draft-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 */\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    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/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/IERC20Upgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.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(\n        address from,\n        address to,\n        uint256 amount\n    ) external returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-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 */\ninterface IERC20Permit {\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    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/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.6.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(\n        address from,\n        address to,\n        uint256 amount\n    ) external returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using Address for address;\n\n    function safeTransfer(\n        IERC20 token,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    function safeTransferFrom(\n        IERC20 token,\n        address from,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    function safeIncreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        uint256 newAllowance = token.allowance(address(this), spender) + value;\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n    }\n\n    function safeDecreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            uint256 newAllowance = oldAllowance - value;\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n        }\n    }\n\n    function safePermit(\n        IERC20Permit token,\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        uint256 nonceBefore = token.nonces(owner);\n        token.permit(owner, spender, value, deadline, v, r, s);\n        uint256 nonceAfter = token.nonces(owner);\n        require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        if (returndata.length > 0) {\n            // Return data is optional\n            require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length > 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n                /// @solidity memory-safe-assembly\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\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    /// @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    /// @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} Seconds that the lotPrice should decay over, after stale price\n    function priceTimeout() external view returns (uint48);\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"
      },
      "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:interaction\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 \"./IBroker.sol\";\nimport \"./IComponent.sol\";\nimport \"./ITrading.sol\";\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\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    // Initialization\n    function init(IMain main_, uint48 warmupPeriod_) external;\n\n    /// Set the prime basket\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[] memory erc20s, uint192[] memory 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 the basket status 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    /// @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    /// @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 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 \"./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 (lot) 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 \"./IGnosis.sol\";\nimport \"./IFurnace.sol\";\nimport \"./IDistributor.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 \"./IBroker.sol\";\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\";\nimport \"./IComponent.sol\";\nimport \"./IMain.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    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 \"../libraries/Fixed.sol\";\nimport \"../libraries/Throttle.sol\";\nimport \"./IAsset.sol\";\nimport \"./IComponent.sol\";\nimport \"./IMain.sol\";\nimport \"./IRewardable.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\";\nimport \"./IMain.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\";\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 {\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 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 \"./IAsset.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\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    /// 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"
      },
      "contracts/libraries/NetworkConfigLib.sol": {
        "content": "// SPDX-License-Identifier: BlueOak-1.0.0\npragma solidity 0.8.19;\n\n/**\n * @title NetworkConfigLib\n * @notice Provides network-specific configuration parameters\n */\nlibrary NetworkConfigLib {\n    error InvalidNetwork();\n\n    // Returns the blocktime based on the current network (e.g. 12s for Ethereum PoS)\n    // See docs/system-design.md for discussion of handling longer or shorter times\n    function blocktime() internal view returns (uint48) {\n        uint256 chainId = block.chainid;\n        // untestable:\n        //    most of the branches will be shown as uncovered, because we only run coverage\n        //    on local Ethereum PoS network (31337). Manual testing was performed.\n        if (chainId == 1 || chainId == 3 || chainId == 5 || chainId == 31337) {\n            return 12; // Ethereum PoS, Goerli, HH (tests)\n        } else if (chainId == 8453 || chainId == 84531) {\n            return 2; // Base, Base Goerli\n        } else {\n            revert InvalidNetwork();\n        }\n    }\n}\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 greater > 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/trading/DutchTrade.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/token/ERC20/utils/SafeERC20.sol\";\nimport \"../../libraries/Fixed.sol\";\nimport \"../../libraries/NetworkConfigLib.sol\";\nimport \"../../interfaces/IAsset.sol\";\nimport \"../../interfaces/IBroker.sol\";\nimport \"../../interfaces/ITrade.sol\";\n\n// A dutch auction in 4 parts:\n//   1.  0% -  20%: Geometric decay from 1000x the bestPrice to ~1.5x the bestPrice\n//   2. 20% -  45%: Linear decay from ~1.5x the bestPrice to the bestPrice\n//   3. 45% -  95%: Linear decay from the bestPrice to the worstPrice\n//   4. 95% - 100%: Constant at the worstPrice\n//\n// For a trade between 2 assets with 1% oracleError:\n//   A 30-minute auction on a chain with a 12-second blocktime has a ~20% price drop per block\n//   during the 1st period, ~0.8% during the 2nd period, and ~0.065% during the 3rd period.\n//\n//   30-minutes is the recommended length of auction for a chain with 12-second blocktimes.\n//   6 minutes, 7.5 minutes, 15 minutes, 1.5 minutes for each pariod respectively.\n//\n//   Longer and shorter times can be used as well. The pricing method does not degrade\n//   beyond the degree to which less overall blocktime means less overall precision.\n\nuint192 constant FIVE_PERCENT = 5e16; // {1} 0.05\nuint192 constant TWENTY_PERCENT = 20e16; // {1} 0.2\nuint192 constant TWENTY_FIVE_PERCENT = 25e16; // {1} 0.25\nuint192 constant FORTY_FIVE_PERCENT = 45e16; // {1} 0.45\nuint192 constant FIFTY_PERCENT = 50e16; // {1} 0.5\nuint192 constant NINETY_FIVE_PERCENT = 95e16; // {1} 0.95\n\nuint192 constant MAX_EXP = 6502287e18; // {1} (1000000/999999)^6502287 = ~666.6667\nuint192 constant BASE = 999999e12; // {1} (999999/1000000)\nuint192 constant ONE_POINT_FIVE = 150e16; // {1} 1.5\n\n/**\n * @title DutchTrade\n * @notice Implements a wholesale dutch auction via a 4-piecewise falling-price mechansim.\n *   The overall idea is to handle 4 cases:\n *     1. Price manipulation of the exchange rate up to 1000x (eg: via a read-only reentrancy)\n *     2. Price movement of up to 50% during the auction\n *     3. Typical case: no significant price movement; clearing price within expected range\n *     4. No bots online; manual human doing bidding; additional time for tx clearing\n *\n *   Case 1: Over the first 20% of the auction the price falls from ~1000x the best plausible\n *   price down to 1.5x the best plausible price in a geometric series.\n *   This period DOES NOT expect to receive a bid; it just defends against manipulated prices.\n *   If a bid occurs during this period, a violation is reported to the Broker.\n *   This is still safe for the protocol since other trades, with price discovery, can occur.\n *\n *   Case 2: Over the next 20% of the auction the price falls from 1.5x the best plausible price\n *   to the best plausible price, linearly. No violation is reported if a bid occurs. This case\n *   exists to handle cases where prices change after the auction is started, naturally.\n *\n *   Case 3: Over the next 50% of the auction the price falls from the best plausible price to the\n *   worst price, linearly. The worst price is further discounted by the maxTradeSlippage.\n *   This is the phase of the auction where bids will typically occur.\n *\n *   Case 4: Lastly the price stays at the worst price for the final 5% of the auction to allow\n *   a bid to occur if no bots are online and the only bidders are humans.\n *\n * To bid:\n * 1. Call `bidAmount()` view to check prices at various blocks.\n * 2. Provide approval of sell tokens for precisely the `bidAmount()` desired\n * 3. Wait until the desired block is reached (hopefully not in the first 20% of the auction)\n * 4. Call bid()\n */\ncontract DutchTrade is ITrade {\n    using FixLib for uint192;\n    using SafeERC20 for IERC20Metadata;\n\n    TradeKind public constant KIND = TradeKind.DUTCH_AUCTION;\n\n    // solhint-disable-next-line var-name-mixedcase\n    uint48 public immutable ONE_BLOCK; // {s} 1 block based on network\n\n    TradeStatus public status; // reentrancy protection\n\n    IBroker public broker; // The Broker that cloned this contract into existence\n    ITrading public origin; // the address that initialized the contract\n\n    // === Auction ===\n    IERC20Metadata public sell;\n    IERC20Metadata public buy;\n    uint192 public sellAmount; // {sellTok}\n\n    // The auction runs from [startBlock, endTime], inclusive\n    uint256 public startBlock; // {block} when the dutch auction begins (one block after init())\n    uint256 public endBlock; // {block} when the dutch auction ends if no bids are received\n    uint48 public endTime; // {s} not used in this contract; needed on interface\n\n    uint192 public bestPrice; // {buyTok/sellTok} The best plausible price based on oracle data\n    uint192 public worstPrice; // {buyTok/sellTok} The worst plausible price based on oracle data\n\n    // === Bid ===\n    address public bidder;\n    // the bid amount is just whatever token balance is in the contract at settlement time\n\n    // This modifier both enforces the state-machine pattern and guards against reentrancy.\n    modifier stateTransition(TradeStatus begin, TradeStatus end) {\n        require(status == begin, \"Invalid trade state\");\n        status = TradeStatus.PENDING;\n        _;\n        assert(status == TradeStatus.PENDING);\n        status = end;\n    }\n\n    // === Auction Sizing Views ===\n\n    /// @return {qSellTok} The size of the lot being sold, in token quanta\n    function lot() public view returns (uint256) {\n        return sellAmount.shiftl_toUint(int8(sell.decimals()));\n    }\n\n    /// Calculates how much buy token is needed to purchase the lot at a particular block\n    /// @param blockNumber {block} The block number of the bid\n    /// @return {qBuyTok} The amount of buy tokens required to purchase the lot\n    function bidAmount(uint256 blockNumber) external view returns (uint256) {\n        return _bidAmount(_price(blockNumber));\n    }\n\n    // ==== Constructor ===\n\n    constructor() {\n        ONE_BLOCK = NetworkConfigLib.blocktime();\n\n        status = TradeStatus.CLOSED;\n    }\n\n    // === External ===\n\n    /// @param origin_ The Trader that originated the trade\n    /// @param sell_ The asset being sold by the protocol\n    /// @param buy_ The asset being bought by the protocol\n    /// @param sellAmount_ {qSellTok} The amount to sell in the auction, in token quanta\n    /// @param auctionLength {s} How many seconds the dutch auction should run for\n    function init(\n        ITrading origin_,\n        IAsset sell_,\n        IAsset buy_,\n        uint256 sellAmount_,\n        uint48 auctionLength,\n        TradePrices memory prices\n    ) external stateTransition(TradeStatus.NOT_STARTED, TradeStatus.OPEN) {\n        assert(\n            address(sell_) != address(0) &&\n                address(buy_) != address(0) &&\n                auctionLength >= 20 * ONE_BLOCK\n        ); // misuse by caller\n\n        // Only start dutch auctions under well-defined prices\n        require(prices.sellLow != 0 && prices.sellHigh < FIX_MAX / 1000, \"bad sell pricing\");\n        require(prices.buyLow != 0 && prices.buyHigh < FIX_MAX / 1000, \"bad buy pricing\");\n\n        broker = IBroker(msg.sender);\n        origin = origin_;\n        sell = sell_.erc20();\n        buy = buy_.erc20();\n\n        require(sellAmount_ <= sell.balanceOf(address(this)), \"unfunded trade\");\n        sellAmount = shiftl_toFix(sellAmount_, -int8(sell.decimals())); // {sellTok}\n\n        uint256 _startBlock = block.number + 1; // start in the next block\n        startBlock = _startBlock; // gas-saver\n\n        uint256 _endBlock = _startBlock + auctionLength / ONE_BLOCK; // FLOOR; endBlock is inclusive\n        endBlock = _endBlock; // gas-saver\n\n        endTime = uint48(block.timestamp + ONE_BLOCK * (_endBlock - _startBlock + 1));\n\n        // {buyTok/sellTok} = {UoA/sellTok} * {1} / {UoA/buyTok}\n        uint192 _worstPrice = prices.sellLow.mulDiv(\n            FIX_ONE - origin.maxTradeSlippage(),\n            prices.buyHigh,\n            FLOOR\n        );\n        uint192 _bestPrice = prices.sellHigh.div(prices.buyLow, CEIL); // no additional slippage\n        assert(_worstPrice <= _bestPrice);\n        worstPrice = _worstPrice; // gas-saver\n        bestPrice = _bestPrice; // gas-saver\n    }\n\n    /// Bid for the auction lot at the current price; settling atomically via a callback\n    /// @dev Caller must have provided approval\n    /// @return amountIn {qBuyTok} The quantity of tokens the bidder paid\n    function bid() external returns (uint256 amountIn) {\n        require(bidder == address(0), \"bid already received\");\n\n        // {buyTok/sellTok}\n        uint192 price = _price(block.number); // enforces auction ongoing\n\n        // {qBuyTok}\n        amountIn = _bidAmount(price);\n\n        // Transfer in buy tokens\n        bidder = msg.sender;\n        buy.safeTransferFrom(msg.sender, address(this), amountIn);\n\n        // status must begin OPEN\n        assert(status == TradeStatus.OPEN);\n\n        // reportViolation if auction cleared in geometric phase\n        if (price > bestPrice.mul(ONE_POINT_FIVE, CEIL)) {\n            broker.reportViolation();\n        }\n\n        // settle() via callback\n        origin.settleTrade(sell);\n\n        // confirm callback succeeded\n        assert(status == TradeStatus.CLOSED);\n    }\n\n    /// Settle the auction, emptying the contract of balances\n    /// @return soldAmt {qSellTok} Token quantity sold by the protocol\n    /// @return boughtAmt {qBuyTok} Token quantity purchased by the protocol\n    function settle()\n        external\n        stateTransition(TradeStatus.OPEN, TradeStatus.CLOSED)\n        returns (uint256 soldAmt, uint256 boughtAmt)\n    {\n        require(msg.sender == address(origin), \"only origin can settle\");\n\n        // Received bid\n        if (bidder != address(0)) {\n            soldAmt = lot(); // {qSellTok}\n            sell.safeTransfer(bidder, soldAmt); // {qSellTok}\n        } else {\n            require(block.number > endBlock, \"auction not over\");\n        }\n\n        // Transfer remaining balances back to origin\n        boughtAmt = buy.balanceOf(address(this)); // {qBuyTok}\n        buy.safeTransfer(address(origin), boughtAmt); // {qBuyTok}\n        sell.safeTransfer(address(origin), sell.balanceOf(address(this))); // {qSellTok}\n    }\n\n    /// Anyone can transfer any ERC20 back to the origin after the trade has been closed\n    /// @dev Escape hatch in case of accidentally transferred tokens after auction end\n    /// @custom:interaction CEI (and respects the state lock)\n    function transferToOriginAfterTradeComplete(IERC20Metadata erc20) external {\n        require(status == TradeStatus.CLOSED, \"only after trade is closed\");\n        erc20.safeTransfer(address(origin), erc20.balanceOf(address(this)));\n    }\n\n    /// @return true iff the trade can be settled.\n    // Guaranteed to be true some time after init(), until settle() is called\n    function canSettle() external view returns (bool) {\n        return status == TradeStatus.OPEN && (bidder != address(0) || block.number > endBlock);\n    }\n\n    // === Private ===\n\n    /// Return the price of the auction at a particular timestamp\n    /// @param blockNumber {block} The block number to get price for\n    /// @return {buyTok/sellTok}\n    function _price(uint256 blockNumber) private view returns (uint192) {\n        uint256 _startBlock = startBlock; // gas savings\n        uint256 _endBlock = endBlock; // gas savings\n        require(blockNumber >= _startBlock, \"auction not started\");\n        require(blockNumber <= _endBlock, \"auction over\");\n\n        /// Price Curve:\n        ///   - first 20%: geometrically decrease the price from 1000x the bestPrice to 1.5x it\n        ///   - next  25%: linearly decrease the price from 1.5x the bestPrice to 1x it\n        ///   - next  50%: linearly decrease the price from bestPrice to worstPrice\n        ///   - last   5%: constant at worstPrice\n\n        uint192 progression = divuu(blockNumber - _startBlock, _endBlock - _startBlock); // {1}\n\n        // Fast geometric decay -- 0%-20% of auction\n        if (progression < TWENTY_PERCENT) {\n            uint192 exp = MAX_EXP.mulDiv(TWENTY_PERCENT - progression, TWENTY_PERCENT, ROUND);\n\n            // bestPrice * ((1000000/999999) ^ exp) = bestPrice / ((999999/1000000) ^ exp)\n            // safe uint48 downcast: exp is at-most 6502287\n            // {buyTok/sellTok} = {buyTok/sellTok} / {1} ^ {1}\n            return bestPrice.mulDiv(ONE_POINT_FIVE, BASE.powu(uint48(exp.toUint(ROUND))), CEIL);\n            // this reverts for bestPrice >= 6.21654046e36 * FIX_ONE\n        } else if (progression < FORTY_FIVE_PERCENT) {\n            // First linear decay -- 20%-45% of auction\n            // 1.5x -> 1x the bestPrice\n\n            uint192 _bestPrice = bestPrice; // gas savings\n            // {buyTok/sellTok} = {buyTok/sellTok} * {1}\n            uint192 highPrice = _bestPrice.mul(ONE_POINT_FIVE, CEIL);\n            return\n                highPrice -\n                (highPrice - _bestPrice).mulDiv(progression - TWENTY_PERCENT, TWENTY_FIVE_PERCENT);\n        } else if (progression < NINETY_FIVE_PERCENT) {\n            // Second linear decay -- 45%-95% of auction\n            // bestPrice -> worstPrice\n\n            uint192 _bestPrice = bestPrice; // gas savings\n            // {buyTok/sellTok} = {buyTok/sellTok} * {1}\n            return\n                _bestPrice -\n                (_bestPrice - worstPrice).mulDiv(progression - FORTY_FIVE_PERCENT, FIFTY_PERCENT);\n        }\n\n        // Constant price -- 95%-100% of auction\n        return worstPrice;\n    }\n\n    /// Calculates how much buy token is needed to purchase the lot at a particular price\n    /// @param price {buyTok/sellTok}\n    /// @return {qBuyTok} The amount of buy tokens required to purchase the lot\n    function _bidAmount(uint192 price) public view returns (uint256) {\n        // {qBuyTok} = {sellTok} * {buyTok/sellTok} * {qBuyTok/buyTok}\n        return sellAmount.mul(price, CEIL).shiftl_toUint(int8(buy.decimals()), CEIL);\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}