{"abi":[{"type":"constructor","inputs":[{"name":"_spotPriceOracle","type":"address","internalType":"address"},{"name":"_Chainlink_BTC_USD_Spot","type":"bytes32","internalType":"bytes32"},{"name":"_Chainlink_WBTC_BTC_Spot","type":"bytes32","internalType":"bytes32"}],"stateMutability":"nonpayable"},{"name":"ErrorInvalidEncodings","type":"error","inputs":[]},{"name":"ErrorParameterUnchanged","type":"error","inputs":[]},{"name":"OwnableInvalidOwner","type":"error","inputs":[{"name":"owner","type":"address","internalType":"address"}]},{"name":"OwnableUnauthorizedAccount","type":"error","inputs":[{"name":"account","type":"address","internalType":"address"}]},{"name":"OwnershipTransferStarted","type":"event","inputs":[{"name":"previousOwner","type":"address","indexed":true,"internalType":"address"},{"name":"newOwner","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"name":"OwnershipTransferred","type":"event","inputs":[{"name":"previousOwner","type":"address","indexed":true,"internalType":"address"},{"name":"newOwner","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"name":"UpdateMaxPriceDeviation","type":"event","inputs":[{"name":"oldValue","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"newValue","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"name":"UpdateMaxWBTCDeviation","type":"event","inputs":[{"name":"oldValue","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"newValue","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"name":"Chainlink_BTC_USD_Spot","type":"function","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"name":"Chainlink_WBTC_BTC_Spot","type":"function","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"name":"acceptOwnership","type":"function","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"name":"getBTCDerivativeUSDAnchorPrice","type":"function","inputs":[{"name":"isRedeem","type":"bool","internalType":"bool"}],"outputs":[{"name":"price","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"getBTCDerivativeUSDSpotPrices","type":"function","inputs":[],"outputs":[{"name":"prices","type":"uint256[]","internalType":"uint256[]"}],"stateMutability":"view"},{"name":"getExchangePrice","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"getLiquidatePrice","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"getPrice","type":"function","inputs":[],"outputs":[{"name":"anchorPrice","type":"uint256","internalType":"uint256"},{"name":"minPrice","type":"uint256","internalType":"uint256"},{"name":"maxPrice","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"getRedeemPrice","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"maxPriceDeviation","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"maxWBTCDeviation","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"owner","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"pendingOwner","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"renounceOwnership","type":"function","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"name":"transferOwnership","type":"function","inputs":[{"name":"newOwner","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"updateMaxPriceDeviation","type":"function","inputs":[{"name":"newMaxPriceDeviation","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"updateMaxWBTCDeviation","type":"function","inputs":[{"name":"newMaxWBTCDeviation","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"updateOnchainSpotEncodings","type":"function","inputs":[{"name":"encodings","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"}],"sources":{"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.20;\n\nimport {IAccessControl} from \"@openzeppelin/contracts/access/IAccessControl.sol\";\nimport {ContextUpgradeable} from \"../utils/ContextUpgradeable.sol\";\nimport {ERC165Upgradeable} from \"../utils/introspection/ERC165Upgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n *     require(hasRole(MY_ROLE, msg.sender));\n *     ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {\n    struct RoleData {\n        mapping(address account => bool) hasRole;\n        bytes32 adminRole;\n    }\n\n    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n\n    /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl\n    struct AccessControlStorage {\n        mapping(bytes32 role => RoleData) _roles;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.AccessControl\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;\n\n    function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {\n        assembly {\n            $.slot := AccessControlStorageLocation\n        }\n    }\n\n    /**\n     * @dev Modifier that checks that an account has a specific role. Reverts\n     * with an {AccessControlUnauthorizedAccount} error including the required role.\n     */\n    modifier onlyRole(bytes32 role) {\n        _checkRole(role);\n        _;\n    }\n\n    function __AccessControl_init() internal onlyInitializing {\n    }\n\n    function __AccessControl_init_unchained() internal onlyInitializing {\n    }\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        return $._roles[role].hasRole[account];\n    }\n\n    /**\n     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n     */\n    function _checkRole(bytes32 role) internal view virtual {\n        _checkRole(role, _msgSender());\n    }\n\n    /**\n     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n     * is missing `role`.\n     */\n    function _checkRole(bytes32 role, address account) internal view virtual {\n        if (!hasRole(role, account)) {\n            revert AccessControlUnauthorizedAccount(account, role);\n        }\n    }\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        return $._roles[role].adminRole;\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n        _grantRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n        _revokeRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been revoked `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `callerConfirmation`.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n        if (callerConfirmation != _msgSender()) {\n            revert AccessControlBadConfirmation();\n        }\n\n        _revokeRole(role, callerConfirmation);\n    }\n\n    /**\n     * @dev Sets `adminRole` as ``role``'s admin role.\n     *\n     * Emits a {RoleAdminChanged} event.\n     */\n    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        bytes32 previousAdminRole = getRoleAdmin(role);\n        $._roles[role].adminRole = adminRole;\n        emit RoleAdminChanged(role, previousAdminRole, adminRole);\n    }\n\n    /**\n     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        if (!hasRole(role, account)) {\n            $._roles[role].hasRole[account] = true;\n            emit RoleGranted(role, account, _msgSender());\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        if (hasRole(role, account)) {\n            $._roles[role].hasRole[account] = false;\n            emit RoleRevoked(role, account, _msgSender());\n            return true;\n        } else {\n            return false;\n        }\n    }\n}\n"},"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.20;\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 Storage of the initializable contract.\n     *\n     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\n     * when using with upgradeable contracts.\n     *\n     * @custom:storage-location erc7201:openzeppelin.storage.Initializable\n     */\n    struct InitializableStorage {\n        /**\n         * @dev Indicates that the contract has been initialized.\n         */\n        uint64 _initialized;\n        /**\n         * @dev Indicates that the contract is in the process of being initialized.\n         */\n        bool _initializing;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Initializable\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\n\n    /**\n     * @dev The contract is already initialized.\n     */\n    error InvalidInitialization();\n\n    /**\n     * @dev The contract is not initializing.\n     */\n    error NotInitializing();\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint64 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 in the context of a constructor an `initializer` may be invoked any\n     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\n     * production.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier initializer() {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        // Cache values to avoid duplicated sloads\n        bool isTopLevelCall = !$._initializing;\n        uint64 initialized = $._initialized;\n\n        // Allowed calls:\n        // - initialSetup: the contract is not in the initializing state and no previous version was\n        //                 initialized\n        // - construction: the contract is initialized at version 1 (no reininitialization) and the\n        //                 current contract is just being deployed\n        bool initialSetup = initialized == 0 && isTopLevelCall;\n        bool construction = initialized == 1 && address(this).code.length == 0;\n\n        if (!initialSetup && !construction) {\n            revert InvalidInitialization();\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 2**64 - 1 will prevent any future reinitialization.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier reinitializer(uint64 version) {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        if ($._initializing || $._initialized >= version) {\n            revert InvalidInitialization();\n        }\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        _checkInitializing();\n        _;\n    }\n\n    /**\n     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\n     */\n    function _checkInitializing() internal view virtual {\n        if (!_isInitializing()) {\n            revert NotInitializing();\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        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        if ($._initializing) {\n            revert InvalidInitialization();\n        }\n        if ($._initialized != type(uint64).max) {\n            $._initialized = type(uint64).max;\n            emit Initialized(type(uint64).max);\n        }\n    }\n\n    /**\n     * @dev Returns the highest version that has been initialized. See {reinitializer}.\n     */\n    function _getInitializedVersion() internal view returns (uint64) {\n        return _getInitializableStorage()._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 _getInitializableStorage()._initializing;\n    }\n\n    /**\n     * @dev Returns a pointer to the storage namespace.\n     */\n    // solhint-disable-next-line var-name-mixedcase\n    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\n        assembly {\n            $.slot := INITIALIZABLE_STORAGE\n        }\n    }\n}\n"},"@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {IERC20Metadata} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport {ContextUpgradeable} from \"../../utils/ContextUpgradeable.sol\";\nimport {IERC20Errors} from \"@openzeppelin/contracts/interfaces/draft-IERC6093.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.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 *\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 */\nabstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, IERC20Metadata, IERC20Errors {\n    /// @custom:storage-location erc7201:openzeppelin.storage.ERC20\n    struct ERC20Storage {\n        mapping(address account => uint256) _balances;\n\n        mapping(address account => mapping(address spender => uint256)) _allowances;\n\n        uint256 _totalSupply;\n\n        string _name;\n        string _symbol;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.ERC20\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00;\n\n    function _getERC20Storage() private pure returns (ERC20Storage storage $) {\n        assembly {\n            $.slot := ERC20StorageLocation\n        }\n    }\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    function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {\n        __ERC20_init_unchained(name_, symbol_);\n    }\n\n    function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {\n        ERC20Storage storage $ = _getERC20Storage();\n        $._name = name_;\n        $._symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual returns (string memory) {\n        ERC20Storage storage $ = _getERC20Storage();\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 returns (string memory) {\n        ERC20Storage storage $ = _getERC20Storage();\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 returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual returns (uint256) {\n        ERC20Storage storage $ = _getERC20Storage();\n        return $._totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual returns (uint256) {\n        ERC20Storage storage $ = _getERC20Storage();\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 `value`.\n     */\n    function transfer(address to, uint256 value) public virtual returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, value);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual returns (uint256) {\n        ERC20Storage storage $ = _getERC20Storage();\n        return $._allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `value` 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 value) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, value);\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 `value`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `value`.\n     */\n    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, value);\n        _transfer(from, to, value);\n        return true;\n    }\n\n    /**\n     * @dev Moves a `value` 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     * NOTE: This function is not virtual, {_update} should be overridden instead.\n     */\n    function _transfer(address from, address to, uint256 value) internal {\n        if (from == address(0)) {\n            revert ERC20InvalidSender(address(0));\n        }\n        if (to == address(0)) {\n            revert ERC20InvalidReceiver(address(0));\n        }\n        _update(from, to, value);\n    }\n\n    /**\n     * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`\n     * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding\n     * this function.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _update(address from, address to, uint256 value) internal virtual {\n        ERC20Storage storage $ = _getERC20Storage();\n        if (from == address(0)) {\n            // Overflow check required: The rest of the code assumes that totalSupply never overflows\n            $._totalSupply += value;\n        } else {\n            uint256 fromBalance = $._balances[from];\n            if (fromBalance < value) {\n                revert ERC20InsufficientBalance(from, fromBalance, value);\n            }\n            unchecked {\n                // Overflow not possible: value <= fromBalance <= totalSupply.\n                $._balances[from] = fromBalance - value;\n            }\n        }\n\n        if (to == address(0)) {\n            unchecked {\n                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.\n                $._totalSupply -= value;\n            }\n        } else {\n            unchecked {\n                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.\n                $._balances[to] += value;\n            }\n        }\n\n        emit Transfer(from, to, value);\n    }\n\n    /**\n     * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).\n     * Relies on the `_update` mechanism\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * NOTE: This function is not virtual, {_update} should be overridden instead.\n     */\n    function _mint(address account, uint256 value) internal {\n        if (account == address(0)) {\n            revert ERC20InvalidReceiver(address(0));\n        }\n        _update(address(0), account, value);\n    }\n\n    /**\n     * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.\n     * Relies on the `_update` mechanism.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * NOTE: This function is not virtual, {_update} should be overridden instead\n     */\n    function _burn(address account, uint256 value) internal {\n        if (account == address(0)) {\n            revert ERC20InvalidSender(address(0));\n        }\n        _update(account, address(0), value);\n    }\n\n    /**\n     * @dev Sets `value` 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     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.\n     */\n    function _approve(address owner, address spender, uint256 value) internal {\n        _approve(owner, spender, value, true);\n    }\n\n    /**\n     * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.\n     *\n     * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by\n     * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any\n     * `Approval` event during `transferFrom` operations.\n     *\n     * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to\n     * true using the following override:\n     * ```\n     * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {\n     *     super._approve(owner, spender, value, true);\n     * }\n     * ```\n     *\n     * Requirements are the same as {_approve}.\n     */\n    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {\n        ERC20Storage storage $ = _getERC20Storage();\n        if (owner == address(0)) {\n            revert ERC20InvalidApprover(address(0));\n        }\n        if (spender == address(0)) {\n            revert ERC20InvalidSpender(address(0));\n        }\n        $._allowances[owner][spender] = value;\n        if (emitEvent) {\n            emit Approval(owner, spender, value);\n        }\n    }\n\n    /**\n     * @dev Updates `owner` s allowance for `spender` based on spent `value`.\n     *\n     * Does not update the allowance value in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Does not emit an {Approval} event.\n     */\n    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            if (currentAllowance < value) {\n                revert ERC20InsufficientAllowance(spender, currentAllowance, value);\n            }\n            unchecked {\n                _approve(owner, spender, currentAllowance - value, false);\n            }\n        }\n    }\n}\n"},"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Permit.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20Permit} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\";\nimport {ERC20Upgradeable} from \"../ERC20Upgradeable.sol\";\nimport {ECDSA} from \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport {EIP712Upgradeable} from \"../../../utils/cryptography/EIP712Upgradeable.sol\";\nimport {NoncesUpgradeable} from \"../../../utils/NoncesUpgradeable.sol\";\nimport {Initializable} from \"../../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation 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 */\nabstract contract ERC20PermitUpgradeable is Initializable, ERC20Upgradeable, IERC20Permit, EIP712Upgradeable, NoncesUpgradeable {\n    bytes32 private constant PERMIT_TYPEHASH =\n        keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n\n    /**\n     * @dev Permit deadline has expired.\n     */\n    error ERC2612ExpiredSignature(uint256 deadline);\n\n    /**\n     * @dev Mismatched signature.\n     */\n    error ERC2612InvalidSigner(address signer, address owner);\n\n    /**\n     * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\"1\"`.\n     *\n     * It's a good idea to use the same `name` that is defined as the ERC20 token name.\n     */\n    function __ERC20Permit_init(string memory name) internal onlyInitializing {\n        __EIP712_init_unchained(name, \"1\");\n    }\n\n    function __ERC20Permit_init_unchained(string memory) internal onlyInitializing {}\n\n    /**\n     * @inheritdoc IERC20Permit\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    ) public virtual {\n        if (block.timestamp > deadline) {\n            revert ERC2612ExpiredSignature(deadline);\n        }\n\n        bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));\n\n        bytes32 hash = _hashTypedDataV4(structHash);\n\n        address signer = ECDSA.recover(hash, v, r, s);\n        if (signer != owner) {\n            revert ERC2612InvalidSigner(signer, owner);\n        }\n\n        _approve(owner, spender, value);\n    }\n\n    /**\n     * @inheritdoc IERC20Permit\n     */\n    function nonces(address owner) public view virtual override(IERC20Permit, NoncesUpgradeable) returns (uint256) {\n        return super.nonces(owner);\n    }\n\n    /**\n     * @inheritdoc IERC20Permit\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view virtual returns (bytes32) {\n        return _domainSeparatorV4();\n    }\n}\n"},"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC4626Upgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC4626.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {IERC20Metadata} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport {ERC20Upgradeable} from \"../ERC20Upgradeable.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {IERC4626} from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport {Initializable} from \"../../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the ERC4626 \"Tokenized Vault Standard\" as defined in\n * https://eips.ethereum.org/EIPS/eip-4626[EIP-4626].\n *\n * This extension allows the minting and burning of \"shares\" (represented using the ERC20 inheritance) in exchange for\n * underlying \"assets\" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends\n * the ERC20 standard. Any additional extensions included along it would affect the \"shares\" token represented by this\n * contract and not the \"assets\" token which is an independent contract.\n *\n * [CAUTION]\n * ====\n * In empty (or nearly empty) ERC-4626 vaults, deposits are at high risk of being stolen through frontrunning\n * with a \"donation\" to the vault that inflates the price of a share. This is variously known as a donation or inflation\n * attack and is essentially a problem of slippage. Vault deployers can protect against this attack by making an initial\n * deposit of a non-trivial amount of the asset, such that price manipulation becomes infeasible. Withdrawals may\n * similarly be affected by slippage. Users can protect against this attack as well as unexpected slippage in general by\n * verifying the amount received is as expected, using a wrapper that performs these checks such as\n * https://github.com/fei-protocol/ERC4626#erc4626router-and-base[ERC4626Router].\n *\n * Since v4.9, this implementation uses virtual assets and shares to mitigate that risk. The `_decimalsOffset()`\n * corresponds to an offset in the decimal representation between the underlying asset's decimals and the vault\n * decimals. This offset also determines the rate of virtual shares to virtual assets in the vault, which itself\n * determines the initial exchange rate. While not fully preventing the attack, analysis shows that the default offset\n * (0) makes it non-profitable, as a result of the value being captured by the virtual shares (out of the attacker's\n * donation) matching the attacker's expected gains. With a larger offset, the attack becomes orders of magnitude more\n * expensive than it is profitable. More details about the underlying math can be found\n * xref:erc4626.adoc#inflation-attack[here].\n *\n * The drawback of this approach is that the virtual shares do capture (a very small) part of the value being accrued\n * to the vault. Also, if the vault experiences losses, the users try to exit the vault, the virtual shares and assets\n * will cause the first user to exit to experience reduced losses in detriment to the last users that will experience\n * bigger losses. Developers willing to revert back to the pre-v4.9 behavior just need to override the\n * `_convertToShares` and `_convertToAssets` functions.\n *\n * To learn more, check out our xref:ROOT:erc4626.adoc[ERC-4626 guide].\n * ====\n */\nabstract contract ERC4626Upgradeable is Initializable, ERC20Upgradeable, IERC4626 {\n    using Math for uint256;\n\n    /// @custom:storage-location erc7201:openzeppelin.storage.ERC4626\n    struct ERC4626Storage {\n        IERC20 _asset;\n        uint8 _underlyingDecimals;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.ERC4626\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant ERC4626StorageLocation = 0x0773e532dfede91f04b12a73d3d2acd361424f41f76b4fb79f090161e36b4e00;\n\n    function _getERC4626Storage() private pure returns (ERC4626Storage storage $) {\n        assembly {\n            $.slot := ERC4626StorageLocation\n        }\n    }\n\n    /**\n     * @dev Attempted to deposit more assets than the max amount for `receiver`.\n     */\n    error ERC4626ExceededMaxDeposit(address receiver, uint256 assets, uint256 max);\n\n    /**\n     * @dev Attempted to mint more shares than the max amount for `receiver`.\n     */\n    error ERC4626ExceededMaxMint(address receiver, uint256 shares, uint256 max);\n\n    /**\n     * @dev Attempted to withdraw more assets than the max amount for `receiver`.\n     */\n    error ERC4626ExceededMaxWithdraw(address owner, uint256 assets, uint256 max);\n\n    /**\n     * @dev Attempted to redeem more shares than the max amount for `receiver`.\n     */\n    error ERC4626ExceededMaxRedeem(address owner, uint256 shares, uint256 max);\n\n    /**\n     * @dev Set the underlying asset contract. This must be an ERC20-compatible contract (ERC20 or ERC777).\n     */\n    function __ERC4626_init(IERC20 asset_) internal onlyInitializing {\n        __ERC4626_init_unchained(asset_);\n    }\n\n    function __ERC4626_init_unchained(IERC20 asset_) internal onlyInitializing {\n        ERC4626Storage storage $ = _getERC4626Storage();\n        (bool success, uint8 assetDecimals) = _tryGetAssetDecimals(asset_);\n        $._underlyingDecimals = success ? assetDecimals : 18;\n        $._asset = asset_;\n    }\n\n    /**\n     * @dev Attempts to fetch the asset decimals. A return value of false indicates that the attempt failed in some way.\n     */\n    function _tryGetAssetDecimals(IERC20 asset_) private view returns (bool, uint8) {\n        (bool success, bytes memory encodedDecimals) = address(asset_).staticcall(\n            abi.encodeCall(IERC20Metadata.decimals, ())\n        );\n        if (success && encodedDecimals.length >= 32) {\n            uint256 returnedDecimals = abi.decode(encodedDecimals, (uint256));\n            if (returnedDecimals <= type(uint8).max) {\n                return (true, uint8(returnedDecimals));\n            }\n        }\n        return (false, 0);\n    }\n\n    /**\n     * @dev Decimals are computed by adding the decimal offset on top of the underlying asset's decimals. This\n     * \"original\" value is cached during construction of the vault contract. If this read operation fails (e.g., the\n     * asset has not been created yet), a default of 18 is used to represent the underlying asset's decimals.\n     *\n     * See {IERC20Metadata-decimals}.\n     */\n    function decimals() public view virtual override(IERC20Metadata, ERC20Upgradeable) returns (uint8) {\n        ERC4626Storage storage $ = _getERC4626Storage();\n        return $._underlyingDecimals + _decimalsOffset();\n    }\n\n    /** @dev See {IERC4626-asset}. */\n    function asset() public view virtual returns (address) {\n        ERC4626Storage storage $ = _getERC4626Storage();\n        return address($._asset);\n    }\n\n    /** @dev See {IERC4626-totalAssets}. */\n    function totalAssets() public view virtual returns (uint256) {\n        ERC4626Storage storage $ = _getERC4626Storage();\n        return $._asset.balanceOf(address(this));\n    }\n\n    /** @dev See {IERC4626-convertToShares}. */\n    function convertToShares(uint256 assets) public view virtual returns (uint256) {\n        return _convertToShares(assets, Math.Rounding.Floor);\n    }\n\n    /** @dev See {IERC4626-convertToAssets}. */\n    function convertToAssets(uint256 shares) public view virtual returns (uint256) {\n        return _convertToAssets(shares, Math.Rounding.Floor);\n    }\n\n    /** @dev See {IERC4626-maxDeposit}. */\n    function maxDeposit(address) public view virtual returns (uint256) {\n        return type(uint256).max;\n    }\n\n    /** @dev See {IERC4626-maxMint}. */\n    function maxMint(address) public view virtual returns (uint256) {\n        return type(uint256).max;\n    }\n\n    /** @dev See {IERC4626-maxWithdraw}. */\n    function maxWithdraw(address owner) public view virtual returns (uint256) {\n        return _convertToAssets(balanceOf(owner), Math.Rounding.Floor);\n    }\n\n    /** @dev See {IERC4626-maxRedeem}. */\n    function maxRedeem(address owner) public view virtual returns (uint256) {\n        return balanceOf(owner);\n    }\n\n    /** @dev See {IERC4626-previewDeposit}. */\n    function previewDeposit(uint256 assets) public view virtual returns (uint256) {\n        return _convertToShares(assets, Math.Rounding.Floor);\n    }\n\n    /** @dev See {IERC4626-previewMint}. */\n    function previewMint(uint256 shares) public view virtual returns (uint256) {\n        return _convertToAssets(shares, Math.Rounding.Ceil);\n    }\n\n    /** @dev See {IERC4626-previewWithdraw}. */\n    function previewWithdraw(uint256 assets) public view virtual returns (uint256) {\n        return _convertToShares(assets, Math.Rounding.Ceil);\n    }\n\n    /** @dev See {IERC4626-previewRedeem}. */\n    function previewRedeem(uint256 shares) public view virtual returns (uint256) {\n        return _convertToAssets(shares, Math.Rounding.Floor);\n    }\n\n    /** @dev See {IERC4626-deposit}. */\n    function deposit(uint256 assets, address receiver) public virtual returns (uint256) {\n        uint256 maxAssets = maxDeposit(receiver);\n        if (assets > maxAssets) {\n            revert ERC4626ExceededMaxDeposit(receiver, assets, maxAssets);\n        }\n\n        uint256 shares = previewDeposit(assets);\n        _deposit(_msgSender(), receiver, assets, shares);\n\n        return shares;\n    }\n\n    /** @dev See {IERC4626-mint}.\n     *\n     * As opposed to {deposit}, minting is allowed even if the vault is in a state where the price of a share is zero.\n     * In this case, the shares will be minted without requiring any assets to be deposited.\n     */\n    function mint(uint256 shares, address receiver) public virtual returns (uint256) {\n        uint256 maxShares = maxMint(receiver);\n        if (shares > maxShares) {\n            revert ERC4626ExceededMaxMint(receiver, shares, maxShares);\n        }\n\n        uint256 assets = previewMint(shares);\n        _deposit(_msgSender(), receiver, assets, shares);\n\n        return assets;\n    }\n\n    /** @dev See {IERC4626-withdraw}. */\n    function withdraw(uint256 assets, address receiver, address owner) public virtual returns (uint256) {\n        uint256 maxAssets = maxWithdraw(owner);\n        if (assets > maxAssets) {\n            revert ERC4626ExceededMaxWithdraw(owner, assets, maxAssets);\n        }\n\n        uint256 shares = previewWithdraw(assets);\n        _withdraw(_msgSender(), receiver, owner, assets, shares);\n\n        return shares;\n    }\n\n    /** @dev See {IERC4626-redeem}. */\n    function redeem(uint256 shares, address receiver, address owner) public virtual returns (uint256) {\n        uint256 maxShares = maxRedeem(owner);\n        if (shares > maxShares) {\n            revert ERC4626ExceededMaxRedeem(owner, shares, maxShares);\n        }\n\n        uint256 assets = previewRedeem(shares);\n        _withdraw(_msgSender(), receiver, owner, assets, shares);\n\n        return assets;\n    }\n\n    /**\n     * @dev Internal conversion function (from assets to shares) with support for rounding direction.\n     */\n    function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256) {\n        return assets.mulDiv(totalSupply() + 10 ** _decimalsOffset(), totalAssets() + 1, rounding);\n    }\n\n    /**\n     * @dev Internal conversion function (from shares to assets) with support for rounding direction.\n     */\n    function _convertToAssets(uint256 shares, Math.Rounding rounding) internal view virtual returns (uint256) {\n        return shares.mulDiv(totalAssets() + 1, totalSupply() + 10 ** _decimalsOffset(), rounding);\n    }\n\n    /**\n     * @dev Deposit/mint common workflow.\n     */\n    function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal virtual {\n        ERC4626Storage storage $ = _getERC4626Storage();\n        // If _asset is ERC777, `transferFrom` can trigger a reentrancy BEFORE the transfer happens through the\n        // `tokensToSend` hook. On the other hand, the `tokenReceived` hook, that is triggered after the transfer,\n        // calls the vault, which is assumed not malicious.\n        //\n        // Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the\n        // assets are transferred and before the shares are minted, which is a valid state.\n        // slither-disable-next-line reentrancy-no-eth\n        SafeERC20.safeTransferFrom($._asset, caller, address(this), assets);\n        _mint(receiver, shares);\n\n        emit Deposit(caller, receiver, assets, shares);\n    }\n\n    /**\n     * @dev Withdraw/redeem common workflow.\n     */\n    function _withdraw(\n        address caller,\n        address receiver,\n        address owner,\n        uint256 assets,\n        uint256 shares\n    ) internal virtual {\n        ERC4626Storage storage $ = _getERC4626Storage();\n        if (caller != owner) {\n            _spendAllowance(owner, caller, shares);\n        }\n\n        // If _asset is ERC777, `transfer` can trigger a reentrancy AFTER the transfer happens through the\n        // `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer,\n        // calls the vault, which is assumed not malicious.\n        //\n        // Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the\n        // shares are burned and after the assets are transferred, which is a valid state.\n        _burn(owner, shares);\n        SafeERC20.safeTransfer($._asset, receiver, assets);\n\n        emit Withdraw(caller, receiver, owner, assets, shares);\n    }\n\n    function _decimalsOffset() internal view virtual returns (uint8) {\n        return 0;\n    }\n}\n"},"@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/ERC721.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC721} from \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\nimport {IERC721Receiver} from \"@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol\";\nimport {IERC721Metadata} from \"@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol\";\nimport {ContextUpgradeable} from \"../../utils/ContextUpgradeable.sol\";\nimport {Strings} from \"@openzeppelin/contracts/utils/Strings.sol\";\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {ERC165Upgradeable} from \"../../utils/introspection/ERC165Upgradeable.sol\";\nimport {IERC721Errors} from \"@openzeppelin/contracts/interfaces/draft-IERC6093.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including\n * the Metadata extension, but not including the Enumerable extension, which is available separately as\n * {ERC721Enumerable}.\n */\nabstract contract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721, IERC721Metadata, IERC721Errors {\n    using Strings for uint256;\n\n    /// @custom:storage-location erc7201:openzeppelin.storage.ERC721\n    struct ERC721Storage {\n        // Token name\n        string _name;\n\n        // Token symbol\n        string _symbol;\n\n        mapping(uint256 tokenId => address) _owners;\n\n        mapping(address owner => uint256) _balances;\n\n        mapping(uint256 tokenId => address) _tokenApprovals;\n\n        mapping(address owner => mapping(address operator => bool)) _operatorApprovals;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.ERC721\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant ERC721StorageLocation = 0x80bb2b638cc20bc4d0a60d66940f3ab4a00c1d7b313497ca82fb0b4ab0079300;\n\n    function _getERC721Storage() private pure returns (ERC721Storage storage $) {\n        assembly {\n            $.slot := ERC721StorageLocation\n        }\n    }\n\n    /**\n     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.\n     */\n    function __ERC721_init(string memory name_, string memory symbol_) internal onlyInitializing {\n        __ERC721_init_unchained(name_, symbol_);\n    }\n\n    function __ERC721_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {\n        ERC721Storage storage $ = _getERC721Storage();\n        $._name = name_;\n        $._symbol = symbol_;\n    }\n\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165) returns (bool) {\n        return\n            interfaceId == type(IERC721).interfaceId ||\n            interfaceId == type(IERC721Metadata).interfaceId ||\n            super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev See {IERC721-balanceOf}.\n     */\n    function balanceOf(address owner) public view virtual returns (uint256) {\n        ERC721Storage storage $ = _getERC721Storage();\n        if (owner == address(0)) {\n            revert ERC721InvalidOwner(address(0));\n        }\n        return $._balances[owner];\n    }\n\n    /**\n     * @dev See {IERC721-ownerOf}.\n     */\n    function ownerOf(uint256 tokenId) public view virtual returns (address) {\n        return _requireOwned(tokenId);\n    }\n\n    /**\n     * @dev See {IERC721Metadata-name}.\n     */\n    function name() public view virtual returns (string memory) {\n        ERC721Storage storage $ = _getERC721Storage();\n        return $._name;\n    }\n\n    /**\n     * @dev See {IERC721Metadata-symbol}.\n     */\n    function symbol() public view virtual returns (string memory) {\n        ERC721Storage storage $ = _getERC721Storage();\n        return $._symbol;\n    }\n\n    /**\n     * @dev See {IERC721Metadata-tokenURI}.\n     */\n    function tokenURI(uint256 tokenId) public view virtual returns (string memory) {\n        _requireOwned(tokenId);\n\n        string memory baseURI = _baseURI();\n        return bytes(baseURI).length > 0 ? string.concat(baseURI, tokenId.toString()) : \"\";\n    }\n\n    /**\n     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each\n     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty\n     * by default, can be overridden in child contracts.\n     */\n    function _baseURI() internal view virtual returns (string memory) {\n        return \"\";\n    }\n\n    /**\n     * @dev See {IERC721-approve}.\n     */\n    function approve(address to, uint256 tokenId) public virtual {\n        _approve(to, tokenId, _msgSender());\n    }\n\n    /**\n     * @dev See {IERC721-getApproved}.\n     */\n    function getApproved(uint256 tokenId) public view virtual returns (address) {\n        _requireOwned(tokenId);\n\n        return _getApproved(tokenId);\n    }\n\n    /**\n     * @dev See {IERC721-setApprovalForAll}.\n     */\n    function setApprovalForAll(address operator, bool approved) public virtual {\n        _setApprovalForAll(_msgSender(), operator, approved);\n    }\n\n    /**\n     * @dev See {IERC721-isApprovedForAll}.\n     */\n    function isApprovedForAll(address owner, address operator) public view virtual returns (bool) {\n        ERC721Storage storage $ = _getERC721Storage();\n        return $._operatorApprovals[owner][operator];\n    }\n\n    /**\n     * @dev See {IERC721-transferFrom}.\n     */\n    function transferFrom(address from, address to, uint256 tokenId) public virtual {\n        if (to == address(0)) {\n            revert ERC721InvalidReceiver(address(0));\n        }\n        // Setting an \"auth\" arguments enables the `_isAuthorized` check which verifies that the token exists\n        // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here.\n        address previousOwner = _update(to, tokenId, _msgSender());\n        if (previousOwner != from) {\n            revert ERC721IncorrectOwner(from, tokenId, previousOwner);\n        }\n    }\n\n    /**\n     * @dev See {IERC721-safeTransferFrom}.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId) public {\n        safeTransferFrom(from, to, tokenId, \"\");\n    }\n\n    /**\n     * @dev See {IERC721-safeTransferFrom}.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual {\n        transferFrom(from, to, tokenId);\n        _checkOnERC721Received(from, to, tokenId, data);\n    }\n\n    /**\n     * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist\n     *\n     * IMPORTANT: Any overrides to this function that add ownership of tokens not tracked by the\n     * core ERC721 logic MUST be matched with the use of {_increaseBalance} to keep balances\n     * consistent with ownership. The invariant to preserve is that for any address `a` the value returned by\n     * `balanceOf(a)` must be equal to the number of tokens such that `_ownerOf(tokenId)` is `a`.\n     */\n    function _ownerOf(uint256 tokenId) internal view virtual returns (address) {\n        ERC721Storage storage $ = _getERC721Storage();\n        return $._owners[tokenId];\n    }\n\n    /**\n     * @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted.\n     */\n    function _getApproved(uint256 tokenId) internal view virtual returns (address) {\n        ERC721Storage storage $ = _getERC721Storage();\n        return $._tokenApprovals[tokenId];\n    }\n\n    /**\n     * @dev Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in\n     * particular (ignoring whether it is owned by `owner`).\n     *\n     * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this\n     * assumption.\n     */\n    function _isAuthorized(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) {\n        return\n            spender != address(0) &&\n            (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender);\n    }\n\n    /**\n     * @dev Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner.\n     * Reverts if `spender` does not have approval from the provided `owner` for the given token or for all its assets\n     * the `spender` for the specific `tokenId`.\n     *\n     * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this\n     * assumption.\n     */\n    function _checkAuthorized(address owner, address spender, uint256 tokenId) internal view virtual {\n        if (!_isAuthorized(owner, spender, tokenId)) {\n            if (owner == address(0)) {\n                revert ERC721NonexistentToken(tokenId);\n            } else {\n                revert ERC721InsufficientApproval(spender, tokenId);\n            }\n        }\n    }\n\n    /**\n     * @dev Unsafe write access to the balances, used by extensions that \"mint\" tokens using an {ownerOf} override.\n     *\n     * NOTE: the value is limited to type(uint128).max. This protect against _balance overflow. It is unrealistic that\n     * a uint256 would ever overflow from increments when these increments are bounded to uint128 values.\n     *\n     * WARNING: Increasing an account's balance using this function tends to be paired with an override of the\n     * {_ownerOf} function to resolve the ownership of the corresponding tokens so that balances and ownership\n     * remain consistent with one another.\n     */\n    function _increaseBalance(address account, uint128 value) internal virtual {\n        ERC721Storage storage $ = _getERC721Storage();\n        unchecked {\n            $._balances[account] += value;\n        }\n    }\n\n    /**\n     * @dev Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner\n     * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update.\n     *\n     * The `auth` argument is optional. If the value passed is non 0, then this function will check that\n     * `auth` is either the owner of the token, or approved to operate on the token (by the owner).\n     *\n     * Emits a {Transfer} event.\n     *\n     * NOTE: If overriding this function in a way that tracks balances, see also {_increaseBalance}.\n     */\n    function _update(address to, uint256 tokenId, address auth) internal virtual returns (address) {\n        ERC721Storage storage $ = _getERC721Storage();\n        address from = _ownerOf(tokenId);\n\n        // Perform (optional) operator check\n        if (auth != address(0)) {\n            _checkAuthorized(from, auth, tokenId);\n        }\n\n        // Execute the update\n        if (from != address(0)) {\n            // Clear approval. No need to re-authorize or emit the Approval event\n            _approve(address(0), tokenId, address(0), false);\n\n            unchecked {\n                $._balances[from] -= 1;\n            }\n        }\n\n        if (to != address(0)) {\n            unchecked {\n                $._balances[to] += 1;\n            }\n        }\n\n        $._owners[tokenId] = to;\n\n        emit Transfer(from, to, tokenId);\n\n        return from;\n    }\n\n    /**\n     * @dev Mints `tokenId` and transfers it to `to`.\n     *\n     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible\n     *\n     * Requirements:\n     *\n     * - `tokenId` must not exist.\n     * - `to` cannot be the zero address.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _mint(address to, uint256 tokenId) internal {\n        if (to == address(0)) {\n            revert ERC721InvalidReceiver(address(0));\n        }\n        address previousOwner = _update(to, tokenId, address(0));\n        if (previousOwner != address(0)) {\n            revert ERC721InvalidSender(address(0));\n        }\n    }\n\n    /**\n     * @dev Mints `tokenId`, transfers it to `to` and checks for `to` acceptance.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must not exist.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _safeMint(address to, uint256 tokenId) internal {\n        _safeMint(to, tokenId, \"\");\n    }\n\n    /**\n     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is\n     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.\n     */\n    function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual {\n        _mint(to, tokenId);\n        _checkOnERC721Received(address(0), to, tokenId, data);\n    }\n\n    /**\n     * @dev Destroys `tokenId`.\n     * The approval is cleared when the token is burned.\n     * This is an internal function that does not check if the sender is authorized to operate on the token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _burn(uint256 tokenId) internal {\n        address previousOwner = _update(address(0), tokenId, address(0));\n        if (previousOwner == address(0)) {\n            revert ERC721NonexistentToken(tokenId);\n        }\n    }\n\n    /**\n     * @dev Transfers `tokenId` from `from` to `to`.\n     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _transfer(address from, address to, uint256 tokenId) internal {\n        if (to == address(0)) {\n            revert ERC721InvalidReceiver(address(0));\n        }\n        address previousOwner = _update(to, tokenId, address(0));\n        if (previousOwner == address(0)) {\n            revert ERC721NonexistentToken(tokenId);\n        } else if (previousOwner != from) {\n            revert ERC721IncorrectOwner(from, tokenId, previousOwner);\n        }\n    }\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking that contract recipients\n     * are aware of the ERC721 standard to prevent tokens from being forever locked.\n     *\n     * `data` is additional data, it has no specified format and it is sent in call to `to`.\n     *\n     * This internal function is like {safeTransferFrom} in the sense that it invokes\n     * {IERC721Receiver-onERC721Received} on the receiver, and can be used to e.g.\n     * implement alternative mechanisms to perform token transfer, such as signature-based.\n     *\n     * Requirements:\n     *\n     * - `tokenId` token must exist and be owned by `from`.\n     * - `to` cannot be the zero address.\n     * - `from` cannot be the zero address.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _safeTransfer(address from, address to, uint256 tokenId) internal {\n        _safeTransfer(from, to, tokenId, \"\");\n    }\n\n    /**\n     * @dev Same as {xref-ERC721-_safeTransfer-address-address-uint256-}[`_safeTransfer`], with an additional `data` parameter which is\n     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.\n     */\n    function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual {\n        _transfer(from, to, tokenId);\n        _checkOnERC721Received(from, to, tokenId, data);\n    }\n\n    /**\n     * @dev Approve `to` to operate on `tokenId`\n     *\n     * The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is\n     * either the owner of the token, or approved to operate on all tokens held by this owner.\n     *\n     * Emits an {Approval} event.\n     *\n     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.\n     */\n    function _approve(address to, uint256 tokenId, address auth) internal {\n        _approve(to, tokenId, auth, true);\n    }\n\n    /**\n     * @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not\n     * emitted in the context of transfers.\n     */\n    function _approve(address to, uint256 tokenId, address auth, bool emitEvent) internal virtual {\n        ERC721Storage storage $ = _getERC721Storage();\n        // Avoid reading the owner unless necessary\n        if (emitEvent || auth != address(0)) {\n            address owner = _requireOwned(tokenId);\n\n            // We do not use _isAuthorized because single-token approvals should not be able to call approve\n            if (auth != address(0) && owner != auth && !isApprovedForAll(owner, auth)) {\n                revert ERC721InvalidApprover(auth);\n            }\n\n            if (emitEvent) {\n                emit Approval(owner, to, tokenId);\n            }\n        }\n\n        $._tokenApprovals[tokenId] = to;\n    }\n\n    /**\n     * @dev Approve `operator` to operate on all of `owner` tokens\n     *\n     * Requirements:\n     * - operator can't be the address zero.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {\n        ERC721Storage storage $ = _getERC721Storage();\n        if (operator == address(0)) {\n            revert ERC721InvalidOperator(operator);\n        }\n        $._operatorApprovals[owner][operator] = approved;\n        emit ApprovalForAll(owner, operator, approved);\n    }\n\n    /**\n     * @dev Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned).\n     * Returns the owner.\n     *\n     * Overrides to ownership logic should be done to {_ownerOf}.\n     */\n    function _requireOwned(uint256 tokenId) internal view returns (address) {\n        address owner = _ownerOf(tokenId);\n        if (owner == address(0)) {\n            revert ERC721NonexistentToken(tokenId);\n        }\n        return owner;\n    }\n\n    /**\n     * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target address. This will revert if the\n     * recipient doesn't accept the token transfer. The call is not executed if the target address is not a contract.\n     *\n     * @param from address representing the previous owner of the given token ID\n     * @param to target address that will receive the tokens\n     * @param tokenId uint256 ID of the token to be transferred\n     * @param data bytes optional data to send along with the call\n     */\n    function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data) private {\n        if (to.code.length > 0) {\n            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {\n                if (retval != IERC721Receiver.onERC721Received.selector) {\n                    revert ERC721InvalidReceiver(to);\n                }\n            } catch (bytes memory reason) {\n                if (reason.length == 0) {\n                    revert ERC721InvalidReceiver(to);\n                } else {\n                    /// @solidity memory-safe-assembly\n                    assembly {\n                        revert(add(32, reason), mload(reason))\n                    }\n                }\n            }\n        }\n    }\n}\n"},"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../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    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"},"@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol)\n\npragma solidity ^0.8.20;\n\nimport {MessageHashUtils} from \"@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol\";\nimport {IERC5267} from \"@openzeppelin/contracts/interfaces/IERC5267.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose\n * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract\n * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to\n * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain\n * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the\n * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.\n */\nabstract contract EIP712Upgradeable is Initializable, IERC5267 {\n    bytes32 private constant TYPE_HASH =\n        keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\");\n\n    /// @custom:storage-location erc7201:openzeppelin.storage.EIP712\n    struct EIP712Storage {\n        /// @custom:oz-renamed-from _HASHED_NAME\n        bytes32 _hashedName;\n        /// @custom:oz-renamed-from _HASHED_VERSION\n        bytes32 _hashedVersion;\n\n        string _name;\n        string _version;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.EIP712\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant EIP712StorageLocation = 0xa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100;\n\n    function _getEIP712Storage() private pure returns (EIP712Storage storage $) {\n        assembly {\n            $.slot := EIP712StorageLocation\n        }\n    }\n\n    /**\n     * @dev Initializes the domain separator and parameter caches.\n     *\n     * The meaning of `name` and `version` is specified in\n     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n     *\n     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n     * - `version`: the current major version of the signing domain.\n     *\n     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n     * contract upgrade].\n     */\n    function __EIP712_init(string memory name, string memory version) internal onlyInitializing {\n        __EIP712_init_unchained(name, version);\n    }\n\n    function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {\n        EIP712Storage storage $ = _getEIP712Storage();\n        $._name = name;\n        $._version = version;\n\n        // Reset prior values in storage if upgrading\n        $._hashedName = 0;\n        $._hashedVersion = 0;\n    }\n\n    /**\n     * @dev Returns the domain separator for the current chain.\n     */\n    function _domainSeparatorV4() internal view returns (bytes32) {\n        return _buildDomainSeparator();\n    }\n\n    function _buildDomainSeparator() private view returns (bytes32) {\n        return keccak256(abi.encode(TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(this)));\n    }\n\n    /**\n     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n     * function returns the hash of the fully encoded EIP712 message for this domain.\n     *\n     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n     *\n     * ```solidity\n     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n     *     keccak256(\"Mail(address to,string contents)\"),\n     *     mailTo,\n     *     keccak256(bytes(mailContents))\n     * )));\n     * address signer = ECDSA.recover(digest, signature);\n     * ```\n     */\n    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n        return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);\n    }\n\n    /**\n     * @dev See {IERC-5267}.\n     */\n    function eip712Domain()\n        public\n        view\n        virtual\n        returns (\n            bytes1 fields,\n            string memory name,\n            string memory version,\n            uint256 chainId,\n            address verifyingContract,\n            bytes32 salt,\n            uint256[] memory extensions\n        )\n    {\n        EIP712Storage storage $ = _getEIP712Storage();\n        // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized\n        // and the EIP712 domain is not reliable, as it will be missing name and version.\n        require($._hashedName == 0 && $._hashedVersion == 0, \"EIP712: Uninitialized\");\n\n        return (\n            hex\"0f\", // 01111\n            _EIP712Name(),\n            _EIP712Version(),\n            block.chainid,\n            address(this),\n            bytes32(0),\n            new uint256[](0)\n        );\n    }\n\n    /**\n     * @dev The name parameter for the EIP712 domain.\n     *\n     * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs\n     * are a concern.\n     */\n    function _EIP712Name() internal view virtual returns (string memory) {\n        EIP712Storage storage $ = _getEIP712Storage();\n        return $._name;\n    }\n\n    /**\n     * @dev The version parameter for the EIP712 domain.\n     *\n     * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs\n     * are a concern.\n     */\n    function _EIP712Version() internal view virtual returns (string memory) {\n        EIP712Storage storage $ = _getEIP712Storage();\n        return $._version;\n    }\n\n    /**\n     * @dev The hash of the name parameter for the EIP712 domain.\n     *\n     * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead.\n     */\n    function _EIP712NameHash() internal view returns (bytes32) {\n        EIP712Storage storage $ = _getEIP712Storage();\n        string memory name = _EIP712Name();\n        if (bytes(name).length > 0) {\n            return keccak256(bytes(name));\n        } else {\n            // If the name is empty, the contract may have been upgraded without initializing the new storage.\n            // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design.\n            bytes32 hashedName = $._hashedName;\n            if (hashedName != 0) {\n                return hashedName;\n            } else {\n                return keccak256(\"\");\n            }\n        }\n    }\n\n    /**\n     * @dev The hash of the version parameter for the EIP712 domain.\n     *\n     * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead.\n     */\n    function _EIP712VersionHash() internal view returns (bytes32) {\n        EIP712Storage storage $ = _getEIP712Storage();\n        string memory version = _EIP712Version();\n        if (bytes(version).length > 0) {\n            return keccak256(bytes(version));\n        } else {\n            // If the version is empty, the contract may have been upgraded without initializing the new storage.\n            // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design.\n            bytes32 hashedVersion = $._hashedVersion;\n            if (hashedVersion != 0) {\n                return hashedVersion;\n            } else {\n                return keccak256(\"\");\n            }\n        }\n    }\n}\n"},"@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165Upgradeable is Initializable, IERC165 {\n    function __ERC165_init() internal onlyInitializing {\n    }\n\n    function __ERC165_init_unchained() internal onlyInitializing {\n    }\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"},"@openzeppelin/contracts-upgradeable/utils/NoncesUpgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol)\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides tracking nonces for addresses. Nonces will only increment.\n */\nabstract contract NoncesUpgradeable is Initializable {\n    /**\n     * @dev The nonce used for an `account` is not the expected current nonce.\n     */\n    error InvalidAccountNonce(address account, uint256 currentNonce);\n\n    /// @custom:storage-location erc7201:openzeppelin.storage.Nonces\n    struct NoncesStorage {\n        mapping(address account => uint256) _nonces;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Nonces\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant NoncesStorageLocation = 0x5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb00;\n\n    function _getNoncesStorage() private pure returns (NoncesStorage storage $) {\n        assembly {\n            $.slot := NoncesStorageLocation\n        }\n    }\n\n    function __Nonces_init() internal onlyInitializing {\n    }\n\n    function __Nonces_init_unchained() internal onlyInitializing {\n    }\n    /**\n     * @dev Returns the next unused nonce for an address.\n     */\n    function nonces(address owner) public view virtual returns (uint256) {\n        NoncesStorage storage $ = _getNoncesStorage();\n        return $._nonces[owner];\n    }\n\n    /**\n     * @dev Consumes a nonce.\n     *\n     * Returns the current value and increments nonce.\n     */\n    function _useNonce(address owner) internal virtual returns (uint256) {\n        NoncesStorage storage $ = _getNoncesStorage();\n        // For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be\n        // decremented or reset. This guarantees that the nonce never overflows.\n        unchecked {\n            // It is important to do x++ and not ++x here.\n            return $._nonces[owner]++;\n        }\n    }\n\n    /**\n     * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`.\n     */\n    function _useCheckedNonce(address owner, uint256 nonce) internal virtual {\n        uint256 current = _useNonce(owner);\n        if (nonce != current) {\n            revert InvalidAccountNonce(owner, current);\n        }\n    }\n}\n"},"@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)\n\npragma solidity ^0.8.20;\n\nimport {ContextUpgradeable} from \"../utils/ContextUpgradeable.sol\";\nimport {Initializable} from \"../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    /// @custom:storage-location erc7201:openzeppelin.storage.Pausable\n    struct PausableStorage {\n        bool _paused;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Pausable\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;\n\n    function _getPausableStorage() private pure returns (PausableStorage storage $) {\n        assembly {\n            $.slot := PausableStorageLocation\n        }\n    }\n\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    /**\n     * @dev The operation failed because the contract is paused.\n     */\n    error EnforcedPause();\n\n    /**\n     * @dev The operation failed because the contract is not paused.\n     */\n    error ExpectedPause();\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        PausableStorage storage $ = _getPausableStorage();\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        PausableStorage storage $ = _getPausableStorage();\n        return $._paused;\n    }\n\n    /**\n     * @dev Throws if the contract is paused.\n     */\n    function _requireNotPaused() internal view virtual {\n        if (paused()) {\n            revert EnforcedPause();\n        }\n    }\n\n    /**\n     * @dev Throws if the contract is not paused.\n     */\n    function _requirePaused() internal view virtual {\n        if (!paused()) {\n            revert ExpectedPause();\n        }\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        PausableStorage storage $ = _getPausableStorage();\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        PausableStorage storage $ = _getPausableStorage();\n        $._paused = false;\n        emit Unpaused(_msgSender());\n    }\n}\n"},"@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../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    /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard\n    struct ReentrancyGuardStorage {\n        uint256 _status;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.ReentrancyGuard\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;\n\n    function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {\n        assembly {\n            $.slot := ReentrancyGuardStorageLocation\n        }\n    }\n\n    /**\n     * @dev Unauthorized reentrant call.\n     */\n    error ReentrancyGuardReentrantCall();\n\n    function __ReentrancyGuard_init() internal onlyInitializing {\n        __ReentrancyGuard_init_unchained();\n    }\n\n    function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\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        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n        // On the first call to nonReentrant, _status will be NOT_ENTERED\n        if ($._status == ENTERED) {\n            revert ReentrancyGuardReentrantCall();\n        }\n\n        // Any calls to nonReentrant after this point will fail\n        $._status = ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\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        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();\n        return $._status == ENTERED;\n    }\n}\n"},"@openzeppelin/contracts-v4/utils/math/Math.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds up instead\n     * of rounding down.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod0 := mul(x, y)\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1, \"Math: mulDiv overflow\");\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n            // in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10 ** 64) {\n                value /= 10 ** 64;\n                result += 64;\n            }\n            if (value >= 10 ** 32) {\n                value /= 10 ** 32;\n                result += 32;\n            }\n            if (value >= 10 ** 16) {\n                value /= 10 ** 16;\n                result += 16;\n            }\n            if (value >= 10 ** 8) {\n                value /= 10 ** 8;\n                result += 8;\n            }\n            if (value >= 10 ** 4) {\n                value /= 10 ** 4;\n                result += 4;\n            }\n            if (value >= 10 ** 2) {\n                value /= 10 ** 2;\n                result += 2;\n            }\n            if (value >= 10 ** 1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\n        }\n    }\n}\n"},"@openzeppelin/contracts/access/AccessControl.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.20;\n\nimport {IAccessControl} from \"./IAccessControl.sol\";\nimport {Context} from \"../utils/Context.sol\";\nimport {ERC165} from \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n *     require(hasRole(MY_ROLE, msg.sender));\n *     ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n    struct RoleData {\n        mapping(address account => bool) hasRole;\n        bytes32 adminRole;\n    }\n\n    mapping(bytes32 role => RoleData) private _roles;\n\n    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n    /**\n     * @dev Modifier that checks that an account has a specific role. Reverts\n     * with an {AccessControlUnauthorizedAccount} error including the required role.\n     */\n    modifier onlyRole(bytes32 role) {\n        _checkRole(role);\n        _;\n    }\n\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n        return _roles[role].hasRole[account];\n    }\n\n    /**\n     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n     */\n    function _checkRole(bytes32 role) internal view virtual {\n        _checkRole(role, _msgSender());\n    }\n\n    /**\n     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n     * is missing `role`.\n     */\n    function _checkRole(bytes32 role, address account) internal view virtual {\n        if (!hasRole(role, account)) {\n            revert AccessControlUnauthorizedAccount(account, role);\n        }\n    }\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n        return _roles[role].adminRole;\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n        _grantRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n        _revokeRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been revoked `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `callerConfirmation`.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n        if (callerConfirmation != _msgSender()) {\n            revert AccessControlBadConfirmation();\n        }\n\n        _revokeRole(role, callerConfirmation);\n    }\n\n    /**\n     * @dev Sets `adminRole` as ``role``'s admin role.\n     *\n     * Emits a {RoleAdminChanged} event.\n     */\n    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n        bytes32 previousAdminRole = getRoleAdmin(role);\n        _roles[role].adminRole = adminRole;\n        emit RoleAdminChanged(role, previousAdminRole, adminRole);\n    }\n\n    /**\n     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n        if (!hasRole(role, account)) {\n            _roles[role].hasRole[account] = true;\n            emit RoleGranted(role, account, _msgSender());\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n        if (hasRole(role, account)) {\n            _roles[role].hasRole[account] = false;\n            emit RoleRevoked(role, account, _msgSender());\n            return true;\n        } else {\n            return false;\n        }\n    }\n}\n"},"@openzeppelin/contracts/access/IAccessControl.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n    /**\n     * @dev The `account` is missing a role.\n     */\n    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n    /**\n     * @dev The caller of a function is not the expected one.\n     *\n     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n     */\n    error AccessControlBadConfirmation();\n\n    /**\n     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n     *\n     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n     * {RoleAdminChanged} not being emitted signaling this.\n     */\n    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n    /**\n     * @dev Emitted when `account` is granted `role`.\n     *\n     * `sender` is the account that originated the contract call, an admin role\n     * bearer except when using {AccessControl-_setupRole}.\n     */\n    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Emitted when `account` is revoked `role`.\n     *\n     * `sender` is the account that originated the contract call:\n     *   - if using `revokeRole`, it is the admin role bearer\n     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)\n     */\n    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) external view returns (bool);\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function grantRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function revokeRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been granted `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `callerConfirmation`.\n     */\n    function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n"},"@openzeppelin/contracts/access/Ownable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.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 * The initial owner is set to the address provided by the deployer. This can\n * 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 Ownable is Context {\n    address private _owner;\n\n    /**\n     * @dev The caller account is not authorized to perform an operation.\n     */\n    error OwnableUnauthorizedAccount(address account);\n\n    /**\n     * @dev The owner is not a valid owner account. (eg. `address(0)`)\n     */\n    error OwnableInvalidOwner(address owner);\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n     */\n    constructor(address initialOwner) {\n        if (initialOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(initialOwner);\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        if (owner() != _msgSender()) {\n            revert OwnableUnauthorizedAccount(_msgSender());\n        }\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        if (newOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\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"},"@openzeppelin/contracts/access/Ownable2Step.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.20;\n\nimport {Ownable} from \"./Ownable.sol\";\n\n/**\n * @dev Contract module which provides access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is specified at deployment time in the constructor for `Ownable`. This\n * can later be changed with {transferOwnership} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2Step is Ownable {\n    address private _pendingOwner;\n\n    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Returns the address of the pending owner.\n     */\n    function pendingOwner() public view virtual returns (address) {\n        return _pendingOwner;\n    }\n\n    /**\n     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual override onlyOwner {\n        _pendingOwner = newOwner;\n        emit OwnershipTransferStarted(owner(), newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual override {\n        delete _pendingOwner;\n        super._transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev The new owner accepts the ownership transfer.\n     */\n    function acceptOwnership() public virtual {\n        address sender = _msgSender();\n        if (pendingOwner() != sender) {\n            revert OwnableUnauthorizedAccount(sender);\n        }\n        _transferOwnership(sender);\n    }\n}\n"},"@openzeppelin/contracts/interfaces/draft-IERC6093.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)\npragma solidity ^0.8.20;\n\n/**\n * @dev Standard ERC20 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.\n */\ninterface IERC20Errors {\n    /**\n     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     * @param balance Current balance for the interacting account.\n     * @param needed Minimum amount required to perform a transfer.\n     */\n    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);\n\n    /**\n     * @dev Indicates a failure with the token `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     */\n    error ERC20InvalidSender(address sender);\n\n    /**\n     * @dev Indicates a failure with the token `receiver`. Used in transfers.\n     * @param receiver Address to which tokens are being transferred.\n     */\n    error ERC20InvalidReceiver(address receiver);\n\n    /**\n     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.\n     * @param spender Address that may be allowed to operate on tokens without being their owner.\n     * @param allowance Amount of tokens a `spender` is allowed to operate with.\n     * @param needed Minimum amount required to perform a transfer.\n     */\n    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);\n\n    /**\n     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n     * @param approver Address initiating an approval operation.\n     */\n    error ERC20InvalidApprover(address approver);\n\n    /**\n     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.\n     * @param spender Address that may be allowed to operate on tokens without being their owner.\n     */\n    error ERC20InvalidSpender(address spender);\n}\n\n/**\n * @dev Standard ERC721 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.\n */\ninterface IERC721Errors {\n    /**\n     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.\n     * Used in balance queries.\n     * @param owner Address of the current owner of a token.\n     */\n    error ERC721InvalidOwner(address owner);\n\n    /**\n     * @dev Indicates a `tokenId` whose `owner` is the zero address.\n     * @param tokenId Identifier number of a token.\n     */\n    error ERC721NonexistentToken(uint256 tokenId);\n\n    /**\n     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     * @param tokenId Identifier number of a token.\n     * @param owner Address of the current owner of a token.\n     */\n    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);\n\n    /**\n     * @dev Indicates a failure with the token `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     */\n    error ERC721InvalidSender(address sender);\n\n    /**\n     * @dev Indicates a failure with the token `receiver`. Used in transfers.\n     * @param receiver Address to which tokens are being transferred.\n     */\n    error ERC721InvalidReceiver(address receiver);\n\n    /**\n     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.\n     * @param operator Address that may be allowed to operate on tokens without being their owner.\n     * @param tokenId Identifier number of a token.\n     */\n    error ERC721InsufficientApproval(address operator, uint256 tokenId);\n\n    /**\n     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n     * @param approver Address initiating an approval operation.\n     */\n    error ERC721InvalidApprover(address approver);\n\n    /**\n     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.\n     * @param operator Address that may be allowed to operate on tokens without being their owner.\n     */\n    error ERC721InvalidOperator(address operator);\n}\n\n/**\n * @dev Standard ERC1155 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.\n */\ninterface IERC1155Errors {\n    /**\n     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     * @param balance Current balance for the interacting account.\n     * @param needed Minimum amount required to perform a transfer.\n     * @param tokenId Identifier number of a token.\n     */\n    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);\n\n    /**\n     * @dev Indicates a failure with the token `sender`. Used in transfers.\n     * @param sender Address whose tokens are being transferred.\n     */\n    error ERC1155InvalidSender(address sender);\n\n    /**\n     * @dev Indicates a failure with the token `receiver`. Used in transfers.\n     * @param receiver Address to which tokens are being transferred.\n     */\n    error ERC1155InvalidReceiver(address receiver);\n\n    /**\n     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.\n     * @param operator Address that may be allowed to operate on tokens without being their owner.\n     * @param owner Address of the current owner of a token.\n     */\n    error ERC1155MissingApprovalForAll(address operator, address owner);\n\n    /**\n     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n     * @param approver Address initiating an approval operation.\n     */\n    error ERC1155InvalidApprover(address approver);\n\n    /**\n     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.\n     * @param operator Address that may be allowed to operate on tokens without being their owner.\n     */\n    error ERC1155InvalidOperator(address operator);\n\n    /**\n     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.\n     * Used in batch transfers.\n     * @param idsLength Length of the array of token identifiers\n     * @param valuesLength Length of the array of token amounts\n     */\n    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);\n}\n"},"@openzeppelin/contracts/interfaces/IERC4626.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4626.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\nimport {IERC20Metadata} from \"../token/ERC20/extensions/IERC20Metadata.sol\";\n\n/**\n * @dev Interface of the ERC4626 \"Tokenized Vault Standard\", as defined in\n * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].\n */\ninterface IERC4626 is IERC20, IERC20Metadata {\n    event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n\n    event Withdraw(\n        address indexed sender,\n        address indexed receiver,\n        address indexed owner,\n        uint256 assets,\n        uint256 shares\n    );\n\n    /**\n     * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n     *\n     * - MUST be an ERC-20 token contract.\n     * - MUST NOT revert.\n     */\n    function asset() external view returns (address assetTokenAddress);\n\n    /**\n     * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n     *\n     * - SHOULD include any compounding that occurs from yield.\n     * - MUST be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT revert.\n     */\n    function totalAssets() external view returns (uint256 totalManagedAssets);\n\n    /**\n     * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n     * scenario where all the conditions are met.\n     *\n     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT show any variations depending on the caller.\n     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n     * - MUST NOT revert.\n     *\n     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n     * from.\n     */\n    function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n    /**\n     * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n     * scenario where all the conditions are met.\n     *\n     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT show any variations depending on the caller.\n     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n     * - MUST NOT revert.\n     *\n     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n     * from.\n     */\n    function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n    /**\n     * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n     * through a deposit call.\n     *\n     * - MUST return a limited value if receiver is subject to some deposit limit.\n     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n     * - MUST NOT revert.\n     */\n    function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n     * current on-chain conditions.\n     *\n     * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n     *   call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n     *   in the same transaction.\n     * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n     *   deposit would be accepted, regardless if the user has enough tokens approved, etc.\n     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n     */\n    function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n    /**\n     * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n     *\n     * - MUST emit the Deposit event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   deposit execution, and are accounted for during deposit.\n     * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n     *   approving enough underlying tokens to the Vault contract, etc).\n     *\n     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n     */\n    function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n    /**\n     * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n     * - MUST return a limited value if receiver is subject to some mint limit.\n     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n     * - MUST NOT revert.\n     */\n    function maxMint(address receiver) external view returns (uint256 maxShares);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n     * current on-chain conditions.\n     *\n     * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n     *   in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n     *   same transaction.\n     * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n     *   would be accepted, regardless if the user has enough tokens approved, etc.\n     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by minting.\n     */\n    function previewMint(uint256 shares) external view returns (uint256 assets);\n\n    /**\n     * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n     *\n     * - MUST emit the Deposit event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n     *   execution, and are accounted for during mint.\n     * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n     *   approving enough underlying tokens to the Vault contract, etc).\n     *\n     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n     */\n    function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n    /**\n     * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n     * Vault, through a withdraw call.\n     *\n     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n     * - MUST NOT revert.\n     */\n    function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n     * given current on-chain conditions.\n     *\n     * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n     *   call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n     *   called\n     *   in the same transaction.\n     * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n     *   the withdrawal would be accepted, regardless if the user has enough shares, etc.\n     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n     */\n    function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n    /**\n     * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n     *\n     * - MUST emit the Withdraw event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   withdraw execution, and are accounted for during withdraw.\n     * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n     *   not having enough shares, etc).\n     *\n     * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n     * Those methods should be performed separately.\n     */\n    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n\n    /**\n     * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n     * through a redeem call.\n     *\n     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n     * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n     * - MUST NOT revert.\n     */\n    function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n     * given current on-chain conditions.\n     *\n     * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n     *   in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n     *   same transaction.\n     * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n     *   redemption would be accepted, regardless if the user has enough shares, etc.\n     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n     */\n    function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n    /**\n     * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n     *\n     * - MUST emit the Withdraw event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   redeem execution, and are accounted for during redeem.\n     * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n     *   not having enough shares, etc).\n     *\n     * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n     * Those methods should be performed separately.\n     */\n    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n}\n"},"@openzeppelin/contracts/interfaces/IERC5267.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)\n\npragma solidity ^0.8.20;\n\ninterface IERC5267 {\n    /**\n     * @dev MAY be emitted to signal that the domain could have changed.\n     */\n    event EIP712DomainChanged();\n\n    /**\n     * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712\n     * signature.\n     */\n    function eip712Domain()\n        external\n        view\n        returns (\n            bytes1 fields,\n            string memory name,\n            string memory version,\n            uint256 chainId,\n            address verifyingContract,\n            bytes32 salt,\n            uint256[] memory extensions\n        );\n}\n"},"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\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/extensions/IERC20Permit.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n *     doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n *     token.safeTransferFrom(msg.sender, address(this), value);\n *     ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     *\n     * CAUTION: See Security Considerations above.\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"},"@openzeppelin/contracts/token/ERC20/IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\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 value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens as the allowance of `spender` over the\n     * 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 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` 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 value) external returns (bool);\n}\n"},"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC20Permit} from \"../extensions/IERC20Permit.sol\";\nimport {Address} from \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using Address for address;\n\n    /**\n     * @dev An operation with an ERC20 token failed.\n     */\n    error SafeERC20FailedOperation(address token);\n\n    /**\n     * @dev Indicates a failed `decreaseAllowance` request.\n     */\n    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\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(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transfer, (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(IERC20 token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, 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(IERC20 token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        forceApprove(token, spender, oldAllowance + value);\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n     * value, non-reverting calls are assumed to be successful.\n     */\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n        unchecked {\n            uint256 currentAllowance = token.allowance(address(this), spender);\n            if (currentAllowance < requestedDecrease) {\n                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n            }\n            forceApprove(token, spender, currentAllowance - requestedDecrease);\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(IERC20 token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data);\n        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {\n            revert SafeERC20FailedOperation(address(token));\n        }\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(IERC20 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 success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;\n    }\n}\n"},"@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC721} from \"../IERC721.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721Metadata is IERC721 {\n    /**\n     * @dev Returns the token collection name.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the token collection symbol.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n     */\n    function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n"},"@openzeppelin/contracts/token/ERC721/IERC721.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n    /**\n     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n     */\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n     */\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    /**\n     * @dev Returns the number of tokens in ``owner``'s account.\n     */\n    function balanceOf(address owner) external view returns (uint256 balance);\n\n    /**\n     * @dev Returns the owner of the `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function ownerOf(uint256 tokenId) external view returns (address owner);\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon\n     *   a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n     * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or\n     *   {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon\n     *   a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId) external;\n\n    /**\n     * @dev Transfers `tokenId` token from `from` to `to`.\n     *\n     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721\n     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must\n     * understand this adds an external call which potentially creates a reentrancy vulnerability.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 tokenId) external;\n\n    /**\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n     * The approval is cleared when the token is transferred.\n     *\n     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n     *\n     * Requirements:\n     *\n     * - The caller must own the token or be an approved operator.\n     * - `tokenId` must exist.\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address to, uint256 tokenId) external;\n\n    /**\n     * @dev Approve or remove `operator` as an operator for the caller.\n     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n     *\n     * Requirements:\n     *\n     * - The `operator` cannot be the address zero.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function setApprovalForAll(address operator, bool approved) external;\n\n    /**\n     * @dev Returns the account approved for `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function getApproved(uint256 tokenId) external view returns (address operator);\n\n    /**\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n     *\n     * See {setApprovalForAll}\n     */\n    function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n"},"@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n    /**\n     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n     * by `operator` from `from`, this function is called.\n     *\n     * It must return its Solidity selector to confirm the token transfer.\n     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be\n     * reverted.\n     *\n     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.\n     */\n    function onERC721Received(\n        address operator,\n        address from,\n        uint256 tokenId,\n        bytes calldata data\n    ) external returns (bytes4);\n}\n"},"@openzeppelin/contracts/utils/Address.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev The ETH balance of the account is not enough to perform the operation.\n     */\n    error AddressInsufficientBalance(address account);\n\n    /**\n     * @dev There's no code at `target` (it is not a contract).\n     */\n    error AddressEmptyCode(address target);\n\n    /**\n     * @dev A call to an address target failed. The target may have reverted.\n     */\n    error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        if (address(this).balance < amount) {\n            revert AddressInsufficientBalance(address(this));\n        }\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        if (!success) {\n            revert FailedInnerCall();\n        }\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 or custom error, it is bubbled\n     * up by this function (like regular Solidity function calls). However, if\n     * the call reverted with no returned reason, this function reverts with a\n     * {FailedInnerCall} error.\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    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0);\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    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        if (address(this).balance < value) {\n            revert AddressInsufficientBalance(address(this));\n        }\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n     * unsuccessful call.\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata\n    ) internal view returns (bytes memory) {\n        if (!success) {\n            _revert(returndata);\n        } else {\n            // only check if target is a contract if the call was successful and the return data is empty\n            // otherwise we already know that it was a contract\n            if (returndata.length == 0 && target.code.length == 0) {\n                revert AddressEmptyCode(target);\n            }\n            return returndata;\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n     * revert reason or with a default {FailedInnerCall} error.\n     */\n    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n        if (!success) {\n            _revert(returndata);\n        } else {\n            return returndata;\n        }\n    }\n\n    /**\n     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n     */\n    function _revert(bytes memory returndata) 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 FailedInnerCall();\n        }\n    }\n}\n"},"@openzeppelin/contracts/utils/Context.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\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    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"},"@openzeppelin/contracts/utils/cryptography/ECDSA.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS\n    }\n\n    /**\n     * @dev The signature derives the `address(0)`.\n     */\n    error ECDSAInvalidSignature();\n\n    /**\n     * @dev The signature has an invalid length.\n     */\n    error ECDSAInvalidSignatureLength(uint256 length);\n\n    /**\n     * @dev The signature has an S value that is in the upper half order.\n     */\n    error ECDSAInvalidSignatureS(bytes32 s);\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not\n     * return address(0) without also returning an error description. Errors are documented using an enum (error type)\n     * and a bytes32 providing additional information about the error.\n     *\n     * If no error is returned, then the address can be used for verification purposes.\n     *\n     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);\n        _throwError(error, errorArg);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     */\n    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {\n        unchecked {\n            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n            // We do not check for an overflow here since the shift operation results in 0 or 1.\n            uint8 v = uint8((uint256(vs) >> 255) + 27);\n            return tryRecover(hash, v, r, s);\n        }\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     */\n    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {\n        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);\n        _throwError(error, errorArg);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError, bytes32) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS, s);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature, bytes32(0));\n        }\n\n        return (signer, RecoverError.NoError, bytes32(0));\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {\n        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);\n        _throwError(error, errorArg);\n        return recovered;\n    }\n\n    /**\n     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.\n     */\n    function _throwError(RecoverError error, bytes32 errorArg) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert ECDSAInvalidSignature();\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert ECDSAInvalidSignatureLength(uint256(errorArg));\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert ECDSAInvalidSignatureS(errorArg);\n        }\n    }\n}\n"},"@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)\n\npragma solidity ^0.8.20;\n\nimport {Strings} from \"../Strings.sol\";\n\n/**\n * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.\n *\n * The library provides methods for generating a hash of a message that conforms to the\n * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]\n * specifications.\n */\nlibrary MessageHashUtils {\n    /**\n     * @dev Returns the keccak256 digest of an EIP-191 signed data with version\n     * `0x45` (`personal_sign` messages).\n     *\n     * The digest is calculated by prefixing a bytes32 `messageHash` with\n     * `\"\\x19Ethereum Signed Message:\\n32\"` and hashing the result. It corresponds with the\n     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.\n     *\n     * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with\n     * keccak256, although any bytes32 value can be safely used because the final digest will\n     * be re-hashed.\n     *\n     * See {ECDSA-recover}.\n     */\n    function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x00, \"\\x19Ethereum Signed Message:\\n32\") // 32 is the bytes-length of messageHash\n            mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix\n            digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)\n        }\n    }\n\n    /**\n     * @dev Returns the keccak256 digest of an EIP-191 signed data with version\n     * `0x45` (`personal_sign` messages).\n     *\n     * The digest is calculated by prefixing an arbitrary `message` with\n     * `\"\\x19Ethereum Signed Message:\\n\" + len(message)` and hashing the result. It corresponds with the\n     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.\n     *\n     * See {ECDSA-recover}.\n     */\n    function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {\n        return\n            keccak256(bytes.concat(\"\\x19Ethereum Signed Message:\\n\", bytes(Strings.toString(message.length)), message));\n    }\n\n    /**\n     * @dev Returns the keccak256 digest of an EIP-191 signed data with version\n     * `0x00` (data with intended validator).\n     *\n     * The digest is calculated by prefixing an arbitrary `data` with `\"\\x19\\x00\"` and the intended\n     * `validator` address. Then hashing the result.\n     *\n     * See {ECDSA-recover}.\n     */\n    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(hex\"19_00\", validator, data));\n    }\n\n    /**\n     * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).\n     *\n     * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with\n     * `\\x19\\x01` and hashing the result. It corresponds to the hash signed by the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.\n     *\n     * See {ECDSA-recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let ptr := mload(0x40)\n            mstore(ptr, hex\"19_01\")\n            mstore(add(ptr, 0x02), domainSeparator)\n            mstore(add(ptr, 0x22), structHash)\n            digest := keccak256(ptr, 0x42)\n        }\n    }\n}\n"},"@openzeppelin/contracts/utils/introspection/ERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"},"@openzeppelin/contracts/utils/introspection/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},"@openzeppelin/contracts/utils/math/Math.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    /**\n     * @dev Muldiv operation overflow.\n     */\n    error MathOverflowedMulDiv();\n\n    enum Rounding {\n        Floor, // Toward negative infinity\n        Ceil, // Toward positive infinity\n        Trunc, // Toward zero\n        Expand // Away from zero\n    }\n\n    /**\n     * @dev Returns the addition of two unsigned integers, with an overflow flag.\n     */\n    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            uint256 c = a + b;\n            if (c < a) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n     */\n    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b > a) return (false, 0);\n            return (true, a - b);\n        }\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n     */\n    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n            // benefit is lost if 'b' is also tested.\n            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n            if (a == 0) return (true, 0);\n            uint256 c = a * b;\n            if (c / a != b) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the division of two unsigned integers, with a division by zero flag.\n     */\n    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a / b);\n        }\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n     */\n    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a % b);\n        }\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds towards infinity instead\n     * of rounding towards zero.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        if (b == 0) {\n            // Guarantee the same behavior as in a regular Solidity division.\n            return a / b;\n        }\n\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n     * denominator == 0.\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by\n     * Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0 = x * y; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            if (denominator <= prod1) {\n                revert MathOverflowedMulDiv();\n            }\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.\n\n            uint256 twos = denominator & (0 - denominator);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n            // works in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded\n     * towards zero.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10 ** 64) {\n                value /= 10 ** 64;\n                result += 64;\n            }\n            if (value >= 10 ** 32) {\n                value /= 10 ** 32;\n                result += 32;\n            }\n            if (value >= 10 ** 16) {\n                value /= 10 ** 16;\n                result += 16;\n            }\n            if (value >= 10 ** 8) {\n                value /= 10 ** 8;\n                result += 8;\n            }\n            if (value >= 10 ** 4) {\n                value /= 10 ** 4;\n                result += 4;\n            }\n            if (value >= 10 ** 2) {\n                value /= 10 ** 2;\n                result += 2;\n            }\n            if (value >= 10 ** 1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.\n     */\n    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {\n        return uint8(rounding) % 2 == 1;\n    }\n}\n"},"@openzeppelin/contracts/utils/math/SignedMath.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Standard signed math utilities missing in the Solidity language.\n */\nlibrary SignedMath {\n    /**\n     * @dev Returns the largest of two signed numbers.\n     */\n    function max(int256 a, int256 b) internal pure returns (int256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two signed numbers.\n     */\n    function min(int256 a, int256 b) internal pure returns (int256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two signed numbers without overflow.\n     * The result is rounded towards zero.\n     */\n    function average(int256 a, int256 b) internal pure returns (int256) {\n        // Formula from the book \"Hacker's Delight\"\n        int256 x = (a & b) + ((a ^ b) >> 1);\n        return x + (int256(uint256(x) >> 255) & (a ^ b));\n    }\n\n    /**\n     * @dev Returns the absolute unsigned value of a signed value.\n     */\n    function abs(int256 n) internal pure returns (uint256) {\n        unchecked {\n            // must be unchecked in order to support `n = type(int256).min`\n            return uint256(n >= 0 ? n : -n);\n        }\n    }\n}\n"},"@openzeppelin/contracts/utils/Strings.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)\n\npragma solidity ^0.8.20;\n\nimport {Math} from \"./math/Math.sol\";\nimport {SignedMath} from \"./math/SignedMath.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant HEX_DIGITS = \"0123456789abcdef\";\n    uint8 private constant ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev The `value` string doesn't fit in the specified `length`.\n     */\n    error StringsInsufficientHexLength(uint256 value, uint256 length);\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            uint256 length = Math.log10(value) + 1;\n            string memory buffer = new string(length);\n            uint256 ptr;\n            /// @solidity memory-safe-assembly\n            assembly {\n                ptr := add(buffer, add(32, length))\n            }\n            while (true) {\n                ptr--;\n                /// @solidity memory-safe-assembly\n                assembly {\n                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))\n                }\n                value /= 10;\n                if (value == 0) break;\n            }\n            return buffer;\n        }\n    }\n\n    /**\n     * @dev Converts a `int256` to its ASCII `string` decimal representation.\n     */\n    function toStringSigned(int256 value) internal pure returns (string memory) {\n        return string.concat(value < 0 ? \"-\" : \"\", toString(SignedMath.abs(value)));\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            return toHexString(value, Math.log256(value) + 1);\n        }\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        uint256 localValue = value;\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i > 1; --i) {\n            buffer[i] = HEX_DIGITS[localValue & 0xf];\n            localValue >>= 4;\n        }\n        if (localValue != 0) {\n            revert StringsInsufficientHexLength(value, length);\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal\n     * representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);\n    }\n\n    /**\n     * @dev Returns true if the two strings are equal.\n     */\n    function equal(string memory a, string memory b) internal pure returns (bool) {\n        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));\n    }\n}\n"},"@openzeppelin/contracts/utils/structs/EnumerableSet.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n *     // Add the library methods\n *     using EnumerableSet for EnumerableSet.AddressSet;\n *\n *     // Declare a set state variable\n *     EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position is the index of the value in the `values` array plus 1.\n        // Position 0 is used to mean a value is not in the set.\n        mapping(bytes32 value => uint256) _positions;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._positions[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We cache the value's position to prevent multiple reads from the same storage slot\n        uint256 position = set._positions[value];\n\n        if (position != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 valueIndex = position - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (valueIndex != lastIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the lastValue to the index where the value to delete is\n                set._values[valueIndex] = lastValue;\n                // Update the tracked position of the lastValue (that was just moved)\n                set._positions[lastValue] = position;\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the tracked position for the deleted slot\n            delete set._positions[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._positions[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        bytes32[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n"},"contracts/common/codec/WordCodec.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n// solhint-disable no-inline-assembly\n\n/// @dev A subset copied from the following contracts:\n///\n/// + `balancer-labs/v2-solidity-utils/contracts/helpers/WordCodec.sol`\n/// + `balancer-labs/v2-solidity-utils/contracts/helpers/WordCodecHelpers.sol`\nlibrary WordCodec {\n  /// @dev Inserts an unsigned integer of bitLength, shifted by an offset, into a 256 bit word,\n  /// replacing the old value. Returns the new word.\n  function insertUint(\n    bytes32 word,\n    uint256 value,\n    uint256 offset,\n    uint256 bitLength\n  ) internal pure returns (bytes32 result) {\n    // Equivalent to:\n    // uint256 mask = (1 << bitLength) - 1;\n    // bytes32 clearedWord = bytes32(uint256(word) & ~(mask << offset));\n    // result = clearedWord | bytes32(value << offset);\n    assembly {\n      let mask := sub(shl(bitLength, 1), 1)\n      let clearedWord := and(word, not(shl(offset, mask)))\n      result := or(clearedWord, shl(offset, value))\n    }\n  }\n\n  /// @dev Decodes and returns an unsigned integer with `bitLength` bits, shifted by an offset, from a 256 bit word.\n  function decodeUint(\n    bytes32 word,\n    uint256 offset,\n    uint256 bitLength\n  ) internal pure returns (uint256 result) {\n    // Equivalent to:\n    // result = uint256(word >> offset) & ((1 << bitLength) - 1);\n    assembly {\n      result := and(shr(offset, word), sub(shl(bitLength, 1), 1))\n    }\n  }\n\n  /// @dev Inserts a signed integer shifted by an offset into a 256 bit word, replacing the old value. Returns\n  /// the new word.\n  ///\n  /// Assumes `value` can be represented using `bitLength` bits.\n  function insertInt(\n    bytes32 word,\n    int256 value,\n    uint256 offset,\n    uint256 bitLength\n  ) internal pure returns (bytes32) {\n    unchecked {\n      uint256 mask = (1 << bitLength) - 1;\n      bytes32 clearedWord = bytes32(uint256(word) & ~(mask << offset));\n      // Integer values need masking to remove the upper bits of negative values.\n      return clearedWord | bytes32((uint256(value) & mask) << offset);\n    }\n  }\n\n  /// @dev Decodes and returns a signed integer with `bitLength` bits, shifted by an offset, from a 256 bit word.\n  function decodeInt(\n    bytes32 word,\n    uint256 offset,\n    uint256 bitLength\n  ) internal pure returns (int256 result) {\n    unchecked {\n      int256 maxInt = int256((1 << (bitLength - 1)) - 1);\n      uint256 mask = (1 << bitLength) - 1;\n\n      int256 value = int256(uint256(word >> offset) & mask);\n      // In case the decoded value is greater than the max positive integer that can be represented with bitLength\n      // bits, we know it was originally a negative integer. Therefore, we mask it to restore the sign in the 256 bit\n      // representation.\n      //\n      // Equivalent to:\n      // result = value > maxInt ? (value | int256(~mask)) : value;\n      assembly {\n        result := or(mul(gt(value, maxInt), not(mask)), value)\n      }\n    }\n  }\n\n  /// @dev Decodes and returns a boolean shifted by an offset from a 256 bit word.\n  function decodeBool(bytes32 word, uint256 offset) internal pure returns (bool result) {\n    // Equivalent to:\n    // result = (uint256(word >> offset) & 1) == 1;\n    assembly {\n      result := and(shr(offset, word), 1)\n    }\n  }\n\n  /// @dev Inserts a boolean value shifted by an offset into a 256 bit word, replacing the old value. Returns the new\n  /// word.\n  function insertBool(\n    bytes32 word,\n    bool value,\n    uint256 offset\n  ) internal pure returns (bytes32 result) {\n    // Equivalent to:\n    // bytes32 clearedWord = bytes32(uint256(word) & ~(1 << offset));\n    // bytes32 referenceInsertBool = clearedWord | bytes32(uint256(value ? 1 : 0) << offset);\n    assembly {\n      let clearedWord := and(word, not(shl(offset, 1)))\n      result := or(clearedWord, shl(offset, value))\n    }\n  }\n\n  function clearWordAtPosition(\n    bytes32 word,\n    uint256 offset,\n    uint256 bitLength\n  ) internal pure returns (bytes32 clearedWord) {\n    unchecked {\n      uint256 mask = (1 << bitLength) - 1;\n      clearedWord = bytes32(uint256(word) & ~(mask << offset));\n    }\n  }\n}\n"},"contracts/common/concentrator/ConcentratorBase.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { AccessControlUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\n\nimport { WordCodec } from \"../codec/WordCodec.sol\";\n\nimport { IHarvesterCallback } from \"../../helpers/interfaces/IHarvesterCallback.sol\";\nimport { IConcentratorBase } from \"./IConcentratorBase.sol\";\n\n// solhint-disable func-name-mixedcase\n// solhint-disable no-inline-assembly\n\nabstract contract ConcentratorBase is AccessControlUpgradeable, IConcentratorBase, IHarvesterCallback {\n  using WordCodec for bytes32;\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the address is zero.\n  error ErrorZeroAddress();\n\n  /// @dev Thrown when the expense ratio exceeds `MAX_EXPENSE_RATIO`.\n  error ErrorExpenseRatioTooLarge();\n\n  /// @dev Thrown when the harvester ratio exceeds `MAX_HARVESTER_RATIO`.\n  error ErrorHarvesterRatioTooLarge();\n\n  /// @dev Thrown when caller is not harvester and try to call some harvester only functions.\n  error ErrorCallerNotHarvester();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The fee denominator used for rate calculation.\n  uint256 internal constant FEE_PRECISION = 1e9;\n\n  /// @dev The maximum expense ratio.\n  uint256 private constant MAX_EXPENSE_RATIO = 5e8; // 50%\n\n  /// @dev The maximum harvester ratio.\n  uint256 private constant MAX_HARVESTER_RATIO = 1e8; // 10%\n\n  /// @dev The number of bits for fee ratios.\n  uint256 private constant RATIO_BITS = 30;\n\n  /// @dev The offset of expense ratio in `_miscData`.\n  uint256 private constant EXPENSE_RATIO_OFFSET = 0;\n\n  /// @dev The offset of harvester ratio in `_miscData`.\n  uint256 private constant HARVESTER_RATIO_OFFSET = 30;\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @inheritdoc IConcentratorBase\n  address public treasury;\n\n  /// @inheritdoc IConcentratorBase\n  address public harvester;\n\n  /// @dev `_miscData` is a storage slot that can be used to store unrelated pieces of information.\n  /// All pools store the *expense ratio*, *harvester ratio* and *withdraw fee percentage*, but\n  /// the `miscData`can be extended to store more pieces of information.\n  ///\n  /// The *expense ratio* is stored in the first most significant 32 bits, and the *harvester ratio* is\n  /// stored in the next most significant 32 bits, and the *withdraw fee percentage* is stored in the\n  /// next most significant 32 bits, leaving the remaining 160 bits free to store any other information\n  /// derived pools might need.\n  ///\n  /// - The *expense ratio* and *harvester ratio* are charged each time when harvester harvest the pool revenue.\n  ///\n  /// [ expense ratio | harvester ratio | available ]\n  /// [    30 bits    |     30 bits     |  196 bits ]\n  /// [ MSB                                     LSB ]\n  bytes32 internal _miscData;\n\n  /// @dev reserved slots.\n  uint256[47] private __gap;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  function __ConcentratorBase_init(address _treasury, address _harvester) internal onlyInitializing {\n    _updateTreasury(_treasury);\n    _updateHarvester(_harvester);\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc IConcentratorBase\n  function getExpenseRatio() public view override returns (uint256) {\n    return _miscData.decodeUint(EXPENSE_RATIO_OFFSET, RATIO_BITS);\n  }\n\n  /// @inheritdoc IConcentratorBase\n  function getHarvesterRatio() public view override returns (uint256) {\n    return _miscData.decodeUint(HARVESTER_RATIO_OFFSET, RATIO_BITS);\n  }\n\n  /// @inheritdoc IHarvesterCallback\n  function onHarvest(address token, uint256 amount) external override {\n    if (_msgSender() != harvester) revert ErrorCallerNotHarvester();\n\n    _onHarvest(token, amount);\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Update the address of treasury contract.\n  ///\n  /// @param _newTreasury The address of the new treasury contract.\n  function updateTreasury(address _newTreasury) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateTreasury(_newTreasury);\n  }\n\n  /// @notice Update the address of harvester contract.\n  ///\n  /// @param _newHarvester The address of the new harvester contract.\n  function updateHarvester(address _newHarvester) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateHarvester(_newHarvester);\n  }\n\n  /// @notice Update the fee ratio distributed to treasury.\n  /// @param _newRatio The new ratio to update, multiplied by 1e9.\n  function updateExpenseRatio(uint32 _newRatio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    if (uint256(_newRatio) > MAX_EXPENSE_RATIO) {\n      revert ErrorExpenseRatioTooLarge();\n    }\n\n    bytes32 _data = _miscData;\n    uint256 _oldRatio = _miscData.decodeUint(EXPENSE_RATIO_OFFSET, RATIO_BITS);\n    _miscData = _data.insertUint(_newRatio, EXPENSE_RATIO_OFFSET, RATIO_BITS);\n\n    emit UpdateExpenseRatio(_oldRatio, _newRatio);\n  }\n\n  /// @notice Update the fee ratio distributed to harvester.\n  /// @param _newRatio The new ratio to update, multiplied by 1e9.\n  function updateHarvesterRatio(uint32 _newRatio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    if (uint256(_newRatio) > MAX_HARVESTER_RATIO) {\n      revert ErrorHarvesterRatioTooLarge();\n    }\n\n    bytes32 _data = _miscData;\n    uint256 _oldRatio = _miscData.decodeUint(HARVESTER_RATIO_OFFSET, RATIO_BITS);\n    _miscData = _data.insertUint(_newRatio, HARVESTER_RATIO_OFFSET, RATIO_BITS);\n\n    emit UpdateHarvesterRatio(_oldRatio, _newRatio);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to update the address of treasury contract.\n  ///\n  /// @param _newTreasury The address of the new treasury contract.\n  function _updateTreasury(address _newTreasury) private {\n    if (_newTreasury == address(0)) revert ErrorZeroAddress();\n\n    address _oldTreasury = treasury;\n    treasury = _newTreasury;\n\n    emit UpdateTreasury(_oldTreasury, _newTreasury);\n  }\n\n  /// @dev Internal function to update the address of harvester contract.\n  ///\n  /// @param _newHarvester The address of the new harvester contract.\n  function _updateHarvester(address _newHarvester) private {\n    address _oldHarvester = harvester;\n    harvester = _newHarvester;\n\n    emit UpdateHarvester(_oldHarvester, _newHarvester);\n  }\n\n  /// @dev Actual logic of onHarvest callback.\n  function _onHarvest(address token, uint256 amount) internal virtual;\n}\n"},"contracts/common/concentrator/IConcentratorBase.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IConcentratorBase {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when the treasury contract is updated.\n  ///\n  /// @param oldTreasury The address of the previous treasury contract.\n  /// @param newTreasury The address of the current treasury contract.\n  event UpdateTreasury(address indexed oldTreasury, address indexed newTreasury);\n\n  /// @notice Emitted when the harvester contract is updated.\n  ///\n  /// @param oldHarvester The address of the previous harvester contract.\n  /// @param newHarvester The address of the current harvester contract.\n  event UpdateHarvester(address indexed oldHarvester, address indexed newHarvester);\n\n  /// @notice Emitted when the ratio for treasury is updated.\n  /// @param oldRatio The value of the previous ratio, multiplied by 1e9.\n  /// @param newRatio The value of the current ratio, multiplied by 1e9.\n  event UpdateExpenseRatio(uint256 oldRatio, uint256 newRatio);\n\n  /// @notice Emitted when the ratio for harvester is updated.\n  /// @param oldRatio The value of the previous ratio, multiplied by 1e9.\n  /// @param newRatio The value of the current ratio, multiplied by 1e9.\n  event UpdateHarvesterRatio(uint256 oldRatio, uint256 newRatio);\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice The address of protocol revenue holder.\n  function treasury() external view returns (address);\n\n  /// @notice The address of harvester contract.\n  function harvester() external view returns (address);\n\n  /// @notice Return the fee ratio distributed to treasury, multiplied by 1e9.\n  function getExpenseRatio() external view returns (uint256);\n\n  /// @notice Return the fee ratio distributed to harvester, multiplied by 1e9.\n  function getHarvesterRatio() external view returns (uint256);\n}\n"},"contracts/common/ERC3156/IERC3156FlashBorrower.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IERC3156FlashBorrower {\n  /**\n   * @dev Receive a flash loan.\n   * @param initiator The initiator of the loan.\n   * @param token The loan currency.\n   * @param amount The amount of tokens lent.\n   * @param fee The additional amount of tokens to repay.\n   * @param data Arbitrary data structure, intended to contain user-defined parameters.\n   * @return The keccak256 hash of \"ERC3156FlashBorrower.onFlashLoan\"\n   */\n  function onFlashLoan(\n    address initiator,\n    address token,\n    uint256 amount,\n    uint256 fee,\n    bytes calldata data\n  ) external returns (bytes32);\n}\n"},"contracts/common/ERC3156/IERC3156FlashLender.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IERC3156FlashBorrower } from \"./IERC3156FlashBorrower.sol\";\n\ninterface IERC3156FlashLender {\n  /**\n   * @dev The amount of currency available to be lent.\n   * @param token The loan currency.\n   * @return The amount of `token` that can be borrowed.\n   */\n  function maxFlashLoan(address token) external view returns (uint256);\n\n  /**\n   * @dev The fee to be charged for a given loan.\n   * @param token The loan currency.\n   * @param amount The amount of tokens lent.\n   * @return The amount of `token` to be charged for the loan, on top of the returned principal.\n   */\n  function flashFee(address token, uint256 amount) external view returns (uint256);\n\n  /**\n   * @dev Initiate a flash loan.\n   * @param receiver The receiver of the tokens in the loan, and the receiver of the callback.\n   * @param token The loan currency.\n   * @param amount The amount of tokens lent.\n   * @param data Arbitrary data structure, intended to contain user-defined parameters.\n   */\n  function flashLoan(\n    IERC3156FlashBorrower receiver,\n    address token,\n    uint256 amount,\n    bytes calldata data\n  ) external returns (bool);\n}\n"},"contracts/common/rewards/distributor/IMultipleRewardDistributor.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IMultipleRewardDistributor {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when new reward token is registered.\n  ///\n  /// @param token The address of reward token.\n  /// @param distributor The address of reward distributor.\n  event RegisterRewardToken(address indexed token, address indexed distributor);\n\n  /// @notice Emitted when the reward distributor is updated.\n  ///\n  /// @param token The address of reward token.\n  /// @param oldDistributor The address of previous reward distributor.\n  /// @param newDistributor The address of current reward distributor.\n  event UpdateRewardDistributor(address indexed token, address indexed oldDistributor, address indexed newDistributor);\n\n  /// @notice Emitted when a reward token is unregistered.\n  ///\n  /// @param token The address of reward token.\n  event UnregisterRewardToken(address indexed token);\n\n  /// @notice Emitted when a reward token is deposited.\n  ///\n  /// @param token The address of reward token.\n  /// @param amount The amount of reward token deposited.\n  event DepositReward(address indexed token, uint256 amount);\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when caller access an unactive reward token.\n  error NotActiveRewardToken();\n\n  /// @dev Thrown when the address of reward distributor is `address(0)`.\n  error RewardDistributorIsZero();\n\n  /// @dev Thrown when caller is not reward distributor.\n  error NotRewardDistributor();\n\n  /// @dev Thrown when caller try to register an existing reward token.\n  error DuplicatedRewardToken();\n\n  /// @dev Thrown when caller try to unregister a reward with pending rewards.\n  error RewardDistributionNotFinished();\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the address of reward distributor.\n  ///\n  /// @param token The address of reward token.\n  function distributors(address token) external view returns (address);\n\n  /// @notice Return the list of active reward tokens.\n  function getActiveRewardTokens() external view returns (address[] memory);\n\n  /// @notice Return the list of historical reward tokens.\n  function getHistoricalRewardTokens() external view returns (address[] memory);\n\n  /// @notice Return the amount of pending distributed rewards in current period.\n  ///\n  /// @param token The address of reward token.\n  /// @return distributable The amount of reward token can be distributed in current period.\n  /// @return undistributed The amount of reward token still locked in current period.\n  function pendingRewards(address token) external view returns (uint256 distributable, uint256 undistributed);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Deposit new rewards to this contract.\n  ///\n  /// @param token The address of reward token.\n  /// @param amount The amount of new rewards.\n  function depositReward(address token, uint256 amount) external;\n}\n"},"contracts/common/utils/PermissionedSwap.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { AccessControlUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n// solhint-disable avoid-low-level-calls\n// solhint-disable no-inline-assembly\n\nabstract contract PermissionedSwap is AccessControlUpgradeable {\n  using SafeERC20 for IERC20;\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the amount of output token is not enough.\n  error InsufficientOutputToken();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @notice The role for permissioned trader.\n  bytes32 public constant PERMISSIONED_TRADER_ROLE = keccak256(\"PERMISSIONED_TRADER_ROLE\");\n\n  /// @notice The role for permissioned trading router.\n  bytes32 public constant PERMISSIONED_ROUTER_ROLE = keccak256(\"PERMISSIONED_ROUTER_ROLE\");\n\n  /***********\n   * Structs *\n   ***********/\n\n  /// @notice The struct for trading parameters.\n  ///\n  /// @param router The address of trading router.\n  /// @param data The calldata passing to the router contract.\n  /// @param minOut The minimum amount of output token should receive.\n  struct TradingParameter {\n    address router;\n    bytes data;\n    uint256 minOut;\n  }\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @dev reserved slots.\n  uint256[50] private __gap;\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Withdraw base token to someone else.\n  /// @dev This should be only used when we are retiring this contract.\n  /// @param baseToken The address of base token.\n  function withdraw(address baseToken, address recipient) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    uint256 amountIn = IERC20(baseToken).balanceOf(address(this));\n    IERC20(baseToken).safeTransfer(recipient, amountIn);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to convert token with routes.\n  /// @param srcToken The address of source token.\n  /// @param dstToken The address of destination token.\n  /// @param amountIn The amount of input token.\n  /// @param params The token converting parameters.\n  /// @return amountOut The amount of output token received.\n  function _doTrade(\n    address srcToken,\n    address dstToken,\n    uint256 amountIn,\n    TradingParameter memory params\n  ) internal virtual onlyRole(PERMISSIONED_TRADER_ROLE) returns (uint256 amountOut) {\n    if (srcToken == dstToken) return amountIn;\n\n    // router should be permissioned\n    _checkRole(PERMISSIONED_ROUTER_ROLE, params.router);\n\n    // approve to router\n    IERC20(srcToken).forceApprove(params.router, amountIn);\n\n    // do trading\n    amountOut = IERC20(dstToken).balanceOf(address(this));\n    (bool success, ) = params.router.call(params.data);\n    if (!success) {\n      // below lines will propagate inner error up\n      assembly {\n        let ptr := mload(0x40)\n        let size := returndatasize()\n        returndatacopy(ptr, 0, size)\n        revert(ptr, size)\n      }\n    }\n\n    amountOut = IERC20(dstToken).balanceOf(address(this)) - amountOut;\n    if (amountOut < params.minOut) {\n      revert InsufficientOutputToken();\n    }\n  }\n}\n"},"contracts/core/FlashLoans.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.25;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { ReentrancyGuardUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol\";\n\nimport { IERC3156FlashBorrower } from \"../common/ERC3156/IERC3156FlashBorrower.sol\";\nimport { IERC3156FlashLender } from \"../common/ERC3156/IERC3156FlashLender.sol\";\n\nimport { ProtocolFees } from \"./ProtocolFees.sol\";\n\ncontract FlashLoans is ProtocolFees, ReentrancyGuardUpgradeable, IERC3156FlashLender {\n  using SafeERC20 for IERC20;\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the returned balance after flash loan is not enough.\n  error ErrorInsufficientFlashLoanReturn();\n\n  /// @dev Thrown when the returned value of `ERC3156Callback` is wrong.\n  error ErrorERC3156CallbackFailed();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The correct value of the return value of `ERC3156FlashBorrower.onFlashLoan`.\n  bytes32 private constant CALLBACK_SUCCESS = keccak256(\"ERC3156FlashBorrower.onFlashLoan\");\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @dev Slots for future use.\n  uint256[50] private _gap;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  function __FlashLoans_init() internal onlyInitializing {}\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc IERC3156FlashLender\n  function maxFlashLoan(address token) external view override returns (uint256) {\n    return IERC20(token).balanceOf(address(this));\n  }\n\n  /// @inheritdoc IERC3156FlashLender\n  function flashFee(address /*token*/, uint256 amount) public view returns (uint256) {\n    return (amount * getFlashLoanFeeRatio()) / FEE_PRECISION;\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IERC3156FlashLender\n  function flashLoan(\n    IERC3156FlashBorrower receiver,\n    address token,\n    uint256 amount,\n    bytes calldata data\n  ) external nonReentrant whenNotPaused returns (bool) {\n    // save the current balance\n    uint256 prevBalance = IERC20(token).balanceOf(address(this));\n    uint256 fee = flashFee(token, amount);\n\n    // transfer token to receiver\n    IERC20(token).safeTransfer(address(receiver), amount);\n\n    // invoke the recipient's callback\n    if (receiver.onFlashLoan(_msgSender(), token, amount, fee, data) != CALLBACK_SUCCESS) {\n      revert ErrorERC3156CallbackFailed();\n    }\n\n    // ensure that the tokens + fee have been deposited back to the network\n    uint256 returnedAmount = IERC20(token).balanceOf(address(this)) - prevBalance;\n    if (returnedAmount < amount + fee) {\n      revert ErrorInsufficientFlashLoanReturn();\n    }\n\n    if (fee > 0) {\n      IERC20(token).safeTransfer(treasury, fee);\n    }\n\n    return true;\n  }\n}\n"},"contracts/core/FxUSDBasePool.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.25;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { AccessControlUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\nimport { ERC20PermitUpgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol\";\nimport { ERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol\";\nimport { ReentrancyGuardUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol\";\n\nimport { IStrategy } from \"../fund/IStrategy.sol\";\nimport { AggregatorV3Interface } from \"../interfaces/Chainlink/AggregatorV3Interface.sol\";\nimport { IPegKeeper } from \"../interfaces/IPegKeeper.sol\";\nimport { IPool } from \"../interfaces/IPool.sol\";\nimport { IPoolManager } from \"../interfaces/IPoolManager.sol\";\nimport { IFxUSDBasePool } from \"../interfaces/IFxUSDBasePool.sol\";\n\nimport { AssetManagement } from \"../fund/AssetManagement.sol\";\nimport { Math } from \"../libraries/Math.sol\";\n\ncontract FxUSDBasePool is\n  ERC20PermitUpgradeable,\n  AccessControlUpgradeable,\n  ReentrancyGuardUpgradeable,\n  AssetManagement,\n  IFxUSDBasePool\n{\n  using SafeERC20 for IERC20;\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the deposited amount is zero.\n  error ErrDepositZeroAmount();\n\n  /// @dev Thrown when the minted shares are not enough.\n  error ErrInsufficientSharesOut();\n\n  /// @dev Thrown the input token in invalid.\n  error ErrInvalidTokenIn();\n\n  /// @dev Thrown when the redeemed shares is zero.\n  error ErrRedeemZeroShares();\n\n  error ErrorCallerNotPegKeeper();\n\n  error ErrorStableTokenDepeg();\n\n  error ErrorSwapExceedBalance();\n\n  error ErrorInsufficientOutput();\n\n  error ErrorInsufficientArbitrage();\n\n  error ErrorRedeemCoolDownPeriodTooLarge();\n\n  error ErrorRedeemMoreThanBalance();\n\n  error ErrorRedeemLockedShares();\n\n  error ErrorInsufficientFreeBalance();\n\n  error ErrorInstantRedeemFeeTooLarge();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The exchange rate precision.\n  uint256 internal constant PRECISION = 1e18;\n\n  uint256 internal constant MAX_INSTANT_REDEEM_FEE = 5e16; // 5%\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @notice The address of `PoolManager` contract.\n  address public immutable poolManager;\n\n  /// @notice The address of `PegKeeper` contract.\n  address public immutable pegKeeper;\n\n  /// @inheritdoc IFxUSDBasePool\n  /// @dev This is also the address of FxUSD token.\n  address public immutable yieldToken;\n\n  /// @inheritdoc IFxUSDBasePool\n  /// @dev The address of USDC token.\n  address public immutable stableToken;\n\n  uint256 private immutable stableTokenScale;\n\n  /// @notice The Chainlink USDC/USD price feed.\n  /// @dev The encoding is below.\n  /// ```text\n  /// |  32 bits  | 64 bits |  160 bits  |\n  /// | heartbeat |  scale  | price_feed |\n  /// |low                          high |\n  /// ```\n  bytes32 public immutable Chainlink_USDC_USD_Spot;\n\n  /***********\n   * Structs *\n   ***********/\n\n  struct RebalanceMemoryVar {\n    uint256 stablePrice;\n    uint256 totalYieldToken;\n    uint256 totalStableToken;\n    uint256 yieldTokenToUse;\n    uint256 stableTokenToUse;\n    uint256 colls;\n    uint256 yieldTokenUsed;\n    uint256 stableTokenUsed;\n  }\n\n  struct RedeemRequest {\n    uint128 amount;\n    uint128 unlockAt;\n  }\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @inheritdoc IFxUSDBasePool\n  uint256 public totalYieldToken;\n\n  /// @inheritdoc IFxUSDBasePool\n  uint256 public totalStableToken;\n\n  /// @notice The depeg price for stable token.\n  uint256 public stableDepegPrice;\n\n  /// @notice Mapping from user address to redeem request.\n  mapping(address => RedeemRequest) public redeemRequests;\n\n  /// @notice The number of seconds of cool down before redeem from this pool.\n  uint256 public redeemCoolDownPeriod;\n\n  /// @notice The fee ratio for instantly redeem.\n  uint256 public instantRedeemFeeRatio;\n\n  /*************\n   * Modifiers *\n   *************/\n\n  modifier onlyValidToken(address token) {\n    if (token != stableToken && token != yieldToken) {\n      revert ErrInvalidTokenIn();\n    }\n    _;\n  }\n\n  modifier onlyPegKeeper() {\n    if (_msgSender() != pegKeeper) revert ErrorCallerNotPegKeeper();\n    _;\n  }\n\n  modifier sync() {\n    {\n      // we only manage stable token\n      Allocation memory b = allocations[stableToken];\n      if (b.strategy != address(0)) {\n        totalStableToken = IStrategy(b.strategy).totalSupply() + IERC20(stableToken).balanceOf(address(this));\n      }\n    }\n    _;\n  }\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(\n    address _poolManager,\n    address _pegKeeper,\n    address _yieldToken,\n    address _stableToken,\n    bytes32 _Chainlink_USDC_USD_Spot\n  ) {\n    poolManager = _poolManager;\n    pegKeeper = _pegKeeper;\n    yieldToken = _yieldToken;\n    stableToken = _stableToken;\n    Chainlink_USDC_USD_Spot = _Chainlink_USDC_USD_Spot;\n\n    stableTokenScale = 10 ** (18 - IERC20Metadata(_stableToken).decimals());\n  }\n\n  function initialize(\n    address admin,\n    string memory _name,\n    string memory _symbol,\n    uint256 _stableDepegPrice,\n    uint256 _redeemCoolDownPeriod\n  ) external initializer {\n    __Context_init();\n    __ERC165_init();\n    __AccessControl_init();\n    __ReentrancyGuard_init();\n\n    __ERC20_init(_name, _symbol);\n    __ERC20Permit_init(_name);\n\n    _grantRole(DEFAULT_ADMIN_ROLE, admin);\n\n    _updateStableDepegPrice(_stableDepegPrice);\n    _updateRedeemCoolDownPeriod(_redeemCoolDownPeriod);\n\n    // approve\n    IERC20(yieldToken).forceApprove(poolManager, type(uint256).max);\n    IERC20(stableToken).forceApprove(poolManager, type(uint256).max);\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc IFxUSDBasePool\n  function previewDeposit(\n    address tokenIn,\n    uint256 amountTokenToDeposit\n  ) public view override onlyValidToken(tokenIn) returns (uint256 amountSharesOut) {\n    uint256 price = getStableTokenPriceWithScale();\n    uint256 amountUSD = amountTokenToDeposit;\n    if (tokenIn == stableToken) {\n      amountUSD = (amountUSD * price) / PRECISION;\n    }\n\n    uint256 _totalSupply = totalSupply();\n    if (_totalSupply == 0) {\n      amountSharesOut = amountUSD;\n    } else {\n      uint256 totalUSD = totalYieldToken + (totalStableToken * price) / PRECISION;\n      amountSharesOut = (amountUSD * _totalSupply) / totalUSD;\n    }\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function previewRedeem(\n    uint256 amountSharesToRedeem\n  ) external view returns (uint256 amountYieldOut, uint256 amountStableOut) {\n    uint256 cachedTotalYieldToken = totalYieldToken;\n    uint256 cachedTotalStableToken = totalStableToken;\n    uint256 cachedTotalSupply = totalSupply();\n    amountYieldOut = (amountSharesToRedeem * cachedTotalYieldToken) / cachedTotalSupply;\n    amountStableOut = (amountSharesToRedeem * cachedTotalStableToken) / cachedTotalSupply;\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function nav() external view returns (uint256) {\n    uint256 _totalSupply = totalSupply();\n    if (_totalSupply == 0) {\n      return PRECISION;\n    } else {\n      uint256 stablePrice = getStableTokenPriceWithScale();\n      uint256 yieldPrice = IPegKeeper(pegKeeper).getFxUSDPrice();\n      return (totalYieldToken * yieldPrice + totalStableToken * stablePrice) / _totalSupply;\n    }\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function getStableTokenPrice() public view returns (uint256) {\n    bytes32 encoding = Chainlink_USDC_USD_Spot;\n    address aggregator;\n    uint256 scale;\n    uint256 heartbeat;\n    assembly {\n      aggregator := shr(96, encoding)\n      scale := and(shr(32, encoding), 0xffffffffffffffff)\n      heartbeat := and(encoding, 0xffffffff)\n    }\n    (, int256 answer, , uint256 updatedAt, ) = AggregatorV3Interface(aggregator).latestRoundData();\n    if (answer < 0) revert(\"invalid\");\n    if (block.timestamp - updatedAt > heartbeat) revert(\"expired\");\n    return uint256(answer) * scale;\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function getStableTokenPriceWithScale() public view returns (uint256) {\n    return getStableTokenPrice() * stableTokenScale;\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IFxUSDBasePool\n  function deposit(\n    address receiver,\n    address tokenIn,\n    uint256 amountTokenToDeposit,\n    uint256 minSharesOut\n  ) external override nonReentrant onlyValidToken(tokenIn) sync returns (uint256 amountSharesOut) {\n    if (amountTokenToDeposit == 0) revert ErrDepositZeroAmount();\n\n    // we are very sure every token is normal token, so no fot check here.\n    IERC20(tokenIn).safeTransferFrom(_msgSender(), address(this), amountTokenToDeposit);\n\n    amountSharesOut = _deposit(tokenIn, amountTokenToDeposit);\n    if (amountSharesOut < minSharesOut) revert ErrInsufficientSharesOut();\n\n    _mint(receiver, amountSharesOut);\n\n    emit Deposit(_msgSender(), receiver, tokenIn, amountTokenToDeposit, amountSharesOut);\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function requestRedeem(uint256 shares) external {\n    address caller = _msgSender();\n    uint256 balance = balanceOf(caller);\n    RedeemRequest memory request = redeemRequests[caller];\n    if (request.amount + shares > balance) revert ErrorRedeemMoreThanBalance();\n    request.amount += uint128(shares);\n    request.unlockAt = uint128(block.timestamp + redeemCoolDownPeriod);\n    redeemRequests[caller] = request;\n\n    emit RequestRedeem(caller, shares, request.unlockAt);\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function redeem(\n    address receiver,\n    uint256 amountSharesToRedeem\n  ) external nonReentrant sync returns (uint256 amountYieldOut, uint256 amountStableOut) {\n    address caller = _msgSender();\n    RedeemRequest memory request = redeemRequests[caller];\n    if (request.unlockAt > block.timestamp) revert ErrorRedeemLockedShares();\n    if (request.amount < amountSharesToRedeem) {\n      amountSharesToRedeem = request.amount;\n    }\n    if (amountSharesToRedeem == 0) revert ErrRedeemZeroShares();\n    request.amount -= uint128(amountSharesToRedeem);\n    redeemRequests[caller] = request;\n\n    uint256 cachedTotalYieldToken = totalYieldToken;\n    uint256 cachedTotalStableToken = totalStableToken;\n    uint256 cachedTotalSupply = totalSupply();\n\n    amountYieldOut = (amountSharesToRedeem * cachedTotalYieldToken) / cachedTotalSupply;\n    amountStableOut = (amountSharesToRedeem * cachedTotalStableToken) / cachedTotalSupply;\n\n    _burn(caller, amountSharesToRedeem);\n\n    if (amountYieldOut > 0) {\n      _transferOut(yieldToken, amountYieldOut, receiver);\n      unchecked {\n        totalYieldToken = cachedTotalYieldToken - amountYieldOut;\n      }\n    }\n    if (amountStableOut > 0) {\n      _transferOut(stableToken, amountStableOut, receiver);\n      unchecked {\n        totalStableToken = cachedTotalStableToken - amountStableOut;\n      }\n    }\n\n    emit Redeem(caller, receiver, amountSharesToRedeem, amountYieldOut, amountStableOut);\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function instantRedeem(\n    address receiver,\n    uint256 amountSharesToRedeem\n  ) external nonReentrant sync returns (uint256 amountYieldOut, uint256 amountStableOut) {\n    if (amountSharesToRedeem == 0) revert ErrRedeemZeroShares();\n\n    address caller = _msgSender();\n    uint256 leftover = balanceOf(caller) - redeemRequests[caller].amount;\n    if (amountSharesToRedeem > leftover) revert ErrorInsufficientFreeBalance();\n\n    uint256 cachedTotalYieldToken = totalYieldToken;\n    uint256 cachedTotalStableToken = totalStableToken;\n    uint256 cachedTotalSupply = totalSupply();\n\n    amountYieldOut = (amountSharesToRedeem * cachedTotalYieldToken) / cachedTotalSupply;\n    amountStableOut = (amountSharesToRedeem * cachedTotalStableToken) / cachedTotalSupply;\n    uint256 feeRatio = instantRedeemFeeRatio;\n\n    _burn(caller, amountSharesToRedeem);\n\n    if (amountYieldOut > 0) {\n      uint256 fee = (amountYieldOut * feeRatio) / PRECISION;\n      amountYieldOut -= fee;\n      _transferOut(yieldToken, amountYieldOut, receiver);\n      unchecked {\n        totalYieldToken = cachedTotalYieldToken - amountYieldOut;\n      }\n    }\n    if (amountStableOut > 0) {\n      uint256 fee = (amountStableOut * feeRatio) / PRECISION;\n      amountStableOut -= fee;\n      _transferOut(stableToken, amountStableOut, receiver);\n      unchecked {\n        totalStableToken = cachedTotalStableToken - amountStableOut;\n      }\n    }\n\n    emit InstantRedeem(caller, receiver, amountSharesToRedeem, amountYieldOut, amountStableOut);\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function rebalance(\n    address pool,\n    int16 tickId,\n    address tokenIn,\n    uint256 maxAmount,\n    uint256 minCollOut\n  ) external onlyValidToken(tokenIn) nonReentrant sync returns (uint256 tokenUsed, uint256 colls) {\n    RebalanceMemoryVar memory op = _beforeRebalanceOrLiquidate(tokenIn, maxAmount);\n    (op.colls, op.yieldTokenUsed, op.stableTokenUsed) = IPoolManager(poolManager).rebalance(\n      pool,\n      _msgSender(),\n      tickId,\n      op.yieldTokenToUse,\n      op.stableTokenToUse\n    );\n    tokenUsed = _afterRebalanceOrLiquidate(tokenIn, minCollOut, op);\n    colls = op.colls;\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function rebalance(\n    address pool,\n    address tokenIn,\n    uint256 maxAmount,\n    uint256 minCollOut\n  ) external onlyValidToken(tokenIn) nonReentrant sync returns (uint256 tokenUsed, uint256 colls) {\n    RebalanceMemoryVar memory op = _beforeRebalanceOrLiquidate(tokenIn, maxAmount);\n    (op.colls, op.yieldTokenUsed, op.stableTokenUsed) = IPoolManager(poolManager).rebalance(\n      pool,\n      _msgSender(),\n      op.yieldTokenToUse,\n      op.stableTokenToUse\n    );\n    tokenUsed = _afterRebalanceOrLiquidate(tokenIn, minCollOut, op);\n    colls = op.colls;\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function liquidate(\n    address pool,\n    address tokenIn,\n    uint256 maxAmount,\n    uint256 minCollOut\n  ) external onlyValidToken(tokenIn) nonReentrant sync returns (uint256 tokenUsed, uint256 colls) {\n    RebalanceMemoryVar memory op = _beforeRebalanceOrLiquidate(tokenIn, maxAmount);\n    (op.colls, op.yieldTokenUsed, op.stableTokenUsed) = IPoolManager(poolManager).liquidate(\n      pool,\n      _msgSender(),\n      op.yieldTokenToUse,\n      op.stableTokenToUse\n    );\n    tokenUsed = _afterRebalanceOrLiquidate(tokenIn, minCollOut, op);\n    colls = op.colls;\n  }\n\n  /// @inheritdoc IFxUSDBasePool\n  function arbitrage(\n    address srcToken,\n    uint256 amountIn,\n    address receiver,\n    bytes calldata data\n  ) external onlyValidToken(srcToken) onlyPegKeeper nonReentrant sync returns (uint256 amountOut, uint256 bonusOut) {\n    address dstToken;\n    uint256 expectedOut;\n    uint256 cachedTotalYieldToken = totalYieldToken;\n    uint256 cachedTotalStableToken = totalStableToken;\n    {\n      uint256 price = getStableTokenPrice();\n      uint256 scaledPrice = price * stableTokenScale;\n      if (srcToken == yieldToken) {\n        // check if usdc depeg\n        if (price < stableDepegPrice) revert ErrorStableTokenDepeg();\n        if (amountIn > cachedTotalYieldToken) revert ErrorSwapExceedBalance();\n        dstToken = stableToken;\n        unchecked {\n          // rounding up\n          expectedOut = Math.mulDivUp(amountIn, PRECISION, scaledPrice);\n          cachedTotalYieldToken -= amountIn;\n          cachedTotalStableToken += expectedOut;\n        }\n      } else {\n        if (amountIn > cachedTotalStableToken) revert ErrorSwapExceedBalance();\n        dstToken = yieldToken;\n        unchecked {\n          // rounding up\n          expectedOut = Math.mulDivUp(amountIn, scaledPrice, PRECISION);\n          cachedTotalStableToken -= amountIn;\n          cachedTotalYieldToken += expectedOut;\n        }\n      }\n    }\n    _transferOut(srcToken, amountIn, pegKeeper);\n    uint256 actualOut = IERC20(dstToken).balanceOf(address(this));\n    amountOut = IPegKeeper(pegKeeper).onSwap(srcToken, dstToken, amountIn, data);\n    actualOut = IERC20(dstToken).balanceOf(address(this)) - actualOut;\n    // check actual fxUSD swapped in case peg keeper is hacked.\n    if (amountOut > actualOut) revert ErrorInsufficientOutput();\n    // check swapped token has no loss\n    if (amountOut < expectedOut) revert ErrorInsufficientArbitrage();\n\n    totalYieldToken = cachedTotalYieldToken;\n    totalStableToken = cachedTotalStableToken;\n    bonusOut = amountOut - expectedOut;\n    if (bonusOut > 0) {\n      _transferOut(dstToken, bonusOut, receiver);\n    }\n\n    emit Arbitrage(_msgSender(), srcToken, amountIn, amountOut, bonusOut);\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Update depeg price for stable token.\n  /// @param newPrice The new depeg price of stable token, multiplied by 1e18\n  function updateStableDepegPrice(uint256 newPrice) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateStableDepegPrice(newPrice);\n  }\n\n  /// @notice Update redeem cool down period.\n  /// @param newPeriod The new redeem cool down period, in seconds.\n  function updateRedeemCoolDownPeriod(uint256 newPeriod) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateRedeemCoolDownPeriod(newPeriod);\n  }\n\n  function updateInstantRedeemFeeRatio(uint256 newRatio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateInstantRedeemFeeRatio(newRatio);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @inheritdoc ERC20Upgradeable\n  function _update(address from, address to, uint256 value) internal virtual override {\n    // make sure from don't transfer more than free balance\n    if (from != address(0) && to != address(0)) {\n      uint256 leftover = balanceOf(from) - redeemRequests[from].amount;\n      if (value > leftover) revert ErrorInsufficientFreeBalance();\n    }\n\n    super._update(from, to, value);\n  }\n\n  /// @dev Internal function to update depeg price for stable token.\n  /// @param newPrice The new depeg price of stable token, multiplied by 1e18\n  function _updateStableDepegPrice(uint256 newPrice) internal {\n    uint256 oldPrice = stableDepegPrice;\n    stableDepegPrice = newPrice;\n\n    emit UpdateStableDepegPrice(oldPrice, newPrice);\n  }\n\n  /// @dev Internal function to update redeem cool down period.\n  /// @param newPeriod The new redeem cool down period, in seconds.\n  function _updateRedeemCoolDownPeriod(uint256 newPeriod) internal {\n    if (newPeriod > 7 days) revert ErrorRedeemCoolDownPeriodTooLarge();\n\n    uint256 oldPeriod = redeemCoolDownPeriod;\n    redeemCoolDownPeriod = newPeriod;\n\n    emit UpdateRedeemCoolDownPeriod(oldPeriod, newPeriod);\n  }\n\n  /// @dev Internal function to update the instant redeem fee ratio.\n  /// @param newRatio The new instant redeem fee ratio, multiplied by 1e18.\n  function _updateInstantRedeemFeeRatio(uint256 newRatio) internal {\n    if (newRatio > MAX_INSTANT_REDEEM_FEE) revert ErrorInstantRedeemFeeTooLarge();\n\n    uint256 oldRatio = instantRedeemFeeRatio;\n    instantRedeemFeeRatio = newRatio;\n\n    emit UpdateInstantRedeemFeeRatio(oldRatio, newRatio);\n  }\n\n  /// @dev mint shares based on the deposited base tokens\n  /// @param tokenIn base token address used to mint shares\n  /// @param amountDeposited amount of base tokens deposited\n  /// @return amountSharesOut amount of shares minted\n  function _deposit(address tokenIn, uint256 amountDeposited) internal virtual returns (uint256 amountSharesOut) {\n    uint256 price = getStableTokenPriceWithScale();\n    if (price < stableDepegPrice * stableTokenScale) revert ErrorStableTokenDepeg();\n\n    uint256 amountUSD = amountDeposited;\n    if (tokenIn == stableToken) {\n      amountUSD = (amountUSD * price) / PRECISION;\n    }\n\n    uint256 cachedTotalYieldToken = totalYieldToken;\n    uint256 cachedTotalStableToken = totalStableToken;\n    uint256 totalUSD = cachedTotalYieldToken + (cachedTotalStableToken * price) / PRECISION;\n    uint256 cachedTotalSupply = totalSupply();\n    if (cachedTotalSupply == 0) {\n      amountSharesOut = amountUSD;\n    } else {\n      amountSharesOut = (amountUSD * cachedTotalSupply) / totalUSD;\n    }\n\n    if (tokenIn == stableToken) {\n      totalStableToken = cachedTotalStableToken + amountDeposited;\n    } else {\n      totalYieldToken = cachedTotalYieldToken + amountDeposited;\n    }\n  }\n\n  /// @dev Internal hook function to prepare before rebalance or liquidate.\n  /// @param tokenIn The address of input token.\n  /// @param maxAmount The maximum amount of input tokens.\n  function _beforeRebalanceOrLiquidate(\n    address tokenIn,\n    uint256 maxAmount\n  ) internal view returns (RebalanceMemoryVar memory op) {\n    op.stablePrice = getStableTokenPriceWithScale();\n    op.totalYieldToken = totalYieldToken;\n    op.totalStableToken = totalStableToken;\n\n    uint256 amountYieldToken = op.totalYieldToken;\n    uint256 amountStableToken;\n    // we always, try use fxUSD first then USDC\n    if (tokenIn == yieldToken) {\n      // user pays fxUSD\n      if (maxAmount < amountYieldToken) amountYieldToken = maxAmount;\n      else {\n        amountStableToken = ((maxAmount - amountYieldToken) * PRECISION) / op.stablePrice;\n      }\n    } else {\n      // user pays USDC\n      uint256 maxAmountInUSD = (maxAmount * op.stablePrice) / PRECISION;\n      if (maxAmountInUSD < amountYieldToken) amountYieldToken = maxAmountInUSD;\n      else {\n        amountStableToken = ((maxAmountInUSD - amountYieldToken) * PRECISION) / op.stablePrice;\n      }\n    }\n\n    if (amountStableToken > op.totalStableToken) {\n      amountStableToken = op.totalStableToken;\n    }\n\n    op.yieldTokenToUse = amountYieldToken;\n    op.stableTokenToUse = amountStableToken;\n  }\n\n  /// @dev Internal hook function after rebalance or liquidate.\n  /// @param tokenIn The address of input token.\n  /// @param minCollOut The minimum expected collateral tokens.\n  /// @param op The memory variable for rebalance or liquidate.\n  /// @return tokenUsed The amount of input token used.\n  function _afterRebalanceOrLiquidate(\n    address tokenIn,\n    uint256 minCollOut,\n    RebalanceMemoryVar memory op\n  ) internal returns (uint256 tokenUsed) {\n    if (op.colls < minCollOut) revert ErrorInsufficientOutput();\n\n    op.totalYieldToken -= op.yieldTokenUsed;\n    op.totalStableToken -= op.stableTokenUsed;\n\n    uint256 amountUSD = op.yieldTokenUsed + (op.stableTokenUsed * op.stablePrice) / PRECISION;\n    if (tokenIn == yieldToken) {\n      tokenUsed = amountUSD;\n      op.totalYieldToken += tokenUsed;\n    } else {\n      // rounding up\n      tokenUsed = Math.mulDivUp(amountUSD, PRECISION, op.stablePrice);\n      op.totalStableToken += tokenUsed;\n    }\n\n    totalYieldToken = op.totalYieldToken;\n    totalStableToken = op.totalStableToken;\n\n    // transfer token from caller, the collateral is already transferred to caller.\n    IERC20(tokenIn).safeTransferFrom(_msgSender(), address(this), tokenUsed);\n\n    emit Rebalance(_msgSender(), tokenIn, tokenUsed, op.colls, op.yieldTokenUsed, op.stableTokenUsed);\n  }\n}\n"},"contracts/core/PegKeeper.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { AccessControlUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\n\nimport { IMultiPathConverter } from \"../helpers/interfaces/IMultiPathConverter.sol\";\nimport { ICurveStableSwapNG } from \"../interfaces/Curve/ICurveStableSwapNG.sol\";\nimport { IFxUSDRegeneracy } from \"../interfaces/IFxUSDRegeneracy.sol\";\nimport { IPegKeeper } from \"../interfaces/IPegKeeper.sol\";\nimport { IFxUSDBasePool } from \"../interfaces/IFxUSDBasePool.sol\";\n\ncontract PegKeeper is AccessControlUpgradeable, IPegKeeper {\n  using SafeERC20 for IERC20;\n\n  /**********\n   * Errors *\n   **********/\n\n  error ErrorNotInCallbackContext();\n\n  error ErrorZeroAddress();\n\n  error ErrorInsufficientOutput();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The precision used to compute nav.\n  uint256 private constant PRECISION = 1e18;\n\n  /// @notice The role for buyback.\n  bytes32 public constant BUYBACK_ROLE = keccak256(\"BUYBACK_ROLE\");\n\n  /// @notice The role for stabilize.\n  bytes32 public constant STABILIZE_ROLE = keccak256(\"STABILIZE_ROLE\");\n\n  /// @dev contexts for buyback and stabilize callback\n  uint8 private constant CONTEXT_NO_CONTEXT = 1;\n  uint8 private constant CONTEXT_BUYBACK = 2;\n  uint8 private constant CONTEXT_STABILIZE = 3;\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @notice The address of fxUSD.\n  address public immutable fxUSD;\n\n  /// @notice The address of stable token.\n  address public immutable stable;\n\n  /// @notice The address of FxUSDBasePool.\n  address public immutable fxBASE;\n\n  /*********************\n   * Storage Variables *\n   *********************/\n\n  /// @dev The context for buyback and stabilize callback.\n  uint8 private context;\n\n  /// @notice The address of MultiPathConverter.\n  address public converter;\n\n  /// @notice The curve pool for stable and fxUSD\n  address public curvePool;\n\n  /// @notice The fxUSD depeg price threshold.\n  uint256 public priceThreshold;\n\n  /*************\n   * Modifiers *\n   *************/\n\n  modifier setContext(uint8 c) {\n    context = c;\n    _;\n    context = CONTEXT_NO_CONTEXT;\n  }\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _fxBASE) {\n    fxBASE = _fxBASE;\n    fxUSD = IFxUSDBasePool(_fxBASE).yieldToken();\n    stable = IFxUSDBasePool(_fxBASE).stableToken();\n  }\n\n  function initialize(address admin, address _converter, address _curvePool) external initializer {\n    __Context_init();\n    __ERC165_init();\n    __AccessControl_init();\n\n    _grantRole(DEFAULT_ADMIN_ROLE, admin);\n\n    _updateConverter(_converter);\n    _updateCurvePool(_curvePool);\n    _updatePriceThreshold(995000000000000000); // 0.995\n\n    context = CONTEXT_NO_CONTEXT;\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc IPegKeeper\n  function isBorrowAllowed() external view returns (bool) {\n    return _getFxUSDEmaPrice() >= priceThreshold;\n  }\n\n  /// @inheritdoc IPegKeeper\n  function isFundingEnabled() external view returns (bool) {\n    return _getFxUSDEmaPrice() < priceThreshold;\n  }\n\n  /// @inheritdoc IPegKeeper\n  function getFxUSDPrice() external view returns (uint256) {\n    return _getFxUSDEmaPrice();\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IPegKeeper\n  function buyback(\n    uint256 amountIn,\n    bytes calldata data\n  ) external onlyRole(BUYBACK_ROLE) setContext(CONTEXT_BUYBACK) returns (uint256 amountOut, uint256 bonus) {\n    (amountOut, bonus) = IFxUSDRegeneracy(fxUSD).buyback(amountIn, _msgSender(), data);\n  }\n\n  /// @inheritdoc IPegKeeper\n  function stabilize(\n    address srcToken,\n    uint256 amountIn,\n    bytes calldata data\n  ) external onlyRole(STABILIZE_ROLE) setContext(CONTEXT_STABILIZE) returns (uint256 amountOut, uint256 bonus) {\n    (amountOut, bonus) = IFxUSDBasePool(fxBASE).arbitrage(srcToken, amountIn, _msgSender(), data);\n  }\n\n  /// @inheritdoc IPegKeeper\n  /// @dev This function will be called in `buyback`, `stabilize`.\n  function onSwap(\n    address srcToken,\n    address targetToken,\n    uint256 amountIn,\n    bytes calldata data\n  ) external returns (uint256 amountOut) {\n    // check callback validity\n    if (context == CONTEXT_NO_CONTEXT) revert ErrorNotInCallbackContext();\n\n    amountOut = _doSwap(srcToken, amountIn, data);\n    IERC20(targetToken).safeTransfer(_msgSender(), amountOut);\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Update the address of converter.\n  /// @param newConverter The address of converter.\n  function updateConverter(address newConverter) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateConverter(newConverter);\n  }\n\n  /// @notice Update the address of curve pool.\n  /// @param newPool The address of curve pool.\n  function updateCurvePool(address newPool) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateCurvePool(newPool);\n  }\n\n  /// @notice Update the value of depeg price threshold.\n  /// @param newThreshold The value of new price threshold.\n  function updatePriceThreshold(uint256 newThreshold) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updatePriceThreshold(newThreshold);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to update the address of converter.\n  /// @param newConverter The address of converter.\n  function _updateConverter(address newConverter) internal {\n    if (newConverter == address(0)) revert ErrorZeroAddress();\n\n    address oldConverter = converter;\n    converter = newConverter;\n\n    emit UpdateConverter(oldConverter, newConverter);\n  }\n\n  /// @dev Internal function to update the address of curve pool.\n  /// @param newPool The address of curve pool.\n  function _updateCurvePool(address newPool) internal {\n    if (newPool == address(0)) revert ErrorZeroAddress();\n\n    address oldPool = curvePool;\n    curvePool = newPool;\n\n    emit UpdateCurvePool(oldPool, newPool);\n  }\n\n  /// @dev Internal function to update the value of depeg price threshold.\n  /// @param newThreshold The value of new price threshold.\n  function _updatePriceThreshold(uint256 newThreshold) internal {\n    uint256 oldThreshold = priceThreshold;\n    priceThreshold = newThreshold;\n\n    emit UpdatePriceThreshold(oldThreshold, newThreshold);\n  }\n\n  /// @dev Internal function to do swap.\n  /// @param srcToken The address of source token.\n  /// @param amountIn The amount of token to use.\n  /// @param data The callback data.\n  /// @return amountOut The amount of token swapped.\n  function _doSwap(address srcToken, uint256 amountIn, bytes calldata data) internal returns (uint256 amountOut) {\n    IERC20(srcToken).forceApprove(converter, amountIn);\n\n    (uint256 minOut, uint256 encoding, uint256[] memory routes) = abi.decode(data, (uint256, uint256, uint256[]));\n    amountOut = IMultiPathConverter(converter).convert(srcToken, amountIn, encoding, routes);\n    if (amountOut < minOut) revert ErrorInsufficientOutput();\n  }\n\n  /// @dev Internal function to get curve ema price for fxUSD.\n  /// @return price The value of ema price, multiplied by 1e18.\n  function _getFxUSDEmaPrice() internal view returns (uint256 price) {\n    address cachedCurvePool = curvePool; // gas saving\n    address firstCoin = ICurveStableSwapNG(cachedCurvePool).coins(0);\n    price = ICurveStableSwapNG(cachedCurvePool).price_oracle(0);\n    if (firstCoin == fxUSD) {\n      price = (PRECISION * PRECISION) / price;\n    }\n  }\n}\n"},"contracts/core/pool/AaveFundingPool.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IAaveV3Pool } from \"../../interfaces/Aave/IAaveV3Pool.sol\";\nimport { IAaveFundingPool } from \"../../interfaces/IAaveFundingPool.sol\";\nimport { IPegKeeper } from \"../../interfaces/IPegKeeper.sol\";\n\nimport { WordCodec } from \"../../common/codec/WordCodec.sol\";\nimport { Math } from \"../../libraries/Math.sol\";\nimport { BasePool } from \"./BasePool.sol\";\n\ncontract AaveFundingPool is BasePool, IAaveFundingPool {\n  using WordCodec for bytes32;\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The offset of *open ratio* in `fundingMiscData`.\n  uint256 private constant OPEN_RATIO_OFFSET = 0;\n\n  /// @dev The offset of *open ratio step* in `fundingMiscData`.\n  uint256 private constant OPEN_RATIO_STEP_OFFSET = 30;\n\n  /// @dev The offset of *close fee ratio* in `fundingMiscData`.\n  uint256 private constant CLOSE_FEE_RATIO_OFFSET = 90;\n\n  /// @dev The offset of *funding ratio* in `fundingMiscData`.\n  uint256 private constant FUNDING_RATIO_OFFSET = 120;\n\n  /// @dev The offset of *interest rate* in `fundingMiscData`.\n  uint256 private constant INTEREST_RATE_OFFSET = 152;\n\n  /// @dev The offset of *timestamp* in `fundingMiscData`.\n  uint256 private constant TIMESTAMP_OFFSET = 220;\n\n  /// @dev The maximum value of *funding ratio*.\n  uint256 private constant MAX_FUNDING_RATIO = 4294967295;\n\n  /// @dev The minimum Aave borrow index snapshot delay.\n  uint256 private constant MIN_SNAPSHOT_DELAY = 30 minutes;\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @dev The address of Aave V3 `LendingPool` contract.\n  address private immutable lendingPool;\n\n  /// @dev The address of asset used for interest calculation.\n  address private immutable baseAsset;\n\n  /***********\n   * Structs *\n   ***********/\n\n  /// @dev The struct for AAVE borrow rate snapshot.\n  /// @param borrowIndex The current borrow index of AAVE, multiplied by 1e27.\n  /// @param lastInterestRate The last recorded interest rate, multiplied by 1e18.\n  /// @param timestamp The timestamp when the snapshot is taken.\n  struct BorrowRateSnapshot {\n    // The initial value of `borrowIndex` is `10^27`, it is very unlikely this value will exceed `2^128`.\n    uint128 borrowIndex;\n    uint80 lastInterestRate;\n    uint48 timestamp;\n  }\n\n  /*********************\n   * Storage Variables *\n   *********************/\n\n  /// @dev `fundingMiscData` is a storage slot that can be used to store unrelated pieces of information.\n  ///\n  /// - The *open ratio* is the fee ratio for opening position, multiplied by 1e9.\n  /// - The *open ratio step* is the fee ratio step for opening position, multiplied by 1e18.\n  /// - The *close fee ratio* is the fee ratio for closing position, multiplied by 1e9.\n  /// - The *funding ratio* is the scalar for funding rate, multiplied by 1e9.\n  ///   The maximum value is `4.294967296`.\n  ///\n  /// [ open ratio | open ratio step | close fee ratio | funding ratio | reserved ]\n  /// [  30  bits  |     60 bits     |     30 bits     |    32 bits    | 104 bits ]\n  /// [ MSB                                                                   LSB ]\n  bytes32 private fundingMiscData;\n\n  /// @notice The snapshot for AAVE borrow rate.\n  BorrowRateSnapshot public borrowRateSnapshot;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _poolManager, address _lendingPool, address _baseAsset) BasePool(_poolManager) {\n    _checkAddressNotZero(_lendingPool);\n    _checkAddressNotZero(_baseAsset);\n\n    lendingPool = _lendingPool;\n    baseAsset = _baseAsset;\n  }\n\n  function initialize(\n    address admin,\n    string memory name_,\n    string memory symbol_,\n    address _collateralToken,\n    address _priceOracle\n  ) external initializer {\n    __Context_init();\n    __ERC165_init();\n    __ERC721_init(name_, symbol_);\n    __AccessControl_init();\n\n    __PoolStorage_init(_collateralToken, _priceOracle);\n    __TickLogic_init();\n    __PositionLogic_init();\n    __BasePool_init();\n\n    _grantRole(DEFAULT_ADMIN_ROLE, admin);\n\n    _updateOpenRatio(1000000, 50000000000000000); // 0.1% and 5%\n    _updateCloseFeeRatio(1000000); // 0.1%\n\n    uint256 borrowIndex = IAaveV3Pool(lendingPool).getReserveNormalizedVariableDebt(baseAsset);\n    IAaveV3Pool.ReserveDataLegacy memory reserveData = IAaveV3Pool(lendingPool).getReserveData(baseAsset);\n    _updateInterestRate(borrowIndex, reserveData.currentVariableBorrowRate / 1e9);\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Get open fee ratio related parameters.\n  /// @return ratio The value of open ratio, multiplied by 1e9.\n  /// @return step The value of open ratio step, multiplied by 1e18.\n  function getOpenRatio() external view returns (uint256 ratio, uint256 step) {\n    return _getOpenRatio();\n  }\n\n  /// @notice Return the value of funding ratio, multiplied by 1e9.\n  function getFundingRatio() external view returns (uint256) {\n    return _getFundingRatio();\n  }\n\n  /// @notice Return the fee ratio for opening position, multiplied by 1e9.\n  function getOpenFeeRatio() public view returns (uint256) {\n    (uint256 openRatio, uint256 openRatioStep) = _getOpenRatio();\n    (, uint256 rate) = _getAverageInterestRate(borrowRateSnapshot);\n    unchecked {\n      uint256 aaveRatio = rate <= openRatioStep ? 1 : (rate - 1) / openRatioStep;\n      return aaveRatio * openRatio;\n    }\n  }\n\n  /// @notice Return the fee ratio for closing position, multiplied by 1e9.\n  function getCloseFeeRatio() external view returns (uint256) {\n    return _getCloseFeeRatio();\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Update the fee ratio for opening position.\n  /// @param ratio The open ratio value, multiplied by 1e9.\n  /// @param step The open ratio step value, multiplied by 1e18.\n  function updateOpenRatio(uint256 ratio, uint256 step) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateOpenRatio(ratio, step);\n  }\n\n  /// @notice Update the fee ratio for closing position.\n  /// @param ratio The close ratio value, multiplied by 1e9.\n  function updateCloseFeeRatio(uint256 ratio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateCloseFeeRatio(ratio);\n  }\n\n  /// @notice Update the funding ratio.\n  /// @param ratio The funding ratio value, multiplied by 1e9.\n  function updateFundingRatio(uint256 ratio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateFundingRatio(ratio);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to get open ratio and open ratio step.\n  /// @return ratio The value of open ratio, multiplied by 1e9.\n  /// @return step The value of open ratio step, multiplied by 1e18.\n  function _getOpenRatio() internal view returns (uint256 ratio, uint256 step) {\n    bytes32 data = fundingMiscData;\n    ratio = data.decodeUint(OPEN_RATIO_OFFSET, 30);\n    step = data.decodeUint(OPEN_RATIO_STEP_OFFSET, 60);\n  }\n\n  /// @dev Internal function to update the fee ratio for opening position.\n  /// @param ratio The open ratio value, multiplied by 1e9.\n  /// @param step The open ratio step value, multiplied by 1e18.\n  function _updateOpenRatio(uint256 ratio, uint256 step) internal {\n    _checkValueTooLarge(ratio, FEE_PRECISION);\n    _checkValueTooLarge(step, PRECISION);\n\n    bytes32 data = fundingMiscData;\n    data = data.insertUint(ratio, OPEN_RATIO_OFFSET, 30);\n    fundingMiscData = data.insertUint(step, OPEN_RATIO_STEP_OFFSET, 60);\n\n    emit UpdateOpenRatio(ratio, step);\n  }\n\n  /// @dev Internal function to get the value of close ratio, multiplied by 1e9.\n  function _getCloseFeeRatio() internal view returns (uint256) {\n    return fundingMiscData.decodeUint(CLOSE_FEE_RATIO_OFFSET, 30);\n  }\n\n  /// @dev Internal function to update the fee ratio for closing position.\n  /// @param newRatio The close fee ratio value, multiplied by 1e9.\n  function _updateCloseFeeRatio(uint256 newRatio) internal {\n    _checkValueTooLarge(newRatio, FEE_PRECISION);\n\n    bytes32 data = fundingMiscData;\n    uint256 oldRatio = data.decodeUint(CLOSE_FEE_RATIO_OFFSET, 30);\n    fundingMiscData = data.insertUint(newRatio, CLOSE_FEE_RATIO_OFFSET, 30);\n\n    emit UpdateCloseFeeRatio(oldRatio, newRatio);\n  }\n\n  /// @dev Internal function to get the value of funding ratio, multiplied by 1e9.\n  function _getFundingRatio() internal view returns (uint256) {\n    return fundingMiscData.decodeUint(FUNDING_RATIO_OFFSET, 32);\n  }\n\n  /// @dev Internal function to update the funding ratio.\n  /// @param newRatio The funding ratio value, multiplied by 1e9.\n  function _updateFundingRatio(uint256 newRatio) internal {\n    _checkValueTooLarge(newRatio, MAX_FUNDING_RATIO);\n\n    bytes32 data = fundingMiscData;\n    uint256 oldRatio = data.decodeUint(FUNDING_RATIO_OFFSET, 32);\n    fundingMiscData = data.insertUint(newRatio, FUNDING_RATIO_OFFSET, 32);\n\n    emit UpdateFundingRatio(oldRatio, newRatio);\n  }\n\n  /// @dev Internal function to return interest rate snapshot.\n  /// @param snapshot The previous borrow index snapshot.\n  /// @return newBorrowIndex The current borrow index, multiplied by 1e27.\n  /// @return rate The annual interest rate, multiplied by 1e18.\n  function _getAverageInterestRate(\n    BorrowRateSnapshot memory snapshot\n  ) internal view returns (uint256 newBorrowIndex, uint256 rate) {\n    uint256 prevBorrowIndex = snapshot.borrowIndex;\n    newBorrowIndex = IAaveV3Pool(lendingPool).getReserveNormalizedVariableDebt(baseAsset);\n    // absolute rate change is (new - prev) / prev\n    // annual interest rate is (new - prev) / prev / duration * 365 days\n    uint256 duration = block.timestamp - snapshot.timestamp;\n    // @note Users can trigger this every `MIN_SNAPSHOT_DELAY` seconds and make the interest rate never change.\n    // We allow users to do so, since the risk is not very high. And if we remove this if, the computed interest\n    // rate may not correct due to small `duration`.\n    if (duration < MIN_SNAPSHOT_DELAY) {\n      rate = snapshot.lastInterestRate;\n    } else {\n      rate = ((newBorrowIndex - prevBorrowIndex) * 365 days * PRECISION) / (prevBorrowIndex * duration);\n      if (rate == 0) rate = snapshot.lastInterestRate;\n    }\n  }\n\n  /// @dev Internal function to update interest rate snapshot.\n  function _updateInterestRate(uint256 newBorrowIndex, uint256 lastInterestRate) internal {\n    BorrowRateSnapshot memory snapshot = borrowRateSnapshot;\n    snapshot.borrowIndex = uint128(newBorrowIndex);\n    snapshot.lastInterestRate = uint80(lastInterestRate);\n    snapshot.timestamp = uint48(block.timestamp);\n    borrowRateSnapshot = snapshot;\n\n    emit SnapshotAaveBorrowIndex(newBorrowIndex, block.timestamp);\n  }\n\n  /// @inheritdoc BasePool\n  function _updateCollAndDebtIndex() internal virtual override returns (uint256 newCollIndex, uint256 newDebtIndex) {\n    (newDebtIndex, newCollIndex) = _getDebtAndCollateralIndex();\n\n    BorrowRateSnapshot memory snapshot = borrowRateSnapshot;\n    uint256 duration = block.timestamp - snapshot.timestamp;\n    if (duration > 0) {\n      (uint256 borrowIndex, uint256 interestRate) = _getAverageInterestRate(snapshot);\n      if (IPegKeeper(pegKeeper).isFundingEnabled()) {\n        (, uint256 totalColls) = _getDebtAndCollateralShares();\n        uint256 totalRawColls = _convertToRawColl(totalColls, newCollIndex, Math.Rounding.Down);\n        uint256 funding = (totalRawColls * interestRate * duration) / (365 days * PRECISION);\n        funding = ((funding * _getFundingRatio()) / FEE_PRECISION);\n\n        // update collateral index with funding costs\n        newCollIndex = (newCollIndex * totalRawColls) / (totalRawColls - funding);\n        _updateCollateralIndex(newCollIndex);\n      }\n\n      // update interest snapshot\n      _updateInterestRate(borrowIndex, interestRate);\n    }\n  }\n\n  /// @inheritdoc BasePool\n  function _deductProtocolFees(int256 rawColl) internal view virtual override returns (uint256) {\n    if (rawColl > 0) {\n      // open position or add collateral\n      uint256 feeRatio = getOpenFeeRatio();\n      if (feeRatio > FEE_PRECISION) feeRatio = FEE_PRECISION;\n      return (uint256(rawColl) * feeRatio) / FEE_PRECISION;\n    } else {\n      // close position or remove collateral\n      return (uint256(-rawColl) * _getCloseFeeRatio()) / FEE_PRECISION;\n    }\n  }\n}\n"},"contracts/core/pool/BasePool.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IPegKeeper } from \"../../interfaces/IPegKeeper.sol\";\nimport { IPool } from \"../../interfaces/IPool.sol\";\nimport { IPoolManager } from \"../../interfaces/IPoolManager.sol\";\nimport { IPriceOracle } from \"../../price-oracle/interfaces/IPriceOracle.sol\";\n\nimport { WordCodec } from \"../../common/codec/WordCodec.sol\";\nimport { Math } from \"../../libraries/Math.sol\";\nimport { TickBitmap } from \"../../libraries/TickBitmap.sol\";\nimport { PositionLogic } from \"./PositionLogic.sol\";\nimport { TickLogic } from \"./TickLogic.sol\";\n\nabstract contract BasePool is TickLogic, PositionLogic {\n  using TickBitmap for mapping(int8 => uint256);\n  using WordCodec for bytes32;\n\n  /***********\n   * Structs *\n   ***********/\n\n  struct OperationMemoryVar {\n    int256 tick;\n    uint48 node;\n    uint256 positionColl;\n    uint256 positionDebt;\n    int256 newColl;\n    int256 newDebt;\n    uint256 collIndex;\n    uint256 debtIndex;\n    uint256 globalColl;\n    uint256 globalDebt;\n    uint256 price;\n  }\n\n  /*************\n   * Modifiers *\n   *************/\n\n  modifier onlyPoolManager() {\n    if (_msgSender() != poolManager) {\n      revert ErrorCallerNotPoolManager();\n    }\n    _;\n  }\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _poolManager) {\n    _checkAddressNotZero(_poolManager);\n\n    poolManager = _poolManager;\n    fxUSD = IPoolManager(_poolManager).fxUSD();\n    pegKeeper = IPoolManager(_poolManager).pegKeeper();\n  }\n\n  function __BasePool_init() internal onlyInitializing {\n    _updateDebtIndex(E96);\n    _updateCollateralIndex(E96);\n    _updateDebtRatioRange(500000000000000000, 857142857142857142); // 1/2 ~ 6/7\n    _updateMaxRedeemRatioPerTick(200000000); // 20%\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IPool\n  function operate(\n    uint256 positionId,\n    int256 newRawColl,\n    int256 newRawDebt,\n    address owner\n  ) external onlyPoolManager returns (uint256, int256, int256, uint256) {\n    if (newRawColl == 0 && newRawDebt == 0) revert ErrorNoSupplyAndNoBorrow();\n    if (newRawColl != 0 && (newRawColl > -MIN_COLLATERAL && newRawColl < MIN_COLLATERAL)) {\n      revert ErrorCollateralTooSmall();\n    }\n    if (newRawDebt != 0 && (newRawDebt > -MIN_DEBT && newRawDebt < MIN_DEBT)) {\n      revert ErrorDebtTooSmall();\n    }\n    if (newRawDebt > 0 && (_isBorrowPaused() || !IPegKeeper(pegKeeper).isBorrowAllowed())) {\n      revert ErrorBorrowPaused();\n    }\n\n    OperationMemoryVar memory op;\n    // price precision and ratio precision are both 1e18, use min price here\n    op.price = IPriceOracle(priceOracle).getExchangePrice();\n    (op.globalDebt, op.globalColl) = _getDebtAndCollateralShares();\n    (op.collIndex, op.debtIndex) = _updateCollAndDebtIndex();\n    if (positionId == 0) {\n      positionId = _mintPosition(owner);\n    } else {\n      // make sure position is owned and check owner only in case of withdraw or borrow\n      if (ownerOf(positionId) != owner && (newRawColl < 0 || newRawDebt > 0)) {\n        revert ErrorNotPositionOwner();\n      }\n      PositionInfo memory position = _getAndUpdatePosition(positionId);\n      // temporarily remove position from tick tree for simplicity\n      _removePositionFromTick(position);\n      op.tick = position.tick;\n      op.node = position.nodeId;\n      op.positionDebt = position.debts;\n      op.positionColl = position.colls;\n\n      // cannot withdraw or borrow when the position is above liquidation ratio\n      if (newRawColl < 0 || newRawDebt > 0) {\n        uint256 rawColls = _convertToRawColl(op.positionColl, op.collIndex, Math.Rounding.Down);\n        uint256 rawDebts = _convertToRawDebt(op.positionDebt, op.debtIndex, Math.Rounding.Down);\n        (uint256 debtRatio, ) = _getLiquidateRatios();\n        if (rawDebts * PRECISION * PRECISION > debtRatio * rawColls * op.price) revert ErrorPositionInLiquidationMode();\n      }\n    }\n\n    uint256 protocolFees;\n    // supply or withdraw\n    if (newRawColl > 0) {\n      protocolFees = _deductProtocolFees(newRawColl);\n      newRawColl -= int256(protocolFees);\n      op.newColl = int256(_convertToCollShares(uint256(newRawColl), op.collIndex, Math.Rounding.Down));\n      op.positionColl += uint256(op.newColl);\n      op.globalColl += uint256(op.newColl);\n    } else if (newRawColl < 0) {\n      if (newRawColl == type(int256).min) {\n        // this is max withdraw\n        newRawColl = -int256(_convertToRawColl(op.positionColl, op.collIndex, Math.Rounding.Down));\n        op.newColl = -int256(op.positionColl);\n      } else {\n        // this is partial withdraw, rounding up removing extra wei from collateral\n        op.newColl = -int256(_convertToCollShares(uint256(-newRawColl), op.collIndex, Math.Rounding.Up));\n        if (uint256(-op.newColl) > op.positionColl) revert ErrorWithdrawExceedSupply();\n      }\n      unchecked {\n        op.positionColl -= uint256(-op.newColl);\n        op.globalColl -= uint256(-op.newColl);\n      }\n      protocolFees = _deductProtocolFees(newRawColl);\n      newRawColl += int256(protocolFees);\n    }\n\n    // borrow or repay\n    if (newRawDebt > 0) {\n      // rounding up adding extra wei in debt\n      op.newDebt = int256(_convertToDebtShares(uint256(newRawDebt), op.debtIndex, Math.Rounding.Up));\n      op.positionDebt += uint256(op.newDebt);\n      op.globalDebt += uint256(op.newDebt);\n    } else if (newRawDebt < 0) {\n      if (newRawDebt == type(int256).min) {\n        // this is max repay, rounding up amount that will be transferred in to pay back full debt:\n        // subtracting -1 of negative debtAmount newDebt_ for safe rounding (increasing payback)\n        newRawDebt = -int256(_convertToRawDebt(op.positionDebt, op.debtIndex, Math.Rounding.Up));\n        op.newDebt = -int256(op.positionDebt);\n      } else {\n        // this is partial repay, safe rounding up negative amount to rounding reduce payback\n        op.newDebt = -int256(_convertToDebtShares(uint256(-newRawDebt), op.debtIndex, Math.Rounding.Up));\n      }\n      op.positionDebt -= uint256(-op.newDebt);\n      op.globalDebt -= uint256(-op.newDebt);\n    }\n\n    // final debt ratio check\n    {\n      // check position debt ratio is between `minDebtRatio` and `maxDebtRatio`.\n      uint256 rawColls = _convertToRawColl(op.positionColl, op.collIndex, Math.Rounding.Down);\n      uint256 rawDebts = _convertToRawDebt(op.positionDebt, op.debtIndex, Math.Rounding.Down);\n      (uint256 minDebtRatio, uint256 maxDebtRatio) = _getDebtRatioRange();\n      if (rawDebts * PRECISION * PRECISION > maxDebtRatio * rawColls * op.price) revert ErrorDebtRatioTooLarge();\n      if (rawDebts * PRECISION * PRECISION < minDebtRatio * rawColls * op.price) revert ErrorDebtRatioTooSmall();\n    }\n\n    // update position state to storage\n    (op.tick, op.node) = _addPositionToTick(op.positionColl, op.positionDebt, true);\n\n    if (op.positionColl > type(uint96).max) revert ErrorOverflow();\n    if (op.positionDebt > type(uint96).max) revert ErrorOverflow();\n    positionData[positionId] = PositionInfo(int16(op.tick), op.node, uint96(op.positionColl), uint96(op.positionDebt));\n\n    // update global state to storage\n    _updateDebtAndCollateralShares(op.globalDebt, op.globalColl);\n\n    emit PositionSnapshot(positionId, int16(op.tick), op.positionColl, op.positionDebt, op.price);\n\n    return (positionId, newRawColl, newRawDebt, protocolFees);\n  }\n\n  /// @inheritdoc IPool\n  function redeem(uint256 rawDebts) external onlyPoolManager returns (uint256 rawColls) {\n    if (_isRedeemPaused()) revert ErrorRedeemPaused();\n\n    (uint256 cachedCollIndex, uint256 cachedDebtIndex) = _updateCollAndDebtIndex();\n    (uint256 cachedTotalDebts, uint256 cachedTotalColls) = _getDebtAndCollateralShares();\n    uint256 price = IPriceOracle(priceOracle).getRedeemPrice();\n    // check global debt ratio, if global debt ratio >= 1, disable redeem\n    {\n      uint256 totalRawColls = _convertToRawColl(cachedTotalColls, cachedCollIndex, Math.Rounding.Down);\n      uint256 totalRawDebts = _convertToRawDebt(cachedTotalDebts, cachedDebtIndex, Math.Rounding.Down);\n      if (totalRawDebts * PRECISION >= totalRawColls * price) revert ErrorPoolUnderCollateral();\n    }\n\n    int16 tick = _getTopTick();\n    bool hasDebt = true;\n    uint256 debtShare = _convertToDebtShares(rawDebts, cachedDebtIndex, Math.Rounding.Down);\n    while (debtShare > 0) {\n      if (!hasDebt) {\n        (tick, hasDebt) = tickBitmap.nextDebtPositionWithinOneWord(tick - 1);\n      } else {\n        uint256 node = tickData[tick];\n        bytes32 value = tickTreeData[node].value;\n        uint256 tickDebtShare = value.decodeUint(DEBT_SHARE_OFFSET, 128);\n        // skip bad debt\n        {\n          uint256 tickCollShare = value.decodeUint(COLL_SHARE_OFFSET, 128);\n          if (\n            _convertToRawDebt(tickDebtShare, cachedDebtIndex, Math.Rounding.Down) * PRECISION >\n            _convertToRawColl(tickCollShare, cachedCollIndex, Math.Rounding.Down) * price\n          ) {\n            hasDebt = false;\n            tick = tick;\n            continue;\n          }\n        }\n\n        // redeem at most `maxRedeemRatioPerTick`\n        uint256 debtShareToRedeem = (tickDebtShare * _getMaxRedeemRatioPerTick()) / FEE_PRECISION;\n        if (debtShareToRedeem > debtShare) debtShareToRedeem = debtShare;\n        uint256 rawCollRedeemed = (_convertToRawDebt(debtShareToRedeem, cachedDebtIndex, Math.Rounding.Down) *\n          PRECISION) / price;\n        uint256 collShareRedeemed = _convertToCollShares(rawCollRedeemed, cachedCollIndex, Math.Rounding.Down);\n        _liquidateTick(tick, collShareRedeemed, debtShareToRedeem, price);\n        debtShare -= debtShareToRedeem;\n        rawColls += rawCollRedeemed;\n\n        cachedTotalColls -= collShareRedeemed;\n        cachedTotalDebts -= debtShareToRedeem;\n\n        (tick, hasDebt) = tickBitmap.nextDebtPositionWithinOneWord(tick - 1);\n      }\n      if (tick == type(int16).min) break;\n    }\n    _updateDebtAndCollateralShares(cachedTotalDebts, cachedTotalColls);\n  }\n\n  /// @inheritdoc IPool\n  function rebalance(int16 tick, uint256 maxRawDebts) external onlyPoolManager returns (RebalanceResult memory result) {\n    (uint256 cachedCollIndex, uint256 cachedDebtIndex) = _updateCollAndDebtIndex();\n    (, uint256 price, ) = IPriceOracle(priceOracle).getPrice(); // use min price\n    uint256 node = tickData[tick];\n    bytes32 value = tickTreeData[node].value;\n    uint256 tickRawColl = _convertToRawColl(\n      value.decodeUint(COLL_SHARE_OFFSET, 128),\n      cachedCollIndex,\n      Math.Rounding.Down\n    );\n    uint256 tickRawDebt = _convertToRawDebt(\n      value.decodeUint(DEBT_SHARE_OFFSET, 128),\n      cachedDebtIndex,\n      Math.Rounding.Down\n    );\n    (uint256 rebalanceDebtRatio, uint256 rebalanceBonusRatio) = _getRebalanceRatios();\n    (uint256 liquidateDebtRatio, ) = _getLiquidateRatios();\n    // rebalance only debt ratio >= `rebalanceDebtRatio` and ratio < `liquidateDebtRatio`\n    if (tickRawDebt * PRECISION * PRECISION < rebalanceDebtRatio * tickRawColl * price) {\n      revert ErrorRebalanceDebtRatioNotReached();\n    }\n    if (tickRawDebt * PRECISION * PRECISION >= liquidateDebtRatio * tickRawColl * price) {\n      revert ErrorRebalanceOnLiquidatableTick();\n    }\n\n    // compute debts to rebalance to make debt ratio to `rebalanceDebtRatio`\n    result.rawDebts = _getRawDebtToRebalance(tickRawColl, tickRawDebt, price, rebalanceDebtRatio, rebalanceBonusRatio);\n    if (maxRawDebts < result.rawDebts) result.rawDebts = maxRawDebts;\n\n    uint256 debtShareToRebalance = _convertToDebtShares(result.rawDebts, cachedDebtIndex, Math.Rounding.Down);\n    result.rawColls = (result.rawDebts * PRECISION) / price;\n    result.bonusRawColls = (result.rawColls * rebalanceBonusRatio) / FEE_PRECISION;\n    if (result.bonusRawColls > tickRawColl - result.rawColls) {\n      result.bonusRawColls = tickRawColl - result.rawColls;\n    }\n    uint256 collShareToRebalance = _convertToCollShares(\n      result.rawColls + result.bonusRawColls,\n      cachedCollIndex,\n      Math.Rounding.Down\n    );\n\n    _liquidateTick(tick, collShareToRebalance, debtShareToRebalance, price);\n    unchecked {\n      (uint256 totalDebts, uint256 totalColls) = _getDebtAndCollateralShares();\n      _updateDebtAndCollateralShares(totalDebts - debtShareToRebalance, totalColls - collShareToRebalance);\n    }\n  }\n\n  struct RebalanceVars {\n    uint256 tickCollShares;\n    uint256 tickDebtShares;\n    uint256 tickRawColls;\n    uint256 tickRawDebts;\n    uint256 maxRawDebts;\n    uint256 rebalanceDebtRatio;\n    uint256 rebalanceBonusRatio;\n    uint256 price;\n    uint256 collIndex;\n    uint256 debtIndex;\n    uint256 totalCollShares;\n    uint256 totalDebtShares;\n  }\n\n  /// @inheritdoc IPool\n  function rebalance(uint256 maxRawDebts) external onlyPoolManager returns (RebalanceResult memory result) {\n    RebalanceVars memory vars;\n    vars.maxRawDebts = maxRawDebts;\n    (vars.rebalanceDebtRatio, vars.rebalanceBonusRatio) = _getRebalanceRatios();\n    (, vars.price, ) = IPriceOracle(priceOracle).getPrice();\n    (vars.collIndex, vars.debtIndex) = _updateCollAndDebtIndex();\n    (vars.totalDebtShares, vars.totalCollShares) = _getDebtAndCollateralShares();\n    (uint256 liquidateDebtRatio, ) = _getLiquidateRatios();\n\n    int16 tick = _getTopTick();\n    bool hasDebt = true;\n    while (vars.maxRawDebts > 0) {\n      if (!hasDebt) {\n        (tick, hasDebt) = tickBitmap.nextDebtPositionWithinOneWord(tick - 1);\n      } else {\n        (vars.tickCollShares, vars.tickDebtShares, vars.tickRawColls, vars.tickRawDebts) = _getTickRawCollAndDebts(\n          tick,\n          vars.collIndex,\n          vars.debtIndex\n        );\n        // skip bad debt and liquidatable positions: coll * price * liquidateDebtRatio <= debts\n        if (vars.tickRawColls * vars.price * liquidateDebtRatio <= vars.tickRawDebts * PRECISION * PRECISION) {\n          hasDebt = false;\n          tick = tick;\n          continue;\n        }\n        // skip dust\n        if (vars.tickRawDebts < uint256(MIN_DEBT)) {\n          hasDebt = false;\n          tick = tick;\n          continue;\n        }\n        // no more rebalanceable tick: coll * price * rebalanceDebtRatio > debts\n        if (vars.tickRawColls * vars.price * vars.rebalanceDebtRatio > vars.tickRawDebts * PRECISION * PRECISION) {\n          break;\n        }\n        // rebalance this tick\n        (uint256 rawDebts, uint256 rawColls, uint256 bonusRawColls) = _rebalanceTick(tick, vars);\n        result.rawDebts += rawDebts;\n        result.rawColls += rawColls;\n        result.bonusRawColls += bonusRawColls;\n\n        // goto next tick\n        (tick, hasDebt) = tickBitmap.nextDebtPositionWithinOneWord(tick - 1);\n      }\n      if (tick == type(int16).min) break;\n    }\n\n    _updateDebtAndCollateralShares(vars.totalDebtShares, vars.totalCollShares);\n  }\n\n  struct LiquidateVars {\n    uint256 tickCollShares;\n    uint256 tickDebtShares;\n    uint256 tickRawColls;\n    uint256 tickRawDebts;\n    uint256 maxRawDebts;\n    uint256 reservedRawColls;\n    uint256 liquidateDebtRatio;\n    uint256 liquidateBonusRatio;\n    uint256 price;\n    uint256 collIndex;\n    uint256 debtIndex;\n    uint256 totalCollShares;\n    uint256 totalDebtShares;\n  }\n\n  /// @inheritdoc IPool\n  function liquidate(\n    uint256 maxRawDebts,\n    uint256 reservedRawColls\n  ) external onlyPoolManager returns (LiquidateResult memory result) {\n    LiquidateVars memory vars;\n    vars.maxRawDebts = maxRawDebts;\n    vars.reservedRawColls = reservedRawColls;\n    (vars.liquidateDebtRatio, vars.liquidateBonusRatio) = _getLiquidateRatios();\n    (, vars.price, ) = IPriceOracle(priceOracle).getPrice();\n    (vars.collIndex, vars.debtIndex) = _updateCollAndDebtIndex();\n    (vars.totalDebtShares, vars.totalCollShares) = _getDebtAndCollateralShares();\n\n    int16 tick = _getTopTick();\n    bool hasDebt = true;\n    while (vars.maxRawDebts > 0) {\n      if (!hasDebt) {\n        (tick, hasDebt) = tickBitmap.nextDebtPositionWithinOneWord(tick - 1);\n      } else {\n        (vars.tickCollShares, vars.tickDebtShares, vars.tickRawColls, vars.tickRawDebts) = _getTickRawCollAndDebts(\n          tick,\n          vars.collIndex,\n          vars.debtIndex\n        );\n        // no more liquidatable tick: coll * price * liquidateDebtRatio > debts\n        if (vars.tickRawColls * vars.price * vars.liquidateDebtRatio > vars.tickRawDebts * PRECISION * PRECISION) {\n          // skip dust, since the results might be wrong\n          if (vars.tickRawDebts < uint256(MIN_DEBT)) {\n            hasDebt = false;\n            tick = tick;\n            continue;\n          }\n          break;\n        }\n        // rebalance this tick\n        (uint256 rawDebts, uint256 rawColls, uint256 bonusRawColls, uint256 bonusFromReserve) = _liquidateTick(\n          tick,\n          vars\n        );\n        result.rawDebts += rawDebts;\n        result.rawColls += rawColls;\n        result.bonusRawColls += bonusRawColls;\n        result.bonusFromReserve += bonusFromReserve;\n\n        // goto next tick\n        (tick, hasDebt) = tickBitmap.nextDebtPositionWithinOneWord(tick - 1);\n      }\n      if (tick == type(int16).min) break;\n    }\n\n    _updateDebtAndCollateralShares(vars.totalDebtShares, vars.totalCollShares);\n    _updateDebtIndex(vars.debtIndex);\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Update the borrow and redeem status.\n  /// @param borrowStatus The new borrow status.\n  /// @param redeemStatus The new redeem status.\n  function updateBorrowAndRedeemStatus(bool borrowStatus, bool redeemStatus) external onlyRole(EMERGENCY_ROLE) {\n    _updateBorrowStatus(borrowStatus);\n    _updateRedeemStatus(redeemStatus);\n  }\n\n  /// @notice Update debt ratio range.\n  /// @param minRatio The minimum allowed debt ratio to update, multiplied by 1e18.\n  /// @param maxRatio The maximum allowed debt ratio to update, multiplied by 1e18.\n  function updateDebtRatioRange(uint256 minRatio, uint256 maxRatio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateDebtRatioRange(minRatio, maxRatio);\n  }\n\n  /// @notice Update maximum redeem ratio per tick.\n  /// @param ratio The ratio to update, multiplied by 1e9.\n  function updateMaxRedeemRatioPerTick(uint256 ratio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateMaxRedeemRatioPerTick(ratio);\n  }\n\n  /// @notice Update ratio for rebalance.\n  /// @param debtRatio The minimum debt ratio to start rebalance, multiplied by 1e18.\n  /// @param bonusRatio The bonus ratio during rebalance, multiplied by 1e9.\n  function updateRebalanceRatios(uint256 debtRatio, uint256 bonusRatio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateRebalanceRatios(debtRatio, bonusRatio);\n  }\n\n  /// @notice Update ratio for liquidate.\n  /// @param debtRatio The minimum debt ratio to start liquidate, multiplied by 1e18.\n  /// @param bonusRatio The bonus ratio during liquidate, multiplied by 1e9.\n  function updateLiquidateRatios(uint256 debtRatio, uint256 bonusRatio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateLiquidateRatios(debtRatio, bonusRatio);\n  }\n\n  /// @notice Update the address of price oracle.\n  /// @param newOracle The address of new price oracle.\n  function updatePriceOracle(address newOracle) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updatePriceOracle(newOracle);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to compute the amount of debt to rebalance to reach certain debt ratio.\n  /// @param coll The amount of collateral tokens.\n  /// @param debt The amount of debt tokens.\n  /// @param price The price of the collateral token.\n  /// @param targetDebtRatio The target debt ratio, multiplied by 1e18.\n  /// @param incentiveRatio The bonus ratio, multiplied by 1e9.\n  /// @return rawDebts The amount of debt tokens to rebalance.\n  function _getRawDebtToRebalance(\n    uint256 coll,\n    uint256 debt,\n    uint256 price,\n    uint256 targetDebtRatio,\n    uint256 incentiveRatio\n  ) internal pure returns (uint256 rawDebts) {\n    // we have\n    //   1. (debt - x) / (price * (coll - y * (1 + incentive))) <= target_ratio\n    //   2. debt / (price * coll) >= target_ratio\n    // then\n    // => debt - x <= target * price * (coll - y * (1 + incentive)) and y = x / price\n    // => debt - target_ratio * price * coll <= (1 - (1 + incentive) * target) * x\n    // => x >= (debt - target_ratio * price * coll) / (1 - (1 + incentive) * target)\n    rawDebts =\n      (debt * PRECISION * PRECISION - targetDebtRatio * price * coll) /\n      (PRECISION * PRECISION - (PRECISION * targetDebtRatio * (FEE_PRECISION + incentiveRatio)) / FEE_PRECISION);\n  }\n\n  function _getTickRawCollAndDebts(\n    int16 tick,\n    uint256 collIndex,\n    uint256 debtIndex\n  ) internal view returns (uint256 colls, uint256 debts, uint256 rawColls, uint256 rawDebts) {\n    uint256 node = tickData[tick];\n    bytes32 value = tickTreeData[node].value;\n    colls = value.decodeUint(COLL_SHARE_OFFSET, 128);\n    debts = value.decodeUint(DEBT_SHARE_OFFSET, 128);\n    rawColls = _convertToRawColl(colls, collIndex, Math.Rounding.Down);\n    rawDebts = _convertToRawDebt(debts, debtIndex, Math.Rounding.Down);\n  }\n\n  function _rebalanceTick(\n    int16 tick,\n    RebalanceVars memory vars\n  ) internal returns (uint256 rawDebts, uint256 rawColls, uint256 bonusRawColls) {\n    // compute debts to rebalance to make debt ratio to `rebalanceDebtRatio`\n    rawDebts = _getRawDebtToRebalance(\n      vars.tickRawColls,\n      vars.tickRawDebts,\n      vars.price,\n      vars.rebalanceDebtRatio,\n      vars.rebalanceBonusRatio\n    );\n    if (vars.maxRawDebts < rawDebts) rawDebts = vars.maxRawDebts;\n\n    uint256 debtShares = _convertToDebtShares(rawDebts, vars.debtIndex, Math.Rounding.Down);\n    rawColls = (rawDebts * PRECISION) / vars.price;\n    bonusRawColls = (rawColls * vars.rebalanceBonusRatio) / FEE_PRECISION;\n    if (bonusRawColls > vars.tickRawColls - rawColls) {\n      bonusRawColls = vars.tickRawColls - rawColls;\n    }\n    uint256 collShares = _convertToCollShares(rawColls + bonusRawColls, vars.collIndex, Math.Rounding.Down);\n\n    _liquidateTick(tick, collShares, debtShares, vars.price);\n    vars.totalCollShares -= collShares;\n    vars.totalDebtShares -= debtShares;\n    vars.maxRawDebts -= rawDebts;\n  }\n\n  function _liquidateTick(\n    int16 tick,\n    LiquidateVars memory vars\n  ) internal returns (uint256 rawDebts, uint256 rawColls, uint256 bonusRawColls, uint256 bonusFromReserve) {\n    uint256 virtualTickRawColls = vars.tickRawColls + vars.reservedRawColls;\n    rawDebts = vars.tickRawDebts;\n    if (rawDebts > vars.maxRawDebts) rawDebts = vars.maxRawDebts;\n    rawColls = (rawDebts * PRECISION) / vars.price;\n    uint256 debtShares;\n    uint256 collShares;\n    if (rawDebts == vars.tickRawDebts) {\n      // full liquidation\n      debtShares = vars.tickDebtShares;\n    } else {\n      // partial liquidation\n      debtShares = _convertToDebtShares(rawDebts, vars.debtIndex, Math.Rounding.Down);\n    }\n    if (virtualTickRawColls <= rawColls) {\n      // even reserve funds cannot cover bad debts, no bonus and will trigger bad debt redistribution\n      rawColls = virtualTickRawColls;\n      bonusFromReserve = vars.reservedRawColls;\n      rawDebts = (virtualTickRawColls * vars.price) / PRECISION;\n      debtShares = _convertToDebtShares(rawDebts, vars.debtIndex, Math.Rounding.Down);\n      collShares = vars.tickCollShares;\n    } else {\n      // Bonus is from colls in tick, if it is not enough will use reserve funds\n      bonusRawColls = (rawColls * vars.liquidateBonusRatio) / FEE_PRECISION;\n      uint256 rawCollWithBonus = bonusRawColls + rawColls;\n      if (rawCollWithBonus > virtualTickRawColls) {\n        rawCollWithBonus = virtualTickRawColls;\n        bonusRawColls = rawCollWithBonus - rawColls;\n      }\n      if (rawCollWithBonus >= vars.tickRawColls) {\n        bonusFromReserve = rawCollWithBonus - vars.tickRawColls;\n        collShares = vars.tickCollShares;\n      } else {\n        collShares = _convertToCollShares(rawCollWithBonus, vars.collIndex, Math.Rounding.Down);\n      }\n    }\n\n    vars.reservedRawColls -= bonusFromReserve;\n    if (collShares == vars.tickCollShares && debtShares < vars.tickDebtShares) {\n      // trigger bad debt redistribution\n      uint256 rawBadDebt = _convertToRawDebt(vars.tickDebtShares - debtShares, vars.debtIndex, Math.Rounding.Down);\n      debtShares = vars.tickDebtShares;\n      vars.totalCollShares -= collShares;\n      vars.totalDebtShares -= debtShares;\n      vars.debtIndex += (rawBadDebt * E96) / vars.totalDebtShares;\n    } else {\n      vars.totalCollShares -= collShares;\n      vars.totalDebtShares -= debtShares;\n    }\n    vars.maxRawDebts -= rawDebts;\n    _liquidateTick(tick, collShares, debtShares, vars.price);\n  }\n\n  /// @dev Internal function to update collateral and debt index.\n  /// @return newCollIndex The updated collateral index.\n  /// @return newDebtIndex The updated debt index.\n  function _updateCollAndDebtIndex() internal virtual returns (uint256 newCollIndex, uint256 newDebtIndex);\n\n  /// @dev Internal function to compute the protocol fees.\n  /// @param rawColl The amount of collateral tokens involved.\n  /// @return fees The expected protocol fees.\n  function _deductProtocolFees(int256 rawColl) internal view virtual returns (uint256 fees);\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   */\n  uint256[50] private __gap;\n}\n"},"contracts/core/pool/PoolConstant.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IPool } from \"../../interfaces/IPool.sol\";\n\nabstract contract PoolConstant is IPool {\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The role for emergency operations.\n  bytes32 public constant EMERGENCY_ROLE = keccak256(\"EMERGENCY_ROLE\");\n\n  /// @dev The value of minimum collateral.\n  int256 internal constant MIN_COLLATERAL = 1e9;\n\n  /// @dev The value of minimum debts.\n  int256 internal constant MIN_DEBT = 1e9;\n\n  /// @dev The precision used for various calculation.\n  uint256 internal constant PRECISION = 1e18;\n\n  /// @dev The precision used for fee ratio calculation.\n  uint256 internal constant FEE_PRECISION = 1e9;\n\n  /// @dev bit operation related constants\n  uint256 internal constant E60 = 2 ** 60; // 2^60\n  uint256 internal constant E96 = 2 ** 96; // 2^96\n\n  uint256 internal constant X60 = 0xfffffffffffffff; // 2^60 - 1\n  uint256 internal constant X96 = 0xffffffffffffffffffffffff; // 2^96 - 1\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @inheritdoc IPool\n  address public immutable fxUSD;\n\n  /// @inheritdoc IPool\n  address public immutable poolManager;\n\n  /// @inheritdoc IPool\n  address public immutable pegKeeper;\n}\n"},"contracts/core/pool/PoolErrors.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nabstract contract PoolErrors {\n  /**********\n   * Errors *\n   **********/\n  \n  /// @dev Thrown when the given address is zero.\n  error ErrorZeroAddress();\n\n  /// @dev Thrown when the given value exceeds maximum value.\n  error ErrorValueTooLarge();\n  \n  /// @dev Thrown when the caller is not pool manager.\n  error ErrorCallerNotPoolManager();\n  \n  /// @dev Thrown when the debt amount is too small.\n  error ErrorDebtTooSmall();\n\n  /// @dev Thrown when the collateral amount is too small.\n  error ErrorCollateralTooSmall();\n  \n  /// @dev Thrown when both collateral amount and debt amount are zero.\n  error ErrorNoSupplyAndNoBorrow();\n  \n  /// @dev Thrown when borrow is paused.\n  error ErrorBorrowPaused();\n\n  /// @dev Thrown when redeem is paused.\n  error ErrorRedeemPaused();\n  \n  /// @dev Thrown when the caller is not position owner during withdraw or borrow.\n  error ErrorNotPositionOwner();\n  \n  /// @dev Thrown when withdraw more than supplied.\n  error ErrorWithdrawExceedSupply();\n  \n  /// @dev Thrown when the debt ratio is too small.\n  error ErrorDebtRatioTooSmall();\n\n  /// @dev Thrown when the debt ratio is too large.\n  error ErrorDebtRatioTooLarge();\n  \n  /// @dev Thrown when pool is under collateral.\n  error ErrorPoolUnderCollateral();\n  \n  /// @dev Thrown when the current debt ratio <= rebalance debt ratio.\n  error ErrorRebalanceDebtRatioNotReached();\n\n  /// @dev Thrown when the current debt ratio > liquidate debt ratio.\n  error ErrorPositionInLiquidationMode();\n\n  error ErrorRebalanceOnLiquidatableTick();\n\n  error ErrorRebalanceOnLiquidatablePosition();\n\n  error ErrorInsufficientCollateralToLiquidate();\n\n  error ErrorOverflow();\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to check value not too large.\n  /// @param value The value to check.\n  /// @param upperBound The upper bound for the given value.\n  function _checkValueTooLarge(uint256 value, uint256 upperBound) internal pure {\n    if (value > upperBound) revert ErrorValueTooLarge();\n  }\n\n  function _checkAddressNotZero(address value) internal pure {\n    if (value == address(0)) revert ErrorZeroAddress();\n  }\n}\n"},"contracts/core/pool/PoolStorage.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { AccessControlUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\nimport { ERC721Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol\";\n\nimport { IPool } from \"../../interfaces/IPool.sol\";\n\nimport { WordCodec } from \"../../common/codec/WordCodec.sol\";\nimport { PoolConstant } from \"./PoolConstant.sol\";\nimport { PoolErrors } from \"./PoolErrors.sol\";\n\nabstract contract PoolStorage is ERC721Upgradeable, AccessControlUpgradeable, PoolConstant, PoolErrors {\n  using WordCodec for bytes32;\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev Below are offsets of each variables in `miscData`.\n  uint256 private constant BORROW_FLAG_OFFSET = 0;\n  uint256 private constant REDEEM_FLAG_OFFSET = 1;\n  uint256 private constant TOP_TICK_OFFSET = 2;\n  uint256 private constant NEXT_POSITION_OFFSET = 18;\n  uint256 private constant NEXT_NODE_OFFSET = 50;\n  uint256 private constant MIN_DEBT_RATIO_OFFSET = 98;\n  uint256 private constant MAX_DEBT_RATIO_OFFSET = 158;\n  uint256 private constant MAX_REDEEM_RATIO_OFFSET = 218;\n\n  /// @dev Below are offsets of each variables in `rebalanceRatioData`.\n  uint256 private constant REBALANCE_DEBT_RATIO_OFFSET = 0;\n  uint256 private constant REBALANCE_BONUS_RATIO_OFFSET = 60;\n  uint256 private constant LIQUIDATE_DEBT_RATIO_OFFSET = 90;\n  uint256 private constant LIQUIDATE_BONUS_RATIO_OFFSET = 150;\n\n  /// @dev Below are offsets of each variables in `indexData`.\n  uint256 private constant DEBT_INDEX_OFFSET = 0;\n  uint256 private constant COLLATERAL_INDEX_OFFSET = 128;\n\n  /// @dev Below are offsets of each variables in `sharesData`.\n  uint256 private constant DEBT_SHARES_OFFSET = 0;\n  uint256 private constant COLLATERAL_SHARES_OFFSET = 128;\n\n  /***********\n   * Structs *\n   ***********/\n\n  /// @dev if nodeId = 0, tick is not used and this position only has collateral\n  ///\n  /// @param tick The tick this position belongs to at the beginning.\n  /// @param nodeId The tree node id this position belongs to at the beginning.\n  /// @param colls The collateral shares this position has.\n  /// @param debts The debt shares this position has.\n  struct PositionInfo {\n    int16 tick;\n    uint48 nodeId;\n    // `uint96` is enough, since we use `86` bits in `PoolManager`.\n    uint96 colls;\n    // `uint96` is enough, since we use `96` bits in `PoolManager`.\n    uint96 debts;\n  }\n\n  /// @dev The compiler will pack it into two `uint256`.\n  /// @param metadata The metadata for tree node.\n  ///   ```text\n  ///   * Field           Bits    Index       Comments\n  ///   * parent          48      0           The index for parent tree node.\n  ///   * tick            16      48          The original tick for this tree node.\n  ///   * coll ratio      64      64          The remained coll share ratio base on parent node, the value is real ratio * 2^60.\n  ///   * debt ratio      64      128         The remained debt share ratio base on parent node, the value is real ratio * 2^60.\n  ///   ```\n  /// @param value The value for tree node\n  ///   ```text\n  ///   * Field           Bits    Index       Comments\n  ///   * coll share      128     0           The original total coll share before rebalance or redeem.\n  ///   * debt share      128     128         The original total debt share before rebalance or redeem.\n  ///   ```\n  struct TickTreeNode {\n    bytes32 metadata;\n    bytes32 value;\n  }\n\n  /*********************\n   * Storage Variables *\n   *********************/\n\n  /// @inheritdoc IPool\n  address public collateralToken;\n\n  /// @inheritdoc IPool\n  address public priceOracle;\n\n  /// @dev `miscData` is a storage slot that can be used to store unrelated pieces of information.\n  ///\n  /// - The *borrow flag* indicates whether borrow fxUSD is allowed, 1 means paused.\n  /// - The *redeem flag* indicates whether redeem fxUSD is allowed, 1 means paused.\n  /// - The *top tick* is the largest tick with debts.\n  /// - The *next position* is the next unassigned position id.\n  /// - The *next node* is the next unassigned tree node id.\n  /// - The *min debt ratio* is the minimum allowed debt ratio, multiplied by 1e18.\n  /// - The *max debt ratio* is the maximum allowed debt ratio, multiplied by 1e18.\n  /// - The *max redeem ratio* is the maximum allowed redeem ratio per tick, multiplied by 1e9.\n  ///\n  /// [ borrow flag | redeem flag | top tick | next position | next node | min debt ratio | max debt ratio | max redeem ratio | reserved ]\n  /// [    1 bit    |    1 bit    | 16  bits |    32 bits    |  48 bits  |    60  bits    |    60  bits    |      30 bits     |  8 bits  ]\n  /// [ MSB                                                                                                                          LSB ]\n  bytes32 private miscData;\n\n  /// @dev `rebalanceRatioData` is a storage slot used to store rebalance and liquidate information.\n  ///\n  /// - The *rebalance debt ratio* is the min debt ratio to start rebalance, multiplied by 1e18.\n  /// - The *rebalance bonus ratio* is the bonus ratio during rebalance, multiplied by 1e9.\n  /// - The *liquidate debt ratio* is the min debt ratio to start liquidate, multiplied by 1e18.\n  /// - The *liquidate bonus ratio* is the bonus ratio during liquidate, multiplied by 1e9.\n  ///\n  /// [ rebalance debt ratio | rebalance bonus ratio | liquidate debt ratio | liquidate bonus ratio | reserved ]\n  /// [       60  bits       |        30 bits        |       60  bits       |        30 bits        | 76  bits ]\n  /// [ MSB                                                                                                LSB ]\n  bytes32 private rebalanceRatioData;\n\n  /// @dev `indexData` is a storage slot used to store debt/collateral index.\n  ///\n  /// - The *debt index* is the index for each debt shares, only increasing, starting from 2^96, max 2^128-1.\n  /// - The *collateral index* is the index for each collateral shares, only increasing, starting from 2^96, max 2^128-1\n  ///\n  /// [ debt index | collateral index ]\n  /// [  128 bits  |     128 bits     ]\n  /// [ MSB                       LSB ]\n  bytes32 private indexData;\n\n  /// @dev `sharesData` is a storage slot used to store debt/collateral shares.\n  ///\n  /// - The *debt shares* is the total debt shares. The actual number of total debts\n  ///   is `<debt shares> * <debt index>`.\n  /// - The *collateral shares* is the total collateral shares. The actual number of\n  ///   total collateral is `<collateral shares> / <collateral index>`.\n  ///\n  /// [ debt shares | collateral shares ]\n  /// [  128  bits  |     128  bits     ]\n  /// [ MSB                         LSB ]\n  bytes32 private sharesData;\n\n  /// @dev Mapping from position id to position information.\n  mapping(uint256 => PositionInfo) public positionData;\n\n  /// @dev Mapping from position id to position metadata.\n  /// [ open timestamp | reserved ]\n  /// [    40  bits    | 216 bits ]\n  /// [ MSB                   LSB ]\n  mapping(uint256 => bytes32) public positionMetadata;\n\n  /// @dev The bitmap for ticks with debts.\n  mapping(int8 => uint256) public tickBitmap;\n\n  /// @dev Mapping from tick to tree node id.\n  mapping(int256 => uint48) public tickData;\n\n  /// @dev Mapping from tree node id to tree node data.\n  mapping(uint256 => TickTreeNode) public tickTreeData;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  function __PoolStorage_init(address _collateralToken, address _priceOracle) internal onlyInitializing {\n    _checkAddressNotZero(_collateralToken);\n\n    collateralToken = _collateralToken;\n    _updatePriceOracle(_priceOracle);\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc AccessControlUpgradeable\n  function supportsInterface(\n    bytes4 interfaceId\n  ) public view virtual override(AccessControlUpgradeable, ERC721Upgradeable) returns (bool) {\n    return super.supportsInterface(interfaceId);\n  }\n\n  /// @inheritdoc IPool\n  function isBorrowPaused() external view returns (bool) {\n    return _isBorrowPaused();\n  }\n\n  /// @inheritdoc IPool\n  function isRedeemPaused() external view returns (bool) {\n    return _isRedeemPaused();\n  }\n\n  /// @inheritdoc IPool\n  function getTopTick() external view returns (int16) {\n    return _getTopTick();\n  }\n\n  /// @inheritdoc IPool\n  function getNextPositionId() external view returns (uint32) {\n    return _getNextPositionId();\n  }\n\n  /// @inheritdoc IPool\n  function getNextTreeNodeId() external view returns (uint48) {\n    return _getNextTreeNodeId();\n  }\n\n  /// @inheritdoc IPool\n  function getDebtRatioRange() external view returns (uint256, uint256) {\n    return _getDebtRatioRange();\n  }\n\n  /// @inheritdoc IPool\n  function getMaxRedeemRatioPerTick() external view returns (uint256) {\n    return _getMaxRedeemRatioPerTick();\n  }\n\n  /// @inheritdoc IPool\n  function getRebalanceRatios() external view returns (uint256, uint256) {\n    return _getRebalanceRatios();\n  }\n\n  /// @inheritdoc IPool\n  function getLiquidateRatios() external view returns (uint256, uint256) {\n    return _getLiquidateRatios();\n  }\n\n  /// @inheritdoc IPool\n  function getDebtAndCollateralIndex() external view returns (uint256, uint256) {\n    return _getDebtAndCollateralIndex();\n  }\n\n  /// @inheritdoc IPool\n  function getDebtAndCollateralShares() external view returns (uint256, uint256) {\n    return _getDebtAndCollateralShares();\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to update price oracle.\n  /// @param newOracle The address of new price oracle;\n  function _updatePriceOracle(address newOracle) internal {\n    _checkAddressNotZero(newOracle);\n\n    address oldOracle = priceOracle;\n    priceOracle = newOracle;\n\n    emit UpdatePriceOracle(oldOracle, newOracle);\n  }\n\n  /*************************************\n   * Internal Functions For `miscData` *\n   *************************************/\n\n  /// @dev Internal function to get the borrow pause status.\n  function _isBorrowPaused() internal view returns (bool) {\n    return miscData.decodeBool(BORROW_FLAG_OFFSET);\n  }\n\n  /// @dev Internal function to update borrow pause status.\n  /// @param status The status to update.\n  function _updateBorrowStatus(bool status) internal {\n    miscData = miscData.insertBool(status, BORROW_FLAG_OFFSET);\n\n    emit UpdateBorrowStatus(status);\n  }\n\n  /// @dev Internal function to get the redeem pause status.\n  function _isRedeemPaused() internal view returns (bool) {\n    return miscData.decodeBool(REDEEM_FLAG_OFFSET);\n  }\n\n  /// @dev Internal function to update redeem pause status.\n  /// @param status The status to update.\n  function _updateRedeemStatus(bool status) internal {\n    miscData = miscData.insertBool(status, REDEEM_FLAG_OFFSET);\n\n    emit UpdateRedeemStatus(status);\n  }\n\n  /// @dev Internal function to get the value of top tick.\n  function _getTopTick() internal view returns (int16) {\n    return int16(miscData.decodeInt(TOP_TICK_OFFSET, 16));\n  }\n\n  /// @dev Internal function to update the top tick.\n  /// @param tick The new top tick.\n  function _updateTopTick(int16 tick) internal {\n    miscData = miscData.insertInt(tick, TOP_TICK_OFFSET, 16);\n  }\n\n  /// @dev Internal function to get next available position id.\n  function _getNextPositionId() internal view returns (uint32) {\n    return uint32(miscData.decodeUint(NEXT_POSITION_OFFSET, 32));\n  }\n\n  /// @dev Internal function to update next available position id.\n  /// @param id The position id to update.\n  function _updateNextPositionId(uint32 id) internal {\n    miscData = miscData.insertUint(id, NEXT_POSITION_OFFSET, 32);\n  }\n\n  /// @dev Internal function to get next available tree node id.\n  function _getNextTreeNodeId() internal view returns (uint48) {\n    return uint48(miscData.decodeUint(NEXT_NODE_OFFSET, 48));\n  }\n\n  /// @dev Internal function to update next available tree node id.\n  /// @param id The tree node id to update.\n  function _updateNextTreeNodeId(uint48 id) internal {\n    miscData = miscData.insertUint(id, NEXT_NODE_OFFSET, 48);\n  }\n\n  /// @dev Internal function to get `minDebtRatio` and `maxDebtRatio`, both multiplied by 1e18.\n  function _getDebtRatioRange() internal view returns (uint256 minDebtRatio, uint256 maxDebtRatio) {\n    bytes32 data = miscData;\n    minDebtRatio = data.decodeUint(MIN_DEBT_RATIO_OFFSET, 60);\n    maxDebtRatio = data.decodeUint(MAX_DEBT_RATIO_OFFSET, 60);\n  }\n\n  /// @dev Internal function to update debt ratio range.\n  /// @param minDebtRatio The minimum allowed debt ratio to update, multiplied by 1e18.\n  /// @param maxDebtRatio The maximum allowed debt ratio to update, multiplied by 1e18.\n  function _updateDebtRatioRange(uint256 minDebtRatio, uint256 maxDebtRatio) internal {\n    _checkValueTooLarge(minDebtRatio, maxDebtRatio);\n    _checkValueTooLarge(maxDebtRatio, PRECISION);\n\n    bytes32 data = miscData;\n    data = data.insertUint(minDebtRatio, MIN_DEBT_RATIO_OFFSET, 60);\n    miscData = data.insertUint(maxDebtRatio, MAX_DEBT_RATIO_OFFSET, 60);\n\n    emit UpdateDebtRatioRange(minDebtRatio, maxDebtRatio);\n  }\n\n  /// @dev Internal function to get the `maxRedeemRatioPerTick`.\n  function _getMaxRedeemRatioPerTick() internal view returns (uint256) {\n    return miscData.decodeUint(MAX_REDEEM_RATIO_OFFSET, 30);\n  }\n\n  /// @dev Internal function to update maximum redeem ratio per tick.\n  /// @param ratio The ratio to update, multiplied by 1e9.\n  function _updateMaxRedeemRatioPerTick(uint256 ratio) internal {\n    _checkValueTooLarge(ratio, FEE_PRECISION);\n\n    miscData = miscData.insertUint(ratio, MAX_REDEEM_RATIO_OFFSET, 30);\n\n    emit UpdateMaxRedeemRatioPerTick(ratio);\n  }\n\n  /***********************************************\n   * Internal Functions For `rebalanceRatioData` *\n   ***********************************************/\n\n  /// @dev Internal function to get `debtRatio` and `bonusRatio` for rebalance.\n  /// @return debtRatio The minimum debt ratio to start rebalance, multiplied by 1e18.\n  /// @return bonusRatio The bonus ratio during rebalance, multiplied by 1e9.\n  function _getRebalanceRatios() internal view returns (uint256 debtRatio, uint256 bonusRatio) {\n    bytes32 data = rebalanceRatioData;\n    debtRatio = data.decodeUint(REBALANCE_DEBT_RATIO_OFFSET, 60);\n    bonusRatio = data.decodeUint(REBALANCE_BONUS_RATIO_OFFSET, 30);\n  }\n\n  /// @dev Internal function to update ratio for rebalance.\n  /// @param debtRatio The minimum debt ratio to start rebalance, multiplied by 1e18.\n  /// @param bonusRatio The bonus ratio during rebalance, multiplied by 1e9.\n  function _updateRebalanceRatios(uint256 debtRatio, uint256 bonusRatio) internal {\n    _checkValueTooLarge(debtRatio, PRECISION);\n    _checkValueTooLarge(bonusRatio, FEE_PRECISION);\n\n    bytes32 data = rebalanceRatioData;\n    data = data.insertUint(debtRatio, REBALANCE_DEBT_RATIO_OFFSET, 60);\n    rebalanceRatioData = data.insertUint(bonusRatio, REBALANCE_BONUS_RATIO_OFFSET, 30);\n\n    emit UpdateRebalanceRatios(debtRatio, bonusRatio);\n  }\n\n  /// @dev Internal function to get `debtRatio` and `bonusRatio` for liquidate.\n  /// @return debtRatio The minimum debt ratio to start liquidate, multiplied by 1e18.\n  /// @return bonusRatio The bonus ratio during liquidate, multiplied by 1e9.\n  function _getLiquidateRatios() internal view returns (uint256 debtRatio, uint256 bonusRatio) {\n    bytes32 data = rebalanceRatioData;\n    debtRatio = data.decodeUint(LIQUIDATE_DEBT_RATIO_OFFSET, 60);\n    bonusRatio = data.decodeUint(LIQUIDATE_BONUS_RATIO_OFFSET, 30);\n  }\n\n  /// @dev Internal function to update ratio for liquidate.\n  /// @param debtRatio The minimum debt ratio to start liquidate, multiplied by 1e18.\n  /// @param bonusRatio The bonus ratio during liquidate, multiplied by 1e9.\n  function _updateLiquidateRatios(uint256 debtRatio, uint256 bonusRatio) internal {\n    _checkValueTooLarge(debtRatio, PRECISION);\n    _checkValueTooLarge(bonusRatio, FEE_PRECISION);\n\n    bytes32 data = rebalanceRatioData;\n    data = data.insertUint(debtRatio, LIQUIDATE_DEBT_RATIO_OFFSET, 60);\n    rebalanceRatioData = data.insertUint(bonusRatio, LIQUIDATE_BONUS_RATIO_OFFSET, 30);\n\n    emit UpdateLiquidateRatios(debtRatio, bonusRatio);\n  }\n\n  /**************************************\n   * Internal Functions For `indexData` *\n   **************************************/\n\n  /// @dev Internal function to get debt and collateral index.\n  /// @return debtIndex The index for debt shares.\n  /// @return collIndex The index for collateral shares.\n  function _getDebtAndCollateralIndex() internal view returns (uint256 debtIndex, uint256 collIndex) {\n    bytes32 data = indexData;\n    debtIndex = data.decodeUint(DEBT_INDEX_OFFSET, 128);\n    collIndex = data.decodeUint(COLLATERAL_INDEX_OFFSET, 128);\n  }\n\n  /// @dev Internal function to update debt index.\n  /// @param index The debt index to update.\n  function _updateDebtIndex(uint256 index) internal {\n    indexData = indexData.insertUint(index, DEBT_INDEX_OFFSET, 128);\n\n    emit DebtIndexSnapshot(index);\n  }\n\n  /// @dev Internal function to update collateral index.\n  /// @param index The collateral index to update.\n  function _updateCollateralIndex(uint256 index) internal {\n    indexData = indexData.insertUint(index, COLLATERAL_INDEX_OFFSET, 128);\n\n    emit CollateralIndexSnapshot(index);\n  }\n\n  /**************************************\n   * Internal Functions For `sharesData` *\n   **************************************/\n\n  /// @dev Internal function to get debt and collateral shares.\n  /// @return debtShares The total number of debt shares.\n  /// @return collShares The total number of collateral shares.\n  function _getDebtAndCollateralShares() internal view returns (uint256 debtShares, uint256 collShares) {\n    bytes32 data = sharesData;\n    debtShares = data.decodeUint(DEBT_SHARES_OFFSET, 128);\n    collShares = data.decodeUint(COLLATERAL_SHARES_OFFSET, 128);\n  }\n\n  /// @dev Internal function to update debt and collateral shares.\n  /// @param debtShares The debt shares to update.\n  /// @param collShares The collateral shares to update.\n  function _updateDebtAndCollateralShares(uint256 debtShares, uint256 collShares) internal {\n    bytes32 data = sharesData;\n    data = data.insertUint(debtShares, DEBT_SHARES_OFFSET, 128);\n    sharesData = data.insertUint(collShares, COLLATERAL_SHARES_OFFSET, 128);\n  }\n\n  /// @dev Internal function to update debt shares.\n  /// @param shares The debt shares to update.\n  function _updateDebtShares(uint256 shares) internal {\n    sharesData = sharesData.insertUint(shares, DEBT_SHARES_OFFSET, 128);\n  }\n\n  /// @dev Internal function to update collateral shares.\n  /// @param shares The collateral shares to update.\n  function _updateCollateralShares(uint256 shares) internal {\n    sharesData = sharesData.insertUint(shares, COLLATERAL_SHARES_OFFSET, 128);\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   */\n  uint256[40] private __gap;\n}\n"},"contracts/core/pool/PositionLogic.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IPool } from \"../../interfaces/IPool.sol\";\nimport { IPriceOracle } from \"../../price-oracle/interfaces/IPriceOracle.sol\";\n\nimport { WordCodec } from \"../../common/codec/WordCodec.sol\";\nimport { Math } from \"../../libraries/Math.sol\";\nimport { TickLogic } from \"./TickLogic.sol\";\n\nabstract contract PositionLogic is TickLogic {\n  using WordCodec for bytes32;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  function __PositionLogic_init() internal onlyInitializing {\n    _updateNextPositionId(1);\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc IPool\n  function getPosition(uint256 tokenId) public view returns (uint256 rawColls, uint256 rawDebts) {\n    // compute actual shares\n    PositionInfo memory position = positionData[tokenId];\n    rawColls = position.colls;\n    rawDebts = position.debts;\n    if (position.nodeId > 0) {\n      (, uint256 collRatio, uint256 debtRatio) = _getRootNode(position.nodeId);\n      rawColls = (rawColls * collRatio) >> 60;\n      rawDebts = (rawDebts * debtRatio) >> 60;\n    }\n\n    // convert shares to actual amount\n    (uint256 debtIndex, uint256 collIndex) = _getDebtAndCollateralIndex();\n    rawColls = _convertToRawColl(rawColls, collIndex, Math.Rounding.Down);\n    rawDebts = _convertToRawDebt(rawDebts, debtIndex, Math.Rounding.Down);\n  }\n\n  /// @inheritdoc IPool\n  function getPositionDebtRatio(uint256 tokenId) external view returns (uint256 debtRatio) {\n    (uint256 rawColls, uint256 rawDebts) = getPosition(tokenId);\n    // price precision and ratio precision are both 1e18, use anchor price here\n    (uint256 price, , ) = IPriceOracle(priceOracle).getPrice();\n    if (rawColls == 0) return 0;\n    return (rawDebts * PRECISION * PRECISION) / (price * rawColls);\n  }\n\n  /// @inheritdoc IPool\n  function getTotalRawCollaterals() external view returns (uint256) {\n    (, uint256 totalColls) = _getDebtAndCollateralShares();\n    (, uint256 collIndex) = _getDebtAndCollateralIndex();\n    return _convertToRawColl(totalColls, collIndex, Math.Rounding.Down);\n  }\n\n  /// @inheritdoc IPool\n  function getTotalRawDebts() external view returns (uint256) {\n    (uint256 totalDebts, ) = _getDebtAndCollateralShares();\n    (uint256 debtIndex, ) = _getDebtAndCollateralIndex();\n    return _convertToRawDebt(totalDebts, debtIndex, Math.Rounding.Down);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to mint a new position.\n  /// @param owner The address of position owner.\n  /// @return positionId The id of the position.\n  function _mintPosition(address owner) internal returns (uint32 positionId) {\n    unchecked {\n      positionId = _getNextPositionId();\n      _updateNextPositionId(positionId + 1);\n    }\n\n    positionMetadata[positionId] = bytes32(0).insertUint(block.timestamp, 0, 40);\n    _mint(owner, positionId);\n  }\n\n  /// @dev Internal function to get and update position.\n  /// @param tokenId The id of the position.\n  /// @return position The position struct.\n  function _getAndUpdatePosition(uint256 tokenId) internal returns (PositionInfo memory position) {\n    position = positionData[tokenId];\n    if (position.nodeId > 0) {\n      (uint256 root, uint256 collRatio, uint256 debtRatio) = _getRootNodeAndCompress(position.nodeId);\n      position.colls = uint96((position.colls * collRatio) >> 60);\n      position.debts = uint96((position.debts * debtRatio) >> 60);\n      position.nodeId = uint32(root);\n      positionData[tokenId] = position;\n    }\n  }\n\n  /// @dev Internal function to convert raw collateral amounts to collateral shares.\n  function _convertToCollShares(\n    uint256 raw,\n    uint256 index,\n    Math.Rounding rounding\n  ) internal pure returns (uint256 shares) {\n    shares = Math.mulDiv(raw, index, E96, rounding);\n  }\n\n  /// @dev Internal function to convert raw debt amounts to debt shares.\n  function _convertToDebtShares(\n    uint256 raw,\n    uint256 index,\n    Math.Rounding rounding\n  ) internal pure returns (uint256 shares) {\n    shares = Math.mulDiv(raw, E96, index, rounding);\n  }\n\n  /// @dev Internal function to convert raw collateral shares to collateral amounts.\n  function _convertToRawColl(\n    uint256 shares,\n    uint256 index,\n    Math.Rounding rounding\n  ) internal pure returns (uint256 raw) {\n    raw = Math.mulDiv(shares, E96, index, rounding);\n  }\n\n  /// @dev Internal function to convert raw debt shares to debt amounts.\n  function _convertToRawDebt(\n    uint256 shares,\n    uint256 index,\n    Math.Rounding rounding\n  ) internal pure returns (uint256 raw) {\n    raw = Math.mulDiv(shares, index, E96, rounding);\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   */\n  uint256[50] private __gap;\n}\n"},"contracts/core/pool/TickLogic.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { WordCodec } from \"../../common/codec/WordCodec.sol\";\nimport { TickBitmap } from \"../../libraries/TickBitmap.sol\";\nimport { TickMath } from \"../../libraries/TickMath.sol\";\nimport { PoolStorage } from \"./PoolStorage.sol\";\n\nabstract contract TickLogic is PoolStorage {\n  using TickBitmap for mapping(int8 => uint256);\n  using WordCodec for bytes32;\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev Below are offsets of each variables in `TickTreeNode.metadata`.\n  uint256 private constant PARENT_OFFSET = 0;\n  uint256 private constant TICK_OFFSET = 48;\n  uint256 private constant COLL_RATIO_OFFSET = 64;\n  uint256 private constant DEBT_RATIO_OFFSET = 128;\n\n  /// @dev Below are offsets of each variables in `TickTreeNode.value`.\n  uint256 internal constant COLL_SHARE_OFFSET = 0;\n  uint256 internal constant DEBT_SHARE_OFFSET = 128;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  function __TickLogic_init() internal onlyInitializing {\n    _updateNextTreeNodeId(1);\n    _updateTopTick(type(int16).min);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to get the root of the given tree node.\n  /// @param node The id of the given tree node.\n  /// @return root The root node id.\n  /// @return collRatio The actual collateral ratio of the given node, multiplied by 2^60.\n  /// @return debtRatio The actual debt ratio of the given node, multiplied by 2^60.\n  function _getRootNode(uint256 node) internal view returns (uint256 root, uint256 collRatio, uint256 debtRatio) {\n    collRatio = E60;\n    debtRatio = E60;\n    while (true) {\n      bytes32 metadata = tickTreeData[node].metadata;\n      uint256 parent = metadata.decodeUint(PARENT_OFFSET, 48);\n      collRatio = (collRatio * metadata.decodeUint(COLL_RATIO_OFFSET, 64)) >> 60;\n      debtRatio = (debtRatio * metadata.decodeUint(DEBT_RATIO_OFFSET, 64)) >> 60;\n      if (parent == 0) break;\n      node = parent;\n    }\n    root = node;\n  }\n\n  /// @dev Internal function to get the root of the given tree node and compress path.\n  /// @param node The id of the given tree node.\n  /// @return root The root node id.\n  /// @return collRatio The actual collateral ratio of the given node, multiplied by 2^60.\n  /// @return debtRatio The actual debt ratio of the given node, multiplied by 2^60.\n  function _getRootNodeAndCompress(uint256 node) internal returns (uint256 root, uint256 collRatio, uint256 debtRatio) {\n    // @note We can change it to non-recursive version to avoid stack overflow. Normally, the depth should be `log(n)`,\n    // where `n` is the total number of tree nodes. So we don't need to worry much about this.\n    bytes32 metadata = tickTreeData[node].metadata;\n    uint256 parent = metadata.decodeUint(PARENT_OFFSET, 48);\n    collRatio = metadata.decodeUint(COLL_RATIO_OFFSET, 64);\n    debtRatio = metadata.decodeUint(DEBT_RATIO_OFFSET, 64);\n    if (parent == 0) {\n      root = node;\n    } else {\n      uint256 collRatioCompressed;\n      uint256 debtRatioCompressed;\n      (root, collRatioCompressed, debtRatioCompressed) = _getRootNodeAndCompress(parent);\n      collRatio = (collRatio * collRatioCompressed) >> 60;\n      debtRatio = (debtRatio * debtRatioCompressed) >> 60;\n      metadata = metadata.insertUint(root, PARENT_OFFSET, 48);\n      metadata = metadata.insertUint(collRatio, COLL_RATIO_OFFSET, 64);\n      metadata = metadata.insertUint(debtRatio, DEBT_RATIO_OFFSET, 64);\n      tickTreeData[node].metadata = metadata;\n    }\n  }\n\n  /// @dev Internal function to create a new tree node.\n  /// @param tick The tick where this tree node belongs to.\n  /// @return node The created tree node id.\n  function _newTickTreeNode(int16 tick) internal returns (uint48 node) {\n    unchecked {\n      node = _getNextTreeNodeId();\n      _updateNextTreeNodeId(node + 1);\n    }\n    tickData[tick] = node;\n\n    bytes32 metadata = bytes32(0);\n    metadata = metadata.insertInt(tick, TICK_OFFSET, 16); // set tick\n    metadata = metadata.insertUint(E60, COLL_RATIO_OFFSET, 64); // set coll ratio\n    metadata = metadata.insertUint(E60, DEBT_RATIO_OFFSET, 64); // set debt ratio\n    tickTreeData[node].metadata = metadata;\n  }\n\n  /// @dev Internal function to find first tick such that `TickMath.getRatioAtTick(tick) >= debts/colls`.\n  /// @param colls The collateral shares.\n  /// @param debts The debt shares.\n  /// @return tick The value of found first tick.\n  function _getTick(uint256 colls, uint256 debts) internal pure returns (int256 tick) {\n    uint256 ratio = (debts * TickMath.ZERO_TICK_SCALED_RATIO) / colls;\n    uint256 ratioAtTick;\n    (tick, ratioAtTick) = TickMath.getTickAtRatio(ratio);\n    if (ratio != ratioAtTick) {\n      tick++;\n      ratio = (ratioAtTick * 10015) / 10000;\n    }\n  }\n\n  /// @dev Internal function to retrieve or create a tree node.\n  /// @param tick The tick where this tree node belongs to.\n  /// @return node The tree node id.\n  function _getOrCreateTickNode(int256 tick) internal returns (uint48 node) {\n    node = tickData[tick];\n    if (node == 0) {\n      node = _newTickTreeNode(int16(tick));\n    }\n  }\n\n  /// @dev Internal function to add position collaterals and debts to some tick.\n  /// @param colls The collateral shares.\n  /// @param debts The debt shares.\n  /// @param checkDebts Whether we should check the value of `debts`.\n  /// @return tick The tick where this position belongs to.\n  /// @return node The corresponding tree node id for this tick.\n  function _addPositionToTick(\n    uint256 colls,\n    uint256 debts,\n    bool checkDebts\n  ) internal returns (int256 tick, uint48 node) {\n    if (debts > 0) {\n      if (checkDebts && int256(debts) < MIN_DEBT) {\n        revert ErrorDebtTooSmall();\n      }\n\n      tick = _getTick(colls, debts);\n      node = _getOrCreateTickNode(tick);\n      bytes32 value = tickTreeData[node].value;\n      uint256 newColls = value.decodeUint(COLL_SHARE_OFFSET, 128) + colls;\n      uint256 newDebts = value.decodeUint(DEBT_SHARE_OFFSET, 128) + debts;\n      value = value.insertUint(newColls, COLL_SHARE_OFFSET, 128);\n      value = value.insertUint(newDebts, DEBT_SHARE_OFFSET, 128);\n      tickTreeData[node].value = value;\n\n      if (newDebts == debts) {\n        tickBitmap.flipTick(int16(tick));\n      }\n\n      // update top tick\n      if (tick > _getTopTick()) {\n        _updateTopTick(int16(tick));\n      }\n    }\n  }\n\n  /// @dev Internal function to remove position from tick.\n  /// @param position The position struct to remove.\n  function _removePositionFromTick(PositionInfo memory position) internal {\n    if (position.nodeId == 0) return;\n\n    bytes32 value = tickTreeData[position.nodeId].value;\n    uint256 oldDebts = value.decodeUint(DEBT_SHARE_OFFSET, 128);\n    uint256 newColls = value.decodeUint(COLL_SHARE_OFFSET, 128) - position.colls;\n    uint256 newDebts = oldDebts - position.debts;\n    value = value.insertUint(newColls, COLL_SHARE_OFFSET, 128);\n    value = value.insertUint(newDebts, DEBT_SHARE_OFFSET, 128);\n    tickTreeData[position.nodeId].value = value;\n\n    if (newDebts == 0 && oldDebts > 0) {\n      int16 tick = int16(tickTreeData[position.nodeId].metadata.decodeInt(TICK_OFFSET, 16));\n      tickBitmap.flipTick(tick);\n\n      // top tick gone, update it to new one\n      int16 topTick = _getTopTick();\n      if (topTick == tick) {\n        _resetTopTick(topTick);\n      }\n    }\n  }\n\n  /// @dev Internal function to liquidate a tick.\n  ///      The caller make sure `max(liquidatedColl, liquidatedDebt) > 0`.\n  ///\n  /// @param tick The id of tick to liquidate.\n  /// @param liquidatedColl The amount of collateral shares liquidated.\n  /// @param liquidatedDebt The amount of debt shares liquidated.\n  function _liquidateTick(int16 tick, uint256 liquidatedColl, uint256 liquidatedDebt, uint256 price) internal {\n    uint48 node = tickData[tick];\n    // create new tree node for this tick\n    _newTickTreeNode(tick);\n    // clear bitmap first, and it will be updated later if needed.\n    tickBitmap.flipTick(tick);\n\n    bytes32 value = tickTreeData[node].value;\n    bytes32 metadata = tickTreeData[node].metadata;\n    uint256 tickColl = value.decodeUint(COLL_SHARE_OFFSET, 128);\n    uint256 tickDebt = value.decodeUint(DEBT_SHARE_OFFSET, 128);\n    uint256 tickCollAfter = tickColl - liquidatedColl;\n    uint256 tickDebtAfter = tickDebt - liquidatedDebt;\n    uint256 collRatio = (tickCollAfter * E60) / tickColl;\n    uint256 debtRatio = (tickDebtAfter * E60) / tickDebt;\n\n    // update metadata\n    metadata = metadata.insertUint(collRatio, COLL_RATIO_OFFSET, 64);\n    metadata = metadata.insertUint(debtRatio, DEBT_RATIO_OFFSET, 64);\n\n    int256 newTick = type(int256).min;\n    if (tickDebtAfter > 0) {\n      // partial liquidated, move funds to another tick\n      uint48 parentNode;\n      (newTick, parentNode) = _addPositionToTick(tickCollAfter, tickDebtAfter, false);\n      metadata = metadata.insertUint(parentNode, PARENT_OFFSET, 48);\n    }\n    emit TickMovement(tick, int16(newTick), tickCollAfter, tickDebtAfter, price);\n\n    // top tick liquidated, update it to new one\n    int16 topTick = _getTopTick();\n    if (topTick == tick && newTick != int256(tick)) {\n      _resetTopTick(topTick);\n    }\n    tickTreeData[node].metadata = metadata;\n  }\n\n  /// @dev Internal function to reset top tick.\n  /// @param oldTopTick The previous value of top tick.\n  function _resetTopTick(int16 oldTopTick) internal {\n    while (oldTopTick > type(int16).min) {\n      bool hasDebt;\n      (oldTopTick, hasDebt) = tickBitmap.nextDebtPositionWithinOneWord(oldTopTick - 1);\n      if (hasDebt) break;\n    }\n    _updateTopTick(oldTopTick);\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   */\n  uint256[50] private __gap;\n}\n"},"contracts/core/PoolManager.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\n\nimport { IFxUSDRegeneracy } from \"../interfaces/IFxUSDRegeneracy.sol\";\nimport { IPool } from \"../interfaces/IPool.sol\";\nimport { IPoolManager } from \"../interfaces/IPoolManager.sol\";\nimport { IReservePool } from \"../interfaces/IReservePool.sol\";\nimport { IRewardSplitter } from \"../interfaces/IRewardSplitter.sol\";\nimport { IFxUSDBasePool } from \"../interfaces/IFxUSDBasePool.sol\";\nimport { IRateProvider } from \"../rate-provider/interfaces/IRateProvider.sol\";\n\nimport { WordCodec } from \"../common/codec/WordCodec.sol\";\nimport { AssetManagement } from \"../fund/AssetManagement.sol\";\nimport { FlashLoans } from \"./FlashLoans.sol\";\nimport { ProtocolFees } from \"./ProtocolFees.sol\";\n\ncontract PoolManager is ProtocolFees, FlashLoans, AssetManagement, IPoolManager {\n  using EnumerableSet for EnumerableSet.AddressSet;\n  using SafeERC20 for IERC20;\n  using WordCodec for bytes32;\n\n  /**********\n   * Errors *\n   **********/\n\n  error ErrorCollateralExceedCapacity();\n\n  error ErrorDebtExceedCapacity();\n\n  error ErrorPoolNotRegistered();\n\n  error ErrorInvalidPool();\n\n  error ErrorCallerNotFxUSDSave();\n\n  error ErrorRedeemExceedBalance();\n\n  error ErrorInsufficientRedeemedCollateral();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The role for emergency operations.\n  bytes32 public constant EMERGENCY_ROLE = keccak256(\"EMERGENCY_ROLE\");\n\n  /// @dev The role for harvester\n  bytes32 public constant HARVESTER_ROLE = keccak256(\"HARVESTER_ROLE\");\n\n  /// @dev The precision for token rate.\n  uint256 internal constant PRECISION = 1e18;\n\n  /// @dev The precision for token rate.\n  int256 internal constant PRECISION_I256 = 1e18;\n\n  uint256 private constant COLLATERAL_CAPACITY_OFFSET = 0;\n  uint256 private constant COLLATERAL_BALANCE_OFFSET = 85;\n  uint256 private constant RAW_COLLATERAL_BALANCE_OFFSET = 170;\n  uint256 private constant COLLATERAL_DATA_BITS = 85;\n  uint256 private constant RAW_COLLATERAL_DATA_BITS = 86;\n\n  uint256 private constant DEBT_CAPACITY_OFFSET = 0;\n  uint256 private constant DEBT_BALANCE_OFFSET = 96;\n  uint256 private constant DEBT_DATA_BITS = 96;\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @inheritdoc IPoolManager\n  address public immutable fxUSD;\n\n  /// @inheritdoc IPoolManager\n  address public immutable fxBASE;\n\n  /// @inheritdoc IPoolManager\n  address public immutable pegKeeper;\n\n  /***********\n   * Structs *\n   ***********/\n\n  /// @dev The struct for pool information.\n  /// @param collateralData The data for collateral.\n  ///   ```text\n  ///   * Field                     Bits    Index       Comments\n  ///   * collateral capacity       85      0           The maximum allowed amount of collateral tokens.\n  ///   * collateral balance        85      85          The amount of collateral tokens deposited.\n  ///   * raw collateral balance    86      170         The amount of raw collateral tokens (without token rate) managed in pool.\n  ///   ```\n  /// @param debtData The data for debt.\n  ///   ```text\n  ///   * Field             Bits    Index       Comments\n  ///   * debt capacity     96      0           The maximum allowed amount of debt tokens.\n  ///   * debt balance      96      96          The amount of debt tokens borrowed.\n  ///   * reserved          64      192         Reserved data.\n  ///   ```\n  struct PoolStruct {\n    bytes32 collateralData;\n    bytes32 debtData;\n  }\n\n  /// @dev The struct for token rate information.\n  /// @param scalar The token scalar to reach 18 decimals.\n  /// @param rateProvider The address of token rate provider.\n  struct TokenRate {\n    uint96 scalar;\n    address rateProvider;\n  }\n\n  /// @dev Memory variables for liquidate or rebalance.\n  /// @param stablePrice The USD price of stable token (with scalar).\n  /// @param scalingFactor The scaling factor for collateral token.\n  /// @param collateralToken The address of collateral token.\n  /// @param rawColls The amount of raw collateral tokens liquidated or rebalanced, including bonus.\n  /// @param bonusRawColls The amount of raw collateral tokens used as bonus.\n  /// @param rawDebts The amount of raw debt tokens liquidated or rebalanced.\n  struct LiquidateOrRebalanceMemoryVar {\n    uint256 stablePrice;\n    uint256 scalingFactor;\n    address collateralToken;\n    uint256 rawColls;\n    uint256 bonusRawColls;\n    uint256 rawDebts;\n  }\n\n  /*********************\n   * Storage Variables *\n   *********************/\n\n  /// @dev The list of registered pools.\n  EnumerableSet.AddressSet private pools;\n\n  /// @notice Mapping to pool address to pool struct.\n  mapping(address => PoolStruct) private poolInfo;\n\n  /// @notice Mapping from pool address to rewards splitter.\n  mapping(address => address) public rewardSplitter;\n\n  /// @notice Mapping from token address to token rate struct.\n  mapping(address => TokenRate) public tokenRates;\n\n  /// @notice The threshold for permissioned liquidate or rebalance.\n  uint256 public permissionedLiquidationThreshold;\n\n  /*************\n   * Modifiers *\n   *************/\n\n  modifier onlyRegisteredPool(address pool) {\n    if (!pools.contains(pool)) revert ErrorPoolNotRegistered();\n    _;\n  }\n\n  modifier onlyFxUSDSave() {\n    if (_msgSender() != fxBASE) {\n      // allow permissonless rebalance or liquidate when insufficient fxUSD/USDC in fxBASE.\n      uint256 totalYieldToken = IFxUSDBasePool(fxBASE).totalYieldToken();\n      uint256 totalStableToken = IFxUSDBasePool(fxBASE).totalStableToken();\n      uint256 price = IFxUSDBasePool(fxBASE).getStableTokenPriceWithScale();\n      if (totalYieldToken + (totalStableToken * price) / PRECISION >= permissionedLiquidationThreshold) {\n        revert ErrorCallerNotFxUSDSave();\n      }\n    }\n    _;\n  }\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _fxUSD, address _fxBASE, address _pegKeeper) {\n    fxUSD = _fxUSD;\n    fxBASE = _fxBASE;\n    pegKeeper = _pegKeeper;\n  }\n\n  function initialize(\n    address admin,\n    uint256 _expenseRatio,\n    uint256 _harvesterRatio,\n    uint256 _flashLoanFeeRatio,\n    address _treasury,\n    address _revenuePool,\n    address _reservePool\n  ) external initializer {\n    __Context_init();\n    __AccessControl_init();\n    __ERC165_init();\n\n    _grantRole(DEFAULT_ADMIN_ROLE, admin);\n\n    __ProtocolFees_init(_expenseRatio, _harvesterRatio, _flashLoanFeeRatio, _treasury, _revenuePool, _reservePool);\n    __FlashLoans_init();\n\n    // default 10000 fxUSD\n    _updateThreshold(10000 ether);\n  }\n\n  function initializeV2(address pool) external onlyRegisteredPool(pool) reinitializer(2) {\n    // fix state of pool\n    address collateralToken = IPool(pool).collateralToken();\n    uint256 scalingFactor = _getTokenScalingFactor(collateralToken);\n    uint256 rawCollaterals = IPool(pool).getTotalRawCollaterals();\n    uint256 collaterals = _scaleDown(rawCollaterals, scalingFactor);\n    bytes32 data = poolInfo[pool].collateralData;\n    data = data.insertUint(collaterals, COLLATERAL_BALANCE_OFFSET, COLLATERAL_DATA_BITS);\n    poolInfo[pool].collateralData = data.insertUint(\n      rawCollaterals,\n      RAW_COLLATERAL_BALANCE_OFFSET,\n      RAW_COLLATERAL_DATA_BITS\n    );\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the pool information.\n  /// @param pool The address of pool to query.\n  /// @return collateralCapacity The maximum allowed amount of collateral tokens.\n  /// @return collateralBalance The amount of collateral tokens deposited.\n  /// @return rawCollateral The amount of raw collateral tokens deposited.\n  /// @return debtCapacity The maximum allowed amount of debt tokens.\n  /// @return debtBalance The amount of debt tokens borrowed.\n  function getPoolInfo(\n    address pool\n  )\n    external\n    view\n    returns (\n      uint256 collateralCapacity,\n      uint256 collateralBalance,\n      uint256 rawCollateral,\n      uint256 debtCapacity,\n      uint256 debtBalance\n    )\n  {\n    bytes32 data = poolInfo[pool].collateralData;\n    collateralCapacity = data.decodeUint(COLLATERAL_CAPACITY_OFFSET, COLLATERAL_DATA_BITS);\n    collateralBalance = data.decodeUint(COLLATERAL_BALANCE_OFFSET, COLLATERAL_DATA_BITS);\n    rawCollateral = data.decodeUint(RAW_COLLATERAL_BALANCE_OFFSET, RAW_COLLATERAL_DATA_BITS);\n    data = poolInfo[pool].debtData;\n    debtCapacity = data.decodeUint(DEBT_CAPACITY_OFFSET, DEBT_DATA_BITS);\n    debtBalance = data.decodeUint(DEBT_BALANCE_OFFSET, DEBT_DATA_BITS);\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IPoolManager\n  function operate(\n    address pool,\n    uint256 positionId,\n    int256 newColl,\n    int256 newDebt\n  ) external onlyRegisteredPool(pool) nonReentrant whenNotPaused returns (uint256) {\n    address collateralToken = IPool(pool).collateralToken();\n    uint256 scalingFactor = _getTokenScalingFactor(collateralToken);\n\n    int256 newRawColl = newColl;\n    if (newRawColl != type(int256).min) {\n      newRawColl = _scaleUp(newRawColl, scalingFactor);\n    }\n\n    uint256 rawProtocolFees;\n    // the `newRawColl` is the result without `protocolFees`\n    (positionId, newRawColl, newDebt, rawProtocolFees) = IPool(pool).operate(\n      positionId,\n      newRawColl,\n      newDebt,\n      _msgSender()\n    );\n\n    newColl = _scaleDown(newRawColl, scalingFactor);\n    uint256 protocolFees = _scaleDown(rawProtocolFees, scalingFactor);\n    _changePoolDebts(pool, newDebt);\n    if (newRawColl > 0) {\n      _accumulatePoolOpenFee(pool, protocolFees);\n      _changePoolCollateral(pool, newColl, newRawColl);\n      IERC20(collateralToken).safeTransferFrom(_msgSender(), address(this), uint256(newColl) + protocolFees);\n    } else if (newRawColl < 0) {\n      _accumulatePoolCloseFee(pool, protocolFees);\n      _changePoolCollateral(pool, newColl - int256(protocolFees), newRawColl - int256(rawProtocolFees));\n      _transferOut(collateralToken, uint256(-newColl), _msgSender());\n    }\n\n    if (newDebt > 0) {\n      IFxUSDRegeneracy(fxUSD).mint(_msgSender(), uint256(newDebt));\n    } else if (newDebt < 0) {\n      IFxUSDRegeneracy(fxUSD).burn(_msgSender(), uint256(-newDebt));\n    }\n\n    emit Operate(pool, positionId, newColl, newDebt, protocolFees);\n\n    return positionId;\n  }\n\n  /// @inheritdoc IPoolManager\n  function redeem(\n    address pool,\n    uint256 debts,\n    uint256 minColls\n  ) external onlyRegisteredPool(pool) nonReentrant whenNotPaused returns (uint256 colls) {\n    if (debts > IERC20(fxUSD).balanceOf(_msgSender())) {\n      revert ErrorRedeemExceedBalance();\n    }\n\n    uint256 rawColls = IPool(pool).redeem(debts);\n\n    address collateralToken = IPool(pool).collateralToken();\n    uint256 scalingFactor = _getTokenScalingFactor(collateralToken);\n    colls = _scaleDown(rawColls, scalingFactor);\n\n    _changePoolCollateral(pool, -int256(colls), -int256(rawColls));\n    _changePoolDebts(pool, -int256(debts));\n\n    uint256 protocolFees = (colls * getRedeemFeeRatio()) / FEE_PRECISION;\n    _accumulatePoolMiscFee(pool, protocolFees);\n    colls -= protocolFees;\n    if (colls < minColls) revert ErrorInsufficientRedeemedCollateral();\n\n    _transferOut(collateralToken, colls, _msgSender());\n    IFxUSDRegeneracy(fxUSD).burn(_msgSender(), debts);\n\n    emit Redeem(pool, colls, debts, protocolFees);\n  }\n\n  /// @inheritdoc IPoolManager\n  function rebalance(\n    address pool,\n    address receiver,\n    int16 tick,\n    uint256 maxFxUSD,\n    uint256 maxStable\n  )\n    external\n    onlyRegisteredPool(pool)\n    nonReentrant\n    whenNotPaused\n    onlyFxUSDSave\n    returns (uint256 colls, uint256 fxUSDUsed, uint256 stableUsed)\n  {\n    LiquidateOrRebalanceMemoryVar memory op = _beforeRebalanceOrLiquidate(pool);\n    IPool.RebalanceResult memory result = IPool(pool).rebalance(tick, maxFxUSD + _scaleUp(maxStable, op.stablePrice));\n    op.rawColls = result.rawColls + result.bonusRawColls;\n    op.bonusRawColls = result.bonusRawColls;\n    op.rawDebts = result.rawDebts;\n    (colls, fxUSDUsed, stableUsed) = _afterRebalanceOrLiquidate(pool, maxFxUSD, op, receiver);\n\n    emit RebalanceTick(pool, tick, colls, fxUSDUsed, stableUsed);\n  }\n\n  /// @inheritdoc IPoolManager\n  function rebalance(\n    address pool,\n    address receiver,\n    uint256 maxFxUSD,\n    uint256 maxStable\n  )\n    external\n    onlyRegisteredPool(pool)\n    nonReentrant\n    whenNotPaused\n    onlyFxUSDSave\n    returns (uint256 colls, uint256 fxUSDUsed, uint256 stableUsed)\n  {\n    LiquidateOrRebalanceMemoryVar memory op = _beforeRebalanceOrLiquidate(pool);\n    IPool.RebalanceResult memory result = IPool(pool).rebalance(maxFxUSD + _scaleUp(maxStable, op.stablePrice));\n    op.rawColls = result.rawColls + result.bonusRawColls;\n    op.bonusRawColls = result.bonusRawColls;\n    op.rawDebts = result.rawDebts;\n    (colls, fxUSDUsed, stableUsed) = _afterRebalanceOrLiquidate(pool, maxFxUSD, op, receiver);\n\n    emit Rebalance(pool, colls, fxUSDUsed, stableUsed);\n  }\n\n  /// @inheritdoc IPoolManager\n  function liquidate(\n    address pool,\n    address receiver,\n    uint256 maxFxUSD,\n    uint256 maxStable\n  )\n    external\n    onlyRegisteredPool(pool)\n    nonReentrant\n    whenNotPaused\n    onlyFxUSDSave\n    returns (uint256 colls, uint256 fxUSDUsed, uint256 stableUsed)\n  {\n    LiquidateOrRebalanceMemoryVar memory op = _beforeRebalanceOrLiquidate(pool);\n    {\n      IPool.LiquidateResult memory result;\n      uint256 reservedRawColls = IReservePool(reservePool).getBalance(op.collateralToken);\n      reservedRawColls = _scaleUp(reservedRawColls, op.scalingFactor);\n      result = IPool(pool).liquidate(maxFxUSD + _scaleUp(maxStable, op.stablePrice), reservedRawColls);\n      op.rawColls = result.rawColls + result.bonusRawColls;\n      op.bonusRawColls = result.bonusRawColls;\n      op.rawDebts = result.rawDebts;\n\n      // take bonus or shortfall from reserve pool\n      uint256 bonusFromReserve = result.bonusFromReserve;\n      if (bonusFromReserve > 0) {\n        bonusFromReserve = _scaleDown(result.bonusFromReserve, op.scalingFactor);\n        IReservePool(reservePool).requestBonus(IPool(pool).collateralToken(), address(this), bonusFromReserve);\n\n        // increase pool reserve first\n        _changePoolCollateral(pool, int256(bonusFromReserve), int256(result.bonusFromReserve));\n      }\n    }\n\n    (colls, fxUSDUsed, stableUsed) = _afterRebalanceOrLiquidate(pool, maxFxUSD, op, receiver);\n\n    emit Liquidate(pool, colls, fxUSDUsed, stableUsed);\n  }\n\n  /// @inheritdoc IPoolManager\n  function harvest(\n    address pool\n  )\n    external\n    onlyRegisteredPool(pool)\n    onlyRole(HARVESTER_ROLE)\n    nonReentrant\n    returns (uint256 amountRewards, uint256 amountFunding)\n  {\n    address collateralToken = IPool(pool).collateralToken();\n    uint256 scalingFactor = _getTokenScalingFactor(collateralToken);\n\n    uint256 collateralRecorded;\n    uint256 rawCollateralRecorded;\n    {\n      bytes32 data = poolInfo[pool].collateralData;\n      collateralRecorded = data.decodeUint(COLLATERAL_BALANCE_OFFSET, COLLATERAL_DATA_BITS);\n      rawCollateralRecorded = data.decodeUint(RAW_COLLATERAL_BALANCE_OFFSET, RAW_COLLATERAL_DATA_BITS);\n    }\n    uint256 performanceFee;\n    uint256 harvestBounty;\n    uint256 pendingRewards;\n    // compute funding\n    uint256 rawCollateral = IPool(pool).getTotalRawCollaterals();\n    if (rawCollateralRecorded > rawCollateral) {\n      unchecked {\n        amountFunding = _scaleDown(rawCollateralRecorded - rawCollateral, scalingFactor);\n        _changePoolCollateral(pool, -int256(amountFunding), -int256(rawCollateralRecorded - rawCollateral));\n\n        performanceFee = (getFundingExpenseRatio() * amountFunding) / FEE_PRECISION;\n        harvestBounty = (getHarvesterRatio() * amountFunding) / FEE_PRECISION;\n        pendingRewards = amountFunding - harvestBounty - performanceFee;\n      }\n      // recorded data changed, update local cache\n      {\n        bytes32 data = poolInfo[pool].collateralData;\n        collateralRecorded = data.decodeUint(COLLATERAL_BALANCE_OFFSET, COLLATERAL_DATA_BITS);\n        rawCollateralRecorded = data.decodeUint(RAW_COLLATERAL_BALANCE_OFFSET, RAW_COLLATERAL_DATA_BITS);\n      }\n    }\n    // compute rewards\n    rawCollateral = _scaleUp(collateralRecorded, scalingFactor);\n    if (rawCollateral > rawCollateralRecorded) {\n      unchecked {\n        amountRewards = _scaleDown(rawCollateral - rawCollateralRecorded, scalingFactor);\n        _changePoolCollateral(pool, -int256(amountRewards), 0);\n\n        uint256 performanceFeeRewards = (getRewardsExpenseRatio() * amountRewards) / FEE_PRECISION;\n        uint256 harvestBountyRewards = (getHarvesterRatio() * amountRewards) / FEE_PRECISION;\n        pendingRewards += amountRewards - harvestBountyRewards - performanceFeeRewards;\n        performanceFee += performanceFeeRewards;\n        harvestBounty += harvestBountyRewards;\n      }\n    }\n\n    // transfer performance fee to treasury\n    if (performanceFee > 0) {\n      _transferOut(collateralToken, performanceFee, treasury);\n    }\n    // transfer various fees to revenue pool\n    _takeAccumulatedPoolFee(pool);\n    // transfer harvest bounty\n    if (harvestBounty > 0) {\n      _transferOut(collateralToken, harvestBounty, _msgSender());\n    }\n    // transfer rewards for fxBASE\n    if (pendingRewards > 0) {\n      address splitter = rewardSplitter[pool];\n      _transferOut(collateralToken, pendingRewards, splitter);\n      IRewardSplitter(splitter).split(collateralToken);\n    }\n\n    emit Harvest(_msgSender(), pool, amountRewards, amountFunding, performanceFee, harvestBounty);\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n  \n  /// @notice Pause or unpause the system.\n  /// @param status The pause status to update.\n  function setPause(bool status) external onlyRole(EMERGENCY_ROLE) {\n    if (status) _pause();\n    else _unpause();\n  }\n\n  /// @notice Register a new pool with reward splitter.\n  /// @param pool The address of pool.\n  /// @param splitter The address of reward splitter.\n  function registerPool(\n    address pool,\n    address splitter,\n    uint96 collateralCapacity,\n    uint96 debtCapacity\n  ) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    if (fxUSD != IPool(pool).fxUSD()) revert ErrorInvalidPool();\n\n    if (pools.add(pool)) {\n      emit RegisterPool(pool);\n\n      _updateRewardSplitter(pool, splitter);\n      _updatePoolCapacity(pool, collateralCapacity, debtCapacity);\n    }\n  }\n\n  /// @notice Update rate provider for the given token.\n  /// @param token The address of the token.\n  /// @param provider The address of corresponding rate provider.\n  function updateRateProvider(address token, address provider) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    uint256 scale = 10 ** (18 - IERC20Metadata(token).decimals());\n    tokenRates[token] = TokenRate(uint96(scale), provider);\n\n    emit UpdateTokenRate(token, scale, provider);\n  }\n\n  /// @notice Update the address of reward splitter for the given pool.\n  /// @param pool The address of the pool.\n  /// @param newSplitter The address of reward splitter.\n  function updateRewardSplitter(\n    address pool,\n    address newSplitter\n  ) external onlyRole(DEFAULT_ADMIN_ROLE) onlyRegisteredPool(pool) {\n    _updateRewardSplitter(pool, newSplitter);\n  }\n\n  /// @notice Update the pool capacity.\n  /// @param pool The address of fx pool.\n  /// @param collateralCapacity The capacity for collateral token.\n  /// @param debtCapacity The capacity for debt token.\n  function updatePoolCapacity(\n    address pool,\n    uint96 collateralCapacity,\n    uint96 debtCapacity\n  ) external onlyRole(DEFAULT_ADMIN_ROLE) onlyRegisteredPool(pool) {\n    _updatePoolCapacity(pool, collateralCapacity, debtCapacity);\n  }\n\n  /// @notice Update threshold for permissionless liquidation.\n  /// @param newThreshold The value of new threshold.\n  function updateThreshold(uint256 newThreshold) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateThreshold(newThreshold);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to update the address of reward splitter for the given pool.\n  /// @param pool The address of the pool.\n  /// @param newSplitter The address of reward splitter.\n  function _updateRewardSplitter(address pool, address newSplitter) internal {\n    address oldSplitter = rewardSplitter[pool];\n    rewardSplitter[pool] = newSplitter;\n\n    emit UpdateRewardSplitter(pool, oldSplitter, newSplitter);\n  }\n\n  /// @dev Internal function to update the pool capacity.\n  /// @param pool The address of fx pool.\n  /// @param collateralCapacity The capacity for collateral token.\n  /// @param debtCapacity The capacity for debt token.\n  function _updatePoolCapacity(address pool, uint96 collateralCapacity, uint96 debtCapacity) internal {\n    poolInfo[pool].collateralData = poolInfo[pool].collateralData.insertUint(\n      collateralCapacity,\n      COLLATERAL_CAPACITY_OFFSET,\n      COLLATERAL_DATA_BITS\n    );\n    poolInfo[pool].debtData = poolInfo[pool].debtData.insertUint(debtCapacity, DEBT_CAPACITY_OFFSET, DEBT_DATA_BITS);\n\n    emit UpdatePoolCapacity(pool, collateralCapacity, debtCapacity);\n  }\n\n  /// @dev Internal function to update threshold for permissionless liquidation.\n  /// @param newThreshold The value of new threshold.\n  function _updateThreshold(uint256 newThreshold) internal {\n    uint256 oldThreshold = permissionedLiquidationThreshold;\n    permissionedLiquidationThreshold = newThreshold;\n\n    emit UpdatePermissionedLiquidationThreshold(oldThreshold, newThreshold);\n  }\n\n  /// @dev Internal function to scaler up for `uint256`.\n  function _scaleUp(uint256 value, uint256 scale) internal pure returns (uint256) {\n    return (value * scale) / PRECISION;\n  }\n\n  /// @dev Internal function to scaler up for `int256`.\n  function _scaleUp(int256 value, uint256 scale) internal pure returns (int256) {\n    return (value * int256(scale)) / PRECISION_I256;\n  }\n\n  /// @dev Internal function to scaler down for `uint256`, rounding down.\n  function _scaleDown(uint256 value, uint256 scale) internal pure returns (uint256) {\n    return (value * PRECISION) / scale;\n  }\n\n  /// @dev Internal function to scaler down for `uint256`, rounding up.\n  function _scaleDownRoundingUp(uint256 value, uint256 scale) internal pure returns (uint256) {\n    return (value * PRECISION + scale - 1) / scale;\n  }\n\n  /// @dev Internal function to scaler down for `int256`.\n  function _scaleDown(int256 value, uint256 scale) internal pure returns (int256) {\n    return (value * PRECISION_I256) / int256(scale);\n  }\n\n  /// @dev Internal function to prepare variables before rebalance or liquidate.\n  /// @param pool The address of pool to liquidate or rebalance.\n  function _beforeRebalanceOrLiquidate(address pool) internal view returns (LiquidateOrRebalanceMemoryVar memory op) {\n    op.stablePrice = IFxUSDBasePool(fxBASE).getStableTokenPriceWithScale();\n    op.collateralToken = IPool(pool).collateralToken();\n    op.scalingFactor = _getTokenScalingFactor(op.collateralToken);\n  }\n\n  /// @dev Internal function to do actions after rebalance or liquidate.\n  /// @param pool The address of pool to liquidate or rebalance.\n  /// @param maxFxUSD The maximum amount of fxUSD can be used.\n  /// @param op The memory helper variable.\n  /// @param receiver The address collateral token receiver.\n  /// @return colls The actual amount of collateral token rebalanced or liquidated.\n  /// @return fxUSDUsed The amount of fxUSD used.\n  /// @return stableUsed The amount of stable token (a.k.a USDC) used.\n  function _afterRebalanceOrLiquidate(\n    address pool,\n    uint256 maxFxUSD,\n    LiquidateOrRebalanceMemoryVar memory op,\n    address receiver\n  ) internal returns (uint256 colls, uint256 fxUSDUsed, uint256 stableUsed) {\n    colls = _scaleDown(op.rawColls, op.scalingFactor);\n    _changePoolCollateral(pool, -int256(colls), -int256(op.rawColls));\n    _changePoolDebts(pool, -int256(op.rawDebts));\n\n    // burn fxUSD or transfer USDC\n    fxUSDUsed = op.rawDebts;\n    if (fxUSDUsed > maxFxUSD) {\n      // rounding up here\n      stableUsed = _scaleDownRoundingUp(fxUSDUsed - maxFxUSD, op.stablePrice);\n      fxUSDUsed = maxFxUSD;\n    }\n    if (fxUSDUsed > 0) {\n      IFxUSDRegeneracy(fxUSD).burn(_msgSender(), fxUSDUsed);\n    }\n    if (stableUsed > 0) {\n      IERC20(IFxUSDBasePool(fxBASE).stableToken()).safeTransferFrom(_msgSender(), fxUSD, stableUsed);\n      IFxUSDRegeneracy(fxUSD).onRebalanceWithStable(stableUsed, op.rawDebts - maxFxUSD);\n    }\n\n    // transfer collateral\n    uint256 protocolRevenue = (_scaleDown(op.bonusRawColls, op.scalingFactor) * getLiquidationExpenseRatio()) /\n      FEE_PRECISION;\n    _accumulatePoolMiscFee(pool, protocolRevenue);\n    unchecked {\n      colls -= protocolRevenue;\n    }\n    _transferOut(op.collateralToken, colls, receiver);\n  }\n\n  /// @dev Internal function to update collateral balance.\n  function _changePoolCollateral(address pool, int256 delta, int256 rawDelta) internal {\n    bytes32 data = poolInfo[pool].collateralData;\n    uint256 capacity = data.decodeUint(COLLATERAL_CAPACITY_OFFSET, COLLATERAL_DATA_BITS);\n    uint256 balance = uint256(int256(data.decodeUint(COLLATERAL_BALANCE_OFFSET, COLLATERAL_DATA_BITS)) + delta);\n    if (balance > capacity) revert ErrorCollateralExceedCapacity();\n    data = data.insertUint(balance, COLLATERAL_BALANCE_OFFSET, COLLATERAL_DATA_BITS);\n    balance = uint256(int256(data.decodeUint(RAW_COLLATERAL_BALANCE_OFFSET, RAW_COLLATERAL_DATA_BITS)) + rawDelta);\n    poolInfo[pool].collateralData = data.insertUint(balance, RAW_COLLATERAL_BALANCE_OFFSET, RAW_COLLATERAL_DATA_BITS);\n  }\n\n  /// @dev Internal function to update debt balance.\n  function _changePoolDebts(address pool, int256 delta) internal {\n    bytes32 data = poolInfo[pool].debtData;\n    uint256 capacity = data.decodeUint(DEBT_CAPACITY_OFFSET, DEBT_DATA_BITS);\n    uint256 balance = uint256(int256(data.decodeUint(DEBT_BALANCE_OFFSET, DEBT_DATA_BITS)) + delta);\n    if (balance > capacity) revert ErrorDebtExceedCapacity();\n    poolInfo[pool].debtData = data.insertUint(balance, DEBT_BALANCE_OFFSET, DEBT_DATA_BITS);\n  }\n\n  /// @dev Internal function to get token scaling factor.\n  function _getTokenScalingFactor(address token) internal view returns (uint256 value) {\n    TokenRate memory rate = tokenRates[token];\n    value = rate.scalar;\n    unchecked {\n      if (rate.rateProvider != address(0)) {\n        value *= IRateProvider(rate.rateProvider).getRate();\n      } else {\n        value *= PRECISION;\n      }\n    }\n  }\n}\n"},"contracts/core/ProtocolFees.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { AccessControlUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\nimport { PausableUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol\";\n\nimport { IPool } from \"../interfaces/IPool.sol\";\nimport { IProtocolFees } from \"../interfaces/IProtocolFees.sol\";\n\nimport { WordCodec } from \"../common/codec/WordCodec.sol\";\n\nabstract contract ProtocolFees is AccessControlUpgradeable, PausableUpgradeable, IProtocolFees {\n  using SafeERC20 for IERC20;\n  using WordCodec for bytes32;\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the given address is zero.\n  error ErrorZeroAddress();\n\n  /// @dev Thrown when the expense ratio exceeds `MAX_EXPENSE_RATIO`.\n  error ErrorExpenseRatioTooLarge();\n\n  /// @dev Thrown when the harvester ratio exceeds `MAX_HARVESTER_RATIO`.\n  error ErrorHarvesterRatioTooLarge();\n\n  /// @dev Thrown when the flash loan fee ratio exceeds `MAX_FLASH_LOAN_FEE_RATIO`.\n  error ErrorFlashLoanFeeRatioTooLarge();\n\n  /// @dev Thrown when the redeem fee ratio exceeds `MAX_REDEEM_FEE_RATIO`.\n  error ErrorRedeemFeeRatioTooLarge();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The maximum expense ratio.\n  uint256 private constant MAX_EXPENSE_RATIO = 5e8; // 50%\n\n  /// @dev The maximum harvester ratio.\n  uint256 private constant MAX_HARVESTER_RATIO = 2e8; // 20%\n\n  /// @dev The maximum flash loan fee ratio.\n  uint256 private constant MAX_FLASH_LOAN_FEE_RATIO = 1e8; // 10%\n\n  /// @dev The maximum redeem fee ratio.\n  uint256 private constant MAX_REDEEM_FEE_RATIO = 1e8; // 10%\n\n  /// @dev The offset of general expense ratio in `_miscData`.\n  uint256 private constant REWARDS_EXPENSE_RATIO_OFFSET = 0;\n\n  /// @dev The offset of harvester ratio in `_miscData`.\n  uint256 private constant HARVESTER_RATIO_OFFSET = 30;\n\n  /// @dev The offset of flash loan ratio in `_miscData`.\n  uint256 private constant FLASH_LOAN_RATIO_OFFSET = 60;\n\n  /// @dev The offset of redeem fee ratio in `_miscData`.\n  uint256 private constant REDEEM_FEE_RATIO_OFFSET = 90;\n\n  /// @dev The offset of funding expense ratio in `_miscData`.\n  uint256 private constant FUNDING_EXPENSE_RATIO_OFFSET = 120;\n\n  /// @dev The offset of liquidation expense ratio in `_miscData`.\n  uint256 private constant LIQUIDATION_EXPENSE_RATIO_OFFSET = 150;\n\n  /// @dev The precision used to compute fees.\n  uint256 internal constant FEE_PRECISION = 1e9;\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @dev `_miscData` is a storage slot that can be used to store unrelated pieces of information.\n  /// All pools store the *expense ratio*, *harvester ratio* and *withdraw fee percentage*, but\n  /// the `miscData`can be extended to store more pieces of information.\n  ///\n  /// The *expense ratio* is stored in the first most significant 32 bits, and the *harvester ratio* is\n  /// stored in the next most significant 32 bits, and the *withdraw fee percentage* is stored in the\n  /// next most significant 32 bits, leaving the remaining 160 bits free to store any other information\n  /// derived pools might need.\n  ///\n  /// - The *expense ratio* and *harvester ratio* are charged each time when harvester harvest the pool revenue.\n  /// - The *withdraw fee percentage* is charged each time when user try to withdraw assets from the pool.\n  ///\n  /// [ rewards expense ratio | harvester ratio | flash loan ratio | redeem ratio | funding expense ratio | liquidation expense ratio | available ]\n  /// [        30 bits        |     30 bits     |     30  bits     |   30  bits   |        30 bits        |          30 bits          |  76 bits  ]\n  /// [ MSB                                                                                                                                   LSB ]\n  bytes32 internal _miscData;\n\n  /// @inheritdoc IProtocolFees\n  address public treasury;\n\n  /// @inheritdoc IProtocolFees\n  /// @dev Hold fees including open.\n  address public openRevenuePool;\n\n  /// @inheritdoc IProtocolFees\n  address public reservePool;\n\n  /// @inheritdoc IProtocolFees\n  mapping(address => uint256) public accumulatedPoolOpenFees;\n\n  /// @inheritdoc IProtocolFees\n  /// @dev Hold fees including close\n  address public closeRevenuePool;\n\n  /// @inheritdoc IProtocolFees\n  mapping(address => uint256) public accumulatedPoolCloseFees;\n\n  /// @inheritdoc IProtocolFees\n  /// @dev Hold fees including redeem, liquidation and rebalance.\n  address public miscRevenuePool;\n\n  /// @inheritdoc IProtocolFees\n  mapping(address => uint256) public accumulatedPoolMiscFees;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  function __ProtocolFees_init(\n    uint256 _expenseRatio,\n    uint256 _harvesterRatio,\n    uint256 _flashLoanFeeRatio,\n    address _treasury,\n    address _revenuePool,\n    address _reservePool\n  ) internal onlyInitializing {\n    _updateFundingExpenseRatio(_expenseRatio);\n    _updateRewardsExpenseRatio(_expenseRatio);\n    _updateLiquidationExpenseRatio(_expenseRatio);\n    _updateHarvesterRatio(_harvesterRatio);\n    _updateFlashLoanFeeRatio(_flashLoanFeeRatio);\n    _updateTreasury(_treasury);\n    _updateOpenRevenuePool(_revenuePool);\n    _updateCloseRevenuePool(_revenuePool);\n    _updateMiscRevenuePool(_revenuePool);\n    _updateReservePool(_reservePool);\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc IProtocolFees\n  function getFundingExpenseRatio() public view returns (uint256) {\n    return _miscData.decodeUint(FUNDING_EXPENSE_RATIO_OFFSET, 30);\n  }\n\n  /// @inheritdoc IProtocolFees\n  function getRewardsExpenseRatio() public view returns (uint256) {\n    return _miscData.decodeUint(REWARDS_EXPENSE_RATIO_OFFSET, 30);\n  }\n\n  /// @inheritdoc IProtocolFees\n  function getLiquidationExpenseRatio() public view returns (uint256) {\n    return _miscData.decodeUint(LIQUIDATION_EXPENSE_RATIO_OFFSET, 30);\n  }\n\n  /// @inheritdoc IProtocolFees\n  function getHarvesterRatio() public view returns (uint256) {\n    return _miscData.decodeUint(HARVESTER_RATIO_OFFSET, 30);\n  }\n\n  /// @inheritdoc IProtocolFees\n  function getFundingFxSaveRatio() external view returns (uint256) {\n    return FEE_PRECISION - getFundingExpenseRatio() - getHarvesterRatio();\n  }\n\n  /// @inheritdoc IProtocolFees\n  function getRewardsFxSaveRatio() external view returns (uint256) {\n    return FEE_PRECISION - getRewardsExpenseRatio() - getHarvesterRatio();\n  }\n\n  /// @inheritdoc IProtocolFees\n  function getFlashLoanFeeRatio() public view returns (uint256) {\n    return _miscData.decodeUint(FLASH_LOAN_RATIO_OFFSET, 30);\n  }\n\n  /// @inheritdoc IProtocolFees\n  function getRedeemFeeRatio() public view returns (uint256) {\n    return _miscData.decodeUint(REDEEM_FEE_RATIO_OFFSET, 30);\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IProtocolFees\n  function withdrawAccumulatedPoolFee(address[] memory pools) external {\n    for (uint256 i = 0; i < pools.length; ++i) {\n      _takeAccumulatedPoolFee(pools[i]);\n    }\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Change address of reserve pool contract.\n  /// @param _newReservePool The new address of reserve pool contract.\n  function updateReservePool(address _newReservePool) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateReservePool(_newReservePool);\n  }\n\n  /// @notice Change address of treasury contract.\n  /// @param _newTreasury The new address of treasury contract.\n  function updateTreasury(address _newTreasury) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateTreasury(_newTreasury);\n  }\n\n  /// @notice Change address of open revenue pool contract.\n  /// @param _newPool The new address of revenue pool contract.\n  function updateOpenRevenuePool(address _newPool) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateOpenRevenuePool(_newPool);\n  }\n\n  /// @notice Change address of close revenue pool contract.\n  /// @param _newPool The new address of revenue pool contract.\n  function updateCloseRevenuePool(address _newPool) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateCloseRevenuePool(_newPool);\n  }\n\n  /// @notice Change address of misc revenue pool contract.\n  /// @param _newPool The new address of revenue pool contract.\n  function updateMiscRevenuePool(address _newPool) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateMiscRevenuePool(_newPool);\n  }\n\n  /// @notice Update the fee ratio distributed to treasury.\n  /// @param newRewardsRatio The new ratio for rewards to update, multiplied by 1e9.\n  /// @param newFundingRatio The new ratio for funding to update, multiplied by 1e9.\n  /// @param newLiquidationRatio The new ratio for liquidation/rebalance to update, multiplied by 1e9.\n  function updateExpenseRatio(\n    uint32 newRewardsRatio,\n    uint32 newFundingRatio,\n    uint32 newLiquidationRatio\n  ) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateRewardsExpenseRatio(newRewardsRatio);\n    _updateFundingExpenseRatio(newFundingRatio);\n    _updateLiquidationExpenseRatio(newLiquidationRatio);\n  }\n\n  /// @notice Update the fee ratio distributed to harvester.\n  /// @param newRatio The new ratio to update, multiplied by 1e9.\n  function updateHarvesterRatio(uint32 newRatio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateHarvesterRatio(newRatio);\n  }\n\n  /// @notice Update the flash loan fee ratio.\n  /// @param newRatio The new ratio to update, multiplied by 1e9.\n  function updateFlashLoanFeeRatio(uint32 newRatio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateFlashLoanFeeRatio(newRatio);\n  }\n\n  /// @notice Update the redeem fee ratio.\n  /// @param newRatio The new ratio to update, multiplied by 1e9.\n  function updateRedeemFeeRatio(uint32 newRatio) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateRedeemFeeRatio(newRatio);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to change address of treasury contract.\n  /// @param _newTreasury The new address of treasury contract.\n  function _updateTreasury(address _newTreasury) private {\n    if (_newTreasury == address(0)) revert ErrorZeroAddress();\n\n    address _oldTreasury = treasury;\n    treasury = _newTreasury;\n\n    emit UpdateTreasury(_oldTreasury, _newTreasury);\n  }\n\n  /// @dev Internal function to change address of revenue pool contract.\n  /// @param _newPool The new address of revenue pool contract.\n  function _updateOpenRevenuePool(address _newPool) private {\n    if (_newPool == address(0)) revert ErrorZeroAddress();\n\n    address _oldPool = openRevenuePool;\n    openRevenuePool = _newPool;\n\n    emit UpdateOpenRevenuePool(_oldPool, _newPool);\n  }\n\n  /// @dev Internal function to change address of revenue pool contract.\n  /// @param _newPool The new address of revenue pool contract.\n  function _updateCloseRevenuePool(address _newPool) private {\n    if (_newPool == address(0)) revert ErrorZeroAddress();\n\n    address _oldPool = closeRevenuePool;\n    closeRevenuePool = _newPool;\n\n    emit UpdateCloseRevenuePool(_oldPool, _newPool);\n  }\n\n  /// @dev Internal function to change address of revenue pool contract.\n  /// @param _newPool The new address of revenue pool contract.\n  function _updateMiscRevenuePool(address _newPool) private {\n    if (_newPool == address(0)) revert ErrorZeroAddress();\n\n    address _oldPool = miscRevenuePool;\n    miscRevenuePool = _newPool;\n\n    emit UpdateMiscRevenuePool(_oldPool, _newPool);\n  }\n\n  /// @dev Internal function to change the address of reserve pool contract.\n  /// @param newReservePool The new address of reserve pool contract.\n  function _updateReservePool(address newReservePool) private {\n    if (newReservePool == address(0)) revert ErrorZeroAddress();\n\n    address oldReservePool = reservePool;\n    reservePool = newReservePool;\n\n    emit UpdateReservePool(oldReservePool, newReservePool);\n  }\n\n  /// @dev Internal function to update the fee ratio distributed to treasury.\n  /// @param newRatio The new ratio to update, multiplied by 1e9.\n  function _updateRewardsExpenseRatio(uint256 newRatio) private {\n    if (uint256(newRatio) > MAX_EXPENSE_RATIO) {\n      revert ErrorExpenseRatioTooLarge();\n    }\n\n    bytes32 _data = _miscData;\n    uint256 _oldRatio = _miscData.decodeUint(REWARDS_EXPENSE_RATIO_OFFSET, 30);\n    _miscData = _data.insertUint(newRatio, REWARDS_EXPENSE_RATIO_OFFSET, 30);\n\n    emit UpdateRewardsExpenseRatio(_oldRatio, newRatio);\n  }\n\n  /// @dev Internal function to update the fee ratio distributed to treasury.\n  /// @param newRatio The new ratio to update, multiplied by 1e9.\n  function _updateLiquidationExpenseRatio(uint256 newRatio) private {\n    if (uint256(newRatio) > MAX_EXPENSE_RATIO) {\n      revert ErrorExpenseRatioTooLarge();\n    }\n\n    bytes32 _data = _miscData;\n    uint256 _oldRatio = _miscData.decodeUint(LIQUIDATION_EXPENSE_RATIO_OFFSET, 30);\n    _miscData = _data.insertUint(newRatio, LIQUIDATION_EXPENSE_RATIO_OFFSET, 30);\n\n    emit UpdateLiquidationExpenseRatio(_oldRatio, newRatio);\n  }\n\n  /// @dev Internal function to update the fee ratio distributed to treasury.\n  /// @param newRatio The new ratio to update, multiplied by 1e9.\n  function _updateFundingExpenseRatio(uint256 newRatio) private {\n    if (uint256(newRatio) > MAX_EXPENSE_RATIO) {\n      revert ErrorExpenseRatioTooLarge();\n    }\n\n    bytes32 _data = _miscData;\n    uint256 _oldRatio = _miscData.decodeUint(FUNDING_EXPENSE_RATIO_OFFSET, 30);\n    _miscData = _data.insertUint(newRatio, FUNDING_EXPENSE_RATIO_OFFSET, 30);\n\n    emit UpdateFundingExpenseRatio(_oldRatio, newRatio);\n  }\n\n  /// @dev Internal function to update the fee ratio distributed to harvester.\n  /// @param newRatio The new ratio to update, multiplied by 1e9.\n  function _updateHarvesterRatio(uint256 newRatio) private {\n    if (uint256(newRatio) > MAX_HARVESTER_RATIO) {\n      revert ErrorHarvesterRatioTooLarge();\n    }\n\n    bytes32 _data = _miscData;\n    uint256 _oldRatio = _miscData.decodeUint(HARVESTER_RATIO_OFFSET, 30);\n    _miscData = _data.insertUint(newRatio, HARVESTER_RATIO_OFFSET, 30);\n\n    emit UpdateHarvesterRatio(_oldRatio, newRatio);\n  }\n\n  /// @dev Internal function to update the flash loan fee ratio.\n  /// @param newRatio The new ratio to update, multiplied by 1e9.\n  function _updateFlashLoanFeeRatio(uint256 newRatio) private {\n    if (uint256(newRatio) > MAX_FLASH_LOAN_FEE_RATIO) {\n      revert ErrorFlashLoanFeeRatioTooLarge();\n    }\n\n    bytes32 _data = _miscData;\n    uint256 _oldRatio = _miscData.decodeUint(FLASH_LOAN_RATIO_OFFSET, 30);\n    _miscData = _data.insertUint(newRatio, FLASH_LOAN_RATIO_OFFSET, 30);\n\n    emit UpdateFlashLoanFeeRatio(_oldRatio, newRatio);\n  }\n\n  /// @dev Internal function to update the redeem fee ratio.\n  /// @param newRatio The new ratio to update, multiplied by 1e9.\n  function _updateRedeemFeeRatio(uint256 newRatio) private {\n    if (uint256(newRatio) > MAX_REDEEM_FEE_RATIO) {\n      revert ErrorRedeemFeeRatioTooLarge();\n    }\n\n    bytes32 _data = _miscData;\n    uint256 _oldRatio = _miscData.decodeUint(REDEEM_FEE_RATIO_OFFSET, 30);\n    _miscData = _data.insertUint(newRatio, REDEEM_FEE_RATIO_OFFSET, 30);\n\n    emit UpdateRedeemFeeRatio(_oldRatio, newRatio);\n  }\n\n  /// @dev Internal function to accumulate protocol fee for the given pool.\n  /// @param pool The address of pool.\n  /// @param amount The amount of protocol fee.\n  function _accumulatePoolOpenFee(address pool, uint256 amount) internal {\n    if (amount > 0) {\n      accumulatedPoolOpenFees[pool] += amount;\n    }\n  }\n\n  /// @dev Internal function to accumulate protocol fee for the given pool.\n  /// @param pool The address of pool.\n  /// @param amount The amount of protocol fee.\n  function _accumulatePoolCloseFee(address pool, uint256 amount) internal {\n    if (amount > 0) {\n      accumulatedPoolCloseFees[pool] += amount;\n    }\n  }\n\n  /// @dev Internal function to accumulate protocol fee for the given pool.\n  /// @param pool The address of pool.\n  /// @param amount The amount of protocol fee.\n  function _accumulatePoolMiscFee(address pool, uint256 amount) internal {\n    if (amount > 0) {\n      accumulatedPoolMiscFees[pool] += amount;\n    }\n  }\n\n  /// @dev Internal function to withdraw accumulated protocol fee for the given pool.\n  /// @param pool The address of pool.\n  function _takeAccumulatedPoolFee(address pool) internal returns (uint256 fees) {\n    address collateralToken = IPool(pool).collateralToken();\n    fees = accumulatedPoolOpenFees[pool];\n    if (fees > 0) {\n      IERC20(collateralToken).safeTransfer(openRevenuePool, fees);\n      accumulatedPoolOpenFees[pool] = 0;\n    }\n    fees = accumulatedPoolCloseFees[pool];\n    if (fees > 0) {\n      IERC20(collateralToken).safeTransfer(closeRevenuePool, fees);\n      accumulatedPoolCloseFees[pool] = 0;\n    }\n    fees = accumulatedPoolMiscFees[pool];\n    if (fees > 0) {\n      IERC20(collateralToken).safeTransfer(miscRevenuePool, fees);\n      accumulatedPoolMiscFees[pool] = 0;\n    }\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   */\n  uint256[41] private __gap;\n}\n"},"contracts/core/SavingFxUSD.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IERC20Permit } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { AccessControlUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\nimport { ERC20PermitUpgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol\";\nimport { ERC4626Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC4626Upgradeable.sol\";\nimport { ERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol\";\n\nimport { IMultipleRewardDistributor } from \"../common/rewards/distributor/IMultipleRewardDistributor.sol\";\nimport { IHarvesterCallback } from \"../helpers/interfaces/IHarvesterCallback.sol\";\nimport { IConvexFXNBooster } from \"../interfaces/Convex/IConvexFXNBooster.sol\";\nimport { IStakingProxyERC20 } from \"../interfaces/Convex/IStakingProxyERC20.sol\";\nimport { IFxUSDBasePool } from \"../interfaces/IFxUSDBasePool.sol\";\nimport { ISavingFxUSD } from \"../interfaces/ISavingFxUSD.sol\";\nimport { ILiquidityGauge } from \"../voting-escrow/interfaces/ILiquidityGauge.sol\";\n\nimport { WordCodec } from \"../common/codec/WordCodec.sol\";\nimport { ConcentratorBase } from \"../common/concentrator/ConcentratorBase.sol\";\n\ncontract LockedFxSaveProxy {\n  address immutable fxSAVE;\n\n  error ErrorCallerNotFxSave();\n\n  constructor() {\n    fxSAVE = msg.sender;\n  }\n\n  function execute(address target, bytes calldata data) external {\n    if (msg.sender != fxSAVE) revert ErrorCallerNotFxSave();\n\n    (bool success, ) = target.call(data);\n    // below lines will propagate inner error up\n    if (!success) {\n      // solhint-disable-next-line no-inline-assembly\n      assembly {\n        let ptr := mload(0x40)\n        let size := returndatasize()\n        returndatacopy(ptr, 0, size)\n        revert(ptr, size)\n      }\n    }\n  }\n}\n\ncontract SavingFxUSD is ERC20PermitUpgradeable, ERC4626Upgradeable, ConcentratorBase, ISavingFxUSD {\n  using SafeERC20 for IERC20;\n  using WordCodec for bytes32;\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the threshold exceeds `MAX_THRESHOLD`.\n  error ErrorThresholdTooLarge();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The role for `claimFor` function.\n  bytes32 public constant CLAIM_FOR_ROLE = keccak256(\"CLAIM_FOR_ROLE\");\n\n  /// @dev The address of Convex's f(x) Booster contract.\n  address private constant BOOSTER = 0xAffe966B27ba3E4Ebb8A0eC124C7b7019CC762f8;\n\n  /// @dev The address of FXN token.\n  address private constant FXN = 0x365AccFCa291e7D3914637ABf1F7635dB165Bb09;\n\n  /// @dev The denominator used for precision calculation.\n  uint256 private constant PRECISION = 1e18;\n\n  /// @dev The number of bits for threshold.\n  uint256 private constant THRESHOLD_BITS = 80;\n\n  /// @dev The offset of threshold in `_miscData`.\n  uint256 private constant THRESHOLD_OFFSET = 60;\n  \n  /// @dev The maximum value of threshold, 2^80-1.\n  uint256 private constant MAX_THRESHOLD = 1208925819614629174706175;\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @notice The address of `FxUSDBasePool` contract.\n  address public immutable base;\n\n  /// @notice The address of `FxUSDBasePool` gauge contract.\n  address public immutable gauge;\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @notice The address of Convex's `StakingProxyERC20` contract.\n  address public vault;\n\n  /// @notice Mapping from user address to `LockedFxSaveProxy` contract.\n  mapping(address => address) public lockedProxy;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  struct InitializationParameters {\n    string name;\n    string symbol;\n    uint256 pid;\n    uint256 threshold;\n    address treasury;\n    address harvester;\n  }\n\n  constructor(address _base, address _gauge) {\n    base = _base;\n    gauge = _gauge;\n  }\n\n  function initialize(address admin, InitializationParameters memory params) external initializer {\n    __Context_init();\n    __ERC165_init();\n    __AccessControl_init();\n\n    __ERC20_init(params.name, params.symbol);\n    __ERC20Permit_init(params.name);\n    __ERC4626_init(IERC20(base));\n\n    __ConcentratorBase_init(params.treasury, params.harvester);\n\n    _grantRole(DEFAULT_ADMIN_ROLE, admin);\n\n    vault = IConvexFXNBooster(BOOSTER).createVault(params.pid);\n    _updateThreshold(params.threshold);\n\n    IERC20(base).forceApprove(gauge, type(uint256).max);\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc ERC4626Upgradeable\n  function decimals() public view virtual override(ERC20Upgradeable, ERC4626Upgradeable) returns (uint8) {\n    return ERC4626Upgradeable.decimals();\n  }\n\n  /// @inheritdoc ERC4626Upgradeable\n  function totalAssets() public view virtual override returns (uint256) {\n    return IERC20(base).balanceOf(address(this)) + IERC20(gauge).balanceOf(vault);\n  }\n\n  /// @notice Return the threshold for batch deposit.\n  function getThreshold() public view returns (uint256) {\n    return _miscData.decodeUint(THRESHOLD_OFFSET, THRESHOLD_BITS);\n  }\n\n  /// @inheritdoc ISavingFxUSD\n  function nav() external view returns (uint256) {\n    return (IFxUSDBasePool(base).nav() * convertToAssets(PRECISION)) / PRECISION;\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc ISavingFxUSD\n  function depositGauge(uint256 assets, address receiver) external returns (uint256) {\n    uint256 maxAssets = maxDeposit(receiver);\n    if (assets > maxAssets) {\n      revert ERC4626ExceededMaxDeposit(receiver, assets, maxAssets);\n    }\n\n    uint256 shares = previewDeposit(assets);\n\n    IERC20(gauge).safeTransferFrom(_msgSender(), vault, assets);\n    _mint(receiver, shares);\n\n    emit Deposit(_msgSender(), receiver, assets, shares);\n\n    return shares;\n  }\n\n  /// @inheritdoc ISavingFxUSD\n  function requestRedeem(uint256 shares) external returns (uint256) {\n    address owner = _msgSender();\n    uint256 maxShares = maxRedeem(owner);\n    if (shares > maxShares) {\n      revert ERC4626ExceededMaxRedeem(owner, shares, maxShares);\n    }\n\n    uint256 assets = previewRedeem(shares);\n    _requestRedeem(owner, assets, shares);\n\n    return assets;\n  }\n\n  /// @inheritdoc ISavingFxUSD\n  function claim(address receiver) external {\n    _claim(_msgSender(), receiver);\n  }\n\n  /// @inheritdoc ISavingFxUSD\n  function claimFor(address owner, address receiver) external onlyRole(CLAIM_FOR_ROLE) {\n    _claim(owner, receiver);\n  }\n\n  /// @inheritdoc ISavingFxUSD\n  function harvest() external {\n    IStakingProxyERC20(vault).getReward();\n    address[] memory tokens = IMultipleRewardDistributor(gauge).getActiveRewardTokens();\n    address cachedHarvester = harvester;\n    uint256 harvesterRatio = getHarvesterRatio();\n    uint256 expenseRatio = getExpenseRatio();\n    bool hasFXN = false;\n    for (uint256 i = 0; i < tokens.length; ++i) {\n      _transferRewards(tokens[i], cachedHarvester, harvesterRatio, expenseRatio);\n      if (tokens[i] == FXN) hasFXN = true;\n    }\n    if (!hasFXN) {\n      _transferRewards(FXN, cachedHarvester, harvesterRatio, expenseRatio);\n    }\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Update the threshold for batch deposit.\n  /// @param newThreshold The address of new threshold.\n  function updateThreshold(uint256 newThreshold) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    _updateThreshold(newThreshold);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @inheritdoc ERC4626Upgradeable\n  function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal virtual override {\n    ERC4626Upgradeable._deposit(caller, receiver, assets, shares);\n\n    // batch deposit to gauge through convex vault\n    uint256 balance = IERC20(base).balanceOf(address(this));\n    if (balance >= getThreshold()) {\n      ILiquidityGauge(gauge).deposit(balance, vault);\n    }\n  }\n\n  /// @inheritdoc ERC4626Upgradeable\n  function _withdraw(\n    address caller,\n    address receiver,\n    address owner,\n    uint256 assets,\n    uint256 shares\n  ) internal virtual override {\n    if (caller != owner) {\n      _spendAllowance(owner, caller, shares);\n    }\n\n    // If _asset is ERC777, `transfer` can trigger a reentrancy AFTER the transfer happens through the\n    // `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer,\n    // calls the vault, which is assumed not malicious.\n    //\n    // Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the\n    // shares are burned and after the assets are transferred, which is a valid state.\n    _burn(owner, shares);\n\n    emit Withdraw(caller, receiver, owner, assets, shares);\n\n    // Withdraw from gauge\n    IStakingProxyERC20(vault).withdraw(assets);\n    IERC20(base).transfer(receiver, assets);\n  }\n\n  /// @inheritdoc ConcentratorBase\n  function _onHarvest(address token, uint256 amount) internal virtual override {\n    if (token == gauge) {\n      IERC20(gauge).safeTransfer(vault, amount);\n      return;\n    } else if (token != base) {\n      IERC20(token).forceApprove(base, amount);\n      IFxUSDBasePool(base).deposit(address(this), token, amount, 0);\n    }\n    amount = IERC20(base).balanceOf(address(this));\n    ILiquidityGauge(gauge).deposit(amount, vault);\n  }\n\n  /// @dev Internal function to update the threshold for batch deposit.\n  /// @param newThreshold The address of new threshold.\n  function _updateThreshold(uint256 newThreshold) internal {\n    if (newThreshold > MAX_THRESHOLD) revert ErrorThresholdTooLarge();\n\n    bytes32 _data = _miscData;\n    uint256 oldThreshold = _miscData.decodeUint(THRESHOLD_OFFSET, THRESHOLD_BITS);\n    _miscData = _data.insertUint(newThreshold, THRESHOLD_OFFSET, THRESHOLD_BITS);\n\n    emit UpdateThreshold(oldThreshold, newThreshold);\n  }\n\n  /// @dev Internal function to transfer rewards to harvester.\n  /// @param token The address of rewards.\n  /// @param receiver The address of harvester.\n  function _transferRewards(address token, address receiver, uint256 harvesterRatio, uint256 expenseRatio) internal {\n    if (token == base) return;\n    uint256 balance = IERC20(token).balanceOf(address(this));\n    if (balance > 0) {\n      uint256 performanceFee = (balance * expenseRatio) / FEE_PRECISION;\n      uint256 harvesterBounty = (balance * harvesterRatio) / FEE_PRECISION;\n      if (harvesterBounty > 0) {\n        IERC20(token).safeTransfer(_msgSender(), harvesterBounty);\n      }\n      if (performanceFee > 0) {\n        IERC20(token).safeTransfer(treasury, performanceFee);\n      }\n      IERC20(token).safeTransfer(receiver, balance - performanceFee - harvesterBounty);\n    }\n  }\n\n  /// @dev Internal function to request redeem.\n  function _requestRedeem(address owner, uint256 assets, uint256 shares) internal {\n    // burn shares\n    _burn(owner, shares);\n\n    // Withdraw from gauge\n    IStakingProxyERC20(vault).withdraw(assets);\n\n    // create locked fxSave proxy\n    address proxy = lockedProxy[owner];\n    if (proxy == address(0)) {\n      proxy = address(new LockedFxSaveProxy{ salt: keccak256(abi.encode(owner)) }());\n      lockedProxy[owner] = proxy;\n    }\n\n    // transfer to proxy for unlocking and request unlock\n    IERC20(base).transfer(proxy, assets);\n    LockedFxSaveProxy(proxy).execute(base, abi.encodeCall(IFxUSDBasePool.requestRedeem, (assets)));\n\n    emit RequestRedeem(owner, shares, assets);\n  }\n\n  /// @dev Internal function to claim unlocked tokens.\n  function _claim(address owner, address receiver) internal {\n    address proxy = lockedProxy[owner];\n    LockedFxSaveProxy(proxy).execute(base, abi.encodeCall(IFxUSDBasePool.redeem, (receiver, type(uint256).max)));\n\n    emit Claim(owner, receiver);\n  }\n}\n"},"contracts/fund/AssetManagement.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { AccessControlUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\n\nimport { IStrategy } from \"./IStrategy.sol\";\n\nabstract contract AssetManagement is AccessControlUpgradeable {\n  using SafeERC20 for IERC20;\n\n  bytes32 public constant ASSET_MANAGER_ROLE = keccak256(\"ASSET_MANAGER_ROLE\");\n\n  struct Allocation {\n    address strategy;\n    uint96 capacity;\n  }\n\n  mapping(address => Allocation) public allocations;\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   */\n  uint256[49] private __gap;\n\n  function kill(address asset) public onlyRole(DEFAULT_ADMIN_ROLE) {\n    Allocation memory curAlloc = allocations[asset];\n    if (curAlloc.strategy != address(0)) {\n      IStrategy(curAlloc.strategy).kill();\n      curAlloc.strategy = address(0);\n      curAlloc.capacity = 0;\n      allocations[asset] = curAlloc;\n    }\n  }\n\n  function alloc(address asset, address strategy, uint96 capacity) external onlyRole(DEFAULT_ADMIN_ROLE) {\n    Allocation memory oldAlloc = allocations[asset];\n    if (oldAlloc.strategy != address(0)) kill(asset);\n    allocations[asset] = Allocation({ strategy: strategy, capacity: capacity });\n  }\n\n  function manage(address asset, uint256 amount) external onlyRole(ASSET_MANAGER_ROLE) {\n    Allocation memory curAlloc = allocations[asset];\n    uint256 managed = IStrategy(curAlloc.strategy).totalSupply();\n    if (managed + amount > curAlloc.capacity) revert();\n    IERC20(asset).safeTransfer(curAlloc.strategy, amount);\n    IStrategy(curAlloc.strategy).deposit(amount);\n  }\n\n  function _transferOut(address asset, uint256 amount, address receiver) internal {\n    uint256 balance = IERC20(asset).balanceOf(address(this));\n    if (balance >= amount) {\n      IERC20(asset).safeTransfer(receiver, amount);\n    } else {\n      IERC20(asset).safeTransfer(receiver, balance);\n      uint256 diff = amount - balance;\n      Allocation memory curAlloc = allocations[asset];\n      if (curAlloc.strategy == address(0)) revert();\n      IStrategy(curAlloc.strategy).withdraw(diff, receiver);\n    }\n  }\n}\n"},"contracts/fund/IStrategy.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IStrategy {\n  function totalSupply() external view returns (uint256);\n\n  function deposit(uint256 amount) external;\n\n  function withdraw(uint256 amount, address recipient) external;\n\n  function kill() external;\n\n  function harvest(address receiver) external;\n}\n"},"contracts/fund/strategy/AaveV3Strategy.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IAaveRewardsController } from \"../../interfaces/Aave/IAaveRewardsController.sol\";\nimport { IAaveV3Pool } from \"../../interfaces/Aave/IAaveV3Pool.sol\";\n\nimport { StrategyBase } from \"./StrategyBase.sol\";\n\ncontract AaveV3Strategy is StrategyBase {\n  using SafeERC20 for IERC20;\n\n  address public immutable POOL;\n\n  address public immutable INCENTIVE;\n\n  address public immutable ASSET;\n\n  address public immutable ATOKEN;\n\n  uint256 public principal;\n\n  constructor(\n    address _admin,\n    address _operator,\n    address _pool,\n    address _incentive,\n    address _asset,\n    address _atoken\n  ) StrategyBase(_admin, _operator) {\n    POOL = _pool;\n    INCENTIVE = _incentive;\n    ASSET = _asset;\n    ATOKEN = _atoken;\n\n    IERC20(ASSET).forceApprove(POOL, type(uint256).max);\n  }\n\n  function totalSupply() public view returns (uint256) {\n    return IERC20(ATOKEN).balanceOf(address(this));\n  }\n\n  function deposit(uint256 amount) external onlyOperator {\n    unchecked {\n      principal += amount;\n    }\n    IAaveV3Pool(POOL).supply(ASSET, amount, address(this), 0);\n  }\n\n  function withdraw(uint256 amount, address recipient) external onlyOperator {\n    uint256 cachedPrincipal = principal;\n    if (amount > cachedPrincipal) amount = cachedPrincipal;\n    unchecked {\n      principal = cachedPrincipal - amount;\n    }\n    IAaveV3Pool(POOL).withdraw(ASSET, amount, recipient);\n  }\n\n  function kill() external onlyOperator {\n    if (totalSupply() > 0) {\n      IAaveV3Pool(POOL).withdraw(ASSET, type(uint256).max, operator);\n    }\n    principal = 0;\n  }\n\n  function _harvest(address receiver) internal virtual override {\n    uint256 rewards = totalSupply() - principal;\n\n    if (rewards > 0) {\n      IAaveV3Pool(POOL).withdraw(ASSET, rewards, receiver);\n    }\n    address[] memory assets = new address[](1);\n    assets[0] = ATOKEN;\n    IAaveRewardsController(INCENTIVE).claimAllRewards(assets, receiver);\n  }\n}\n"},"contracts/fund/strategy/StrategyBase.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { AccessControl } from \"@openzeppelin/contracts/access/AccessControl.sol\";\n\nabstract contract StrategyBase is AccessControl {\n  bytes32 public constant HARVESTER_ROLE = keccak256(\"HARVESTER_ROLE\");\n\n  address public immutable operator;\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   */\n  uint256[50] private __gap;\n\n  modifier onlyOperator() {\n    if (msg.sender != operator) revert();\n    _;\n  }\n\n  constructor(address _admin, address _operator) {\n    operator = _operator;\n\n    _grantRole(DEFAULT_ADMIN_ROLE, _admin);\n  }\n\n  function harvest(address receiver) external onlyRole(HARVESTER_ROLE) {\n    _harvest(receiver);\n  }\n\n  function execute(\n    address to,\n    uint256 value,\n    bytes calldata data\n  ) external onlyOperator returns (bool success, bytes memory returnData) {\n    (success, returnData) = to.call{ value: value }(data);\n  }\n\n  function _harvest(address receiver) internal virtual;\n}\n"},"contracts/helpers/interfaces/IHarvesterCallback.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IHarvesterCallback {\n  /// @notice Hook function to handle harvested rewards.\n  /// @param token The address of token.\n  /// @param amount The amount of tokens.\n  function onHarvest(address token, uint256 amount) external;\n}\n"},"contracts/helpers/interfaces/IMultiPathConverter.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IMultiPathConverter {\n  function queryConvert(\n    uint256 _amount,\n    uint256 _encoding,\n    uint256[] calldata _routes\n  ) external returns (uint256 amountOut);\n\n  function convert(\n    address _tokenIn,\n    uint256 _amount,\n    uint256 _encoding,\n    uint256[] calldata _routes\n  ) external payable returns (uint256 amountOut);\n}\n"},"contracts/helpers/StrategyHarvester.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { IStrategy } from \"../fund/IStrategy.sol\";\n\nimport { PermissionedSwap } from \"../common/utils/PermissionedSwap.sol\";\n\ncontract StrategyHarvester is PermissionedSwap {\n  using SafeERC20 for IERC20;\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @notice The address of strategy contract.\n  address public immutable strategy;\n\n  /// @notice The address of rewards receiver.\n  address public immutable receiver;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _strategy, address _receiver) initializer {\n    __Context_init();\n    __ERC165_init();\n    __AccessControl_init();\n\n    strategy = _strategy;\n    receiver = _receiver;\n\n    _grantRole(DEFAULT_ADMIN_ROLE, _msgSender());\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Harvest pending rewards from strategy.\n  function harvest() external onlyRole(PERMISSIONED_TRADER_ROLE) {\n    IStrategy(strategy).harvest(address(this));\n  }\n\n  /// @notice Harvest base token to target token by amm trading and distribute to fxSAVE.\n  /// @param amountIn The amount of input tokens.\n  /// @param baseToken The address of base token to use.\n  /// @param targetToken The address target token.\n  /// @param params The parameters used for trading.\n  /// @return amountOut The amount of target token received.\n  function swapAndDistribute(\n    uint256 amountIn,\n    address baseToken,\n    address targetToken,\n    TradingParameter memory params\n  ) external returns (uint256 amountOut) {\n    // swap base token to target\n    amountOut = _doTrade(baseToken, targetToken, amountIn, params);\n\n    // transfer target token to receiver\n    IERC20(targetToken).safeTransfer(receiver, amountOut);\n  }\n}\n"},"contracts/interfaces/Aave/IAaveRewardsController.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IAaveRewardsController {\n  /**\n   * @dev Whitelists an address to claim the rewards on behalf of another address\n   * @param user The address of the user\n   * @param claimer The address of the claimer\n   */\n  function setClaimer(address user, address claimer) external;\n\n  /**\n   * @dev Claims reward for a user to the desired address, on all the assets of the pool, accumulating the pending rewards\n   * @param assets List of assets to check eligible distributions before claiming rewards\n   * @param amount The amount of rewards to claim\n   * @param to The address that will be receiving the rewards\n   * @param reward The address of the reward token\n   * @return The amount of rewards claimed\n   **/\n  function claimRewards(\n    address[] calldata assets,\n    uint256 amount,\n    address to,\n    address reward\n  ) external returns (uint256);\n\n  /**\n   * @dev Claims all rewards for a user to the desired address, on all the assets of the pool, accumulating the pending rewards\n   * @param assets The list of assets to check eligible distributions before claiming rewards\n   * @param to The address that will be receiving the rewards\n   * @return rewardsList List of addresses of the reward tokens\n   * @return claimedAmounts List that contains the claimed amount per reward, following same order as \"rewardList\"\n   **/\n  function claimAllRewards(\n    address[] calldata assets,\n    address to\n  ) external returns (address[] memory rewardsList, uint256[] memory claimedAmounts);\n\n  /**\n   * @dev Claims all rewards for a user on behalf, on all the assets of the pool, accumulating the pending rewards. The caller must\n   * be whitelisted via \"allowClaimOnBehalf\" function by the RewardsAdmin role manager\n   * @param assets The list of assets to check eligible distributions before claiming rewards\n   * @param user The address to check and claim rewards\n   * @param to The address that will be receiving the rewards\n   * @return rewardsList List of addresses of the reward tokens\n   * @return claimedAmounts List that contains the claimed amount per reward, following same order as \"rewardsList\"\n   **/\n  function claimAllRewardsOnBehalf(\n    address[] calldata assets,\n    address user,\n    address to\n  ) external returns (address[] memory rewardsList, uint256[] memory claimedAmounts);\n}\n"},"contracts/interfaces/Aave/IAaveV3Pool.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IAaveV3Pool {\n  struct ReserveConfigurationMap {\n    //bit 0-15: LTV\n    //bit 16-31: Liq. threshold\n    //bit 32-47: Liq. bonus\n    //bit 48-55: Decimals\n    //bit 56: reserve is active\n    //bit 57: reserve is frozen\n    //bit 58: borrowing is enabled\n    //bit 59: DEPRECATED: stable rate borrowing enabled\n    //bit 60: asset is paused\n    //bit 61: borrowing in isolation mode is enabled\n    //bit 62: siloed borrowing enabled\n    //bit 63: flashloaning enabled\n    //bit 64-79: reserve factor\n    //bit 80-115: borrow cap in whole tokens, borrowCap == 0 => no cap\n    //bit 116-151: supply cap in whole tokens, supplyCap == 0 => no cap\n    //bit 152-167: liquidation protocol fee\n    //bit 168-175: DEPRECATED: eMode category\n    //bit 176-211: unbacked mint cap in whole tokens, unbackedMintCap == 0 => minting disabled\n    //bit 212-251: debt ceiling for isolation mode with (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals\n    //bit 252: virtual accounting is enabled for the reserve\n    //bit 253-255 unused\n\n    uint256 data;\n  }\n\n  /**\n   * This exists specifically to maintain the `getReserveData()` interface, since the new, internal\n   * `ReserveData` struct includes the reserve's `virtualUnderlyingBalance`.\n   */\n  struct ReserveDataLegacy {\n    //stores the reserve configuration\n    ReserveConfigurationMap configuration;\n    //the liquidity index. Expressed in ray\n    uint128 liquidityIndex;\n    //the current supply rate. Expressed in ray\n    uint128 currentLiquidityRate;\n    //variable borrow index. Expressed in ray\n    uint128 variableBorrowIndex;\n    //the current variable borrow rate. Expressed in ray\n    uint128 currentVariableBorrowRate;\n    // DEPRECATED on v3.2.0\n    uint128 currentStableBorrowRate;\n    //timestamp of last update\n    uint40 lastUpdateTimestamp;\n    //the id of the reserve. Represents the position in the list of the active reserves\n    uint16 id;\n    //aToken address\n    address aTokenAddress;\n    // DEPRECATED on v3.2.0\n    address stableDebtTokenAddress;\n    //variableDebtToken address\n    address variableDebtTokenAddress;\n    //address of the interest rate strategy\n    address interestRateStrategyAddress;\n    //the current treasury balance, scaled\n    uint128 accruedToTreasury;\n    //the outstanding unbacked aTokens minted through the bridging feature\n    uint128 unbacked;\n    //the outstanding debt borrowed against this asset in isolation mode\n    uint128 isolationModeTotalDebt;\n  }\n\n  /**\n   * @notice Returns the state and configuration of the reserve\n   * @param asset The address of the underlying asset of the reserve\n   * @return The state and configuration data of the reserve\n   */\n  function getReserveData(address asset) external view returns (ReserveDataLegacy memory);\n\n  /**\n   * @notice Returns the normalized variable debt per unit of asset\n   * @dev WARNING: This function is intended to be used primarily by the protocol itself to get a\n   * \"dynamic\" variable index based on time, current stored index and virtual rate at the current\n   * moment (approx. a borrower would get if opening a position). This means that is always used in\n   * combination with variable debt supply/balances.\n   * If using this function externally, consider that is possible to have an increasing normalized\n   * variable debt that is not equivalent to how the variable debt index would be updated in storage\n   * (e.g. only updates with non-zero variable debt supply)\n   * @param asset The address of the underlying asset of the reserve\n   * @return The reserve normalized variable debt\n   */\n  function getReserveNormalizedVariableDebt(address asset) external view returns (uint256);\n\n  /**\n   * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.\n   * - E.g. User supplies 100 USDC and gets in return 100 aUSDC\n   * @param asset The address of the underlying asset to supply\n   * @param amount The amount to be supplied\n   * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user\n   *   wants to receive them on his own wallet, or a different address if the beneficiary of aTokens\n   *   is a different wallet\n   * @param referralCode Code used to register the integrator originating the operation, for potential rewards.\n   *   0 if the action is executed directly by the user, without any middle-man\n   */\n  function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;\n\n  /**\n   * @notice Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned\n   * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC\n   * @param asset The address of the underlying asset to withdraw\n   * @param amount The underlying amount to be withdrawn\n   *   - Send the value type(uint256).max in order to withdraw the whole aToken balance\n   * @param to The address that will receive the underlying, same as msg.sender if the user\n   *   wants to receive it on his own wallet, or a different address if the beneficiary is a\n   *   different wallet\n   * @return The final amount withdrawn\n   */\n  function withdraw(address asset, uint256 amount, address to) external returns (uint256);\n}\n"},"contracts/interfaces/Balancer/IBalancerVault.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\npragma abicoder v2;\n\ninterface IBalancerVault {\n  enum JoinKind {\n    INIT,\n    EXACT_TOKENS_IN_FOR_BPT_OUT,\n    TOKEN_IN_FOR_EXACT_BPT_OUT,\n    ALL_TOKENS_IN_FOR_EXACT_BPT_OUT\n  }\n\n  enum ExitKind {\n    EXACT_BPT_IN_FOR_ONE_TOKEN_OUT,\n    EXACT_BPT_IN_FOR_TOKENS_OUT,\n    BPT_IN_FOR_EXACT_TOKENS_OUT\n  }\n\n  enum SwapKind {\n    GIVEN_IN,\n    GIVEN_OUT\n  }\n\n  struct SingleSwap {\n    bytes32 poolId;\n    SwapKind kind;\n    address assetIn;\n    address assetOut;\n    uint256 amount;\n    bytes userData;\n  }\n\n  struct FundManagement {\n    address sender;\n    bool fromInternalBalance;\n    address payable recipient;\n    bool toInternalBalance;\n  }\n\n  function getPoolTokens(bytes32 poolId)\n    external\n    view\n    returns (\n      address[] memory tokens,\n      uint256[] memory balances,\n      uint256 lastChangeBlock\n    );\n\n  function swap(\n    SingleSwap memory singleSwap,\n    FundManagement memory funds,\n    uint256 limit,\n    uint256 deadline\n  ) external payable returns (uint256 amountCalculated);\n\n  struct JoinPoolRequest {\n    address[] assets;\n    uint256[] maxAmountsIn;\n    bytes userData;\n    bool fromInternalBalance;\n  }\n\n  function joinPool(\n    bytes32 poolId,\n    address sender,\n    address recipient,\n    JoinPoolRequest memory request\n  ) external payable;\n\n  struct ExitPoolRequest {\n    address[] assets;\n    uint256[] minAmountsOut;\n    bytes userData;\n    bool toInternalBalance;\n  }\n\n  function exitPool(\n    bytes32 poolId,\n    address sender,\n    address payable recipient,\n    ExitPoolRequest memory request\n  ) external;\n\n  /**\n   * @dev Data for each individual swap executed by `batchSwap`. The asset in and out fields are indexes into the\n   * `assets` array passed to that function, and ETH assets are converted to WETH.\n   *\n   * If `amount` is zero, the multihop mechanism is used to determine the actual amount based on the amount in/out\n   * from the previous swap, depending on the swap kind.\n   *\n   * The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be\n   * used to extend swap behavior.\n   */\n  struct BatchSwapStep {\n    bytes32 poolId;\n    uint256 assetInIndex;\n    uint256 assetOutIndex;\n    uint256 amount;\n    bytes userData;\n  }\n\n  // This function is not marked as `nonReentrant` because the underlying mechanism relies on reentrancy\n  function queryBatchSwap(\n    SwapKind kind,\n    BatchSwapStep[] memory swaps,\n    address[] memory assets,\n    FundManagement memory funds\n  ) external returns (int256[] memory);\n\n  function flashLoan(\n    address recipient,\n    address[] memory tokens,\n    uint256[] memory amounts,\n    bytes memory userData\n  ) external;\n}\n"},"contracts/interfaces/Chainlink/AggregatorV3Interface.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n  function decimals() external view returns (uint8);\n\n  function description() external view returns (string memory);\n\n  function version() external view returns (uint256);\n\n  function latestAnswer() external view returns (uint256);\n\n  function getRoundData(uint80 _roundId)\n    external\n    view\n    returns (\n      uint80 roundId,\n      int256 answer,\n      uint256 startedAt,\n      uint256 updatedAt,\n      uint80 answeredInRound\n    );\n\n  function latestRoundData()\n    external\n    view\n    returns (\n      uint80 roundId,\n      int256 answer,\n      uint256 startedAt,\n      uint256 updatedAt,\n      uint80 answeredInRound\n    );\n}\n"},"contracts/interfaces/Convex/IConvexFXNBooster.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IConvexFXNBooster {\n  function createVault(uint256 _pid) external returns (address);\n}\n"},"contracts/interfaces/Convex/IStakingProxyERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IStakingProxyERC20 {\n  //deposit into gauge\n  function deposit(uint256 _amount) external;\n\n  //deposit into gauge with manage flag\n  function deposit(uint256 _amount, bool _manage) external;\n\n  //withdraw a staked position\n  function withdraw(uint256 _amount) external;\n\n  //return earned tokens on staking contract and any tokens that are on this vault\n  function earned() external returns (address[] memory token_addresses, uint256[] memory total_earned);\n\n  /*\n    claim flow:\n        mint fxn rewards directly to vault\n        claim extra rewards directly to the owner\n        calculate fees on fxn\n        distribute fxn between owner and fee deposit\n    */\n  function getReward() external;\n\n  //get reward with claim option.\n  function getReward(bool _claim) external;\n\n  //get reward with claim option, as well as a specific token list to claim from convex extra rewards\n  function getReward(bool _claim, address[] calldata _tokenList) external;\n\n  //return any tokens in vault back to owner\n  function transferTokens(address[] calldata _tokenList) external;\n}\n"},"contracts/interfaces/Curve/ICurvePoolOracle.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n// solhint-disable func-name-mixedcase\n\ninterface ICurvePoolOracle {\n  /********************\n   * Common Functions *\n   ********************/\n\n  function ma_exp_time() external view returns (uint256);\n\n  function ma_last_time() external view returns (uint256);\n\n  /***************************\n   * Functions of Plain Pool *\n   ***************************/\n\n  function get_p() external view returns (uint256);\n\n  function last_price() external view returns (uint256);\n\n  function last_prices() external view returns (uint256);\n\n  function ema_price() external view returns (uint256);\n\n  function price_oracle() external view returns (uint256);\n\n  /************************\n   * Functions of NG Pool *\n   ************************/\n\n  function get_p(uint256 index) external view returns (uint256);\n\n  /// @notice Returns last price of the coin at index `k` w.r.t the coin\n  ///         at index 0.\n  /// @dev last_prices returns the quote by the AMM for an infinitesimally small swap\n  ///      after the last trade. It is not equivalent to the last traded price, and\n  ///      is computed by taking the partial differential of `x` w.r.t `y`. The\n  ///      derivative is calculated in `get_p` and then multiplied with price_scale\n  ///      to give last_prices.\n  /// @param index The index of the coin.\n  /// @return uint256 Last logged price of coin.\n  function last_price(uint256 index) external view returns (uint256);\n\n  function last_prices(uint256 index) external view returns (uint256);\n\n  function ema_price(uint256 index) external view returns (uint256);\n\n  function price_oracle(uint256 index) external view returns (uint256);\n}\n"},"contracts/interfaces/Curve/ICurveStableSwapNG.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface ICurveStableSwapNG {\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  function coins(uint256 index) external view returns (address);\n\n  function last_price(uint256 index) external view returns (uint256);\n\n  function ema_price(uint256 index) external view returns (uint256);\n\n  /// @notice Returns the AMM State price of token\n  /// @dev if i = 0, it will return the state price of coin[1].\n  /// @param i index of state price (0 for coin[1], 1 for coin[2], ...)\n  /// @return uint256 The state price quoted by the AMM for coin[i+1]\n  function get_p(uint256 i) external view returns (uint256);\n\n  function price_oracle(uint256 index) external view returns (uint256);\n\n  function D_oracle() external view returns (uint256);\n\n  function A() external view returns (uint256);\n\n  function A_precise() external view returns (uint256);\n\n  /// @notice Calculate the current input dx given output dy\n  /// @dev Index values can be found via the `coins` public getter method\n  /// @param i Index value for the coin to send\n  /// @param j Index value of the coin to receive\n  /// @param dy Amount of `j` being received after exchange\n  /// @return Amount of `i` predicted\n  function get_dx(\n    int128 i,\n    int128 j,\n    uint256 dy\n  ) external view returns (uint256);\n\n  /// @notice Calculate the current output dy given input dx\n  /// @dev Index values can be found via the `coins` public getter method\n  /// @param i Index value for the coin to send\n  /// @param j Index value of the coin to receive\n  /// @param dx Amount of `i` being exchanged\n  /// @return Amount of `j` predicted\n  function get_dy(\n    int128 i,\n    int128 j,\n    uint256 dx\n  ) external view returns (uint256);\n\n  /// @notice Calculate the amount received when withdrawing a single coin\n  /// @param burn_amount Amount of LP tokens to burn in the withdrawal\n  /// @param i Index value of the coin to withdraw\n  /// @return Amount of coin received\n  function calc_withdraw_one_coin(uint256 burn_amount, int128 i) external view returns (uint256);\n\n  /// @notice The current virtual price of the pool LP token\n  /// @dev Useful for calculating profits.\n  ///      The method may be vulnerable to donation-style attacks if implementation\n  ///      contains rebasing tokens. For integrators, caution is advised.\n  /// @return LP token virtual price normalized to 1e18\n  function get_virtual_price() external view returns (uint256);\n\n  /// @notice Calculate addition or reduction in token supply from a deposit or withdrawal\n  /// @param amounts Amount of each coin being deposited\n  /// @param is_deposit set True for deposits, False for withdrawals\n  /// @return Expected amount of LP tokens received\n  function calc_token_amount(uint256[] calldata amounts, bool is_deposit) external view returns (uint256);\n\n  /// @notice Get the current balance of a coin within the\n  ///         pool, less the accrued admin fees\n  /// @param i Index value for the coin to query balance of\n  /// @return Token balance\n  function balances(uint256 i) external view returns (uint256);\n\n  function get_balances() external view returns (uint256[] memory);\n\n  function stored_rates() external view returns (uint256[] memory);\n\n  /// @notice Return the fee for swapping between `i` and `j`\n  /// @param i Index value for the coin to send\n  /// @param j Index value of the coin to receive\n  /// @return Swap fee expressed as an integer with 1e10 precision\n  function dynamic_fee(int128 i, int128 j) external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Perform an exchange between two coins\n  /// @dev Index values can be found via the `coins` public getter method\n  /// @param i Index value for the coin to send\n  /// @param j Index value of the coin to receive\n  /// @param dx Amount of `i` being exchanged\n  /// @param min_dy Minimum amount of `j` to receive\n  /// @return Actual amount of `j` received\n  function exchange(\n    int128 i,\n    int128 j,\n    uint256 dx,\n    uint256 min_dy\n  ) external returns (uint256);\n\n  /// @notice Perform an exchange between two coins\n  /// @dev Index values can be found via the `coins` public getter method\n  /// @param i Index value for the coin to send\n  /// @param j Index value of the coin to receive\n  /// @param dx Amount of `i` being exchanged\n  /// @param min_dy Minimum amount of `j` to receive\n  /// @param receiver Address that receives `j`\n  /// @return Actual amount of `j` received\n  function exchange(\n    int128 i,\n    int128 j,\n    uint256 dx,\n    uint256 min_dy,\n    address receiver\n  ) external returns (uint256);\n\n  /// @notice Perform an exchange between two coins without transferring token in\n  /// @dev The contract swaps tokens based on a change in balance of coin[i]. The\n  ///      dx = ERC20(coin[i]).balanceOf(self) - self.stored_balances[i]. Users of\n  ///      this method are dex aggregators, arbitrageurs, or other users who do not\n  ///      wish to grant approvals to the contract: they would instead send tokens\n  ///      directly to the contract and call `exchange_received`.\n  ///      Note: This is disabled if pool contains rebasing tokens.\n  /// @param i Index value for the coin to send\n  /// @param j Index value of the coin to receive\n  /// @param dx Amount of `i` being exchanged\n  /// @param min_dy Minimum amount of `j` to receive\n  /// @return Actual amount of `j` received\n  function exchange_received(\n    int128 i,\n    int128 j,\n    uint256 dx,\n    uint256 min_dy\n  ) external returns (uint256);\n\n  /// @notice Perform an exchange between two coins without transferring token in\n  /// @dev The contract swaps tokens based on a change in balance of coin[i]. The\n  ///      dx = ERC20(coin[i]).balanceOf(self) - self.stored_balances[i]. Users of\n  ///      this method are dex aggregators, arbitrageurs, or other users who do not\n  ///      wish to grant approvals to the contract: they would instead send tokens\n  ///      directly to the contract and call `exchange_received`.\n  ///      Note: This is disabled if pool contains rebasing tokens.\n  /// @param i Index value for the coin to send\n  /// @param j Index value of the coin to receive\n  /// @param dx Amount of `i` being exchanged\n  /// @param min_dy Minimum amount of `j` to receive\n  /// @param receiver Address that receives `j`\n  /// @return Actual amount of `j` received\n  function exchange_received(\n    int128 i,\n    int128 j,\n    uint256 dx,\n    uint256 min_dy,\n    address receiver\n  ) external returns (uint256);\n\n  /// @notice Deposit coins into the pool\n  /// @param amounts List of amounts of coins to deposit\n  /// @param min_mint_amount Minimum amount of LP tokens to mint from the deposit\n  /// @return Amount of LP tokens received by depositing\n  function add_liquidity(uint256[] calldata amounts, uint256 min_mint_amount) external returns (uint256);\n\n  /// @notice Deposit coins into the pool\n  /// @param amounts List of amounts of coins to deposit\n  /// @param min_mint_amount Minimum amount of LP tokens to mint from the deposit\n  /// @param receiver Address that owns the minted LP tokens\n  /// @return Amount of LP tokens received by depositing\n  function add_liquidity(\n    uint256[] calldata amounts,\n    uint256 min_mint_amount,\n    address receiver\n  ) external returns (uint256);\n\n  /// @notice Withdraw a single coin from the pool\n  /// @param burn_amount Amount of LP tokens to burn in the withdrawal\n  /// @param i Index value of the coin to withdraw\n  /// @param min_received Minimum amount of coin to receive\n  /// @return Amount of coin received\n  function remove_liquidity_one_coin(\n    uint256 burn_amount,\n    int128 i,\n    uint256 min_received\n  ) external returns (uint256);\n\n  /// @notice Withdraw a single coin from the pool\n  /// @param burn_amount Amount of LP tokens to burn in the withdrawal\n  /// @param i Index value of the coin to withdraw\n  /// @param min_received Minimum amount of coin to receive\n  /// @param receiver Address that receives the withdrawn coins\n  /// @return Amount of coin received\n  function remove_liquidity_one_coin(\n    uint256 burn_amount,\n    int128 i,\n    uint256 min_received,\n    address receiver\n  ) external returns (uint256);\n\n  /// @notice Withdraw coins from the pool in an imbalanced amount\n  /// @param amounts List of amounts of underlying coins to withdraw\n  /// @param max_burn_amount Maximum amount of LP token to burn in the withdrawal\n  /// @return Actual amount of the LP token burned in the withdrawal\n  function remove_liquidity_imbalance(uint256[] calldata amounts, uint256 max_burn_amount) external returns (uint256);\n\n  /// @notice Withdraw coins from the pool in an imbalanced amount\n  /// @param amounts List of amounts of underlying coins to withdraw\n  /// @param max_burn_amount Maximum amount of LP token to burn in the withdrawal\n  /// @param receiver Address that receives the withdrawn coins\n  /// @return Actual amount of the LP token burned in the withdrawal\n  function remove_liquidity_imbalance(\n    uint256[] calldata amounts,\n    uint256 max_burn_amount,\n    address receiver\n  ) external returns (uint256);\n\n  /// @notice Withdraw coins from the pool\n  /// @dev Withdrawal amounts are based on current deposit ratios\n  /// @param burn_amount Quantity of LP tokens to burn in the withdrawal\n  /// @param min_amounts Minimum amounts of underlying coins to receive\n  /// @return List of amounts of coins that were withdrawn\n  function remove_liquidity(uint256 burn_amount, uint256[] calldata min_amounts) external returns (uint256[] memory);\n\n  /// @notice Withdraw coins from the pool\n  /// @dev Withdrawal amounts are based on current deposit ratios\n  /// @param burn_amount Quantity of LP tokens to burn in the withdrawal\n  /// @param min_amounts Minimum amounts of underlying coins to receive\n  /// @param receiver Address that receives the withdrawn coins\n  /// @return List of amounts of coins that were withdrawn\n  function remove_liquidity(\n    uint256 burn_amount,\n    uint256[] calldata min_amounts,\n    address receiver\n  ) external returns (uint256[] memory);\n\n  /// @notice Withdraw coins from the pool\n  /// @dev Withdrawal amounts are based on current deposit ratios\n  /// @param burn_amount Quantity of LP tokens to burn in the withdrawal\n  /// @param min_amounts Minimum amounts of underlying coins to receive\n  /// @param receiver Address that receives the withdrawn coins\n  /// @return List of amounts of coins that were withdrawn\n  function remove_liquidity(\n    uint256 burn_amount,\n    uint256[] calldata min_amounts,\n    address receiver,\n    bool claim_admin_fees\n  ) external returns (uint256[] memory);\n\n  /// @notice Claim admin fees. Callable by anyone.\n  function withdraw_admin_fees() external;\n}\n"},"contracts/interfaces/IAaveFundingPool.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IPool } from \"./IPool.sol\";\n\ninterface IAaveFundingPool is IPool {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when interest snapshot is taken.\n  /// @param borrowIndex The borrow index, multiplied by 1e27.\n  /// @param timestamp The timestamp when this snapshot is taken.\n  event SnapshotAaveBorrowIndex(uint256 borrowIndex, uint256 timestamp);\n\n  /// @notice Emitted when the open fee ratio related parameters are updated.\n  /// @param ratio The open ratio value, multiplied by 1e9.\n  /// @param step The open ratio step value, multiplied by 1e18.\n  event UpdateOpenRatio(uint256 ratio, uint256 step);\n\n  /// @notice Emitted when the open fee ratio is updated.\n  /// @param oldRatio The value of previous close fee ratio, multiplied by 1e9.\n  /// @param newRatio The value of current close fee ratio, multiplied by 1e9.\n  event UpdateCloseFeeRatio(uint256 oldRatio, uint256 newRatio);\n\n  /// @notice Emitted when the funding fee ratio is updated.\n  /// @param oldRatio The value of previous funding fee ratio, multiplied by 1e9.\n  /// @param newRatio The value of current funding fee ratio, multiplied by 1e9.\n  event UpdateFundingRatio(uint256 oldRatio, uint256 newRatio);\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the value of funding ratio, multiplied by 1e9.\n  function getFundingRatio() external view returns (uint256);\n}\n"},"contracts/interfaces/IFxUSDBasePool.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IFxUSDBasePool {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when the stable depeg price is updated.\n  /// @param oldPrice The value of previous depeg price, multiplied by 1e18.\n  /// @param newPrice The value of current depeg price, multiplied by 1e18.\n  event UpdateStableDepegPrice(uint256 oldPrice, uint256 newPrice);\n\n  /// @notice Emitted when the redeem cool down period is updated.\n  /// @param oldPeriod The value of previous redeem cool down period.\n  /// @param newPeriod The value of current redeem cool down period.\n  event UpdateRedeemCoolDownPeriod(uint256 oldPeriod, uint256 newPeriod);\n\n  /// @notice Emitted when the instant redeem fee ratio is updated.\n  /// @param oldRatio The value of previous instant redeem fee ratio, multiplied by 1e18.\n  /// @param newRatio The value of current instant redeem fee ratio, multiplied by 1e18.\n  event UpdateInstantRedeemFeeRatio(uint256 oldRatio, uint256 newRatio);\n\n  /// @notice Emitted when deposit tokens.\n  /// @param caller The address of caller.\n  /// @param receiver The address of pool share recipient.\n  /// @param tokenIn The address of input token.\n  /// @param amountDeposited The amount of input tokens.\n  /// @param amountSharesOut The amount of pool shares minted.\n  event Deposit(\n    address indexed caller,\n    address indexed receiver,\n    address indexed tokenIn,\n    uint256 amountDeposited,\n    uint256 amountSharesOut\n  );\n  \n  /// @notice Emitted when users request redeem.\n  /// @param caller The address of caller.\n  /// @param shares The amount of shares to redeem.\n  /// @param unlockAt The timestamp when this share can be redeemed.\n  event RequestRedeem(address indexed caller, uint256 shares, uint256 unlockAt);\n\n  /// @notice Emitted when redeem pool shares.\n  /// @param caller The address of caller.\n  /// @param receiver The address of pool share recipient.\n  /// @param amountSharesToRedeem The amount of pool shares burned.\n  /// @param amountYieldTokenOut The amount of yield tokens redeemed.\n  /// @param amountStableTokenOut The amount of stable tokens redeemed.\n  event Redeem(\n    address indexed caller,\n    address indexed receiver,\n    uint256 amountSharesToRedeem,\n    uint256 amountYieldTokenOut,\n    uint256 amountStableTokenOut\n  );\n\n  /// @notice Emitted when instant redeem pool shares.\n  /// @param caller The address of caller.\n  /// @param receiver The address of pool share recipient.\n  /// @param amountSharesToRedeem The amount of pool shares burned.\n  /// @param amountYieldTokenOut The amount of yield tokens redeemed.\n  /// @param amountStableTokenOut The amount of stable tokens redeemed.\n  event InstantRedeem(\n    address indexed caller,\n    address indexed receiver,\n    uint256 amountSharesToRedeem,\n    uint256 amountYieldTokenOut,\n    uint256 amountStableTokenOut\n  );\n\n  /// @notice Emitted when rebalance or liquidate.\n  /// @param caller The address of caller.\n  /// @param tokenIn The address of input token.\n  /// @param amountTokenIn The amount of input token used.\n  /// @param amountCollateral The amount of collateral token rebalanced.\n  /// @param amountYieldToken The amount of yield token used.\n  /// @param amountStableToken The amount of stable token used.\n  event Rebalance(\n    address indexed caller,\n    address indexed tokenIn,\n    uint256 amountTokenIn,\n    uint256 amountCollateral,\n    uint256 amountYieldToken,\n    uint256 amountStableToken\n  );\n\n  /// @notice Emitted when arbitrage in curve pool.\n  /// @param caller The address of caller.\n  /// @param tokenIn The address of input token.\n  /// @param amountIn The amount of input token used.\n  /// @param amountOut The amount of output token swapped.\n  /// @param bonusOut The amount of bonus token.\n  event Arbitrage(\n    address indexed caller,\n    address indexed tokenIn,\n    uint256 amountIn,\n    uint256 amountOut,\n    uint256 bonusOut\n  );\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice The address of yield token.\n  function yieldToken() external view returns (address);\n\n  /// @notice The address of stable token.\n  function stableToken() external view returns (address);\n\n  /// @notice The total amount of yield token managed in this contract\n  function totalYieldToken() external view returns (uint256);\n\n  /// @notice The total amount of stable token managed in this contract\n  function totalStableToken() external view returns (uint256);\n\n  /// @notice The net asset value, multiplied by 1e18.\n  function nav() external view returns (uint256);\n\n  /// @notice Return the stable token price, multiplied by 1e18.\n  function getStableTokenPrice() external view returns (uint256);\n\n  /// @notice Return the stable token price with scaling to 18 decimals, multiplied by 1e18.\n  function getStableTokenPriceWithScale() external view returns (uint256);\n\n  /// @notice Preview the result of deposit.\n  /// @param tokenIn The address of input token.\n  /// @param amount The amount of input tokens to deposit.\n  /// @return amountSharesOut The amount of pool shares should receive.\n  function previewDeposit(address tokenIn, uint256 amount) external view returns (uint256 amountSharesOut);\n\n  /// @notice Preview the result of redeem.\n  /// @param amountSharesToRedeem The amount of pool shares to redeem.\n  /// @return amountYieldOut The amount of yield token should receive.\n  /// @return amountStableOut The amount of stable token should receive.\n  function previewRedeem(\n    uint256 amountSharesToRedeem\n  ) external view returns (uint256 amountYieldOut, uint256 amountStableOut);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Deposit token.\n  /// @param receiver The address of pool shares recipient.\n  /// @param tokenIn The address of input token.\n  /// @param amountTokenToDeposit The amount of input tokens to deposit.\n  /// @param minSharesOut The minimum amount of pool shares should receive.\n  /// @return amountSharesOut The amount of pool shares received.\n  function deposit(\n    address receiver,\n    address tokenIn,\n    uint256 amountTokenToDeposit,\n    uint256 minSharesOut\n  ) external returns (uint256 amountSharesOut);\n\n  /// @notice Request redeem.\n  /// @param shares The amount of shares to request.\n  function requestRedeem(uint256 shares) external;\n\n  /// @notice Redeem pool shares.\n  /// @param receiver The address of token recipient.\n  /// @param shares The amount of pool shares to redeem.\n  /// @return amountYieldOut The amount of yield token should received.\n  /// @return amountStableOut The amount of stable token should received.\n  function redeem(address receiver, uint256 shares) external returns (uint256 amountYieldOut, uint256 amountStableOut);\n\n  /// @notice Redeem pool shares instantly with withdraw fee.\n  /// @param receiver The address of token recipient.\n  /// @param shares The amount of pool shares to redeem.\n  /// @return amountYieldOut The amount of yield token should received.\n  /// @return amountStableOut The amount of stable token should received.\n  function instantRedeem(address receiver, uint256 shares) external returns (uint256 amountYieldOut, uint256 amountStableOut);\n\n  /// @notice Rebalance all positions in the given tick.\n  /// @param pool The address of pool to rebalance.\n  /// @param tick The index of tick to rebalance.\n  /// @param tokenIn The address of token to rebalance.\n  /// @param maxAmount The maximum amount of input token to rebalance.\n  /// @param minBaseOut The minimum amount of collateral tokens should receive.\n  /// @return tokenUsed The amount of input token used to rebalance.\n  /// @return baseOut The amount of collateral tokens rebalanced.\n  function rebalance(\n    address pool,\n    int16 tick,\n    address tokenIn,\n    uint256 maxAmount,\n    uint256 minBaseOut\n  ) external returns (uint256 tokenUsed, uint256 baseOut);\n\n  /// @notice Rebalance all possible ticks.\n  /// @param pool The address of pool to rebalance.\n  /// @param tokenIn The address of token to rebalance.\n  /// @param maxAmount The maximum amount of input token to rebalance.\n  /// @param minBaseOut The minimum amount of collateral tokens should receive.\n  /// @return tokenUsed The amount of input token used to rebalance.\n  /// @return baseOut The amount of collateral tokens rebalanced.\n  function rebalance(\n    address pool,\n    address tokenIn,\n    uint256 maxAmount,\n    uint256 minBaseOut\n  ) external returns (uint256 tokenUsed, uint256 baseOut);\n\n  /// @notice Liquidate all possible ticks.\n  /// @param pool The address of pool to rebalance.\n  /// @param tokenIn The address of token to rebalance.\n  /// @param maxAmount The maximum amount of input token to rebalance.\n  /// @param minBaseOut The minimum amount of collateral tokens should receive.\n  /// @return tokenUsed The amount of input token used to rebalance.\n  /// @return baseOut The amount of collateral tokens rebalanced.\n  function liquidate(\n    address pool,\n    address tokenIn,\n    uint256 maxAmount,\n    uint256 minBaseOut\n  ) external returns (uint256 tokenUsed, uint256 baseOut);\n\n  /// @notice Arbitrage between yield token and stable token.\n  /// @param srcToken The address of source token.\n  /// @param amountIn The amount of source token to use.\n  /// @param receiver The address of bonus receiver.\n  /// @param data The hook data to `onSwap`.\n  /// @return amountOut The amount of target token swapped.\n  /// @return bonusOut The amount of bonus token.\n  function arbitrage(\n    address srcToken,\n    uint256 amountIn,\n    address receiver,\n    bytes calldata data\n  ) external returns (uint256 amountOut, uint256 bonusOut);\n}\n"},"contracts/interfaces/IFxUSDRegeneracy.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IFxUSDRegeneracy {\n  /**********\n   * Events *\n   **********/\n  \n  /// @notice Emitted when rebalance/liquidate with stable token.\n  /// @param amountStable The amount of stable token used.\n  /// @param amountFxUSD The corresponding amount of fxUSD.\n  event RebalanceWithStable(uint256 amountStable, uint256 amountFxUSD);\n  \n  /// @notice Emitted when buyback fxUSD with stable reserve.\n  /// @param amountStable the amount of stable token used.\n  /// @param amountFxUSD The amount of fxUSD bought.\n  /// @param bonusFxUSD The amount of fxUSD as bonus for caller.\n  event Buyback(uint256 amountStable, uint256 amountFxUSD, uint256 bonusFxUSD);\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice The address of `PoolManager` contract.\n  function poolManager() external view returns (address);\n\n  /// @notice The address of stable token.\n  function stableToken() external view returns (address);\n\n  /// @notice The address of `PegKeeper` contract.\n  function pegKeeper() external view returns (address);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Mint fxUSD token someone.\n  function mint(address to, uint256 amount) external;\n\n  /// @notice Burn fxUSD from someone.\n  function burn(address from, uint256 amount) external;\n\n  /// @notice Hook for rebalance/liquidate with stable token.\n  /// @param amountStableToken The amount of stable token.\n  /// @param amountFxUSD The amount of fxUSD.\n  function onRebalanceWithStable(uint256 amountStableToken, uint256 amountFxUSD) external;\n\n  /// @notice Buyback fxUSD with stable token.\n  /// @param amountIn the amount of stable token to use.\n  /// @param receiver The address of bonus receiver.\n  /// @param data The hook data to PegKeeper.\n  /// @return amountOut The amount of fxUSD swapped.\n  /// @return bonusOut The amount of bonus fxUSD.\n  function buyback(\n    uint256 amountIn,\n    address receiver,\n    bytes calldata data\n  ) external returns (uint256 amountOut, uint256 bonusOut);\n}\n"},"contracts/interfaces/IPegKeeper.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IPegKeeper {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when the converter contract is updated.\n  /// @param oldConverter The address of previous converter contract.\n  /// @param newConverter The address of current converter contract.\n  event UpdateConverter(address indexed oldConverter, address indexed newConverter);\n\n  /// @notice Emitted when the curve pool contract is updated.\n  /// @param oldPool The address of previous curve pool contract.\n  /// @param newPool The address of current curve pool contract.\n  event UpdateCurvePool(address indexed oldPool, address indexed newPool);\n\n  /// @notice Emitted when the price threshold is updated.\n  /// @param oldThreshold The value of previous price threshold\n  /// @param newThreshold The value of current price threshold\n  event UpdatePriceThreshold(uint256 oldThreshold, uint256 newThreshold);\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return whether borrow for fxUSD is allowed.\n  function isBorrowAllowed() external view returns (bool);\n\n  /// @notice Return whether funding costs is enabled.\n  function isFundingEnabled() external view returns (bool);\n  \n  /// @notice Return the price of fxUSD, multiplied by 1e18\n  function getFxUSDPrice() external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Buyback fxUSD with stable reserve in FxUSDSave.\n  /// @param amountIn the amount of stable token to use.\n  /// @param data The hook data to `onSwap`.\n  /// @return amountOut The amount of fxUSD swapped.\n  /// @return bonusOut The amount of bonus fxUSD.\n  function buyback(uint256 amountIn, bytes calldata data) external returns (uint256 amountOut, uint256 bonusOut);\n\n  /// @notice Stabilize the fxUSD price in curve pool.\n  /// @param srcToken The address of source token (fxUSD or stable token).\n  /// @param amountIn the amount of source token to use.\n  /// @param data The hook data to `onSwap`.\n  /// @return amountOut The amount of target token swapped.\n  /// @return bonusOut The amount of bonus token.\n  function stabilize(\n    address srcToken,\n    uint256 amountIn,\n    bytes calldata data\n  ) external returns (uint256 amountOut, uint256 bonusOut);\n\n  /// @notice Swap callback from `buyback` and `stabilize`.\n  /// @param srcToken The address of source token.\n  /// @param srcToken The address of target token.\n  /// @param amountIn the amount of source token to use.\n  /// @param data The callback data.\n  /// @return amountOut The amount of target token swapped.\n  function onSwap(\n    address srcToken,\n    address targetToken,\n    uint256 amountIn,\n    bytes calldata data\n  ) external returns (uint256 amountOut);\n}\n"},"contracts/interfaces/IPool.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IPool {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when price oracle is updated.\n  /// @param oldOracle The previous address of price oracle.\n  /// @param newOracle The current address of price oracle.\n  event UpdatePriceOracle(address oldOracle, address newOracle);\n\n  /// @notice Emitted when borrow status is updated.\n  /// @param status The updated borrow status.\n  event UpdateBorrowStatus(bool status);\n\n  /// @notice Emitted when redeem status is updated.\n  /// @param status The updated redeem status.\n  event UpdateRedeemStatus(bool status);\n\n  /// @notice Emitted when debt ratio range is updated.\n  /// @param minDebtRatio The current value of minimum debt ratio, multiplied by 1e18.\n  /// @param maxDebtRatio The current value of maximum debt ratio, multiplied by 1e18.\n  event UpdateDebtRatioRange(uint256 minDebtRatio, uint256 maxDebtRatio);\n\n  /// @notice Emitted when max redeem ratio per tick is updated.\n  /// @param ratio The current value of max redeem ratio per tick, multiplied by 1e9.\n  event UpdateMaxRedeemRatioPerTick(uint256 ratio);\n\n  /// @notice Emitted when the rebalance ratio is updated.\n  /// @param debtRatio The current value of rebalance debt ratio, multiplied by 1e18.\n  /// @param bonusRatio The current value of rebalance bonus ratio, multiplied by 1e9.\n  event UpdateRebalanceRatios(uint256 debtRatio, uint256 bonusRatio);\n\n  /// @notice Emitted when the liquidate ratio is updated.\n  /// @param debtRatio The current value of liquidate debt ratio, multiplied by 1e18.\n  /// @param bonusRatio The current value of liquidate bonus ratio, multiplied by 1e9.\n  event UpdateLiquidateRatios(uint256 debtRatio, uint256 bonusRatio);\n\n  /// @notice Emitted when position is updated.\n  /// @param position The index of this position.\n  /// @param tick The index of tick, this position belongs to.\n  /// @param collShares The amount of collateral shares in this position.\n  /// @param debtShares The amount of debt shares in this position.\n  /// @param price The price used for this operation.\n  event PositionSnapshot(uint256 position, int16 tick, uint256 collShares, uint256 debtShares, uint256 price);\n\n  /// @notice Emitted when tick moved due to rebalance, liquidate or redeem.\n  /// @param oldTick The index of the previous tick.\n  /// @param newTick The index of the current tick.\n  /// @param collShares The amount of collateral shares added to new tick.\n  /// @param debtShares The amount of debt shares added to new tick.\n  /// @param price The price used for this operation.\n  event TickMovement(int16 oldTick, int16 newTick, uint256 collShares, uint256 debtShares, uint256 price);\n\n  /// @notice Emitted when debt index increase.\n  event DebtIndexSnapshot(uint256 index);\n\n  /// @notice Emitted when collateral index increase.\n  event CollateralIndexSnapshot(uint256 index);\n\n  /***********\n   * Structs *\n   ***********/\n\n  /// @dev The result for liquidation.\n  /// @param rawColls The amount of collateral tokens liquidated.\n  /// @param rawDebts The amount of debt tokens liquidated.\n  /// @param bonusRawColls The amount of bonus collateral tokens given.\n  /// @param bonusFromReserve The amount of bonus collateral tokens coming from reserve pool.\n  struct LiquidateResult {\n    uint256 rawColls;\n    uint256 rawDebts;\n    uint256 bonusRawColls;\n    uint256 bonusFromReserve;\n  }\n\n  /// @dev The result for rebalance.\n  /// @param rawColls The amount of collateral tokens rebalanced.\n  /// @param rawDebts The amount of debt tokens rebalanced.\n  /// @param bonusRawColls The amount of bonus collateral tokens given.\n  struct RebalanceResult {\n    uint256 rawColls;\n    uint256 rawDebts;\n    uint256 bonusRawColls;\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice The address of fxUSD.\n  function fxUSD() external view returns (address);\n\n  /// @notice The address of `PoolManager` contract.\n  function poolManager() external view returns (address);\n\n  /// @notice The address of `PegKeeper` contract.\n  function pegKeeper() external view returns (address);\n\n  /// @notice The address of collateral token.\n  function collateralToken() external view returns (address);\n\n  /// @notice The address of price oracle.\n  function priceOracle() external view returns (address);\n\n  /// @notice Return whether borrow is paused.\n  function isBorrowPaused() external view returns (bool);\n\n  /// @notice Return whether redeem is paused.\n  function isRedeemPaused() external view returns (bool);\n\n  /// @notice Return the current top tick with debts.\n  function getTopTick() external view returns (int16);\n\n  /// @notice Return the next position id.\n  function getNextPositionId() external view returns (uint32);\n\n  /// @notice Return the next tick tree node id.\n  function getNextTreeNodeId() external view returns (uint48);\n\n  /// @notice Return the debt ratio range.\n  /// @param minDebtRatio The minimum required debt ratio, multiplied by 1e18.\n  /// @param maxDebtRatio The minimum allowed debt ratio, multiplied by 1e18.\n  function getDebtRatioRange() external view returns (uint256 minDebtRatio, uint256 maxDebtRatio);\n\n  /// @notice Return the maximum redeem percentage per tick, multiplied by 1e9.\n  function getMaxRedeemRatioPerTick() external view returns (uint256);\n\n  /// @notice Get `debtRatio` and `bonusRatio` for rebalance.\n  /// @return debtRatio The minimum debt ratio to start rebalance, multiplied by 1e18.\n  /// @return bonusRatio The bonus ratio during rebalance, multiplied by 1e9.\n  function getRebalanceRatios() external view returns (uint256 debtRatio, uint256 bonusRatio);\n\n  /// @notice Get `debtRatio` and `bonusRatio` for liquidate.\n  /// @return debtRatio The minimum debt ratio to start liquidate, multiplied by 1e18.\n  /// @return bonusRatio The bonus ratio during liquidate, multiplied by 1e9.\n  function getLiquidateRatios() external view returns (uint256 debtRatio, uint256 bonusRatio);\n\n  /// @notice Get debt and collateral index.\n  /// @return debtIndex The index for debt shares.\n  /// @return collIndex The index for collateral shares.\n  function getDebtAndCollateralIndex() external view returns (uint256 debtIndex, uint256 collIndex);\n\n  /// @notice Get debt and collateral shares.\n  /// @return debtShares The total number of debt shares.\n  /// @return collShares The total number of collateral shares.\n  function getDebtAndCollateralShares() external view returns (uint256 debtShares, uint256 collShares);\n\n  /// @notice Return the details of the given position.\n  /// @param tokenId The id of position to query.\n  /// @return rawColls The amount of collateral tokens supplied in this position.\n  /// @return rawDebts The amount of debt tokens borrowed in this position.\n  function getPosition(uint256 tokenId) external view returns (uint256 rawColls, uint256 rawDebts);\n\n  /// @notice Return the debt ratio of the given position.\n  /// @param tokenId The id of position to query.\n  /// @return debtRatio The debt ratio of this position.\n  function getPositionDebtRatio(uint256 tokenId) external view returns (uint256 debtRatio);\n\n  /// @notice The total amount of raw collateral tokens.\n  function getTotalRawCollaterals() external view returns (uint256);\n\n  /// @notice The total amount of raw debt tokens.\n  function getTotalRawDebts() external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Open a new position or operate on an old position.\n  /// @param positionId The id of the position. If `positionId=0`, it means we need to open a new position.\n  /// @param newRawColl The amount of collateral token to supply (positive value) or withdraw (negative value).\n  /// @param newRawColl The amount of debt token to borrow (positive value) or repay (negative value).\n  /// @param owner The address of position owner.\n  /// @return actualPositionId The id of this position.\n  /// @return actualRawColl The actual amount of collateral tokens supplied (positive value) or withdrawn (negative value).\n  /// @return actualRawDebt The actual amount of debt tokens borrowed (positive value) or repay (negative value).\n  function operate(\n    uint256 positionId,\n    int256 newRawColl,\n    int256 newRawDebt,\n    address owner\n  ) external returns (uint256 actualPositionId, int256 actualRawColl, int256 actualRawDebt, uint256 protocolFees);\n\n  /// @notice Redeem debt tokens to get collateral tokens.\n  /// @param rawDebts The amount of debt tokens to redeem.\n  /// @return rawColls The amount of collateral tokens to redeemed.\n  function redeem(uint256 rawDebts) external returns (uint256 rawColls);\n\n  /// @notice Rebalance all positions in the given tick.\n  /// @param tick The id of tick to rebalance.\n  /// @param maxRawDebts The maximum amount of debt tokens to rebalance.\n  /// @return result The result of rebalance.\n  function rebalance(int16 tick, uint256 maxRawDebts) external returns (RebalanceResult memory result);\n\n  /// @notice Rebalance all ticks in the decreasing order of LTV.\n  /// @param maxRawDebts The maximum amount of debt tokens to rebalance.\n  /// @return result The result of rebalance.\n  function rebalance(uint256 maxRawDebts) external returns (RebalanceResult memory result);\n\n  /// @notice Liquidate all ticks in the decreasing order of LTV.\n  /// @param maxRawDebts The maximum amount of debt tokens to liquidate.\n  /// @param reservedRawColls The amount of collateral tokens in reserve pool.\n  /// @return result The result of liquidate.\n  function liquidate(uint256 maxRawDebts, uint256 reservedRawColls) external returns (LiquidateResult memory result);\n}\n"},"contracts/interfaces/IPoolManager.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IPoolManager {\n  /**********\n   * Events *\n   **********/\n  \n  /// @notice Register a new pool.\n  /// @param pool The address of fx pool.\n  event RegisterPool(address indexed pool);\n\n  /// @notice Emitted when the reward splitter contract is updated.\n  /// @param pool The address of fx pool.\n  /// @param oldSplitter The address of previous reward splitter contract.\n  /// @param newSplitter The address of current reward splitter contract.\n  event UpdateRewardSplitter(address indexed pool, address indexed oldSplitter, address indexed newSplitter);\n\n  /// @notice Emitted when the threshold for permissionless liquidate/rebalance is updated.\n  /// @param oldThreshold The value of previous threshold.\n  /// @param newThreshold The value of current threshold.\n  event UpdatePermissionedLiquidationThreshold(uint256 oldThreshold, uint256 newThreshold);\n\n  /// @notice Emitted when token rate is updated.\n  /// @param scalar The token scalar to reach 18 decimals.\n  /// @param provider The address of token rate provider.\n  event UpdateTokenRate(address indexed token, uint256 scalar, address provider);\n\n  /// @notice Emitted when pool capacity is updated.\n  /// @param pool The address of fx pool.\n  /// @param collateralCapacity The capacity for collateral token.\n  /// @param debtCapacity The capacity for debt token.\n  event UpdatePoolCapacity(address indexed pool, uint256 collateralCapacity, uint256 debtCapacity);\n\n  /// @notice Emitted when position is updated.\n  /// @param pool The address of pool where the position belongs to.\n  /// @param position The id of the position.\n  /// @param deltaColls The amount of collateral token changes.\n  /// @param deltaDebts The amount of debt token changes.\n  /// @param protocolFees The amount of protocol fees charges.\n  event Operate(\n    address indexed pool,\n    uint256 indexed position,\n    int256 deltaColls,\n    int256 deltaDebts,\n    uint256 protocolFees\n  );\n  \n  /// @notice Emitted when redeem happened.\n  /// @param pool The address of pool redeemed.\n  /// @param colls The amount of collateral tokens redeemed.\n  /// @param debts The amount of debt tokens redeemed.\n  /// @param protocolFees The amount of protocol fees charges.\n  event Redeem(address indexed pool, uint256 colls, uint256 debts, uint256 protocolFees);\n\n  /// @notice Emitted when rebalance for a tick happened.\n  /// @param pool The address of pool rebalanced.\n  /// @param tick The index of tick rebalanced.\n  /// @param colls The amount of collateral tokens rebalanced.\n  /// @param fxUSDDebts The amount of fxUSD rebalanced.\n  /// @param stableDebts The amount of stable token (a.k.a USDC) rebalanced.\n  event RebalanceTick(address indexed pool, int16 indexed tick, uint256 colls, uint256 fxUSDDebts, uint256 stableDebts);\n\n  /// @notice Emitted when rebalance happened.\n  /// @param pool The address of pool rebalanced.\n  /// @param colls The amount of collateral tokens rebalanced.\n  /// @param fxUSDDebts The amount of fxUSD rebalanced.\n  /// @param stableDebts The amount of stable token (a.k.a USDC) rebalanced.\n  event Rebalance(address indexed pool, uint256 colls, uint256 fxUSDDebts, uint256 stableDebts);\n\n  /// @notice Emitted when liquidate happened.\n  /// @param pool The address of pool liquidated.\n  /// @param colls The amount of collateral tokens liquidated.\n  /// @param fxUSDDebts The amount of fxUSD liquidated.\n  /// @param stableDebts The amount of stable token (a.k.a USDC) liquidated.\n  event Liquidate(address indexed pool, uint256 colls, uint256 fxUSDDebts, uint256 stableDebts);\n\n  /// @notice Emitted when someone harvest pending rewards.\n  /// @param caller The address of caller.\n  /// @param amountRewards The amount of total harvested rewards.\n  /// @param amountFunding The amount of total harvested funding.\n  /// @param performanceFee The amount of harvested rewards distributed to protocol revenue.\n  /// @param harvestBounty The amount of harvested rewards distributed to caller as harvest bounty.\n  event Harvest(\n    address indexed caller,\n    address indexed pool,\n    uint256 amountRewards,\n    uint256 amountFunding,\n    uint256 performanceFee,\n    uint256 harvestBounty\n  );\n\n  /*************************\n   * Public View Functions *\n   *************************/\n  \n  /// @notice The address of fxUSD.\n  function fxUSD() external view returns (address);\n\n  /// @notice The address of FxUSDSave.\n  function fxBASE() external view returns (address);\n\n  /// @notice The address of `PegKeeper`.\n  function pegKeeper() external view returns (address);\n\n  /// @notice The address of reward splitter.\n  function rewardSplitter(address pool) external view returns (address);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n  \n  /// @notice Open a new position or operate on an old position.\n  /// @param pool The address of pool to operate.\n  /// @param positionId The id of the position. If `positionId=0`, it means we need to open a new position.\n  /// @param newColl The amount of collateral token to supply (positive value) or withdraw (negative value).\n  /// @param newDebt The amount of debt token to borrow (positive value) or repay (negative value).\n  /// @return actualPositionId The id of this position.\n  function operate(\n    address pool,\n    uint256 positionId,\n    int256 newColl,\n    int256 newDebt\n  ) external returns (uint256 actualPositionId);\n\n  /// @notice Redeem debt tokens to get collateral tokens.\n  /// @param pool The address of pool to redeem.\n  /// @param debts The amount of debt tokens to redeem.\n  /// @param minColls The minimum amount of collateral tokens should redeem.\n  /// @return colls The amount of collateral tokens redeemed.\n  function redeem(address pool, uint256 debts, uint256 minColls) external returns (uint256 colls);\n\n  /// @notice Rebalance all positions in the given tick.\n  /// @param pool The address of pool to rebalance.\n  /// @param receiver The address of recipient for rebalanced tokens.\n  /// @param tick The index of tick to rebalance.\n  /// @param maxFxUSD The maximum amount of fxUSD to rebalance.\n  /// @param maxStable The maximum amount of stable token (a.k.a USDC) to rebalance.\n  /// @return colls The amount of collateral tokens rebalanced.\n  /// @return fxUSDUsed The amount of fxUSD used to rebalance.\n  /// @return stableUsed The amount of stable token used to rebalance.\n  function rebalance(\n    address pool,\n    address receiver,\n    int16 tick,\n    uint256 maxFxUSD,\n    uint256 maxStable\n  ) external returns (uint256 colls, uint256 fxUSDUsed, uint256 stableUsed);\n\n  /// @notice Rebalance all positions in the given tick.\n  /// @param pool The address of pool to rebalance.\n  /// @param receiver The address of recipient for rebalanced tokens.\n  /// @param maxFxUSD The maximum amount of fxUSD to rebalance.\n  /// @param maxStable The maximum amount of stable token (a.k.a USDC) to rebalance.\n  /// @return colls The amount of collateral tokens rebalanced.\n  /// @return fxUSDUsed The amount of fxUSD used to rebalance.\n  /// @return stableUsed The amount of stable token used to rebalance.\n  function rebalance(\n    address pool,\n    address receiver,\n    uint256 maxFxUSD,\n    uint256 maxStable\n  ) external returns (uint256 colls, uint256 fxUSDUsed, uint256 stableUsed);\n\n  /// @notice Liquidate a given position.\n  /// @param pool The address of pool to liquidate.\n  /// @param receiver The address of recipient for liquidated tokens.\n  /// @param maxFxUSD The maximum amount of fxUSD to liquidate.\n  /// @param maxStable The maximum amount of stable token (a.k.a USDC) to liquidate.\n  /// @return colls The amount of collateral tokens liquidated.\n  /// @return fxUSDUsed The amount of fxUSD used to liquidate.\n  /// @return stableUsed The amount of stable token used to liquidate.\n  function liquidate(\n    address pool,\n    address receiver,\n    uint256 maxFxUSD,\n    uint256 maxStable\n  ) external returns (uint256 colls, uint256 fxUSDUsed, uint256 stableUsed);\n\n  /// @notice Harvest pending rewards of the given pool.\n  /// @param pool The address of pool to harvest.\n  /// @return amountRewards The amount of rewards harvested.\n  /// @return amountFunding The amount of funding harvested.\n  function harvest(address pool) external returns (uint256 amountRewards, uint256 amountFunding);\n}\n"},"contracts/interfaces/IProtocolFees.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IProtocolFees {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when the reserve pool contract is updated.\n  /// @param oldReservePool The address of previous reserve pool.\n  /// @param newReservePool The address of current reserve pool.\n  event UpdateReservePool(address indexed oldReservePool, address indexed newReservePool);\n\n  /// @notice Emitted when the treasury contract is updated.\n  /// @param oldTreasury The address of previous treasury contract.\n  /// @param newTreasury The address of current treasury contract.\n  event UpdateTreasury(address indexed oldTreasury, address indexed newTreasury);\n\n  /// @notice Emitted when the open revenue pool contract is updated.\n  /// @param oldPool The address of previous revenue pool contract.\n  /// @param newPool The address of current revenue pool contract.\n  event UpdateOpenRevenuePool(address indexed oldPool, address indexed newPool);\n\n  /// @notice Emitted when the close revenue pool contract is updated.\n  /// @param oldPool The address of previous revenue pool contract.\n  /// @param newPool The address of current revenue pool contract.\n  event UpdateCloseRevenuePool(address indexed oldPool, address indexed newPool);\n\n  /// @notice Emitted when the misc revenue pool contract is updated.\n  /// @param oldPool The address of previous revenue pool contract.\n  /// @param newPool The address of current revenue pool contract.\n  event UpdateMiscRevenuePool(address indexed oldPool, address indexed newPool);\n\n  /// @notice Emitted when the ratio for treasury is updated.\n  /// @param oldRatio The value of the previous ratio, multiplied by 1e9.\n  /// @param newRatio The value of the current ratio, multiplied by 1e9.\n  event UpdateRewardsExpenseRatio(uint256 oldRatio, uint256 newRatio);\n\n  /// @notice Emitted when the ratio for treasury is updated.\n  /// @param oldRatio The value of the previous ratio, multiplied by 1e9.\n  /// @param newRatio The value of the current ratio, multiplied by 1e9.\n  event UpdateFundingExpenseRatio(uint256 oldRatio, uint256 newRatio);\n\n  /// @notice Emitted when the ratio for treasury is updated.\n  /// @param oldRatio The value of the previous ratio, multiplied by 1e9.\n  /// @param newRatio The value of the current ratio, multiplied by 1e9.\n  event UpdateLiquidationExpenseRatio(uint256 oldRatio, uint256 newRatio);\n\n  /// @notice Emitted when the ratio for harvester is updated.\n  /// @param oldRatio The value of the previous ratio, multiplied by 1e9.\n  /// @param newRatio The value of the current ratio, multiplied by 1e9.\n  event UpdateHarvesterRatio(uint256 oldRatio, uint256 newRatio);\n\n  /// @notice Emitted when the flash loan fee ratio is updated.\n  /// @param oldRatio The value of the previous ratio, multiplied by 1e9.\n  /// @param newRatio The value of the current ratio, multiplied by 1e9.\n  event UpdateFlashLoanFeeRatio(uint256 oldRatio, uint256 newRatio);\n\n  /// @notice Emitted when the redeem fee ratio is updated.\n  /// @param oldRatio The value of the previous ratio, multiplied by 1e9.\n  /// @param newRatio The value of the current ratio, multiplied by 1e9.\n  event UpdateRedeemFeeRatio(uint256 oldRatio, uint256 newRatio);\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the fee ratio distributed as protocol revenue in funding costs, multiplied by 1e9.\n  function getFundingExpenseRatio() external view returns (uint256);\n\n  /// @notice Return the fee ratio distributed as protocol revenue in general rewards, multiplied by 1e9.\n  function getRewardsExpenseRatio() external view returns (uint256);\n\n  /// @notice Return the fee ratio distributed as protocol revenue in liquidation/rebalance, multiplied by 1e9.\n  function getLiquidationExpenseRatio() external view returns (uint256);\n\n  /// @notice Return the fee ratio distributed to fxBASE in funding costs, multiplied by 1e9.\n  function getFundingFxSaveRatio() external view returns (uint256);\n\n  /// @notice Return the fee ratio distributed to fxBASE in general rewards, multiplied by 1e9.\n  function getRewardsFxSaveRatio() external view returns (uint256);\n\n  /// @notice Return the fee ratio distributed ad harvester bounty, multiplied by 1e9.\n  function getHarvesterRatio() external view returns (uint256);\n\n  /// @notice Return the flash loan fee ratio, multiplied by 1e9.\n  function getFlashLoanFeeRatio() external view returns (uint256);\n\n  /// @notice Return the redeem fee ratio, multiplied by 1e9.\n  function getRedeemFeeRatio() external view returns (uint256);\n\n  /// @notice Return the address of reserve pool.\n  function reservePool() external view returns (address);\n\n  /// @notice Return the address of protocol treasury.\n  function treasury() external view returns (address);\n\n  /// @notice Return the address of protocol revenue pool.\n  function openRevenuePool() external view returns (address);\n\n  /// @notice Return the address of protocol revenue pool.\n  function closeRevenuePool() external view returns (address);\n\n  /// @notice Return the address of protocol revenue pool.\n  function miscRevenuePool() external view returns (address);\n\n  /// @notice Return the amount of protocol open fees accumulated by the given pool.\n  function accumulatedPoolOpenFees(address pool) external view returns (uint256);\n\n  /// @notice Return the amount of protocol close fees accumulated by the given pool.\n  function accumulatedPoolCloseFees(address pool) external view returns (uint256);\n\n  /// @notice Return the amount of protocol misc fees accumulated by the given pool.\n  function accumulatedPoolMiscFees(address pool) external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Withdraw accumulated pool fee for the given pool lists.\n  /// @param pools The list of pool addresses to withdraw.\n  function withdrawAccumulatedPoolFee(address[] memory pools) external;\n}\n"},"contracts/interfaces/IReservePool.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IReservePool {\n  /// @notice Emitted when the market request bonus.\n  /// @param token The address of the token requested.\n  /// @param receiver The address of token receiver.\n  /// @param bonus The amount of bonus token.\n  event RequestBonus(address indexed token, address indexed receiver, uint256 bonus);\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the balance of token in this contract.\n  function getBalance(address token) external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Request bonus token from Reserve Pool.\n  /// @param token The address of token to request.\n  /// @param receiver The address recipient for the bonus token.\n  /// @param bonus The amount of bonus token to send.\n  function requestBonus(address token, address receiver, uint256 bonus) external;\n\n  /// @notice Withdraw dust assets in this contract.\n  /// @param token The address of token to withdraw.\n  /// @param amount The amount of token to withdraw.\n  /// @param recipient The address of token receiver.\n  function withdrawFund(address token, uint256 amount, address recipient) external;\n}\n"},"contracts/interfaces/IRewardSplitter.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IRewardSplitter {\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Split token to different RebalancePool.\n  /// @param token The address of token to split.\n  function split(address token) external;\n\n  /// @notice Deposit new rewards to this contract.\n  ///\n  /// @param token The address of reward token.\n  /// @param amount The amount of new rewards.\n  function depositReward(address token, uint256 amount) external;\n}\n"},"contracts/interfaces/ISavingFxUSD.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface ISavingFxUSD {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when the threshold for batch deposit is updated.\n  /// @param oldThreshold The value of the previous threshold.\n  /// @param newThreshold The value of the current threshold.\n  event UpdateThreshold(uint256 oldThreshold, uint256 newThreshold);\n  \n  /// @notice Emitted when user direct request unlocking through this contract.\n  /// @param owner The address of token owner.\n  /// @param shares The amount of shares to unlock.\n  /// @param assets The amount of corresponding assets.\n  event RequestRedeem(address owner, uint256 shares, uint256 assets);\n  \n  /// @notice Emitted when user claim unlocked tokens.\n  /// @param owner The address of token owner.\n  /// @param receiver The address of token receiver.\n  event Claim(address owner, address receiver);\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the net asset value, multiplied by 1e18.\n  function nav() external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Deposit with gauge token.\n  /// @param assets The amount of gauge token.\n  /// @param receiver The address of pool share recipient.\n  function depositGauge(uint256 assets, address receiver) external returns (uint256);\n\n  /// @notice Harvest the pending rewards.\n  function harvest() external;\n\n  /// @notice Request redeem.\n  /// @param shares The amount of shares to request.\n  /// @return assets The amount of corresponding assets.\n  function requestRedeem(uint256 shares) external returns (uint256);\n\n  /// @notice Claim unlocked tokens.\n  /// @param receiver The address of recipient.\n  function claim(address receiver) external;\n\n  /// @notice Claim unlocked tokens for someone.\n  /// @param owner The address of token owner.\n  /// @param receiver The address of recipient.\n  function claimFor(address owner, address receiver) external;\n}\n"},"contracts/interfaces/IWrappedEther.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IWrappedEther {\n  function deposit() external payable;\n\n  function withdraw(uint256 wad) external;\n}\n"},"contracts/interfaces/Morpho/IMorpho.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IMorpho {\n    /// @notice Executes a flash loan.\n    /// @dev Flash loans have access to the whole balance of the contract (the liquidity and deposited collateral of all\n    /// markets combined, plus donations).\n    /// @dev Warning: Not ERC-3156 compliant but compatibility is easily reached:\n    /// - `flashFee` is zero.\n    /// - `maxFlashLoan` is the token's balance of this contract.\n    /// - The receiver of `assets` is the caller.\n    /// @param token The token to flash loan.\n    /// @param assets The amount of assets to flash loan.\n    /// @param data Arbitrary data to pass to the `onMorphoFlashLoan` callback.\n    function flashLoan(address token, uint256 assets, bytes calldata data) external;\n}"},"contracts/libraries/BitMath.sol":{"content":"// SPDX-License-Identifier: GPL-2.0-or-later\n\npragma solidity ^0.8.0;\n\n/// @title BitMath\n/// @dev This library provides functionality for computing bit properties of an unsigned integer\n///\n/// copy from: https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/BitMath.sol\nlibrary BitMath {\n    /// @notice Returns the index of the most significant bit of the number,\n    ///     where the least significant bit is at index 0 and the most significant bit is at index 255\n    /// @dev The function satisfies the property:\n    ///     x >= 2**mostSignificantBit(x) and x < 2**(mostSignificantBit(x)+1)\n    /// @param x the value for which to compute the most significant bit, must be greater than 0\n    /// @return r the index of the most significant bit\n    function mostSignificantBit(uint256 x) internal pure returns (uint8 r) {\n        require(x > 0);\n\n        if (x >= 0x100000000000000000000000000000000) {\n            x >>= 128;\n            r += 128;\n        }\n        if (x >= 0x10000000000000000) {\n            x >>= 64;\n            r += 64;\n        }\n        if (x >= 0x100000000) {\n            x >>= 32;\n            r += 32;\n        }\n        if (x >= 0x10000) {\n            x >>= 16;\n            r += 16;\n        }\n        if (x >= 0x100) {\n            x >>= 8;\n            r += 8;\n        }\n        if (x >= 0x10) {\n            x >>= 4;\n            r += 4;\n        }\n        if (x >= 0x4) {\n            x >>= 2;\n            r += 2;\n        }\n        if (x >= 0x2) r += 1;\n    }\n\n    /// @notice Returns the index of the least significant bit of the number,\n    ///     where the least significant bit is at index 0 and the most significant bit is at index 255\n    /// @dev The function satisfies the property:\n    ///     (x & 2**leastSignificantBit(x)) != 0 and (x & (2**(leastSignificantBit(x)) - 1)) == 0)\n    /// @param x the value for which to compute the least significant bit, must be greater than 0\n    /// @return r the index of the least significant bit\n    function leastSignificantBit(uint256 x) internal pure returns (uint8 r) {\n        require(x > 0);\n\n        r = 255;\n        if (x & type(uint128).max > 0) {\n            r -= 128;\n        } else {\n            x >>= 128;\n        }\n        if (x & type(uint64).max > 0) {\n            r -= 64;\n        } else {\n            x >>= 64;\n        }\n        if (x & type(uint32).max > 0) {\n            r -= 32;\n        } else {\n            x >>= 32;\n        }\n        if (x & type(uint16).max > 0) {\n            r -= 16;\n        } else {\n            x >>= 16;\n        }\n        if (x & type(uint8).max > 0) {\n            r -= 8;\n        } else {\n            x >>= 8;\n        }\n        if (x & 0xf > 0) {\n            r -= 4;\n        } else {\n            x >>= 4;\n        }\n        if (x & 0x3 > 0) {\n            r -= 2;\n        } else {\n            x >>= 2;\n        }\n        if (x & 0x1 > 0) r -= 1;\n    }\n}\n"},"contracts/libraries/Math.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nlibrary Math {\n  enum Rounding {\n    Up,\n    Down\n  }\n\n  /// @dev Internal return the value of min(a, b).\n  function min(uint256 a, uint256 b) internal pure returns (uint256) {\n    return a < b ? a : b;\n  }\n\n  /// @dev Internal return the value of max(a, b).\n  function max(uint256 a, uint256 b) internal pure returns (uint256) {\n    return a > b ? a : b;\n  }\n\n  /// @dev Internal return the value of a * b / c, with rounding.\n  function mulDiv(uint256 a, uint256 b, uint256 c, Rounding rounding) internal pure returns (uint256) {\n    return rounding == Rounding.Down ? mulDivDown(a, b, c) : mulDivUp(a, b, c);\n  }\n\n  /// @dev Internal return the value of ceil(a * b / c).\n  function mulDivUp(uint256 a, uint256 b, uint256 c) internal pure returns (uint256) {\n    return (a * b + c - 1) / c;\n  }\n\n  /// @dev Internal return the value of floor(a * b / c).\n  function mulDivDown(uint256 a, uint256 b, uint256 c) internal pure returns (uint256) {\n    return (a * b) / c;\n  }\n}\n"},"contracts/libraries/TickBitmap.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { BitMath } from \"./BitMath.sol\";\n\nlibrary TickBitmap {\n  function position(int16 tick) private pure returns (int8 wordPos, uint8 bitPos) {\n    assembly {\n      wordPos := shr(8, tick)\n      bitPos := and(tick, 255)\n    }\n  }\n\n  function flipTick(mapping(int8 => uint256) storage self, int16 tick) internal {\n    (int8 wordPos, uint8 bitPos) = position(tick);\n    uint256 mask = 1 << bitPos;\n    self[wordPos] ^= mask;\n  }\n\n  function isBitSet(mapping(int8 => uint256) storage self, int16 tick) internal view returns (bool) {\n    (int8 wordPos, uint8 bitPos) = position(tick);\n    uint256 mask = 1 << bitPos;\n    return (self[wordPos] & mask) > 0;\n  }\n\n  /// @notice Returns the next initialized tick contained in the same word (or adjacent word) as the tick that is\n  /// to the left (less than or equal to).\n  function nextDebtPositionWithinOneWord(\n    mapping(int8 => uint256) storage self,\n    int16 tick\n  ) internal view returns (int16 next, bool hasDebt) {\n    unchecked {\n      // start from the word of the next tick, since the current tick state doesn't matter\n      (int8 wordPos, uint8 bitPos) = position(tick);\n      // all the 1s at or to the right of the current bitPos\n      uint256 mask = (1 << bitPos) - 1 + (1 << bitPos);\n      uint256 masked = self[wordPos] & mask;\n\n      // if there are no initialized ticks to the left of the current tick, return leftmost in the word\n      hasDebt = masked != 0;\n      // overflow/underflow is possible, but prevented externally by limiting tick\n      next = hasDebt\n        ? (tick - int16(uint16(bitPos - BitMath.mostSignificantBit(masked))))\n        : (tick - int16(uint16(bitPos)));\n    }\n  }\n}\n"},"contracts/libraries/TickMath.sol":{"content":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.26;\n\n/// @title library that calculates number \"tick\" and \"ratioX96\" from this: ratioX96 = (1.0015^tick) * 2^96\n/// @notice this library is used in Fluid Vault protocol for optimiziation.\n/// @dev \"tick\" supports between -32767 and 32767. \"ratioX96\" supports between 37075072 and 169307877264527972847801929085841449095838922544595\n///\n/// @dev Copy from https://github.com/Instadapp/fluid-contracts-public/blob/main/contracts/libraries/tickMath.sol\nlibrary TickMath {\n    /// The minimum tick that can be passed in getRatioAtTick. 1.0015**-32767\n    int24 internal constant MIN_TICK = -32767;\n    /// The maximum tick that can be passed in getRatioAtTick. 1.0015**32767\n    int24 internal constant MAX_TICK = 32767;\n\n    uint256 internal constant FACTOR00 = 0x100000000000000000000000000000000;\n    uint256 internal constant FACTOR01 = 0xff9dd7de423466c20352b1246ce4856f; // 2^128/1.0015**1 = 339772707859149738855091969477551883631\n    uint256 internal constant FACTOR02 = 0xff3bd55f4488ad277531fa1c725a66d0; // 2^128/1.0015**2 = 339263812140938331358054887146831636176\n    uint256 internal constant FACTOR03 = 0xfe78410fd6498b73cb96a6917f853259; // 2^128/1.0015**4 = 338248306163758188337119769319392490073\n    uint256 internal constant FACTOR04 = 0xfcf2d9987c9be178ad5bfeffaa123273; // 2^128/1.0015**8 = 336226404141693512316971918999264834163\n    uint256 internal constant FACTOR05 = 0xf9ef02c4529258b057769680fc6601b3; // 2^128/1.0015**16 = 332218786018727629051611634067491389875\n    uint256 internal constant FACTOR06 = 0xf402d288133a85a17784a411f7aba082; // 2^128/1.0015**32 = 324346285652234375371948336458280706178\n    uint256 internal constant FACTOR07 = 0xe895615b5beb6386553757b0352bda90; // 2^128/1.0015**64 = 309156521885964218294057947947195947664\n    uint256 internal constant FACTOR08 = 0xd34f17a00ffa00a8309940a15930391a; // 2^128/1.0015**128 = 280877777739312896540849703637713172762 \n    uint256 internal constant FACTOR09 = 0xae6b7961714e20548d88ea5123f9a0ff; // 2^128/1.0015**256 = 231843708922198649176471782639349113087\n    uint256 internal constant FACTOR10 = 0x76d6461f27082d74e0feed3b388c0ca1; // 2^128/1.0015**512 = 157961477267171621126394973980180876449\n    uint256 internal constant FACTOR11 = 0x372a3bfe0745d8b6b19d985d9a8b85bb; // 2^128/1.0015**1024 = 73326833024599564193373530205717235131\n    uint256 internal constant FACTOR12 = 0x0be32cbee48979763cf7247dd7bb539d; // 2^128/1.0015**2048 = 15801066890623697521348224657638773661\n    uint256 internal constant FACTOR13 = 0x8d4f70c9ff4924dac37612d1e2921e;   // 2^128/1.0015**4096 = 733725103481409245883800626999235102\n    uint256 internal constant FACTOR14 = 0x4e009ae5519380809a02ca7aec77;     // 2^128/1.0015**8192 = 1582075887005588088019997442108535\n    uint256 internal constant FACTOR15 = 0x17c45e641b6e95dee056ff10;         // 2^128/1.0015**16384 = 7355550435635883087458926352\n\n    /// The minimum value that can be returned from getRatioAtTick. Equivalent to getRatioAtTick(MIN_TICK). ~ Equivalent to `(1 << 96) * (1.0015**-32767)`\n    uint256 internal constant MIN_RATIOX96 = 37075072;\n    /// The maximum value that can be returned from getRatioAtTick. Equivalent to getRatioAtTick(MAX_TICK).\n    /// ~ Equivalent to `(1 << 96) * (1.0015**32767)`, rounding etc. leading to minor difference\n    uint256 internal constant MAX_RATIOX96 = 169307877264527972847801929085841449095838922544595;\n\n    uint256 internal constant ZERO_TICK_SCALED_RATIO = 0x1000000000000000000000000; // 1 << 96 // 79228162514264337593543950336\n    uint256 internal constant _1E26 = 1e26;\n\n    /// @notice ratioX96 = (1.0015^tick) * 2^96\n    /// @dev Throws if |tick| > max tick\n    /// @param tick The input tick for the above formula\n    /// @return ratioX96 ratio = (debt amount/collateral amount)\n    function getRatioAtTick(int tick) internal pure returns (uint256 ratioX96) {\n        assembly {\n            let absTick_ := sub(xor(tick, sar(255, tick)), sar(255, tick))\n\n            if gt(absTick_, MAX_TICK) {\n                revert(0, 0)\n            }\n            let factor_ := FACTOR00\n            if and(absTick_, 0x1) {\n                factor_ := FACTOR01\n            }\n            if and(absTick_, 0x2) {\n                factor_ := shr(128, mul(factor_, FACTOR02))\n            }\n            if and(absTick_, 0x4) {\n                factor_ := shr(128, mul(factor_, FACTOR03))\n            }\n            if and(absTick_, 0x8) {\n                factor_ := shr(128, mul(factor_, FACTOR04))\n            }\n            if and(absTick_, 0x10) {\n                factor_ := shr(128, mul(factor_, FACTOR05))\n            }\n            if and(absTick_, 0x20) {\n                factor_ := shr(128, mul(factor_, FACTOR06))\n            }\n            if and(absTick_, 0x40) {\n                factor_ := shr(128, mul(factor_, FACTOR07))\n            }\n            if and(absTick_, 0x80) {\n                factor_ := shr(128, mul(factor_, FACTOR08))\n            }\n            if and(absTick_, 0x100) {\n                factor_ := shr(128, mul(factor_, FACTOR09))\n            }\n            if and(absTick_, 0x200) {\n                factor_ := shr(128, mul(factor_, FACTOR10))\n            }\n            if and(absTick_, 0x400) {\n                factor_ := shr(128, mul(factor_, FACTOR11))\n            }\n            if and(absTick_, 0x800) {\n                factor_ := shr(128, mul(factor_, FACTOR12))\n            }\n            if and(absTick_, 0x1000) {\n                factor_ := shr(128, mul(factor_, FACTOR13))\n            }\n            if and(absTick_, 0x2000) {\n                factor_ := shr(128, mul(factor_, FACTOR14))\n            }\n            if and(absTick_, 0x4000) {\n                factor_ := shr(128, mul(factor_, FACTOR15))\n            }\n\n            let precision_ := 0\n            if iszero(and(tick, 0x8000000000000000000000000000000000000000000000000000000000000000)) {\n                factor_ := div(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, factor_)\n                // we round up in the division so getTickAtRatio of the output price is always consistent\n                if mod(factor_, 0x100000000) {\n                    precision_ := 1\n                }\n            }\n            ratioX96 := add(shr(32, factor_), precision_)\n        }\n    }\n\n    /// @notice ratioX96 = (1.0015^tick) * 2^96\n    /// @dev Throws if ratioX96 > max ratio || ratioX96 < min ratio\n    /// @param ratioX96 The input ratio; ratio = (debt amount/collateral amount)\n    /// @return tick The output tick for the above formula. Returns in round down form. if tick is 123.23 then 123, if tick is -123.23 then returns -124\n    /// @return perfectRatioX96 perfect ratio for the above tick\n    function getTickAtRatio(uint256 ratioX96) internal pure returns (int tick, uint perfectRatioX96) {\n        assembly {\n            if or(gt(ratioX96, MAX_RATIOX96), lt(ratioX96, MIN_RATIOX96)) {\n                revert(0, 0)\n            }\n\n            let cond := lt(ratioX96, ZERO_TICK_SCALED_RATIO)\n            let factor_\n\n            if iszero(cond) {\n                // if ratioX96 >= ZERO_TICK_SCALED_RATIO\n                factor_ := div(mul(ratioX96, _1E26), ZERO_TICK_SCALED_RATIO)\n            }\n            if cond {\n                // ratioX96 < ZERO_TICK_SCALED_RATIO\n                factor_ := div(mul(ZERO_TICK_SCALED_RATIO, _1E26), ratioX96)\n            }\n\n            // put in https://www.wolframalpha.com/ whole equation: (1.0015^tick) * 2^96 * 10^26 / 79228162514264337593543950336\n\n            // for tick = 16384\n            // ratioX96 = (1.0015^16384) * 2^96 = 3665252098134783297721995888537077351735\n            // 3665252098134783297721995888537077351735 * 10^26 / 79228162514264337593543950336 =\n            // 4626198540796508716348404308345255985.06131964639489434655721\n            if iszero(lt(factor_, 4626198540796508716348404308345255985)) {\n                tick := or(tick, 0x4000)\n                factor_ := div(mul(factor_, _1E26), 4626198540796508716348404308345255985)\n            }\n            // for tick = 8192\n            // ratioX96 = (1.0015^8192) * 2^96 = 17040868196391020479062776466509865\n            // 17040868196391020479062776466509865 * 10^26 / 79228162514264337593543950336 =\n            // 21508599537851153911767490449162.3037648642153898377655505172\n            if iszero(lt(factor_, 21508599537851153911767490449162)) {\n                tick := or(tick, 0x2000)\n                factor_ := div(mul(factor_, _1E26), 21508599537851153911767490449162)\n            }\n            // for tick = 4096\n            // ratioX96 = (1.0015^4096) * 2^96 = 36743933851015821532611831851150\n            // 36743933851015821532611831851150 * 10^26 / 79228162514264337593543950336 =\n            // 46377364670549310883002866648.9777607649742626173648716941385\n            if iszero(lt(factor_, 46377364670549310883002866649)) {\n                tick := or(tick, 0x1000)\n                factor_ := div(mul(factor_, _1E26), 46377364670549310883002866649)\n            }\n            // for tick = 2048\n            // ratioX96 = (1.0015^2048) * 2^96 = 1706210527034005899209104452335\n            // 1706210527034005899209104452335 * 10^26 / 79228162514264337593543950336 =\n            // 2153540449365864845468344760.06357108484096046743300420319322\n            if iszero(lt(factor_, 2153540449365864845468344760)) {\n                tick := or(tick, 0x800)\n                factor_ := div(mul(factor_, _1E26), 2153540449365864845468344760)\n            }\n            // for tick = 1024\n            // ratioX96 = (1.0015^1024) * 2^96 = 367668226692760093024536487236\n            // 367668226692760093024536487236 * 10^26 / 79228162514264337593543950336 =\n            // 464062544207767844008185024.950588990554136265212906454481127\n            if iszero(lt(factor_, 464062544207767844008185025)) {\n                tick := or(tick, 0x400)\n                factor_ := div(mul(factor_, _1E26), 464062544207767844008185025)\n            }\n            // for tick = 512\n            // ratioX96 = (1.0015^512) * 2^96 = 170674186729409605620119663668\n            // 170674186729409605620119663668 * 10^26 / 79228162514264337593543950336 =\n            // 215421109505955298802281577.031879604792139232258508172947569\n            if iszero(lt(factor_, 215421109505955298802281577)) {\n                tick := or(tick, 0x200)\n                factor_ := div(mul(factor_, _1E26), 215421109505955298802281577)\n            }\n            // for tick = 256\n            // ratioX96 = (1.0015^256) * 2^96 = 116285004205991934861656513301\n            // 116285004205991934861656513301 * 10^26 / 79228162514264337593543950336 =\n            // 146772309890508740607270614.667650899656438875541505058062410\n            if iszero(lt(factor_, 146772309890508740607270615)) {\n                tick := or(tick, 0x100)\n                factor_ := div(mul(factor_, _1E26), 146772309890508740607270615)\n            }\n            // for tick = 128\n            // ratioX96 = (1.0015^128) * 2^96 = 95984619659632141743747099590\n            // 95984619659632141743747099590 * 10^26 / 79228162514264337593543950336 =\n            // 121149622323187099817270416.157248837742741760456796835775887\n            if iszero(lt(factor_, 121149622323187099817270416)) {\n                tick := or(tick, 0x80)\n                factor_ := div(mul(factor_, _1E26), 121149622323187099817270416)\n            }\n            // for tick = 64\n            // ratioX96 = (1.0015^64) * 2^96 = 87204845308406958006717891124\n            // 87204845308406958006717891124 * 10^26 / 79228162514264337593543950336 =\n            // 110067989135437147685980801.568068573422377364214113968609839\n            if iszero(lt(factor_, 110067989135437147685980801)) {\n                tick := or(tick, 0x40)\n                factor_ := div(mul(factor_, _1E26), 110067989135437147685980801)\n            }\n            // for tick = 32\n            // ratioX96 = (1.0015^32) * 2^96 = 83120873769022354029916374475\n            // 83120873769022354029916374475 * 10^26 / 79228162514264337593543950336 =\n            // 104913292358707887270979599.831816586773651266562785765558183\n            if iszero(lt(factor_, 104913292358707887270979600)) {\n                tick := or(tick, 0x20)\n                factor_ := div(mul(factor_, _1E26), 104913292358707887270979600)\n            }\n            // for tick = 16\n            // ratioX96 = (1.0015^16) * 2^96 = 81151180492336368327184716176\n            // 81151180492336368327184716176 * 10^26 / 79228162514264337593543950336 =\n            // 102427189924701091191840927.762844039579442328381455567932128\n            if iszero(lt(factor_, 102427189924701091191840928)) {\n                tick := or(tick, 0x10)\n                factor_ := div(mul(factor_, _1E26), 102427189924701091191840928)\n            }\n            // for tick = 8\n            // ratioX96 = (1.0015^8) * 2^96 = 80183906840906820640659903620\n            // 80183906840906820640659903620 * 10^26 / 79228162514264337593543950336 =\n            // 101206318935480056907421312.890625\n            if iszero(lt(factor_, 101206318935480056907421313)) {\n                tick := or(tick, 0x8)\n                factor_ := div(mul(factor_, _1E26), 101206318935480056907421313)\n            }\n            // for tick = 4\n            // ratioX96 = (1.0015^4) * 2^96 = 79704602139525152702959747603\n            // 79704602139525152702959747603 * 10^26 / 79228162514264337593543950336 =\n            // 100601351350506250000000000\n            if iszero(lt(factor_, 100601351350506250000000000)) {\n                tick := or(tick, 0x4)\n                factor_ := div(mul(factor_, _1E26), 100601351350506250000000000)\n            }\n            // for tick = 2\n            // ratioX96 = (1.0015^2) * 2^96 = 79466025265172787701084167660\n            // 79466025265172787701084167660 * 10^26 / 79228162514264337593543950336 =\n            // 100300225000000000000000000\n            if iszero(lt(factor_, 100300225000000000000000000)) {\n                tick := or(tick, 0x2)\n                factor_ := div(mul(factor_, _1E26), 100300225000000000000000000)\n            }\n            // for tick = 1\n            // ratioX96 = (1.0015^1) * 2^96 = 79347004758035734099934266261\n            // 79347004758035734099934266261 * 10^26 / 79228162514264337593543950336 =\n            // 100150000000000000000000000\n            if iszero(lt(factor_, 100150000000000000000000000)) {\n                tick := or(tick, 0x1)\n                factor_ := div(mul(factor_, _1E26), 100150000000000000000000000)\n            }\n            if iszero(cond) {\n                // if ratioX96 >= ZERO_TICK_SCALED_RATIO\n                perfectRatioX96 := div(mul(ratioX96, _1E26), factor_)\n            }\n            if cond {\n                // ratioX96 < ZERO_TICK_SCALED_RATIO\n                tick := not(tick)\n                perfectRatioX96 := div(mul(ratioX96, factor_), 100150000000000000000000000)\n            }\n            // perfect ratio should always be <= ratioX96\n            // not sure if it can ever be bigger but better to have extra checks\n            if gt(perfectRatioX96, ratioX96) {\n                revert(0, 0)\n            }\n        }\n    }\n}\n"},"contracts/mocks/MockAaveV3Pool.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IAaveV3Pool } from \"../interfaces/Aave/IAaveV3Pool.sol\";\n\ncontract MockAaveV3Pool is IAaveV3Pool {\n  uint128 public variableBorrowRate;\n  uint256 public reserveNormalizedVariableDebt;\n\n  constructor(uint128 _variableBorrowRate) {\n    variableBorrowRate = _variableBorrowRate;\n  }\n\n  function setVariableBorrowRate(uint128 _variableBorrowRate) external {\n    variableBorrowRate = _variableBorrowRate;\n  }\n\n  function setReserveNormalizedVariableDebt(uint256 _reserveNormalizedVariableDebt) external {\n    reserveNormalizedVariableDebt = _reserveNormalizedVariableDebt;\n  }\n\n  function getReserveData(address) external view returns (ReserveDataLegacy memory result) {\n    result.currentVariableBorrowRate = variableBorrowRate;\n  }\n\n  function getReserveNormalizedVariableDebt(address) external view returns (uint256) {\n    return reserveNormalizedVariableDebt;\n  }\n\n  function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external override {}\n\n  function withdraw(address asset, uint256 amount, address to) external override returns (uint256) {}\n}\n"},"contracts/mocks/MockPriceOracle.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IPriceOracle } from \"../price-oracle/interfaces/IPriceOracle.sol\";\n\ncontract MockPriceOracle is IPriceOracle {\n  uint256 public anchorPrice;\n  uint256 public minPrice;\n  uint256 public maxPrice;\n\n  constructor(uint256 _anchorPrice, uint256 _minPrice, uint256 _maxPrice) {\n    anchorPrice = _anchorPrice;\n    minPrice = _minPrice;\n    maxPrice = _maxPrice;\n  }\n\n  function setPrices(uint256 _anchorPrice, uint256 _minPrice, uint256 _maxPrice) external {\n    anchorPrice = _anchorPrice;\n    minPrice = _minPrice;\n    maxPrice = _maxPrice;\n  }\n\n  function getPrice() public view returns (uint256, uint256, uint256) {\n    return (anchorPrice, minPrice, maxPrice);\n  }\n\n  /// @inheritdoc IPriceOracle\n  function getExchangePrice() public view returns (uint256) {\n    (, uint256 price, ) = getPrice();\n    return price;\n  }\n\n  /// @inheritdoc IPriceOracle\n  function getLiquidatePrice() external view returns (uint256) {\n    return getExchangePrice();\n  }\n\n  /// @inheritdoc IPriceOracle\n  function getRedeemPrice() external view returns (uint256) {\n    (, , uint256 price) = getPrice();\n    return price;\n  }\n}\n"},"contracts/mocks/MockStakedFxUSD.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\nimport { AggregatorV3Interface } from \"../interfaces/Chainlink/AggregatorV3Interface.sol\";\nimport { IPoolManager } from \"../interfaces/IPoolManager.sol\";\n\ncontract MockFxUSDSave {\n  /// @notice The address of `PoolManager` contract.\n  address public immutable poolManager;\n\n  /// @notice The address of `PegKeeper` contract.\n  address public immutable pegKeeper;\n\n  /// @dev This is also the address of FxUSD token.\n  address public immutable yieldToken;\n\n  /// @dev The address of USDC token.\n  address public immutable stableToken;\n\n  uint256 private immutable stableTokenScale;\n\n  /// @notice The Chainlink USDC/USD price feed.\n  /// @dev The encoding is below.\n  /// ```text\n  /// |  32 bits  | 64 bits |  160 bits  |\n  /// | heartbeat |  scale  | price_feed |\n  /// |low                          high |\n  /// ```\n  bytes32 public immutable Chainlink_USDC_USD_Spot;\n\n  constructor(\n    address _poolManager,\n    address _pegKeeper,\n    address _yieldToken,\n    address _stableToken,\n    bytes32 _Chainlink_USDC_USD_Spot\n  ) {\n    poolManager = _poolManager;\n    pegKeeper = _pegKeeper;\n    yieldToken = _yieldToken;\n    stableToken = _stableToken;\n    Chainlink_USDC_USD_Spot = _Chainlink_USDC_USD_Spot;\n\n    stableTokenScale = 10 ** (18 - IERC20Metadata(_stableToken).decimals());\n  }\n\n  function totalYieldToken() external view returns (uint256) {\n    return IERC20Metadata(yieldToken).balanceOf(address(this));\n  }\n\n  /// @notice The total amount of stable token managed in this contract\n  function totalStableToken() external view returns (uint256) {\n    return IERC20Metadata(stableToken).balanceOf(address(this));\n  }\n\n  function getStableTokenPrice() public view returns (uint256) {\n    bytes32 encoding = Chainlink_USDC_USD_Spot;\n    address aggregator;\n    uint256 scale;\n    uint256 heartbeat;\n    assembly {\n      aggregator := shr(96, encoding)\n      scale := and(shr(32, encoding), 0xffffffffffffffff)\n      heartbeat := and(encoding, 0xffffffff)\n    }\n    (, int256 answer, , uint256 updatedAt, ) = AggregatorV3Interface(aggregator).latestRoundData();\n    if (answer < 0) revert(\"invalid\");\n    if (block.timestamp - updatedAt > heartbeat) revert(\"expired\");\n    return uint256(answer) * scale;\n  }\n\n  function getStableTokenPriceWithScale() public view returns (uint256) {\n    return getStableTokenPrice() * stableTokenScale;\n  }\n\n  function rebalance(\n    address pool,\n    int16 tickId,\n    uint256 maxFxUSD,\n    uint256 maxStable\n  ) external returns (uint256 colls, uint256 yieldTokenUsed, uint256 stableTokenUsed) {\n    IERC20Metadata(yieldToken).approve(poolManager, type(uint256).max);\n    IERC20Metadata(stableToken).approve(poolManager, type(uint256).max);\n    (colls, yieldTokenUsed, stableTokenUsed) = IPoolManager(poolManager).rebalance(\n      pool,\n      msg.sender,\n      tickId,\n      maxFxUSD,\n      maxStable\n    );\n  }\n\n  function rebalance(\n    address pool,\n    uint256 maxFxUSD,\n    uint256 maxStable\n  ) external returns (uint256 colls, uint256 yieldTokenUsed, uint256 stableTokenUsed) {\n    IERC20Metadata(yieldToken).approve(poolManager, type(uint256).max);\n    IERC20Metadata(stableToken).approve(poolManager, type(uint256).max);\n    (colls, yieldTokenUsed, stableTokenUsed) = IPoolManager(poolManager).rebalance(\n      pool,\n      msg.sender,\n      maxFxUSD,\n      maxStable\n    );\n  }\n\n  function liquidate(\n    address pool,\n    uint256 maxFxUSD,\n    uint256 maxStable\n  ) external returns (uint256 colls, uint256 yieldTokenUsed, uint256 stableTokenUsed) {\n    IERC20Metadata(yieldToken).approve(poolManager, type(uint256).max);\n    IERC20Metadata(stableToken).approve(poolManager, type(uint256).max);\n    (colls, yieldTokenUsed, stableTokenUsed) = IPoolManager(poolManager).liquidate(\n      pool,\n      msg.sender,\n      maxFxUSD,\n      maxStable\n    );\n  }\n}\n"},"contracts/periphery/facets/FlashLoanFacetBase.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IBalancerVault } from \"../../interfaces/Balancer/IBalancerVault.sol\";\n\nimport { LibRouter } from \"../libraries/LibRouter.sol\";\n\nabstract contract FlashLoanFacetBase {\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the caller is not self.\n  error ErrorNotFromSelf();\n\n  /// @dev Unauthorized reentrant call.\n  error ReentrancyGuardReentrantCall();\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @dev The address of Balancer V2 Vault.\n  address private immutable balancer;\n\n  /*************\n   * Modifiers *\n   *************/\n\n  modifier onlySelf() {\n    if (msg.sender != address(this)) revert ErrorNotFromSelf();\n    _;\n  }\n\n  modifier onFlashLoan() {\n    LibRouter.RouterStorage storage $ = LibRouter.routerStorage();\n    $.flashLoanContext = LibRouter.HAS_FLASH_LOAN;\n    _;\n    $.flashLoanContext = LibRouter.NOT_FLASH_LOAN;\n  }\n\n  modifier nonReentrant() {\n    LibRouter.RouterStorage storage $ = LibRouter.routerStorage();\n    if ($.reentrantContext == LibRouter.HAS_ENTRANT) {\n      revert ReentrancyGuardReentrantCall();\n    }\n    $.reentrantContext = LibRouter.HAS_ENTRANT;\n    _;\n    $.reentrantContext = LibRouter.NOT_ENTRANT;\n  }\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _balancer) {\n    balancer = _balancer;\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  function _invokeFlashLoan(address token, uint256 amount, bytes memory data) internal onFlashLoan {\n    address[] memory tokens = new address[](1);\n    uint256[] memory amounts = new uint256[](1);\n    tokens[0] = token;\n    amounts[0] = amount;\n    IBalancerVault(balancer).flashLoan(address(this), tokens, amounts, data);\n  }\n}\n"},"contracts/periphery/facets/FxUSDBasePoolFacet.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IFxUSDBasePool } from \"../../interfaces/IFxUSDBasePool.sol\";\nimport { IFxShareableRebalancePool } from \"../../v2/interfaces/IFxShareableRebalancePool.sol\";\nimport { IFxUSD } from \"../../v2/interfaces/IFxUSD.sol\";\nimport { ILiquidityGauge } from \"../../voting-escrow/interfaces/ILiquidityGauge.sol\";\n\nimport { WordCodec } from \"../../common/codec/WordCodec.sol\";\nimport { LibRouter } from \"../libraries/LibRouter.sol\";\n\ncontract FxUSDBasePoolFacet {\n  using SafeERC20 for IERC20;\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @notice The address of USDC token.\n  address private constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;\n\n  /// @notice The address of fxUSD token.\n  address private constant fxUSD = 0x085780639CC2cACd35E474e71f4d000e2405d8f6;\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @dev The address of `PoolManager` contract.\n  address private immutable poolManager;\n\n  /// @dev The address of `FxUSDBasePool` contract.\n  address private immutable fxBASE;\n\n  /// @dev The address of fxBASE gauge contract.\n  address private immutable gauge;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _poolManager, address _fxBASE, address _gauge) {\n    poolManager = _poolManager;\n    fxBASE = _fxBASE;\n    gauge = _gauge;\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Migrate fxUSD from rebalance pool to fxBASE.\n  /// @param pool The address of rebalance pool.\n  /// @param amountIn The amount of rebalance pool shares to migrate.\n  /// @param minShares The minimum shares should receive.\n  /// @param receiver The address of fxBASE share recipient.\n  function migrateToFxBase(address pool, uint256 amountIn, uint256 minShares, address receiver) external {\n    IFxShareableRebalancePool(pool).withdrawFrom(msg.sender, amountIn, address(this));\n    address baseToken = IFxShareableRebalancePool(pool).baseToken();\n    address asset = IFxShareableRebalancePool(pool).asset();\n    LibRouter.approve(asset, fxUSD, amountIn);\n    IFxUSD(fxUSD).wrap(baseToken, amountIn, address(this));\n    LibRouter.approve(fxUSD, fxBASE, amountIn);\n    IFxUSDBasePool(fxBASE).deposit(receiver, fxUSD, amountIn, minShares);\n  }\n\n  /// @notice Migrate fxUSD from rebalance pool to fxBASE gauge.\n  /// @param pool The address of rebalance pool.\n  /// @param amountIn The amount of rebalance pool shares to migrate.\n  /// @param minShares The minimum shares should receive.\n  /// @param receiver The address of fxBASE share recipient.\n  function migrateToFxBaseGauge(address pool, uint256 amountIn, uint256 minShares, address receiver) external {\n    IFxShareableRebalancePool(pool).withdrawFrom(msg.sender, amountIn, address(this));\n    address baseToken = IFxShareableRebalancePool(pool).baseToken();\n    address asset = IFxShareableRebalancePool(pool).asset();\n    LibRouter.approve(asset, fxUSD, amountIn);\n    IFxUSD(fxUSD).wrap(baseToken, amountIn, address(this));\n    LibRouter.approve(fxUSD, fxBASE, amountIn);\n    uint256 shares = IFxUSDBasePool(fxBASE).deposit(address(this), fxUSD, amountIn, minShares);\n    LibRouter.approve(fxBASE, gauge, shares);\n    ILiquidityGauge(gauge).deposit(shares, receiver);\n  }\n\n  /// @notice Deposit token to fxBASE.\n  /// @param params The parameters to convert source token to `tokenOut`.\n  /// @param tokenOut The target token, USDC or fxUSD.\n  /// @param minShares The minimum shares should receive.\n  /// @param receiver The address of fxBASE share recipient.\n  function depositToFxBase(\n    LibRouter.ConvertInParams memory params,\n    address tokenOut,\n    uint256 minShares,\n    address receiver\n  ) external payable {\n    uint256 amountIn = LibRouter.transferInAndConvert(params, tokenOut);\n    LibRouter.approve(tokenOut, fxBASE, amountIn);\n    IFxUSDBasePool(fxBASE).deposit(receiver, tokenOut, amountIn, minShares);\n  }\n\n  /// @notice Deposit token to fxBase and then deposit to gauge.\n  /// @param params The parameters to convert source token to `tokenOut`.\n  /// @param tokenOut The target token, USDC or fxUSD.\n  /// @param minShares The minimum shares should receive.\n  /// @param receiver The address of gauge share recipient.\n  function depositToFxBaseGauge(\n    LibRouter.ConvertInParams memory params,\n    address tokenOut,\n    uint256 minShares,\n    address receiver\n  ) external payable {\n    uint256 amountIn = LibRouter.transferInAndConvert(params, tokenOut);\n    LibRouter.approve(tokenOut, fxBASE, amountIn);\n    uint256 shares = IFxUSDBasePool(fxBASE).deposit(address(this), tokenOut, amountIn, minShares);\n    LibRouter.approve(fxBASE, gauge, shares);\n    ILiquidityGauge(gauge).deposit(shares, receiver);\n  }\n  \n  /*\n  /// @notice Burn fxBASE shares and then convert USDC and fxUSD to another token.\n  /// @param fxusdParams The parameters to convert fxUSD to target token.\n  /// @param usdcParams The parameters to convert USDC to target token.\n  /// @param amountIn The amount of fxBASE to redeem.\n  /// @param receiver The address of token recipient.\n  function redeemFromFxBase(\n    LibRouter.ConvertOutParams memory fxusdParams,\n    LibRouter.ConvertOutParams memory usdcParams,\n    uint256 amountIn,\n    address receiver\n  ) external {\n    IERC20(fxBASE).safeTransferFrom(msg.sender, address(this), amountIn);\n    (uint256 amountFxUSD, uint256 amountUSDC) = IFxUSDBasePool(fxBASE).redeem(address(this), amountIn);\n    LibRouter.convertAndTransferOut(fxusdParams, fxUSD, amountFxUSD, receiver);\n    LibRouter.convertAndTransferOut(usdcParams, USDC, amountUSDC, receiver);\n  }\n\n  /// @notice Burn fxBASE shares from gauge and then convert USDC and fxUSD to another token.\n  /// @param fxusdParams The parameters to convert fxUSD to target token.\n  /// @param usdcParams The parameters to convert USDC to target token.\n  /// @param amountIn The amount of fxBASE to redeem.\n  /// @param receiver The address of token recipient.\n  function redeemFromFxBaseGauge(\n    LibRouter.ConvertOutParams memory fxusdParams,\n    LibRouter.ConvertOutParams memory usdcParams,\n    uint256 amountIn,\n    address receiver\n  ) external {\n    IERC20(gauge).safeTransferFrom(msg.sender, address(this), amountIn);\n    ILiquidityGauge(gauge).withdraw(amountIn);\n    (uint256 amountFxUSD, uint256 amountUSDC) = IFxUSDBasePool(fxBASE).redeem(address(this), amountIn);\n    LibRouter.convertAndTransferOut(fxusdParams, fxUSD, amountFxUSD, receiver);\n    LibRouter.convertAndTransferOut(usdcParams, USDC, amountUSDC, receiver);\n  }\n  */\n}\n"},"contracts/periphery/facets/FxUSDBasePoolV2Facet.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IFxUSDBasePool } from \"../../interfaces/IFxUSDBasePool.sol\";\nimport { IFxShareableRebalancePool } from \"../../v2/interfaces/IFxShareableRebalancePool.sol\";\nimport { IFxUSD } from \"../../v2/interfaces/IFxUSD.sol\";\nimport { ILiquidityGauge } from \"../../voting-escrow/interfaces/ILiquidityGauge.sol\";\n\nimport { WordCodec } from \"../../common/codec/WordCodec.sol\";\nimport { LibRouter } from \"../libraries/LibRouter.sol\";\n\ncontract FxUSDBasePoolV2Facet {\n  using SafeERC20 for IERC20;\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @notice The address of fxUSD token.\n  address private constant fxUSD = 0x085780639CC2cACd35E474e71f4d000e2405d8f6;\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @dev The address of `FxUSDBasePool` contract.\n  address private immutable fxBASE;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _fxBASE) {\n    fxBASE = _fxBASE;\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Migrate fxUSD from rebalance pool to fxBASE gauge.\n  /// @param pool The address of rebalance pool.\n  /// @param amountIn The amount of rebalance pool shares to migrate.\n  /// @param minShares The minimum shares should receive.\n  /// @param receiver The address of fxBASE share recipient.\n  function migrateToFxBaseGaugeV2(address pool, address gauge, uint256 amountIn, uint256 minShares, address receiver) external {\n    LibRouter.ensureWhitelisted(gauge);\n    IFxShareableRebalancePool(pool).withdrawFrom(msg.sender, amountIn, address(this));\n    address baseToken = IFxShareableRebalancePool(pool).baseToken();\n    address asset = IFxShareableRebalancePool(pool).asset();\n    LibRouter.approve(asset, fxUSD, amountIn);\n    IFxUSD(fxUSD).wrap(baseToken, amountIn, address(this));\n    LibRouter.approve(fxUSD, fxBASE, amountIn);\n    uint256 shares = IFxUSDBasePool(fxBASE).deposit(address(this), fxUSD, amountIn, minShares);\n    LibRouter.approve(fxBASE, gauge, shares);\n    ILiquidityGauge(gauge).deposit(shares, receiver);\n  }\n\n  /// @notice Deposit token to fxBase and then deposit to gauge.\n  /// @param params The parameters to convert source token to `tokenOut`.\n  /// @param tokenOut The target token, USDC or fxUSD.\n  /// @param minShares The minimum shares should receive.\n  /// @param receiver The address of gauge share recipient.\n  function depositToFxBaseGaugeV2(\n    LibRouter.ConvertInParams memory params,\n    address gauge,\n    address tokenOut,\n    uint256 minShares,\n    address receiver\n  ) external payable {\n    LibRouter.ensureWhitelisted(gauge);\n    uint256 amountIn = LibRouter.transferInAndConvert(params, tokenOut);\n    LibRouter.approve(tokenOut, fxBASE, amountIn);\n    uint256 shares = IFxUSDBasePool(fxBASE).deposit(address(this), tokenOut, amountIn, minShares);\n    LibRouter.approve(fxBASE, gauge, shares);\n    ILiquidityGauge(gauge).deposit(shares, receiver);\n  }\n}\n"},"contracts/periphery/facets/MigrateFacet.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC721 } from \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\n\nimport { IMultiPathConverter } from \"../../helpers/interfaces/IMultiPathConverter.sol\";\nimport { IBalancerVault } from \"../../interfaces/Balancer/IBalancerVault.sol\";\nimport { IPool } from \"../../interfaces/IPool.sol\";\nimport { IPoolManager } from \"../../interfaces/IPoolManager.sol\";\nimport { IFxMarketV2 } from \"../../v2/interfaces/IFxMarketV2.sol\";\nimport { IFxUSD } from \"../../v2/interfaces/IFxUSD.sol\";\n\nimport { WordCodec } from \"../../common/codec/WordCodec.sol\";\nimport { LibRouter } from \"../libraries/LibRouter.sol\";\nimport { FlashLoanFacetBase } from \"./FlashLoanFacetBase.sol\";\n\ncontract MigrateFacet is FlashLoanFacetBase {\n  using SafeERC20 for IERC20;\n  using WordCodec for bytes32;\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the amount of tokens swapped are not enough.\n  error ErrorInsufficientAmountSwapped();\n\n  /// @dev Thrown when debt ratio out of range.\n  error ErrorDebtRatioOutOfRange();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The address of USDC token.\n  address private constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;\n\n  /// @dev The address of fxUSD token.\n  address private constant fxUSD = 0x085780639CC2cACd35E474e71f4d000e2405d8f6;\n\n  /// @dev The address of wstETH market contract.\n  address private constant wstETHMarket = 0xAD9A0E7C08bc9F747dF97a3E7E7f620632CB6155;\n\n  /// @dev The address of wstETH token.\n  address private constant wstETH = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0;\n\n  /// @dev The address of fstETH token.\n  address private constant fstETH = 0xD6B8162e2fb9F3EFf09bb8598ca0C8958E33A23D;\n\n  /// @dev The address of xstETH token.\n  address private constant xstETH = 0x5a097b014C547718e79030a077A91Ae37679EfF5;\n\n  /// @dev The address of sfrxETH market contract.\n  address private constant sfrxETHMarket = 0x714B853b3bA73E439c652CfE79660F329E6ebB42;\n\n  /// @dev The address of sfrxETH token.\n  address private constant sfrxETH = 0xac3E018457B222d93114458476f3E3416Abbe38F;\n\n  /// @dev The address of ffrxETH token.\n  address private constant ffrxETH = 0xa87F04c9743Fd1933F82bdDec9692e9D97673769;\n\n  /// @dev The address of xfrxETH token.\n  address private constant xfrxETH = 0x2bb0C32101456F5960d4e994Bac183Fe0dc6C82c;\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @dev The address of `PoolManager` contract.\n  address private immutable poolManager;\n\n  /// @dev The address of `MultiPathConverter` contract.\n  address private immutable converter;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _balancer, address _poolManager, address _converter) FlashLoanFacetBase(_balancer) {\n    poolManager = _poolManager;\n    converter = _converter;\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Migrate xstETH to fx position.\n  /// @param pool The address of fx position pool.\n  /// @param positionId The index of position.\n  /// @param xTokenAmount The amount of xstETH to migrate.\n  /// @param borrowAmount The amount of USDC to borrow.\n  /// @param data The calldata passing to `onMigrateXstETHPosition` hook function.\n  function migrateXstETHPosition(\n    address pool,\n    uint256 positionId,\n    uint256 xTokenAmount,\n    uint256 borrowAmount,\n    bytes calldata data\n  ) external nonReentrant {\n    IERC20(xstETH).safeTransferFrom(msg.sender, address(this), xTokenAmount);\n    if (positionId > 0) {\n      IERC721(pool).transferFrom(msg.sender, address(this), positionId);\n    }\n\n    _invokeFlashLoan(\n      USDC,\n      borrowAmount,\n      abi.encodeCall(\n        MigrateFacet.onMigrateXstETHPosition,\n        (pool, positionId, xTokenAmount, borrowAmount, msg.sender, data)\n      )\n    );\n\n    // refund USDC to caller\n    LibRouter.refundERC20(USDC, LibRouter.routerStorage().revenuePool);\n  }\n\n  /// @notice Migrate xfrxETH to fx position.\n  /// @param pool The address of fx position pool.\n  /// @param positionId The index of position.\n  /// @param xTokenAmount The amount of xfrxETH to migrate.\n  /// @param borrowAmount The amount of USDC to borrow.\n  /// @param data The calldata passing to `onMigrateXfrxETHPosition` hook function.\n  function migrateXfrxETHPosition(\n    address pool,\n    uint256 positionId,\n    uint256 xTokenAmount,\n    uint256 borrowAmount,\n    bytes calldata data\n  ) external nonReentrant {\n    IERC20(xfrxETH).safeTransferFrom(msg.sender, address(this), xTokenAmount);\n    if (positionId > 0) {\n      IERC721(pool).transferFrom(msg.sender, address(this), positionId);\n    }\n\n    _invokeFlashLoan(\n      USDC,\n      borrowAmount,\n      abi.encodeCall(\n        MigrateFacet.onMigrateXfrxETHPosition,\n        (pool, positionId, xTokenAmount, borrowAmount, msg.sender, data)\n      )\n    );\n\n    // refund USDC to caller\n    LibRouter.refundERC20(USDC, LibRouter.routerStorage().revenuePool);\n  }\n\n  /// @notice Hook for `migrateXstETHPosition`.\n  /// @param pool The address of fx position pool.\n  /// @param positionId The index of position.\n  /// @param xTokenAmount The amount of xstETH to migrate.\n  /// @param borrowAmount The amount of USDC to borrow.\n  /// @param recipient The address of position holder.\n  /// @param data Hook data.\n  function onMigrateXstETHPosition(\n    address pool,\n    uint256 positionId,\n    uint256 xTokenAmount,\n    uint256 borrowAmount,\n    address recipient,\n    bytes memory data\n  ) external onlySelf {\n    uint256 fTokenAmount = (xTokenAmount * IERC20(fstETH).totalSupply()) / IERC20(xstETH).totalSupply();\n\n    // swap USDC to fxUSD\n    fTokenAmount = _swapUSDCToFxUSD(borrowAmount, fTokenAmount, data);\n\n    // unwrap fxUSD as fToken\n    IFxUSD(fxUSD).unwrap(wstETH, fTokenAmount, address(this));\n\n    uint256 wstETHAmount;\n    {\n      wstETHAmount = IFxMarketV2(wstETHMarket).redeemXToken(xTokenAmount, address(this), 0);\n      (uint256 baseOut, uint256 bonus) = IFxMarketV2(wstETHMarket).redeemFToken(fTokenAmount, address(this), 0);\n      wstETHAmount += baseOut + bonus;\n    }\n\n    // since we need to swap back to USDC, mint 0.1% more fxUSD to cover slippage.\n    fTokenAmount = (fTokenAmount * 1001) / 1000;\n\n    LibRouter.approve(wstETH, poolManager, wstETHAmount);\n    positionId = IPoolManager(poolManager).operate(pool, positionId, int256(wstETHAmount), int256(fTokenAmount));\n    _checkPositionDebtRatio(pool, positionId, abi.decode(data, (bytes32)));\n    IERC721(pool).transferFrom(address(this), recipient, positionId);\n\n    // swap fxUSD to USDC and pay debts\n    _swapFxUSDToUSDC(IERC20(fxUSD).balanceOf(address(this)), borrowAmount, data);\n  }\n\n  /// @notice Hook for `migrateXfrxETHPosition`.\n  /// @param pool The address of fx position pool.\n  /// @param positionId The index of position.\n  /// @param xTokenAmount The amount of xstETH to migrate.\n  /// @param borrowAmount The amount of USDC to borrow.\n  /// @param recipient The address of position holder.\n  /// @param data Hook data.\n  function onMigrateXfrxETHPosition(\n    address pool,\n    uint256 positionId,\n    uint256 xTokenAmount,\n    uint256 borrowAmount,\n    address recipient,\n    bytes memory data\n  ) external onlySelf {\n    uint256 fTokenAmount = (xTokenAmount * IERC20(ffrxETH).totalSupply()) / IERC20(xfrxETH).totalSupply();\n\n    // swap USDC to fxUSD\n    fTokenAmount = _swapUSDCToFxUSD(borrowAmount, fTokenAmount, data);\n\n    // unwrap fxUSD as fToken\n    IFxUSD(fxUSD).unwrap(sfrxETH, fTokenAmount, address(this));\n\n    uint256 wstETHAmount;\n    {\n      // redeem\n      wstETHAmount = IFxMarketV2(sfrxETHMarket).redeemXToken(xTokenAmount, address(this), 0);\n      (uint256 baseOut, uint256 bonus) = IFxMarketV2(sfrxETHMarket).redeemFToken(fTokenAmount, address(this), 0);\n      wstETHAmount += baseOut + bonus;\n      // swap sfrxETH to wstETH\n      wstETHAmount = _swapSfrxETHToWstETH(wstETHAmount, 0, data);\n    }\n\n    // since we need to swap back to USDC, mint 0.1% more fxUSD to cover slippage.\n    fTokenAmount = (fTokenAmount * 1001) / 1000;\n\n    LibRouter.approve(wstETH, poolManager, wstETHAmount);\n    positionId = IPoolManager(poolManager).operate(pool, positionId, int256(wstETHAmount), int256(fTokenAmount));\n    _checkPositionDebtRatio(pool, positionId, abi.decode(data, (bytes32)));\n    IERC721(pool).transferFrom(address(this), recipient, positionId);\n\n    // swap fxUSD to USDC and pay debts\n    _swapFxUSDToUSDC(IERC20(fxUSD).balanceOf(address(this)), borrowAmount, data);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to swap USDC to fxUSD.\n  /// @param amountUSDC The amount of USDC to use.\n  /// @param minFxUSD The minimum amount of fxUSD should receive.\n  /// @param data The swap route encoding.\n  /// @return amountFxUSD The amount of fxUSD received.\n  function _swapUSDCToFxUSD(\n    uint256 amountUSDC,\n    uint256 minFxUSD,\n    bytes memory data\n  ) internal returns (uint256 amountFxUSD) {\n    (, uint256 swapEncoding, uint256[] memory swapRoutes) = abi.decode(data, (bytes32, uint256, uint256[]));\n    return _swap(USDC, amountUSDC, minFxUSD, swapEncoding, swapRoutes);\n  }\n\n  /// @dev Internal function to swap fxUSD to USDC.\n  /// @param amountFxUSD The amount of fxUSD to use.\n  /// @param minUSDC The minimum amount of USDC should receive.\n  /// @param data The swap route encoding.\n  /// @return amountUSDC The amount of USDC received.\n  function _swapFxUSDToUSDC(\n    uint256 amountFxUSD,\n    uint256 minUSDC,\n    bytes memory data\n  ) internal returns (uint256 amountUSDC) {\n    (, , , uint256 swapEncoding, uint256[] memory swapRoutes) = abi.decode(\n      data,\n      (bytes32, uint256, uint256[], uint256, uint256[])\n    );\n    return _swap(fxUSD, amountFxUSD, minUSDC, swapEncoding, swapRoutes);\n  }\n\n  /// @dev Internal function to swap sfrxETH to wstETH.\n  /// @param amountSfrxETH The amount of sfrxETH to use.\n  /// @param minWstETH The minimum amount of wstETH should receive.\n  /// @param data The swap route encoding.\n  /// @return amountWstETH The amount of wstETH received.\n  function _swapSfrxETHToWstETH(\n    uint256 amountSfrxETH,\n    uint256 minWstETH,\n    bytes memory data\n  ) internal returns (uint256 amountWstETH) {\n    (, , , , , uint256 swapEncoding, uint256[] memory swapRoutes) = abi.decode(\n      data,\n      (bytes32, uint256, uint256[], uint256, uint256[], uint256, uint256[])\n    );\n    return _swap(sfrxETH, amountSfrxETH, minWstETH, swapEncoding, swapRoutes);\n  }\n\n  /// @dev Internal function to do swap.\n  /// @param token The address of input token.\n  /// @param amountIn The amount of input token.\n  /// @param minOut The minimum amount of output tokens should receive.\n  /// @param encoding The encoding for swap routes.\n  /// @param routes The swap routes to `MultiPathConverter`.\n  /// @return amountOut The amount of output tokens received.\n  function _swap(\n    address token,\n    uint256 amountIn,\n    uint256 minOut,\n    uint256 encoding,\n    uint256[] memory routes\n  ) internal returns (uint256 amountOut) {\n    LibRouter.approve(token, converter, amountIn);\n    amountOut = IMultiPathConverter(converter).convert(token, amountIn, encoding, routes);\n    if (amountOut < minOut) revert ErrorInsufficientAmountSwapped();\n  }\n\n  /// @dev Internal function to check debt ratio for the position.\n  /// @param pool The address of fx position pool.\n  /// @param positionId The index of the position.\n  /// @param miscData The encoded data for debt ratio range.\n  function _checkPositionDebtRatio(address pool, uint256 positionId, bytes32 miscData) internal view {\n    uint256 debtRatio = IPool(pool).getPositionDebtRatio(positionId);\n    uint256 minDebtRatio = miscData.decodeUint(0, 60);\n    uint256 maxDebtRatio = miscData.decodeUint(60, 60);\n    if (debtRatio < minDebtRatio || debtRatio > maxDebtRatio) {\n      revert ErrorDebtRatioOutOfRange();\n    }\n  }\n}\n"},"contracts/periphery/facets/MorphoFlashLoanFacetBase.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IMorpho } from \"../../interfaces/Morpho/IMorpho.sol\";\n\nimport { LibRouter } from \"../libraries/LibRouter.sol\";\n\nabstract contract MorphoFlashLoanFacetBase {\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the caller is not self.\n  error ErrorNotFromSelf();\n\n  /// @dev Unauthorized reentrant call.\n  error ReentrancyGuardReentrantCall();\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @dev The address of Morpho Blue contract.\n  /// In ethereum, it is 0xbbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb.\n  address private immutable morpho;\n\n  /*************\n   * Modifiers *\n   *************/\n\n  modifier onlySelf() {\n    if (msg.sender != address(this)) revert ErrorNotFromSelf();\n    _;\n  }\n\n  modifier onFlashLoan() {\n    LibRouter.RouterStorage storage $ = LibRouter.routerStorage();\n    $.flashLoanContext = LibRouter.HAS_FLASH_LOAN;\n    _;\n    $.flashLoanContext = LibRouter.NOT_FLASH_LOAN;\n  }\n\n  modifier nonReentrant() {\n    LibRouter.RouterStorage storage $ = LibRouter.routerStorage();\n    if ($.reentrantContext == LibRouter.HAS_ENTRANT) {\n      revert ReentrancyGuardReentrantCall();\n    }\n    $.reentrantContext = LibRouter.HAS_ENTRANT;\n    _;\n    $.reentrantContext = LibRouter.NOT_ENTRANT;\n  }\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _morpho) {\n    morpho = _morpho;\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  function _invokeFlashLoan(address token, uint256 amount, bytes memory data) internal onFlashLoan {\n    IMorpho(morpho).flashLoan(token, amount, abi.encode(token, data));\n  }\n}\n"},"contracts/periphery/facets/PositionOperateFlashLoanFacet.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC721 } from \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\n\nimport { IMultiPathConverter } from \"../../helpers/interfaces/IMultiPathConverter.sol\";\nimport { IPoolManager } from \"../../interfaces/IPoolManager.sol\";\nimport { IPool } from \"../../interfaces/IPool.sol\";\n\nimport { WordCodec } from \"../../common/codec/WordCodec.sol\";\nimport { LibRouter } from \"../libraries/LibRouter.sol\";\nimport { FlashLoanFacetBase } from \"./FlashLoanFacetBase.sol\";\n\ncontract PositionOperateFlashLoanFacet is FlashLoanFacetBase {\n  using SafeERC20 for IERC20;\n  using WordCodec for bytes32;\n\n  /**********\n   * Events *\n   **********/\n\n  event OpenOrAdd(address pool, uint256 position, address recipient, uint256 colls, uint256 debts, uint256 borrows);\n\n  event CloseOrRemove(address pool, uint256 position, address recipient, uint256 colls, uint256 debts, uint256 borrows);\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the amount of tokens swapped are not enough.\n  error ErrorInsufficientAmountSwapped();\n\n  /// @dev Thrown when debt ratio out of range.\n  error ErrorDebtRatioOutOfRange();\n\n  /*************\n   * Constants *\n   *************/\n\n  address private constant fxUSD = 0x085780639CC2cACd35E474e71f4d000e2405d8f6;\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @dev The address of `PoolManager` contract.\n  address private immutable poolManager;\n\n  /// @dev The address of `MultiPathConverter` contract.\n  address private immutable converter;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _balancer, address _poolManager, address _converter) FlashLoanFacetBase(_balancer) {\n    poolManager = _poolManager;\n    converter = _converter;\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Open a new position or add collateral to position with any tokens.\n  /// @param params The parameters to convert source token to collateral token.\n  /// @param pool The address of fx position pool.\n  /// @param positionId The index of position.\n  /// @param borrowAmount The amount of collateral token to borrow.\n  /// @param data Hook data passing to `onOpenOrAddPositionFlashLoan`.\n  function openOrAddPositionFlashLoan(\n    LibRouter.ConvertInParams memory params,\n    address pool,\n    uint256 positionId,\n    uint256 borrowAmount,\n    bytes calldata data\n  ) external payable nonReentrant {\n    uint256 amountIn = LibRouter.transferInAndConvert(params, IPool(pool).collateralToken()) + borrowAmount;\n    _invokeFlashLoan(\n      IPool(pool).collateralToken(),\n      borrowAmount,\n      abi.encodeCall(\n        PositionOperateFlashLoanFacet.onOpenOrAddPositionFlashLoan,\n        (pool, positionId, amountIn, borrowAmount, msg.sender, data)\n      )\n    );\n    // refund collateral token to caller\n    LibRouter.refundERC20(IPool(pool).collateralToken(), LibRouter.routerStorage().revenuePool);\n  }\n\n  /// @notice Close a position or remove collateral from position.\n  /// @param params The parameters to convert collateral token to target token.\n  /// @param positionId The index of position.\n  /// @param pool The address of fx position pool.\n  /// @param borrowAmount The amount of collateral token to borrow.\n  /// @param data Hook data passing to `onCloseOrRemovePositionFlashLoan`.\n  function closeOrRemovePositionFlashLoan(\n    LibRouter.ConvertOutParams memory params,\n    address pool,\n    uint256 positionId,\n    uint256 amountOut,\n    uint256 borrowAmount,\n    bytes calldata data\n  ) external nonReentrant {\n    address collateralToken = IPool(pool).collateralToken();\n\n    _invokeFlashLoan(\n      collateralToken,\n      borrowAmount,\n      abi.encodeCall(\n        PositionOperateFlashLoanFacet.onCloseOrRemovePositionFlashLoan,\n        (pool, positionId, amountOut, borrowAmount, msg.sender, data)\n      )\n    );\n\n    // convert collateral token to other token\n    amountOut = IERC20(collateralToken).balanceOf(address(this));\n    LibRouter.convertAndTransferOut(params, collateralToken, amountOut, msg.sender);\n\n    // refund rest fxUSD and leveraged token\n    LibRouter.refundERC20(fxUSD, LibRouter.routerStorage().revenuePool);\n  }\n\n  /// @notice Hook for `openOrAddPositionFlashLoan`.\n  /// @param pool The address of fx position pool.\n  /// @param position The index of position.\n  /// @param amount The amount of collateral token to supply.\n  /// @param repayAmount The amount of collateral token to repay.\n  /// @param recipient The address of position holder.\n  /// @param data Hook data passing to `onOpenOrAddPositionFlashLoan`.\n  function onOpenOrAddPositionFlashLoan(\n    address pool,\n    uint256 position,\n    uint256 amount,\n    uint256 repayAmount,\n    address recipient,\n    bytes memory data\n  ) external onlySelf {\n    (bytes32 miscData, uint256 fxUSDAmount, uint256 swapEncoding, uint256[] memory swapRoutes) = abi.decode(\n      data,\n      (bytes32, uint256, uint256, uint256[])\n    );\n\n    // open or add collateral to position\n    if (position != 0) {\n      IERC721(pool).transferFrom(recipient, address(this), position);\n    }\n    LibRouter.approve(IPool(pool).collateralToken(), poolManager, amount);\n    position = IPoolManager(poolManager).operate(pool, position, int256(amount), int256(fxUSDAmount));\n    _checkPositionDebtRatio(pool, position, miscData);\n    IERC721(pool).transferFrom(address(this), recipient, position);\n\n    emit OpenOrAdd(pool, position, recipient, amount, fxUSDAmount, repayAmount);\n\n    // swap fxUSD to collateral token\n    _swap(fxUSD, fxUSDAmount, repayAmount, swapEncoding, swapRoutes);\n  }\n\n  /// @notice Hook for `closeOrRemovePositionFlashLoan`.\n  /// @param pool The address of fx position pool.\n  /// @param position The index of position.\n  /// @param amount The amount of collateral token to withdraw.\n  /// @param repayAmount The amount of collateral token to repay.\n  /// @param recipient The address of position holder.\n  /// @param data Hook data passing to `onCloseOrRemovePositionFlashLoan`.\n  function onCloseOrRemovePositionFlashLoan(\n    address pool,\n    uint256 position,\n    uint256 amount,\n    uint256 repayAmount,\n    address recipient,\n    bytes memory data\n  ) external onlySelf {\n    (bytes32 miscData, uint256 fxUSDAmount, uint256 swapEncoding, uint256[] memory swapRoutes) = abi.decode(\n      data,\n      (bytes32, uint256, uint256, uint256[])\n    );\n\n    // swap collateral token to fxUSD\n    _swap(IPool(pool).collateralToken(), repayAmount, fxUSDAmount, swapEncoding, swapRoutes);\n\n    // close or remove collateral from position\n    IERC721(pool).transferFrom(recipient, address(this), position);\n    (, uint256 maxFxUSD) = IPool(pool).getPosition(position);\n    if (fxUSDAmount >= maxFxUSD) {\n      // close entire position\n      IPoolManager(poolManager).operate(pool, position, type(int256).min, type(int256).min);\n    } else {\n      IPoolManager(poolManager).operate(pool, position, -int256(amount), -int256(fxUSDAmount));\n      _checkPositionDebtRatio(pool, position, miscData);\n    }\n    IERC721(pool).transferFrom(address(this), recipient, position);\n\n    emit CloseOrRemove(pool, position, recipient, amount, fxUSDAmount, repayAmount);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to do swap.\n  /// @param token The address of input token.\n  /// @param amountIn The amount of input token.\n  /// @param minOut The minimum amount of output tokens should receive.\n  /// @param encoding The encoding for swap routes.\n  /// @param routes The swap routes to `MultiPathConverter`.\n  /// @return amountOut The amount of output tokens received.\n  function _swap(\n    address token,\n    uint256 amountIn,\n    uint256 minOut,\n    uint256 encoding,\n    uint256[] memory routes\n  ) internal returns (uint256 amountOut) {\n    if (amountIn == 0) return 0;\n\n    LibRouter.approve(token, converter, amountIn);\n    amountOut = IMultiPathConverter(converter).convert(token, amountIn, encoding, routes);\n    if (amountOut < minOut) revert ErrorInsufficientAmountSwapped();\n  }\n\n  /// @dev Internal function to check debt ratio for the position.\n  /// @param pool The address of fx position pool.\n  /// @param positionId The index of the position.\n  /// @param miscData The encoded data for debt ratio range.\n  function _checkPositionDebtRatio(address pool, uint256 positionId, bytes32 miscData) internal view {\n    uint256 debtRatio = IPool(pool).getPositionDebtRatio(positionId);\n    uint256 minDebtRatio = miscData.decodeUint(0, 60);\n    uint256 maxDebtRatio = miscData.decodeUint(60, 60);\n    if (debtRatio < minDebtRatio || debtRatio > maxDebtRatio) {\n      revert ErrorDebtRatioOutOfRange();\n    }\n  }\n}\n"},"contracts/periphery/facets/PositionOperateFlashLoanFacetV2.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport { IERC721 } from \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\n\nimport { IMultiPathConverter } from \"../../helpers/interfaces/IMultiPathConverter.sol\";\nimport { IPoolManager } from \"../../interfaces/IPoolManager.sol\";\nimport { IPool } from \"../../interfaces/IPool.sol\";\n\nimport { WordCodec } from \"../../common/codec/WordCodec.sol\";\nimport { LibRouter } from \"../libraries/LibRouter.sol\";\nimport { MorphoFlashLoanFacetBase } from \"./MorphoFlashLoanFacetBase.sol\";\n\ncontract PositionOperateFlashLoanFacetV2 is MorphoFlashLoanFacetBase {\n  using EnumerableSet for EnumerableSet.AddressSet;\n  using SafeERC20 for IERC20;\n  using WordCodec for bytes32;\n\n  /**********\n   * Events *\n   **********/\n\n  event OpenOrAdd(address pool, uint256 position, address recipient, uint256 colls, uint256 debts, uint256 borrows);\n\n  event CloseOrRemove(address pool, uint256 position, address recipient, uint256 colls, uint256 debts, uint256 borrows);\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the amount of tokens swapped are not enough.\n  error ErrorInsufficientAmountSwapped();\n\n  /// @dev Thrown when debt ratio out of range.\n  error ErrorDebtRatioOutOfRange();\n\n  /*************\n   * Constants *\n   *************/\n\n  address private constant fxUSD = 0x085780639CC2cACd35E474e71f4d000e2405d8f6;\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @dev The address of `PoolManager` contract.\n  address private immutable poolManager;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _morpho, address _poolManager) MorphoFlashLoanFacetBase(_morpho) {\n    poolManager = _poolManager;\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Open a new position or add collateral to position with any tokens.\n  /// @param params The parameters to convert source token to collateral token.\n  /// @param pool The address of fx position pool.\n  /// @param positionId The index of position.\n  /// @param borrowAmount The amount of collateral token to borrow.\n  /// @param data Hook data passing to `onOpenOrAddPositionFlashLoan`.\n  function openOrAddPositionFlashLoanV2(\n    LibRouter.ConvertInParams memory params,\n    address pool,\n    uint256 positionId,\n    uint256 borrowAmount,\n    bytes calldata data\n  ) external payable nonReentrant {\n    uint256 amountIn = LibRouter.transferInAndConvert(params, IPool(pool).collateralToken()) + borrowAmount;\n    _invokeFlashLoan(\n      IPool(pool).collateralToken(),\n      borrowAmount,\n      abi.encodeCall(\n        PositionOperateFlashLoanFacetV2.onOpenOrAddPositionFlashLoanV2,\n        (pool, positionId, amountIn, borrowAmount, msg.sender, data)\n      )\n    );\n    // transfer extra collateral token to revenue pool\n    LibRouter.refundERC20(IPool(pool).collateralToken(), LibRouter.routerStorage().revenuePool);\n  }\n\n  /// @notice Close a position or remove collateral from position.\n  /// @param params The parameters to convert collateral token to target token.\n  /// @param positionId The index of position.\n  /// @param pool The address of fx position pool.\n  /// @param borrowAmount The amount of collateral token to borrow.\n  /// @param data Hook data passing to `onCloseOrRemovePositionFlashLoan`.\n  function closeOrRemovePositionFlashLoanV2(\n    LibRouter.ConvertOutParams memory params,\n    address pool,\n    uint256 positionId,\n    uint256 amountOut,\n    uint256 borrowAmount,\n    bytes calldata data\n  ) external nonReentrant {\n    address collateralToken = IPool(pool).collateralToken();\n\n    _invokeFlashLoan(\n      collateralToken,\n      borrowAmount,\n      abi.encodeCall(\n        PositionOperateFlashLoanFacetV2.onCloseOrRemovePositionFlashLoanV2,\n        (pool, positionId, amountOut, borrowAmount, msg.sender, data)\n      )\n    );\n\n    // convert collateral token to other token\n    amountOut = IERC20(collateralToken).balanceOf(address(this));\n    LibRouter.convertAndTransferOut(params, collateralToken, amountOut, msg.sender);\n\n    // transfer extra fxUSD to revenue pool\n    LibRouter.refundERC20(fxUSD, LibRouter.routerStorage().revenuePool);\n  }\n\n  /// @notice Hook for `openOrAddPositionFlashLoan`.\n  /// @param pool The address of fx position pool.\n  /// @param position The index of position.\n  /// @param amount The amount of collateral token to supply.\n  /// @param repayAmount The amount of collateral token to repay.\n  /// @param recipient The address of position holder.\n  /// @param data Hook data passing to `onOpenOrAddPositionFlashLoan`.\n  function onOpenOrAddPositionFlashLoanV2(\n    address pool,\n    uint256 position,\n    uint256 amount,\n    uint256 repayAmount,\n    address recipient,\n    bytes memory data\n  ) external onlySelf {\n    (bytes32 miscData, uint256 fxUSDAmount, address swapTarget, bytes memory swapData) = abi.decode(\n      data,\n      (bytes32, uint256, address, bytes)\n    );\n\n    // open or add collateral to position\n    if (position != 0) {\n      IERC721(pool).transferFrom(recipient, address(this), position);\n    }\n    LibRouter.approve(IPool(pool).collateralToken(), poolManager, amount);\n    position = IPoolManager(poolManager).operate(pool, position, int256(amount), int256(fxUSDAmount));\n    _checkPositionDebtRatio(pool, position, miscData);\n    IERC721(pool).transferFrom(address(this), recipient, position);\n\n    emit OpenOrAdd(pool, position, recipient, amount, fxUSDAmount, repayAmount);\n\n    // swap fxUSD to collateral token\n    _swap(fxUSD, IPool(pool).collateralToken(), fxUSDAmount, repayAmount, swapTarget, swapData);\n  }\n\n  /// @notice Hook for `closeOrRemovePositionFlashLoan`.\n  /// @param pool The address of fx position pool.\n  /// @param position The index of position.\n  /// @param amount The amount of collateral token to withdraw.\n  /// @param borrowAmount The amount of collateral token borrowed.\n  /// @param recipient The address of position holder.\n  /// @param data Hook data passing to `onCloseOrRemovePositionFlashLoan`.\n  function onCloseOrRemovePositionFlashLoanV2(\n    address pool,\n    uint256 position,\n    uint256 amount,\n    uint256 borrowAmount,\n    address recipient,\n    bytes memory data\n  ) external onlySelf {\n    (bytes32 miscData, uint256 fxUSDAmount, address swapTarget, bytes memory swapData) = abi.decode(\n      data,\n      (bytes32, uint256, address, bytes)\n    );\n\n    // swap collateral token to fxUSD\n    _swap(IPool(pool).collateralToken(), fxUSD, borrowAmount, fxUSDAmount, swapTarget, swapData);\n\n    // close or remove collateral from position\n    IERC721(pool).transferFrom(recipient, address(this), position);\n    (, uint256 maxFxUSD) = IPool(pool).getPosition(position);\n    if (fxUSDAmount >= maxFxUSD) {\n      // close entire position\n      IPoolManager(poolManager).operate(pool, position, type(int256).min, type(int256).min);\n    } else {\n      IPoolManager(poolManager).operate(pool, position, -int256(amount), -int256(fxUSDAmount));\n      _checkPositionDebtRatio(pool, position, miscData);\n    }\n    IERC721(pool).transferFrom(address(this), recipient, position);\n\n    emit CloseOrRemove(pool, position, recipient, amount, fxUSDAmount, borrowAmount);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to do swap.\n  /// @param tokenIn The address of input token.\n  /// @param tokenOut The address of output token.\n  /// @param amountIn The amount of input token.\n  /// @param minOut The minimum amount of output tokens should receive.\n  /// @param swapTarget The address of target contract used for swap.\n  /// @param swapData The calldata passed to target contract.\n  /// @return amountOut The amount of output tokens received.\n  function _swap(\n    address tokenIn,\n    address tokenOut,\n    uint256 amountIn,\n    uint256 minOut,\n    address swapTarget,\n    bytes memory swapData\n  ) internal returns (uint256 amountOut) {\n    if (amountIn == 0) return 0;\n\n    LibRouter.RouterStorage storage $ = LibRouter.routerStorage();\n    if (!$.approvedTargets.contains(swapTarget)) {\n      revert LibRouter.ErrorTargetNotApproved();\n    }\n    address spender = $.spenders[swapTarget];\n    if (spender == address(0)) spender = swapTarget;\n    LibRouter.approve(tokenIn, spender, amountIn);\n\n    amountOut = IERC20(tokenOut).balanceOf(address(this));\n    (bool success, ) = swapTarget.call(swapData);\n    // below lines will propagate inner error up\n    if (!success) {\n      // solhint-disable-next-line no-inline-assembly\n      assembly {\n        let ptr := mload(0x40)\n        let size := returndatasize()\n        returndatacopy(ptr, 0, size)\n        revert(ptr, size)\n      }\n    }\n    amountOut = IERC20(tokenOut).balanceOf(address(this)) - amountOut;\n\n    if (amountOut < minOut) revert ErrorInsufficientAmountSwapped();\n  }\n\n  /// @dev Internal function to check debt ratio for the position.\n  /// @param pool The address of fx position pool.\n  /// @param positionId The index of the position.\n  /// @param miscData The encoded data for debt ratio range.\n  function _checkPositionDebtRatio(address pool, uint256 positionId, bytes32 miscData) internal view {\n    uint256 debtRatio = IPool(pool).getPositionDebtRatio(positionId);\n    uint256 minDebtRatio = miscData.decodeUint(0, 60);\n    uint256 maxDebtRatio = miscData.decodeUint(60, 60);\n    if (debtRatio < minDebtRatio || debtRatio > maxDebtRatio) {\n      revert ErrorDebtRatioOutOfRange();\n    }\n  }\n}\n"},"contracts/periphery/facets/SavingFxUSDFacet.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IERC4626 } from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { IFxUSDBasePool } from \"../../interfaces/IFxUSDBasePool.sol\";\nimport { ISavingFxUSD } from \"../../interfaces/ISavingFxUSD.sol\";\nimport { IFxShareableRebalancePool } from \"../../v2/interfaces/IFxShareableRebalancePool.sol\";\nimport { IFxUSD } from \"../../v2/interfaces/IFxUSD.sol\";\nimport { ILiquidityGauge } from \"../../voting-escrow/interfaces/ILiquidityGauge.sol\";\n\nimport { WordCodec } from \"../../common/codec/WordCodec.sol\";\nimport { LibRouter } from \"../libraries/LibRouter.sol\";\n\ncontract SavingFxUSDFacet {\n  using SafeERC20 for IERC20;\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @notice The address of USDC token.\n  address private constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;\n\n  /// @notice The address of fxUSD token.\n  address private constant fxUSD = 0x085780639CC2cACd35E474e71f4d000e2405d8f6;\n\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @dev The address of `FxUSDBasePool` contract.\n  address private immutable fxBASE;\n\n  /// @dev The address of `SavingFxUSD` contract.\n  address private immutable fxSAVE;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _fxBASE, address _fxSAVE) {\n    fxBASE = _fxBASE;\n    fxSAVE = _fxSAVE;\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Deposit token to fxSAVE.\n  /// @param params The parameters to convert source token to `tokenOut`.\n  /// @param tokenOut The target token, USDC or fxUSD.\n  /// @param minShares The minimum shares should receive.\n  /// @param receiver The address of fxSAVE share recipient.\n  function depositToFxSave(\n    LibRouter.ConvertInParams memory params,\n    address tokenOut,\n    uint256 minShares,\n    address receiver\n  ) external payable {\n    uint256 amountIn = LibRouter.transferInAndConvert(params, tokenOut);\n    LibRouter.approve(tokenOut, fxBASE, amountIn);\n    uint256 shares = IFxUSDBasePool(fxBASE).deposit(address(this), tokenOut, amountIn, minShares);\n    LibRouter.approve(fxBASE, fxSAVE, shares);\n    IERC4626(fxSAVE).deposit(shares, receiver);\n  }\n\n  /// @notice Burn fxSave shares and then convert USDC and fxUSD to another token.\n  /// @param fxusdParams The parameters to convert fxUSD to target token.\n  /// @param usdcParams The parameters to convert USDC to target token.\n  /// @param receiver The address of token recipient.\n  function redeemFromFxSave(\n    LibRouter.ConvertOutParams memory fxusdParams,\n    LibRouter.ConvertOutParams memory usdcParams,\n    address receiver\n  ) external {\n    ISavingFxUSD(fxSAVE).claimFor(msg.sender, address(this));\n    uint256 amountFxUSD = IERC20(fxUSD).balanceOf(address(this));\n    uint256 amountUSDC = IERC20(USDC).balanceOf(address(this));\n    LibRouter.convertAndTransferOut(fxusdParams, fxUSD, amountFxUSD, receiver);\n    LibRouter.convertAndTransferOut(usdcParams, USDC, amountUSDC, receiver);\n  }\n\n  /// @notice Burn fxSave shares and then convert USDC and fxUSD to another token instantly.\n  /// @param fxusdParams The parameters to convert fxUSD to target token.\n  /// @param usdcParams The parameters to convert USDC to target token.\n  /// @param receiver The address of token recipient.\n  function instantRedeemFromFxSave(\n    LibRouter.ConvertOutParams memory fxusdParams,\n    LibRouter.ConvertOutParams memory usdcParams,\n    uint256 shares,\n    address receiver\n  ) external {\n    uint256 assets = IERC4626(fxSAVE).redeem(shares, address(this), msg.sender);\n    (uint256 amountFxUSD, uint256 amountUSDC) = IFxUSDBasePool(fxBASE).instantRedeem(address(this), assets);\n    LibRouter.convertAndTransferOut(fxusdParams, fxUSD, amountFxUSD, receiver);\n    LibRouter.convertAndTransferOut(usdcParams, USDC, amountUSDC, receiver);\n  }\n}\n"},"contracts/periphery/libraries/LibRouter.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { IMultiPathConverter } from \"../../helpers/interfaces/IMultiPathConverter.sol\";\nimport { IWrappedEther } from \"../../interfaces/IWrappedEther.sol\";\n\nlibrary LibRouter {\n  using SafeERC20 for IERC20;\n  using EnumerableSet for EnumerableSet.AddressSet;\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when use unapproved target contract.\n  error ErrorTargetNotApproved();\n\n  /// @dev Thrown when msg.value is different from amount.\n  error ErrorMsgValueMismatch();\n\n  /// @dev Thrown when the output token is not enough.\n  error ErrorInsufficientOutput();\n\n  /// @dev Thrown when the whitelisted account type is incorrect.\n  error ErrorNotWhitelisted();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The storage slot for router storage.\n  bytes32 private constant ROUTER_STORAGE_SLOT = keccak256(\"diamond.router.storage\");\n\n  /// @dev The address of WETH token.\n  address internal constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n\n  uint8 internal constant NOT_FLASH_LOAN = 0;\n\n  uint8 internal constant HAS_FLASH_LOAN = 1;\n\n  uint8 internal constant NOT_ENTRANT = 0;\n\n  uint8 internal constant HAS_ENTRANT = 1;\n\n  /***********\n   * Structs *\n   ***********/\n\n  /// @param spenders Mapping from target address to token spender address.\n  /// @param approvedTargets The list of approved target contracts.\n  /// @param whitelisted The list of whitelisted contracts.\n  struct RouterStorage {\n    mapping(address => address) spenders;\n    EnumerableSet.AddressSet approvedTargets;\n    EnumerableSet.AddressSet whitelisted;\n    address revenuePool;\n    uint8 flashLoanContext;\n    uint8 reentrantContext;\n  }\n\n  /// @notice The struct for input token convert parameters.\n  ///\n  /// @param tokenIn The address of source token.\n  /// @param amount The amount of source token.\n  /// @param target The address of converter contract.\n  /// @param data The calldata passing to the target contract.\n  /// @param minOut The minimum amount of output token should receive.\n  /// @param signature The optional data for future usage.\n  struct ConvertInParams {\n    address tokenIn;\n    uint256 amount;\n    address target;\n    bytes data;\n    uint256 minOut;\n    bytes signature;\n  }\n\n  /// @notice The struct for output token convert parameters.\n  /// @param tokenOut The address of output token.\n  /// @param converter The address of converter contract.\n  /// @param encodings The encodings for `MultiPathConverter`.\n  /// @param minOut The minimum amount of output token should receive.\n  /// @param routes The convert route encodings.\n  /// @param signature The optional data for future usage.\n  struct ConvertOutParams {\n    address tokenOut;\n    address converter;\n    uint256 encodings;\n    uint256[] routes;\n    uint256 minOut;\n    bytes signature;\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Return the RouterStorage reference.\n  function routerStorage() internal pure returns (RouterStorage storage gs) {\n    bytes32 position = ROUTER_STORAGE_SLOT;\n    assembly {\n      gs.slot := position\n    }\n  }\n\n  /// @dev Approve contract to be used in token converting.\n  function approveTarget(address target, address spender) internal {\n    RouterStorage storage $ = routerStorage();\n\n    if ($.approvedTargets.add(target) && target != spender) {\n      $.spenders[target] = spender;\n    }\n  }\n\n  /// @dev Remove approve contract in token converting.\n  function removeTarget(address target) internal {\n    RouterStorage storage $ = routerStorage();\n\n    if ($.approvedTargets.remove(target)) {\n      delete $.spenders[target];\n    }\n  }\n\n  /// @dev Whitelist account with type.\n  function updateWhitelist(address account, bool status) internal {\n    RouterStorage storage $ = routerStorage();\n\n    if (status) {\n      $.whitelisted.add(account);\n    } else {\n      $.whitelisted.remove(account);\n    }\n  }\n\n  /// @dev Check whether the account is whitelisted with specific type.\n  function ensureWhitelisted(address account) internal view {\n    RouterStorage storage $ = routerStorage();\n    if (!$.whitelisted.contains(account)) {\n      revert ErrorNotWhitelisted();\n    }\n  }\n\n  function updateRevenuePool(address revenuePool) internal {\n    RouterStorage storage $ = routerStorage();\n    $.revenuePool = revenuePool;\n  }\n\n  /// @dev Transfer token into this contract and convert to `tokenOut`.\n  /// @param params The parameters used in token converting.\n  /// @param tokenOut The address of final converted token.\n  /// @return amountOut The amount of token received.\n  function transferInAndConvert(ConvertInParams memory params, address tokenOut) internal returns (uint256 amountOut) {\n    RouterStorage storage $ = routerStorage();\n    if (!$.approvedTargets.contains(params.target)) {\n      revert ErrorTargetNotApproved();\n    }\n\n    transferTokenIn(params.tokenIn, address(this), params.amount);\n\n    amountOut = IERC20(tokenOut).balanceOf(address(this));\n    if (params.tokenIn == tokenOut) return amountOut;\n\n    bool _success;\n    if (params.tokenIn == address(0)) {\n      (_success, ) = params.target.call{ value: params.amount }(params.data);\n    } else {\n      address _spender = $.spenders[params.target];\n      if (_spender == address(0)) _spender = params.target;\n\n      approve(params.tokenIn, _spender, params.amount);\n      (_success, ) = params.target.call(params.data);\n    }\n\n    // below lines will propagate inner error up\n    if (!_success) {\n      // solhint-disable-next-line no-inline-assembly\n      assembly {\n        let ptr := mload(0x40)\n        let size := returndatasize()\n        returndatacopy(ptr, 0, size)\n        revert(ptr, size)\n      }\n    }\n\n    amountOut = IERC20(tokenOut).balanceOf(address(this)) - amountOut;\n  }\n\n  /// @dev Convert `tokenIn` to other token and transfer out.\n  /// @param params The parameters used in token converting.\n  /// @param tokenIn The address of token to convert.\n  /// @param amountIn The amount of token to convert.\n  /// @return amountOut The amount of token received.\n  function convertAndTransferOut(\n    ConvertOutParams memory params,\n    address tokenIn,\n    uint256 amountIn,\n    address receiver\n  ) internal returns (uint256 amountOut) {\n    RouterStorage storage $ = routerStorage();\n    if (!$.approvedTargets.contains(params.converter)) {\n      revert ErrorTargetNotApproved();\n    }\n    if (amountIn == 0) return 0;\n\n    amountOut = amountIn;\n    if (params.routes.length > 0) {\n      approve(tokenIn, params.converter, amountIn);\n      amountOut = IMultiPathConverter(params.converter).convert(tokenIn, amountIn, params.encodings, params.routes);\n    }\n    if (amountOut < params.minOut) revert ErrorInsufficientOutput();\n    if (params.tokenOut == address(0)) {\n      IWrappedEther(WETH).withdraw(amountOut);\n      Address.sendValue(payable(receiver), amountOut);\n    } else {\n      IERC20(params.tokenOut).safeTransfer(receiver, amountOut);\n    }\n  }\n\n  /// @dev Internal function to transfer token to this contract.\n  /// @param token The address of token to transfer.\n  /// @param amount The amount of token to transfer.\n  /// @return uint256 The amount of token transferred.\n  function transferTokenIn(address token, address receiver, uint256 amount) internal returns (uint256) {\n    if (token == address(0)) {\n      if (msg.value != amount) revert ErrorMsgValueMismatch();\n    } else {\n      IERC20(token).safeTransferFrom(msg.sender, receiver, amount);\n    }\n    return amount;\n  }\n\n  /// @dev Internal function to refund extra token.\n  /// @param token The address of token to refund.\n  /// @param recipient The address of the token receiver.\n  function refundERC20(address token, address recipient) internal {\n    uint256 _balance = IERC20(token).balanceOf(address(this));\n    if (_balance > 0) {\n      IERC20(token).safeTransfer(recipient, _balance);\n    }\n  }\n\n  /// @dev Internal function to approve token.\n  function approve(address token, address spender, uint256 amount) internal {\n    IERC20(token).forceApprove(spender, amount);\n  }\n}\n"},"contracts/price-oracle/BTCDerivativeOracleBase.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { Math } from \"@openzeppelin/contracts-v4/utils/math/Math.sol\";\n\nimport { SpotPriceOracleBase } from \"./SpotPriceOracleBase.sol\";\n\nimport { IPriceOracle } from \"./interfaces/IPriceOracle.sol\";\n\nabstract contract BTCDerivativeOracleBase is SpotPriceOracleBase, IPriceOracle {\n  /*************\n   * Constants *\n   *************/\n\n  /// @notice The Chainlink BTC/USD price feed.\n  /// @dev See comments of `_readSpotPriceByChainlink` for more details.\n  bytes32 public immutable Chainlink_BTC_USD_Spot;\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @dev The encodings for BTCDerivative/USD spot sources.\n  bytes private onchainSpotEncodings_BTCDerivativeUSD;\n\n  /// @notice The value of maximum price deviation, multiplied by 1e18.\n  uint256 public maxPriceDeviation;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(bytes32 _Chainlink_BTC_USD_Spot) {\n    Chainlink_BTC_USD_Spot = _Chainlink_BTC_USD_Spot;\n\n    _updateMaxPriceDeviation(1e16); // 1%\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the BTCDerivative/USD spot prices.\n  /// @return prices The list of spot price among all available sources, multiplied by 1e18.\n  function getBTCDerivativeUSDSpotPrices() public view returns (uint256[] memory prices) {\n    prices = _getSpotPriceByEncoding(onchainSpotEncodings_BTCDerivativeUSD);\n  }\n\n  /// @notice Return the BTCDerivative/USD anchor price, the price that is hard to manipulate in single tx.\n  /// @return price The anchor price, multiplied by 1e18.\n  function getBTCDerivativeUSDAnchorPrice(bool isRedeem) external view returns (uint256 price) {\n    price = _getBTCDerivativeUSDAnchorPrice(isRedeem);\n  }\n\n  /// @inheritdoc IPriceOracle\n  /// @dev The price is valid iff |maxPrice-minPrice|/minPrice < maxPriceDeviation\n  function getPrice() external view override returns (uint256 anchorPrice, uint256 minPrice, uint256 maxPrice) {\n    anchorPrice = _getBTCDerivativeUSDAnchorPrice(false);\n    (minPrice, maxPrice) = _getBTCDerivativeMinMaxPrice(anchorPrice);\n\n    uint256 cachedMaxPriceDeviation = maxPriceDeviation; // gas saving\n    // use anchor price when the price deviation between anchor price and min price exceed threshold\n    if ((anchorPrice - minPrice) * PRECISION > cachedMaxPriceDeviation * minPrice) {\n      minPrice = anchorPrice;\n    }\n\n    // use anchor price when the price deviation between anchor price and max price exceed threshold\n    if ((maxPrice - anchorPrice) * PRECISION > cachedMaxPriceDeviation * anchorPrice) {\n      maxPrice = anchorPrice;\n    }\n  }\n\n  /// @inheritdoc IPriceOracle\n  function getExchangePrice() public view returns (uint256) {\n    uint256 anchorPrice = _getBTCDerivativeUSDAnchorPrice(false);\n    (uint256 minPrice, ) = _getBTCDerivativeMinMaxPrice(anchorPrice);\n    // use anchor price when the price deviation between anchor price and min price exceed threshold\n    if ((anchorPrice - minPrice) * PRECISION > maxPriceDeviation * minPrice) {\n      minPrice = anchorPrice;\n    }\n    return minPrice;\n  }\n\n  /// @inheritdoc IPriceOracle\n  function getLiquidatePrice() external view returns (uint256) {\n    return getExchangePrice();\n  }\n\n  /// @inheritdoc IPriceOracle\n  function getRedeemPrice() external view returns (uint256) {\n    uint256 anchorPrice = _getBTCDerivativeUSDAnchorPrice(true);\n    (, uint256 maxPrice) = _getBTCDerivativeMinMaxPrice(anchorPrice);\n\n    // use anchor price when the price deviation between anchor price and max price exceed threshold\n    if ((maxPrice - anchorPrice) * PRECISION > maxPriceDeviation * anchorPrice) {\n      maxPrice = anchorPrice;\n    }\n    return maxPrice;\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Update the on-chain spot encodings.\n  /// @param encodings The encodings to update. See `_getSpotPriceByEncoding` for more details.\n  function updateOnchainSpotEncodings(bytes memory encodings) external onlyOwner {\n    // validate encoding\n    uint256[] memory prices = _getSpotPriceByEncoding(encodings);\n    if (prices.length == 0) revert();\n\n    onchainSpotEncodings_BTCDerivativeUSD = encodings;\n  }\n\n  /// @notice Update the value of maximum price deviation.\n  /// @param newMaxPriceDeviation The new value of maximum price deviation, multiplied by 1e18.\n  function updateMaxPriceDeviation(uint256 newMaxPriceDeviation) external onlyOwner {\n    _updateMaxPriceDeviation(newMaxPriceDeviation);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to update the value of maximum price deviation.\n  /// @param newMaxPriceDeviation The new value of maximum price deviation, multiplied by 1e18.\n  function _updateMaxPriceDeviation(uint256 newMaxPriceDeviation) private {\n    uint256 oldMaxPriceDeviation = maxPriceDeviation;\n    if (oldMaxPriceDeviation == newMaxPriceDeviation) {\n      revert ErrorParameterUnchanged();\n    }\n\n    maxPriceDeviation = newMaxPriceDeviation;\n\n    emit UpdateMaxPriceDeviation(oldMaxPriceDeviation, newMaxPriceDeviation);\n  }\n\n  /// @dev Internal function to return the min/max BTCDerivative/USD prices.\n  /// @param anchorPrice The BTCDerivative/USD anchor price, multiplied by 1e18.\n  /// @return minPrice The minimum price among all available sources (including anchor price), multiplied by 1e18.\n  /// @return maxPrice The maximum price among all available sources (including anchor price), multiplied by 1e18.\n  function _getBTCDerivativeMinMaxPrice(\n    uint256 anchorPrice\n  ) internal view returns (uint256 minPrice, uint256 maxPrice) {\n    minPrice = maxPrice = anchorPrice;\n    uint256[] memory BTCDerivative_USD_prices = getBTCDerivativeUSDSpotPrices();\n\n    uint256 length = BTCDerivative_USD_prices.length;\n    for (uint256 i = 0; i < length; i++) {\n      uint256 price = BTCDerivative_USD_prices[i];\n      if (price > maxPrice) maxPrice = price;\n      if (price < minPrice) minPrice = price;\n    }\n  }\n\n  /// @dev Internal function to return the BTCDerivative/USD anchor price.\n  /// @return price The anchor price of BTCDerivative/USD, multiplied by 1e18.\n  function _getBTCDerivativeUSDAnchorPrice(bool isRedeem) internal view virtual returns (uint256 price);\n}\n"},"contracts/price-oracle/ETHPriceOracle.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nimport { SpotPriceOracleBase } from \"./SpotPriceOracleBase.sol\";\n\nimport { IPriceOracle } from \"./interfaces/IPriceOracle.sol\";\nimport { ITwapOracle } from \"./interfaces/ITwapOracle.sol\";\n\ncontract ETHPriceOracle is SpotPriceOracleBase, IPriceOracle {\n  /*************\n   * Constants *\n   *************/\n\n  /// @notice The Chainlink ETH/USD price feed.\n  /// @dev See comments of `_readSpotPriceByChainlink` for more details.\n  bytes32 public immutable Chainlink_ETH_USD_Spot;\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @dev The encodings for ETH/USD spot sources.\n  bytes private onchainSpotEncodings_ETHUSD;\n\n  /// @notice The value of maximum price deviation, multiplied by 1e18.\n  uint256 public maxPriceDeviation;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _spotPriceOracle, bytes32 _Chainlink_ETH_USD_Spot) SpotPriceOracleBase(_spotPriceOracle) {\n    Chainlink_ETH_USD_Spot = _Chainlink_ETH_USD_Spot;\n\n    _updateMaxPriceDeviation(1e16); // 1%\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the ETH/USD spot price.\n  /// @return chainlinkPrice The spot price from Chainlink price feed.\n  /// @return minPrice The minimum spot price among all available sources.\n  /// @return maxPrice The maximum spot price among all available sources.\n  function getETHUSDSpotPrice() external view returns (uint256 chainlinkPrice, uint256 minPrice, uint256 maxPrice) {\n    (chainlinkPrice, minPrice, maxPrice) = _getETHUSDSpotPrice();\n  }\n\n  /// @notice Return the ETH/USD spot prices.\n  /// @return prices The list of spot price among all available sources, multiplied by 1e18.\n  function getETHUSDSpotPrices() external view returns (uint256[] memory prices) {\n    prices = _getSpotPriceByEncoding(onchainSpotEncodings_ETHUSD);\n  }\n\n  /// @inheritdoc IPriceOracle\n  /// @dev The price is valid iff |maxPrice-minPrice|/minPrice < maxPriceDeviation\n  function getPrice() public view override returns (uint256 anchorPrice, uint256 minPrice, uint256 maxPrice) {\n    (anchorPrice, minPrice, maxPrice) = _getETHUSDSpotPrice();\n\n    uint256 cachedMaxPriceDeviation = maxPriceDeviation; // gas saving\n    // use anchor price when the price deviation between anchor price and min price exceed threshold\n    if ((anchorPrice - minPrice) * PRECISION > cachedMaxPriceDeviation * minPrice) {\n      minPrice = anchorPrice;\n    }\n\n    // use anchor price when the price deviation between anchor price and max price exceed threshold\n    if ((maxPrice - anchorPrice) * PRECISION > cachedMaxPriceDeviation * anchorPrice) {\n      maxPrice = anchorPrice;\n    }\n  }\n\n  /// @inheritdoc IPriceOracle\n  function getExchangePrice() public view returns (uint256) {\n    (, uint256 price, ) = getPrice();\n    return price;\n  }\n\n  /// @inheritdoc IPriceOracle\n  function getLiquidatePrice() external view returns (uint256) {\n    return getExchangePrice();\n  }\n\n  /// @inheritdoc IPriceOracle\n  function getRedeemPrice() external view returns (uint256) {\n    (, , uint256 price) = getPrice();\n    return price;\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Update the on-chain spot encodings.\n  /// @param encodings The encodings to update. See `_getSpotPriceByEncoding` for more details.\n  function updateOnchainSpotEncodings(bytes memory encodings) external onlyOwner {\n    // validate encoding\n    _getSpotPriceByEncoding(encodings);\n\n    onchainSpotEncodings_ETHUSD = encodings;\n  }\n\n  /// @notice Update the value of maximum price deviation.\n  /// @param newMaxPriceDeviation The new value of maximum price deviation, multiplied by 1e18.\n  function updateMaxPriceDeviation(uint256 newMaxPriceDeviation) external onlyOwner {\n    _updateMaxPriceDeviation(newMaxPriceDeviation);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to update the value of maximum price deviation.\n  /// @param newMaxPriceDeviation The new value of maximum price deviation, multiplied by 1e18.\n  function _updateMaxPriceDeviation(uint256 newMaxPriceDeviation) private {\n    uint256 oldMaxPriceDeviation = maxPriceDeviation;\n    if (oldMaxPriceDeviation == newMaxPriceDeviation) {\n      revert ErrorParameterUnchanged();\n    }\n\n    maxPriceDeviation = newMaxPriceDeviation;\n\n    emit UpdateMaxPriceDeviation(oldMaxPriceDeviation, newMaxPriceDeviation);\n  }\n\n  /// @dev Internal function to calculate the ETH/USD spot price.\n  /// @return chainlinkPrice The spot price from Chainlink price feed, multiplied by 1e18.\n  /// @return minPrice The minimum spot price among all available sources, multiplied by 1e18.\n  /// @return maxPrice The maximum spot price among all available sources, multiplied by 1e18.\n  function _getETHUSDSpotPrice() internal view returns (uint256 chainlinkPrice, uint256 minPrice, uint256 maxPrice) {\n    chainlinkPrice = _readSpotPriceByChainlink(Chainlink_ETH_USD_Spot);\n    uint256[] memory prices = _getSpotPriceByEncoding(onchainSpotEncodings_ETHUSD);\n    minPrice = maxPrice = chainlinkPrice;\n    for (uint256 i = 0; i < prices.length; i++) {\n      if (prices[i] > maxPrice) maxPrice = prices[i];\n      if (prices[i] < minPrice) minPrice = prices[i];\n    }\n  }\n}\n"},"contracts/price-oracle/interfaces/IPriceOracle.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IPriceOracle {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when the value of maximum price deviation is updated.\n  /// @param oldValue The value of the previous maximum price deviation.\n  /// @param newValue The value of the current maximum price deviation.\n  event UpdateMaxPriceDeviation(uint256 oldValue, uint256 newValue);\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the oracle price with 18 decimal places.\n  /// @return anchorPrice The anchor price for this asset, multiplied by 1e18. It should be hard to manipulate,\n  ///         like time-weighted average price or chainlink spot price.\n  /// @return minPrice The minimum oracle price among all available price sources (including twap), multiplied by 1e18.\n  /// @return maxPrice The maximum oracle price among all available price sources (including twap), multiplied by 1e18.\n  function getPrice() external view returns (uint256 anchorPrice, uint256 minPrice, uint256 maxPrice);\n\n  /// @notice Return the oracle price for exchange with 18 decimal places.\n  function getExchangePrice() external view returns (uint256);\n\n  /// @notice Return the oracle price for liquidation with 18 decimal places.\n  function getLiquidatePrice() external view returns (uint256);\n\n  /// @notice Return the oracle price for redemption with 18 decimal places.\n  function getRedeemPrice() external view returns (uint256);\n}\n"},"contracts/price-oracle/interfaces/ISpotPriceOracle.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface ISpotPriceOracle {\n  /// @notice Return spot price with 18 decimal places.\n  ///\n  /// @dev encoding for single route\n  /// |   8 bits  | 160 bits |  88  bits  |\n  /// | pool_type |   pool   | customized |\n  /// assume all base and quote token has no more than 18 decimals.\n  ///\n  /// + pool_type = 0: UniswapV2\n  ///   customized = |   1  bit   |   8  bits   |   8 bits   | ... |\n  ///                | base_index | base_scale | quote_scale | ... |\n  /// + pool_type = 1: UniswapV3\n  ///   customized = |   1  bit   |   8 bits   |   8  bits   | ... |\n  ///                | base_index | base_scale | quote_scale | ... |\n  /// + pool_type = 2: Balancer V2 Weighted\n  ///   customized = |   3  bit   |    3 bit    |   8 bits   |   8  bits   | ... |\n  ///                | base_index | quote_index | base_scale | quote_scale | ... |\n  /// + pool_type = 3: Balancer V2 Stable\n  ///   customized = |   3 bits   |   3  bits   | ... |\n  ///                | base_index | quote_index | ... |\n  /// + pool_type = 4: Curve Plain\n  ///   customized = | 3 bits |   3 bits   |   3  bits   |     1  bits     |  8 bits  | ... |  8 bits  | ... |\n  ///                | tokens | base_index | quote_index | has_amm_precise | scale[0] | ... | scale[n] | ... |\n  /// + pool_type = 5: Curve Plain with oracle\n  ///   customized = |   1  bit   |   1 bit   |... |\n  ///                | base_index | use_cache | ... |\n  /// + pool_type = 6: Curve Plain NG\n  ///   customized = |   3 bits   |   3  bits   |   1 bit   | ... |\n  ///                | base_index | quote_index | use_cache | ... |\n  /// + pool_type = 7: Curve Crypto\n  ///   customized = |   1  bit   | ... |\n  ///                | base_index | ... |\n  /// + pool_type = 8: Curve TriCrypto\n  ///   customized = |   2 bits   |   2  bits   | ... |\n  ///                | base_index | quote_index | ... |\n  /// + pool_type = 9: ERC4626\n  ///   customized = |       1  bit       | ... |\n  ///                | base_is_underlying | ... |\n  /// + pool_type = 10: ETHLSD, wstETH, weETH, ezETH\n  ///   customized = |    1 bit    | ... |\n  ///                | base_is_ETH | ... |\n  /// + pool_type = 11: BalancerV2CachedRate\n  ///   customized = |   3 bits   | ... |\n  ///                | base_index | ... |\n  ///\n  /// @param encoding The encoding of the price source.\n  /// @return spotPrice The spot price with 18 decimal places.\n  function getSpotPrice(uint256 encoding) external view returns (uint256 spotPrice);\n}\n"},"contracts/price-oracle/interfaces/ITwapOracle.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface ITwapOracle {\n  /// @notice Return TWAP with 18 decimal places in the epoch ending at the specified timestamp.\n  ///         Zero is returned if TWAP in the epoch is not available.\n  /// @param timestamp End Timestamp in seconds of the epoch\n  /// @return TWAP (18 decimal places) in the epoch, or zero if not available\n  function getTwap(uint256 timestamp) external view returns (uint256);\n\n  /// @notice Return the latest price with 18 decimal places.\n  function getLatest() external view returns (uint256);\n}\n"},"contracts/price-oracle/LSDPriceOracleBase.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { Math } from \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nimport { SpotPriceOracleBase } from \"./SpotPriceOracleBase.sol\";\n\nimport { IPriceOracle } from \"./interfaces/IPriceOracle.sol\";\nimport { ITwapOracle } from \"./interfaces/ITwapOracle.sol\";\n\nabstract contract LSDPriceOracleBase is SpotPriceOracleBase, IPriceOracle {\n  /*************\n   * Constants *\n   *************/\n\n  /// @notice The Chainlink ETH/USD price feed.\n  /// @dev See comments of `_readSpotPriceByChainlink` for more details.\n  bytes32 public immutable Chainlink_ETH_USD_Spot;\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @dev The encodings for ETH/USD spot sources.\n  bytes private onchainSpotEncodings_ETHUSD;\n\n  /// @dev The encodings for LSD/ETH spot sources.\n  bytes private onchainSpotEncodings_LSDETH;\n\n  /// @dev The encodings for LSD/USD spot sources.\n  bytes private onchainSpotEncodings_LSDUSD;\n\n  /// @notice The value of maximum price deviation, multiplied by 1e18.\n  uint256 public maxPriceDeviation;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(bytes32 _Chainlink_ETH_USD_Spot) {\n    Chainlink_ETH_USD_Spot = _Chainlink_ETH_USD_Spot;\n\n    _updateMaxPriceDeviation(1e16); // 1%\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the ETH/USD spot price.\n  /// @return chainlinkPrice The spot price from Chainlink price feed.\n  /// @return minPrice The minimum spot price among all available sources.\n  /// @return maxPrice The maximum spot price among all available sources.\n  function getETHUSDSpotPrice() external view returns (uint256 chainlinkPrice, uint256 minPrice, uint256 maxPrice) {\n    (chainlinkPrice, minPrice, maxPrice) = _getETHUSDSpotPrice();\n  }\n\n  /// @notice Return the ETH/USD spot prices.\n  /// @return prices The list of spot price among all available sources, multiplied by 1e18.\n  function getETHUSDSpotPrices() external view returns (uint256[] memory prices) {\n    prices = _getSpotPriceByEncoding(onchainSpotEncodings_ETHUSD);\n  }\n\n  /// @notice Return the LSD/ETH spot prices.\n  /// @return prices The list of spot price among all available sources, multiplied by 1e18.\n  function getLSDETHSpotPrices() public view returns (uint256[] memory prices) {\n    prices = _getSpotPriceByEncoding(onchainSpotEncodings_LSDETH);\n  }\n\n  /// @notice Return the LSD/ETH spot prices.\n  /// @return prices The list of spot price among all available sources, multiplied by 1e18.\n  function getLSDUSDSpotPrices() public view returns (uint256[] memory prices) {\n    prices = _getSpotPriceByEncoding(onchainSpotEncodings_LSDUSD);\n  }\n\n  /// @notice Return the LSD/USD anchor price, the price that is hard to manipulate in single tx.\n  /// @return price The anchor price, multiplied by 1e18.\n  function getLSDUSDAnchorPrice() external view returns (uint256 price) {\n    price = _getLSDUSDAnchorPrice();\n  }\n\n  /// @inheritdoc IPriceOracle\n  /// @dev The price is valid iff |maxPrice-minPrice|/minPrice < maxPriceDeviation\n  function getPrice() public view override returns (uint256 anchorPrice, uint256 minPrice, uint256 maxPrice) {\n    anchorPrice = _getLSDUSDAnchorPrice();\n    (minPrice, maxPrice) = _getLSDMinMaxPrice(anchorPrice);\n\n    uint256 cachedMaxPriceDeviation = maxPriceDeviation; // gas saving\n    // use anchor price when the price deviation between anchor price and min price exceed threshold\n    if ((anchorPrice - minPrice) * PRECISION > cachedMaxPriceDeviation * minPrice) {\n      minPrice = anchorPrice;\n    }\n\n    // use anchor price when the price deviation between anchor price and max price exceed threshold\n    if ((maxPrice - anchorPrice) * PRECISION > cachedMaxPriceDeviation * anchorPrice) {\n      maxPrice = anchorPrice;\n    }\n  }\n\n  /// @inheritdoc IPriceOracle\n  function getExchangePrice() public view returns (uint256) {\n    (, uint256 price, ) = getPrice();\n    return price;\n  }\n\n  /// @inheritdoc IPriceOracle\n  function getLiquidatePrice() external view returns (uint256) {\n    return getExchangePrice();\n  }\n\n  /// @inheritdoc IPriceOracle\n  function getRedeemPrice() external view returns (uint256) {\n    (, , uint256 price) = getPrice();\n    return price;\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Update the on-chain spot encodings.\n  /// @param encodings The encodings to update. See `_getSpotPriceByEncoding` for more details.\n  /// @param spotType The type of the encodings.\n  function updateOnchainSpotEncodings(bytes memory encodings, uint256 spotType) external onlyOwner {\n    // validate encoding\n    uint256[] memory prices = _getSpotPriceByEncoding(encodings);\n\n    if (spotType == 0) {\n      onchainSpotEncodings_ETHUSD = encodings;\n      if (prices.length == 0) revert ErrorInvalidEncodings();\n    } else if (spotType == 1) {\n      onchainSpotEncodings_LSDETH = encodings;\n    } else if (spotType == 2) {\n      onchainSpotEncodings_LSDUSD = encodings;\n    }\n  }\n\n  /// @notice Update the value of maximum price deviation.\n  /// @param newMaxPriceDeviation The new value of maximum price deviation, multiplied by 1e18.\n  function updateMaxPriceDeviation(uint256 newMaxPriceDeviation) external onlyOwner {\n    _updateMaxPriceDeviation(newMaxPriceDeviation);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to update the value of maximum price deviation.\n  /// @param newMaxPriceDeviation The new value of maximum price deviation, multiplied by 1e18.\n  function _updateMaxPriceDeviation(uint256 newMaxPriceDeviation) private {\n    uint256 oldMaxPriceDeviation = maxPriceDeviation;\n    if (oldMaxPriceDeviation == newMaxPriceDeviation) {\n      revert ErrorParameterUnchanged();\n    }\n\n    maxPriceDeviation = newMaxPriceDeviation;\n\n    emit UpdateMaxPriceDeviation(oldMaxPriceDeviation, newMaxPriceDeviation);\n  }\n\n  /// @dev Internal function to calculate the ETH/USD spot price.\n  /// @return chainlinkPrice The spot price from Chainlink price feed, multiplied by 1e18.\n  /// @return minPrice The minimum spot price among all available sources, multiplied by 1e18.\n  /// @return maxPrice The maximum spot price among all available sources, multiplied by 1e18.\n  function _getETHUSDSpotPrice() internal view returns (uint256 chainlinkPrice, uint256 minPrice, uint256 maxPrice) {\n    chainlinkPrice = _readSpotPriceByChainlink(Chainlink_ETH_USD_Spot);\n    uint256[] memory prices = _getSpotPriceByEncoding(onchainSpotEncodings_ETHUSD);\n    minPrice = maxPrice = chainlinkPrice;\n    for (uint256 i = 0; i < prices.length; i++) {\n      if (prices[i] > maxPrice) maxPrice = prices[i];\n      if (prices[i] < minPrice) minPrice = prices[i];\n    }\n  }\n\n  /// @dev Internal function to return the min/max LSD/USD prices.\n  /// @param anchorPrice The LSD/USD anchor price, multiplied by 1e18.\n  /// @return minPrice The minimum price among all available sources (including twap), multiplied by 1e18.\n  /// @return maxPrice The maximum price among all available sources (including twap), multiplied by 1e18.\n  function _getLSDMinMaxPrice(uint256 anchorPrice) internal view returns (uint256 minPrice, uint256 maxPrice) {\n    minPrice = maxPrice = anchorPrice;\n    (, uint256 minETHUSDPrice, uint256 maxETHUSDPrice) = _getETHUSDSpotPrice();\n    uint256[] memory LSD_ETH_prices = getLSDETHSpotPrices();\n    uint256[] memory LSD_USD_prices = getLSDUSDSpotPrices();\n\n    uint256 length = LSD_ETH_prices.length;\n    uint256 LSD_ETH_minPrice = type(uint256).max;\n    uint256 LSD_ETH_maxPrice;\n    unchecked {\n      for (uint256 i = 0; i < length; i++) {\n        uint256 price = LSD_ETH_prices[i];\n        if (price > LSD_ETH_maxPrice) LSD_ETH_maxPrice = price;\n        if (price < LSD_ETH_minPrice) LSD_ETH_minPrice = price;\n      }\n      if (LSD_ETH_maxPrice != 0) {\n        minPrice = Math.min(minPrice, (LSD_ETH_minPrice * minETHUSDPrice) / PRECISION);\n        maxPrice = Math.max(maxPrice, (LSD_ETH_maxPrice * maxETHUSDPrice) / PRECISION);\n      }\n\n      length = LSD_USD_prices.length;\n      for (uint256 i = 0; i < length; i++) {\n        uint256 price = LSD_USD_prices[i];\n        if (price > maxPrice) maxPrice = price;\n        if (price < minPrice) minPrice = price;\n      }\n    }\n  }\n\n  /// @dev Internal function to return the LSD/USD anchor price.\n  /// @return price The anchor price of LSD/USD, multiplied by 1e18.\n  function _getLSDUSDAnchorPrice() internal view virtual returns (uint256 price);\n}\n"},"contracts/price-oracle/SpotPriceOracleBase.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.26;\n\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { Ownable2Step } from \"@openzeppelin/contracts/access/Ownable2Step.sol\";\n\nimport { AggregatorV3Interface } from \"../interfaces/Chainlink/AggregatorV3Interface.sol\";\nimport { ISpotPriceOracle } from \"./interfaces/ISpotPriceOracle.sol\";\n\nabstract contract SpotPriceOracleBase is Ownable2Step {\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the given encodings are invalid.\n  error ErrorInvalidEncodings();\n\n  /// @dev Thrown when update some parameters to the same value.\n  error ErrorParameterUnchanged();\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The precision for oracle price.\n  uint256 internal constant PRECISION = 1e18;\n\n  /// @dev The address of `SpotPriceOracle` contract.\n  address immutable spotPriceOracle;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(address _spotPriceOracle) Ownable(_msgSender()) {\n    spotPriceOracle = _spotPriceOracle;\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev The encoding is below.\n  /// ```text\n  /// |  32 bits  | 64 bits |  160 bits  |\n  /// | heartbeat |  scale  | price_feed |\n  /// |low                          high |\n  /// ```\n  function _readSpotPriceByChainlink(bytes32 encoding) internal view returns (uint256) {\n    address aggregator;\n    uint256 scale;\n    uint256 heartbeat;\n    assembly {\n      aggregator := shr(96, encoding)\n      scale := and(shr(32, encoding), 0xffffffffffffffff)\n      heartbeat := and(encoding, 0xffffffff)\n    }\n    (, int256 answer, , uint256 updatedAt, ) = AggregatorV3Interface(aggregator).latestRoundData();\n    if (answer <= 0) revert(\"invalid\");\n    if (block.timestamp - updatedAt > heartbeat) revert(\"expired\");\n    return uint256(answer) * scale;\n  }\n\n  /// @dev Internal function to calculate spot price by encodings.\n  ///\n  /// The details of the encoding is below\n  /// ```text\n  /// |   1 byte   |    ...    |    ...    | ... |    ...    |\n  /// | num_source | source[0] | source[1] | ... | source[n] |\n  ///\n  /// source encoding:\n  /// |  1 byte  | 32 bytes | 32 bytes | ... | 32 bytes |\n  /// | num_pool |  pool[0] |  pool[1] | ... |  pool[n] |\n  /// 1 <= num_pool <= 3\n  ///\n  /// The encoding of each pool can be found in `SpotPriceOracle` contract.\n  /// ```\n  /// @return prices The list of prices of each source, multiplied by 1e18.\n  function _getSpotPriceByEncoding(bytes memory encodings) internal view returns (uint256[] memory prices) {\n    uint256 ptr;\n    uint256 length;\n    assembly {\n      ptr := add(encodings, 0x21)\n      length := byte(0, mload(sub(ptr, 1)))\n    }\n    prices = new uint256[](length);\n    for (uint256 i = 0; i < length; i++) {\n      uint256 encoding1;\n      uint256 encoding2;\n      uint256 encoding3;\n      assembly {\n        let cnt := byte(0, mload(ptr))\n        ptr := add(ptr, 0x01)\n        if gt(cnt, 0) {\n          encoding1 := mload(ptr)\n          ptr := add(ptr, 0x20)\n        }\n        if gt(cnt, 1) {\n          encoding2 := mload(ptr)\n          ptr := add(ptr, 0x20)\n        }\n        if gt(cnt, 2) {\n          encoding3 := mload(ptr)\n          ptr := add(ptr, 0x20)\n        }\n      }\n      if (encoding1 == 0) {\n        revert ErrorInvalidEncodings();\n      } else if (encoding2 == 0) {\n        prices[i] = _readSpotPrice(encoding1);\n      } else if (encoding3 == 0) {\n        prices[i] = _readSpotPrice(encoding1, encoding2);\n      } else {\n        prices[i] = _readSpotPrice(encoding1, encoding2, encoding3);\n      }\n    }\n  }\n\n  /// @dev Internal function to calculate spot price of single pool.\n  /// @param encoding The encoding for the pool.\n  /// @return price The spot price of the source, multiplied by 1e18.\n  function _readSpotPrice(uint256 encoding) private view returns (uint256 price) {\n    price = ISpotPriceOracle(spotPriceOracle).getSpotPrice(encoding);\n  }\n\n  /// @dev Internal function to calculate spot price of two pools.\n  /// @param encoding1 The encoding for the first pool.\n  /// @param encoding2 The encoding for the second pool.\n  /// @return price The spot price of the source, multiplied by 1e18.\n  function _readSpotPrice(uint256 encoding1, uint256 encoding2) private view returns (uint256 price) {\n    unchecked {\n      price = (_readSpotPrice(encoding1) * _readSpotPrice(encoding2)) / PRECISION;\n    }\n  }\n\n  /// @dev Internal function to calculate spot price of three pools.\n  /// @param encoding1 The encoding for the first pool.\n  /// @param encoding2 The encoding for the second pool.\n  /// @param encoding3 The encoding for the third pool.\n  /// @return price The spot price of the source, multiplied by 1e18.\n  function _readSpotPrice(\n    uint256 encoding1,\n    uint256 encoding2,\n    uint256 encoding3\n  ) private view returns (uint256 price) {\n    unchecked {\n      price = (_readSpotPrice(encoding1, encoding2) * _readSpotPrice(encoding3)) / PRECISION;\n    }\n  }\n}\n"},"contracts/price-oracle/StETHPriceOracle.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { ICurvePoolOracle } from \"../interfaces/Curve/ICurvePoolOracle.sol\";\n\nimport { SpotPriceOracleBase } from \"./SpotPriceOracleBase.sol\";\nimport { LSDPriceOracleBase } from \"./LSDPriceOracleBase.sol\";\n\ncontract StETHPriceOracle is LSDPriceOracleBase {\n  /***********************\n   * Immutable Variables *\n   ***********************/\n\n  /// @notice The address of curve ETH/stETH pool.\n  address public immutable Curve_ETH_stETH_Pool;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(\n    address _spotPriceOracle,\n    bytes32 _Chainlink_ETH_USD_Spot,\n    address _Curve_ETH_stETH_Pool\n  ) SpotPriceOracleBase(_spotPriceOracle) LSDPriceOracleBase(_Chainlink_ETH_USD_Spot) {\n    Curve_ETH_stETH_Pool = _Curve_ETH_stETH_Pool;\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @inheritdoc LSDPriceOracleBase\n  /// @dev [Curve stETH/ETH ema price] * [Chainlink ETH/USD spot]\n  function _getLSDUSDAnchorPrice() internal view virtual override returns (uint256) {\n    uint256 stETH_ETH_CurveEma = ICurvePoolOracle(Curve_ETH_stETH_Pool).price_oracle();\n    uint256 ETH_USD_ChainlinkSpot = _readSpotPriceByChainlink(Chainlink_ETH_USD_Spot);\n    unchecked {\n      return (stETH_ETH_CurveEma * ETH_USD_ChainlinkSpot) / PRECISION;\n    }\n  }\n}\n"},"contracts/price-oracle/WBTCPriceOracle.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { Math } from \"@openzeppelin/contracts-v4/utils/math/Math.sol\";\n\nimport { SpotPriceOracleBase } from \"./SpotPriceOracleBase.sol\";\nimport { BTCDerivativeOracleBase } from \"./BTCDerivativeOracleBase.sol\";\n\ncontract WBTCPriceOracle is BTCDerivativeOracleBase {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when the value of maximum WBTC deviation is updated.\n  /// @param oldValue The value of the previous maximum WBTC deviation.\n  /// @param newValue The value of the current maximum WBTC deviation.\n  event UpdateMaxWBTCDeviation(uint256 oldValue, uint256 newValue);\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @notice The encoding of the Chainlink WBTC/BTC Spot.\n  bytes32 public immutable Chainlink_WBTC_BTC_Spot;\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @notice The value of maximum WBTC price deviation, multiplied by 1e18.\n  uint256 public maxWBTCDeviation;\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(\n    address _spotPriceOracle,\n    bytes32 _Chainlink_BTC_USD_Spot,\n    bytes32 _Chainlink_WBTC_BTC_Spot\n  ) SpotPriceOracleBase(_spotPriceOracle) BTCDerivativeOracleBase(_Chainlink_BTC_USD_Spot) {\n    Chainlink_WBTC_BTC_Spot = _Chainlink_WBTC_BTC_Spot;\n\n    _updateMaxWBTCDeviation(2e16); // 2%\n  }\n\n  /************************\n   * Restricted Functions *\n   ************************/\n\n  /// @notice Update the value of maximum WBTC deviation.\n  /// @param newMaxWBTCDeviation The new value of maximum WBTC deviation, multiplied by 1e18.\n  function updateMaxWBTCDeviation(uint256 newMaxWBTCDeviation) external onlyOwner {\n    _updateMaxWBTCDeviation(newMaxWBTCDeviation);\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to update the value of maximum WBTC deviation.\n  /// @param newMaxWBTCDeviation The new value of maximum WBTC deviation, multiplied by 1e18.\n  function _updateMaxWBTCDeviation(uint256 newMaxWBTCDeviation) private {\n    uint256 oldMaxWBTCDeviation = maxWBTCDeviation;\n    if (oldMaxWBTCDeviation == newMaxWBTCDeviation) {\n      revert ErrorParameterUnchanged();\n    }\n\n    maxWBTCDeviation = newMaxWBTCDeviation;\n\n    emit UpdateMaxWBTCDeviation(oldMaxWBTCDeviation, newMaxWBTCDeviation);\n  }\n\n  /// @inheritdoc BTCDerivativeOracleBase\n  /// @dev [Chainlink BTC/USD spot] * [Chainlink WBTC/BTC spot]\n  function _getBTCDerivativeUSDAnchorPrice(bool isRedeem) internal view virtual override returns (uint256) {\n    uint256 BTC_USD_ChainlinkSpot = _readSpotPriceByChainlink(Chainlink_BTC_USD_Spot);\n    uint256 WBTC_BTC_ChainlinkSpot = _readSpotPriceByChainlink(Chainlink_WBTC_BTC_Spot);\n    uint256 WBTC_USD_ChainlinkSpot = (WBTC_BTC_ChainlinkSpot * BTC_USD_ChainlinkSpot) / PRECISION;\n    if (!isRedeem) return WBTC_USD_ChainlinkSpot;\n    else {\n      uint256 cachedMaxWBTCDeviation = maxWBTCDeviation;\n      if (\n        PRECISION - cachedMaxWBTCDeviation <= WBTC_BTC_ChainlinkSpot &&\n        WBTC_BTC_ChainlinkSpot <= PRECISION + cachedMaxWBTCDeviation\n      ) {\n        return WBTC_USD_ChainlinkSpot < BTC_USD_ChainlinkSpot ? BTC_USD_ChainlinkSpot : WBTC_USD_ChainlinkSpot;\n      } else {\n        return WBTC_USD_ChainlinkSpot;\n      }\n    }\n  }\n}\n"},"contracts/rate-provider/interfaces/IRateProvider.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IRateProvider {\n  /// @notice Return the exchange rate from wrapped token to underlying rate,\n  /// multiplied by 1e18.\n  function getRate() external view returns (uint256);\n}\n"},"contracts/v2/interfaces/IFxBoostableRebalancePool.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IFxBoostableRebalancePool {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when user deposit asset into this contract.\n  /// @param owner The address of asset owner.\n  /// @param reciever The address of receiver of the asset in this contract.\n  /// @param amount The amount of asset deposited.\n  event Deposit(address indexed owner, address indexed reciever, uint256 amount);\n\n  /// @notice Emitted when the amount of deposited asset changed due to liquidation or deposit or unlock.\n  /// @param owner The address of asset owner.\n  /// @param newDeposit The new amount of deposited asset.\n  /// @param loss The amount of asset used by liquidation.\n  event UserDepositChange(address indexed owner, uint256 newDeposit, uint256 loss);\n\n  /// @notice Emitted when user withdraw asset.\n  /// @param owner The address of asset owner.\n  /// @param reciever The address of receiver of the asset.\n  /// @param amount The amount of token to withdraw.\n  event Withdraw(address indexed owner, address indexed reciever, uint256 amount);\n\n  /// @notice Emitted when liquidation happens.\n  /// @param liquidated The amount of asset liquidated.\n  /// @param baseGained The amount of base token gained.\n  event Liquidate(uint256 liquidated, uint256 baseGained);\n\n  /// @notice Emitted when the address of reward wrapper is updated.\n  /// @param oldWrapper The address of previous reward wrapper.\n  /// @param newWrapper The address of current reward wrapper.\n  event UpdateWrapper(address indexed oldWrapper, address indexed newWrapper);\n\n  /// @notice Emitted when the liquidatable collateral ratio is updated.\n  /// @param oldRatio The previous liquidatable collateral ratio.\n  /// @param newRatio The current liquidatable collateral ratio.\n  event UpdateLiquidatableCollateralRatio(uint256 oldRatio, uint256 newRatio);\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown then the src token mismatched.\n  error ErrorWrapperSrcMismatch();\n\n  /// @dev Thrown then the dst token mismatched.\n  error ErrorWrapperDstMismatch();\n\n  /// @dev Thrown when the deposited amount is zero.\n  error DepositZeroAmount();\n\n  /// @dev Thrown when the withdrawn amount is zero.\n  error WithdrawZeroAmount();\n\n  /// @dev Thrown the cannot liquidate.\n  error CannotLiquidate();\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the address of treasury contract.\n  function treasury() external view returns (address);\n\n  /// @notice Return the address of market contract.\n  function market() external view returns (address);\n\n  /// @notice Return the address of base token.\n  function baseToken() external view returns (address);\n\n  /// @notice Return the address of underlying token of this contract.\n  function asset() external view returns (address);\n\n  /// @notice Return the total amount of asset deposited to this contract.\n  function totalSupply() external view returns (uint256);\n\n  /// @notice Return the amount of deposited asset for some specific user.\n  /// @param account The address of user to query.\n  function balanceOf(address account) external view returns (uint256);\n\n  /// @notice Return the current boost ratio for some specific user.\n  /// @param account The address of user to query, multiplied by 1e18.\n  function getBoostRatio(address account) external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Deposit some asset to this contract.\n  /// @dev Use `amount=uint256(-1)` if you want to deposit all asset held.\n  /// @param amount The amount of asset to deposit.\n  /// @param receiver The address of recipient for the deposited asset.\n  function deposit(uint256 amount, address receiver) external;\n\n  /// @notice Withdraw asset from this contract.\n  function withdraw(uint256 amount, address receiver) external;\n\n  /// @notice Liquidate asset for base token.\n  /// @param maxAmount The maximum amount of asset to liquidate.\n  /// @param minBaseOut The minimum amount of base token should receive.\n  /// @return liquidated The amount of asset liquidated.\n  /// @return baseOut The amount of base token received.\n  function liquidate(uint256 maxAmount, uint256 minBaseOut) external returns (uint256 liquidated, uint256 baseOut);\n}\n"},"contracts/v2/interfaces/IFxMarketV2.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IFxMarketV2 {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when fToken is minted.\n  /// @param owner The address of base token owner.\n  /// @param recipient The address of receiver for fToken or xToken.\n  /// @param baseTokenIn The amount of base token deposited.\n  /// @param fTokenOut The amount of fToken minted.\n  /// @param mintFee The amount of mint fee charged.\n  event MintFToken(\n    address indexed owner,\n    address indexed recipient,\n    uint256 baseTokenIn,\n    uint256 fTokenOut,\n    uint256 mintFee\n  );\n\n  /// @notice Emitted when xToken is minted.\n  /// @param owner The address of base token owner.\n  /// @param recipient The address of receiver for fToken or xToken.\n  /// @param baseTokenIn The amount of base token deposited.\n  /// @param xTokenOut The amount of xToken minted.\n  /// @param bonus The amount of base token as bonus.\n  /// @param mintFee The amount of mint fee charged.\n  event MintXToken(\n    address indexed owner,\n    address indexed recipient,\n    uint256 baseTokenIn,\n    uint256 xTokenOut,\n    uint256 bonus,\n    uint256 mintFee\n  );\n\n  /// @notice Emitted when someone redeem base token with fToken or xToken.\n  /// @param owner The address of fToken and xToken owner.\n  /// @param recipient The address of receiver for base token.\n  /// @param fTokenBurned The amount of fToken burned.\n  /// @param baseTokenOut The amount of base token redeemed.\n  /// @param bonus The amount of base token as bonus.\n  /// @param redeemFee The amount of redeem fee charged.\n  event RedeemFToken(\n    address indexed owner,\n    address indexed recipient,\n    uint256 fTokenBurned,\n    uint256 baseTokenOut,\n    uint256 bonus,\n    uint256 redeemFee\n  );\n\n  /// @notice Emitted when someone redeem base token with fToken or xToken.\n  /// @param owner The address of fToken and xToken owner.\n  /// @param recipient The address of receiver for base token.\n  /// @param xTokenBurned The amount of xToken burned.\n  /// @param baseTokenOut The amount of base token redeemed.\n  /// @param redeemFee The amount of redeem fee charged.\n  event RedeemXToken(\n    address indexed owner,\n    address indexed recipient,\n    uint256 xTokenBurned,\n    uint256 baseTokenOut,\n    uint256 redeemFee\n  );\n\n  /// @notice Emitted when the fee ratio for minting fToken is updated.\n  /// @param defaultFeeRatio The new default fee ratio, multipled by 1e18.\n  /// @param extraFeeRatio The new extra fee ratio, multipled by 1e18.\n  event UpdateMintFeeRatioFToken(uint256 defaultFeeRatio, int256 extraFeeRatio);\n\n  /// @notice Emitted when the fee ratio for minting xToken is updated.\n  /// @param defaultFeeRatio The new default fee ratio, multipled by 1e18.\n  /// @param extraFeeRatio The new extra fee ratio, multipled by 1e18.\n  event UpdateMintFeeRatioXToken(uint256 defaultFeeRatio, int256 extraFeeRatio);\n\n  /// @notice Emitted when the fee ratio for redeeming fToken is updated.\n  /// @param defaultFeeRatio The new default fee ratio, multipled by 1e18.\n  /// @param extraFeeRatio The new extra fee ratio, multipled by 1e18.\n  event UpdateRedeemFeeRatioFToken(uint256 defaultFeeRatio, int256 extraFeeRatio);\n\n  /// @notice Emitted when the fee ratio for redeeming xToken is updated.\n  /// @param defaultFeeRatio The new default fee ratio, multipled by 1e18.\n  /// @param extraFeeRatio The new extra fee ratio, multipled by 1e18.\n  event UpdateRedeemFeeRatioXToken(uint256 defaultFeeRatio, int256 extraFeeRatio);\n\n  /// @notice Emitted when the stability ratio is updated.\n  /// @param oldRatio The previous collateral ratio to enter stability mode, multiplied by 1e18.\n  /// @param newRatio The current collateral ratio to enter stability mode, multiplied by 1e18.\n  event UpdateStabilityRatio(uint256 oldRatio, uint256 newRatio);\n\n  /// @notice Emitted when the platform contract is updated.\n  /// @param oldPlatform The address of previous platform contract.\n  /// @param newPlatform The address of current platform contract.\n  event UpdatePlatform(address indexed oldPlatform, address indexed newPlatform);\n\n  /// @notice Emitted when the  reserve pool contract is updated.\n  /// @param oldReservePool The address of previous reserve pool contract.\n  /// @param newReservePool The address of current reserve pool contract.\n  event UpdateReservePool(address indexed oldReservePool, address indexed newReservePool);\n\n  /// @notice Emitted when the RebalancePoolRegistry contract is updated.\n  /// @param oldRegistry The address of previous RebalancePoolRegistry contract.\n  /// @param newRegistry The address of current RebalancePoolRegistry contract.\n  event UpdateRebalancePoolRegistry(address indexed oldRegistry, address indexed newRegistry);\n\n  /// @notice Pause or unpause mint.\n  /// @param oldStatus The previous status for mint.\n  /// @param newStatus The current status for mint.\n  event UpdateMintStatus(bool oldStatus, bool newStatus);\n\n  /// @notice Pause or unpause redeem.\n  /// @param oldStatus The previous status for redeem.\n  /// @param newStatus The current status for redeem.\n  event UpdateRedeemStatus(bool oldStatus, bool newStatus);\n\n  /// @notice Pause or unpause fToken mint in stability mode.\n  /// @param oldStatus The previous status for mint.\n  /// @param newStatus The current status for mint.\n  event UpdateFTokenMintStatusInStabilityMode(bool oldStatus, bool newStatus);\n\n  /// @notice Pause or unpause xToken redeem in stability mode.\n  /// @param oldStatus The previous status for redeem.\n  /// @param newStatus The current status for redeem.\n  event UpdateXTokenRedeemStatusInStabilityMode(bool oldStatus, bool newStatus);\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when the caller if not fUSD contract.\n  error ErrorCallerNotFUSD();\n\n  /// @dev Thrown when token mint is paused.\n  error ErrorMintPaused();\n\n  /// @dev Thrown when fToken mint is paused in stability mode.\n  error ErrorFTokenMintPausedInStabilityMode();\n\n  /// @dev Thrown when mint with zero amount base token.\n  error ErrorMintZeroAmount();\n\n  /// @dev Thrown when the amount of fToken is not enough.\n  error ErrorInsufficientFTokenOutput();\n\n  /// @dev Thrown when the amount of xToken is not enough.\n  error ErrorInsufficientXTokenOutput();\n\n  /// @dev Thrown when token redeem is paused.\n  error ErrorRedeemPaused();\n\n  /// @dev Thrown when xToken redeem is paused in stability mode.\n  error ErrorXTokenRedeemPausedInStabilityMode();\n\n  /// @dev Thrown when redeem with zero amount fToken or xToken.\n  error ErrorRedeemZeroAmount();\n\n  /// @dev Thrown when the amount of base token is not enough.\n  error ErrorInsufficientBaseOutput();\n\n  /// @dev Thrown when the stability ratio is too large.\n  error ErrorStabilityRatioTooLarge();\n\n  /// @dev Thrown when the default fee is too large.\n  error ErrorDefaultFeeTooLarge();\n\n  /// @dev Thrown when the delta fee is too small.\n  error ErrorDeltaFeeTooSmall();\n\n  /// @dev Thrown when the sum of default fee and delta fee is too large.\n  error ErrorTotalFeeTooLarge();\n\n  /// @dev Thrown when the given address is zero.\n  error ErrorZeroAddress();\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice The address of Treasury contract.\n  function treasury() external view returns (address);\n\n  /// @notice Return the address of base token.\n  function baseToken() external view returns (address);\n\n  /// @notice Return the address fractional base token.\n  function fToken() external view returns (address);\n\n  /// @notice Return the address leveraged base token.\n  function xToken() external view returns (address);\n\n  /// @notice Return the address of fxUSD token.\n  function fxUSD() external view returns (address);\n\n  /// @notice Return the collateral ratio to enter stability mode, multiplied by 1e18.\n  function stabilityRatio() external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Mint some fToken with some base token.\n  /// @param baseIn The amount of wrapped value of base token supplied, use `uint256(-1)` to supply all base token.\n  /// @param recipient The address of receiver for fToken.\n  /// @param minFTokenMinted The minimum amount of fToken should be received.\n  /// @return fTokenMinted The amount of fToken should be received.\n  function mintFToken(\n    uint256 baseIn,\n    address recipient,\n    uint256 minFTokenMinted\n  ) external returns (uint256 fTokenMinted);\n\n  /// @notice Mint some xToken with some base token.\n  /// @param baseIn The amount of wrapped value of base token supplied, use `uint256(-1)` to supply all base token.\n  /// @param recipient The address of receiver for xToken.\n  /// @param minXTokenMinted The minimum amount of xToken should be received.\n  /// @return xTokenMinted The amount of xToken should be received.\n  /// @return bonus The amount of wrapped value of base token as bonus.\n  function mintXToken(\n    uint256 baseIn,\n    address recipient,\n    uint256 minXTokenMinted\n  ) external returns (uint256 xTokenMinted, uint256 bonus);\n\n  /// @notice Redeem base token with fToken.\n  /// @param fTokenIn the amount of fToken to redeem, use `uint256(-1)` to redeem all fToken.\n  /// @param recipient The address of receiver for base token.\n  /// @param minBaseOut The minimum amount of wrapped value of base token should be received.\n  /// @return baseOut The amount of wrapped value of base token should be received.\n  /// @return bonus The amount of wrapped value of base token as bonus.\n  function redeemFToken(\n    uint256 fTokenIn,\n    address recipient,\n    uint256 minBaseOut\n  ) external returns (uint256 baseOut, uint256 bonus);\n\n  /// @notice Redeem base token with xToken.\n  /// @param xTokenIn the amount of xToken to redeem, use `uint256(-1)` to redeem all xToken.\n  /// @param recipient The address of receiver for base token.\n  /// @param minBaseOut The minimum amount of wrapped value of base token should be received.\n  /// @return baseOut The amount of wrapped value of base token should be received.\n  function redeemXToken(\n    uint256 xTokenIn,\n    address recipient,\n    uint256 minBaseOut\n  ) external returns (uint256 baseOut);\n}\n"},"contracts/v2/interfaces/IFxShareableRebalancePool.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IFxBoostableRebalancePool } from \"./IFxBoostableRebalancePool.sol\";\n\ninterface IFxShareableRebalancePool is IFxBoostableRebalancePool {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when one user share votes to another user.\n  /// @param owner The address of votes owner.\n  /// @param staker The address of staker to share votes.\n  event ShareVote(address indexed owner, address indexed staker);\n\n  /// @notice Emitted when the owner cancel sharing to some staker.\n  /// @param owner The address of votes owner.\n  /// @param staker The address of staker to cancel votes share.\n  event CancelShareVote(address indexed owner, address indexed staker);\n\n  /// @notice Emitted when staker accept the vote sharing.\n  /// @param staker The address of the staker.\n  /// @param oldOwner The address of the previous vote sharing owner.\n  /// @param newOwner The address of the current vote sharing owner.\n  event AcceptSharedVote(address indexed staker, address indexed oldOwner, address indexed newOwner);\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when caller shares votes to self.\n  error ErrorSelfSharingIsNotAllowed();\n\n  /// @dev Thrown when a staker with shared votes try to share its votes to others.\n  error ErrorCascadedSharingIsNotAllowed();\n\n  /// @dev Thrown when staker try to accept non-allowed vote sharing.\n  error ErrorVoteShareNotAllowed();\n\n  /// @dev Thrown when staker try to reject a non-existed vote sharing.\n  error ErrorNoAcceptedSharedVote();\n\n  /// @dev Thrown when the staker has ability to share ve balance.\n  error ErrorVoteOwnerCannotStake();\n\n  /// @dev Thrown when staker try to accept twice.\n  error ErrorRepeatAcceptSharedVote();\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the owner of votes of some staker.\n  /// @param account The address of user to query.\n  function getStakerVoteOwner(address account) external view returns (address);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Withdraw asset from this contract on behalf of someone\n  function withdrawFrom(\n    address owner,\n    uint256 amount,\n    address receiver\n  ) external;\n\n  /// @notice Owner changes the vote sharing state for some user.\n  /// @param staker The address of user to change.\n  function toggleVoteSharing(address staker) external;\n\n  /// @notice Staker accepts the vote sharing.\n  /// @param newOwner The address of the owner of the votes.\n  function acceptSharedVote(address newOwner) external;\n\n  /// @notice Staker reject the current vote sharing.\n  function rejectSharedVote() external;\n}\n"},"contracts/v2/interfaces/IFxUSD.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\ninterface IFxUSD {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when a new market is added.\n  /// @param baseToken The address of base token of the market.\n  /// @param mintCap The mint capacity of the market.\n  event AddMarket(address indexed baseToken, uint256 mintCap);\n\n  /// @notice Emitted when the mint capacity is updated.\n  /// @param baseToken The address of base token of the market.\n  /// @param oldCap The value of previous mint capacity.\n  /// @param newCap The value of current mint capacity.\n  event UpdateMintCap(address indexed baseToken, uint256 oldCap, uint256 newCap);\n\n  /// @notice Emitted when a new rebalance pool is added.\n  /// @param baseToken The address of base token of the market.\n  /// @param pool The address of the rebalance pool.\n  event AddRebalancePool(address indexed baseToken, address indexed pool);\n\n  /// @notice Emitted when a new rebalance pool is removed.\n  /// @param baseToken The address of base token of the market.\n  /// @param pool The address of the rebalance pool.\n  event RemoveRebalancePool(address indexed baseToken, address indexed pool);\n\n  /// @notice Emitted when someone wrap fToken as fxUSD.\n  /// @param baseToken The address of base token of the market.\n  /// @param owner The address of fToken owner.\n  /// @param receiver The address of fxUSD recipient.\n  /// @param amount The amount of fxUSD minted.\n  event Wrap(address indexed baseToken, address indexed owner, address indexed receiver, uint256 amount);\n\n  /// @notice Emitted when someone unwrap fxUSD as fToken.\n  /// @param baseToken The address of base token of the market.\n  /// @param owner The address of fxUSD owner.\n  /// @param receiver The address of base token recipient.\n  /// @param amount The amount of fxUSD burned.\n  event Unwrap(address indexed baseToken, address indexed owner, address indexed receiver, uint256 amount);\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when someone tries to interact with unsupported market.\n  error ErrorUnsupportedMarket();\n\n  /// @dev Thrown when someone tries to interact with unsupported rebalance pool.\n  error ErrorUnsupportedRebalancePool();\n\n  /// @dev Thrown when someone tries to interact with market in stability mode.\n  error ErrorMarketInStabilityMode();\n\n  /// @dev Thrown when someone tries to interact with market has invalid price.\n  error ErrorMarketWithInvalidPrice();\n\n  /// @dev Thrown when someone tries to add a supported market.\n  error ErrorMarketAlreadySupported();\n\n  /// @dev Thrown when the total supply of fToken exceed mint capacity.\n  error ErrorExceedMintCap();\n\n  /// @dev Thrown when the amount of fToken is not enough for redeem.\n  error ErrorInsufficientLiquidity();\n\n  /// @dev Thrown when current is under collateral.\n  error ErrorUnderCollateral();\n\n  /// @dev Thrown when the length of two arrays is mismatch.\n  error ErrorLengthMismatch();\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the list of supported markets.\n  function getMarkets() external view returns (address[] memory);\n\n  /// @notice Return the list of supported rebalance pools.\n  function getRebalancePools() external view returns (address[] memory);\n\n  /// @notice Return the nav of fxUSD.\n  function nav() external view returns (uint256);\n\n  /// @notice Return whether the system is under collateral.\n  function isUnderCollateral() external view returns (bool);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Wrap fToken to fxUSD.\n  /// @param baseToken The address of corresponding base token.\n  /// @param amount The amount of fToken to wrap.\n  /// @param receiver The address of fxUSD recipient.\n  function wrap(\n    address baseToken,\n    uint256 amount,\n    address receiver\n  ) external;\n\n  /// @notice Unwrap fxUSD to fToken.\n  /// @param baseToken The address of corresponding base token.\n  /// @param amount The amount of fxUSD to unwrap.\n  /// @param receiver The address of fToken recipient.\n  function unwrap(\n    address baseToken,\n    uint256 amount,\n    address receiver\n  ) external;\n\n  /// @notice Wrap fToken from rebalance pool to fxUSD.\n  /// @param pool The address of rebalance pool.\n  /// @param amount The amount of fToken to wrap.\n  /// @param receiver The address of fxUSD recipient.\n  function wrapFrom(\n    address pool,\n    uint256 amount,\n    address receiver\n  ) external;\n\n  /// @notice Mint fxUSD with base token.\n  /// @param baseToken The address of the base token.\n  /// @param amountIn The amount of base token to use.\n  /// @param receiver The address of fxUSD recipient.\n  /// @param minOut The minimum amount of fxUSD should receive.\n  /// @return amountOut The amount of fxUSD received by the receiver.\n  function mint(\n    address baseToken,\n    uint256 amountIn,\n    address receiver,\n    uint256 minOut\n  ) external returns (uint256 amountOut);\n\n  /// @notice Deposit fxUSD to rebalance pool.\n  /// @param pool The address of rebalance pool.\n  /// @param amount The amount of fxUSD to use.\n  /// @param receiver The address of rebalance pool share recipient.\n  function earn(\n    address pool,\n    uint256 amount,\n    address receiver\n  ) external;\n\n  /// @notice Mint fxUSD with base token and deposit to rebalance pool.\n  /// @param pool The address of rebalance pool.\n  /// @param amountIn The amount of base token to use.\n  /// @param receiver The address of rebalance pool recipient.\n  /// @param minOut The minimum amount of rebalance pool shares should receive.\n  /// @return amountOut The amount of rebalance pool shares received by the receiver.\n  function mintAndEarn(\n    address pool,\n    uint256 amountIn,\n    address receiver,\n    uint256 minOut\n  ) external returns (uint256 amountOut);\n\n  /// @notice Redeem fxUSD to base token.\n  /// @param baseToken The address of the base token.\n  /// @param amountIn The amount of fxUSD to redeem.\n  /// @param receiver The address of base token recipient.\n  /// @param minOut The minimum amount of base token should receive.\n  /// @return amountOut The amount of base token received by the receiver.\n  /// @return bonusOut The amount of bonus base token received by the receiver.\n  function redeem(\n    address baseToken,\n    uint256 amountIn,\n    address receiver,\n    uint256 minOut\n  ) external returns (uint256 amountOut, uint256 bonusOut);\n\n  /// @notice Redeem fToken from rebalance pool to base token.\n  /// @param amountIn The amount of fxUSD to redeem.\n  /// @param receiver The address of base token recipient.\n  /// @param minOut The minimum amount of base token should receive.\n  /// @return amountOut The amount of base token received by the receiver.\n  /// @return bonusOut The amount of bonus base token received by the receiver.\n  function redeemFrom(\n    address pool,\n    uint256 amountIn,\n    address receiver,\n    uint256 minOut\n  ) external returns (uint256 amountOut, uint256 bonusOut);\n\n  /// @notice Redeem fxUSD to base token optimally.\n  /// @param amountIn The amount of fxUSD to redeem.\n  /// @param receiver The address of base token recipient.\n  /// @param minOuts The list of minimum amount of base token should receive.\n  /// @return baseTokens The list of base token received by the receiver.\n  /// @return amountOuts The list of amount of base token received by the receiver.\n  /// @return bonusOuts The list of amount of bonus base token received by the receiver.\n  function autoRedeem(\n    uint256 amountIn,\n    address receiver,\n    uint256[] memory minOuts\n  )\n    external\n    returns (\n      address[] memory baseTokens,\n      uint256[] memory amountOuts,\n      uint256[] memory bonusOuts\n    );\n}\n"},"contracts/voting-escrow/interfaces/ILiquidityGauge.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n// solhint-disable func-name-mixedcase\n\ninterface ILiquidityGauge {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when user deposit staking token to this contract.\n  /// @param owner The address of token owner.\n  /// @param receiver The address of recipient for the pool share.\n  /// @param amount The amount of staking token deposited.\n  event Deposit(address indexed owner, address indexed receiver, uint256 amount);\n\n  /// @notice Emitted when user withdraw staking token from this contract.\n  /// @param owner The address of token owner.\n  /// @param receiver The address of recipient for the staking token\n  /// @param amount The amount of staking token withdrawn.\n  event Withdraw(address indexed owner, address indexed receiver, uint256 amount);\n\n  /// @notice Emitted then the working balance is updated.\n  /// @param account The address of user updated.\n  /// @param originalBalance The original pool share of the user.\n  /// @param originalSupply The original total pool share of the contract.\n  /// @param workingBalance The current working balance of the user.\n  /// @param workingSupply The current working supply of the contract.\n  event UpdateLiquidityLimit(\n    address indexed account,\n    uint256 originalBalance,\n    uint256 originalSupply,\n    uint256 workingBalance,\n    uint256 workingSupply\n  );\n\n  /// @notice Emitted when the address of liquidity manager is updated.\n  /// @param oldLiquidityManager The address of previous liquidity manager contract.\n  /// @param newLiquidityManager The address of current liquidity manager contract.\n  event UpdateLiquidityManager(address indexed oldLiquidityManager, address indexed newLiquidityManager);\n\n  /**********\n   * Errors *\n   **********/\n\n  /// @dev Thrown when someone deposit zero amount staking token.\n  error DepositZeroAmount();\n\n  /// @dev Thrown when someone withdraw zero amount staking token.\n  error WithdrawZeroAmount();\n\n  /// @dev Thrown when some unauthorized user call `user_checkpoint`.\n  error UnauthorizedCaller();\n\n  /// @dev Throw when someone try to kick user who has no changes on their ve balance.\n  error KickNotAllowed();\n\n  /// @dev Thrown when someone try to do unnecessary kick.\n  error KickNotNeeded();\n\n  /// @dev Thrown when try to remove an active liquidity manager.\n  error LiquidityManagerIsActive();\n\n  /// @dev Thrown when try to add an inactive liquidity manager.\n  error LiquidityManagerIsNotActive();\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return whether the gauge is active.\n  function isActive() external view returns (bool);\n\n  /// @notice Return the address of staking token.\n  function stakingToken() external view returns (address);\n\n  /// @notice Return the amount of working supply.\n  function workingSupply() external view returns (uint256);\n\n  /// @notice Return the amount of working balance of some user.\n  /// @param account The address of user to query.\n  function workingBalanceOf(address account) external view returns (uint256);\n\n  /// @notice Return the governance token reward integrate for some user.\n  ///\n  /// @dev This is used in TokenMinter.\n  ///\n  /// @param account The address of user to query.\n  function integrate_fraction(address account) external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Initialize the state of LiquidityGauge.\n  ///\n  /// @param _stakingToken The address of staking token.\n  function initialize(address _stakingToken) external;\n\n  /// @notice Deposit some staking token to this contract.\n  ///\n  /// @dev Use `amount = type(uint256).max`, if caller wants to deposit all held staking tokens.\n  ///\n  /// @param amount The amount of staking token to deposit.\n  function deposit(uint256 amount) external;\n\n  /// @notice Deposit some staking token to this contract and transfer the share to others.\n  ///\n  /// @dev Use `amount = type(uint256).max`, if caller wants to deposit all held staking tokens.\n  ///\n  /// @param amount The amount of staking token to deposit.\n  /// @param receiver The address of the pool share recipient.\n  function deposit(uint256 amount, address receiver) external;\n\n  /// @notice Deposit some staking token to this contract and transfer the share to others.\n  ///\n  /// @dev Use `amount = type(uint256).max`, if caller wants to deposit all held staking tokens.\n  ///\n  /// @param amount The amount of staking token to deposit.\n  /// @param receiver The address of the pool share recipient.\n  /// @param manage The parameter passed to possible `LiquidityManager`.\n  function deposit(\n    uint256 amount,\n    address receiver,\n    bool manage\n  ) external;\n\n  /// @notice Withdraw some staking token from this contract.\n  ///\n  /// @dev Use `amount = type(uint256).max`, if caller wants to deposit all held staking tokens.\n  ///\n  /// @param amount The amount of staking token to withdraw.\n  function withdraw(uint256 amount) external;\n\n  /// @notice Withdraw some staking token from this contract and transfer the token to others.\n  ///\n  /// @dev Use `amount = type(uint256).max`, if caller wants to deposit all held staking tokens.\n  ///\n  /// @param amount The amount of staking token to withdraw.\n  /// @param receiver The address of the staking token recipient.\n  function withdraw(uint256 amount, address receiver) external;\n\n  /// @notice Update the snapshot for some user.\n  ///\n  /// @dev This is used in TokenMinter.\n  ///\n  /// @param account The address of user to update.\n  function user_checkpoint(address account) external returns (bool);\n\n  /// @notice Kick some user for abusing their boost.\n  ///\n  /// @dev Only if either they had another voting event, or their voting escrow lock expired.\n  ///\n  /// @param account The address of user to kick.\n  function kick(address account) external;\n}\n"}},"matchId":"20648810","creationMatch":"exact_match","runtimeMatch":"exact_match","verifiedAt":"2026-02-27T17:40:30Z","match":"exact_match","chainId":"1","address":"0xb3c90e64EB6f456A5F5C17Aa99b6aecA6f4a6390"}