{
  "language": "Solidity",
  "sources": {
    "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n  function decimals() external view returns (uint8);\n\n  function description() external view returns (string memory);\n\n  function version() external view returns (uint256);\n\n  function getRoundData(uint80 _roundId)\n    external\n    view\n    returns (\n      uint80 roundId,\n      int256 answer,\n      uint256 startedAt,\n      uint256 updatedAt,\n      uint80 answeredInRound\n    );\n\n  function latestRoundData()\n    external\n    view\n    returns (\n      uint80 roundId,\n      int256 answer,\n      uint256 startedAt,\n      uint256 updatedAt,\n      uint80 answeredInRound\n    );\n}\n"
    },
    "@openzeppelin/contracts-upgradeable/access/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/AccessControl.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n *     require(hasRole(MY_ROLE, msg.sender));\n *     ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n    struct RoleData {\n        mapping(address => bool) members;\n        bytes32 adminRole;\n    }\n\n    mapping(bytes32 => RoleData) private _roles;\n\n    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n    /**\n     * @dev Modifier that checks that an account has a specific role. Reverts\n     * with a standardized message including the required role.\n     *\n     * The format of the revert reason is given by the following regular expression:\n     *\n     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n     *\n     * _Available since v4.1._\n     */\n    modifier onlyRole(bytes32 role) {\n        _checkRole(role);\n        _;\n    }\n\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\n        return _roles[role].members[account];\n    }\n\n    /**\n     * @dev Revert with a standard message if `_msgSender()` is missing `role`.\n     * Overriding this function changes the behavior of the {onlyRole} modifier.\n     *\n     * Format of the revert message is described in {_checkRole}.\n     *\n     * _Available since v4.6._\n     */\n    function _checkRole(bytes32 role) internal view virtual {\n        _checkRole(role, _msgSender());\n    }\n\n    /**\n     * @dev Revert with a standard message if `account` is missing `role`.\n     *\n     * The format of the revert reason is given by the following regular expression:\n     *\n     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n     */\n    function _checkRole(bytes32 role, address account) internal view virtual {\n        if (!hasRole(role, account)) {\n            revert(\n                string(\n                    abi.encodePacked(\n                        \"AccessControl: account \",\n                        Strings.toHexString(account),\n                        \" is missing role \",\n                        Strings.toHexString(uint256(role), 32)\n                    )\n                )\n            );\n        }\n    }\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\n        return _roles[role].adminRole;\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n        _grantRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n        _revokeRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been revoked `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `account`.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function renounceRole(bytes32 role, address account) public virtual override {\n        require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n        _revokeRole(role, account);\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event. Note that unlike {grantRole}, this function doesn't perform any\n     * checks on the calling account.\n     *\n     * May emit a {RoleGranted} event.\n     *\n     * [WARNING]\n     * ====\n     * This function should only be called from the constructor when setting\n     * up the initial roles for the system.\n     *\n     * Using this function in any other way is effectively circumventing the admin\n     * system imposed by {AccessControl}.\n     * ====\n     *\n     * NOTE: This function is deprecated in favor of {_grantRole}.\n     */\n    function _setupRole(bytes32 role, address account) internal virtual {\n        _grantRole(role, account);\n    }\n\n    /**\n     * @dev Sets `adminRole` as ``role``'s admin role.\n     *\n     * Emits a {RoleAdminChanged} event.\n     */\n    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n        bytes32 previousAdminRole = getRoleAdmin(role);\n        _roles[role].adminRole = adminRole;\n        emit RoleAdminChanged(role, previousAdminRole, adminRole);\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function _grantRole(bytes32 role, address account) internal virtual {\n        if (!hasRole(role, account)) {\n            _roles[role].members[account] = true;\n            emit RoleGranted(role, account, _msgSender());\n        }\n    }\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function _revokeRole(bytes32 role, address account) internal virtual {\n        if (hasRole(role, account)) {\n            _roles[role].members[account] = false;\n            emit RoleRevoked(role, account, _msgSender());\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/token/ERC20/extensions/IERC20Metadata.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n"
    },
    "@openzeppelin/contracts/utils/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/introspection/ERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/introspection/IERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
    },
    "@openzeppelin/contracts/utils/math/Math.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds up instead\n     * of rounding down.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod0 := mul(x, y)\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1, \"Math: mulDiv overflow\");\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n            // in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10 ** 64) {\n                value /= 10 ** 64;\n                result += 64;\n            }\n            if (value >= 10 ** 32) {\n                value /= 10 ** 32;\n                result += 32;\n            }\n            if (value >= 10 ** 16) {\n                value /= 10 ** 16;\n                result += 16;\n            }\n            if (value >= 10 ** 8) {\n                value /= 10 ** 8;\n                result += 8;\n            }\n            if (value >= 10 ** 4) {\n                value /= 10 ** 4;\n                result += 4;\n            }\n            if (value >= 10 ** 2) {\n                value /= 10 ** 2;\n                result += 2;\n            }\n            if (value >= 10 ** 1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\n        }\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/math/SignedMath.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard signed math utilities missing in the Solidity language.\n */\nlibrary SignedMath {\n    /**\n     * @dev Returns the largest of two signed numbers.\n     */\n    function max(int256 a, int256 b) internal pure returns (int256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two signed numbers.\n     */\n    function min(int256 a, int256 b) internal pure returns (int256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two signed numbers without overflow.\n     * The result is rounded towards zero.\n     */\n    function average(int256 a, int256 b) internal pure returns (int256) {\n        // Formula from the book \"Hacker's Delight\"\n        int256 x = (a & b) + ((a ^ b) >> 1);\n        return x + (int256(uint256(x) >> 255) & (a ^ b));\n    }\n\n    /**\n     * @dev Returns the absolute unsigned value of a signed value.\n     */\n    function abs(int256 n) internal pure returns (uint256) {\n        unchecked {\n            // must be unchecked in order to support `n = type(int256).min`\n            return uint256(n >= 0 ? n : -n);\n        }\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/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"
    },
    "@openzeppelin/contracts/utils/Strings.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\nimport \"./math/SignedMath.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            uint256 length = Math.log10(value) + 1;\n            string memory buffer = new string(length);\n            uint256 ptr;\n            /// @solidity memory-safe-assembly\n            assembly {\n                ptr := add(buffer, add(32, length))\n            }\n            while (true) {\n                ptr--;\n                /// @solidity memory-safe-assembly\n                assembly {\n                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n                }\n                value /= 10;\n                if (value == 0) break;\n            }\n            return buffer;\n        }\n    }\n\n    /**\n     * @dev Converts a `int256` to its ASCII `string` decimal representation.\n     */\n    function toString(int256 value) internal pure returns (string memory) {\n        return string(abi.encodePacked(value < 0 ? \"-\" : \"\", toString(SignedMath.abs(value))));\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            return toHexString(value, Math.log256(value) + 1);\n        }\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i > 1; --i) {\n            buffer[i] = _SYMBOLS[value & 0xf];\n            value >>= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n\n    /**\n     * @dev Returns true if the two strings are equal.\n     */\n    function equal(string memory a, string memory b) internal pure returns (bool) {\n        return keccak256(bytes(a)) == keccak256(bytes(b));\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/AccessControlManager.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\nimport \"@openzeppelin/contracts/access/AccessControl.sol\";\nimport \"./IAccessControlManagerV8.sol\";\n\n/**\n * @title AccessControlManager\n * @author Venus\n * @dev This contract is a wrapper of OpenZeppelin AccessControl extending it in a way to standartize access control within Venus Smart Contract Ecosystem.\n * @notice Access control plays a crucial role in the Venus governance model. It is used to restrict functions so that they can only be called from one\n * account or list of accounts (EOA or Contract Accounts).\n *\n * The implementation of `AccessControlManager`(https://github.com/VenusProtocol/governance-contracts/blob/main/contracts/Governance/AccessControlManager.sol)\n * inherits the [Open Zeppelin AccessControl](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/AccessControl.sol)\n * contract as a base for role management logic. There are two role types: admin and granular permissions.\n * \n * ## Granular Roles\n * \n * Granular roles are built by hashing the contract address and its function signature. For example, given contract `Foo` with function `Foo.bar()` which\n * is guarded by ACM, calling `giveRolePermission` for account B do the following:\n * \n * 1. Compute `keccak256(contractFooAddress,functionSignatureBar)`\n * 1. Add the computed role to the roles of account B\n * 1. Account B now can call `ContractFoo.bar()`\n * \n * ## Admin Roles\n * \n * Admin roles allow for an address to call a function signature on any contract guarded by the `AccessControlManager`. This is particularly useful for\n * contracts created by factories.\n * \n * For Admin roles a null address is hashed in place of the contract address (`keccak256(0x0000000000000000000000000000000000000000,functionSignatureBar)`.\n * \n * In the previous example, giving account B the admin role, account B will have permissions to call the `bar()` function on any contract that is guarded by\n * ACM, not only contract A.\n * \n * ## Protocol Integration\n * \n * All restricted functions in Venus Protocol use a hook to ACM in order to check if the caller has the right permission to call the guarded function.\n * `AccessControlledV5` and `AccessControlledV8` abstract contract makes this integration easier. They call ACM's external method\n * `isAllowedToCall(address caller, string functionSig)`. Here is an example of how `setCollateralFactor` function in `Comptroller` is integrated with ACM:\n\n```\n    contract Comptroller is [...] AccessControlledV8 {\n        [...]\n        function setCollateralFactor(VToken vToken, uint256 newCollateralFactorMantissa, uint256 newLiquidationThresholdMantissa) external {\n            _checkAccessAllowed(\"setCollateralFactor(address,uint256,uint256)\");\n            [...]\n        }\n    }\n```\n */\ncontract AccessControlManager is AccessControl, IAccessControlManagerV8 {\n    /// @notice Emitted when an account is given a permission to a certain contract function\n    /// @dev If contract address is 0x000..0 this means that the account is a default admin of this function and\n    /// can call any contract function with this signature\n    event PermissionGranted(address account, address contractAddress, string functionSig);\n\n    /// @notice Emitted when an account is revoked a permission to a certain contract function\n    event PermissionRevoked(address account, address contractAddress, string functionSig);\n\n    constructor() {\n        // Grant the contract deployer the default admin role: it will be able\n        // to grant and revoke any roles\n        _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);\n    }\n\n    /**\n     * @notice Gives a function call permission to one single account\n     * @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE\n     * @param contractAddress address of contract for which call permissions will be granted\n     * @dev if contractAddress is zero address, the account can access the specified function\n     *      on **any** contract managed by this ACL\n     * @param functionSig signature e.g. \"functionName(uint256,bool)\"\n     * @param accountToPermit account that will be given access to the contract function\n     * @custom:event Emits a {RoleGranted} and {PermissionGranted} events.\n     */\n    function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) public {\n        bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n        grantRole(role, accountToPermit);\n        emit PermissionGranted(accountToPermit, contractAddress, functionSig);\n    }\n\n    /**\n     * @notice Revokes an account's permission to a particular function call\n     * @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE\n     * \t\tMay emit a {RoleRevoked} event.\n     * @param contractAddress address of contract for which call permissions will be revoked\n     * @param functionSig signature e.g. \"functionName(uint256,bool)\"\n     * @custom:event Emits {RoleRevoked} and {PermissionRevoked} events.\n     */\n    function revokeCallPermission(\n        address contractAddress,\n        string calldata functionSig,\n        address accountToRevoke\n    ) public {\n        bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n        revokeRole(role, accountToRevoke);\n        emit PermissionRevoked(accountToRevoke, contractAddress, functionSig);\n    }\n\n    /**\n     * @notice Verifies if the given account can call a contract's guarded function\n     * @dev Since restricted contracts using this function as a permission hook, we can get contracts address with msg.sender\n     * @param account for which call permissions will be checked\n     * @param functionSig restricted function signature e.g. \"functionName(uint256,bool)\"\n     * @return false if the user account cannot call the particular contract function\n     *\n     */\n    function isAllowedToCall(address account, string calldata functionSig) public view returns (bool) {\n        bytes32 role = keccak256(abi.encodePacked(msg.sender, functionSig));\n\n        if (hasRole(role, account)) {\n            return true;\n        } else {\n            role = keccak256(abi.encodePacked(address(0), functionSig));\n            return hasRole(role, account);\n        }\n    }\n\n    /**\n     * @notice Verifies if the given account can call a contract's guarded function\n     * @dev This function is used as a view function to check permissions rather than contract hook for access restriction check.\n     * @param account for which call permissions will be checked against\n     * @param contractAddress address of the restricted contract\n     * @param functionSig signature of the restricted function e.g. \"functionName(uint256,bool)\"\n     * @return false if the user account cannot call the particular contract function\n     */\n    function hasPermission(\n        address account,\n        address contractAddress,\n        string calldata functionSig\n    ) public view returns (bool) {\n        bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n        return hasRole(role, account);\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/FeedRegistryInterface.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\ninterface FeedRegistryInterface {\n    function latestRoundDataByName(\n        string memory base,\n        string memory quote\n    )\n        external\n        view\n        returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);\n\n    function decimalsByName(string memory base, string memory quote) external view returns (uint8);\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/oracle/contracts/interfaces/PublicResolverInterface.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\n// SPDX-FileCopyrightText: 2022 Venus\npragma solidity ^0.8.25;\n\ninterface PublicResolverInterface {\n    function addr(bytes32 node) external view returns (address payable);\n}\n"
    },
    "@venusprotocol/oracle/contracts/interfaces/SIDRegistryInterface.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\n// SPDX-FileCopyrightText: 2022 Venus\npragma solidity ^0.8.25;\n\ninterface SIDRegistryInterface {\n    function resolver(bytes32 node) external view returns (address);\n}\n"
    },
    "@venusprotocol/oracle/contracts/interfaces/VBep20Interface.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\ninterface VBep20Interface is IERC20Metadata {\n    /**\n     * @notice Underlying asset for this VToken\n     */\n    function underlying() external view returns (address);\n}\n"
    },
    "@venusprotocol/oracle/contracts/oracles/BinanceOracle.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"../interfaces/VBep20Interface.sol\";\nimport \"../interfaces/SIDRegistryInterface.sol\";\nimport \"../interfaces/FeedRegistryInterface.sol\";\nimport \"../interfaces/PublicResolverInterface.sol\";\nimport \"../interfaces/OracleInterface.sol\";\nimport \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\nimport \"../interfaces/OracleInterface.sol\";\n\n/**\n * @title BinanceOracle\n * @author Venus\n * @notice This oracle fetches price of assets from Binance.\n */\ncontract BinanceOracle is AccessControlledV8, OracleInterface {\n    /// @notice Used to fetch feed registry address.\n    address public sidRegistryAddress;\n\n    /// @notice Set this as asset address for BNB. This is the underlying address for vBNB\n    address public constant BNB_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;\n\n    /// @notice Max stale period configuration for assets\n    mapping(string => uint256) public maxStalePeriod;\n\n    /// @notice Override symbols to be compatible with Binance feed registry\n    mapping(string => string) public symbols;\n\n    /// @notice Used to fetch price of assets used directly when space ID is not supported by current chain.\n    address public feedRegistryAddress;\n\n    /// @notice Emits when asset stale period is updated.\n    event MaxStalePeriodAdded(string indexed asset, uint256 maxStalePeriod);\n\n    /// @notice Emits when symbol of the asset is updated.\n    event SymbolOverridden(string indexed symbol, string overriddenSymbol);\n\n    /// @notice Emits when address of feed registry is updated.\n    event FeedRegistryUpdated(address indexed oldFeedRegistry, address indexed newFeedRegistry);\n\n    /**\n     * @notice Checks whether an address is null or not\n     */\n    modifier notNullAddress(address someone) {\n        if (someone == address(0)) revert(\"can't be zero address\");\n        _;\n    }\n\n    /// @notice Constructor for the implementation contract.\n    /// @custom:oz-upgrades-unsafe-allow constructor\n    constructor() {\n        _disableInitializers();\n    }\n\n    /**\n     * @notice Sets the contracts required to fetch prices\n     * @param _sidRegistryAddress Address of SID registry\n     * @param _accessControlManager Address of the access control manager contract\n     */\n    function initialize(address _sidRegistryAddress, address _accessControlManager) external initializer {\n        sidRegistryAddress = _sidRegistryAddress;\n        __AccessControlled_init(_accessControlManager);\n    }\n\n    /**\n     * @notice Used to set the max stale period of an asset\n     * @param symbol The symbol of the asset\n     * @param _maxStalePeriod The max stake period\n     */\n    function setMaxStalePeriod(string memory symbol, uint256 _maxStalePeriod) external {\n        _checkAccessAllowed(\"setMaxStalePeriod(string,uint256)\");\n        if (_maxStalePeriod == 0) revert(\"stale period can't be zero\");\n        if (bytes(symbol).length == 0) revert(\"symbol cannot be empty\");\n\n        maxStalePeriod[symbol] = _maxStalePeriod;\n        emit MaxStalePeriodAdded(symbol, _maxStalePeriod);\n    }\n\n    /**\n     * @notice Used to override a symbol when fetching price\n     * @param symbol The symbol to override\n     * @param overrideSymbol The symbol after override\n     */\n    function setSymbolOverride(string calldata symbol, string calldata overrideSymbol) external {\n        _checkAccessAllowed(\"setSymbolOverride(string,string)\");\n        if (bytes(symbol).length == 0) revert(\"symbol cannot be empty\");\n\n        symbols[symbol] = overrideSymbol;\n        emit SymbolOverridden(symbol, overrideSymbol);\n    }\n\n    /**\n     * @notice Used to set feed registry address when current chain does not support space ID.\n     * @param newfeedRegistryAddress Address of new feed registry.\n     */\n    function setFeedRegistryAddress(\n        address newfeedRegistryAddress\n    ) external notNullAddress(newfeedRegistryAddress) onlyOwner {\n        if (sidRegistryAddress != address(0)) revert(\"sidRegistryAddress must be zero\");\n        emit FeedRegistryUpdated(feedRegistryAddress, newfeedRegistryAddress);\n        feedRegistryAddress = newfeedRegistryAddress;\n    }\n\n    /**\n     * @notice Uses Space ID to fetch the feed registry address\n     * @return feedRegistryAddress Address of binance oracle feed registry.\n     */\n    function getFeedRegistryAddress() public view returns (address) {\n        bytes32 nodeHash = 0x94fe3821e0768eb35012484db4df61890f9a6ca5bfa984ef8ff717e73139faff;\n\n        SIDRegistryInterface sidRegistry = SIDRegistryInterface(sidRegistryAddress);\n        address publicResolverAddress = sidRegistry.resolver(nodeHash);\n        PublicResolverInterface publicResolver = PublicResolverInterface(publicResolverAddress);\n\n        return publicResolver.addr(nodeHash);\n    }\n\n    /**\n     * @notice Gets the price of a asset from the binance oracle\n     * @param asset Address of the asset\n     * @return Price in USD\n     */\n    function getPrice(address asset) public view returns (uint256) {\n        string memory symbol;\n        uint256 decimals;\n\n        if (asset == BNB_ADDR) {\n            symbol = \"BNB\";\n            decimals = 18;\n        } else {\n            IERC20Metadata token = IERC20Metadata(asset);\n            symbol = token.symbol();\n            decimals = token.decimals();\n        }\n\n        string memory overrideSymbol = symbols[symbol];\n\n        if (bytes(overrideSymbol).length != 0) {\n            symbol = overrideSymbol;\n        }\n\n        return _getPrice(symbol, decimals);\n    }\n\n    function _getPrice(string memory symbol, uint256 decimals) internal view returns (uint256) {\n        FeedRegistryInterface feedRegistry;\n\n        if (sidRegistryAddress != address(0)) {\n            // If sidRegistryAddress is available, fetch feedRegistryAddress from sidRegistry\n            feedRegistry = FeedRegistryInterface(getFeedRegistryAddress());\n        } else {\n            // Use feedRegistry directly if sidRegistryAddress is not available\n            feedRegistry = FeedRegistryInterface(feedRegistryAddress);\n        }\n\n        (, int256 answer, , uint256 updatedAt, ) = feedRegistry.latestRoundDataByName(symbol, \"USD\");\n        if (answer <= 0) revert(\"invalid binance oracle price\");\n        if (block.timestamp < updatedAt) revert(\"updatedAt exceeds block time\");\n\n        uint256 deltaTime;\n        unchecked {\n            deltaTime = block.timestamp - updatedAt;\n        }\n        if (deltaTime > maxStalePeriod[symbol]) revert(\"binance oracle price expired\");\n\n        uint256 decimalDelta = feedRegistry.decimalsByName(symbol, \"USD\");\n        return (uint256(answer) * (10 ** (18 - decimalDelta))) * (10 ** (18 - decimals));\n    }\n}\n"
    },
    "@venusprotocol/oracle/contracts/oracles/ChainlinkOracle.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport \"../interfaces/VBep20Interface.sol\";\nimport \"../interfaces/OracleInterface.sol\";\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\n/**\n * @title ChainlinkOracle\n * @author Venus\n * @notice This oracle fetches prices of assets from the Chainlink oracle.\n */\ncontract ChainlinkOracle is AccessControlledV8, OracleInterface {\n    struct TokenConfig {\n        /// @notice Underlying token address, which can't be a null address\n        /// @notice Used to check if a token is supported\n        /// @notice 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB address for native tokens\n        ///         (e.g BNB for BNB chain, ETH for Ethereum network)\n        address asset;\n        /// @notice Chainlink feed address\n        address feed;\n        /// @notice Price expiration period of this asset\n        uint256 maxStalePeriod;\n    }\n\n    /// @notice Set this as asset address for native token on each chain.\n    /// This is the underlying address for vBNB on BNB chain or an underlying asset for a native market on any chain.\n    address public constant NATIVE_TOKEN_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;\n\n    /// @notice Manually set an override price, useful under extenuating conditions such as price feed failure\n    mapping(address => uint256) public prices;\n\n    /// @notice Token config by assets\n    mapping(address => TokenConfig) public tokenConfigs;\n\n    /// @notice Emit when a price is manually set\n    event PricePosted(address indexed asset, uint256 previousPriceMantissa, uint256 newPriceMantissa);\n\n    /// @notice Emit when a token config is added\n    event TokenConfigAdded(address indexed asset, address feed, uint256 maxStalePeriod);\n\n    modifier notNullAddress(address someone) {\n        if (someone == address(0)) revert(\"can't be zero address\");\n        _;\n    }\n\n    /// @notice Constructor for the implementation contract.\n    /// @custom:oz-upgrades-unsafe-allow constructor\n    constructor() {\n        _disableInitializers();\n    }\n\n    /**\n     * @notice Initializes the owner of the contract\n     * @param accessControlManager_ Address of the access control manager contract\n     */\n    function initialize(address accessControlManager_) external initializer {\n        __AccessControlled_init(accessControlManager_);\n    }\n\n    /**\n     * @notice Manually set the price of a given asset\n     * @param asset Asset address\n     * @param price Asset price in 18 decimals\n     * @custom:access Only Governance\n     * @custom:event Emits PricePosted event on successfully setup of asset price\n     */\n    function setDirectPrice(address asset, uint256 price) external notNullAddress(asset) {\n        _checkAccessAllowed(\"setDirectPrice(address,uint256)\");\n\n        uint256 previousPriceMantissa = prices[asset];\n        prices[asset] = price;\n        emit PricePosted(asset, previousPriceMantissa, price);\n    }\n\n    /**\n     * @notice Add multiple token configs at the same time\n     * @param tokenConfigs_ config array\n     * @custom:access Only Governance\n     * @custom:error Zero length error thrown, if length of the array in parameter is 0\n     */\n    function setTokenConfigs(TokenConfig[] memory tokenConfigs_) external {\n        if (tokenConfigs_.length == 0) revert(\"length can't be 0\");\n        uint256 numTokenConfigs = tokenConfigs_.length;\n        for (uint256 i; i < numTokenConfigs; ) {\n            setTokenConfig(tokenConfigs_[i]);\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Add single token config. asset & feed cannot be null addresses and maxStalePeriod must be positive\n     * @param tokenConfig Token config struct\n     * @custom:access Only Governance\n     * @custom:error NotNullAddress error is thrown if asset address is null\n     * @custom:error NotNullAddress error is thrown if token feed address is null\n     * @custom:error Range error is thrown if maxStale period of token is not greater than zero\n     * @custom:event Emits TokenConfigAdded event on successfully setting of the token config\n     */\n    function setTokenConfig(\n        TokenConfig memory tokenConfig\n    ) public notNullAddress(tokenConfig.asset) notNullAddress(tokenConfig.feed) {\n        _checkAccessAllowed(\"setTokenConfig(TokenConfig)\");\n\n        if (tokenConfig.maxStalePeriod == 0) revert(\"stale period can't be zero\");\n        tokenConfigs[tokenConfig.asset] = tokenConfig;\n        emit TokenConfigAdded(tokenConfig.asset, tokenConfig.feed, tokenConfig.maxStalePeriod);\n    }\n\n    /**\n     * @notice Gets the price of a asset from the chainlink oracle\n     * @param asset Address of the asset\n     * @return Price in USD from Chainlink or a manually set price for the asset\n     */\n    function getPrice(address asset) public view virtual returns (uint256) {\n        uint256 decimals;\n\n        if (asset == NATIVE_TOKEN_ADDR) {\n            decimals = 18;\n        } else {\n            IERC20Metadata token = IERC20Metadata(asset);\n            decimals = token.decimals();\n        }\n\n        return _getPriceInternal(asset, decimals);\n    }\n\n    /**\n     * @notice Gets the Chainlink price for a given asset\n     * @param asset address of the asset\n     * @param decimals decimals of the asset\n     * @return price Asset price in USD or a manually set price of the asset\n     */\n    function _getPriceInternal(address asset, uint256 decimals) internal view returns (uint256 price) {\n        uint256 tokenPrice = prices[asset];\n        if (tokenPrice != 0) {\n            price = tokenPrice;\n        } else {\n            price = _getChainlinkPrice(asset);\n        }\n\n        uint256 decimalDelta = 18 - decimals;\n        return price * (10 ** decimalDelta);\n    }\n\n    /**\n     * @notice Get the Chainlink price for an asset, revert if token config doesn't exist\n     * @dev The precision of the price feed is used to ensure the returned price has 18 decimals of precision\n     * @param asset Address of the asset\n     * @return price Price in USD, with 18 decimals of precision\n     * @custom:error NotNullAddress error is thrown if the asset address is null\n     * @custom:error Price error is thrown if the Chainlink price of asset is not greater than zero\n     * @custom:error Timing error is thrown if current timestamp is less than the last updatedAt timestamp\n     * @custom:error Timing error is thrown if time difference between current time and last updated time\n     * is greater than maxStalePeriod\n     */\n    function _getChainlinkPrice(\n        address asset\n    ) private view notNullAddress(tokenConfigs[asset].asset) returns (uint256) {\n        TokenConfig memory tokenConfig = tokenConfigs[asset];\n        AggregatorV3Interface feed = AggregatorV3Interface(tokenConfig.feed);\n\n        // note: maxStalePeriod cannot be 0\n        uint256 maxStalePeriod = tokenConfig.maxStalePeriod;\n\n        // Chainlink USD-denominated feeds store answers at 8 decimals, mostly\n        uint256 decimalDelta = 18 - feed.decimals();\n\n        (, int256 answer, , uint256 updatedAt, ) = feed.latestRoundData();\n        if (answer <= 0) revert(\"chainlink price must be positive\");\n        if (block.timestamp < updatedAt) revert(\"updatedAt exceeds block time\");\n\n        uint256 deltaTime;\n        unchecked {\n            deltaTime = block.timestamp - updatedAt;\n        }\n\n        if (deltaTime > maxStalePeriod) revert(\"chainlink price expired\");\n\n        return uint256(answer) * (10 ** decimalDelta);\n    }\n}\n"
    },
    "@venusprotocol/protocol-reserve/contracts/Interfaces/IComptroller.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\ninterface IComptroller {\n    function isComptroller() external view returns (bool);\n\n    function markets(address) external view returns (bool);\n\n    function getAllMarkets() external view returns (address[] memory);\n}\n"
    },
    "@venusprotocol/protocol-reserve/contracts/Interfaces/IIncomeDestination.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\ninterface IIncomeDestination {\n    function updateAssetsState(address comptroller, address asset) external;\n}\n"
    },
    "@venusprotocol/protocol-reserve/contracts/Interfaces/IPoolRegistry.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\ninterface IPoolRegistry {\n    /// @notice Get VToken in the Pool for an 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"
    },
    "@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/protocol-reserve/contracts/Interfaces/IVToken.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\ninterface IVToken {\n    function underlying() external view returns (address);\n}\n"
    },
    "@venusprotocol/protocol-reserve/contracts/ProtocolReserve/ProtocolShareReserve.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { SafeERC20Upgradeable, IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\nimport { ReentrancyGuardUpgradeable } from \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport { MaxLoopsLimitHelper } from \"@venusprotocol/solidity-utilities/contracts/MaxLoopsLimitHelper.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\n\nimport { IProtocolShareReserve } from \"../Interfaces/IProtocolShareReserve.sol\";\nimport { IComptroller } from \"../Interfaces/IComptroller.sol\";\nimport { IPoolRegistry } from \"../Interfaces/IPoolRegistry.sol\";\nimport { IVToken } from \"../Interfaces/IVToken.sol\";\nimport { IIncomeDestination } from \"../Interfaces/IIncomeDestination.sol\";\n\nerror InvalidAddress();\nerror UnsupportedAsset();\nerror InvalidTotalPercentage();\nerror InvalidMaxLoopsLimit();\n\ncontract ProtocolShareReserve is\n    AccessControlledV8,\n    ReentrancyGuardUpgradeable,\n    MaxLoopsLimitHelper,\n    IProtocolShareReserve\n{\n    using SafeERC20Upgradeable for IERC20Upgradeable;\n\n    /// @notice protocol income is categorized into two schemas.\n    /// The first schema is for spread income\n    /// The second schema is for liquidation income\n    enum Schema {\n        PROTOCOL_RESERVES,\n        ADDITIONAL_REVENUE\n    }\n\n    struct DistributionConfig {\n        Schema schema;\n        /// @dev percenatge is represented without any scale\n        uint16 percentage;\n        address destination;\n    }\n\n    /// @notice address of core pool comptroller contract\n    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n    address public immutable CORE_POOL_COMPTROLLER;\n\n    /// @notice address of WBNB contract\n    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n    address public immutable WBNB;\n\n    /// @notice address of vBNB contract\n    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n    address public immutable vBNB;\n\n    /// @notice address of pool registry contract\n    address public poolRegistry;\n\n    uint16 public constant MAX_PERCENT = 1e4;\n\n    /// @notice comptroller => asset => schema => balance\n    mapping(address => mapping(address => mapping(Schema => uint256))) public assetsReserves;\n\n    /// @notice asset => balance\n    mapping(address => uint256) public totalAssetReserve;\n\n    /// @notice configuration for different income distribution targets\n    DistributionConfig[] public distributionTargets;\n\n    /// @notice Emitted when pool registry address is updated\n    event PoolRegistryUpdated(address indexed oldPoolRegistry, address indexed newPoolRegistry);\n\n    /// @notice Event emitted after updating of the assets reserves.\n    event AssetsReservesUpdated(\n        address indexed comptroller,\n        address indexed asset,\n        uint256 amount,\n        IncomeType incomeType,\n        Schema schema\n    );\n\n    /// @notice Event emitted when an asset is released to a target\n    event AssetReleased(\n        address indexed destination,\n        address indexed asset,\n        Schema schema,\n        uint256 percent,\n        uint256 amount\n    );\n\n    /// @notice Event emitted when asset reserves state is updated\n    event ReservesUpdated(\n        address indexed comptroller,\n        address indexed asset,\n        Schema schema,\n        uint256 oldBalance,\n        uint256 newBalance\n    );\n\n    /// @notice Event emitted when distribution configuration is updated\n    event DistributionConfigUpdated(\n        address indexed destination,\n        uint16 oldPercentage,\n        uint16 newPercentage,\n        Schema schema\n    );\n\n    /// @notice Event emitted when distribution configuration is added\n    event DistributionConfigAdded(address indexed destination, uint16 percentage, Schema schema);\n\n    /// @notice Event emitted when distribution configuration is removed\n    event DistributionConfigRemoved(address indexed destination, uint16 percentage, Schema schema);\n\n    /**\n     * @dev Constructor to initialize the immutable variables\n     * @param _corePoolComptroller The address of core pool comptroller\n     * @param _wbnb The address of WBNB\n     * @param _vbnb The address of vBNB\n     */\n    /// @custom:oz-upgrades-unsafe-allow constructor\n    constructor(\n        address _corePoolComptroller,\n        address _wbnb,\n        address _vbnb\n    ) {\n        ensureNonzeroAddress(_corePoolComptroller);\n        ensureNonzeroAddress(_wbnb);\n        ensureNonzeroAddress(_vbnb);\n\n        CORE_POOL_COMPTROLLER = _corePoolComptroller;\n        WBNB = _wbnb;\n        vBNB = _vbnb;\n\n        // Note that the contract is upgradeable. Use initialize() or reinitializers\n        // to set the state variables.\n        _disableInitializers();\n    }\n\n    /**\n     * @dev Initializes the deployer to owner.\n     * @param _accessControlManager The address of ACM contract\n     * @param _loopsLimit Limit for the loops in the contract to avoid DOS\n     */\n    function initialize(address _accessControlManager, uint256 _loopsLimit) external initializer {\n        __AccessControlled_init(_accessControlManager);\n        __ReentrancyGuard_init();\n        _setMaxLoopsLimit(_loopsLimit);\n    }\n\n    /**\n     * @dev Pool registry setter.\n     * @param _poolRegistry Address of the pool registry\n     * @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n     */\n    function setPoolRegistry(address _poolRegistry) external onlyOwner {\n        ensureNonzeroAddress(_poolRegistry);\n        emit PoolRegistryUpdated(poolRegistry, _poolRegistry);\n        poolRegistry = _poolRegistry;\n    }\n\n    /**\n     * @dev Add or update destination targets based on destination address\n     * @param configs configurations of the destinations.\n     */\n    function addOrUpdateDistributionConfigs(DistributionConfig[] calldata configs) external nonReentrant {\n        _checkAccessAllowed(\"addOrUpdateDistributionConfigs(DistributionConfig[])\");\n\n        for (uint256 i = 0; i < configs.length; ) {\n            DistributionConfig memory _config = configs[i];\n            ensureNonzeroAddress(_config.destination);\n\n            bool updated = false;\n            uint256 distributionTargetsLength = distributionTargets.length;\n            for (uint256 j = 0; j < distributionTargetsLength; ) {\n                DistributionConfig storage config = distributionTargets[j];\n\n                if (_config.schema == config.schema && config.destination == _config.destination) {\n                    emit DistributionConfigUpdated(\n                        _config.destination,\n                        config.percentage,\n                        _config.percentage,\n                        _config.schema\n                    );\n                    config.percentage = _config.percentage;\n                    updated = true;\n                    break;\n                }\n\n                unchecked {\n                    ++j;\n                }\n            }\n\n            if (!updated) {\n                distributionTargets.push(_config);\n                emit DistributionConfigAdded(_config.destination, _config.percentage, _config.schema);\n            }\n\n            unchecked {\n                ++i;\n            }\n        }\n\n        _ensurePercentages();\n        _ensureMaxLoops(distributionTargets.length);\n    }\n\n    /**\n     * @dev Remove destionation target if percentage is 0\n     * @param schema schema of the configuration\n     * @param destination destination address of the configuration\n     */\n    function removeDistributionConfig(Schema schema, address destination) external {\n        _checkAccessAllowed(\"removeDistributionConfig(Schema,address)\");\n\n        uint256 distributionIndex;\n        bool found = false;\n        for (uint256 i = 0; i < distributionTargets.length; ) {\n            DistributionConfig storage config = distributionTargets[i];\n\n            if (schema == config.schema && destination == config.destination && config.percentage == 0) {\n                found = true;\n                distributionIndex = i;\n                break;\n            }\n\n            unchecked {\n                ++i;\n            }\n        }\n\n        if (found) {\n            emit DistributionConfigRemoved(\n                distributionTargets[distributionIndex].destination,\n                distributionTargets[distributionIndex].percentage,\n                distributionTargets[distributionIndex].schema\n            );\n\n            distributionTargets[distributionIndex] = distributionTargets[distributionTargets.length - 1];\n            distributionTargets.pop();\n        }\n\n        _ensurePercentages();\n    }\n\n    /**\n     * @dev Release funds\n     * @param comptroller the comptroller address of the pool\n     * @param assets assets to be released to distribution targets\n     */\n    function releaseFunds(address comptroller, address[] calldata assets) external nonReentrant {\n        for (uint256 i = 0; i < assets.length; ) {\n            _releaseFund(comptroller, assets[i]);\n\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @dev Used to find out the amount of funds that's going to be released when release funds is called.\n     * @param comptroller the comptroller address of the pool\n     * @param schema the schema of the distribution target\n     * @param destination the destination address of the distribution target\n     * @param asset the asset address which will be released\n     */\n    function getUnreleasedFunds(\n        address comptroller,\n        Schema schema,\n        address destination,\n        address asset\n    ) external view returns (uint256) {\n        uint256 distributionTargetsLength = distributionTargets.length;\n        for (uint256 i = 0; i < distributionTargetsLength; ) {\n            DistributionConfig storage _config = distributionTargets[i];\n            if (_config.schema == schema && _config.destination == destination) {\n                uint256 total = assetsReserves[comptroller][asset][schema];\n                return (total * _config.percentage) / MAX_PERCENT;\n            }\n\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @dev Returns the total number of distribution targets\n     */\n    function totalDistributions() external view returns (uint256) {\n        return distributionTargets.length;\n    }\n\n    /**\n     * @dev Used to find out the percentage distribution for a particular destination based on schema\n     * @param destination the destination address of the distribution target\n     * @param schema the schema of the distribution target\n     * @return percentage percentage distribution\n     */\n    function getPercentageDistribution(address destination, Schema schema) external view returns (uint256) {\n        uint256 distributionTargetsLength = distributionTargets.length;\n        for (uint256 i = 0; i < distributionTargetsLength; ) {\n            DistributionConfig memory config = distributionTargets[i];\n\n            if (config.destination == destination && config.schema == schema) {\n                return config.percentage;\n            }\n\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @dev Update the reserve of the asset for the specific pool after transferring to the protocol share reserve.\n     * @param comptroller Comptroller address (pool)\n     * @param asset Asset address.\n     * @param incomeType type of income\n     */\n    function updateAssetsState(\n        address comptroller,\n        address asset,\n        IncomeType incomeType\n    ) public override(IProtocolShareReserve) nonReentrant {\n        if (!IComptroller(comptroller).isComptroller()) revert InvalidAddress();\n        ensureNonzeroAddress(asset);\n\n        if (\n            comptroller != CORE_POOL_COMPTROLLER &&\n            IPoolRegistry(poolRegistry).getVTokenForAsset(comptroller, asset) == address(0)\n        ) revert InvalidAddress();\n\n        Schema schema = _getSchema(incomeType);\n        uint256 currentBalance = IERC20Upgradeable(asset).balanceOf(address(this));\n        uint256 assetReserve = totalAssetReserve[asset];\n\n        if (currentBalance > assetReserve) {\n            uint256 balanceDifference;\n            unchecked {\n                balanceDifference = currentBalance - assetReserve;\n            }\n\n            assetsReserves[comptroller][asset][schema] += balanceDifference;\n            totalAssetReserve[asset] += balanceDifference;\n            emit AssetsReservesUpdated(comptroller, asset, balanceDifference, incomeType, schema);\n        }\n    }\n\n    /**\n     * @dev asset from a particular pool to be release to distribution targets\n     * @param comptroller  Comptroller address(pool)\n     * @param asset Asset address.\n     */\n    function _releaseFund(address comptroller, address asset) internal {\n        uint256 totalSchemas = uint256(type(Schema).max) + 1;\n        uint256[] memory schemaBalances = new uint256[](totalSchemas);\n        uint256 totalBalance;\n        for (uint256 schemaValue; schemaValue < totalSchemas; ) {\n            schemaBalances[schemaValue] = assetsReserves[comptroller][asset][Schema(schemaValue)];\n            totalBalance += schemaBalances[schemaValue];\n\n            unchecked {\n                ++schemaValue;\n            }\n        }\n\n        if (totalBalance == 0) {\n            return;\n        }\n\n        uint256[] memory totalTransferAmounts = new uint256[](totalSchemas);\n        for (uint256 i = 0; i < distributionTargets.length; ) {\n            DistributionConfig memory _config = distributionTargets[i];\n\n            uint256 transferAmount = (schemaBalances[uint256(_config.schema)] * _config.percentage) / MAX_PERCENT;\n            totalTransferAmounts[uint256(_config.schema)] += transferAmount;\n\n            if (transferAmount != 0) {\n                IERC20Upgradeable(asset).safeTransfer(_config.destination, transferAmount);\n                IIncomeDestination(_config.destination).updateAssetsState(comptroller, asset);\n\n                emit AssetReleased(_config.destination, asset, _config.schema, _config.percentage, transferAmount);\n            }\n\n            unchecked {\n                ++i;\n            }\n        }\n\n        uint256[] memory newSchemaBalances = new uint256[](totalSchemas);\n        for (uint256 schemaValue = 0; schemaValue < totalSchemas; ) {\n            newSchemaBalances[schemaValue] = schemaBalances[schemaValue] - totalTransferAmounts[schemaValue];\n            assetsReserves[comptroller][asset][Schema(schemaValue)] = newSchemaBalances[schemaValue];\n            totalAssetReserve[asset] = totalAssetReserve[asset] - totalTransferAmounts[schemaValue];\n\n            emit ReservesUpdated(\n                comptroller,\n                asset,\n                Schema(schemaValue),\n                schemaBalances[schemaValue],\n                newSchemaBalances[schemaValue]\n            );\n\n            unchecked {\n                ++schemaValue;\n            }\n        }\n    }\n\n    /**\n     * @dev Returns the schema based on income type\n     * @param incomeType type of income\n     * @return schema schema for distribution\n     */\n    function _getSchema(IncomeType incomeType) internal view returns (Schema schema) {\n        schema = Schema.ADDITIONAL_REVENUE;\n\n        if (incomeType == IncomeType.SPREAD) {\n            schema = Schema.PROTOCOL_RESERVES;\n        }\n    }\n\n    /**\n     * @dev This ensures that the total percentage of all the distribution targets is 100% or 0%\n     */\n    function _ensurePercentages() internal view {\n        uint256 totalSchemas = uint256(type(Schema).max) + 1;\n        uint16[] memory totalPercentages = new uint16[](totalSchemas);\n\n        uint256 distributionTargetsLength = distributionTargets.length;\n        for (uint256 i = 0; i < distributionTargetsLength; ) {\n            DistributionConfig memory config = distributionTargets[i];\n            totalPercentages[uint256(config.schema)] += config.percentage;\n\n            unchecked {\n                ++i;\n            }\n        }\n        for (uint256 schemaValue = 0; schemaValue < totalSchemas; ) {\n            if (totalPercentages[schemaValue] != MAX_PERCENT && totalPercentages[schemaValue] != 0)\n                revert InvalidTotalPercentage();\n\n            unchecked {\n                ++schemaValue;\n            }\n        }\n    }\n\n    /**\n     * @dev Returns the underlying asset address for the vToken\n     * @param vToken vToken address\n     * @return asset address of asset\n     */\n    function _getUnderlying(address vToken) internal view returns (address) {\n        if (vToken == vBNB) {\n            return WBNB;\n        } else {\n            return IVToken(vToken).underlying();\n        }\n    }\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/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"
    },
    "@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/CheckpointView.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\n/**\n * @title Venus CheckpointView Contract\n * @notice A contract that calls a view function from two different contracts\n *   based on whether a checkpoint in time has passed. Using this contract, we\n *   can change dependencies at a certain timestamp, which is useful for\n *   scheduled changes in, e.g., interest rate models.\n * @author Venus\n */\ncontract CheckpointView {\n    using Address for address;\n\n    address public immutable DATA_SOURCE_1;\n    address public immutable DATA_SOURCE_2;\n    uint256 public immutable CHECKPOINT_TIMESTAMP;\n\n    /**\n     * @notice Constructor\n     * @param dataSource1 Data source to use before the checkpoint\n     * @param dataSource2 Data source to use after the checkpoint\n     * @param checkpointTimestamp Checkpoint timestamp\n     */\n    constructor(address dataSource1, address dataSource2, uint256 checkpointTimestamp) {\n        ensureNonzeroAddress(address(dataSource1));\n        ensureNonzeroAddress(address(dataSource2));\n        DATA_SOURCE_1 = dataSource1;\n        DATA_SOURCE_2 = dataSource2;\n        CHECKPOINT_TIMESTAMP = checkpointTimestamp;\n    }\n\n    /**\n     * @notice Fallback function that proxies the view calls to the current data source\n     * @param input Input data (with a function selector) for the call\n     */\n    fallback(bytes calldata input) external returns (bytes memory) {\n        return _getCurrentDataSource().functionStaticCall(input);\n    }\n\n    /**\n     * @notice Returns the current data source contract (either the old one or the new one)\n     * @return Data source contract in use\n     */\n    function currentDataSource() external view returns (address) {\n        return _getCurrentDataSource();\n    }\n\n    /**\n     * @dev Returns the current data source contract (either the old one or the new one)\n     * @return Data source contract in use\n     */\n    function _getCurrentDataSource() internal view returns (address) {\n        return (block.timestamp < CHECKPOINT_TIMESTAMP) ? DATA_SOURCE_1 : DATA_SOURCE_2;\n    }\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 { MathUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.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 MathUpgradeable for uint256;\n    using SafeERC20Upgradeable for ERC20Upgradeable;\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 invoke 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\n        uint256 totalSupplyBefore = totalSupply();\n        _deposit(_msgSender(), receiver, assets, shares);\n        uint256 actualShares = totalSupply() - totalSupplyBefore;\n\n        return actualShares;\n    }\n\n    /// @dev The minted shares are calculated considering the minted VTokens\n    /// @dev It can mint slightly fewer shares than requested, because VToken.mint rounds down\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        return assets;\n    }\n\n    /// @dev Receiver can receive slightly more assets than requested, because VToken.redeemUnderlying rounds up\n    /// @dev The shares to burn are calculated considering the actual transferred assets, not the requested ones\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 actualAssets, uint256 actualShares) = _beforeWithdraw(assets);\n        _withdraw(_msgSender(), receiver, owner, actualAssets, actualShares);\n\n        return actualShares;\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 actualAssets = _beforeRedeem(shares);\n        if (actualAssets == 0) {\n            revert ERC4626__ZeroAmount(\"redeem\");\n        }\n\n        _withdraw(_msgSender(), receiver, owner, actualAssets, shares);\n        return actualAssets;\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 the amount of vTokens equivalent to the provided shares.\n    /// @dev Calls `redeem` on the vToken contract. Reverts on error.\n    /// @param shares The amount of shares to redeem.\n    /// @return The amount of assets transferred in\n    function _beforeRedeem(uint256 shares) internal returns (uint256) {\n        IERC20Upgradeable token = IERC20Upgradeable(asset());\n        uint256 balanceBefore = token.balanceOf(address(this));\n\n        // Calculate the amount of vTokens equivalent to the amount of shares, rounding it down\n        uint256 vTokens = shares.mulDiv(\n            vToken.balanceOf(address(this)),\n            totalSupply() + 10 ** _decimalsOffset(),\n            MathUpgradeable.Rounding.Down\n        );\n\n        uint256 errorCode = vToken.redeem(vTokens);\n        if (errorCode != NO_ERROR) {\n            revert VenusERC4626__VenusError(errorCode);\n        }\n\n        uint256 balanceAfter = token.balanceOf(address(this));\n\n        // Return the amount of assets that was *actually* transferred in\n        return balanceAfter - balanceBefore;\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 actualAssets The amount of assets transferred in\n    /// @return actualShares The shares equivalent to `actualAssets`, to be burned, rounded up\n    /// @custom:error ERC4626__ZeroAmount is thrown when the redeemed VTokens are zero\n    function _beforeWithdraw(uint256 assets) internal returns (uint256 actualAssets, uint256 actualShares) {\n        IERC20Upgradeable token = IERC20Upgradeable(asset());\n        uint256 balanceBefore = token.balanceOf(address(this));\n        uint256 vTokenBalanceBefore = vToken.balanceOf(address(this));\n\n        uint256 errorCode = vToken.redeemUnderlying(assets);\n        if (errorCode != NO_ERROR) {\n            revert VenusERC4626__VenusError(errorCode);\n        }\n\n        // Return the amount of assets *actually* transferred in\n        actualAssets = token.balanceOf(address(this)) - balanceBefore;\n\n        uint256 actualVTokens = vTokenBalanceBefore - vToken.balanceOf(address(this));\n        if (actualVTokens == 0) {\n            revert ERC4626__ZeroAmount(\"actualVTokens at _beforeWithdraw\");\n        }\n        // Return the shares equivalent to the burned vTokens\n        actualShares = actualVTokens.mulDiv(\n            totalSupply() + 10 ** _decimalsOffset(),\n            vTokenBalanceBefore,\n            MathUpgradeable.Rounding.Up\n        );\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 _mintVTokens(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 Deposits the assets into the VToken and calculates the shares to mint based on the\n    /// underlying assets equivalent to the new VTokens minted\n    /// @custom:error ERC4626__ZeroAmount is thrown when the minted VTokens are zero\n    /// @inheritdoc ERC4626Upgradeable\n    function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal override {\n        // 1. Track pre-transfer balances\n        uint256 assetBalanceBefore = IERC20Upgradeable(asset()).balanceOf(address(this));\n        uint256 vTokenBalanceBefore = vToken.balanceOf(address(this));\n\n        // 2. Perform asset transfer (original OZ 4626 logic)\n        SafeERC20Upgradeable.safeTransferFrom(IERC20Upgradeable(asset()), caller, address(this), assets);\n\n        // 3. Calculate actual assets received (protects against fee-on-transfer)\n        uint256 assetsReceived = IERC20Upgradeable(asset()).balanceOf(address(this)) - assetBalanceBefore;\n\n        // 4. Mint vTokens with received assets\n        _mintVTokens(assetsReceived);\n\n        // 5. Verify actual vTokens received\n        uint256 vTokensReceived = vToken.balanceOf(address(this)) - vTokenBalanceBefore;\n        if (vTokensReceived == 0) {\n            revert ERC4626__ZeroAmount(\"vTokensReceived at _deposit\");\n        }\n        uint256 actualAssetsValue = (vTokensReceived * vToken.exchangeRateStored()) / EXP_SCALE;\n\n        // 6. Recalculate shares based on actual received value\n        // This is the same operation performed by previewDeposit, adjusting the total assets\n        uint256 actualShares = actualAssetsValue.mulDiv(\n            totalSupply() + 10 ** _decimalsOffset(),\n            totalAssets() + 1 - actualAssetsValue, // remove the new assets deposited to the VToken in this operation\n            MathUpgradeable.Rounding.Down\n        );\n\n        // 7. Mint the corrected share amount\n        _mint(receiver, actualShares);\n\n        emit Deposit(caller, receiver, assets, actualShares);\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 and 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"
    },
    "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/IPancakeswapV2Router.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\ninterface IPancakeswapV2Router {\n    function swapExactTokensForTokens(\n        uint256 amountIn,\n        uint256 amountOutMin,\n        address[] calldata path,\n        address to,\n        uint256 deadline\n    ) external returns (uint256[] memory amounts);\n}\n"
    },
    "contracts/legacy/RiskFund/IRiskFund.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\n/**\n * @title IRiskFund\n * @author Venus\n * @notice Interface implemented by `RiskFund`.\n */\ninterface IRiskFundV1 {\n    function swapPoolsAssets(\n        address[] calldata markets,\n        uint256[] calldata amountsOutMin,\n        address[][] calldata paths,\n        uint256 deadline\n    ) external returns (uint256);\n\n    function transferReserveForAuction(address comptroller, uint256 amount) external returns (uint256);\n\n    function updateAssetsState(address comptroller, address asset) external;\n\n    function convertibleBaseAsset() external view returns (address);\n\n    function getPoolsBaseAssetReserves(address comptroller) external view returns (uint256);\n}\n"
    },
    "contracts/legacy/RiskFund/ReserveHelpers.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\";\n\nimport { ensureNonzeroAddress } from \"../../lib/validators.sol\";\nimport { ComptrollerInterface } from \"../../ComptrollerInterface.sol\";\nimport { PoolRegistryInterface } from \"../../Pool/PoolRegistryInterface.sol\";\nimport { VToken } from \"../../VToken.sol\";\n\ncontract ReserveHelpers is Ownable2StepUpgradeable {\n    using SafeERC20Upgradeable for IERC20Upgradeable;\n\n    uint256 private constant NOT_ENTERED = 1;\n\n    uint256 private constant ENTERED = 2;\n\n    // Address of the core pool's comptroller\n    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n    address public immutable CORE_POOL_COMPTROLLER;\n\n    // Address of the VBNB\n    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n    address public immutable VBNB;\n\n    // Address of the native wrapped token\n    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n    address public immutable NATIVE_WRAPPED;\n\n    // Store the previous state for the asset transferred to ProtocolShareReserve combined(for all pools).\n    mapping(address => uint256) public assetsReserves;\n\n    // Store the asset's reserve per pool in the ProtocolShareReserve.\n    // Comptroller(pool) -> Asset -> amount\n    mapping(address => mapping(address => uint256)) internal _poolsAssetsReserves;\n\n    // Address of pool registry contract\n    address public poolRegistry;\n\n    /**\n     * @dev Guard variable for re-entrancy checks\n     */\n    uint256 internal status;\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     */\n    uint256[46] private __gap;\n\n    /// @notice Event emitted after the update of the assets reserves.\n    /// @param comptroller Pool's Comptroller address\n    /// @param asset Token address\n    /// @param amount An amount by which the reserves have increased\n    event AssetsReservesUpdated(address indexed comptroller, address indexed asset, uint256 amount);\n\n    /// @notice event emitted on sweep token success\n    event SweepToken(address indexed token, address indexed to, uint256 amount);\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     */\n    modifier nonReentrant() {\n        require(status != ENTERED, \"re-entered\");\n        status = ENTERED;\n        _;\n        status = NOT_ENTERED;\n    }\n\n    /// @custom:oz-upgrades-unsafe-allow constructor\n    constructor(address corePoolComptroller_, address vbnb_, address nativeWrapped_) {\n        ensureNonzeroAddress(corePoolComptroller_);\n        ensureNonzeroAddress(vbnb_);\n        ensureNonzeroAddress(nativeWrapped_);\n\n        CORE_POOL_COMPTROLLER = corePoolComptroller_;\n        VBNB = vbnb_;\n        NATIVE_WRAPPED = nativeWrapped_;\n    }\n\n    /**\n     * @notice A public function to sweep accidental BEP-20 transfers to this contract. Tokens are sent to the address `to`, provided in input\n     * @param _token The address of the BEP-20 token to sweep\n     * @param _to Recipient of the output tokens.\n     * @custom:error ZeroAddressNotAllowed is thrown when asset address is zero\n     * @custom:access Only Owner\n     */\n    function sweepToken(address _token, address _to) external onlyOwner nonReentrant {\n        ensureNonzeroAddress(_to);\n        uint256 balanceDfference_;\n        uint256 balance_ = IERC20Upgradeable(_token).balanceOf(address(this));\n\n        require(balance_ > assetsReserves[_token], \"ReserveHelpers: Zero surplus tokens\");\n        unchecked {\n            balanceDfference_ = balance_ - assetsReserves[_token];\n        }\n\n        emit SweepToken(_token, _to, balanceDfference_);\n        IERC20Upgradeable(_token).safeTransfer(_to, balanceDfference_);\n    }\n\n    /**\n     * @notice Get the Amount of the asset in the risk fund for the specific pool.\n     * @param comptroller  Comptroller address(pool).\n     * @param asset Asset address.\n     * @return Asset's reserve in risk fund.\n     * @custom:error ZeroAddressNotAllowed is thrown when asset address is zero\n     */\n    function getPoolAssetReserve(address comptroller, address asset) external view returns (uint256) {\n        ensureNonzeroAddress(asset);\n        require(ComptrollerInterface(comptroller).isComptroller(), \"ReserveHelpers: Comptroller address invalid\");\n        return _poolsAssetsReserves[comptroller][asset];\n    }\n\n    /**\n     * @notice Update the reserve of the asset for the specific pool after transferring to risk fund\n     * and transferring funds to the protocol share reserve\n     * @param comptroller  Comptroller address(pool).\n     * @param asset Asset address.\n     * @custom:error ZeroAddressNotAllowed is thrown when asset address is zero\n     */\n    function updateAssetsState(address comptroller, address asset) public virtual {\n        ensureNonzeroAddress(asset);\n        require(ComptrollerInterface(comptroller).isComptroller(), \"ReserveHelpers: Comptroller address invalid\");\n        address poolRegistry_ = poolRegistry;\n        require(poolRegistry_ != address(0), \"ReserveHelpers: Pool Registry address is not set\");\n        require(ensureAssetListed(comptroller, asset), \"ReserveHelpers: The pool doesn't support the asset\");\n        uint256 currentBalance = IERC20Upgradeable(asset).balanceOf(address(this));\n        uint256 assetReserve = assetsReserves[asset];\n        if (currentBalance > assetReserve) {\n            uint256 balanceDifference;\n            unchecked {\n                balanceDifference = currentBalance - assetReserve;\n            }\n            assetsReserves[asset] += balanceDifference;\n            _poolsAssetsReserves[comptroller][asset] += balanceDifference;\n            emit AssetsReservesUpdated(comptroller, asset, balanceDifference);\n        }\n    }\n\n    function isAssetListedInCore(address tokenAddress) internal view returns (bool isAssetListed) {\n        VToken[] memory coreMarkets = ComptrollerInterface(CORE_POOL_COMPTROLLER).getAllMarkets();\n        for (uint256 i; i < coreMarkets.length; ++i) {\n            isAssetListed = (VBNB == address(coreMarkets[i]))\n                ? (tokenAddress == NATIVE_WRAPPED)\n                : (coreMarkets[i].underlying() == tokenAddress);\n            if (isAssetListed) {\n                break;\n            }\n        }\n    }\n\n    /// @notice This function checks for the given asset is listed or not\n    /// @param comptroller Address of the comptroller\n    /// @param asset Address of the asset\n    function ensureAssetListed(address comptroller, address asset) internal view returns (bool) {\n        if (comptroller == CORE_POOL_COMPTROLLER) {\n            return isAssetListedInCore(asset);\n        }\n        return PoolRegistryInterface(poolRegistry).getVTokenForAsset(comptroller, asset) != address(0);\n    }\n}\n"
    },
    "contracts/legacy/RiskFund/RiskFund.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 { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { ComptrollerInterface } from \"../../ComptrollerInterface.sol\";\nimport { IRiskFundV1 } from \"./IRiskFund.sol\";\nimport { ReserveHelpers } from \"./ReserveHelpers.sol\";\nimport { ExponentialNoError } from \"../../ExponentialNoError.sol\";\nimport { VToken } from \"../../VToken.sol\";\nimport { ComptrollerViewInterface } from \"../../ComptrollerInterface.sol\";\nimport { Comptroller } from \"../../Comptroller.sol\";\nimport { PoolRegistry } from \"../../Pool/PoolRegistry.sol\";\nimport { IPancakeswapV2Router } from \"../../IPancakeswapV2Router.sol\";\nimport { MaxLoopsLimitHelper } from \"../../MaxLoopsLimitHelper.sol\";\nimport { ensureNonzeroAddress } from \"../../lib/validators.sol\";\nimport { ApproveOrRevert } from \"../../lib/ApproveOrRevert.sol\";\n\n/**\n * @title RiskFund\n * @author Venus\n * @notice Contract with basic features to track/hold different assets for different Comptrollers.\n * @dev This contract does not support BNB.\n */\ncontract RiskFund is AccessControlledV8, ExponentialNoError, ReserveHelpers, MaxLoopsLimitHelper, IRiskFundV1 {\n    using SafeERC20Upgradeable for IERC20Upgradeable;\n    using ApproveOrRevert for IERC20Upgradeable;\n\n    address public convertibleBaseAsset;\n    address public shortfall;\n    address public pancakeSwapRouter;\n    uint256 public minAmountToConvert;\n\n    /// @notice Emitted when pool registry address is updated\n    event PoolRegistryUpdated(address indexed oldPoolRegistry, address indexed newPoolRegistry);\n\n    /// @notice Emitted when shortfall contract address is updated\n    event ShortfallContractUpdated(address indexed oldShortfallContract, address indexed newShortfallContract);\n\n    /// @notice Emitted when convertible base asset is updated\n    event ConvertibleBaseAssetUpdated(address indexed oldConvertibleBaseAsset, address indexed newConvertibleBaseAsset);\n\n    /// @notice Emitted when PancakeSwap router contract address is updated\n    event PancakeSwapRouterUpdated(address indexed oldPancakeSwapRouter, address indexed newPancakeSwapRouter);\n\n    /// @notice Emitted when minimum amount to convert is updated\n    event MinAmountToConvertUpdated(uint256 oldMinAmountToConvert, uint256 newMinAmountToConvert);\n\n    /// @notice Emitted when pools assets are swapped\n    event SwappedPoolsAssets(address[] markets, uint256[] amountsOutMin, uint256 totalAmount);\n\n    /// @notice Emitted when reserves are transferred for auction\n    event TransferredReserveForAuction(address indexed comptroller, uint256 amount);\n\n    /// @dev Note that the contract is upgradeable. Use initialize() or reinitializers\n    ///      to set the state variables.\n    /// @custom:oz-upgrades-unsafe-allow constructor\n    constructor(\n        address corePoolComptroller_,\n        address vbnb_,\n        address nativeWrapped_\n    ) ReserveHelpers(corePoolComptroller_, vbnb_, nativeWrapped_) {\n        _disableInitializers();\n    }\n\n    /**\n     * @notice Initializes the deployer to owner.\n     * @param pancakeSwapRouter_ Address of the PancakeSwap router\n     * @param minAmountToConvert_ Minimum amount assets must be worth to convert into base asset\n     * @param convertibleBaseAsset_ Address of the base asset\n     * @param accessControlManager_ Address of the access control contract\n     * @param loopsLimit_ Limit for the loops in the contract to avoid DOS\n     * @custom:error ZeroAddressNotAllowed is thrown when PCS router address is zero\n     * @custom:error ZeroAddressNotAllowed is thrown when convertible base asset address is zero\n     */\n    function initialize(\n        address pancakeSwapRouter_,\n        uint256 minAmountToConvert_,\n        address convertibleBaseAsset_,\n        address accessControlManager_,\n        uint256 loopsLimit_\n    ) external initializer {\n        ensureNonzeroAddress(pancakeSwapRouter_);\n        ensureNonzeroAddress(convertibleBaseAsset_);\n        require(minAmountToConvert_ > 0, \"Risk Fund: Invalid min amount to convert\");\n        require(loopsLimit_ > 0, \"Risk Fund: Loops limit can not be zero\");\n\n        __Ownable2Step_init();\n        __AccessControlled_init_unchained(accessControlManager_);\n\n        pancakeSwapRouter = pancakeSwapRouter_;\n        minAmountToConvert = minAmountToConvert_;\n        convertibleBaseAsset = convertibleBaseAsset_;\n\n        _setMaxLoopsLimit(loopsLimit_);\n    }\n\n    /**\n     * @notice Pool registry setter\n     * @param poolRegistry_ Address of the pool registry\n     * @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n     */\n    function setPoolRegistry(address poolRegistry_) external onlyOwner {\n        ensureNonzeroAddress(poolRegistry_);\n        address oldPoolRegistry = poolRegistry;\n        poolRegistry = poolRegistry_;\n        emit PoolRegistryUpdated(oldPoolRegistry, poolRegistry_);\n    }\n\n    /**\n     * @notice Shortfall contract address setter\n     * @param shortfallContractAddress_ Address of the auction contract\n     * @custom:error ZeroAddressNotAllowed is thrown when shortfall contract address is zero\n     */\n    function setShortfallContractAddress(address shortfallContractAddress_) external onlyOwner {\n        ensureNonzeroAddress(shortfallContractAddress_);\n\n        address oldShortfallContractAddress = shortfall;\n        shortfall = shortfallContractAddress_;\n        emit ShortfallContractUpdated(oldShortfallContractAddress, shortfallContractAddress_);\n    }\n\n    /**\n     * @notice PancakeSwap router address setter\n     * @param pancakeSwapRouter_ Address of the PancakeSwap router\n     * @custom:error ZeroAddressNotAllowed is thrown when PCS router address is zero\n     */\n    function setPancakeSwapRouter(address pancakeSwapRouter_) external onlyOwner {\n        ensureNonzeroAddress(pancakeSwapRouter_);\n        address oldPancakeSwapRouter = pancakeSwapRouter;\n        pancakeSwapRouter = pancakeSwapRouter_;\n        emit PancakeSwapRouterUpdated(oldPancakeSwapRouter, pancakeSwapRouter_);\n    }\n\n    /**\n     * @notice Min amount to convert setter\n     * @param minAmountToConvert_ Min amount to convert.\n     */\n    function setMinAmountToConvert(uint256 minAmountToConvert_) external {\n        _checkAccessAllowed(\"setMinAmountToConvert(uint256)\");\n        require(minAmountToConvert_ > 0, \"Risk Fund: Invalid min amount to convert\");\n        uint256 oldMinAmountToConvert = minAmountToConvert;\n        minAmountToConvert = minAmountToConvert_;\n        emit MinAmountToConvertUpdated(oldMinAmountToConvert, minAmountToConvert_);\n    }\n\n    /**\n     * @notice Sets a new convertible base asset\n     * @param _convertibleBaseAsset Address for new convertible base asset.\n     */\n    function setConvertibleBaseAsset(address _convertibleBaseAsset) external {\n        _checkAccessAllowed(\"setConvertibleBaseAsset(address)\");\n        require(_convertibleBaseAsset != address(0), \"Risk Fund: new convertible base asset address invalid\");\n\n        address oldConvertibleBaseAsset = convertibleBaseAsset;\n        convertibleBaseAsset = _convertibleBaseAsset;\n\n        emit ConvertibleBaseAssetUpdated(oldConvertibleBaseAsset, _convertibleBaseAsset);\n    }\n\n    /**\n     * @notice Swap array of pool assets into base asset's tokens of at least a minimum amount\n     * @param markets Array of vTokens whose assets to swap for base asset\n     * @param amountsOutMin Minimum amount to receive for swap\n     * @param paths A path consisting of PCS token pairs for each swap\n     * @param deadline Deadline for the swap\n     * @return Number of swapped tokens\n     * @custom:error ZeroAddressNotAllowed is thrown if PoolRegistry contract address is not configured\n     */\n    function swapPoolsAssets(\n        address[] calldata markets,\n        uint256[] calldata amountsOutMin,\n        address[][] calldata paths,\n        uint256 deadline\n    ) external override nonReentrant returns (uint256) {\n        _checkAccessAllowed(\"swapPoolsAssets(address[],uint256[],address[][],uint256)\");\n        require(deadline >= block.timestamp, \"Risk fund: deadline passed\");\n        address poolRegistry_ = poolRegistry;\n        ensureNonzeroAddress(poolRegistry_);\n        require(markets.length == amountsOutMin.length, \"Risk fund: markets and amountsOutMin are unequal lengths\");\n        require(markets.length == paths.length, \"Risk fund: markets and paths are unequal lengths\");\n\n        uint256 totalAmount;\n        uint256 marketsCount = markets.length;\n\n        _ensureMaxLoops(marketsCount);\n\n        for (uint256 i; i < marketsCount; ++i) {\n            address comptroller = address(VToken(markets[i]).comptroller());\n\n            PoolRegistry.VenusPool memory pool = PoolRegistry(poolRegistry_).getPoolByComptroller(comptroller);\n            require(pool.comptroller == comptroller, \"comptroller doesn't exist pool registry\");\n            require(Comptroller(comptroller).isMarketListed(VToken(markets[i])), \"market is not listed\");\n            uint256 swappedTokens = _swapAsset(VToken(markets[i]), comptroller, amountsOutMin[i], paths[i]);\n            _poolsAssetsReserves[comptroller][convertibleBaseAsset] += swappedTokens;\n            assetsReserves[convertibleBaseAsset] += swappedTokens;\n            totalAmount = totalAmount + swappedTokens;\n        }\n        emit SwappedPoolsAssets(markets, amountsOutMin, totalAmount);\n        return totalAmount;\n    }\n\n    /**\n     * @notice Transfer tokens for auction.\n     * @param comptroller Comptroller of the pool.\n     * @param amount Amount to be transferred to auction contract.\n     * @return Number reserved tokens.\n     */\n    function transferReserveForAuction(\n        address comptroller,\n        uint256 amount\n    ) external override nonReentrant returns (uint256) {\n        address shortfall_ = shortfall;\n        require(msg.sender == shortfall_, \"Risk fund: Only callable by Shortfall contract\");\n        require(\n            amount <= _poolsAssetsReserves[comptroller][convertibleBaseAsset],\n            \"Risk Fund: Insufficient pool reserve.\"\n        );\n        unchecked {\n            _poolsAssetsReserves[comptroller][convertibleBaseAsset] =\n                _poolsAssetsReserves[comptroller][convertibleBaseAsset] -\n                amount;\n        }\n        unchecked {\n            assetsReserves[convertibleBaseAsset] = assetsReserves[convertibleBaseAsset] - amount;\n        }\n        emit TransferredReserveForAuction(comptroller, amount);\n        IERC20Upgradeable(convertibleBaseAsset).safeTransfer(shortfall_, amount);\n        return amount;\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 Get the Amount of the Base asset in the risk fund for the specific pool.\n     * @param comptroller  Comptroller address(pool).\n     * @return Base Asset's reserve in risk fund.\n     */\n    function getPoolsBaseAssetReserves(address comptroller) external view returns (uint256) {\n        require(ComptrollerInterface(comptroller).isComptroller(), \"Risk Fund: Comptroller address invalid\");\n        return _poolsAssetsReserves[comptroller][convertibleBaseAsset];\n    }\n\n    /**\n     * @notice Update the reserve of the asset for the specific pool after transferring to risk fund.\n     * @param comptroller  Comptroller address(pool).\n     * @param asset Asset address.\n     */\n    function updateAssetsState(address comptroller, address asset) public override(IRiskFundV1, ReserveHelpers) {\n        super.updateAssetsState(comptroller, asset);\n    }\n\n    /**\n     * @dev Swap single asset to base asset.\n     * @param vToken VToken\n     * @param comptroller Comptroller address\n     * @param amountOutMin Minimum amount to receive for swap\n     * @param path A path for the swap consisting of PCS token pairs\n     * @return Number of swapped tokens.\n     */\n    function _swapAsset(\n        VToken vToken,\n        address comptroller,\n        uint256 amountOutMin,\n        address[] calldata path\n    ) internal returns (uint256) {\n        require(amountOutMin != 0, \"RiskFund: amountOutMin must be greater than 0 to swap vToken\");\n        uint256 totalAmount;\n\n        address underlyingAsset = vToken.underlying();\n        address convertibleBaseAsset_ = convertibleBaseAsset;\n        uint256 balanceOfUnderlyingAsset = _poolsAssetsReserves[comptroller][underlyingAsset];\n\n        if (balanceOfUnderlyingAsset == 0) {\n            return 0;\n        }\n\n        ResilientOracleInterface oracle = ComptrollerViewInterface(comptroller).oracle();\n        oracle.updateAssetPrice(convertibleBaseAsset_);\n        Exp memory baseAssetPrice = Exp({ mantissa: oracle.getPrice(convertibleBaseAsset_) });\n        uint256 amountOutMinInUsd = mul_ScalarTruncate(baseAssetPrice, amountOutMin);\n\n        require(amountOutMinInUsd >= minAmountToConvert, \"RiskFund: minAmountToConvert violated\");\n\n        assetsReserves[underlyingAsset] -= balanceOfUnderlyingAsset;\n        _poolsAssetsReserves[comptroller][underlyingAsset] -= balanceOfUnderlyingAsset;\n\n        if (underlyingAsset != convertibleBaseAsset_) {\n            require(path[0] == underlyingAsset, \"RiskFund: swap path must start with the underlying asset\");\n            require(\n                path[path.length - 1] == convertibleBaseAsset_,\n                \"RiskFund: finally path must be convertible base asset\"\n            );\n            address pancakeSwapRouter_ = pancakeSwapRouter;\n            IERC20Upgradeable(underlyingAsset).approveOrRevert(pancakeSwapRouter_, 0);\n            IERC20Upgradeable(underlyingAsset).approveOrRevert(pancakeSwapRouter_, balanceOfUnderlyingAsset);\n            uint256[] memory amounts = IPancakeswapV2Router(pancakeSwapRouter_).swapExactTokensForTokens(\n                balanceOfUnderlyingAsset,\n                amountOutMin,\n                path,\n                address(this),\n                block.timestamp\n            );\n            totalAmount = amounts[path.length - 1];\n        } else {\n            totalAmount = balanceOfUnderlyingAsset;\n        }\n\n        return totalAmount;\n    }\n}\n"
    },
    "contracts/Lens/legacy/PoolLensR1.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { ExponentialNoError } from \"../../ExponentialNoError.sol\";\nimport { VToken } from \"../../VToken.sol\";\nimport { ComptrollerInterface, ComptrollerViewInterface } from \"../../ComptrollerInterface.sol\";\nimport { PoolRegistryInterface } from \"../../Pool/PoolRegistryInterface.sol\";\nimport { PoolRegistry } from \"../../Pool/PoolRegistry.sol\";\nimport { RewardsDistributor } from \"../../Rewards/RewardsDistributor.sol\";\n\n/**\n * @title PoolLens\n * @author Venus\n * @notice The `PoolLens` contract is designed to retrieve important information for each registered pool. A list of essential information\n * for all pools within the lending protocol can be acquired through the function `getAllPools()`. Additionally, the following records can be\n * looked up for specific pools and markets:\n- the vToken balance of a given user;\n- the pool data (oracle address, associated vToken, liquidation incentive, etc) of a pool via its associated comptroller address;\n- the vToken address in a pool for a given asset;\n- a list of all pools that support an asset;\n- the underlying asset price of a vToken;\n- the metadata (exchange/borrow/supply rate, total supply, collateral factor, etc) of any vToken.\n */\ncontract PoolLensR1 is ExponentialNoError {\n    /**\n     * @dev Struct for PoolDetails.\n     */\n    struct PoolData {\n        string name;\n        address creator;\n        address comptroller;\n        uint256 blockPosted;\n        uint256 timestampPosted;\n        string category;\n        string logoURL;\n        string description;\n        address priceOracle;\n        uint256 closeFactor;\n        uint256 liquidationIncentive;\n        uint256 minLiquidatableCollateral;\n        VTokenMetadata[] vTokens;\n    }\n\n    /**\n     * @dev Struct for VToken.\n     */\n    struct VTokenMetadata {\n        address vToken;\n        uint256 exchangeRateCurrent;\n        uint256 supplyRatePerBlock;\n        uint256 borrowRatePerBlock;\n        uint256 reserveFactorMantissa;\n        uint256 supplyCaps;\n        uint256 borrowCaps;\n        uint256 totalBorrows;\n        uint256 totalReserves;\n        uint256 totalSupply;\n        uint256 totalCash;\n        bool isListed;\n        uint256 collateralFactorMantissa;\n        address underlyingAssetAddress;\n        uint256 vTokenDecimals;\n        uint256 underlyingDecimals;\n    }\n\n    /**\n     * @dev Struct for VTokenBalance.\n     */\n    struct VTokenBalances {\n        address vToken;\n        uint256 balanceOf;\n        uint256 borrowBalanceCurrent;\n        uint256 balanceOfUnderlying;\n        uint256 tokenBalance;\n        uint256 tokenAllowance;\n    }\n\n    /**\n     * @dev Struct for underlyingPrice of VToken.\n     */\n    struct VTokenUnderlyingPrice {\n        address vToken;\n        uint256 underlyingPrice;\n    }\n\n    /**\n     * @dev Struct with pending reward info for a market.\n     */\n    struct PendingReward {\n        address vTokenAddress;\n        uint256 amount;\n    }\n\n    /**\n     * @dev Struct with reward distribution totals for a single reward token and distributor.\n     */\n    struct RewardSummary {\n        address distributorAddress;\n        address rewardTokenAddress;\n        uint256 totalRewards;\n        PendingReward[] pendingRewards;\n    }\n\n    /**\n     * @dev Struct used in RewardDistributor to save last updated market state.\n     */\n    struct RewardTokenState {\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    /**\n     * @dev Struct with bad debt of a market denominated\n     */\n    struct BadDebt {\n        address vTokenAddress;\n        uint256 badDebtUsd;\n    }\n\n    /**\n     * @dev Struct with bad debt total denominated in usd for a pool and an array of BadDebt structs for each market\n     */\n    struct BadDebtSummary {\n        address comptroller;\n        uint256 totalBadDebtUsd;\n        BadDebt[] badDebts;\n    }\n\n    /**\n     * @notice Queries the user's supply/borrow balances in vTokens\n     * @param vTokens The list of vToken addresses\n     * @param account The user Account\n     * @return A list of structs containing balances data\n     */\n    function vTokenBalancesAll(VToken[] calldata vTokens, address account) external returns (VTokenBalances[] memory) {\n        uint256 vTokenCount = vTokens.length;\n        VTokenBalances[] memory res = new VTokenBalances[](vTokenCount);\n        for (uint256 i; i < vTokenCount; ++i) {\n            res[i] = vTokenBalances(vTokens[i], account);\n        }\n        return res;\n    }\n\n    /**\n     * @notice Queries all pools with addtional details for each of them\n     * @dev This function is not designed to be called in a transaction: it is too gas-intensive\n     * @param poolRegistryAddress The address of the PoolRegistry contract\n     * @return Arrays of all Venus pools' data\n     */\n    function getAllPools(address poolRegistryAddress) external view returns (PoolData[] memory) {\n        PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n        PoolRegistry.VenusPool[] memory venusPools = poolRegistryInterface.getAllPools();\n        uint256 poolLength = venusPools.length;\n\n        PoolData[] memory poolDataItems = new PoolData[](poolLength);\n\n        for (uint256 i; i < poolLength; ++i) {\n            PoolRegistry.VenusPool memory venusPool = venusPools[i];\n            PoolData memory poolData = getPoolDataFromVenusPool(poolRegistryAddress, venusPool);\n            poolDataItems[i] = poolData;\n        }\n\n        return poolDataItems;\n    }\n\n    /**\n     * @notice Queries the details of a pool identified by Comptroller address\n     * @param poolRegistryAddress The address of the PoolRegistry contract\n     * @param comptroller The Comptroller implementation address\n     * @return PoolData structure containing the details of the pool\n     */\n    function getPoolByComptroller(\n        address poolRegistryAddress,\n        address comptroller\n    ) external view returns (PoolData memory) {\n        PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n        return getPoolDataFromVenusPool(poolRegistryAddress, poolRegistryInterface.getPoolByComptroller(comptroller));\n    }\n\n    /**\n     * @notice Returns vToken holding the specified underlying asset in the specified pool\n     * @param poolRegistryAddress The address of the PoolRegistry contract\n     * @param comptroller The pool comptroller\n     * @param asset The underlyingAsset of VToken\n     * @return Address of the vToken\n     */\n    function getVTokenForAsset(\n        address poolRegistryAddress,\n        address comptroller,\n        address asset\n    ) external view returns (address) {\n        PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n        return poolRegistryInterface.getVTokenForAsset(comptroller, asset);\n    }\n\n    /**\n     * @notice Returns all pools that support the specified underlying asset\n     * @param poolRegistryAddress The address of the PoolRegistry contract\n     * @param asset The underlying asset of vToken\n     * @return A list of Comptroller contracts\n     */\n    function getPoolsSupportedByAsset(\n        address poolRegistryAddress,\n        address asset\n    ) external view returns (address[] memory) {\n        PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n        return poolRegistryInterface.getPoolsSupportedByAsset(asset);\n    }\n\n    /**\n     * @notice Returns the price data for the underlying assets of the specified vTokens\n     * @param vTokens The list of vToken addresses\n     * @return An array containing the price data for each asset\n     */\n    function vTokenUnderlyingPriceAll(\n        VToken[] calldata vTokens\n    ) external view returns (VTokenUnderlyingPrice[] memory) {\n        uint256 vTokenCount = vTokens.length;\n        VTokenUnderlyingPrice[] memory res = new VTokenUnderlyingPrice[](vTokenCount);\n        for (uint256 i; i < vTokenCount; ++i) {\n            res[i] = vTokenUnderlyingPrice(vTokens[i]);\n        }\n        return res;\n    }\n\n    /**\n     * @notice Returns the pending rewards for a user for a given pool.\n     * @param account The user account.\n     * @param comptrollerAddress address\n     * @return Pending rewards array\n     */\n    function getPendingRewards(\n        address account,\n        address comptrollerAddress\n    ) external view returns (RewardSummary[] memory) {\n        VToken[] memory markets = ComptrollerInterface(comptrollerAddress).getAllMarkets();\n        RewardsDistributor[] memory rewardsDistributors = ComptrollerViewInterface(comptrollerAddress)\n            .getRewardDistributors();\n        RewardSummary[] memory rewardSummary = new RewardSummary[](rewardsDistributors.length);\n        for (uint256 i; i < rewardsDistributors.length; ++i) {\n            RewardSummary memory reward;\n            reward.distributorAddress = address(rewardsDistributors[i]);\n            reward.rewardTokenAddress = address(rewardsDistributors[i].rewardToken());\n            reward.totalRewards = rewardsDistributors[i].rewardTokenAccrued(account);\n            reward.pendingRewards = _calculateNotDistributedAwards(account, markets, rewardsDistributors[i]);\n            rewardSummary[i] = reward;\n        }\n        return rewardSummary;\n    }\n\n    /**\n     * @notice Returns a summary of a pool's bad debt broken down by market\n     *\n     * @param comptrollerAddress Address of the comptroller\n     *\n     * @return badDebtSummary A struct with comptroller address, total bad debut denominated in usd, and\n     *   a break down of bad debt by market\n     */\n    function getPoolBadDebt(address comptrollerAddress) external view returns (BadDebtSummary memory) {\n        uint256 totalBadDebtUsd;\n\n        // Get every market in the pool\n        ComptrollerViewInterface comptroller = ComptrollerViewInterface(comptrollerAddress);\n        VToken[] memory markets = comptroller.getAllMarkets();\n        ResilientOracleInterface priceOracle = comptroller.oracle();\n\n        BadDebt[] memory badDebts = new BadDebt[](markets.length);\n\n        BadDebtSummary memory badDebtSummary;\n        badDebtSummary.comptroller = comptrollerAddress;\n        badDebtSummary.badDebts = badDebts;\n\n        // // Calculate the bad debt is USD per market\n        for (uint256 i; i < markets.length; ++i) {\n            BadDebt memory badDebt;\n            badDebt.vTokenAddress = address(markets[i]);\n            badDebt.badDebtUsd =\n                (VToken(address(markets[i])).badDebt() * priceOracle.getUnderlyingPrice(address(markets[i]))) /\n                EXP_SCALE;\n            badDebtSummary.badDebts[i] = badDebt;\n            totalBadDebtUsd = totalBadDebtUsd + badDebt.badDebtUsd;\n        }\n\n        badDebtSummary.totalBadDebtUsd = totalBadDebtUsd;\n\n        return badDebtSummary;\n    }\n\n    /**\n     * @notice Queries the user's supply/borrow balances in the specified vToken\n     * @param vToken vToken address\n     * @param account The user Account\n     * @return A struct containing the balances data\n     */\n    function vTokenBalances(VToken vToken, address account) public returns (VTokenBalances memory) {\n        uint256 balanceOf = vToken.balanceOf(account);\n        uint256 borrowBalanceCurrent = vToken.borrowBalanceCurrent(account);\n        uint256 balanceOfUnderlying = vToken.balanceOfUnderlying(account);\n        uint256 tokenBalance;\n        uint256 tokenAllowance;\n\n        IERC20 underlying = IERC20(vToken.underlying());\n        tokenBalance = underlying.balanceOf(account);\n        tokenAllowance = underlying.allowance(account, address(vToken));\n\n        return\n            VTokenBalances({\n                vToken: address(vToken),\n                balanceOf: balanceOf,\n                borrowBalanceCurrent: borrowBalanceCurrent,\n                balanceOfUnderlying: balanceOfUnderlying,\n                tokenBalance: tokenBalance,\n                tokenAllowance: tokenAllowance\n            });\n    }\n\n    /**\n     * @notice Queries additional information for the pool\n     * @param poolRegistryAddress Address of the PoolRegistry\n     * @param venusPool The VenusPool Object from PoolRegistry\n     * @return Enriched PoolData\n     */\n    function getPoolDataFromVenusPool(\n        address poolRegistryAddress,\n        PoolRegistry.VenusPool memory venusPool\n    ) public view returns (PoolData memory) {\n        // Get tokens in the Pool\n        ComptrollerInterface comptrollerInstance = ComptrollerInterface(venusPool.comptroller);\n\n        VToken[] memory vTokens = comptrollerInstance.getAllMarkets();\n\n        VTokenMetadata[] memory vTokenMetadataItems = vTokenMetadataAll(vTokens);\n\n        PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n\n        PoolRegistry.VenusPoolMetaData memory venusPoolMetaData = poolRegistryInterface.getVenusPoolMetadata(\n            venusPool.comptroller\n        );\n\n        ComptrollerViewInterface comptrollerViewInstance = ComptrollerViewInterface(venusPool.comptroller);\n\n        PoolData memory poolData = PoolData({\n            name: venusPool.name,\n            creator: venusPool.creator,\n            comptroller: venusPool.comptroller,\n            blockPosted: venusPool.blockPosted,\n            timestampPosted: venusPool.timestampPosted,\n            category: venusPoolMetaData.category,\n            logoURL: venusPoolMetaData.logoURL,\n            description: venusPoolMetaData.description,\n            vTokens: vTokenMetadataItems,\n            priceOracle: address(comptrollerViewInstance.oracle()),\n            closeFactor: comptrollerViewInstance.closeFactorMantissa(),\n            liquidationIncentive: comptrollerViewInstance.liquidationIncentiveMantissa(),\n            minLiquidatableCollateral: comptrollerViewInstance.minLiquidatableCollateral()\n        });\n\n        return poolData;\n    }\n\n    /**\n     * @notice Returns the metadata of VToken\n     * @param vToken The address of vToken\n     * @return VTokenMetadata struct\n     */\n    function vTokenMetadata(VToken vToken) public view returns (VTokenMetadata memory) {\n        uint256 exchangeRateCurrent = vToken.exchangeRateStored();\n        address comptrollerAddress = address(vToken.comptroller());\n        ComptrollerViewInterface comptroller = ComptrollerViewInterface(comptrollerAddress);\n        (bool isListed, uint256 collateralFactorMantissa) = comptroller.markets(address(vToken));\n\n        address underlyingAssetAddress = vToken.underlying();\n        uint256 underlyingDecimals = IERC20Metadata(underlyingAssetAddress).decimals();\n\n        return\n            VTokenMetadata({\n                vToken: address(vToken),\n                exchangeRateCurrent: exchangeRateCurrent,\n                supplyRatePerBlock: vToken.supplyRatePerBlock(),\n                borrowRatePerBlock: vToken.borrowRatePerBlock(),\n                reserveFactorMantissa: vToken.reserveFactorMantissa(),\n                supplyCaps: comptroller.supplyCaps(address(vToken)),\n                borrowCaps: comptroller.borrowCaps(address(vToken)),\n                totalBorrows: vToken.totalBorrows(),\n                totalReserves: vToken.totalReserves(),\n                totalSupply: vToken.totalSupply(),\n                totalCash: vToken.getCash(),\n                isListed: isListed,\n                collateralFactorMantissa: collateralFactorMantissa,\n                underlyingAssetAddress: underlyingAssetAddress,\n                vTokenDecimals: vToken.decimals(),\n                underlyingDecimals: underlyingDecimals\n            });\n    }\n\n    /**\n     * @notice Returns the metadata of all VTokens\n     * @param vTokens The list of vToken addresses\n     * @return An array of VTokenMetadata structs\n     */\n    function vTokenMetadataAll(VToken[] memory vTokens) public view returns (VTokenMetadata[] memory) {\n        uint256 vTokenCount = vTokens.length;\n        VTokenMetadata[] memory res = new VTokenMetadata[](vTokenCount);\n        for (uint256 i; i < vTokenCount; ++i) {\n            res[i] = vTokenMetadata(vTokens[i]);\n        }\n        return res;\n    }\n\n    /**\n     * @notice Returns the price data for the underlying asset of the specified vToken\n     * @param vToken vToken address\n     * @return The price data for each asset\n     */\n    function vTokenUnderlyingPrice(VToken vToken) public view returns (VTokenUnderlyingPrice memory) {\n        ComptrollerViewInterface comptroller = ComptrollerViewInterface(address(vToken.comptroller()));\n        ResilientOracleInterface priceOracle = comptroller.oracle();\n\n        return\n            VTokenUnderlyingPrice({\n                vToken: address(vToken),\n                underlyingPrice: priceOracle.getUnderlyingPrice(address(vToken))\n            });\n    }\n\n    function _calculateNotDistributedAwards(\n        address account,\n        VToken[] memory markets,\n        RewardsDistributor rewardsDistributor\n    ) internal view returns (PendingReward[] memory) {\n        PendingReward[] memory pendingRewards = new PendingReward[](markets.length);\n        for (uint256 i; i < markets.length; ++i) {\n            // Market borrow and supply state we will modify update in-memory, in order to not modify storage\n            RewardTokenState memory borrowState;\n            (borrowState.index, borrowState.block, borrowState.lastRewardingBlock) = rewardsDistributor\n                .rewardTokenBorrowState(address(markets[i]));\n            RewardTokenState memory supplyState;\n            (supplyState.index, supplyState.block, supplyState.lastRewardingBlock) = rewardsDistributor\n                .rewardTokenSupplyState(address(markets[i]));\n            Exp memory marketBorrowIndex = Exp({ mantissa: markets[i].borrowIndex() });\n\n            // Update market supply and borrow index in-memory\n            updateMarketBorrowIndex(address(markets[i]), rewardsDistributor, borrowState, marketBorrowIndex);\n            updateMarketSupplyIndex(address(markets[i]), rewardsDistributor, supplyState);\n\n            // Calculate pending rewards\n            uint256 borrowReward = calculateBorrowerReward(\n                address(markets[i]),\n                rewardsDistributor,\n                account,\n                borrowState,\n                marketBorrowIndex\n            );\n            uint256 supplyReward = calculateSupplierReward(\n                address(markets[i]),\n                rewardsDistributor,\n                account,\n                supplyState\n            );\n\n            PendingReward memory pendingReward;\n            pendingReward.vTokenAddress = address(markets[i]);\n            pendingReward.amount = borrowReward + supplyReward;\n            pendingRewards[i] = pendingReward;\n        }\n        return pendingRewards;\n    }\n\n    function updateMarketBorrowIndex(\n        address vToken,\n        RewardsDistributor rewardsDistributor,\n        RewardTokenState memory borrowState,\n        Exp memory marketBorrowIndex\n    ) internal view {\n        uint256 borrowSpeed = rewardsDistributor.rewardTokenBorrowSpeeds(vToken);\n        uint256 blockNumber = block.number;\n\n        if (borrowState.lastRewardingBlock > 0 && blockNumber > borrowState.lastRewardingBlock) {\n            blockNumber = borrowState.lastRewardingBlock;\n        }\n\n        uint256 deltaBlocks = sub_(blockNumber, uint256(borrowState.block));\n        if (deltaBlocks > 0 && borrowSpeed > 0) {\n            // Remove the total earned interest rate since the opening of the market from total borrows\n            uint256 borrowAmount = div_(VToken(vToken).totalBorrows(), marketBorrowIndex);\n            uint256 tokensAccrued = mul_(deltaBlocks, borrowSpeed);\n            Double memory ratio = borrowAmount > 0 ? fraction(tokensAccrued, borrowAmount) : Double({ mantissa: 0 });\n            Double memory index = add_(Double({ mantissa: borrowState.index }), ratio);\n            borrowState.index = safe224(index.mantissa, \"new index overflows\");\n            borrowState.block = safe32(blockNumber, \"block number overflows\");\n        } else if (deltaBlocks > 0) {\n            borrowState.block = safe32(blockNumber, \"block number overflows\");\n        }\n    }\n\n    function updateMarketSupplyIndex(\n        address vToken,\n        RewardsDistributor rewardsDistributor,\n        RewardTokenState memory supplyState\n    ) internal view {\n        uint256 supplySpeed = rewardsDistributor.rewardTokenSupplySpeeds(vToken);\n        uint256 blockNumber = block.number;\n\n        if (supplyState.lastRewardingBlock > 0 && blockNumber > supplyState.lastRewardingBlock) {\n            blockNumber = supplyState.lastRewardingBlock;\n        }\n\n        uint256 deltaBlocks = sub_(blockNumber, uint256(supplyState.block));\n        if (deltaBlocks > 0 && supplySpeed > 0) {\n            uint256 supplyTokens = VToken(vToken).totalSupply();\n            uint256 tokensAccrued = mul_(deltaBlocks, supplySpeed);\n            Double memory ratio = supplyTokens > 0 ? fraction(tokensAccrued, supplyTokens) : Double({ mantissa: 0 });\n            Double memory index = add_(Double({ mantissa: supplyState.index }), ratio);\n            supplyState.index = safe224(index.mantissa, \"new index overflows\");\n            supplyState.block = safe32(blockNumber, \"block number overflows\");\n        } else if (deltaBlocks > 0) {\n            supplyState.block = safe32(blockNumber, \"block number overflows\");\n        }\n    }\n\n    function calculateBorrowerReward(\n        address vToken,\n        RewardsDistributor rewardsDistributor,\n        address borrower,\n        RewardTokenState memory borrowState,\n        Exp memory marketBorrowIndex\n    ) internal view returns (uint256) {\n        Double memory borrowIndex = Double({ mantissa: borrowState.index });\n        Double memory borrowerIndex = Double({\n            mantissa: rewardsDistributor.rewardTokenBorrowerIndex(vToken, borrower)\n        });\n        if (borrowerIndex.mantissa == 0 && borrowIndex.mantissa >= rewardsDistributor.INITIAL_INDEX()) {\n            // Covers the case where users borrowed tokens before the market's borrow state index was set\n            borrowerIndex.mantissa = rewardsDistributor.INITIAL_INDEX();\n        }\n        Double memory deltaIndex = sub_(borrowIndex, borrowerIndex);\n        uint256 borrowerAmount = div_(VToken(vToken).borrowBalanceStored(borrower), marketBorrowIndex);\n        uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex);\n        return borrowerDelta;\n    }\n\n    function calculateSupplierReward(\n        address vToken,\n        RewardsDistributor rewardsDistributor,\n        address supplier,\n        RewardTokenState memory supplyState\n    ) internal view returns (uint256) {\n        Double memory supplyIndex = Double({ mantissa: supplyState.index });\n        Double memory supplierIndex = Double({\n            mantissa: rewardsDistributor.rewardTokenSupplierIndex(vToken, supplier)\n        });\n        if (supplierIndex.mantissa == 0 && supplyIndex.mantissa >= rewardsDistributor.INITIAL_INDEX()) {\n            // Covers the case where users supplied tokens before the market's supply state index was set\n            supplierIndex.mantissa = rewardsDistributor.INITIAL_INDEX();\n        }\n        Double memory deltaIndex = sub_(supplyIndex, supplierIndex);\n        uint256 supplierTokens = VToken(vToken).balanceOf(supplier);\n        uint256 supplierDelta = mul_(supplierTokens, deltaIndex);\n        return supplierDelta;\n    }\n}\n"
    },
    "contracts/Lens/legacy/PoolLensR2.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { ExponentialNoError } from \"../../ExponentialNoError.sol\";\nimport { VToken } from \"../../VToken.sol\";\nimport { Action, ComptrollerInterface, ComptrollerViewInterface } from \"../../ComptrollerInterface.sol\";\nimport { PoolRegistryInterface } from \"../../Pool/PoolRegistryInterface.sol\";\nimport { PoolRegistry } from \"../../Pool/PoolRegistry.sol\";\nimport { RewardsDistributor } from \"../../Rewards/RewardsDistributor.sol\";\n\n/**\n * @title PoolLens\n * @author Venus\n * @notice The `PoolLens` contract is designed to retrieve important information for each registered pool. A list of essential information\n * for all pools within the lending protocol can be acquired through the function `getAllPools()`. Additionally, the following records can be\n * looked up for specific pools and markets:\n- the vToken balance of a given user;\n- the pool data (oracle address, associated vToken, liquidation incentive, etc) of a pool via its associated comptroller address;\n- the vToken address in a pool for a given asset;\n- a list of all pools that support an asset;\n- the underlying asset price of a vToken;\n- the metadata (exchange/borrow/supply rate, total supply, collateral factor, etc) of any vToken.\n */\ncontract PoolLensR2 is ExponentialNoError {\n    /**\n     * @dev Struct for PoolDetails.\n     */\n    struct PoolData {\n        string name;\n        address creator;\n        address comptroller;\n        uint256 blockPosted;\n        uint256 timestampPosted;\n        string category;\n        string logoURL;\n        string description;\n        address priceOracle;\n        uint256 closeFactor;\n        uint256 liquidationIncentive;\n        uint256 minLiquidatableCollateral;\n        VTokenMetadata[] vTokens;\n    }\n\n    /**\n     * @dev Struct for VToken.\n     */\n    struct VTokenMetadata {\n        address vToken;\n        uint256 exchangeRateCurrent;\n        uint256 supplyRatePerBlock;\n        uint256 borrowRatePerBlock;\n        uint256 reserveFactorMantissa;\n        uint256 supplyCaps;\n        uint256 borrowCaps;\n        uint256 totalBorrows;\n        uint256 totalReserves;\n        uint256 totalSupply;\n        uint256 totalCash;\n        bool isListed;\n        uint256 collateralFactorMantissa;\n        address underlyingAssetAddress;\n        uint256 vTokenDecimals;\n        uint256 underlyingDecimals;\n        uint256 pausedActions;\n    }\n\n    /**\n     * @dev Struct for VTokenBalance.\n     */\n    struct VTokenBalances {\n        address vToken;\n        uint256 balanceOf;\n        uint256 borrowBalanceCurrent;\n        uint256 balanceOfUnderlying;\n        uint256 tokenBalance;\n        uint256 tokenAllowance;\n    }\n\n    /**\n     * @dev Struct for underlyingPrice of VToken.\n     */\n    struct VTokenUnderlyingPrice {\n        address vToken;\n        uint256 underlyingPrice;\n    }\n\n    /**\n     * @dev Struct with pending reward info for a market.\n     */\n    struct PendingReward {\n        address vTokenAddress;\n        uint256 amount;\n    }\n\n    /**\n     * @dev Struct with reward distribution totals for a single reward token and distributor.\n     */\n    struct RewardSummary {\n        address distributorAddress;\n        address rewardTokenAddress;\n        uint256 totalRewards;\n        PendingReward[] pendingRewards;\n    }\n\n    /**\n     * @dev Struct used in RewardDistributor to save last updated market state.\n     */\n    struct RewardTokenState {\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    /**\n     * @dev Struct with bad debt of a market denominated\n     */\n    struct BadDebt {\n        address vTokenAddress;\n        uint256 badDebtUsd;\n    }\n\n    /**\n     * @dev Struct with bad debt total denominated in usd for a pool and an array of BadDebt structs for each market\n     */\n    struct BadDebtSummary {\n        address comptroller;\n        uint256 totalBadDebtUsd;\n        BadDebt[] badDebts;\n    }\n\n    /**\n     * @notice Queries the user's supply/borrow balances in vTokens\n     * @param vTokens The list of vToken addresses\n     * @param account The user Account\n     * @return A list of structs containing balances data\n     */\n    function vTokenBalancesAll(VToken[] calldata vTokens, address account) external returns (VTokenBalances[] memory) {\n        uint256 vTokenCount = vTokens.length;\n        VTokenBalances[] memory res = new VTokenBalances[](vTokenCount);\n        for (uint256 i; i < vTokenCount; ++i) {\n            res[i] = vTokenBalances(vTokens[i], account);\n        }\n        return res;\n    }\n\n    /**\n     * @notice Queries all pools with addtional details for each of them\n     * @dev This function is not designed to be called in a transaction: it is too gas-intensive\n     * @param poolRegistryAddress The address of the PoolRegistry contract\n     * @return Arrays of all Venus pools' data\n     */\n    function getAllPools(address poolRegistryAddress) external view returns (PoolData[] memory) {\n        PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n        PoolRegistry.VenusPool[] memory venusPools = poolRegistryInterface.getAllPools();\n        uint256 poolLength = venusPools.length;\n\n        PoolData[] memory poolDataItems = new PoolData[](poolLength);\n\n        for (uint256 i; i < poolLength; ++i) {\n            PoolRegistry.VenusPool memory venusPool = venusPools[i];\n            PoolData memory poolData = getPoolDataFromVenusPool(poolRegistryAddress, venusPool);\n            poolDataItems[i] = poolData;\n        }\n\n        return poolDataItems;\n    }\n\n    /**\n     * @notice Queries the details of a pool identified by Comptroller address\n     * @param poolRegistryAddress The address of the PoolRegistry contract\n     * @param comptroller The Comptroller implementation address\n     * @return PoolData structure containing the details of the pool\n     */\n    function getPoolByComptroller(\n        address poolRegistryAddress,\n        address comptroller\n    ) external view returns (PoolData memory) {\n        PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n        return getPoolDataFromVenusPool(poolRegistryAddress, poolRegistryInterface.getPoolByComptroller(comptroller));\n    }\n\n    /**\n     * @notice Returns vToken holding the specified underlying asset in the specified pool\n     * @param poolRegistryAddress The address of the PoolRegistry contract\n     * @param comptroller The pool comptroller\n     * @param asset The underlyingAsset of VToken\n     * @return Address of the vToken\n     */\n    function getVTokenForAsset(\n        address poolRegistryAddress,\n        address comptroller,\n        address asset\n    ) external view returns (address) {\n        PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n        return poolRegistryInterface.getVTokenForAsset(comptroller, asset);\n    }\n\n    /**\n     * @notice Returns all pools that support the specified underlying asset\n     * @param poolRegistryAddress The address of the PoolRegistry contract\n     * @param asset The underlying asset of vToken\n     * @return A list of Comptroller contracts\n     */\n    function getPoolsSupportedByAsset(\n        address poolRegistryAddress,\n        address asset\n    ) external view returns (address[] memory) {\n        PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n        return poolRegistryInterface.getPoolsSupportedByAsset(asset);\n    }\n\n    /**\n     * @notice Returns the price data for the underlying assets of the specified vTokens\n     * @param vTokens The list of vToken addresses\n     * @return An array containing the price data for each asset\n     */\n    function vTokenUnderlyingPriceAll(\n        VToken[] calldata vTokens\n    ) external view returns (VTokenUnderlyingPrice[] memory) {\n        uint256 vTokenCount = vTokens.length;\n        VTokenUnderlyingPrice[] memory res = new VTokenUnderlyingPrice[](vTokenCount);\n        for (uint256 i; i < vTokenCount; ++i) {\n            res[i] = vTokenUnderlyingPrice(vTokens[i]);\n        }\n        return res;\n    }\n\n    /**\n     * @notice Returns the pending rewards for a user for a given pool.\n     * @param account The user account.\n     * @param comptrollerAddress address\n     * @return Pending rewards array\n     */\n    function getPendingRewards(\n        address account,\n        address comptrollerAddress\n    ) external view returns (RewardSummary[] memory) {\n        VToken[] memory markets = ComptrollerInterface(comptrollerAddress).getAllMarkets();\n        RewardsDistributor[] memory rewardsDistributors = ComptrollerViewInterface(comptrollerAddress)\n            .getRewardDistributors();\n        RewardSummary[] memory rewardSummary = new RewardSummary[](rewardsDistributors.length);\n        for (uint256 i; i < rewardsDistributors.length; ++i) {\n            RewardSummary memory reward;\n            reward.distributorAddress = address(rewardsDistributors[i]);\n            reward.rewardTokenAddress = address(rewardsDistributors[i].rewardToken());\n            reward.totalRewards = rewardsDistributors[i].rewardTokenAccrued(account);\n            reward.pendingRewards = _calculateNotDistributedAwards(account, markets, rewardsDistributors[i]);\n            rewardSummary[i] = reward;\n        }\n        return rewardSummary;\n    }\n\n    /**\n     * @notice Returns a summary of a pool's bad debt broken down by market\n     *\n     * @param comptrollerAddress Address of the comptroller\n     *\n     * @return badDebtSummary A struct with comptroller address, total bad debut denominated in usd, and\n     *   a break down of bad debt by market\n     */\n    function getPoolBadDebt(address comptrollerAddress) external view returns (BadDebtSummary memory) {\n        uint256 totalBadDebtUsd;\n\n        // Get every market in the pool\n        ComptrollerViewInterface comptroller = ComptrollerViewInterface(comptrollerAddress);\n        VToken[] memory markets = comptroller.getAllMarkets();\n        ResilientOracleInterface priceOracle = comptroller.oracle();\n\n        BadDebt[] memory badDebts = new BadDebt[](markets.length);\n\n        BadDebtSummary memory badDebtSummary;\n        badDebtSummary.comptroller = comptrollerAddress;\n        badDebtSummary.badDebts = badDebts;\n\n        // // Calculate the bad debt is USD per market\n        for (uint256 i; i < markets.length; ++i) {\n            BadDebt memory badDebt;\n            badDebt.vTokenAddress = address(markets[i]);\n            badDebt.badDebtUsd =\n                (VToken(address(markets[i])).badDebt() * priceOracle.getUnderlyingPrice(address(markets[i]))) /\n                EXP_SCALE;\n            badDebtSummary.badDebts[i] = badDebt;\n            totalBadDebtUsd = totalBadDebtUsd + badDebt.badDebtUsd;\n        }\n\n        badDebtSummary.totalBadDebtUsd = totalBadDebtUsd;\n\n        return badDebtSummary;\n    }\n\n    /**\n     * @notice Queries the user's supply/borrow balances in the specified vToken\n     * @param vToken vToken address\n     * @param account The user Account\n     * @return A struct containing the balances data\n     */\n    function vTokenBalances(VToken vToken, address account) public returns (VTokenBalances memory) {\n        uint256 balanceOf = vToken.balanceOf(account);\n        uint256 borrowBalanceCurrent = vToken.borrowBalanceCurrent(account);\n        uint256 balanceOfUnderlying = vToken.balanceOfUnderlying(account);\n        uint256 tokenBalance;\n        uint256 tokenAllowance;\n\n        IERC20 underlying = IERC20(vToken.underlying());\n        tokenBalance = underlying.balanceOf(account);\n        tokenAllowance = underlying.allowance(account, address(vToken));\n\n        return\n            VTokenBalances({\n                vToken: address(vToken),\n                balanceOf: balanceOf,\n                borrowBalanceCurrent: borrowBalanceCurrent,\n                balanceOfUnderlying: balanceOfUnderlying,\n                tokenBalance: tokenBalance,\n                tokenAllowance: tokenAllowance\n            });\n    }\n\n    /**\n     * @notice Queries additional information for the pool\n     * @param poolRegistryAddress Address of the PoolRegistry\n     * @param venusPool The VenusPool Object from PoolRegistry\n     * @return Enriched PoolData\n     */\n    function getPoolDataFromVenusPool(\n        address poolRegistryAddress,\n        PoolRegistry.VenusPool memory venusPool\n    ) public view returns (PoolData memory) {\n        // Get tokens in the Pool\n        ComptrollerInterface comptrollerInstance = ComptrollerInterface(venusPool.comptroller);\n\n        VToken[] memory vTokens = comptrollerInstance.getAllMarkets();\n\n        VTokenMetadata[] memory vTokenMetadataItems = vTokenMetadataAll(vTokens);\n\n        PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n\n        PoolRegistry.VenusPoolMetaData memory venusPoolMetaData = poolRegistryInterface.getVenusPoolMetadata(\n            venusPool.comptroller\n        );\n\n        ComptrollerViewInterface comptrollerViewInstance = ComptrollerViewInterface(venusPool.comptroller);\n\n        PoolData memory poolData = PoolData({\n            name: venusPool.name,\n            creator: venusPool.creator,\n            comptroller: venusPool.comptroller,\n            blockPosted: venusPool.blockPosted,\n            timestampPosted: venusPool.timestampPosted,\n            category: venusPoolMetaData.category,\n            logoURL: venusPoolMetaData.logoURL,\n            description: venusPoolMetaData.description,\n            vTokens: vTokenMetadataItems,\n            priceOracle: address(comptrollerViewInstance.oracle()),\n            closeFactor: comptrollerViewInstance.closeFactorMantissa(),\n            liquidationIncentive: comptrollerViewInstance.liquidationIncentiveMantissa(),\n            minLiquidatableCollateral: comptrollerViewInstance.minLiquidatableCollateral()\n        });\n\n        return poolData;\n    }\n\n    /**\n     * @notice Returns the metadata of VToken\n     * @param vToken The address of vToken\n     * @return VTokenMetadata struct\n     */\n    function vTokenMetadata(VToken vToken) public view returns (VTokenMetadata memory) {\n        uint256 exchangeRateCurrent = vToken.exchangeRateStored();\n        address comptrollerAddress = address(vToken.comptroller());\n        ComptrollerViewInterface comptroller = ComptrollerViewInterface(comptrollerAddress);\n        (bool isListed, uint256 collateralFactorMantissa) = comptroller.markets(address(vToken));\n\n        address underlyingAssetAddress = vToken.underlying();\n        uint256 underlyingDecimals = IERC20Metadata(underlyingAssetAddress).decimals();\n\n        uint256 pausedActions;\n        for (uint8 i; i <= uint8(type(Action).max); ++i) {\n            uint256 paused = ComptrollerInterface(comptrollerAddress).actionPaused(address(vToken), Action(i)) ? 1 : 0;\n            pausedActions |= paused << i;\n        }\n\n        return\n            VTokenMetadata({\n                vToken: address(vToken),\n                exchangeRateCurrent: exchangeRateCurrent,\n                supplyRatePerBlock: vToken.supplyRatePerBlock(),\n                borrowRatePerBlock: vToken.borrowRatePerBlock(),\n                reserveFactorMantissa: vToken.reserveFactorMantissa(),\n                supplyCaps: comptroller.supplyCaps(address(vToken)),\n                borrowCaps: comptroller.borrowCaps(address(vToken)),\n                totalBorrows: vToken.totalBorrows(),\n                totalReserves: vToken.totalReserves(),\n                totalSupply: vToken.totalSupply(),\n                totalCash: vToken.getCash(),\n                isListed: isListed,\n                collateralFactorMantissa: collateralFactorMantissa,\n                underlyingAssetAddress: underlyingAssetAddress,\n                vTokenDecimals: vToken.decimals(),\n                underlyingDecimals: underlyingDecimals,\n                pausedActions: pausedActions\n            });\n    }\n\n    /**\n     * @notice Returns the metadata of all VTokens\n     * @param vTokens The list of vToken addresses\n     * @return An array of VTokenMetadata structs\n     */\n    function vTokenMetadataAll(VToken[] memory vTokens) public view returns (VTokenMetadata[] memory) {\n        uint256 vTokenCount = vTokens.length;\n        VTokenMetadata[] memory res = new VTokenMetadata[](vTokenCount);\n        for (uint256 i; i < vTokenCount; ++i) {\n            res[i] = vTokenMetadata(vTokens[i]);\n        }\n        return res;\n    }\n\n    /**\n     * @notice Returns the price data for the underlying asset of the specified vToken\n     * @param vToken vToken address\n     * @return The price data for each asset\n     */\n    function vTokenUnderlyingPrice(VToken vToken) public view returns (VTokenUnderlyingPrice memory) {\n        ComptrollerViewInterface comptroller = ComptrollerViewInterface(address(vToken.comptroller()));\n        ResilientOracleInterface priceOracle = comptroller.oracle();\n\n        return\n            VTokenUnderlyingPrice({\n                vToken: address(vToken),\n                underlyingPrice: priceOracle.getUnderlyingPrice(address(vToken))\n            });\n    }\n\n    function _calculateNotDistributedAwards(\n        address account,\n        VToken[] memory markets,\n        RewardsDistributor rewardsDistributor\n    ) internal view returns (PendingReward[] memory) {\n        PendingReward[] memory pendingRewards = new PendingReward[](markets.length);\n        for (uint256 i; i < markets.length; ++i) {\n            // Market borrow and supply state we will modify update in-memory, in order to not modify storage\n            RewardTokenState memory borrowState;\n            (borrowState.index, borrowState.block, borrowState.lastRewardingBlock) = rewardsDistributor\n                .rewardTokenBorrowState(address(markets[i]));\n            RewardTokenState memory supplyState;\n            (supplyState.index, supplyState.block, supplyState.lastRewardingBlock) = rewardsDistributor\n                .rewardTokenSupplyState(address(markets[i]));\n            Exp memory marketBorrowIndex = Exp({ mantissa: markets[i].borrowIndex() });\n\n            // Update market supply and borrow index in-memory\n            updateMarketBorrowIndex(address(markets[i]), rewardsDistributor, borrowState, marketBorrowIndex);\n            updateMarketSupplyIndex(address(markets[i]), rewardsDistributor, supplyState);\n\n            // Calculate pending rewards\n            uint256 borrowReward = calculateBorrowerReward(\n                address(markets[i]),\n                rewardsDistributor,\n                account,\n                borrowState,\n                marketBorrowIndex\n            );\n            uint256 supplyReward = calculateSupplierReward(\n                address(markets[i]),\n                rewardsDistributor,\n                account,\n                supplyState\n            );\n\n            PendingReward memory pendingReward;\n            pendingReward.vTokenAddress = address(markets[i]);\n            pendingReward.amount = borrowReward + supplyReward;\n            pendingRewards[i] = pendingReward;\n        }\n        return pendingRewards;\n    }\n\n    function updateMarketBorrowIndex(\n        address vToken,\n        RewardsDistributor rewardsDistributor,\n        RewardTokenState memory borrowState,\n        Exp memory marketBorrowIndex\n    ) internal view {\n        uint256 borrowSpeed = rewardsDistributor.rewardTokenBorrowSpeeds(vToken);\n        uint256 blockNumber = block.number;\n\n        if (borrowState.lastRewardingBlock > 0 && blockNumber > borrowState.lastRewardingBlock) {\n            blockNumber = borrowState.lastRewardingBlock;\n        }\n\n        uint256 deltaBlocks = sub_(blockNumber, uint256(borrowState.block));\n        if (deltaBlocks > 0 && borrowSpeed > 0) {\n            // Remove the total earned interest rate since the opening of the market from total borrows\n            uint256 borrowAmount = div_(VToken(vToken).totalBorrows(), marketBorrowIndex);\n            uint256 tokensAccrued = mul_(deltaBlocks, borrowSpeed);\n            Double memory ratio = borrowAmount > 0 ? fraction(tokensAccrued, borrowAmount) : Double({ mantissa: 0 });\n            Double memory index = add_(Double({ mantissa: borrowState.index }), ratio);\n            borrowState.index = safe224(index.mantissa, \"new index overflows\");\n            borrowState.block = safe32(blockNumber, \"block number overflows\");\n        } else if (deltaBlocks > 0) {\n            borrowState.block = safe32(blockNumber, \"block number overflows\");\n        }\n    }\n\n    function updateMarketSupplyIndex(\n        address vToken,\n        RewardsDistributor rewardsDistributor,\n        RewardTokenState memory supplyState\n    ) internal view {\n        uint256 supplySpeed = rewardsDistributor.rewardTokenSupplySpeeds(vToken);\n        uint256 blockNumber = block.number;\n\n        if (supplyState.lastRewardingBlock > 0 && blockNumber > supplyState.lastRewardingBlock) {\n            blockNumber = supplyState.lastRewardingBlock;\n        }\n\n        uint256 deltaBlocks = sub_(blockNumber, uint256(supplyState.block));\n        if (deltaBlocks > 0 && supplySpeed > 0) {\n            uint256 supplyTokens = VToken(vToken).totalSupply();\n            uint256 tokensAccrued = mul_(deltaBlocks, supplySpeed);\n            Double memory ratio = supplyTokens > 0 ? fraction(tokensAccrued, supplyTokens) : Double({ mantissa: 0 });\n            Double memory index = add_(Double({ mantissa: supplyState.index }), ratio);\n            supplyState.index = safe224(index.mantissa, \"new index overflows\");\n            supplyState.block = safe32(blockNumber, \"block number overflows\");\n        } else if (deltaBlocks > 0) {\n            supplyState.block = safe32(blockNumber, \"block number overflows\");\n        }\n    }\n\n    function calculateBorrowerReward(\n        address vToken,\n        RewardsDistributor rewardsDistributor,\n        address borrower,\n        RewardTokenState memory borrowState,\n        Exp memory marketBorrowIndex\n    ) internal view returns (uint256) {\n        Double memory borrowIndex = Double({ mantissa: borrowState.index });\n        Double memory borrowerIndex = Double({\n            mantissa: rewardsDistributor.rewardTokenBorrowerIndex(vToken, borrower)\n        });\n        if (borrowerIndex.mantissa == 0 && borrowIndex.mantissa >= rewardsDistributor.INITIAL_INDEX()) {\n            // Covers the case where users borrowed tokens before the market's borrow state index was set\n            borrowerIndex.mantissa = rewardsDistributor.INITIAL_INDEX();\n        }\n        Double memory deltaIndex = sub_(borrowIndex, borrowerIndex);\n        uint256 borrowerAmount = div_(VToken(vToken).borrowBalanceStored(borrower), marketBorrowIndex);\n        uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex);\n        return borrowerDelta;\n    }\n\n    function calculateSupplierReward(\n        address vToken,\n        RewardsDistributor rewardsDistributor,\n        address supplier,\n        RewardTokenState memory supplyState\n    ) internal view returns (uint256) {\n        Double memory supplyIndex = Double({ mantissa: supplyState.index });\n        Double memory supplierIndex = Double({\n            mantissa: rewardsDistributor.rewardTokenSupplierIndex(vToken, supplier)\n        });\n        if (supplierIndex.mantissa == 0 && supplyIndex.mantissa >= rewardsDistributor.INITIAL_INDEX()) {\n            // Covers the case where users supplied tokens before the market's supply state index was set\n            supplierIndex.mantissa = rewardsDistributor.INITIAL_INDEX();\n        }\n        Double memory deltaIndex = sub_(supplyIndex, supplierIndex);\n        uint256 supplierTokens = VToken(vToken).balanceOf(supplier);\n        uint256 supplierDelta = mul_(supplierTokens, deltaIndex);\n        return supplierDelta;\n    }\n}\n"
    },
    "contracts/Lens/PoolLens.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { ExponentialNoError } from \"../ExponentialNoError.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { Action, ComptrollerInterface, ComptrollerViewInterface } from \"../ComptrollerInterface.sol\";\nimport { PoolRegistryInterface } from \"../Pool/PoolRegistryInterface.sol\";\nimport { PoolRegistry } from \"../Pool/PoolRegistry.sol\";\nimport { RewardsDistributor } from \"../Rewards/RewardsDistributor.sol\";\nimport { TimeManagerV8 } from \"@venusprotocol/solidity-utilities/contracts/TimeManagerV8.sol\";\n\n/**\n * @title PoolLens\n * @author Venus\n * @notice The `PoolLens` contract is designed to retrieve important information for each registered pool. A list of essential information\n * for all pools within the lending protocol can be acquired through the function `getAllPools()`. Additionally, the following records can be\n * looked up for specific pools and markets:\n- the vToken balance of a given user;\n- the pool data (oracle address, associated vToken, liquidation incentive, etc) of a pool via its associated comptroller address;\n- the vToken address in a pool for a given asset;\n- a list of all pools that support an asset;\n- the underlying asset price of a vToken;\n- the metadata (exchange/borrow/supply rate, total supply, collateral factor, etc) of any vToken.\n */\ncontract PoolLens is ExponentialNoError, TimeManagerV8 {\n    /**\n     * @dev Struct for PoolDetails.\n     */\n    struct PoolData {\n        string name;\n        address creator;\n        address comptroller;\n        uint256 blockPosted;\n        uint256 timestampPosted;\n        string category;\n        string logoURL;\n        string description;\n        address priceOracle;\n        uint256 closeFactor;\n        uint256 liquidationIncentive;\n        uint256 minLiquidatableCollateral;\n        VTokenMetadata[] vTokens;\n    }\n\n    /**\n     * @dev Struct for VToken.\n     */\n    struct VTokenMetadata {\n        address vToken;\n        uint256 exchangeRateCurrent;\n        uint256 supplyRatePerBlockOrTimestamp;\n        uint256 borrowRatePerBlockOrTimestamp;\n        uint256 reserveFactorMantissa;\n        uint256 supplyCaps;\n        uint256 borrowCaps;\n        uint256 totalBorrows;\n        uint256 totalReserves;\n        uint256 totalSupply;\n        uint256 totalCash;\n        bool isListed;\n        uint256 collateralFactorMantissa;\n        address underlyingAssetAddress;\n        uint256 vTokenDecimals;\n        uint256 underlyingDecimals;\n        uint256 pausedActions;\n    }\n\n    /**\n     * @dev Struct for VTokenBalance.\n     */\n    struct VTokenBalances {\n        address vToken;\n        uint256 balanceOf;\n        uint256 borrowBalanceCurrent;\n        uint256 balanceOfUnderlying;\n        uint256 tokenBalance;\n        uint256 tokenAllowance;\n    }\n\n    /**\n     * @dev Struct for underlyingPrice of VToken.\n     */\n    struct VTokenUnderlyingPrice {\n        address vToken;\n        uint256 underlyingPrice;\n    }\n\n    /**\n     * @dev Struct with pending reward info for a market.\n     */\n    struct PendingReward {\n        address vTokenAddress;\n        uint256 amount;\n    }\n\n    /**\n     * @dev Struct with reward distribution totals for a single reward token and distributor.\n     */\n    struct RewardSummary {\n        address distributorAddress;\n        address rewardTokenAddress;\n        uint256 totalRewards;\n        PendingReward[] pendingRewards;\n    }\n\n    /**\n     * @dev Struct used in RewardDistributor to save last updated market state.\n     */\n    struct RewardTokenState {\n        // The market's last updated rewardTokenBorrowIndex or rewardTokenSupplyIndex\n        uint224 index;\n        // The block number or timestamp the index was last updated at\n        uint256 blockOrTimestamp;\n        // The block number or timestamp at which to stop rewards\n        uint256 lastRewardingBlockOrTimestamp;\n    }\n\n    /**\n     * @dev Struct with bad debt of a market denominated\n     */\n    struct BadDebt {\n        address vTokenAddress;\n        uint256 badDebtUsd;\n    }\n\n    /**\n     * @dev Struct with bad debt total denominated in usd for a pool and an array of BadDebt structs for each market\n     */\n    struct BadDebtSummary {\n        address comptroller;\n        uint256 totalBadDebtUsd;\n        BadDebt[] badDebts;\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\n    /**\n     * @notice Queries the user's supply/borrow balances in vTokens\n     * @param vTokens The list of vToken addresses\n     * @param account The user Account\n     * @return A list of structs containing balances data\n     */\n    function vTokenBalancesAll(VToken[] calldata vTokens, address account) external returns (VTokenBalances[] memory) {\n        uint256 vTokenCount = vTokens.length;\n        VTokenBalances[] memory res = new VTokenBalances[](vTokenCount);\n        for (uint256 i; i < vTokenCount; ++i) {\n            res[i] = vTokenBalances(vTokens[i], account);\n        }\n        return res;\n    }\n\n    /**\n     * @notice Queries all pools with addtional details for each of them\n     * @dev This function is not designed to be called in a transaction: it is too gas-intensive\n     * @param poolRegistryAddress The address of the PoolRegistry contract\n     * @return Arrays of all Venus pools' data\n     */\n    function getAllPools(address poolRegistryAddress) external view returns (PoolData[] memory) {\n        PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n        PoolRegistry.VenusPool[] memory venusPools = poolRegistryInterface.getAllPools();\n        uint256 poolLength = venusPools.length;\n\n        PoolData[] memory poolDataItems = new PoolData[](poolLength);\n\n        for (uint256 i; i < poolLength; ++i) {\n            PoolRegistry.VenusPool memory venusPool = venusPools[i];\n            PoolData memory poolData = getPoolDataFromVenusPool(poolRegistryAddress, venusPool);\n            poolDataItems[i] = poolData;\n        }\n\n        return poolDataItems;\n    }\n\n    /**\n     * @notice Queries the details of a pool identified by Comptroller address\n     * @param poolRegistryAddress The address of the PoolRegistry contract\n     * @param comptroller The Comptroller implementation address\n     * @return PoolData structure containing the details of the pool\n     */\n    function getPoolByComptroller(\n        address poolRegistryAddress,\n        address comptroller\n    ) external view returns (PoolData memory) {\n        PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n        return getPoolDataFromVenusPool(poolRegistryAddress, poolRegistryInterface.getPoolByComptroller(comptroller));\n    }\n\n    /**\n     * @notice Returns vToken holding the specified underlying asset in the specified pool\n     * @param poolRegistryAddress The address of the PoolRegistry contract\n     * @param comptroller The pool comptroller\n     * @param asset The underlyingAsset of VToken\n     * @return Address of the vToken\n     */\n    function getVTokenForAsset(\n        address poolRegistryAddress,\n        address comptroller,\n        address asset\n    ) external view returns (address) {\n        PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n        return poolRegistryInterface.getVTokenForAsset(comptroller, asset);\n    }\n\n    /**\n     * @notice Returns all pools that support the specified underlying asset\n     * @param poolRegistryAddress The address of the PoolRegistry contract\n     * @param asset The underlying asset of vToken\n     * @return A list of Comptroller contracts\n     */\n    function getPoolsSupportedByAsset(\n        address poolRegistryAddress,\n        address asset\n    ) external view returns (address[] memory) {\n        PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n        return poolRegistryInterface.getPoolsSupportedByAsset(asset);\n    }\n\n    /**\n     * @notice Returns the price data for the underlying assets of the specified vTokens\n     * @param vTokens The list of vToken addresses\n     * @return An array containing the price data for each asset\n     */\n    function vTokenUnderlyingPriceAll(\n        VToken[] calldata vTokens\n    ) external view returns (VTokenUnderlyingPrice[] memory) {\n        uint256 vTokenCount = vTokens.length;\n        VTokenUnderlyingPrice[] memory res = new VTokenUnderlyingPrice[](vTokenCount);\n        for (uint256 i; i < vTokenCount; ++i) {\n            res[i] = vTokenUnderlyingPrice(vTokens[i]);\n        }\n        return res;\n    }\n\n    /**\n     * @notice Returns the pending rewards for a user for a given pool.\n     * @param account The user account.\n     * @param comptrollerAddress address\n     * @return Pending rewards array\n     */\n    function getPendingRewards(\n        address account,\n        address comptrollerAddress\n    ) external view returns (RewardSummary[] memory) {\n        VToken[] memory markets = ComptrollerInterface(comptrollerAddress).getAllMarkets();\n        RewardsDistributor[] memory rewardsDistributors = ComptrollerViewInterface(comptrollerAddress)\n            .getRewardDistributors();\n        RewardSummary[] memory rewardSummary = new RewardSummary[](rewardsDistributors.length);\n        for (uint256 i; i < rewardsDistributors.length; ++i) {\n            RewardSummary memory reward;\n            reward.distributorAddress = address(rewardsDistributors[i]);\n            reward.rewardTokenAddress = address(rewardsDistributors[i].rewardToken());\n            reward.totalRewards = rewardsDistributors[i].rewardTokenAccrued(account);\n            reward.pendingRewards = _calculateNotDistributedAwards(account, markets, rewardsDistributors[i]);\n            rewardSummary[i] = reward;\n        }\n        return rewardSummary;\n    }\n\n    /**\n     * @notice Returns a summary of a pool's bad debt broken down by market\n     *\n     * @param comptrollerAddress Address of the comptroller\n     *\n     * @return badDebtSummary A struct with comptroller address, total bad debut denominated in usd, and\n     *   a break down of bad debt by market\n     */\n    function getPoolBadDebt(address comptrollerAddress) external view returns (BadDebtSummary memory) {\n        uint256 totalBadDebtUsd;\n\n        // Get every market in the pool\n        ComptrollerViewInterface comptroller = ComptrollerViewInterface(comptrollerAddress);\n        VToken[] memory markets = comptroller.getAllMarkets();\n        ResilientOracleInterface priceOracle = comptroller.oracle();\n\n        BadDebt[] memory badDebts = new BadDebt[](markets.length);\n\n        BadDebtSummary memory badDebtSummary;\n        badDebtSummary.comptroller = comptrollerAddress;\n        badDebtSummary.badDebts = badDebts;\n\n        // // Calculate the bad debt is USD per market\n        for (uint256 i; i < markets.length; ++i) {\n            BadDebt memory badDebt;\n            badDebt.vTokenAddress = address(markets[i]);\n            badDebt.badDebtUsd =\n                (VToken(address(markets[i])).badDebt() * priceOracle.getUnderlyingPrice(address(markets[i]))) /\n                EXP_SCALE;\n            badDebtSummary.badDebts[i] = badDebt;\n            totalBadDebtUsd = totalBadDebtUsd + badDebt.badDebtUsd;\n        }\n\n        badDebtSummary.totalBadDebtUsd = totalBadDebtUsd;\n\n        return badDebtSummary;\n    }\n\n    /**\n     * @notice Queries the user's supply/borrow balances in the specified vToken\n     * @param vToken vToken address\n     * @param account The user Account\n     * @return A struct containing the balances data\n     */\n    function vTokenBalances(VToken vToken, address account) public returns (VTokenBalances memory) {\n        uint256 balanceOf = vToken.balanceOf(account);\n        uint256 borrowBalanceCurrent = vToken.borrowBalanceCurrent(account);\n        uint256 balanceOfUnderlying = vToken.balanceOfUnderlying(account);\n        uint256 tokenBalance;\n        uint256 tokenAllowance;\n\n        IERC20 underlying = IERC20(vToken.underlying());\n        tokenBalance = underlying.balanceOf(account);\n        tokenAllowance = underlying.allowance(account, address(vToken));\n\n        return\n            VTokenBalances({\n                vToken: address(vToken),\n                balanceOf: balanceOf,\n                borrowBalanceCurrent: borrowBalanceCurrent,\n                balanceOfUnderlying: balanceOfUnderlying,\n                tokenBalance: tokenBalance,\n                tokenAllowance: tokenAllowance\n            });\n    }\n\n    /**\n     * @notice Queries additional information for the pool\n     * @param poolRegistryAddress Address of the PoolRegistry\n     * @param venusPool The VenusPool Object from PoolRegistry\n     * @return Enriched PoolData\n     */\n    function getPoolDataFromVenusPool(\n        address poolRegistryAddress,\n        PoolRegistry.VenusPool memory venusPool\n    ) public view returns (PoolData memory) {\n        // Get tokens in the Pool\n        ComptrollerInterface comptrollerInstance = ComptrollerInterface(venusPool.comptroller);\n\n        VToken[] memory vTokens = comptrollerInstance.getAllMarkets();\n\n        VTokenMetadata[] memory vTokenMetadataItems = vTokenMetadataAll(vTokens);\n\n        PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n\n        PoolRegistry.VenusPoolMetaData memory venusPoolMetaData = poolRegistryInterface.getVenusPoolMetadata(\n            venusPool.comptroller\n        );\n\n        ComptrollerViewInterface comptrollerViewInstance = ComptrollerViewInterface(venusPool.comptroller);\n\n        PoolData memory poolData = PoolData({\n            name: venusPool.name,\n            creator: venusPool.creator,\n            comptroller: venusPool.comptroller,\n            blockPosted: venusPool.blockPosted,\n            timestampPosted: venusPool.timestampPosted,\n            category: venusPoolMetaData.category,\n            logoURL: venusPoolMetaData.logoURL,\n            description: venusPoolMetaData.description,\n            vTokens: vTokenMetadataItems,\n            priceOracle: address(comptrollerViewInstance.oracle()),\n            closeFactor: comptrollerViewInstance.closeFactorMantissa(),\n            liquidationIncentive: comptrollerViewInstance.liquidationIncentiveMantissa(),\n            minLiquidatableCollateral: comptrollerViewInstance.minLiquidatableCollateral()\n        });\n\n        return poolData;\n    }\n\n    /**\n     * @notice Returns the metadata of VToken\n     * @param vToken The address of vToken\n     * @return VTokenMetadata struct\n     */\n    function vTokenMetadata(VToken vToken) public view returns (VTokenMetadata memory) {\n        uint256 exchangeRateCurrent = vToken.exchangeRateStored();\n        address comptrollerAddress = address(vToken.comptroller());\n        ComptrollerViewInterface comptroller = ComptrollerViewInterface(comptrollerAddress);\n        (bool isListed, uint256 collateralFactorMantissa) = comptroller.markets(address(vToken));\n\n        address underlyingAssetAddress = vToken.underlying();\n        uint256 underlyingDecimals = IERC20Metadata(underlyingAssetAddress).decimals();\n\n        uint256 pausedActions;\n        for (uint8 i; i <= uint8(type(Action).max); ++i) {\n            uint256 paused = ComptrollerInterface(comptrollerAddress).actionPaused(address(vToken), Action(i)) ? 1 : 0;\n            pausedActions |= paused << i;\n        }\n\n        return\n            VTokenMetadata({\n                vToken: address(vToken),\n                exchangeRateCurrent: exchangeRateCurrent,\n                supplyRatePerBlockOrTimestamp: vToken.supplyRatePerBlock(),\n                borrowRatePerBlockOrTimestamp: vToken.borrowRatePerBlock(),\n                reserveFactorMantissa: vToken.reserveFactorMantissa(),\n                supplyCaps: comptroller.supplyCaps(address(vToken)),\n                borrowCaps: comptroller.borrowCaps(address(vToken)),\n                totalBorrows: vToken.totalBorrows(),\n                totalReserves: vToken.totalReserves(),\n                totalSupply: vToken.totalSupply(),\n                totalCash: vToken.getCash(),\n                isListed: isListed,\n                collateralFactorMantissa: collateralFactorMantissa,\n                underlyingAssetAddress: underlyingAssetAddress,\n                vTokenDecimals: vToken.decimals(),\n                underlyingDecimals: underlyingDecimals,\n                pausedActions: pausedActions\n            });\n    }\n\n    /**\n     * @notice Returns the metadata of all VTokens\n     * @param vTokens The list of vToken addresses\n     * @return An array of VTokenMetadata structs\n     */\n    function vTokenMetadataAll(VToken[] memory vTokens) public view returns (VTokenMetadata[] memory) {\n        uint256 vTokenCount = vTokens.length;\n        VTokenMetadata[] memory res = new VTokenMetadata[](vTokenCount);\n        for (uint256 i; i < vTokenCount; ++i) {\n            res[i] = vTokenMetadata(vTokens[i]);\n        }\n        return res;\n    }\n\n    /**\n     * @notice Returns the price data for the underlying asset of the specified vToken\n     * @param vToken vToken address\n     * @return The price data for each asset\n     */\n    function vTokenUnderlyingPrice(VToken vToken) public view returns (VTokenUnderlyingPrice memory) {\n        ComptrollerViewInterface comptroller = ComptrollerViewInterface(address(vToken.comptroller()));\n        ResilientOracleInterface priceOracle = comptroller.oracle();\n\n        return\n            VTokenUnderlyingPrice({\n                vToken: address(vToken),\n                underlyingPrice: priceOracle.getUnderlyingPrice(address(vToken))\n            });\n    }\n\n    function _calculateNotDistributedAwards(\n        address account,\n        VToken[] memory markets,\n        RewardsDistributor rewardsDistributor\n    ) internal view returns (PendingReward[] memory) {\n        PendingReward[] memory pendingRewards = new PendingReward[](markets.length);\n\n        for (uint256 i; i < markets.length; ++i) {\n            // Market borrow and supply state we will modify update in-memory, in order to not modify storage\n            RewardTokenState memory borrowState;\n            RewardTokenState memory supplyState;\n\n            if (isTimeBased) {\n                (\n                    borrowState.index,\n                    borrowState.blockOrTimestamp,\n                    borrowState.lastRewardingBlockOrTimestamp\n                ) = rewardsDistributor.rewardTokenBorrowStateTimeBased(address(markets[i]));\n                (\n                    supplyState.index,\n                    supplyState.blockOrTimestamp,\n                    supplyState.lastRewardingBlockOrTimestamp\n                ) = rewardsDistributor.rewardTokenSupplyStateTimeBased(address(markets[i]));\n            } else {\n                (\n                    borrowState.index,\n                    borrowState.blockOrTimestamp,\n                    borrowState.lastRewardingBlockOrTimestamp\n                ) = rewardsDistributor.rewardTokenBorrowState(address(markets[i]));\n                (\n                    supplyState.index,\n                    supplyState.blockOrTimestamp,\n                    supplyState.lastRewardingBlockOrTimestamp\n                ) = rewardsDistributor.rewardTokenSupplyState(address(markets[i]));\n            }\n\n            Exp memory marketBorrowIndex = Exp({ mantissa: markets[i].borrowIndex() });\n\n            // Update market supply and borrow index in-memory\n            updateMarketBorrowIndex(address(markets[i]), rewardsDistributor, borrowState, marketBorrowIndex);\n            updateMarketSupplyIndex(address(markets[i]), rewardsDistributor, supplyState);\n\n            // Calculate pending rewards\n            uint256 borrowReward = calculateBorrowerReward(\n                address(markets[i]),\n                rewardsDistributor,\n                account,\n                borrowState,\n                marketBorrowIndex\n            );\n            uint256 supplyReward = calculateSupplierReward(\n                address(markets[i]),\n                rewardsDistributor,\n                account,\n                supplyState\n            );\n\n            PendingReward memory pendingReward;\n            pendingReward.vTokenAddress = address(markets[i]);\n            pendingReward.amount = borrowReward + supplyReward;\n            pendingRewards[i] = pendingReward;\n        }\n        return pendingRewards;\n    }\n\n    function updateMarketBorrowIndex(\n        address vToken,\n        RewardsDistributor rewardsDistributor,\n        RewardTokenState memory borrowState,\n        Exp memory marketBorrowIndex\n    ) internal view {\n        uint256 borrowSpeed = rewardsDistributor.rewardTokenBorrowSpeeds(vToken);\n        uint256 blockNumberOrTimestamp = getBlockNumberOrTimestamp();\n\n        if (\n            borrowState.lastRewardingBlockOrTimestamp > 0 &&\n            blockNumberOrTimestamp > borrowState.lastRewardingBlockOrTimestamp\n        ) {\n            blockNumberOrTimestamp = borrowState.lastRewardingBlockOrTimestamp;\n        }\n\n        uint256 deltaBlocksOrTimestamp = sub_(blockNumberOrTimestamp, borrowState.blockOrTimestamp);\n        if (deltaBlocksOrTimestamp > 0 && borrowSpeed > 0) {\n            // Remove the total earned interest rate since the opening of the market from total borrows\n            uint256 borrowAmount = div_(VToken(vToken).totalBorrows(), marketBorrowIndex);\n            uint256 tokensAccrued = mul_(deltaBlocksOrTimestamp, borrowSpeed);\n            Double memory ratio = borrowAmount > 0 ? fraction(tokensAccrued, borrowAmount) : Double({ mantissa: 0 });\n            Double memory index = add_(Double({ mantissa: borrowState.index }), ratio);\n            borrowState.index = safe224(index.mantissa, \"new index overflows\");\n            borrowState.blockOrTimestamp = blockNumberOrTimestamp;\n        } else if (deltaBlocksOrTimestamp > 0) {\n            borrowState.blockOrTimestamp = blockNumberOrTimestamp;\n        }\n    }\n\n    function updateMarketSupplyIndex(\n        address vToken,\n        RewardsDistributor rewardsDistributor,\n        RewardTokenState memory supplyState\n    ) internal view {\n        uint256 supplySpeed = rewardsDistributor.rewardTokenSupplySpeeds(vToken);\n        uint256 blockNumberOrTimestamp = getBlockNumberOrTimestamp();\n\n        if (\n            supplyState.lastRewardingBlockOrTimestamp > 0 &&\n            blockNumberOrTimestamp > supplyState.lastRewardingBlockOrTimestamp\n        ) {\n            blockNumberOrTimestamp = supplyState.lastRewardingBlockOrTimestamp;\n        }\n\n        uint256 deltaBlocksOrTimestamp = sub_(blockNumberOrTimestamp, supplyState.blockOrTimestamp);\n        if (deltaBlocksOrTimestamp > 0 && supplySpeed > 0) {\n            uint256 supplyTokens = VToken(vToken).totalSupply();\n            uint256 tokensAccrued = mul_(deltaBlocksOrTimestamp, supplySpeed);\n            Double memory ratio = supplyTokens > 0 ? fraction(tokensAccrued, supplyTokens) : Double({ mantissa: 0 });\n            Double memory index = add_(Double({ mantissa: supplyState.index }), ratio);\n            supplyState.index = safe224(index.mantissa, \"new index overflows\");\n            supplyState.blockOrTimestamp = blockNumberOrTimestamp;\n        } else if (deltaBlocksOrTimestamp > 0) {\n            supplyState.blockOrTimestamp = blockNumberOrTimestamp;\n        }\n    }\n\n    function calculateBorrowerReward(\n        address vToken,\n        RewardsDistributor rewardsDistributor,\n        address borrower,\n        RewardTokenState memory borrowState,\n        Exp memory marketBorrowIndex\n    ) internal view returns (uint256) {\n        Double memory borrowIndex = Double({ mantissa: borrowState.index });\n        Double memory borrowerIndex = Double({\n            mantissa: rewardsDistributor.rewardTokenBorrowerIndex(vToken, borrower)\n        });\n        if (borrowerIndex.mantissa == 0 && borrowIndex.mantissa >= rewardsDistributor.INITIAL_INDEX()) {\n            // Covers the case where users borrowed tokens before the market's borrow state index was set\n            borrowerIndex.mantissa = rewardsDistributor.INITIAL_INDEX();\n        }\n        Double memory deltaIndex = sub_(borrowIndex, borrowerIndex);\n        uint256 borrowerAmount = div_(VToken(vToken).borrowBalanceStored(borrower), marketBorrowIndex);\n        uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex);\n        return borrowerDelta;\n    }\n\n    function calculateSupplierReward(\n        address vToken,\n        RewardsDistributor rewardsDistributor,\n        address supplier,\n        RewardTokenState memory supplyState\n    ) internal view returns (uint256) {\n        Double memory supplyIndex = Double({ mantissa: supplyState.index });\n        Double memory supplierIndex = Double({\n            mantissa: rewardsDistributor.rewardTokenSupplierIndex(vToken, supplier)\n        });\n        if (supplierIndex.mantissa == 0 && supplyIndex.mantissa >= rewardsDistributor.INITIAL_INDEX()) {\n            // Covers the case where users supplied tokens before the market's supply state index was set\n            supplierIndex.mantissa = rewardsDistributor.INITIAL_INDEX();\n        }\n        Double memory deltaIndex = sub_(supplyIndex, supplierIndex);\n        uint256 supplierTokens = VToken(vToken).balanceOf(supplier);\n        uint256 supplierDelta = mul_(supplierTokens, deltaIndex);\n        return supplierDelta;\n    }\n}\n"
    },
    "contracts/lib/ApproveOrRevert.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.25;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\n\nlibrary ApproveOrRevert {\n    /// @notice Thrown if a contract is unable to approve a transfer\n    error ApproveFailed();\n\n    /// @notice Approves a transfer, ensuring that it is successful. This function supports non-compliant\n    /// tokens like the ones that don't return a boolean value on success. Thus, such approve call supports\n    /// three different kinds of tokens:\n    ///   * Compliant tokens that revert on failure\n    ///   * Compliant tokens that return false on failure\n    ///   * Non-compliant tokens that don't return a value\n    /// @param token The contract address of the token which will be transferred\n    /// @param spender The spender contract address\n    /// @param amount The value of the transfer\n    function approveOrRevert(IERC20Upgradeable token, address spender, uint256 amount) internal {\n        bytes memory callData = abi.encodeCall(token.approve, (spender, amount));\n\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool success, bytes memory result) = address(token).call(callData);\n\n        if (!success || (result.length != 0 && !abi.decode(result, (bool)))) {\n            revert ApproveFailed();\n        }\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/TokenDebtTracker.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.25;\n\nimport { Initializable } from \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\n/**\n * @title TokenDebtTracker\n * @author Venus\n * @notice TokenDebtTracker is an abstract contract that handles transfers _out_ of the inheriting contract.\n * If there is an error transferring out (due to any reason, e.g. the token contract restricted the user from\n * receiving incoming transfers), the amount is recorded as a debt that can be claimed later.\n * @dev Note that the inheriting contract keeps some amount of users' tokens on its balance, so be careful when\n * using balanceOf(address(this))!\n */\nabstract contract TokenDebtTracker is Initializable {\n    using SafeERC20Upgradeable for IERC20Upgradeable;\n\n    /**\n     * @notice Mapping (IERC20Upgradeable token => (address user => uint256 amount)).\n     * Tracks failed transfers: when a token transfer fails, we record the\n     * amount of the transfer, so that the user can redeem this debt later.\n     */\n    mapping(IERC20Upgradeable => mapping(address => uint256)) public tokenDebt;\n\n    /**\n     * @notice Mapping (IERC20Upgradeable token => uint256 amount) shows how many\n     * tokens the contract owes to all users. This is useful for accounting to\n     * understand how much of balanceOf(address(this)) is already owed to users.\n     */\n    mapping(IERC20Upgradeable => uint256) public totalTokenDebt;\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     * @notice Emitted when the contract's debt to the user is increased due to a failed transfer\n     * @param token Token address\n     * @param user User address\n     * @param amount The amount of debt added\n     */\n    event TokenDebtAdded(address indexed token, address indexed user, uint256 amount);\n\n    /**\n     * @notice Emitted when a user claims tokens that the contract owes them\n     * @param token Token address\n     * @param user User address\n     * @param amount The amount transferred\n     */\n    event TokenDebtClaimed(address indexed token, address indexed user, uint256 amount);\n\n    /**\n     * @notice Thrown if the user tries to claim more tokens than they are owed\n     * @param token The token the user is trying to claim\n     * @param owedAmount The amount of tokens the contract owes to the user\n     * @param amount The amount of tokens the user is trying to claim\n     */\n    error InsufficientDebt(address token, address user, uint256 owedAmount, uint256 amount);\n\n    /**\n     * @notice Thrown if trying to transfer more tokens than the contract currently has\n     * @param token The token the contract is trying to transfer\n     * @param recipient The recipient of the transfer\n     * @param amount The amount of tokens the contract is trying to transfer\n     * @param availableBalance The amount of tokens the contract currently has\n     */\n    error InsufficientBalance(address token, address recipient, uint256 amount, uint256 availableBalance);\n\n    /**\n     * @notice Transfers the tokens we owe to msg.sender, if any\n     * @param token The token to claim\n     * @param amount_ The amount of tokens to claim (or max uint256 to claim all)\n     * @custom:error InsufficientDebt The contract doesn't have enough debt to the user\n     */\n    function claimTokenDebt(IERC20Upgradeable token, uint256 amount_) external {\n        uint256 owedAmount = tokenDebt[token][msg.sender];\n        uint256 amount = (amount_ == type(uint256).max ? owedAmount : amount_);\n        if (amount > owedAmount) {\n            revert InsufficientDebt(address(token), msg.sender, owedAmount, amount);\n        }\n        unchecked {\n            // Safe because we revert if amount > owedAmount above\n            tokenDebt[token][msg.sender] = owedAmount - amount;\n        }\n        totalTokenDebt[token] -= amount;\n        emit TokenDebtClaimed(address(token), msg.sender, amount);\n        token.safeTransfer(msg.sender, amount);\n    }\n\n    // solhint-disable-next-line func-name-mixedcase\n    function __TokenDebtTracker_init() internal onlyInitializing {\n        __TokenDebtTracker_init_unchained();\n    }\n\n    // solhint-disable-next-line func-name-mixedcase, no-empty-blocks\n    function __TokenDebtTracker_init_unchained() internal onlyInitializing {}\n\n    /**\n     * @dev Transfers tokens to the recipient if the contract has enough balance, or\n     * records the debt if the transfer fails due to reasons unrelated to the contract's\n     * balance (e.g. if the token forbids transfers to the recipient).\n     * @param token The token to transfer\n     * @param to The recipient of the transfer\n     * @param amount The amount to transfer\n     * @custom:error InsufficientBalance The contract doesn't have enough balance to transfer\n     */\n    function _transferOutOrTrackDebt(IERC20Upgradeable token, address to, uint256 amount) internal {\n        uint256 balance = token.balanceOf(address(this));\n        if (balance < amount) {\n            revert InsufficientBalance(address(token), address(this), amount, balance);\n        }\n        _transferOutOrTrackDebtSkippingBalanceCheck(token, to, amount);\n    }\n\n    /**\n     * @dev Transfers tokens to the recipient, or records the debt if the transfer fails\n     * due to any reason, including insufficient balance.\n     * @param token The token to transfer\n     * @param to The recipient of the transfer\n     * @param amount The amount to transfer\n     */\n    function _transferOutOrTrackDebtSkippingBalanceCheck(IERC20Upgradeable token, address to, uint256 amount) internal {\n        // We can't use safeTransfer here because we can't try-catch internal calls\n        bool success = _tryTransferOut(token, to, amount);\n        if (!success) {\n            tokenDebt[token][to] += amount;\n            totalTokenDebt[token] += amount;\n            emit TokenDebtAdded(address(token), to, amount);\n        }\n    }\n\n    /**\n     * @dev Either transfers tokens to the recepient or returns false. Supports tokens\n     *      thet revert or return false to indicate failure, and the non-compliant ones\n     *      that do not return any value.\n     * @param token The token to transfer\n     * @param to The recipient of the transfer\n     * @param amount The amount to transfer\n     * @return true if the transfer succeeded, false otherwise\n     */\n    function _tryTransferOut(IERC20Upgradeable token, address to, uint256 amount) private returns (bool) {\n        bytes memory callData = abi.encodeCall(token.transfer, (to, amount));\n\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool success, bytes memory returndata) = address(token).call(callData);\n        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;\n    }\n}\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/PoolRegistry.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { PoolRegistryInterface } from \"./PoolRegistryInterface.sol\";\nimport { Comptroller } from \"../Comptroller.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\n\n/**\n * @title PoolRegistry\n * @author Venus\n * @notice The Isolated Pools architecture centers around the `PoolRegistry` contract. The `PoolRegistry` maintains a directory of isolated lending\n * pools and can perform actions like creating and registering new pools, adding new markets to existing pools, setting and updating the pool's required\n * metadata, and providing the getter methods to get information on the pools.\n *\n * Isolated lending has three main components: PoolRegistry, pools, and markets. The PoolRegistry is responsible for managing pools.\n * It can create new pools, update pool metadata and manage markets within pools. PoolRegistry contains getter methods to get the details of\n * any existing pool like `getVTokenForAsset` and `getPoolsSupportedByAsset`. It also contains methods for updating pool metadata (`updatePoolMetadata`)\n * and setting pool name (`setPoolName`).\n *\n * The directory of pools is managed through two mappings: `_poolByComptroller` which is a hashmap with the comptroller address as the key and `VenusPool` as\n * the value and `_poolsByID` which is an array of comptroller addresses. Individual pools can be accessed by calling `getPoolByComptroller` with the pool's\n * comptroller address. `_poolsByID` is used to iterate through all of the pools.\n *\n * PoolRegistry also contains a map of asset addresses called `_supportedPools` that maps to an array of assets suppored by each pool. This array of pools by\n * asset is retrieved by calling `getPoolsSupportedByAsset`.\n *\n * PoolRegistry registers new isolated pools in the directory with the `createRegistryPool` method. Isolated pools are composed of independent markets with\n * specific assets and custom risk management configurations according to their markets.\n */\ncontract PoolRegistry is Ownable2StepUpgradeable, AccessControlledV8, PoolRegistryInterface {\n    using SafeERC20Upgradeable for IERC20Upgradeable;\n\n    struct AddMarketInput {\n        VToken vToken;\n        uint256 collateralFactor;\n        uint256 liquidationThreshold;\n        uint256 initialSupply;\n        address vTokenReceiver;\n        uint256 supplyCap;\n        uint256 borrowCap;\n    }\n\n    uint256 internal constant MAX_POOL_NAME_LENGTH = 100;\n\n    /**\n     * @notice Maps pool's comptroller address to metadata.\n     */\n    mapping(address => VenusPoolMetaData) public metadata;\n\n    /**\n     * @dev Maps pool ID to pool's comptroller address\n     */\n    mapping(uint256 => address) private _poolsByID;\n\n    /**\n     * @dev Total number of pools created.\n     */\n    uint256 private _numberOfPools;\n\n    /**\n     * @dev Maps comptroller address to Venus pool Index.\n     */\n    mapping(address => VenusPool) private _poolByComptroller;\n\n    /**\n     * @dev Maps pool's comptroller address to asset to vToken.\n     */\n    mapping(address => mapping(address => address)) private _vTokens;\n\n    /**\n     * @dev Maps asset to list of supported pools.\n     */\n    mapping(address => address[]) private _supportedPools;\n\n    /**\n     * @notice Emitted when a new Venus pool is added to the directory.\n     */\n    event PoolRegistered(address indexed comptroller, VenusPool pool);\n\n    /**\n     * @notice Emitted when a pool name is set.\n     */\n    event PoolNameSet(address indexed comptroller, string oldName, string newName);\n\n    /**\n     * @notice Emitted when a pool metadata is updated.\n     */\n    event PoolMetadataUpdated(\n        address indexed comptroller,\n        VenusPoolMetaData oldMetadata,\n        VenusPoolMetaData newMetadata\n    );\n\n    /**\n     * @notice Emitted when a Market is added to the pool.\n     */\n    event MarketAdded(address indexed comptroller, address indexed vTokenAddress);\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    /**\n     * @notice Initializes the deployer to owner\n     * @param accessControlManager_ AccessControlManager contract address\n     */\n    function initialize(address accessControlManager_) external initializer {\n        __Ownable2Step_init();\n        __AccessControlled_init_unchained(accessControlManager_);\n    }\n\n    /**\n     * @notice Adds a new Venus pool to the directory\n     * @dev Price oracle must be configured before adding a pool\n     * @param name The name of the pool\n     * @param comptroller Pool's Comptroller contract\n     * @param closeFactor The pool's close factor (scaled by 1e18)\n     * @param liquidationIncentive The pool's liquidation incentive (scaled by 1e18)\n     * @param minLiquidatableCollateral Minimal collateral for regular (non-batch) liquidations flow\n     * @return index The index of the registered Venus pool\n     * @custom:error ZeroAddressNotAllowed is thrown when Comptroller address is zero\n     * @custom:error ZeroAddressNotAllowed is thrown when price oracle address is zero\n     */\n    function addPool(\n        string calldata name,\n        Comptroller comptroller,\n        uint256 closeFactor,\n        uint256 liquidationIncentive,\n        uint256 minLiquidatableCollateral\n    ) external virtual returns (uint256 index) {\n        _checkAccessAllowed(\"addPool(string,address,uint256,uint256,uint256)\");\n        // Input validation\n        ensureNonzeroAddress(address(comptroller));\n        ensureNonzeroAddress(address(comptroller.oracle()));\n\n        uint256 poolId = _registerPool(name, address(comptroller));\n\n        // Set Venus pool parameters\n        comptroller.setCloseFactor(closeFactor);\n        comptroller.setLiquidationIncentive(liquidationIncentive);\n        comptroller.setMinLiquidatableCollateral(minLiquidatableCollateral);\n\n        return poolId;\n    }\n\n    /**\n     * @notice Add a market to an existing pool and then mint to provide initial supply\n     * @param input The structure describing the parameters for adding a market to a pool\n     * @custom:error ZeroAddressNotAllowed is thrown when vToken address is zero\n     * @custom:error ZeroAddressNotAllowed is thrown when vTokenReceiver address is zero\n     */\n    function addMarket(AddMarketInput memory input) external {\n        _checkAccessAllowed(\"addMarket(AddMarketInput)\");\n        ensureNonzeroAddress(address(input.vToken));\n        ensureNonzeroAddress(input.vTokenReceiver);\n        require(input.initialSupply > 0, \"PoolRegistry: initialSupply is zero\");\n\n        VToken vToken = input.vToken;\n        address vTokenAddress = address(vToken);\n        address comptrollerAddress = address(vToken.comptroller());\n        Comptroller comptroller = Comptroller(comptrollerAddress);\n        address underlyingAddress = vToken.underlying();\n        IERC20Upgradeable underlying = IERC20Upgradeable(underlyingAddress);\n\n        require(_poolByComptroller[comptrollerAddress].creator != address(0), \"PoolRegistry: Pool not registered\");\n        // solhint-disable-next-line reason-string\n        require(\n            _vTokens[comptrollerAddress][underlyingAddress] == address(0),\n            \"PoolRegistry: Market already added for asset comptroller combination\"\n        );\n\n        comptroller.supportMarket(vToken);\n        comptroller.setCollateralFactor(vToken, input.collateralFactor, input.liquidationThreshold);\n\n        uint256[] memory newSupplyCaps = new uint256[](1);\n        uint256[] memory newBorrowCaps = new uint256[](1);\n        VToken[] memory vTokens = new VToken[](1);\n\n        newSupplyCaps[0] = input.supplyCap;\n        newBorrowCaps[0] = input.borrowCap;\n        vTokens[0] = vToken;\n\n        comptroller.setMarketSupplyCaps(vTokens, newSupplyCaps);\n        comptroller.setMarketBorrowCaps(vTokens, newBorrowCaps);\n\n        _vTokens[comptrollerAddress][underlyingAddress] = vTokenAddress;\n        _supportedPools[underlyingAddress].push(comptrollerAddress);\n\n        uint256 amountToSupply = _transferIn(underlying, msg.sender, input.initialSupply);\n        underlying.forceApprove(vTokenAddress, 0);\n        underlying.forceApprove(vTokenAddress, amountToSupply);\n        vToken.mintBehalf(input.vTokenReceiver, amountToSupply);\n\n        emit MarketAdded(comptrollerAddress, vTokenAddress);\n    }\n\n    /**\n     * @notice Modify existing Venus pool name\n     * @param comptroller Pool's Comptroller\n     * @param name New pool name\n     */\n    function setPoolName(address comptroller, string calldata name) external {\n        _checkAccessAllowed(\"setPoolName(address,string)\");\n        _ensureValidName(name);\n        VenusPool storage pool = _poolByComptroller[comptroller];\n        string memory oldName = pool.name;\n        pool.name = name;\n        emit PoolNameSet(comptroller, oldName, name);\n    }\n\n    /**\n     * @notice Update metadata of an existing pool\n     * @param comptroller Pool's Comptroller\n     * @param metadata_ New pool metadata\n     */\n    function updatePoolMetadata(address comptroller, VenusPoolMetaData calldata metadata_) external {\n        _checkAccessAllowed(\"updatePoolMetadata(address,VenusPoolMetaData)\");\n        VenusPoolMetaData memory oldMetadata = metadata[comptroller];\n        metadata[comptroller] = metadata_;\n        emit PoolMetadataUpdated(comptroller, oldMetadata, metadata_);\n    }\n\n    /**\n     * @notice Returns arrays of all Venus pools' data\n     * @dev This function is not designed to be called in a transaction: it is too gas-intensive\n     * @return A list of all pools within PoolRegistry, with details for each pool\n     */\n    function getAllPools() external view override returns (VenusPool[] memory) {\n        uint256 numberOfPools_ = _numberOfPools; // storage load to save gas\n        VenusPool[] memory _pools = new VenusPool[](numberOfPools_);\n        for (uint256 i = 1; i <= numberOfPools_; ++i) {\n            address comptroller = _poolsByID[i];\n            _pools[i - 1] = (_poolByComptroller[comptroller]);\n        }\n        return _pools;\n    }\n\n    /**\n     * @param comptroller The comptroller proxy address associated to the pool\n     * @return  Returns Venus pool\n     */\n    function getPoolByComptroller(address comptroller) external view override returns (VenusPool memory) {\n        return _poolByComptroller[comptroller];\n    }\n\n    /**\n     * @param comptroller comptroller of Venus pool\n     * @return Returns Metadata of Venus pool\n     */\n    function getVenusPoolMetadata(address comptroller) external view override returns (VenusPoolMetaData memory) {\n        return metadata[comptroller];\n    }\n\n    function getVTokenForAsset(address comptroller, address asset) external view override returns (address) {\n        return _vTokens[comptroller][asset];\n    }\n\n    function getPoolsSupportedByAsset(address asset) external view override returns (address[] memory) {\n        return _supportedPools[asset];\n    }\n\n    /**\n     * @dev Adds a new Venus pool to the directory (without checking msg.sender).\n     * @param name The name of the pool\n     * @param comptroller The pool's Comptroller proxy contract address\n     * @return The index of the registered Venus pool\n     */\n    function _registerPool(string calldata name, address comptroller) internal returns (uint256) {\n        VenusPool storage storedPool = _poolByComptroller[comptroller];\n\n        require(storedPool.creator == address(0), \"PoolRegistry: Pool already exists in the directory.\");\n        _ensureValidName(name);\n\n        ++_numberOfPools;\n        uint256 numberOfPools_ = _numberOfPools; // cache on stack to save storage read gas\n\n        VenusPool memory pool = VenusPool(name, msg.sender, comptroller, block.number, block.timestamp);\n\n        _poolsByID[numberOfPools_] = comptroller;\n        _poolByComptroller[comptroller] = pool;\n\n        emit PoolRegistered(comptroller, pool);\n        return numberOfPools_;\n    }\n\n    function _transferIn(IERC20Upgradeable token, address from, uint256 amount) internal returns (uint256) {\n        uint256 balanceBefore = token.balanceOf(address(this));\n        token.safeTransferFrom(from, address(this), amount);\n        uint256 balanceAfter = token.balanceOf(address(this));\n        return balanceAfter - balanceBefore;\n    }\n\n    function _ensureValidName(string calldata name) internal pure {\n        require(bytes(name).length <= MAX_POOL_NAME_LENGTH, \"Pool's name is too large\");\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/Shortfall/IRiskFund.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\n/**\n * @title IRiskFund\n * @author Venus\n * @notice Interface implemented by `RiskFund`.\n */\ninterface IRiskFund {\n    function transferReserveForAuction(address comptroller, uint256 amount) external returns (uint256);\n\n    function convertibleBaseAsset() external view returns (address);\n\n    function getPoolsBaseAssetReserves(address comptroller) external view returns (uint256);\n}\n"
    },
    "contracts/Shortfall/Shortfall.sol": {
      "content": "/// @notice  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 { ReentrancyGuardUpgradeable } from \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\nimport { ensureNonzeroAddress, ensureNonzeroValue } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\nimport { TimeManagerV8 } from \"@venusprotocol/solidity-utilities/contracts/TimeManagerV8.sol\";\n\nimport { VToken } from \"../VToken.sol\";\nimport { ComptrollerInterface, ComptrollerViewInterface } from \"../ComptrollerInterface.sol\";\nimport { IRiskFund } from \"./IRiskFund.sol\";\nimport { PoolRegistry } from \"../Pool/PoolRegistry.sol\";\nimport { PoolRegistryInterface } from \"../Pool/PoolRegistryInterface.sol\";\nimport { TokenDebtTracker } from \"../lib/TokenDebtTracker.sol\";\nimport { ShortfallStorage } from \"./ShortfallStorage.sol\";\nimport { EXP_SCALE } from \"../lib/constants.sol\";\n\n/**\n * @title Shortfall\n * @author Venus\n * @notice Shortfall is an auction contract designed to auction off the `convertibleBaseAsset` accumulated in `RiskFund`. The `convertibleBaseAsset`\n * is auctioned in exchange for users paying off the pool's bad debt. An auction can be started by anyone once a pool's bad debt has reached a minimum value.\n * This value is set and can be changed by the authorized accounts. If the pool’s bad debt exceeds the risk fund plus a 10% incentive, then the auction winner\n * is determined by who will pay off the largest percentage of the pool's bad debt. The auction winner then exchanges for the entire risk fund. Otherwise,\n * if the risk fund covers the pool's bad debt plus the 10% incentive, then the auction winner is determined by who will take the smallest percentage of the\n * risk fund in exchange for paying off all the pool's bad debt.\n */\ncontract Shortfall is\n    Ownable2StepUpgradeable,\n    AccessControlledV8,\n    ReentrancyGuardUpgradeable,\n    TokenDebtTracker,\n    ShortfallStorage,\n    TimeManagerV8\n{\n    using SafeERC20Upgradeable for IERC20Upgradeable;\n\n    /// @dev Max basis points i.e., 100%\n    uint256 private constant MAX_BPS = 10000;\n\n    // @notice Default incentive basis points (BPS) for the auction participants, set to 10%\n    uint256 private constant DEFAULT_INCENTIVE_BPS = 1000;\n\n    // @notice Default block or timestamp limit for the next bidder to place a bid\n    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n    uint256 private immutable DEFAULT_NEXT_BIDDER_BLOCK_OR_TIMESTAMP_LIMIT;\n\n    // @notice Default number of blocks or seconds to wait for the first bidder before starting the auction\n    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n    uint256 private immutable DEFAULT_WAIT_FOR_FIRST_BIDDER;\n\n    /// @notice Emitted when a auction starts\n    event AuctionStarted(\n        address indexed comptroller,\n        uint256 auctionStartBlockOrTimestamp,\n        AuctionType auctionType,\n        VToken[] markets,\n        uint256[] marketsDebt,\n        uint256 seizedRiskFund,\n        uint256 startBidBps\n    );\n\n    /// @notice Emitted when a bid is placed\n    event BidPlaced(\n        address indexed comptroller,\n        uint256 auctionStartBlockOrTimestamp,\n        uint256 bidBps,\n        address indexed bidder\n    );\n\n    /// @notice Emitted when a auction is completed\n    event AuctionClosed(\n        address indexed comptroller,\n        uint256 auctionStartBlockOrTimestamp,\n        address indexed highestBidder,\n        uint256 highestBidBps,\n        uint256 seizedRiskFind,\n        VToken[] markets,\n        uint256[] marketDebt\n    );\n\n    /// @notice Emitted when a auction is restarted\n    event AuctionRestarted(address indexed comptroller, uint256 auctionStartBlockOrTimestamp);\n\n    /// @notice Emitted when pool registry address is updated\n    event PoolRegistryUpdated(address indexed oldPoolRegistry, address indexed newPoolRegistry);\n\n    /// @notice Emitted when minimum pool bad debt is updated\n    event MinimumPoolBadDebtUpdated(uint256 oldMinimumPoolBadDebt, uint256 newMinimumPoolBadDebt);\n\n    /// @notice Emitted when wait for first bidder block or timestamp count is updated\n    event WaitForFirstBidderUpdated(uint256 oldWaitForFirstBidder, uint256 newWaitForFirstBidder);\n\n    /// @notice Emitted when next bidder block or timestamp limit is updated\n    event NextBidderBlockLimitUpdated(\n        uint256 oldNextBidderBlockOrTimestampLimit,\n        uint256 newNextBidderBlockOrTimestampLimit\n    );\n\n    /// @notice Emitted when incentiveBps is updated\n    event IncentiveBpsUpdated(uint256 oldIncentiveBps, uint256 newIncentiveBps);\n\n    /// @notice Emitted when auctions are paused\n    event AuctionsPaused(address sender);\n\n    /// @notice Emitted when auctions are unpaused\n    event AuctionsResumed(address sender);\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 nextBidderBlockOrTimestampLimit_ Default block or timestamp limit for the next bidder to place a bid\n     * @param waitForFirstBidder_ Default number of blocks or seconds to wait for the first bidder before starting the auction\n     * @custom:oz-upgrades-unsafe-allow constructor\n     */\n    constructor(\n        bool timeBased_,\n        uint256 blocksPerYear_,\n        uint256 nextBidderBlockOrTimestampLimit_,\n        uint256 waitForFirstBidder_\n    ) TimeManagerV8(timeBased_, blocksPerYear_) {\n        ensureNonzeroValue(nextBidderBlockOrTimestampLimit_);\n        ensureNonzeroValue(waitForFirstBidder_);\n\n        DEFAULT_NEXT_BIDDER_BLOCK_OR_TIMESTAMP_LIMIT = nextBidderBlockOrTimestampLimit_;\n        DEFAULT_WAIT_FOR_FIRST_BIDDER = waitForFirstBidder_;\n\n        // Note that the contract is upgradeable. Use initialize() or reinitializers\n        // to set the state variables.\n        _disableInitializers();\n    }\n\n    /**\n     * @notice Initialize the shortfall contract\n     * @param riskFund_ RiskFund contract address\n     * @param minimumPoolBadDebt_ Minimum bad debt in base asset for a pool to start auction\n     * @param accessControlManager_ AccessControlManager contract address\n     * @custom:error ZeroAddressNotAllowed is thrown when convertible base asset address is zero\n     * @custom:error ZeroAddressNotAllowed is thrown when risk fund address is zero\n     */\n    function initialize(\n        IRiskFund riskFund_,\n        uint256 minimumPoolBadDebt_,\n        address accessControlManager_\n    ) external initializer {\n        ensureNonzeroAddress(address(riskFund_));\n        require(minimumPoolBadDebt_ != 0, \"invalid minimum pool bad debt\");\n\n        __Ownable2Step_init();\n        __AccessControlled_init_unchained(accessControlManager_);\n        __ReentrancyGuard_init();\n        __TokenDebtTracker_init();\n        minimumPoolBadDebt = minimumPoolBadDebt_;\n        riskFund = riskFund_;\n        incentiveBps = DEFAULT_INCENTIVE_BPS;\n        auctionsPaused = false;\n\n        waitForFirstBidder = DEFAULT_WAIT_FOR_FIRST_BIDDER;\n        nextBidderBlockLimit = DEFAULT_NEXT_BIDDER_BLOCK_OR_TIMESTAMP_LIMIT;\n    }\n\n    /**\n     * @notice Place a bid greater than the previous in an ongoing auction\n     * @param comptroller Comptroller address of the pool\n     * @param bidBps The bid percent of the risk fund or bad debt depending on auction type\n     * @param auctionStartBlockOrTimestamp The block number or timestamp when auction started\n     * @custom:event Emits BidPlaced event on success\n     */\n    function placeBid(address comptroller, uint256 bidBps, uint256 auctionStartBlockOrTimestamp) external nonReentrant {\n        Auction storage auction = auctions[comptroller];\n\n        require(auction.startBlockOrTimestamp == auctionStartBlockOrTimestamp, \"auction has been restarted\");\n        require(_isStarted(auction), \"no on-going auction\");\n        require(!_isStale(auction), \"auction is stale, restart it\");\n        require(bidBps > 0, \"basis points cannot be zero\");\n        require(bidBps <= MAX_BPS, \"basis points cannot be more than 10000\");\n        require(\n            (auction.auctionType == AuctionType.LARGE_POOL_DEBT &&\n                ((auction.highestBidder != address(0) && bidBps > auction.highestBidBps) ||\n                    (auction.highestBidder == address(0) && bidBps >= auction.startBidBps))) ||\n                (auction.auctionType == AuctionType.LARGE_RISK_FUND &&\n                    ((auction.highestBidder != address(0) && bidBps < auction.highestBidBps) ||\n                        (auction.highestBidder == address(0) && bidBps <= auction.startBidBps))),\n            \"your bid is not the highest\"\n        );\n\n        uint256 marketsCount = auction.markets.length;\n        for (uint256 i; i < marketsCount; ++i) {\n            VToken vToken = VToken(address(auction.markets[i]));\n            IERC20Upgradeable erc20 = IERC20Upgradeable(address(vToken.underlying()));\n\n            if (auction.highestBidder != address(0)) {\n                _transferOutOrTrackDebt(erc20, auction.highestBidder, auction.bidAmount[auction.markets[i]]);\n            }\n            uint256 balanceBefore = erc20.balanceOf(address(this));\n\n            if (auction.auctionType == AuctionType.LARGE_POOL_DEBT) {\n                uint256 currentBidAmount = ((auction.marketDebt[auction.markets[i]] * bidBps) / MAX_BPS);\n                erc20.safeTransferFrom(msg.sender, address(this), currentBidAmount);\n            } else {\n                erc20.safeTransferFrom(msg.sender, address(this), auction.marketDebt[auction.markets[i]]);\n            }\n\n            uint256 balanceAfter = erc20.balanceOf(address(this));\n            auction.bidAmount[auction.markets[i]] = balanceAfter - balanceBefore;\n        }\n\n        auction.highestBidder = msg.sender;\n        auction.highestBidBps = bidBps;\n        auction.highestBidBlockOrTimestamp = getBlockNumberOrTimestamp();\n\n        emit BidPlaced(comptroller, auction.startBlockOrTimestamp, bidBps, msg.sender);\n    }\n\n    /**\n     * @notice Close an auction\n     * @param comptroller Comptroller address of the pool\n     * @custom:event Emits AuctionClosed event on successful close\n     */\n    function closeAuction(address comptroller) external nonReentrant {\n        Auction storage auction = auctions[comptroller];\n\n        require(_isStarted(auction), \"no on-going auction\");\n        require(\n            getBlockNumberOrTimestamp() > auction.highestBidBlockOrTimestamp + nextBidderBlockLimit &&\n                auction.highestBidder != address(0),\n            \"waiting for next bidder. cannot close auction\"\n        );\n\n        uint256 marketsCount = auction.markets.length;\n        uint256[] memory marketsDebt = new uint256[](marketsCount);\n\n        auction.status = AuctionStatus.ENDED;\n\n        for (uint256 i; i < marketsCount; ++i) {\n            VToken vToken = VToken(address(auction.markets[i]));\n            IERC20Upgradeable erc20 = IERC20Upgradeable(address(vToken.underlying()));\n\n            uint256 balanceBefore = erc20.balanceOf(address(auction.markets[i]));\n            erc20.safeTransfer(address(auction.markets[i]), auction.bidAmount[auction.markets[i]]);\n            uint256 balanceAfter = erc20.balanceOf(address(auction.markets[i]));\n            marketsDebt[i] = balanceAfter - balanceBefore;\n\n            auction.markets[i].badDebtRecovered(marketsDebt[i]);\n        }\n\n        uint256 riskFundBidAmount;\n\n        if (auction.auctionType == AuctionType.LARGE_POOL_DEBT) {\n            riskFundBidAmount = auction.seizedRiskFund;\n        } else {\n            riskFundBidAmount = (auction.seizedRiskFund * auction.highestBidBps) / MAX_BPS;\n        }\n\n        address convertibleBaseAsset = riskFund.convertibleBaseAsset();\n\n        uint256 transferredAmount = riskFund.transferReserveForAuction(comptroller, riskFundBidAmount);\n        _transferOutOrTrackDebt(IERC20Upgradeable(convertibleBaseAsset), auction.highestBidder, riskFundBidAmount);\n\n        emit AuctionClosed(\n            comptroller,\n            auction.startBlockOrTimestamp,\n            auction.highestBidder,\n            auction.highestBidBps,\n            transferredAmount,\n            auction.markets,\n            marketsDebt\n        );\n    }\n\n    /**\n     * @notice Start a auction when there is not currently one active\n     * @param comptroller Comptroller address of the pool\n     * @custom:event Emits AuctionStarted event on success\n     * @custom:event Errors if auctions are paused\n     */\n    function startAuction(address comptroller) external nonReentrant {\n        require(!auctionsPaused, \"Auctions are paused\");\n        _startAuction(comptroller);\n    }\n\n    /**\n     * @notice Restart an auction\n     * @param comptroller Address of the pool\n     * @custom:event Emits AuctionRestarted event on successful restart\n     */\n    function restartAuction(address comptroller) external nonReentrant {\n        Auction storage auction = auctions[comptroller];\n\n        require(!auctionsPaused, \"auctions are paused\");\n        require(_isStarted(auction), \"no on-going auction\");\n        require(_isStale(auction), \"you need to wait for more time for first bidder\");\n\n        auction.status = AuctionStatus.ENDED;\n\n        emit AuctionRestarted(comptroller, auction.startBlockOrTimestamp);\n        _startAuction(comptroller);\n    }\n\n    /**\n     * @notice Update next bidder block or timestamp limit which is used determine when an auction can be closed\n     * @param nextBidderBlockOrTimestampLimit_  New next bidder slot (block or second) limit\n     * @custom:event Emits NextBidderBlockLimitUpdated on success\n     * @custom:access Restricted by ACM\n     */\n    function updateNextBidderBlockLimit(uint256 nextBidderBlockOrTimestampLimit_) external {\n        _checkAccessAllowed(\"updateNextBidderBlockLimit(uint256)\");\n        require(nextBidderBlockOrTimestampLimit_ != 0, \"nextBidderBlockOrTimestampLimit_ must not be 0\");\n\n        emit NextBidderBlockLimitUpdated(nextBidderBlockLimit, nextBidderBlockOrTimestampLimit_);\n        nextBidderBlockLimit = nextBidderBlockOrTimestampLimit_;\n    }\n\n    /**\n     * @notice Updates the incentive BPS\n     * @param incentiveBps_ New incentive BPS\n     * @custom:event Emits IncentiveBpsUpdated on success\n     * @custom:access Restricted by ACM\n     */\n    function updateIncentiveBps(uint256 incentiveBps_) external {\n        _checkAccessAllowed(\"updateIncentiveBps(uint256)\");\n        require(incentiveBps_ != 0, \"incentiveBps must not be 0\");\n        uint256 oldIncentiveBps = incentiveBps;\n        incentiveBps = incentiveBps_;\n        emit IncentiveBpsUpdated(oldIncentiveBps, incentiveBps_);\n    }\n\n    /**\n     * @notice Update minimum pool bad debt to start auction\n     * @param minimumPoolBadDebt_ Minimum bad debt in the base asset for a pool to start auction\n     * @custom:event Emits MinimumPoolBadDebtUpdated on success\n     * @custom:access Restricted by ACM\n     */\n    function updateMinimumPoolBadDebt(uint256 minimumPoolBadDebt_) external {\n        _checkAccessAllowed(\"updateMinimumPoolBadDebt(uint256)\");\n        uint256 oldMinimumPoolBadDebt = minimumPoolBadDebt;\n        minimumPoolBadDebt = minimumPoolBadDebt_;\n        emit MinimumPoolBadDebtUpdated(oldMinimumPoolBadDebt, minimumPoolBadDebt_);\n    }\n\n    /**\n     * @notice Update wait for first bidder block or timestamp count. If the first bid is not made within this limit, the auction is closed and needs to be restarted\n     * @param waitForFirstBidder_  New wait for first bidder block or timestamp count\n     * @custom:event Emits WaitForFirstBidderUpdated on success\n     * @custom:access Restricted by ACM\n     */\n    function updateWaitForFirstBidder(uint256 waitForFirstBidder_) external {\n        _checkAccessAllowed(\"updateWaitForFirstBidder(uint256)\");\n        uint256 oldWaitForFirstBidder = waitForFirstBidder;\n        waitForFirstBidder = waitForFirstBidder_;\n        emit WaitForFirstBidderUpdated(oldWaitForFirstBidder, waitForFirstBidder_);\n    }\n\n    /**\n     * @notice Update the pool registry this shortfall supports\n     * @dev After Pool Registry is deployed we need to set the pool registry address\n     * @param poolRegistry_ Address of pool registry contract\n     * @custom:event Emits PoolRegistryUpdated on success\n     * @custom:access Restricted to owner\n     * @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n     */\n    function updatePoolRegistry(address poolRegistry_) external onlyOwner {\n        ensureNonzeroAddress(poolRegistry_);\n        address oldPoolRegistry = poolRegistry;\n        poolRegistry = poolRegistry_;\n        emit PoolRegistryUpdated(oldPoolRegistry, poolRegistry_);\n    }\n\n    /**\n     * @notice Pause auctions. This disables starting new auctions but lets the current auction finishes\n     * @custom:event Emits AuctionsPaused on success\n     * @custom:error Errors is auctions are paused\n     * @custom:access Restricted by ACM\n     */\n    function pauseAuctions() external {\n        _checkAccessAllowed(\"pauseAuctions()\");\n        require(!auctionsPaused, \"Auctions are already paused\");\n        auctionsPaused = true;\n        emit AuctionsPaused(msg.sender);\n    }\n\n    /**\n     * @notice Resume paused auctions.\n     * @custom:event Emits AuctionsResumed on success\n     * @custom:error Errors is auctions are active\n     * @custom:access Restricted by ACM\n     */\n    function resumeAuctions() external {\n        _checkAccessAllowed(\"resumeAuctions()\");\n        require(auctionsPaused, \"Auctions are not paused\");\n        auctionsPaused = false;\n        emit AuctionsResumed(msg.sender);\n    }\n\n    /**\n     * @notice Start a auction when there is not currently one active\n     * @param comptroller Comptroller address of the pool\n     */\n    function _startAuction(address comptroller) internal {\n        PoolRegistryInterface.VenusPool memory pool = PoolRegistry(poolRegistry).getPoolByComptroller(comptroller);\n        require(pool.comptroller == comptroller, \"comptroller doesn't exist pool registry\");\n\n        Auction storage auction = auctions[comptroller];\n        require(\n            auction.status == AuctionStatus.NOT_STARTED || auction.status == AuctionStatus.ENDED,\n            \"auction is on-going\"\n        );\n\n        auction.highestBidBps = 0;\n        auction.highestBidBlockOrTimestamp = 0;\n\n        uint256 marketsCount = auction.markets.length;\n        for (uint256 i; i < marketsCount; ++i) {\n            VToken vToken = auction.markets[i];\n            auction.marketDebt[vToken] = 0;\n        }\n\n        delete auction.markets;\n\n        VToken[] memory vTokens = _getAllMarkets(comptroller);\n        marketsCount = vTokens.length;\n        ResilientOracleInterface priceOracle = _getPriceOracle(comptroller);\n        uint256 poolBadDebt;\n\n        uint256[] memory marketsDebt = new uint256[](marketsCount);\n        auction.markets = new VToken[](marketsCount);\n\n        for (uint256 i; i < marketsCount; ++i) {\n            uint256 marketBadDebt = vTokens[i].badDebt();\n\n            priceOracle.updatePrice(address(vTokens[i]));\n            uint256 usdValue = (priceOracle.getUnderlyingPrice(address(vTokens[i])) * marketBadDebt) / EXP_SCALE;\n\n            poolBadDebt = poolBadDebt + usdValue;\n            auction.markets[i] = vTokens[i];\n            auction.marketDebt[vTokens[i]] = marketBadDebt;\n            marketsDebt[i] = marketBadDebt;\n        }\n\n        require(poolBadDebt >= minimumPoolBadDebt, \"pool bad debt is too low\");\n\n        priceOracle.updateAssetPrice(riskFund.convertibleBaseAsset());\n        uint256 riskFundBalance = (priceOracle.getPrice(riskFund.convertibleBaseAsset()) *\n            riskFund.getPoolsBaseAssetReserves(comptroller)) / EXP_SCALE;\n        uint256 remainingRiskFundBalance = riskFundBalance;\n        uint256 badDebtPlusIncentive = poolBadDebt + ((poolBadDebt * incentiveBps) / MAX_BPS);\n        if (badDebtPlusIncentive >= riskFundBalance) {\n            auction.startBidBps =\n                (MAX_BPS * MAX_BPS * remainingRiskFundBalance) /\n                (poolBadDebt * (MAX_BPS + incentiveBps));\n            remainingRiskFundBalance = 0;\n            auction.auctionType = AuctionType.LARGE_POOL_DEBT;\n        } else {\n            uint256 maxSeizeableRiskFundBalance = badDebtPlusIncentive;\n\n            remainingRiskFundBalance = remainingRiskFundBalance - maxSeizeableRiskFundBalance;\n            auction.auctionType = AuctionType.LARGE_RISK_FUND;\n            auction.startBidBps = MAX_BPS;\n        }\n\n        auction.seizedRiskFund = riskFundBalance - remainingRiskFundBalance;\n        auction.startBlockOrTimestamp = getBlockNumberOrTimestamp();\n        auction.status = AuctionStatus.STARTED;\n        auction.highestBidder = address(0);\n\n        emit AuctionStarted(\n            comptroller,\n            auction.startBlockOrTimestamp,\n            auction.auctionType,\n            auction.markets,\n            marketsDebt,\n            auction.seizedRiskFund,\n            auction.startBidBps\n        );\n    }\n\n    /**\n     * @dev Returns the price oracle of the pool\n     * @param comptroller Address of the pool's comptroller\n     * @return oracle The pool's price oracle\n     */\n    function _getPriceOracle(address comptroller) internal view returns (ResilientOracleInterface) {\n        return ResilientOracleInterface(ComptrollerViewInterface(comptroller).oracle());\n    }\n\n    /**\n     * @dev Returns all markets of the pool\n     * @param comptroller Address of the pool's comptroller\n     * @return markets The pool's markets as VToken array\n     */\n    function _getAllMarkets(address comptroller) internal view returns (VToken[] memory) {\n        return ComptrollerInterface(comptroller).getAllMarkets();\n    }\n\n    /**\n     * @dev Checks if the auction has started\n     * @param auction The auction to query the status for\n     * @return True if the auction has started\n     */\n    function _isStarted(Auction storage auction) internal view returns (bool) {\n        return auction.status == AuctionStatus.STARTED;\n    }\n\n    /**\n     * @dev Checks if the auction is stale, i.e. there's no bidder and the auction\n     *   was started more than waitForFirstBidder blocks or seconds ago.\n     * @param auction The auction to query the status for\n     * @return True if the auction is stale\n     */\n    function _isStale(Auction storage auction) internal view returns (bool) {\n        bool noBidder = auction.highestBidder == address(0);\n        return noBidder && (getBlockNumberOrTimestamp() > auction.startBlockOrTimestamp + waitForFirstBidder);\n    }\n}\n"
    },
    "contracts/Shortfall/ShortfallStorage.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { VToken } from \"../VToken.sol\";\nimport { IRiskFund } from \"../Shortfall/IRiskFund.sol\";\n\n/**\n * @title ShortfallStorage\n * @author Venus\n * @dev Storage for Shortfall\n */\ncontract ShortfallStorage {\n    /// @notice Type of auction\n    enum AuctionType {\n        LARGE_POOL_DEBT,\n        LARGE_RISK_FUND\n    }\n\n    /// @notice Status of auction\n    enum AuctionStatus {\n        NOT_STARTED,\n        STARTED,\n        ENDED\n    }\n\n    /// @notice Auction metadata\n    struct Auction {\n        /// @notice It holds either the starting block number or timestamp\n        uint256 startBlockOrTimestamp;\n        AuctionType auctionType;\n        AuctionStatus status;\n        VToken[] markets;\n        uint256 seizedRiskFund;\n        address highestBidder;\n        uint256 highestBidBps;\n        /// @notice It holds either the highestBid block or timestamp\n        uint256 highestBidBlockOrTimestamp;\n        uint256 startBidBps;\n        mapping(VToken => uint256) marketDebt;\n        mapping(VToken => uint256) bidAmount;\n    }\n\n    /// @notice Pool registry address\n    address public poolRegistry;\n\n    /// @notice Risk fund address\n    IRiskFund public riskFund;\n\n    /// @notice Minimum USD debt in pool for shortfall to trigger\n    uint256 public minimumPoolBadDebt;\n\n    /// @notice Incentive to auction participants, initial value set to 1000 or 10%\n    uint256 public incentiveBps;\n\n    /// @notice Time to wait for next bidder. Initially waits for DEFAULT_NEXT_BIDDER_BLOCK_OR_TIMESTAMP_LIMIT\n    uint256 public nextBidderBlockLimit;\n\n    /// @notice Boolean of if auctions are paused\n    bool public auctionsPaused;\n\n    /// @notice Time to wait for first bidder. Initially waits for DEFAULT_WAIT_FOR_FIRST_BIDDER\n    uint256 public waitForFirstBidder;\n\n    /// @notice Auctions for each pool\n    mapping(address => Auction) public auctions;\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[42] private __gap;\n}\n"
    },
    "contracts/test/ComptrollerHarness.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { Comptroller } from \"../Comptroller.sol\";\n\ncontract ComptrollerHarness is Comptroller {\n    uint256 public blockNumber;\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(address _poolRegistry) Comptroller(_poolRegistry) {}\n\n    function harnessFastForward(uint256 blocks) public returns (uint256) {\n        blockNumber += blocks;\n        return blockNumber;\n    }\n\n    function setBlockNumber(uint256 number) public {\n        blockNumber = number;\n    }\n}\n\ncontract EchoTypesComptroller {\n    function stringy(string memory s) public pure returns (string memory) {\n        return s;\n    }\n\n    function addresses(address a) public pure returns (address) {\n        return a;\n    }\n\n    function booly(bool b) public pure returns (bool) {\n        return b;\n    }\n\n    function listOInts(uint256[] memory u) public pure returns (uint256[] memory) {\n        return u;\n    }\n\n    function reverty() public pure {\n        require(false, \"gotcha sucka\");\n    }\n}\n"
    },
    "contracts/test/ComptrollerScenario.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { Comptroller } from \"../Comptroller.sol\";\nimport { VToken } from \"../VToken.sol\";\n\ncontract ComptrollerScenario is Comptroller {\n    uint256 public blockNumber;\n\n    // solhint-disable-next-line no-empty-blocks\n    constructor(address _poolRegistry) Comptroller(_poolRegistry) {}\n\n    function fastForward(uint256 blocks) public returns (uint256) {\n        blockNumber += blocks;\n        return blockNumber;\n    }\n\n    function setBlockNumber(uint256 number) public {\n        blockNumber = number;\n    }\n\n    function unlist(VToken vToken) public {\n        markets[address(vToken)].isListed = false;\n    }\n\n    function membershipLength(VToken vToken) public view returns (uint256) {\n        return accountAssets[address(vToken)].length;\n    }\n}\n"
    },
    "contracts/test/Mocks/MockPriceOracle.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { BinanceOracle } from \"@venusprotocol/oracle/contracts/oracles/BinanceOracle.sol\";\nimport { ChainlinkOracle } from \"@venusprotocol/oracle/contracts/oracles/ChainlinkOracle.sol\";\nimport { ProtocolShareReserve } from \"@venusprotocol/protocol-reserve/contracts/ProtocolReserve/ProtocolShareReserve.sol\";\nimport { VToken } from \"../../VToken.sol\";\n\ncontract MockPriceOracle is ResilientOracleInterface {\n    struct TokenConfig {\n        /// @notice asset address\n        address asset;\n        /// @notice `oracles` stores the oracles based on their role in the following order:\n        /// [main, pivot, fallback],\n        /// It can be indexed with the corresponding enum OracleRole value\n        address[3] oracles;\n        /// @notice `enableFlagsForOracles` stores the enabled state\n        /// for each oracle in the same order as `oracles`\n        bool[3] enableFlagsForOracles;\n    }\n\n    mapping(address => uint256) public assetPrices;\n\n    //set price in 6 decimal precision\n    // solhint-disable-next-line no-empty-blocks\n    constructor() {}\n\n    function setPrice(address asset, uint256 price) external {\n        assetPrices[asset] = price;\n    }\n\n    // solhint-disable-next-line no-empty-blocks\n    function updatePrice(address vToken) external override {}\n\n    // solhint-disable-next-line no-empty-blocks\n    function updateAssetPrice(address asset) external override {}\n\n    function getPrice(address asset) external view returns (uint256) {\n        return assetPrices[asset];\n    }\n\n    function getTokenConfig(address asset) external view returns (TokenConfig memory) {}\n\n    function setTokenConfig(TokenConfig memory tokenConfig) public {}\n\n    //https://compound.finance/docs/prices\n    function getUnderlyingPrice(address vToken) public view override returns (uint256) {\n        return assetPrices[VToken(vToken).underlying()];\n    }\n}\n"
    },
    "contracts/test/Mocks/MockVenusERC4626.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { VenusERC4626 } from \"../../ERC4626/VenusERC4626.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { ERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol\";\n\ncontract MockVenusERC4626 is VenusERC4626 {\n    mapping(address => uint256) private _balances;\n    uint256 private mockTotalAssets;\n    uint256 private mockMaxDeposit;\n    uint256 private mockMaxWithdraw;\n    uint256 private mockMaxMint;\n    uint256 private mockMaxRedeem;\n    uint256 private mockTotalSupply;\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    function setTotalSupply(uint256 _totalSupply) external {\n        mockTotalSupply = _totalSupply;\n    }\n\n    function setAccountBalance(address account, uint256 balance) public {\n        _balances[account] = balance;\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    function totalSupply() public view override(ERC20Upgradeable, IERC20Upgradeable) returns (uint256) {\n        return mockTotalSupply;\n    }\n\n    function _mint(address account, uint256 amount) internal override {\n        mockTotalSupply += amount;\n        _balances[account] += amount;\n        super._mint(account, amount);\n    }\n\n    function _burn(address account, uint256 amount) internal override {\n        mockTotalSupply -= amount;\n        _balances[account] -= amount;\n        super._burn(account, amount);\n    }\n}\n"
    },
    "contracts/test/UpgradedVToken.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { AccessControlManager } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlManager.sol\";\n\nimport { VToken } from \"../VToken.sol\";\nimport { ComptrollerInterface } from \"../ComptrollerInterface.sol\";\nimport { InterestRateModel } from \"../InterestRateModel.sol\";\n\n/**\n * @title Venus's VToken Contract\n * @notice VTokens which wrap an EIP-20 underlying and are immutable\n * @author Venus\n */\ncontract UpgradedVToken is VToken {\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(\n        bool timeBased_,\n        uint256 blocksPerYear_,\n        uint256 maxBorrowRateMantissa_\n    ) VToken(timeBased_, blocksPerYear_, maxBorrowRateMantissa_) {\n        // Note that the contract is upgradeable. Use initialize() or reinitializers\n        // to set the state variables.\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 riskManagement Addresses of risk fund contracts\n     */\n\n    /// @notice We added this new function to test contract upgrade\n    function version() external pure returns (uint256) {\n        return 2;\n    }\n\n    function initializeV2(\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 payable admin_,\n        address accessControlManager_,\n        RiskManagementInit memory riskManagement,\n        uint256 reserveFactorMantissa_\n    ) public reinitializer(2) {\n        super._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    function getTokenUnderlying() public view returns (address) {\n        return underlying;\n    }\n}\n"
    },
    "contracts/test/VTokenHarness.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { AccessControlManager } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlManager.sol\";\n\nimport { VToken } from \"../VToken.sol\";\nimport { InterestRateModel } from \"../InterestRateModel.sol\";\n\ncontract VTokenHarness is VToken {\n    uint256 public blockNumber;\n    uint256 public harnessExchangeRate;\n    bool public harnessExchangeRateStored;\n\n    mapping(address => bool) public failTransferToAddresses;\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(\n        bool timeBased_,\n        uint256 blocksPerYear_,\n        uint256 maxBorrowRateMantissa_\n    ) VToken(timeBased_, blocksPerYear_, maxBorrowRateMantissa_) {\n        // Note that the contract is upgradeable. Use initialize() or reinitializers\n        // to set the state variables.\n        _disableInitializers();\n    }\n\n    function harnessSetAccrualBlockNumber(uint256 accrualBlockNumber_) external {\n        accrualBlockNumber = accrualBlockNumber_;\n    }\n\n    function harnessSetBlockNumber(uint256 newBlockNumber) external {\n        blockNumber = newBlockNumber;\n    }\n\n    function harnessFastForward(uint256 blocks) external {\n        blockNumber += blocks;\n    }\n\n    function harnessSetBalance(address account, uint256 amount) external {\n        accountTokens[account] = amount;\n    }\n\n    function harnessSetTotalSupply(uint256 totalSupply_) external {\n        totalSupply = totalSupply_;\n    }\n\n    function harnessSetTotalBorrows(uint256 totalBorrows_) external {\n        totalBorrows = totalBorrows_;\n    }\n\n    function harnessSetTotalReserves(uint256 totalReserves_) external {\n        totalReserves = totalReserves_;\n    }\n\n    function harnessExchangeRateDetails(uint256 totalSupply_, uint256 totalBorrows_, uint256 totalReserves_) external {\n        totalSupply = totalSupply_;\n        totalBorrows = totalBorrows_;\n        totalReserves = totalReserves_;\n    }\n\n    function harnessSetExchangeRate(uint256 exchangeRate) external {\n        harnessExchangeRate = exchangeRate;\n        harnessExchangeRateStored = true;\n    }\n\n    function harnessSetFailTransferToAddress(address to_, bool fail_) external {\n        failTransferToAddresses[to_] = fail_;\n    }\n\n    function harnessMintFresh(address account, uint256 mintAmount) external {\n        super._mintFresh(account, account, mintAmount);\n    }\n\n    function harnessRedeemFresh(address payable account, uint256 vTokenAmount, uint256 underlyingAmount) external {\n        super._redeemFresh(account, account, vTokenAmount, underlyingAmount);\n    }\n\n    function harnessSetAccountBorrows(address account, uint256 principal, uint256 interestIndex) external {\n        accountBorrows[account] = BorrowSnapshot({ principal: principal, interestIndex: interestIndex });\n    }\n\n    function harnessSetBorrowIndex(uint256 borrowIndex_) external {\n        borrowIndex = borrowIndex_;\n    }\n\n    function harnessBorrowFresh(address payable account, uint256 borrowAmount) external {\n        _borrowFresh(account, account, borrowAmount);\n    }\n\n    function harnessRepayBorrowFresh(address payer, address account, uint256 repayAmount) external {\n        _repayBorrowFresh(payer, account, repayAmount);\n    }\n\n    function harnessLiquidateBorrowFresh(\n        address liquidator,\n        address borrower,\n        uint256 repayAmount,\n        VToken vTokenCollateral,\n        bool skipLiquidityCheck\n    ) external {\n        _liquidateBorrowFresh(liquidator, borrower, repayAmount, vTokenCollateral, skipLiquidityCheck);\n    }\n\n    function harnessReduceReservesFresh(uint256 spreadAmount) external {\n        return _reduceReservesFresh(spreadAmount);\n    }\n\n    function harnessSetReserveFactorFresh(uint256 newReserveFactorMantissa) external {\n        _setReserveFactorFresh(newReserveFactorMantissa);\n    }\n\n    function harnessSetInterestRateModelFresh(InterestRateModel newInterestRateModel) external {\n        _setInterestRateModelFresh(newInterestRateModel);\n    }\n\n    function harnessAccountBorrows(address account) external view returns (uint256 principal, uint256 interestIndex) {\n        BorrowSnapshot memory snapshot = accountBorrows[account];\n        return (snapshot.principal, snapshot.interestIndex);\n    }\n\n    function getBorrowRateMaxMantissa() external view returns (uint256) {\n        return MAX_BORROW_RATE_MANTISSA;\n    }\n\n    function harnessSetInterestRateModel(address newInterestRateModelAddress) public {\n        interestRateModel = InterestRateModel(newInterestRateModelAddress);\n    }\n\n    function harnessCallPreBorrowHook(uint256 amount) public {\n        comptroller.preBorrowHook(address(this), msg.sender, amount);\n    }\n\n    function getBlockNumberOrTimestamp() public view override returns (uint256) {\n        return blockNumber;\n    }\n\n    function _doTransferOut(address to, uint256 amount) internal override {\n        require(failTransferToAddresses[to] == false, \"HARNESS_TOKEN_TRANSFER_OUT_FAILED\");\n        return super._doTransferOut(to, amount);\n    }\n\n    function _exchangeRateStored() internal view override returns (uint256) {\n        if (harnessExchangeRateStored) {\n            return harnessExchangeRate;\n        }\n        return super._exchangeRateStored();\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"
    },
    "contracts/WUSDMLiquidator.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 { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\n\nimport { ApproveOrRevert } from \"./lib/ApproveOrRevert.sol\";\nimport { Comptroller } from \"./Comptroller.sol\";\nimport { Action } from \"./ComptrollerInterface.sol\";\nimport { VToken } from \"./VToken.sol\";\n\ncontract WUSDMLiquidator is Ownable2StepUpgradeable {\n    using SafeERC20Upgradeable for IERC20Upgradeable;\n    using ApproveOrRevert for IERC20Upgradeable;\n\n    struct OriginalConfig {\n        uint256 minLiquidatableCollateral;\n        uint256 closeFactor;\n        uint256 wUSDMCollateralFactor;\n        uint256 wUSDMLiquidationThreshold;\n        uint256 vWUSDMProtocolSeizeShare;\n        uint256 vWETHProtocolSeizeShare;\n        uint256 vUSDCEProtocolSeizeShare;\n        uint256 vUSDTProtocolSeizeShare;\n    }\n\n    OriginalConfig private _originalConfig;\n\n    ResilientOracleInterface public constant ORACLE =\n        ResilientOracleInterface(0xDe564a4C887d5ad315a19a96DC81991c98b12182);\n    Comptroller public constant COMPTROLLER = Comptroller(0xddE4D098D9995B659724ae6d5E3FB9681Ac941B1);\n    VToken public constant VWUSDM = VToken(0x183dE3C349fCf546aAe925E1c7F364EA6FB4033c);\n    VToken public constant VWETH = VToken(0x1Fa916C27c7C2c4602124A14C77Dbb40a5FF1BE8);\n    VToken public constant VUSDCE = VToken(0x1aF23bD57c62A99C59aD48236553D0Dd11e49D2D);\n    VToken public constant VUSDT = VToken(0x69cDA960E3b20DFD480866fFfd377Ebe40bd0A46);\n\n    uint256 public constant LIQUIDATION_INCENTIVE = 1.1e18;\n\n    address public constant A2 = 0x4C0e4B3e6c5756fb31886a0A01079701ffEC0561;\n    address public constant A3 = 0x924EDEd3D010b3F20009b872183eec48D0111265;\n    address public constant A4 = 0x2B379d8c90e02016658aD00ba2566F55E814C369;\n    address public constant A5 = 0xfffAB9120d9Df39EEa07063F6465a0aA45a80C52;\n\n    IERC20Upgradeable public immutable WUSDM;\n    IERC20Upgradeable public immutable WETH;\n    IERC20Upgradeable public immutable USDCE;\n    IERC20Upgradeable public immutable USDT;\n\n    /// @notice Emitted when token is swept from the contract\n    event SweepToken(address indexed token, address indexed receiver, uint256 amount);\n\n    /**\n     * @notice Constructor to initialize immutable token references and disable initializers\n     */\n    constructor() {\n        WUSDM = IERC20Upgradeable(VWUSDM.underlying());\n        WETH = IERC20Upgradeable(VWETH.underlying());\n        USDCE = IERC20Upgradeable(VUSDCE.underlying());\n        USDT = IERC20Upgradeable(VUSDT.underlying());\n        _disableInitializers();\n    }\n\n    /**\n     * @notice Initializes the contract and sets up ownership\n     * @dev This function can only be called once\n     */\n    function initialize() external initializer {\n        __Ownable2Step_init();\n    }\n\n    /**\n     * @notice Executes the liquidation and repayment process\n     * @dev This function performs the following steps:\n     *      1. Configures the markets by setting collateral factors, close factors, and enabling actions.\n     *      2. Supplies WUSDM as collateral.\n     *      3. Borrows WETH and liquidates borrowers with WETH debt.\n     *      4. Borrows USDCE and liquidates borrowers with USDCE debt.\n     *      5. Borrows USDT and liquidates borrowers with USDT debt.\n     *      6. Restores the original market configuration.\n     */\n    function run() external onlyOwner {\n        uint256 wusdmPrice = ORACLE.getPrice(address(WUSDM));\n        uint256 vwUSDMExchangeRate = VWUSDM.exchangeRateCurrent();\n\n        _configureMarkets();\n        _supplyCollateral();\n        _borrowWETHAndLiquidateBorrowers(wusdmPrice, vwUSDMExchangeRate);\n        _borrowUSDCeAndLiquidateBorrowers(wusdmPrice, vwUSDMExchangeRate);\n        _borrowUSDTAndLiquidateBorrowers(wusdmPrice, vwUSDMExchangeRate);\n        _restoreOriginalConfiguration();\n    }\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 Controlled by Governance\n     */\n    function sweepToken(IERC20Upgradeable token) external onlyOwner {\n        uint256 balance = token.balanceOf(address(this));\n\n        if (balance > 0) {\n            address owner_ = owner();\n            token.safeTransfer(owner_, balance);\n            emit SweepToken(address(token), owner_, balance);\n        }\n    }\n\n    function _configureMarkets() internal {\n        (, uint256 wUSDMCollateralFactor, uint256 wUSDMLiquidationThreshold) = COMPTROLLER.markets(address(VWUSDM));\n        _originalConfig = OriginalConfig({\n            minLiquidatableCollateral: COMPTROLLER.minLiquidatableCollateral(),\n            closeFactor: COMPTROLLER.closeFactorMantissa(),\n            wUSDMCollateralFactor: wUSDMCollateralFactor,\n            wUSDMLiquidationThreshold: wUSDMLiquidationThreshold,\n            vWUSDMProtocolSeizeShare: VWUSDM.protocolSeizeShareMantissa(),\n            vWETHProtocolSeizeShare: VWETH.protocolSeizeShareMantissa(),\n            vUSDCEProtocolSeizeShare: VUSDCE.protocolSeizeShareMantissa(),\n            vUSDTProtocolSeizeShare: VUSDT.protocolSeizeShareMantissa()\n        });\n        COMPTROLLER.setMinLiquidatableCollateral(0);\n        COMPTROLLER.setCloseFactor(1e18);\n        COMPTROLLER.setCollateralFactor(VWUSDM, 0.78e18, 0.78e18);\n        VToken[] memory markets = new VToken[](1);\n        Action[] memory actions = new Action[](2);\n        markets[0] = VWUSDM;\n        actions[0] = Action.MINT;\n        actions[1] = Action.ENTER_MARKET;\n        COMPTROLLER.setActionsPaused(markets, actions, false);\n        VWUSDM.setProtocolSeizeShare(0);\n        VWETH.setProtocolSeizeShare(0);\n        VUSDCE.setProtocolSeizeShare(0);\n        VUSDT.setProtocolSeizeShare(0);\n    }\n\n    function _restoreOriginalConfiguration() internal {\n        COMPTROLLER.setMinLiquidatableCollateral(_originalConfig.minLiquidatableCollateral);\n        COMPTROLLER.setCloseFactor(_originalConfig.closeFactor);\n        COMPTROLLER.setCollateralFactor(\n            VWUSDM,\n            _originalConfig.wUSDMCollateralFactor,\n            _originalConfig.wUSDMLiquidationThreshold\n        );\n        VToken[] memory markets = new VToken[](1);\n        Action[] memory actions = new Action[](2);\n        markets[0] = VWUSDM;\n        actions[0] = Action.MINT;\n        actions[1] = Action.ENTER_MARKET;\n        COMPTROLLER.setActionsPaused(markets, actions, true);\n        VWUSDM.setProtocolSeizeShare(_originalConfig.vWUSDMProtocolSeizeShare);\n        VWETH.setProtocolSeizeShare(_originalConfig.vWETHProtocolSeizeShare);\n        VUSDCE.setProtocolSeizeShare(_originalConfig.vUSDCEProtocolSeizeShare);\n        VUSDT.setProtocolSeizeShare(_originalConfig.vUSDTProtocolSeizeShare);\n        // Get some gas refunds for zeroing out storage\n        _originalConfig = OriginalConfig(0, 0, 0, 0, 0, 0, 0, 0);\n    }\n\n    function _supplyCollateral() internal {\n        uint256 amount = WUSDM.balanceOf(address(this));\n        WUSDM.approveOrRevert(address(VWUSDM), amount);\n        VWUSDM.mint(amount);\n        WUSDM.approveOrRevert(address(VWUSDM), 0);\n        address[] memory markets = new address[](1);\n        markets[0] = address(VWUSDM);\n        COMPTROLLER.enterMarkets(markets);\n    }\n\n    function _borrowWETHAndLiquidateBorrowers(uint256 wusdmPrice, uint256 vwUSDMExchangeRate) internal {\n        uint256 a2Debt = _getDebt(VWETH, A2);\n        uint256 ratio = _getBorrowedTokensToCollateralVTokensRatio(VWETH, wusdmPrice, vwUSDMExchangeRate);\n        uint256 amountToRepay = _getAmountToRepayDuringLiquidation(A2, a2Debt, VWUSDM, ratio);\n        if (amountToRepay > 0) {\n            _borrow(VWETH, amountToRepay);\n            WETH.approveOrRevert(address(VWETH), amountToRepay);\n            VWETH.liquidateBorrow(A2, amountToRepay, VWUSDM);\n            WETH.approveOrRevert(address(VWETH), 0);\n        }\n    }\n\n    function _borrowUSDCeAndLiquidateBorrowers(uint256 wusdmPrice, uint256 vwUSDMExchangeRate) internal {\n        uint256 a3Debt = _getDebt(VUSDCE, A3);\n        uint256 a4Debt = _getDebt(VUSDCE, A4);\n        uint256 a5Debt = _getDebt(VUSDCE, A5);\n        uint256 totalRepayment = a3Debt + a4Debt + a5Debt;\n\n        _borrow(VUSDCE, totalRepayment);\n        USDCE.approveOrRevert(address(VUSDCE), totalRepayment);\n        uint256 ratio = _getBorrowedTokensToCollateralVTokensRatio(VUSDCE, wusdmPrice, vwUSDMExchangeRate);\n        a3Debt = _liquidateAsMuchAsPossible(A3, a3Debt, VUSDCE, VWUSDM, ratio);\n        a4Debt = _liquidateAsMuchAsPossible(A4, a4Debt, VUSDCE, VWUSDM, ratio);\n        a5Debt = _liquidateAsMuchAsPossible(A5, a5Debt, VUSDCE, VWUSDM, ratio);\n        _repay(A3, VUSDCE, a3Debt > 1 ? a3Debt - 1 : 0);\n        _repay(A4, VUSDCE, a4Debt > 1 ? a4Debt - 1 : 0);\n        _repay(A5, VUSDCE, a5Debt > 1 ? a5Debt - 1 : 0);\n        USDCE.approveOrRevert(address(VUSDCE), 0);\n    }\n\n    function _borrowUSDTAndLiquidateBorrowers(uint256 wusdmPrice, uint256 vwUSDMExchangeRate) internal {\n        uint256 a3Debt = _getDebt(VUSDT, A3);\n        uint256 a4Debt = _getDebt(VUSDT, A4);\n        uint256 a5Debt = _getDebt(VUSDT, A5);\n        uint256 totalRepayment = a3Debt + a4Debt + a5Debt;\n\n        _borrow(VUSDT, totalRepayment);\n        USDT.approveOrRevert(address(VUSDT), totalRepayment);\n        uint256 ratio = _getBorrowedTokensToCollateralVTokensRatio(VUSDT, wusdmPrice, vwUSDMExchangeRate);\n        a3Debt = _liquidateAsMuchAsPossible(A3, a3Debt, VUSDT, VWUSDM, ratio);\n        a4Debt = _liquidateAsMuchAsPossible(A4, a4Debt, VUSDT, VWUSDM, ratio);\n        a5Debt = _liquidateAsMuchAsPossible(A5, a5Debt, VUSDT, VWUSDM, ratio);\n        _repay(A3, VUSDT, a3Debt > 1 ? a3Debt - 1 : 0);\n        _repay(A4, VUSDT, a4Debt > 1 ? a4Debt - 1 : 0);\n        _repay(A5, VUSDT, a5Debt > 1 ? a5Debt - 1 : 0);\n        USDT.approveOrRevert(address(VUSDT), 0);\n    }\n\n    function _getDebt(VToken market, address account) internal returns (uint256) {\n        if (!_isUnderwater(account)) {\n            return 0; // no debt if not underwater\n        }\n        return market.borrowBalanceCurrent(account);\n    }\n\n    function _borrow(VToken market, uint256 amount) internal {\n        market.borrow(amount);\n    }\n\n    function _repay(address account, VToken market, uint256 amount) internal {\n        if (amount == 0) {\n            return;\n        }\n        market.repayBorrowBehalf(account, amount);\n    }\n\n    function _liquidateAsMuchAsPossible(\n        address account,\n        uint256 debt,\n        VToken market,\n        VToken collateral,\n        uint256 ratio\n    ) internal returns (uint256) {\n        if (debt == 0) {\n            return 0;\n        }\n        uint256 amountToRepay = _getAmountToRepayDuringLiquidation(account, debt, collateral, ratio);\n        if (amountToRepay > 1) {\n            market.liquidateBorrow(account, amountToRepay, collateral);\n        }\n        return debt - amountToRepay;\n    }\n\n    function _getAmountToRepayDuringLiquidation(\n        address account,\n        uint256 debt,\n        VToken collateral,\n        uint256 ratio\n    ) internal view returns (uint256) {\n        if (debt == 0) {\n            return 0;\n        }\n        uint256 seizeableVTokens = collateral.balanceOf(account);\n        if (seizeableVTokens <= 1) {\n            return debt;\n        }\n        // Ideally, we should round up here so that we repay as much as possible during the liquidation,\n        // leaving no vTokens supplied, but due to anvil-zksync issues, we want to keep at least 1 wei\n        // of vTokens supplied so that we're able to test it later\n        uint256 amountToRepayForEntireCollateral = ((seizeableVTokens - 1) * 1e18) / ratio;\n        // Keeping 1 wei of debt, for the same purpose\n        return debt > amountToRepayForEntireCollateral ? amountToRepayForEntireCollateral : (debt - 1);\n    }\n\n    function _getBorrowedTokensToCollateralVTokensRatio(\n        VToken borrowed,\n        uint256 collateralPrice,\n        uint256 collateralExchangeRate\n    ) internal view returns (uint256) {\n        uint256 borrowedPrice = ORACLE.getUnderlyingPrice(address(borrowed));\n        return (borrowedPrice * LIQUIDATION_INCENTIVE * 1e18) / (collateralPrice * collateralExchangeRate);\n    }\n\n    function _isUnderwater(address account) internal view returns (bool) {\n        (, uint256 liquidity, uint256 shortfall) = COMPTROLLER.getAccountLiquidity(account);\n        return liquidity == 0 && shortfall > 0;\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
    }
  }
}
