diff --git a/audits/152_nativeTokenGateway_certik_20250911.pdf b/audits/152_nativeTokenGateway_certik_20250911.pdf new file mode 100644 index 00000000..c5d52df5 Binary files /dev/null and b/audits/152_nativeTokenGateway_certik_20250911.pdf differ diff --git a/contracts/Gateway/INativeTokenGateway.sol b/contracts/Gateway/INativeTokenGateway.sol new file mode 100644 index 00000000..27c42359 --- /dev/null +++ b/contracts/Gateway/INativeTokenGateway.sol @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: BSD-3-Clause +pragma solidity ^0.8.25; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +/** + * @title INativeTokenGateway + * @author Venus + * @notice Interface for NativeTokenGateway contract + */ +interface INativeTokenGateway { + /** + * @dev Emitted when native currency is supplied + */ + event TokensWrappedAndSupplied(address indexed sender, address indexed vToken, uint256 amount); + + /** + * @dev Emitted when tokens are redeemed and then unwrapped to be sent to user + */ + event TokensRedeemedAndUnwrapped(address indexed sender, address indexed vToken, uint256 amount); + + /** + * @dev Emitted when native tokens are borrowed and unwrapped + */ + event TokensBorrowedAndUnwrapped(address indexed sender, address indexed vToken, uint256 amount); + + /** + * @dev Emitted when native currency is wrapped and repaid + */ + event TokensWrappedAndRepaid(address indexed sender, address indexed vToken, uint256 amount); + + /** + * @dev Emitted when token is swept from the contract + */ + event SweepToken(address indexed token, address indexed receiver, uint256 amount); + + /** + * @dev Emitted when native asset is swept from the contract + */ + event SweepNative(address indexed receiver, uint256 amount); + + /** + * @notice Thrown if transfer of native token fails + */ + error NativeTokenTransferFailed(); + + /** + * @notice Thrown if the supplied address is a zero address where it is not allowed + */ + error ZeroAddressNotAllowed(); + + /** + * @notice Thrown if the supplied value is 0 where it is not allowed + */ + error ZeroValueNotAllowed(); + + /** + * @dev Wrap Native Token, get wNativeToken, mint vWNativeTokens, and supply to the market + * @param minter The address on behalf of whom the supply is performed + */ + function wrapAndSupply(address minter) external payable; + + /** + * @dev Redeem vWNativeTokens, unwrap to Native Token, and send to the user + * @param redeemAmount The amount of underlying tokens to redeem + */ + function redeemUnderlyingAndUnwrap(uint256 redeemAmount) external; + + /** + * @dev Redeem vWNativeTokens, unwrap to Native Token, and send to the user + * @param redeemTokens The amount of vWNative tokens to redeem + */ + function redeemAndUnwrap(uint256 redeemTokens) external; + + /** + * @dev Borrow wNativeToken, unwrap to Native Token, and send to the user + * @param amount The amount of underlying tokens to borrow + */ + function borrowAndUnwrap(uint256 amount) external; + + /** + * @dev Wrap Native Token, repay borrow in the market, and send remaining Native Token to the user + */ + function wrapAndRepay() external payable; + + /** + * @dev Sweeps input token address tokens from the contract and sends them to the owner + */ + function sweepToken(IERC20 token) external; + + /** + * @dev Sweeps native assets (Native Token) from the contract and sends them to the owner + */ + function sweepNative() external; +} diff --git a/contracts/Gateway/Interfaces/IVToken.sol b/contracts/Gateway/Interfaces/IVToken.sol new file mode 100644 index 00000000..445647f9 --- /dev/null +++ b/contracts/Gateway/Interfaces/IVToken.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: BSD-3-Clause +pragma solidity ^0.8.25; + +interface IVToken { + function mintBehalf(address receiver, uint256 mintAmount) external returns (uint256); + + function redeemUnderlyingBehalf(address redeemer, uint256 redeemAmount) external returns (uint256); + + function redeemBehalf(address redeemer, uint256 redeemTokens) external returns (uint256); + + function repayBorrowBehalf(address borrower, uint256 repayAmount) external returns (uint256); + + function borrowBehalf(address borrower, uint256 borrowAmount) external returns (uint256); + + function borrowBalanceCurrent(address account) external returns (uint256); + + function underlying() external returns (address); + + function exchangeRateCurrent() external returns (uint256); + + function transferFrom(address from, address to, uint256 amount) external returns (bool); + + function redeem(uint256 redeemTokens) external returns (uint256); +} diff --git a/contracts/Gateway/Interfaces/IWrappedNative.sol b/contracts/Gateway/Interfaces/IWrappedNative.sol new file mode 100644 index 00000000..35ec0081 --- /dev/null +++ b/contracts/Gateway/Interfaces/IWrappedNative.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: BSD-3-Clause +pragma solidity ^0.8.25; + +interface IWrappedNative { + function deposit() external payable; + + function withdraw(uint256) external; + + function approve(address guy, uint256 wad) external returns (bool); + + function transferFrom(address src, address dst, uint256 wad) external returns (bool); + + function transfer(address dst, uint256 wad) external returns (bool); + + function balanceOf(address account) external view returns (uint256); +} diff --git a/contracts/Gateway/NativeTokenGateway.sol b/contracts/Gateway/NativeTokenGateway.sol new file mode 100644 index 00000000..0ff595db --- /dev/null +++ b/contracts/Gateway/NativeTokenGateway.sol @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: BSD-3-Clause +pragma solidity 0.8.25; + +import { Ownable2Step } from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; + +import { IWrappedNative } from "./Interfaces/IWrappedNative.sol"; +import { INativeTokenGateway } from "./INativeTokenGateway.sol"; +import { IVToken } from "./Interfaces/IVToken.sol"; + +/** + * @title NativeTokenGateway + * @author Venus + * @notice NativeTokenGateway contract facilitates interactions with a vToken market for native tokens (Native or wNativeToken) + */ +contract NativeTokenGateway is INativeTokenGateway, Ownable2Step, ReentrancyGuard { + using SafeERC20 for IERC20; + + /// @notice Error code representing no errors in Venus operations + uint256 internal constant NO_ERROR = 0; + + /** + * @notice Address of wrapped native token contract + */ + IWrappedNative public immutable wNativeToken; + + /** + * @notice Address of wrapped native token market + */ + IVToken public immutable vWNativeToken; + + /// @custom:error RedeemFailed + error RedeemFailed(uint256 err); + + /// @custom:error BorrowFailed + error BorrowFailed(uint256 err); + + /// @custom:error MintFailed + error MintFailed(uint256 err); + + /// @custom:error RepayFailed + error RepayFailed(uint256 err); + + /** + * @notice Constructor for NativeTokenGateway + * @param vWrappedNativeToken Address of wrapped native token market + */ + constructor(IVToken vWrappedNativeToken) { + ensureNonzeroAddress(address(vWrappedNativeToken)); + + vWNativeToken = vWrappedNativeToken; + wNativeToken = IWrappedNative(vWNativeToken.underlying()); + } + + /** + * @notice To receive Native when msg.data is empty + */ + receive() external payable {} + + /** + * @notice To receive Native when msg.data is not empty + */ + fallback() external payable {} + + /** + * @notice Wrap Native, get wNativeToken, mint vWNativeToken, and supply to the market. + * @param minter The address on behalf of whom the supply is performed. + * @custom:error ZeroAddressNotAllowed is thrown if address of minter is zero address + * @custom:error ZeroValueNotAllowed is thrown if mintAmount is zero + * @custom:error MintFailed is thrown if the mint operation fails + * @custom:event TokensWrappedAndSupplied is emitted when assets are supplied to the market + */ + function wrapAndSupply(address minter) external payable nonReentrant { + ensureNonzeroAddress(minter); + + uint256 mintAmount = msg.value; + ensureNonzeroValue(mintAmount); + + wNativeToken.deposit{ value: mintAmount }(); + IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), mintAmount); + + uint256 err = vWNativeToken.mintBehalf(minter, mintAmount); + if (err != NO_ERROR) revert MintFailed(err); + + IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), 0); + emit TokensWrappedAndSupplied(minter, address(vWNativeToken), mintAmount); + } + + /** + * @notice Redeem vWNativeToken, unwrap to Native Token, and send to the user + * @param redeemAmount The amount of underlying tokens to redeem + * @custom:error ZeroValueNotAllowed is thrown if redeemAmount is zero + * @custom:error RedeemFailed is thrown if the redeem operation fails + * @custom:event TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped + */ + function redeemUnderlyingAndUnwrap(uint256 redeemAmount) external nonReentrant { + _redeemAndUnwrap(redeemAmount, true); + } + + /** + * @notice Redeem vWNativeToken, unwrap to Native Token, and send to the user + * @param redeemTokens The amount of vWNative tokens to redeem + * @custom:error ZeroValueNotAllowed is thrown if redeemTokens is zero + * @custom:error RedeemFailed is thrown if the redeem operation fails + * @custom:event TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped + */ + function redeemAndUnwrap(uint256 redeemTokens) external nonReentrant { + _redeemAndUnwrap(redeemTokens, false); + } + + /** + * @dev Borrow wNativeToken, unwrap to Native, and send to the user + * @param borrowAmount The amount of underlying tokens to borrow + * @custom:error ZeroValueNotAllowed is thrown if borrowAmount is zero + * @custom:error BorrowFailed is thrown if the borrow operation fails + * @custom:event TokensBorrowedAndUnwrapped is emitted when assets are borrowed from a market and unwrapped + */ + function borrowAndUnwrap(uint256 borrowAmount) external nonReentrant { + ensureNonzeroValue(borrowAmount); + + uint256 err = vWNativeToken.borrowBehalf(msg.sender, borrowAmount); + if (err != NO_ERROR) revert BorrowFailed(err); + + wNativeToken.withdraw(borrowAmount); + _safeTransferNativeTokens(msg.sender, borrowAmount); + emit TokensBorrowedAndUnwrapped(msg.sender, address(vWNativeToken), borrowAmount); + } + + /** + * @notice Wrap Native, repay borrow in the market, and send remaining Native to the user + * @custom:error ZeroValueNotAllowed is thrown if repayAmount is zero + * @custom:error RepayFailed is thrown if the repay operation fails + * @custom:event TokensWrappedAndRepaid is emitted when assets are repaid to a market and unwrapped + */ + function wrapAndRepay() external payable nonReentrant { + uint256 repayAmount = msg.value; + ensureNonzeroValue(repayAmount); + + wNativeToken.deposit{ value: repayAmount }(); + IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), repayAmount); + + uint256 borrowBalanceBefore = vWNativeToken.borrowBalanceCurrent(msg.sender); + uint256 err = vWNativeToken.repayBorrowBehalf(msg.sender, repayAmount); + if (err != NO_ERROR) revert RepayFailed(err); + uint256 borrowBalanceAfter = vWNativeToken.borrowBalanceCurrent(msg.sender); + + IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), 0); + + if (borrowBalanceAfter == 0 && (repayAmount > borrowBalanceBefore)) { + uint256 dust; + unchecked { + dust = repayAmount - borrowBalanceBefore; + } + + wNativeToken.withdraw(dust); + _safeTransferNativeTokens(msg.sender, dust); + } + emit TokensWrappedAndRepaid(msg.sender, address(vWNativeToken), borrowBalanceBefore - borrowBalanceAfter); + } + + /** + * @notice Sweeps native assets (Native) from the contract and sends them to the owner + * @custom:event SweepNative is emitted when assets are swept from the contract + * @custom:access Controlled by Governance + */ + function sweepNative() external onlyOwner { + uint256 balance = address(this).balance; + + if (balance > 0) { + address owner_ = owner(); + _safeTransferNativeTokens(owner_, balance); + emit SweepNative(owner_, balance); + } + } + + /** + * @notice Sweeps the input token address tokens from the contract and sends them to the owner + * @param token Address of the token + * @custom:event SweepToken emits on success + * @custom:access Controlled by Governance + */ + function sweepToken(IERC20 token) external onlyOwner { + uint256 balance = token.balanceOf(address(this)); + + if (balance > 0) { + address owner_ = owner(); + token.safeTransfer(owner_, balance); + emit SweepToken(address(token), owner_, balance); + } + } + + /** + * @dev Redeems tokens, unwrap them to Native Token, and send to the user + * This function is internally called by `redeemUnderlyingAndUnwrap` and `redeemAndUnwrap` + * @param redeemTokens The amount of tokens to be redeemed. This can refer to either the underlying tokens directly or their equivalent vTokens + * @param isUnderlying A boolean flag indicating whether the redemption is for underlying tokens directly (`true`) or for their equivalent vTokens (`false`). + * @custom:error ZeroValueNotAllowed is thrown if redeemTokens is zero + * @custom:error RedeemFailed is thrown if the redeem operation fails + * @custom:event TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped + */ + function _redeemAndUnwrap(uint256 redeemTokens, bool isUnderlying) internal { + ensureNonzeroValue(redeemTokens); + + uint256 balanceBefore = wNativeToken.balanceOf(address(this)); + + if (isUnderlying) { + uint256 err = vWNativeToken.redeemUnderlyingBehalf(msg.sender, redeemTokens); + if (err != NO_ERROR) revert RedeemFailed(err); + } else { + uint256 err = vWNativeToken.redeemBehalf(msg.sender, redeemTokens); + if (err != NO_ERROR) revert RedeemFailed(err); + } + + uint256 balanceAfter = wNativeToken.balanceOf(address(this)); + uint256 redeemedAmount = balanceAfter - balanceBefore; + wNativeToken.withdraw(redeemedAmount); + + _safeTransferNativeTokens(msg.sender, redeemedAmount); + emit TokensRedeemedAndUnwrapped(msg.sender, address(vWNativeToken), redeemedAmount); + } + + /** + * @dev transfer Native tokens to an address, revert if it fails + * @param to recipient of the transfer + * @param value the amount to send + * @custom:error NativeTokenTransferFailed is thrown if the Native token transfer fails + */ + function _safeTransferNativeTokens(address to, uint256 value) internal { + (bool success, ) = to.call{ value: value }(new bytes(0)); + + if (!success) { + revert NativeTokenTransferFailed(); + } + } + + /** + * @dev Checks if the provided address is nonzero, reverts otherwise + * @param address_ Address to check + * @custom:error ZeroAddressNotAllowed is thrown if the provided address is a zero address + **/ + function ensureNonzeroAddress(address address_) internal pure { + if (address_ == address(0)) { + revert ZeroAddressNotAllowed(); + } + } + + /** + * @dev Checks if the provided value is nonzero, reverts otherwise + * @param value_ Value to check + * @custom:error ZeroValueNotAllowed is thrown if the provided value is 0 + */ + function ensureNonzeroValue(uint256 value_) internal pure { + if (value_ == 0) { + revert ZeroValueNotAllowed(); + } + } +} diff --git a/contracts/test/ERC20.sol b/contracts/test/ERC20.sol new file mode 100644 index 00000000..9dbc4d2a --- /dev/null +++ b/contracts/test/ERC20.sol @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: BSD-3-Clause +pragma solidity ^0.8.10; + +import { SafeMath } from "./SafeMath.sol"; + +interface ERC20Base { + event Approval(address indexed owner, address indexed spender, uint256 value); + event Transfer(address indexed from, address indexed to, uint256 value); + + function approve(address spender, uint256 value) external returns (bool); + + function totalSupply() external view returns (uint256); + + function allowance(address owner, address spender) external view returns (uint256); + + function balanceOf(address who) external view returns (uint256); +} + +abstract contract ERC20 is ERC20Base { + function transfer(address to, uint256 value) external virtual returns (bool); + + function transferFrom(address from, address to, uint256 value) external virtual returns (bool); +} + +abstract contract ERC20NS is ERC20Base { + function transfer(address to, uint256 value) external virtual; + + function transferFrom(address from, address to, uint256 value) external virtual; +} + +/** + * @title Standard ERC20 token + * @dev Implementation of the basic standard token. + * See https://github.com/ethereum/EIPs/issues/20 + */ +contract StandardToken is ERC20 { + using SafeMath for uint256; + + string public name; + string public symbol; + uint8 public decimals; + uint256 public override totalSupply; + mapping(address => mapping(address => uint256)) public override allowance; + mapping(address => uint256) public override balanceOf; + + constructor(uint256 _initialAmount, string memory _tokenName, uint8 _decimalUnits, string memory _tokenSymbol) { + totalSupply = _initialAmount; + balanceOf[msg.sender] = _initialAmount; + name = _tokenName; + symbol = _tokenSymbol; + decimals = _decimalUnits; + } + + function transfer(address dst, uint256 amount) external virtual override returns (bool) { + balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount, "Insufficient balance"); + balanceOf[dst] = balanceOf[dst].add(amount, "Balance overflow"); + emit Transfer(msg.sender, dst, amount); + return true; + } + + function transferFrom(address src, address dst, uint256 amount) external virtual override returns (bool) { + allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount, "Insufficient allowance"); + balanceOf[src] = balanceOf[src].sub(amount, "Insufficient balance"); + balanceOf[dst] = balanceOf[dst].add(amount, "Balance overflow"); + emit Transfer(src, dst, amount); + return true; + } + + function approve(address _spender, uint256 amount) external virtual override returns (bool) { + allowance[msg.sender][_spender] = amount; + emit Approval(msg.sender, _spender, amount); + return true; + } +} + +/** + * @title Non-Standard ERC20 token + * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` + * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca + */ +contract NonStandardToken is ERC20NS { + using SafeMath for uint256; + + string public name; + uint8 public decimals; + string public symbol; + uint256 public override totalSupply; + mapping(address => mapping(address => uint256)) public override allowance; + mapping(address => uint256) public override balanceOf; + + constructor(uint256 _initialAmount, string memory _tokenName, uint8 _decimalUnits, string memory _tokenSymbol) { + totalSupply = _initialAmount; + balanceOf[msg.sender] = _initialAmount; + name = _tokenName; + symbol = _tokenSymbol; + decimals = _decimalUnits; + } + + function transfer(address dst, uint256 amount) external override { + balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount, "Insufficient balance"); + balanceOf[dst] = balanceOf[dst].add(amount, "Balance overflow"); + emit Transfer(msg.sender, dst, amount); + } + + function transferFrom(address src, address dst, uint256 amount) external override { + allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount, "Insufficient allowance"); + balanceOf[src] = balanceOf[src].sub(amount, "Insufficient balance"); + balanceOf[dst] = balanceOf[dst].add(amount, "Balance overflow"); + emit Transfer(src, dst, amount); + } + + function approve(address _spender, uint256 amount) external override returns (bool) { + allowance[msg.sender][_spender] = amount; + emit Approval(msg.sender, _spender, amount); + return true; + } +} + +contract ERC20Harness is StandardToken { + using SafeMath for uint256; + // To support testing, we can specify addresses for which transferFrom should fail and return false + mapping(address => bool) public failTransferFromAddresses; + + // To support testing, we allow the contract to always fail `transfer`. + mapping(address => bool) public failTransferToAddresses; + + constructor( + uint256 _initialAmount, + string memory _tokenName, + uint8 _decimalUnits, + string memory _tokenSymbol + ) + StandardToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol) + /* solhint-disable-next-line no-empty-blocks */ + { + + } + + function transfer(address dst, uint256 amount) external override returns (bool success) { + // Added for testing purposes + if (failTransferToAddresses[dst]) { + return false; + } + balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount, "Insufficient balance"); + balanceOf[dst] = balanceOf[dst].add(amount, "Balance overflow"); + emit Transfer(msg.sender, dst, amount); + return true; + } + + function transferFrom(address src, address dst, uint256 amount) external override returns (bool success) { + // Added for testing purposes + if (failTransferFromAddresses[src]) { + return false; + } + allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount, "Insufficient allowance"); + balanceOf[src] = balanceOf[src].sub(amount, "Insufficient balance"); + balanceOf[dst] = balanceOf[dst].add(amount, "Balance overflow"); + emit Transfer(src, dst, amount); + return true; + } + + function harnessSetFailTransferFromAddress(address src, bool _fail) public { + failTransferFromAddresses[src] = _fail; + } + + function harnessSetFailTransferToAddress(address dst, bool _fail) public { + failTransferToAddresses[dst] = _fail; + } + + function harnessSetBalance(address _account, uint256 _amount) public { + balanceOf[_account] = _amount; + } +} diff --git a/contracts/test/SafeMath.sol b/contracts/test/SafeMath.sol new file mode 100644 index 00000000..569e8e8a --- /dev/null +++ b/contracts/test/SafeMath.sol @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: BSD-3-Clause +pragma solidity ^0.8.10; + +// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol +// Subject to the MIT license. + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, reverting on overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c; + unchecked { + c = a + b; + } + require(c >= a, "SafeMath: addition overflow"); + + return c; + } + + /** + * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + uint256 c; + unchecked { + c = a + b; + } + require(c >= a, errorMessage); + + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * - Subtraction cannot underflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + return sub(a, b, "SafeMath: subtraction underflow"); + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * - Subtraction cannot underflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + uint256 c = a - b; + + return c; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) { + return 0; + } + + uint256 c; + unchecked { + c = a * b; + } + require(c / a == b, "SafeMath: multiplication overflow"); + + return c; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) { + return 0; + } + + uint256 c; + unchecked { + c = a * b; + } + require(c / a == b, errorMessage); + + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers. + * Reverts on division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + return div(a, b, "SafeMath: division by zero"); + } + + /** + * @dev Returns the integer division of two unsigned integers. + * Reverts with custom message on division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + // Solidity only automatically asserts when dividing by 0 + require(b > 0, errorMessage); + uint256 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + + return c; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * Reverts when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + return mod(a, b, "SafeMath: modulo by zero"); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * Reverts with custom message when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b != 0, errorMessage); + return a % b; + } +} diff --git a/contracts/test/WrappedNative.sol b/contracts/test/WrappedNative.sol new file mode 100644 index 00000000..df650e6b --- /dev/null +++ b/contracts/test/WrappedNative.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: BSD-3-Clause +pragma solidity 0.8.25; + +contract WrappedNative { + string public name = "Wrapped Native"; + string public symbol = "WNATIVE"; + uint8 public decimals = 18; + + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) public allowance; + + event Approval(address indexed src, address indexed guy, uint256 wad); + event Transfer(address indexed src, address indexed dst, uint256 wad); + event Deposit(address indexed dst, uint256 wad); + event Withdrawal(address indexed src, uint256 wad); + + receive() external payable { + deposit(); + } + + function deposit() public payable { + // console.log("depositing:", msg.value); + balanceOf[msg.sender] += msg.value; + emit Deposit(msg.sender, msg.value); + } + + function withdraw(uint256 wad) public { + // console.log("withdrawing:", wad); + require(balanceOf[msg.sender] >= wad); + balanceOf[msg.sender] -= wad; + payable(msg.sender).transfer(wad); + emit Withdrawal(msg.sender, wad); + } + + function approve(address guy, uint256 wad) public returns (bool) { + allowance[msg.sender][guy] = wad; + emit Approval(msg.sender, guy, wad); + return true; + } + + function transfer(address dst, uint256 wad) public returns (bool) { + return transferFrom(msg.sender, dst, wad); + } + + function transferFrom(address src, address dst, uint256 wad) public returns (bool) { + require(balanceOf[src] >= wad); + + if (src != msg.sender && allowance[src][msg.sender] != type(uint256).max) { + require(allowance[src][msg.sender] >= wad); + allowance[src][msg.sender] -= wad; + } + + balanceOf[src] -= wad; + balanceOf[dst] += wad; + + emit Transfer(src, dst, wad); + + return true; + } + + function mint(uint256 value) public returns (bool) { + balanceOf[msg.sender] += value; + emit Transfer(address(0), msg.sender, value); + } + + function totalSupply() public view returns (uint256) { + return address(this).balance; + } +} diff --git a/contracts/test/imports.sol b/contracts/test/imports.sol new file mode 100644 index 00000000..fc4552c6 --- /dev/null +++ b/contracts/test/imports.sol @@ -0,0 +1,8 @@ +pragma solidity ^0.5.16; + +import { ComptrollerHarness } from "@venusprotocol/venus-protocol/contracts/test/ComptrollerHarness.sol"; +import { VToken } from "@venusprotocol/venus-protocol/contracts/Tokens/VTokens/VToken.sol"; +import { VBep20Delegator } from "@venusprotocol/venus-protocol/contracts/Tokens/VTokens/VBep20Delegator.sol"; +import { VBep20Harness } from "@venusprotocol/venus-protocol/contracts/test/VBep20Harness.sol"; +import { VBep20 } from "@venusprotocol/venus-protocol/contracts/Tokens/VTokens/VBep20.sol"; +import { ComptrollerLens } from "@venusprotocol/venus-protocol/contracts/Lens/ComptrollerLens.sol"; diff --git a/contracts/test/imports2.sol b/contracts/test/imports2.sol new file mode 100644 index 00000000..5838592f --- /dev/null +++ b/contracts/test/imports2.sol @@ -0,0 +1,20 @@ +pragma solidity ^0.8.0; + +// This file is needed to make hardhat and typechain generate artifacts for +// contracts we depend on (e.g. in tests or deployments) but not use directly. +// Another way to do this would be to use hardhat-dependency-compiler, but +// since we only have a couple of dependencies, installing a separate package +// seems an overhead. + +import { UpgradeableBeacon } from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; +import { BeaconProxy } from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { MockToken } from "@venusprotocol/venus-protocol/contracts/test/MockToken.sol"; +import { IAccessControlManagerV8 } from "@venusprotocol/governance-contracts/contracts/Governance/IAccessControlManagerV8.sol"; +import { Comptroller } from "@venusprotocol/isolated-pools/contracts/Comptroller.sol"; +import { VToken } from "@venusprotocol/isolated-pools/contracts/VToken.sol"; +import { PoolRegistry } from "@venusprotocol/isolated-pools/contracts/Pool/PoolRegistry.sol"; +import { Shortfall } from "@venusprotocol/isolated-pools/contracts/Shortfall/Shortfall.sol"; +import { ProtocolShareReserve } from "@venusprotocol/protocol-reserve/contracts/ProtocolReserve/ProtocolShareReserve.sol"; +import { MockPriceOracle } from "@venusprotocol/isolated-pools/contracts/test/Mocks/MockPriceOracle.sol"; +import { VTokenHarness } from "@venusprotocol/isolated-pools/contracts/test/VTokenHarness.sol"; diff --git a/deploy/01-native-token-gateway.ts b/deploy/01-native-token-gateway.ts new file mode 100644 index 00000000..af16bcdb --- /dev/null +++ b/deploy/01-native-token-gateway.ts @@ -0,0 +1,66 @@ +import { contracts as bscmainnet } from "@venusprotocol/governance-contracts/deployments/bscmainnet.json"; +import { ethers } from "hardhat"; +import { DeployFunction } from "hardhat-deploy/types"; +import { HardhatRuntimeEnvironment } from "hardhat/types"; + +interface VTokenConfig { + name: string; + address: string; +} + +const VWNativeInfo: { [key: string]: VTokenConfig[] } = { + bsctestnet: [ + { + name: "vWBNB_Core", + address: "0xd9E77847ec815E56ae2B9E69596C69b6972b0B1C", + }, + ], + bscmainnet: [ + { + name: "vWBNB_Core", + address: "0x6bCa74586218dB34cdB402295796b79663d816e9", + }, + ], +}; + +const getVWNativeTokens = (networkName: string): VTokenConfig[] => { + const vTokensInfo = VWNativeInfo[networkName]; + if (vTokensInfo === undefined) { + throw new Error(`config for network ${networkName} is not available.`); + } + + return vTokensInfo; +}; + +const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { + const { deployments, getNamedAccounts } = hre; + const { deploy } = deployments; + const { deployer } = await getNamedAccounts(); + const timelockAddress = bscmainnet.NormalTimelock.address; + + const vWNativesInfo = getVWNativeTokens(hre.getNetworkName()); + for (const vWNativeInfo of vWNativesInfo) { + await deploy(`NativeTokenGateway_${vWNativeInfo.name}`, { + contract: "contracts/Gateway/NativeTokenGateway.sol:NativeTokenGateway", + from: deployer, + args: [vWNativeInfo.address], + log: true, + autoMine: true, + skipIfAlreadyDeployed: false, + }); + + const nativeTokenGateway = await ethers.getContract(`NativeTokenGateway_${vWNativeInfo.name}`); + const targetOwner = timelockAddress || deployer; + if (hre.network.live && (await nativeTokenGateway.owner()) !== targetOwner) { + const tx = await nativeTokenGateway.transferOwnership(targetOwner); + await tx.wait(); + console.log(`Transferred ownership of NativeTokenGateway_${vWNativeInfo.name} to Timelock`); + } + } +}; + +func.tags = ["NativeTokenGateway"]; + +func.skip = async (hre: HardhatRuntimeEnvironment) => !hre.network.live; + +export default func; diff --git a/deployments/bscmainnet.json b/deployments/bscmainnet.json index b1a740e8..e302b524 100644 --- a/deployments/bscmainnet.json +++ b/deployments/bscmainnet.json @@ -1,5 +1,429 @@ { "name": "bscmainnet", "chainId": "56", - "contracts": {} + "contracts": { + "NativeTokenGateway_vWBNB_Core": { + "address": "0x5143eb18aA057Cd8BC9734cCfD2651823e71585f", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IVToken", + "name": "vWrappedNativeToken", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "err", + "type": "uint256" + } + ], + "name": "BorrowFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "err", + "type": "uint256" + } + ], + "name": "MintFailed", + "type": "error" + }, + { + "inputs": [], + "name": "NativeTokenTransferFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "err", + "type": "uint256" + } + ], + "name": "RedeemFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "err", + "type": "uint256" + } + ], + "name": "RepayFailed", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddressNotAllowed", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroValueNotAllowed", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "SweepNative", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "SweepToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensBorrowedAndUnwrapped", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensRedeemedAndUnwrapped", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensWrappedAndRepaid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensWrappedAndSupplied", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "acceptOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowAndUnwrap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemAndUnwrap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlyingAndUnwrap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sweepNative", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "sweepToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "vWNativeToken", + "outputs": [ + { + "internalType": "contract IVToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "wNativeToken", + "outputs": [ + { + "internalType": "contract IWrappedNative", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "wrapAndRepay", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "minter", + "type": "address" + } + ], + "name": "wrapAndSupply", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ] + } + } } diff --git a/deployments/bscmainnet/.chainId b/deployments/bscmainnet/.chainId new file mode 100644 index 00000000..2ebc6516 --- /dev/null +++ b/deployments/bscmainnet/.chainId @@ -0,0 +1 @@ +56 \ No newline at end of file diff --git a/deployments/bscmainnet/NativeTokenGateway_vWBNB_Core.json b/deployments/bscmainnet/NativeTokenGateway_vWBNB_Core.json new file mode 100644 index 00000000..d7db61a5 --- /dev/null +++ b/deployments/bscmainnet/NativeTokenGateway_vWBNB_Core.json @@ -0,0 +1,665 @@ +{ + "address": "0x5143eb18aA057Cd8BC9734cCfD2651823e71585f", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IVToken", + "name": "vWrappedNativeToken", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "err", + "type": "uint256" + } + ], + "name": "BorrowFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "err", + "type": "uint256" + } + ], + "name": "MintFailed", + "type": "error" + }, + { + "inputs": [], + "name": "NativeTokenTransferFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "err", + "type": "uint256" + } + ], + "name": "RedeemFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "err", + "type": "uint256" + } + ], + "name": "RepayFailed", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddressNotAllowed", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroValueNotAllowed", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "SweepNative", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "SweepToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensBorrowedAndUnwrapped", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensRedeemedAndUnwrapped", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensWrappedAndRepaid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensWrappedAndSupplied", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "acceptOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowAndUnwrap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemAndUnwrap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlyingAndUnwrap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sweepNative", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "sweepToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "vWNativeToken", + "outputs": [ + { + "internalType": "contract IVToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "wNativeToken", + "outputs": [ + { + "internalType": "contract IWrappedNative", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "wrapAndRepay", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "minter", + "type": "address" + } + ], + "name": "wrapAndSupply", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "transactionHash": "0x985d8a6fa28b339da2337f5c0514e89682128decf92ed55c3dce87ce2e7377e7", + "receipt": { + "to": null, + "from": "0x7Bf1Fe2C42E79dbA813Bf5026B7720935a55ec5f", + "contractAddress": "0x5143eb18aA057Cd8BC9734cCfD2651823e71585f", + "transactionIndex": 171, + "gasUsed": "1419962", + "logsBloom": "0x00000000000000000000000000002000000000000000000000808020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000008020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000400000000000000000000000000000000000000000000000000000", + "blockHash": "0x9dd83b524c44630e1330f205189a50604609752934d4c5a06f9aaa674f4159f7", + "transactionHash": "0x985d8a6fa28b339da2337f5c0514e89682128decf92ed55c3dce87ce2e7377e7", + "logs": [ + { + "transactionIndex": 171, + "blockNumber": 60900952, + "transactionHash": "0x985d8a6fa28b339da2337f5c0514e89682128decf92ed55c3dce87ce2e7377e7", + "address": "0x5143eb18aA057Cd8BC9734cCfD2651823e71585f", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000007bf1fe2c42e79dba813bf5026b7720935a55ec5f" + ], + "data": "0x", + "logIndex": 628, + "blockHash": "0x9dd83b524c44630e1330f205189a50604609752934d4c5a06f9aaa674f4159f7" + } + ], + "blockNumber": 60900952, + "cumulativeGasUsed": "22095656", + "status": 1, + "byzantium": true + }, + "args": ["0x6bCa74586218dB34cdB402295796b79663d816e9"], + "numDeployments": 1, + "solcInputHash": "c08fabaf010efcb44a3923892ebe65cc", + "metadata": "{\"compiler\":{\"version\":\"0.8.25+commit.b61c2a91\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IVToken\",\"name\":\"vWrappedNativeToken\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"err\",\"type\":\"uint256\"}],\"name\":\"BorrowFailed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"err\",\"type\":\"uint256\"}],\"name\":\"MintFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTokenTransferFailed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"err\",\"type\":\"uint256\"}],\"name\":\"RedeemFailed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"err\",\"type\":\"uint256\"}],\"name\":\"RepayFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroValueNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SweepNative\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SweepToken\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"vToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"TokensBorrowedAndUnwrapped\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"vToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"TokensRedeemedAndUnwrapped\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"vToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"TokensWrappedAndRepaid\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"vToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"TokensWrappedAndSupplied\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"borrowAmount\",\"type\":\"uint256\"}],\"name\":\"borrowAndUnwrap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pendingOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"redeemTokens\",\"type\":\"uint256\"}],\"name\":\"redeemAndUnwrap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"redeemAmount\",\"type\":\"uint256\"}],\"name\":\"redeemUnderlyingAndUnwrap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sweepNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"sweepToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vWNativeToken\",\"outputs\":[{\"internalType\":\"contract IVToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wNativeToken\",\"outputs\":[{\"internalType\":\"contract IWrappedNative\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrapAndRepay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"minter\",\"type\":\"address\"}],\"name\":\"wrapAndSupply\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Venus\",\"errors\":{\"BorrowFailed(uint256)\":[{\"custom:error\":\"BorrowFailed\"}],\"MintFailed(uint256)\":[{\"custom:error\":\"MintFailed\"}],\"RedeemFailed(uint256)\":[{\"custom:error\":\"RedeemFailed\"}],\"RepayFailed(uint256)\":[{\"custom:error\":\"RepayFailed\"}]},\"events\":{\"SweepNative(address,uint256)\":{\"details\":\"Emitted when native asset is swept from the contract\"},\"SweepToken(address,address,uint256)\":{\"details\":\"Emitted when token is swept from the contract\"},\"TokensBorrowedAndUnwrapped(address,address,uint256)\":{\"details\":\"Emitted when native tokens are borrowed and unwrapped\"},\"TokensRedeemedAndUnwrapped(address,address,uint256)\":{\"details\":\"Emitted when tokens are redeemed and then unwrapped to be sent to user\"},\"TokensWrappedAndRepaid(address,address,uint256)\":{\"details\":\"Emitted when native currency is wrapped and repaid\"},\"TokensWrappedAndSupplied(address,address,uint256)\":{\"details\":\"Emitted when native currency is supplied\"}},\"kind\":\"dev\",\"methods\":{\"acceptOwnership()\":{\"details\":\"The new owner accepts the ownership transfer.\"},\"borrowAndUnwrap(uint256)\":{\"custom:error\":\"ZeroValueNotAllowed is thrown if borrowAmount is zeroBorrowFailed is thrown if the borrow operation fails\",\"custom:event\":\"TokensBorrowedAndUnwrapped is emitted when assets are borrowed from a market and unwrapped\",\"details\":\"Borrow wNativeToken, unwrap to Native, and send to the user\",\"params\":{\"borrowAmount\":\"The amount of underlying tokens to borrow\"}},\"constructor\":{\"params\":{\"vWrappedNativeToken\":\"Address of wrapped native token market\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"pendingOwner()\":{\"details\":\"Returns the address of the pending owner.\"},\"redeemAndUnwrap(uint256)\":{\"custom:error\":\"ZeroValueNotAllowed is thrown if redeemTokens is zeroRedeemFailed is thrown if the redeem operation fails\",\"custom:event\":\"TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped\",\"params\":{\"redeemTokens\":\"The amount of vWNative tokens to redeem\"}},\"redeemUnderlyingAndUnwrap(uint256)\":{\"custom:error\":\"ZeroValueNotAllowed is thrown if redeemAmount is zeroRedeemFailed is thrown if the redeem operation fails\",\"custom:event\":\"TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped\",\"params\":{\"redeemAmount\":\"The amount of underlying tokens to redeem\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.\"},\"sweepNative()\":{\"custom:access\":\"Controlled by Governance\",\"custom:event\":\"SweepNative is emitted when assets are swept from the contract\"},\"sweepToken(address)\":{\"custom:access\":\"Controlled by Governance\",\"custom:event\":\"SweepToken emits on success\",\"params\":{\"token\":\"Address of the token\"}},\"transferOwnership(address)\":{\"details\":\"Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. Can only be called by the current owner.\"},\"wrapAndRepay()\":{\"custom:error\":\"ZeroValueNotAllowed is thrown if repayAmount is zeroRepayFailed is thrown if the repay operation fails\",\"custom:event\":\"TokensWrappedAndRepaid is emitted when assets are repaid to a market and unwrapped\"},\"wrapAndSupply(address)\":{\"custom:error\":\"ZeroAddressNotAllowed is thrown if address of minter is zero addressZeroValueNotAllowed is thrown if mintAmount is zeroMintFailed is thrown if the mint operation fails\",\"custom:event\":\"TokensWrappedAndSupplied is emitted when assets are supplied to the market\",\"params\":{\"minter\":\"The address on behalf of whom the supply is performed.\"}}},\"title\":\"NativeTokenGateway\",\"version\":1},\"userdoc\":{\"errors\":{\"NativeTokenTransferFailed()\":[{\"notice\":\"Thrown if transfer of native token fails\"}],\"ZeroAddressNotAllowed()\":[{\"notice\":\"Thrown if the supplied address is a zero address where it is not allowed\"}],\"ZeroValueNotAllowed()\":[{\"notice\":\"Thrown if the supplied value is 0 where it is not allowed\"}]},\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructor for NativeTokenGateway\"},\"redeemAndUnwrap(uint256)\":{\"notice\":\"Redeem vWNativeToken, unwrap to Native Token, and send to the user\"},\"redeemUnderlyingAndUnwrap(uint256)\":{\"notice\":\"Redeem vWNativeToken, unwrap to Native Token, and send to the user\"},\"sweepNative()\":{\"notice\":\"Sweeps native assets (Native) from the contract and sends them to the owner\"},\"sweepToken(address)\":{\"notice\":\"Sweeps the input token address tokens from the contract and sends them to the owner\"},\"vWNativeToken()\":{\"notice\":\"Address of wrapped native token market\"},\"wNativeToken()\":{\"notice\":\"Address of wrapped native token contract\"},\"wrapAndRepay()\":{\"notice\":\"Wrap Native, repay borrow in the market, and send remaining Native to the user\"},\"wrapAndSupply(address)\":{\"notice\":\"Wrap Native, get wNativeToken, mint vWNativeToken, and supply to the market.\"}},\"notice\":\"NativeTokenGateway contract facilitates interactions with a vToken market for native tokens (Native or wNativeToken)\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Gateway/NativeTokenGatewayCore.sol\":\"NativeTokenGateway\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@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\",\"keccak256\":\"0xba43b97fba0d32eb4254f6a5a297b39a19a247082a02d6e69349e071e2946218\",\"license\":\"MIT\"},\"@openzeppelin/contracts/access/Ownable2Step.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 \\\"./Ownable.sol\\\";\\n\\n/**\\n * @dev Contract module which provides access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * 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 Ownable2Step is Ownable {\\n address private _pendingOwner;\\n\\n event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Returns the address of the pending owner.\\n */\\n function pendingOwner() public view virtual returns (address) {\\n return _pendingOwner;\\n }\\n\\n /**\\n * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual override onlyOwner {\\n _pendingOwner = newOwner;\\n emit OwnershipTransferStarted(owner(), newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual override {\\n delete _pendingOwner;\\n super._transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev The new owner accepts the ownership transfer.\\n */\\n function acceptOwnership() public virtual {\\n address sender = _msgSender();\\n require(pendingOwner() == sender, \\\"Ownable2Step: caller is not the new owner\\\");\\n _transferOwnership(sender);\\n }\\n}\\n\",\"keccak256\":\"0xde231558366826d7cb61725af8147965a61c53b77a352cc8c9af38fc5a92ac3c\",\"license\":\"MIT\"},\"@openzeppelin/contracts/security/ReentrancyGuard.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\\n\\npragma solidity ^0.8.0;\\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 ReentrancyGuard {\\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 constructor() {\\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\",\"keccak256\":\"0xa535a5df777d44e945dd24aa43a11e44b024140fc340ad0dfe42acf4002aade1\",\"license\":\"MIT\"},\"@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\",\"keccak256\":\"0x287b55befed2961a7eabd7d7b1b2839cbca8a5b80ef8dcbb25ed3d4c2002c305\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.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 IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n *\\n * CAUTION: See Security Considerations above.\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xb264c03a3442eb37a68ad620cefd1182766b58bee6cec40343480392d6b14d69\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.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 \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n /**\\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\\n * non-reverting calls are assumed to be successful.\\n */\\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\\n _callOptionalReturn(token, abi.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(IERC20 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(IERC20 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(IERC20 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(IERC20 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(IERC20 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 IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n 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(IERC20 token, bytes memory data) private returns (bool) {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\\n // and not revert is the subcall reverts.\\n\\n (bool success, bytes memory returndata) = address(token).call(data);\\n return\\n success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));\\n }\\n}\\n\",\"keccak256\":\"0xabefac93435967b4d36a4fabcbdbb918d1f0b7ae3c3d85bc30923b326c927ed1\",\"license\":\"MIT\"},\"@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\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"@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\",\"keccak256\":\"0xa92e4fa126feb6907daa0513ddd816b2eb91f30a808de54f63c17d0e162c3439\",\"license\":\"MIT\"},\"contracts/Gateway/INativeTokenGateway.sol\":{\"content\":\"// SPDX-License-Identifier: BSD-3-Clause\\npragma solidity ^0.8.25;\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @title INativeTokenGateway\\n * @author Venus\\n * @notice Interface for NativeTokenGateway contract\\n */\\ninterface INativeTokenGateway {\\n /**\\n * @dev Emitted when native currency is supplied\\n */\\n event TokensWrappedAndSupplied(address indexed sender, address indexed vToken, uint256 amount);\\n\\n /**\\n * @dev Emitted when tokens are redeemed and then unwrapped to be sent to user\\n */\\n event TokensRedeemedAndUnwrapped(address indexed sender, address indexed vToken, uint256 amount);\\n\\n /**\\n * @dev Emitted when native tokens are borrowed and unwrapped\\n */\\n event TokensBorrowedAndUnwrapped(address indexed sender, address indexed vToken, uint256 amount);\\n\\n /**\\n * @dev Emitted when native currency is wrapped and repaid\\n */\\n event TokensWrappedAndRepaid(address indexed sender, address indexed vToken, uint256 amount);\\n\\n /**\\n * @dev Emitted when token is swept from the contract\\n */\\n event SweepToken(address indexed token, address indexed receiver, uint256 amount);\\n\\n /**\\n * @dev Emitted when native asset is swept from the contract\\n */\\n event SweepNative(address indexed receiver, uint256 amount);\\n\\n /**\\n * @notice Thrown if transfer of native token fails\\n */\\n error NativeTokenTransferFailed();\\n\\n /**\\n * @notice Thrown if the supplied address is a zero address where it is not allowed\\n */\\n error ZeroAddressNotAllowed();\\n\\n /**\\n * @notice Thrown if the supplied value is 0 where it is not allowed\\n */\\n error ZeroValueNotAllowed();\\n\\n /**\\n * @dev Wrap Native Token, get wNativeToken, mint vWNativeTokens, and supply to the market\\n * @param minter The address on behalf of whom the supply is performed\\n */\\n function wrapAndSupply(address minter) external payable;\\n\\n /**\\n * @dev Redeem vWNativeTokens, unwrap to Native Token, and send to the user\\n * @param redeemAmount The amount of underlying tokens to redeem\\n */\\n function redeemUnderlyingAndUnwrap(uint256 redeemAmount) external;\\n\\n /**\\n * @dev Redeem vWNativeTokens, unwrap to Native Token, and send to the user\\n * @param redeemTokens The amount of vWNative tokens to redeem\\n */\\n function redeemAndUnwrap(uint256 redeemTokens) external;\\n\\n /**\\n * @dev Borrow wNativeToken, unwrap to Native Token, and send to the user\\n * @param amount The amount of underlying tokens to borrow\\n */\\n function borrowAndUnwrap(uint256 amount) external;\\n\\n /**\\n * @dev Wrap Native Token, repay borrow in the market, and send remaining Native Token to the user\\n */\\n function wrapAndRepay() external payable;\\n\\n /**\\n * @dev Sweeps input token address tokens from the contract and sends them to the owner\\n */\\n function sweepToken(IERC20 token) external;\\n\\n /**\\n * @dev Sweeps native assets (Native Token) from the contract and sends them to the owner\\n */\\n function sweepNative() external;\\n}\\n\",\"keccak256\":\"0xbb97f05167348ef8510421f8530de125d83982f8ae1df5bf8167cfb3c8bf7fb9\",\"license\":\"BSD-3-Clause\"},\"contracts/Gateway/Interfaces/IVToken.sol\":{\"content\":\"// SPDX-License-Identifier: BSD-3-Clause\\npragma solidity ^0.8.25;\\n\\ninterface IVToken {\\n function mintBehalf(address receiver, uint256 mintAmount) external returns (uint256);\\n\\n function redeemUnderlyingBehalf(address redeemer, uint256 redeemAmount) external returns (uint256);\\n\\n function redeemBehalf(address redeemer, uint256 redeemTokens) external returns (uint256);\\n\\n function repayBorrowBehalf(address borrower, uint256 repayAmount) external returns (uint256);\\n\\n function borrowBehalf(address borrower, uint256 borrowAmount) external returns (uint256);\\n\\n function borrowBalanceCurrent(address account) external returns (uint256);\\n\\n function underlying() external returns (address);\\n\\n function exchangeRateCurrent() external returns (uint256);\\n\\n function transferFrom(address from, address to, uint256 amount) external returns (bool);\\n\\n function redeem(uint256 redeemTokens) external returns (uint256);\\n}\\n\",\"keccak256\":\"0xbb2bca2f551d9859daba74a6f30a75b960edd392edbfe658008813cb3a630939\",\"license\":\"BSD-3-Clause\"},\"contracts/Gateway/Interfaces/IWrappedNative.sol\":{\"content\":\"// SPDX-License-Identifier: BSD-3-Clause\\npragma solidity ^0.8.25;\\n\\ninterface IWrappedNative {\\n function deposit() external payable;\\n\\n function withdraw(uint256) external;\\n\\n function approve(address guy, uint256 wad) external returns (bool);\\n\\n function transferFrom(address src, address dst, uint256 wad) external returns (bool);\\n\\n function transfer(address dst, uint256 wad) external returns (bool);\\n\\n function balanceOf(address account) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x71e46aaa5ca7af98667bcf399b704c1af9f051af8842abb2c4d26632dd40b9e7\",\"license\":\"BSD-3-Clause\"},\"contracts/Gateway/NativeTokenGatewayCore.sol\":{\"content\":\"// SPDX-License-Identifier: BSD-3-Clause\\npragma solidity 0.8.25;\\n\\nimport { Ownable2Step } from \\\"@openzeppelin/contracts/access/Ownable2Step.sol\\\";\\nimport { SafeERC20, IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { ReentrancyGuard } from \\\"@openzeppelin/contracts/security/ReentrancyGuard.sol\\\";\\n\\nimport { IWrappedNative } from \\\"./Interfaces/IWrappedNative.sol\\\";\\nimport { INativeTokenGateway } from \\\"./INativeTokenGateway.sol\\\";\\nimport { IVToken } from \\\"./Interfaces/IVToken.sol\\\";\\n\\n/**\\n * @title NativeTokenGateway\\n * @author Venus\\n * @notice NativeTokenGateway contract facilitates interactions with a vToken market for native tokens (Native or wNativeToken)\\n */\\ncontract NativeTokenGateway is INativeTokenGateway, Ownable2Step, ReentrancyGuard {\\n using SafeERC20 for IERC20;\\n\\n /// @notice Error code representing no errors in Venus operations\\n uint256 internal constant NO_ERROR = 0;\\n\\n /**\\n * @notice Address of wrapped native token contract\\n */\\n IWrappedNative public immutable wNativeToken;\\n\\n /**\\n * @notice Address of wrapped native token market\\n */\\n IVToken public immutable vWNativeToken;\\n\\n /// @custom:error RedeemFailed\\n error RedeemFailed(uint256 err);\\n\\n /// @custom:error BorrowFailed\\n error BorrowFailed(uint256 err);\\n\\n /// @custom:error MintFailed\\n error MintFailed(uint256 err);\\n\\n /// @custom:error RepayFailed\\n error RepayFailed(uint256 err);\\n\\n /**\\n * @notice Constructor for NativeTokenGateway\\n * @param vWrappedNativeToken Address of wrapped native token market\\n */\\n constructor(IVToken vWrappedNativeToken) {\\n ensureNonzeroAddress(address(vWrappedNativeToken));\\n\\n vWNativeToken = vWrappedNativeToken;\\n wNativeToken = IWrappedNative(vWNativeToken.underlying());\\n }\\n\\n /**\\n * @notice To receive Native when msg.data is empty\\n */\\n receive() external payable {}\\n\\n /**\\n * @notice To receive Native when msg.data is not empty\\n */\\n fallback() external payable {}\\n\\n /**\\n * @notice Wrap Native, get wNativeToken, mint vWNativeToken, and supply to the market.\\n * @param minter The address on behalf of whom the supply is performed.\\n * @custom:error ZeroAddressNotAllowed is thrown if address of minter is zero address\\n * @custom:error ZeroValueNotAllowed is thrown if mintAmount is zero\\n * @custom:error MintFailed is thrown if the mint operation fails\\n * @custom:event TokensWrappedAndSupplied is emitted when assets are supplied to the market\\n */\\n function wrapAndSupply(address minter) external payable nonReentrant {\\n ensureNonzeroAddress(minter);\\n\\n uint256 mintAmount = msg.value;\\n ensureNonzeroValue(mintAmount);\\n\\n wNativeToken.deposit{ value: mintAmount }();\\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), mintAmount);\\n\\n uint256 err = vWNativeToken.mintBehalf(minter, mintAmount);\\n if (err != NO_ERROR) revert MintFailed(err);\\n\\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), 0);\\n emit TokensWrappedAndSupplied(minter, address(vWNativeToken), mintAmount);\\n }\\n\\n /**\\n * @notice Redeem vWNativeToken, unwrap to Native Token, and send to the user\\n * @param redeemAmount The amount of underlying tokens to redeem\\n * @custom:error ZeroValueNotAllowed is thrown if redeemAmount is zero\\n * @custom:error RedeemFailed is thrown if the redeem operation fails\\n * @custom:event TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped\\n */\\n function redeemUnderlyingAndUnwrap(uint256 redeemAmount) external nonReentrant {\\n _redeemAndUnwrap(redeemAmount, true);\\n }\\n\\n /**\\n * @notice Redeem vWNativeToken, unwrap to Native Token, and send to the user\\n * @param redeemTokens The amount of vWNative tokens to redeem\\n * @custom:error ZeroValueNotAllowed is thrown if redeemTokens is zero\\n * @custom:error RedeemFailed is thrown if the redeem operation fails\\n * @custom:event TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped\\n */\\n function redeemAndUnwrap(uint256 redeemTokens) external nonReentrant {\\n _redeemAndUnwrap(redeemTokens, false);\\n }\\n\\n /**\\n * @dev Borrow wNativeToken, unwrap to Native, and send to the user\\n * @param borrowAmount The amount of underlying tokens to borrow\\n * @custom:error ZeroValueNotAllowed is thrown if borrowAmount is zero\\n * @custom:error BorrowFailed is thrown if the borrow operation fails\\n * @custom:event TokensBorrowedAndUnwrapped is emitted when assets are borrowed from a market and unwrapped\\n */\\n function borrowAndUnwrap(uint256 borrowAmount) external nonReentrant {\\n ensureNonzeroValue(borrowAmount);\\n\\n uint256 err = vWNativeToken.borrowBehalf(msg.sender, borrowAmount);\\n if (err != NO_ERROR) revert BorrowFailed(err);\\n\\n wNativeToken.withdraw(borrowAmount);\\n _safeTransferNativeTokens(msg.sender, borrowAmount);\\n emit TokensBorrowedAndUnwrapped(msg.sender, address(vWNativeToken), borrowAmount);\\n }\\n\\n /**\\n * @notice Wrap Native, repay borrow in the market, and send remaining Native to the user\\n * @custom:error ZeroValueNotAllowed is thrown if repayAmount is zero\\n * @custom:error RepayFailed is thrown if the repay operation fails\\n * @custom:event TokensWrappedAndRepaid is emitted when assets are repaid to a market and unwrapped\\n */\\n function wrapAndRepay() external payable nonReentrant {\\n uint256 repayAmount = msg.value;\\n ensureNonzeroValue(repayAmount);\\n\\n wNativeToken.deposit{ value: repayAmount }();\\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), repayAmount);\\n\\n uint256 borrowBalanceBefore = vWNativeToken.borrowBalanceCurrent(msg.sender);\\n uint256 err = vWNativeToken.repayBorrowBehalf(msg.sender, repayAmount);\\n if (err != NO_ERROR) revert RepayFailed(err);\\n uint256 borrowBalanceAfter = vWNativeToken.borrowBalanceCurrent(msg.sender);\\n\\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), 0);\\n\\n if (borrowBalanceAfter == 0 && (repayAmount > borrowBalanceBefore)) {\\n uint256 dust;\\n unchecked {\\n dust = repayAmount - borrowBalanceBefore;\\n }\\n\\n wNativeToken.withdraw(dust);\\n _safeTransferNativeTokens(msg.sender, dust);\\n }\\n emit TokensWrappedAndRepaid(msg.sender, address(vWNativeToken), borrowBalanceBefore - borrowBalanceAfter);\\n }\\n\\n /**\\n * @notice Sweeps native assets (Native) from the contract and sends them to the owner\\n * @custom:event SweepNative is emitted when assets are swept from the contract\\n * @custom:access Controlled by Governance\\n */\\n function sweepNative() external onlyOwner {\\n uint256 balance = address(this).balance;\\n\\n if (balance > 0) {\\n address owner_ = owner();\\n _safeTransferNativeTokens(owner_, balance);\\n emit SweepNative(owner_, balance);\\n }\\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(IERC20 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 /**\\n * @dev Redeems tokens, unwrap them to Native Token, and send to the user\\n * This function is internally called by `redeemUnderlyingAndUnwrap` and `redeemAndUnwrap`\\n * @param redeemTokens The amount of tokens to be redeemed. This can refer to either the underlying tokens directly or their equivalent vTokens\\n * @param isUnderlying A boolean flag indicating whether the redemption is for underlying tokens directly (`true`) or for their equivalent vTokens (`false`).\\n * @custom:error ZeroValueNotAllowed is thrown if redeemTokens is zero\\n * @custom:error RedeemFailed is thrown if the redeem operation fails\\n * @custom:event TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped\\n */\\n function _redeemAndUnwrap(uint256 redeemTokens, bool isUnderlying) internal {\\n ensureNonzeroValue(redeemTokens);\\n\\n uint256 balanceBefore = wNativeToken.balanceOf(address(this));\\n\\n if (isUnderlying) {\\n uint256 err = vWNativeToken.redeemUnderlyingBehalf(msg.sender, redeemTokens);\\n if (err != NO_ERROR) revert RedeemFailed(err);\\n } else {\\n uint256 err = vWNativeToken.redeemBehalf(msg.sender, redeemTokens);\\n if (err != NO_ERROR) revert RedeemFailed(err);\\n }\\n\\n uint256 balanceAfter = wNativeToken.balanceOf(address(this));\\n uint256 redeemedAmount = balanceAfter - balanceBefore;\\n wNativeToken.withdraw(redeemedAmount);\\n\\n _safeTransferNativeTokens(msg.sender, redeemedAmount);\\n emit TokensRedeemedAndUnwrapped(msg.sender, address(vWNativeToken), redeemedAmount);\\n }\\n\\n /**\\n * @dev transfer Native tokens to an address, revert if it fails\\n * @param to recipient of the transfer\\n * @param value the amount to send\\n * @custom:error NativeTokenTransferFailed is thrown if the Native token transfer fails\\n */\\n function _safeTransferNativeTokens(address to, uint256 value) internal {\\n (bool success, ) = to.call{ value: value }(new bytes(0));\\n\\n if (!success) {\\n revert NativeTokenTransferFailed();\\n }\\n }\\n\\n /**\\n * @dev 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\\n **/\\n function ensureNonzeroAddress(address address_) internal pure {\\n if (address_ == address(0)) {\\n revert ZeroAddressNotAllowed();\\n }\\n }\\n\\n /**\\n * @dev 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\\n */\\n function ensureNonzeroValue(uint256 value_) internal pure {\\n if (value_ == 0) {\\n revert ZeroValueNotAllowed();\\n }\\n }\\n}\\n\",\"keccak256\":\"0xbb88319f2ede452eb55661c02c14eb61d091159a104b2d236b5dcae35ea0c522\",\"license\":\"BSD-3-Clause\"}},\"version\":1}", + "bytecode": "0x60c060405234801561000f575f80fd5b50604051611a1e380380611a1e83398101604081905261002e9161016a565b610037336100c4565b6001600255610045816100e0565b6001600160a01b03811660a081905260408051636f307dc360e01b81529051636f307dc39160048082019260209290919082900301815f875af115801561008e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100b2919061016a565b6001600160a01b03166080525061018c565b600180546001600160a01b03191690556100dd81610107565b50565b6001600160a01b0381166100dd576040516342bcdf7f60e11b815260040160405180910390fd5b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146100dd575f80fd5b5f6020828403121561017a575f80fd5b815161018581610156565b9392505050565b60805160a0516117bb6102635f395f818161010d015281816104670152818161058c015281816106a2015281816106f1015281816107b0015281816107d7015281816109db01528181610a1901528181610ab401528181610b5901528181610bfc01528181610cc201528181610f1401528181610fce015261118d01525f818161015c01528181610513015281816106040152818161067e0152818161078e0152818161093d015281816109b701528181610bda01528181610c4d01528181610e7d0152818161107d015261111401526117bb5ff3fe6080604052600436106100d4575f3560e01c80638da5cb5b11610078578063ab803a7611610055578063ab803a7614610232578063e30c397814610246578063f2fde38b14610263578063ff0f4abd1461028257005b80638da5cb5b146101e45780639cc60d4414610200578063a86f82211461021f57005b8063715018a6116100b1578063715018a61461017e57806379ba50971461019257806385ceb1e4146101a657806389f1cf38146101c557005b80631be19560146100dd57806355a490a7146100fc57806359c91f191461014b57005b366100db57005b005b3480156100e8575f80fd5b506100db6100f73660046116ac565b61028a565b348015610107575f80fd5b5061012f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b348015610156575f80fd5b5061012f7f000000000000000000000000000000000000000000000000000000000000000081565b348015610189575f80fd5b506100db610377565b34801561019d575f80fd5b506100db61038a565b3480156101b1575f80fd5b506100db6101c03660046116ce565b610409565b3480156101d0575f80fd5b506100db6101df3660046116ce565b610426565b3480156101ef575f80fd5b505f546001600160a01b031661012f565b34801561020b575f80fd5b506100db61021a3660046116ce565b610438565b6100db61022d3660046116ac565b6105e7565b34801561023d575f80fd5b506100db61084e565b348015610251575f80fd5b506001546001600160a01b031661012f565b34801561026e575f80fd5b506100db61027d3660046116ac565b6108b9565b6100db610929565b610292610d2c565b6040516370a0823160e01b81523060048201525f906001600160a01b038316906370a0823190602401602060405180830381865afa1580156102d6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102fa91906116e5565b90508015610373575f80546001600160a01b031690506103246001600160a01b0384168284610d85565b806001600160a01b0316836001600160a01b03167f6d25be279134f4ecaa4770aff0c3d916d9e7c5ef37b65ed95dbdba411f5d54d58460405161036991815260200190565b60405180910390a3505b5050565b61037f610d2c565b6103885f610ded565b565b60015433906001600160a01b031681146103fd5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084015b60405180910390fd5b61040681610ded565b50565b610411610e06565b61041c816001610e5d565b6104066001600255565b61042e610e06565b61041c815f610e5d565b610440610e06565b610449816111e4565b60405163856e5bb360e01b8152336004820152602481018290525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063856e5bb3906044016020604051808303815f875af11580156104b5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104d991906116e5565b905080156104fd5760405163158f1c0f60e01b8152600481018290526024016103f4565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024015f604051808303815f87803b15801561055c575f80fd5b505af115801561056e573d5f803e3d5ffd5b5050505061057c3383611204565b6040518281526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169033907f3b325d03ea6fc2aa5ba54c0fd65bb0febe127cb8c7ff01f190fcddf2893b80699060200160405180910390a3506104066001600255565b6105ef610e06565b6105f88161128e565b34610602816111e4565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b15801561065b575f80fd5b505af115801561066d573d5f803e3d5ffd5b506106c99350506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691507f00000000000000000000000000000000000000000000000000000000000000009050836112b5565b6040516323323e0360e01b81526001600160a01b038381166004830152602482018390525f917f0000000000000000000000000000000000000000000000000000000000000000909116906323323e03906044016020604051808303815f875af1158015610739573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061075d91906116e5565b905080156107815760405163ac55121f60e01b8152600481018290526024016103f4565b6107d56001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f00000000000000000000000000000000000000000000000000000000000000005f6112b5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03167ffc54dd2cff8bcf58b0746818b1d9aac56525760131df031a96427ecd6e5612448460405161083a91815260200190565b60405180910390a350506104066001600255565b610856610d2c565b478015610406575f546001600160a01b03166108728183611204565b806001600160a01b03167f0a1dd7c5bdc40ecbdefc1bfda22f1dfb98c8fc3e3940aab73ad7fba37720d0a0836040516108ad91815260200190565b60405180910390a25050565b6108c1610d2c565b600180546001600160a01b0383166001600160a01b031990911681179091556108f15f546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b610931610e06565b3461093b816111e4565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b158015610994575f80fd5b505af11580156109a6573d5f803e3d5ffd5b50610a029350506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691507f00000000000000000000000000000000000000000000000000000000000000009050836112b5565b6040516305eff7ef60e21b81523360048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906317bfdfbc906024016020604051808303815f875af1158015610a67573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a8b91906116e5565b6040516304c11f0360e31b8152336004820152602481018490529091505f906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632608f818906044016020604051808303815f875af1158015610afa573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b1e91906116e5565b90508015610b42576040516305e4427960e11b8152600481018290526024016103f4565b6040516305eff7ef60e21b81523360048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906317bfdfbc906024016020604051808303815f875af1158015610ba7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bcb91906116e5565b9050610c216001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f00000000000000000000000000000000000000000000000000000000000000005f6112b5565b80158015610c2e57508284115b15610cb857604051632e1a7d4d60e01b815283850360048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024015f604051808303815f87803b158015610c96575f80fd5b505af1158015610ca8573d5f803e3d5ffd5b50505050610cb63382611204565b505b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016337e2a489ca326b23ea0117956ee9d62960c53a81b8f57fafd608e56f57f324168610d0d84876116fc565b60405190815260200160405180910390a3505050506103886001600255565b5f546001600160a01b031633146103885760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103f4565b6040516001600160a01b038316602482015260448101829052610de890849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611349565b505050565b600180546001600160a01b03191690556104068161141c565b6002805403610e575760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103f4565b60028055565b610e66826111e4565b6040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610eca573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610eee91906116e5565b90508115610fb057604051636f9d28b760e11b8152336004820152602481018490525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063df3a516e906044016020604051808303815f875af1158015610f62573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f8691906116e5565b90508015610faa5760405163eeddaac560e01b8152600481018290526024016103f4565b50611066565b604051631085e02960e11b8152336004820152602481018490525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063210bc052906044016020604051808303815f875af115801561101c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061104091906116e5565b905080156110645760405163eeddaac560e01b8152600481018290526024016103f4565b505b6040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156110ca573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110ee91906116e5565b90505f6110fb83836116fc565b604051632e1a7d4d60e01b8152600481018290529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024015f604051808303815f87803b15801561115d575f80fd5b505af115801561116f573d5f803e3d5ffd5b5050505061117d3382611204565b6040518181526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169033907faf321c699f4cc4970eef3edf8fe2a0a395a3f5b62c6e91958cad3d424952436b9060200160405180910390a35050505050565b805f036104065760405163273e150360e21b815260040160405180910390fd5b604080515f808252602082019092526001600160a01b03841690839060405161122d919061171b565b5f6040518083038185875af1925050503d805f8114611267576040519150601f19603f3d011682016040523d82523d5f602084013e61126c565b606091505b5050905080610de857604051630c08bcb960e21b815260040160405180910390fd5b6001600160a01b038116610406576040516342bcdf7f60e11b815260040160405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052611306848261146b565b611343576040516001600160a01b03841660248201525f604482015261133990859063095ea7b360e01b90606401610db1565b6113438482611349565b50505050565b5f61139d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661150e9092919063ffffffff16565b905080515f14806113bd5750808060200190518101906113bd9190611731565b610de85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016103f4565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f805f846001600160a01b031684604051611486919061171b565b5f604051808303815f865af19150503d805f81146114bf576040519150601f19603f3d011682016040523d82523d5f602084013e6114c4565b606091505b50915091508180156114ee5750805115806114ee5750808060200190518101906114ee9190611731565b801561150357506001600160a01b0385163b15155b925050505b92915050565b606061151c84845f85611524565b949350505050565b6060824710156115855760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016103f4565b5f80866001600160a01b031685876040516115a0919061171b565b5f6040518083038185875af1925050503d805f81146115da576040519150601f19603f3d011682016040523d82523d5f602084013e6115df565b606091505b50915091506115f0878383876115fb565b979650505050505050565b606083156116695782515f03611662576001600160a01b0385163b6116625760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103f4565b508161151c565b61151c838381511561167e5781518083602001fd5b8060405162461bcd60e51b81526004016103f49190611750565b6001600160a01b0381168114610406575f80fd5b5f602082840312156116bc575f80fd5b81356116c781611698565b9392505050565b5f602082840312156116de575f80fd5b5035919050565b5f602082840312156116f5575f80fd5b5051919050565b8181038181111561150857634e487b7160e01b5f52601160045260245ffd5b5f82518060208501845e5f920191825250919050565b5f60208284031215611741575f80fd5b815180151581146116c7575f80fd5b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056fea26469706673582212208c3032e5d1d392610ad04108f5b5b7bb95becc9f021ff4bba0c847dc71c8783664736f6c63430008190033", + "deployedBytecode": "0x6080604052600436106100d4575f3560e01c80638da5cb5b11610078578063ab803a7611610055578063ab803a7614610232578063e30c397814610246578063f2fde38b14610263578063ff0f4abd1461028257005b80638da5cb5b146101e45780639cc60d4414610200578063a86f82211461021f57005b8063715018a6116100b1578063715018a61461017e57806379ba50971461019257806385ceb1e4146101a657806389f1cf38146101c557005b80631be19560146100dd57806355a490a7146100fc57806359c91f191461014b57005b366100db57005b005b3480156100e8575f80fd5b506100db6100f73660046116ac565b61028a565b348015610107575f80fd5b5061012f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b348015610156575f80fd5b5061012f7f000000000000000000000000000000000000000000000000000000000000000081565b348015610189575f80fd5b506100db610377565b34801561019d575f80fd5b506100db61038a565b3480156101b1575f80fd5b506100db6101c03660046116ce565b610409565b3480156101d0575f80fd5b506100db6101df3660046116ce565b610426565b3480156101ef575f80fd5b505f546001600160a01b031661012f565b34801561020b575f80fd5b506100db61021a3660046116ce565b610438565b6100db61022d3660046116ac565b6105e7565b34801561023d575f80fd5b506100db61084e565b348015610251575f80fd5b506001546001600160a01b031661012f565b34801561026e575f80fd5b506100db61027d3660046116ac565b6108b9565b6100db610929565b610292610d2c565b6040516370a0823160e01b81523060048201525f906001600160a01b038316906370a0823190602401602060405180830381865afa1580156102d6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102fa91906116e5565b90508015610373575f80546001600160a01b031690506103246001600160a01b0384168284610d85565b806001600160a01b0316836001600160a01b03167f6d25be279134f4ecaa4770aff0c3d916d9e7c5ef37b65ed95dbdba411f5d54d58460405161036991815260200190565b60405180910390a3505b5050565b61037f610d2c565b6103885f610ded565b565b60015433906001600160a01b031681146103fd5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084015b60405180910390fd5b61040681610ded565b50565b610411610e06565b61041c816001610e5d565b6104066001600255565b61042e610e06565b61041c815f610e5d565b610440610e06565b610449816111e4565b60405163856e5bb360e01b8152336004820152602481018290525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063856e5bb3906044016020604051808303815f875af11580156104b5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104d991906116e5565b905080156104fd5760405163158f1c0f60e01b8152600481018290526024016103f4565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024015f604051808303815f87803b15801561055c575f80fd5b505af115801561056e573d5f803e3d5ffd5b5050505061057c3383611204565b6040518281526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169033907f3b325d03ea6fc2aa5ba54c0fd65bb0febe127cb8c7ff01f190fcddf2893b80699060200160405180910390a3506104066001600255565b6105ef610e06565b6105f88161128e565b34610602816111e4565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b15801561065b575f80fd5b505af115801561066d573d5f803e3d5ffd5b506106c99350506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691507f00000000000000000000000000000000000000000000000000000000000000009050836112b5565b6040516323323e0360e01b81526001600160a01b038381166004830152602482018390525f917f0000000000000000000000000000000000000000000000000000000000000000909116906323323e03906044016020604051808303815f875af1158015610739573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061075d91906116e5565b905080156107815760405163ac55121f60e01b8152600481018290526024016103f4565b6107d56001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f00000000000000000000000000000000000000000000000000000000000000005f6112b5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03167ffc54dd2cff8bcf58b0746818b1d9aac56525760131df031a96427ecd6e5612448460405161083a91815260200190565b60405180910390a350506104066001600255565b610856610d2c565b478015610406575f546001600160a01b03166108728183611204565b806001600160a01b03167f0a1dd7c5bdc40ecbdefc1bfda22f1dfb98c8fc3e3940aab73ad7fba37720d0a0836040516108ad91815260200190565b60405180910390a25050565b6108c1610d2c565b600180546001600160a01b0383166001600160a01b031990911681179091556108f15f546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b610931610e06565b3461093b816111e4565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b158015610994575f80fd5b505af11580156109a6573d5f803e3d5ffd5b50610a029350506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691507f00000000000000000000000000000000000000000000000000000000000000009050836112b5565b6040516305eff7ef60e21b81523360048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906317bfdfbc906024016020604051808303815f875af1158015610a67573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a8b91906116e5565b6040516304c11f0360e31b8152336004820152602481018490529091505f906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632608f818906044016020604051808303815f875af1158015610afa573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b1e91906116e5565b90508015610b42576040516305e4427960e11b8152600481018290526024016103f4565b6040516305eff7ef60e21b81523360048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906317bfdfbc906024016020604051808303815f875af1158015610ba7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bcb91906116e5565b9050610c216001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f00000000000000000000000000000000000000000000000000000000000000005f6112b5565b80158015610c2e57508284115b15610cb857604051632e1a7d4d60e01b815283850360048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024015f604051808303815f87803b158015610c96575f80fd5b505af1158015610ca8573d5f803e3d5ffd5b50505050610cb63382611204565b505b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016337e2a489ca326b23ea0117956ee9d62960c53a81b8f57fafd608e56f57f324168610d0d84876116fc565b60405190815260200160405180910390a3505050506103886001600255565b5f546001600160a01b031633146103885760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103f4565b6040516001600160a01b038316602482015260448101829052610de890849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611349565b505050565b600180546001600160a01b03191690556104068161141c565b6002805403610e575760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103f4565b60028055565b610e66826111e4565b6040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610eca573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610eee91906116e5565b90508115610fb057604051636f9d28b760e11b8152336004820152602481018490525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063df3a516e906044016020604051808303815f875af1158015610f62573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f8691906116e5565b90508015610faa5760405163eeddaac560e01b8152600481018290526024016103f4565b50611066565b604051631085e02960e11b8152336004820152602481018490525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063210bc052906044016020604051808303815f875af115801561101c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061104091906116e5565b905080156110645760405163eeddaac560e01b8152600481018290526024016103f4565b505b6040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156110ca573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110ee91906116e5565b90505f6110fb83836116fc565b604051632e1a7d4d60e01b8152600481018290529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024015f604051808303815f87803b15801561115d575f80fd5b505af115801561116f573d5f803e3d5ffd5b5050505061117d3382611204565b6040518181526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169033907faf321c699f4cc4970eef3edf8fe2a0a395a3f5b62c6e91958cad3d424952436b9060200160405180910390a35050505050565b805f036104065760405163273e150360e21b815260040160405180910390fd5b604080515f808252602082019092526001600160a01b03841690839060405161122d919061171b565b5f6040518083038185875af1925050503d805f8114611267576040519150601f19603f3d011682016040523d82523d5f602084013e61126c565b606091505b5050905080610de857604051630c08bcb960e21b815260040160405180910390fd5b6001600160a01b038116610406576040516342bcdf7f60e11b815260040160405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052611306848261146b565b611343576040516001600160a01b03841660248201525f604482015261133990859063095ea7b360e01b90606401610db1565b6113438482611349565b50505050565b5f61139d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661150e9092919063ffffffff16565b905080515f14806113bd5750808060200190518101906113bd9190611731565b610de85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016103f4565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f805f846001600160a01b031684604051611486919061171b565b5f604051808303815f865af19150503d805f81146114bf576040519150601f19603f3d011682016040523d82523d5f602084013e6114c4565b606091505b50915091508180156114ee5750805115806114ee5750808060200190518101906114ee9190611731565b801561150357506001600160a01b0385163b15155b925050505b92915050565b606061151c84845f85611524565b949350505050565b6060824710156115855760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016103f4565b5f80866001600160a01b031685876040516115a0919061171b565b5f6040518083038185875af1925050503d805f81146115da576040519150601f19603f3d011682016040523d82523d5f602084013e6115df565b606091505b50915091506115f0878383876115fb565b979650505050505050565b606083156116695782515f03611662576001600160a01b0385163b6116625760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103f4565b508161151c565b61151c838381511561167e5781518083602001fd5b8060405162461bcd60e51b81526004016103f49190611750565b6001600160a01b0381168114610406575f80fd5b5f602082840312156116bc575f80fd5b81356116c781611698565b9392505050565b5f602082840312156116de575f80fd5b5035919050565b5f602082840312156116f5575f80fd5b5051919050565b8181038181111561150857634e487b7160e01b5f52601160045260245ffd5b5f82518060208501845e5f920191825250919050565b5f60208284031215611741575f80fd5b815180151581146116c7575f80fd5b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056fea26469706673582212208c3032e5d1d392610ad04108f5b5b7bb95becc9f021ff4bba0c847dc71c8783664736f6c63430008190033", + "devdoc": { + "author": "Venus", + "errors": { + "BorrowFailed(uint256)": [ + { + "custom:error": "BorrowFailed" + } + ], + "MintFailed(uint256)": [ + { + "custom:error": "MintFailed" + } + ], + "RedeemFailed(uint256)": [ + { + "custom:error": "RedeemFailed" + } + ], + "RepayFailed(uint256)": [ + { + "custom:error": "RepayFailed" + } + ] + }, + "events": { + "SweepNative(address,uint256)": { + "details": "Emitted when native asset is swept from the contract" + }, + "SweepToken(address,address,uint256)": { + "details": "Emitted when token is swept from the contract" + }, + "TokensBorrowedAndUnwrapped(address,address,uint256)": { + "details": "Emitted when native tokens are borrowed and unwrapped" + }, + "TokensRedeemedAndUnwrapped(address,address,uint256)": { + "details": "Emitted when tokens are redeemed and then unwrapped to be sent to user" + }, + "TokensWrappedAndRepaid(address,address,uint256)": { + "details": "Emitted when native currency is wrapped and repaid" + }, + "TokensWrappedAndSupplied(address,address,uint256)": { + "details": "Emitted when native currency is supplied" + } + }, + "kind": "dev", + "methods": { + "acceptOwnership()": { + "details": "The new owner accepts the ownership transfer." + }, + "borrowAndUnwrap(uint256)": { + "custom:error": "ZeroValueNotAllowed is thrown if borrowAmount is zeroBorrowFailed is thrown if the borrow operation fails", + "custom:event": "TokensBorrowedAndUnwrapped is emitted when assets are borrowed from a market and unwrapped", + "details": "Borrow wNativeToken, unwrap to Native, and send to the user", + "params": { + "borrowAmount": "The amount of underlying tokens to borrow" + } + }, + "constructor": { + "params": { + "vWrappedNativeToken": "Address of wrapped native token market" + } + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "pendingOwner()": { + "details": "Returns the address of the pending owner." + }, + "redeemAndUnwrap(uint256)": { + "custom:error": "ZeroValueNotAllowed is thrown if redeemTokens is zeroRedeemFailed is thrown if the redeem operation fails", + "custom:event": "TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped", + "params": { + "redeemTokens": "The amount of vWNative tokens to redeem" + } + }, + "redeemUnderlyingAndUnwrap(uint256)": { + "custom:error": "ZeroValueNotAllowed is thrown if redeemAmount is zeroRedeemFailed is thrown if the redeem operation fails", + "custom:event": "TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped", + "params": { + "redeemAmount": "The amount of underlying tokens to redeem" + } + }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner." + }, + "sweepNative()": { + "custom:access": "Controlled by Governance", + "custom:event": "SweepNative is emitted when assets are swept from the contract" + }, + "sweepToken(address)": { + "custom:access": "Controlled by Governance", + "custom:event": "SweepToken emits on success", + "params": { + "token": "Address of the token" + } + }, + "transferOwnership(address)": { + "details": "Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. Can only be called by the current owner." + }, + "wrapAndRepay()": { + "custom:error": "ZeroValueNotAllowed is thrown if repayAmount is zeroRepayFailed is thrown if the repay operation fails", + "custom:event": "TokensWrappedAndRepaid is emitted when assets are repaid to a market and unwrapped" + }, + "wrapAndSupply(address)": { + "custom:error": "ZeroAddressNotAllowed is thrown if address of minter is zero addressZeroValueNotAllowed is thrown if mintAmount is zeroMintFailed is thrown if the mint operation fails", + "custom:event": "TokensWrappedAndSupplied is emitted when assets are supplied to the market", + "params": { + "minter": "The address on behalf of whom the supply is performed." + } + } + }, + "title": "NativeTokenGateway", + "version": 1 + }, + "userdoc": { + "errors": { + "NativeTokenTransferFailed()": [ + { + "notice": "Thrown if transfer of native token fails" + } + ], + "ZeroAddressNotAllowed()": [ + { + "notice": "Thrown if the supplied address is a zero address where it is not allowed" + } + ], + "ZeroValueNotAllowed()": [ + { + "notice": "Thrown if the supplied value is 0 where it is not allowed" + } + ] + }, + "kind": "user", + "methods": { + "constructor": { + "notice": "Constructor for NativeTokenGateway" + }, + "redeemAndUnwrap(uint256)": { + "notice": "Redeem vWNativeToken, unwrap to Native Token, and send to the user" + }, + "redeemUnderlyingAndUnwrap(uint256)": { + "notice": "Redeem vWNativeToken, unwrap to Native Token, and send to the user" + }, + "sweepNative()": { + "notice": "Sweeps native assets (Native) from the contract and sends them to the owner" + }, + "sweepToken(address)": { + "notice": "Sweeps the input token address tokens from the contract and sends them to the owner" + }, + "vWNativeToken()": { + "notice": "Address of wrapped native token market" + }, + "wNativeToken()": { + "notice": "Address of wrapped native token contract" + }, + "wrapAndRepay()": { + "notice": "Wrap Native, repay borrow in the market, and send remaining Native to the user" + }, + "wrapAndSupply(address)": { + "notice": "Wrap Native, get wNativeToken, mint vWNativeToken, and supply to the market." + } + }, + "notice": "NativeTokenGateway contract facilitates interactions with a vToken market for native tokens (Native or wNativeToken)", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 1807, + "contract": "contracts/Gateway/NativeTokenGatewayCore.sol:NativeTokenGateway", + "label": "_owner", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 1920, + "contract": "contracts/Gateway/NativeTokenGatewayCore.sol:NativeTokenGateway", + "label": "_pendingOwner", + "offset": 0, + "slot": "1", + "type": "t_address" + }, + { + "astId": 2544, + "contract": "contracts/Gateway/NativeTokenGatewayCore.sol:NativeTokenGateway", + "label": "_status", + "offset": 0, + "slot": "2", + "type": "t_uint256" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} diff --git a/deployments/bscmainnet/solcInputs/c08fabaf010efcb44a3923892ebe65cc.json b/deployments/bscmainnet/solcInputs/c08fabaf010efcb44a3923892ebe65cc.json new file mode 100644 index 00000000..2530fa2c --- /dev/null +++ b/deployments/bscmainnet/solcInputs/c08fabaf010efcb44a3923892ebe65cc.json @@ -0,0 +1,295 @@ +{ + "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/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/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/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/access/Ownable2Step.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 \"./Ownable.sol\";\n\n/**\n * @dev Contract module which provides access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * 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 Ownable2Step is Ownable {\n address private _pendingOwner;\n\n event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Returns the address of the pending owner.\n */\n function pendingOwner() public view virtual returns (address) {\n return _pendingOwner;\n }\n\n /**\n * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual override onlyOwner {\n _pendingOwner = newOwner;\n emit OwnershipTransferStarted(owner(), newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual override {\n delete _pendingOwner;\n super._transferOwnership(newOwner);\n }\n\n /**\n * @dev The new owner accepts the ownership transfer.\n */\n function acceptOwnership() public virtual {\n address sender = _msgSender();\n require(pendingOwner() == sender, \"Ownable2Step: caller is not the new owner\");\n _transferOwnership(sender);\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/security/ReentrancyGuard.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\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 ReentrancyGuard {\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 constructor() {\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" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the default value returned by this function, unless\n * it's overridden.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(address from, address to, uint256 amount) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n // decrementing then incrementing.\n _balances[to] += amount;\n }\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n unchecked {\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n _balances[account] += amount;\n }\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n // Overflow not possible: amount <= accountBalance <= totalSupply.\n _totalSupply -= amount;\n }\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(address owner, address spender, uint256 amount) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.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 IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated 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/token/ERC20/utils/SafeERC20.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 \"../IERC20.sol\";\nimport \"../extensions/IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.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(IERC20 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(IERC20 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(IERC20 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(IERC20 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(IERC20 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 IERC20Permit token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n 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(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return\n success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));\n }\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/isolated-pools/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" + }, + "@venusprotocol/isolated-pools/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" + }, + "@venusprotocol/isolated-pools/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" + }, + "@venusprotocol/isolated-pools/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" + }, + "@venusprotocol/isolated-pools/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" + }, + "@venusprotocol/isolated-pools/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" + }, + "@venusprotocol/isolated-pools/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" + }, + "@venusprotocol/isolated-pools/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" + }, + "@venusprotocol/isolated-pools/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" + }, + "@venusprotocol/isolated-pools/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/isolated-pools/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" + }, + "@venusprotocol/isolated-pools/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" + }, + "@venusprotocol/isolated-pools/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" + }, + "@venusprotocol/isolated-pools/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" + }, + "@venusprotocol/isolated-pools/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" + }, + "@venusprotocol/isolated-pools/contracts/Shortfall/Shortfall.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 { 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" + }, + "@venusprotocol/isolated-pools/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" + }, + "@venusprotocol/isolated-pools/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" + }, + "@venusprotocol/isolated-pools/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" + }, + "@venusprotocol/isolated-pools/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" + }, + "@venusprotocol/isolated-pools/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" + }, + "@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 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 _acm Address of the access control manager contract\n */\n function initialize(address _sidRegistryAddress, address _acm) external initializer {\n sidRegistryAddress = _sidRegistryAddress;\n __AccessControlled_init(_acm);\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; ++i) {\n setTokenConfig(tokenConfigs_[i]);\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/test/MockToken.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockToken is ERC20 {\n uint8 private immutable _decimals;\n\n constructor(string memory name_, string memory symbol_, uint8 decimals_) ERC20(name_, symbol_) {\n _decimals = decimals_;\n }\n\n function faucet(uint256 amount) external {\n _mint(msg.sender, amount);\n }\n\n function decimals() public view virtual override returns (uint8) {\n return _decimals;\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/Gateway/INativeTokenGateway.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @title INativeTokenGateway\n * @author Venus\n * @notice Interface for NativeTokenGateway contract\n */\ninterface INativeTokenGateway {\n /**\n * @dev Emitted when native currency is supplied\n */\n event TokensWrappedAndSupplied(address indexed sender, address indexed vToken, uint256 amount);\n\n /**\n * @dev Emitted when tokens are redeemed and then unwrapped to be sent to user\n */\n event TokensRedeemedAndUnwrapped(address indexed sender, address indexed vToken, uint256 amount);\n\n /**\n * @dev Emitted when native tokens are borrowed and unwrapped\n */\n event TokensBorrowedAndUnwrapped(address indexed sender, address indexed vToken, uint256 amount);\n\n /**\n * @dev Emitted when native currency is wrapped and repaid\n */\n event TokensWrappedAndRepaid(address indexed sender, address indexed vToken, uint256 amount);\n\n /**\n * @dev Emitted when token is swept from the contract\n */\n event SweepToken(address indexed token, address indexed receiver, uint256 amount);\n\n /**\n * @dev Emitted when native asset is swept from the contract\n */\n event SweepNative(address indexed receiver, uint256 amount);\n\n /**\n * @notice Thrown if transfer of native token fails\n */\n error NativeTokenTransferFailed();\n\n /**\n * @notice Thrown if the supplied address is a zero address where it is not allowed\n */\n error ZeroAddressNotAllowed();\n\n /**\n * @notice Thrown if the supplied value is 0 where it is not allowed\n */\n error ZeroValueNotAllowed();\n\n /**\n * @dev Wrap Native Token, get wNativeToken, mint vWNativeTokens, and supply to the market\n * @param minter The address on behalf of whom the supply is performed\n */\n function wrapAndSupply(address minter) external payable;\n\n /**\n * @dev Redeem vWNativeTokens, unwrap to Native Token, and send to the user\n * @param redeemAmount The amount of underlying tokens to redeem\n */\n function redeemUnderlyingAndUnwrap(uint256 redeemAmount) external;\n\n /**\n * @dev Redeem vWNativeTokens, unwrap to Native Token, and send to the user\n * @param redeemTokens The amount of vWNative tokens to redeem\n */\n function redeemAndUnwrap(uint256 redeemTokens) external;\n\n /**\n * @dev Borrow wNativeToken, unwrap to Native Token, and send to the user\n * @param amount The amount of underlying tokens to borrow\n */\n function borrowAndUnwrap(uint256 amount) external;\n\n /**\n * @dev Wrap Native Token, repay borrow in the market, and send remaining Native Token to the user\n */\n function wrapAndRepay() external payable;\n\n /**\n * @dev Sweeps input token address tokens from the contract and sends them to the owner\n */\n function sweepToken(IERC20 token) external;\n\n /**\n * @dev Sweeps native assets (Native Token) from the contract and sends them to the owner\n */\n function sweepNative() external;\n}\n" + }, + "contracts/Gateway/Interfaces/IVToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\ninterface IVToken {\n function mintBehalf(address receiver, uint256 mintAmount) external returns (uint256);\n\n function redeemUnderlyingBehalf(address redeemer, uint256 redeemAmount) external returns (uint256);\n\n function redeemBehalf(address redeemer, uint256 redeemTokens) external returns (uint256);\n\n function repayBorrowBehalf(address borrower, uint256 repayAmount) external returns (uint256);\n\n function borrowBehalf(address borrower, uint256 borrowAmount) external returns (uint256);\n\n function borrowBalanceCurrent(address account) external returns (uint256);\n\n function underlying() external returns (address);\n\n function exchangeRateCurrent() external returns (uint256);\n\n function transferFrom(address from, address to, uint256 amount) external returns (bool);\n\n function redeem(uint256 redeemTokens) external returns (uint256);\n}\n" + }, + "contracts/Gateway/Interfaces/IWrappedNative.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\ninterface IWrappedNative {\n function deposit() external payable;\n\n function withdraw(uint256) external;\n\n function approve(address guy, uint256 wad) external returns (bool);\n\n function transferFrom(address src, address dst, uint256 wad) external returns (bool);\n\n function transfer(address dst, uint256 wad) external returns (bool);\n\n function balanceOf(address account) external view returns (uint256);\n}\n" + }, + "contracts/Gateway/NativeTokenGatewayCore.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { Ownable2Step } from \"@openzeppelin/contracts/access/Ownable2Step.sol\";\nimport { SafeERC20, IERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { ReentrancyGuard } from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\n\nimport { IWrappedNative } from \"./Interfaces/IWrappedNative.sol\";\nimport { INativeTokenGateway } from \"./INativeTokenGateway.sol\";\nimport { IVToken } from \"./Interfaces/IVToken.sol\";\n\n/**\n * @title NativeTokenGateway\n * @author Venus\n * @notice NativeTokenGateway contract facilitates interactions with a vToken market for native tokens (Native or wNativeToken)\n */\ncontract NativeTokenGateway is INativeTokenGateway, Ownable2Step, ReentrancyGuard {\n using SafeERC20 for IERC20;\n\n /// @notice Error code representing no errors in Venus operations\n uint256 internal constant NO_ERROR = 0;\n\n /**\n * @notice Address of wrapped native token contract\n */\n IWrappedNative public immutable wNativeToken;\n\n /**\n * @notice Address of wrapped native token market\n */\n IVToken public immutable vWNativeToken;\n\n /// @custom:error RedeemFailed\n error RedeemFailed(uint256 err);\n\n /// @custom:error BorrowFailed\n error BorrowFailed(uint256 err);\n\n /// @custom:error MintFailed\n error MintFailed(uint256 err);\n\n /// @custom:error RepayFailed\n error RepayFailed(uint256 err);\n\n /**\n * @notice Constructor for NativeTokenGateway\n * @param vWrappedNativeToken Address of wrapped native token market\n */\n constructor(IVToken vWrappedNativeToken) {\n ensureNonzeroAddress(address(vWrappedNativeToken));\n\n vWNativeToken = vWrappedNativeToken;\n wNativeToken = IWrappedNative(vWNativeToken.underlying());\n }\n\n /**\n * @notice To receive Native when msg.data is empty\n */\n receive() external payable {}\n\n /**\n * @notice To receive Native when msg.data is not empty\n */\n fallback() external payable {}\n\n /**\n * @notice Wrap Native, get wNativeToken, mint vWNativeToken, and supply to the market.\n * @param minter The address on behalf of whom the supply is performed.\n * @custom:error ZeroAddressNotAllowed is thrown if address of minter is zero address\n * @custom:error ZeroValueNotAllowed is thrown if mintAmount is zero\n * @custom:error MintFailed is thrown if the mint operation fails\n * @custom:event TokensWrappedAndSupplied is emitted when assets are supplied to the market\n */\n function wrapAndSupply(address minter) external payable nonReentrant {\n ensureNonzeroAddress(minter);\n\n uint256 mintAmount = msg.value;\n ensureNonzeroValue(mintAmount);\n\n wNativeToken.deposit{ value: mintAmount }();\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), mintAmount);\n\n uint256 err = vWNativeToken.mintBehalf(minter, mintAmount);\n if (err != NO_ERROR) revert MintFailed(err);\n\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), 0);\n emit TokensWrappedAndSupplied(minter, address(vWNativeToken), mintAmount);\n }\n\n /**\n * @notice Redeem vWNativeToken, unwrap to Native Token, and send to the user\n * @param redeemAmount The amount of underlying tokens to redeem\n * @custom:error ZeroValueNotAllowed is thrown if redeemAmount is zero\n * @custom:error RedeemFailed is thrown if the redeem operation fails\n * @custom:event TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped\n */\n function redeemUnderlyingAndUnwrap(uint256 redeemAmount) external nonReentrant {\n _redeemAndUnwrap(redeemAmount, true);\n }\n\n /**\n * @notice Redeem vWNativeToken, unwrap to Native Token, and send to the user\n * @param redeemTokens The amount of vWNative tokens to redeem\n * @custom:error ZeroValueNotAllowed is thrown if redeemTokens is zero\n * @custom:error RedeemFailed is thrown if the redeem operation fails\n * @custom:event TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped\n */\n function redeemAndUnwrap(uint256 redeemTokens) external nonReentrant {\n _redeemAndUnwrap(redeemTokens, false);\n }\n\n /**\n * @dev Borrow wNativeToken, unwrap to Native, and send to the user\n * @param borrowAmount The amount of underlying tokens to borrow\n * @custom:error ZeroValueNotAllowed is thrown if borrowAmount is zero\n * @custom:error BorrowFailed is thrown if the borrow operation fails\n * @custom:event TokensBorrowedAndUnwrapped is emitted when assets are borrowed from a market and unwrapped\n */\n function borrowAndUnwrap(uint256 borrowAmount) external nonReentrant {\n ensureNonzeroValue(borrowAmount);\n\n uint256 err = vWNativeToken.borrowBehalf(msg.sender, borrowAmount);\n if (err != NO_ERROR) revert BorrowFailed(err);\n\n wNativeToken.withdraw(borrowAmount);\n _safeTransferNativeTokens(msg.sender, borrowAmount);\n emit TokensBorrowedAndUnwrapped(msg.sender, address(vWNativeToken), borrowAmount);\n }\n\n /**\n * @notice Wrap Native, repay borrow in the market, and send remaining Native to the user\n * @custom:error ZeroValueNotAllowed is thrown if repayAmount is zero\n * @custom:error RepayFailed is thrown if the repay operation fails\n * @custom:event TokensWrappedAndRepaid is emitted when assets are repaid to a market and unwrapped\n */\n function wrapAndRepay() external payable nonReentrant {\n uint256 repayAmount = msg.value;\n ensureNonzeroValue(repayAmount);\n\n wNativeToken.deposit{ value: repayAmount }();\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), repayAmount);\n\n uint256 borrowBalanceBefore = vWNativeToken.borrowBalanceCurrent(msg.sender);\n uint256 err = vWNativeToken.repayBorrowBehalf(msg.sender, repayAmount);\n if (err != NO_ERROR) revert RepayFailed(err);\n uint256 borrowBalanceAfter = vWNativeToken.borrowBalanceCurrent(msg.sender);\n\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), 0);\n\n if (borrowBalanceAfter == 0 && (repayAmount > borrowBalanceBefore)) {\n uint256 dust;\n unchecked {\n dust = repayAmount - borrowBalanceBefore;\n }\n\n wNativeToken.withdraw(dust);\n _safeTransferNativeTokens(msg.sender, dust);\n }\n emit TokensWrappedAndRepaid(msg.sender, address(vWNativeToken), borrowBalanceBefore - borrowBalanceAfter);\n }\n\n /**\n * @notice Sweeps native assets (Native) from the contract and sends them to the owner\n * @custom:event SweepNative is emitted when assets are swept from the contract\n * @custom:access Controlled by Governance\n */\n function sweepNative() external onlyOwner {\n uint256 balance = address(this).balance;\n\n if (balance > 0) {\n address owner_ = owner();\n _safeTransferNativeTokens(owner_, balance);\n emit SweepNative(owner_, balance);\n }\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(IERC20 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 /**\n * @dev Redeems tokens, unwrap them to Native Token, and send to the user\n * This function is internally called by `redeemUnderlyingAndUnwrap` and `redeemAndUnwrap`\n * @param redeemTokens The amount of tokens to be redeemed. This can refer to either the underlying tokens directly or their equivalent vTokens\n * @param isUnderlying A boolean flag indicating whether the redemption is for underlying tokens directly (`true`) or for their equivalent vTokens (`false`).\n * @custom:error ZeroValueNotAllowed is thrown if redeemTokens is zero\n * @custom:error RedeemFailed is thrown if the redeem operation fails\n * @custom:event TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped\n */\n function _redeemAndUnwrap(uint256 redeemTokens, bool isUnderlying) internal {\n ensureNonzeroValue(redeemTokens);\n\n uint256 balanceBefore = wNativeToken.balanceOf(address(this));\n\n if (isUnderlying) {\n uint256 err = vWNativeToken.redeemUnderlyingBehalf(msg.sender, redeemTokens);\n if (err != NO_ERROR) revert RedeemFailed(err);\n } else {\n uint256 err = vWNativeToken.redeemBehalf(msg.sender, redeemTokens);\n if (err != NO_ERROR) revert RedeemFailed(err);\n }\n\n uint256 balanceAfter = wNativeToken.balanceOf(address(this));\n uint256 redeemedAmount = balanceAfter - balanceBefore;\n wNativeToken.withdraw(redeemedAmount);\n\n _safeTransferNativeTokens(msg.sender, redeemedAmount);\n emit TokensRedeemedAndUnwrapped(msg.sender, address(vWNativeToken), redeemedAmount);\n }\n\n /**\n * @dev transfer Native tokens to an address, revert if it fails\n * @param to recipient of the transfer\n * @param value the amount to send\n * @custom:error NativeTokenTransferFailed is thrown if the Native token transfer fails\n */\n function _safeTransferNativeTokens(address to, uint256 value) internal {\n (bool success, ) = to.call{ value: value }(new bytes(0));\n\n if (!success) {\n revert NativeTokenTransferFailed();\n }\n }\n\n /**\n * @dev 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\n **/\n function ensureNonzeroAddress(address address_) internal pure {\n if (address_ == address(0)) {\n revert ZeroAddressNotAllowed();\n }\n }\n\n /**\n * @dev 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\n */\n function ensureNonzeroValue(uint256 value_) internal pure {\n if (value_ == 0) {\n revert ZeroValueNotAllowed();\n }\n }\n}\n" + }, + "contracts/Gateway/NativeTokenGatewayIL.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { Ownable2Step } from \"@openzeppelin/contracts/access/Ownable2Step.sol\";\nimport { SafeERC20, IERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { ReentrancyGuard } from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\n\nimport { IWrappedNative } from \"./Interfaces/IWrappedNative.sol\";\nimport { INativeTokenGateway } from \"./INativeTokenGateway.sol\";\nimport { IVToken } from \"./Interfaces/IVToken.sol\";\n\n/**\n * @title NativeTokenGateway\n * @author Venus\n * @notice NativeTokenGateway contract facilitates interactions with a vToken market for native tokens (Native or wNativeToken)\n */\ncontract NativeTokenGateway is INativeTokenGateway, Ownable2Step, ReentrancyGuard {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Address of wrapped native token contract\n */\n IWrappedNative public immutable wNativeToken;\n\n /**\n * @notice Address of wrapped native token market\n */\n IVToken public immutable vWNativeToken;\n\n /**\n * @notice Constructor for NativeTokenGateway\n * @param vWrappedNativeToken Address of wrapped native token market\n */\n constructor(IVToken vWrappedNativeToken) {\n ensureNonzeroAddress(address(vWrappedNativeToken));\n\n vWNativeToken = vWrappedNativeToken;\n wNativeToken = IWrappedNative(vWNativeToken.underlying());\n }\n\n /**\n * @notice To receive Native when msg.data is empty\n */\n receive() external payable {}\n\n /**\n * @notice To receive Native when msg.data is not empty\n */\n fallback() external payable {}\n\n /**\n * @notice Wrap Native, get wNativeToken, mint vWNativeToken, and supply to the market.\n * @param minter The address on behalf of whom the supply is performed.\n * @custom:error ZeroAddressNotAllowed is thrown if address of minter is zero address\n * @custom:error ZeroValueNotAllowed is thrown if mintAmount is zero\n * @custom:event TokensWrappedAndSupplied is emitted when assets are supplied to the market\n */\n function wrapAndSupply(address minter) external payable nonReentrant {\n ensureNonzeroAddress(minter);\n\n uint256 mintAmount = msg.value;\n ensureNonzeroValue(mintAmount);\n\n wNativeToken.deposit{ value: mintAmount }();\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), mintAmount);\n\n vWNativeToken.mintBehalf(minter, mintAmount);\n\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), 0);\n emit TokensWrappedAndSupplied(minter, address(vWNativeToken), mintAmount);\n }\n\n /**\n * @notice Redeem vWNativeToken, unwrap to Native Token, and send to the user\n * @param redeemAmount The amount of underlying tokens to redeem\n * @custom:error ZeroValueNotAllowed is thrown if redeemAmount is zero\n * @custom:event TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped\n */\n function redeemUnderlyingAndUnwrap(uint256 redeemAmount) external nonReentrant {\n _redeemAndUnwrap(redeemAmount, true);\n }\n\n /**\n * @notice Redeem vWNativeToken, unwrap to Native Token, and send to the user\n * @param redeemTokens The amount of vWNative tokens to redeem\n * @custom:error ZeroValueNotAllowed is thrown if redeemTokens is zero\n * @custom:event TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped\n */\n function redeemAndUnwrap(uint256 redeemTokens) external nonReentrant {\n _redeemAndUnwrap(redeemTokens, false);\n }\n\n /**\n * @dev Borrow wNativeToken, unwrap to Native, and send to the user\n * @param borrowAmount The amount of underlying tokens to borrow\n * @custom:error ZeroValueNotAllowed is thrown if borrowAmount is zero\n * @custom:event TokensBorrowedAndUnwrapped is emitted when assets are borrowed from a market and unwrapped\n */\n function borrowAndUnwrap(uint256 borrowAmount) external nonReentrant {\n ensureNonzeroValue(borrowAmount);\n\n vWNativeToken.borrowBehalf(msg.sender, borrowAmount);\n\n wNativeToken.withdraw(borrowAmount);\n _safeTransferNativeTokens(msg.sender, borrowAmount);\n emit TokensBorrowedAndUnwrapped(msg.sender, address(vWNativeToken), borrowAmount);\n }\n\n /**\n * @notice Wrap Native, repay borrow in the market, and send remaining Native to the user\n * @custom:error ZeroValueNotAllowed is thrown if repayAmount is zero\n * @custom:event TokensWrappedAndRepaid is emitted when assets are repaid to a market and unwrapped\n */\n function wrapAndRepay() external payable nonReentrant {\n uint256 repayAmount = msg.value;\n ensureNonzeroValue(repayAmount);\n\n wNativeToken.deposit{ value: repayAmount }();\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), repayAmount);\n\n uint256 borrowBalanceBefore = vWNativeToken.borrowBalanceCurrent(msg.sender);\n vWNativeToken.repayBorrowBehalf(msg.sender, repayAmount);\n uint256 borrowBalanceAfter = vWNativeToken.borrowBalanceCurrent(msg.sender);\n\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), 0);\n\n if (borrowBalanceAfter == 0 && (repayAmount > borrowBalanceBefore)) {\n uint256 dust;\n unchecked {\n dust = repayAmount - borrowBalanceBefore;\n }\n\n wNativeToken.withdraw(dust);\n _safeTransferNativeTokens(msg.sender, dust);\n }\n emit TokensWrappedAndRepaid(msg.sender, address(vWNativeToken), borrowBalanceBefore - borrowBalanceAfter);\n }\n\n /**\n * @notice Sweeps native assets (Native) from the contract and sends them to the owner\n * @custom:event SweepNative is emitted when assets are swept from the contract\n * @custom:access Controlled by Governance\n */\n function sweepNative() external onlyOwner {\n uint256 balance = address(this).balance;\n\n if (balance > 0) {\n address owner_ = owner();\n _safeTransferNativeTokens(owner_, balance);\n emit SweepNative(owner_, balance);\n }\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(IERC20 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 /**\n * @dev Redeems tokens, unwrap them to Native Token, and send to the user\n * This function is internally called by `redeemUnderlyingAndUnwrap` and `redeemAndUnwrap`\n * @param redeemTokens The amount of tokens to be redeemed. This can refer to either the underlying tokens directly or their equivalent vTokens\n * @param isUnderlying A boolean flag indicating whether the redemption is for underlying tokens directly (`true`) or for their equivalent vTokens (`false`).\n * @custom:error ZeroValueNotAllowed is thrown if redeemTokens is zero\n * @custom:event TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped\n */\n function _redeemAndUnwrap(uint256 redeemTokens, bool isUnderlying) internal {\n ensureNonzeroValue(redeemTokens);\n\n uint256 balanceBefore = wNativeToken.balanceOf(address(this));\n\n if (isUnderlying) {\n vWNativeToken.redeemUnderlyingBehalf(msg.sender, redeemTokens);\n } else {\n vWNativeToken.redeemBehalf(msg.sender, redeemTokens);\n }\n\n uint256 balanceAfter = wNativeToken.balanceOf(address(this));\n uint256 redeemedAmount = balanceAfter - balanceBefore;\n wNativeToken.withdraw(redeemedAmount);\n\n _safeTransferNativeTokens(msg.sender, redeemedAmount);\n emit TokensRedeemedAndUnwrapped(msg.sender, address(vWNativeToken), redeemedAmount);\n }\n\n /**\n * @dev transfer Native tokens to an address, revert if it fails\n * @param to recipient of the transfer\n * @param value the amount to send\n * @custom:error NativeTokenTransferFailed is thrown if the Native token transfer fails\n */\n function _safeTransferNativeTokens(address to, uint256 value) internal {\n (bool success, ) = to.call{ value: value }(new bytes(0));\n\n if (!success) {\n revert NativeTokenTransferFailed();\n }\n }\n\n /**\n * @dev 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\n **/\n function ensureNonzeroAddress(address address_) internal pure {\n if (address_ == address(0)) {\n revert ZeroAddressNotAllowed();\n }\n }\n\n /**\n * @dev 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\n */\n function ensureNonzeroValue(uint256 value_) internal pure {\n if (value_ == 0) {\n revert ZeroValueNotAllowed();\n }\n }\n}\n" + }, + "contracts/test/ERC20.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { SafeMath } from \"./SafeMath.sol\";\n\ninterface ERC20Base {\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n function approve(address spender, uint256 value) external returns (bool);\n\n function totalSupply() external view returns (uint256);\n\n function allowance(address owner, address spender) external view returns (uint256);\n\n function balanceOf(address who) external view returns (uint256);\n}\n\nabstract contract ERC20 is ERC20Base {\n function transfer(address to, uint256 value) external virtual returns (bool);\n\n function transferFrom(address from, address to, uint256 value) external virtual returns (bool);\n}\n\nabstract contract ERC20NS is ERC20Base {\n function transfer(address to, uint256 value) external virtual;\n\n function transferFrom(address from, address to, uint256 value) external virtual;\n}\n\n/**\n * @title Standard ERC20 token\n * @dev Implementation of the basic standard token.\n * See https://github.com/ethereum/EIPs/issues/20\n */\ncontract StandardToken is ERC20 {\n using SafeMath for uint256;\n\n string public name;\n string public symbol;\n uint8 public decimals;\n uint256 public override totalSupply;\n mapping(address => mapping(address => uint256)) public override allowance;\n mapping(address => uint256) public override balanceOf;\n\n constructor(uint256 _initialAmount, string memory _tokenName, uint8 _decimalUnits, string memory _tokenSymbol) {\n totalSupply = _initialAmount;\n balanceOf[msg.sender] = _initialAmount;\n name = _tokenName;\n symbol = _tokenSymbol;\n decimals = _decimalUnits;\n }\n\n function transfer(address dst, uint256 amount) external virtual override returns (bool) {\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(address src, address dst, uint256 amount) external virtual override returns (bool) {\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount, \"Insufficient allowance\");\n balanceOf[src] = balanceOf[src].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(src, dst, amount);\n return true;\n }\n\n function approve(address _spender, uint256 amount) external virtual override returns (bool) {\n allowance[msg.sender][_spender] = amount;\n emit Approval(msg.sender, _spender, amount);\n return true;\n }\n}\n\n/**\n * @title Non-Standard ERC20 token\n * @dev Version of ERC20 with no return values for `transfer` and `transferFrom`\n * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca\n */\ncontract NonStandardToken is ERC20NS {\n using SafeMath for uint256;\n\n string public name;\n uint8 public decimals;\n string public symbol;\n uint256 public override totalSupply;\n mapping(address => mapping(address => uint256)) public override allowance;\n mapping(address => uint256) public override balanceOf;\n\n constructor(uint256 _initialAmount, string memory _tokenName, uint8 _decimalUnits, string memory _tokenSymbol) {\n totalSupply = _initialAmount;\n balanceOf[msg.sender] = _initialAmount;\n name = _tokenName;\n symbol = _tokenSymbol;\n decimals = _decimalUnits;\n }\n\n function transfer(address dst, uint256 amount) external override {\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(msg.sender, dst, amount);\n }\n\n function transferFrom(address src, address dst, uint256 amount) external override {\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount, \"Insufficient allowance\");\n balanceOf[src] = balanceOf[src].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(src, dst, amount);\n }\n\n function approve(address _spender, uint256 amount) external override returns (bool) {\n allowance[msg.sender][_spender] = amount;\n emit Approval(msg.sender, _spender, amount);\n return true;\n }\n}\n\ncontract ERC20Harness is StandardToken {\n using SafeMath for uint256;\n // To support testing, we can specify addresses for which transferFrom should fail and return false\n mapping(address => bool) public failTransferFromAddresses;\n\n // To support testing, we allow the contract to always fail `transfer`.\n mapping(address => bool) public failTransferToAddresses;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n )\n StandardToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol)\n /* solhint-disable-next-line no-empty-blocks */\n {\n\n }\n\n function transfer(address dst, uint256 amount) external override returns (bool success) {\n // Added for testing purposes\n if (failTransferToAddresses[dst]) {\n return false;\n }\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(address src, address dst, uint256 amount) external override returns (bool success) {\n // Added for testing purposes\n if (failTransferFromAddresses[src]) {\n return false;\n }\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount, \"Insufficient allowance\");\n balanceOf[src] = balanceOf[src].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(src, dst, amount);\n return true;\n }\n\n function harnessSetFailTransferFromAddress(address src, bool _fail) public {\n failTransferFromAddresses[src] = _fail;\n }\n\n function harnessSetFailTransferToAddress(address dst, bool _fail) public {\n failTransferToAddresses[dst] = _fail;\n }\n\n function harnessSetBalance(address _account, uint256 _amount) public {\n balanceOf[_account] = _amount;\n }\n}\n" + }, + "contracts/test/imports2.sol": { + "content": "pragma solidity ^0.8.0;\n\n// This file is needed to make hardhat and typechain generate artifacts for\n// contracts we depend on (e.g. in tests or deployments) but not use directly.\n// Another way to do this would be to use hardhat-dependency-compiler, but\n// since we only have a couple of dependencies, installing a separate package\n// seems an overhead.\n\nimport { UpgradeableBeacon } from \"@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol\";\nimport { BeaconProxy } from \"@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol\";\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { MockToken } from \"@venusprotocol/venus-protocol/contracts/test/MockToken.sol\";\nimport { IAccessControlManagerV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/IAccessControlManagerV8.sol\";\nimport { Comptroller } from \"@venusprotocol/isolated-pools/contracts/Comptroller.sol\";\nimport { VToken } from \"@venusprotocol/isolated-pools/contracts/VToken.sol\";\nimport { PoolRegistry } from \"@venusprotocol/isolated-pools/contracts/Pool/PoolRegistry.sol\";\nimport { Shortfall } from \"@venusprotocol/isolated-pools/contracts/Shortfall/Shortfall.sol\";\nimport { ProtocolShareReserve } from \"@venusprotocol/protocol-reserve/contracts/ProtocolReserve/ProtocolShareReserve.sol\";\nimport { MockPriceOracle } from \"@venusprotocol/isolated-pools/contracts/test/Mocks/MockPriceOracle.sol\";\nimport { VTokenHarness } from \"@venusprotocol/isolated-pools/contracts/test/VTokenHarness.sol\";\n" + }, + "contracts/test/SafeMath.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\n// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol\n// Subject to the MIT license.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c;\n unchecked {\n c = a + b;\n }\n require(c >= a, \"SafeMath: addition overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n uint256 c;\n unchecked {\n c = a + b;\n }\n require(c >= a, errorMessage);\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot underflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMath: subtraction underflow\");\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot underflow.\n */\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n uint256 c = a - b;\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c;\n unchecked {\n c = a * b;\n }\n require(c / a == b, \"SafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c;\n unchecked {\n c = a * b;\n }\n require(c / a == b, errorMessage);\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers.\n * Reverts on division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers.\n * Reverts with custom message on division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b > 0, errorMessage);\n uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMath: modulo by zero\");\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts with custom message when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n return a % b;\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200, + "details": { + "yul": true + } + }, + "evmVersion": "cancun", + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/bscmainnet_addresses.json b/deployments/bscmainnet_addresses.json index 8d0acc3d..f4dd2cd0 100644 --- a/deployments/bscmainnet_addresses.json +++ b/deployments/bscmainnet_addresses.json @@ -1,5 +1,7 @@ { "name": "bscmainnet", "chainId": "56", - "addresses": {} + "addresses": { + "NativeTokenGateway_vWBNB_Core": "0x5143eb18aA057Cd8BC9734cCfD2651823e71585f" + } } diff --git a/deployments/bsctestnet.json b/deployments/bsctestnet.json index eed803e9..c832dc1e 100644 --- a/deployments/bsctestnet.json +++ b/deployments/bsctestnet.json @@ -1,5 +1,429 @@ { "name": "bsctestnet", "chainId": "97", - "contracts": {} + "contracts": { + "NativeTokenGateway_vWBNB": { + "address": "0xF34AAfc540Adc827A84736553BD29DE87a117558", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IVToken", + "name": "vWrappedNativeToken", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "err", + "type": "uint256" + } + ], + "name": "BorrowFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "err", + "type": "uint256" + } + ], + "name": "MintFailed", + "type": "error" + }, + { + "inputs": [], + "name": "NativeTokenTransferFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "err", + "type": "uint256" + } + ], + "name": "RedeemFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "err", + "type": "uint256" + } + ], + "name": "RepayFailed", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddressNotAllowed", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroValueNotAllowed", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "SweepNative", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "SweepToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensBorrowedAndUnwrapped", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensRedeemedAndUnwrapped", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensWrappedAndRepaid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensWrappedAndSupplied", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "acceptOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowAndUnwrap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemAndUnwrap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlyingAndUnwrap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sweepNative", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "sweepToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "vWNativeToken", + "outputs": [ + { + "internalType": "contract IVToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "wNativeToken", + "outputs": [ + { + "internalType": "contract IWrappedNative", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "wrapAndRepay", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "minter", + "type": "address" + } + ], + "name": "wrapAndSupply", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ] + } + } } diff --git a/deployments/bsctestnet/.chainId b/deployments/bsctestnet/.chainId new file mode 100644 index 00000000..c4fbb1cf --- /dev/null +++ b/deployments/bsctestnet/.chainId @@ -0,0 +1 @@ +97 \ No newline at end of file diff --git a/deployments/bsctestnet/NativeTokenGateway_vWBNB.json b/deployments/bsctestnet/NativeTokenGateway_vWBNB.json new file mode 100644 index 00000000..23db6c33 --- /dev/null +++ b/deployments/bsctestnet/NativeTokenGateway_vWBNB.json @@ -0,0 +1,665 @@ +{ + "address": "0xF34AAfc540Adc827A84736553BD29DE87a117558", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IVToken", + "name": "vWrappedNativeToken", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "err", + "type": "uint256" + } + ], + "name": "BorrowFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "err", + "type": "uint256" + } + ], + "name": "MintFailed", + "type": "error" + }, + { + "inputs": [], + "name": "NativeTokenTransferFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "err", + "type": "uint256" + } + ], + "name": "RedeemFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "err", + "type": "uint256" + } + ], + "name": "RepayFailed", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddressNotAllowed", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroValueNotAllowed", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "SweepNative", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "SweepToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensBorrowedAndUnwrapped", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensRedeemedAndUnwrapped", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensWrappedAndRepaid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensWrappedAndSupplied", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "acceptOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowAndUnwrap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemAndUnwrap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlyingAndUnwrap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sweepNative", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "sweepToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "vWNativeToken", + "outputs": [ + { + "internalType": "contract IVToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "wNativeToken", + "outputs": [ + { + "internalType": "contract IWrappedNative", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "wrapAndRepay", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "minter", + "type": "address" + } + ], + "name": "wrapAndSupply", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "transactionHash": "0x1d4e7d3f3dc0d7d9439d63090d4e9a56801f07b97e24104ff5bc5bc123ac2e66", + "receipt": { + "to": null, + "from": "0x33C6476F88eeA28D7E7900F759B4597704Ef95B7", + "contractAddress": "0xF34AAfc540Adc827A84736553BD29DE87a117558", + "transactionIndex": 0, + "gasUsed": "1419949", + "logsBloom": "0x00000000000000000000000000000400000000000000000000800000000000000000000000040000000000002000000000000000000000000000000000000000000000000000000000000000000000000001000002000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020020000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x887a124dce097d5c263227c336dc77ca7cc5a4f04318bac73d7451c9fdbf0d12", + "transactionHash": "0x1d4e7d3f3dc0d7d9439d63090d4e9a56801f07b97e24104ff5bc5bc123ac2e66", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 64999171, + "transactionHash": "0x1d4e7d3f3dc0d7d9439d63090d4e9a56801f07b97e24104ff5bc5bc123ac2e66", + "address": "0xF34AAfc540Adc827A84736553BD29DE87a117558", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000033c6476f88eea28d7e7900f759b4597704ef95b7" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0x887a124dce097d5c263227c336dc77ca7cc5a4f04318bac73d7451c9fdbf0d12" + } + ], + "blockNumber": 64999171, + "cumulativeGasUsed": "1419949", + "status": 1, + "byzantium": true + }, + "args": ["0xd9E77847ec815E56ae2B9E69596C69b6972b0B1C"], + "numDeployments": 2, + "solcInputHash": "d4715e66be994f4f4035be2d5c03faba", + "metadata": "{\"compiler\":{\"version\":\"0.8.25+commit.b61c2a91\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IVToken\",\"name\":\"vWrappedNativeToken\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"err\",\"type\":\"uint256\"}],\"name\":\"BorrowFailed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"err\",\"type\":\"uint256\"}],\"name\":\"MintFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTokenTransferFailed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"err\",\"type\":\"uint256\"}],\"name\":\"RedeemFailed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"err\",\"type\":\"uint256\"}],\"name\":\"RepayFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroValueNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SweepNative\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SweepToken\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"vToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"TokensBorrowedAndUnwrapped\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"vToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"TokensRedeemedAndUnwrapped\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"vToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"TokensWrappedAndRepaid\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"vToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"TokensWrappedAndSupplied\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"borrowAmount\",\"type\":\"uint256\"}],\"name\":\"borrowAndUnwrap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pendingOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"redeemTokens\",\"type\":\"uint256\"}],\"name\":\"redeemAndUnwrap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"redeemAmount\",\"type\":\"uint256\"}],\"name\":\"redeemUnderlyingAndUnwrap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sweepNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"sweepToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vWNativeToken\",\"outputs\":[{\"internalType\":\"contract IVToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wNativeToken\",\"outputs\":[{\"internalType\":\"contract IWrappedNative\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrapAndRepay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"minter\",\"type\":\"address\"}],\"name\":\"wrapAndSupply\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"author\":\"Venus\",\"errors\":{\"BorrowFailed(uint256)\":[{\"custom:error\":\"BorrowFailed\"}],\"MintFailed(uint256)\":[{\"custom:error\":\"MintFailed\"}],\"RedeemFailed(uint256)\":[{\"custom:error\":\"RedeemFailed\"}],\"RepayFailed(uint256)\":[{\"custom:error\":\"RepayFailed\"}]},\"events\":{\"SweepNative(address,uint256)\":{\"details\":\"Emitted when native asset is swept from the contract\"},\"SweepToken(address,address,uint256)\":{\"details\":\"Emitted when token is swept from the contract\"},\"TokensBorrowedAndUnwrapped(address,address,uint256)\":{\"details\":\"Emitted when native tokens are borrowed and unwrapped\"},\"TokensRedeemedAndUnwrapped(address,address,uint256)\":{\"details\":\"Emitted when tokens are redeemed and then unwrapped to be sent to user\"},\"TokensWrappedAndRepaid(address,address,uint256)\":{\"details\":\"Emitted when native currency is wrapped and repaid\"},\"TokensWrappedAndSupplied(address,address,uint256)\":{\"details\":\"Emitted when native currency is supplied\"}},\"kind\":\"dev\",\"methods\":{\"acceptOwnership()\":{\"details\":\"The new owner accepts the ownership transfer.\"},\"borrowAndUnwrap(uint256)\":{\"custom:error\":\"ZeroValueNotAllowed is thrown if borrowAmount is zeroBorrowFailed is thrown if the borrow operation fails\",\"custom:event\":\"TokensBorrowedAndUnwrapped is emitted when assets are borrowed from a market and unwrapped\",\"details\":\"Borrow wNativeToken, unwrap to Native, and send to the user\",\"params\":{\"borrowAmount\":\"The amount of underlying tokens to borrow\"}},\"constructor\":{\"params\":{\"vWrappedNativeToken\":\"Address of wrapped native token market\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"pendingOwner()\":{\"details\":\"Returns the address of the pending owner.\"},\"redeemAndUnwrap(uint256)\":{\"custom:error\":\"ZeroValueNotAllowed is thrown if redeemTokens is zero\",\"custom:event\":\"TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped\",\"params\":{\"redeemTokens\":\"The amount of vWNative tokens to redeem\"}},\"redeemUnderlyingAndUnwrap(uint256)\":{\"custom:error\":\"ZeroValueNotAllowed is thrown if redeemAmount is zero\",\"custom:event\":\"TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped\",\"params\":{\"redeemAmount\":\"The amount of underlying tokens to redeem\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.\"},\"sweepNative()\":{\"custom:access\":\"Controlled by Governance\",\"custom:event\":\"SweepNative is emitted when assets are swept from the contract\"},\"sweepToken(address)\":{\"custom:access\":\"Controlled by Governance\",\"custom:event\":\"SweepToken emits on success\",\"params\":{\"token\":\"Address of the token\"}},\"transferOwnership(address)\":{\"details\":\"Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. Can only be called by the current owner.\"},\"wrapAndRepay()\":{\"custom:error\":\"ZeroValueNotAllowed is thrown if repayAmount is zeroRepayFailed is thrown if the repay operation fails\",\"custom:event\":\"TokensWrappedAndRepaid is emitted when assets are repaid to a market and unwrapped\"},\"wrapAndSupply(address)\":{\"custom:error\":\"ZeroAddressNotAllowed is thrown if address of minter is zero addressZeroValueNotAllowed is thrown if mintAmount is zeroMintFailed is thrown if the mint operation fails\",\"custom:event\":\"TokensWrappedAndSupplied is emitted when assets are supplied to the market\",\"params\":{\"minter\":\"The address on behalf of whom the supply is performed.\"}}},\"title\":\"NativeTokenGateway\",\"version\":1},\"userdoc\":{\"errors\":{\"NativeTokenTransferFailed()\":[{\"notice\":\"Thrown if transfer of native token fails\"}],\"ZeroAddressNotAllowed()\":[{\"notice\":\"Thrown if the supplied address is a zero address where it is not allowed\"}],\"ZeroValueNotAllowed()\":[{\"notice\":\"Thrown if the supplied value is 0 where it is not allowed\"}]},\"kind\":\"user\",\"methods\":{\"constructor\":{\"notice\":\"Constructor for NativeTokenGateway\"},\"redeemAndUnwrap(uint256)\":{\"notice\":\"Redeem vWNativeToken, unwrap to Native Token, and send to the user\"},\"redeemUnderlyingAndUnwrap(uint256)\":{\"notice\":\"Redeem vWNativeToken, unwrap to Native Token, and send to the user\"},\"sweepNative()\":{\"notice\":\"Sweeps native assets (Native) from the contract and sends them to the owner\"},\"sweepToken(address)\":{\"notice\":\"Sweeps the input token address tokens from the contract and sends them to the owner\"},\"vWNativeToken()\":{\"notice\":\"Address of wrapped native token market\"},\"wNativeToken()\":{\"notice\":\"Address of wrapped native token contract\"},\"wrapAndRepay()\":{\"notice\":\"Wrap Native, repay borrow in the market, and send remaining Native to the user\"},\"wrapAndSupply(address)\":{\"notice\":\"Wrap Native, get wNativeToken, mint vWNativeToken, and supply to the market.\"}},\"notice\":\"NativeTokenGateway contract facilitates interactions with a vToken market for native tokens (Native or wNativeToken)\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Gateway/NativeTokenGateway.sol\":\"NativeTokenGateway\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@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\",\"keccak256\":\"0xba43b97fba0d32eb4254f6a5a297b39a19a247082a02d6e69349e071e2946218\",\"license\":\"MIT\"},\"@openzeppelin/contracts/access/Ownable2Step.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 \\\"./Ownable.sol\\\";\\n\\n/**\\n * @dev Contract module which provides access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * 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 Ownable2Step is Ownable {\\n address private _pendingOwner;\\n\\n event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Returns the address of the pending owner.\\n */\\n function pendingOwner() public view virtual returns (address) {\\n return _pendingOwner;\\n }\\n\\n /**\\n * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual override onlyOwner {\\n _pendingOwner = newOwner;\\n emit OwnershipTransferStarted(owner(), newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual override {\\n delete _pendingOwner;\\n super._transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev The new owner accepts the ownership transfer.\\n */\\n function acceptOwnership() public virtual {\\n address sender = _msgSender();\\n require(pendingOwner() == sender, \\\"Ownable2Step: caller is not the new owner\\\");\\n _transferOwnership(sender);\\n }\\n}\\n\",\"keccak256\":\"0xde231558366826d7cb61725af8147965a61c53b77a352cc8c9af38fc5a92ac3c\",\"license\":\"MIT\"},\"@openzeppelin/contracts/security/ReentrancyGuard.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\\n\\npragma solidity ^0.8.0;\\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 ReentrancyGuard {\\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 constructor() {\\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\",\"keccak256\":\"0xa535a5df777d44e945dd24aa43a11e44b024140fc340ad0dfe42acf4002aade1\",\"license\":\"MIT\"},\"@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\",\"keccak256\":\"0x287b55befed2961a7eabd7d7b1b2839cbca8a5b80ef8dcbb25ed3d4c2002c305\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.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 IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n *\\n * CAUTION: See Security Considerations above.\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xb264c03a3442eb37a68ad620cefd1182766b58bee6cec40343480392d6b14d69\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.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 \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n /**\\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\\n * non-reverting calls are assumed to be successful.\\n */\\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\\n _callOptionalReturn(token, abi.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(IERC20 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(IERC20 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(IERC20 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(IERC20 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(IERC20 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 IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n 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(IERC20 token, bytes memory data) private returns (bool) {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\\n // and not revert is the subcall reverts.\\n\\n (bool success, bytes memory returndata) = address(token).call(data);\\n return\\n success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));\\n }\\n}\\n\",\"keccak256\":\"0xabefac93435967b4d36a4fabcbdbb918d1f0b7ae3c3d85bc30923b326c927ed1\",\"license\":\"MIT\"},\"@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\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"@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\",\"keccak256\":\"0xa92e4fa126feb6907daa0513ddd816b2eb91f30a808de54f63c17d0e162c3439\",\"license\":\"MIT\"},\"contracts/Gateway/INativeTokenGateway.sol\":{\"content\":\"// SPDX-License-Identifier: BSD-3-Clause\\npragma solidity ^0.8.25;\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @title INativeTokenGateway\\n * @author Venus\\n * @notice Interface for NativeTokenGateway contract\\n */\\ninterface INativeTokenGateway {\\n /**\\n * @dev Emitted when native currency is supplied\\n */\\n event TokensWrappedAndSupplied(address indexed sender, address indexed vToken, uint256 amount);\\n\\n /**\\n * @dev Emitted when tokens are redeemed and then unwrapped to be sent to user\\n */\\n event TokensRedeemedAndUnwrapped(address indexed sender, address indexed vToken, uint256 amount);\\n\\n /**\\n * @dev Emitted when native tokens are borrowed and unwrapped\\n */\\n event TokensBorrowedAndUnwrapped(address indexed sender, address indexed vToken, uint256 amount);\\n\\n /**\\n * @dev Emitted when native currency is wrapped and repaid\\n */\\n event TokensWrappedAndRepaid(address indexed sender, address indexed vToken, uint256 amount);\\n\\n /**\\n * @dev Emitted when token is swept from the contract\\n */\\n event SweepToken(address indexed token, address indexed receiver, uint256 amount);\\n\\n /**\\n * @dev Emitted when native asset is swept from the contract\\n */\\n event SweepNative(address indexed receiver, uint256 amount);\\n\\n /**\\n * @notice Thrown if transfer of native token fails\\n */\\n error NativeTokenTransferFailed();\\n\\n /**\\n * @notice Thrown if the supplied address is a zero address where it is not allowed\\n */\\n error ZeroAddressNotAllowed();\\n\\n /**\\n * @notice Thrown if the supplied value is 0 where it is not allowed\\n */\\n error ZeroValueNotAllowed();\\n\\n /**\\n * @dev Wrap Native Token, get wNativeToken, mint vWNativeTokens, and supply to the market\\n * @param minter The address on behalf of whom the supply is performed\\n */\\n function wrapAndSupply(address minter) external payable;\\n\\n /**\\n * @dev Redeem vWNativeTokens, unwrap to Native Token, and send to the user\\n * @param redeemAmount The amount of underlying tokens to redeem\\n */\\n function redeemUnderlyingAndUnwrap(uint256 redeemAmount) external;\\n\\n /**\\n * @dev Redeem vWNativeTokens, unwrap to Native Token, and send to the user\\n * @param redeemTokens The amount of vWNative tokens to redeem\\n */\\n function redeemAndUnwrap(uint256 redeemTokens) external;\\n\\n /**\\n * @dev Borrow wNativeToken, unwrap to Native Token, and send to the user\\n * @param amount The amount of underlying tokens to borrow\\n */\\n function borrowAndUnwrap(uint256 amount) external;\\n\\n /**\\n * @dev Wrap Native Token, repay borrow in the market, and send remaining Native Token to the user\\n */\\n function wrapAndRepay() external payable;\\n\\n /**\\n * @dev Sweeps input token address tokens from the contract and sends them to the owner\\n */\\n function sweepToken(IERC20 token) external;\\n\\n /**\\n * @dev Sweeps native assets (Native Token) from the contract and sends them to the owner\\n */\\n function sweepNative() external;\\n}\\n\",\"keccak256\":\"0xbb97f05167348ef8510421f8530de125d83982f8ae1df5bf8167cfb3c8bf7fb9\",\"license\":\"BSD-3-Clause\"},\"contracts/Gateway/Interfaces/IVToken.sol\":{\"content\":\"// SPDX-License-Identifier: BSD-3-Clause\\npragma solidity ^0.8.25;\\n\\ninterface IVToken {\\n function mintBehalf(address receiver, uint256 mintAmount) external returns (uint256);\\n\\n function redeemUnderlyingBehalf(address redeemer, uint256 redeemAmount) external returns (uint256);\\n\\n function redeemBehalf(address redeemer, uint256 redeemTokens) external returns (uint256);\\n\\n function repayBorrowBehalf(address borrower, uint256 repayAmount) external returns (uint256);\\n\\n function borrowBehalf(address borrower, uint256 borrowAmount) external returns (uint256);\\n\\n function borrowBalanceCurrent(address account) external returns (uint256);\\n\\n function underlying() external returns (address);\\n\\n function exchangeRateCurrent() external returns (uint256);\\n\\n function transferFrom(address from, address to, uint256 amount) external returns (bool);\\n\\n function redeem(uint256 redeemTokens) external returns (uint256);\\n}\\n\",\"keccak256\":\"0xbb2bca2f551d9859daba74a6f30a75b960edd392edbfe658008813cb3a630939\",\"license\":\"BSD-3-Clause\"},\"contracts/Gateway/Interfaces/IWrappedNative.sol\":{\"content\":\"// SPDX-License-Identifier: BSD-3-Clause\\npragma solidity ^0.8.25;\\n\\ninterface IWrappedNative {\\n function deposit() external payable;\\n\\n function withdraw(uint256) external;\\n\\n function approve(address guy, uint256 wad) external returns (bool);\\n\\n function transferFrom(address src, address dst, uint256 wad) external returns (bool);\\n\\n function transfer(address dst, uint256 wad) external returns (bool);\\n\\n function balanceOf(address account) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x71e46aaa5ca7af98667bcf399b704c1af9f051af8842abb2c4d26632dd40b9e7\",\"license\":\"BSD-3-Clause\"},\"contracts/Gateway/NativeTokenGateway.sol\":{\"content\":\"// SPDX-License-Identifier: BSD-3-Clause\\npragma solidity 0.8.25;\\n\\nimport { Ownable2Step } from \\\"@openzeppelin/contracts/access/Ownable2Step.sol\\\";\\nimport { SafeERC20, IERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { ReentrancyGuard } from \\\"@openzeppelin/contracts/security/ReentrancyGuard.sol\\\";\\n\\nimport { IWrappedNative } from \\\"./Interfaces/IWrappedNative.sol\\\";\\nimport { INativeTokenGateway } from \\\"./INativeTokenGateway.sol\\\";\\nimport { IVToken } from \\\"./Interfaces/IVToken.sol\\\";\\n\\n/**\\n * @title NativeTokenGateway\\n * @author Venus\\n * @notice NativeTokenGateway contract facilitates interactions with a vToken market for native tokens (Native or wNativeToken)\\n */\\ncontract NativeTokenGateway is INativeTokenGateway, Ownable2Step, ReentrancyGuard {\\n using SafeERC20 for IERC20;\\n\\n /**\\n * @notice Address of wrapped native token contract\\n */\\n IWrappedNative public immutable wNativeToken;\\n\\n /**\\n * @notice Address of wrapped native token market\\n */\\n IVToken public immutable vWNativeToken;\\n\\n /// @custom:error RedeemFailed\\n error RedeemFailed(uint256 err);\\n\\n /// @custom:error BorrowFailed\\n error BorrowFailed(uint256 err);\\n\\n /// @custom:error MintFailed\\n error MintFailed(uint256 err);\\n\\n /// @custom:error RepayFailed\\n error RepayFailed(uint256 err);\\n\\n /**\\n * @notice Constructor for NativeTokenGateway\\n * @param vWrappedNativeToken Address of wrapped native token market\\n */\\n constructor(IVToken vWrappedNativeToken) {\\n ensureNonzeroAddress(address(vWrappedNativeToken));\\n\\n vWNativeToken = vWrappedNativeToken;\\n wNativeToken = IWrappedNative(vWNativeToken.underlying());\\n }\\n\\n /**\\n * @notice To receive Native when msg.data is empty\\n */\\n receive() external payable {}\\n\\n /**\\n * @notice To receive Native when msg.data is not empty\\n */\\n fallback() external payable {}\\n\\n /**\\n * @notice Wrap Native, get wNativeToken, mint vWNativeToken, and supply to the market.\\n * @param minter The address on behalf of whom the supply is performed.\\n * @custom:error ZeroAddressNotAllowed is thrown if address of minter is zero address\\n * @custom:error ZeroValueNotAllowed is thrown if mintAmount is zero\\n * @custom:error MintFailed is thrown if the mint operation fails\\n * @custom:event TokensWrappedAndSupplied is emitted when assets are supplied to the market\\n */\\n function wrapAndSupply(address minter) external payable nonReentrant {\\n ensureNonzeroAddress(minter);\\n\\n uint256 mintAmount = msg.value;\\n ensureNonzeroValue(mintAmount);\\n\\n wNativeToken.deposit{ value: mintAmount }();\\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), mintAmount);\\n\\n uint256 err = vWNativeToken.mintBehalf(minter, mintAmount);\\n if (err != 0) revert MintFailed(err);\\n\\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), 0);\\n emit TokensWrappedAndSupplied(minter, address(vWNativeToken), mintAmount);\\n }\\n\\n /**\\n * @notice Redeem vWNativeToken, unwrap to Native Token, and send to the user\\n * @param redeemAmount The amount of underlying tokens to redeem\\n * @custom:error ZeroValueNotAllowed is thrown if redeemAmount is zero\\n * @custom:event TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped\\n */\\n function redeemUnderlyingAndUnwrap(uint256 redeemAmount) external nonReentrant {\\n _redeemAndUnwrap(redeemAmount, true);\\n }\\n\\n /**\\n * @notice Redeem vWNativeToken, unwrap to Native Token, and send to the user\\n * @param redeemTokens The amount of vWNative tokens to redeem\\n * @custom:error ZeroValueNotAllowed is thrown if redeemTokens is zero\\n * @custom:event TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped\\n */\\n function redeemAndUnwrap(uint256 redeemTokens) external nonReentrant {\\n _redeemAndUnwrap(redeemTokens, false);\\n }\\n\\n /**\\n * @dev Borrow wNativeToken, unwrap to Native, and send to the user\\n * @param borrowAmount The amount of underlying tokens to borrow\\n * @custom:error ZeroValueNotAllowed is thrown if borrowAmount is zero\\n * @custom:error BorrowFailed is thrown if the borrow operation fails\\n * @custom:event TokensBorrowedAndUnwrapped is emitted when assets are borrowed from a market and unwrapped\\n */\\n function borrowAndUnwrap(uint256 borrowAmount) external nonReentrant {\\n ensureNonzeroValue(borrowAmount);\\n\\n uint256 err = vWNativeToken.borrowBehalf(msg.sender, borrowAmount);\\n if (err != 0) revert BorrowFailed(err);\\n\\n wNativeToken.withdraw(borrowAmount);\\n _safeTransferNativeTokens(msg.sender, borrowAmount);\\n emit TokensBorrowedAndUnwrapped(msg.sender, address(vWNativeToken), borrowAmount);\\n }\\n\\n /**\\n * @notice Wrap Native, repay borrow in the market, and send remaining Native to the user\\n * @custom:error ZeroValueNotAllowed is thrown if repayAmount is zero\\n * @custom:error RepayFailed is thrown if the repay operation fails\\n * @custom:event TokensWrappedAndRepaid is emitted when assets are repaid to a market and unwrapped\\n */\\n function wrapAndRepay() external payable nonReentrant {\\n uint256 repayAmount = msg.value;\\n ensureNonzeroValue(repayAmount);\\n\\n wNativeToken.deposit{ value: repayAmount }();\\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), repayAmount);\\n\\n uint256 borrowBalanceBefore = vWNativeToken.borrowBalanceCurrent(msg.sender);\\n uint256 err = vWNativeToken.repayBorrowBehalf(msg.sender, repayAmount);\\n if (err != 0) revert RepayFailed(err);\\n uint256 borrowBalanceAfter = vWNativeToken.borrowBalanceCurrent(msg.sender);\\n\\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), 0);\\n\\n if (borrowBalanceAfter == 0 && (repayAmount > borrowBalanceBefore)) {\\n uint256 dust;\\n unchecked {\\n dust = repayAmount - borrowBalanceBefore;\\n }\\n\\n wNativeToken.withdraw(dust);\\n _safeTransferNativeTokens(msg.sender, dust);\\n }\\n emit TokensWrappedAndRepaid(msg.sender, address(vWNativeToken), borrowBalanceBefore - borrowBalanceAfter);\\n }\\n\\n /**\\n * @notice Sweeps native assets (Native) from the contract and sends them to the owner\\n * @custom:event SweepNative is emitted when assets are swept from the contract\\n * @custom:access Controlled by Governance\\n */\\n function sweepNative() external onlyOwner {\\n uint256 balance = address(this).balance;\\n\\n if (balance > 0) {\\n address owner_ = owner();\\n _safeTransferNativeTokens(owner_, balance);\\n emit SweepNative(owner_, balance);\\n }\\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(IERC20 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 /**\\n * @dev Redeems tokens, unwrap them to Native Token, and send to the user\\n * This function is internally called by `redeemUnderlyingAndUnwrap` and `redeemAndUnwrap`\\n * @param redeemTokens The amount of tokens to be redeemed. This can refer to either the underlying tokens directly or their equivalent vTokens\\n * @param isUnderlying A boolean flag indicating whether the redemption is for underlying tokens directly (`true`) or for their equivalent vTokens (`false`).\\n * @custom:error ZeroValueNotAllowed is thrown if redeemTokens is zero\\n * @custom:error RedeemFailed is thrown if the redeem operation fails\\n * @custom:event TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped\\n */\\n function _redeemAndUnwrap(uint256 redeemTokens, bool isUnderlying) internal {\\n ensureNonzeroValue(redeemTokens);\\n\\n uint256 balanceBefore = wNativeToken.balanceOf(address(this));\\n\\n if (isUnderlying) {\\n uint256 err = vWNativeToken.redeemUnderlyingBehalf(msg.sender, redeemTokens);\\n if (err != 0) revert RedeemFailed(err);\\n } else {\\n uint256 err = vWNativeToken.redeemBehalf(msg.sender, redeemTokens);\\n if (err != 0) revert RedeemFailed(err);\\n }\\n\\n uint256 balanceAfter = wNativeToken.balanceOf(address(this));\\n uint256 redeemedAmount = balanceAfter - balanceBefore;\\n wNativeToken.withdraw(redeemedAmount);\\n\\n _safeTransferNativeTokens(msg.sender, redeemedAmount);\\n emit TokensRedeemedAndUnwrapped(msg.sender, address(vWNativeToken), redeemedAmount);\\n }\\n\\n /**\\n * @dev transfer Native tokens to an address, revert if it fails\\n * @param to recipient of the transfer\\n * @param value the amount to send\\n * @custom:error NativeTokenTransferFailed is thrown if the Native token transfer fails\\n */\\n function _safeTransferNativeTokens(address to, uint256 value) internal {\\n (bool success, ) = to.call{ value: value }(new bytes(0));\\n\\n if (!success) {\\n revert NativeTokenTransferFailed();\\n }\\n }\\n\\n /**\\n * @dev 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\\n **/\\n function ensureNonzeroAddress(address address_) internal pure {\\n if (address_ == address(0)) {\\n revert ZeroAddressNotAllowed();\\n }\\n }\\n\\n /**\\n * @dev 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\\n */\\n function ensureNonzeroValue(uint256 value_) internal pure {\\n if (value_ == 0) {\\n revert ZeroValueNotAllowed();\\n }\\n }\\n}\\n\",\"keccak256\":\"0x7fd0fc938069724e98b2d95e85b00cb83bdbfa239aa980d6ee86891a333a0d9e\",\"license\":\"BSD-3-Clause\"}},\"version\":1}", + "bytecode": "0x60c060405234801561000f575f80fd5b50604051611a1e380380611a1e83398101604081905261002e9161016a565b610037336100c4565b6001600255610045816100e0565b6001600160a01b03811660a081905260408051636f307dc360e01b81529051636f307dc39160048082019260209290919082900301815f875af115801561008e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100b2919061016a565b6001600160a01b03166080525061018c565b600180546001600160a01b03191690556100dd81610107565b50565b6001600160a01b0381166100dd576040516342bcdf7f60e11b815260040160405180910390fd5b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146100dd575f80fd5b5f6020828403121561017a575f80fd5b815161018581610156565b9392505050565b60805160a0516117bb6102635f395f818161010d015281816104670152818161058c015281816106a2015281816106f1015281816107b0015281816107d7015281816109db01528181610a1901528181610ab401528181610b5901528181610bfc01528181610cc201528181610f1401528181610fce015261118d01525f818161015c01528181610513015281816106040152818161067e0152818161078e0152818161093d015281816109b701528181610bda01528181610c4d01528181610e7d0152818161107d015261111401526117bb5ff3fe6080604052600436106100d4575f3560e01c80638da5cb5b11610078578063ab803a7611610055578063ab803a7614610232578063e30c397814610246578063f2fde38b14610263578063ff0f4abd1461028257005b80638da5cb5b146101e45780639cc60d4414610200578063a86f82211461021f57005b8063715018a6116100b1578063715018a61461017e57806379ba50971461019257806385ceb1e4146101a657806389f1cf38146101c557005b80631be19560146100dd57806355a490a7146100fc57806359c91f191461014b57005b366100db57005b005b3480156100e8575f80fd5b506100db6100f73660046116ac565b61028a565b348015610107575f80fd5b5061012f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b348015610156575f80fd5b5061012f7f000000000000000000000000000000000000000000000000000000000000000081565b348015610189575f80fd5b506100db610377565b34801561019d575f80fd5b506100db61038a565b3480156101b1575f80fd5b506100db6101c03660046116ce565b610409565b3480156101d0575f80fd5b506100db6101df3660046116ce565b610426565b3480156101ef575f80fd5b505f546001600160a01b031661012f565b34801561020b575f80fd5b506100db61021a3660046116ce565b610438565b6100db61022d3660046116ac565b6105e7565b34801561023d575f80fd5b506100db61084e565b348015610251575f80fd5b506001546001600160a01b031661012f565b34801561026e575f80fd5b506100db61027d3660046116ac565b6108b9565b6100db610929565b610292610d2c565b6040516370a0823160e01b81523060048201525f906001600160a01b038316906370a0823190602401602060405180830381865afa1580156102d6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102fa91906116e5565b90508015610373575f80546001600160a01b031690506103246001600160a01b0384168284610d85565b806001600160a01b0316836001600160a01b03167f6d25be279134f4ecaa4770aff0c3d916d9e7c5ef37b65ed95dbdba411f5d54d58460405161036991815260200190565b60405180910390a3505b5050565b61037f610d2c565b6103885f610ded565b565b60015433906001600160a01b031681146103fd5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084015b60405180910390fd5b61040681610ded565b50565b610411610e06565b61041c816001610e5d565b6104066001600255565b61042e610e06565b61041c815f610e5d565b610440610e06565b610449816111e4565b60405163856e5bb360e01b8152336004820152602481018290525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063856e5bb3906044016020604051808303815f875af11580156104b5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104d991906116e5565b905080156104fd5760405163158f1c0f60e01b8152600481018290526024016103f4565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024015f604051808303815f87803b15801561055c575f80fd5b505af115801561056e573d5f803e3d5ffd5b5050505061057c3383611204565b6040518281526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169033907f3b325d03ea6fc2aa5ba54c0fd65bb0febe127cb8c7ff01f190fcddf2893b80699060200160405180910390a3506104066001600255565b6105ef610e06565b6105f88161128e565b34610602816111e4565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b15801561065b575f80fd5b505af115801561066d573d5f803e3d5ffd5b506106c99350506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691507f00000000000000000000000000000000000000000000000000000000000000009050836112b5565b6040516323323e0360e01b81526001600160a01b038381166004830152602482018390525f917f0000000000000000000000000000000000000000000000000000000000000000909116906323323e03906044016020604051808303815f875af1158015610739573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061075d91906116e5565b905080156107815760405163ac55121f60e01b8152600481018290526024016103f4565b6107d56001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f00000000000000000000000000000000000000000000000000000000000000005f6112b5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03167ffc54dd2cff8bcf58b0746818b1d9aac56525760131df031a96427ecd6e5612448460405161083a91815260200190565b60405180910390a350506104066001600255565b610856610d2c565b478015610406575f546001600160a01b03166108728183611204565b806001600160a01b03167f0a1dd7c5bdc40ecbdefc1bfda22f1dfb98c8fc3e3940aab73ad7fba37720d0a0836040516108ad91815260200190565b60405180910390a25050565b6108c1610d2c565b600180546001600160a01b0383166001600160a01b031990911681179091556108f15f546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b610931610e06565b3461093b816111e4565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b158015610994575f80fd5b505af11580156109a6573d5f803e3d5ffd5b50610a029350506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691507f00000000000000000000000000000000000000000000000000000000000000009050836112b5565b6040516305eff7ef60e21b81523360048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906317bfdfbc906024016020604051808303815f875af1158015610a67573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a8b91906116e5565b6040516304c11f0360e31b8152336004820152602481018490529091505f906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632608f818906044016020604051808303815f875af1158015610afa573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b1e91906116e5565b90508015610b42576040516305e4427960e11b8152600481018290526024016103f4565b6040516305eff7ef60e21b81523360048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906317bfdfbc906024016020604051808303815f875af1158015610ba7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bcb91906116e5565b9050610c216001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f00000000000000000000000000000000000000000000000000000000000000005f6112b5565b80158015610c2e57508284115b15610cb857604051632e1a7d4d60e01b815283850360048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024015f604051808303815f87803b158015610c96575f80fd5b505af1158015610ca8573d5f803e3d5ffd5b50505050610cb63382611204565b505b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016337e2a489ca326b23ea0117956ee9d62960c53a81b8f57fafd608e56f57f324168610d0d84876116fc565b60405190815260200160405180910390a3505050506103886001600255565b5f546001600160a01b031633146103885760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103f4565b6040516001600160a01b038316602482015260448101829052610de890849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611349565b505050565b600180546001600160a01b03191690556104068161141c565b6002805403610e575760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103f4565b60028055565b610e66826111e4565b6040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610eca573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610eee91906116e5565b90508115610fb057604051636f9d28b760e11b8152336004820152602481018490525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063df3a516e906044016020604051808303815f875af1158015610f62573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f8691906116e5565b90508015610faa5760405163eeddaac560e01b8152600481018290526024016103f4565b50611066565b604051631085e02960e11b8152336004820152602481018490525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063210bc052906044016020604051808303815f875af115801561101c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061104091906116e5565b905080156110645760405163eeddaac560e01b8152600481018290526024016103f4565b505b6040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156110ca573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110ee91906116e5565b90505f6110fb83836116fc565b604051632e1a7d4d60e01b8152600481018290529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024015f604051808303815f87803b15801561115d575f80fd5b505af115801561116f573d5f803e3d5ffd5b5050505061117d3382611204565b6040518181526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169033907faf321c699f4cc4970eef3edf8fe2a0a395a3f5b62c6e91958cad3d424952436b9060200160405180910390a35050505050565b805f036104065760405163273e150360e21b815260040160405180910390fd5b604080515f808252602082019092526001600160a01b03841690839060405161122d919061171b565b5f6040518083038185875af1925050503d805f8114611267576040519150601f19603f3d011682016040523d82523d5f602084013e61126c565b606091505b5050905080610de857604051630c08bcb960e21b815260040160405180910390fd5b6001600160a01b038116610406576040516342bcdf7f60e11b815260040160405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052611306848261146b565b611343576040516001600160a01b03841660248201525f604482015261133990859063095ea7b360e01b90606401610db1565b6113438482611349565b50505050565b5f61139d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661150e9092919063ffffffff16565b905080515f14806113bd5750808060200190518101906113bd9190611731565b610de85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016103f4565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f805f846001600160a01b031684604051611486919061171b565b5f604051808303815f865af19150503d805f81146114bf576040519150601f19603f3d011682016040523d82523d5f602084013e6114c4565b606091505b50915091508180156114ee5750805115806114ee5750808060200190518101906114ee9190611731565b801561150357506001600160a01b0385163b15155b925050505b92915050565b606061151c84845f85611524565b949350505050565b6060824710156115855760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016103f4565b5f80866001600160a01b031685876040516115a0919061171b565b5f6040518083038185875af1925050503d805f81146115da576040519150601f19603f3d011682016040523d82523d5f602084013e6115df565b606091505b50915091506115f0878383876115fb565b979650505050505050565b606083156116695782515f03611662576001600160a01b0385163b6116625760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103f4565b508161151c565b61151c838381511561167e5781518083602001fd5b8060405162461bcd60e51b81526004016103f49190611750565b6001600160a01b0381168114610406575f80fd5b5f602082840312156116bc575f80fd5b81356116c781611698565b9392505050565b5f602082840312156116de575f80fd5b5035919050565b5f602082840312156116f5575f80fd5b5051919050565b8181038181111561150857634e487b7160e01b5f52601160045260245ffd5b5f82518060208501845e5f920191825250919050565b5f60208284031215611741575f80fd5b815180151581146116c7575f80fd5b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056fea26469706673582212204ac0cba011f73ed41ce7953915916774d93c37d57a6f894bb3265d008d027f4264736f6c63430008190033", + "deployedBytecode": "0x6080604052600436106100d4575f3560e01c80638da5cb5b11610078578063ab803a7611610055578063ab803a7614610232578063e30c397814610246578063f2fde38b14610263578063ff0f4abd1461028257005b80638da5cb5b146101e45780639cc60d4414610200578063a86f82211461021f57005b8063715018a6116100b1578063715018a61461017e57806379ba50971461019257806385ceb1e4146101a657806389f1cf38146101c557005b80631be19560146100dd57806355a490a7146100fc57806359c91f191461014b57005b366100db57005b005b3480156100e8575f80fd5b506100db6100f73660046116ac565b61028a565b348015610107575f80fd5b5061012f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b348015610156575f80fd5b5061012f7f000000000000000000000000000000000000000000000000000000000000000081565b348015610189575f80fd5b506100db610377565b34801561019d575f80fd5b506100db61038a565b3480156101b1575f80fd5b506100db6101c03660046116ce565b610409565b3480156101d0575f80fd5b506100db6101df3660046116ce565b610426565b3480156101ef575f80fd5b505f546001600160a01b031661012f565b34801561020b575f80fd5b506100db61021a3660046116ce565b610438565b6100db61022d3660046116ac565b6105e7565b34801561023d575f80fd5b506100db61084e565b348015610251575f80fd5b506001546001600160a01b031661012f565b34801561026e575f80fd5b506100db61027d3660046116ac565b6108b9565b6100db610929565b610292610d2c565b6040516370a0823160e01b81523060048201525f906001600160a01b038316906370a0823190602401602060405180830381865afa1580156102d6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102fa91906116e5565b90508015610373575f80546001600160a01b031690506103246001600160a01b0384168284610d85565b806001600160a01b0316836001600160a01b03167f6d25be279134f4ecaa4770aff0c3d916d9e7c5ef37b65ed95dbdba411f5d54d58460405161036991815260200190565b60405180910390a3505b5050565b61037f610d2c565b6103885f610ded565b565b60015433906001600160a01b031681146103fd5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084015b60405180910390fd5b61040681610ded565b50565b610411610e06565b61041c816001610e5d565b6104066001600255565b61042e610e06565b61041c815f610e5d565b610440610e06565b610449816111e4565b60405163856e5bb360e01b8152336004820152602481018290525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063856e5bb3906044016020604051808303815f875af11580156104b5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104d991906116e5565b905080156104fd5760405163158f1c0f60e01b8152600481018290526024016103f4565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024015f604051808303815f87803b15801561055c575f80fd5b505af115801561056e573d5f803e3d5ffd5b5050505061057c3383611204565b6040518281526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169033907f3b325d03ea6fc2aa5ba54c0fd65bb0febe127cb8c7ff01f190fcddf2893b80699060200160405180910390a3506104066001600255565b6105ef610e06565b6105f88161128e565b34610602816111e4565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b15801561065b575f80fd5b505af115801561066d573d5f803e3d5ffd5b506106c99350506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691507f00000000000000000000000000000000000000000000000000000000000000009050836112b5565b6040516323323e0360e01b81526001600160a01b038381166004830152602482018390525f917f0000000000000000000000000000000000000000000000000000000000000000909116906323323e03906044016020604051808303815f875af1158015610739573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061075d91906116e5565b905080156107815760405163ac55121f60e01b8152600481018290526024016103f4565b6107d56001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f00000000000000000000000000000000000000000000000000000000000000005f6112b5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03167ffc54dd2cff8bcf58b0746818b1d9aac56525760131df031a96427ecd6e5612448460405161083a91815260200190565b60405180910390a350506104066001600255565b610856610d2c565b478015610406575f546001600160a01b03166108728183611204565b806001600160a01b03167f0a1dd7c5bdc40ecbdefc1bfda22f1dfb98c8fc3e3940aab73ad7fba37720d0a0836040516108ad91815260200190565b60405180910390a25050565b6108c1610d2c565b600180546001600160a01b0383166001600160a01b031990911681179091556108f15f546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b610931610e06565b3461093b816111e4565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b158015610994575f80fd5b505af11580156109a6573d5f803e3d5ffd5b50610a029350506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691507f00000000000000000000000000000000000000000000000000000000000000009050836112b5565b6040516305eff7ef60e21b81523360048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906317bfdfbc906024016020604051808303815f875af1158015610a67573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a8b91906116e5565b6040516304c11f0360e31b8152336004820152602481018490529091505f906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632608f818906044016020604051808303815f875af1158015610afa573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b1e91906116e5565b90508015610b42576040516305e4427960e11b8152600481018290526024016103f4565b6040516305eff7ef60e21b81523360048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906317bfdfbc906024016020604051808303815f875af1158015610ba7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bcb91906116e5565b9050610c216001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f00000000000000000000000000000000000000000000000000000000000000005f6112b5565b80158015610c2e57508284115b15610cb857604051632e1a7d4d60e01b815283850360048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024015f604051808303815f87803b158015610c96575f80fd5b505af1158015610ca8573d5f803e3d5ffd5b50505050610cb63382611204565b505b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016337e2a489ca326b23ea0117956ee9d62960c53a81b8f57fafd608e56f57f324168610d0d84876116fc565b60405190815260200160405180910390a3505050506103886001600255565b5f546001600160a01b031633146103885760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103f4565b6040516001600160a01b038316602482015260448101829052610de890849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611349565b505050565b600180546001600160a01b03191690556104068161141c565b6002805403610e575760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103f4565b60028055565b610e66826111e4565b6040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610eca573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610eee91906116e5565b90508115610fb057604051636f9d28b760e11b8152336004820152602481018490525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063df3a516e906044016020604051808303815f875af1158015610f62573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f8691906116e5565b90508015610faa5760405163eeddaac560e01b8152600481018290526024016103f4565b50611066565b604051631085e02960e11b8152336004820152602481018490525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063210bc052906044016020604051808303815f875af115801561101c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061104091906116e5565b905080156110645760405163eeddaac560e01b8152600481018290526024016103f4565b505b6040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156110ca573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110ee91906116e5565b90505f6110fb83836116fc565b604051632e1a7d4d60e01b8152600481018290529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024015f604051808303815f87803b15801561115d575f80fd5b505af115801561116f573d5f803e3d5ffd5b5050505061117d3382611204565b6040518181526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169033907faf321c699f4cc4970eef3edf8fe2a0a395a3f5b62c6e91958cad3d424952436b9060200160405180910390a35050505050565b805f036104065760405163273e150360e21b815260040160405180910390fd5b604080515f808252602082019092526001600160a01b03841690839060405161122d919061171b565b5f6040518083038185875af1925050503d805f8114611267576040519150601f19603f3d011682016040523d82523d5f602084013e61126c565b606091505b5050905080610de857604051630c08bcb960e21b815260040160405180910390fd5b6001600160a01b038116610406576040516342bcdf7f60e11b815260040160405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052611306848261146b565b611343576040516001600160a01b03841660248201525f604482015261133990859063095ea7b360e01b90606401610db1565b6113438482611349565b50505050565b5f61139d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661150e9092919063ffffffff16565b905080515f14806113bd5750808060200190518101906113bd9190611731565b610de85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016103f4565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f805f846001600160a01b031684604051611486919061171b565b5f604051808303815f865af19150503d805f81146114bf576040519150601f19603f3d011682016040523d82523d5f602084013e6114c4565b606091505b50915091508180156114ee5750805115806114ee5750808060200190518101906114ee9190611731565b801561150357506001600160a01b0385163b15155b925050505b92915050565b606061151c84845f85611524565b949350505050565b6060824710156115855760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016103f4565b5f80866001600160a01b031685876040516115a0919061171b565b5f6040518083038185875af1925050503d805f81146115da576040519150601f19603f3d011682016040523d82523d5f602084013e6115df565b606091505b50915091506115f0878383876115fb565b979650505050505050565b606083156116695782515f03611662576001600160a01b0385163b6116625760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103f4565b508161151c565b61151c838381511561167e5781518083602001fd5b8060405162461bcd60e51b81526004016103f49190611750565b6001600160a01b0381168114610406575f80fd5b5f602082840312156116bc575f80fd5b81356116c781611698565b9392505050565b5f602082840312156116de575f80fd5b5035919050565b5f602082840312156116f5575f80fd5b5051919050565b8181038181111561150857634e487b7160e01b5f52601160045260245ffd5b5f82518060208501845e5f920191825250919050565b5f60208284031215611741575f80fd5b815180151581146116c7575f80fd5b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056fea26469706673582212204ac0cba011f73ed41ce7953915916774d93c37d57a6f894bb3265d008d027f4264736f6c63430008190033", + "devdoc": { + "author": "Venus", + "errors": { + "BorrowFailed(uint256)": [ + { + "custom:error": "BorrowFailed" + } + ], + "MintFailed(uint256)": [ + { + "custom:error": "MintFailed" + } + ], + "RedeemFailed(uint256)": [ + { + "custom:error": "RedeemFailed" + } + ], + "RepayFailed(uint256)": [ + { + "custom:error": "RepayFailed" + } + ] + }, + "events": { + "SweepNative(address,uint256)": { + "details": "Emitted when native asset is swept from the contract" + }, + "SweepToken(address,address,uint256)": { + "details": "Emitted when token is swept from the contract" + }, + "TokensBorrowedAndUnwrapped(address,address,uint256)": { + "details": "Emitted when native tokens are borrowed and unwrapped" + }, + "TokensRedeemedAndUnwrapped(address,address,uint256)": { + "details": "Emitted when tokens are redeemed and then unwrapped to be sent to user" + }, + "TokensWrappedAndRepaid(address,address,uint256)": { + "details": "Emitted when native currency is wrapped and repaid" + }, + "TokensWrappedAndSupplied(address,address,uint256)": { + "details": "Emitted when native currency is supplied" + } + }, + "kind": "dev", + "methods": { + "acceptOwnership()": { + "details": "The new owner accepts the ownership transfer." + }, + "borrowAndUnwrap(uint256)": { + "custom:error": "ZeroValueNotAllowed is thrown if borrowAmount is zeroBorrowFailed is thrown if the borrow operation fails", + "custom:event": "TokensBorrowedAndUnwrapped is emitted when assets are borrowed from a market and unwrapped", + "details": "Borrow wNativeToken, unwrap to Native, and send to the user", + "params": { + "borrowAmount": "The amount of underlying tokens to borrow" + } + }, + "constructor": { + "params": { + "vWrappedNativeToken": "Address of wrapped native token market" + } + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "pendingOwner()": { + "details": "Returns the address of the pending owner." + }, + "redeemAndUnwrap(uint256)": { + "custom:error": "ZeroValueNotAllowed is thrown if redeemTokens is zero", + "custom:event": "TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped", + "params": { + "redeemTokens": "The amount of vWNative tokens to redeem" + } + }, + "redeemUnderlyingAndUnwrap(uint256)": { + "custom:error": "ZeroValueNotAllowed is thrown if redeemAmount is zero", + "custom:event": "TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped", + "params": { + "redeemAmount": "The amount of underlying tokens to redeem" + } + }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner." + }, + "sweepNative()": { + "custom:access": "Controlled by Governance", + "custom:event": "SweepNative is emitted when assets are swept from the contract" + }, + "sweepToken(address)": { + "custom:access": "Controlled by Governance", + "custom:event": "SweepToken emits on success", + "params": { + "token": "Address of the token" + } + }, + "transferOwnership(address)": { + "details": "Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. Can only be called by the current owner." + }, + "wrapAndRepay()": { + "custom:error": "ZeroValueNotAllowed is thrown if repayAmount is zeroRepayFailed is thrown if the repay operation fails", + "custom:event": "TokensWrappedAndRepaid is emitted when assets are repaid to a market and unwrapped" + }, + "wrapAndSupply(address)": { + "custom:error": "ZeroAddressNotAllowed is thrown if address of minter is zero addressZeroValueNotAllowed is thrown if mintAmount is zeroMintFailed is thrown if the mint operation fails", + "custom:event": "TokensWrappedAndSupplied is emitted when assets are supplied to the market", + "params": { + "minter": "The address on behalf of whom the supply is performed." + } + } + }, + "title": "NativeTokenGateway", + "version": 1 + }, + "userdoc": { + "errors": { + "NativeTokenTransferFailed()": [ + { + "notice": "Thrown if transfer of native token fails" + } + ], + "ZeroAddressNotAllowed()": [ + { + "notice": "Thrown if the supplied address is a zero address where it is not allowed" + } + ], + "ZeroValueNotAllowed()": [ + { + "notice": "Thrown if the supplied value is 0 where it is not allowed" + } + ] + }, + "kind": "user", + "methods": { + "constructor": { + "notice": "Constructor for NativeTokenGateway" + }, + "redeemAndUnwrap(uint256)": { + "notice": "Redeem vWNativeToken, unwrap to Native Token, and send to the user" + }, + "redeemUnderlyingAndUnwrap(uint256)": { + "notice": "Redeem vWNativeToken, unwrap to Native Token, and send to the user" + }, + "sweepNative()": { + "notice": "Sweeps native assets (Native) from the contract and sends them to the owner" + }, + "sweepToken(address)": { + "notice": "Sweeps the input token address tokens from the contract and sends them to the owner" + }, + "vWNativeToken()": { + "notice": "Address of wrapped native token market" + }, + "wNativeToken()": { + "notice": "Address of wrapped native token contract" + }, + "wrapAndRepay()": { + "notice": "Wrap Native, repay borrow in the market, and send remaining Native to the user" + }, + "wrapAndSupply(address)": { + "notice": "Wrap Native, get wNativeToken, mint vWNativeToken, and supply to the market." + } + }, + "notice": "NativeTokenGateway contract facilitates interactions with a vToken market for native tokens (Native or wNativeToken)", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 7, + "contract": "contracts/Gateway/NativeTokenGateway.sol:NativeTokenGateway", + "label": "_owner", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 120, + "contract": "contracts/Gateway/NativeTokenGateway.sol:NativeTokenGateway", + "label": "_pendingOwner", + "offset": 0, + "slot": "1", + "type": "t_address" + }, + { + "astId": 206, + "contract": "contracts/Gateway/NativeTokenGateway.sol:NativeTokenGateway", + "label": "_status", + "offset": 0, + "slot": "2", + "type": "t_uint256" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} diff --git a/deployments/bsctestnet/solcInputs/d4715e66be994f4f4035be2d5c03faba.json b/deployments/bsctestnet/solcInputs/d4715e66be994f4f4035be2d5c03faba.json new file mode 100644 index 00000000..03ea3aec --- /dev/null +++ b/deployments/bsctestnet/solcInputs/d4715e66be994f4f4035be2d5c03faba.json @@ -0,0 +1,70 @@ +{ + "language": "Solidity", + "sources": { + "@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/access/Ownable2Step.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 \"./Ownable.sol\";\n\n/**\n * @dev Contract module which provides access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * 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 Ownable2Step is Ownable {\n address private _pendingOwner;\n\n event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Returns the address of the pending owner.\n */\n function pendingOwner() public view virtual returns (address) {\n return _pendingOwner;\n }\n\n /**\n * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual override onlyOwner {\n _pendingOwner = newOwner;\n emit OwnershipTransferStarted(owner(), newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual override {\n delete _pendingOwner;\n super._transferOwnership(newOwner);\n }\n\n /**\n * @dev The new owner accepts the ownership transfer.\n */\n function acceptOwnership() public virtual {\n address sender = _msgSender();\n require(pendingOwner() == sender, \"Ownable2Step: caller is not the new owner\");\n _transferOwnership(sender);\n }\n}\n" + }, + "@openzeppelin/contracts/security/ReentrancyGuard.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\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 ReentrancyGuard {\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 constructor() {\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" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.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 IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated 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/token/ERC20/utils/SafeERC20.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 \"../IERC20.sol\";\nimport \"../extensions/IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.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(IERC20 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(IERC20 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(IERC20 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(IERC20 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(IERC20 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 IERC20Permit token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n 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(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return\n success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));\n }\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" + }, + "contracts/Gateway/INativeTokenGateway.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n * @title INativeTokenGateway\n * @author Venus\n * @notice Interface for NativeTokenGateway contract\n */\ninterface INativeTokenGateway {\n /**\n * @dev Emitted when native currency is supplied\n */\n event TokensWrappedAndSupplied(address indexed sender, address indexed vToken, uint256 amount);\n\n /**\n * @dev Emitted when tokens are redeemed and then unwrapped to be sent to user\n */\n event TokensRedeemedAndUnwrapped(address indexed sender, address indexed vToken, uint256 amount);\n\n /**\n * @dev Emitted when native tokens are borrowed and unwrapped\n */\n event TokensBorrowedAndUnwrapped(address indexed sender, address indexed vToken, uint256 amount);\n\n /**\n * @dev Emitted when native currency is wrapped and repaid\n */\n event TokensWrappedAndRepaid(address indexed sender, address indexed vToken, uint256 amount);\n\n /**\n * @dev Emitted when token is swept from the contract\n */\n event SweepToken(address indexed token, address indexed receiver, uint256 amount);\n\n /**\n * @dev Emitted when native asset is swept from the contract\n */\n event SweepNative(address indexed receiver, uint256 amount);\n\n /**\n * @notice Thrown if transfer of native token fails\n */\n error NativeTokenTransferFailed();\n\n /**\n * @notice Thrown if the supplied address is a zero address where it is not allowed\n */\n error ZeroAddressNotAllowed();\n\n /**\n * @notice Thrown if the supplied value is 0 where it is not allowed\n */\n error ZeroValueNotAllowed();\n\n /**\n * @dev Wrap Native Token, get wNativeToken, mint vWNativeTokens, and supply to the market\n * @param minter The address on behalf of whom the supply is performed\n */\n function wrapAndSupply(address minter) external payable;\n\n /**\n * @dev Redeem vWNativeTokens, unwrap to Native Token, and send to the user\n * @param redeemAmount The amount of underlying tokens to redeem\n */\n function redeemUnderlyingAndUnwrap(uint256 redeemAmount) external;\n\n /**\n * @dev Redeem vWNativeTokens, unwrap to Native Token, and send to the user\n * @param redeemTokens The amount of vWNative tokens to redeem\n */\n function redeemAndUnwrap(uint256 redeemTokens) external;\n\n /**\n * @dev Borrow wNativeToken, unwrap to Native Token, and send to the user\n * @param amount The amount of underlying tokens to borrow\n */\n function borrowAndUnwrap(uint256 amount) external;\n\n /**\n * @dev Wrap Native Token, repay borrow in the market, and send remaining Native Token to the user\n */\n function wrapAndRepay() external payable;\n\n /**\n * @dev Sweeps input token address tokens from the contract and sends them to the owner\n */\n function sweepToken(IERC20 token) external;\n\n /**\n * @dev Sweeps native assets (Native Token) from the contract and sends them to the owner\n */\n function sweepNative() external;\n}\n" + }, + "contracts/Gateway/Interfaces/IVToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\ninterface IVToken {\n function mintBehalf(address receiver, uint256 mintAmount) external returns (uint256);\n\n function redeemUnderlyingBehalf(address redeemer, uint256 redeemAmount) external returns (uint256);\n\n function redeemBehalf(address redeemer, uint256 redeemTokens) external returns (uint256);\n\n function repayBorrowBehalf(address borrower, uint256 repayAmount) external returns (uint256);\n\n function borrowBehalf(address borrower, uint256 borrowAmount) external returns (uint256);\n\n function borrowBalanceCurrent(address account) external returns (uint256);\n\n function underlying() external returns (address);\n\n function exchangeRateCurrent() external returns (uint256);\n\n function transferFrom(address from, address to, uint256 amount) external returns (bool);\n\n function redeem(uint256 redeemTokens) external returns (uint256);\n}\n" + }, + "contracts/Gateway/Interfaces/IWrappedNative.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\ninterface IWrappedNative {\n function deposit() external payable;\n\n function withdraw(uint256) external;\n\n function approve(address guy, uint256 wad) external returns (bool);\n\n function transferFrom(address src, address dst, uint256 wad) external returns (bool);\n\n function transfer(address dst, uint256 wad) external returns (bool);\n\n function balanceOf(address account) external view returns (uint256);\n}\n" + }, + "contracts/Gateway/NativeTokenGateway.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { Ownable2Step } from \"@openzeppelin/contracts/access/Ownable2Step.sol\";\nimport { SafeERC20, IERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { ReentrancyGuard } from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\n\nimport { IWrappedNative } from \"./Interfaces/IWrappedNative.sol\";\nimport { INativeTokenGateway } from \"./INativeTokenGateway.sol\";\nimport { IVToken } from \"./Interfaces/IVToken.sol\";\n\n/**\n * @title NativeTokenGateway\n * @author Venus\n * @notice NativeTokenGateway contract facilitates interactions with a vToken market for native tokens (Native or wNativeToken)\n */\ncontract NativeTokenGateway is INativeTokenGateway, Ownable2Step, ReentrancyGuard {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Address of wrapped native token contract\n */\n IWrappedNative public immutable wNativeToken;\n\n /**\n * @notice Address of wrapped native token market\n */\n IVToken public immutable vWNativeToken;\n\n /// @custom:error RedeemFailed\n error RedeemFailed(uint256 err);\n\n /// @custom:error BorrowFailed\n error BorrowFailed(uint256 err);\n\n /// @custom:error MintFailed\n error MintFailed(uint256 err);\n\n /// @custom:error RepayFailed\n error RepayFailed(uint256 err);\n\n /**\n * @notice Constructor for NativeTokenGateway\n * @param vWrappedNativeToken Address of wrapped native token market\n */\n constructor(IVToken vWrappedNativeToken) {\n ensureNonzeroAddress(address(vWrappedNativeToken));\n\n vWNativeToken = vWrappedNativeToken;\n wNativeToken = IWrappedNative(vWNativeToken.underlying());\n }\n\n /**\n * @notice To receive Native when msg.data is empty\n */\n receive() external payable {}\n\n /**\n * @notice To receive Native when msg.data is not empty\n */\n fallback() external payable {}\n\n /**\n * @notice Wrap Native, get wNativeToken, mint vWNativeToken, and supply to the market.\n * @param minter The address on behalf of whom the supply is performed.\n * @custom:error ZeroAddressNotAllowed is thrown if address of minter is zero address\n * @custom:error ZeroValueNotAllowed is thrown if mintAmount is zero\n * @custom:error MintFailed is thrown if the mint operation fails\n * @custom:event TokensWrappedAndSupplied is emitted when assets are supplied to the market\n */\n function wrapAndSupply(address minter) external payable nonReentrant {\n ensureNonzeroAddress(minter);\n\n uint256 mintAmount = msg.value;\n ensureNonzeroValue(mintAmount);\n\n wNativeToken.deposit{ value: mintAmount }();\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), mintAmount);\n\n uint256 err = vWNativeToken.mintBehalf(minter, mintAmount);\n if (err != 0) revert MintFailed(err);\n\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), 0);\n emit TokensWrappedAndSupplied(minter, address(vWNativeToken), mintAmount);\n }\n\n /**\n * @notice Redeem vWNativeToken, unwrap to Native Token, and send to the user\n * @param redeemAmount The amount of underlying tokens to redeem\n * @custom:error ZeroValueNotAllowed is thrown if redeemAmount is zero\n * @custom:event TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped\n */\n function redeemUnderlyingAndUnwrap(uint256 redeemAmount) external nonReentrant {\n _redeemAndUnwrap(redeemAmount, true);\n }\n\n /**\n * @notice Redeem vWNativeToken, unwrap to Native Token, and send to the user\n * @param redeemTokens The amount of vWNative tokens to redeem\n * @custom:error ZeroValueNotAllowed is thrown if redeemTokens is zero\n * @custom:event TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped\n */\n function redeemAndUnwrap(uint256 redeemTokens) external nonReentrant {\n _redeemAndUnwrap(redeemTokens, false);\n }\n\n /**\n * @dev Borrow wNativeToken, unwrap to Native, and send to the user\n * @param borrowAmount The amount of underlying tokens to borrow\n * @custom:error ZeroValueNotAllowed is thrown if borrowAmount is zero\n * @custom:error BorrowFailed is thrown if the borrow operation fails\n * @custom:event TokensBorrowedAndUnwrapped is emitted when assets are borrowed from a market and unwrapped\n */\n function borrowAndUnwrap(uint256 borrowAmount) external nonReentrant {\n ensureNonzeroValue(borrowAmount);\n\n uint256 err = vWNativeToken.borrowBehalf(msg.sender, borrowAmount);\n if (err != 0) revert BorrowFailed(err);\n\n wNativeToken.withdraw(borrowAmount);\n _safeTransferNativeTokens(msg.sender, borrowAmount);\n emit TokensBorrowedAndUnwrapped(msg.sender, address(vWNativeToken), borrowAmount);\n }\n\n /**\n * @notice Wrap Native, repay borrow in the market, and send remaining Native to the user\n * @custom:error ZeroValueNotAllowed is thrown if repayAmount is zero\n * @custom:error RepayFailed is thrown if the repay operation fails\n * @custom:event TokensWrappedAndRepaid is emitted when assets are repaid to a market and unwrapped\n */\n function wrapAndRepay() external payable nonReentrant {\n uint256 repayAmount = msg.value;\n ensureNonzeroValue(repayAmount);\n\n wNativeToken.deposit{ value: repayAmount }();\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), repayAmount);\n\n uint256 borrowBalanceBefore = vWNativeToken.borrowBalanceCurrent(msg.sender);\n uint256 err = vWNativeToken.repayBorrowBehalf(msg.sender, repayAmount);\n if (err != 0) revert RepayFailed(err);\n uint256 borrowBalanceAfter = vWNativeToken.borrowBalanceCurrent(msg.sender);\n\n IERC20(address(wNativeToken)).forceApprove(address(vWNativeToken), 0);\n\n if (borrowBalanceAfter == 0 && (repayAmount > borrowBalanceBefore)) {\n uint256 dust;\n unchecked {\n dust = repayAmount - borrowBalanceBefore;\n }\n\n wNativeToken.withdraw(dust);\n _safeTransferNativeTokens(msg.sender, dust);\n }\n emit TokensWrappedAndRepaid(msg.sender, address(vWNativeToken), borrowBalanceBefore - borrowBalanceAfter);\n }\n\n /**\n * @notice Sweeps native assets (Native) from the contract and sends them to the owner\n * @custom:event SweepNative is emitted when assets are swept from the contract\n * @custom:access Controlled by Governance\n */\n function sweepNative() external onlyOwner {\n uint256 balance = address(this).balance;\n\n if (balance > 0) {\n address owner_ = owner();\n _safeTransferNativeTokens(owner_, balance);\n emit SweepNative(owner_, balance);\n }\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(IERC20 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 /**\n * @dev Redeems tokens, unwrap them to Native Token, and send to the user\n * This function is internally called by `redeemUnderlyingAndUnwrap` and `redeemAndUnwrap`\n * @param redeemTokens The amount of tokens to be redeemed. This can refer to either the underlying tokens directly or their equivalent vTokens\n * @param isUnderlying A boolean flag indicating whether the redemption is for underlying tokens directly (`true`) or for their equivalent vTokens (`false`).\n * @custom:error ZeroValueNotAllowed is thrown if redeemTokens is zero\n * @custom:error RedeemFailed is thrown if the redeem operation fails\n * @custom:event TokensRedeemedAndUnwrapped is emitted when assets are redeemed from a market and unwrapped\n */\n function _redeemAndUnwrap(uint256 redeemTokens, bool isUnderlying) internal {\n ensureNonzeroValue(redeemTokens);\n\n uint256 balanceBefore = wNativeToken.balanceOf(address(this));\n\n if (isUnderlying) {\n uint256 err = vWNativeToken.redeemUnderlyingBehalf(msg.sender, redeemTokens);\n if (err != 0) revert RedeemFailed(err);\n } else {\n uint256 err = vWNativeToken.redeemBehalf(msg.sender, redeemTokens);\n if (err != 0) revert RedeemFailed(err);\n }\n\n uint256 balanceAfter = wNativeToken.balanceOf(address(this));\n uint256 redeemedAmount = balanceAfter - balanceBefore;\n wNativeToken.withdraw(redeemedAmount);\n\n _safeTransferNativeTokens(msg.sender, redeemedAmount);\n emit TokensRedeemedAndUnwrapped(msg.sender, address(vWNativeToken), redeemedAmount);\n }\n\n /**\n * @dev transfer Native tokens to an address, revert if it fails\n * @param to recipient of the transfer\n * @param value the amount to send\n * @custom:error NativeTokenTransferFailed is thrown if the Native token transfer fails\n */\n function _safeTransferNativeTokens(address to, uint256 value) internal {\n (bool success, ) = to.call{ value: value }(new bytes(0));\n\n if (!success) {\n revert NativeTokenTransferFailed();\n }\n }\n\n /**\n * @dev 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\n **/\n function ensureNonzeroAddress(address address_) internal pure {\n if (address_ == address(0)) {\n revert ZeroAddressNotAllowed();\n }\n }\n\n /**\n * @dev 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\n */\n function ensureNonzeroValue(uint256 value_) internal pure {\n if (value_ == 0) {\n revert ZeroValueNotAllowed();\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200, + "details": { + "yul": true + } + }, + "evmVersion": "cancun", + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/bsctestnet_addresses.json b/deployments/bsctestnet_addresses.json index c0beb7d1..64a8a859 100644 --- a/deployments/bsctestnet_addresses.json +++ b/deployments/bsctestnet_addresses.json @@ -1,5 +1,7 @@ { "name": "bsctestnet", "chainId": "97", - "addresses": {} + "addresses": { + "NativeTokenGateway_vWBNB": "0xF34AAfc540Adc827A84736553BD29DE87a117558" + } } diff --git a/hardhat.config.ts b/hardhat.config.ts index 36022b88..a02503ca 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -39,8 +39,14 @@ extendConfig((config: HardhatConfig) => { ...config.external, deployments: { hardhat: [], - bsctestnet: ["node_modules/@venusprotocol/venus-protocol/deployments/bsctestnet"], - bscmainnet: ["node_modules/@venusprotocol/venus-protocol/deployments/bscmainnet"], + bsctestnet: [ + "node_modules/@venusprotocol/venus-protocol/deployments/bsctestnet", + "node_modules/@venusprotocol/governance-contracts/deployments/bsctestnet", + ], + bscmainnet: [ + "node_modules/@venusprotocol/venus-protocol/deployments/bscmainnet", + "node_modules/@venusprotocol/governance-contracts/deployments/bscmainnet", + ], unichainmainnet: ["node_modules/@venusprotocol/venus-protocol/deployments/unichainmainnet"], }, }; diff --git a/hardhat.config.zksync.ts b/hardhat.config.zksync.ts index d903f580..1304f279 100644 --- a/hardhat.config.zksync.ts +++ b/hardhat.config.zksync.ts @@ -47,7 +47,7 @@ task("accounts", "Prints the list of accounts", async (taskArgs, hre) => { const config: HardhatUserConfig = { defaultNetwork: "hardhat", zksolc: { - version: "1.5.3", + version: "1.5.0", }, solidity: { compilers: [ diff --git a/helpers/deploymentConfig.ts b/helpers/deploymentConfig.ts index 32c3f384..fe161f13 100644 --- a/helpers/deploymentConfig.ts +++ b/helpers/deploymentConfig.ts @@ -57,6 +57,12 @@ export const BASE_MAINNET_MULTISIG = "0x1803Cf1D3495b43cC628aa1d8638A981F8CD341C export const UNICHAIN_SEPOLIA_MULTISIG = "0x9831D3A641E8c7F082EEA75b8249c99be9D09a34"; export const UNICHAIN_MAINNET_MULTISIG = "0x1803Cf1D3495b43cC628aa1d8638A981F8CD341C"; +export const DEFAULT_BLOCKS_PER_YEAR = 42_048_000; // assuming a block is mined every 0.75 seconds +export const BSC_BLOCKS_PER_YEAR = 42_048_000; // assuming a block is mined every 0.75 seconds +export const ETH_BLOCKS_PER_YEAR = 2_628_000; // assuming a block is mined every 12 seconds +export const OPBNB_BLOCKS_PER_YEAR = 63_072_000; // assuming a block is mined every 0.5 seconds +export const SECONDS_PER_YEAR = 31_536_000; // seconds per year + export const preconfiguredAddresses = { hardhat: { VTreasury: "account:deployer", diff --git a/package.json b/package.json index b9bfc429..07d40c82 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "build": "rm -rf dist && hardhat compile && hardhat compile --config hardhat.config.zksync.ts && tsc --declaration", "docgen": "hardhat docgen", "prepare": "husky install", - "clean": "hardhat clean && hardhat clean --config hardhat.config.zksync.ts" + "clean": "hardhat clean && hardhat clean --config hardhat.config.zksync.ts", + "postinstall": "yarn patch-package" }, "repository": { "type": "git", @@ -91,12 +92,13 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "3.4.1", "eslint-plugin-promise": "^5.2.0", - "hardhat": "^2.22.18", + "hardhat": "^2.22.15", "hardhat-dependency-compiler": "^1.2.1", "hardhat-deploy": "^0.12.4", "hardhat-deploy-ethers": "^0.3.0-beta.13", "hardhat-gas-reporter": "^1.0.8", "husky": "^8.0.1", + "patch-package": "^8.0.0", "prettier": "2.7.1", "prettier-plugin-solidity": "1.1.3", "semantic-release": "^19.0.3", @@ -114,7 +116,7 @@ "ganache-core": "github:compound-finance/ganache-core.git#jflatow/unbreak-fork", "solidity-parser-antlr": "https://github.com/solidity-parser/parser#0.8.2", "@defi-wonderland/smock": "2.4.0", - "hardhat": "2.22.18", + "hardhat": "2.22.15", "@venusprotocol/solidity-utilities": "2.0.3" }, "publishConfig": { diff --git a/patches/@defi-wonderland+smock+2.4.0.patch b/patches/@defi-wonderland+smock+2.4.0.patch new file mode 100644 index 00000000..c2c2178e --- /dev/null +++ b/patches/@defi-wonderland+smock+2.4.0.patch @@ -0,0 +1,18 @@ +diff --git a/node_modules/@defi-wonderland/smock/dist/src/utils/hardhat.js b/node_modules/@defi-wonderland/smock/dist/src/utils/hardhat.js +index 15b140c..7a0c157 100644 +--- a/node_modules/@defi-wonderland/smock/dist/src/utils/hardhat.js ++++ b/node_modules/@defi-wonderland/smock/dist/src/utils/hardhat.js +@@ -6,7 +6,12 @@ const getHardhatBaseProvider = async (runtime) => { + const maxLoopIterations = 1024; + let currentLoopIterations = 0; + let provider = runtime.network.provider; +- await provider.init(); ++ if ('init' in provider) { ++ // Newer versions of Hardhat initialize the provider lazily, so we need to ++ // call provider.init() explicitly. This is a no-op if the provider is ++ // already initialized. ++ await provider.init(); ++ } + while (provider._wrapped !== undefined) { + provider = provider._wrapped; + currentLoopIterations += 1; \ No newline at end of file diff --git a/tests/hardhat/Fork/NativeTokenGateway.ts b/tests/hardhat/Fork/NativeTokenGateway.ts new file mode 100644 index 00000000..0200857a --- /dev/null +++ b/tests/hardhat/Fork/NativeTokenGateway.ts @@ -0,0 +1,370 @@ +import { expect } from "chai"; +import { Signer } from "ethers"; +import { parseUnits } from "ethers/lib/utils"; +import { ethers } from "hardhat"; + +import { + Comptroller, + ComptrollerHarness, + ERC20, + NativeTokenGateway, + VBep20Delegator, + VToken, +} from "../../../typechain"; +import { initMainnetUser, setForkBlock } from "./utils"; + +// Core Pool Configurations +const ADMIN_CORE = "0xce10739590001705F7FF231611ba4A48B2820327"; +const COMPTROLLER_ADDRESS_CORE = "0x94d1820b2D1c7c7452A163983Dc888CEC546b77D"; +const VWBNB_CORE = "0xd9E77847ec815E56ae2B9E69596C69b6972b0B1C"; +const USDT_CORE = "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c"; +const VUSDT_CORE = "0xb7526572FFE56AB9D7489838Bf2E18e3323b441A"; +const USER1_CORE = "0x745bCE0D540AbE9cB639b6eACb5f6Ded3Cf947C9"; +const USER2_CORE = "0xbEe5b9859B03FEefd5Ae3ce7C5d92f3b09a55149"; +const BLOCK_NUMBER_BNB = 64998882; + +async function configureTimeLockCore() { + impersonatedTimeLock_core = await initMainnetUser(ADMIN_CORE, ethers.utils.parseUnits("2")); +} + +const FORK = process.env.FORK === "true"; +const FORKED_NETWORK = process.env.FORKED_NETWORK; + +let user1_core: Signer; +let user2_core: Signer; +let impersonatedTimeLock_core: Signer; +let comptroller_core: ComptrollerHarness; +let vwbnb_core: VBep20Delegator; +let usdt_core: ERC20; +let vusdt_core: VBep20Delegator; +let nativeTokenGateway_core: NativeTokenGateway; + +async function setupCore() { + await configureTimeLockCore(); + + user1_core = await initMainnetUser(USER1_CORE, ethers.utils.parseEther("100")); + user2_core = await initMainnetUser(USER2_CORE, ethers.utils.parseEther("100")); + + await ethers.provider.send("hardhat_setBalance", [ + await user1_core.getAddress(), + "0x56BC75E2D63100000", // 100 BNB in hex + ]); + await ethers.provider.send("hardhat_setBalance", [ + await user2_core.getAddress(), + "0x56BC75E2D63100000", // 100 BNB in hex + ]); + + usdt_core = await ethers.getContractAt("@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20", USDT_CORE); + + const comptroller_core = await ethers.getContractAt("ComptrollerHarness", COMPTROLLER_ADDRESS_CORE); + + vusdt_core = await ethers.getContractAt("VBep20Delegator", VUSDT_CORE); + vwbnb_core = await ethers.getContractAt("VBep20Delegator", VWBNB_CORE); + + await comptroller_core.connect(impersonatedTimeLock_core)._supportMarket(vwbnb_core.address); + + await comptroller_core + .connect(impersonatedTimeLock_core) + ._setMarketSupplyCaps([VUSDT_CORE, VWBNB_CORE], [parseUnits("100000000000", 40), parseUnits("100000000000", 40)]); + + await comptroller_core + .connect(impersonatedTimeLock_core) + ._setMarketBorrowCaps([VUSDT_CORE, VWBNB_CORE], [parseUnits("100000000000", 40), parseUnits("100000000000", 40)]); + + await comptroller_core.connect(user1_core).enterMarkets([vusdt_core.address, vwbnb_core.address]); + await comptroller_core.connect(user2_core).enterMarkets([vusdt_core.address, vwbnb_core.address]); + + const nativeTokenGatewayFactory = await ethers.getContractFactory( + "contracts/Gateway/NativeTokenGateway.sol:NativeTokenGateway", + ); + const nativeTokenGateway_core = await nativeTokenGatewayFactory.deploy(VWBNB_CORE); + + return { + usdt_core, + comptroller_core, + vusdt_core, + vwbnb_core, + nativeTokenGateway_core, + }; +} + +// IL Pool Configurations + +const ADMIN_IL = "0x285960C5B22fD66A736C7136967A3eB15e93CC67"; +const COMPTROLLER_ADDRESS_IL = "0x687a01ecF6d3907658f7A7c714749fAC32336D1B"; +const VWETH_IL = "0x7c8ff7d2A1372433726f879BD945fFb250B94c65"; +const USDT_IL = "0xdAC17F958D2ee523a2206206994597C13D831ec7"; +const VUSDT_IL = "0x8C3e3821259B82fFb32B2450A95d2dcbf161C24E"; + +const USER1_IL = "0xf89d7b9c864f589bbF53a82105107622B35EaA40"; +const USER2_IL = "0x974CaA59e49682CdA0AD2bbe82983419A2ECC400"; +const BLOCK_NUMBER_ETHEREUM = 19781700; + +async function configureTimeLockIL() { + impersonatedTimeLock_il = await initMainnetUser(ADMIN_IL, ethers.utils.parseUnits("2")); +} + +let user1_il: Signer; +let user2_il: Signer; +let impersonatedTimeLock_il: Signer; +let comptroller_il: Comptroller; +let vweth_il: VToken; +let usdt_il: ERC20; +let vusdt_il: VToken; +let nativeTokenGateway_il: NativeTokenGateway; + +async function setupIL() { + await configureTimeLockIL(); + + user1_il = await initMainnetUser(USER1_IL, ethers.utils.parseEther("100")); + user2_il = await initMainnetUser(USER2_IL, ethers.utils.parseEther("100")); + + usdt_il = await ethers.getContractAt("@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20", USDT_IL); + + const comptroller_il = await ethers.getContractAt("Comptroller", COMPTROLLER_ADDRESS_IL); + + vusdt_il = await ethers.getContractAt("@venusprotocol/isolated-pools/contracts/VToken.sol:VToken", VUSDT_IL); + vweth_il = await ethers.getContractAt("@venusprotocol/isolated-pools/contracts/VToken.sol:VToken", VWETH_IL); + + await comptroller_il + .connect(impersonatedTimeLock_il) + .setMarketSupplyCaps([VUSDT_IL, VWETH_IL], [parseUnits("10000", 18), parseUnits("10000", 18)]); + + await comptroller_il.connect(user1_il).enterMarkets([vusdt_il.address, vweth_il.address]); + await comptroller_il.connect(user2_il).enterMarkets([vusdt_il.address, vweth_il.address]); + + const nativeTokenGatewayFactory = await ethers.getContractFactory( + "contracts/Gateway/NativeTokenGateway.sol:NativeTokenGateway", + ); + const nativeTokenGateway_il = await nativeTokenGatewayFactory.deploy(VWETH_IL); + + return { + usdt_il, + comptroller_il, + vusdt_il, + vweth_il, + nativeTokenGateway_il, + }; +} + +// Core +if (FORK && FORKED_NETWORK === "bsctestnet") { + describe("Core Pool's NativeTokenGateway", async () => { + const supplyAmount = parseUnits("10", 18); + beforeEach("setup", async () => { + await setForkBlock(BLOCK_NUMBER_BNB); + ({ usdt_core, comptroller_core, vusdt_core, nativeTokenGateway_core } = await setupCore()); + }); + + describe("wrapAndSupply", () => { + it("should wrap and supply bnb", async () => { + const balanceBeforeSupplying = await vwbnb_core.balanceOf(await user1_core.getAddress()); + + const tx = await nativeTokenGateway_core + .connect(user1_core) + .wrapAndSupply(await user1_core.getAddress(), { value: supplyAmount }); + const balanceAfterSupplying = await vwbnb_core.balanceOf(await user1_core.getAddress()); + await expect(balanceAfterSupplying.sub(balanceBeforeSupplying).toString()).to.closeTo( + parseUnits("10", 8), + parseUnits("1", 7), + ); + await expect(tx).to.changeEtherBalances([user1_core], [supplyAmount.mul(-1)]); + }); + }); + + describe("redeemUnderlyingAndUnwrap", () => { + beforeEach(async () => { + await nativeTokenGateway_core + .connect(user1_core) + .wrapAndSupply(await user1_core.getAddress(), { value: supplyAmount }); + }); + + it("should redeem underlying tokens and unwrap and send it to the user", async () => { + const redeemAmount = parseUnits("10", 18); + await comptroller_core.connect(user1_core).updateDelegate(nativeTokenGateway_core.address, true); + + const bnbBalanceBefore = await user1_core.getBalance(); + await nativeTokenGateway_core.connect(user1_core).redeemUnderlyingAndUnwrap(redeemAmount); + const bnbBalanceAfter = await user1_core.getBalance(); + + await expect(bnbBalanceAfter.sub(bnbBalanceBefore)).to.closeTo(redeemAmount, parseUnits("1", 16)); + + expect(await vwbnb_core.balanceOf(await user1_core.getAddress())).to.closeTo(0, 10); + }); + }); + + describe("redeemAndUnwrap", () => { + beforeEach(async () => { + await nativeTokenGateway_core + .connect(user1_core) + .wrapAndSupply(await user1_core.getAddress(), { value: supplyAmount }); + }); + + it("should redeem vTokens and unwrap and send it to the user", async () => { + const redeemTokens = await vwbnb_core.balanceOf(await user1_core.getAddress()); + await comptroller_core.connect(user1_core).updateDelegate(nativeTokenGateway_core.address, true); + + const bnbBalanceBefore = await user1_core.getBalance(); + await nativeTokenGateway_core.connect(user1_core).redeemAndUnwrap(redeemTokens); + const bnbBalanceAfter = await user1_core.getBalance(); + + await expect(bnbBalanceAfter.sub(bnbBalanceBefore)).to.closeTo(parseUnits("10", 18), parseUnits("1", 16)); + expect(await vwbnb_core.balanceOf(await user1_core.getAddress())).to.eq(0); + }); + }); + + describe("borrowAndUnwrap", () => { + beforeEach(async () => { + await nativeTokenGateway_core + .connect(user1_core) + .wrapAndSupply(await user1_core.getAddress(), { value: supplyAmount }); + }); + + it("should borrow and unwrap wbnb and send it to borrower", async () => { + await nativeTokenGateway_core + .connect(user1_core) + .wrapAndSupply(await user1_core.getAddress(), { value: supplyAmount }); + await usdt_core.connect(user2_core).approve(vusdt_core.address, parseUnits("5000", 6)); + await vusdt_core.connect(user2_core).mint(parseUnits("500", 6)); + + await comptroller_core.connect(user2_core).updateDelegate(nativeTokenGateway_core.address, true); + + const borrowAmount = parseUnits("2", 6); + + const tx = await nativeTokenGateway_core.connect(user2_core).borrowAndUnwrap(borrowAmount); + + await expect(tx).to.changeEtherBalances([user2_core], [borrowAmount]); + }); + }); + + describe("wrapAndRepay", () => { + beforeEach(async () => { + await nativeTokenGateway_core + .connect(user1_core) + .wrapAndSupply(await user1_core.getAddress(), { value: supplyAmount }); + }); + + it("should wrap and repay", async () => { + const borrowAmount = parseUnits("0.2", 18); + const repayAmount = parseUnits("0.2", 18); + await usdt_core.connect(user2_core).approve(vusdt_core.address, parseUnits("500", 6)); + await vusdt_core.connect(user2_core).mint(parseUnits("500", 6)); + + await vwbnb_core.connect(user2_core).borrow(borrowAmount); + const bnbBalanceBefore = await user2_core.getBalance(); + await nativeTokenGateway_core.connect(user2_core).wrapAndRepay({ value: repayAmount }); + const bnbBalanceAfter = await user2_core.getBalance(); + + expect(bnbBalanceBefore.sub(bnbBalanceAfter)).to.closeTo(borrowAmount, parseUnits("1", 18)); + expect(await vwbnb_core.balanceOf(await user1_core.getAddress())).to.gt(0); + }); + }); + }); +} + +if (FORK && FORKED_NETWORK === "ethereum") { + describe("Isolated Pool's NativeTokenGateway", async () => { + const supplyAmount = parseUnits("10", 18); + beforeEach("setup", async () => { + await setForkBlock(BLOCK_NUMBER_ETHEREUM); + ({ usdt_il, comptroller_il, vusdt_il, nativeTokenGateway_il } = await setupIL()); + }); + + describe("wrapAndSupply", () => { + it("should wrap and supply eth", async () => { + const balanceBeforeSupplying = await vweth_il.balanceOf(await user1_il.getAddress()); + const tx = await nativeTokenGateway_il + .connect(user1_il) + .wrapAndSupply(await user1_il.getAddress(), { value: supplyAmount }); + const balanceAfterSupplying = await vweth_il.balanceOf(await user1_il.getAddress()); + await expect(balanceAfterSupplying.sub(balanceBeforeSupplying).toString()).to.closeTo( + parseUnits("10", 8), + parseUnits("1", 7), + ); + await expect(tx).to.changeEtherBalances([user1_il], [supplyAmount.mul(-1)]); + }); + }); + + describe("redeemUnderlyingAndUnwrap", () => { + beforeEach(async () => { + await nativeTokenGateway_il + .connect(user1_il) + .wrapAndSupply(await user1_il.getAddress(), { value: supplyAmount }); + }); + + it("should redeem underlying tokens and unwrap and send it to the user", async () => { + const redeemAmount = parseUnits("10", 18); + await comptroller_il.connect(user1_il).updateDelegate(nativeTokenGateway_il.address, true); + + const ethBalanceBefore = await user1_il.getBalance(); + await nativeTokenGateway_il.connect(user1_il).redeemUnderlyingAndUnwrap(redeemAmount); + const ethBalanceAfter = await user1_il.getBalance(); + + await expect(ethBalanceAfter.sub(ethBalanceBefore)).to.closeTo(redeemAmount, parseUnits("1", 16)); + + expect(await vweth_il.balanceOf(await user1_il.getAddress())).to.closeTo(0, 10); + }); + }); + + describe("redeemAndUnwrap", () => { + beforeEach(async () => { + await nativeTokenGateway_il + .connect(user1_il) + .wrapAndSupply(await user1_il.getAddress(), { value: supplyAmount }); + }); + + it("should redeem vTokens and unwrap and send it to the user", async () => { + const redeemTokens = await vweth_il.balanceOf(await user1_il.getAddress()); + await comptroller_il.connect(user1_il).updateDelegate(nativeTokenGateway_il.address, true); + + const ethBalanceBefore = await user1_il.getBalance(); + await nativeTokenGateway_il.connect(user1_il).redeemAndUnwrap(redeemTokens); + const ethBalanceAfter = await user1_il.getBalance(); + + await expect(ethBalanceAfter.sub(ethBalanceBefore)).to.closeTo(parseUnits("10", 18), parseUnits("1", 16)); + expect(await vweth_il.balanceOf(await user1_il.getAddress())).to.eq(0); + }); + }); + + describe("borrowAndUnwrap", () => { + beforeEach(async () => { + await nativeTokenGateway_il + .connect(user1_il) + .wrapAndSupply(await user1_il.getAddress(), { value: supplyAmount }); + }); + + it("should borrow and unwrap weth and send it to borrower", async () => { + await nativeTokenGateway_il + .connect(user1_il) + .wrapAndSupply(await user1_il.getAddress(), { value: supplyAmount }); + await usdt_il.connect(user2_il).approve(vusdt_il.address, parseUnits("5000", 6)); + + await vusdt_il.connect(user2_il).mint(parseUnits("5000", 6)); + + await comptroller_il.connect(user2_il).updateDelegate(nativeTokenGateway_il.address, true); + + const borrowAmount = parseUnits("2", 6); + const tx = await nativeTokenGateway_il.connect(user2_il).borrowAndUnwrap(borrowAmount); + + await expect(tx).to.changeEtherBalances([user2_il], [borrowAmount]); + }); + }); + + describe("wrapAndRepay", () => { + it("should wrap and repay", async () => { + const borrowAmount = parseUnits("1", 18); + const repayAmount = parseUnits("10", 18); + await usdt_il.connect(user2_il).approve(vusdt_il.address, parseUnits("5000", 6)); + await vusdt_il.connect(user2_il).mint(parseUnits("5000", 6)); + await vweth_il.connect(user2_il).borrow(borrowAmount); + + const ethBalanceBefore = await user2_il.getBalance(); + await nativeTokenGateway_il.connect(user2_il).wrapAndRepay({ value: repayAmount }); + const ethBalanceAfter = await user2_il.getBalance(); + + expect(ethBalanceBefore.sub(ethBalanceAfter)).to.closeTo(borrowAmount, parseUnits("1", 18)); + expect(await vweth_il.balanceOf(await user1_il.getAddress())).to.eq(0); + }); + }); + }); +} diff --git a/tests/hardhat/Gateway/NativeTokenGateway.ts b/tests/hardhat/Gateway/NativeTokenGateway.ts new file mode 100644 index 00000000..89a68da3 --- /dev/null +++ b/tests/hardhat/Gateway/NativeTokenGateway.ts @@ -0,0 +1,600 @@ +import { FakeContract, MockContract, smock } from "@defi-wonderland/smock"; +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers"; +import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; +import chai from "chai"; +import { Signer } from "ethers"; +import { parseUnits } from "ethers/lib/utils"; +import { ethers, upgrades } from "hardhat"; + +import { + Comptroller, + ComptrollerHarness, + ComptrollerHarness__factory, + ComptrollerLens__factory, + IAccessControlManagerV5, + IAccessControlManagerV8, + MockPriceOracle__factory, + MockToken, + MockToken__factory, + NativeTokenGateway, + PoolRegistry, + PoolRegistry__factory, + PriceOracle, + ResilientOracleInterface, + VBep20Immutable, + VToken, + VTokenHarness, + VTokenHarness__factory, + WrappedNative, +} from "../../../typechain"; +import { makeVToken } from "../util/TokenTestHelpers"; + +const { expect } = chai; +chai.use(smock.matchers); + +type GatewayFixtureCore = { + oracle: FakeContract; + accessControl: FakeContract; + comptroller: MockContract; + usdt: MockContract; + vusdt: VBep20Immutable; + vweth: VBep20Immutable; + weth: WrappedNative; + nativeTokenGateway: NativeTokenGateway; +}; + +type GatewayFixtureIL = { + oracle: FakeContract; + accessControl: FakeContract; + comptroller: Comptroller; + usdt: MockContract; + vusdt: VTokenHarness; + weth: WrappedNative; + vweth: VTokenHarness; + nativeTokenGateway: NativeTokenGateway; +}; + +async function configureVtoken( + underlyingToken: MockContract | VBep20Immutable, + name: string, + symbol: string, + comptroller: MockContract, + admin: SignerWithAddress, +) { + const InterstRateModel = await ethers.getContractFactory("InterestRateModelHarness"); + const interestRateModel = await InterstRateModel.deploy(parseUnits("1", 12)); + await interestRateModel.deployed(); + + const vTokenFactory = await ethers.getContractFactory("VBep20Immutable"); + const vToken = await vTokenFactory.deploy( + underlyingToken.address, + comptroller.address, + interestRateModel.address, + parseUnits("1", 28), + name, + symbol, + 18, + admin.address, + ); + await vToken.deployed(); + return vToken; +} + +async function deployGatewayCore(): Promise { + const [, , user2, admin] = await ethers.getSigners(); + + const MockToken = await smock.mock("MockToken"); + const usdt = await MockToken.deploy("USDT", "USDT", 18); + + const accessControl = await smock.fake("IAccessControlManagerV8"); + accessControl.isAllowedToCall.returns(true); + + const closeFactor = parseUnits("6", 17); + const liquidationIncentive = parseUnits("1", 18); + + const ComptrollerFactory = await smock.mock("ComptrollerHarness"); + const comptroller = await ComptrollerFactory.deploy(); + + const ComptrollerLensFactory = await smock.mock("ComptrollerLens"); + const comptrollerLens = await ComptrollerLensFactory.deploy(); + + const fakePriceOracle = await smock.fake( + "@venusprotocol/venus-protocol/contracts/Oracle/PriceOracle.sol:PriceOracle", + ); + + await comptroller._setPriceOracle(fakePriceOracle.address); + await comptroller._setAccessControl(accessControl.address); + await comptroller._setCloseFactor(closeFactor); + await comptroller._setLiquidationIncentive(liquidationIncentive); + await comptroller._setComptrollerLens(comptrollerLens.address); + + const wethFactory = await ethers.getContractFactory("WrappedNative"); + const weth = await wethFactory.deploy(); + weth.mint(parseUnits("100000000", 18)); + + const vusdt = await configureVtoken(usdt, "Venus USDT", "vusdt", comptroller, admin); + const vweth = await configureVtoken(weth, "Venus WETH", "vweth", comptroller, admin); + + await comptroller._supportMarket(vusdt.address); + await comptroller._supportMarket(vweth.address); + await comptroller._setMarketBorrowCaps( + [vusdt.address, vweth.address], + [parseUnits("10000", 18), parseUnits("10000", 18)], + ); + await comptroller._setMarketSupplyCaps( + [vusdt.address, vweth.address], + [parseUnits("10000", 18), parseUnits("10000", 18)], + ); + await comptroller._setCollateralFactor(vusdt.address, parseUnits("5", 17)); + await comptroller._setCollateralFactor(vweth.address, parseUnits("5", 17)); + + const nativeTokenGatewayFactory = await ethers.getContractFactory( + "contracts/Gateway/NativeTokenGateway.sol:NativeTokenGateway", + ); + const nativeTokenGateway = await nativeTokenGatewayFactory.deploy(vweth.address); + + fakePriceOracle.getUnderlyingPrice.whenCalledWith(vusdt.address).returns(parseUnits("1", 18)); + fakePriceOracle.getUnderlyingPrice.whenCalledWith(vweth.address).returns(parseUnits("1000", 18)); + + await usdt.faucet(parseUnits("100000", 18)); + await usdt.transfer(user2.address, parseUnits("10000", 18)); + + return { + oracle: fakePriceOracle, + comptroller, + accessControl, + usdt, + vusdt, + weth, + vweth, + nativeTokenGateway, + }; +} + +async function deployGatewayIL(): Promise { + const [wallet, , user2] = await ethers.getSigners(); + + const MockToken = await smock.mock("MockToken"); + const usdt = await MockToken.deploy("USDT", "USDT", 18); + + const accessControl = await smock.fake("AccessControlManager"); + accessControl.isAllowedToCall.returns(true); + + const closeFactor = parseUnits("6", 17); + const liquidationIncentive = parseUnits("1", 18); + const minLiquidatableCollateral = parseUnits("100", 18); + + const PoolRegistry = await ethers.getContractFactory("PoolRegistry"); + const poolRegistry = (await upgrades.deployProxy(PoolRegistry, [accessControl.address])) as PoolRegistry; + + const Comptroller = await ethers.getContractFactory("Comptroller"); + const comptrollerBeacon = await upgrades.deployBeacon(Comptroller, { constructorArgs: [poolRegistry.address] }); + + const maxLoopsLimit = 150; + const fakePriceOracle = await smock.fake(MockPriceOracle__factory.abi); + + const comptrollerProxy = (await upgrades.deployBeaconProxy(comptrollerBeacon, Comptroller, [ + maxLoopsLimit, + accessControl.address, + ])) as Comptroller; + + await comptrollerProxy.setPriceOracle(fakePriceOracle.address); + + // Registering the pool + await poolRegistry.addPool( + "Pool 1", + comptrollerProxy.address, + closeFactor, + liquidationIncentive, + minLiquidatableCollateral, + ); + + await comptrollerProxy.setPriceOracle(fakePriceOracle.address); + + const wethFactory = await ethers.getContractFactory("WrappedNative"); + const weth = await wethFactory.deploy(); + weth.mint(parseUnits("100000000", 18)); + console.log("WETH deployed at ", weth.address); + const vusdt = await makeVToken( + { + underlying: usdt, + comptroller: comptrollerProxy, + accessControlManager: accessControl, + admin: wallet, + initialExchangeRateMantissa: parseUnits("1", 28), + }, + { kind: "VTokenHarness" }, + ); + console.log("VUSDT deployed at ", vusdt.address); + + const vweth = await makeVToken( + { + underlying: weth, + comptroller: comptrollerProxy, + accessControlManager: accessControl, + admin: wallet, + initialExchangeRateMantissa: parseUnits("1", 28), + }, + { kind: "VTokenHarness" }, + ); + + const nativeTokenGatewayFactory = await ethers.getContractFactory( + "contracts/Gateway/NativeTokenGateway.sol:NativeTokenGateway", + ); + const nativeTokenGateway = await nativeTokenGatewayFactory.deploy(vweth.address); + + fakePriceOracle.getUnderlyingPrice.whenCalledWith(vusdt.address).returns(parseUnits("1", 18)); + fakePriceOracle.getUnderlyingPrice.whenCalledWith(vweth.address).returns(parseUnits("1000", 18)); + + const usdtInitialSupply = parseUnits("10", 18); + await usdt.faucet(usdtInitialSupply); + await usdt.approve(poolRegistry.address, usdtInitialSupply); + await poolRegistry.addMarket({ + vToken: vusdt.address, + collateralFactor: parseUnits("5", 17), + liquidationThreshold: parseUnits("5", 17), + initialSupply: usdtInitialSupply, + vTokenReceiver: wallet.address, + supplyCap: parseUnits("10000", 18), + borrowCap: parseUnits("10000", 18), + }); + + const wethInitialSupply = parseUnits("10", 18); + await weth.approve(poolRegistry.address, usdtInitialSupply); + await poolRegistry.addMarket({ + vToken: vweth.address, + collateralFactor: parseUnits("5", 17), + liquidationThreshold: parseUnits("5", 17), + initialSupply: wethInitialSupply, + vTokenReceiver: wallet.address, + supplyCap: parseUnits("10000", 18), + borrowCap: parseUnits("10000", 18), + }); + + await usdt.faucet(parseUnits("100000", 18)); + await usdt.transfer(user2.address, parseUnits("10000", 18)); + + return { + oracle: fakePriceOracle, + comptroller: comptrollerProxy, + accessControl, + usdt, + vusdt, + weth, + vweth, + nativeTokenGateway, + }; +} + +describe("NativeTokenGateway", () => { + describe("Core Pool", () => { + let deployer: Signer; + let user1: Signer; + let user2: Signer; + let comptroller: MockContract; + let vusdt: VBep20Immutable; + let vweth: VBep20Immutable; + let usdt: MockContract; + let weth: WrappedNative; + let nativeTokenGateway: NativeTokenGateway; + const supplyAmount = parseUnits("10", 18); + + beforeEach(async () => { + ({ comptroller, vusdt, vweth, weth, usdt, nativeTokenGateway } = await loadFixture(deployGatewayCore)); + [deployer, user1, user2] = await ethers.getSigners(); + + await comptroller.connect(user1).enterMarkets([vusdt.address, vweth.address]); + await comptroller.connect(user2).enterMarkets([vusdt.address, vweth.address]); + }); + + describe("wrapAndSupply", () => { + it("should revert when minter address provided is zero address", async () => { + await expect( + nativeTokenGateway.connect(user1).wrapAndSupply(ethers.constants.AddressZero, { value: 0 }), + ).to.be.revertedWithCustomError(nativeTokenGateway, "ZeroAddressNotAllowed"); + }); + + it("should revert when zero amount is provided to mint", async () => { + await expect( + nativeTokenGateway.connect(user1).wrapAndSupply(await user1.getAddress(), { value: 0 }), + ).to.be.revertedWithCustomError(nativeTokenGateway, "ZeroValueNotAllowed"); + }); + + it("should wrap and supply eth", async () => { + await nativeTokenGateway.connect(user1).wrapAndSupply(await user1.getAddress(), { value: supplyAmount }); + const balanceAfterSupplying = await vweth.balanceOf(await user1.getAddress()); + await expect(balanceAfterSupplying.toString()).to.eq(parseUnits("10", 8)); + }); + }); + + describe("redeemUnderlyingAndUnwrap", () => { + beforeEach(async () => { + await nativeTokenGateway.connect(user1).wrapAndSupply(await user1.getAddress(), { value: supplyAmount }); + }); + + it("should revert when zero value is passed", async () => { + const tx = nativeTokenGateway.connect(user1).redeemUnderlyingAndUnwrap(0); + await expect(tx).to.be.revertedWithCustomError(nativeTokenGateway, "ZeroValueNotAllowed"); + }); + + it("should revert when sender is not approved to redeem on behalf", async () => { + const tx = nativeTokenGateway.connect(user1).redeemUnderlyingAndUnwrap(parseUnits("10", 18)); + await expect(tx).to.be.revertedWith("not an approved delegate"); + }); + + it("should redeem underlying tokens and unwrap and sent it to the user", async () => { + const redeemAmount = parseUnits("10", 18); + await comptroller.connect(user1).updateDelegate(nativeTokenGateway.address, true); + + await nativeTokenGateway.connect(user1).redeemUnderlyingAndUnwrap(redeemAmount); + expect(await vweth.balanceOf(await user1.getAddress())).to.eq(0); + }); + }); + + describe("redeemAndUnwrap", () => { + beforeEach(async () => { + await nativeTokenGateway.connect(user1).wrapAndSupply(await user1.getAddress(), { value: supplyAmount }); + }); + + it("should revert when zero value is passed", async () => { + const tx = nativeTokenGateway.connect(user1).redeemAndUnwrap(0); + await expect(tx).to.be.revertedWithCustomError(nativeTokenGateway, "ZeroValueNotAllowed"); + }); + + it("should revert when sender is not approved to redeem on behalf", async () => { + const tx = nativeTokenGateway.connect(user1).redeemAndUnwrap(parseUnits("10", 18)); + await expect(tx).to.be.revertedWith("not an approved delegate"); + }); + + it("should redeem vTokens and unwrap and sent it to the user", async () => { + const redeemTokens = parseUnits("10", 8); + await comptroller.connect(user1).updateDelegate(nativeTokenGateway.address, true); + + await nativeTokenGateway.connect(user1).redeemAndUnwrap(redeemTokens); + expect(await vweth.balanceOf(await user1.getAddress())).to.eq(0); + }); + }); + + describe("borrowAndUnwrap", () => { + beforeEach(async () => { + await comptroller._setCollateralFactor(vweth.address, parseUnits("5", 17)); + await comptroller._setCollateralFactor(vusdt.address, parseUnits("5", 17)); + await nativeTokenGateway.connect(user1).wrapAndSupply(await user1.getAddress(), { value: supplyAmount }); + }); + + it("should revert when sender is not approved to borrow on behalf", async () => { + const tx = nativeTokenGateway.connect(user2).borrowAndUnwrap(parseUnits("1", 18)); + await expect(tx).to.be.revertedWith("not an approved delegate"); + }); + + it("should borrow and unwrap weth and sent it to borrower", async () => { + await nativeTokenGateway.connect(user1).wrapAndSupply(await user1.getAddress(), { value: supplyAmount }); + await usdt.connect(user2).approve(vusdt.address, parseUnits("5000", 18)); + await vusdt.connect(user2).mint(parseUnits("5000", 18)); + + await comptroller.connect(user2).updateDelegate(nativeTokenGateway.address, true); + + const borrowAmount = parseUnits("2", 18); + const user2BalancePrevious = await user2.getBalance(); + await nativeTokenGateway.connect(user2).borrowAndUnwrap(borrowAmount); + + expect(await user2.getBalance()).to.closeTo(user2BalancePrevious.add(borrowAmount), parseUnits("1", 15)); + }); + }); + + describe("wrapAndRepay", () => { + it("should wrap and repay", async () => { + await comptroller._setCollateralFactor(vweth.address, parseUnits("5", 17)); + await comptroller._setCollateralFactor(vusdt.address, parseUnits("5", 17)); + await nativeTokenGateway.connect(user1).wrapAndSupply(await user1.getAddress(), { value: supplyAmount }); + await usdt.connect(user2).approve(vusdt.address, parseUnits("5000", 18)); + await vusdt.connect(user2).mint(parseUnits("5000", 18)); + await vweth.connect(user2).borrow(parseUnits("2", 18)); + + const userBalancePrevious = await user2.getBalance(); + await nativeTokenGateway.connect(user2).wrapAndRepay({ value: parseUnits("2.000002", 18) }); + + expect(await user2.getBalance()).to.closeTo(userBalancePrevious.sub(parseUnits("2", 18)), parseUnits("1", 16)); + expect(await vweth.balanceOf(await user1.getAddress())).to.gt(0); + }); + }); + + describe("sweepNative", () => { + it("should revert when called by non owener", async () => { + await expect(nativeTokenGateway.connect(user1).sweepNative()).to.be.rejectedWith( + "Ownable: caller is not the owner", + ); + }); + + it("should execute successfully", async () => { + await user1.sendTransaction({ to: nativeTokenGateway.address, value: ethers.utils.parseEther("10") }); + + const previousBalance = await deployer.getBalance(); + await nativeTokenGateway.sweepNative(); + + expect(await deployer.getBalance()).to.be.greaterThan(previousBalance); + }); + }); + + describe("SweepToken", () => { + it("should revert when called by non owner", async () => { + await expect(nativeTokenGateway.connect(user1).sweepToken(weth.address)).to.be.rejectedWith( + "Ownable: caller is not the owner", + ); + }); + + it("should sweep all tokens", async () => { + await weth.transfer(nativeTokenGateway.address, parseUnits("2", 18)); + + const ownerPreviousBalance = await weth.balanceOf(await deployer.getAddress()); + await nativeTokenGateway.sweepToken(weth.address); + + expect(await weth.balanceOf(nativeTokenGateway.address)).to.be.eq(0); + expect(await weth.balanceOf(await deployer.getAddress())).to.be.greaterThan(ownerPreviousBalance); + }); + }); + }); + + describe("Isolated Pool", () => { + let deployer: Signer; + let user1: Signer; + let user2: Signer; + let comptroller: Comptroller; + let vusdt: VToken; + let vweth: VToken; + let usdt: MockContract; + let weth: WrappedNative; + let nativeTokenGateway: NativeTokenGateway; + const supplyAmount = parseUnits("10", 18); + + beforeEach(async () => { + ({ comptroller, vusdt, vweth, weth, usdt, nativeTokenGateway } = await loadFixture(deployGatewayIL)); + [deployer, user1, user2] = await ethers.getSigners(); + + await comptroller.connect(user1).enterMarkets([vusdt.address, vweth.address]); + await comptroller.connect(user2).enterMarkets([vusdt.address, vweth.address]); + }); + + describe("wrapAndSupply", () => { + it("should revert when minter address provided is zero address", async () => { + await expect( + nativeTokenGateway.connect(user1).wrapAndSupply(ethers.constants.AddressZero, { value: 0 }), + ).to.be.revertedWithCustomError(nativeTokenGateway, "ZeroAddressNotAllowed"); + }); + + it("should revert when zero amount is provided to mint", async () => { + await expect( + nativeTokenGateway.connect(user1).wrapAndSupply(await user1.getAddress(), { value: 0 }), + ).to.be.revertedWithCustomError(nativeTokenGateway, "ZeroValueNotAllowed"); + }); + + it("should wrap and supply eth", async () => { + await nativeTokenGateway.connect(user1).wrapAndSupply(await user1.getAddress(), { value: supplyAmount }); + const balanceAfterSupplying = await vweth.balanceOf(await user1.getAddress()); + await expect(balanceAfterSupplying.toString()).to.eq(parseUnits("10", 8)); + }); + }); + + describe("redeemUnderlyingAndUnwrap", () => { + beforeEach(async () => { + await nativeTokenGateway.connect(user1).wrapAndSupply(await user1.getAddress(), { value: supplyAmount }); + }); + + it("should revert when zero value is passed", async () => { + const tx = nativeTokenGateway.connect(user1).redeemUnderlyingAndUnwrap(0); + await expect(tx).to.be.revertedWithCustomError(nativeTokenGateway, "ZeroValueNotAllowed"); + }); + + it("should revert when sender is not approved to redeem on behalf", async () => { + const tx = nativeTokenGateway.connect(user1).redeemUnderlyingAndUnwrap(parseUnits("10", 18)); + await expect(tx).to.be.revertedWithCustomError(vweth, "DelegateNotApproved"); + }); + + it("should redeem underlying tokens and unwrap and sent it to the user", async () => { + const redeemAmount = parseUnits("10", 18); + await comptroller.connect(user1).updateDelegate(nativeTokenGateway.address, true); + + await nativeTokenGateway.connect(user1).redeemUnderlyingAndUnwrap(redeemAmount); + expect(await vweth.balanceOf(await user1.getAddress())).to.eq(0); + }); + }); + + describe("redeemAndUnwrap", () => { + beforeEach(async () => { + await nativeTokenGateway.connect(user1).wrapAndSupply(await user1.getAddress(), { value: supplyAmount }); + }); + + it("should revert when zero value is passed", async () => { + const tx = nativeTokenGateway.connect(user1).redeemAndUnwrap(0); + await expect(tx).to.be.revertedWithCustomError(nativeTokenGateway, "ZeroValueNotAllowed"); + }); + + it("should revert when sender is not approved to redeem on behalf", async () => { + const tx = nativeTokenGateway.connect(user1).redeemAndUnwrap(parseUnits("10", 18)); + await expect(tx).to.be.revertedWithCustomError(vweth, "DelegateNotApproved"); + }); + + it("should redeem vTokens and unwrap and sent it to the user", async () => { + const redeemTokens = parseUnits("10", 8); + await comptroller.connect(user1).updateDelegate(nativeTokenGateway.address, true); + + await nativeTokenGateway.connect(user1).redeemAndUnwrap(redeemTokens); + expect(await vweth.balanceOf(await user1.getAddress())).to.eq(0); + }); + }); + + describe("borrowAndUnwrap", () => { + beforeEach(async () => { + await nativeTokenGateway.connect(user1).wrapAndSupply(await user1.getAddress(), { value: supplyAmount }); + }); + + it("should revert when sender is not approved to borrow on behalf", async () => { + const tx = nativeTokenGateway.connect(user2).borrowAndUnwrap(parseUnits("1", 18)); + await expect(tx).to.be.revertedWithCustomError(vweth, "DelegateNotApproved"); + }); + + it("should borrow and unwrap weth and sent it to borrower", async () => { + await nativeTokenGateway.connect(user1).wrapAndSupply(await user1.getAddress(), { value: supplyAmount }); + await usdt.connect(user2).approve(vusdt.address, parseUnits("5000", 18)); + await vusdt.connect(user2).mint(parseUnits("5000", 18)); + + await comptroller.connect(user2).updateDelegate(nativeTokenGateway.address, true); + + const borrowAmount = parseUnits("2", 18); + const user2BalancePrevious = await user2.getBalance(); + await nativeTokenGateway.connect(user2).borrowAndUnwrap(borrowAmount); + + expect(await user2.getBalance()).to.closeTo(user2BalancePrevious.add(borrowAmount), parseUnits("1", 15)); + }); + }); + + describe("wrapAndRepay", () => { + it("should wrap and repay", async () => { + await usdt.connect(user2).approve(vusdt.address, parseUnits("5000", 18)); + await vusdt.connect(user2).mint(parseUnits("5000", 18)); + await vweth.connect(user2).borrow(parseUnits("2", 18)); + + const userBalancePrevious = await user2.getBalance(); + await nativeTokenGateway.connect(user2).wrapAndRepay({ value: parseUnits("10", 18) }); + + expect(await user2.getBalance()).to.closeTo(userBalancePrevious.sub(parseUnits("2", 18)), parseUnits("1", 16)); + expect(await vweth.balanceOf(await user1.getAddress())).to.eq(0); + }); + }); + + describe("sweepNative", () => { + it("should revert when called by non owener", async () => { + await expect(nativeTokenGateway.connect(user1).sweepNative()).to.be.rejectedWith( + "Ownable: caller is not the owner", + ); + }); + + it("should execute successfully", async () => { + await user1.sendTransaction({ to: nativeTokenGateway.address, value: ethers.utils.parseEther("10") }); + + const previousBalance = await deployer.getBalance(); + await nativeTokenGateway.sweepNative(); + + expect(await deployer.getBalance()).to.be.greaterThan(previousBalance); + }); + }); + + describe("SweepToken", () => { + it("should revert when called by non owner", async () => { + await expect(nativeTokenGateway.connect(user1).sweepToken(weth.address)).to.be.rejectedWith( + "Ownable: caller is not the owner", + ); + }); + + it("should sweep all tokens", async () => { + await weth.transfer(nativeTokenGateway.address, parseUnits("2", 18)); + + const ownerPreviousBalance = await weth.balanceOf(await deployer.getAddress()); + await nativeTokenGateway.sweepToken(weth.address); + + expect(await weth.balanceOf(nativeTokenGateway.address)).to.be.eq(0); + expect(await weth.balanceOf(await deployer.getAddress())).to.be.greaterThan(ownerPreviousBalance); + }); + }); + }); +}); diff --git a/tests/hardhat/util/AddressOrContract.ts b/tests/hardhat/util/AddressOrContract.ts new file mode 100644 index 00000000..bca12ce3 --- /dev/null +++ b/tests/hardhat/util/AddressOrContract.ts @@ -0,0 +1,12 @@ +export interface EntityWithAddress { + address: string; +} + +export type AddressOrContract = string | EntityWithAddress; + +export const getAddress = (addressOrContract: AddressOrContract): string => { + if (typeof addressOrContract === "string") { + return addressOrContract; + } + return addressOrContract.address; +}; diff --git a/tests/hardhat/util/TokenTestHelpers.ts b/tests/hardhat/util/TokenTestHelpers.ts new file mode 100644 index 00000000..8c9dfbe0 --- /dev/null +++ b/tests/hardhat/util/TokenTestHelpers.ts @@ -0,0 +1,277 @@ +import { FakeContract, MockContract, smock } from "@defi-wonderland/smock"; +import chai from "chai"; +import { BaseContract, BigNumber, BigNumberish, Signer } from "ethers"; +import { parseUnits } from "ethers/lib/utils"; +import { ethers, upgrades } from "hardhat"; + +import { DEFAULT_BLOCKS_PER_YEAR } from "../../../helpers/deploymentConfig"; +import { + AccessControlManager, + Comptroller, + ERC20Harness, + ERC20Harness__factory, + InterestRateModel, + UpgradeableBeacon, + VTokenHarness, + VTokenHarness__factory, + VToken__factory, +} from "../../../typechain"; +import { AddressOrContract, getAddress } from "./AddressOrContract"; +import { DeployedContract } from "./types"; + +chai.use(smock.matchers); + +interface VTokenParameters { + underlying: AddressOrContract; + comptroller: AddressOrContract; + interestRateModel: AddressOrContract; + initialExchangeRateMantissa: BigNumberish; + name: string; + symbol: string; + decimals: BigNumberish; + admin: AddressOrContract; + accessControlManager: AddressOrContract; + shortfall: AddressOrContract; + protocolShareReserve: AddressOrContract; + reserveFactorMantissa: BigNumberish; + beacon: UpgradeableBeacon; + isTimeBased: boolean; + blocksPerYear: BigNumberish; + maxBorrowRateMantissa: BigNumberish; +} + +const getNameAndSymbol = async (underlying: AddressOrContract): Promise<[string, string]> => { + const underlying_ = await ethers.getContractAt("ERC20Harness", getAddress(underlying)); + const name = await underlying_.name(); + const symbol = await underlying_.symbol(); + return [name, symbol]; +}; + +export const fakeComptroller = async (): Promise> => { + const comptroller = await smock.fake("Comptroller"); + comptroller.isComptroller.returns(true); + return comptroller; +}; + +export const mockUnderlying = async (name: string, symbol: string): Promise> => { + const underlyingFactory = await smock.mock("ERC20Harness"); + const underlying = await underlyingFactory.deploy(0, name, 18, symbol); + return underlying; +}; + +export const fakeInterestRateModel = async (): Promise> => { + const interestRateModel = await smock.fake( + "@venusprotocol/isolated-pools/contracts/InterestRateModel.sol:InterestRateModel", + ); + interestRateModel.isInterestRateModel.returns(true); + return interestRateModel; +}; + +export const fakeAccessControlManager = async (): Promise => { + const accessControlManager = await smock.fake("AccessControlManager"); + accessControlManager.isAllowedToCall.returns(true); + return accessControlManager.address; +}; + +export type AnyVTokenFactory = VTokenHarness__factory | VToken__factory; + +export const deployVTokenBeacon = async ( + { kind }: { kind: string } = { kind: "VToken" }, + maxBorrowRateMantissa: BigNumberish = BigNumber.from(0.0005e16), + isTimeBased: boolean = false, + blocksPerYear: BigNumberish = DEFAULT_BLOCKS_PER_YEAR, +): Promise => { + const VToken = await ethers.getContractFactory(kind); + const vTokenBeacon = (await upgrades.deployBeacon(VToken, { + constructorArgs: [isTimeBased, blocksPerYear, maxBorrowRateMantissa], + unsafeAllow: ["internal-function-storage"], + })) as UpgradeableBeacon; + return vTokenBeacon; +}; + +const deployVTokenDependencies = async ( + params: Partial, + { kind }: { kind: string } = { kind: "VToken" }, +): Promise => { + let underlyingName = "SomeMockToken"; + let underlyingSymbol = "MOCK"; + if (params.underlying) { + [underlyingName, underlyingSymbol] = await getNameAndSymbol(params.underlying); + } + return { + underlying: params.underlying || (await mockUnderlying(underlyingName, underlyingSymbol)), + comptroller: params.comptroller || (await fakeComptroller()), + interestRateModel: params.interestRateModel || (await fakeInterestRateModel()), + name: params.name || `Venus ${underlyingName}`, + symbol: params.symbol || `v${underlyingSymbol}`, + decimals: params.decimals || 8, + admin: params.admin || (await ethers.getSigners())[0], + accessControlManager: params.accessControlManager || (await fakeAccessControlManager()), + initialExchangeRateMantissa: params.initialExchangeRateMantissa || parseUnits("1", 18), + shortfall: params.shortfall || (await smock.fake("Shortfall")), + protocolShareReserve: params.protocolShareReserve || (await smock.fake("ProtocolShareReserve")), + reserveFactorMantissa: params.reserveFactorMantissa || parseUnits("0.3", 18), + maxBorrowRateMantissa: params.maxBorrowRateMantissa || BigNumber.from(0.0005e16), + beacon: + params.beacon || + (await deployVTokenBeacon( + { kind }, + params.maxBorrowRateMantissa || BigNumber.from(0.0005e16), + params.isTimeBased || false, + params.blocksPerYear === undefined ? DEFAULT_BLOCKS_PER_YEAR : params.blocksPerYear, + )), + isTimeBased: params.isTimeBased || false, + blocksPerYear: params.blocksPerYear === undefined ? DEFAULT_BLOCKS_PER_YEAR : params.blocksPerYear, + }; +}; + +export const makeVToken = async ( + params: Partial, + { kind }: { kind: string } = { kind: "VToken" }, +): Promise> => { + const params_ = await deployVTokenDependencies(params, { kind }); + + const VToken = await ethers.getContractFactory(kind); + + const vToken = (await upgrades.deployBeaconProxy(params_.beacon, VToken, [ + getAddress(params_.underlying), + getAddress(params_.comptroller), + getAddress(params_.interestRateModel), + params_.initialExchangeRateMantissa, + params_.name, + params_.symbol, + params_.decimals, + getAddress(params_.admin), + getAddress(params_.accessControlManager), + { + shortfall: getAddress(params_.shortfall), + protocolShareReserve: getAddress(params_.protocolShareReserve), + }, + params_.reserveFactorMantissa, + ])) as DeployedContract; + + return vToken; +}; + +export type VTokenTestFixture = { + accessControlManager: FakeContract; + comptroller: FakeContract; + vToken: VTokenHarness; + underlying: MockContract; + interestRateModel: FakeContract; + protocolShareReserve: FakeContract; +}; + +export async function vTokenTestFixture(): Promise { + const comptroller = await fakeComptroller(); + const accessControlManager = await smock.fake("AccessControlManager"); + accessControlManager.isAllowedToCall.returns(true); + + const [admin] = await ethers.getSigners(); + const underlying = await mockUnderlying("BAT", "BAT"); + const interestRateModel = await fakeInterestRateModel(); + const protocolShareReserve = await smock.fake("ProtocolShareReserve"); + const vToken = await makeVToken( + { + underlying, + comptroller, + accessControlManager, + admin, + interestRateModel, + protocolShareReserve, + }, + { kind: "VTokenHarness" }, + ); + + return { accessControlManager, comptroller, vToken, interestRateModel, underlying, protocolShareReserve }; +} + +type BalancesSnapshot = { + [vToken: string]: HoldersSnapshot; +}; + +type HoldersSnapshot = { + [holder: string]: HolderSnapshot; +}; + +type HolderSnapshot = { + eth: BigNumber; + cash: BigNumber; + tokens: BigNumber; + borrows: BigNumber; + reserves?: BigNumber; +}; + +type BalanceDeltaEntry = + | [VTokenHarness, string, keyof HolderSnapshot, BigNumberish] + | [VTokenHarness, keyof HolderSnapshot, BigNumberish]; + +export async function getBalances(vTokens: VTokenHarness[], accounts: string[]): Promise { + const balances: BalancesSnapshot = {}; + for (const vToken of vTokens) { + const vBalances: HoldersSnapshot = (balances[vToken.address] = {}); + const underlying = await ethers.getContractAt("ERC20Harness", await vToken.underlying()); + for (const account of accounts) { + vBalances[account] = { + eth: await ethers.provider.getBalance(account), + cash: await underlying.balanceOf(account), + tokens: await vToken.balanceOf(account), + borrows: (await vToken.harnessAccountBorrows(account)).principal, + }; + } + vBalances[vToken.address] = { + eth: await ethers.provider.getBalance(vToken.address), + cash: await underlying.balanceOf(vToken.address), + tokens: await vToken.totalSupply(), + borrows: await vToken.totalBorrows(), + reserves: await vToken.totalReserves(), + }; + } + return balances; +} + +export function adjustBalances(balances: BalancesSnapshot, deltas: BalanceDeltaEntry[]) { + for (const delta of deltas) { + let vToken: VTokenHarness; + let account: string; + let key: keyof HolderSnapshot; + let diff: BigNumberish; + if (delta.length == 4) { + [vToken, account, key, diff] = delta; + } else { + [vToken, key, diff] = delta; + account = vToken.address; + } + balances[vToken.address][account][key] = BigNumber.from(balances[vToken.address][account][key]!).add(diff); + } + return balances; +} + +export async function preApprove( + erc20: MockContract, + vToken: VTokenHarness, + from: Signer, + amount: BigNumberish, + opts: { faucet?: boolean } = {}, +) { + if (opts.faucet) { + await erc20.connect(from).harnessSetBalance(await from.getAddress(), amount); + } + + return erc20.connect(from).approve(vToken.address, amount); +} + +export async function pretendBorrow( + vToken: VTokenHarness, + borrower: Signer, + accountIndexRaw: BigNumberish, + marketIndexRaw: BigNumberish, + principalRaw: BigNumberish, + blockNumber: number = 2e7, +) { + await vToken.harnessSetTotalBorrows(principalRaw); + await vToken.harnessSetAccountBorrows(await borrower.getAddress(), principalRaw, accountIndexRaw); + await vToken.harnessSetBorrowIndex(marketIndexRaw); + await vToken.harnessSetAccrualBlockNumber(blockNumber); + await vToken.harnessSetBlockNumber(blockNumber); +} diff --git a/tests/hardhat/util/types.ts b/tests/hardhat/util/types.ts new file mode 100644 index 00000000..8d0ad558 --- /dev/null +++ b/tests/hardhat/util/types.ts @@ -0,0 +1,4 @@ +import { ContractFactory } from "ethers"; + +type ThenArg = T extends PromiseLike ? U : T; +export type DeployedContract = ThenArg>; diff --git a/yarn.lock b/yarn.lock index 0f0eba3e..02cdd78c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1455,67 +1455,67 @@ __metadata: languageName: node linkType: hard -"@nomicfoundation/edr-darwin-arm64@npm:0.7.0": - version: 0.7.0 - resolution: "@nomicfoundation/edr-darwin-arm64@npm:0.7.0" - checksum: 15541029227f65df2cf1df93343f6c8e9484494ddf26cf12289cea7410446ce5b2ebb9ac750a7d438276c427da7678aba0fd8fda33ed7c1e8c743955fb657055 +"@nomicfoundation/edr-darwin-arm64@npm:0.6.5": + version: 0.6.5 + resolution: "@nomicfoundation/edr-darwin-arm64@npm:0.6.5" + checksum: fb4ec67761fa044156fac5bcc0540312e93c6b1a8086d9871fb88cfc880fcc0f8db58a9ae8cab0fb9b74b3cb54571053f7016039c4730f5186c088102f5a43c6 languageName: node linkType: hard -"@nomicfoundation/edr-darwin-x64@npm:0.7.0": - version: 0.7.0 - resolution: "@nomicfoundation/edr-darwin-x64@npm:0.7.0" - checksum: 4b7cbbe6e6b0484805814ca7f2151de780dfc6102d443126666a4e5a19955343cb6e709c0f99b3a80b0b07fce50d5c2cee9958c516a1c2b0f2ac568a30db1712 +"@nomicfoundation/edr-darwin-x64@npm:0.6.5": + version: 0.6.5 + resolution: "@nomicfoundation/edr-darwin-x64@npm:0.6.5" + checksum: 31444f48aee4e9c522da4dc799665b2d11432ca9aa27510161f1833b6f566714cecf8e99649d4209556a8346ab2ae521060ebd47ce21dad31a3f2a5d053607f0 languageName: node linkType: hard -"@nomicfoundation/edr-linux-arm64-gnu@npm:0.7.0": - version: 0.7.0 - resolution: "@nomicfoundation/edr-linux-arm64-gnu@npm:0.7.0" - checksum: 836786bbe5f9ee9fce220c7177fd5f6565b4049e42ca8163d2676c01b211aa7c688d6662cf2e469ba44147bfeaf2152f5cc168aaba171af1507477511f3289cc +"@nomicfoundation/edr-linux-arm64-gnu@npm:0.6.5": + version: 0.6.5 + resolution: "@nomicfoundation/edr-linux-arm64-gnu@npm:0.6.5" + checksum: c7059092122dd58ad38f0fa2d577b9c822424f335c217bf11c01b05257f6de7788f9db15546d2f3cbb6ba3cf0a6062d113d093f0000fd2e13fc1e2033b39c4ad languageName: node linkType: hard -"@nomicfoundation/edr-linux-arm64-musl@npm:0.7.0": - version: 0.7.0 - resolution: "@nomicfoundation/edr-linux-arm64-musl@npm:0.7.0" - checksum: 005faee82c11965430a72eaa8a55d87db0ea8b149b6d0f483b505e099152c7148a959412c387e143efc0fd51fb2221dae4e1d7004c83a9f323819db1049713f7 +"@nomicfoundation/edr-linux-arm64-musl@npm:0.6.5": + version: 0.6.5 + resolution: "@nomicfoundation/edr-linux-arm64-musl@npm:0.6.5" + checksum: 4d011d07c2d63f36bea81d935eb29a41815ddc2570e60c6b62668a96442b00e03285ed7fea2afd40554ef3f4a2f45b8123d8623f05862ecc6d9a4c7c606cdff4 languageName: node linkType: hard -"@nomicfoundation/edr-linux-x64-gnu@npm:0.7.0": - version: 0.7.0 - resolution: "@nomicfoundation/edr-linux-x64-gnu@npm:0.7.0" - checksum: 18b60a0bbb7ad35240fc5f4bbe62cd83cdbc0c3e6a513d3bca3c291874d9cb02da7eb55ec3af0d8e273060347d588f80b7fbf304704c2c4cf9f7b302d4d1b466 +"@nomicfoundation/edr-linux-x64-gnu@npm:0.6.5": + version: 0.6.5 + resolution: "@nomicfoundation/edr-linux-x64-gnu@npm:0.6.5" + checksum: d20616245f643cc930c9b10e2969a550f39a506c5e77d69dca2ecfd23b23bfbae4fe63a7d8add355e2c79b3624c130270cbd24cba0ae42583b087019e7d2e3fa languageName: node linkType: hard -"@nomicfoundation/edr-linux-x64-musl@npm:0.7.0": - version: 0.7.0 - resolution: "@nomicfoundation/edr-linux-x64-musl@npm:0.7.0" - checksum: 84e4cc834f71db02e21ea218919e9cec67983894372c232d5f36519d2d5579268d0019eb4f548826bfd1677867c78a0db81fce26bced330b375da68c91458a38 +"@nomicfoundation/edr-linux-x64-musl@npm:0.6.5": + version: 0.6.5 + resolution: "@nomicfoundation/edr-linux-x64-musl@npm:0.6.5" + checksum: 4e47f0e5b5176cc500c4a5beff526688a26be69d9ac2d6176c432a7ca51da4270f3b3f6738771a13c68149c66c94dcf4b719c33cf97edf96a15ddabbbc22ba1c languageName: node linkType: hard -"@nomicfoundation/edr-win32-x64-msvc@npm:0.7.0": - version: 0.7.0 - resolution: "@nomicfoundation/edr-win32-x64-msvc@npm:0.7.0" - checksum: 9f070a202cecab2d1f28353e5d90cd113ef98b9473169c83b97ab140898bd47a301a0cae69733346fe4cc57c31aa6f3796ab3280f1316aa79d561fecd00cc222 +"@nomicfoundation/edr-win32-x64-msvc@npm:0.6.5": + version: 0.6.5 + resolution: "@nomicfoundation/edr-win32-x64-msvc@npm:0.6.5" + checksum: ae953433f5e45e96f0448219716b7e204fc18e8b0b7f840e4158daf26e75163de528cb74940ded25b24a1f23af82993ff312ddcde120d94acecaaaf7e87f7eb7 languageName: node linkType: hard -"@nomicfoundation/edr@npm:^0.7.0": - version: 0.7.0 - resolution: "@nomicfoundation/edr@npm:0.7.0" +"@nomicfoundation/edr@npm:^0.6.4": + version: 0.6.5 + resolution: "@nomicfoundation/edr@npm:0.6.5" dependencies: - "@nomicfoundation/edr-darwin-arm64": 0.7.0 - "@nomicfoundation/edr-darwin-x64": 0.7.0 - "@nomicfoundation/edr-linux-arm64-gnu": 0.7.0 - "@nomicfoundation/edr-linux-arm64-musl": 0.7.0 - "@nomicfoundation/edr-linux-x64-gnu": 0.7.0 - "@nomicfoundation/edr-linux-x64-musl": 0.7.0 - "@nomicfoundation/edr-win32-x64-msvc": 0.7.0 - checksum: 83c54e2e2815c57ce56262f1010a0c5a2917b366bcf0acfad7662cbf2ccf46fd281e66c6db67bca9db7d91f699254216708045e882fda08c81361f111a07cb48 + "@nomicfoundation/edr-darwin-arm64": 0.6.5 + "@nomicfoundation/edr-darwin-x64": 0.6.5 + "@nomicfoundation/edr-linux-arm64-gnu": 0.6.5 + "@nomicfoundation/edr-linux-arm64-musl": 0.6.5 + "@nomicfoundation/edr-linux-x64-gnu": 0.6.5 + "@nomicfoundation/edr-linux-x64-musl": 0.6.5 + "@nomicfoundation/edr-win32-x64-msvc": 0.6.5 + checksum: 5390da27b59836b64a4f5975e02dc803a70c5ba82dd29795366a79b62b53927f69d43aaf533ec0e5f56a613c29c5edea4b188059d80caf51db9cd7bd9da9fb0a languageName: node linkType: hard @@ -3395,13 +3395,14 @@ __metadata: eslint-plugin-prettier: 3.4.1 eslint-plugin-promise: ^5.2.0 ethers: ^5.7.0 - hardhat: ^2.22.18 + hardhat: ^2.22.15 hardhat-dependency-compiler: ^1.2.1 hardhat-deploy: ^0.12.4 hardhat-deploy-ethers: ^0.3.0-beta.13 hardhat-gas-reporter: ^1.0.8 husky: ^8.0.1 module-alias: ^2.2.2 + patch-package: ^8.0.0 prettier: 2.7.1 prettier-plugin-solidity: 1.1.3 semantic-release: ^19.0.3 @@ -6555,18 +6556,6 @@ __metadata: languageName: node linkType: hard -"fdir@npm:^6.4.4": - version: 6.4.6 - resolution: "fdir@npm:6.4.6" - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - checksum: fe9f3014901d023cf631831dcb9eae5447f4d7f69218001dd01ecf007eccc40f6c129a04411b5cc273a5f93c14e02e971e17270afc9022041c80be924091eb6f - languageName: node - linkType: hard - "figures@npm:^2.0.0": version: 2.0.0 resolution: "figures@npm:2.0.0" @@ -7123,6 +7112,20 @@ __metadata: languageName: node linkType: hard +"glob@npm:7.2.0": + version: 7.2.0 + resolution: "glob@npm:7.2.0" + dependencies: + fs.realpath: ^1.0.0 + inflight: ^1.0.4 + inherits: 2 + minimatch: ^3.0.4 + once: ^1.3.0 + path-is-absolute: ^1.0.0 + checksum: 78a8ea942331f08ed2e055cb5b9e40fe6f46f579d7fd3d694f3412fe5db23223d29b7fee1575440202e9a7ff9a72ab106a39fee39934c7bedafe5e5f8ae20134 + languageName: node + linkType: hard + "glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.3.7, glob@npm:^10.4.1": version: 10.4.5 resolution: "glob@npm:10.4.5" @@ -7498,13 +7501,13 @@ __metadata: languageName: node linkType: hard -"hardhat@npm:2.22.18": - version: 2.22.18 - resolution: "hardhat@npm:2.22.18" +"hardhat@npm:2.22.15": + version: 2.22.15 + resolution: "hardhat@npm:2.22.15" dependencies: "@ethersproject/abi": ^5.1.2 "@metamask/eth-sig-util": ^4.0.0 - "@nomicfoundation/edr": ^0.7.0 + "@nomicfoundation/edr": ^0.6.4 "@nomicfoundation/ethereumjs-common": 4.0.4 "@nomicfoundation/ethereumjs-tx": 5.0.4 "@nomicfoundation/ethereumjs-util": 9.0.4 @@ -7516,6 +7519,7 @@ __metadata: aggregate-error: ^3.0.0 ansi-escapes: ^4.3.0 boxen: ^5.1.2 + chalk: ^2.4.2 chokidar: ^4.0.0 ci-info: ^2.0.0 debug: ^4.1.1 @@ -7523,9 +7527,10 @@ __metadata: env-paths: ^2.2.0 ethereum-cryptography: ^1.0.3 ethereumjs-abi: ^0.6.8 - find-up: ^5.0.0 + find-up: ^2.1.0 fp-ts: 1.19.3 fs-extra: ^7.0.1 + glob: 7.2.0 immutable: ^4.0.0-rc.12 io-ts: 1.10.4 json-stream-stringify: ^3.1.4 @@ -7534,14 +7539,12 @@ __metadata: mnemonist: ^0.38.0 mocha: ^10.0.0 p-map: ^4.0.0 - picocolors: ^1.1.0 raw-body: ^2.4.1 resolve: 1.17.0 semver: ^6.3.0 solc: 0.8.26 source-map-support: ^0.5.13 stacktrace-parser: ^0.1.10 - tinyglobby: ^0.2.6 tsort: 0.0.1 undici: ^5.14.0 uuid: ^8.3.2 @@ -7556,7 +7559,7 @@ __metadata: optional: true bin: hardhat: internal/cli/bootstrap.js - checksum: e350e80a96846a465e1ca0c92a30a83e5a04225b8def19c9703d049f4a05ac69ff12150f93bf647e3ce3f82e2264558c6a2cec1b8e8a8494b97ffbf241f54077 + checksum: 214f0bf9b8a7cb90d5be906e49adf7da87df0d10db42cc7a48ccc1129cda11da8578fe12bbb30a1e5f2c5d9e96a7733a4750626abd602e0a263a8d1f366a4f9a languageName: node linkType: hard @@ -10870,13 +10873,6 @@ __metadata: languageName: node linkType: hard -"picomatch@npm:^4.0.2": - version: 4.0.3 - resolution: "picomatch@npm:4.0.3" - checksum: 6817fb74eb745a71445debe1029768de55fd59a42b75606f478ee1d0dc1aa6e78b711d041a7c9d5550e042642029b7f373dc1a43b224c4b7f12d23436735dba0 - languageName: node - linkType: hard - "pify@npm:^3.0.0": version: 3.0.0 resolution: "pify@npm:3.0.0" @@ -12886,16 +12882,6 @@ __metadata: languageName: node linkType: hard -"tinyglobby@npm:^0.2.6": - version: 0.2.14 - resolution: "tinyglobby@npm:0.2.14" - dependencies: - fdir: ^6.4.4 - picomatch: ^4.0.2 - checksum: 261e986e3f2062dec3a582303bad2ce31b4634b9348648b46828c000d464b012cf474e38f503312367d4117c3f2f18611992738fca684040758bba44c24de522 - languageName: node - linkType: hard - "tmp@npm:0.0.33, tmp@npm:^0.0.33": version: 0.0.33 resolution: "tmp@npm:0.0.33"