{
  "language": "Solidity",
  "sources": {
    "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./OwnableUpgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.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 * By default, the owner account will be the one that deploys the contract. 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 Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {\n    address private _pendingOwner;\n\n    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n    function __Ownable2Step_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable2Step_init_unchained() internal onlyInitializing {\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        require(pendingOwner() == sender, \"Ownable2Step: caller is not the new owner\");\n        _transferOwnership(sender);\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"
    },
    "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"
    },
    "@openzeppelin/contracts-upgradeable/interfaces/IERC4626Upgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4626.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../token/ERC20/IERC20Upgradeable.sol\";\nimport \"../token/ERC20/extensions/IERC20MetadataUpgradeable.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 *\n * _Available since v4.7._\n */\ninterface IERC4626Upgradeable is IERC20Upgradeable, IERC20MetadataUpgradeable {\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-upgradeable/proxy/utils/Initializable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\n *     }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n *     function initializeV2() reinitializer(2) public {\n *         __ERC20Permit_init(\"MyToken\");\n *     }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n *     _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n    /**\n     * @dev Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 version);\n\n    /**\n     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n     * `onlyInitializing` functions can be used to initialize parent contracts.\n     *\n     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n     * constructor.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = !_initializing;\n        require(\n            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n            \"Initializable: contract is already initialized\"\n        );\n        _initialized = 1;\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(1);\n        }\n    }\n\n    /**\n     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n     * used to initialize parent contracts.\n     *\n     * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n     * are added through upgrades and that require initialization.\n     *\n     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n     * cannot be nested. If one is invoked in the context of another, execution will revert.\n     *\n     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n     * a contract, executing them in the right order is up to the developer or operator.\n     *\n     * WARNING: setting the version to 255 will prevent any future reinitialization.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier reinitializer(uint8 version) {\n        require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n        _initialized = version;\n        _initializing = true;\n        _;\n        _initializing = false;\n        emit Initialized(version);\n    }\n\n    /**\n     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n     * {initializer} and {reinitializer} modifiers, directly or indirectly.\n     */\n    modifier onlyInitializing() {\n        require(_initializing, \"Initializable: contract is not initializing\");\n        _;\n    }\n\n    /**\n     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n     * through proxies.\n     *\n     * Emits an {Initialized} event the first time it is successfully executed.\n     */\n    function _disableInitializers() internal virtual {\n        require(!_initializing, \"Initializable: contract is initializing\");\n        if (_initialized != type(uint8).max) {\n            _initialized = type(uint8).max;\n            emit Initialized(type(uint8).max);\n        }\n    }\n\n    /**\n     * @dev Returns the highest version that has been initialized. See {reinitializer}.\n     */\n    function _getInitializedVersion() internal view returns (uint8) {\n        return _initialized;\n    }\n\n    /**\n     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n     */\n    function _isInitializing() internal view returns (bool) {\n        return _initializing;\n    }\n}\n"
    },
    "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\nimport {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    uint256 private _status;\n\n    function __ReentrancyGuard_init() internal onlyInitializing {\n        __ReentrancyGuard_init_unchained();\n    }\n\n    function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be _NOT_ENTERED\n        require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n        // Any calls to nonReentrant after this point will fail\n        _status = _ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        return _status == _ENTERED;\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"
    },
    "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20Upgradeable.sol\";\nimport \"./extensions/IERC20MetadataUpgradeable.sol\";\nimport \"../../utils/ContextUpgradeable.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 * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {\n    mapping(address => uint256) private _balances;\n\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    string private _name;\n    string private _symbol;\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    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        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the default value returned by this function, unless\n     * it's overridden.\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual override returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual override returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(address to, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * NOTE: Does not update the allowance if the current allowance\n     * is the maximum `uint256`.\n     *\n     * Requirements:\n     *\n     * - `from` and `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, amount);\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, allowance(owner, spender) + addedValue);\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        uint256 currentAllowance = allowance(owner, spender);\n        require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n        unchecked {\n            _approve(owner, spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Moves `amount` of tokens from `from` to `to`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     */\n    function _transfer(address from, address to, uint256 amount) internal virtual {\n        require(from != address(0), \"ERC20: transfer from the zero address\");\n        require(to != address(0), \"ERC20: transfer to the zero address\");\n\n        _beforeTokenTransfer(from, to, amount);\n\n        uint256 fromBalance = _balances[from];\n        require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n        unchecked {\n            _balances[from] = fromBalance - amount;\n            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n            // decrementing then incrementing.\n            _balances[to] += amount;\n        }\n\n        emit Transfer(from, to, amount);\n\n        _afterTokenTransfer(from, to, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _mint(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        _beforeTokenTransfer(address(0), account, amount);\n\n        _totalSupply += amount;\n        unchecked {\n            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n            _balances[account] += amount;\n        }\n        emit Transfer(address(0), account, amount);\n\n        _afterTokenTransfer(address(0), account, amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: burn from the zero address\");\n\n        _beforeTokenTransfer(account, address(0), amount);\n\n        uint256 accountBalance = _balances[account];\n        require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n        unchecked {\n            _balances[account] = accountBalance - amount;\n            // Overflow not possible: amount <= accountBalance <= totalSupply.\n            _totalSupply -= amount;\n        }\n\n        emit Transfer(account, address(0), amount);\n\n        _afterTokenTransfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(address owner, address spender, uint256 amount) internal virtual {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n     *\n     * Does not update the allowance amount in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Might emit an {Approval} event.\n     */\n    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n            unchecked {\n                _approve(owner, spender, currentAllowance - amount);\n            }\n        }\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n    /**\n     * @dev Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[45] private __gap;\n}\n"
    },
    "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC4626Upgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/ERC4626.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC20Upgradeable.sol\";\nimport \"../utils/SafeERC20Upgradeable.sol\";\nimport \"../../../interfaces/IERC4626Upgradeable.sol\";\nimport \"../../../utils/math/MathUpgradeable.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 *\n * _Available since v4.7._\n */\nabstract contract ERC4626Upgradeable is Initializable, ERC20Upgradeable, IERC4626Upgradeable {\n    using MathUpgradeable for uint256;\n\n    IERC20Upgradeable private _asset;\n    uint8 private _underlyingDecimals;\n\n    /**\n     * @dev Set the underlying asset contract. This must be an ERC20-compatible contract (ERC20 or ERC777).\n     */\n    function __ERC4626_init(IERC20Upgradeable asset_) internal onlyInitializing {\n        __ERC4626_init_unchained(asset_);\n    }\n\n    function __ERC4626_init_unchained(IERC20Upgradeable asset_) internal onlyInitializing {\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(IERC20Upgradeable asset_) private view returns (bool, uint8) {\n        (bool success, bytes memory encodedDecimals) = address(asset_).staticcall(\n            abi.encodeWithSelector(IERC20MetadataUpgradeable.decimals.selector)\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(IERC20MetadataUpgradeable, ERC20Upgradeable) returns (uint8) {\n        return _underlyingDecimals + _decimalsOffset();\n    }\n\n    /** @dev See {IERC4626-asset}. */\n    function asset() public view virtual override returns (address) {\n        return address(_asset);\n    }\n\n    /** @dev See {IERC4626-totalAssets}. */\n    function totalAssets() public view virtual override returns (uint256) {\n        return _asset.balanceOf(address(this));\n    }\n\n    /** @dev See {IERC4626-convertToShares}. */\n    function convertToShares(uint256 assets) public view virtual override returns (uint256) {\n        return _convertToShares(assets, MathUpgradeable.Rounding.Down);\n    }\n\n    /** @dev See {IERC4626-convertToAssets}. */\n    function convertToAssets(uint256 shares) public view virtual override returns (uint256) {\n        return _convertToAssets(shares, MathUpgradeable.Rounding.Down);\n    }\n\n    /** @dev See {IERC4626-maxDeposit}. */\n    function maxDeposit(address) public view virtual override returns (uint256) {\n        return type(uint256).max;\n    }\n\n    /** @dev See {IERC4626-maxMint}. */\n    function maxMint(address) public view virtual override returns (uint256) {\n        return type(uint256).max;\n    }\n\n    /** @dev See {IERC4626-maxWithdraw}. */\n    function maxWithdraw(address owner) public view virtual override returns (uint256) {\n        return _convertToAssets(balanceOf(owner), MathUpgradeable.Rounding.Down);\n    }\n\n    /** @dev See {IERC4626-maxRedeem}. */\n    function maxRedeem(address owner) public view virtual override returns (uint256) {\n        return balanceOf(owner);\n    }\n\n    /** @dev See {IERC4626-previewDeposit}. */\n    function previewDeposit(uint256 assets) public view virtual override returns (uint256) {\n        return _convertToShares(assets, MathUpgradeable.Rounding.Down);\n    }\n\n    /** @dev See {IERC4626-previewMint}. */\n    function previewMint(uint256 shares) public view virtual override returns (uint256) {\n        return _convertToAssets(shares, MathUpgradeable.Rounding.Up);\n    }\n\n    /** @dev See {IERC4626-previewWithdraw}. */\n    function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {\n        return _convertToShares(assets, MathUpgradeable.Rounding.Up);\n    }\n\n    /** @dev See {IERC4626-previewRedeem}. */\n    function previewRedeem(uint256 shares) public view virtual override returns (uint256) {\n        return _convertToAssets(shares, MathUpgradeable.Rounding.Down);\n    }\n\n    /** @dev See {IERC4626-deposit}. */\n    function deposit(uint256 assets, address receiver) public virtual override returns (uint256) {\n        require(assets <= maxDeposit(receiver), \"ERC4626: deposit more than max\");\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 override returns (uint256) {\n        require(shares <= maxMint(receiver), \"ERC4626: mint more than max\");\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 override returns (uint256) {\n        require(assets <= maxWithdraw(owner), \"ERC4626: withdraw more than max\");\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 override returns (uint256) {\n        require(shares <= maxRedeem(owner), \"ERC4626: redeem more than max\");\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, MathUpgradeable.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, MathUpgradeable.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        // 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        SafeERC20Upgradeable.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        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        SafeERC20Upgradeable.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    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"
    },
    "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20MetadataUpgradeable is IERC20Upgradeable {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"
    },
    "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20PermitUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n *     doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n *     token.safeTransferFrom(msg.sender, address(this), value);\n *     ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20PermitUpgradeable {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     *\n     * CAUTION: See Security Considerations above.\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"
    },
    "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20Upgradeable {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n"
    },
    "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\nimport \"../extensions/IERC20PermitUpgradeable.sol\";\nimport \"../../../utils/AddressUpgradeable.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20Upgradeable {\n    using AddressUpgradeable for address;\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     */\n    function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.\n     * Revert on invalid signature.\n     */\n    function safePermit(\n        IERC20PermitUpgradeable token,\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        uint256 nonceBefore = token.nonces(owner);\n        token.permit(owner, spender, value, deadline, v, r, s);\n        uint256 nonceAfter = token.nonces(owner);\n        require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        require(returndata.length == 0 || abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n        // and not revert is the subcall reverts.\n\n        (bool success, bytes memory returndata) = address(token).call(data);\n        return\n            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token));\n    }\n}\n"
    },
    "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     *\n     * Furthermore, `isContract` will also return true if the target contract within\n     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n     * which only has an effect at the end of a transaction.\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n     *\n     * _Available since v4.8._\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason or using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(bytes memory returndata, string memory errorMessage) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert(errorMessage);\n        }\n    }\n}\n"
    },
    "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)\n\npragma solidity ^0.8.0;\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    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[50] private __gap;\n}\n"
    },
    "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.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 MathUpgradeable {\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/IAccessControl.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n    /**\n     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n     *\n     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n     * {RoleAdminChanged} not being emitted signaling this.\n     *\n     * _Available since v3.1._\n     */\n    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n    /**\n     * @dev Emitted when `account` is granted `role`.\n     *\n     * `sender` is the account that originated the contract call, an admin role\n     * bearer except when using {AccessControl-_setupRole}.\n     */\n    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Emitted when `account` is revoked `role`.\n     *\n     * `sender` is the account that originated the contract call:\n     *   - if using `revokeRole`, it is the admin role bearer\n     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)\n     */\n    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) external view returns (bool);\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function grantRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function revokeRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been granted `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `account`.\n     */\n    function renounceRole(bytes32 role, address account) external;\n}\n"
    },
    "@openzeppelin/contracts/access/Ownable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/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 * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"
    },
    "@openzeppelin/contracts/interfaces/draft-IERC1822.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\n * proxy whose upgrades are fully controlled by the current implementation.\n */\ninterface IERC1822Proxiable {\n    /**\n     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\n     * address.\n     *\n     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\n     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\n     * function revert if invoked through a proxy.\n     */\n    function proxiableUUID() external view returns (bytes32);\n}\n"
    },
    "@openzeppelin/contracts/interfaces/IERC1967.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.\n *\n * _Available since v4.8.3._\n */\ninterface IERC1967 {\n    /**\n     * @dev Emitted when the implementation is upgraded.\n     */\n    event Upgraded(address indexed implementation);\n\n    /**\n     * @dev Emitted when the admin account has changed.\n     */\n    event AdminChanged(address previousAdmin, address newAdmin);\n\n    /**\n     * @dev Emitted when the beacon is changed.\n     */\n    event BeaconUpgraded(address indexed beacon);\n}\n"
    },
    "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (proxy/beacon/BeaconProxy.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IBeacon.sol\";\nimport \"../Proxy.sol\";\nimport \"../ERC1967/ERC1967Upgrade.sol\";\n\n/**\n * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}.\n *\n * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't\n * conflict with the storage layout of the implementation behind the proxy.\n *\n * _Available since v3.4._\n */\ncontract BeaconProxy is Proxy, ERC1967Upgrade {\n    /**\n     * @dev Initializes the proxy with `beacon`.\n     *\n     * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This\n     * will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity\n     * constructor.\n     *\n     * Requirements:\n     *\n     * - `beacon` must be a contract with the interface {IBeacon}.\n     */\n    constructor(address beacon, bytes memory data) payable {\n        _upgradeBeaconToAndCall(beacon, data, false);\n    }\n\n    /**\n     * @dev Returns the current beacon address.\n     */\n    function _beacon() internal view virtual returns (address) {\n        return _getBeacon();\n    }\n\n    /**\n     * @dev Returns the current implementation address of the associated beacon.\n     */\n    function _implementation() internal view virtual override returns (address) {\n        return IBeacon(_getBeacon()).implementation();\n    }\n\n    /**\n     * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}.\n     *\n     * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.\n     *\n     * Requirements:\n     *\n     * - `beacon` must be a contract.\n     * - The implementation returned by `beacon` must be a contract.\n     */\n    function _setBeacon(address beacon, bytes memory data) internal virtual {\n        _upgradeBeaconToAndCall(beacon, data, false);\n    }\n}\n"
    },
    "@openzeppelin/contracts/proxy/beacon/IBeacon.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\n */\ninterface IBeacon {\n    /**\n     * @dev Must return an address that can be used as a delegate call target.\n     *\n     * {BeaconProxy} will check that this address is a contract.\n     */\n    function implementation() external view returns (address);\n}\n"
    },
    "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/UpgradeableBeacon.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IBeacon.sol\";\nimport \"../../access/Ownable.sol\";\nimport \"../../utils/Address.sol\";\n\n/**\n * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their\n * implementation contract, which is where they will delegate all function calls.\n *\n * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon.\n */\ncontract UpgradeableBeacon is IBeacon, Ownable {\n    address private _implementation;\n\n    /**\n     * @dev Emitted when the implementation returned by the beacon is changed.\n     */\n    event Upgraded(address indexed implementation);\n\n    /**\n     * @dev Sets the address of the initial implementation, and the deployer account as the owner who can upgrade the\n     * beacon.\n     */\n    constructor(address implementation_) {\n        _setImplementation(implementation_);\n    }\n\n    /**\n     * @dev Returns the current implementation address.\n     */\n    function implementation() public view virtual override returns (address) {\n        return _implementation;\n    }\n\n    /**\n     * @dev Upgrades the beacon to a new implementation.\n     *\n     * Emits an {Upgraded} event.\n     *\n     * Requirements:\n     *\n     * - msg.sender must be the owner of the contract.\n     * - `newImplementation` must be a contract.\n     */\n    function upgradeTo(address newImplementation) public virtual onlyOwner {\n        _setImplementation(newImplementation);\n        emit Upgraded(newImplementation);\n    }\n\n    /**\n     * @dev Sets the implementation contract address for this beacon\n     *\n     * Requirements:\n     *\n     * - `newImplementation` must be a contract.\n     */\n    function _setImplementation(address newImplementation) private {\n        require(Address.isContract(newImplementation), \"UpgradeableBeacon: implementation is not a contract\");\n        _implementation = newImplementation;\n    }\n}\n"
    },
    "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../beacon/IBeacon.sol\";\nimport \"../../interfaces/IERC1967.sol\";\nimport \"../../interfaces/draft-IERC1822.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/StorageSlot.sol\";\n\n/**\n * @dev This abstract contract provides getters and event emitting update functions for\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\n *\n * _Available since v4.1._\n */\nabstract contract ERC1967Upgrade is IERC1967 {\n    // This is the keccak-256 hash of \"eip1967.proxy.rollback\" subtracted by 1\n    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\n\n    /**\n     * @dev Storage slot with the address of the current implementation.\n     * This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is\n     * validated in the constructor.\n     */\n    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n    /**\n     * @dev Returns the current implementation address.\n     */\n    function _getImplementation() internal view returns (address) {\n        return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n    }\n\n    /**\n     * @dev Stores a new address in the EIP1967 implementation slot.\n     */\n    function _setImplementation(address newImplementation) private {\n        require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n        StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n    }\n\n    /**\n     * @dev Perform implementation upgrade\n     *\n     * Emits an {Upgraded} event.\n     */\n    function _upgradeTo(address newImplementation) internal {\n        _setImplementation(newImplementation);\n        emit Upgraded(newImplementation);\n    }\n\n    /**\n     * @dev Perform implementation upgrade with additional setup call.\n     *\n     * Emits an {Upgraded} event.\n     */\n    function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {\n        _upgradeTo(newImplementation);\n        if (data.length > 0 || forceCall) {\n            Address.functionDelegateCall(newImplementation, data);\n        }\n    }\n\n    /**\n     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\n     *\n     * Emits an {Upgraded} event.\n     */\n    function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {\n        // Upgrades from old implementations will perform a rollback test. This test requires the new\n        // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\n        // this special case will break upgrade paths from old UUPS implementation to new ones.\n        if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {\n            _setImplementation(newImplementation);\n        } else {\n            try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\n                require(slot == _IMPLEMENTATION_SLOT, \"ERC1967Upgrade: unsupported proxiableUUID\");\n            } catch {\n                revert(\"ERC1967Upgrade: new implementation is not UUPS\");\n            }\n            _upgradeToAndCall(newImplementation, data, forceCall);\n        }\n    }\n\n    /**\n     * @dev Storage slot with the admin of the contract.\n     * This is the keccak-256 hash of \"eip1967.proxy.admin\" subtracted by 1, and is\n     * validated in the constructor.\n     */\n    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\n\n    /**\n     * @dev Returns the current admin.\n     */\n    function _getAdmin() internal view returns (address) {\n        return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;\n    }\n\n    /**\n     * @dev Stores a new address in the EIP1967 admin slot.\n     */\n    function _setAdmin(address newAdmin) private {\n        require(newAdmin != address(0), \"ERC1967: new admin is the zero address\");\n        StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\n    }\n\n    /**\n     * @dev Changes the admin of the proxy.\n     *\n     * Emits an {AdminChanged} event.\n     */\n    function _changeAdmin(address newAdmin) internal {\n        emit AdminChanged(_getAdmin(), newAdmin);\n        _setAdmin(newAdmin);\n    }\n\n    /**\n     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\n     * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\n     */\n    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\n\n    /**\n     * @dev Returns the current beacon.\n     */\n    function _getBeacon() internal view returns (address) {\n        return StorageSlot.getAddressSlot(_BEACON_SLOT).value;\n    }\n\n    /**\n     * @dev Stores a new beacon in the EIP1967 beacon slot.\n     */\n    function _setBeacon(address newBeacon) private {\n        require(Address.isContract(newBeacon), \"ERC1967: new beacon is not a contract\");\n        require(\n            Address.isContract(IBeacon(newBeacon).implementation()),\n            \"ERC1967: beacon implementation is not a contract\"\n        );\n        StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;\n    }\n\n    /**\n     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\n     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\n     *\n     * Emits a {BeaconUpgraded} event.\n     */\n    function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {\n        _setBeacon(newBeacon);\n        emit BeaconUpgraded(newBeacon);\n        if (data.length > 0 || forceCall) {\n            Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\n        }\n    }\n}\n"
    },
    "@openzeppelin/contracts/proxy/Proxy.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM\n * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to\n * be specified by overriding the virtual {_implementation} function.\n *\n * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a\n * different contract through the {_delegate} function.\n *\n * The success and return data of the delegated call will be returned back to the caller of the proxy.\n */\nabstract contract Proxy {\n    /**\n     * @dev Delegates the current call to `implementation`.\n     *\n     * This function does not return to its internal call site, it will return directly to the external caller.\n     */\n    function _delegate(address implementation) internal virtual {\n        assembly {\n            // Copy msg.data. We take full control of memory in this inline assembly\n            // block because it will not return to Solidity code. We overwrite the\n            // Solidity scratch pad at memory position 0.\n            calldatacopy(0, 0, calldatasize())\n\n            // Call the implementation.\n            // out and outsize are 0 because we don't know the size yet.\n            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\n\n            // Copy the returned data.\n            returndatacopy(0, 0, returndatasize())\n\n            switch result\n            // delegatecall returns 0 on error.\n            case 0 {\n                revert(0, returndatasize())\n            }\n            default {\n                return(0, returndatasize())\n            }\n        }\n    }\n\n    /**\n     * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function\n     * and {_fallback} should delegate.\n     */\n    function _implementation() internal view virtual returns (address);\n\n    /**\n     * @dev Delegates the current call to the address returned by `_implementation()`.\n     *\n     * This function does not return to its internal call site, it will return directly to the external caller.\n     */\n    function _fallback() internal virtual {\n        _beforeFallback();\n        _delegate(_implementation());\n    }\n\n    /**\n     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\n     * function in the contract matches the call data.\n     */\n    fallback() external payable virtual {\n        _fallback();\n    }\n\n    /**\n     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data\n     * is empty.\n     */\n    receive() external payable virtual {\n        _fallback();\n    }\n\n    /**\n     * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`\n     * call, or as part of the Solidity `fallback` or `receive` functions.\n     *\n     * If overridden should call `super._beforeFallback()`.\n     */\n    function _beforeFallback() internal virtual {}\n}\n"
    },
    "@openzeppelin/contracts/utils/Address.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     *\n     * Furthermore, `isContract` will also return true if the target contract within\n     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n     * which only has an effect at the end of a transaction.\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n     *\n     * _Available since v4.8._\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason or using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(bytes memory returndata, string memory errorMessage) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert(errorMessage);\n        }\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/Context.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/StorageSlot.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC1967 implementation slot:\n * ```solidity\n * contract ERC1967 {\n *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n *     function _getImplementation() internal view returns (address) {\n *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n *     }\n *\n *     function _setImplementation(address newImplementation) internal {\n *         require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n *     }\n * }\n * ```\n *\n * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._\n * _Available since v4.9 for `string`, `bytes`._\n */\nlibrary StorageSlot {\n    struct AddressSlot {\n        address value;\n    }\n\n    struct BooleanSlot {\n        bool value;\n    }\n\n    struct Bytes32Slot {\n        bytes32 value;\n    }\n\n    struct Uint256Slot {\n        uint256 value;\n    }\n\n    struct StringSlot {\n        string value;\n    }\n\n    struct BytesSlot {\n        bytes value;\n    }\n\n    /**\n     * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n     */\n    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\n     */\n    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\n     */\n    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\n     */\n    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `StringSlot` with member `value` located at `slot`.\n     */\n    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\n     */\n    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := store.slot\n        }\n    }\n\n    /**\n     * @dev Returns an `BytesSlot` with member `value` located at `slot`.\n     */\n    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\n     */\n    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := store.slot\n        }\n    }\n}\n"
    },
    "@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\n\nimport \"./IAccessControlManagerV8.sol\";\n\n/**\n * @title AccessControlledV8\n * @author Venus\n * @notice This contract is helper between access control manager and actual contract. This contract further inherited by other contract (using solidity 0.8.13)\n * to integrate access controlled mechanism. It provides initialise methods and verifying access methods.\n */\nabstract contract AccessControlledV8 is Initializable, Ownable2StepUpgradeable {\n    /// @notice Access control manager contract\n    IAccessControlManagerV8 internal _accessControlManager;\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n\n    /// @notice Emitted when access control manager contract address is changed\n    event NewAccessControlManager(address oldAccessControlManager, address newAccessControlManager);\n\n    /// @notice Thrown when the action is prohibited by AccessControlManager\n    error Unauthorized(address sender, address calledContract, string methodSignature);\n\n    function __AccessControlled_init(address accessControlManager_) internal onlyInitializing {\n        __Ownable2Step_init();\n        __AccessControlled_init_unchained(accessControlManager_);\n    }\n\n    function __AccessControlled_init_unchained(address accessControlManager_) internal onlyInitializing {\n        _setAccessControlManager(accessControlManager_);\n    }\n\n    /**\n     * @notice Sets the address of AccessControlManager\n     * @dev Admin function to set address of AccessControlManager\n     * @param accessControlManager_ The new address of the AccessControlManager\n     * @custom:event Emits NewAccessControlManager event\n     * @custom:access Only Governance\n     */\n    function setAccessControlManager(address accessControlManager_) external onlyOwner {\n        _setAccessControlManager(accessControlManager_);\n    }\n\n    /**\n     * @notice Returns the address of the access control manager contract\n     */\n    function accessControlManager() external view returns (IAccessControlManagerV8) {\n        return _accessControlManager;\n    }\n\n    /**\n     * @dev Internal function to set address of AccessControlManager\n     * @param accessControlManager_ The new address of the AccessControlManager\n     */\n    function _setAccessControlManager(address accessControlManager_) internal {\n        require(address(accessControlManager_) != address(0), \"invalid acess control manager address\");\n        address oldAccessControlManager = address(_accessControlManager);\n        _accessControlManager = IAccessControlManagerV8(accessControlManager_);\n        emit NewAccessControlManager(oldAccessControlManager, accessControlManager_);\n    }\n\n    /**\n     * @notice Reverts if the call is not allowed by AccessControlManager\n     * @param signature Method signature\n     */\n    function _checkAccessAllowed(string memory signature) internal view {\n        bool isAllowedToCall = _accessControlManager.isAllowedToCall(msg.sender, signature);\n\n        if (!isAllowedToCall) {\n            revert Unauthorized(msg.sender, address(this), signature);\n        }\n    }\n}\n"
    },
    "@venusprotocol/governance-contracts/contracts/Governance/IAccessControlManagerV8.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\nimport \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\n/**\n * @title IAccessControlManagerV8\n * @author Venus\n * @notice Interface implemented by the `AccessControlManagerV8` contract.\n */\ninterface IAccessControlManagerV8 is IAccessControl {\n    function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) external;\n\n    function revokeCallPermission(\n        address contractAddress,\n        string calldata functionSig,\n        address accountToRevoke\n    ) external;\n\n    function isAllowedToCall(address account, string calldata functionSig) external view returns (bool);\n\n    function hasPermission(\n        address account,\n        address contractAddress,\n        string calldata functionSig\n    ) external view returns (bool);\n}\n"
    },
    "@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\ninterface OracleInterface {\n    function getPrice(address asset) external view returns (uint256);\n}\n\ninterface ResilientOracleInterface is OracleInterface {\n    function updatePrice(address vToken) external;\n\n    function updateAssetPrice(address asset) external;\n\n    function getUnderlyingPrice(address vToken) external view returns (uint256);\n}\n\ninterface TwapInterface is OracleInterface {\n    function updateTwap(address asset) external returns (uint256);\n}\n\ninterface BoundValidatorInterface {\n    function validatePriceWithAnchorPrice(\n        address asset,\n        uint256 reporterPrice,\n        uint256 anchorPrice\n    ) external view returns (bool);\n}\n"
    },
    "@venusprotocol/protocol-reserve/contracts/Interfaces/IProtocolShareReserve.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\ninterface IProtocolShareReserve {\n    /// @notice it represents the type of vToken income\n    enum IncomeType {\n        SPREAD,\n        LIQUIDATION\n    }\n\n    function updateAssetsState(\n        address comptroller,\n        address asset,\n        IncomeType incomeType\n    ) external;\n}\n"
    },
    "@venusprotocol/solidity-utilities/contracts/constants.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\n/// @dev Base unit for computations, usually used in scaling (multiplications, divisions)\nuint256 constant EXP_SCALE = 1e18;\n\n/// @dev A unit (literal one) in EXP_SCALE, usually used in additions/subtractions\nuint256 constant MANTISSA_ONE = EXP_SCALE;\n\n/// @dev The approximate number of seconds per year\nuint256 constant SECONDS_PER_YEAR = 31_536_000;\n"
    },
    "@venusprotocol/solidity-utilities/contracts/TimeManagerV8.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { SECONDS_PER_YEAR } from \"./constants.sol\";\n\nabstract contract TimeManagerV8 {\n    /// @notice Stores blocksPerYear if isTimeBased is true else secondsPerYear is stored\n    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n    uint256 public immutable blocksOrSecondsPerYear;\n\n    /// @notice Acknowledges if a contract is time based or not\n    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n    bool public immutable isTimeBased;\n\n    /// @notice Stores the current block timestamp or block number depending on isTimeBased\n    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n    function() view returns (uint256) private immutable _getCurrentSlot;\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[48] private __gap;\n\n    /// @notice Thrown when blocks per year is invalid\n    error InvalidBlocksPerYear();\n\n    /// @notice Thrown when time based but blocks per year is provided\n    error InvalidTimeBasedConfiguration();\n\n    /**\n     * @param timeBased_ A boolean indicating whether the contract is based on time or block\n     * If timeBased is true than blocksPerYear_ param is ignored as blocksOrSecondsPerYear is set to SECONDS_PER_YEAR\n     * @param blocksPerYear_ The number of blocks per year\n     * @custom:error InvalidBlocksPerYear is thrown if blocksPerYear entered is zero and timeBased is false\n     * @custom:error InvalidTimeBasedConfiguration is thrown if blocksPerYear entered is non zero and timeBased is true\n     * @custom:oz-upgrades-unsafe-allow constructor\n     */\n    constructor(bool timeBased_, uint256 blocksPerYear_) {\n        if (!timeBased_ && blocksPerYear_ == 0) {\n            revert InvalidBlocksPerYear();\n        }\n\n        if (timeBased_ && blocksPerYear_ != 0) {\n            revert InvalidTimeBasedConfiguration();\n        }\n\n        isTimeBased = timeBased_;\n        blocksOrSecondsPerYear = timeBased_ ? SECONDS_PER_YEAR : blocksPerYear_;\n        _getCurrentSlot = timeBased_ ? _getBlockTimestamp : _getBlockNumber;\n    }\n\n    /**\n     * @dev Function to simply retrieve block number or block timestamp\n     * @return Current block number or block timestamp\n     */\n    function getBlockNumberOrTimestamp() public view virtual returns (uint256) {\n        return _getCurrentSlot();\n    }\n\n    /**\n     * @dev Returns the current timestamp in seconds\n     * @return The current timestamp\n     */\n    function _getBlockTimestamp() private view returns (uint256) {\n        return block.timestamp;\n    }\n\n    /**\n     * @dev Returns the current block number\n     * @return The current block number\n     */\n    function _getBlockNumber() private view returns (uint256) {\n        return block.number;\n    }\n}\n"
    },
    "@venusprotocol/solidity-utilities/contracts/validators.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\n/// @notice Thrown if the supplied address is a zero address where it is not allowed\nerror ZeroAddressNotAllowed();\n\n/// @notice Thrown if the supplied value is 0 where it is not allowed\nerror ZeroValueNotAllowed();\n\n/// @notice Checks if the provided address is nonzero, reverts otherwise\n/// @param address_ Address to check\n/// @custom:error ZeroAddressNotAllowed is thrown if the provided address is a zero address\nfunction ensureNonzeroAddress(address address_) pure {\n    if (address_ == address(0)) {\n        revert ZeroAddressNotAllowed();\n    }\n}\n\n/// @notice Checks if the provided value is nonzero, reverts otherwise\n/// @param value_ Value to check\n/// @custom:error ZeroValueNotAllowed is thrown if the provided value is 0\nfunction ensureNonzeroValue(uint256 value_) pure {\n    if (value_ == 0) {\n        revert ZeroValueNotAllowed();\n    }\n}\n"
    },
    "@venusprotocol/venus-protocol/contracts/Tokens/Prime/Interfaces/IPrime.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\nimport { PrimeStorageV1 } from \"../PrimeStorage.sol\";\n\n/**\n * @title IPrime\n * @author Venus\n * @notice Interface for Prime Token\n */\ninterface IPrime {\n    struct APRInfo {\n        // supply APR of the user in BPS\n        uint256 supplyAPR;\n        // borrow APR of the user in BPS\n        uint256 borrowAPR;\n        // total score of the market\n        uint256 totalScore;\n        // score of the user\n        uint256 userScore;\n        // capped XVS balance of the user\n        uint256 xvsBalanceForScore;\n        // capital of the user\n        uint256 capital;\n        // capped supply of the user\n        uint256 cappedSupply;\n        // capped borrow of the user\n        uint256 cappedBorrow;\n        // capped supply of user in USD\n        uint256 supplyCapUSD;\n        // capped borrow of user in USD\n        uint256 borrowCapUSD;\n    }\n\n    struct Capital {\n        // capital of the user\n        uint256 capital;\n        // capped supply of the user\n        uint256 cappedSupply;\n        // capped borrow of the user\n        uint256 cappedBorrow;\n        // capped supply of user in USD\n        uint256 supplyCapUSD;\n        // capped borrow of user in USD\n        uint256 borrowCapUSD;\n    }\n\n    /**\n     * @notice Returns boosted pending interest accrued for a user for all markets\n     * @param user the account for which to get the accrued interests\n     * @return pendingRewards the number of underlying tokens accrued by the user for all markets\n     */\n    function getPendingRewards(address user) external returns (PrimeStorageV1.PendingReward[] memory pendingRewards);\n\n    /**\n     * @notice Update total score of multiple users and market\n     * @param users accounts for which we need to update score\n     */\n    function updateScores(address[] memory users) external;\n\n    /**\n     * @notice Update value of alpha\n     * @param _alphaNumerator numerator of alpha. If alpha is 0.5 then numerator is 1\n     * @param _alphaDenominator denominator of alpha. If alpha is 0.5 then denominator is 2\n     */\n    function updateAlpha(uint128 _alphaNumerator, uint128 _alphaDenominator) external;\n\n    /**\n     * @notice Update multipliers for a market\n     * @param market address of the market vToken\n     * @param supplyMultiplier new supply multiplier for the market, scaled by 1e18\n     * @param borrowMultiplier new borrow multiplier for the market, scaled by 1e18\n     */\n    function updateMultipliers(address market, uint256 supplyMultiplier, uint256 borrowMultiplier) external;\n\n    /**\n     * @notice Add a market to prime program\n     * @param comptroller address of the comptroller\n     * @param market address of the market vToken\n     * @param supplyMultiplier the multiplier for supply cap. It should be converted to 1e18\n     * @param borrowMultiplier the multiplier for borrow cap. It should be converted to 1e18\n     */\n    function addMarket(\n        address comptroller,\n        address market,\n        uint256 supplyMultiplier,\n        uint256 borrowMultiplier\n    ) external;\n\n    /**\n     * @notice Set limits for total tokens that can be minted\n     * @param _irrevocableLimit total number of irrevocable tokens that can be minted\n     * @param _revocableLimit total number of revocable tokens that can be minted\n     */\n    function setLimit(uint256 _irrevocableLimit, uint256 _revocableLimit) external;\n\n    /**\n     * @notice Directly issue prime tokens to users\n     * @param isIrrevocable are the tokens being issued\n     * @param users list of address to issue tokens to\n     */\n    function issue(bool isIrrevocable, address[] calldata users) external;\n\n    /**\n     * @notice Executed by XVSVault whenever user's XVSVault balance changes\n     * @param user the account address whose balance was updated\n     */\n    function xvsUpdated(address user) external;\n\n    /**\n     * @notice accrues interest and updates score for an user for a specific market\n     * @param user the account address for which to accrue interest and update score\n     * @param market the market for which to accrue interest and update score\n     */\n    function accrueInterestAndUpdateScore(address user, address market) external;\n\n    /**\n     * @notice For claiming prime token when staking period is completed\n     */\n    function claim() external;\n\n    /**\n     * @notice For burning any prime token\n     * @param user the account address for which the prime token will be burned\n     */\n    function burn(address user) external;\n\n    /**\n     * @notice To pause or unpause claiming of interest\n     */\n    function togglePause() external;\n\n    /**\n     * @notice For user to claim boosted yield\n     * @param vToken the market for which claim the accrued interest\n     * @return amount the amount of tokens transferred to the user\n     */\n    function claimInterest(address vToken) external returns (uint256);\n\n    /**\n     * @notice For user to claim boosted yield\n     * @param vToken the market for which claim the accrued interest\n     * @param user the user for which to claim the accrued interest\n     * @return amount the amount of tokens transferred to the user\n     */\n    function claimInterest(address vToken, address user) external returns (uint256);\n\n    /**\n     * @notice Distributes income from market since last distribution\n     * @param vToken the market for which to distribute the income\n     */\n    function accrueInterest(address vToken) external;\n\n    /**\n     * @notice Returns boosted interest accrued for a user\n     * @param vToken the market for which to fetch the accrued interest\n     * @param user the account for which to get the accrued interest\n     * @return interestAccrued the number of underlying tokens accrued by the user since the last accrual\n     */\n    function getInterestAccrued(address vToken, address user) external returns (uint256);\n\n    /**\n     * @notice Retrieves an array of all available markets\n     * @return an array of addresses representing all available markets\n     */\n    function getAllMarkets() external view returns (address[] memory);\n\n    /**\n     * @notice fetch the numbers of seconds remaining for staking period to complete\n     * @param user the account address for which we are checking the remaining time\n     * @return timeRemaining the number of seconds the user needs to wait to claim prime token\n     */\n    function claimTimeRemaining(address user) external view returns (uint256);\n\n    /**\n     * @notice Returns supply and borrow APR for user for a given market\n     * @param market the market for which to fetch the APR\n     * @param user the account for which to get the APR\n     * @return aprInfo APR information for the user for the given market\n     */\n    function calculateAPR(address market, address user) external view returns (APRInfo memory aprInfo);\n\n    /**\n     * @notice Returns supply and borrow APR for estimated supply, borrow and XVS staked\n     * @param market the market for which to fetch the APR\n     * @param user the account for which to get the APR\n     * @param borrow hypothetical borrow amount\n     * @param supply hypothetical supply amount\n     * @param xvsStaked hypothetical staked XVS amount\n     * @return aprInfo APR information for the user for the given market\n     */\n    function estimateAPR(\n        address market,\n        address user,\n        uint256 borrow,\n        uint256 supply,\n        uint256 xvsStaked\n    ) external view returns (APRInfo memory aprInfo);\n\n    /**\n     * @notice the total income that's going to be distributed in a year to prime token holders\n     * @param vToken the market for which to fetch the total income that's going to distributed in a year\n     * @return amount the total income\n     */\n    function incomeDistributionYearly(address vToken) external view returns (uint256 amount);\n\n    /**\n     * @notice Returns if user is a prime holder\n     * @return isPrimeHolder true if user is a prime holder\n     */\n    function isUserPrimeHolder(address user) external view returns (bool);\n\n    /**\n     * @notice Set the limit for the loops can iterate to avoid the DOS\n     * @param loopsLimit Number of loops limit\n     */\n    function setMaxLoopsLimit(uint256 loopsLimit) external;\n\n    /**\n     * @notice Update staked at timestamp for multiple users\n     * @param users accounts for which we need to update staked at timestamp\n     * @param timestamps new staked at timestamp for the users\n     */\n    function setStakedAt(address[] calldata users, uint256[] calldata timestamps) external;\n}\n"
    },
    "@venusprotocol/venus-protocol/contracts/Tokens/Prime/PrimeStorage.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\n/**\n * @title PrimeStorageV1\n * @author Venus\n * @notice Storage for Prime Token\n */\ncontract PrimeStorageV1 {\n    struct Token {\n        bool exists;\n        bool isIrrevocable;\n    }\n\n    struct Market {\n        uint256 supplyMultiplier;\n        uint256 borrowMultiplier;\n        uint256 rewardIndex;\n        uint256 sumOfMembersScore;\n        bool exists;\n    }\n\n    struct Interest {\n        uint256 accrued;\n        uint256 score;\n        uint256 rewardIndex;\n    }\n\n    struct PendingReward {\n        address vToken;\n        address rewardToken;\n        uint256 amount;\n    }\n\n    /// @notice Base unit for computations, usually used in scaling (multiplications, divisions)\n    uint256 internal constant EXP_SCALE = 1e18;\n\n    /// @notice maximum BPS = 100%\n    uint256 internal constant MAXIMUM_BPS = 1e4;\n\n    /// @notice Mapping to get prime token's metadata\n    mapping(address => Token) public tokens;\n\n    /// @notice  Tracks total irrevocable tokens minted\n    uint256 public totalIrrevocable;\n\n    /// @notice  Tracks total revocable tokens minted\n    uint256 public totalRevocable;\n\n    /// @notice  Indicates maximum revocable tokens that can be minted\n    uint256 public revocableLimit;\n\n    /// @notice  Indicates maximum irrevocable tokens that can be minted\n    uint256 public irrevocableLimit;\n\n    /// @notice Tracks when prime token eligible users started staking for claiming prime token\n    mapping(address => uint256) public stakedAt;\n\n    /// @notice vToken to market configuration\n    mapping(address => Market) public markets;\n\n    /// @notice vToken to user to user index\n    mapping(address => mapping(address => Interest)) public interests;\n\n    /// @notice A list of boosted markets\n    address[] internal _allMarkets;\n\n    /// @notice numerator of alpha. Ex: if alpha is 0.5 then this will be 1\n    uint128 public alphaNumerator;\n\n    /// @notice denominator of alpha. Ex: if alpha is 0.5 then this will be 2\n    uint128 public alphaDenominator;\n\n    /// @notice address of XVS vault\n    address public xvsVault;\n\n    /// @notice address of XVS vault reward token\n    address public xvsVaultRewardToken;\n\n    /// @notice address of XVS vault pool id\n    uint256 public xvsVaultPoolId;\n\n    /// @notice mapping to check if a account's score was updated in the round\n    mapping(uint256 => mapping(address => bool)) public isScoreUpdated;\n\n    /// @notice unique id for next round\n    uint256 public nextScoreUpdateRoundId;\n\n    /// @notice total number of accounts whose score needs to be updated\n    uint256 public totalScoreUpdatesRequired;\n\n    /// @notice total number of accounts whose score is yet to be updated\n    uint256 public pendingScoreUpdates;\n\n    /// @notice mapping used to find if an asset is part of prime markets\n    mapping(address => address) public vTokenForAsset;\n\n    /// @notice Address of core pool comptroller contract\n    address internal corePoolComptroller;\n\n    /// @notice unreleased income from PLP that's already distributed to prime holders\n    /// @dev mapping of asset address => amount\n    mapping(address => uint256) public unreleasedPLPIncome;\n\n    /// @notice The address of PLP contract\n    address public primeLiquidityProvider;\n\n    /// @notice The address of ResilientOracle contract\n    ResilientOracleInterface public oracle;\n\n    /// @notice The address of PoolRegistry contract\n    address public poolRegistry;\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    uint256[26] private __gap;\n}\n"
    },
    "contracts/Comptroller.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\nimport { IPrime } from \"@venusprotocol/venus-protocol/contracts/Tokens/Prime/Interfaces/IPrime.sol\";\n\nimport { ComptrollerInterface, Action } from \"./ComptrollerInterface.sol\";\nimport { ComptrollerStorage } from \"./ComptrollerStorage.sol\";\nimport { ExponentialNoError } from \"./ExponentialNoError.sol\";\nimport { VToken } from \"./VToken.sol\";\nimport { RewardsDistributor } from \"./Rewards/RewardsDistributor.sol\";\nimport { MaxLoopsLimitHelper } from \"./MaxLoopsLimitHelper.sol\";\nimport { ensureNonzeroAddress } from \"./lib/validators.sol\";\n\n/**\n * @title Comptroller\n * @author Venus\n * @notice The Comptroller is designed to provide checks for all minting, redeeming, transferring, borrowing, lending, repaying, liquidating,\n * and seizing done by the `vToken` contract. Each pool has one `Comptroller` checking these interactions across markets. When a user interacts\n * with a given market by one of these main actions, a call is made to a corresponding hook in the associated `Comptroller`, which either allows\n * or reverts the transaction. These hooks also update supply and borrow rewards as they are called. The comptroller holds the logic for assessing\n * liquidity snapshots of an account via the collateral factor and liquidation threshold. This check determines the collateral needed for a borrow,\n * as well as how much of a borrow may be liquidated. A user may borrow a portion of their collateral with the maximum amount determined by the\n * markets collateral factor. However, if their borrowed amount exceeds an amount calculated using the market’s corresponding liquidation threshold,\n * the borrow is eligible for liquidation.\n *\n * The `Comptroller` also includes two functions `liquidateAccount()` and `healAccount()`, which are meant to handle accounts that do not exceed\n * the `minLiquidatableCollateral` for the `Comptroller`:\n *\n * - `healAccount()`: This function is called to seize all of a given user’s collateral, requiring the `msg.sender` repay a certain percentage\n * of the debt calculated by `collateral/(borrows*liquidationIncentive)`. The function can only be called if the calculated percentage does not exceed\n * 100%, because otherwise no `badDebt` would be created and `liquidateAccount()` should be used instead. The difference in the actual amount of debt\n * and debt paid off is recorded as `badDebt` for each market, which can then be auctioned off for the risk reserves of the associated pool.\n * - `liquidateAccount()`: This function can only be called if the collateral seized will cover all borrows of an account, as well as the liquidation\n * incentive. Otherwise, the pool will incur bad debt, in which case the function `healAccount()` should be used instead. This function skips the logic\n * verifying that the repay amount does not exceed the close factor.\n */\ncontract Comptroller is\n    Ownable2StepUpgradeable,\n    AccessControlledV8,\n    ComptrollerStorage,\n    ComptrollerInterface,\n    ExponentialNoError,\n    MaxLoopsLimitHelper\n{\n    // PoolRegistry, immutable to save on gas\n    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n    address public immutable poolRegistry;\n\n    /// @notice Emitted when an account enters a market\n    event MarketEntered(VToken indexed vToken, address indexed account);\n\n    /// @notice Emitted when an account exits a market\n    event MarketExited(VToken indexed vToken, address indexed account);\n\n    /// @notice Emitted when close factor is changed by admin\n    event NewCloseFactor(uint256 oldCloseFactorMantissa, uint256 newCloseFactorMantissa);\n\n    /// @notice Emitted when a collateral factor is changed by admin\n    event NewCollateralFactor(VToken vToken, uint256 oldCollateralFactorMantissa, uint256 newCollateralFactorMantissa);\n\n    /// @notice Emitted when liquidation threshold is changed by admin\n    event NewLiquidationThreshold(\n        VToken vToken,\n        uint256 oldLiquidationThresholdMantissa,\n        uint256 newLiquidationThresholdMantissa\n    );\n\n    /// @notice Emitted when liquidation incentive is changed by admin\n    event NewLiquidationIncentive(uint256 oldLiquidationIncentiveMantissa, uint256 newLiquidationIncentiveMantissa);\n\n    /// @notice Emitted when price oracle is changed\n    event NewPriceOracle(ResilientOracleInterface oldPriceOracle, ResilientOracleInterface newPriceOracle);\n\n    /// @notice Emitted when an action is paused on a market\n    event ActionPausedMarket(VToken vToken, Action action, bool pauseState);\n\n    /// @notice Emitted when borrow cap for a vToken is changed\n    event NewBorrowCap(VToken indexed vToken, uint256 newBorrowCap);\n\n    /// @notice Emitted when the collateral threshold (in USD) for non-batch liquidations is changed\n    event NewMinLiquidatableCollateral(uint256 oldMinLiquidatableCollateral, uint256 newMinLiquidatableCollateral);\n\n    /// @notice Emitted when supply cap for a vToken is changed\n    event NewSupplyCap(VToken indexed vToken, uint256 newSupplyCap);\n\n    /// @notice Emitted when a rewards distributor is added\n    event NewRewardsDistributor(address indexed rewardsDistributor, address indexed rewardToken);\n\n    /// @notice Emitted when a market is supported\n    event MarketSupported(VToken vToken);\n\n    /// @notice Emitted when prime token contract address is changed\n    event NewPrimeToken(IPrime oldPrimeToken, IPrime newPrimeToken);\n\n    /// @notice Emitted when forced liquidation is enabled or disabled for a market\n    event IsForcedLiquidationEnabledUpdated(address indexed vToken, bool enable);\n\n    /// @notice Emitted when a market is unlisted\n    event MarketUnlisted(address indexed vToken);\n    /// @notice Emitted when the borrowing or redeeming delegate rights are updated for an account\n    event DelegateUpdated(address indexed approver, address indexed delegate, bool approved);\n\n    /// @notice Thrown when collateral factor exceeds the upper bound\n    error InvalidCollateralFactor();\n\n    /// @notice Thrown when liquidation threshold exceeds the collateral factor\n    error InvalidLiquidationThreshold();\n\n    /// @notice Thrown when the action is only available to specific sender, but the real sender was different\n    error UnexpectedSender(address expectedSender, address actualSender);\n\n    /// @notice Thrown when the oracle returns an invalid price for some asset\n    error PriceError(address vToken);\n\n    /// @notice Thrown if VToken unexpectedly returned a nonzero error code while trying to get account snapshot\n    error SnapshotError(address vToken, address user);\n\n    /// @notice Thrown when the market is not listed\n    error MarketNotListed(address market);\n\n    /// @notice Thrown when a market has an unexpected comptroller\n    error ComptrollerMismatch();\n\n    /// @notice Thrown when user is not member of market\n    error MarketNotCollateral(address vToken, address user);\n\n    /// @notice Thrown when borrow action is not paused\n    error BorrowActionNotPaused();\n\n    /// @notice Thrown when mint action is not paused\n    error MintActionNotPaused();\n\n    /// @notice Thrown when redeem action is not paused\n    error RedeemActionNotPaused();\n\n    /// @notice Thrown when repay action is not paused\n    error RepayActionNotPaused();\n\n    /// @notice Thrown when seize action is not paused\n    error SeizeActionNotPaused();\n\n    /// @notice Thrown when exit market action is not paused\n    error ExitMarketActionNotPaused();\n\n    /// @notice Thrown when transfer action is not paused\n    error TransferActionNotPaused();\n\n    /// @notice Thrown when enter market action is not paused\n    error EnterMarketActionNotPaused();\n\n    /// @notice Thrown when liquidate action is not paused\n    error LiquidateActionNotPaused();\n\n    /// @notice Thrown when borrow cap is not zero\n    error BorrowCapIsNotZero();\n\n    /// @notice Thrown when supply cap is not zero\n    error SupplyCapIsNotZero();\n\n    /// @notice Thrown when collateral factor is not zero\n    error CollateralFactorIsNotZero();\n\n    /**\n     * @notice Thrown during the liquidation if user's total collateral amount is lower than\n     *   a predefined threshold. In this case only batch liquidations (either liquidateAccount\n     *   or healAccount) are available.\n     */\n    error MinimalCollateralViolated(uint256 expectedGreaterThan, uint256 actual);\n    error CollateralExceedsThreshold(uint256 expectedLessThanOrEqualTo, uint256 actual);\n    error InsufficientCollateral(uint256 collateralToSeize, uint256 availableCollateral);\n\n    /// @notice Thrown when the account doesn't have enough liquidity to redeem or borrow\n    error InsufficientLiquidity();\n\n    /// @notice Thrown when trying to liquidate a healthy account\n    error InsufficientShortfall();\n\n    /// @notice Thrown when trying to repay more than allowed by close factor\n    error TooMuchRepay();\n\n    /// @notice Thrown if the user is trying to exit a market in which they have an outstanding debt\n    error NonzeroBorrowBalance();\n\n    /// @notice Thrown when trying to perform an action that is paused\n    error ActionPaused(address market, Action action);\n\n    /// @notice Thrown when trying to add a market that is already listed\n    error MarketAlreadyListed(address market);\n\n    /// @notice Thrown if the supply cap is exceeded\n    error SupplyCapExceeded(address market, uint256 cap);\n\n    /// @notice Thrown if the borrow cap is exceeded\n    error BorrowCapExceeded(address market, uint256 cap);\n\n    /// @notice Thrown if delegate approval status is already set to the requested value\n    error DelegationStatusUnchanged();\n\n    /// @param poolRegistry_ Pool registry address\n    /// @custom:oz-upgrades-unsafe-allow constructor\n    /// @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n    constructor(address poolRegistry_) {\n        ensureNonzeroAddress(poolRegistry_);\n\n        poolRegistry = poolRegistry_;\n        _disableInitializers();\n    }\n\n    /**\n     * @param loopLimit Limit for the loops can iterate to avoid the DOS\n     * @param accessControlManager Access control manager contract address\n     */\n    function initialize(uint256 loopLimit, address accessControlManager) external initializer {\n        __Ownable2Step_init();\n        __AccessControlled_init_unchained(accessControlManager);\n\n        _setMaxLoopsLimit(loopLimit);\n    }\n\n    /**\n     * @notice Add assets to be included in account liquidity calculation; enabling them to be used as collateral\n     * @param vTokens The list of addresses of the vToken markets to be enabled\n     * @return errors An array of NO_ERROR for compatibility with Venus core tooling\n     * @custom:event MarketEntered is emitted for each market on success\n     * @custom:error ActionPaused error is thrown if entering any of the markets is paused\n     * @custom:error MarketNotListed error is thrown if any of the markets is not listed\n     * @custom:access Not restricted\n     */\n    function enterMarkets(address[] memory vTokens) external override returns (uint256[] memory) {\n        uint256 len = vTokens.length;\n\n        uint256[] memory results = new uint256[](len);\n        for (uint256 i; i < len; ++i) {\n            VToken vToken = VToken(vTokens[i]);\n\n            _addToMarket(vToken, msg.sender);\n            results[i] = NO_ERROR;\n        }\n\n        return results;\n    }\n\n    /**\n     * @notice Unlist a market by setting isListed to false\n     * @dev Checks if all actions are paused, borrow/supply caps is set to 0 and collateral factor is to 0.\n     * @param market The address of the market (token) to unlist\n     * @return uint256 Always NO_ERROR for compatibility with Venus core tooling\n     * @custom:event MarketUnlisted is emitted on success\n     * @custom:error MarketNotListed error is thrown when the market is not listed\n     * @custom:error BorrowActionNotPaused error is thrown if borrow action is not paused\n     * @custom:error MintActionNotPaused error is thrown if mint action is not paused\n     * @custom:error RedeemActionNotPaused error is thrown if redeem action is not paused\n     * @custom:error RepayActionNotPaused error is thrown if repay action is not paused\n     * @custom:error EnterMarketActionNotPaused error is thrown if enter market action is not paused\n     * @custom:error LiquidateActionNotPaused error is thrown if liquidate action is not paused\n     * @custom:error BorrowCapIsNotZero error is thrown if borrow cap is not zero\n     * @custom:error SupplyCapIsNotZero error is thrown if supply cap is not zero\n     * @custom:error CollateralFactorIsNotZero error is thrown if collateral factor is not zero\n     */\n    function unlistMarket(address market) external returns (uint256) {\n        _checkAccessAllowed(\"unlistMarket(address)\");\n\n        Market storage _market = markets[market];\n\n        if (!_market.isListed) {\n            revert MarketNotListed(market);\n        }\n\n        if (!actionPaused(market, Action.BORROW)) {\n            revert BorrowActionNotPaused();\n        }\n\n        if (!actionPaused(market, Action.MINT)) {\n            revert MintActionNotPaused();\n        }\n\n        if (!actionPaused(market, Action.REDEEM)) {\n            revert RedeemActionNotPaused();\n        }\n\n        if (!actionPaused(market, Action.REPAY)) {\n            revert RepayActionNotPaused();\n        }\n\n        if (!actionPaused(market, Action.SEIZE)) {\n            revert SeizeActionNotPaused();\n        }\n\n        if (!actionPaused(market, Action.ENTER_MARKET)) {\n            revert EnterMarketActionNotPaused();\n        }\n\n        if (!actionPaused(market, Action.LIQUIDATE)) {\n            revert LiquidateActionNotPaused();\n        }\n\n        if (!actionPaused(market, Action.TRANSFER)) {\n            revert TransferActionNotPaused();\n        }\n\n        if (!actionPaused(market, Action.EXIT_MARKET)) {\n            revert ExitMarketActionNotPaused();\n        }\n\n        if (borrowCaps[market] != 0) {\n            revert BorrowCapIsNotZero();\n        }\n\n        if (supplyCaps[market] != 0) {\n            revert SupplyCapIsNotZero();\n        }\n\n        if (_market.collateralFactorMantissa != 0) {\n            revert CollateralFactorIsNotZero();\n        }\n\n        _market.isListed = false;\n        emit MarketUnlisted(market);\n\n        return NO_ERROR;\n    }\n\n    /**\n     * @notice Grants or revokes the borrowing or redeeming delegate rights to / from an account\n     *  If allowed, the delegate will be able to borrow funds on behalf of the sender\n     *  Upon a delegated borrow, the delegate will receive the funds, and the borrower\n     *  will see the debt on their account\n     *  Upon a delegated redeem, the delegate will receive the redeemed amount and the approver\n     *  will see a deduction in his vToken balance\n     * @param delegate The address to update the rights for\n     * @param approved Whether to grant (true) or revoke (false) the borrowing or redeeming rights\n     * @custom:event DelegateUpdated emits on success\n     * @custom:error ZeroAddressNotAllowed is thrown when delegate address is zero\n     * @custom:error DelegationStatusUnchanged is thrown if approval status is already set to the requested value\n     * @custom:access Not restricted\n     */\n    function updateDelegate(address delegate, bool approved) external {\n        ensureNonzeroAddress(delegate);\n        if (approvedDelegates[msg.sender][delegate] == approved) {\n            revert DelegationStatusUnchanged();\n        }\n\n        approvedDelegates[msg.sender][delegate] = approved;\n        emit DelegateUpdated(msg.sender, delegate, approved);\n    }\n\n    /**\n     * @notice Removes asset from sender's account liquidity calculation; disabling them as collateral\n     * @dev Sender must not have an outstanding borrow balance in the asset,\n     *  or be providing necessary collateral for an outstanding borrow.\n     * @param vTokenAddress The address of the asset to be removed\n     * @return error Always NO_ERROR for compatibility with Venus core tooling\n     * @custom:event MarketExited is emitted on success\n     * @custom:error ActionPaused error is thrown if exiting the market is paused\n     * @custom:error NonzeroBorrowBalance error is thrown if the user has an outstanding borrow in this market\n     * @custom:error MarketNotListed error is thrown when the market is not listed\n     * @custom:error InsufficientLiquidity error is thrown if exiting the market would lead to user's insolvency\n     * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n     * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n     * @custom:access Not restricted\n     */\n    function exitMarket(address vTokenAddress) external override returns (uint256) {\n        _checkActionPauseState(vTokenAddress, Action.EXIT_MARKET);\n        VToken vToken = VToken(vTokenAddress);\n        /* Get sender tokensHeld and amountOwed underlying from the vToken */\n        (uint256 tokensHeld, uint256 amountOwed, ) = _safeGetAccountSnapshot(vToken, msg.sender);\n\n        /* Fail if the sender has a borrow balance */\n        if (amountOwed != 0) {\n            revert NonzeroBorrowBalance();\n        }\n\n        /* Fail if the sender is not permitted to redeem all of their tokens */\n        _checkRedeemAllowed(vTokenAddress, msg.sender, tokensHeld);\n\n        Market storage marketToExit = markets[address(vToken)];\n\n        /* Return true if the sender is not already ‘in’ the market */\n        if (!marketToExit.accountMembership[msg.sender]) {\n            return NO_ERROR;\n        }\n\n        /* Set vToken account membership to false */\n        delete marketToExit.accountMembership[msg.sender];\n\n        /* Delete vToken from the account’s list of assets */\n        // load into memory for faster iteration\n        VToken[] memory userAssetList = accountAssets[msg.sender];\n        uint256 len = userAssetList.length;\n\n        uint256 assetIndex = len;\n        for (uint256 i; i < len; ++i) {\n            if (userAssetList[i] == vToken) {\n                assetIndex = i;\n                break;\n            }\n        }\n\n        // We *must* have found the asset in the list or our redundant data structure is broken\n        assert(assetIndex < len);\n\n        // copy last item in list to location of item to be removed, reduce length by 1\n        VToken[] storage storedList = accountAssets[msg.sender];\n        storedList[assetIndex] = storedList[storedList.length - 1];\n        storedList.pop();\n\n        emit MarketExited(vToken, msg.sender);\n\n        return NO_ERROR;\n    }\n\n    /*** Policy Hooks ***/\n\n    /**\n     * @notice Checks if the account should be allowed to mint tokens in the given market\n     * @param vToken The market to verify the mint against\n     * @param minter The account which would get the minted tokens\n     * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens\n     * @custom:error ActionPaused error is thrown if supplying to this market is paused\n     * @custom:error MarketNotListed error is thrown when the market is not listed\n     * @custom:error SupplyCapExceeded error is thrown if the total supply exceeds the cap after minting\n     * @custom:access Not restricted\n     */\n    function preMintHook(address vToken, address minter, uint256 mintAmount) external override {\n        _checkActionPauseState(vToken, Action.MINT);\n\n        if (!markets[vToken].isListed) {\n            revert MarketNotListed(address(vToken));\n        }\n\n        uint256 supplyCap = supplyCaps[vToken];\n        // Skipping the cap check for uncapped coins to save some gas\n        if (supplyCap != type(uint256).max) {\n            uint256 vTokenSupply = VToken(vToken).totalSupply();\n            Exp memory exchangeRate = Exp({ mantissa: VToken(vToken).exchangeRateStored() });\n            uint256 nextTotalSupply = mul_ScalarTruncateAddUInt(exchangeRate, vTokenSupply, mintAmount);\n            if (nextTotalSupply > supplyCap) {\n                revert SupplyCapExceeded(vToken, supplyCap);\n            }\n        }\n\n        // Keep the flywheel moving\n        uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n        for (uint256 i; i < rewardDistributorsCount; ++i) {\n            RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n            rewardsDistributor.updateRewardTokenSupplyIndex(vToken);\n            rewardsDistributor.distributeSupplierRewardToken(vToken, minter);\n        }\n    }\n\n    /**\n     * @notice Validates mint, accrues interest and updates score in prime. Reverts on rejection. May emit logs.\n     * @param vToken Asset being minted\n     * @param minter The address minting the tokens\n     * @param actualMintAmount The amount of the underlying asset being minted\n     * @param mintTokens The number of tokens being minted\n     */\n    // solhint-disable-next-line no-unused-vars\n    function mintVerify(address vToken, address minter, uint256 actualMintAmount, uint256 mintTokens) external {\n        if (address(prime) != address(0)) {\n            prime.accrueInterestAndUpdateScore(minter, vToken);\n        }\n    }\n\n    /**\n     * @notice Checks if the account should be allowed to redeem tokens in the given market\n     * @param vToken The market to verify the redeem against\n     * @param redeemer The account which would redeem the tokens\n     * @param redeemTokens The number of vTokens to exchange for the underlying asset in the market\n     * @custom:error ActionPaused error is thrown if withdrawals are paused in this market\n     * @custom:error MarketNotListed error is thrown when the market is not listed\n     * @custom:error InsufficientLiquidity error is thrown if the withdrawal would lead to user's insolvency\n     * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n     * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n     * @custom:access Not restricted\n     */\n    function preRedeemHook(address vToken, address redeemer, uint256 redeemTokens) external override {\n        _checkActionPauseState(vToken, Action.REDEEM);\n\n        _checkRedeemAllowed(vToken, redeemer, redeemTokens);\n\n        // Keep the flywheel moving\n        uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n        for (uint256 i; i < rewardDistributorsCount; ++i) {\n            RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n            rewardsDistributor.updateRewardTokenSupplyIndex(vToken);\n            rewardsDistributor.distributeSupplierRewardToken(vToken, redeemer);\n        }\n    }\n\n    /**\n     * @notice Validates redeem, accrues interest and updates score in prime. Reverts on rejection. May emit logs.\n     * @param vToken Asset being redeemed\n     * @param redeemer The address redeeming the tokens\n     * @param redeemAmount The amount of the underlying asset being redeemed\n     * @param redeemTokens The number of tokens being redeemed\n     */\n    function redeemVerify(address vToken, address redeemer, uint256 redeemAmount, uint256 redeemTokens) external {\n        if (address(prime) != address(0)) {\n            prime.accrueInterestAndUpdateScore(redeemer, vToken);\n        }\n    }\n\n    /**\n     * @notice Validates repayBorrow, accrues interest and updates score in prime. Reverts on rejection. May emit logs.\n     * @param vToken Asset being repaid\n     * @param payer The address repaying the borrow\n     * @param borrower The address of the borrower\n     * @param actualRepayAmount The amount of underlying being repaid\n     */\n    function repayBorrowVerify(\n        address vToken,\n        address payer, // solhint-disable-line no-unused-vars\n        address borrower,\n        uint256 actualRepayAmount, // solhint-disable-line no-unused-vars\n        uint256 borrowerIndex // solhint-disable-line no-unused-vars\n    ) external {\n        if (address(prime) != address(0)) {\n            prime.accrueInterestAndUpdateScore(borrower, vToken);\n        }\n    }\n\n    /**\n     * @notice Validates liquidateBorrow, accrues interest and updates score in prime. Reverts on rejection. May emit logs.\n     * @param vTokenBorrowed Asset which was borrowed by the borrower\n     * @param vTokenCollateral Asset which was used as collateral and will be seized\n     * @param liquidator The address repaying the borrow and seizing the collateral\n     * @param borrower The address of the borrower\n     * @param actualRepayAmount The amount of underlying being repaid\n     * @param seizeTokens The amount of collateral token that will be seized\n     */\n    function liquidateBorrowVerify(\n        address vTokenBorrowed,\n        address vTokenCollateral, // solhint-disable-line no-unused-vars\n        address liquidator,\n        address borrower,\n        uint256 actualRepayAmount, // solhint-disable-line no-unused-vars\n        uint256 seizeTokens // solhint-disable-line no-unused-vars\n    ) external {\n        if (address(prime) != address(0)) {\n            prime.accrueInterestAndUpdateScore(borrower, vTokenBorrowed);\n            prime.accrueInterestAndUpdateScore(liquidator, vTokenBorrowed);\n        }\n    }\n\n    /**\n     * @notice Validates seize, accrues interest and updates score in prime. Reverts on rejection. May emit logs.\n     * @param vTokenCollateral Asset which was used as collateral and will be seized\n     * @param vTokenBorrowed Asset which was borrowed by the borrower\n     * @param liquidator The address repaying the borrow and seizing the collateral\n     * @param borrower The address of the borrower\n     * @param seizeTokens The number of collateral tokens to seize\n     */\n    function seizeVerify(\n        address vTokenCollateral,\n        address vTokenBorrowed, // solhint-disable-line no-unused-vars\n        address liquidator,\n        address borrower,\n        uint256 seizeTokens // solhint-disable-line no-unused-vars\n    ) external {\n        if (address(prime) != address(0)) {\n            prime.accrueInterestAndUpdateScore(borrower, vTokenCollateral);\n            prime.accrueInterestAndUpdateScore(liquidator, vTokenCollateral);\n        }\n    }\n\n    /**\n     * @notice Validates transfer, accrues interest and updates score in prime. Reverts on rejection. May emit logs.\n     * @param vToken Asset being transferred\n     * @param src The account which sources the tokens\n     * @param dst The account which receives the tokens\n     * @param transferTokens The number of vTokens to transfer\n     */\n    // solhint-disable-next-line no-unused-vars\n    function transferVerify(address vToken, address src, address dst, uint256 transferTokens) external {\n        if (address(prime) != address(0)) {\n            prime.accrueInterestAndUpdateScore(src, vToken);\n            prime.accrueInterestAndUpdateScore(dst, vToken);\n        }\n    }\n\n    /**\n     * @notice Checks if the account should be allowed to borrow the underlying asset of the given market\n     * @param vToken The market to verify the borrow against\n     * @param borrower The account which would borrow the asset\n     * @param borrowAmount The amount of underlying the account would borrow\n     * @custom:error ActionPaused error is thrown if borrowing is paused in this market\n     * @custom:error MarketNotListed error is thrown when the market is not listed\n     * @custom:error InsufficientLiquidity error is thrown if there is not enough collateral to borrow\n     * @custom:error BorrowCapExceeded is thrown if the borrow cap will be exceeded should this borrow succeed\n     * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n     * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n     * @custom:access Not restricted if vToken is enabled as collateral, otherwise only vToken\n     */\n    /// disable-eslint\n    function preBorrowHook(address vToken, address borrower, uint256 borrowAmount) external override {\n        _checkActionPauseState(vToken, Action.BORROW);\n\n        if (!markets[vToken].isListed) {\n            revert MarketNotListed(address(vToken));\n        }\n\n        if (!markets[vToken].accountMembership[borrower]) {\n            // only vTokens may call borrowAllowed if borrower not in market\n            _checkSenderIs(vToken);\n\n            // attempt to add borrower to the market or revert\n            _addToMarket(VToken(msg.sender), borrower);\n        }\n\n        // Update the prices of tokens\n        updatePrices(borrower);\n\n        if (oracle.getUnderlyingPrice(vToken) == 0) {\n            revert PriceError(address(vToken));\n        }\n\n        uint256 borrowCap = borrowCaps[vToken];\n        // Skipping the cap check for uncapped coins to save some gas\n        if (borrowCap != type(uint256).max) {\n            uint256 totalBorrows = VToken(vToken).totalBorrows();\n            uint256 badDebt = VToken(vToken).badDebt();\n            uint256 nextTotalBorrows = totalBorrows + borrowAmount + badDebt;\n            if (nextTotalBorrows > borrowCap) {\n                revert BorrowCapExceeded(vToken, borrowCap);\n            }\n        }\n\n        AccountLiquiditySnapshot memory snapshot = _getHypotheticalLiquiditySnapshot(\n            borrower,\n            VToken(vToken),\n            0,\n            borrowAmount,\n            _getCollateralFactor\n        );\n\n        if (snapshot.shortfall > 0) {\n            revert InsufficientLiquidity();\n        }\n\n        Exp memory borrowIndex = Exp({ mantissa: VToken(vToken).borrowIndex() });\n\n        // Keep the flywheel moving\n        uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n        for (uint256 i; i < rewardDistributorsCount; ++i) {\n            RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n            rewardsDistributor.updateRewardTokenBorrowIndex(vToken, borrowIndex);\n            rewardsDistributor.distributeBorrowerRewardToken(vToken, borrower, borrowIndex);\n        }\n    }\n\n    /**\n     * @notice Validates borrow, accrues interest and updates score in prime. Reverts on rejection. May emit logs.\n     * @param vToken Asset whose underlying is being borrowed\n     * @param borrower The address borrowing the underlying\n     * @param borrowAmount The amount of the underlying asset requested to borrow\n     */\n    // solhint-disable-next-line no-unused-vars\n    function borrowVerify(address vToken, address borrower, uint256 borrowAmount) external {\n        if (address(prime) != address(0)) {\n            prime.accrueInterestAndUpdateScore(borrower, vToken);\n        }\n    }\n\n    /**\n     * @notice Checks if the account should be allowed to repay a borrow in the given market\n     * @param vToken The market to verify the repay against\n     * @param borrower The account which would borrowed the asset\n     * @custom:error ActionPaused error is thrown if repayments are paused in this market\n     * @custom:error MarketNotListed error is thrown when the market is not listed\n     * @custom:access Not restricted\n     */\n    function preRepayHook(address vToken, address borrower) external override {\n        _checkActionPauseState(vToken, Action.REPAY);\n\n        oracle.updatePrice(vToken);\n\n        if (!markets[vToken].isListed) {\n            revert MarketNotListed(address(vToken));\n        }\n\n        // Keep the flywheel moving\n        uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n        for (uint256 i; i < rewardDistributorsCount; ++i) {\n            Exp memory borrowIndex = Exp({ mantissa: VToken(vToken).borrowIndex() });\n            RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n            rewardsDistributor.updateRewardTokenBorrowIndex(vToken, borrowIndex);\n            rewardsDistributor.distributeBorrowerRewardToken(vToken, borrower, borrowIndex);\n        }\n    }\n\n    /**\n     * @notice Checks if the liquidation should be allowed to occur\n     * @param vTokenBorrowed Asset which was borrowed by the borrower\n     * @param vTokenCollateral Asset which was used as collateral and will be seized\n     * @param borrower The address of the borrower\n     * @param repayAmount The amount of underlying being repaid\n     * @param skipLiquidityCheck Allows the borrow to be liquidated regardless of the account liquidity\n     * @custom:error ActionPaused error is thrown if liquidations are paused in this market\n     * @custom:error MarketNotListed error is thrown if either collateral or borrowed token is not listed\n     * @custom:error TooMuchRepay error is thrown if the liquidator is trying to repay more than allowed by close factor\n     * @custom:error MinimalCollateralViolated is thrown if the users' total collateral is lower than the threshold for non-batch liquidations\n     * @custom:error InsufficientShortfall is thrown when trying to liquidate a healthy account\n     * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n     * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n     */\n    function preLiquidateHook(\n        address vTokenBorrowed,\n        address vTokenCollateral,\n        address borrower,\n        uint256 repayAmount,\n        bool skipLiquidityCheck\n    ) external override {\n        // Pause Action.LIQUIDATE on BORROWED TOKEN to prevent liquidating it.\n        // If we want to pause liquidating to vTokenCollateral, we should pause\n        // Action.SEIZE on it\n        _checkActionPauseState(vTokenBorrowed, Action.LIQUIDATE);\n\n        // Update the prices of tokens\n        updatePrices(borrower);\n\n        if (!markets[vTokenBorrowed].isListed) {\n            revert MarketNotListed(address(vTokenBorrowed));\n        }\n        if (!markets[vTokenCollateral].isListed) {\n            revert MarketNotListed(address(vTokenCollateral));\n        }\n\n        uint256 borrowBalance = VToken(vTokenBorrowed).borrowBalanceStored(borrower);\n\n        /* Allow accounts to be liquidated if it is a forced liquidation */\n        if (skipLiquidityCheck || isForcedLiquidationEnabled[vTokenBorrowed]) {\n            if (repayAmount > borrowBalance) {\n                revert TooMuchRepay();\n            }\n            return;\n        }\n\n        /* The borrower must have shortfall and collateral > threshold in order to be liquidatable */\n        AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(borrower, _getLiquidationThreshold);\n\n        if (snapshot.totalCollateral <= minLiquidatableCollateral) {\n            /* The liquidator should use either liquidateAccount or healAccount */\n            revert MinimalCollateralViolated(minLiquidatableCollateral, snapshot.totalCollateral);\n        }\n\n        if (snapshot.shortfall == 0) {\n            revert InsufficientShortfall();\n        }\n\n        /* The liquidator may not repay more than what is allowed by the closeFactor */\n        uint256 maxClose = mul_ScalarTruncate(Exp({ mantissa: closeFactorMantissa }), borrowBalance);\n        if (repayAmount > maxClose) {\n            revert TooMuchRepay();\n        }\n    }\n\n    /**\n     * @notice Checks if the seizing of assets should be allowed to occur\n     * @param vTokenCollateral Asset which was used as collateral and will be seized\n     * @param seizerContract Contract that tries to seize the asset (either borrowed vToken or Comptroller)\n     * @param liquidator The address repaying the borrow and seizing the collateral\n     * @param borrower The address of the borrower\n     * @custom:error ActionPaused error is thrown if seizing this type of collateral is paused\n     * @custom:error MarketNotListed error is thrown if either collateral or borrowed token is not listed\n     * @custom:error ComptrollerMismatch error is when seizer contract or seized asset belong to different pools\n     * @custom:access Not restricted\n     */\n    function preSeizeHook(\n        address vTokenCollateral,\n        address seizerContract,\n        address liquidator,\n        address borrower\n    ) external override {\n        // Pause Action.SEIZE on COLLATERAL to prevent seizing it.\n        // If we want to pause liquidating vTokenBorrowed, we should pause\n        // Action.LIQUIDATE on it\n        _checkActionPauseState(vTokenCollateral, Action.SEIZE);\n\n        Market storage market = markets[vTokenCollateral];\n\n        if (!market.isListed) {\n            revert MarketNotListed(vTokenCollateral);\n        }\n\n        if (seizerContract == address(this)) {\n            // If Comptroller is the seizer, just check if collateral's comptroller\n            // is equal to the current address\n            if (address(VToken(vTokenCollateral).comptroller()) != address(this)) {\n                revert ComptrollerMismatch();\n            }\n        } else {\n            // If the seizer is not the Comptroller, check that the seizer is a\n            // listed market, and that the markets' comptrollers match\n            if (!markets[seizerContract].isListed) {\n                revert MarketNotListed(seizerContract);\n            }\n            if (VToken(vTokenCollateral).comptroller() != VToken(seizerContract).comptroller()) {\n                revert ComptrollerMismatch();\n            }\n        }\n\n        if (!market.accountMembership[borrower]) {\n            revert MarketNotCollateral(vTokenCollateral, borrower);\n        }\n\n        // Keep the flywheel moving\n        uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n        for (uint256 i; i < rewardDistributorsCount; ++i) {\n            RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n            rewardsDistributor.updateRewardTokenSupplyIndex(vTokenCollateral);\n            rewardsDistributor.distributeSupplierRewardToken(vTokenCollateral, borrower);\n            rewardsDistributor.distributeSupplierRewardToken(vTokenCollateral, liquidator);\n        }\n    }\n\n    /**\n     * @notice Checks if the account should be allowed to transfer tokens in the given market\n     * @param vToken The market to verify the transfer against\n     * @param src The account which sources the tokens\n     * @param dst The account which receives the tokens\n     * @param transferTokens The number of vTokens to transfer\n     * @custom:error ActionPaused error is thrown if withdrawals are paused in this market\n     * @custom:error MarketNotListed error is thrown when the market is not listed\n     * @custom:error InsufficientLiquidity error is thrown if the withdrawal would lead to user's insolvency\n     * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n     * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n     * @custom:access Not restricted\n     */\n    function preTransferHook(address vToken, address src, address dst, uint256 transferTokens) external override {\n        _checkActionPauseState(vToken, Action.TRANSFER);\n\n        // Currently the only consideration is whether or not\n        //  the src is allowed to redeem this many tokens\n        _checkRedeemAllowed(vToken, src, transferTokens);\n\n        // Keep the flywheel moving\n        uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n        for (uint256 i; i < rewardDistributorsCount; ++i) {\n            RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n            rewardsDistributor.updateRewardTokenSupplyIndex(vToken);\n            rewardsDistributor.distributeSupplierRewardToken(vToken, src);\n            rewardsDistributor.distributeSupplierRewardToken(vToken, dst);\n        }\n    }\n\n    /*** Pool-level operations ***/\n\n    /**\n     * @notice Seizes all the remaining collateral, makes msg.sender repay the existing\n     *   borrows, and treats the rest of the debt as bad debt (for each market).\n     *   The sender has to repay a certain percentage of the debt, computed as\n     *   collateral / (borrows * liquidationIncentive).\n     * @param user account to heal\n     * @custom:error CollateralExceedsThreshold error is thrown when the collateral is too big for healing\n     * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n     * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n     * @custom:access Not restricted\n     */\n    function healAccount(address user) external {\n        VToken[] memory userAssets = getAssetsIn(user);\n        uint256 userAssetsCount = userAssets.length;\n\n        address liquidator = msg.sender;\n        {\n            ResilientOracleInterface oracle_ = oracle;\n            // We need all user's markets to be fresh for the computations to be correct\n            for (uint256 i; i < userAssetsCount; ++i) {\n                userAssets[i].accrueInterest();\n                oracle_.updatePrice(address(userAssets[i]));\n            }\n        }\n\n        AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(user, _getLiquidationThreshold);\n\n        if (snapshot.totalCollateral > minLiquidatableCollateral) {\n            revert CollateralExceedsThreshold(minLiquidatableCollateral, snapshot.totalCollateral);\n        }\n\n        if (snapshot.shortfall == 0) {\n            revert InsufficientShortfall();\n        }\n\n        // percentage = collateral / (borrows * liquidation incentive)\n        Exp memory collateral = Exp({ mantissa: snapshot.totalCollateral });\n        Exp memory scaledBorrows = mul_(\n            Exp({ mantissa: snapshot.borrows }),\n            Exp({ mantissa: liquidationIncentiveMantissa })\n        );\n\n        Exp memory percentage = div_(collateral, scaledBorrows);\n        if (lessThanExp(Exp({ mantissa: MANTISSA_ONE }), percentage)) {\n            revert CollateralExceedsThreshold(scaledBorrows.mantissa, collateral.mantissa);\n        }\n\n        for (uint256 i; i < userAssetsCount; ++i) {\n            VToken market = userAssets[i];\n\n            (uint256 tokens, uint256 borrowBalance, ) = _safeGetAccountSnapshot(market, user);\n            uint256 repaymentAmount = mul_ScalarTruncate(percentage, borrowBalance);\n\n            // Seize the entire collateral\n            if (tokens != 0) {\n                market.seize(liquidator, user, tokens);\n            }\n            // Repay a certain percentage of the borrow, forgive the rest\n            if (borrowBalance != 0) {\n                market.healBorrow(liquidator, user, repaymentAmount);\n            }\n        }\n    }\n\n    /**\n     * @notice Liquidates all borrows of the borrower. Callable only if the collateral is less than\n     *   a predefined threshold, and the account collateral can be seized to cover all borrows. If\n     *   the collateral is higher than the threshold, use regular liquidations. If the collateral is\n     *   below the threshold, and the account is insolvent, use healAccount.\n     * @param borrower the borrower address\n     * @param orders an array of liquidation orders\n     * @custom:error CollateralExceedsThreshold error is thrown when the collateral is too big for a batch liquidation\n     * @custom:error InsufficientCollateral error is thrown when there is not enough collateral to cover the debt\n     * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n     * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n     * @custom:access Not restricted\n     */\n    function liquidateAccount(address borrower, LiquidationOrder[] calldata orders) external {\n        // We will accrue interest and update the oracle prices later during the liquidation\n\n        AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(borrower, _getLiquidationThreshold);\n\n        if (snapshot.totalCollateral > minLiquidatableCollateral) {\n            // You should use the regular vToken.liquidateBorrow(...) call\n            revert CollateralExceedsThreshold(minLiquidatableCollateral, snapshot.totalCollateral);\n        }\n\n        uint256 collateralToSeize = mul_ScalarTruncate(\n            Exp({ mantissa: liquidationIncentiveMantissa }),\n            snapshot.borrows\n        );\n        if (collateralToSeize >= snapshot.totalCollateral) {\n            // There is not enough collateral to seize. Use healBorrow to repay some part of the borrow\n            // and record bad debt.\n            revert InsufficientCollateral(collateralToSeize, snapshot.totalCollateral);\n        }\n\n        if (snapshot.shortfall == 0) {\n            revert InsufficientShortfall();\n        }\n\n        uint256 ordersCount = orders.length;\n\n        _ensureMaxLoops(ordersCount / 2);\n\n        for (uint256 i; i < ordersCount; ++i) {\n            if (!markets[address(orders[i].vTokenBorrowed)].isListed) {\n                revert MarketNotListed(address(orders[i].vTokenBorrowed));\n            }\n            if (!markets[address(orders[i].vTokenCollateral)].isListed) {\n                revert MarketNotListed(address(orders[i].vTokenCollateral));\n            }\n\n            LiquidationOrder calldata order = orders[i];\n            order.vTokenBorrowed.forceLiquidateBorrow(\n                msg.sender,\n                borrower,\n                order.repayAmount,\n                order.vTokenCollateral,\n                true\n            );\n        }\n\n        VToken[] memory borrowMarkets = getAssetsIn(borrower);\n        uint256 marketsCount = borrowMarkets.length;\n\n        for (uint256 i; i < marketsCount; ++i) {\n            (, uint256 borrowBalance, ) = _safeGetAccountSnapshot(borrowMarkets[i], borrower);\n            require(borrowBalance == 0, \"Nonzero borrow balance after liquidation\");\n        }\n    }\n\n    /**\n     * @notice Sets the closeFactor to use when liquidating borrows\n     * @param newCloseFactorMantissa New close factor, scaled by 1e18\n     * @custom:event Emits NewCloseFactor on success\n     * @custom:access Controlled by AccessControlManager\n     */\n    function setCloseFactor(uint256 newCloseFactorMantissa) external {\n        _checkAccessAllowed(\"setCloseFactor(uint256)\");\n        require(MAX_CLOSE_FACTOR_MANTISSA >= newCloseFactorMantissa, \"Close factor greater than maximum close factor\");\n        require(MIN_CLOSE_FACTOR_MANTISSA <= newCloseFactorMantissa, \"Close factor smaller than minimum close factor\");\n\n        uint256 oldCloseFactorMantissa = closeFactorMantissa;\n        closeFactorMantissa = newCloseFactorMantissa;\n        emit NewCloseFactor(oldCloseFactorMantissa, newCloseFactorMantissa);\n    }\n\n    /**\n     * @notice Sets the collateralFactor for a market\n     * @dev This function is restricted by the AccessControlManager\n     * @param vToken The market to set the factor on\n     * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18\n     * @param newLiquidationThresholdMantissa The new liquidation threshold, scaled by 1e18\n     * @custom:event Emits NewCollateralFactor when collateral factor is updated\n     *    and NewLiquidationThreshold when liquidation threshold is updated\n     * @custom:error MarketNotListed error is thrown when the market is not listed\n     * @custom:error InvalidCollateralFactor error is thrown when collateral factor is too high\n     * @custom:error InvalidLiquidationThreshold error is thrown when liquidation threshold is lower than collateral factor\n     * @custom:error PriceError is thrown when the oracle returns an invalid price for the asset\n     * @custom:access Controlled by AccessControlManager\n     */\n    function setCollateralFactor(\n        VToken vToken,\n        uint256 newCollateralFactorMantissa,\n        uint256 newLiquidationThresholdMantissa\n    ) external {\n        _checkAccessAllowed(\"setCollateralFactor(address,uint256,uint256)\");\n\n        // Verify market is listed\n        Market storage market = markets[address(vToken)];\n        if (!market.isListed) {\n            revert MarketNotListed(address(vToken));\n        }\n\n        // Check collateral factor <= 0.9\n        if (newCollateralFactorMantissa > MAX_COLLATERAL_FACTOR_MANTISSA) {\n            revert InvalidCollateralFactor();\n        }\n\n        // Ensure that liquidation threshold <= 1\n        if (newLiquidationThresholdMantissa > MANTISSA_ONE) {\n            revert InvalidLiquidationThreshold();\n        }\n\n        // Ensure that liquidation threshold >= CF\n        if (newLiquidationThresholdMantissa < newCollateralFactorMantissa) {\n            revert InvalidLiquidationThreshold();\n        }\n\n        // If collateral factor != 0, fail if price == 0\n        if (newCollateralFactorMantissa != 0 && oracle.getUnderlyingPrice(address(vToken)) == 0) {\n            revert PriceError(address(vToken));\n        }\n\n        uint256 oldCollateralFactorMantissa = market.collateralFactorMantissa;\n        if (newCollateralFactorMantissa != oldCollateralFactorMantissa) {\n            market.collateralFactorMantissa = newCollateralFactorMantissa;\n            emit NewCollateralFactor(vToken, oldCollateralFactorMantissa, newCollateralFactorMantissa);\n        }\n\n        uint256 oldLiquidationThresholdMantissa = market.liquidationThresholdMantissa;\n        if (newLiquidationThresholdMantissa != oldLiquidationThresholdMantissa) {\n            market.liquidationThresholdMantissa = newLiquidationThresholdMantissa;\n            emit NewLiquidationThreshold(vToken, oldLiquidationThresholdMantissa, newLiquidationThresholdMantissa);\n        }\n    }\n\n    /**\n     * @notice Sets liquidationIncentive\n     * @dev This function is restricted by the AccessControlManager\n     * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18\n     * @custom:event Emits NewLiquidationIncentive on success\n     * @custom:access Controlled by AccessControlManager\n     */\n    function setLiquidationIncentive(uint256 newLiquidationIncentiveMantissa) external {\n        require(newLiquidationIncentiveMantissa >= MANTISSA_ONE, \"liquidation incentive should be greater than 1e18\");\n\n        _checkAccessAllowed(\"setLiquidationIncentive(uint256)\");\n\n        // Save current value for use in log\n        uint256 oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa;\n\n        // Set liquidation incentive to new incentive\n        liquidationIncentiveMantissa = newLiquidationIncentiveMantissa;\n\n        // Emit event with old incentive, new incentive\n        emit NewLiquidationIncentive(oldLiquidationIncentiveMantissa, newLiquidationIncentiveMantissa);\n    }\n\n    /**\n     * @notice Add the market to the markets mapping and set it as listed\n     * @dev Only callable by the PoolRegistry\n     * @param vToken The address of the market (token) to list\n     * @custom:error MarketAlreadyListed is thrown if the market is already listed in this pool\n     * @custom:access Only PoolRegistry\n     */\n    function supportMarket(VToken vToken) external {\n        _checkSenderIs(poolRegistry);\n\n        if (markets[address(vToken)].isListed) {\n            revert MarketAlreadyListed(address(vToken));\n        }\n\n        require(vToken.isVToken(), \"Comptroller: Invalid vToken\"); // Sanity check to make sure its really a VToken\n\n        Market storage newMarket = markets[address(vToken)];\n        newMarket.isListed = true;\n        newMarket.collateralFactorMantissa = 0;\n        newMarket.liquidationThresholdMantissa = 0;\n\n        _addMarket(address(vToken));\n\n        uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n        for (uint256 i; i < rewardDistributorsCount; ++i) {\n            rewardsDistributors[i].initializeMarket(address(vToken));\n        }\n\n        emit MarketSupported(vToken);\n    }\n\n    /**\n     * @notice Set the given borrow caps for the given vToken markets. Borrowing that brings total borrows to or above borrow cap will revert.\n     * @dev This function is restricted by the AccessControlManager\n     * @dev A borrow cap of type(uint256).max corresponds to unlimited borrowing.\n     * @dev Borrow caps smaller than the current total borrows are accepted. This way, new borrows will not be allowed\n            until the total borrows amount goes below the new borrow cap\n     * @param vTokens The addresses of the markets (tokens) to change the borrow caps for\n     * @param newBorrowCaps The new borrow cap values in underlying to be set. A value of type(uint256).max corresponds to unlimited borrowing.\n     * @custom:access Controlled by AccessControlManager\n     */\n    function setMarketBorrowCaps(VToken[] calldata vTokens, uint256[] calldata newBorrowCaps) external {\n        _checkAccessAllowed(\"setMarketBorrowCaps(address[],uint256[])\");\n\n        uint256 numMarkets = vTokens.length;\n        uint256 numBorrowCaps = newBorrowCaps.length;\n\n        require(numMarkets != 0 && numMarkets == numBorrowCaps, \"invalid input\");\n\n        _ensureMaxLoops(numMarkets);\n\n        for (uint256 i; i < numMarkets; ++i) {\n            borrowCaps[address(vTokens[i])] = newBorrowCaps[i];\n            emit NewBorrowCap(vTokens[i], newBorrowCaps[i]);\n        }\n    }\n\n    /**\n     * @notice Set the given supply caps for the given vToken markets. Supply that brings total Supply to or above supply cap will revert.\n     * @dev This function is restricted by the AccessControlManager\n     * @dev A supply cap of type(uint256).max corresponds to unlimited supply.\n     * @dev Supply caps smaller than the current total supplies are accepted. This way, new supplies will not be allowed\n            until the total supplies amount goes below the new supply cap\n     * @param vTokens The addresses of the markets (tokens) to change the supply caps for\n     * @param newSupplyCaps The new supply cap values in underlying to be set. A value of type(uint256).max corresponds to unlimited supply.\n     * @custom:access Controlled by AccessControlManager\n     */\n    function setMarketSupplyCaps(VToken[] calldata vTokens, uint256[] calldata newSupplyCaps) external {\n        _checkAccessAllowed(\"setMarketSupplyCaps(address[],uint256[])\");\n        uint256 vTokensCount = vTokens.length;\n\n        require(vTokensCount != 0, \"invalid number of markets\");\n        require(vTokensCount == newSupplyCaps.length, \"invalid number of markets\");\n\n        _ensureMaxLoops(vTokensCount);\n\n        for (uint256 i; i < vTokensCount; ++i) {\n            supplyCaps[address(vTokens[i])] = newSupplyCaps[i];\n            emit NewSupplyCap(vTokens[i], newSupplyCaps[i]);\n        }\n    }\n\n    /**\n     * @notice Pause/unpause specified actions\n     * @dev This function is restricted by the AccessControlManager\n     * @param marketsList Markets to pause/unpause the actions on\n     * @param actionsList List of action ids to pause/unpause\n     * @param paused The new paused state (true=paused, false=unpaused)\n     * @custom:access Controlled by AccessControlManager\n     */\n    function setActionsPaused(VToken[] calldata marketsList, Action[] calldata actionsList, bool paused) external {\n        _checkAccessAllowed(\"setActionsPaused(address[],uint256[],bool)\");\n\n        uint256 marketsCount = marketsList.length;\n        uint256 actionsCount = actionsList.length;\n\n        _ensureMaxLoops(marketsCount * actionsCount);\n\n        for (uint256 marketIdx; marketIdx < marketsCount; ++marketIdx) {\n            for (uint256 actionIdx; actionIdx < actionsCount; ++actionIdx) {\n                _setActionPaused(address(marketsList[marketIdx]), actionsList[actionIdx], paused);\n            }\n        }\n    }\n\n    /**\n     * @notice Set the given collateral threshold for non-batch liquidations. Regular liquidations\n     *   will fail if the collateral amount is less than this threshold. Liquidators should use batch\n     *   operations like liquidateAccount or healAccount.\n     * @dev This function is restricted by the AccessControlManager\n     * @param newMinLiquidatableCollateral The new min liquidatable collateral (in USD).\n     * @custom:access Controlled by AccessControlManager\n     */\n    function setMinLiquidatableCollateral(uint256 newMinLiquidatableCollateral) external {\n        _checkAccessAllowed(\"setMinLiquidatableCollateral(uint256)\");\n\n        uint256 oldMinLiquidatableCollateral = minLiquidatableCollateral;\n        minLiquidatableCollateral = newMinLiquidatableCollateral;\n        emit NewMinLiquidatableCollateral(oldMinLiquidatableCollateral, newMinLiquidatableCollateral);\n    }\n\n    /**\n     * @notice Add a new RewardsDistributor and initialize it with all markets. We can add several RewardsDistributor\n     * contracts with the same rewardToken, and there could be overlaping among them considering the last reward slot (block or second)\n     * @dev Only callable by the admin\n     * @param _rewardsDistributor Address of the RewardDistributor contract to add\n     * @custom:access Only Governance\n     * @custom:event Emits NewRewardsDistributor with distributor address\n     */\n    function addRewardsDistributor(RewardsDistributor _rewardsDistributor) external onlyOwner {\n        require(!rewardsDistributorExists[address(_rewardsDistributor)], \"already exists\");\n\n        uint256 rewardsDistributorsLen = rewardsDistributors.length;\n        _ensureMaxLoops(rewardsDistributorsLen + 1);\n\n        rewardsDistributors.push(_rewardsDistributor);\n        rewardsDistributorExists[address(_rewardsDistributor)] = true;\n\n        uint256 marketsCount = allMarkets.length;\n\n        for (uint256 i; i < marketsCount; ++i) {\n            _rewardsDistributor.initializeMarket(address(allMarkets[i]));\n        }\n\n        emit NewRewardsDistributor(address(_rewardsDistributor), address(_rewardsDistributor.rewardToken()));\n    }\n\n    /**\n     * @notice Sets a new price oracle for the Comptroller\n     * @dev Only callable by the admin\n     * @param newOracle Address of the new price oracle to set\n     * @custom:event Emits NewPriceOracle on success\n     * @custom:error ZeroAddressNotAllowed is thrown when the new oracle address is zero\n     */\n    function setPriceOracle(ResilientOracleInterface newOracle) external onlyOwner {\n        ensureNonzeroAddress(address(newOracle));\n\n        ResilientOracleInterface oldOracle = oracle;\n        oracle = newOracle;\n        emit NewPriceOracle(oldOracle, newOracle);\n    }\n\n    /**\n     * @notice Set the for loop iteration limit to avoid DOS\n     * @param limit Limit for the max loops can execute at a time\n     */\n    function setMaxLoopsLimit(uint256 limit) external onlyOwner {\n        _setMaxLoopsLimit(limit);\n    }\n\n    /**\n     * @notice Sets the prime token contract for the comptroller\n     * @param _prime Address of the Prime contract\n     */\n    function setPrimeToken(IPrime _prime) external onlyOwner {\n        ensureNonzeroAddress(address(_prime));\n\n        emit NewPrimeToken(prime, _prime);\n        prime = _prime;\n    }\n\n    /**\n     * @notice Enables forced liquidations for a market. If forced liquidation is enabled,\n     * borrows in the market may be liquidated regardless of the account liquidity\n     * @param vTokenBorrowed Borrowed vToken\n     * @param enable Whether to enable forced liquidations\n     */\n    function setForcedLiquidation(address vTokenBorrowed, bool enable) external {\n        _checkAccessAllowed(\"setForcedLiquidation(address,bool)\");\n        ensureNonzeroAddress(vTokenBorrowed);\n\n        if (!markets[vTokenBorrowed].isListed) {\n            revert MarketNotListed(vTokenBorrowed);\n        }\n\n        isForcedLiquidationEnabled[vTokenBorrowed] = enable;\n        emit IsForcedLiquidationEnabledUpdated(vTokenBorrowed, enable);\n    }\n\n    /**\n     * @notice Determine the current account liquidity with respect to liquidation threshold requirements\n     * @dev The interface of this function is intentionally kept compatible with Compound and Venus Core\n     * @param account The account get liquidity for\n     * @return error Always NO_ERROR for compatibility with Venus core tooling\n     * @return liquidity Account liquidity in excess of liquidation threshold requirements,\n     * @return shortfall Account shortfall below liquidation threshold requirements\n     */\n    function getAccountLiquidity(\n        address account\n    ) external view returns (uint256 error, uint256 liquidity, uint256 shortfall) {\n        AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(account, _getLiquidationThreshold);\n        return (NO_ERROR, snapshot.liquidity, snapshot.shortfall);\n    }\n\n    /**\n     * @notice Determine the current account liquidity with respect to collateral requirements\n     * @dev The interface of this function is intentionally kept compatible with Compound and Venus Core\n     * @param account The account get liquidity for\n     * @return error Always NO_ERROR for compatibility with Venus core tooling\n     * @return liquidity Account liquidity in excess of collateral requirements,\n     * @return shortfall Account shortfall below collateral requirements\n     */\n    function getBorrowingPower(\n        address account\n    ) external view returns (uint256 error, uint256 liquidity, uint256 shortfall) {\n        AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(account, _getCollateralFactor);\n        return (NO_ERROR, snapshot.liquidity, snapshot.shortfall);\n    }\n\n    /**\n     * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed\n     * @dev The interface of this function is intentionally kept compatible with Compound and Venus Core\n     * @param vTokenModify The market to hypothetically redeem/borrow in\n     * @param account The account to determine liquidity for\n     * @param redeemTokens The number of tokens to hypothetically redeem\n     * @param borrowAmount The amount of underlying to hypothetically borrow\n     * @return error Always NO_ERROR for compatibility with Venus core tooling\n     * @return liquidity Hypothetical account liquidity in excess of collateral requirements,\n     * @return shortfall Hypothetical account shortfall below collateral requirements\n     */\n    function getHypotheticalAccountLiquidity(\n        address account,\n        address vTokenModify,\n        uint256 redeemTokens,\n        uint256 borrowAmount\n    ) external view returns (uint256 error, uint256 liquidity, uint256 shortfall) {\n        AccountLiquiditySnapshot memory snapshot = _getHypotheticalLiquiditySnapshot(\n            account,\n            VToken(vTokenModify),\n            redeemTokens,\n            borrowAmount,\n            _getCollateralFactor\n        );\n        return (NO_ERROR, snapshot.liquidity, snapshot.shortfall);\n    }\n\n    /**\n     * @notice Return all of the markets\n     * @dev The automatic getter may be used to access an individual market.\n     * @return markets The list of market addresses\n     */\n    function getAllMarkets() external view override returns (VToken[] memory) {\n        return allMarkets;\n    }\n\n    /**\n     * @notice Check if a market is marked as listed (active)\n     * @param vToken vToken Address for the market to check\n     * @return listed True if listed otherwise false\n     */\n    function isMarketListed(VToken vToken) external view returns (bool) {\n        return markets[address(vToken)].isListed;\n    }\n\n    /*** Assets You Are In ***/\n\n    /**\n     * @notice Returns whether the given account is entered in a given market\n     * @param account The address of the account to check\n     * @param vToken The vToken to check\n     * @return True if the account is in the market specified, otherwise false.\n     */\n    function checkMembership(address account, VToken vToken) external view returns (bool) {\n        return markets[address(vToken)].accountMembership[account];\n    }\n\n    /**\n     * @notice Calculate number of tokens of collateral asset to seize given an underlying amount\n     * @dev Used in liquidation (called in vToken.liquidateBorrowFresh)\n     * @param vTokenBorrowed The address of the borrowed vToken\n     * @param vTokenCollateral The address of the collateral vToken\n     * @param actualRepayAmount The amount of vTokenBorrowed underlying to convert into vTokenCollateral tokens\n     * @return error Always NO_ERROR for compatibility with Venus core tooling\n     * @return tokensToSeize Number of vTokenCollateral tokens to be seized in a liquidation\n     * @custom:error PriceError if the oracle returns an invalid price\n     */\n    function liquidateCalculateSeizeTokens(\n        address vTokenBorrowed,\n        address vTokenCollateral,\n        uint256 actualRepayAmount\n    ) external view override returns (uint256 error, uint256 tokensToSeize) {\n        /* Read oracle prices for borrowed and collateral markets */\n        uint256 priceBorrowedMantissa = _safeGetUnderlyingPrice(VToken(vTokenBorrowed));\n        uint256 priceCollateralMantissa = _safeGetUnderlyingPrice(VToken(vTokenCollateral));\n\n        /*\n         * Get the exchange rate and calculate the number of collateral tokens to seize:\n         *  seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral\n         *  seizeTokens = seizeAmount / exchangeRate\n         *   = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate)\n         */\n        uint256 exchangeRateMantissa = VToken(vTokenCollateral).exchangeRateStored(); // Note: reverts on error\n        uint256 seizeTokens;\n        Exp memory numerator;\n        Exp memory denominator;\n        Exp memory ratio;\n\n        numerator = mul_(Exp({ mantissa: liquidationIncentiveMantissa }), Exp({ mantissa: priceBorrowedMantissa }));\n        denominator = mul_(Exp({ mantissa: priceCollateralMantissa }), Exp({ mantissa: exchangeRateMantissa }));\n        ratio = div_(numerator, denominator);\n\n        seizeTokens = mul_ScalarTruncate(ratio, actualRepayAmount);\n\n        return (NO_ERROR, seizeTokens);\n    }\n\n    /**\n     * @notice Returns reward speed given a vToken\n     * @param vToken The vToken to get the reward speeds for\n     * @return rewardSpeeds Array of total supply and borrow speeds and reward token for all reward distributors\n     */\n    function getRewardsByMarket(address vToken) external view returns (RewardSpeeds[] memory rewardSpeeds) {\n        uint256 rewardsDistributorsLength = rewardsDistributors.length;\n        rewardSpeeds = new RewardSpeeds[](rewardsDistributorsLength);\n        for (uint256 i; i < rewardsDistributorsLength; ++i) {\n            RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n            address rewardToken = address(rewardsDistributor.rewardToken());\n            rewardSpeeds[i] = RewardSpeeds({\n                rewardToken: rewardToken,\n                supplySpeed: rewardsDistributor.rewardTokenSupplySpeeds(vToken),\n                borrowSpeed: rewardsDistributor.rewardTokenBorrowSpeeds(vToken)\n            });\n        }\n        return rewardSpeeds;\n    }\n\n    /**\n     * @notice Return all reward distributors for this pool\n     * @return Array of RewardDistributor addresses\n     */\n    function getRewardDistributors() external view returns (RewardsDistributor[] memory) {\n        return rewardsDistributors;\n    }\n\n    /**\n     * @notice A marker method that returns true for a valid Comptroller contract\n     * @return Always true\n     */\n    function isComptroller() external pure override returns (bool) {\n        return true;\n    }\n\n    /**\n     * @notice Update the prices of all the tokens associated with the provided account\n     * @param account Address of the account to get associated tokens with\n     */\n    function updatePrices(address account) public {\n        VToken[] memory vTokens = getAssetsIn(account);\n        uint256 vTokensCount = vTokens.length;\n\n        ResilientOracleInterface oracle_ = oracle;\n\n        for (uint256 i; i < vTokensCount; ++i) {\n            oracle_.updatePrice(address(vTokens[i]));\n        }\n    }\n\n    /**\n     * @notice Checks if a certain action is paused on a market\n     * @param market vToken address\n     * @param action Action to check\n     * @return paused True if the action is paused otherwise false\n     */\n    function actionPaused(address market, Action action) public view returns (bool) {\n        return _actionPaused[market][action];\n    }\n\n    /**\n     * @notice Returns the assets an account has entered\n     * @param account The address of the account to pull assets for\n     * @return A list with the assets the account has entered\n     */\n    function getAssetsIn(address account) public view returns (VToken[] memory) {\n        uint256 len;\n        VToken[] memory _accountAssets = accountAssets[account];\n        uint256 _accountAssetsLength = _accountAssets.length;\n\n        VToken[] memory assetsIn = new VToken[](_accountAssetsLength);\n\n        for (uint256 i; i < _accountAssetsLength; ++i) {\n            Market storage market = markets[address(_accountAssets[i])];\n            if (market.isListed) {\n                assetsIn[len] = _accountAssets[i];\n                ++len;\n            }\n        }\n\n        assembly {\n            mstore(assetsIn, len)\n        }\n\n        return assetsIn;\n    }\n\n    /**\n     * @notice Add the market to the borrower's \"assets in\" for liquidity calculations\n     * @param vToken The market to enter\n     * @param borrower The address of the account to modify\n     */\n    function _addToMarket(VToken vToken, address borrower) internal {\n        _checkActionPauseState(address(vToken), Action.ENTER_MARKET);\n        Market storage marketToJoin = markets[address(vToken)];\n\n        if (!marketToJoin.isListed) {\n            revert MarketNotListed(address(vToken));\n        }\n\n        if (marketToJoin.accountMembership[borrower]) {\n            // already joined\n            return;\n        }\n\n        // survived the gauntlet, add to list\n        // NOTE: we store these somewhat redundantly as a significant optimization\n        //  this avoids having to iterate through the list for the most common use cases\n        //  that is, only when we need to perform liquidity checks\n        //  and not whenever we want to check if an account is in a particular market\n        marketToJoin.accountMembership[borrower] = true;\n        accountAssets[borrower].push(vToken);\n\n        emit MarketEntered(vToken, borrower);\n    }\n\n    /**\n     * @notice Internal function to validate that a market hasn't already been added\n     * and if it hasn't adds it\n     * @param vToken The market to support\n     */\n    function _addMarket(address vToken) internal {\n        uint256 marketsCount = allMarkets.length;\n\n        for (uint256 i; i < marketsCount; ++i) {\n            if (allMarkets[i] == VToken(vToken)) {\n                revert MarketAlreadyListed(vToken);\n            }\n        }\n        allMarkets.push(VToken(vToken));\n        marketsCount = allMarkets.length;\n        _ensureMaxLoops(marketsCount);\n    }\n\n    /**\n     * @dev Pause/unpause an action on a market\n     * @param market Market to pause/unpause the action on\n     * @param action Action id to pause/unpause\n     * @param paused The new paused state (true=paused, false=unpaused)\n     */\n    function _setActionPaused(address market, Action action, bool paused) internal {\n        require(markets[market].isListed, \"cannot pause a market that is not listed\");\n        _actionPaused[market][action] = paused;\n        emit ActionPausedMarket(VToken(market), action, paused);\n    }\n\n    /**\n     * @dev Internal function to check that vTokens can be safely redeemed for the underlying asset.\n     * @param vToken Address of the vTokens to redeem\n     * @param redeemer Account redeeming the tokens\n     * @param redeemTokens The number of tokens to redeem\n     */\n    function _checkRedeemAllowed(address vToken, address redeemer, uint256 redeemTokens) internal {\n        Market storage market = markets[vToken];\n\n        if (!market.isListed) {\n            revert MarketNotListed(address(vToken));\n        }\n\n        /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */\n        if (!market.accountMembership[redeemer]) {\n            return;\n        }\n\n        // Update the prices of tokens\n        updatePrices(redeemer);\n\n        /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */\n        AccountLiquiditySnapshot memory snapshot = _getHypotheticalLiquiditySnapshot(\n            redeemer,\n            VToken(vToken),\n            redeemTokens,\n            0,\n            _getCollateralFactor\n        );\n        if (snapshot.shortfall > 0) {\n            revert InsufficientLiquidity();\n        }\n    }\n\n    /**\n     * @notice Get the total collateral, weighted collateral, borrow balance, liquidity, shortfall\n     * @param account The account to get the snapshot for\n     * @param weight The function to compute the weight of the collateral – either collateral factor or\n     *  liquidation threshold. Accepts the address of the vToken and returns the weight as Exp.\n     * @dev Note that we calculate the exchangeRateStored for each collateral vToken using stored data,\n     *  without calculating accumulated interest.\n     * @return snapshot Account liquidity snapshot\n     */\n    function _getCurrentLiquiditySnapshot(\n        address account,\n        function(VToken) internal view returns (Exp memory) weight\n    ) internal view returns (AccountLiquiditySnapshot memory snapshot) {\n        return _getHypotheticalLiquiditySnapshot(account, VToken(address(0)), 0, 0, weight);\n    }\n\n    /**\n     * @notice Determine what the supply/borrow balances would be if the given amounts were redeemed/borrowed\n     * @param vTokenModify The market to hypothetically redeem/borrow in\n     * @param account The account to determine liquidity for\n     * @param redeemTokens The number of tokens to hypothetically redeem\n     * @param borrowAmount The amount of underlying to hypothetically borrow\n     * @param weight The function to compute the weight of the collateral – either collateral factor or\n         liquidation threshold. Accepts the address of the VToken and returns the weight\n     * @dev Note that we calculate the exchangeRateStored for each collateral vToken using stored data,\n     *  without calculating accumulated interest.\n     * @return snapshot Account liquidity snapshot\n     */\n    function _getHypotheticalLiquiditySnapshot(\n        address account,\n        VToken vTokenModify,\n        uint256 redeemTokens,\n        uint256 borrowAmount,\n        function(VToken) internal view returns (Exp memory) weight\n    ) internal view returns (AccountLiquiditySnapshot memory snapshot) {\n        // For each asset the account is in\n        VToken[] memory assets = getAssetsIn(account);\n        uint256 assetsCount = assets.length;\n\n        for (uint256 i; i < assetsCount; ++i) {\n            VToken asset = assets[i];\n\n            // Read the balances and exchange rate from the vToken\n            (uint256 vTokenBalance, uint256 borrowBalance, uint256 exchangeRateMantissa) = _safeGetAccountSnapshot(\n                asset,\n                account\n            );\n\n            // Get the normalized price of the asset\n            Exp memory oraclePrice = Exp({ mantissa: _safeGetUnderlyingPrice(asset) });\n\n            // Pre-compute conversion factors from vTokens -> usd\n            Exp memory vTokenPrice = mul_(Exp({ mantissa: exchangeRateMantissa }), oraclePrice);\n            Exp memory weightedVTokenPrice = mul_(weight(asset), vTokenPrice);\n\n            // weightedCollateral += weightedVTokenPrice * vTokenBalance\n            snapshot.weightedCollateral = mul_ScalarTruncateAddUInt(\n                weightedVTokenPrice,\n                vTokenBalance,\n                snapshot.weightedCollateral\n            );\n\n            // totalCollateral += vTokenPrice * vTokenBalance\n            snapshot.totalCollateral = mul_ScalarTruncateAddUInt(vTokenPrice, vTokenBalance, snapshot.totalCollateral);\n\n            // borrows += oraclePrice * borrowBalance\n            snapshot.borrows = mul_ScalarTruncateAddUInt(oraclePrice, borrowBalance, snapshot.borrows);\n\n            // Calculate effects of interacting with vTokenModify\n            if (asset == vTokenModify) {\n                // redeem effect\n                // effects += tokensToDenom * redeemTokens\n                snapshot.effects = mul_ScalarTruncateAddUInt(weightedVTokenPrice, redeemTokens, snapshot.effects);\n\n                // borrow effect\n                // effects += oraclePrice * borrowAmount\n                snapshot.effects = mul_ScalarTruncateAddUInt(oraclePrice, borrowAmount, snapshot.effects);\n            }\n        }\n\n        uint256 borrowPlusEffects = snapshot.borrows + snapshot.effects;\n        // These are safe, as the underflow condition is checked first\n        unchecked {\n            if (snapshot.weightedCollateral > borrowPlusEffects) {\n                snapshot.liquidity = snapshot.weightedCollateral - borrowPlusEffects;\n                snapshot.shortfall = 0;\n            } else {\n                snapshot.liquidity = 0;\n                snapshot.shortfall = borrowPlusEffects - snapshot.weightedCollateral;\n            }\n        }\n\n        return snapshot;\n    }\n\n    /**\n     * @dev Retrieves price from oracle for an asset and checks it is nonzero\n     * @param asset Address for asset to query price\n     * @return Underlying price\n     */\n    function _safeGetUnderlyingPrice(VToken asset) internal view returns (uint256) {\n        uint256 oraclePriceMantissa = oracle.getUnderlyingPrice(address(asset));\n        if (oraclePriceMantissa == 0) {\n            revert PriceError(address(asset));\n        }\n        return oraclePriceMantissa;\n    }\n\n    /**\n     * @dev Return collateral factor for a market\n     * @param asset Address for asset\n     * @return Collateral factor as exponential\n     */\n    function _getCollateralFactor(VToken asset) internal view returns (Exp memory) {\n        return Exp({ mantissa: markets[address(asset)].collateralFactorMantissa });\n    }\n\n    /**\n     * @dev Retrieves liquidation threshold for a market as an exponential\n     * @param asset Address for asset to liquidation threshold\n     * @return Liquidation threshold as exponential\n     */\n    function _getLiquidationThreshold(VToken asset) internal view returns (Exp memory) {\n        return Exp({ mantissa: markets[address(asset)].liquidationThresholdMantissa });\n    }\n\n    /**\n     * @dev Returns supply and borrow balances of user in vToken, reverts on failure\n     * @param vToken Market to query\n     * @param user Account address\n     * @return vTokenBalance Balance of vTokens, the same as vToken.balanceOf(user)\n     * @return borrowBalance Borrowed amount, including the interest\n     * @return exchangeRateMantissa Stored exchange rate\n     */\n    function _safeGetAccountSnapshot(\n        VToken vToken,\n        address user\n    ) internal view returns (uint256 vTokenBalance, uint256 borrowBalance, uint256 exchangeRateMantissa) {\n        uint256 err;\n        (err, vTokenBalance, borrowBalance, exchangeRateMantissa) = vToken.getAccountSnapshot(user);\n        if (err != 0) {\n            revert SnapshotError(address(vToken), user);\n        }\n        return (vTokenBalance, borrowBalance, exchangeRateMantissa);\n    }\n\n    /// @notice Reverts if the call is not from expectedSender\n    /// @param expectedSender Expected transaction sender\n    function _checkSenderIs(address expectedSender) internal view {\n        if (msg.sender != expectedSender) {\n            revert UnexpectedSender(expectedSender, msg.sender);\n        }\n    }\n\n    /// @notice Reverts if a certain action is paused on a market\n    /// @param market Market to check\n    /// @param action Action to check\n    function _checkActionPauseState(address market, Action action) private view {\n        if (actionPaused(market, action)) {\n            revert ActionPaused(market, action);\n        }\n    }\n}\n"
    },
    "contracts/ComptrollerInterface.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { VToken } from \"./VToken.sol\";\nimport { RewardsDistributor } from \"./Rewards/RewardsDistributor.sol\";\n\nenum Action {\n    MINT,\n    REDEEM,\n    BORROW,\n    REPAY,\n    SEIZE,\n    LIQUIDATE,\n    TRANSFER,\n    ENTER_MARKET,\n    EXIT_MARKET\n}\n\n/**\n * @title ComptrollerInterface\n * @author Venus\n * @notice Interface implemented by the `Comptroller` contract.\n */\ninterface ComptrollerInterface {\n    /*** Assets You Are In ***/\n\n    function enterMarkets(address[] calldata vTokens) external returns (uint256[] memory);\n\n    function exitMarket(address vToken) external returns (uint256);\n\n    /*** Policy Hooks ***/\n\n    function preMintHook(address vToken, address minter, uint256 mintAmount) external;\n\n    function preRedeemHook(address vToken, address redeemer, uint256 redeemTokens) external;\n\n    function preBorrowHook(address vToken, address borrower, uint256 borrowAmount) external;\n\n    function preRepayHook(address vToken, address borrower) external;\n\n    function preLiquidateHook(\n        address vTokenBorrowed,\n        address vTokenCollateral,\n        address borrower,\n        uint256 repayAmount,\n        bool skipLiquidityCheck\n    ) external;\n\n    function preSeizeHook(\n        address vTokenCollateral,\n        address vTokenBorrowed,\n        address liquidator,\n        address borrower\n    ) external;\n\n    function borrowVerify(address vToken, address borrower, uint borrowAmount) external;\n\n    function mintVerify(address vToken, address minter, uint mintAmount, uint mintTokens) external;\n\n    function redeemVerify(address vToken, address redeemer, uint redeemAmount, uint redeemTokens) external;\n\n    function repayBorrowVerify(\n        address vToken,\n        address payer,\n        address borrower,\n        uint repayAmount,\n        uint borrowerIndex\n    ) external;\n\n    function liquidateBorrowVerify(\n        address vTokenBorrowed,\n        address vTokenCollateral,\n        address liquidator,\n        address borrower,\n        uint repayAmount,\n        uint seizeTokens\n    ) external;\n\n    function seizeVerify(\n        address vTokenCollateral,\n        address vTokenBorrowed,\n        address liquidator,\n        address borrower,\n        uint seizeTokens\n    ) external;\n\n    function transferVerify(address vToken, address src, address dst, uint transferTokens) external;\n\n    function preTransferHook(address vToken, address src, address dst, uint256 transferTokens) external;\n\n    function isComptroller() external view returns (bool);\n\n    /*** Liquidity/Liquidation Calculations ***/\n\n    function liquidateCalculateSeizeTokens(\n        address vTokenBorrowed,\n        address vTokenCollateral,\n        uint256 repayAmount\n    ) external view returns (uint256, uint256);\n\n    function getAllMarkets() external view returns (VToken[] memory);\n\n    function actionPaused(address market, Action action) external view returns (bool);\n}\n\n/**\n * @title ComptrollerViewInterface\n * @author Venus\n * @notice Interface implemented by the `Comptroller` contract, including only some util view functions.\n */\ninterface ComptrollerViewInterface {\n    function markets(address) external view returns (bool, uint256);\n\n    function oracle() external view returns (ResilientOracleInterface);\n\n    function getAssetsIn(address) external view returns (VToken[] memory);\n\n    function closeFactorMantissa() external view returns (uint256);\n\n    function liquidationIncentiveMantissa() external view returns (uint256);\n\n    function minLiquidatableCollateral() external view returns (uint256);\n\n    function getRewardDistributors() external view returns (RewardsDistributor[] memory);\n\n    function getAllMarkets() external view returns (VToken[] memory);\n\n    function borrowCaps(address) external view returns (uint256);\n\n    function supplyCaps(address) external view returns (uint256);\n\n    function approvedDelegates(address user, address delegate) external view returns (bool);\n}\n"
    },
    "contracts/ComptrollerStorage.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { VToken } from \"./VToken.sol\";\nimport { RewardsDistributor } from \"./Rewards/RewardsDistributor.sol\";\nimport { IPrime } from \"@venusprotocol/venus-protocol/contracts/Tokens/Prime/Interfaces/IPrime.sol\";\nimport { Action } from \"./ComptrollerInterface.sol\";\n\n/**\n * @title ComptrollerStorage\n * @author Venus\n * @notice Storage layout for the `Comptroller` contract.\n */\ncontract ComptrollerStorage {\n    struct LiquidationOrder {\n        VToken vTokenCollateral;\n        VToken vTokenBorrowed;\n        uint256 repayAmount;\n    }\n\n    struct AccountLiquiditySnapshot {\n        uint256 totalCollateral;\n        uint256 weightedCollateral;\n        uint256 borrows;\n        uint256 effects;\n        uint256 liquidity;\n        uint256 shortfall;\n    }\n\n    struct RewardSpeeds {\n        address rewardToken;\n        uint256 supplySpeed;\n        uint256 borrowSpeed;\n    }\n\n    struct Market {\n        // Whether or not this market is listed\n        bool isListed;\n        //  Multiplier representing the most one can borrow against their collateral in this market.\n        //  For instance, 0.9 to allow borrowing 90% of collateral value.\n        //  Must be between 0 and 1, and stored as a mantissa.\n        uint256 collateralFactorMantissa;\n        //  Multiplier representing the collateralization after which the borrow is eligible\n        //  for liquidation. For instance, 0.8 liquidate when the borrow is 80% of collateral\n        //  value. Must be between 0 and collateral factor, stored as a mantissa.\n        uint256 liquidationThresholdMantissa;\n        // Per-market mapping of \"accounts in this asset\"\n        mapping(address => bool) accountMembership;\n    }\n\n    /**\n     * @notice Oracle which gives the price of any given asset\n     */\n    ResilientOracleInterface public oracle;\n\n    /**\n     * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow\n     */\n    uint256 public closeFactorMantissa;\n\n    /**\n     * @notice Multiplier representing the discount on collateral that a liquidator receives\n     */\n    uint256 public liquidationIncentiveMantissa;\n\n    /**\n     * @notice Per-account mapping of \"assets you are in\"\n     */\n    mapping(address => VToken[]) public accountAssets;\n\n    /**\n     * @notice Official mapping of vTokens -> Market metadata\n     * @dev Used e.g. to determine if a market is supported\n     */\n    mapping(address => Market) public markets;\n\n    /// @notice A list of all markets\n    VToken[] public allMarkets;\n\n    /// @notice Borrow caps enforced by borrowAllowed for each vToken address. Defaults to zero which restricts borrowing.\n    mapping(address => uint256) public borrowCaps;\n\n    /// @notice Minimal collateral required for regular (non-batch) liquidations\n    uint256 public minLiquidatableCollateral;\n\n    /// @notice Supply caps enforced by mintAllowed for each vToken address. Defaults to zero which corresponds to minting not allowed\n    mapping(address => uint256) public supplyCaps;\n\n    /// @notice True if a certain action is paused on a certain market\n    mapping(address => mapping(Action => bool)) internal _actionPaused;\n\n    // List of Reward Distributors added\n    RewardsDistributor[] internal rewardsDistributors;\n\n    // Used to check if rewards distributor is added\n    mapping(address => bool) internal rewardsDistributorExists;\n\n    /// @notice Flag indicating whether forced liquidation enabled for a market\n    mapping(address => bool) public isForcedLiquidationEnabled;\n\n    uint256 internal constant NO_ERROR = 0;\n\n    // closeFactorMantissa must be strictly greater than this value\n    uint256 internal constant MIN_CLOSE_FACTOR_MANTISSA = 0.05e18; // 0.05\n\n    // closeFactorMantissa must not exceed this value\n    uint256 internal constant MAX_CLOSE_FACTOR_MANTISSA = 0.9e18; // 0.9\n\n    // No collateralFactorMantissa may exceed this value\n    uint256 internal constant MAX_COLLATERAL_FACTOR_MANTISSA = 0.95e18; // 0.95\n\n    /// Prime token address\n    IPrime public prime;\n\n    /// @notice Whether the delegate is allowed to borrow or redeem on behalf of the user\n    //mapping(address user => mapping (address delegate => bool approved)) public approvedDelegates;\n    mapping(address => mapping(address => bool)) public approvedDelegates;\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[47] private __gap;\n}\n"
    },
    "contracts/ERC4626/Interfaces/IComptroller.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { Action } from \"../../ComptrollerInterface.sol\";\nimport { RewardsDistributor } from \"../../Rewards/RewardsDistributor.sol\";\n\n/**\n * @title IComptroller\n * @author Venus\n * @notice Combined interface for the `Comptroller` contract, including both core and view functions.\n */\ninterface IComptroller {\n    function actionPaused(address market, Action action) external view returns (bool);\n\n    function getRewardDistributors() external view returns (RewardsDistributor[] memory);\n\n    function supplyCaps(address) external view returns (uint256);\n}\n"
    },
    "contracts/ERC4626/Interfaces/IProtocolShareReserve.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\ninterface IProtocolShareReserve {\n    /// @notice it represents the type of vToken income\n    enum IncomeType {\n        SPREAD,\n        LIQUIDATION,\n        ERC4626_WRAPPER_REWARDS,\n        FLASHLOAN\n    }\n\n    function updateAssetsState(address comptroller, address asset, IncomeType incomeType) external;\n}\n"
    },
    "contracts/ERC4626/Interfaces/IRewardsDistributor.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { VToken } from \"../../VToken.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\n\nabstract contract IRewardsDistributor {\n    struct RewardToken {\n        // The market's last updated rewardTokenBorrowIndex or rewardTokenSupplyIndex\n        uint224 index;\n        // The block number the index was last updated at\n        uint32 block;\n        // The block number at which to stop rewards\n        uint32 lastRewardingBlock;\n    }\n\n    IERC20Upgradeable public rewardToken;\n\n    function claimRewardToken(address holder, VToken[] memory vTokens) external virtual;\n}\n"
    },
    "contracts/ERC4626/VenusERC4626.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { ERC4626Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC4626Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { ERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol\";\nimport { ReentrancyGuardUpgradeable } from \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { IProtocolShareReserve } from \"./Interfaces/IProtocolShareReserve.sol\";\nimport { RewardsDistributor } from \".././Rewards/RewardsDistributor.sol\";\nimport { MaxLoopsLimitHelper } from \"../MaxLoopsLimitHelper.sol\";\nimport { IComptroller } from \"./Interfaces/IComptroller.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\n\nimport { Action } from \"../ComptrollerInterface.sol\";\nimport { EXP_SCALE } from \".././lib/constants.sol\";\nimport { VToken } from \"../VToken.sol\";\n\n/// @title VenusERC4626\n/// @notice ERC4626 wrapper for Venus vTokens, enabling standard ERC4626 vault interactions with Venus Protocol.\ncontract VenusERC4626 is ERC4626Upgradeable, AccessControlledV8, MaxLoopsLimitHelper, ReentrancyGuardUpgradeable {\n    using SafeERC20Upgradeable for ERC20Upgradeable;\n\n    enum Rounding {\n        Down,\n        Up\n    }\n\n    /// @notice Error code representing no errors in Venus operations.\n    uint256 internal constant NO_ERROR = 0;\n\n    /// @notice The Venus vToken associated with this ERC4626 vault.\n    VToken public vToken;\n\n    /// @notice The Venus Comptroller contract, responsible for market operations.\n    IComptroller public comptroller;\n\n    /// @notice The recipient of rewards distributed by the Venus Protocol.\n    address public rewardRecipient;\n\n    /// @notice Emitted when rewards are claimed.\n    /// @param amount The amount of reward tokens claimed.\n    /// @param rewardToken The address of the reward token claimed.\n    event ClaimRewards(uint256 amount, address indexed rewardToken);\n\n    /// @notice Emitted when the reward recipient address is updated.\n    /// @param oldRecipient The previous reward recipient address.\n    /// @param newRecipient The new reward recipient address.\n    event RewardRecipientUpdated(address indexed oldRecipient, address indexed newRecipient);\n\n    /// @notice Event emitted when tokens are swept\n    event SweepToken(address indexed token, address indexed receiver, uint256 amount);\n\n    /// @notice Thrown when a Venus protocol call returns an error.\n    /// @dev This error is triggered if a Venus operation (such as minting or redeeming vTokens) fails.\n    /// @param errorCode The error code returned by the Venus protocol.\n    error VenusERC4626__VenusError(uint256 errorCode);\n\n    /// @notice Thrown when a deposit exceeds the maximum allowed limit.\n    /// @dev This error is triggered if the deposit amount is greater than `maxDeposit(receiver)`.\n    error ERC4626__DepositMoreThanMax();\n\n    /// @notice Thrown when a mint operation exceeds the maximum allowed limit.\n    /// @dev This error is triggered if the mint amount is greater than `maxMint(receiver)`.\n    error ERC4626__MintMoreThanMax();\n\n    /// @notice Thrown when a withdrawal exceeds the maximum available assets.\n    /// @dev This error is triggered if the withdrawal amount is greater than `maxWithdraw(owner)`.\n    error ERC4626__WithdrawMoreThanMax();\n\n    /// @notice Thrown when a redemption exceeds the maximum redeemable shares.\n    /// @dev This error is triggered if the redemption amount is greater than `maxRedeem(owner)`.\n    error ERC4626__RedeemMoreThanMax();\n\n    /// @notice Thrown when attempting an operation with a zero amount.\n    /// @dev This error prevents unnecessary transactions with zero amounts in deposit, withdraw, mint, or redeem operations.\n    /// @param operation The name of the operation that failed (e.g., \"deposit\", \"withdraw\", \"mint\", \"redeem\").\n    error ERC4626__ZeroAmount(string operation);\n\n    /// @custom:oz-upgrades-unsafe-allow constructor\n    constructor() {\n        // Note that the contract is upgradeable. Use initialize() or reinitializers\n        // to set the state variables.\n        _disableInitializers();\n    }\n\n    /// @notice Initializes the VenusERC4626 vault, only with the VToken address associated to the vault\n    /// @dev `initialize2` should be invoked to complete the configuration of the vault\n    /// @param vToken_ The VToken associated with the vault, representing the yield-bearing asset.\n    function initialize(address vToken_) public initializer {\n        ensureNonzeroAddress(vToken_);\n\n        vToken = VToken(vToken_);\n        comptroller = IComptroller(address(vToken.comptroller()));\n        ERC20Upgradeable asset = ERC20Upgradeable(vToken.underlying());\n\n        __ERC20_init(_generateVaultName(asset), _generateVaultSymbol(asset));\n        __ERC4626_init(asset);\n        __ReentrancyGuard_init();\n    }\n\n    /**\n     * @notice Set the limit for the loops can iterate to avoid the DOS\n     * @param loopsLimit Number of loops limit\n     * @custom:event Emits MaxLoopsLimitUpdated event on success\n     * @custom:access Controlled by ACM\n     */\n    function setMaxLoopsLimit(uint256 loopsLimit) external {\n        _checkAccessAllowed(\"setMaxLoopsLimit(uint256)\");\n        _setMaxLoopsLimit(loopsLimit);\n    }\n\n    /// @notice Sets a new reward recipient address\n    /// @param newRecipient The address of the new reward recipient\n    /// @custom:access Controlled by ACM\n    function setRewardRecipient(address newRecipient) external {\n        _checkAccessAllowed(\"setRewardRecipient(address)\");\n        _setRewardRecipient(newRecipient);\n    }\n\n    /// @notice Sweeps the input token address tokens from the contract and sends them to the owner\n    /// @param token Address of the token\n    /// @custom:event SweepToken emits on success\n    /// @custom:access Only owner\n    function sweepToken(IERC20Upgradeable token) external onlyOwner {\n        uint256 balance = token.balanceOf(address(this));\n\n        if (balance > 0) {\n            address owner_ = owner();\n            SafeERC20Upgradeable.safeTransfer(token, owner_, balance);\n            emit SweepToken(address(token), owner_, balance);\n        }\n    }\n\n    /// @notice Claims rewards from all reward distributors associated with the VToken and transfers them to the reward recipient.\n    /// @dev Iterates through all reward distributors fetched from the comptroller, claims rewards, and transfers them if available.\n    function claimRewards() external {\n        IComptroller _comptroller = comptroller;\n        VToken _vToken = vToken;\n        address _rewardRecipient = rewardRecipient;\n\n        RewardsDistributor[] memory rewardDistributors = comptroller.getRewardDistributors();\n\n        _ensureMaxLoops(rewardDistributors.length);\n\n        for (uint256 i = 0; i < rewardDistributors.length; i++) {\n            RewardsDistributor rewardDistributor = rewardDistributors[i];\n            IERC20Upgradeable rewardToken = IERC20Upgradeable(address(rewardDistributor.rewardToken()));\n\n            VToken[] memory vTokens = new VToken[](1);\n            vTokens[0] = _vToken;\n            RewardsDistributor(rewardDistributor).claimRewardToken(address(this), vTokens);\n            uint256 rewardBalance = rewardToken.balanceOf(address(this));\n\n            if (rewardBalance > 0) {\n                SafeERC20Upgradeable.safeTransfer(rewardToken, _rewardRecipient, rewardBalance);\n\n                // Try to update the asset state on the recipient if reward recipient is a protocol share reserve\n                // reward recipient cannot be an EOA\n                try\n                    IProtocolShareReserve(_rewardRecipient).updateAssetsState(\n                        address(_comptroller),\n                        address(rewardToken),\n                        IProtocolShareReserve.IncomeType.ERC4626_WRAPPER_REWARDS\n                    )\n                {} catch {}\n            }\n            emit ClaimRewards(rewardBalance, address(rewardToken));\n        }\n    }\n\n    /// @notice Second function to invoked to complete the configuration of the vault, setting the rest of the attributes\n    /// @param accessControlManager_ Address of the ACM contract\n    /// @param rewardRecipient_ The address that will receive rewards generated by the vault.\n    /// @param loopsLimit_ The maximum number of loops allowed for reward distribution.\n    /// @param vaultOwner_ The owner that will be set for the created vault\n    function initialize2(\n        address accessControlManager_,\n        address rewardRecipient_,\n        uint256 loopsLimit_,\n        address vaultOwner_\n    ) public reinitializer(2) {\n        ensureNonzeroAddress(vaultOwner_);\n\n        __AccessControlled_init(accessControlManager_);\n        _setMaxLoopsLimit(loopsLimit_);\n        _setRewardRecipient(rewardRecipient_);\n        _transferOwnership(vaultOwner_);\n    }\n\n    /// @inheritdoc ERC4626Upgradeable\n    function deposit(uint256 assets, address receiver) public override nonReentrant returns (uint256) {\n        ensureNonzeroAddress(receiver);\n\n        vToken.accrueInterest();\n        if (assets == 0) {\n            revert ERC4626__ZeroAmount(\"deposit\");\n        }\n        if (assets > maxDeposit(receiver)) {\n            revert ERC4626__DepositMoreThanMax();\n        }\n\n        uint256 shares = previewDeposit(assets);\n        if (shares == 0) {\n            revert ERC4626__ZeroAmount(\"deposit\");\n        }\n        _deposit(_msgSender(), receiver, assets, shares);\n        afterDeposit(assets);\n        return shares;\n    }\n\n    /// @inheritdoc ERC4626Upgradeable\n    function mint(uint256 shares, address receiver) public override nonReentrant returns (uint256) {\n        ensureNonzeroAddress(receiver);\n\n        vToken.accrueInterest();\n        if (shares == 0) {\n            revert ERC4626__ZeroAmount(\"mint\");\n        }\n        if (shares > maxMint(receiver)) {\n            revert ERC4626__MintMoreThanMax();\n        }\n        uint256 assets = previewMint(shares);\n        if (assets == 0) {\n            revert ERC4626__ZeroAmount(\"mint\");\n        }\n        _deposit(_msgSender(), receiver, assets, shares);\n        afterDeposit(assets);\n        return assets;\n    }\n\n    /// @inheritdoc ERC4626Upgradeable\n    function withdraw(uint256 assets, address receiver, address owner) public override nonReentrant returns (uint256) {\n        ensureNonzeroAddress(receiver);\n        ensureNonzeroAddress(owner);\n\n        vToken.accrueInterest();\n        if (assets == 0) {\n            revert ERC4626__ZeroAmount(\"withdraw\");\n        }\n        if (assets > maxWithdraw(owner)) {\n            revert ERC4626__WithdrawMoreThanMax();\n        }\n\n        uint256 shares = previewWithdraw(assets);\n        if (shares == 0) {\n            revert ERC4626__ZeroAmount(\"withdraw\");\n        }\n        uint256 actualAssets = beforeWithdraw(assets);\n        _withdraw(_msgSender(), receiver, owner, actualAssets, shares);\n        return shares;\n    }\n\n    /// @inheritdoc ERC4626Upgradeable\n    function redeem(uint256 shares, address receiver, address owner) public override nonReentrant returns (uint256) {\n        ensureNonzeroAddress(receiver);\n        ensureNonzeroAddress(owner);\n\n        vToken.accrueInterest();\n        if (shares == 0) {\n            revert ERC4626__ZeroAmount(\"redeem\");\n        }\n        if (shares > maxRedeem(owner)) {\n            revert ERC4626__RedeemMoreThanMax();\n        }\n\n        uint256 assets = previewRedeem(shares);\n        if (assets == 0) {\n            revert ERC4626__ZeroAmount(\"redeem\");\n        }\n\n        // actualAssets should be equal to assets, because of the round performed in previewRedeem\n        // but let's use the returned value anyway\n        uint256 actualAssets = beforeWithdraw(assets);\n        _withdraw(_msgSender(), receiver, owner, actualAssets, shares);\n        return actualAssets;\n    }\n\n    /// @inheritdoc ERC4626Upgradeable\n    function previewDeposit(uint256 assets) public view virtual override returns (uint256) {\n        // round down the asset amount, to deposit an amont equivalent to a natural number of vTokens, without decimals\n        uint256 adjustedAssets = _roundAssets(assets, Rounding.Down);\n\n        return super.previewDeposit(adjustedAssets);\n    }\n\n    /// @inheritdoc ERC4626Upgradeable\n    function previewMint(uint256 shares) public view virtual override returns (uint256) {\n        uint256 assets = super.previewMint(shares);\n\n        // round up the asset amount, to deposit an amont equivalent to a natural number of vTokens, without decimals\n        return _roundAssets(assets, Rounding.Up);\n    }\n\n    /// @inheritdoc ERC4626Upgradeable\n    function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {\n        // round up the asset amount to redeem a natural number of vTokens, without decimals\n        uint256 adjustedAssets = _roundAssets(assets, Rounding.Up);\n\n        return super.previewWithdraw(adjustedAssets);\n    }\n\n    /// @inheritdoc ERC4626Upgradeable\n    function previewRedeem(uint256 shares) public view virtual override returns (uint256) {\n        uint256 assets = super.previewRedeem(shares);\n\n        // round down the asset amount to redeem a natural number of vTokens, without decimals\n        return _roundAssets(assets, Rounding.Down);\n    }\n\n    /// @notice Returns the total amount of assets deposited\n    /// @return Amount of assets deposited\n    function totalAssets() public view virtual override returns (uint256) {\n        return (vToken.balanceOf(address(this)) * vToken.exchangeRateStored()) / EXP_SCALE;\n    }\n\n    /// @notice Returns the maximum deposit allowed based on Venus supply caps.\n    /// @dev If minting is paused or the supply cap is reached, returns 0.\n    /// @param /*account*/ The address of the account.\n    /// @return The maximum amount of assets that can be deposited.\n    function maxDeposit(address /*account*/) public view virtual override returns (uint256) {\n        if (comptroller.actionPaused(address(vToken), Action.MINT)) {\n            return 0;\n        }\n\n        uint256 supplyCap = comptroller.supplyCaps(address(vToken));\n        uint256 totalSupply_ = (vToken.totalSupply() * vToken.exchangeRateStored()) / EXP_SCALE;\n        return supplyCap > totalSupply_ ? supplyCap - totalSupply_ : 0;\n    }\n\n    /// @notice Returns the maximum amount of shares that can be minted.\n    /// @dev This is derived from the maximum deposit amount converted to shares.\n    /// @param /*account*/ The address of the account.\n    /// @return The maximum number of shares that can be minted.\n    function maxMint(address /*account*/) public view virtual override returns (uint256) {\n        return convertToShares(maxDeposit(address(0)));\n    }\n\n    /// @notice Returns the maximum amount that can be withdrawn.\n    /// @dev The withdrawable amount is limited by the available cash in the vault.\n    /// @param receiver The address of the account withdrawing.\n    /// @return The maximum amount of assets that can be withdrawn.\n    function maxWithdraw(address receiver) public view virtual override returns (uint256) {\n        if (comptroller.actionPaused(address(vToken), Action.REDEEM)) {\n            return 0;\n        }\n\n        uint256 cash = vToken.getCash();\n        uint256 totalReserves = vToken.totalReserves();\n        uint256 assetsBalance = convertToAssets(balanceOf(receiver));\n\n        if (cash < totalReserves) {\n            return 0;\n        } else {\n            uint256 availableCash = cash - totalReserves;\n            return availableCash < assetsBalance ? availableCash : assetsBalance;\n        }\n    }\n\n    /// @notice Returns the maximum amount of shares that can be redeemed.\n    /// @dev Redemption is limited by the available cash in the vault.\n    /// @param receiver The address of the account redeeming.\n    /// @return The maximum number of shares that can be redeemed.\n    function maxRedeem(address receiver) public view virtual override returns (uint256) {\n        if (comptroller.actionPaused(address(vToken), Action.REDEEM)) {\n            return 0;\n        }\n\n        uint256 cash = vToken.getCash();\n        uint256 totalReserves = vToken.totalReserves();\n        if (cash < totalReserves) {\n            return 0;\n        } else {\n            uint256 availableCash = cash - totalReserves;\n            uint256 availableCashInShares = convertToShares(availableCash);\n            uint256 shareBalance = balanceOf(receiver);\n            return availableCashInShares < shareBalance ? availableCashInShares : shareBalance;\n        }\n    }\n\n    /// @notice Redeems underlying assets before withdrawing from the vault.\n    /// @dev Calls `redeemUnderlying` on the vToken contract. Reverts on error.\n    /// @param assets The amount of underlying assets to redeem.\n    /// @return The amount of assets transferred in\n    function beforeWithdraw(uint256 assets) internal returns (uint256) {\n        IERC20Upgradeable token = IERC20Upgradeable(asset());\n        uint256 balanceBefore = token.balanceOf(address(this));\n\n        uint256 errorCode = vToken.redeemUnderlying(assets);\n        if (errorCode != NO_ERROR) {\n            revert VenusERC4626__VenusError(errorCode);\n        }\n\n        uint256 balanceAfter = token.balanceOf(address(this));\n        // Return the amount that was *actually* transferred\n        return balanceAfter - balanceBefore;\n    }\n\n    /// @notice Mints vTokens after depositing assets.\n    /// @dev Calls `mint` on the vToken contract. Reverts on error.\n    /// @param assets The amount of underlying assets to deposit.\n    function afterDeposit(uint256 assets) internal {\n        ERC20Upgradeable(asset()).safeApprove(address(vToken), assets);\n        uint256 errorCode = vToken.mint(assets);\n        if (errorCode != NO_ERROR) {\n            revert VenusERC4626__VenusError(errorCode);\n        }\n    }\n\n    /// @notice Sets a new reward recipient address\n    /// @param newRecipient The address of the new reward recipient\n    /// @custom:error ZeroAddressNotAllowed is thrown when the new recipient address is zero\n    /// @custom:event RewardRecipientUpdated is emitted when the reward recipient address is updated\n    function _setRewardRecipient(address newRecipient) internal {\n        ensureNonzeroAddress(newRecipient);\n\n        emit RewardRecipientUpdated(rewardRecipient, newRecipient);\n        rewardRecipient = newRecipient;\n    }\n\n    /// @notice Override `_decimalsOffset` to normalize decimals to 18 for all VenusERC4626 vaults.\n    /// @return Gap between 18 and the decimals of the asset token\n    function _decimalsOffset() internal view virtual override returns (uint8) {\n        return 18 - ERC20Upgradeable(asset()).decimals();\n    }\n\n    /// @notice Generates an returns the derived name of the vault considering the asset name\n    /// @param asset_ Asset to be accepted in the vault whose name this function will return\n    /// @return Name of the vault considering the asset name\n    function _generateVaultName(ERC20Upgradeable asset_) internal view returns (string memory) {\n        return string(abi.encodePacked(\"ERC4626-Wrapped Venus \", asset_.name()));\n    }\n\n    /// @notice Generates and returns the derived symbol of the vault considering the asset symbol\n    /// @param asset_ Asset to be accepted in the vault whose symbol this function will return\n    /// @return Symbol of the vault considering the asset name\n    function _generateVaultSymbol(ERC20Upgradeable asset_) internal view returns (string memory) {\n        return string(abi.encodePacked(\"v4626\", asset_.symbol()));\n    }\n\n    /// @notice Round the amount of assets, up or down, to a multiple of the exchange rate. That way the\n    /// associated number of VTokens won't have any decimals\n    /// @param assets The amount of assets to round\n    /// @param rounding If the round should be up (Rounding.Up), or down (Rounding.Down)\n    /// @return The rounded amount of assets\n    function _roundAssets(uint256 assets, Rounding rounding) internal view returns (uint256) {\n        uint256 exchangeRate = vToken.exchangeRateStored();\n        uint256 redeemTokens = (assets * EXP_SCALE) / exchangeRate;\n\n        uint256 _redeemAmount = (redeemTokens * exchangeRate) / EXP_SCALE;\n\n        if (_redeemAmount != 0 && _redeemAmount != assets && rounding == Rounding.Up) redeemTokens++; // round up\n\n        // redeemAmount = exchangeRate * redeemTokens\n        return (exchangeRate * redeemTokens) / EXP_SCALE;\n    }\n}\n"
    },
    "contracts/ERC4626/VenusERC4626Factory.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { ERC4626Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC4626Upgradeable.sol\";\nimport { UpgradeableBeacon } from \"@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol\";\nimport { BeaconProxy } from \"@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol\";\n\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\nimport { PoolRegistryInterface } from \"../Pool/PoolRegistryInterface.sol\";\nimport { MaxLoopsLimitHelper } from \"../MaxLoopsLimitHelper.sol\";\nimport { VTokenInterface } from \"../VTokenInterfaces.sol\";\nimport { VenusERC4626 } from \"./VenusERC4626.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\n\n/// @title VenusERC4626Factory\n/// @notice Factory for creating VenusERC4626 contracts\ncontract VenusERC4626Factory is AccessControlledV8, MaxLoopsLimitHelper {\n    /// @notice A constant salt value used for deterministic contract deployment\n    bytes32 public constant SALT = keccak256(\"Venus-ERC4626 Vault\");\n\n    /// @notice The beacon contract for VenusERC4626 proxies\n    UpgradeableBeacon public beacon;\n\n    /// @notice The Pool Registry contract\n    PoolRegistryInterface public poolRegistry;\n\n    /// @notice The address that will receive the liquidity mining rewards\n    address public rewardRecipient;\n\n    // @notice Map of vaults created by this factory\n    mapping(address vToken => ERC4626Upgradeable vault) public createdVaults;\n\n    /// @notice Emitted when a new ERC4626 vault has been created\n    /// @param vToken The vToken used by the vault\n    /// @param vault The vault that was created\n    event CreateERC4626(VTokenInterface indexed vToken, ERC4626Upgradeable indexed vault);\n\n    /// @notice Emitted when the reward recipient address is updated.\n    /// @param oldRecipient The previous reward recipient address.\n    /// @param newRecipient The new reward recipient address.\n    event RewardRecipientUpdated(address indexed oldRecipient, address indexed newRecipient);\n\n    /// @notice Thrown when the provided vToken is not registered in PoolRegistry\n    error VenusERC4626Factory__InvalidVToken();\n\n    /// @notice Thrown when a VenusERC4626 already exists for the provided vToken\n    error VenusERC4626Factory__ERC4626AlreadyExists();\n\n    /// @custom:oz-upgrades-unsafe-allow constructor\n    constructor() {\n        // Note that the contract is upgradeable. Use initialize() or reinitializers\n        // to set the state variables.\n        _disableInitializers();\n    }\n\n    /// @notice Initializes the contract\n    /// @param accessControlManager Address of the ACM contract\n    /// @param poolRegistryAddress Address of the Pool Registry contract\n    /// @param rewardRecipientAddress Reward recipient address\n    /// @param venusERC4626Implementation Address of the VenusERC4626 implementation contract\n    /// @param loopsLimitNumber The loops limit for the MaxLoopsLimit helper\n    function initialize(\n        address accessControlManager,\n        address poolRegistryAddress,\n        address rewardRecipientAddress,\n        address venusERC4626Implementation,\n        uint256 loopsLimitNumber\n    ) external initializer {\n        ensureNonzeroAddress(accessControlManager);\n        ensureNonzeroAddress(poolRegistryAddress);\n        ensureNonzeroAddress(rewardRecipientAddress);\n        ensureNonzeroAddress(venusERC4626Implementation);\n\n        __AccessControlled_init(accessControlManager);\n\n        poolRegistry = PoolRegistryInterface(poolRegistryAddress);\n        rewardRecipient = rewardRecipientAddress;\n        _setMaxLoopsLimit(loopsLimitNumber);\n\n        // Deploy the upgradeable beacon with the initial implementation\n        beacon = new UpgradeableBeacon(venusERC4626Implementation);\n\n        // The owner of the beacon will initially be the owner of the factory\n        beacon.transferOwnership(owner());\n    }\n\n    /// @notice Sets a new reward recipient address\n    /// @param newRecipient The address of the new reward recipient\n    /// @custom:access Controlled by ACM\n    /// @custom:error ZeroAddressNotAllowed is thrown when the new recipient address is zero\n    /// @custom:event RewardRecipientUpdated is emitted when the reward recipient address is updated\n    function setRewardRecipient(address newRecipient) external {\n        _checkAccessAllowed(\"setRewardRecipient(address)\");\n        ensureNonzeroAddress(newRecipient);\n\n        emit RewardRecipientUpdated(rewardRecipient, newRecipient);\n        rewardRecipient = newRecipient;\n    }\n\n    /**\n     * @notice Set the limit for the loops can iterate to avoid the DOS\n     * @param loopsLimit Number of loops limit\n     * @custom:event Emits MaxLoopsLimitUpdated event on success\n     * @custom:access Controlled by ACM\n     */\n    function setMaxLoopsLimit(uint256 loopsLimit) external {\n        _checkAccessAllowed(\"setMaxLoopsLimit(uint256)\");\n        _setMaxLoopsLimit(loopsLimit);\n    }\n\n    /// @notice Creates a VenusERC4626 vault for a given asset and comptroller\n    /// @param vToken The vToken address to create the vault\n    /// @return vault The deployed VenusERC4626 vault\n    /// @custom:error ZeroAddressNotAllowed is thrown when the vToken address is zero\n    /// @custom:error VenusERC4626Factory__InvalidVToken is thrown when the provided vToken is not supported by the poolRegistry\n    /// @custom:error VenusERC4626Factory__ERC4626AlreadyExists is thrown when this factory already created a VenusERC4626 for the provided vToken\n    /// @custom:event CreateERC4626 is emitted when the ERC4626 wrapper is created\n    function createERC4626(address vToken) external returns (ERC4626Upgradeable vault) {\n        ensureNonzeroAddress(vToken);\n\n        if (address(createdVaults[vToken]) != address(0)) {\n            revert VenusERC4626Factory__ERC4626AlreadyExists();\n        }\n\n        VTokenInterface vToken_ = VTokenInterface(vToken);\n\n        address comptroller = address(vToken_.comptroller());\n\n        if (vToken != poolRegistry.getVTokenForAsset(comptroller, vToken_.underlying())) {\n            revert VenusERC4626Factory__InvalidVToken();\n        }\n\n        VenusERC4626 venusERC4626 = VenusERC4626(\n            address(\n                new BeaconProxy{ salt: SALT }(\n                    address(beacon),\n                    abi.encodeWithSelector(VenusERC4626.initialize.selector, vToken)\n                )\n            )\n        );\n\n        venusERC4626.initialize2(address(_accessControlManager), rewardRecipient, maxLoopsLimit, owner());\n\n        vault = ERC4626Upgradeable(address(venusERC4626));\n\n        createdVaults[vToken] = vault;\n\n        emit CreateERC4626(vToken_, vault);\n    }\n\n    /// @notice Predicts the vault address for a given vToken\n    /// @param vToken The vToken address\n    /// @return The precomputed vault address\n    function computeVaultAddress(address vToken) public view returns (address) {\n        return\n            address(\n                uint160(\n                    uint256(\n                        keccak256(\n                            abi.encodePacked(\n                                bytes1(0xff),\n                                address(this),\n                                SALT,\n                                keccak256(\n                                    abi.encodePacked(\n                                        type(BeaconProxy).creationCode,\n                                        abi.encode(\n                                            address(beacon),\n                                            abi.encodeWithSelector(VenusERC4626.initialize.selector, vToken)\n                                        )\n                                    )\n                                )\n                            )\n                        )\n                    )\n                )\n            );\n    }\n}\n"
    },
    "contracts/ErrorReporter.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\n/**\n * @title TokenErrorReporter\n * @author Venus\n * @notice Errors that can be thrown by the `VToken` contract.\n */\ncontract TokenErrorReporter {\n    uint256 public constant NO_ERROR = 0; // support legacy return codes\n\n    error TransferNotAllowed();\n\n    error MintFreshnessCheck();\n\n    error RedeemFreshnessCheck();\n    error RedeemTransferOutNotPossible();\n\n    error BorrowFreshnessCheck();\n    error BorrowCashNotAvailable();\n    error DelegateNotApproved();\n\n    error RepayBorrowFreshnessCheck();\n\n    error HealBorrowUnauthorized();\n    error ForceLiquidateBorrowUnauthorized();\n\n    error LiquidateFreshnessCheck();\n    error LiquidateCollateralFreshnessCheck();\n    error LiquidateAccrueCollateralInterestFailed(uint256 errorCode);\n    error LiquidateLiquidatorIsBorrower();\n    error LiquidateCloseAmountIsZero();\n    error LiquidateCloseAmountIsUintMax();\n\n    error LiquidateSeizeLiquidatorIsBorrower();\n\n    error ProtocolSeizeShareTooBig();\n\n    error SetReserveFactorFreshCheck();\n    error SetReserveFactorBoundsCheck();\n\n    error AddReservesFactorFreshCheck(uint256 actualAddAmount);\n\n    error ReduceReservesFreshCheck();\n    error ReduceReservesCashNotAvailable();\n    error ReduceReservesCashValidation();\n\n    error SetInterestRateModelFreshCheck();\n}\n"
    },
    "contracts/ExponentialNoError.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { EXP_SCALE as EXP_SCALE_, MANTISSA_ONE as MANTISSA_ONE_ } from \"./lib/constants.sol\";\n\n/**\n * @title Exponential module for storing fixed-precision decimals\n * @author Compound\n * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.\n *         Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:\n *         `Exp({mantissa: 5100000000000000000})`.\n */\ncontract ExponentialNoError {\n    struct Exp {\n        uint256 mantissa;\n    }\n\n    struct Double {\n        uint256 mantissa;\n    }\n\n    uint256 internal constant EXP_SCALE = EXP_SCALE_;\n    uint256 internal constant DOUBLE_SCALE = 1e36;\n    uint256 internal constant HALF_EXP_SCALE = EXP_SCALE / 2;\n    uint256 internal constant MANTISSA_ONE = MANTISSA_ONE_;\n\n    /**\n     * @dev Truncates the given exp to a whole number value.\n     *      For example, truncate(Exp{mantissa: 15 * EXP_SCALE}) = 15\n     */\n    function truncate(Exp memory exp) internal pure returns (uint256) {\n        // Note: We are not using careful math here as we're performing a division that cannot fail\n        return exp.mantissa / EXP_SCALE;\n    }\n\n    /**\n     * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function mul_ScalarTruncate(Exp memory a, uint256 scalar) internal pure returns (uint256) {\n        Exp memory product = mul_(a, scalar);\n        return truncate(product);\n    }\n\n    /**\n     * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function mul_ScalarTruncateAddUInt(Exp memory a, uint256 scalar, uint256 addend) internal pure returns (uint256) {\n        Exp memory product = mul_(a, scalar);\n        return add_(truncate(product), addend);\n    }\n\n    /**\n     * @dev Checks if first Exp is less than second Exp.\n     */\n    function lessThanExp(Exp memory left, Exp memory right) internal pure returns (bool) {\n        return left.mantissa < right.mantissa;\n    }\n\n    function safe224(uint256 n, string memory errorMessage) internal pure returns (uint224) {\n        require(n <= type(uint224).max, errorMessage);\n        return uint224(n);\n    }\n\n    function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {\n        require(n <= type(uint32).max, errorMessage);\n        return uint32(n);\n    }\n\n    function add_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n        return Exp({ mantissa: add_(a.mantissa, b.mantissa) });\n    }\n\n    function add_(Double memory a, Double memory b) internal pure returns (Double memory) {\n        return Double({ mantissa: add_(a.mantissa, b.mantissa) });\n    }\n\n    function add_(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a + b;\n    }\n\n    function sub_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n        return Exp({ mantissa: sub_(a.mantissa, b.mantissa) });\n    }\n\n    function sub_(Double memory a, Double memory b) internal pure returns (Double memory) {\n        return Double({ mantissa: sub_(a.mantissa, b.mantissa) });\n    }\n\n    function sub_(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a - b;\n    }\n\n    function mul_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n        return Exp({ mantissa: mul_(a.mantissa, b.mantissa) / EXP_SCALE });\n    }\n\n    function mul_(Exp memory a, uint256 b) internal pure returns (Exp memory) {\n        return Exp({ mantissa: mul_(a.mantissa, b) });\n    }\n\n    function mul_(uint256 a, Exp memory b) internal pure returns (uint256) {\n        return mul_(a, b.mantissa) / EXP_SCALE;\n    }\n\n    function mul_(Double memory a, Double memory b) internal pure returns (Double memory) {\n        return Double({ mantissa: mul_(a.mantissa, b.mantissa) / DOUBLE_SCALE });\n    }\n\n    function mul_(Double memory a, uint256 b) internal pure returns (Double memory) {\n        return Double({ mantissa: mul_(a.mantissa, b) });\n    }\n\n    function mul_(uint256 a, Double memory b) internal pure returns (uint256) {\n        return mul_(a, b.mantissa) / DOUBLE_SCALE;\n    }\n\n    function mul_(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a * b;\n    }\n\n    function div_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n        return Exp({ mantissa: div_(mul_(a.mantissa, EXP_SCALE), b.mantissa) });\n    }\n\n    function div_(Exp memory a, uint256 b) internal pure returns (Exp memory) {\n        return Exp({ mantissa: div_(a.mantissa, b) });\n    }\n\n    function div_(uint256 a, Exp memory b) internal pure returns (uint256) {\n        return div_(mul_(a, EXP_SCALE), b.mantissa);\n    }\n\n    function div_(Double memory a, Double memory b) internal pure returns (Double memory) {\n        return Double({ mantissa: div_(mul_(a.mantissa, DOUBLE_SCALE), b.mantissa) });\n    }\n\n    function div_(Double memory a, uint256 b) internal pure returns (Double memory) {\n        return Double({ mantissa: div_(a.mantissa, b) });\n    }\n\n    function div_(uint256 a, Double memory b) internal pure returns (uint256) {\n        return div_(mul_(a, DOUBLE_SCALE), b.mantissa);\n    }\n\n    function div_(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a / b;\n    }\n\n    function fraction(uint256 a, uint256 b) internal pure returns (Double memory) {\n        return Double({ mantissa: div_(mul_(a, DOUBLE_SCALE), b) });\n    }\n}\n"
    },
    "contracts/InterestRateModel.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\n/**\n * @title Compound's InterestRateModel Interface\n * @author Compound\n */\nabstract contract InterestRateModel {\n    /**\n     * @notice Calculates the current borrow interest rate per slot (block or second)\n     * @param cash The total amount of cash the market has\n     * @param borrows The total amount of borrows the market has outstanding\n     * @param reserves The total amount of reserves the market has\n     * @param badDebt The amount of badDebt in the market\n     * @return The borrow rate percentage per slot (block or second) as a mantissa (scaled by EXP_SCALE)\n     */\n    function getBorrowRate(\n        uint256 cash,\n        uint256 borrows,\n        uint256 reserves,\n        uint256 badDebt\n    ) external view virtual returns (uint256);\n\n    /**\n     * @notice Calculates the current supply interest rate per slot (block or second)\n     * @param cash The total amount of cash the market has\n     * @param borrows The total amount of borrows the market has outstanding\n     * @param reserves The total amount of reserves the market has\n     * @param reserveFactorMantissa The current reserve factor the market has\n     * @param badDebt The amount of badDebt in the market\n     * @return The supply rate percentage per slot (block or second) as a mantissa (scaled by EXP_SCALE)\n     */\n    function getSupplyRate(\n        uint256 cash,\n        uint256 borrows,\n        uint256 reserves,\n        uint256 reserveFactorMantissa,\n        uint256 badDebt\n    ) external view virtual returns (uint256);\n\n    /**\n     * @notice Indicator that this is an InterestRateModel contract (for inspection)\n     * @return Always true\n     */\n    function isInterestRateModel() external pure virtual returns (bool) {\n        return true;\n    }\n}\n"
    },
    "contracts/lib/constants.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\n/// @dev The approximate number of seconds per year\nuint256 constant SECONDS_PER_YEAR = 31_536_000;\n\n/// @dev Base unit for computations, usually used in scaling (multiplications, divisions)\nuint256 constant EXP_SCALE = 1e18;\n\n/// @dev A unit (literal one) in EXP_SCALE, usually used in additions/subtractions\nuint256 constant MANTISSA_ONE = EXP_SCALE;\n"
    },
    "contracts/lib/validators.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\n/// @notice Thrown if the supplied address is a zero address where it is not allowed\nerror ZeroAddressNotAllowed();\n\n/// @notice Checks if the provided address is nonzero, reverts otherwise\n/// @param address_ Address to check\n/// @custom:error ZeroAddressNotAllowed is thrown if the provided address is a zero address\nfunction ensureNonzeroAddress(address address_) pure {\n    if (address_ == address(0)) {\n        revert ZeroAddressNotAllowed();\n    }\n}\n"
    },
    "contracts/MaxLoopsLimitHelper.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\n/**\n * @title MaxLoopsLimitHelper\n * @author Venus\n * @notice Abstract contract used to avoid collection with too many items that would generate gas errors and DoS.\n */\nabstract contract MaxLoopsLimitHelper {\n    // Limit for the loops to avoid the DOS\n    uint256 public maxLoopsLimit;\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n\n    /// @notice Emitted when max loops limit is set\n    event MaxLoopsLimitUpdated(uint256 oldMaxLoopsLimit, uint256 newmaxLoopsLimit);\n\n    /// @notice Thrown an error on maxLoopsLimit exceeds for any loop\n    error MaxLoopsLimitExceeded(uint256 loopsLimit, uint256 requiredLoops);\n\n    /**\n     * @notice Set the limit for the loops can iterate to avoid the DOS\n     * @param limit Limit for the max loops can execute at a time\n     */\n    function _setMaxLoopsLimit(uint256 limit) internal {\n        require(limit > maxLoopsLimit, \"Comptroller: Invalid maxLoopsLimit\");\n\n        uint256 oldMaxLoopsLimit = maxLoopsLimit;\n        maxLoopsLimit = limit;\n\n        emit MaxLoopsLimitUpdated(oldMaxLoopsLimit, limit);\n    }\n\n    /**\n     * @notice Compare the maxLoopsLimit with number of the times loop iterate\n     * @param len Length of the loops iterate\n     * @custom:error MaxLoopsLimitExceeded error is thrown when loops length exceeds maxLoopsLimit\n     */\n    function _ensureMaxLoops(uint256 len) internal view {\n        if (len > maxLoopsLimit) {\n            revert MaxLoopsLimitExceeded(maxLoopsLimit, len);\n        }\n    }\n}\n"
    },
    "contracts/Pool/PoolRegistryInterface.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\n/**\n * @title PoolRegistryInterface\n * @author Venus\n * @notice Interface implemented by `PoolRegistry`.\n */\ninterface PoolRegistryInterface {\n    /**\n     * @notice Struct for a Venus interest rate pool.\n     */\n    struct VenusPool {\n        string name;\n        address creator;\n        address comptroller;\n        uint256 blockPosted;\n        uint256 timestampPosted;\n    }\n\n    /**\n     * @notice Struct for a Venus interest rate pool metadata.\n     */\n    struct VenusPoolMetaData {\n        string category;\n        string logoURL;\n        string description;\n    }\n\n    /// @notice Get all pools in PoolRegistry\n    function getAllPools() external view returns (VenusPool[] memory);\n\n    /// @notice Get a pool by comptroller address\n    function getPoolByComptroller(address comptroller) external view returns (VenusPool memory);\n\n    /// @notice Get the address of the VToken contract in the Pool where the underlying token is the provided asset\n    function getVTokenForAsset(address comptroller, address asset) external view returns (address);\n\n    /// @notice Get the addresss of the Pools supported that include a market for the provided asset\n    function getPoolsSupportedByAsset(address asset) external view returns (address[] memory);\n\n    /// @notice Get the metadata of a Pool by comptroller address\n    function getVenusPoolMetadata(address comptroller) external view returns (VenusPoolMetaData memory);\n}\n"
    },
    "contracts/Rewards/RewardsDistributor.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\nimport { TimeManagerV8 } from \"@venusprotocol/solidity-utilities/contracts/TimeManagerV8.sol\";\n\nimport { ExponentialNoError } from \"../ExponentialNoError.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { Comptroller } from \"../Comptroller.sol\";\nimport { MaxLoopsLimitHelper } from \"../MaxLoopsLimitHelper.sol\";\nimport { RewardsDistributorStorage } from \"./RewardsDistributorStorage.sol\";\n\n/**\n * @title `RewardsDistributor`\n * @author Venus\n * @notice Contract used to configure, track and distribute rewards to users based on their actions (borrows and supplies) in the protocol.\n * Users can receive additional rewards through a `RewardsDistributor`. Each `RewardsDistributor` proxy is initialized with a specific reward\n * token and `Comptroller`, which can then distribute the reward token to users that supply or borrow in the associated pool.\n * Authorized users can set the reward token borrow and supply speeds for each market in the pool. This sets a fixed amount of reward\n * token to be released each slot (block or second) for borrowers and suppliers, which is distributed based on a user’s percentage of the borrows or supplies\n * respectively. The owner can also set up reward distributions to contributor addresses (distinct from suppliers and borrowers) by setting\n * their contributor reward token speed, which similarly allocates a fixed amount of reward token per slot (block or second).\n *\n * The owner has the ability to transfer any amount of reward tokens held by the contract to any other address. Rewards are not distributed\n * automatically and must be claimed by a user calling `claimRewardToken()`. Users should be aware that it is up to the owner and other centralized\n * entities to ensure that the `RewardsDistributor` holds enough tokens to distribute the accumulated rewards of users and contributors.\n */\ncontract RewardsDistributor is\n    ExponentialNoError,\n    Ownable2StepUpgradeable,\n    AccessControlledV8,\n    MaxLoopsLimitHelper,\n    RewardsDistributorStorage,\n    TimeManagerV8\n{\n    using SafeERC20Upgradeable for IERC20Upgradeable;\n\n    /// @notice The initial REWARD TOKEN index for a market\n    uint224 public constant INITIAL_INDEX = 1e36;\n\n    /// @notice Emitted when REWARD TOKEN is distributed to a supplier\n    event DistributedSupplierRewardToken(\n        VToken indexed vToken,\n        address indexed supplier,\n        uint256 rewardTokenDelta,\n        uint256 rewardTokenTotal,\n        uint256 rewardTokenSupplyIndex\n    );\n\n    /// @notice Emitted when REWARD TOKEN is distributed to a borrower\n    event DistributedBorrowerRewardToken(\n        VToken indexed vToken,\n        address indexed borrower,\n        uint256 rewardTokenDelta,\n        uint256 rewardTokenTotal,\n        uint256 rewardTokenBorrowIndex\n    );\n\n    /// @notice Emitted when a new supply-side REWARD TOKEN speed is calculated for a market\n    event RewardTokenSupplySpeedUpdated(VToken indexed vToken, uint256 newSpeed);\n\n    /// @notice Emitted when a new borrow-side REWARD TOKEN speed is calculated for a market\n    event RewardTokenBorrowSpeedUpdated(VToken indexed vToken, uint256 newSpeed);\n\n    /// @notice Emitted when REWARD TOKEN is granted by admin\n    event RewardTokenGranted(address indexed recipient, uint256 amount);\n\n    /// @notice Emitted when a new REWARD TOKEN speed is set for a contributor\n    event ContributorRewardTokenSpeedUpdated(address indexed contributor, uint256 newSpeed);\n\n    /// @notice Emitted when a market is initialized\n    event MarketInitialized(address indexed vToken);\n\n    /// @notice Emitted when a reward token supply index is updated\n    event RewardTokenSupplyIndexUpdated(address indexed vToken);\n\n    /// @notice Emitted when a reward token borrow index is updated\n    event RewardTokenBorrowIndexUpdated(address indexed vToken, Exp marketBorrowIndex);\n\n    /// @notice Emitted when a reward for contributor is updated\n    event ContributorRewardsUpdated(address indexed contributor, uint256 rewardAccrued);\n\n    /// @notice Emitted when a reward token last rewarding block for supply is updated\n    event SupplyLastRewardingBlockUpdated(address indexed vToken, uint32 newBlock);\n\n    /// @notice Emitted when a reward token last rewarding block for borrow is updated\n    event BorrowLastRewardingBlockUpdated(address indexed vToken, uint32 newBlock);\n\n    /// @notice Emitted when a reward token last rewarding timestamp for supply is updated\n    event SupplyLastRewardingBlockTimestampUpdated(address indexed vToken, uint256 newTimestamp);\n\n    /// @notice Emitted when a reward token last rewarding timestamp for borrow is updated\n    event BorrowLastRewardingBlockTimestampUpdated(address indexed vToken, uint256 newTimestamp);\n\n    modifier onlyComptroller() {\n        require(address(comptroller) == msg.sender, \"Only comptroller can call this function\");\n        _;\n    }\n\n    /**\n     * @param timeBased_ A boolean indicating whether the contract is based on time or block.\n     * @param blocksPerYear_ The number of blocks per year\n     * @custom:oz-upgrades-unsafe-allow constructor\n     */\n    constructor(bool timeBased_, uint256 blocksPerYear_) TimeManagerV8(timeBased_, blocksPerYear_) {\n        // Note that the contract is upgradeable. Use initialize() or reinitializers\n        // to set the state variables.\n        _disableInitializers();\n    }\n\n    /**\n     * @notice RewardsDistributor initializer\n     * @dev Initializes the deployer to owner\n     * @param comptroller_ Comptroller to attach the reward distributor to\n     * @param rewardToken_ Reward token to distribute\n     * @param loopsLimit_ Maximum number of iterations for the loops in this contract\n     * @param accessControlManager_ AccessControlManager contract address\n     */\n    function initialize(\n        Comptroller comptroller_,\n        IERC20Upgradeable rewardToken_,\n        uint256 loopsLimit_,\n        address accessControlManager_\n    ) external initializer {\n        comptroller = comptroller_;\n        rewardToken = rewardToken_;\n        __Ownable2Step_init();\n        __AccessControlled_init_unchained(accessControlManager_);\n\n        _setMaxLoopsLimit(loopsLimit_);\n    }\n\n    /**\n     * @notice Initializes the market state for a specific vToken\n     * @param vToken The address of the vToken to be initialized\n     * @custom:event MarketInitialized emits on success\n     * @custom:access Only Comptroller\n     */\n    function initializeMarket(address vToken) external onlyComptroller {\n        uint256 blockNumberOrTimestamp = getBlockNumberOrTimestamp();\n\n        isTimeBased\n            ? _initializeMarketTimestampBased(vToken, blockNumberOrTimestamp)\n            : _initializeMarketBlockBased(vToken, safe32(blockNumberOrTimestamp, \"block number exceeds 32 bits\"));\n\n        emit MarketInitialized(vToken);\n    }\n\n    /*** Reward Token Distribution ***/\n\n    /**\n     * @notice Calculate reward token accrued by a borrower and possibly transfer it to them\n     *         Borrowers will begin to accrue after the first interaction with the protocol.\n     * @dev This function should only be called when the user has a borrow position in the market\n     *      (e.g. Comptroller.preBorrowHook, and Comptroller.preRepayHook)\n     *      We avoid an external call to check if they are in the market to save gas because this function is called in many places\n     * @param vToken The market in which the borrower is interacting\n     * @param borrower The address of the borrower to distribute REWARD TOKEN to\n     * @param marketBorrowIndex The current global borrow index of vToken\n     */\n    function distributeBorrowerRewardToken(\n        address vToken,\n        address borrower,\n        Exp memory marketBorrowIndex\n    ) external onlyComptroller {\n        _distributeBorrowerRewardToken(vToken, borrower, marketBorrowIndex);\n    }\n\n    function updateRewardTokenSupplyIndex(address vToken) external onlyComptroller {\n        _updateRewardTokenSupplyIndex(vToken);\n    }\n\n    /**\n     * @notice Transfer REWARD TOKEN to the recipient\n     * @dev Note: If there is not enough REWARD TOKEN, we do not perform the transfer all\n     * @param recipient The address of the recipient to transfer REWARD TOKEN to\n     * @param amount The amount of REWARD TOKEN to (possibly) transfer\n     */\n    function grantRewardToken(address recipient, uint256 amount) external onlyOwner {\n        uint256 amountLeft = _grantRewardToken(recipient, amount);\n        require(amountLeft == 0, \"insufficient rewardToken for grant\");\n        emit RewardTokenGranted(recipient, amount);\n    }\n\n    function updateRewardTokenBorrowIndex(address vToken, Exp memory marketBorrowIndex) external onlyComptroller {\n        _updateRewardTokenBorrowIndex(vToken, marketBorrowIndex);\n    }\n\n    /**\n     * @notice Set REWARD TOKEN borrow and supply speeds for the specified markets\n     * @param vTokens The markets whose REWARD TOKEN speed to update\n     * @param supplySpeeds New supply-side REWARD TOKEN speed for the corresponding market\n     * @param borrowSpeeds New borrow-side REWARD TOKEN speed for the corresponding market\n     */\n    function setRewardTokenSpeeds(\n        VToken[] memory vTokens,\n        uint256[] memory supplySpeeds,\n        uint256[] memory borrowSpeeds\n    ) external {\n        _checkAccessAllowed(\"setRewardTokenSpeeds(address[],uint256[],uint256[])\");\n        uint256 numTokens = vTokens.length;\n        require(numTokens == supplySpeeds.length && numTokens == borrowSpeeds.length, \"invalid setRewardTokenSpeeds\");\n\n        for (uint256 i; i < numTokens; ++i) {\n            _setRewardTokenSpeed(vTokens[i], supplySpeeds[i], borrowSpeeds[i]);\n        }\n    }\n\n    /**\n     * @notice Set REWARD TOKEN last rewarding block for the specified markets, used when contract is block based\n     * @param vTokens The markets whose REWARD TOKEN last rewarding block to update\n     * @param supplyLastRewardingBlocks New supply-side REWARD TOKEN last rewarding block for the corresponding market\n     * @param borrowLastRewardingBlocks New borrow-side REWARD TOKEN last rewarding block for the corresponding market\n     */\n    function setLastRewardingBlocks(\n        VToken[] calldata vTokens,\n        uint32[] calldata supplyLastRewardingBlocks,\n        uint32[] calldata borrowLastRewardingBlocks\n    ) external {\n        _checkAccessAllowed(\"setLastRewardingBlocks(address[],uint32[],uint32[])\");\n        require(!isTimeBased, \"Block-based operation only\");\n\n        uint256 numTokens = vTokens.length;\n        require(\n            numTokens == supplyLastRewardingBlocks.length && numTokens == borrowLastRewardingBlocks.length,\n            \"RewardsDistributor::setLastRewardingBlocks invalid input\"\n        );\n\n        for (uint256 i; i < numTokens; ) {\n            _setLastRewardingBlock(vTokens[i], supplyLastRewardingBlocks[i], borrowLastRewardingBlocks[i]);\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Set REWARD TOKEN last rewarding block timestamp for the specified markets, used when contract is time based\n     * @param vTokens The markets whose REWARD TOKEN last rewarding block to update\n     * @param supplyLastRewardingBlockTimestamps New supply-side REWARD TOKEN last rewarding block timestamp for the corresponding market\n     * @param borrowLastRewardingBlockTimestamps New borrow-side REWARD TOKEN last rewarding block timestamp for the corresponding market\n     */\n    function setLastRewardingBlockTimestamps(\n        VToken[] calldata vTokens,\n        uint256[] calldata supplyLastRewardingBlockTimestamps,\n        uint256[] calldata borrowLastRewardingBlockTimestamps\n    ) external {\n        _checkAccessAllowed(\"setLastRewardingBlockTimestamps(address[],uint256[],uint256[])\");\n        require(isTimeBased, \"Time-based operation only\");\n\n        uint256 numTokens = vTokens.length;\n        require(\n            numTokens == supplyLastRewardingBlockTimestamps.length &&\n                numTokens == borrowLastRewardingBlockTimestamps.length,\n            \"RewardsDistributor::setLastRewardingBlockTimestamps invalid input\"\n        );\n\n        for (uint256 i; i < numTokens; ) {\n            _setLastRewardingBlockTimestamp(\n                vTokens[i],\n                supplyLastRewardingBlockTimestamps[i],\n                borrowLastRewardingBlockTimestamps[i]\n            );\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Set REWARD TOKEN speed for a single contributor\n     * @param contributor The contributor whose REWARD TOKEN speed to update\n     * @param rewardTokenSpeed New REWARD TOKEN speed for contributor\n     */\n    function setContributorRewardTokenSpeed(address contributor, uint256 rewardTokenSpeed) external onlyOwner {\n        // note that REWARD TOKEN speed could be set to 0 to halt liquidity rewards for a contributor\n        updateContributorRewards(contributor);\n        if (rewardTokenSpeed == 0) {\n            // release storage\n            delete lastContributorBlock[contributor];\n        } else {\n            lastContributorBlock[contributor] = getBlockNumberOrTimestamp();\n        }\n        rewardTokenContributorSpeeds[contributor] = rewardTokenSpeed;\n\n        emit ContributorRewardTokenSpeedUpdated(contributor, rewardTokenSpeed);\n    }\n\n    function distributeSupplierRewardToken(address vToken, address supplier) external onlyComptroller {\n        _distributeSupplierRewardToken(vToken, supplier);\n    }\n\n    /**\n     * @notice Claim all the rewardToken accrued by holder in all markets\n     * @param holder The address to claim REWARD TOKEN for\n     */\n    function claimRewardToken(address holder) external {\n        return claimRewardToken(holder, comptroller.getAllMarkets());\n    }\n\n    /**\n     * @notice Set the limit for the loops can iterate to avoid the DOS\n     * @param limit Limit for the max loops can execute at a time\n     */\n    function setMaxLoopsLimit(uint256 limit) external onlyOwner {\n        _setMaxLoopsLimit(limit);\n    }\n\n    /**\n     * @notice Calculate additional accrued REWARD TOKEN for a contributor since last accrual\n     * @param contributor The address to calculate contributor rewards for\n     */\n    function updateContributorRewards(address contributor) public {\n        uint256 rewardTokenSpeed = rewardTokenContributorSpeeds[contributor];\n        uint256 blockNumberOrTimestamp = getBlockNumberOrTimestamp();\n        uint256 deltaBlocksOrTimestamp = sub_(blockNumberOrTimestamp, lastContributorBlock[contributor]);\n        if (deltaBlocksOrTimestamp > 0 && rewardTokenSpeed > 0) {\n            uint256 newAccrued = mul_(deltaBlocksOrTimestamp, rewardTokenSpeed);\n            uint256 contributorAccrued = add_(rewardTokenAccrued[contributor], newAccrued);\n\n            rewardTokenAccrued[contributor] = contributorAccrued;\n            lastContributorBlock[contributor] = blockNumberOrTimestamp;\n\n            emit ContributorRewardsUpdated(contributor, rewardTokenAccrued[contributor]);\n        }\n    }\n\n    /**\n     * @notice Claim all the rewardToken accrued by holder in the specified markets\n     * @param holder The address to claim REWARD TOKEN for\n     * @param vTokens The list of markets to claim REWARD TOKEN in\n     */\n    function claimRewardToken(address holder, VToken[] memory vTokens) public {\n        uint256 vTokensCount = vTokens.length;\n\n        _ensureMaxLoops(vTokensCount);\n\n        for (uint256 i; i < vTokensCount; ++i) {\n            VToken vToken = vTokens[i];\n            require(comptroller.isMarketListed(vToken), \"market must be listed\");\n            Exp memory borrowIndex = Exp({ mantissa: vToken.borrowIndex() });\n            _updateRewardTokenBorrowIndex(address(vToken), borrowIndex);\n            _distributeBorrowerRewardToken(address(vToken), holder, borrowIndex);\n            _updateRewardTokenSupplyIndex(address(vToken));\n            _distributeSupplierRewardToken(address(vToken), holder);\n        }\n        rewardTokenAccrued[holder] = _grantRewardToken(holder, rewardTokenAccrued[holder]);\n    }\n\n    /**\n     * @notice Set REWARD TOKEN last rewarding block for a single market.\n     * @param vToken market's whose reward token last rewarding block to be updated\n     * @param supplyLastRewardingBlock New supply-side REWARD TOKEN last rewarding block for market\n     * @param borrowLastRewardingBlock New borrow-side REWARD TOKEN last rewarding block for market\n     */\n    function _setLastRewardingBlock(\n        VToken vToken,\n        uint32 supplyLastRewardingBlock,\n        uint32 borrowLastRewardingBlock\n    ) internal {\n        require(comptroller.isMarketListed(vToken), \"rewardToken market is not listed\");\n\n        uint256 blockNumber = getBlockNumberOrTimestamp();\n\n        require(supplyLastRewardingBlock > blockNumber, \"setting last rewarding block in the past is not allowed\");\n        require(borrowLastRewardingBlock > blockNumber, \"setting last rewarding block in the past is not allowed\");\n\n        uint32 currentSupplyLastRewardingBlock = rewardTokenSupplyState[address(vToken)].lastRewardingBlock;\n        uint32 currentBorrowLastRewardingBlock = rewardTokenBorrowState[address(vToken)].lastRewardingBlock;\n\n        require(\n            currentSupplyLastRewardingBlock == 0 || currentSupplyLastRewardingBlock > blockNumber,\n            \"this RewardsDistributor is already locked\"\n        );\n        require(\n            currentBorrowLastRewardingBlock == 0 || currentBorrowLastRewardingBlock > blockNumber,\n            \"this RewardsDistributor is already locked\"\n        );\n\n        if (currentSupplyLastRewardingBlock != supplyLastRewardingBlock) {\n            rewardTokenSupplyState[address(vToken)].lastRewardingBlock = supplyLastRewardingBlock;\n            emit SupplyLastRewardingBlockUpdated(address(vToken), supplyLastRewardingBlock);\n        }\n\n        if (currentBorrowLastRewardingBlock != borrowLastRewardingBlock) {\n            rewardTokenBorrowState[address(vToken)].lastRewardingBlock = borrowLastRewardingBlock;\n            emit BorrowLastRewardingBlockUpdated(address(vToken), borrowLastRewardingBlock);\n        }\n    }\n\n    /**\n     * @notice Set REWARD TOKEN last rewarding timestamp for a single market.\n     * @param vToken market's whose reward token last rewarding timestamp to be updated\n     * @param supplyLastRewardingBlockTimestamp New supply-side REWARD TOKEN last rewarding timestamp for market\n     * @param borrowLastRewardingBlockTimestamp New borrow-side REWARD TOKEN last rewarding timestamp for market\n     */\n    function _setLastRewardingBlockTimestamp(\n        VToken vToken,\n        uint256 supplyLastRewardingBlockTimestamp,\n        uint256 borrowLastRewardingBlockTimestamp\n    ) internal {\n        require(comptroller.isMarketListed(vToken), \"rewardToken market is not listed\");\n\n        uint256 blockTimestamp = getBlockNumberOrTimestamp();\n\n        require(\n            supplyLastRewardingBlockTimestamp > blockTimestamp,\n            \"setting last rewarding timestamp in the past is not allowed\"\n        );\n        require(\n            borrowLastRewardingBlockTimestamp > blockTimestamp,\n            \"setting last rewarding timestamp in the past is not allowed\"\n        );\n\n        uint256 currentSupplyLastRewardingBlockTimestamp = rewardTokenSupplyStateTimeBased[address(vToken)]\n            .lastRewardingTimestamp;\n        uint256 currentBorrowLastRewardingBlockTimestamp = rewardTokenBorrowStateTimeBased[address(vToken)]\n            .lastRewardingTimestamp;\n\n        require(\n            currentSupplyLastRewardingBlockTimestamp == 0 || currentSupplyLastRewardingBlockTimestamp > blockTimestamp,\n            \"this RewardsDistributor is already locked\"\n        );\n        require(\n            currentBorrowLastRewardingBlockTimestamp == 0 || currentBorrowLastRewardingBlockTimestamp > blockTimestamp,\n            \"this RewardsDistributor is already locked\"\n        );\n\n        if (currentSupplyLastRewardingBlockTimestamp != supplyLastRewardingBlockTimestamp) {\n            rewardTokenSupplyStateTimeBased[address(vToken)].lastRewardingTimestamp = supplyLastRewardingBlockTimestamp;\n            emit SupplyLastRewardingBlockTimestampUpdated(address(vToken), supplyLastRewardingBlockTimestamp);\n        }\n\n        if (currentBorrowLastRewardingBlockTimestamp != borrowLastRewardingBlockTimestamp) {\n            rewardTokenBorrowStateTimeBased[address(vToken)].lastRewardingTimestamp = borrowLastRewardingBlockTimestamp;\n            emit BorrowLastRewardingBlockTimestampUpdated(address(vToken), borrowLastRewardingBlockTimestamp);\n        }\n    }\n\n    /**\n     * @notice Set REWARD TOKEN speed for a single market.\n     * @param vToken market's whose reward token rate to be updated\n     * @param supplySpeed New supply-side REWARD TOKEN speed for market\n     * @param borrowSpeed New borrow-side REWARD TOKEN speed for market\n     */\n    function _setRewardTokenSpeed(VToken vToken, uint256 supplySpeed, uint256 borrowSpeed) internal {\n        require(comptroller.isMarketListed(vToken), \"rewardToken market is not listed\");\n\n        if (rewardTokenSupplySpeeds[address(vToken)] != supplySpeed) {\n            // Supply speed updated so let's update supply state to ensure that\n            //  1. REWARD TOKEN accrued properly for the old speed, and\n            //  2. REWARD TOKEN accrued at the new speed starts after this block.\n            _updateRewardTokenSupplyIndex(address(vToken));\n\n            // Update speed and emit event\n            rewardTokenSupplySpeeds[address(vToken)] = supplySpeed;\n            emit RewardTokenSupplySpeedUpdated(vToken, supplySpeed);\n        }\n\n        if (rewardTokenBorrowSpeeds[address(vToken)] != borrowSpeed) {\n            // Borrow speed updated so let's update borrow state to ensure that\n            //  1. REWARD TOKEN accrued properly for the old speed, and\n            //  2. REWARD TOKEN accrued at the new speed starts after this block.\n            Exp memory borrowIndex = Exp({ mantissa: vToken.borrowIndex() });\n            _updateRewardTokenBorrowIndex(address(vToken), borrowIndex);\n\n            // Update speed and emit event\n            rewardTokenBorrowSpeeds[address(vToken)] = borrowSpeed;\n            emit RewardTokenBorrowSpeedUpdated(vToken, borrowSpeed);\n        }\n    }\n\n    /**\n     * @notice Calculate REWARD TOKEN accrued by a supplier and possibly transfer it to them.\n     * @param vToken The market in which the supplier is interacting\n     * @param supplier The address of the supplier to distribute REWARD TOKEN to\n     */\n    function _distributeSupplierRewardToken(address vToken, address supplier) internal {\n        RewardToken storage supplyState = rewardTokenSupplyState[vToken];\n        TimeBasedRewardToken storage supplyStateTimeBased = rewardTokenSupplyStateTimeBased[vToken];\n\n        uint256 supplyIndex = isTimeBased ? supplyStateTimeBased.index : supplyState.index;\n        uint256 supplierIndex = rewardTokenSupplierIndex[vToken][supplier];\n\n        // Update supplier's index to the current index since we are distributing accrued REWARD TOKEN\n        rewardTokenSupplierIndex[vToken][supplier] = supplyIndex;\n\n        if (supplierIndex == 0 && supplyIndex >= INITIAL_INDEX) {\n            // Covers the case where users supplied tokens before the market's supply state index was set.\n            // Rewards the user with REWARD TOKEN accrued from the start of when supplier rewards were first\n            // set for the market.\n            supplierIndex = INITIAL_INDEX;\n        }\n\n        // Calculate change in the cumulative sum of the REWARD TOKEN per vToken accrued\n        Double memory deltaIndex = Double({ mantissa: sub_(supplyIndex, supplierIndex) });\n\n        uint256 supplierTokens = VToken(vToken).balanceOf(supplier);\n\n        // Calculate REWARD TOKEN accrued: vTokenAmount * accruedPerVToken\n        uint256 supplierDelta = mul_(supplierTokens, deltaIndex);\n\n        uint256 supplierAccrued = add_(rewardTokenAccrued[supplier], supplierDelta);\n        rewardTokenAccrued[supplier] = supplierAccrued;\n\n        emit DistributedSupplierRewardToken(VToken(vToken), supplier, supplierDelta, supplierAccrued, supplyIndex);\n    }\n\n    /**\n     * @notice Calculate reward token accrued by a borrower and possibly transfer it to them.\n     * @param vToken The market in which the borrower is interacting\n     * @param borrower The address of the borrower to distribute REWARD TOKEN to\n     * @param marketBorrowIndex The current global borrow index of vToken\n     */\n    function _distributeBorrowerRewardToken(address vToken, address borrower, Exp memory marketBorrowIndex) internal {\n        RewardToken storage borrowState = rewardTokenBorrowState[vToken];\n        TimeBasedRewardToken storage borrowStateTimeBased = rewardTokenBorrowStateTimeBased[vToken];\n\n        uint256 borrowIndex = isTimeBased ? borrowStateTimeBased.index : borrowState.index;\n        uint256 borrowerIndex = rewardTokenBorrowerIndex[vToken][borrower];\n\n        // Update borrowers's index to the current index since we are distributing accrued REWARD TOKEN\n        rewardTokenBorrowerIndex[vToken][borrower] = borrowIndex;\n\n        if (borrowerIndex == 0 && borrowIndex >= INITIAL_INDEX) {\n            // Covers the case where users borrowed tokens before the market's borrow state index was set.\n            // Rewards the user with REWARD TOKEN accrued from the start of when borrower rewards were first\n            // set for the market.\n            borrowerIndex = INITIAL_INDEX;\n        }\n\n        // Calculate change in the cumulative sum of the REWARD TOKEN per borrowed unit accrued\n        Double memory deltaIndex = Double({ mantissa: sub_(borrowIndex, borrowerIndex) });\n\n        uint256 borrowerAmount = div_(VToken(vToken).borrowBalanceStored(borrower), marketBorrowIndex);\n\n        // Calculate REWARD TOKEN accrued: vTokenAmount * accruedPerBorrowedUnit\n        if (borrowerAmount != 0) {\n            uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex);\n\n            uint256 borrowerAccrued = add_(rewardTokenAccrued[borrower], borrowerDelta);\n            rewardTokenAccrued[borrower] = borrowerAccrued;\n\n            emit DistributedBorrowerRewardToken(VToken(vToken), borrower, borrowerDelta, borrowerAccrued, borrowIndex);\n        }\n    }\n\n    /**\n     * @notice Transfer REWARD TOKEN to the user.\n     * @dev Note: If there is not enough REWARD TOKEN, we do not perform the transfer all.\n     * @param user The address of the user to transfer REWARD TOKEN to\n     * @param amount The amount of REWARD TOKEN to (possibly) transfer\n     * @return The amount of REWARD TOKEN which was NOT transferred to the user\n     */\n    function _grantRewardToken(address user, uint256 amount) internal returns (uint256) {\n        uint256 rewardTokenRemaining = rewardToken.balanceOf(address(this));\n        if (amount > 0 && amount <= rewardTokenRemaining) {\n            rewardToken.safeTransfer(user, amount);\n            return 0;\n        }\n        return amount;\n    }\n\n    /**\n     * @notice Accrue REWARD TOKEN to the market by updating the supply index\n     * @param vToken The market whose supply index to update\n     * @dev Index is a cumulative sum of the REWARD TOKEN per vToken accrued\n     */\n    function _updateRewardTokenSupplyIndex(address vToken) internal {\n        RewardToken storage supplyState = rewardTokenSupplyState[vToken];\n        TimeBasedRewardToken storage supplyStateTimeBased = rewardTokenSupplyStateTimeBased[vToken];\n\n        uint256 supplySpeed = rewardTokenSupplySpeeds[vToken];\n        uint256 blockNumberOrTimestamp = getBlockNumberOrTimestamp();\n\n        if (!isTimeBased) {\n            safe32(blockNumberOrTimestamp, \"block number exceeds 32 bits\");\n        }\n\n        uint256 lastRewardingBlockOrTimestamp = isTimeBased\n            ? supplyStateTimeBased.lastRewardingTimestamp\n            : uint256(supplyState.lastRewardingBlock);\n\n        if (lastRewardingBlockOrTimestamp > 0 && blockNumberOrTimestamp > lastRewardingBlockOrTimestamp) {\n            blockNumberOrTimestamp = lastRewardingBlockOrTimestamp;\n        }\n\n        uint256 deltaBlocksOrTimestamp = sub_(\n            blockNumberOrTimestamp,\n            (isTimeBased ? supplyStateTimeBased.timestamp : uint256(supplyState.block))\n        );\n        if (deltaBlocksOrTimestamp > 0 && supplySpeed > 0) {\n            uint256 supplyTokens = VToken(vToken).totalSupply();\n            uint256 accruedSinceUpdate = mul_(deltaBlocksOrTimestamp, supplySpeed);\n            Double memory ratio = supplyTokens > 0\n                ? fraction(accruedSinceUpdate, supplyTokens)\n                : Double({ mantissa: 0 });\n            uint224 supplyIndex = isTimeBased ? supplyStateTimeBased.index : supplyState.index;\n            uint224 index = safe224(\n                add_(Double({ mantissa: supplyIndex }), ratio).mantissa,\n                \"new index exceeds 224 bits\"\n            );\n\n            if (isTimeBased) {\n                supplyStateTimeBased.index = index;\n                supplyStateTimeBased.timestamp = blockNumberOrTimestamp;\n            } else {\n                supplyState.index = index;\n                supplyState.block = uint32(blockNumberOrTimestamp);\n            }\n        } else if (deltaBlocksOrTimestamp > 0) {\n            isTimeBased ? supplyStateTimeBased.timestamp = blockNumberOrTimestamp : supplyState.block = uint32(\n                blockNumberOrTimestamp\n            );\n        }\n\n        emit RewardTokenSupplyIndexUpdated(vToken);\n    }\n\n    /**\n     * @notice Accrue REWARD TOKEN to the market by updating the borrow index\n     * @param vToken The market whose borrow index to update\n     * @param marketBorrowIndex The current global borrow index of vToken\n     * @dev Index is a cumulative sum of the REWARD TOKEN per vToken accrued\n     */\n    function _updateRewardTokenBorrowIndex(address vToken, Exp memory marketBorrowIndex) internal {\n        RewardToken storage borrowState = rewardTokenBorrowState[vToken];\n        TimeBasedRewardToken storage borrowStateTimeBased = rewardTokenBorrowStateTimeBased[vToken];\n\n        uint256 borrowSpeed = rewardTokenBorrowSpeeds[vToken];\n        uint256 blockNumberOrTimestamp = getBlockNumberOrTimestamp();\n\n        if (!isTimeBased) {\n            safe32(blockNumberOrTimestamp, \"block number exceeds 32 bits\");\n        }\n\n        uint256 lastRewardingBlockOrTimestamp = isTimeBased\n            ? borrowStateTimeBased.lastRewardingTimestamp\n            : uint256(borrowState.lastRewardingBlock);\n\n        if (lastRewardingBlockOrTimestamp > 0 && blockNumberOrTimestamp > lastRewardingBlockOrTimestamp) {\n            blockNumberOrTimestamp = lastRewardingBlockOrTimestamp;\n        }\n\n        uint256 deltaBlocksOrTimestamp = sub_(\n            blockNumberOrTimestamp,\n            (isTimeBased ? borrowStateTimeBased.timestamp : uint256(borrowState.block))\n        );\n        if (deltaBlocksOrTimestamp > 0 && borrowSpeed > 0) {\n            uint256 borrowAmount = div_(VToken(vToken).totalBorrows(), marketBorrowIndex);\n            uint256 accruedSinceUpdate = mul_(deltaBlocksOrTimestamp, borrowSpeed);\n            Double memory ratio = borrowAmount > 0\n                ? fraction(accruedSinceUpdate, borrowAmount)\n                : Double({ mantissa: 0 });\n            uint224 borrowIndex = isTimeBased ? borrowStateTimeBased.index : borrowState.index;\n            uint224 index = safe224(\n                add_(Double({ mantissa: borrowIndex }), ratio).mantissa,\n                \"new index exceeds 224 bits\"\n            );\n\n            if (isTimeBased) {\n                borrowStateTimeBased.index = index;\n                borrowStateTimeBased.timestamp = blockNumberOrTimestamp;\n            } else {\n                borrowState.index = index;\n                borrowState.block = uint32(blockNumberOrTimestamp);\n            }\n        } else if (deltaBlocksOrTimestamp > 0) {\n            if (isTimeBased) {\n                borrowStateTimeBased.timestamp = blockNumberOrTimestamp;\n            } else {\n                borrowState.block = uint32(blockNumberOrTimestamp);\n            }\n        }\n\n        emit RewardTokenBorrowIndexUpdated(vToken, marketBorrowIndex);\n    }\n\n    /**\n     * @notice Initializes the market state for a specific vToken called when contract is block-based\n     * @param vToken The address of the vToken to be initialized\n     * @param blockNumber current block number\n     */\n    function _initializeMarketBlockBased(address vToken, uint32 blockNumber) internal {\n        RewardToken storage supplyState = rewardTokenSupplyState[vToken];\n        RewardToken storage borrowState = rewardTokenBorrowState[vToken];\n\n        /*\n         * Update market state indices\n         */\n        if (supplyState.index == 0) {\n            // Initialize supply state index with default value\n            supplyState.index = INITIAL_INDEX;\n        }\n\n        if (borrowState.index == 0) {\n            // Initialize borrow state index with default value\n            borrowState.index = INITIAL_INDEX;\n        }\n\n        /*\n         * Update market state block numbers\n         */\n        supplyState.block = borrowState.block = blockNumber;\n    }\n\n    /**\n     * @notice Initializes the market state for a specific vToken called when contract is time-based\n     * @param vToken The address of the vToken to be initialized\n     * @param blockTimestamp current block timestamp\n     */\n    function _initializeMarketTimestampBased(address vToken, uint256 blockTimestamp) internal {\n        TimeBasedRewardToken storage supplyState = rewardTokenSupplyStateTimeBased[vToken];\n        TimeBasedRewardToken storage borrowState = rewardTokenBorrowStateTimeBased[vToken];\n\n        /*\n         * Update market state indices\n         */\n        if (supplyState.index == 0) {\n            // Initialize supply state index with default value\n            supplyState.index = INITIAL_INDEX;\n        }\n\n        if (borrowState.index == 0) {\n            // Initialize borrow state index with default value\n            borrowState.index = INITIAL_INDEX;\n        }\n\n        /*\n         * Update market state block timestamp\n         */\n        supplyState.timestamp = borrowState.timestamp = blockTimestamp;\n    }\n}\n"
    },
    "contracts/Rewards/RewardsDistributorStorage.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\n\nimport { Comptroller } from \"../Comptroller.sol\";\n\n/**\n * @title RewardsDistributorStorage\n * @author Venus\n * @dev Storage for RewardsDistributor\n */\ncontract RewardsDistributorStorage {\n    struct RewardToken {\n        // The market's last updated rewardTokenBorrowIndex or rewardTokenSupplyIndex\n        uint224 index;\n        // The block number the index was last updated at\n        uint32 block;\n        // The block number at which to stop rewards\n        uint32 lastRewardingBlock;\n    }\n\n    struct TimeBasedRewardToken {\n        // The market's last updated rewardTokenBorrowIndex or rewardTokenSupplyIndex\n        uint224 index;\n        // The block timestamp the index was last updated at\n        uint256 timestamp;\n        // The block timestamp at which to stop rewards\n        uint256 lastRewardingTimestamp;\n    }\n\n    /// @notice The REWARD TOKEN market supply state for each market\n    mapping(address => RewardToken) public rewardTokenSupplyState;\n\n    /// @notice The REWARD TOKEN borrow index for each market for each supplier as of the last time they accrued REWARD TOKEN\n    mapping(address => mapping(address => uint256)) public rewardTokenSupplierIndex;\n\n    /// @notice The REWARD TOKEN accrued but not yet transferred to each user\n    mapping(address => uint256) public rewardTokenAccrued;\n\n    /// @notice The rate at which rewardToken is distributed to the corresponding borrow market per slot (block or second)\n    mapping(address => uint256) public rewardTokenBorrowSpeeds;\n\n    /// @notice The rate at which rewardToken is distributed to the corresponding supply market per slot (block or second)\n    mapping(address => uint256) public rewardTokenSupplySpeeds;\n\n    /// @notice The REWARD TOKEN market borrow state for each market\n    mapping(address => RewardToken) public rewardTokenBorrowState;\n\n    /// @notice The portion of REWARD TOKEN that each contributor receives per slot (block or second)\n    mapping(address => uint256) public rewardTokenContributorSpeeds;\n\n    /// @notice Last slot (block or second) at which a contributor's REWARD TOKEN rewards have been allocated\n    mapping(address => uint256) public lastContributorBlock;\n\n    /// @notice The REWARD TOKEN borrow index for each market for each borrower as of the last time they accrued REWARD TOKEN\n    mapping(address => mapping(address => uint256)) public rewardTokenBorrowerIndex;\n\n    Comptroller internal comptroller;\n\n    IERC20Upgradeable public rewardToken;\n\n    /// @notice The REWARD TOKEN market supply state for each market\n    mapping(address => TimeBasedRewardToken) public rewardTokenSupplyStateTimeBased;\n\n    /// @notice The REWARD TOKEN market borrow state for each market\n    mapping(address => TimeBasedRewardToken) public rewardTokenBorrowStateTimeBased;\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[37] private __gap;\n}\n"
    },
    "contracts/test/Mocks/MockVenusERC4626.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\nimport { VenusERC4626 } from \"../../ERC4626/VenusERC4626.sol\";\n\ncontract MockVenusERC4626 is VenusERC4626 {\n    uint256 private mockTotalAssets;\n    uint256 private mockMaxDeposit;\n    uint256 private mockMaxWithdraw;\n    uint256 private mockMaxMint;\n    uint256 private mockMaxRedeem;\n\n    // Mock functions for testing\n    function setTotalAssets(uint256 _totalAssets) external {\n        mockTotalAssets = _totalAssets;\n    }\n\n    function setMaxWithdraw(uint256 _maxWithdraw) external {\n        mockMaxWithdraw = _maxWithdraw;\n    }\n\n    function setMaxDeposit(uint256 _maxDeposit) external {\n        mockMaxDeposit = _maxDeposit;\n    }\n\n    function setMaxRedeem(uint256 _maxRedeem) external {\n        mockMaxRedeem = _maxRedeem;\n    }\n\n    function setMaxMint(uint256 _maxMint) external {\n        mockMaxMint = _maxMint;\n    }\n\n    // Expose internal functions for testing\n    function getDecimalsOffset() external view returns (uint8) {\n        return _decimalsOffset();\n    }\n\n    // Override totalAssets to return the mocked value\n    function totalAssets() public view override returns (uint256) {\n        return mockTotalAssets;\n    }\n\n    // Override maxDeposit to return the mocked value\n    function maxDeposit(address) public view override returns (uint256) {\n        return mockMaxDeposit;\n    }\n\n    // Override maxWithdraw to return the mocked value\n    function maxWithdraw(address) public view override returns (uint256) {\n        return mockMaxWithdraw;\n    }\n\n    function maxMint(address) public view override returns (uint256) {\n        return mockMaxMint;\n    }\n\n    function maxRedeem(address) public view override returns (uint256) {\n        return mockMaxRedeem;\n    }\n}\n"
    },
    "contracts/VToken.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\nimport { IProtocolShareReserve } from \"@venusprotocol/protocol-reserve/contracts/Interfaces/IProtocolShareReserve.sol\";\n\nimport { VTokenInterface } from \"./VTokenInterfaces.sol\";\nimport { ComptrollerInterface, ComptrollerViewInterface } from \"./ComptrollerInterface.sol\";\nimport { TokenErrorReporter } from \"./ErrorReporter.sol\";\nimport { InterestRateModel } from \"./InterestRateModel.sol\";\nimport { ExponentialNoError } from \"./ExponentialNoError.sol\";\nimport { TimeManagerV8 } from \"@venusprotocol/solidity-utilities/contracts/TimeManagerV8.sol\";\nimport { ensureNonzeroAddress } from \"./lib/validators.sol\";\n\n/**\n * @title VToken\n * @author Venus\n * @notice Each asset that is supported by a pool is integrated through an instance of the `VToken` contract. As outlined in the protocol overview,\n * each isolated pool creates its own `vToken` corresponding to an asset. Within a given pool, each included `vToken` is referred to as a market of\n * the pool. The main actions a user regularly interacts with in a market are:\n\n- mint/redeem of vTokens;\n- transfer of vTokens;\n- borrow/repay a loan on an underlying asset;\n- liquidate a borrow or liquidate/heal an account.\n\n * A user supplies the underlying asset to a pool by minting `vTokens`, where the corresponding `vToken` amount is determined by the `exchangeRate`.\n * The `exchangeRate` will change over time, dependent on a number of factors, some of which accrue interest. Additionally, once users have minted\n * `vToken` in a pool, they can borrow any asset in the isolated pool by using their `vToken` as collateral. In order to borrow an asset or use a `vToken`\n * as collateral, the user must be entered into each corresponding market (else, the `vToken` will not be considered collateral for a borrow). Note that\n * a user may borrow up to a portion of their collateral determined by the market’s collateral factor. However, if their borrowed amount exceeds an amount\n * calculated using the market’s corresponding liquidation threshold, the borrow is eligible for liquidation. When a user repays a borrow, they must also\n * pay off interest accrued on the borrow.\n * \n * The Venus protocol includes unique mechanisms for healing an account and liquidating an account. These actions are performed in the `Comptroller`\n * and consider all borrows and collateral for which a given account is entered within a market. These functions may only be called on an account with a\n * total collateral amount that is no larger than a universal `minLiquidatableCollateral` value, which is used for all markets within a `Comptroller`.\n * Both functions settle all of an account’s borrows, but `healAccount()` may add `badDebt` to a vToken. For more detail, see the description of\n * `healAccount()` and `liquidateAccount()` in the `Comptroller` summary section below.\n */\ncontract VToken is\n    Ownable2StepUpgradeable,\n    AccessControlledV8,\n    VTokenInterface,\n    ExponentialNoError,\n    TokenErrorReporter,\n    TimeManagerV8\n{\n    using SafeERC20Upgradeable for IERC20Upgradeable;\n\n    uint256 internal constant DEFAULT_PROTOCOL_SEIZE_SHARE_MANTISSA = 5e16; // 5%\n\n    // Maximum fraction of interest that can be set aside for reserves\n    uint256 internal constant MAX_RESERVE_FACTOR_MANTISSA = 1e18;\n\n    // Maximum borrow rate that can ever be applied per slot(block or second)\n    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n    uint256 internal immutable MAX_BORROW_RATE_MANTISSA;\n\n    /**\n     * Reentrancy Guard **\n     */\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     */\n    modifier nonReentrant() {\n        require(_notEntered, \"re-entered\");\n        _notEntered = false;\n        _;\n        _notEntered = true; // get a gas-refund post-Istanbul\n    }\n\n    /**\n     * @param timeBased_ A boolean indicating whether the contract is based on time or block.\n     * @param blocksPerYear_ The number of blocks per year\n     * @param maxBorrowRateMantissa_ The maximum value of borrowing rate mantissa\n     * @custom:oz-upgrades-unsafe-allow constructor\n     */\n    constructor(\n        bool timeBased_,\n        uint256 blocksPerYear_,\n        uint256 maxBorrowRateMantissa_\n    ) TimeManagerV8(timeBased_, blocksPerYear_) {\n        // Note that the contract is upgradeable. Use initialize() or reinitializers\n        // to set the state variables.\n        require(maxBorrowRateMantissa_ <= 1e18, \"Max borrow rate must be <= 1e18\");\n\n        MAX_BORROW_RATE_MANTISSA = maxBorrowRateMantissa_;\n        _disableInitializers();\n    }\n\n    /**\n     * @notice Construct a new money market\n     * @param underlying_ The address of the underlying asset\n     * @param comptroller_ The address of the Comptroller\n     * @param interestRateModel_ The address of the interest rate model\n     * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n     * @param name_ ERC-20 name of this token\n     * @param symbol_ ERC-20 symbol of this token\n     * @param decimals_ ERC-20 decimal precision of this token\n     * @param admin_ Address of the administrator of this token\n     * @param accessControlManager_ AccessControlManager contract address\n     * @param riskManagement Addresses of risk & income related contracts\n     * @param reserveFactorMantissa_ Percentage of borrow interest that goes to reserves (from 0 to 1e18)\n     * @custom:error ZeroAddressNotAllowed is thrown when admin address is zero\n     * @custom:error ZeroAddressNotAllowed is thrown when shortfall contract address is zero\n     * @custom:error ZeroAddressNotAllowed is thrown when protocol share reserve address is zero\n     */\n    function initialize(\n        address underlying_,\n        ComptrollerInterface comptroller_,\n        InterestRateModel interestRateModel_,\n        uint256 initialExchangeRateMantissa_,\n        string memory name_,\n        string memory symbol_,\n        uint8 decimals_,\n        address admin_,\n        address accessControlManager_,\n        RiskManagementInit memory riskManagement,\n        uint256 reserveFactorMantissa_\n    ) external initializer {\n        ensureNonzeroAddress(admin_);\n\n        // Initialize the market\n        _initialize(\n            underlying_,\n            comptroller_,\n            interestRateModel_,\n            initialExchangeRateMantissa_,\n            name_,\n            symbol_,\n            decimals_,\n            admin_,\n            accessControlManager_,\n            riskManagement,\n            reserveFactorMantissa_\n        );\n    }\n\n    /**\n     * @notice Transfer `amount` tokens from `msg.sender` to `dst`\n     * @param dst The address of the destination account\n     * @param amount The number of tokens to transfer\n     * @return success True if the transfer succeeded, reverts otherwise\n     * @custom:event Emits Transfer event on success\n     * @custom:error TransferNotAllowed is thrown if trying to transfer to self\n     * @custom:access Not restricted\n     */\n    function transfer(address dst, uint256 amount) external override nonReentrant returns (bool) {\n        _transferTokens(msg.sender, msg.sender, dst, amount);\n        return true;\n    }\n\n    /**\n     * @notice Transfer `amount` tokens from `src` to `dst`\n     * @param src The address of the source account\n     * @param dst The address of the destination account\n     * @param amount The number of tokens to transfer\n     * @return success True if the transfer succeeded, reverts otherwise\n     * @custom:event Emits Transfer event on success\n     * @custom:error TransferNotAllowed is thrown if trying to transfer to self\n     * @custom:access Not restricted\n     */\n    function transferFrom(address src, address dst, uint256 amount) external override nonReentrant returns (bool) {\n        _transferTokens(msg.sender, src, dst, amount);\n        return true;\n    }\n\n    /**\n     * @notice Approve `spender` to transfer up to `amount` from `src`\n     * @dev This will overwrite the approval amount for `spender`\n     *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)\n     * @param spender The address of the account which may transfer tokens\n     * @param amount The number of tokens that are approved (uint256.max means infinite)\n     * @return success Whether or not the approval succeeded\n     * @custom:event Emits Approval event\n     * @custom:access Not restricted\n     * @custom:error ZeroAddressNotAllowed is thrown when spender address is zero\n     */\n    function approve(address spender, uint256 amount) external override returns (bool) {\n        ensureNonzeroAddress(spender);\n\n        address src = msg.sender;\n        transferAllowances[src][spender] = amount;\n        emit Approval(src, spender, amount);\n        return true;\n    }\n\n    /**\n     * @notice Increase approval for `spender`\n     * @param spender The address of the account which may transfer tokens\n     * @param addedValue The number of additional tokens spender can transfer\n     * @return success Whether or not the approval succeeded\n     * @custom:event Emits Approval event\n     * @custom:access Not restricted\n     * @custom:error ZeroAddressNotAllowed is thrown when spender address is zero\n     */\n    function increaseAllowance(address spender, uint256 addedValue) external override returns (bool) {\n        ensureNonzeroAddress(spender);\n\n        address src = msg.sender;\n        uint256 newAllowance = transferAllowances[src][spender];\n        newAllowance += addedValue;\n        transferAllowances[src][spender] = newAllowance;\n\n        emit Approval(src, spender, newAllowance);\n        return true;\n    }\n\n    /**\n     * @notice Decreases approval for `spender`\n     * @param spender The address of the account which may transfer tokens\n     * @param subtractedValue The number of tokens to remove from total approval\n     * @return success Whether or not the approval succeeded\n     * @custom:event Emits Approval event\n     * @custom:access Not restricted\n     * @custom:error ZeroAddressNotAllowed is thrown when spender address is zero\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) external override returns (bool) {\n        ensureNonzeroAddress(spender);\n\n        address src = msg.sender;\n        uint256 currentAllowance = transferAllowances[src][spender];\n        require(currentAllowance >= subtractedValue, \"decreased allowance below zero\");\n        unchecked {\n            currentAllowance -= subtractedValue;\n        }\n\n        transferAllowances[src][spender] = currentAllowance;\n\n        emit Approval(src, spender, currentAllowance);\n        return true;\n    }\n\n    /**\n     * @notice Get the underlying balance of the `owner`\n     * @dev This also accrues interest in a transaction\n     * @param owner The address of the account to query\n     * @return amount The amount of underlying owned by `owner`\n     */\n    function balanceOfUnderlying(address owner) external override returns (uint256) {\n        Exp memory exchangeRate = Exp({ mantissa: exchangeRateCurrent() });\n        return mul_ScalarTruncate(exchangeRate, accountTokens[owner]);\n    }\n\n    /**\n     * @notice Returns the current total borrows plus accrued interest\n     * @return totalBorrows The total borrows with interest\n     */\n    function totalBorrowsCurrent() external override nonReentrant returns (uint256) {\n        accrueInterest();\n        return totalBorrows;\n    }\n\n    /**\n     * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex\n     * @param account The address whose balance should be calculated after updating borrowIndex\n     * @return borrowBalance The calculated balance\n     */\n    function borrowBalanceCurrent(address account) external override nonReentrant returns (uint256) {\n        accrueInterest();\n        return _borrowBalanceStored(account);\n    }\n\n    /**\n     * @notice Sender supplies assets into the market and receives vTokens in exchange\n     * @dev Accrues interest whether or not the operation succeeds, unless reverted\n     * @param mintAmount The amount of the underlying asset to supply\n     * @return error Always NO_ERROR for compatibility with Venus core tooling\n     * @custom:event Emits Mint and Transfer events; may emit AccrueInterest\n     * @custom:access Not restricted\n     */\n    function mint(uint256 mintAmount) external override nonReentrant returns (uint256) {\n        accrueInterest();\n\n        _mintFresh(msg.sender, msg.sender, mintAmount);\n        return NO_ERROR;\n    }\n\n    /**\n     * @notice Sender calls on-behalf of minter. minter supplies assets into the market and receives vTokens in exchange\n     * @dev Accrues interest whether or not the operation succeeds, unless reverted\n     * @param minter User whom the supply will be attributed to\n     * @param mintAmount The amount of the underlying asset to supply\n     * @return error Always NO_ERROR for compatibility with Venus core tooling\n     * @custom:event Emits Mint and Transfer events; may emit AccrueInterest\n     * @custom:access Not restricted\n     * @custom:error ZeroAddressNotAllowed is thrown when minter address is zero\n     */\n    function mintBehalf(address minter, uint256 mintAmount) external override nonReentrant returns (uint256) {\n        ensureNonzeroAddress(minter);\n\n        accrueInterest();\n\n        _mintFresh(msg.sender, minter, mintAmount);\n        return NO_ERROR;\n    }\n\n    /**\n     * @notice Sender redeems vTokens in exchange for the underlying asset\n     * @dev Accrues interest whether or not the operation succeeds, unless reverted\n     * @param redeemTokens The number of vTokens to redeem into underlying\n     * @return error Always NO_ERROR for compatibility with Venus core tooling\n     * @custom:event Emits Redeem and Transfer events; may emit AccrueInterest\n     * @custom:error RedeemTransferOutNotPossible is thrown when the protocol has insufficient cash\n     * @custom:access Not restricted\n     */\n    function redeem(uint256 redeemTokens) external override nonReentrant returns (uint256) {\n        accrueInterest();\n\n        _redeemFresh(msg.sender, msg.sender, redeemTokens, 0);\n        return NO_ERROR;\n    }\n\n    /**\n     * @notice Sender redeems assets on behalf of some other address. This function is only available\n     *   for senders, explicitly marked as delegates of the supplier using `comptroller.updateDelegate`\n     * @dev Accrues interest whether or not the operation succeeds, unless reverted\n     * @param redeemer The user on behalf of whom to redeem\n     * @param redeemTokens The number of vTokens to redeem into underlying\n     * @return error Always NO_ERROR for compatibility with Venus core tooling\n     * @custom:error InsufficientRedeemApproval is thrown when sender is not approved by the redeemer for the given amount\n     * @custom:error RedeemTransferOutNotPossible is thrown when the protocol has insufficient cash\n     * @custom:event Emits Redeem and Transfer events; may emit AccrueInterest\n     * @custom:access Not restricted\n     */\n    function redeemBehalf(address redeemer, uint256 redeemTokens) external override nonReentrant returns (uint256) {\n        _ensureSenderIsDelegateOf(redeemer);\n\n        accrueInterest();\n\n        _redeemFresh(redeemer, msg.sender, redeemTokens, 0);\n        return NO_ERROR;\n    }\n\n    /**\n     * @notice Sender redeems vTokens in exchange for a specified amount of underlying asset\n     * @dev Accrues interest whether or not the operation succeeds, unless reverted\n     * @param redeemAmount The amount of underlying to receive from redeeming vTokens\n     * @return error Always NO_ERROR for compatibility with Venus core tooling\n     */\n    function redeemUnderlying(uint256 redeemAmount) external override nonReentrant returns (uint256) {\n        accrueInterest();\n\n        _redeemFresh(msg.sender, msg.sender, 0, redeemAmount);\n        return NO_ERROR;\n    }\n\n    /**\n     * @notice Sender redeems underlying assets on behalf of some other address. This function is only available\n     *   for senders, explicitly marked as delegates of the supplier using `comptroller.updateDelegate`\n     * @dev Accrues interest whether or not the operation succeeds, unless reverted\n     * @param redeemer, on behalf of whom to redeem\n     * @param redeemAmount The amount of underlying to receive from redeeming vTokens\n     * @return error Always NO_ERROR for compatibility with Venus core tooling\n     * @custom:error InsufficientRedeemApproval is thrown when sender is not approved by the redeemer for the given amount\n     * @custom:event Emits Redeem and Transfer events; may emit AccrueInterest\n     * @custom:access Not restricted\n     */\n    function redeemUnderlyingBehalf(\n        address redeemer,\n        uint256 redeemAmount\n    ) external override nonReentrant returns (uint256) {\n        _ensureSenderIsDelegateOf(redeemer);\n\n        accrueInterest();\n\n        _redeemFresh(redeemer, msg.sender, 0, redeemAmount);\n        return NO_ERROR;\n    }\n\n    /**\n     * @notice Sender borrows assets from the protocol to their own address\n     * @param borrowAmount The amount of the underlying asset to borrow\n     * @return error Always NO_ERROR for compatibility with Venus core tooling\n     * @custom:event Emits Borrow event; may emit AccrueInterest\n     * @custom:error BorrowCashNotAvailable is thrown when the protocol has insufficient cash\n     * @custom:access Not restricted\n     */\n    function borrow(uint256 borrowAmount) external override nonReentrant returns (uint256) {\n        accrueInterest();\n\n        _borrowFresh(msg.sender, msg.sender, borrowAmount);\n        return NO_ERROR;\n    }\n\n    /**\n     * @notice Sender borrows assets on behalf of some other address. This function is only available\n     *   for senders, explicitly marked as delegates of the borrower using `comptroller.updateDelegate`\n     * @param borrower The borrower, on behalf of whom to borrow\n     * @param borrowAmount The amount of the underlying asset to borrow\n     * @return error Always NO_ERROR for compatibility with Venus core tooling\n     * @custom:error DelegateNotApproved is thrown if caller is not approved delegate\n     * @custom:error BorrowCashNotAvailable is thrown when the protocol has insufficient cash\n     * @custom:event Emits Borrow event; may emit AccrueInterest\n     * @custom:access Not restricted\n     */\n    function borrowBehalf(address borrower, uint256 borrowAmount) external override returns (uint256) {\n        _ensureSenderIsDelegateOf(borrower);\n        accrueInterest();\n\n        _borrowFresh(borrower, msg.sender, borrowAmount);\n        return NO_ERROR;\n    }\n\n    /**\n     * @notice Sender repays their own borrow\n     * @param repayAmount The amount to repay, or type(uint256).max for the full outstanding amount\n     * @return error Always NO_ERROR for compatibility with Venus core tooling\n     * @custom:event Emits RepayBorrow event; may emit AccrueInterest\n     * @custom:access Not restricted\n     */\n    function repayBorrow(uint256 repayAmount) external override nonReentrant returns (uint256) {\n        accrueInterest();\n\n        _repayBorrowFresh(msg.sender, msg.sender, repayAmount);\n        return NO_ERROR;\n    }\n\n    /**\n     * @notice Sender repays a borrow belonging to borrower\n     * @param borrower the account with the debt being payed off\n     * @param repayAmount The amount to repay, or type(uint256).max for the full outstanding amount\n     * @return error Always NO_ERROR for compatibility with Venus core tooling\n     * @custom:event Emits RepayBorrow event; may emit AccrueInterest\n     * @custom:access Not restricted\n     */\n    function repayBorrowBehalf(address borrower, uint256 repayAmount) external override nonReentrant returns (uint256) {\n        accrueInterest();\n\n        _repayBorrowFresh(msg.sender, borrower, repayAmount);\n        return NO_ERROR;\n    }\n\n    /**\n     * @notice The sender liquidates the borrowers collateral.\n     *  The collateral seized is transferred to the liquidator.\n     * @param borrower The borrower of this vToken to be liquidated\n     * @param repayAmount The amount of the underlying borrowed asset to repay\n     * @param vTokenCollateral The market in which to seize collateral from the borrower\n     * @return error Always NO_ERROR for compatibility with Venus core tooling\n     * @custom:event Emits LiquidateBorrow event; may emit AccrueInterest\n     * @custom:error LiquidateAccrueCollateralInterestFailed is thrown when it is not possible to accrue interest on the collateral vToken\n     * @custom:error LiquidateCollateralFreshnessCheck is thrown when interest has not been accrued on the collateral vToken\n     * @custom:error LiquidateLiquidatorIsBorrower is thrown when trying to liquidate self\n     * @custom:error LiquidateCloseAmountIsZero is thrown when repayment amount is zero\n     * @custom:error LiquidateCloseAmountIsUintMax is thrown when repayment amount is UINT_MAX\n     * @custom:access Not restricted\n     */\n    function liquidateBorrow(\n        address borrower,\n        uint256 repayAmount,\n        VTokenInterface vTokenCollateral\n    ) external override returns (uint256) {\n        _liquidateBorrow(msg.sender, borrower, repayAmount, vTokenCollateral, false);\n        return NO_ERROR;\n    }\n\n    /**\n     * @notice sets protocol share accumulated from liquidations\n     * @dev must be equal or less than liquidation incentive - 1\n     * @param newProtocolSeizeShareMantissa_ new protocol share mantissa\n     * @custom:event Emits NewProtocolSeizeShare event on success\n     * @custom:error Unauthorized error is thrown when the call is not authorized by AccessControlManager\n     * @custom:error ProtocolSeizeShareTooBig is thrown when the new seize share is too high\n     * @custom:access Controlled by AccessControlManager\n     */\n    function setProtocolSeizeShare(uint256 newProtocolSeizeShareMantissa_) external {\n        _checkAccessAllowed(\"setProtocolSeizeShare(uint256)\");\n        uint256 liquidationIncentive = ComptrollerViewInterface(address(comptroller)).liquidationIncentiveMantissa();\n        if (newProtocolSeizeShareMantissa_ + MANTISSA_ONE > liquidationIncentive) {\n            revert ProtocolSeizeShareTooBig();\n        }\n\n        uint256 oldProtocolSeizeShareMantissa = protocolSeizeShareMantissa;\n        protocolSeizeShareMantissa = newProtocolSeizeShareMantissa_;\n        emit NewProtocolSeizeShare(oldProtocolSeizeShareMantissa, newProtocolSeizeShareMantissa_);\n    }\n\n    /**\n     * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh\n     * @dev Admin function to accrue interest and set a new reserve factor\n     * @param newReserveFactorMantissa New reserve factor (from 0 to 1e18)\n     * @custom:event Emits NewReserveFactor event; may emit AccrueInterest\n     * @custom:error Unauthorized error is thrown when the call is not authorized by AccessControlManager\n     * @custom:error SetReserveFactorBoundsCheck is thrown when the new reserve factor is too high\n     * @custom:access Controlled by AccessControlManager\n     */\n    function setReserveFactor(uint256 newReserveFactorMantissa) external override nonReentrant {\n        _checkAccessAllowed(\"setReserveFactor(uint256)\");\n\n        accrueInterest();\n        _setReserveFactorFresh(newReserveFactorMantissa);\n    }\n\n    /**\n     * @notice Accrues interest and reduces reserves by transferring to the protocol reserve contract\n     * @dev Gracefully return if reserves already reduced in accrueInterest\n     * @param reduceAmount Amount of reduction to reserves\n     * @custom:event Emits ReservesReduced event; may emit AccrueInterest\n     * @custom:error ReduceReservesCashNotAvailable is thrown when the vToken does not have sufficient cash\n     * @custom:error ReduceReservesCashValidation is thrown when trying to withdraw more cash than the reserves have\n     * @custom:access Not restricted\n     */\n    function reduceReserves(uint256 reduceAmount) external override nonReentrant {\n        accrueInterest();\n        if (reduceReservesBlockNumber == getBlockNumberOrTimestamp()) return;\n        _reduceReservesFresh(reduceAmount);\n    }\n\n    /**\n     * @notice The sender adds to reserves.\n     * @param addAmount The amount of underlying token to add as reserves\n     * @custom:event Emits ReservesAdded event; may emit AccrueInterest\n     * @custom:access Not restricted\n     */\n    function addReserves(uint256 addAmount) external override nonReentrant {\n        accrueInterest();\n        _addReservesFresh(addAmount);\n    }\n\n    /**\n     * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh\n     * @dev Admin function to accrue interest and update the interest rate model\n     * @param newInterestRateModel the new interest rate model to use\n     * @custom:event Emits NewMarketInterestRateModel event; may emit AccrueInterest\n     * @custom:error Unauthorized error is thrown when the call is not authorized by AccessControlManager\n     * @custom:access Controlled by AccessControlManager\n     */\n    function setInterestRateModel(InterestRateModel newInterestRateModel) external override {\n        _checkAccessAllowed(\"setInterestRateModel(address)\");\n\n        accrueInterest();\n        _setInterestRateModelFresh(newInterestRateModel);\n    }\n\n    /**\n     * @notice Repays a certain amount of debt, treats the rest of the borrow as bad debt, essentially\n     *   \"forgiving\" the borrower. Healing is a situation that should rarely happen. However, some pools\n     *   may list risky assets or be configured improperly – we want to still handle such cases gracefully.\n     *   We assume that Comptroller does the seizing, so this function is only available to Comptroller.\n     * @dev This function does not call any Comptroller hooks (like \"healAllowed\"), because we assume\n     *   the Comptroller does all the necessary checks before calling this function.\n     * @param payer account who repays the debt\n     * @param borrower account to heal\n     * @param repayAmount amount to repay\n     * @custom:event Emits RepayBorrow, BadDebtIncreased events; may emit AccrueInterest\n     * @custom:error HealBorrowUnauthorized is thrown when the request does not come from Comptroller\n     * @custom:access Only Comptroller\n     */\n    function healBorrow(address payer, address borrower, uint256 repayAmount) external override nonReentrant {\n        if (repayAmount != 0) {\n            comptroller.preRepayHook(address(this), borrower);\n        }\n\n        if (msg.sender != address(comptroller)) {\n            revert HealBorrowUnauthorized();\n        }\n\n        uint256 accountBorrowsPrev = _borrowBalanceStored(borrower);\n        uint256 totalBorrowsNew = totalBorrows;\n\n        uint256 actualRepayAmount;\n        if (repayAmount != 0) {\n            // _doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.\n            // We violate checks-effects-interactions here to account for tokens that take transfer fees\n            actualRepayAmount = _doTransferIn(payer, repayAmount);\n            totalBorrowsNew = totalBorrowsNew - actualRepayAmount;\n            emit RepayBorrow(\n                payer,\n                borrower,\n                actualRepayAmount,\n                accountBorrowsPrev - actualRepayAmount,\n                totalBorrowsNew\n            );\n        }\n\n        // The transaction will fail if trying to repay too much\n        uint256 badDebtDelta = accountBorrowsPrev - actualRepayAmount;\n        if (badDebtDelta != 0) {\n            uint256 badDebtOld = badDebt;\n            uint256 badDebtNew = badDebtOld + badDebtDelta;\n            totalBorrowsNew = totalBorrowsNew - badDebtDelta;\n            badDebt = badDebtNew;\n\n            // We treat healing as \"repayment\", where vToken is the payer\n            emit RepayBorrow(address(this), borrower, badDebtDelta, 0, totalBorrowsNew);\n            emit BadDebtIncreased(borrower, badDebtDelta, badDebtOld, badDebtNew);\n        }\n\n        accountBorrows[borrower].principal = 0;\n        accountBorrows[borrower].interestIndex = borrowIndex;\n        totalBorrows = totalBorrowsNew;\n\n        emit HealBorrow(payer, borrower, repayAmount);\n    }\n\n    /**\n     * @notice The extended version of liquidations, callable only by Comptroller. May skip\n     *  the close factor check. The collateral seized is transferred to the liquidator.\n     * @param liquidator The address repaying the borrow and seizing collateral\n     * @param borrower The borrower of this vToken to be liquidated\n     * @param repayAmount The amount of the underlying borrowed asset to repay\n     * @param vTokenCollateral The market in which to seize collateral from the borrower\n     * @param skipLiquidityCheck If set to true, allows to liquidate up to 100% of the borrow\n     *   regardless of the account liquidity\n     * @custom:event Emits LiquidateBorrow event; may emit AccrueInterest\n     * @custom:error ForceLiquidateBorrowUnauthorized is thrown when the request does not come from Comptroller\n     * @custom:error LiquidateAccrueCollateralInterestFailed is thrown when it is not possible to accrue interest on the collateral vToken\n     * @custom:error LiquidateCollateralFreshnessCheck is thrown when interest has not been accrued on the collateral vToken\n     * @custom:error LiquidateLiquidatorIsBorrower is thrown when trying to liquidate self\n     * @custom:error LiquidateCloseAmountIsZero is thrown when repayment amount is zero\n     * @custom:error LiquidateCloseAmountIsUintMax is thrown when repayment amount is UINT_MAX\n     * @custom:access Only Comptroller\n     */\n    function forceLiquidateBorrow(\n        address liquidator,\n        address borrower,\n        uint256 repayAmount,\n        VTokenInterface vTokenCollateral,\n        bool skipLiquidityCheck\n    ) external override {\n        if (msg.sender != address(comptroller)) {\n            revert ForceLiquidateBorrowUnauthorized();\n        }\n        _liquidateBorrow(liquidator, borrower, repayAmount, vTokenCollateral, skipLiquidityCheck);\n    }\n\n    /**\n     * @notice Transfers collateral tokens (this market) to the liquidator.\n     * @dev Will fail unless called by another vToken during the process of liquidation.\n     *  It's absolutely critical to use msg.sender as the borrowed vToken and not a parameter.\n     * @param liquidator The account receiving seized collateral\n     * @param borrower The account having collateral seized\n     * @param seizeTokens The number of vTokens to seize\n     * @custom:event Emits Transfer, ReservesAdded events\n     * @custom:error LiquidateSeizeLiquidatorIsBorrower is thrown when trying to liquidate self\n     * @custom:access Not restricted\n     */\n    function seize(address liquidator, address borrower, uint256 seizeTokens) external override nonReentrant {\n        _seize(msg.sender, liquidator, borrower, seizeTokens);\n    }\n\n    /**\n     * @notice Updates bad debt\n     * @dev Called only when bad debt is recovered from auction\n     * @param recoveredAmount_ The amount of bad debt recovered\n     * @custom:event Emits BadDebtRecovered event\n     * @custom:access Only Shortfall contract\n     */\n    function badDebtRecovered(uint256 recoveredAmount_) external {\n        require(msg.sender == shortfall, \"only shortfall contract can update bad debt\");\n        require(recoveredAmount_ <= badDebt, \"more than bad debt recovered from auction\");\n\n        uint256 badDebtOld = badDebt;\n        uint256 badDebtNew = badDebtOld - recoveredAmount_;\n        badDebt = badDebtNew;\n\n        emit BadDebtRecovered(badDebtOld, badDebtNew);\n    }\n\n    /**\n     * @notice Sets protocol share reserve contract address\n     * @param protocolShareReserve_ The address of the protocol share reserve contract\n     * @custom:error ZeroAddressNotAllowed is thrown when protocol share reserve address is zero\n     * @custom:access Only Governance\n     */\n    function setProtocolShareReserve(address payable protocolShareReserve_) external onlyOwner {\n        _setProtocolShareReserve(protocolShareReserve_);\n    }\n\n    /**\n     * @notice Sets shortfall contract address\n     * @param shortfall_ The address of the shortfall contract\n     * @custom:error ZeroAddressNotAllowed is thrown when shortfall contract address is zero\n     * @custom:access Only Governance\n     */\n    function setShortfallContract(address shortfall_) external onlyOwner {\n        _setShortfallContract(shortfall_);\n    }\n\n    /**\n     * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock)\n     * @param token The address of the ERC-20 token to sweep\n     * @custom:access Only Governance\n     */\n    function sweepToken(IERC20Upgradeable token) external override {\n        require(msg.sender == owner(), \"VToken::sweepToken: only admin can sweep tokens\");\n        require(address(token) != underlying, \"VToken::sweepToken: can not sweep underlying token\");\n        uint256 balance = token.balanceOf(address(this));\n        token.safeTransfer(owner(), balance);\n\n        emit SweepToken(address(token));\n    }\n\n    /**\n     * @notice A public function to set new threshold of slot(block or second) difference after which funds will be sent to the protocol share reserve\n     * @param _newReduceReservesBlockOrTimestampDelta slot(block or second) difference value\n     * @custom:access Only Governance\n     */\n    function setReduceReservesBlockDelta(uint256 _newReduceReservesBlockOrTimestampDelta) external {\n        _checkAccessAllowed(\"setReduceReservesBlockDelta(uint256)\");\n        require(_newReduceReservesBlockOrTimestampDelta > 0, \"Invalid Input\");\n        emit NewReduceReservesBlockDelta(reduceReservesBlockDelta, _newReduceReservesBlockOrTimestampDelta);\n        reduceReservesBlockDelta = _newReduceReservesBlockOrTimestampDelta;\n    }\n\n    /**\n     * @notice Get the current allowance from `owner` for `spender`\n     * @param owner The address of the account which owns the tokens to be spent\n     * @param spender The address of the account which may transfer tokens\n     * @return amount The number of tokens allowed to be spent (type(uint256).max means infinite)\n     */\n    function allowance(address owner, address spender) external view override returns (uint256) {\n        return transferAllowances[owner][spender];\n    }\n\n    /**\n     * @notice Get the token balance of the `owner`\n     * @param owner The address of the account to query\n     * @return amount The number of tokens owned by `owner`\n     */\n    function balanceOf(address owner) external view override returns (uint256) {\n        return accountTokens[owner];\n    }\n\n    /**\n     * @notice Get a snapshot of the account's balances, and the cached exchange rate\n     * @dev This is used by comptroller to more efficiently perform liquidity checks.\n     * @param account Address of the account to snapshot\n     * @return error Always NO_ERROR for compatibility with Venus core tooling\n     * @return vTokenBalance User's balance of vTokens\n     * @return borrowBalance Amount owed in terms of underlying\n     * @return exchangeRate Stored exchange rate\n     */\n    function getAccountSnapshot(\n        address account\n    )\n        external\n        view\n        override\n        returns (uint256 error, uint256 vTokenBalance, uint256 borrowBalance, uint256 exchangeRate)\n    {\n        return (NO_ERROR, accountTokens[account], _borrowBalanceStored(account), _exchangeRateStored());\n    }\n\n    /**\n     * @notice Get cash balance of this vToken in the underlying asset\n     * @return cash The quantity of underlying asset owned by this contract\n     */\n    function getCash() external view override returns (uint256) {\n        return _getCashPrior();\n    }\n\n    /**\n     * @notice Returns the current per slot(block or second) borrow interest rate for this vToken\n     * @return rate The borrow interest rate per slot(block or second), scaled by 1e18\n     */\n    function borrowRatePerBlock() external view override returns (uint256) {\n        return interestRateModel.getBorrowRate(_getCashPrior(), totalBorrows, totalReserves, badDebt);\n    }\n\n    /**\n     * @notice Returns the current per-slot(block or second) supply interest rate for this v\n     * @return rate The supply interest rate per slot(block or second), scaled by 1e18\n     */\n    function supplyRatePerBlock() external view override returns (uint256) {\n        return\n            interestRateModel.getSupplyRate(\n                _getCashPrior(),\n                totalBorrows,\n                totalReserves,\n                reserveFactorMantissa,\n                badDebt\n            );\n    }\n\n    /**\n     * @notice Return the borrow balance of account based on stored data\n     * @param account The address whose balance should be calculated\n     * @return borrowBalance The calculated balance\n     */\n    function borrowBalanceStored(address account) external view override returns (uint256) {\n        return _borrowBalanceStored(account);\n    }\n\n    /**\n     * @notice Calculates the exchange rate from the underlying to the VToken\n     * @dev This function does not accrue interest before calculating the exchange rate\n     * @return exchangeRate Calculated exchange rate scaled by 1e18\n     */\n    function exchangeRateStored() external view override returns (uint256) {\n        return _exchangeRateStored();\n    }\n\n    /**\n     * @notice Accrue interest then return the up-to-date exchange rate\n     * @return exchangeRate Calculated exchange rate scaled by 1e18\n     */\n    function exchangeRateCurrent() public override nonReentrant returns (uint256) {\n        accrueInterest();\n        return _exchangeRateStored();\n    }\n\n    /**\n     * @notice Applies accrued interest to total borrows and reserves\n     * @dev This calculates interest accrued from the last checkpointed slot(block or second)\n     *  up to the current slot(block or second) and writes new checkpoint to storage and\n     *  reduce spread reserves to protocol share reserve\n     *  if currentSlot - reduceReservesBlockNumber >= slotDelta\n     * @return Always NO_ERROR\n     * @custom:event Emits AccrueInterest event on success\n     * @custom:access Not restricted\n     */\n    function accrueInterest() public virtual override returns (uint256) {\n        /* Remember the initial block number or timestamp */\n        uint256 currentSlotNumber = getBlockNumberOrTimestamp();\n        uint256 accrualSlotNumberPrior = accrualBlockNumber;\n\n        /* Short-circuit accumulating 0 interest */\n        if (accrualSlotNumberPrior == currentSlotNumber) {\n            return NO_ERROR;\n        }\n\n        /* Read the previous values out of storage */\n        uint256 cashPrior = _getCashPrior();\n        uint256 borrowsPrior = totalBorrows;\n        uint256 reservesPrior = totalReserves;\n        uint256 borrowIndexPrior = borrowIndex;\n\n        /* Calculate the current borrow interest rate */\n        uint256 borrowRateMantissa = interestRateModel.getBorrowRate(cashPrior, borrowsPrior, reservesPrior, badDebt);\n        require(borrowRateMantissa <= MAX_BORROW_RATE_MANTISSA, \"borrow rate is absurdly high\");\n\n        /* Calculate the number of slots elapsed since the last accrual */\n        uint256 slotDelta = currentSlotNumber - accrualSlotNumberPrior;\n\n        /*\n         * Calculate the interest accumulated into borrows and reserves and the new index:\n         *  simpleInterestFactor = borrowRate * slotDelta\n         *  interestAccumulated = simpleInterestFactor * totalBorrows\n         *  totalBorrowsNew = interestAccumulated + totalBorrows\n         *  totalReservesNew = interestAccumulated * reserveFactor + totalReserves\n         *  borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex\n         */\n\n        Exp memory simpleInterestFactor = mul_(Exp({ mantissa: borrowRateMantissa }), slotDelta);\n        uint256 interestAccumulated = mul_ScalarTruncate(simpleInterestFactor, borrowsPrior);\n        uint256 totalBorrowsNew = interestAccumulated + borrowsPrior;\n        uint256 totalReservesNew = mul_ScalarTruncateAddUInt(\n            Exp({ mantissa: reserveFactorMantissa }),\n            interestAccumulated,\n            reservesPrior\n        );\n        uint256 borrowIndexNew = mul_ScalarTruncateAddUInt(simpleInterestFactor, borrowIndexPrior, borrowIndexPrior);\n\n        /////////////////////////\n        // EFFECTS & INTERACTIONS\n        // (No safe failures beyond this point)\n\n        /* We write the previously calculated values into storage */\n        accrualBlockNumber = currentSlotNumber;\n        borrowIndex = borrowIndexNew;\n        totalBorrows = totalBorrowsNew;\n        totalReserves = totalReservesNew;\n\n        if (currentSlotNumber - reduceReservesBlockNumber >= reduceReservesBlockDelta) {\n            reduceReservesBlockNumber = currentSlotNumber;\n            if (cashPrior < totalReservesNew) {\n                _reduceReservesFresh(cashPrior);\n            } else {\n                _reduceReservesFresh(totalReservesNew);\n            }\n        }\n\n        /* We emit an AccrueInterest event */\n        emit AccrueInterest(cashPrior, interestAccumulated, borrowIndexNew, totalBorrowsNew);\n\n        return NO_ERROR;\n    }\n\n    /**\n     * @notice User supplies assets into the market and receives vTokens in exchange\n     * @dev Assumes interest has already been accrued up to the current block or timestamp\n     * @param payer The address of the account which is sending the assets for supply\n     * @param minter The address of the account which is supplying the assets\n     * @param mintAmount The amount of the underlying asset to supply\n     */\n    function _mintFresh(address payer, address minter, uint256 mintAmount) internal {\n        /* Fail if mint not allowed */\n        comptroller.preMintHook(address(this), minter, mintAmount);\n\n        /* Verify market's slot(block or second) number equals current slot(block or second) number */\n        if (accrualBlockNumber != getBlockNumberOrTimestamp()) {\n            revert MintFreshnessCheck();\n        }\n\n        Exp memory exchangeRate = Exp({ mantissa: _exchangeRateStored() });\n\n        /////////////////////////\n        // EFFECTS & INTERACTIONS\n        // (No safe failures beyond this point)\n\n        /*\n         *  We call `_doTransferIn` for the minter and the mintAmount.\n         *  `_doTransferIn` reverts if anything goes wrong, since we can't be sure if\n         *  side-effects occurred. The function returns the amount actually transferred,\n         *  in case of a fee. On success, the vToken holds an additional `actualMintAmount`\n         *  of cash.\n         */\n        uint256 actualMintAmount = _doTransferIn(payer, mintAmount);\n\n        /*\n         * We get the current exchange rate and calculate the number of vTokens to be minted:\n         *  mintTokens = actualMintAmount / exchangeRate\n         */\n\n        uint256 mintTokens = div_(actualMintAmount, exchangeRate);\n\n        /*\n         * We calculate the new total supply of vTokens and minter token balance, checking for overflow:\n         *  totalSupplyNew = totalSupply + mintTokens\n         *  accountTokensNew = accountTokens[minter] + mintTokens\n         * And write them into storage\n         */\n        totalSupply = totalSupply + mintTokens;\n        uint256 balanceAfter = accountTokens[minter] + mintTokens;\n        accountTokens[minter] = balanceAfter;\n\n        /* We emit a Mint event, and a Transfer event */\n        emit Mint(minter, actualMintAmount, mintTokens, balanceAfter);\n        emit Transfer(address(0), minter, mintTokens);\n\n        /* We call the defense and prime accrue interest hook */\n        comptroller.mintVerify(address(this), minter, actualMintAmount, mintTokens);\n    }\n\n    /**\n     * @notice Redeemer redeems vTokens in exchange for the underlying assets, transferred to the receiver. Redeemer and receiver can be the same\n     *   address, or different addresses if the receiver was previously approved by the redeemer as a valid delegate (see Comptroller.updateDelegate)\n     * @dev Assumes interest has already been accrued up to the current slot(block or second)\n     * @param redeemer The address of the account which is redeeming the tokens\n     * @param receiver The receiver of the underlying tokens\n     * @param redeemTokensIn The number of vTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero)\n     * @param redeemAmountIn The number of underlying tokens to receive from redeeming vTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero)\n     */\n    function _redeemFresh(address redeemer, address receiver, uint256 redeemTokensIn, uint256 redeemAmountIn) internal {\n        require(redeemTokensIn == 0 || redeemAmountIn == 0, \"one of redeemTokensIn or redeemAmountIn must be zero\");\n\n        /* Verify market's slot(block or second) number equals current slot(block or second) number */\n        if (accrualBlockNumber != getBlockNumberOrTimestamp()) {\n            revert RedeemFreshnessCheck();\n        }\n\n        /* exchangeRate = invoke Exchange Rate Stored() */\n        Exp memory exchangeRate = Exp({ mantissa: _exchangeRateStored() });\n\n        uint256 redeemTokens;\n        uint256 redeemAmount;\n\n        /* If redeemTokensIn > 0: */\n        if (redeemTokensIn > 0) {\n            /*\n             * We calculate the exchange rate and the amount of underlying to be redeemed:\n             *  redeemTokens = redeemTokensIn\n             */\n            redeemTokens = redeemTokensIn;\n        } else {\n            /*\n             * We get the current exchange rate and calculate the amount to be redeemed:\n             *  redeemTokens = redeemAmountIn / exchangeRate\n             */\n            redeemTokens = div_(redeemAmountIn, exchangeRate);\n\n            uint256 _redeemAmount = mul_(redeemTokens, exchangeRate);\n            if (_redeemAmount != 0 && _redeemAmount != redeemAmountIn) redeemTokens++; // round up\n        }\n\n        // redeemAmount = exchangeRate * redeemTokens\n        redeemAmount = mul_ScalarTruncate(exchangeRate, redeemTokens);\n\n        // Revert if amount is zero\n        if (redeemAmount == 0) {\n            revert(\"redeemAmount is zero\");\n        }\n\n        /* Fail if redeem not allowed */\n        comptroller.preRedeemHook(address(this), redeemer, redeemTokens);\n\n        /* Fail gracefully if protocol has insufficient cash */\n        if (_getCashPrior() - totalReserves < redeemAmount) {\n            revert RedeemTransferOutNotPossible();\n        }\n\n        /////////////////////////\n        // EFFECTS & INTERACTIONS\n        // (No safe failures beyond this point)\n\n        /*\n         * We write the previously calculated values into storage.\n         *  Note: Avoid token reentrancy attacks by writing reduced supply before external transfer.\n         */\n        totalSupply = totalSupply - redeemTokens;\n        uint256 balanceAfter = accountTokens[redeemer] - redeemTokens;\n        accountTokens[redeemer] = balanceAfter;\n\n        /*\n         * We invoke _doTransferOut for the receiver and the redeemAmount.\n         *  On success, the vToken has redeemAmount less of cash.\n         *  _doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n         */\n        _doTransferOut(receiver, redeemAmount);\n\n        /* We emit a Transfer event, and a Redeem event */\n        emit Transfer(redeemer, address(this), redeemTokens);\n        emit Redeem(redeemer, redeemAmount, redeemTokens, balanceAfter);\n\n        /* We call the defense and prime accrue interest hook */\n        comptroller.redeemVerify(address(this), redeemer, redeemAmount, redeemTokens);\n    }\n\n    /**\n     * @notice Users or their delegates borrow assets from the protocol\n     * @param borrower User who borrows the assets\n     * @param receiver The receiver of the tokens, if called by a delegate\n     * @param borrowAmount The amount of the underlying asset to borrow\n     */\n    function _borrowFresh(address borrower, address receiver, uint256 borrowAmount) internal {\n        /* Fail if borrow not allowed */\n        comptroller.preBorrowHook(address(this), borrower, borrowAmount);\n\n        /* Verify market's slot(block or second) number equals current slot(block or second) number */\n        if (accrualBlockNumber != getBlockNumberOrTimestamp()) {\n            revert BorrowFreshnessCheck();\n        }\n\n        /* Fail gracefully if protocol has insufficient underlying cash */\n        if (_getCashPrior() - totalReserves < borrowAmount) {\n            revert BorrowCashNotAvailable();\n        }\n\n        /*\n         * We calculate the new borrower and total borrow balances, failing on overflow:\n         *  accountBorrowNew = accountBorrow + borrowAmount\n         *  totalBorrowsNew = totalBorrows + borrowAmount\n         */\n        uint256 accountBorrowsPrev = _borrowBalanceStored(borrower);\n        uint256 accountBorrowsNew = accountBorrowsPrev + borrowAmount;\n        uint256 totalBorrowsNew = totalBorrows + borrowAmount;\n\n        /////////////////////////\n        // EFFECTS & INTERACTIONS\n        // (No safe failures beyond this point)\n\n        /*\n         * We write the previously calculated values into storage.\n         *  Note: Avoid token reentrancy attacks by writing increased borrow before external transfer.\n        `*/\n        accountBorrows[borrower].principal = accountBorrowsNew;\n        accountBorrows[borrower].interestIndex = borrowIndex;\n        totalBorrows = totalBorrowsNew;\n\n        /*\n         * We invoke _doTransferOut for the receiver and the borrowAmount.\n         *  On success, the vToken borrowAmount less of cash.\n         *  _doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n         */\n        _doTransferOut(receiver, borrowAmount);\n\n        /* We emit a Borrow event */\n        emit Borrow(borrower, borrowAmount, accountBorrowsNew, totalBorrowsNew);\n\n        /* We call the defense and prime accrue interest hook */\n        comptroller.borrowVerify(address(this), borrower, borrowAmount);\n    }\n\n    /**\n     * @notice Borrows are repaid by another user (possibly the borrower).\n     * @param payer the account paying off the borrow\n     * @param borrower the account with the debt being payed off\n     * @param repayAmount the amount of underlying tokens being returned, or type(uint256).max for the full outstanding amount\n     * @return (uint) the actual repayment amount.\n     */\n    function _repayBorrowFresh(address payer, address borrower, uint256 repayAmount) internal returns (uint256) {\n        /* Fail if repayBorrow not allowed */\n        comptroller.preRepayHook(address(this), borrower);\n\n        /* Verify market's slot(block or second) number equals current slot(block or second) number */\n        if (accrualBlockNumber != getBlockNumberOrTimestamp()) {\n            revert RepayBorrowFreshnessCheck();\n        }\n\n        /* We fetch the amount the borrower owes, with accumulated interest */\n        uint256 accountBorrowsPrev = _borrowBalanceStored(borrower);\n\n        uint256 repayAmountFinal = repayAmount >= accountBorrowsPrev ? accountBorrowsPrev : repayAmount;\n\n        /////////////////////////\n        // EFFECTS & INTERACTIONS\n        // (No safe failures beyond this point)\n\n        /*\n         * We call _doTransferIn for the payer and the repayAmount\n         *  On success, the vToken holds an additional repayAmount of cash.\n         *  _doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.\n         *   it returns the amount actually transferred, in case of a fee.\n         */\n        uint256 actualRepayAmount = _doTransferIn(payer, repayAmountFinal);\n\n        /*\n         * We calculate the new borrower and total borrow balances, failing on underflow:\n         *  accountBorrowsNew = accountBorrows - actualRepayAmount\n         *  totalBorrowsNew = totalBorrows - actualRepayAmount\n         */\n        uint256 accountBorrowsNew = accountBorrowsPrev - actualRepayAmount;\n        uint256 totalBorrowsNew = totalBorrows - actualRepayAmount;\n\n        /* We write the previously calculated values into storage */\n        accountBorrows[borrower].principal = accountBorrowsNew;\n        accountBorrows[borrower].interestIndex = borrowIndex;\n        totalBorrows = totalBorrowsNew;\n\n        /* We emit a RepayBorrow event */\n        emit RepayBorrow(payer, borrower, actualRepayAmount, accountBorrowsNew, totalBorrowsNew);\n\n        /* We call the defense and prime accrue interest hook */\n        comptroller.repayBorrowVerify(address(this), payer, borrower, actualRepayAmount, borrowIndex);\n\n        return actualRepayAmount;\n    }\n\n    /**\n     * @notice The sender liquidates the borrowers collateral.\n     *  The collateral seized is transferred to the liquidator.\n     * @param liquidator The address repaying the borrow and seizing collateral\n     * @param borrower The borrower of this vToken to be liquidated\n     * @param vTokenCollateral The market in which to seize collateral from the borrower\n     * @param repayAmount The amount of the underlying borrowed asset to repay\n     * @param skipLiquidityCheck If set to true, allows to liquidate up to 100% of the borrow\n     *   regardless of the account liquidity\n     */\n    function _liquidateBorrow(\n        address liquidator,\n        address borrower,\n        uint256 repayAmount,\n        VTokenInterface vTokenCollateral,\n        bool skipLiquidityCheck\n    ) internal nonReentrant {\n        accrueInterest();\n\n        uint256 error = vTokenCollateral.accrueInterest();\n        if (error != NO_ERROR) {\n            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed\n            revert LiquidateAccrueCollateralInterestFailed(error);\n        }\n\n        _liquidateBorrowFresh(liquidator, borrower, repayAmount, vTokenCollateral, skipLiquidityCheck);\n    }\n\n    /**\n     * @notice The liquidator liquidates the borrowers collateral.\n     *  The collateral seized is transferred to the liquidator.\n     * @param liquidator The address repaying the borrow and seizing collateral\n     * @param borrower The borrower of this vToken to be liquidated\n     * @param vTokenCollateral The market in which to seize collateral from the borrower\n     * @param repayAmount The amount of the underlying borrowed asset to repay\n     * @param skipLiquidityCheck If set to true, allows to liquidate up to 100% of the borrow\n     *   regardless of the account liquidity\n     */\n    function _liquidateBorrowFresh(\n        address liquidator,\n        address borrower,\n        uint256 repayAmount,\n        VTokenInterface vTokenCollateral,\n        bool skipLiquidityCheck\n    ) internal {\n        /* Fail if liquidate not allowed */\n        comptroller.preLiquidateHook(\n            address(this),\n            address(vTokenCollateral),\n            borrower,\n            repayAmount,\n            skipLiquidityCheck\n        );\n\n        /* Verify market's slot(block or second) number equals current slot(block or second) number */\n        if (accrualBlockNumber != getBlockNumberOrTimestamp()) {\n            revert LiquidateFreshnessCheck();\n        }\n\n        /* Verify vTokenCollateral market's slot(block or second) number equals current slot(block or second) number */\n        if (vTokenCollateral.accrualBlockNumber() != getBlockNumberOrTimestamp()) {\n            revert LiquidateCollateralFreshnessCheck();\n        }\n\n        /* Fail if borrower = liquidator */\n        if (borrower == liquidator) {\n            revert LiquidateLiquidatorIsBorrower();\n        }\n\n        /* Fail if repayAmount = 0 */\n        if (repayAmount == 0) {\n            revert LiquidateCloseAmountIsZero();\n        }\n\n        /* Fail if repayAmount = type(uint256).max */\n        if (repayAmount == type(uint256).max) {\n            revert LiquidateCloseAmountIsUintMax();\n        }\n\n        /* Fail if repayBorrow fails */\n        uint256 actualRepayAmount = _repayBorrowFresh(liquidator, borrower, repayAmount);\n\n        /////////////////////////\n        // EFFECTS & INTERACTIONS\n        // (No safe failures beyond this point)\n\n        /* We calculate the number of collateral tokens that will be seized */\n        (uint256 amountSeizeError, uint256 seizeTokens) = comptroller.liquidateCalculateSeizeTokens(\n            address(this),\n            address(vTokenCollateral),\n            actualRepayAmount\n        );\n        require(amountSeizeError == NO_ERROR, \"LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED\");\n\n        /* Revert if borrower collateral token balance < seizeTokens */\n        require(vTokenCollateral.balanceOf(borrower) >= seizeTokens, \"LIQUIDATE_SEIZE_TOO_MUCH\");\n\n        // If this is also the collateral, call _seize internally to avoid re-entrancy, otherwise make an external call\n        if (address(vTokenCollateral) == address(this)) {\n            _seize(address(this), liquidator, borrower, seizeTokens);\n        } else {\n            vTokenCollateral.seize(liquidator, borrower, seizeTokens);\n        }\n\n        /* We emit a LiquidateBorrow event */\n        emit LiquidateBorrow(liquidator, borrower, actualRepayAmount, address(vTokenCollateral), seizeTokens);\n\n        /* We call the defense and prime accrue interest hook */\n        comptroller.liquidateBorrowVerify(\n            address(this),\n            address(vTokenCollateral),\n            liquidator,\n            borrower,\n            actualRepayAmount,\n            seizeTokens\n        );\n    }\n\n    /**\n     * @notice Transfers collateral tokens (this market) to the liquidator.\n     * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another VToken.\n     *  It's absolutely critical to use msg.sender as the seizer vToken and not a parameter.\n     * @param seizerContract The contract seizing the collateral (either borrowed vToken or Comptroller)\n     * @param liquidator The account receiving seized collateral\n     * @param borrower The account having collateral seized\n     * @param seizeTokens The number of vTokens to seize\n     */\n    function _seize(address seizerContract, address liquidator, address borrower, uint256 seizeTokens) internal {\n        /* Fail if seize not allowed */\n        comptroller.preSeizeHook(address(this), seizerContract, liquidator, borrower);\n\n        /* Fail if borrower = liquidator */\n        if (borrower == liquidator) {\n            revert LiquidateSeizeLiquidatorIsBorrower();\n        }\n\n        /*\n         * We calculate the new borrower and liquidator token balances, failing on underflow/overflow:\n         *  borrowerTokensNew = accountTokens[borrower] - seizeTokens\n         *  liquidatorTokensNew = accountTokens[liquidator] + seizeTokens\n         */\n        uint256 liquidationIncentiveMantissa = ComptrollerViewInterface(address(comptroller))\n            .liquidationIncentiveMantissa();\n        uint256 numerator = mul_(seizeTokens, Exp({ mantissa: protocolSeizeShareMantissa }));\n        uint256 protocolSeizeTokens = div_(numerator, Exp({ mantissa: liquidationIncentiveMantissa }));\n        uint256 liquidatorSeizeTokens = seizeTokens - protocolSeizeTokens;\n        Exp memory exchangeRate = Exp({ mantissa: _exchangeRateStored() });\n        uint256 protocolSeizeAmount = mul_ScalarTruncate(exchangeRate, protocolSeizeTokens);\n\n        /////////////////////////\n        // EFFECTS & INTERACTIONS\n        // (No safe failures beyond this point)\n\n        /* We write the calculated values into storage */\n        totalSupply = totalSupply - protocolSeizeTokens;\n        accountTokens[borrower] = accountTokens[borrower] - seizeTokens;\n        accountTokens[liquidator] = accountTokens[liquidator] + liquidatorSeizeTokens;\n\n        // _doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n        // Transferring an underlying asset to the protocolShareReserve contract to channel the funds for different use.\n        _doTransferOut(protocolShareReserve, protocolSeizeAmount);\n\n        // Update the pool asset's state in the protocol share reserve for the above transfer.\n        IProtocolShareReserve(protocolShareReserve).updateAssetsState(\n            address(comptroller),\n            underlying,\n            IProtocolShareReserve.IncomeType.LIQUIDATION\n        );\n\n        /* Emit a Transfer event */\n        emit Transfer(borrower, liquidator, liquidatorSeizeTokens);\n        emit ProtocolSeize(borrower, protocolShareReserve, protocolSeizeAmount);\n\n        /* We call the defense and prime accrue interest hook */\n        comptroller.seizeVerify(address(this), seizerContract, liquidator, borrower, seizeTokens);\n    }\n\n    function _setComptroller(ComptrollerInterface newComptroller) internal {\n        ComptrollerInterface oldComptroller = comptroller;\n        // Ensure invoke comptroller.isComptroller() returns true\n        require(newComptroller.isComptroller(), \"marker method returned false\");\n\n        // Set market's comptroller to newComptroller\n        comptroller = newComptroller;\n\n        // Emit NewComptroller(oldComptroller, newComptroller)\n        emit NewComptroller(oldComptroller, newComptroller);\n    }\n\n    /**\n     * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual)\n     * @dev Admin function to set a new reserve factor\n     * @param newReserveFactorMantissa New reserve factor (from 0 to 1e18)\n     */\n    function _setReserveFactorFresh(uint256 newReserveFactorMantissa) internal {\n        // Verify market's slot(block or second) number equals current slot(block or second) number\n        if (accrualBlockNumber != getBlockNumberOrTimestamp()) {\n            revert SetReserveFactorFreshCheck();\n        }\n\n        // Check newReserveFactor ≤ maxReserveFactor\n        if (newReserveFactorMantissa > MAX_RESERVE_FACTOR_MANTISSA) {\n            revert SetReserveFactorBoundsCheck();\n        }\n\n        uint256 oldReserveFactorMantissa = reserveFactorMantissa;\n        reserveFactorMantissa = newReserveFactorMantissa;\n\n        emit NewReserveFactor(oldReserveFactorMantissa, newReserveFactorMantissa);\n    }\n\n    /**\n     * @notice Add reserves by transferring from caller\n     * @dev Requires fresh interest accrual\n     * @param addAmount Amount of addition to reserves\n     * @return actualAddAmount The actual amount added, excluding the potential token fees\n     */\n    function _addReservesFresh(uint256 addAmount) internal returns (uint256) {\n        // totalReserves + actualAddAmount\n        uint256 totalReservesNew;\n        uint256 actualAddAmount;\n\n        // We fail gracefully unless market's slot(block or second) number equals current slot(block or second) number\n        if (accrualBlockNumber != getBlockNumberOrTimestamp()) {\n            revert AddReservesFactorFreshCheck(actualAddAmount);\n        }\n\n        actualAddAmount = _doTransferIn(msg.sender, addAmount);\n        totalReservesNew = totalReserves + actualAddAmount;\n        totalReserves = totalReservesNew;\n        emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew);\n\n        return actualAddAmount;\n    }\n\n    /**\n     * @notice Reduces reserves by transferring to the protocol reserve contract\n     * @dev Requires fresh interest accrual\n     * @param reduceAmount Amount of reduction to reserves\n     */\n    function _reduceReservesFresh(uint256 reduceAmount) internal {\n        if (reduceAmount == 0) {\n            return;\n        }\n        // totalReserves - reduceAmount\n        uint256 totalReservesNew;\n\n        // We fail gracefully unless market's slot(block or second) number equals current slot(block or second) number\n        if (accrualBlockNumber != getBlockNumberOrTimestamp()) {\n            revert ReduceReservesFreshCheck();\n        }\n\n        // Fail gracefully if protocol has insufficient underlying cash\n        if (_getCashPrior() < reduceAmount) {\n            revert ReduceReservesCashNotAvailable();\n        }\n\n        // Check reduceAmount ≤ reserves[n] (totalReserves)\n        if (reduceAmount > totalReserves) {\n            revert ReduceReservesCashValidation();\n        }\n\n        /////////////////////////\n        // EFFECTS & INTERACTIONS\n        // (No safe failures beyond this point)\n\n        totalReservesNew = totalReserves - reduceAmount;\n\n        // Store reserves[n+1] = reserves[n] - reduceAmount\n        totalReserves = totalReservesNew;\n\n        // _doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n        // Transferring an underlying asset to the protocolShareReserve contract to channel the funds for different use.\n        _doTransferOut(protocolShareReserve, reduceAmount);\n\n        // Update the pool asset's state in the protocol share reserve for the above transfer.\n        IProtocolShareReserve(protocolShareReserve).updateAssetsState(\n            address(comptroller),\n            underlying,\n            IProtocolShareReserve.IncomeType.SPREAD\n        );\n\n        emit SpreadReservesReduced(protocolShareReserve, reduceAmount, totalReservesNew);\n    }\n\n    /**\n     * @notice updates the interest rate model (*requires fresh interest accrual)\n     * @dev Admin function to update the interest rate model\n     * @param newInterestRateModel the new interest rate model to use\n     */\n    function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) internal {\n        // Used to store old model for use in the event that is emitted on success\n        InterestRateModel oldInterestRateModel;\n\n        // We fail gracefully unless market's slot(block or second) number equals current slot(block or second) number\n        if (accrualBlockNumber != getBlockNumberOrTimestamp()) {\n            revert SetInterestRateModelFreshCheck();\n        }\n\n        // Track the market's current interest rate model\n        oldInterestRateModel = interestRateModel;\n\n        // Ensure invoke newInterestRateModel.isInterestRateModel() returns true\n        require(newInterestRateModel.isInterestRateModel(), \"marker method returned false\");\n\n        // Set the interest rate model to newInterestRateModel\n        interestRateModel = newInterestRateModel;\n\n        // Emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel)\n        emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel);\n    }\n\n    /**\n     * Safe Token **\n     */\n\n    /**\n     * @dev Similar to ERC-20 transfer, but handles tokens that have transfer fees.\n     *      This function returns the actual amount received,\n     *      which may be less than `amount` if there is a fee attached to the transfer.\n     * @param from Sender of the underlying tokens\n     * @param amount Amount of underlying to transfer\n     * @return Actual amount received\n     */\n    function _doTransferIn(address from, uint256 amount) internal virtual returns (uint256) {\n        IERC20Upgradeable token = IERC20Upgradeable(underlying);\n        uint256 balanceBefore = token.balanceOf(address(this));\n        token.safeTransferFrom(from, address(this), amount);\n        uint256 balanceAfter = token.balanceOf(address(this));\n        // Return the amount that was *actually* transferred\n        return balanceAfter - balanceBefore;\n    }\n\n    /**\n     * @dev Just a regular ERC-20 transfer, reverts on failure\n     * @param to Receiver of the underlying tokens\n     * @param amount Amount of underlying to transfer\n     */\n    function _doTransferOut(address to, uint256 amount) internal virtual {\n        IERC20Upgradeable token = IERC20Upgradeable(underlying);\n        token.safeTransfer(to, amount);\n    }\n\n    /**\n     * @notice Transfer `tokens` tokens from `src` to `dst` by `spender`\n     * @dev Called by both `transfer` and `transferFrom` internally\n     * @param spender The address of the account performing the transfer\n     * @param src The address of the source account\n     * @param dst The address of the destination account\n     * @param tokens The number of tokens to transfer\n     */\n    function _transferTokens(address spender, address src, address dst, uint256 tokens) internal {\n        /* Fail if transfer not allowed */\n        comptroller.preTransferHook(address(this), src, dst, tokens);\n\n        /* Do not allow self-transfers */\n        if (src == dst) {\n            revert TransferNotAllowed();\n        }\n\n        /* Get the allowance, infinite for the account owner */\n        uint256 startingAllowance;\n        if (spender == src) {\n            startingAllowance = type(uint256).max;\n        } else {\n            startingAllowance = transferAllowances[src][spender];\n        }\n\n        /* Do the calculations, checking for {under,over}flow */\n        uint256 allowanceNew = startingAllowance - tokens;\n        uint256 srcTokensNew = accountTokens[src] - tokens;\n        uint256 dstTokensNew = accountTokens[dst] + tokens;\n\n        /////////////////////////\n        // EFFECTS & INTERACTIONS\n\n        accountTokens[src] = srcTokensNew;\n        accountTokens[dst] = dstTokensNew;\n\n        /* Eat some of the allowance (if necessary) */\n        if (startingAllowance != type(uint256).max) {\n            transferAllowances[src][spender] = allowanceNew;\n        }\n\n        /* We emit a Transfer event */\n        emit Transfer(src, dst, tokens);\n\n        comptroller.transferVerify(address(this), src, dst, tokens);\n    }\n\n    /**\n     * @notice Initialize the money market\n     * @param underlying_ The address of the underlying asset\n     * @param comptroller_ The address of the Comptroller\n     * @param interestRateModel_ The address of the interest rate model\n     * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n     * @param name_ ERC-20 name of this token\n     * @param symbol_ ERC-20 symbol of this token\n     * @param decimals_ ERC-20 decimal precision of this token\n     * @param admin_ Address of the administrator of this token\n     * @param accessControlManager_ AccessControlManager contract address\n     * @param riskManagement Addresses of risk & income related contracts\n     * @param reserveFactorMantissa_ Percentage of borrow interest that goes to reserves (from 0 to 1e18)\n     */\n    function _initialize(\n        address underlying_,\n        ComptrollerInterface comptroller_,\n        InterestRateModel interestRateModel_,\n        uint256 initialExchangeRateMantissa_,\n        string memory name_,\n        string memory symbol_,\n        uint8 decimals_,\n        address admin_,\n        address accessControlManager_,\n        RiskManagementInit memory riskManagement,\n        uint256 reserveFactorMantissa_\n    ) internal onlyInitializing {\n        __Ownable2Step_init();\n        __AccessControlled_init_unchained(accessControlManager_);\n        require(accrualBlockNumber == 0 && borrowIndex == 0, \"market may only be initialized once\");\n\n        // Set initial exchange rate\n        initialExchangeRateMantissa = initialExchangeRateMantissa_;\n        require(initialExchangeRateMantissa > 0, \"initial exchange rate must be greater than zero.\");\n\n        _setComptroller(comptroller_);\n\n        // Initialize slot(block or second) number and borrow index (slot(block or second) number mocks depend on comptroller being set)\n        accrualBlockNumber = getBlockNumberOrTimestamp();\n        borrowIndex = MANTISSA_ONE;\n\n        // Set the interest rate model (depends on slot(block or second) number / borrow index)\n        _setInterestRateModelFresh(interestRateModel_);\n\n        _setReserveFactorFresh(reserveFactorMantissa_);\n\n        name = name_;\n        symbol = symbol_;\n        decimals = decimals_;\n        _setShortfallContract(riskManagement.shortfall);\n        _setProtocolShareReserve(riskManagement.protocolShareReserve);\n        protocolSeizeShareMantissa = DEFAULT_PROTOCOL_SEIZE_SHARE_MANTISSA;\n\n        // Set underlying and sanity check it\n        underlying = underlying_;\n        IERC20Upgradeable(underlying).totalSupply();\n\n        // The counter starts true to prevent changing it from zero to non-zero (i.e. smaller cost/refund)\n        _notEntered = true;\n        _transferOwnership(admin_);\n    }\n\n    function _setShortfallContract(address shortfall_) internal {\n        ensureNonzeroAddress(shortfall_);\n        address oldShortfall = shortfall;\n        shortfall = shortfall_;\n        emit NewShortfallContract(oldShortfall, shortfall_);\n    }\n\n    function _setProtocolShareReserve(address payable protocolShareReserve_) internal {\n        ensureNonzeroAddress(protocolShareReserve_);\n        address oldProtocolShareReserve = address(protocolShareReserve);\n        protocolShareReserve = protocolShareReserve_;\n        emit NewProtocolShareReserve(oldProtocolShareReserve, address(protocolShareReserve_));\n    }\n\n    function _ensureSenderIsDelegateOf(address user) internal view {\n        if (!ComptrollerViewInterface(address(comptroller)).approvedDelegates(user, msg.sender)) {\n            revert DelegateNotApproved();\n        }\n    }\n\n    /**\n     * @notice Gets balance of this contract in terms of the underlying\n     * @dev This excludes the value of the current message, if any\n     * @return The quantity of underlying tokens owned by this contract\n     */\n    function _getCashPrior() internal view virtual returns (uint256) {\n        return IERC20Upgradeable(underlying).balanceOf(address(this));\n    }\n\n    /**\n     * @notice Return the borrow balance of account based on stored data\n     * @param account The address whose balance should be calculated\n     * @return borrowBalance the calculated balance\n     */\n    function _borrowBalanceStored(address account) internal view returns (uint256) {\n        /* Get borrowBalance and borrowIndex */\n        BorrowSnapshot memory borrowSnapshot = accountBorrows[account];\n\n        /* If borrowBalance = 0 then borrowIndex is likely also 0.\n         * Rather than failing the calculation with a division by 0, we immediately return 0 in this case.\n         */\n        if (borrowSnapshot.principal == 0) {\n            return 0;\n        }\n\n        /* Calculate new borrow balance using the interest index:\n         *  recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex\n         */\n        uint256 principalTimesIndex = borrowSnapshot.principal * borrowIndex;\n\n        return principalTimesIndex / borrowSnapshot.interestIndex;\n    }\n\n    /**\n     * @notice Calculates the exchange rate from the underlying to the VToken\n     * @dev This function does not accrue interest before calculating the exchange rate\n     * @return exchangeRate Calculated exchange rate scaled by 1e18\n     */\n    function _exchangeRateStored() internal view virtual returns (uint256) {\n        uint256 _totalSupply = totalSupply;\n        if (_totalSupply == 0) {\n            /*\n             * If there are no tokens minted:\n             *  exchangeRate = initialExchangeRate\n             */\n            return initialExchangeRateMantissa;\n        }\n        /*\n         * Otherwise:\n         *  exchangeRate = (totalCash + totalBorrows + badDebt - totalReserves) / totalSupply\n         */\n        uint256 totalCash = _getCashPrior();\n        uint256 cashPlusBorrowsMinusReserves = totalCash + totalBorrows + badDebt - totalReserves;\n        uint256 exchangeRate = (cashPlusBorrowsMinusReserves * EXP_SCALE) / _totalSupply;\n\n        return exchangeRate;\n    }\n}\n"
    },
    "contracts/VTokenInterfaces.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { ComptrollerInterface } from \"./ComptrollerInterface.sol\";\nimport { InterestRateModel } from \"./InterestRateModel.sol\";\n\n/**\n * @title VTokenStorage\n * @author Venus\n * @notice Storage layout used by the `VToken` contract\n */\n// solhint-disable-next-line max-states-count\ncontract VTokenStorage {\n    /**\n     * @notice Container for borrow balance information\n     * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action\n     * @member interestIndex Global borrowIndex as of the most recent balance-changing action\n     */\n    struct BorrowSnapshot {\n        uint256 principal;\n        uint256 interestIndex;\n    }\n\n    /**\n     * @dev Guard variable for re-entrancy checks\n     */\n    bool internal _notEntered;\n\n    /**\n     * @notice Underlying asset for this VToken\n     */\n    address public underlying;\n\n    /**\n     * @notice EIP-20 token name for this token\n     */\n    string public name;\n\n    /**\n     * @notice EIP-20 token symbol for this token\n     */\n    string public symbol;\n\n    /**\n     * @notice EIP-20 token decimals for this token\n     */\n    uint8 public decimals;\n\n    /**\n     * @notice Protocol share Reserve contract address\n     */\n    address payable public protocolShareReserve;\n\n    /**\n     * @notice Contract which oversees inter-vToken operations\n     */\n    ComptrollerInterface public comptroller;\n\n    /**\n     * @notice Model which tells what the current interest rate should be\n     */\n    InterestRateModel public interestRateModel;\n\n    // Initial exchange rate used when minting the first VTokens (used when totalSupply = 0)\n    uint256 internal initialExchangeRateMantissa;\n\n    /**\n     * @notice Fraction of interest currently set aside for reserves\n     */\n    uint256 public reserveFactorMantissa;\n\n    /**\n     * @notice Slot(block or second) number that interest was last accrued at\n     */\n    uint256 public accrualBlockNumber;\n\n    /**\n     * @notice Accumulator of the total earned interest rate since the opening of the market\n     */\n    uint256 public borrowIndex;\n\n    /**\n     * @notice Total amount of outstanding borrows of the underlying in this market\n     */\n    uint256 public totalBorrows;\n\n    /**\n     * @notice Total amount of reserves of the underlying held in this market\n     */\n    uint256 public totalReserves;\n\n    /**\n     * @notice Total number of tokens in circulation\n     */\n    uint256 public totalSupply;\n\n    /**\n     * @notice Total bad debt of the market\n     */\n    uint256 public badDebt;\n\n    // Official record of token balances for each account\n    mapping(address => uint256) internal accountTokens;\n\n    // Approved token transfer amounts on behalf of others\n    mapping(address => mapping(address => uint256)) internal transferAllowances;\n\n    // Mapping of account addresses to outstanding borrow balances\n    mapping(address => BorrowSnapshot) internal accountBorrows;\n\n    /**\n     * @notice Share of seized collateral that is added to reserves\n     */\n    uint256 public protocolSeizeShareMantissa;\n\n    /**\n     * @notice Storage of Shortfall contract address\n     */\n    address public shortfall;\n\n    /**\n     * @notice delta slot (block or second) after which reserves will be reduced\n     */\n    uint256 public reduceReservesBlockDelta;\n\n    /**\n     * @notice last slot (block or second) number at which reserves were reduced\n     */\n    uint256 public reduceReservesBlockNumber;\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[48] private __gap;\n}\n\n/**\n * @title VTokenInterface\n * @author Venus\n * @notice Interface implemented by the `VToken` contract\n */\nabstract contract VTokenInterface is VTokenStorage {\n    struct RiskManagementInit {\n        address shortfall;\n        address payable protocolShareReserve;\n    }\n\n    /*** Market Events ***/\n\n    /**\n     * @notice Event emitted when interest is accrued\n     */\n    event AccrueInterest(uint256 cashPrior, uint256 interestAccumulated, uint256 borrowIndex, uint256 totalBorrows);\n\n    /**\n     * @notice Event emitted when tokens are minted\n     */\n    event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens, uint256 accountBalance);\n\n    /**\n     * @notice Event emitted when tokens are redeemed\n     */\n    event Redeem(address indexed redeemer, uint256 redeemAmount, uint256 redeemTokens, uint256 accountBalance);\n\n    /**\n     * @notice Event emitted when underlying is borrowed\n     */\n    event Borrow(address indexed borrower, uint256 borrowAmount, uint256 accountBorrows, uint256 totalBorrows);\n\n    /**\n     * @notice Event emitted when a borrow is repaid\n     */\n    event RepayBorrow(\n        address indexed payer,\n        address indexed borrower,\n        uint256 repayAmount,\n        uint256 accountBorrows,\n        uint256 totalBorrows\n    );\n\n    /**\n     * @notice Event emitted when bad debt is accumulated on a market\n     * @param borrower borrower to \"forgive\"\n     * @param badDebtDelta amount of new bad debt recorded\n     * @param badDebtOld previous bad debt value\n     * @param badDebtNew new bad debt value\n     */\n    event BadDebtIncreased(address indexed borrower, uint256 badDebtDelta, uint256 badDebtOld, uint256 badDebtNew);\n\n    /**\n     * @notice Event emitted when bad debt is recovered via an auction\n     * @param badDebtOld previous bad debt value\n     * @param badDebtNew new bad debt value\n     */\n    event BadDebtRecovered(uint256 badDebtOld, uint256 badDebtNew);\n\n    /**\n     * @notice Event emitted when a borrow is liquidated\n     */\n    event LiquidateBorrow(\n        address indexed liquidator,\n        address indexed borrower,\n        uint256 repayAmount,\n        address indexed vTokenCollateral,\n        uint256 seizeTokens\n    );\n\n    /*** Admin Events ***/\n\n    /**\n     * @notice Event emitted when comptroller is changed\n     */\n    event NewComptroller(ComptrollerInterface indexed oldComptroller, ComptrollerInterface indexed newComptroller);\n\n    /**\n     * @notice Event emitted when shortfall contract address is changed\n     */\n    event NewShortfallContract(address indexed oldShortfall, address indexed newShortfall);\n\n    /**\n     * @notice Event emitted when protocol share reserve contract address is changed\n     */\n    event NewProtocolShareReserve(address indexed oldProtocolShareReserve, address indexed newProtocolShareReserve);\n\n    /**\n     * @notice Event emitted when interestRateModel is changed\n     */\n    event NewMarketInterestRateModel(\n        InterestRateModel indexed oldInterestRateModel,\n        InterestRateModel indexed newInterestRateModel\n    );\n\n    /**\n     * @notice Event emitted when protocol seize share is changed\n     */\n    event NewProtocolSeizeShare(uint256 oldProtocolSeizeShareMantissa, uint256 newProtocolSeizeShareMantissa);\n\n    /**\n     * @notice Event emitted when the reserve factor is changed\n     */\n    event NewReserveFactor(uint256 oldReserveFactorMantissa, uint256 newReserveFactorMantissa);\n\n    /**\n     * @notice Event emitted when the reserves are added\n     */\n    event ReservesAdded(address indexed benefactor, uint256 addAmount, uint256 newTotalReserves);\n\n    /**\n     * @notice Event emitted when the spread reserves are reduced\n     */\n    event SpreadReservesReduced(address indexed protocolShareReserve, uint256 reduceAmount, uint256 newTotalReserves);\n\n    /**\n     * @notice EIP20 Transfer event\n     */\n    event Transfer(address indexed from, address indexed to, uint256 amount);\n\n    /**\n     * @notice EIP20 Approval event\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n    /**\n     * @notice Event emitted when healing the borrow\n     */\n    event HealBorrow(address indexed payer, address indexed borrower, uint256 repayAmount);\n\n    /**\n     * @notice Event emitted when tokens are swept\n     */\n    event SweepToken(address indexed token);\n\n    /**\n     * @notice Event emitted when reduce reserves slot (block or second) delta is changed\n     */\n    event NewReduceReservesBlockDelta(\n        uint256 oldReduceReservesBlockOrTimestampDelta,\n        uint256 newReduceReservesBlockOrTimestampDelta\n    );\n\n    /**\n     * @notice Event emitted when liquidation reserves are reduced\n     */\n    event ProtocolSeize(address indexed from, address indexed to, uint256 amount);\n\n    /*** User Interface ***/\n\n    function mint(uint256 mintAmount) external virtual returns (uint256);\n\n    function mintBehalf(address minter, uint256 mintAllowed) external virtual returns (uint256);\n\n    function redeem(uint256 redeemTokens) external virtual returns (uint256);\n\n    function redeemBehalf(address redeemer, uint256 redeemTokens) external virtual returns (uint256);\n\n    function redeemUnderlying(uint256 redeemAmount) external virtual returns (uint256);\n\n    function redeemUnderlyingBehalf(address redeemer, uint256 redeemAmount) external virtual returns (uint256);\n\n    function borrow(uint256 borrowAmount) external virtual returns (uint256);\n\n    function borrowBehalf(address borrwwer, uint256 borrowAmount) external virtual returns (uint256);\n\n    function repayBorrow(uint256 repayAmount) external virtual returns (uint256);\n\n    function repayBorrowBehalf(address borrower, uint256 repayAmount) external virtual returns (uint256);\n\n    function liquidateBorrow(\n        address borrower,\n        uint256 repayAmount,\n        VTokenInterface vTokenCollateral\n    ) external virtual returns (uint256);\n\n    function healBorrow(address payer, address borrower, uint256 repayAmount) external virtual;\n\n    function forceLiquidateBorrow(\n        address liquidator,\n        address borrower,\n        uint256 repayAmount,\n        VTokenInterface vTokenCollateral,\n        bool skipCloseFactorCheck\n    ) external virtual;\n\n    function seize(address liquidator, address borrower, uint256 seizeTokens) external virtual;\n\n    function transfer(address dst, uint256 amount) external virtual returns (bool);\n\n    function transferFrom(address src, address dst, uint256 amount) external virtual returns (bool);\n\n    function accrueInterest() external virtual returns (uint256);\n\n    function sweepToken(IERC20Upgradeable token) external virtual;\n\n    /*** Admin Functions ***/\n\n    function setReserveFactor(uint256 newReserveFactorMantissa) external virtual;\n\n    function reduceReserves(uint256 reduceAmount) external virtual;\n\n    function exchangeRateCurrent() external virtual returns (uint256);\n\n    function borrowBalanceCurrent(address account) external virtual returns (uint256);\n\n    function setInterestRateModel(InterestRateModel newInterestRateModel) external virtual;\n\n    function addReserves(uint256 addAmount) external virtual;\n\n    function totalBorrowsCurrent() external virtual returns (uint256);\n\n    function balanceOfUnderlying(address owner) external virtual returns (uint256);\n\n    function approve(address spender, uint256 amount) external virtual returns (bool);\n\n    function increaseAllowance(address spender, uint256 addedValue) external virtual returns (bool);\n\n    function decreaseAllowance(address spender, uint256 subtractedValue) external virtual returns (bool);\n\n    function allowance(address owner, address spender) external view virtual returns (uint256);\n\n    function balanceOf(address owner) external view virtual returns (uint256);\n\n    function getAccountSnapshot(address account) external view virtual returns (uint256, uint256, uint256, uint256);\n\n    function borrowRatePerBlock() external view virtual returns (uint256);\n\n    function supplyRatePerBlock() external view virtual returns (uint256);\n\n    function borrowBalanceStored(address account) external view virtual returns (uint256);\n\n    function exchangeRateStored() external view virtual returns (uint256);\n\n    function getCash() external view virtual returns (uint256);\n\n    /**\n     * @notice Indicator that this is a VToken contract (for inspection)\n     * @return Always true\n     */\n    function isVToken() external pure virtual returns (bool) {\n        return true;\n    }\n}\n"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 200,
      "details": {
        "yul": true
      }
    },
    "evmVersion": "paris",
    "outputSelection": {
      "*": {
        "*": [
          "storageLayout",
          "abi",
          "evm.bytecode",
          "evm.deployedBytecode",
          "evm.methodIdentifiers",
          "metadata",
          "devdoc",
          "userdoc",
          "evm.gasEstimates"
        ],
        "": ["ast"]
      }
    },
    "metadata": {
      "useLiteralContent": true
    }
  }
}
