creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\n *     }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n *     function initializeV2() reinitializer(2) public {\n *         __ERC20Permit_init(\"MyToken\");\n *     }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n *     _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n    /**\n     * @dev Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 version);\n\n    /**\n     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n     * `onlyInitializing` functions can be used to initialize parent contracts.\n     *\n     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n     * constructor.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = !_initializing;\n        require(\n            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n            \"Initializable: contract is already initialized\"\n        );\n        _initialized = 1;\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(1);\n        }\n    }\n\n    /**\n     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n     * used to initialize parent contracts.\n     *\n     * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n     * are added through upgrades and that require initialization.\n     *\n     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n     * cannot be nested. If one is invoked in the context of another, execution will revert.\n     *\n     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n     * a contract, executing them in the right order is up to the developer or operator.\n     *\n     * WARNING: setting the version to 255 will prevent any future reinitialization.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier reinitializer(uint8 version) {\n        require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n        _initialized = version;\n        _initializing = true;\n        _;\n        _initializing = false;\n        emit Initialized(version);\n    }\n\n    /**\n     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n     * {initializer} and {reinitializer} modifiers, directly or indirectly.\n     */\n    modifier onlyInitializing() {\n        require(_initializing, \"Initializable: contract is not initializing\");\n        _;\n    }\n\n    /**\n     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n     * through proxies.\n     *\n     * Emits an {Initialized} event the first time it is successfully executed.\n     */\n    function _disableInitializers() internal virtual {\n        require(!_initializing, \"Initializable: contract is initializing\");\n        if (_initialized != type(uint8).max) {\n            _initialized = type(uint8).max;\n            emit Initialized(type(uint8).max);\n        }\n    }\n\n    /**\n     * @dev Returns the highest version that has been initialized. See {reinitializer}.\n     */\n    function _getInitializedVersion() internal view returns (uint8) {\n        return _initialized;\n    }\n\n    /**\n     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n     */\n    function _isInitializing() internal view returns (bool) {\n        return _initializing;\n    }\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract PausableUpgradeable is Initializable, ContextUpgradeable {\n    /**\n     * @dev Emitted when the pause is triggered by `account`.\n     */\n    event Paused(address account);\n\n    /**\n     * @dev Emitted when the pause is lifted by `account`.\n     */\n    event Unpaused(address account);\n\n    bool private _paused;\n\n    /**\n     * @dev Initializes the contract in unpaused state.\n     */\n    function __Pausable_init() internal onlyInitializing {\n        __Pausable_init_unchained();\n    }\n\n    function __Pausable_init_unchained() internal onlyInitializing {\n        _paused = false;\n    }\n\n    /**\n     * @dev Modifier to make a function callable only when the contract is not paused.\n     *\n     * Requirements:\n     *\n     * - The contract must not be paused.\n     */\n    modifier whenNotPaused() {\n        _requireNotPaused();\n        _;\n    }\n\n    /**\n     * @dev Modifier to make a function callable only when the contract is paused.\n     *\n     * Requirements:\n     *\n     * - The contract must be paused.\n     */\n    modifier whenPaused() {\n        _requirePaused();\n        _;\n    }\n\n    /**\n     * @dev Returns true if the contract is paused, and false otherwise.\n     */\n    function paused() public view virtual returns (bool) {\n        return _paused;\n    }\n\n    /**\n     * @dev Throws if the contract is paused.\n     */\n    function _requireNotPaused() internal view virtual {\n        require(!paused(), \"Pausable: paused\");\n    }\n\n    /**\n     * @dev Throws if the contract is not paused.\n     */\n    function _requirePaused() internal view virtual {\n        require(paused(), \"Pausable: not paused\");\n    }\n\n    /**\n     * @dev Triggers stopped state.\n     *\n     * Requirements:\n     *\n     * - The contract must not be paused.\n     */\n    function _pause() internal virtual whenNotPaused {\n        _paused = true;\n        emit Paused(_msgSender());\n    }\n\n    /**\n     * @dev Returns to normal state.\n     *\n     * Requirements:\n     *\n     * - The contract must be paused.\n     */\n    function _unpause() internal virtual whenPaused {\n        _paused = false;\n        emit Unpaused(_msgSender());\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant _NOT_ENTERED = 1;\n    uint256 private constant _ENTERED = 2;\n\n    uint256 private _status;\n\n    function __ReentrancyGuard_init() internal onlyInitializing {\n        __ReentrancyGuard_init_unchained();\n    }\n\n    function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be _NOT_ENTERED\n        require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n        // Any calls to nonReentrant after this point will fail\n        _status = _ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        return _status == _ENTERED;\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20PermitUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\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/IERC20Upgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20Upgradeable {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\nimport \"../extensions/IERC20PermitUpgradeable.sol\";\nimport \"../../../utils/AddressUpgradeable.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 SafeERC20Upgradeable {\n    using AddressUpgradeable for address;\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) 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(IERC20Upgradeable token, address spender, uint256 value) 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    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     */\n    function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.\n     * Revert on invalid signature.\n     */\n    function safePermit(\n        IERC20PermitUpgradeable 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(IERC20Upgradeable 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        require(returndata.length == 0 || abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation 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     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) {\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 cannot use {Address-functionCall} here since this should return false\n        // and not revert is the subcall reverts.\n\n        (bool success, bytes memory returndata) = address(token).call(data);\n        return\n            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token));\n    }\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\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     * Furthermore, `isContract` will also return true if the target contract within\n     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n     * which only has an effect at the end of a transaction.\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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) 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        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, 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        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, 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        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n     *\n     * _Available since v4.8._\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason or 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            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(bytes memory returndata, string memory errorMessage) private pure {\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"
      },
      "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n    function __Context_init() internal onlyInitializing {\n    }\n\n    function __Context_init_unchained() internal onlyInitializing {\n    }\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[50] private __gap;\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/ERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n    mapping(address => uint256) private _balances;\n\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    string private _name;\n    string private _symbol;\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    constructor(string memory name_, string memory symbol_) {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the default value returned by this function, unless\n     * it's overridden.\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual override returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual override returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(address to, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * NOTE: Does not update the allowance if the current allowance\n     * is the maximum `uint256`.\n     *\n     * Requirements:\n     *\n     * - `from` and `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, amount);\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, allowance(owner, spender) + addedValue);\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        uint256 currentAllowance = allowance(owner, spender);\n        require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n        unchecked {\n            _approve(owner, spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Moves `amount` of tokens from `from` to `to`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     */\n    function _transfer(address from, address to, uint256 amount) internal virtual {\n        require(from != address(0), \"ERC20: transfer from the zero address\");\n        require(to != address(0), \"ERC20: transfer to the zero address\");\n\n        _beforeTokenTransfer(from, to, amount);\n\n        uint256 fromBalance = _balances[from];\n        require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n        unchecked {\n            _balances[from] = fromBalance - amount;\n            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n            // decrementing then incrementing.\n            _balances[to] += amount;\n        }\n\n        emit Transfer(from, to, amount);\n\n        _afterTokenTransfer(from, to, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _mint(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        _beforeTokenTransfer(address(0), account, amount);\n\n        _totalSupply += amount;\n        unchecked {\n            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n            _balances[account] += amount;\n        }\n        emit Transfer(address(0), account, amount);\n\n        _afterTokenTransfer(address(0), account, amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: burn from the zero address\");\n\n        _beforeTokenTransfer(account, address(0), amount);\n\n        uint256 accountBalance = _balances[account];\n        require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n        unchecked {\n            _balances[account] = accountBalance - amount;\n            // Overflow not possible: amount <= accountBalance <= totalSupply.\n            _totalSupply -= amount;\n        }\n\n        emit Transfer(account, address(0), amount);\n\n        _afterTokenTransfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(address owner, address spender, uint256 amount) internal virtual {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n     *\n     * Does not update the allowance amount in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Might emit an {Approval} event.\n     */\n    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n            unchecked {\n                _approve(owner, spender, currentAllowance - amount);\n            }\n        }\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n    /**\n     * @dev Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n"
      },
      "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router01.sol": {
        "content": "pragma solidity >=0.6.2;\n\ninterface IUniswapV2Router01 {\n    function factory() external pure returns (address);\n    function WETH() external pure returns (address);\n\n    function addLiquidity(\n        address tokenA,\n        address tokenB,\n        uint amountADesired,\n        uint amountBDesired,\n        uint amountAMin,\n        uint amountBMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountA, uint amountB, uint liquidity);\n    function addLiquidityETH(\n        address token,\n        uint amountTokenDesired,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline\n    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);\n    function removeLiquidity(\n        address tokenA,\n        address tokenB,\n        uint liquidity,\n        uint amountAMin,\n        uint amountBMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountA, uint amountB);\n    function removeLiquidityETH(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountToken, uint amountETH);\n    function removeLiquidityWithPermit(\n        address tokenA,\n        address tokenB,\n        uint liquidity,\n        uint amountAMin,\n        uint amountBMin,\n        address to,\n        uint deadline,\n        bool approveMax, uint8 v, bytes32 r, bytes32 s\n    ) external returns (uint amountA, uint amountB);\n    function removeLiquidityETHWithPermit(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline,\n        bool approveMax, uint8 v, bytes32 r, bytes32 s\n    ) external returns (uint amountToken, uint amountETH);\n    function swapExactTokensForTokens(\n        uint amountIn,\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external returns (uint[] memory amounts);\n    function swapTokensForExactTokens(\n        uint amountOut,\n        uint amountInMax,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external returns (uint[] memory amounts);\n    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)\n        external\n        payable\n        returns (uint[] memory amounts);\n    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)\n        external\n        returns (uint[] memory amounts);\n    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)\n        external\n        returns (uint[] memory amounts);\n    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)\n        external\n        payable\n        returns (uint[] memory amounts);\n\n    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);\n    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);\n    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);\n    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);\n    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);\n}\n"
      },
      "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol": {
        "content": "pragma solidity >=0.6.2;\n\nimport './IUniswapV2Router01.sol';\n\ninterface IUniswapV2Router02 is IUniswapV2Router01 {\n    function removeLiquidityETHSupportingFeeOnTransferTokens(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountETH);\n    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline,\n        bool approveMax, uint8 v, bytes32 r, bytes32 s\n    ) external returns (uint amountETH);\n\n    function swapExactTokensForTokensSupportingFeeOnTransferTokens(\n        uint amountIn,\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external;\n    function swapExactETHForTokensSupportingFeeOnTransferTokens(\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external payable;\n    function swapExactTokensForETHSupportingFeeOnTransferTokens(\n        uint amountIn,\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external;\n}\n"
      },
      "@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol": {
        "content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\n/// @title Callback for IUniswapV3PoolActions#swap\n/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface\ninterface IUniswapV3SwapCallback {\n    /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.\n    /// @dev In the implementation you must pay the pool tokens owed for the swap.\n    /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.\n    /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.\n    /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by\n    /// the end of the swap. If positive, the callback must send that amount of token0 to the pool.\n    /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by\n    /// the end of the swap. If positive, the callback must send that amount of token1 to the pool.\n    /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call\n    function uniswapV3SwapCallback(\n        int256 amount0Delta,\n        int256 amount1Delta,\n        bytes calldata data\n    ) external;\n}\n"
      },
      "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol": {
        "content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.7.5;\npragma abicoder v2;\n\nimport '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol';\n\n/// @title Router token swapping functionality\n/// @notice Functions for swapping tokens via Uniswap V3\ninterface ISwapRouter is IUniswapV3SwapCallback {\n    struct ExactInputSingleParams {\n        address tokenIn;\n        address tokenOut;\n        uint24 fee;\n        address recipient;\n        uint256 deadline;\n        uint256 amountIn;\n        uint256 amountOutMinimum;\n        uint160 sqrtPriceLimitX96;\n    }\n\n    /// @notice Swaps `amountIn` of one token for as much as possible of another token\n    /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata\n    /// @return amountOut The amount of the received token\n    function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);\n\n    struct ExactInputParams {\n        bytes path;\n        address recipient;\n        uint256 deadline;\n        uint256 amountIn;\n        uint256 amountOutMinimum;\n    }\n\n    /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path\n    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata\n    /// @return amountOut The amount of the received token\n    function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);\n\n    struct ExactOutputSingleParams {\n        address tokenIn;\n        address tokenOut;\n        uint24 fee;\n        address recipient;\n        uint256 deadline;\n        uint256 amountOut;\n        uint256 amountInMaximum;\n        uint160 sqrtPriceLimitX96;\n    }\n\n    /// @notice Swaps as little as possible of one token for `amountOut` of another token\n    /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata\n    /// @return amountIn The amount of the input token\n    function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);\n\n    struct ExactOutputParams {\n        bytes path;\n        address recipient;\n        uint256 deadline;\n        uint256 amountOut;\n        uint256 amountInMaximum;\n    }\n\n    /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)\n    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata\n    /// @return amountIn The amount of the input token\n    function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);\n}\n"
      },
      "contracts/GuardedLaunchUpgradable.sol": {
        "content": "//SPDX-License-Identifier: Apache 2.0\npragma solidity 0.8.10;\n\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\n\n/// @notice This abstract contract is used to add an updatable limit on the total value locked\n/// that the contract can have. It also have an emergency method that allows the owner to pull\n/// funds into predefined recovery address\n/// @dev Inherit this contract and add the _guarded method to the child contract\nabstract contract GuardedLaunchUpgradable is Initializable, OwnableUpgradeable, ReentrancyGuardUpgradeable {\n  using SafeERC20Upgradeable for IERC20Upgradeable;\n\n  // ERROR MESSAGES:\n  // 0 = is 0\n  // 1 = already initialized\n  // 2 = Contract limit reached\n\n  // TVL limit in underlying value\n  uint256 public limit;\n  // recovery address\n  address public governanceRecoveryFund;\n\n  /// @param _limit TVL limit. (0 means unlimited)\n  /// @param _governanceRecoveryFund recovery address\n  /// @param _owner owner address\n  function __GuardedLaunch_init(uint256 _limit, address _governanceRecoveryFund, address _owner) internal {\n    require(_governanceRecoveryFund != address(0), '0');\n    require(_owner != address(0), '0');\n    // Initialize inherited contracts\n    OwnableUpgradeable.__Ownable_init();\n    ReentrancyGuardUpgradeable.__ReentrancyGuard_init();\n    // Initialize state variables\n    limit = _limit;\n    governanceRecoveryFund = _governanceRecoveryFund;\n    // Transfer ownership\n    transferOwnership(_owner);\n  }\n\n  /// @notice this check should be called inside the child contract on deposits to check that the\n  /// TVL didn't exceed a threshold\n  /// @param _amount new amount to deposit\n  function _guarded(uint256 _amount) internal view {\n    uint256 _limit = limit;\n    if (_limit == 0) {\n      return;\n    }\n    require(getContractValue() + _amount <= _limit, '2');\n  }\n\n  /// @dev Check that the second function is not called in the same tx from the same tx.origin\n  function _checkOnlyOwner() internal view {\n    require(owner() == msg.sender, '6');\n  }\n\n  /// @notice abstract method, should return the TVL in underlyings\n  function getContractValue() public virtual view returns (uint256);\n\n  /// @notice set contract TVL limit\n  /// @param _limit limit in underlying value, 0 means no limit\n  function _setLimit(uint256 _limit) external {\n    _checkOnlyOwner();\n    limit = _limit;\n  }\n\n  /// @notice Emergency method, tokens gets transferred to the governanceRecoveryFund address\n  /// @param _token address of the token to transfer\n  /// @param _value amount to transfer\n  function transferToken(address _token, uint256 _value) external {\n    _checkOnlyOwner();\n    IERC20Upgradeable(_token).safeTransfer(governanceRecoveryFund, _value);\n  }\n}\n"
      },
      "contracts/IdleCDO.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.10;\n\nimport \"@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol\";\nimport '@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol';\nimport \"@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\nimport \"./interfaces/IIdleCDOStrategy.sol\";\nimport \"./interfaces/IERC20Detailed.sol\";\n\nimport \"./GuardedLaunchUpgradable.sol\";\nimport \"./IdleCDOTranche.sol\";\nimport \"./IdleCDOStorage.sol\";\n\n/// @title A perpetual tranche implementation\n/// @author Idle Labs Inc.\n/// @notice More info and high level overview in the README\n/// @dev The contract is upgradable, to add storage slots, create IdleCDOStorageVX and inherit from IdleCDOStorage, then update the definitaion below\ncontract IdleCDO is PausableUpgradeable, GuardedLaunchUpgradable, IdleCDOStorage {\n  using SafeERC20Upgradeable for IERC20Detailed;\n\n  // ERROR MESSAGES:\n  // 0 = is 0\n  // 1 = already initialized\n  // 2 = Contract limit reached\n  // 3 = Tranche withdraw not allowed (Paused or in shutdown)\n  // 4 = Default, wait shutdown\n  // 5 = Amount too low\n  // 6 = Not authorized\n  // 7 = Amount too high\n  // 8 = Same block\n  // 9 = Invalid\n\n  // Used to prevent initialization of the implementation contract\n  /// @custom:oz-upgrades-unsafe-allow constructor\n  constructor() {\n    token = address(1);\n  }\n\n  // ###################\n  // Initializer\n  // ###################\n\n  /// @notice can only be called once\n  /// @dev Initialize the upgradable contract\n  /// @param _limit contract value limit, can be 0\n  /// @param _guardedToken underlying token\n  /// @param _governanceFund address where funds will be sent in case of emergency\n  /// @param _owner guardian address (can pause, unpause and call emergencyShutdown)\n  /// @param _rebalancer rebalancer address\n  /// @param _strategy strategy address\n  /// @param _trancheAPRSplitRatio trancheAPRSplitRatio value\n  /// @param // deprecated\n  /// @param // deprecated _incentiveTokens array of addresses for incentive tokens\n  function initialize(\n    uint256 _limit, address _guardedToken, address _governanceFund, address _owner, // GuardedLaunch args\n    address _rebalancer,\n    address _strategy,\n    uint256 _trancheAPRSplitRatio, // for AA tranches, so eg 10000 means 10% interest to AA and 90% BB\n    uint256, // Deprecated\n    address[] memory // Deprecated\n  ) external initializer {\n    require(token == address(0), '1');\n    require(_rebalancer != address(0), '0');\n    require(_strategy != address(0), '0');\n    require(_guardedToken != address(0), '0');\n    require( _trancheAPRSplitRatio <= FULL_ALLOC, '7');\n    // Initialize contracts\n    PausableUpgradeable.__Pausable_init();\n    // check for _governanceFund and _owner != address(0) are inside GuardedLaunchUpgradable\n    GuardedLaunchUpgradable.__GuardedLaunch_init(_limit, _governanceFund, _owner);\n    // Deploy Tranches tokens\n    address _strategyToken = IIdleCDOStrategy(_strategy).strategyToken();\n    // get strategy token symbol (eg. idleDAI)\n    string memory _symbol = IERC20Detailed(_strategyToken).symbol();\n    // create tranche tokens (concat strategy token symbol in the name and symbol of the tranche tokens)\n    AATranche = address(new IdleCDOTranche(_concat(string(\"IdleCDO AA Tranche - \"), _symbol), _concat(string(\"AA_\"), _symbol)));\n    BBTranche = address(new IdleCDOTranche(_concat(string(\"IdleCDO BB Tranche - \"), _symbol), _concat(string(\"BB_\"), _symbol)));\n    // Set CDO params\n    token = _guardedToken;\n    strategy = _strategy;\n    strategyToken = _strategyToken;\n    rebalancer = _rebalancer;\n    trancheAPRSplitRatio = _trancheAPRSplitRatio;\n    uint256 _oneToken = 10**(IERC20Detailed(_guardedToken).decimals());\n    oneToken = _oneToken;\n    uniswapRouterV2 = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);\n    weth = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);\n    // incentiveTokens = _incentiveTokens; [DEPRECATED]\n    priceAA = _oneToken;\n    priceBB = _oneToken;\n    unlentPerc = 2000; // 2%\n    // # blocks, after an harvest, during which harvested rewards gets progressively unlocked\n    releaseBlocksPeriod = 6400; // about 1 day\n    // Set flags\n    allowAAWithdraw = true;\n    allowBBWithdraw = true;\n    revertIfTooLow = true;\n    // skipDefaultCheck = false is the default value\n    // Set allowance for strategy\n    _allowUnlimitedSpend(_guardedToken, _strategy);\n    _allowUnlimitedSpend(_strategyToken, _strategy);\n    // Save current strategy price\n    lastStrategyPrice = _strategyPrice();\n    // Fee params\n    fee = 15000; // 15% performance fee\n    feeReceiver = address(0xFb3bD022D5DAcF95eE28a6B07825D4Ff9C5b3814); // treasury multisig\n    guardian = _owner;\n    // feeSplit = 0; // default all to feeReceiver\n    isAYSActive = true; // adaptive yield split\n    minAprSplitAYS = AA_RATIO_LIM_DOWN; // AA tranche will get min 50% of the yield\n\n    maxDecreaseDefault = 5000; // 5% decrease for triggering a default\n    _additionalInit();\n  }\n\n  /// @notice used by child contracts (cdo variants) if anything needs to be done on/after init\n  function _additionalInit() internal virtual {}\n\n  // ###############\n  // Public methods\n  // ###############\n\n  /// @notice pausable\n  /// @dev msg.sender should approve this contract first to spend `_amount` of `token`\n  /// @param _amount amount of `token` to deposit\n  /// @return AA tranche tokens minted\n  function depositAA(uint256 _amount) external returns (uint256) {\n    return _deposit(_amount, AATranche, address(0));\n  }\n\n  /// @notice pausable in _deposit\n  /// @dev msg.sender should approve this contract first to spend `_amount` of `token`\n  /// @param _amount amount of `token` to deposit\n  /// @return BB tranche tokens minted\n  function depositBB(uint256 _amount) external returns (uint256) {\n    return _deposit(_amount, BBTranche, address(0));\n  }\n\n  /// @notice pausable\n  /// @dev msg.sender should approve this contract first to spend `_amount` of `token`\n  /// @param _amount amount of `token` to deposit\n  /// @param _referral address of the referral\n  /// @return AA tranche tokens minted\n  function depositAARef(uint256 _amount, address _referral) external returns (uint256) {\n    return _deposit(_amount, AATranche, _referral);\n  }\n\n  /// @notice pausable in _deposit\n  /// @dev msg.sender should approve this contract first to spend `_amount` of `token`\n  /// @param _amount amount of `token` to deposit\n  /// @param _referral address of the referral\n  /// @return BB tranche tokens minted\n  function depositBBRef(uint256 _amount, address _referral) external returns (uint256) {\n    return _deposit(_amount, BBTranche, _referral);\n  }\n\n  /// @notice pausable in _deposit\n  /// @param _amount amount of AA tranche tokens to burn\n  /// @return underlying tokens redeemed\n  function withdrawAA(uint256 _amount) external returns (uint256) {\n    require(!paused() || allowAAWithdraw, '3');\n    return _withdraw(_amount, AATranche);\n  }\n\n  /// @notice pausable\n  /// @param _amount amount of BB tranche tokens to burn\n  /// @return underlying tokens redeemed\n  function withdrawBB(uint256 _amount) external returns (uint256) {\n    require(!paused() || allowBBWithdraw, '3');\n    return _withdraw(_amount, BBTranche);\n  }\n\n  // ###############\n  // Views\n  // ###############\n\n  /// @param _tranche tranche address\n  /// @return tranche price, in underlyings, at the last interaction (not considering interest earned \n  /// since last interaction)\n  function tranchePrice(address _tranche) external view returns (uint256) {\n    return _tranchePrice(_tranche);\n  }\n\n  /// @notice calculates the current net TVL (in `token` terms)\n  /// @dev unclaimed rewards (gov tokens) and `unclaimedFees` are not counted. \n  /// Harvested rewards are counted only if enough blocks have passed (`_lockedRewards`)\n  function getContractValue() public override view returns (uint256) {\n    address _strategyToken = strategyToken;\n    uint256 strategyTokenDecimals = IERC20Detailed(_strategyToken).decimals();\n    // TVL is the sum of unlent balance in the contract + the balance in lending - harvested but locked rewards - unclaimedFees\n    // Balance in lending is the value of the interest bearing assets (strategyTokens) in this contract\n    // TVL = (strategyTokens * strategy token price) + unlent balance - lockedRewards - unclaimedFees\n    return (_contractTokenBalance(_strategyToken) * _strategyPrice() / (10**(strategyTokenDecimals))) +\n            _contractTokenBalance(token) -\n            _lockedRewards() -\n            unclaimedFees;\n  }\n\n  /// @param _tranche tranche address\n  /// @return actual apr given current ratio between AA and BB tranches\n  function getApr(address _tranche) external view returns (uint256) {\n    return _getApr(_tranche, _getAARatio(false));\n  }\n\n  /// @notice calculates the current AA tranches ratio\n  /// @dev _virtualBalance is used to have a more accurate/recent value for the AA ratio\n  /// because it calculates the balance after splitting the accrued interest since the\n  /// last depositXX/withdrawXX/harvest\n  /// @return AA tranches ratio (in underlying value) considering all interest\n  function getCurrentAARatio() external view returns (uint256) {\n    return _getAARatio(false);\n  }\n\n  /// @notice calculates the current tranches price considering the interest/loss that is yet to be splitted\n  /// ie the interest/loss generated since the last update of priceAA and priceBB (done on depositXX/withdrawXX/harvest)\n  /// @param _tranche address of the requested tranche\n  /// @return _virtualPrice tranche price considering all interest/losses\n  function virtualPrice(address _tranche) public virtual view returns (uint256 _virtualPrice) {\n    // get both NAVs, because we need the total NAV anyway\n    uint256 _lastNAVAA = lastNAVAA;\n    uint256 _lastNAVBB = lastNAVBB;\n\n    (_virtualPrice, ) = _virtualPriceAux(\n      _tranche,\n      getContractValue(), // nav\n      _lastNAVAA + _lastNAVBB, // lastNAV\n      _tranche == AATranche ? _lastNAVAA : _lastNAVBB, // lastTrancheNAV\n      trancheAPRSplitRatio\n    );\n  }\n\n  /// @notice [DEPRECATED]\n  /// @return array with addresses of incentiveTokens (can be empty)\n  function getIncentiveTokens() external view returns (address[] memory) {\n    return incentiveTokens;\n  }\n\n  // ###############\n  // Internal\n  // ###############\n\n  /// @notice method used to check if depositor has enough stkIDLE per unit of underlying to access the vault.\n  /// This can be used to give priority access to new vaults to stkIDLE holders. \n  /// @dev This check is only intended for \"regular\" users as it does not strictly enforce the _stkIDLEPerUnderlying \n  /// ratio (eg: deposit+transfer). This will be mitigated by the fee rebate mechanism (airdrop) as otherwise those\n  /// rebates will be lost.\n  /// @param _amount amount of underlying to deposit\n  function _checkStkIDLEBal(address _tranche, uint256 _amount) internal view {\n    uint256 _stkIDLEPerUnderlying = stkIDLEPerUnderlying;\n    // check if stkIDLE requirement is active for _tranche\n    if (_stkIDLEPerUnderlying == 0 || \n      (_tranche == BBTranche && BBStaking == address(0)) || \n      (_tranche == AATranche && AAStaking == address(0))) {\n      return;\n    }\n\n    uint256 trancheBal = IERC20Detailed(_tranche).balanceOf(msg.sender);\n    // We check if sender deposited in the same tranche previously and add the bal to _amount\n    uint256 bal = _amount + (trancheBal > 0 ? (trancheBal * _tranchePrice(_tranche) / ONE_TRANCHE_TOKEN) : 0);\n    require(\n      IERC20(STK_IDLE).balanceOf(msg.sender) >= \n      bal * _stkIDLEPerUnderlying / oneToken, \n      '7'\n    );\n  }\n\n  /// @notice method used to deposit `token` and mint tranche tokens\n  /// Ideally users should deposit right after an `harvest` call to maximize profit\n  /// @dev this contract must be approved to spend at least _amount of `token` before calling this method\n  /// automatically reverts on lending provider default (_strategyPrice decreased)\n  /// @param _amount amount of underlyings (`token`) to deposit\n  /// @param _tranche tranche address\n  /// @param _referral referral address\n  /// @return _minted number of tranche tokens minted\n  function _deposit(uint256 _amount, address _tranche, address _referral) internal virtual whenNotPaused returns (uint256 _minted) {\n    if (_amount == 0) {\n      return _minted;\n    }\n    // check that we are not depositing more than the contract available limit\n    _guarded(_amount);\n    // set _lastCallerBlock hash\n    _updateCallerBlock();\n    // check if _strategyPrice decreased\n    _checkDefault();\n    // interest accrued since last depositXX/withdrawXX/harvest is splitted between AA and BB\n    // according to trancheAPRSplitRatio. NAVs of AA and BB are updated and tranche\n    // prices adjusted accordingly\n    _updateAccounting();\n    // check if depositor has enough stkIDLE for the amount to be deposited\n    _checkStkIDLEBal(_tranche, _amount);\n    // get underlyings from sender\n    address _token = token;\n    uint256 _preBal = _contractTokenBalance(_token);\n    IERC20Detailed(_token).safeTransferFrom(msg.sender, address(this), _amount);\n    // mint tranche tokens according to the current tranche price\n    _minted = _mintShares(_contractTokenBalance(_token) - _preBal, msg.sender, _tranche);\n    // update trancheAPRSplitRatio\n    _updateSplitRatio(_getAARatio(true));\n\n    if (_referral != address(0)) {\n      emit Referral(_amount, _referral);\n    }\n  }\n\n  /// @notice this method is called on depositXX/withdrawXX/harvest and\n  /// updates the accounting of the contract and effectively splits the yield/loss between the\n  /// AA and BB tranches\n  /// @dev this method:\n  /// - update tranche prices (priceAA and priceBB)\n  /// - update net asset value for both tranches (lastNAVAA and lastNAVBB)\n  /// - update fee accounting (unclaimedFees)\n  function _updateAccounting() internal virtual {\n    uint256 _lastNAVAA = lastNAVAA;\n    uint256 _lastNAVBB = lastNAVBB;\n    uint256 _lastNAV = _lastNAVAA + _lastNAVBB;\n    uint256 nav = getContractValue();\n    uint256 _aprSplitRatio = trancheAPRSplitRatio;\n    // If gain is > 0, then collect some fees in `unclaimedFees`\n    if (nav > _lastNAV) {\n      unclaimedFees += (nav - _lastNAV) * fee / FULL_ALLOC;\n    }\n    (uint256 _priceAA, int256 _totalAAGain) = _virtualPriceAux(AATranche, nav, _lastNAV, _lastNAVAA, _aprSplitRatio);\n    (uint256 _priceBB, int256 _totalBBGain) = _virtualPriceAux(BBTranche, nav, _lastNAV, _lastNAVBB, _aprSplitRatio);\n    lastNAVAA = uint256(int256(_lastNAVAA) + _totalAAGain);\n\n    // if we have a loss and it's gte last junior NAV we trigger a default\n    if (_totalBBGain < 0 && -_totalBBGain >= int256(_lastNAVBB)) {\n      // revert with 'default' error (4) if skipDefaultCheck is false, as seniors will have a loss too not covered. \n      // `updateAccounting` should be manually called to distribute loss\n      require(skipDefaultCheck, \"4\");\n      // This path will be called when a default happens and guardian calls\n      // `updateAccounting` after setting skipDefaultCheck or when skipDefaultCheck is already set to true\n      lastNAVBB = 0;\n      // if skipDefaultCheck is set to true prior a default (eg because AA is used as collateral and needs to be liquid), \n      // emergencyShutdown won't prevent the current deposit/redeem (the one that called this _updateAccounting) and is \n      // still correct because:\n      // - depositBB will revert as priceBB is 0\n      // - depositAA won't revert (unless the loss is 100% of TVL) and user will get \n      //   correct number of share at a priceAA already post junior default\n      // - withdrawBB will redeem 0 and burn BB tokens because priceBB is 0\n      // - withdrawAA will redeem the correct amount of underlyings post junior default\n      // We pass true as we still want AA to be redeemable in any case even after a junior default\n      _emergencyShutdown(true);\n    } else {\n      // we add the gain to last saved NAV\n      lastNAVBB = uint256(int256(_lastNAVBB) + _totalBBGain);\n    }\n    priceAA = _priceAA;\n    priceBB = _priceBB;\n  }\n\n  /// @notice calculates the NAV for a tranche considering the interest that is yet to be splitted\n  /// @param _tranche address of the requested tranche\n  /// @return net asset value, in underlying tokens, for _tranche considering all nav\n  function _virtualBalance(address _tranche) internal view returns (uint256) {\n    // balance is: tranche supply * virtual tranche price\n    return IdleCDOTranche(_tranche).totalSupply() * virtualPrice(_tranche) / ONE_TRANCHE_TOKEN;\n  }\n\n  /// @notice calculates the NAV for a tranche without considering the interest that is yet to be splitted\n  /// @param _tranche address of the requested tranche\n  /// @return net asset value, in underlying tokens, for _tranche\n  function _instantBalance(address _tranche) internal view returns (uint256) {\n    return IdleCDOTranche(_tranche).totalSupply() * _tranchePrice(_tranche) / ONE_TRANCHE_TOKEN;\n  }\n\n  /// @notice calculates the current tranches price considering the interest/loss that is yet to be splitted and the\n  /// total gain/loss for a specific tranche\n  /// @dev Main scenarios covered:\n  /// - if there is a loss on the lending protocol (ie strategy price decrease) up to maxDecreaseDefault (_checkDefault method), the loss is\n  ///     - totally absorbed by junior holders if they have enough TVL and deposits/redeems work as normal\n  ///     - otherwise a 'default' error (4) is raised and deposits/redeems are blocked\n  /// - if there is a loss on the lending protocol (ie strategy price decrease) more than maxDecreaseDefault all deposits and redeems\n  ///   are blocked and a 'default' error (4) is raised\n  /// - if there is a loss somewhere not in the lending protocol (ie in our contracts) and the TVL decreases then the same process as above\n  ///   applies, the only difference is that maxDecreaseDefault is not considered\n  /// In any case, once a loss happens, it only gets accounted when new deposits/redeems are made, but those are blocked.\n  /// For this reason a protected updateAccounting method has been added which should be used to distributed the loss after a default event\n  /// @param _tranche address of the requested tranche\n  /// @param _nav current NAV\n  /// @param _lastNAV last saved NAV\n  /// @param _lastTrancheNAV last saved tranche NAV\n  /// @param _trancheAPRSplitRatio APR split ratio for AA tranche\n  /// @return _virtualPrice tranche price considering all interest\n  /// @return _totalTrancheGain (int256) tranche gain/loss since last update\n  function _virtualPriceAux(\n    address _tranche,\n    uint256 _nav,\n    uint256 _lastNAV,\n    uint256 _lastTrancheNAV,\n    uint256 _trancheAPRSplitRatio\n  ) internal virtual view returns (uint256 _virtualPrice, int256 _totalTrancheGain) {\n    // Check if there are tranche holders\n    uint256 trancheSupply = IdleCDOTranche(_tranche).totalSupply();\n    if (_lastNAV == 0 || trancheSupply == 0) {\n      return (oneToken, 0);\n    }\n\n    // In order to correctly split the interest generated between AA and BB tranche holders\n    // (according to the trancheAPRSplitRatio) we need to know how much interest/loss we gained\n    // since the last price update (during a depositXX/withdrawXX/harvest)\n    // To do that we need to get the current value of the assets in this contract\n    // and the last saved one (always during a depositXX/withdrawXX/harvest)\n    // Calculate the total gain/loss\n    int256 totalGain = int256(_nav) - int256(_lastNAV);\n    // If there is no gain/loss return the current price\n    if (totalGain == 0) {\n      return (_tranchePrice(_tranche), 0);\n    }\n\n    // Remove performance fee for gains\n    if (totalGain > 0) {\n      totalGain -= totalGain * int256(fee) / int256(FULL_ALLOC);\n    }\n\n    address _AATranche = AATranche;\n    address _BBTranche = BBTranche;\n    bool _isAATranche = _tranche == _AATranche;\n    // Get the supply of the other tranche and\n    // if it's 0 then give all gain to the current `_tranche` holders\n    if (IdleCDOTranche(_isAATranche ? _BBTranche : _AATranche).totalSupply() == 0) {\n      _totalTrancheGain = totalGain;\n    } else {\n      // if we gained something or the loss is between 0 and lossToleranceBps then we socialize the gain/loss\n      if (totalGain > 0) {\n        // Split the net gain, according to _trancheAPRSplitRatio, with precision loss favoring the AA tranche.\n        int256 totalBBGain = totalGain * int256(FULL_ALLOC - _trancheAPRSplitRatio) / int256(FULL_ALLOC);\n        // The new NAV for the tranche is old NAV + total gain for the tranche\n        _totalTrancheGain = _isAATranche ? (totalGain - totalBBGain) : totalBBGain;\n      } else if (uint256(-totalGain) <= (lossToleranceBps * _lastNAV) / FULL_ALLOC) {\n        // Split the loss, according to TVL ratio instead of _trancheAPRSplitRatio (loss socialized between all tranches)\n        uint256 _lastNAVBB = lastNAVBB;\n        int256 totalBBLoss = totalGain * int256(_lastNAVBB) / int256(lastNAVAA + _lastNAVBB);\n        // The new NAV for the tranche is old NAV - loss for the tranche\n        _totalTrancheGain = _isAATranche ? (totalGain - totalBBLoss) : totalBBLoss;\n      } else { // totalGain is negative here\n        // Redirect the whole loss (which should be < maxDecreaseDefault) to junior holders\n        int256 _juniorTVL = int256(_isAATranche ? _lastNAV - _lastTrancheNAV : _lastTrancheNAV);\n        int256 _newJuniorTVL = _juniorTVL + totalGain; \n        // if junior holders have enough TVL to cover\n        if (_newJuniorTVL > 0) {\n          // then juniors get all loss (totalGain) and senior gets 0 loss\n          _totalTrancheGain = _isAATranche ? int256(0) : totalGain;\n        } else {\n          // otherwise all loss minus junior tvl to senior\n          if (!_isAATranche) {\n            // juniors have no more claims, price is set to 0, gain is set to -juniorTVL\n            return (0, -_juniorTVL);\n          }\n          // seniors get the loss - old junior TVL\n          _totalTrancheGain = _newJuniorTVL;\n        }\n      }\n    }\n    // Split the new NAV (_lastTrancheNAV + _totalTrancheGain) per tranche token\n    _virtualPrice = uint256(int256(_lastTrancheNAV) + _totalTrancheGain) * ONE_TRANCHE_TOKEN / trancheSupply;\n  }\n\n  /// @notice mint tranche tokens and updates tranche last NAV\n  /// @param _amount, in underlyings, to convert in tranche tokens\n  /// @param _to receiver address of the newly minted tranche tokens\n  /// @param _tranche tranche address\n  /// @return _minted number of tranche tokens minted\n  function _mintShares(uint256 _amount, address _to, address _tranche) internal virtual returns (uint256 _minted) {\n    // calculate # of tranche token to mint based on current tranche price: _amount / tranchePrice\n    _minted = _amount * ONE_TRANCHE_TOKEN / _tranchePrice(_tranche);\n    IdleCDOTranche(_tranche).mint(_to, _minted);\n    // update NAV with the _amount of underlyings added\n    if (_tranche == AATranche) {\n      lastNAVAA += _amount;\n    } else {\n      lastNAVBB += _amount;\n    }\n  }\n\n  /// @notice convert fees (`unclaimedFees`) in AA tranche tokens\n  /// @dev this will be called only during harvests\n  function _depositFees() internal {\n    uint256 _amount = unclaimedFees;\n    if (_amount != 0) {\n      // mint tranches tokens (always AA) to this contract\n      _mintShares(_amount, feeReceiver, AATranche);\n      // reset unclaimedFees counter\n      unclaimedFees = 0;\n      // update trancheAPRSplitRatio using instant balance\n      _updateSplitRatio(_getAARatio(true));\n    }\n  }\n\n  /// @notice It allows users to burn their tranche token and redeem their principal + interest back\n  /// @dev automatically reverts on lending provider default (_strategyPrice decreased).\n  /// @param _amount in tranche tokens\n  /// @param _tranche tranche address\n  /// @return toRedeem number of underlyings redeemed\n  function _withdraw(uint256 _amount, address _tranche) virtual internal nonReentrant returns (uint256 toRedeem) {\n    // check if a deposit is made in the same block from the same user\n    _checkSameTx();\n    // check if _strategyPrice decreased\n    _checkDefault();\n    // accrue interest to tranches and updates tranche prices\n    _updateAccounting();\n    // redeem all user balance if 0 is passed as _amount\n    if (_amount == 0) {\n      _amount = IERC20Detailed(_tranche).balanceOf(msg.sender);\n    }\n    require(_amount != 0, '0');\n    address _token = token;\n    // get current available unlent balance\n    uint256 balanceUnderlying = _contractTokenBalance(_token);\n    // Calculate the amount to redeem\n    toRedeem = _amount * _tranchePrice(_tranche) / ONE_TRANCHE_TOKEN;\n    uint256 _want = toRedeem;\n    if (toRedeem > balanceUnderlying) {\n      // if the unlent balance is not enough we try to redeem what's missing directly from the strategy\n      // and then add it to the current unlent balance\n      // NOTE: A difference of up to 100 wei due to rounding is tolerated\n      toRedeem = _liquidate(toRedeem - balanceUnderlying, revertIfTooLow) + balanceUnderlying;\n    }\n    // burn tranche token\n    IdleCDOTranche(_tranche).burn(msg.sender, _amount);\n\n    // update NAV with the _amount of underlyings removed\n    if (_tranche == AATranche) {\n      lastNAVAA -= _want;\n    } else {\n      lastNAVBB -= _want;\n    }\n\n    // update trancheAPRSplitRatio\n    _updateSplitRatio(_getAARatio(true));\n  \n    // send underlying to msg.sender. Keep this at the end of the function to avoid \n    // potential read only reentrancy on cdo variants that have hooks (eg with nfts)\n    IERC20Detailed(_token).safeTransfer(msg.sender, toRedeem);\n  }\n\n  /// @notice updates trancheAPRSplitRatio based on the current tranches TVL ratio between AA and BB\n  /// @dev the idea here is to limit the min and max APR that the senior tranche can get\n  function _updateSplitRatio(uint256 tvlAARatio) internal virtual {\n    uint256 _minSplit = minAprSplitAYS;\n    _minSplit = _minSplit == 0 ? AA_RATIO_LIM_DOWN : _minSplit;\n\n    if (isAYSActive) {\n      uint256 aux;\n      if (tvlAARatio >= AA_RATIO_LIM_UP) {\n        aux = AA_RATIO_LIM_UP;\n      } else if (tvlAARatio > _minSplit) {\n        aux = tvlAARatio;\n      } else {\n        aux = _minSplit;\n      }\n      trancheAPRSplitRatio = aux * tvlAARatio / FULL_ALLOC;\n    }\n  }\n\n  /// @notice calculates the current AA tranches ratio\n  /// @dev it does count accrued interest not yet split since last\n  /// depositXX/withdrawXX/harvest only if _instant flag is true\n  /// @param _instant if true, it returns the current ratio without accrued interest\n  /// @return AA tranches ratio (in underlying value) considering all interest\n  function _getAARatio(bool _instant) internal view returns (uint256) {\n    function(address) internal view returns (uint256) _getNAV =\n      _instant ? _instantBalance : _virtualBalance;\n    uint256 AABal = _getNAV(AATranche);\n    uint256 contractVal = AABal + _getNAV(BBTranche);\n    if (contractVal == 0) {\n      return 0;\n    }\n    // Current AA tranche split ratio = AABal * FULL_ALLOC / (AABal + BBBal)\n    return AABal * FULL_ALLOC / contractVal;\n  }\n\n  /// @dev check if _strategyPrice is decreased more than X% with X configurable since last update \n  /// and updates last saved strategy price\n  function _checkDefault() virtual internal {\n    uint256 currPrice = _strategyPrice();\n    if (!skipDefaultCheck) {\n      // calculate if % of decrease of strategyPrice is within maxDecreaseDefault\n      require(lastStrategyPrice * (FULL_ALLOC - maxDecreaseDefault) / FULL_ALLOC <= currPrice, \"4\");\n    }\n    lastStrategyPrice = currPrice;\n  }\n\n  /// @return strategy price, in underlyings\n  function _strategyPrice() internal view returns (uint256) {\n    return IIdleCDOStrategy(strategy).price();\n  }\n\n  /// @dev this should liquidate at least _amount of `token` from the lending provider or revertIfNeeded\n  /// @param _amount in underlying tokens\n  /// @param _revertIfNeeded flag whether to revert or not if the redeemed amount is not enough\n  /// @return _redeemedTokens number of underlyings redeemed\n  function _liquidate(uint256 _amount, bool _revertIfNeeded) internal virtual returns (uint256 _redeemedTokens) {\n    _redeemedTokens = IIdleCDOStrategy(strategy).redeemUnderlying(_amount);\n    if (_revertIfNeeded) {\n      uint256 _tolerance = liquidationTolerance;\n      if (_tolerance == 0) {\n        _tolerance = 100;\n      }\n      // keep `_tolerance` wei as margin for rounding errors\n      require(_redeemedTokens + _tolerance >= _amount, '5');\n    }\n\n    if (_redeemedTokens > _amount) {\n      _redeemedTokens = _amount;\n    }\n  }\n\n  /// @notice method used to sell `_rewardToken` for `_token` on uniswap\n  /// @param _rewardToken address of the token to sell\n  /// @param _path to buy\n  /// @param _amount of `_rewardToken` to sell\n  /// @param _minAmount min amount of `_token` to buy\n  /// @return _amount of _rewardToken sold\n  /// @return _amount received for the sell\n  function _sellReward(address _rewardToken, bytes memory _path, uint256 _amount, uint256 _minAmount)\n    internal virtual\n    returns (uint256, uint256) {\n    // If 0 is passed as sell amount, we get the whole contract balance\n    if (_amount == 0) {\n      _amount = _contractTokenBalance(_rewardToken);\n    }\n    if (_amount == 0) {\n      return (0, 0);\n    }\n  \n    if (_path.length != 0) {\n      // Uni v3 swap\n      ISwapRouter _swapRouter = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564);\n      IERC20Detailed(_rewardToken).safeIncreaseAllowance(address(_swapRouter), _amount);\n      // multi hop swap params\n      ISwapRouter.ExactInputParams memory params = ISwapRouter.ExactInputParams({\n        path: _path,\n        recipient: address(this),\n        deadline: block.timestamp + 100,\n        amountIn: _amount,\n        amountOutMinimum: _minAmount\n      });\n      // do the swap and return the amount swapped and the amount received\n      return (_amount, _swapRouter.exactInput(params));\n    } else {\n      // Uni v2 swap\n      IUniswapV2Router02 _uniRouter = uniswapRouterV2;\n      // approve the uniswap router to spend our reward\n      IERC20Detailed(_rewardToken).safeIncreaseAllowance(address(_uniRouter), _amount);\n      // do the trade with all `_rewardToken` in this contract\n      address[] memory _pathUniv2 = new address[](3);\n      _pathUniv2[0] = _rewardToken;\n      _pathUniv2[1] = weth;\n      _pathUniv2[2] = token;\n      uint256[] memory _amounts = _uniRouter.swapExactTokensForTokens(\n        _amount,\n        _minAmount,\n        _pathUniv2,\n        address(this),\n        block.timestamp + 100\n      );\n      // return the amount swapped and the amount received\n      return (_amounts[0], _amounts[_amounts.length - 1]);\n    }\n  }\n\n  /// @notice method used to sell all sellable rewards for `_token` on uniswap\n  /// @param _strategy IIdleCDOStrategy stategy instance\n  /// @param _sellAmounts array with amounts of rewards to sell\n  /// @param _minAmount array with amounts of _token buy for each reward sold. (should have the same length as _sellAmounts)\n  /// @param _skipReward array of flags for skipping the market sell of specific rewards (should have the same length as _sellAmounts)\n  /// @return _soldAmounts array with amounts of rewards actually sold\n  /// @return _swappedAmounts array with amounts of _token actually bought\n  /// @return _totSold total rewards sold in `_token`\n  function _sellAllRewards(IIdleCDOStrategy _strategy, uint256[] memory _sellAmounts, uint256[] memory _minAmount, bool[] memory _skipReward, bytes memory _extraData)\n    internal\n    returns (uint256[] memory _soldAmounts, uint256[] memory _swappedAmounts, uint256 _totSold) {\n    // Fetch state variables once to save gas\n    // get all rewards addresses\n    address[] memory _rewards = _strategy.getRewardTokens();\n    address _rewardToken;\n    bytes[] memory _paths = new bytes[](_rewards.length);\n    if (_extraData.length > 0) {\n      _paths = abi.decode(_extraData, (bytes[]));\n    }\n    uint256 rewardsLen = _rewards.length;\n    // Initialize the return array, containing the amounts received after swapping reward tokens\n    _soldAmounts = new uint256[](rewardsLen);\n    _swappedAmounts = new uint256[](rewardsLen);\n    // loop through all reward tokens\n    for (uint256 i; i < rewardsLen; ++i) {\n      _rewardToken = _rewards[i];\n      // check if it should be sold or not\n      if (_skipReward[i]) { continue; }\n      // do not sell stkAAVE but only AAVE if present\n      if (_rewardToken == stkAave) {\n        _rewardToken = AAVE;\n      }\n      // Market sell _rewardToken in this contract for _token\n      (_soldAmounts[i], _swappedAmounts[i]) = _sellReward(_rewardToken, _paths[i], _sellAmounts[i], _minAmount[i]);\n      _totSold += _swappedAmounts[i];\n    }\n  }\n\n  /// @param _tranche tranche address\n  /// @return last saved tranche price, in underlyings\n  function _tranchePrice(address _tranche) internal view returns (uint256) {\n    if (IdleCDOTranche(_tranche).totalSupply() == 0) {\n      return oneToken;\n    }\n    return _tranche == AATranche ? priceAA : priceBB;\n  }\n\n  /// @notice returns the current apr for a tranche based on trancheAPRSplitRatio and the provided AA ratio\n  /// @dev the apr for a tranche can be higher than the strategy apr\n  /// @param _tranche tranche token address\n  /// @param _AATrancheSplitRatio AA split ratio used for calculations\n  /// @return apr for the specific tranche\n  function _getApr(address _tranche, uint256 _AATrancheSplitRatio) internal view returns (uint256) {\n    uint256 stratApr = IIdleCDOStrategy(strategy).getApr();\n    uint256 _trancheAPRSplitRatio = trancheAPRSplitRatio;\n    bool isAATranche = _tranche == AATranche;\n    if (_AATrancheSplitRatio == 0) {\n      // if there are no AA tranches, apr for AA is 0 (all apr to BB and it will be equal to stratApr)\n      return isAATranche ? 0 : stratApr;\n    }\n    return isAATranche ?\n      // AA apr is: stratApr * AAaprSplitRatio / AASplitRatio\n      stratApr * _trancheAPRSplitRatio / _AATrancheSplitRatio :\n      // BB apr is: stratApr * BBaprSplitRatio / BBSplitRatio -> where\n      // BBaprSplitRatio is: (FULL_ALLOC - _trancheAPRSplitRatio) and\n      // BBSplitRatio is: (FULL_ALLOC - _AATrancheSplitRatio)\n      stratApr * (FULL_ALLOC - _trancheAPRSplitRatio) / (FULL_ALLOC - _AATrancheSplitRatio);\n  }\n\n  /// @return _locked amount of harvested rewards that are still not available to be redeemed\n  function _lockedRewards() internal view returns (uint256 _locked) {\n    uint256 _releaseBlocksPeriod = releaseBlocksPeriod;\n    uint256 _blocksSinceLastHarvest = block.number - latestHarvestBlock;\n    uint256 _harvestedRewards = harvestedRewards;\n\n    // NOTE: _harvestedRewards is never set to 0, but rather to 1 to save some gas\n    if (_harvestedRewards > 1 && _blocksSinceLastHarvest < _releaseBlocksPeriod) {\n      // progressively release harvested rewards\n      _locked = _harvestedRewards * (_releaseBlocksPeriod - _blocksSinceLastHarvest) / _releaseBlocksPeriod;\n    }\n  }\n\n  // ###################\n  // Protected\n  // ###################\n\n  /// @notice This method is used to lend user funds in the lending provider through an IIdleCDOStrategy\n  /// The method:\n  /// - redeems rewards (if any) from the lending provider\n  /// - converts the rewards in underlyings through uniswap v2 or v3\n  /// - calls _updateAccounting to update the accounting of the system with the new underlyings received\n  /// - it then convert fees in tranche tokens\n  /// - finally it deposits the (initial unlent balance + the underlyings get from uniswap - fees) in the\n  ///   lending provider through the IIdleCDOStrategy `deposit` call\n  /// The method will be called by an external, whitelisted, keeper bot which will call the method sistematically (eg once a day)\n  /// @dev can be called only by the rebalancer or the owner\n  /// @param _skipFlags array of flags, [0] = skip reward redemption, [1] = skip incentives update, [2] = skip fee deposit, [3] = skip all\n  /// @param _skipReward array of flags for skipping the market sell of specific rewards. Length should be equal to the `IIdleCDOStrategy(strategy).getRewardTokens()` array\n  /// @param _minAmount array of min amounts for uniswap trades. Lenght should be equal to the _skipReward array\n  /// @param _sellAmounts array of amounts (of reward tokens) to sell on uniswap. Lenght should be equal to the _minAmount array\n  /// if a sellAmount is 0 the whole contract balance for that token is swapped\n  /// @param _extraData bytes to be passed to the redeemRewards call\n  /// @return _res array of arrays with the following elements:\n  ///   [0] _soldAmounts array with amounts of rewards actually sold\n  ///   [1] _swappedAmounts array with amounts of _token actually bought\n  ///   [2] _redeemedRewards array with amounts of rewards redeemed\n  function harvest(\n    // _skipFlags[0] _skipRedeem,\n    // _skipFlags[1] _skipIncentivesUpdate, [DEPRECATED]\n    // _skipFlags[2] _skipFeeDeposit,\n    // _skipFlags[3] _skipRedeem && _skipIncentivesUpdate && _skipFeeDeposit,\n    bool[] calldata _skipFlags,\n    bool[] calldata _skipReward,\n    uint256[] calldata _minAmount,\n    uint256[] calldata _sellAmounts,\n    bytes[] calldata _extraData\n  ) public\n    virtual\n    returns (uint256[][] memory _res) {\n    _checkOnlyOwnerOrRebalancer();\n    // initalize the returned array (elements will be [_soldAmounts, _swappedAmounts, _redeemedRewards])\n    _res = new uint256[][](3);\n    // Fetch state variable once to save gas\n    IIdleCDOStrategy _strategy = IIdleCDOStrategy(strategy);\n    // Check whether to redeem rewards from strategy or not\n    if (!_skipFlags[3]) {\n      uint256 _totSold;\n\n      if (!_skipFlags[0]) {\n        // Redeem all rewards associated with the strategy\n        _res[2] = _strategy.redeemRewards(_extraData[0]);\n        // Sell rewards\n        (_res[0], _res[1], _totSold) = _sellAllRewards(_strategy, _sellAmounts, _minAmount, _skipReward, _extraData[1]);\n      }\n      // update last saved harvest block number\n      latestHarvestBlock = block.number;\n      // update harvested rewards value (avoid setting it to 0 to save some gas)\n      harvestedRewards = _totSold == 0 ? 1 : _totSold;\n\n      // split converted rewards if any and update tranche prices\n      // NOTE: harvested rewards won't be counted directly but released over time\n      _updateAccounting();\n\n      if (!_skipFlags[2]) {\n        // Get fees in the form of totalSupply diluition\n        _depositFees();\n      }\n    }\n\n    // Deposit the remaining balance in the lending provider and \n    // keep some unlent balance for cheap redeems and as reserve of last resort\n    uint256 underlyingBal = _contractTokenBalance(token);\n    uint256 idealUnlent = getContractValue() * unlentPerc / FULL_ALLOC;\n    if (underlyingBal > idealUnlent) {\n      // Put unlent balance at work in the lending provider\n      _strategy.deposit(underlyingBal - idealUnlent);\n    }\n  }\n\n  /// @notice method used to redeem underlyings from the lending provider\n  /// @dev can be called only by the rebalancer or the owner\n  /// @param _amount in underlyings to liquidate from lending provider\n  /// @param _revertIfNeeded flag to revert if amount liquidated is too low\n  /// @return liquidated amount in underlyings\n  function liquidate(uint256 _amount, bool _revertIfNeeded) external returns (uint256) {\n    _checkOnlyOwnerOrRebalancer();\n    return _liquidate(_amount, _revertIfNeeded);\n  }\n\n  // ###################\n  // onlyOwner\n  // ###################\n\n  /// @dev automatically reverts if strategyPrice decreased more than `_maxDecreaseDefault`\n  /// @param _maxDecreaseDefault max value, in % where `100000` = 100%, of accettable price decrease for the strategy\n  function setMaxDecreaseDefault(uint256 _maxDecreaseDefault) external {\n    _checkOnlyOwner();\n    require(_maxDecreaseDefault < FULL_ALLOC, '7');\n    maxDecreaseDefault = _maxDecreaseDefault;\n  }\n\n  /// @param _active flag to allow Adaptive Yield Split\n  function setIsAYSActive(bool _active) external {\n    _checkOnlyOwner();\n    isAYSActive = _active;\n  }\n\n  /// @param _allowed flag to allow AA withdraws\n  function setAllowAAWithdraw(bool _allowed) external {\n    _checkOnlyOwner();\n    allowAAWithdraw = _allowed;\n  }\n\n  /// @param _allowed flag to allow BB withdraws\n  function setAllowBBWithdraw(bool _allowed) external {\n    _checkOnlyOwner();\n    allowBBWithdraw = _allowed;\n  }\n\n  /// @param _allowed flag to enable the 'default' check (whether _strategyPrice decreased or not)\n  function setSkipDefaultCheck(bool _allowed) external {\n    _checkOnlyOwner();\n    skipDefaultCheck = _allowed;\n  }\n\n  /// @param _allowed flag to enable the check if redeemed amount during liquidations is enough\n  function setRevertIfTooLow(bool _allowed) external {\n    _checkOnlyOwner();\n    revertIfTooLow = _allowed;\n  }\n\n  /// @param _rebalancer new rebalancer address\n  function setRebalancer(address _rebalancer) external {\n    _checkOnlyOwner();\n    require((rebalancer = _rebalancer) != address(0), '0');\n  }\n\n  /// @param _feeReceiver new fee receiver address\n  function setFeeReceiver(address _feeReceiver) external {\n    _checkOnlyOwner();\n    require((feeReceiver = _feeReceiver) != address(0), '0');\n  }\n\n  /// @param _guardian new guardian (pauser) address\n  function setGuardian(address _guardian) external {\n    _checkOnlyOwner();\n    require((guardian = _guardian) != address(0), '0');\n  }\n\n  /// @param _diff max liquidation diff tolerance in underlyings\n  function setLiquidationTolerance(uint256 _diff) external {\n    _checkOnlyOwner();\n    liquidationTolerance = _diff;\n  }\n\n  /// @param _val stkIDLE per underlying required for deposits\n  function setStkIDLEPerUnderlying(uint256 _val) external {\n    _checkOnlyOwner();\n    stkIDLEPerUnderlying = _val;\n  }\n\n  /// @param _aprSplit min apr split for AA, considering FULL_ALLOC = 100%\n  function setMinAprSplitAYS(uint256 _aprSplit) external {\n    _checkOnlyOwner();\n    require((minAprSplitAYS = _aprSplit) <= FULL_ALLOC, '7');\n    minAprSplitAYS = _aprSplit;\n  }\n\n  /// @param _fee new fee\n  function setFee(uint256 _fee) external {\n    _checkOnlyOwner();\n    require((fee = _fee) <= MAX_FEE, '7');\n  }\n\n  /// @param _unlentPerc new unlent percentage\n  function setUnlentPerc(uint256 _unlentPerc) external {\n    _checkOnlyOwner();\n    require((unlentPerc = _unlentPerc) <= FULL_ALLOC, '7');\n  }\n\n  /// @notice set new release block period. WARN: this should be called only when there \n  /// are no active rewards being unlocked\n  /// @param _releaseBlocksPeriod new # of blocks after an harvest during which\n  /// harvested rewards gets progressively redistriburted to users\n  function setReleaseBlocksPeriod(uint256 _releaseBlocksPeriod) external {\n    _checkOnlyOwner();\n    releaseBlocksPeriod = _releaseBlocksPeriod;\n  }\n\n  /// @param _trancheAPRSplitRatio new apr split ratio\n  function setTrancheAPRSplitRatio(uint256 _trancheAPRSplitRatio) external {\n    _checkOnlyOwner();\n    require((trancheAPRSplitRatio = _trancheAPRSplitRatio) <= FULL_ALLOC, '7');\n  }\n\n  /// @param _diffBps tolerance in % (FULL_ALLOC = 100%) for socializing small losses \n  function setLossToleranceBps(uint256 _diffBps) external {\n      _checkOnlyOwner();\n      lossToleranceBps = _diffBps;\n  }\n\n  /// @dev toggle stkIDLE requirement for tranche\n  /// @param _tranche address\n  function toggleStkIDLEForTranche(address _tranche) external {\n    _checkOnlyOwner();\n    address aa = AATranche;\n    require(_tranche == BBTranche || _tranche == aa, '9');\n    if (_tranche == aa) {\n      AAStaking = AAStaking == address(0) ? address(1) : address(0);\n      return;\n    }\n\n    BBStaking = BBStaking == address(0) ? address(1) : address(0);\n  }\n\n  /// @notice this method updates the accounting of the contract and effectively splits the yield/loss between the\n  /// AA and BB tranches. This can be called at any time as is called automatically on each deposit/redeem. It's here\n  /// just to be called when a default happened, as deposits/redeems are paused, but we need to update\n  /// the loss for junior holders\n  function updateAccounting() external {\n    _checkOnlyOwnerOrGuardian();\n    skipDefaultCheck = true;\n    _updateAccounting();\n    // _updateAccounting can set `skipDefaultCheck` to true in case of default\n    // but this can be manually be reset to true if needed\n    skipDefaultCheck = false;\n  }\n\n  /// @notice pause deposits and redeems for all classes of tranches\n  /// @dev can be called by both the owner and the guardian\n  function emergencyShutdown() external {\n    _checkOnlyOwnerOrGuardian();\n    _emergencyShutdown(false);\n  }\n\n  function _emergencyShutdown(bool isAAWithdrawAllowed) internal {\n    // prevent deposits\n    _pause();\n    // prevent withdraws\n    allowAAWithdraw = isAAWithdrawAllowed;\n    allowBBWithdraw = false;\n    // Allow deposits/withdraws (once selectively re-enabled, eg for AA holders)\n    // without checking for lending protocol default\n    skipDefaultCheck = true;\n    revertIfTooLow = true;\n  }\n\n  /// @notice allow deposits and redeems for all classes of tranches\n  /// @dev can be called by the owner only\n  function restoreOperations() external {\n    _checkOnlyOwner();\n    // restore deposits\n    _unpause();\n    // restore withdraws\n    allowAAWithdraw = true;\n    allowBBWithdraw = true;\n    // Allow deposits/withdraws but checks for lending protocol default\n    skipDefaultCheck = false;\n    revertIfTooLow = true;\n  }\n\n  /// @notice Pauses deposits\n  /// @dev can be called by both the owner and the guardian\n  function pause() external  {\n    _checkOnlyOwnerOrGuardian();\n    _pause();\n  }\n\n  /// @notice Unpauses deposits\n  /// @dev can be called by both the owner and the guardian\n  function unpause() external {\n    _checkOnlyOwnerOrGuardian();\n    _unpause();\n  }\n\n  // ###################\n  // Helpers\n  // ###################\n\n  /// @dev Check that the msg.sender is the either the owner or the guardian\n  function _checkOnlyOwnerOrGuardian() internal view {\n    require(msg.sender == guardian || msg.sender == owner(), \"6\");\n  }\n\n  /// @dev Check that the msg.sender is the either the owner or the rebalancer\n  function _checkOnlyOwnerOrRebalancer() internal view {\n    require(msg.sender == rebalancer || msg.sender == owner(), \"6\");\n  }\n\n  /// @notice returns the current balance of this contract for a specific token\n  /// @param _token token address\n  /// @return balance of `_token` for this contract\n  function _contractTokenBalance(address _token) internal view returns (uint256) {\n    return IERC20Detailed(_token).balanceOf(address(this));\n  }\n\n  /// @dev Set allowance for _token to unlimited for _spender\n  /// @param _token token address\n  /// @param _spender spender address\n  function _allowUnlimitedSpend(address _token, address _spender) internal {\n    IERC20Detailed(_token).safeIncreaseAllowance(_spender, type(uint256).max);\n  }\n\n  /// @dev Set last caller and block.number hash. This should be called at the beginning of the first function to protect\n  function _updateCallerBlock() internal {\n    _lastCallerBlock = keccak256(abi.encodePacked(tx.origin, block.number));\n  }\n\n  /// @dev Check that the second function is not called in the same tx from the same tx.origin\n  function _checkSameTx() internal view {\n    require(keccak256(abi.encodePacked(tx.origin, block.number)) != _lastCallerBlock, \"8\");\n  }\n\n  /// @notice concat 2 strings in a single one\n  /// @param a first string\n  /// @param b second string\n  /// @return new string with a and b concatenated\n  function _concat(string memory a, string memory b) internal pure returns (string memory) {\n    return string(abi.encodePacked(a, b));\n  }\n}"
      },
      "contracts/IdleCDOGearboxVariant.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.10;\n\nimport {IdleCDO} from \"./IdleCDO.sol\";\n\n/// @title IdleCDO variant for gearbox passive lending.\n/// @notice strategyToken is set to the strategy itself which tokenizes the staked position (sdTokens) to farm GEAR\ncontract IdleCDOGearboxVariant is IdleCDO {\n  function _additionalInit() internal override {\n    strategyToken = strategy;\n  }\n}\n"
      },
      "contracts/IdleCDOStorage.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.10;\n\nimport '@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol';\n\ncontract IdleCDOStorage {\n  // constant to represent 100%\n  uint256 public constant FULL_ALLOC = 100000;\n  // max fee, relative to FULL_ALLOC\n  uint256 public constant MAX_FEE = 20000;\n  // one token\n  uint256 public constant ONE_TRANCHE_TOKEN = 10**18;\n  // variable used to save the last tx.origin and block.number\n  bytes32 internal _lastCallerBlock;\n  // variable used to save the block of the latest harvest\n  uint256 internal latestHarvestBlock;\n  // WETH address\n  address public weth;\n  // [DEPRECATED] tokens used to incentivize the idle tranche ideal ratio\n  address[] public incentiveTokens;\n  // underlying token (eg DAI)\n  address public token;\n  // address that can only pause/unpause the contract in case of emergency\n  address public guardian;\n  // one `token` (eg for DAI 10**18)\n  uint256 public oneToken;\n  // address that can call the 'harvest' method and lend pool assets\n  address public rebalancer;\n  // address of the uniswap v2 router\n  IUniswapV2Router02 internal uniswapRouterV2;\n\n  // Flag for allowing AA withdraws\n  bool public allowAAWithdraw;\n  // Flag for allowing BB withdraws\n  bool public allowBBWithdraw;\n  // Flag for allowing to enable reverting in case the strategy gives back less\n  // amount than the requested one\n  bool public revertIfTooLow;\n  // Flag to enable the `Default Check` (related to the emergency shutdown)\n  bool public skipDefaultCheck;\n\n  // address of the strategy used to lend funds\n  address public strategy;\n  // address of the strategy token which represent the position in the lending provider\n  address public strategyToken;\n  // address of AA Tranche token contract\n  address public AATranche;\n  // address of BB Tranche token contract\n  address public BBTranche;\n  // address for stkIDLE gating for AA tranche. addr(0) -> inactive, addr(1) -> active\n  address public AAStaking;\n  // address for stkIDLE gating for BB tranche. addr(0) -> inactive, addr(1) -> active\n  address public BBStaking;\n\n  // Apr split ratio for AA tranches\n  // (relative to FULL_ALLOC so 50% => 50000 => 50% of the interest to tranche AA)\n  uint256 public trancheAPRSplitRatio; //\n  // [DEPRECATED] Ideal tranche split ratio in `token` value\n  // (relative to FULL_ALLOC so 50% => 50000 means 50% of tranches (in value) should be AA)\n  uint256 public trancheIdealWeightRatio;\n  // Price for minting AA tranche, in underlyings\n  uint256 public priceAA;\n  // Price for minting BB tranche, in underlyings\n  uint256 public priceBB;\n  // last saved net asset value (in `token`) for AA tranches\n  uint256 public lastNAVAA;\n  // last saved net asset value (in `token`) for BB tranches\n  uint256 public lastNAVBB;\n  // last saved lending provider price\n  uint256 public lastStrategyPrice;\n  // Keeps track of unclaimed fees for feeReceiver\n  uint256 public unclaimedFees;\n  // Keeps an unlent balance both for cheap redeem and as 'insurance of last resort'\n  uint256 public unlentPerc;\n\n  // Fee amount (relative to FULL_ALLOC)\n  uint256 public fee;\n  // address of the fee receiver\n  address public feeReceiver;\n\n  // [DEPRECATED] trancheIdealWeightRatio ± idealRanges, used in updateIncentives\n  uint256 public idealRange;\n  // period, in blocks, for progressively releasing harvested rewards to users\n  uint256 public releaseBlocksPeriod;\n  // amount of rewards sold in the last harvest (in `token`)\n  uint256 internal harvestedRewards;\n  // stkAave address\n  address internal constant stkAave = address(0x4da27a545c0c5B758a6BA100e3a049001de870f5);\n  // aave address\n  address internal constant AAVE = address(0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9);\n  // [DEPRECATED] if the cdo receive stkAAVE\n  bool internal isStkAAVEActive;\n  // referral address of the strategy developer\n  address public referral;\n  // amount of fee for feeReceiver. Max is FULL_ALLOC\n  uint256 public feeSplit;\n\n  // if Adaptive Yield Split is active\n  bool public isAYSActive;\n  // constant to represent 99% (for ADS AA ratio upper limit)\n  uint256 internal constant AA_RATIO_LIM_UP = 99000;\n  // constant to represent 50% (for ADS AA ratio lower limit)\n  uint256 internal constant AA_RATIO_LIM_DOWN = 50000;\n\n  address internal constant STK_IDLE = address(0xaAC13a116eA7016689993193FcE4BadC8038136f);\n\n  // Referral event\n  event Referral(uint256 _amount, address _ref);\n  // tolerance in underlyings when redeeming\n  uint256 public liquidationTolerance;\n\n  // Add new variables here. For each storage slot\n  // used, reduce the __gap length by 1. \n  // ####################### \n  // Min apr ratio for AA tranches when using AYS\n  uint256 public minAprSplitAYS;\n  // Max strategy price decrease before triggering a default\n  uint256 public maxDecreaseDefault;\n  // The tolerance for the loss socialized so equally distributed between junior and senior tranches.\n  uint256 public lossToleranceBps;\n  // Amount of stkIDLE required to mint 1 underlying\n  uint256 public stkIDLEPerUnderlying;\n  // uint256 public test;\n\n\n\n  // ####################### \n  // This is empty reserved space in storage that is put \n  // in place in Upgradeable contracts. It allows us to \n  // freely add new state variables in the future without \n  // compromising the storage compatibility with existing \n  // deployments.\n  // The size of the __gap array is calculated so that the \n  // amount of storage used by a contract always adds up to \n  // always the same number, 50 in this case.\n  uint256[46] private __gap;\n  // uint256[45] private __gap; -> after adding `test`\n  // #######################\n  // IMPORTANT: Do not add any variables below `__gap`\n}\n"
      },
      "contracts/IdleCDOTranche.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.10;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\n/// @dev ERC20 representing a tranche token\ncontract IdleCDOTranche is ERC20 {\n  // allowed minter address\n  address public minter;\n\n  /// @param _name tranche name\n  /// @param _symbol tranche symbol\n  constructor(\n    string memory _name, // eg. IdleDAI\n    string memory _symbol // eg. IDLEDAI\n  ) ERC20(_name, _symbol) {\n    // minter is msg.sender which is IdleCDO (in initialize)\n    minter = msg.sender;\n  }\n\n  /// @param account that should receive the tranche tokens\n  /// @param amount of tranche tokens to mint\n  function mint(address account, uint256 amount) external {\n    require(msg.sender == minter, 'TRANCHE:!AUTH');\n    _mint(account, amount);\n  }\n\n  /// @param account that should have the tranche tokens burned\n  /// @param amount of tranche tokens to burn\n  function burn(address account, uint256 amount) external {\n    require(msg.sender == minter, 'TRANCHE:!AUTH');\n    _burn(account, amount);\n  }\n}\n"
      },
      "contracts/interfaces/IERC20Detailed.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.10;\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\n\ninterface IERC20Detailed is IERC20Upgradeable {\n  function name() external view returns(string memory);\n  function symbol() external view returns(string memory);\n  function decimals() external view returns(uint256);\n}\n"
      },
      "contracts/interfaces/IIdleCDOStrategy.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.10;\n\ninterface IIdleCDOStrategy {\n  function strategyToken() external view returns(address);\n  function token() external view returns(address);\n  function tokenDecimals() external view returns(uint256);\n  function oneToken() external view returns(uint256);\n  function redeemRewards(bytes calldata _extraData) external returns(uint256[] memory);\n  function pullStkAAVE() external returns(uint256);\n  function price() external view returns(uint256);\n  function getRewardTokens() external view returns(address[] memory);\n  function deposit(uint256 _amount) external returns(uint256);\n  // _amount in `strategyToken`\n  function redeem(uint256 _amount) external returns(uint256);\n  // _amount in `token`\n  function redeemUnderlying(uint256 _amount) external returns(uint256);\n  function getApr() external view returns(uint256);\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 170
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}