编译器
0.8.18+commit.87f61d96
文件 1 的 33:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(
address(this).balance >= amount,
"Address: insufficient balance"
);
(bool success, ) = recipient.call{value: amount}("");
require(
success,
"Address: unable to send value, recipient may have reverted"
);
}
function functionCall(
address target,
bytes memory data
) internal returns (bytes memory) {
return
functionCallWithValue(
target,
data,
0,
"Address: low-level call failed"
);
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return
functionCallWithValue(
target,
data,
value,
"Address: low-level call with value failed"
);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(
address(this).balance >= value,
"Address: insufficient balance for call"
);
(bool success, bytes memory returndata) = target.call{value: value}(
data
);
return
verifyCallResultFromTarget(
target,
success,
returndata,
errorMessage
);
}
function functionStaticCall(
address target,
bytes memory data
) internal view returns (bytes memory) {
return
functionStaticCall(
target,
data,
"Address: low-level static call failed"
);
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return
verifyCallResultFromTarget(
target,
success,
returndata,
errorMessage
);
}
function functionDelegateCall(
address target,
bytes memory data
) internal returns (bytes memory) {
return
functionDelegateCall(
target,
data,
"Address: low-level delegate call failed"
);
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return
verifyCallResultFromTarget(
target,
success,
returndata,
errorMessage
);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(
bytes memory returndata,
string memory errorMessage
) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 33:AddressId.sol
pragma solidity ^0.8.0;
pragma abicoder v2;
library AddressId {
uint256 constant ADDRESS_ID_WETH9 = 1;
uint256 constant ADDRESS_ID_UNI_V3_FACTORY = 2;
uint256 constant ADDRESS_ID_UNI_V3_NONFUNGIBLE_POSITION_MANAGER = 3;
uint256 constant ADDRESS_ID_UNI_V3_SWAP_ROUTER = 4;
uint256 constant ADDRESS_ID_VELO_ROUTER = 5;
uint256 constant ADDRESS_ID_VELO_FACTORY = 6;
uint256 constant ADDRESS_ID_VAULT_POSITION_MANAGER = 7;
uint256 constant ADDRESS_ID_SWAP_EXECUTOR_MANAGER = 8;
uint256 constant ADDRESS_ID_LENDING_POOL = 9;
uint256 constant ADDRESS_ID_VAULT_FACTORY = 10;
uint256 constant ADDRESS_ID_TREASURY = 11;
uint256 constant ADDRESS_ID_VE_TOKEN = 12;
uint256 constant ADDRESS_ID_VELO_ROUTER_V2 = 13;
uint256 constant ADDRESS_ID_VELO_FACTORY_V2 = 14;
uint256 constant ADDRESS_ID_VAULT_DEPLOYER_SELECTOR = 101;
uint256 constant ADDRESS_ID_VELO_VAULT_INITIALIZER = 102;
uint256 constant ADDRESS_ID_VELO_VAULT_POSITION_LOGIC = 103;
uint256 constant ADDRESS_ID_VELO_VAULT_REWARDS_LOGIC = 104;
uint256 constant ADDRESS_ID_VELO_VAULT_OWNER_ACTIONS = 105;
uint256 constant ADDRESS_ID_VELO_SWAP_PATH_MANAGER = 106;
uint256 constant ADDRESS_ID_CHAINLINK_ORACLE = 107;
uint256 constant ADDRESS_ID_VAULT_DEPLOYER = 1001;
uint256 constant ADDRESS_ID_VAULT_INITIALIZER = 1002;
uint256 constant ADDRESS_ID_VAULT_POSITION_LOGIC = 1003;
uint256 constant ADDRESS_ID_VAULT_REWARDS_LOGIC = 1004;
uint256 constant ADDRESS_ID_VAULT_OWNER_ACTIONS = 1005;
function versionedAddressId(
uint16 vaultVersion,
uint256 addressId
) internal pure returns (uint256) {
if (addressId < 1000) {
return addressId;
}
return (uint256(vaultVersion) << 128) | addressId;
}
}
文件 3 的 33:AddressRegistry.sol
pragma solidity ^0.8.0;
import "./external/openzeppelin/contracts/access/Ownable.sol";
import "./interfaces/IAddressRegistry.sol";
contract AddressRegistry is IAddressRegistry, Ownable {
mapping(uint256 => address) libraryAndContractAddresses;
constructor(address _weth9) {
setAddress(AddressId.ADDRESS_ID_WETH9, _weth9);
}
function setAddress(uint256 id, address _addr) public onlyOwner {
libraryAndContractAddresses[id] = _addr;
emit SetAddress(_msgSender(), id, _addr);
}
function getAddress(uint256 id) external view returns (address) {
return libraryAndContractAddresses[id];
}
}
文件 4 的 33:Constants.sol
pragma solidity ^0.8.0;
library Constants {
uint256 internal constant PERCENT_100 = 10000;
uint256 internal constant PROTOCOL_FEE_TYPE_WITHDRAW = 1;
uint256 internal constant PROTOCOL_FEE_TYPE_LIQUIDATE = 2;
uint256 internal constant PROTOCOL_FEE_TYPE_COMPOUND = 3;
uint256 internal constant PROTOCOL_FEE_TYPE_RANGESTOP = 4;
uint16 internal constant VAULT_VERSION_VELO_V1 = 0;
uint16 internal constant VAULT_VERSION_VELO_V2 = 1;
uint16 internal constant VAULT_VERSION_UNI_V3 = 2;
uint16 internal constant VAULT_VERSION_CURVE = 3;
}
文件 5 的 33:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 6 的 33:DataTypes.sol
pragma solidity ^0.8.0;
library DataTypes {
struct DebtPositionData {
uint256 reserveId;
address owner;
uint256 borrowed;
uint256 borrowedIndex;
}
struct VaultPositionData {
address manager;
uint256 v3TokenId;
uint256 debtPositionId0;
uint256 debtShare0;
uint256 debtPositionId1;
uint256 debtShare1;
uint256 totalShares;
}
struct InterestRateConfig {
uint128 utilizationA;
uint128 borrowingRateA;
uint128 utilizationB;
uint128 borrowingRateB;
uint128 maxBorrowingRate;
}
struct ReserveData {
uint256 borrowingIndex;
uint256 currentBorrowingRate;
uint256 totalBorrows;
address underlyingTokenAddress;
address eTokenAddress;
address stakingAddress;
uint256 reserveCapacity;
InterestRateConfig borrowingRateConfig;
uint256 id;
uint128 lastUpdateTimestamp;
uint16 reserveFeeRate;
Flags flags;
}
struct Flags {
bool isActive;
bool frozen;
bool borrowingEnabled;
}
}
文件 7 的 33:ERC20.sol
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function decimals() public view virtual override returns (uint8) {
return 18;
}
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
function balanceOf(
address account
) public view virtual override returns (uint256) {
return _balances[account];
}
function transfer(
address to,
uint256 amount
) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
function allowance(
address owner,
address spender
) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(
address spender,
uint256 amount
) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
function increaseAllowance(
address spender,
uint256 addedValue
) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
function decreaseAllowance(
address spender,
uint256 subtractedValue
) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(
currentAllowance >= subtractedValue,
"ERC20: decreased allowance below zero"
);
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(
fromBalance >= amount,
"ERC20: transfer amount exceeds balance"
);
unchecked {
_balances[from] = fromBalance - amount;
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(
currentAllowance >= amount,
"ERC20: insufficient allowance"
);
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}
文件 8 的 33:ETokenDeployer.sol
pragma solidity ^0.8.0;
import "../../lendingpool/ExtraInterestBearingToken.sol";
library ETokenDeployer {
function deploy(
string memory name_,
string memory symbol_,
uint8 decimals_,
address underlyingAsset_,
uint256 id
) external returns (address) {
address eTokenAddress = address(
new ExtraInterestBearingToken{
salt: keccak256(
abi.encode(
underlyingAsset_,
id,
"ExtraInterestBearingToken"
)
)
}(name_, symbol_, decimals_, underlyingAsset_)
);
return eTokenAddress;
}
}
文件 9 的 33:Errors.sol
pragma solidity ^0.8.0;
library Errors {
string internal constant VL_TRANSACTION_TOO_OLD = "0";
string internal constant VL_NO_ACTIVE_RESERVE = "1";
string internal constant VL_RESERVE_FROZEN = "2";
string internal constant VL_CURRENT_AVAILABLE_LIQUIDITY_NOT_ENOUGH = "3";
string internal constant VL_NOT_ENOUGH_AVAILABLE_USER_BALANCE = "4";
string internal constant VL_TRANSFER_NOT_ALLOWED = "5";
string internal constant VL_BORROWING_NOT_ENABLED = "6";
string internal constant VL_INVALID_DEBT_OWNER = "7";
string internal constant VL_BORROWING_CALLER_NOT_IN_WHITELIST = "8";
string internal constant VL_DEPOSIT_TOO_MUCH = "9";
string internal constant VL_OUT_OF_CAPACITY = "10";
string internal constant VL_OUT_OF_CREDITS = "11";
string internal constant VL_PERCENT_TOO_LARGE = "12";
string internal constant VL_ADDRESS_CANNOT_ZERO = "13";
string internal constant VL_VAULT_UN_ACTIVE = "14";
string internal constant VL_VAULT_FROZEN = "15";
string internal constant VL_VAULT_BORROWING_DISABLED = "16";
string internal constant VL_NOT_WETH9 = "17";
string internal constant VL_INSUFFICIENT_WETH9 = "18";
string internal constant VL_INSUFFICIENT_TOKEN = "19";
string internal constant VL_LIQUIDATOR_NOT_IN_WHITELIST = "20";
string internal constant VL_COMPOUNDER_NOT_IN_WHITELIST = "21";
string internal constant VL_VAULT_ALREADY_INITIALIZED = "22";
string internal constant VL_TREASURY_ADDRESS_NOT_SET = "23";
string internal constant VT_INVALID_RESERVE_ID = "40";
string internal constant VT_INVALID_POOL = "41";
string internal constant VT_INVALID_VAULT_POSITION_MANAGER = "42";
string internal constant VT_VAULT_POSITION_NOT_ACTIVE = "43";
string internal constant VT_VAULT_POSITION_AUTO_COMPOUND_NOT_ENABLED = "44";
string internal constant VT_VAULT_POSITION_ID_INVALID = "45";
string internal constant VT_VAULT_PAUSED = "46";
string internal constant VT_VAULT_FROZEN = "47";
string internal constant VT_VAULT_CALLBACK_INVALID_SENDER = "48";
string internal constant VT_VAULT_DEBT_RATIO_TOO_LOW_TO_LIQUIDATE = "49";
string internal constant VT_VAULT_POSITION_MANAGER_INVALID = "50";
string internal constant VT_VAULT_POSITION_RANGE_STOP_DISABLED = "60";
string internal constant VT_VAULT_POSITION_RANGE_STOP_PRICE_INVALID = "61";
string internal constant VT_VAULT_POSITION_OUT_OF_MAX_LEVERAGE = "62";
string internal constant VT_VAULT_POSITION_SHARES_INVALID = "63";
string internal constant LP_NOT_ENOUGH_LIQUIDITY_TO_BORROW = "80";
string internal constant LP_CALLER_MUST_BE_LENDING_POOL = "81";
string internal constant LP_BORROW_INDEX_OVERFLOW = "82";
string internal constant LP_IS_PAUSED = "83";
}
文件 10 的 33:ExtraInterestBearingToken.sol
pragma solidity ^0.8.0;
import "../external/openzeppelin/contracts/utils/math/SafeMath.sol";
import "../external/openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../external/openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../external/openzeppelin/contracts/token/ERC20/ERC20.sol";
import "../external/openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../interfaces/IExtraInterestBearingToken.sol";
import "../interfaces/ILendingPool.sol";
import "../libraries/helpers/Errors.sol";
contract ExtraInterestBearingToken is
IExtraInterestBearingToken,
ReentrancyGuard,
ERC20
{
using SafeERC20 for IERC20;
address public immutable lendingPool;
address public immutable underlyingAsset;
uint8 private _decimals;
modifier onlyLendingPool() {
require(
msg.sender == lendingPool,
Errors.LP_CALLER_MUST_BE_LENDING_POOL
);
_;
}
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_,
address underlyingAsset_
) ERC20(name_, symbol_) {
_decimals = decimals_;
require(underlyingAsset_ != address(0), Errors.VL_ADDRESS_CANNOT_ZERO);
underlyingAsset = underlyingAsset_;
lendingPool = msg.sender;
}
function mint(
address user,
uint256 amount
) external onlyLendingPool nonReentrant {
_mint(user, amount);
emit Mint(user, amount);
}
function burn(
address receiverOfUnderlying,
uint256 eTokenAmount,
uint256 underlyingTokenAmount
) external onlyLendingPool nonReentrant {
_burn(msg.sender, eTokenAmount);
IERC20(underlyingAsset).safeTransfer(
receiverOfUnderlying,
underlyingTokenAmount
);
emit Burn(
msg.sender,
receiverOfUnderlying,
eTokenAmount,
underlyingTokenAmount
);
}
function mintToTreasury(
address treasury,
uint256 amount
) external onlyLendingPool nonReentrant {
require(treasury != address(0), "zero address");
_mint(treasury, amount);
emit MintToTreasury(treasury, amount);
}
function transferUnderlyingTo(
address target,
uint256 amount
) external onlyLendingPool nonReentrant returns (uint256) {
IERC20(underlyingAsset).safeTransfer(target, amount);
return amount;
}
function decimals() public view override returns (uint8) {
return _decimals;
}
}
文件 11 的 33:IAddressRegistry.sol
pragma solidity ^0.8.0;
import "../libraries/helpers/AddressId.sol";
interface IAddressRegistry {
event SetAddress(
address indexed setter,
uint256 indexed id,
address newAddress
);
function getAddress(uint256 id) external view returns (address);
}
文件 12 的 33:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(
address owner,
address spender
) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
文件 13 的 33:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 14 的 33:IExtraInterestBearingToken.sol
pragma solidity ^0.8.0;
import "../external/openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IExtraInterestBearingToken is IERC20 {
event Mint(address indexed to, uint256 value);
function mint(address user, uint256 amount) external;
event Burn(
address indexed from,
address indexed target,
uint256 eTokenAmount,
uint256 underlyingTokenAmount
);
function burn(
address receiverOfUnderlying,
uint256 eTokenAmount,
uint256 underlyingTokenAmount
) external;
event MintToTreasury(address indexed treasury, uint256 value);
function mintToTreasury(address treasury, uint256 amount) external;
function transferUnderlyingTo(
address target,
uint256 amount
) external returns (uint256);
}
文件 15 的 33:ILendingPool.sol
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;
import "../libraries/types/DataTypes.sol";
interface ILendingPool {
function utilizationRateOfReserve(
uint256 reserveId
) external view returns (uint256);
function borrowingRateOfReserve(
uint256 reserveId
) external view returns (uint256);
function exchangeRateOfReserve(
uint256 reserveId
) external view returns (uint256);
function totalLiquidityOfReserve(
uint256 reserveId
) external view returns (uint256 totalLiquidity);
function totalBorrowsOfReserve(
uint256 reserveId
) external view returns (uint256 totalBorrows);
function getReserveIdOfDebt(uint256 debtId) external view returns (uint256);
event InitReserve(
address indexed reserve,
address indexed eTokenAddress,
address stakingAddress,
uint256 id
);
event Deposited(
uint256 indexed reserveId,
address user,
address indexed onBehalfOf,
uint256 reserveAmount,
uint256 eTokenAmount,
uint16 indexed referral
);
event Redeemed(
uint256 indexed reserveId,
address indexed user,
address indexed to,
uint256 eTokenAmount,
uint256 underlyingTokenAmount
);
event Borrow(
uint256 indexed reserveId,
address indexed contractAddress,
address indexed onBehalfOf,
uint256 amount
);
event Repay(
uint256 indexed reserveId,
address indexed onBehalfOf,
address indexed contractAddress,
uint256 amount
);
event Paused();
event UnPaused();
event EnableVaultToBorrow(
uint256 indexed vaultId,
address indexed vaultAddress
);
event DisableVaultToBorrow(
uint256 indexed vaultId,
address indexed vaultAddress
);
event SetCreditsOfVault(
uint256 indexed vaultId,
address indexed vaultAddress,
uint256 indexed reserveId,
uint256 credit
);
event SetInterestRateConfig(
uint256 indexed reserveId,
uint16 utilizationA,
uint16 borrowingRateA,
uint16 utilizationB,
uint16 borrowingRateB,
uint16 maxBorrowingRate
);
event SetReserveCapacity(uint256 indexed reserveId, uint256 cap);
event SetReserveFeeRate(uint256 indexed reserveId, uint256 feeRate);
event ReserveActivated(uint256 indexed reserveId);
event ReserveDeActivated(uint256 indexed reserveId);
event ReserveFrozen(uint256 indexed reserveId);
event ReserveUnFreeze(uint256 indexed reserveId);
event ReserveBorrowEnabled(uint256 indexed reserveId);
event ReserveBorrowDisabled(uint256 indexed reserveId);
struct ReserveStatus {
uint256 reserveId;
address underlyingTokenAddress;
address eTokenAddress;
address stakingAddress;
uint256 totalLiquidity;
uint256 totalBorrows;
uint256 exchangeRate;
uint256 borrowingRate;
}
struct PositionStatus {
uint256 reserveId;
address user;
uint256 eTokenStaked;
uint256 eTokenUnStaked;
uint256 liquidity;
}
function getReserveStatus(
uint256[] calldata reserveIdArr
) external view returns (ReserveStatus[] memory statusArr);
function getPositionStatus(
uint256[] calldata reserveIdArr,
address user
) external view returns (PositionStatus[] memory statusArr);
function deposit(
uint256 reserveId,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external payable returns (uint256);
function redeem(
uint256 reserveId,
uint256 eTokenAmount,
address to,
bool receiveNativeETH
) external returns (uint256);
function newDebtPosition(uint256 reserveId) external returns (uint256);
function getCurrentDebt(
uint256 debtId
) external view returns (uint256 currentDebt, uint256 latestBorrowingIndex);
function borrow(
address onBehalfOf,
uint256 debtId,
uint256 amount
) external;
function repay(
address onBehalfOf,
uint256 debtId,
uint256 amount
) external returns (uint256);
function getUnderlyingTokenAddress(
uint256 reserveId
) external view returns (address underlyingTokenAddress);
function getETokenAddress(
uint256 reserveId
) external view returns (address underlyingTokenAddress);
function getStakingAddress(
uint256 reserveId
) external view returns (address);
function reserves(
uint256
)
external
view
returns (
uint256,
uint256,
uint256,
address,
address,
address,
uint256,
DataTypes.InterestRateConfig memory,
uint256,
uint128,
uint16,
DataTypes.Flags memory
);
}
文件 16 的 33:IStakingRewards.sol
pragma solidity ^0.8.0;
import "../external/openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IStakingRewards {
event RewardsSet(
address rewardsToken,
uint256 start,
uint256 end,
uint256 total
);
event Staked(
address indexed user,
address indexed onBehalfOf,
uint256 amount
);
event Withdraw(address indexed user, address indexed to, uint256 amount);
event RewardPaid(
address indexed user,
address indexed rewardsToken,
uint256 claimed
);
struct Reward {
uint256 startTime;
uint256 endTime;
uint256 rewardRate;
uint256 lastUpdateTime;
uint256 rewardPerTokenStored;
}
function rewardData(
address
) external view returns (uint256, uint256, uint256, uint256, uint256);
function stakedToken() external view returns (IERC20);
function lendingPool() external view returns (address);
function totalStaked() external view returns (uint256);
function balanceOf(address) external view returns (uint256);
function rewardsTokenListLength() external view returns (uint256);
function earned(
address _account,
address _rewardsToken
) external view returns (uint256);
function stake(uint _amount, address onBehalfOf) external;
function withdraw(uint _amount, address to) external;
function withdrawByLendingPool(
uint _amount,
address user,
address to
) external;
function claim() external;
}
文件 17 的 33:IVaultFactory.sol
pragma solidity ^0.8.0;
pragma abicoder v2;
interface IVaultFactory {
event NewVault(
address indexed token0,
address indexed token1,
bool stable,
address vaultAddress,
uint256 indexed vaultId
);
function vaults(uint256 vaultId) external view returns (address);
}
文件 18 的 33:IWETH9.sol
pragma solidity ^0.8.0;
import "../external/openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWETH9 is IERC20 {
function deposit() external payable;
function withdraw(uint256) external;
}
文件 19 的 33:InterestRateUtils.sol
pragma solidity ^0.8.0;
import "../../external/openzeppelin/contracts/utils/math/SafeMath.sol";
import "../../libraries/Precision.sol";
import "../types/DataTypes.sol";
library InterestRateUtils {
using SafeMath for uint256;
uint256 internal constant SECONDS_PER_YEAR = 365 days;
function calculateBorrowingRate(
DataTypes.InterestRateConfig storage config,
uint256 utilizationRate
) internal view returns (uint256 borrowingRate) {
if (utilizationRate <= config.utilizationA) {
if (config.utilizationA == 0) {
return config.borrowingRateA;
}
borrowingRate = utilizationRate.mul(config.borrowingRateA).div(
config.utilizationA
);
} else if (utilizationRate <= config.utilizationB) {
if (config.utilizationB == config.utilizationA) {
return config.borrowingRateB;
}
borrowingRate = uint256(config.borrowingRateB)
.sub(config.borrowingRateA)
.mul(utilizationRate.sub(config.utilizationA))
.div(uint256(config.utilizationB).sub(config.utilizationA))
.add(config.borrowingRateA);
} else {
if (config.utilizationB >= Precision.FACTOR1E18) {
return config.maxBorrowingRate;
}
borrowingRate = uint256(config.maxBorrowingRate)
.sub(config.borrowingRateB)
.mul(utilizationRate.sub(config.utilizationB))
.div(Precision.FACTOR1E18.sub(config.utilizationB))
.add(config.borrowingRateB);
}
return borrowingRate;
}
function calculateLinearInterest(
uint256 rate,
uint40 lastUpdateTimestamp
) internal view returns (uint256) {
uint256 timeDifference = block.timestamp.sub(
uint256(lastUpdateTimestamp)
);
return
rate.mul(timeDifference).div(SECONDS_PER_YEAR).add(
Precision.FACTOR1E18
);
}
function calculateCompoundedInterest(
uint256 rate,
uint128 lastUpdateTimestamp,
uint256 currentTimestamp
) internal pure returns (uint256) {
uint256 exp = currentTimestamp.sub(uint256(lastUpdateTimestamp));
if (exp == 0) {
return Precision.FACTOR1E18;
}
uint256 expMinusOne = exp - 1;
uint256 expMinusTwo = exp > 2 ? exp - 2 : 0;
uint256 ratePerSecond = rate.div(SECONDS_PER_YEAR);
uint256 basePowerTwo = ratePerSecond.mul(ratePerSecond).div(
Precision.FACTOR1E18
);
uint256 basePowerThree = basePowerTwo.mul(ratePerSecond).div(
Precision.FACTOR1E18
);
uint256 secondTerm = exp.mul(expMinusOne).mul(basePowerTwo) / 2;
uint256 thirdTerm = exp.mul(expMinusOne).mul(expMinusTwo).mul(
basePowerThree
) / 6;
return
(Precision.FACTOR1E18)
.add(ratePerSecond.mul(exp))
.add(secondTerm)
.add(thirdTerm);
}
function calculateCompoundedInterest(
uint256 rate,
uint128 lastUpdateTimestamp
) internal view returns (uint256) {
return
calculateCompoundedInterest(
rate,
lastUpdateTimestamp,
block.timestamp
);
}
}
文件 20 的 33:LendingPool.sol
pragma solidity ^0.8.0;
pragma abicoder v2;
import "../external/openzeppelin/contracts/utils/math/SafeMath.sol";
import "../external/openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../external/openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../external/openzeppelin/contracts/access/Ownable.sol";
import "../external/openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../interfaces/ILendingPool.sol";
import "../interfaces/IVaultFactory.sol";
import "../libraries/types/DataTypes.sol";
import "../libraries/logic/ReserveLogic.sol";
import "../libraries/logic/ReserveKey.sol";
import "../libraries/logic/ETokenDeployer.sol";
import "../libraries/logic/StakingRewardsDeployer.sol";
import "../AddressRegistry.sol";
import "../Payments.sol";
contract LendingPool is ILendingPool, Ownable, Payments, ReentrancyGuard {
using SafeMath for uint256;
using SafeERC20 for IERC20;
using ReserveLogic for DataTypes.ReserveData;
mapping(uint256 => DataTypes.ReserveData) public reserves;
uint256 public nextReserveId = 1;
mapping(uint256 => mapping(address => uint256)) public credits;
mapping(address => bool) public borrowingWhiteList;
address public immutable addressRegistry;
mapping(uint256 => DataTypes.DebtPositionData) public debtPositions;
uint256 public nextDebtPositionId = 1;
bool public paused = false;
modifier notPaused() {
require(!paused, Errors.LP_IS_PAUSED);
_;
}
constructor(address _addressRegistry, address _WETH9) Payments(_WETH9) {
require(_addressRegistry != address(0), Errors.VL_ADDRESS_CANNOT_ZERO);
require(_WETH9 != address(0), Errors.VL_ADDRESS_CANNOT_ZERO);
addressRegistry = _addressRegistry;
}
function initReserve(address asset) external onlyOwner notPaused {
uint256 id = nextReserveId;
nextReserveId += 1;
string memory name = string(
abi.encodePacked(
ERC20(asset).name(),
"(ExtraFi Interest Bearing Token)"
)
);
string memory symbol = string(
abi.encodePacked("e", ERC20(asset).symbol())
);
uint8 decimals = ERC20(asset).decimals();
address eTokenAddress = ETokenDeployer.deploy(
name,
symbol,
decimals,
asset,
id
);
DataTypes.ReserveData storage reserveData = reserves[id];
reserveData.setActive(true);
reserveData.setBorrowingEnabled(true);
initReserve(reserveData, asset, eTokenAddress, type(uint256).max, id);
createStakingPoolForReserve(id);
emit InitReserve(asset, eTokenAddress, reserveData.stakingAddress, id);
}
function deposit(
uint256 reserveId,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) public payable notPaused nonReentrant returns (uint256 eTokenAmount) {
eTokenAmount = _deposit(reserveId, amount, onBehalfOf);
if (msg.value > 0) {
refundETH();
}
emit Deposited(
reserveId,
_msgSender(),
onBehalfOf,
amount,
eTokenAmount,
referralCode
);
}
function depositAndStake(
uint256 reserveId,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external payable notPaused nonReentrant returns (uint256 eTokenAmount) {
eTokenAmount = _deposit(reserveId, amount, address(this));
address stakingPool = reserves[reserveId].stakingAddress;
require(stakingPool != address(0), "Address=0");
IERC20(getETokenAddress(reserveId)).approve(stakingPool, eTokenAmount);
IStakingRewards(stakingPool).stake(eTokenAmount, onBehalfOf);
if (msg.value > 0) {
refundETH();
}
emit Deposited(
reserveId,
_msgSender(),
onBehalfOf,
amount,
eTokenAmount,
referralCode
);
}
function redeem(
uint256 reserveId,
uint256 eTokenAmount,
address to,
bool receiveNativeETH
) public notPaused nonReentrant returns (uint256) {
DataTypes.ReserveData storage reserve = getReserve(reserveId);
if (eTokenAmount == type(uint256).max) {
eTokenAmount = IExtraInterestBearingToken(reserve.eTokenAddress)
.balanceOf(_msgSender());
}
IERC20(reserve.eTokenAddress).safeTransferFrom(
_msgSender(),
address(this),
eTokenAmount
);
uint256 underlyingTokenAmount = _redeem(
reserveId,
eTokenAmount,
to,
receiveNativeETH
);
emit Redeemed(
reserveId,
_msgSender(),
to,
eTokenAmount,
underlyingTokenAmount
);
return (underlyingTokenAmount);
}
function unStakeAndWithdraw(
uint256 reserveId,
uint256 eTokenAmount,
address to,
bool receiveNativeETH
) external notPaused nonReentrant returns (uint256) {
address stakingPool = reserves[reserveId].stakingAddress;
require(stakingPool != address(0), "Address=0");
IStakingRewards(stakingPool).withdrawByLendingPool(
eTokenAmount,
_msgSender(),
address(this)
);
uint256 underlyingTokenAmount = _redeem(
reserveId,
eTokenAmount,
to,
receiveNativeETH
);
emit Redeemed(
reserveId,
_msgSender(),
to,
eTokenAmount,
underlyingTokenAmount
);
return (underlyingTokenAmount);
}
function _deposit(
uint256 reserveId,
uint256 amount,
address onBehalfOf
) internal returns (uint256 eTokenAmount) {
DataTypes.ReserveData storage reserve = getReserve(reserveId);
require(!reserve.getFrozen(), Errors.VL_RESERVE_FROZEN);
reserve.updateState(getTreasury());
reserve.checkCapacity(amount);
uint256 exchangeRate = reserve.reserveToETokenExchangeRate();
pay(
reserve.underlyingTokenAddress,
_msgSender(),
reserve.eTokenAddress,
amount
);
eTokenAmount = amount.mul(exchangeRate).div(Precision.FACTOR1E18);
IExtraInterestBearingToken(reserve.eTokenAddress).mint(
onBehalfOf,
eTokenAmount
);
reserve.updateInterestRates();
}
function _redeem(
uint256 reserveId,
uint256 eTokenAmount,
address to,
bool receiveNativeETH
) internal returns (uint256) {
DataTypes.ReserveData storage reserve = getReserve(reserveId);
reserve.updateState(getTreasury());
uint256 underlyingTokenAmount = reserve
.eTokenToReserveExchangeRate()
.mul(eTokenAmount)
.div(Precision.FACTOR1E18);
require(
underlyingTokenAmount <= reserve.availableLiquidity(),
Errors.VL_CURRENT_AVAILABLE_LIQUIDITY_NOT_ENOUGH
);
if (reserve.underlyingTokenAddress == WETH9 && receiveNativeETH) {
IExtraInterestBearingToken(reserve.eTokenAddress).burn(
address(this),
eTokenAmount,
underlyingTokenAmount
);
unwrapWETH9(underlyingTokenAmount, to);
} else {
IExtraInterestBearingToken(reserve.eTokenAddress).burn(
to,
eTokenAmount,
underlyingTokenAmount
);
}
reserve.updateInterestRates();
return (underlyingTokenAmount);
}
function newDebtPosition(
uint256 reserveId
) external notPaused nonReentrant returns (uint256 debtId) {
DataTypes.ReserveData storage reserve = getReserve(reserveId);
require(!reserve.getFrozen(), Errors.VL_RESERVE_FROZEN);
require(reserve.getBorrowingEnabled(), Errors.VL_BORROWING_NOT_ENABLED);
debtId = nextDebtPositionId;
nextDebtPositionId = nextDebtPositionId + 1;
DataTypes.DebtPositionData storage newPosition = debtPositions[debtId];
newPosition.owner = _msgSender();
reserve.updateState(getTreasury());
reserve.updateInterestRates();
newPosition.reserveId = reserveId;
newPosition.borrowedIndex = reserve.borrowingIndex;
}
function borrow(
address onBehalfOf,
uint256 debtId,
uint256 amount
) external notPaused nonReentrant {
require(
borrowingWhiteList[_msgSender()],
Errors.VL_BORROWING_CALLER_NOT_IN_WHITELIST
);
DataTypes.DebtPositionData storage debtPosition = debtPositions[debtId];
require(
_msgSender() == debtPosition.owner,
Errors.VL_INVALID_DEBT_OWNER
);
DataTypes.ReserveData storage reserve = getReserve(
debtPosition.reserveId
);
require(!reserve.getFrozen(), Errors.VL_RESERVE_FROZEN);
require(reserve.getBorrowingEnabled(), Errors.VL_BORROWING_NOT_ENABLED);
reserve.updateState(getTreasury());
updateDebtPosition(debtPosition, reserve.borrowingIndex);
uint256 credit = credits[debtPosition.reserveId][_msgSender()];
require(amount <= credit, Errors.VL_OUT_OF_CREDITS);
credits[debtPosition.reserveId][_msgSender()] = credit.sub(amount);
require(
amount <= reserve.availableLiquidity(),
Errors.LP_NOT_ENOUGH_LIQUIDITY_TO_BORROW
);
reserve.totalBorrows += amount;
debtPosition.borrowed += amount;
IExtraInterestBearingToken(reserve.eTokenAddress).transferUnderlyingTo(
_msgSender(),
amount
);
reserve.updateInterestRates();
emit Borrow(debtPosition.reserveId, _msgSender(), onBehalfOf, amount);
}
function repay(
address onBehalfOf,
uint256 debtId,
uint256 amount
) external notPaused nonReentrant returns (uint256) {
require(
borrowingWhiteList[_msgSender()],
Errors.VL_BORROWING_CALLER_NOT_IN_WHITELIST
);
DataTypes.DebtPositionData storage debtPosition = debtPositions[debtId];
require(
_msgSender() == debtPosition.owner,
Errors.VL_INVALID_DEBT_OWNER
);
DataTypes.ReserveData storage reserve = getReserve(
debtPosition.reserveId
);
reserve.updateState(getTreasury());
updateDebtPosition(debtPosition, reserve.borrowingIndex);
uint256 credit = credits[debtPosition.reserveId][_msgSender()];
credits[debtPosition.reserveId][_msgSender()] = credit.add(amount);
if (amount > debtPosition.borrowed) {
amount = debtPosition.borrowed;
}
reserve.totalBorrows = reserve.totalBorrows.sub(amount);
debtPosition.borrowed = debtPosition.borrowed.sub(amount);
IERC20(reserve.underlyingTokenAddress).safeTransferFrom(
_msgSender(),
reserve.eTokenAddress,
amount
);
reserve.updateInterestRates();
emit Repay(debtPosition.reserveId, onBehalfOf, _msgSender(), amount);
return amount;
}
function initReserve(
DataTypes.ReserveData storage reserveData,
address underlyingTokenAddress,
address eTokenAddress,
uint256 reserveCapacity,
uint256 id
) internal {
reserveData.underlyingTokenAddress = underlyingTokenAddress;
reserveData.eTokenAddress = eTokenAddress;
reserveData.reserveCapacity = reserveCapacity;
reserveData.id = id;
reserveData.lastUpdateTimestamp = uint128(block.timestamp);
reserveData.borrowingIndex = Precision.FACTOR1E18;
reserveData.reserveFeeRate = 1500;
setBorrowingRateConfig(reserveData, 8000, 2000, 9000, 5000, 15000);
}
function createStakingPoolForReserve(uint256 reserveId) internal {
address eTokenAddress = reserves[reserveId].eTokenAddress;
require(eTokenAddress != address(0), "Address=0");
reserves[reserveId].stakingAddress = StakingRewardsDeployer.deploy(
eTokenAddress
);
Ownable(reserves[reserveId].stakingAddress).transferOwnership(owner());
}
function updateDebtPosition(
DataTypes.DebtPositionData storage debtPosition,
uint256 latestBorrowingIndex
) internal {
debtPosition.borrowed = debtPosition
.borrowed
.mul(latestBorrowingIndex)
.div(debtPosition.borrowedIndex);
debtPosition.borrowedIndex = latestBorrowingIndex;
}
function setBorrowingRateConfig(
DataTypes.ReserveData storage reserve,
uint16 utilizationA,
uint16 borrowingRateA,
uint16 utilizationB,
uint16 borrowingRateB,
uint16 maxBorrowingRate
) internal {
reserve.borrowingRateConfig.utilizationA = uint128(
Precision.FACTOR1E18.mul(utilizationA).div(Constants.PERCENT_100)
);
reserve.borrowingRateConfig.borrowingRateA = uint128(
Precision.FACTOR1E18.mul(borrowingRateA).div(Constants.PERCENT_100)
);
reserve.borrowingRateConfig.utilizationB = uint128(
Precision.FACTOR1E18.mul(utilizationB).div(Constants.PERCENT_100)
);
reserve.borrowingRateConfig.borrowingRateB = uint128(
Precision.FACTOR1E18.mul(borrowingRateB).div(Constants.PERCENT_100)
);
reserve.borrowingRateConfig.maxBorrowingRate = uint128(
Precision.FACTOR1E18.mul(maxBorrowingRate).div(
Constants.PERCENT_100
)
);
}
function getReserve(
uint256 reserveId
) internal view returns (DataTypes.ReserveData storage reserve) {
reserve = reserves[reserveId];
require(reserve.getActive(), Errors.VL_NO_ACTIVE_RESERVE);
}
function getTreasury() internal view returns (address treasury) {
treasury = AddressRegistry(addressRegistry).getAddress(
AddressId.ADDRESS_ID_TREASURY
);
require(treasury != address(0), Errors.VL_TREASURY_ADDRESS_NOT_SET);
}
function getVault(
uint256 vaultId
) internal view returns (address vaultAddress) {
address vaultFactory = AddressRegistry(addressRegistry).getAddress(
AddressId.ADDRESS_ID_VAULT_FACTORY
);
vaultAddress = IVaultFactory(vaultFactory).vaults(vaultId);
require(vaultAddress != address(0), "Invalid VaultId");
}
function getReserveStatus(
uint256[] calldata reserveIdArr
) external view returns (ReserveStatus[] memory statusArr) {
statusArr = new ReserveStatus[](reserveIdArr.length);
for (uint256 i = 0; i < reserveIdArr.length; i++) {
statusArr[i].reserveId = reserveIdArr[i];
statusArr[i].underlyingTokenAddress = reserves[reserveIdArr[i]]
.underlyingTokenAddress;
statusArr[i].eTokenAddress = reserves[reserveIdArr[i]]
.eTokenAddress;
statusArr[i].stakingAddress = reserves[reserveIdArr[i]]
.stakingAddress;
(statusArr[i].totalLiquidity, statusArr[i].totalBorrows) = reserves[
reserveIdArr[i]
].totalLiquidityAndBorrows();
statusArr[i].exchangeRate = reserves[reserveIdArr[i]]
.eTokenToReserveExchangeRate();
statusArr[i].borrowingRate = reserves[reserveIdArr[i]]
.borrowingRate();
}
}
function getPositionStatus(
uint256[] calldata reserveIdArr,
address user
) external view returns (PositionStatus[] memory statusArr) {
statusArr = new PositionStatus[](reserveIdArr.length);
for (uint256 i = 0; i < reserveIdArr.length; i++) {
statusArr[i].reserveId = reserveIdArr[i];
statusArr[i].user = user;
statusArr[i].eTokenStaked = IStakingRewards(
reserves[reserveIdArr[i]].stakingAddress
).balanceOf(user);
statusArr[i].eTokenUnStaked = IERC20(
reserves[reserveIdArr[i]].eTokenAddress
).balanceOf(user);
statusArr[i].liquidity = statusArr[i]
.eTokenStaked
.add(statusArr[i].eTokenUnStaked)
.mul(reserves[reserveIdArr[i]].eTokenToReserveExchangeRate())
.div(Precision.FACTOR1E18);
}
}
function getCurrentDebt(
uint256 debtId
)
external
view
returns (uint256 currentDebt, uint256 latestBorrowingIndex)
{
DataTypes.DebtPositionData storage debtPosition = debtPositions[debtId];
DataTypes.ReserveData storage reserve = reserves[
debtPosition.reserveId
];
latestBorrowingIndex = reserve.latestBorrowingIndex();
currentDebt = debtPosition.borrowed.mul(latestBorrowingIndex).div(
debtPosition.borrowedIndex
);
}
function getReserveIdOfDebt(uint256 debtId) public view returns (uint256) {
return debtPositions[debtId].reserveId;
}
function getUnderlyingTokenAddress(
uint256 reserveId
) public view returns (address) {
DataTypes.ReserveData storage reserve = reserves[reserveId];
return reserve.underlyingTokenAddress;
}
function getETokenAddress(uint256 reserveId) public view returns (address) {
DataTypes.ReserveData storage reserve = reserves[reserveId];
return reserve.eTokenAddress;
}
function getStakingAddress(
uint256 reserveId
) public view returns (address) {
DataTypes.ReserveData storage reserve = reserves[reserveId];
return reserve.stakingAddress;
}
function exchangeRateOfReserve(
uint256 reserveId
) public view returns (uint256) {
DataTypes.ReserveData storage reserve = reserves[reserveId];
return reserve.eTokenToReserveExchangeRate();
}
function utilizationRateOfReserve(
uint256 reserveId
) public view returns (uint256) {
DataTypes.ReserveData storage reserve = reserves[reserveId];
return reserve.utilizationRate();
}
function borrowingRateOfReserve(
uint256 reserveId
) public view returns (uint256) {
DataTypes.ReserveData storage reserve = reserves[reserveId];
return uint256(reserve.borrowingRate());
}
function totalLiquidityOfReserve(
uint256 reserveId
) public view returns (uint256 totalLiquidity) {
DataTypes.ReserveData storage reserve = reserves[reserveId];
(totalLiquidity, ) = reserve.totalLiquidityAndBorrows();
}
function totalBorrowsOfReserve(
uint256 reserveId
) public view returns (uint256 totalBorrows) {
DataTypes.ReserveData storage reserve = reserves[reserveId];
(, totalBorrows) = reserve.totalLiquidityAndBorrows();
}
function emergencyPauseAll() external onlyOwner {
paused = true;
emit Paused();
}
function unPauseAll() external onlyOwner {
paused = false;
emit UnPaused();
}
function enableVaultToBorrow(uint256 vaultId) external onlyOwner notPaused {
address vaultAddr = getVault(vaultId);
borrowingWhiteList[vaultAddr] = true;
emit EnableVaultToBorrow(vaultId, vaultAddr);
}
function disableVaultToBorrow(
uint256 vaultId
) external onlyOwner notPaused {
address vaultAddr = getVault(vaultId);
borrowingWhiteList[vaultAddr] = false;
emit DisableVaultToBorrow(vaultId, vaultAddr);
}
function setCreditsOfVault(
uint256 vaultId,
uint256 reserveId,
uint256 credit
) external onlyOwner notPaused {
address vaultAddr = getVault(vaultId);
credits[reserveId][vaultAddr] = credit;
emit SetCreditsOfVault(vaultId, vaultAddr, reserveId, credit);
}
function activateReserve(uint256 reserveId) public onlyOwner notPaused {
DataTypes.ReserveData storage reserve = reserves[reserveId];
reserve.setActive(true);
emit ReserveActivated(reserveId);
}
function deActivateReserve(uint256 reserveId) public onlyOwner notPaused {
DataTypes.ReserveData storage reserve = reserves[reserveId];
reserve.setActive(false);
emit ReserveDeActivated(reserveId);
}
function freezeReserve(uint256 reserveId) public onlyOwner notPaused {
DataTypes.ReserveData storage reserve = reserves[reserveId];
reserve.setFrozen(true);
emit ReserveFrozen(reserveId);
}
function unFreezeReserve(uint256 reserveId) public onlyOwner notPaused {
DataTypes.ReserveData storage reserve = reserves[reserveId];
reserve.setFrozen(false);
emit ReserveUnFreeze(reserveId);
}
function enableBorrowing(uint256 reserveId) public onlyOwner notPaused {
DataTypes.ReserveData storage reserve = reserves[reserveId];
reserve.setBorrowingEnabled(true);
emit ReserveBorrowEnabled(reserveId);
}
function disableBorrowing(uint256 reserveId) public onlyOwner notPaused {
DataTypes.ReserveData storage reserve = reserves[reserveId];
reserve.setBorrowingEnabled(false);
emit ReserveBorrowDisabled(reserveId);
}
function setReserveFeeRate(
uint256 reserveId,
uint16 _rate
) public onlyOwner notPaused {
require(_rate <= Constants.PERCENT_100, "invalid percent");
DataTypes.ReserveData storage reserve = reserves[reserveId];
reserve.reserveFeeRate = _rate;
emit SetReserveFeeRate(reserveId, _rate);
}
function setBorrowingRateConfig(
uint256 reserveId,
uint16 utilizationA,
uint16 borrowingRateA,
uint16 utilizationB,
uint16 borrowingRateB,
uint16 maxBorrowingRate
) public onlyOwner notPaused {
DataTypes.ReserveData storage reserve = reserves[reserveId];
setBorrowingRateConfig(
reserve,
utilizationA,
borrowingRateA,
utilizationB,
borrowingRateB,
maxBorrowingRate
);
emit SetInterestRateConfig(
reserveId,
utilizationA,
borrowingRateA,
utilizationB,
borrowingRateB,
maxBorrowingRate
);
}
function setReserveCapacity(
uint256 reserveId,
uint256 cap
) public onlyOwner notPaused {
DataTypes.ReserveData storage reserve = reserves[reserveId];
reserve.reserveCapacity = cap;
emit SetReserveCapacity(reserveId, cap);
}
}
文件 21 的 33:Math.sol
pragma solidity ^0.8.0;
library Math {
enum Rounding {
Down,
Up,
Zero
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a & b) + (a ^ b) / 2;
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
return a == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
uint256 prod0;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
return prod0 / denominator;
}
require(denominator > prod1);
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = denominator & (~denominator + 1);
assembly {
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 result = 1 << (log2(a) >> 1);
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
function sqrt(
uint256 a,
Rounding rounding
) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return
result +
(rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
function log2(
uint256 value,
Rounding rounding
) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return
result +
(rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
function log10(
uint256 value,
Rounding rounding
) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return
result +
(rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
function log256(
uint256 value,
Rounding rounding
) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return
result +
(rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}
文件 22 的 33:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(
newOwner != address(0),
"Ownable: new owner is the zero address"
);
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 23 的 33:Payments.sol
pragma solidity ^0.8.0;
pragma abicoder v2;
import "./interfaces/IWETH9.sol";
import "./libraries/TransferHelper.sol";
import "./libraries/helpers/Errors.sol";
abstract contract Payments {
address public immutable WETH9;
modifier avoidUsingNativeEther() {
require(msg.value == 0, "avoid using native ether");
_;
}
constructor(address _WETH9) {
WETH9 = _WETH9;
}
receive() external payable {
require(msg.sender == WETH9, Errors.VL_NOT_WETH9);
}
function unwrapWETH9(uint256 amountMinimum, address recipient) internal {
uint256 balanceWETH9 = IWETH9(WETH9).balanceOf(address(this));
require(balanceWETH9 >= amountMinimum, Errors.VL_INSUFFICIENT_WETH9);
if (balanceWETH9 > 0) {
IWETH9(WETH9).withdraw(balanceWETH9);
TransferHelper.safeTransferETH(recipient, balanceWETH9);
}
}
function refundETH() internal {
if (address(this).balance > 0)
TransferHelper.safeTransferETH(msg.sender, address(this).balance);
}
function pay(
address token,
address payer,
address recipient,
uint256 value
) internal {
if (token == WETH9 && address(this).balance >= value) {
IWETH9(WETH9).deposit{value: value}();
require(
IWETH9(WETH9).transfer(recipient, value),
"transfer failed"
);
} else if (payer == address(this)) {
TransferHelper.safeTransfer(token, recipient, value);
} else {
TransferHelper.safeTransferFrom(token, payer, recipient, value);
}
}
}
文件 24 的 33:Precision.sol
pragma solidity >=0.4.0;
library Precision {
uint8 internal constant RESOLUTION = 96;
uint256 internal constant FACTOR1E18 = 1e18;
}
文件 25 的 33:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
}
function _nonReentrantAfter() private {
_status = _NOT_ENTERED;
}
}
文件 26 的 33:ReserveKey.sol
pragma solidity ^0.8.0;
library ReserveKey {
function compute(
address reserve,
address eTokenAddress
) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(reserve, eTokenAddress));
}
}
文件 27 的 33:ReserveLogic.sol
pragma solidity ^0.8.0;
import "../../external/openzeppelin/contracts/utils/math/SafeMath.sol";
import "../../external/openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../../external/openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../../libraries/Precision.sol";
import "../../interfaces/IExtraInterestBearingToken.sol";
import "./InterestRateUtils.sol";
import "../types/DataTypes.sol";
import "../helpers/Errors.sol";
import "../Constants.sol";
library ReserveLogic {
using SafeMath for uint256;
using SafeERC20 for IERC20;
function totalLiquidityAndBorrows(
DataTypes.ReserveData storage reserve
) internal view returns (uint256 total, uint256 borrows) {
borrows = borrowedLiquidity(reserve);
total = availableLiquidity(reserve).add(borrows);
}
function availableLiquidity(
DataTypes.ReserveData storage reserve
) internal view returns (uint256 liquidity) {
liquidity = IERC20(reserve.underlyingTokenAddress).balanceOf(
reserve.eTokenAddress
);
}
function borrowedLiquidity(
DataTypes.ReserveData storage reserve
) internal view returns (uint256 liquidity) {
liquidity = latestBorrowingIndex(reserve).mul(reserve.totalBorrows).div(
reserve.borrowingIndex
);
}
function utilizationRate(
DataTypes.ReserveData storage reserve
) internal view returns (uint256 rate) {
(uint256 total, uint256 borrows) = totalLiquidityAndBorrows(reserve);
if (total > 0) {
rate = borrows.mul(Precision.FACTOR1E18).div(total);
}
return rate;
}
function borrowingRate(
DataTypes.ReserveData storage reserve
) internal view returns (uint256 rate) {
rate = InterestRateUtils.calculateBorrowingRate(
reserve.borrowingRateConfig,
utilizationRate(reserve)
);
}
function reserveToETokenExchangeRate(
DataTypes.ReserveData storage reserve
) internal view returns (uint256) {
(uint256 totalLiquidity, ) = totalLiquidityAndBorrows(reserve);
uint256 totalETokens = IERC20(reserve.eTokenAddress).totalSupply();
if (totalETokens == 0 || totalLiquidity == 0) {
return Precision.FACTOR1E18;
}
return totalETokens.mul(Precision.FACTOR1E18).div(totalLiquidity);
}
function eTokenToReserveExchangeRate(
DataTypes.ReserveData storage reserve
) external view returns (uint256) {
(uint256 totalLiquidity, ) = totalLiquidityAndBorrows(reserve);
uint256 totalETokens = IERC20(reserve.eTokenAddress).totalSupply();
if (totalETokens == 0 || totalLiquidity == 0) {
return Precision.FACTOR1E18;
}
return totalLiquidity.mul(Precision.FACTOR1E18).div(totalETokens);
}
function latestBorrowingIndex(
DataTypes.ReserveData storage reserve
) internal view returns (uint256) {
if (reserve.lastUpdateTimestamp == uint128(block.timestamp)) {
return reserve.borrowingIndex;
}
return
reserve
.borrowingIndex
.mul(
InterestRateUtils.calculateCompoundedInterest(
reserve.currentBorrowingRate,
reserve.lastUpdateTimestamp
)
)
.div(Precision.FACTOR1E18);
}
function checkCapacity(
DataTypes.ReserveData storage reserve,
uint256 depositAmount
) internal view {
(uint256 totalLiquidity, ) = totalLiquidityAndBorrows(reserve);
require(
totalLiquidity.add(depositAmount) <= reserve.reserveCapacity,
Errors.VL_OUT_OF_CAPACITY
);
}
function updateState(
DataTypes.ReserveData storage reserve,
address treasury
) internal {
uint256 previousDebt = reserve.totalBorrows;
_updateIndexes(reserve);
_mintToTreasury(reserve, previousDebt, reserve.totalBorrows, treasury);
}
function updateInterestRates(
DataTypes.ReserveData storage reserve
) internal {
reserve.currentBorrowingRate = InterestRateUtils.calculateBorrowingRate(
reserve.borrowingRateConfig,
utilizationRate(reserve)
);
}
function _updateIndexes(DataTypes.ReserveData storage reserve) internal {
uint256 newBorrowingIndex = reserve.borrowingIndex;
uint256 newTotalBorrows = reserve.totalBorrows;
if (reserve.totalBorrows > 0) {
newBorrowingIndex = latestBorrowingIndex(reserve);
newTotalBorrows = newBorrowingIndex.mul(reserve.totalBorrows).div(
reserve.borrowingIndex
);
require(
newBorrowingIndex <= type(uint128).max,
Errors.LP_BORROW_INDEX_OVERFLOW
);
reserve.borrowingIndex = newBorrowingIndex;
reserve.totalBorrows = newTotalBorrows;
reserve.lastUpdateTimestamp = uint128(block.timestamp);
}
}
function _mintToTreasury(
DataTypes.ReserveData storage reserve,
uint256 previousDebt,
uint256 currentDebt,
address treasury
) internal {
uint256 feeRate = reserve.reserveFeeRate;
if (feeRate == 0) {
return;
}
uint256 totalDebtAccrued = currentDebt.sub(previousDebt);
uint256 reserveValueAccrued = totalDebtAccrued.mul(feeRate).div(
Constants.PERCENT_100
);
uint256 exchangeRate = reserveToETokenExchangeRate(reserve);
uint256 feeInEToken = reserveValueAccrued.mul(exchangeRate).div(
Precision.FACTOR1E18
);
if (feeInEToken != 0) {
IExtraInterestBearingToken(reserve.eTokenAddress).mintToTreasury(
treasury,
feeInEToken
);
}
}
function setActive(
DataTypes.ReserveData storage reserve,
bool state
) internal {
reserve.flags.isActive = state;
}
function getActive(
DataTypes.ReserveData storage reserve
) internal view returns (bool) {
return reserve.flags.isActive;
}
function setFrozen(
DataTypes.ReserveData storage reserve,
bool state
) internal {
reserve.flags.frozen = state;
}
function getFrozen(
DataTypes.ReserveData storage reserve
) internal view returns (bool) {
return reserve.flags.frozen;
}
function setBorrowingEnabled(
DataTypes.ReserveData storage reserve,
bool state
) internal {
reserve.flags.borrowingEnabled = state;
}
function getBorrowingEnabled(
DataTypes.ReserveData storage reserve
) internal view returns (bool) {
return reserve.flags.borrowingEnabled;
}
}
文件 28 的 33:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(
token,
abi.encodeWithSelector(token.transfer.selector, to, value)
);
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(
token,
abi.encodeWithSelector(token.transferFrom.selector, from, to, value)
);
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(
token,
abi.encodeWithSelector(token.approve.selector, spender, value)
);
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(
token,
abi.encodeWithSelector(
token.approve.selector,
spender,
newAllowance
)
);
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(
oldAllowance >= value,
"SafeERC20: decreased allowance below zero"
);
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(
token,
abi.encodeWithSelector(
token.approve.selector,
spender,
newAllowance
)
);
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(
nonceAfter == nonceBefore + 1,
"SafeERC20: permit did not succeed"
);
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(
data,
"SafeERC20: low-level call failed"
);
if (returndata.length > 0) {
require(
abi.decode(returndata, (bool)),
"SafeERC20: ERC20 operation did not succeed"
);
}
}
}
文件 29 的 33:SafeMath.sol
pragma solidity ^0.8.0;
library SafeMath {
function tryAdd(
uint256 a,
uint256 b
) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
function trySub(
uint256 a,
uint256 b
) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
function tryMul(
uint256 a,
uint256 b
) internal pure returns (bool, uint256) {
unchecked {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
function tryDiv(
uint256 a,
uint256 b
) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
function tryMod(
uint256 a,
uint256 b
) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
文件 30 的 33:StakingRewards.sol
pragma solidity ^0.8.0;
import "../external/openzeppelin/contracts/access/Ownable.sol";
import "../external/openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../external/openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../external/openzeppelin/contracts/utils/math/Math.sol";
import "../external/openzeppelin/contracts/utils/math/SafeMath.sol";
import "../interfaces/IExtraInterestBearingToken.sol";
import "../interfaces/IStakingRewards.sol";
contract StakingRewards is Ownable, IStakingRewards {
using SafeMath for uint256;
using SafeERC20 for IERC20;
IERC20 public immutable stakedToken;
address public immutable lendingPool;
address[] public rewardTokens;
mapping(address => bool) public inRewardsTokenList;
uint256 public totalStaked;
mapping(address => Reward) public rewardData;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256))
public userRewardPerTokenPaid;
mapping(address => mapping(address => uint256)) public userRewardsClaimable;
uint internal _unlocked = 1;
modifier nonReentrant() {
require(_unlocked == 1, "reentrant call");
_unlocked = 2;
_;
_unlocked = 1;
}
modifier onlyLendingPool() {
require(lendingPool == msg.sender);
_;
}
modifier updateReward(address user) {
for (uint i; i < rewardTokens.length; i++) {
address rewardToken = rewardTokens[i];
rewardData[rewardToken].rewardPerTokenStored = rewardPerToken(
rewardToken
);
rewardData[rewardToken].lastUpdateTime = Math.min(
rewardData[rewardToken].endTime,
block.timestamp
);
if (user != address(0)) {
userRewardsClaimable[user][rewardToken] = earned(
user,
rewardToken,
rewardData[rewardToken].rewardPerTokenStored
);
userRewardPerTokenPaid[user][rewardToken] = rewardData[
rewardToken
].rewardPerTokenStored;
}
}
_;
}
constructor(address _stakingToken) {
stakedToken = IERC20(_stakingToken);
lendingPool = msg.sender;
}
function rewardPerToken(address rewardToken) public view returns (uint) {
if (block.timestamp <= rewardData[rewardToken].startTime) {
return rewardData[rewardToken].rewardPerTokenStored;
}
uint256 dt = Math.min(
rewardData[rewardToken].endTime,
block.timestamp
) - (rewardData[rewardToken].lastUpdateTime);
if (dt == 0 || totalStaked == 0) {
return rewardData[rewardToken].rewardPerTokenStored;
}
return
rewardData[rewardToken].rewardPerTokenStored +
(rewardData[rewardToken].rewardRate * dt * 1e18) /
totalStaked;
}
function earned(
address user,
address rewardToken
) public view returns (uint) {
uint256 curRewardPerToken = rewardPerToken(rewardToken);
return earned(user, rewardToken, curRewardPerToken);
}
function earned(
address user,
address rewardToken,
uint256 curRewardPerToken
) internal view returns (uint) {
uint256 d = curRewardPerToken -
userRewardPerTokenPaid[user][rewardToken];
return
(balanceOf[user] * d) /
1e18 +
userRewardsClaimable[user][rewardToken];
}
function setReward(
address rewardToken,
uint256 startTime,
uint256 endTime,
uint256 totalRewards
) public onlyOwner nonReentrant updateReward(address(0)) {
require(startTime < endTime, "start must lt end");
require(rewardData[rewardToken].endTime < block.timestamp, "not end");
if (!inRewardsTokenList[rewardToken]) {
rewardTokens.push(rewardToken);
inRewardsTokenList[rewardToken] = true;
}
rewardData[rewardToken].startTime = startTime;
rewardData[rewardToken].endTime = endTime;
rewardData[rewardToken].lastUpdateTime = block.timestamp;
rewardData[rewardToken].rewardRate =
totalRewards /
(endTime - startTime);
if (block.timestamp > startTime && totalStaked > 0) {
uint256 dt = block.timestamp - startTime;
rewardData[rewardToken].rewardPerTokenStored +=
(rewardData[rewardToken].rewardRate * dt * 1e18) /
totalStaked;
}
if (block.timestamp > startTime && totalStaked == 0) {
uint256 dt = block.timestamp - startTime;
totalRewards -= rewardData[rewardToken].rewardRate * dt;
}
IERC20(rewardToken).safeTransferFrom(
msg.sender,
address(this),
totalRewards
);
emit RewardsSet(rewardToken, startTime, endTime, totalRewards);
}
function stake(
uint amount,
address onBehalfOf
) external nonReentrant updateReward(onBehalfOf) {
require(amount > 0, "amount = 0");
stakedToken.safeTransferFrom(msg.sender, address(this), amount);
balanceOf[onBehalfOf] += amount;
totalStaked += amount;
emit Staked(msg.sender, onBehalfOf, amount);
}
function withdraw(
uint amount,
address to
) external nonReentrant updateReward(msg.sender) {
require(amount > 0, "amount = 0");
balanceOf[msg.sender] -= amount;
totalStaked -= amount;
require(stakedToken.transfer(to, amount), "transfer failed");
emit Withdraw(msg.sender, to, amount);
}
function withdrawByLendingPool(
uint amount,
address user,
address to
) external onlyLendingPool nonReentrant updateReward(user) {
require(amount > 0, "amount = 0");
balanceOf[user] -= amount;
totalStaked -= amount;
require(stakedToken.transfer(to, amount), "transfer falied");
emit Withdraw(user, to, amount);
}
function claim() external nonReentrant updateReward(msg.sender) {
for (uint i = 0; i < rewardTokens.length; i++) {
address rewardToken = rewardTokens[i];
uint256 claimable = userRewardsClaimable[msg.sender][rewardToken];
if (claimable > 0) {
userRewardsClaimable[msg.sender][rewardToken] = 0;
require(
IERC20(rewardToken).transfer(msg.sender, claimable),
"transfer failed"
);
emit RewardPaid(msg.sender, rewardToken, claimable);
}
}
}
function update() external updateReward(address(0)) onlyOwner {}
function rewardsTokenListLength() external view returns (uint256) {
return rewardTokens.length;
}
}
文件 31 的 33:StakingRewardsDeployer.sol
pragma solidity ^0.8.0;
import "../../lendingpool/StakingRewards.sol";
library StakingRewardsDeployer {
function deploy(address stakingToken) external returns (address) {
address stakingAddress = address(new StakingRewards(stakingToken));
return stakingAddress;
}
}
文件 32 的 33:TransferHelper.sol
pragma solidity >=0.6.0;
import "../external/openzeppelin/contracts/token/ERC20/IERC20.sol";
library TransferHelper {
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(
IERC20.transferFrom.selector,
from,
to,
value
)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"STF"
);
}
function safeTransfer(address token, address to, uint256 value) internal {
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(IERC20.transfer.selector, to, value)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"ST"
);
}
function safeApprove(address token, address to, uint256 value) internal {
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(IERC20.approve.selector, to, value)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"SA"
);
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, "STE");
}
}
文件 33 的 33:draft-IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
{
"compilationTarget": {
"contracts/lendingpool/LendingPool.sol": "LendingPool"
},
"evmVersion": "paris",
"libraries": {
"contracts/libraries/logic/ETokenDeployer.sol:ETokenDeployer": "0xecce0f5e758d01c142ebd5ed2565038e4c0edd80",
"contracts/libraries/logic/ReserveLogic.sol:ReserveLogic": "0xec120bc6e12cea127553b1f53445947b1f73a132",
"contracts/libraries/logic/StakingRewardsDeployer.sol:StakingRewardsDeployer": "0xcefa665165281b7a9807bdcd4d7ac54a54ca1e13"
},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_addressRegistry","type":"address"},{"internalType":"address","name":"_WETH9","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"reserveId","type":"uint256"},{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":true,"internalType":"address","name":"onBehalfOf","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"reserveId","type":"uint256"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"onBehalfOf","type":"address"},{"indexed":false,"internalType":"uint256","name":"reserveAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"eTokenAmount","type":"uint256"},{"indexed":true,"internalType":"uint16","name":"referral","type":"uint16"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":true,"internalType":"address","name":"vaultAddress","type":"address"}],"name":"DisableVaultToBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":true,"internalType":"address","name":"vaultAddress","type":"address"}],"name":"EnableVaultToBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"reserve","type":"address"},{"indexed":true,"internalType":"address","name":"eTokenAddress","type":"address"},{"indexed":false,"internalType":"address","name":"stakingAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"}],"name":"InitReserve","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":[],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"reserveId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"eTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"underlyingTokenAmount","type":"uint256"}],"name":"Redeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"reserveId","type":"uint256"},{"indexed":true,"internalType":"address","name":"onBehalfOf","type":"address"},{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Repay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"ReserveActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"ReserveBorrowDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"ReserveBorrowEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"ReserveDeActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"ReserveFrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"ReserveUnFreeze","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":true,"internalType":"address","name":"vaultAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"reserveId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"credit","type":"uint256"}],"name":"SetCreditsOfVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"reserveId","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"utilizationA","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"borrowingRateA","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"utilizationB","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"borrowingRateB","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"maxBorrowingRate","type":"uint16"}],"name":"SetInterestRateConfig","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"reserveId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cap","type":"uint256"}],"name":"SetReserveCapacity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"reserveId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeRate","type":"uint256"}],"name":"SetReserveFeeRate","type":"event"},{"anonymous":false,"inputs":[],"name":"UnPaused","type":"event"},{"inputs":[],"name":"WETH9","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"activateReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"addressRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"onBehalfOf","type":"address"},{"internalType":"uint256","name":"debtId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"borrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"borrowingRateOfReserve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"borrowingWhiteList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"credits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"deActivateReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"debtPositions","outputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"borrowed","type":"uint256"},{"internalType":"uint256","name":"borrowedIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"onBehalfOf","type":"address"},{"internalType":"uint16","name":"referralCode","type":"uint16"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"eTokenAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"onBehalfOf","type":"address"},{"internalType":"uint16","name":"referralCode","type":"uint16"}],"name":"depositAndStake","outputs":[{"internalType":"uint256","name":"eTokenAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"disableBorrowing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultId","type":"uint256"}],"name":"disableVaultToBorrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyPauseAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"enableBorrowing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultId","type":"uint256"}],"name":"enableVaultToBorrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"exchangeRateOfReserve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"freezeReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"debtId","type":"uint256"}],"name":"getCurrentDebt","outputs":[{"internalType":"uint256","name":"currentDebt","type":"uint256"},{"internalType":"uint256","name":"latestBorrowingIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"getETokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"reserveIdArr","type":"uint256[]"},{"internalType":"address","name":"user","type":"address"}],"name":"getPositionStatus","outputs":[{"components":[{"internalType":"uint256","name":"reserveId","type":"uint256"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"eTokenStaked","type":"uint256"},{"internalType":"uint256","name":"eTokenUnStaked","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"internalType":"struct ILendingPool.PositionStatus[]","name":"statusArr","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"debtId","type":"uint256"}],"name":"getReserveIdOfDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"reserveIdArr","type":"uint256[]"}],"name":"getReserveStatus","outputs":[{"components":[{"internalType":"uint256","name":"reserveId","type":"uint256"},{"internalType":"address","name":"underlyingTokenAddress","type":"address"},{"internalType":"address","name":"eTokenAddress","type":"address"},{"internalType":"address","name":"stakingAddress","type":"address"},{"internalType":"uint256","name":"totalLiquidity","type":"uint256"},{"internalType":"uint256","name":"totalBorrows","type":"uint256"},{"internalType":"uint256","name":"exchangeRate","type":"uint256"},{"internalType":"uint256","name":"borrowingRate","type":"uint256"}],"internalType":"struct ILendingPool.ReserveStatus[]","name":"statusArr","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"getStakingAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"getUnderlyingTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"initReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"newDebtPosition","outputs":[{"internalType":"uint256","name":"debtId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nextDebtPositionId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextReserveId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"},{"internalType":"uint256","name":"eTokenAmount","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"receiveNativeETH","type":"bool"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"onBehalfOf","type":"address"},{"internalType":"uint256","name":"debtId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"repay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"reserves","outputs":[{"internalType":"uint256","name":"borrowingIndex","type":"uint256"},{"internalType":"uint256","name":"currentBorrowingRate","type":"uint256"},{"internalType":"uint256","name":"totalBorrows","type":"uint256"},{"internalType":"address","name":"underlyingTokenAddress","type":"address"},{"internalType":"address","name":"eTokenAddress","type":"address"},{"internalType":"address","name":"stakingAddress","type":"address"},{"internalType":"uint256","name":"reserveCapacity","type":"uint256"},{"components":[{"internalType":"uint128","name":"utilizationA","type":"uint128"},{"internalType":"uint128","name":"borrowingRateA","type":"uint128"},{"internalType":"uint128","name":"utilizationB","type":"uint128"},{"internalType":"uint128","name":"borrowingRateB","type":"uint128"},{"internalType":"uint128","name":"maxBorrowingRate","type":"uint128"}],"internalType":"struct DataTypes.InterestRateConfig","name":"borrowingRateConfig","type":"tuple"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint128","name":"lastUpdateTimestamp","type":"uint128"},{"internalType":"uint16","name":"reserveFeeRate","type":"uint16"},{"components":[{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"bool","name":"frozen","type":"bool"},{"internalType":"bool","name":"borrowingEnabled","type":"bool"}],"internalType":"struct DataTypes.Flags","name":"flags","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"},{"internalType":"uint16","name":"utilizationA","type":"uint16"},{"internalType":"uint16","name":"borrowingRateA","type":"uint16"},{"internalType":"uint16","name":"utilizationB","type":"uint16"},{"internalType":"uint16","name":"borrowingRateB","type":"uint16"},{"internalType":"uint16","name":"maxBorrowingRate","type":"uint16"}],"name":"setBorrowingRateConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultId","type":"uint256"},{"internalType":"uint256","name":"reserveId","type":"uint256"},{"internalType":"uint256","name":"credit","type":"uint256"}],"name":"setCreditsOfVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"},{"internalType":"uint256","name":"cap","type":"uint256"}],"name":"setReserveCapacity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"},{"internalType":"uint16","name":"_rate","type":"uint16"}],"name":"setReserveFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"totalBorrowsOfReserve","outputs":[{"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"totalLiquidityOfReserve","outputs":[{"internalType":"uint256","name":"totalLiquidity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"unFreezeReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unPauseAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"},{"internalType":"uint256","name":"eTokenAmount","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"receiveNativeETH","type":"bool"}],"name":"unStakeAndWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reserveId","type":"uint256"}],"name":"utilizationRateOfReserve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]