编译器
0.6.12+commit.27d51765
文件 1 的 64:Address.sol
pragma solidity 0.6.12;
library Address {
function isContract(address account) internal view returns (bool) {
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
assembly {
codehash := extcodehash(account)
}
return (codehash != accountHash && codehash != 0x0);
}
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');
}
}
文件 2 的 64:AdminUpgradeabilityProxy.sol
pragma solidity 0.6.12;
import './BaseAdminUpgradeabilityProxy.sol';
contract AdminUpgradeabilityProxy is BaseAdminUpgradeabilityProxy, UpgradeabilityProxy {
constructor(
address _logic,
address _admin,
bytes memory _data
) public payable UpgradeabilityProxy(_logic, _data) {
assert(ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1));
_setAdmin(_admin);
}
function _willFallback() internal override(BaseAdminUpgradeabilityProxy, Proxy) {
BaseAdminUpgradeabilityProxy._willFallback();
}
}
文件 3 的 64:BaseAdminUpgradeabilityProxy.sol
pragma solidity 0.6.12;
import './UpgradeabilityProxy.sol';
contract BaseAdminUpgradeabilityProxy is BaseUpgradeabilityProxy {
event AdminChanged(address previousAdmin, address newAdmin);
bytes32 internal constant ADMIN_SLOT =
0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
modifier ifAdmin() {
if (msg.sender == _admin()) {
_;
} else {
_fallback();
}
}
function admin() external ifAdmin returns (address) {
return _admin();
}
function implementation() external ifAdmin returns (address) {
return _implementation();
}
function changeAdmin(address newAdmin) external ifAdmin {
require(newAdmin != address(0), 'Cannot change the admin of a proxy to the zero address');
emit AdminChanged(_admin(), newAdmin);
_setAdmin(newAdmin);
}
function upgradeTo(address newImplementation) external ifAdmin {
_upgradeTo(newImplementation);
}
function upgradeToAndCall(address newImplementation, bytes calldata data)
external
payable
ifAdmin
{
_upgradeTo(newImplementation);
(bool success, ) = newImplementation.delegatecall(data);
require(success, "upgradeToAndCall failed");
}
function _admin() internal view returns (address adm) {
bytes32 slot = ADMIN_SLOT;
assembly {
adm := sload(slot)
}
}
function _setAdmin(address newAdmin) internal {
bytes32 slot = ADMIN_SLOT;
assembly {
sstore(slot, newAdmin)
}
}
function _willFallback() internal virtual override {
require(msg.sender != _admin(), 'Cannot call fallback function from the proxy admin');
super._willFallback();
}
}
文件 4 的 64:BaseImmutableAdminUpgradeabilityProxy.sol
pragma solidity 0.6.12;
import './BaseUpgradeabilityProxy.sol';
contract BaseImmutableAdminUpgradeabilityProxy is BaseUpgradeabilityProxy {
address immutable ADMIN;
constructor(address admin) public {
ADMIN = admin;
}
modifier ifAdmin() {
if (msg.sender == ADMIN) {
_;
} else {
_fallback();
}
}
function admin() external ifAdmin returns (address) {
return ADMIN;
}
function implementation() external ifAdmin returns (address) {
return _implementation();
}
function upgradeTo(address newImplementation) external ifAdmin {
_upgradeTo(newImplementation);
}
function upgradeToAndCall(address newImplementation, bytes calldata data)
external
payable
ifAdmin
{
_upgradeTo(newImplementation);
(bool success, ) = newImplementation.delegatecall(data);
require(success, "upgradeToAndCall failed");
}
function _willFallback() internal virtual override {
require(msg.sender != ADMIN, 'Cannot call fallback function from the proxy admin');
super._willFallback();
}
}
文件 5 的 64:BaseUpgradeabilityProxy.sol
pragma solidity 0.6.12;
import './Proxy.sol';
import './Address.sol';
contract BaseUpgradeabilityProxy is Proxy {
event Upgraded(address indexed implementation);
bytes32 internal constant IMPLEMENTATION_SLOT =
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
function _implementation() internal view override returns (address impl) {
bytes32 slot = IMPLEMENTATION_SLOT;
assembly {
impl := sload(slot)
}
}
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
function _setImplementation(address newImplementation) internal {
require(
Address.isContract(newImplementation),
'Cannot set a proxy implementation to a non-contract address'
);
bytes32 slot = IMPLEMENTATION_SLOT;
assembly {
sstore(slot, newImplementation)
}
}
}
文件 6 的 64:Context.sol
pragma solidity 0.6.12;
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
}
文件 7 的 64:DataTypes.sol
pragma solidity 0.6.12;
library DataTypes {
struct ReserveData {
ReserveConfigurationMap configuration;
uint128 liquidityIndex;
uint128 variableBorrowIndex;
uint128 currentLiquidityRate;
uint128 currentVariableBorrowRate;
uint40 lastUpdateTimestamp;
address xTokenAddress;
address variableDebtTokenAddress;
address interestRateStrategyAddress;
uint8 id;
}
struct ReserveConfigurationMap {
uint256 data;
}
struct UserConfigurationMap {
uint256 data;
}
}
文件 8 的 64:DebtTokenBase.sol
pragma solidity 0.6.12;
import {IMarginPool} from './IMarginPool.sol';
import {ICreditDelegationToken} from './ICreditDelegationToken.sol';
import {IncentivizedERC20} from './IncentivizedERC20.sol';
import {Errors} from './Errors.sol';
abstract contract DebtTokenBase is
IncentivizedERC20,
ICreditDelegationToken
{
address public immutable UNDERLYING_ASSET_ADDRESS;
IMarginPool public immutable POOL;
mapping(address => mapping(address => uint256)) internal _borrowAllowances;
modifier onlyMarginPool {
require(_msgSender() == address(POOL), Errors.CT_CALLER_MUST_BE_MARGIN_POOL);
_;
}
constructor(
address pool,
address underlyingAssetAddress,
string memory name,
string memory symbol,
uint8 decimals
) public IncentivizedERC20(name, symbol, decimals) {
POOL = IMarginPool(pool);
UNDERLYING_ASSET_ADDRESS = underlyingAssetAddress;
}
function approveDelegation(address delegatee, uint256 amount) external override {
_borrowAllowances[_msgSender()][delegatee] = amount;
emit BorrowAllowanceDelegated(_msgSender(), delegatee, UNDERLYING_ASSET_ADDRESS, amount);
}
function borrowAllowance(address fromUser, address toUser)
external
view
override
returns (uint256)
{
return _borrowAllowances[fromUser][toUser];
}
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
recipient;
amount;
revert('TRANSFER_NOT_SUPPORTED');
}
function allowance(address owner, address spender)
public
view
virtual
override
returns (uint256)
{
owner;
spender;
revert('ALLOWANCE_NOT_SUPPORTED');
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
spender;
amount;
revert('APPROVAL_NOT_SUPPORTED');
}
function transferFrom(
address sender,
address recipient,
uint256 amount
) public virtual override returns (bool) {
sender;
recipient;
amount;
revert('TRANSFER_NOT_SUPPORTED');
}
function increaseAllowance(address spender, uint256 addedValue)
public
virtual
override
returns (bool)
{
spender;
addedValue;
revert('ALLOWANCE_NOT_SUPPORTED');
}
function decreaseAllowance(address spender, uint256 subtractedValue)
public
virtual
override
returns (bool)
{
spender;
subtractedValue;
revert('ALLOWANCE_NOT_SUPPORTED');
}
function _decreaseBorrowAllowance(
address delegator,
address delegatee,
uint256 amount
) internal {
uint256 newAllowance =
_borrowAllowances[delegator][delegatee].sub(amount, Errors.BORROW_ALLOWANCE_NOT_ENOUGH);
_borrowAllowances[delegator][delegatee] = newAllowance;
emit BorrowAllowanceDelegated(delegator, delegatee, UNDERLYING_ASSET_ADDRESS, newAllowance);
}
}
文件 9 的 64:DefaultReserveInterestRateStrategy.sol
pragma solidity 0.6.12;
import {SafeMath} from './SafeMath.sol';
import {IReserveInterestRateStrategy} from './IReserveInterestRateStrategy.sol';
import {WadRayMath} from './WadRayMath.sol';
import {PercentageMath} from './PercentageMath.sol';
import {IMarginPoolAddressesProvider} from './IMarginPoolAddressesProvider.sol';
contract DefaultReserveInterestRateStrategy is IReserveInterestRateStrategy {
using WadRayMath for uint256;
using SafeMath for uint256;
using PercentageMath for uint256;
uint256 public immutable OPTIMAL_UTILIZATION_RATE;
uint256 public immutable EXCESS_UTILIZATION_RATE;
IMarginPoolAddressesProvider public immutable addressesProvider;
uint256 internal immutable _baseVariableBorrowRate;
uint256 internal immutable _variableRateSlope1;
uint256 internal immutable _variableRateSlope2;
constructor(
IMarginPoolAddressesProvider provider,
uint256 optimalUtilizationRate,
uint256 baseVariableBorrowRate,
uint256 variableRateSlope1,
uint256 variableRateSlope2
) public {
OPTIMAL_UTILIZATION_RATE = optimalUtilizationRate;
EXCESS_UTILIZATION_RATE = WadRayMath.ray().sub(optimalUtilizationRate);
addressesProvider = provider;
_baseVariableBorrowRate = baseVariableBorrowRate;
_variableRateSlope1 = variableRateSlope1;
_variableRateSlope2 = variableRateSlope2;
}
function variableRateSlope1() external view returns (uint256) {
return _variableRateSlope1;
}
function variableRateSlope2() external view returns (uint256) {
return _variableRateSlope2;
}
function baseVariableBorrowRate() external view override returns (uint256) {
return _baseVariableBorrowRate;
}
function getMaxVariableBorrowRate() external view override returns (uint256) {
return _baseVariableBorrowRate.add(_variableRateSlope1).add(_variableRateSlope2);
}
struct CalcInterestRatesLocalVars {
uint256 totalDebt;
uint256 currentVariableBorrowRate;
uint256 currentLiquidityRate;
uint256 utilizationRate;
}
function calculateInterestRates(
uint256 availableLiquidity,
uint256 totalVariableDebt,
uint256 reserveFactor
)
external
view
override
returns (
uint256,
uint256
)
{
CalcInterestRatesLocalVars memory vars;
vars.totalDebt = totalVariableDebt;
vars.currentVariableBorrowRate = 0;
vars.currentLiquidityRate = 0;
uint256 utilizationRate =
vars.totalDebt == 0 ? 0 : vars.totalDebt.rayDiv(availableLiquidity.add(vars.totalDebt));
if (utilizationRate > OPTIMAL_UTILIZATION_RATE) {
uint256 excessUtilizationRateRatio =
utilizationRate.sub(OPTIMAL_UTILIZATION_RATE).rayDiv(EXCESS_UTILIZATION_RATE);
vars.currentVariableBorrowRate = _baseVariableBorrowRate.add(_variableRateSlope1).add(
_variableRateSlope2.rayMul(excessUtilizationRateRatio)
);
} else {
vars.currentVariableBorrowRate = _baseVariableBorrowRate.add(
utilizationRate.rayMul(_variableRateSlope1).rayDiv(OPTIMAL_UTILIZATION_RATE)
);
}
vars.currentLiquidityRate = _getOverallBorrowRate(
totalVariableDebt,
vars.currentVariableBorrowRate
)
.rayMul(utilizationRate)
.percentMul(PercentageMath.PERCENTAGE_FACTOR.sub(reserveFactor));
return (
vars.currentLiquidityRate,
vars.currentVariableBorrowRate
);
}
function _getOverallBorrowRate(
uint256 totalVariableDebt,
uint256 currentVariableBorrowRate
) internal pure returns (uint256) {
if (totalVariableDebt == 0) return 0;
uint256 weightedVariableRate = totalVariableDebt.wadToRay().rayMul(currentVariableBorrowRate);
uint256 overallBorrowRate =
weightedVariableRate.rayDiv(totalVariableDebt.wadToRay());
return overallBorrowRate;
}
}
文件 10 的 64:ERC20.sol
pragma solidity ^0.6.0;
import './Context.sol';
import './IERC20.sol';
import './SafeMath.sol';
import './Address.sol';
contract ERC20 is Context, IERC20 {
using SafeMath for uint256;
using Address for address;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
uint8 private _decimals;
constructor(string memory name, string memory symbol) public {
_name = name;
_symbol = symbol;
_decimals = 18;
}
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function decimals() public view returns (uint8) {
return _decimals;
}
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, 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) {
_approve(_msgSender(), spender, amount);
return true;
}
function transferFrom(
address sender,
address recipient,
uint256 amount
) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
_approve(
sender,
_msgSender(),
_allowances[sender][_msgSender()].sub(amount, 'ERC20: transfer amount exceeds allowance')
);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue)
public
virtual
returns (bool)
{
_approve(
_msgSender(),
spender,
_allowances[_msgSender()][spender].sub(
subtractedValue,
'ERC20: decreased allowance below zero'
)
);
return true;
}
function _transfer(
address sender,
address recipient,
uint256 amount
) internal virtual {
require(sender != address(0), 'ERC20: transfer from the zero address');
require(recipient != address(0), 'ERC20: transfer to the zero address');
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] = _balances[sender].sub(amount, 'ERC20: transfer amount exceeds balance');
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, 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 = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(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);
_balances[account] = _balances[account].sub(amount, 'ERC20: burn amount exceeds balance');
_totalSupply = _totalSupply.sub(amount);
emit Transfer(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 _setupDecimals(uint8 decimals_) internal {
_decimals = decimals_;
}
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}
文件 11 的 64:Errors.sol
pragma solidity 0.6.12;
library Errors {
string public constant CALLER_NOT_POOL_ADMIN = '33';
string public constant BORROW_ALLOWANCE_NOT_ENOUGH = '59';
string public constant VL_INVALID_AMOUNT = '1';
string public constant VL_NO_ACTIVE_RESERVE = '2';
string public constant VL_RESERVE_FROZEN = '3';
string public constant VL_CURRENT_AVAILABLE_LIQUIDITY_NOT_ENOUGH = '4';
string public constant VL_NOT_ENOUGH_AVAILABLE_USER_BALANCE = '5';
string public constant VL_TRANSFER_NOT_ALLOWED = '6';
string public constant VL_BORROWING_NOT_ENABLED = '7';
string public constant VL_INVALID_INTEREST_RATE_MODE_SELECTED = '8';
string public constant VL_COLLATERAL_BALANCE_IS_0 = '9';
string public constant VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD = '10';
string public constant VL_COLLATERAL_CANNOT_COVER_NEW_BORROW = '11';
string public constant VL_COLLATERAL_SAME_AS_BORROWING_CURRENCY = '13';
string public constant VL_NO_DEBT_OF_SELECTED_TYPE = '15';
string public constant VL_NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF = '16';
string public constant VL_NO_VARIABLE_RATE_LOAN_IN_RESERVE = '18';
string public constant VL_UNDERLYING_BALANCE_NOT_GREATER_THAN_0 = '19';
string public constant VL_DEPOSIT_ALREADY_IN_USE = '20';
string public constant MP_INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET = '22';
string public constant MP_LIQUIDATION_CALL_FAILED = '23';
string public constant MP_NOT_ENOUGH_LIQUIDITY_TO_BORROW = '24';
string public constant MP_REQUESTED_AMOUNT_TOO_SMALL = '25';
string public constant MP_INCONSISTENT_PROTOCOL_ACTUAL_BALANCE = '26';
string public constant MP_CALLER_NOT_MARGIN_POOL_CONFIGURATOR = '27';
string public constant MP_INCONSISTENT_FLASHLOAN_PARAMS = '28';
string public constant CT_CALLER_MUST_BE_MARGIN_POOL = '29';
string public constant CT_CANNOT_GIVE_ALLOWANCE_TO_HIMSELF = '30';
string public constant CT_TRANSFER_AMOUNT_NOT_GT_0 = '31';
string public constant RL_RESERVE_ALREADY_INITIALIZED = '32';
string public constant MPC_RESERVE_LIQUIDITY_NOT_0 = '34';
string public constant MPC_INVALID_XTOKEN_POOL_ADDRESS = '35';
string public constant MPC_INVALID_VARIABLE_DEBT_TOKEN_POOL_ADDRESS = '37';
string public constant MPC_INVALID_VARIABLE_DEBT_TOKEN_UNDERLYING_ADDRESS = '39';
string public constant MPC_INVALID_ADDRESSES_PROVIDER_ID = '40';
string public constant MPC_INVALID_CONFIGURATION = '75';
string public constant MPC_CALLER_NOT_EMERGENCY_ADMIN = '76';
string public constant MPAPR_PROVIDER_NOT_REGISTERED = '41';
string public constant MPCM_HEALTH_FACTOR_NOT_BELOW_THRESHOLD = '42';
string public constant MPCM_COLLATERAL_CANNOT_BE_LIQUIDATED = '43';
string public constant MPCM_SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER = '44';
string public constant MPCM_NOT_ENOUGH_LIQUIDITY_TO_LIQUIDATE = '45';
string public constant MPCM_NO_ERRORS = '46';
string public constant MP_INVALID_FLASHLOAN_MODE = '47';
string public constant MATH_MULTIPLICATION_OVERFLOW = '48';
string public constant MATH_ADDITION_OVERFLOW = '49';
string public constant MATH_DIVISION_BY_ZERO = '50';
string public constant RL_LIQUIDITY_INDEX_OVERFLOW = '51';
string public constant RL_VARIABLE_BORROW_INDEX_OVERFLOW = '52';
string public constant RL_LIQUIDITY_RATE_OVERFLOW = '53';
string public constant RL_VARIABLE_BORROW_RATE_OVERFLOW = '54';
string public constant CT_INVALID_MINT_AMOUNT = '56';
string public constant MP_FAILED_REPAY_WITH_COLLATERAL = '57';
string public constant CT_INVALID_BURN_AMOUNT = '58';
string public constant MP_FAILED_COLLATERAL_SWAP = '60';
string public constant MP_INVALID_EQUAL_ASSETS_TO_SWAP = '61';
string public constant MP_REENTRANCY_NOT_ALLOWED = '62';
string public constant MP_CALLER_MUST_BE_AN_XTOKEN = '63';
string public constant MP_IS_PAUSED = '64';
string public constant MP_NO_MORE_RESERVES_ALLOWED = '65';
string public constant MP_INVALID_FLASH_LOAN_EXECUTOR_RETURN = '66';
string public constant RC_INVALID_LTV = '67';
string public constant RC_INVALID_LIQ_THRESHOLD = '68';
string public constant RC_INVALID_LIQ_BONUS = '69';
string public constant RC_INVALID_DECIMALS = '70';
string public constant RC_INVALID_RESERVE_FACTOR = '71';
string public constant MPAPR_INVALID_ADDRESSES_PROVIDER_ID = '72';
string public constant VL_INCONSISTENT_FLASHLOAN_PARAMS = '73';
string public constant MP_INCONSISTENT_PARAMS_LENGTH = '74';
string public constant UL_INVALID_INDEX = '77';
string public constant MP_NOT_CONTRACT = '78';
string public constant SDT_BURN_EXCEEDS_BALANCE = '80';
enum CollateralManagerErrors {
NO_ERROR,
NO_COLLATERAL_AVAILABLE,
COLLATERAL_CANNOT_BE_LIQUIDATED,
CURRRENCY_NOT_BORROWED,
HEALTH_FACTOR_ABOVE_THRESHOLD,
NOT_ENOUGH_LIQUIDITY,
NO_ACTIVE_RESERVE,
HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD,
INVALID_EQUAL_ASSETS_TO_SWAP,
FROZEN_RESERVE
}
}
文件 12 的 64:GenericLogic.sol
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import {SafeMath} from './SafeMath.sol';
import {IERC20} from './IERC20.sol';
import {ReserveLogic} from './ReserveLogic.sol';
import {ReserveConfiguration} from './ReserveConfiguration.sol';
import {UserConfiguration} from './UserConfiguration.sol';
import {WadRayMath} from './WadRayMath.sol';
import {PercentageMath} from './PercentageMath.sol';
import {IPriceOracleGetter} from './IPriceOracleGetter.sol';
import {DataTypes} from './DataTypes.sol';
library GenericLogic {
using ReserveLogic for DataTypes.ReserveData;
using SafeMath for uint256;
using WadRayMath for uint256;
using PercentageMath for uint256;
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
using UserConfiguration for DataTypes.UserConfigurationMap;
uint256 public constant HEALTH_FACTOR_LIQUIDATION_THRESHOLD = 1 ether;
struct balanceDecreaseAllowedLocalVars {
uint256 decimals;
uint256 liquidationThreshold;
uint256 totalCollateralInETH;
uint256 totalDebtInETH;
uint256 avgLiquidationThreshold;
uint256 amountToDecreaseInETH;
uint256 collateralBalanceAfterDecrease;
uint256 liquidationThresholdAfterDecrease;
uint256 healthFactorAfterDecrease;
bool reserveUsageAsCollateralEnabled;
}
function balanceDecreaseAllowed(
address asset,
address user,
uint256 amount,
mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap calldata userConfig,
mapping(uint256 => address) storage reserves,
uint256 reservesCount,
address oracle
) external view returns (bool) {
if (!userConfig.isBorrowingAny() || !userConfig.isUsingAsCollateral(reservesData[asset].id)) {
return true;
}
balanceDecreaseAllowedLocalVars memory vars;
(, vars.liquidationThreshold, , vars.decimals, ) = reservesData[asset]
.configuration
.getParams();
if (vars.liquidationThreshold == 0) {
return true;
}
(
vars.totalCollateralInETH,
vars.totalDebtInETH,
,
vars.avgLiquidationThreshold,
) = calculateUserAccountData(user, reservesData, userConfig, reserves, reservesCount, oracle);
if (vars.totalDebtInETH == 0) {
return true;
}
vars.amountToDecreaseInETH = IPriceOracleGetter(oracle).getAssetPrice(asset).mul(amount).div(
10**vars.decimals
);
vars.collateralBalanceAfterDecrease = vars.totalCollateralInETH.sub(vars.amountToDecreaseInETH);
if (vars.collateralBalanceAfterDecrease == 0) {
return false;
}
vars.liquidationThresholdAfterDecrease = vars
.totalCollateralInETH
.mul(vars.avgLiquidationThreshold)
.sub(vars.amountToDecreaseInETH.mul(vars.liquidationThreshold))
.div(vars.collateralBalanceAfterDecrease);
uint256 healthFactorAfterDecrease =
calculateHealthFactorFromBalances(
vars.collateralBalanceAfterDecrease,
vars.totalDebtInETH,
vars.liquidationThresholdAfterDecrease
);
return healthFactorAfterDecrease >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD;
}
struct CalculateUserAccountDataVars {
uint256 reserveUnitPrice;
uint256 tokenUnit;
uint256 compoundedLiquidityBalance;
uint256 compoundedBorrowBalance;
uint256 decimals;
uint256 ltv;
uint256 liquidationThreshold;
uint256 i;
uint256 healthFactor;
uint256 totalCollateralInETH;
uint256 totalDebtInETH;
uint256 avgLtv;
uint256 avgLiquidationThreshold;
uint256 reservesLength;
bool healthFactorBelowThreshold;
address currentReserveAddress;
bool usageAsCollateralEnabled;
bool userUsesReserveAsCollateral;
}
function calculateUserAccountData(
address user,
mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap memory userConfig,
mapping(uint256 => address) storage reserves,
uint256 reservesCount,
address oracle
)
internal
view
returns (
uint256,
uint256,
uint256,
uint256,
uint256
)
{
CalculateUserAccountDataVars memory vars;
if (userConfig.isEmpty()) {
return (0, 0, 0, 0, uint256(-1));
}
for (vars.i = 0; vars.i < reservesCount; vars.i++) {
if (!userConfig.isUsingAsCollateralOrBorrowing(vars.i)) {
continue;
}
vars.currentReserveAddress = reserves[vars.i];
DataTypes.ReserveData storage currentReserve = reservesData[vars.currentReserveAddress];
(vars.ltv, vars.liquidationThreshold, , vars.decimals, ) = currentReserve
.configuration
.getParams();
vars.tokenUnit = 10**vars.decimals;
vars.reserveUnitPrice = IPriceOracleGetter(oracle).getAssetPrice(vars.currentReserveAddress);
if (vars.liquidationThreshold != 0 && userConfig.isUsingAsCollateral(vars.i)) {
vars.compoundedLiquidityBalance = IERC20(currentReserve.xTokenAddress).balanceOf(user);
uint256 liquidityBalanceETH =
vars.reserveUnitPrice.mul(vars.compoundedLiquidityBalance).div(vars.tokenUnit);
vars.totalCollateralInETH = vars.totalCollateralInETH.add(liquidityBalanceETH);
vars.avgLtv = vars.avgLtv.add(liquidityBalanceETH.mul(vars.ltv));
vars.avgLiquidationThreshold = vars.avgLiquidationThreshold.add(
liquidityBalanceETH.mul(vars.liquidationThreshold)
);
}
if (userConfig.isBorrowing(vars.i)) {
vars.compoundedBorrowBalance = IERC20(currentReserve.variableDebtTokenAddress).balanceOf(
user
);
vars.totalDebtInETH = vars.totalDebtInETH.add(
vars.reserveUnitPrice.mul(vars.compoundedBorrowBalance).div(vars.tokenUnit)
);
}
}
vars.avgLtv = vars.totalCollateralInETH > 0 ? vars.avgLtv.div(vars.totalCollateralInETH) : 0;
vars.avgLiquidationThreshold = vars.totalCollateralInETH > 0
? vars.avgLiquidationThreshold.div(vars.totalCollateralInETH)
: 0;
vars.healthFactor = calculateHealthFactorFromBalances(
vars.totalCollateralInETH,
vars.totalDebtInETH,
vars.avgLiquidationThreshold
);
return (
vars.totalCollateralInETH,
vars.totalDebtInETH,
vars.avgLtv,
vars.avgLiquidationThreshold,
vars.healthFactor
);
}
function calculateHealthFactorFromBalances(
uint256 totalCollateralInETH,
uint256 totalDebtInETH,
uint256 liquidationThreshold
) internal pure returns (uint256) {
if (totalDebtInETH == 0) return uint256(-1);
return (totalCollateralInETH.percentMul(liquidationThreshold)).wadDiv(totalDebtInETH);
}
function calculateAvailableBorrowsETH(
uint256 totalCollateralInETH,
uint256 totalDebtInETH,
uint256 ltv
) internal pure returns (uint256) {
uint256 availableBorrowsETH = totalCollateralInETH.percentMul(ltv);
if (availableBorrowsETH < totalDebtInETH) {
return 0;
}
availableBorrowsETH = availableBorrowsETH.sub(totalDebtInETH);
return availableBorrowsETH;
}
struct AvailableCollateralToLiquidateLocalVars {
uint256 userCompoundedBorrowBalance;
uint256 liquidationBonus;
uint256 collateralPrice;
uint256 debtAssetPrice;
uint256 maxAmountCollateralToLiquidate;
uint256 debtAssetDecimals;
uint256 collateralDecimals;
}
function calculateAvailableCollateralToLiquidate(
DataTypes.ReserveData storage collateralReserve,
DataTypes.ReserveData storage debtReserve,
address collateralAsset,
address debtAsset,
uint256 debtToCover,
uint256 userCollateralBalance,
address oracle
) internal view returns (uint256, uint256) {
uint256 collateralAmount = 0;
AvailableCollateralToLiquidateLocalVars memory vars;
vars.collateralPrice = IPriceOracleGetter(oracle).getAssetPrice(
collateralAsset
);
vars.debtAssetPrice = IPriceOracleGetter(oracle).getAssetPrice(
debtAsset
);
(
,
,
vars.liquidationBonus,
vars.collateralDecimals,
) = collateralReserve.configuration.getParams();
vars.debtAssetDecimals = debtReserve.configuration.getDecimals();
vars.maxAmountCollateralToLiquidate = vars
.debtAssetPrice
.mul(debtToCover)
.mul(10**vars.collateralDecimals)
.percentMul(vars.liquidationBonus)
.div(vars.collateralPrice.mul(10**vars.debtAssetDecimals));
if (vars.maxAmountCollateralToLiquidate > userCollateralBalance) {
collateralAmount = userCollateralBalance;
} else {
collateralAmount = vars.maxAmountCollateralToLiquidate;
}
return (
collateralAmount,
collateralAmount.percentDiv(vars.liquidationBonus)
);
}
}
文件 13 的 64:Helpers.sol
pragma solidity 0.6.12;
import {IERC20} from './IERC20.sol';
import {DataTypes} from './DataTypes.sol';
library Helpers {
function getUserCurrentDebt(address user, DataTypes.ReserveData storage reserve)
internal
view
returns (uint256)
{
return IERC20(reserve.variableDebtTokenAddress).balanceOf(user);
}
function getUserCurrentDebtMemory(address user, DataTypes.ReserveData memory reserve)
internal
view
returns (uint256)
{
return IERC20(reserve.variableDebtTokenAddress).balanceOf(user);
}
}
文件 14 的 64:IChainlinkAggregator.sol
pragma solidity 0.6.12;
interface IChainlinkAggregator {
function latestAnswer() external view returns (int256);
function latestTimestamp() external view returns (uint256);
function latestRound() external view returns (uint256);
function getAnswer(uint256 roundId) external view returns (int256);
function getTimestamp(uint256 roundId) external view returns (uint256);
event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 timestamp);
event NewRound(uint256 indexed roundId, address indexed startedBy);
}
文件 15 的 64:ICreditDelegationToken.sol
pragma solidity 0.6.12;
interface ICreditDelegationToken {
event BorrowAllowanceDelegated(
address indexed fromUser,
address indexed toUser,
address asset,
uint256 amount
);
function approveDelegation(address delegatee, uint256 amount) external;
function borrowAllowance(address fromUser, address toUser) external view returns (uint256);
}
文件 16 的 64:IERC20.sol
pragma solidity 0.6.12;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, 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 sender,
address recipient,
uint256 amount
) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 17 的 64:IERC20Detailed.sol
pragma solidity 0.6.12;
import {IERC20} from './IERC20.sol';
interface IERC20Detailed is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 18 的 64:IERC20DetailedBytes.sol
pragma solidity 0.6.12;
contract IERC20DetailedBytes {
bytes32 public name;
bytes32 public symbol;
uint256 public decimals;
}
文件 19 的 64:IERC20WithPermit.sol
pragma solidity 0.6.12;
import {IERC20} from './IERC20.sol';
interface IERC20WithPermit is IERC20 {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
文件 20 的 64:IExtendedPriceAggregator.sol
pragma solidity 0.6.12;
interface IExtendedPriceAggregator {
event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 timestamp);
function getToken() external view returns (address);
function getTokenType() external view returns (uint256);
function getPlatformId() external view returns (uint256);
function getSubTokens() external view returns (address[] memory);
function latestAnswer() external view returns (int256);
}
文件 21 的 64:IMarginPool.sol
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import {IMarginPoolAddressesProvider} from './IMarginPoolAddressesProvider.sol';
import {DataTypes} from './DataTypes.sol';
interface IMarginPool {
event Deposit(
address indexed reserve,
address indexed user,
address indexed onBehalfOf,
uint256 amount
);
event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount);
event Borrow(
address indexed reserve,
address indexed user,
address indexed onBehalfOf,
uint256 amount,
uint256 borrowRate
);
event Repay(
address indexed reserve,
address indexed user,
address indexed repayer,
uint256 amount
);
event Swap(
address indexed user,
address indexed srcReserve,
address indexed dstReserve,
uint256 srcAmount,
uint256 dstAmount
);
event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user);
event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user);
event Paused();
event Unpaused();
event LiquidationCall(
address indexed collateralAsset,
address indexed debtAsset,
address indexed user,
uint256 debtToCover,
uint256 liquidatedCollateralAmount,
address liquidator
);
event ReserveDataUpdated(
address indexed reserve,
uint256 liquidityRate,
uint256 variableBorrowRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex
);
function deposit(
address asset,
uint256 amount,
address onBehalfOf
) external;
function withdraw(
address asset,
uint256 amount,
address to
) external returns (uint256);
function borrow(
address asset,
uint256 amount,
address onBehalfOf
) external;
function repay(
address asset,
uint256 amount,
address onBehalfOf
) external returns (uint256);
function swapTokensForTokens(
uint256 amountIn,
uint256 amountOut,
address[] calldata path,
bool isExactIn,
bool isUni
) external;
function swapTokensForClosePosition(
uint256 amountIn,
uint256 amountOut,
address[] calldata path,
bool isExactIn,
bool isUni
) external;
function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external;
function liquidationCall(
address collateralAsset,
address debtAsset,
address user,
uint256 debtToCover
) external;
function getUserAccountData(address user)
external
view
returns (
uint256 totalCollateralETH,
uint256 totalDebtETH,
uint256 availableBorrowsETH,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
);
function initReserve(
address reserve,
address xTokenAddress,
address variableDebtAddress,
address interestRateStrategyAddress
) external;
function setReserveInterestRateStrategyAddress(address reserve, address rateStrategyAddress)
external;
function setConfiguration(address reserve, uint256 configuration) external;
function getConfiguration(address asset)
external
view
returns (DataTypes.ReserveConfigurationMap memory);
function getUserConfiguration(address user)
external
view
returns (DataTypes.UserConfigurationMap memory);
function getReserveNormalizedIncome(address asset) external view returns (uint256);
function getReserveNormalizedVariableDebt(address asset) external view returns (uint256);
function getReserveData(address asset) external view returns (DataTypes.ReserveData memory);
function finalizeTransfer(
address asset,
address from,
address to,
uint256 amount,
uint256 balanceFromAfter,
uint256 balanceToBefore
) external;
function getReservesList() external view returns (address[] memory);
function getAddressesProvider() external view returns (IMarginPoolAddressesProvider);
function setPause(bool val) external;
function paused() external view returns (bool);
}
文件 22 的 64:IMarginPoolAddressesProvider.sol
pragma solidity 0.6.12;
interface IMarginPoolAddressesProvider {
event MarginPoolUpdated(address indexed newAddress);
event ConfigurationAdminUpdated(address indexed newAddress);
event EmergencyAdminUpdated(address indexed newAddress);
event MarginPoolConfiguratorUpdated(address indexed newAddress);
event MarginPoolCollateralManagerUpdated(address indexed newAddress);
event PriceOracleUpdated(address indexed newAddress);
event ProxyCreated(bytes32 id, address indexed newAddress);
event AddressSet(bytes32 id, address indexed newAddress, bool hasProxy);
event LeverTokenUpdated(address indexed newAddress);
event TreasuryAddressUpdated(address indexed newAddress);
event RewardsDistributionUpdated(address indexed newAddress);
event OrderBookUpdated(address indexed newAddress);
event SwapMinerUpdated(address indexed newAddress);
function setAddress(bytes32 id, address newAddress) external;
function setAddressAsProxy(bytes32 id, address impl) external;
function getAddress(bytes32 id) external view returns (address);
function getMarginPool() external view returns (address);
function setMarginPoolImpl(address pool, address UniswapRouter,address SushiswapRouter, address weth) external;
function getMarginPoolConfigurator() external view returns (address);
function setMarginPoolConfiguratorImpl(address configurator) external;
function getPoolAdmin() external view returns (address);
function setPoolAdmin(address admin) external;
function getEmergencyAdmin() external view returns (address);
function setEmergencyAdmin(address admin) external;
function getPriceOracle() external view returns (address);
function setPriceOracle(address priceOracle) external;
function getLeverToken() external view returns (address);
function setLeverToken(address lever) external;
function getTreasuryAddress() external view returns (address);
function setTreasuryAddress(address treasuryAddress) external;
function getRewardsDistribution() external view returns (address);
function setRewardsDistribution(address rewardsDistribution) external;
function getOrderBook() external view returns (address);
function setOrderBookImpl(address addressProvider, address UniswapRouter, address weth) external;
function getSwapMiner() external view returns (address);
function setSwapMinerImpl(address _swapMiner, address UniswapRouter, address _uniswapLevPairToken, address LeverUsdOracle) external;
}
文件 23 的 64:IPriceOracle.sol
pragma solidity 0.6.12;
interface IPriceOracle {
function getAssetPrice(address asset) external view returns (uint256);
function setAssetPrice(address asset, uint256 price) external;
}
文件 24 的 64:IPriceOracleGetter.sol
pragma solidity 0.6.12;
interface IPriceOracleGetter {
function getAssetPrice(address asset) external view returns (uint256);
}
文件 25 的 64:IReserveInterestRateStrategy.sol
pragma solidity 0.6.12;
interface IReserveInterestRateStrategy {
function baseVariableBorrowRate() external view returns (uint256);
function getMaxVariableBorrowRate() external view returns (uint256);
function calculateInterestRates(
uint256 utilizationRate,
uint256 totalVariableDebt,
uint256 reserveFactor
)
external
view
returns (
uint256 liquidityRate,
uint256 variableBorrowRate
);
}
文件 26 的 64:IScaledBalanceToken.sol
pragma solidity 0.6.12;
interface IScaledBalanceToken {
function scaledBalanceOf(address user) external view returns (uint256);
function getScaledUserBalanceAndSupply(address user) external view returns (uint256, uint256);
function scaledTotalSupply() external view returns (uint256);
}
文件 27 的 64:ITokenConfiguration.sol
pragma solidity ^0.6.12;
interface ITokenConfiguration {
function UNDERLYING_ASSET_ADDRESS() external view returns (address);
function POOL() external view returns (address);
}
文件 28 的 64:IUniswapV2Router01.sol
pragma solidity >=0.6.2;
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
)
external
returns (
uint256 amountA,
uint256 amountB,
uint256 liquidity
);
function addLiquidityETH(
address token,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
)
external
payable
returns (
uint256 amountToken,
uint256 amountETH,
uint256 liquidity
);
function removeLiquidity(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB);
function removeLiquidityETH(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountToken, uint256 amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountA, uint256 amountB);
function removeLiquidityETHWithPermit(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountToken, uint256 amountETH);
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactETHForTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function swapTokensForExactETH(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactTokensForETH(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapETHForExactTokens(
uint256 amountOut,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function quote(
uint256 amountA,
uint256 reserveA,
uint256 reserveB
) external pure returns (uint256 amountB);
function getAmountOut(
uint256 amountIn,
uint256 reserveIn,
uint256 reserveOut
) external pure returns (uint256 amountOut);
function getAmountIn(
uint256 amountOut,
uint256 reserveIn,
uint256 reserveOut
) external pure returns (uint256 amountIn);
function getAmountsOut(uint256 amountIn, address[] calldata path)
external
view
returns (uint256[] memory amounts);
function getAmountsIn(uint256 amountOut, address[] calldata path)
external
view
returns (uint256[] memory amounts);
}
文件 29 的 64:IUniswapV2Router02.sol
pragma solidity >=0.6.2;
import './IUniswapV2Router01.sol';
interface IUniswapV2Router02 is IUniswapV2Router01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external;
}
文件 30 的 64:IVariableDebtToken.sol
pragma solidity 0.6.12;
import {IScaledBalanceToken} from './IScaledBalanceToken.sol';
interface IVariableDebtToken is IScaledBalanceToken {
event Mint(address indexed from, address indexed onBehalfOf, uint256 value, uint256 index);
function mint(
address user,
address onBehalfOf,
uint256 amount,
uint256 index
) external returns (bool);
event Burn(address indexed user, uint256 amount, uint256 index);
function burn(
address user,
uint256 amount,
uint256 index
) external;
}
文件 31 的 64:IWETH.sol
pragma solidity 0.6.12;
interface IWETH {
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);
}
文件 32 的 64:IWETHGateway.sol
pragma solidity 0.6.12;
interface IWETHGateway {
function depositETH(address onBehalfOf) external payable;
function withdrawETH(uint256 amount, address onBehalfOf) external;
function borrowETH(
uint256 amount
) external;
}
文件 33 的 64:IXToken.sol
pragma solidity 0.6.12;
import {IERC20} from './IERC20.sol';
import {IScaledBalanceToken} from './IScaledBalanceToken.sol';
interface IXToken is IERC20, IScaledBalanceToken {
event Mint(address indexed from, uint256 value, uint256 index);
function mint(
address user,
uint256 amount,
uint256 index
) external returns (bool);
event Burn(address indexed from, address indexed target, uint256 value, uint256 index);
event BalanceTransfer(address indexed from, address indexed to, uint256 value, uint256 index);
function burn(
address user,
address receiverOfUnderlying,
uint256 amount,
uint256 index
) external;
function mintToTreasury(uint256 amount, uint256 index) external;
function transferOnLiquidation(
address from,
address to,
uint256 value
) external;
function transferUnderlyingTo(address user, uint256 amount) external returns (uint256);
}
文件 34 的 64:IncentivizedERC20.sol
pragma solidity 0.6.12;
import {Context} from './Context.sol';
import {IERC20} from './IERC20.sol';
import {IERC20Detailed} from './IERC20Detailed.sol';
import {SafeMath} from './SafeMath.sol';
contract IncentivizedERC20 is Context, IERC20, IERC20Detailed {
using SafeMath for uint256;
mapping(address => uint256) internal _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 internal _totalSupply;
string private _name;
string private _symbol;
uint8 private _decimals;
constructor(
string memory name,
string memory symbol,
uint8 decimals
) public {
_name = name;
_symbol = symbol;
_decimals = decimals;
}
function name() public view override returns (string memory) {
return _name;
}
function symbol() public view override returns (string memory) {
return _symbol;
}
function decimals() public view override returns (uint8) {
return _decimals;
}
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 recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
emit Transfer(_msgSender(), recipient, 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) {
_approve(_msgSender(), spender, amount);
return true;
}
function transferFrom(
address sender,
address recipient,
uint256 amount
) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
_approve(
sender,
_msgSender(),
_allowances[sender][_msgSender()].sub(amount, 'ERC20: transfer amount exceeds allowance')
);
emit Transfer(sender, recipient, amount);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue)
public
virtual
returns (bool)
{
_approve(
_msgSender(),
spender,
_allowances[_msgSender()][spender].sub(
subtractedValue,
'ERC20: decreased allowance below zero'
)
);
return true;
}
function _transfer(
address sender,
address recipient,
uint256 amount
) internal virtual {
require(sender != address(0), 'ERC20: transfer from the zero address');
require(recipient != address(0), 'ERC20: transfer to the zero address');
_beforeTokenTransfer(sender, recipient, amount);
uint256 oldSenderBalance = _balances[sender];
_balances[sender] = oldSenderBalance.sub(amount, 'ERC20: transfer amount exceeds balance');
_balances[recipient] = _balances[recipient].add(amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), 'ERC20: mint to the zero address');
_beforeTokenTransfer(address(0), account, amount);
uint256 oldTotalSupply = _totalSupply;
_totalSupply = oldTotalSupply.add(amount);
uint256 oldAccountBalance = _balances[account];
_balances[account] = oldAccountBalance.add(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 oldTotalSupply = _totalSupply;
_totalSupply = oldTotalSupply.sub(amount);
uint256 oldAccountBalance = _balances[account];
_balances[account] = oldAccountBalance.sub(amount, 'ERC20: burn amount exceeds balance');
}
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 _setName(string memory newName) internal {
_name = newName;
}
function _setSymbol(string memory newSymbol) internal {
_symbol = newSymbol;
}
function _setDecimals(uint8 newDecimals) internal {
_decimals = newDecimals;
}
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}
文件 35 的 64:Initializable.sol
pragma solidity >=0.4.24 <0.7.0;
contract Initializable {
bool private initialized;
bool private initializing;
modifier initializer() {
require(
initializing || isConstructor() || !initialized,
'Contract instance has already been initialized'
);
bool isTopLevelCall = !initializing;
if (isTopLevelCall) {
initializing = true;
initialized = true;
}
_;
if (isTopLevelCall) {
initializing = false;
}
}
function isConstructor() private view returns (bool) {
uint256 cs;
assembly {
cs := extcodesize(address())
}
return cs == 0;
}
uint256[50] private ______gap;
}
文件 36 的 64:InitializableAdminUpgradeabilityProxy.sol
pragma solidity 0.6.12;
import './BaseAdminUpgradeabilityProxy.sol';
import './InitializableUpgradeabilityProxy.sol';
contract InitializableAdminUpgradeabilityProxy is
BaseAdminUpgradeabilityProxy,
InitializableUpgradeabilityProxy
{
function initialize(
address logic,
address admin,
bytes memory data
) public payable {
require(_implementation() == address(0),"_implementation() != address(0)");
InitializableUpgradeabilityProxy.initialize(logic, data);
assert(ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1));
_setAdmin(admin);
}
function _willFallback() internal override(BaseAdminUpgradeabilityProxy, Proxy) {
BaseAdminUpgradeabilityProxy._willFallback();
}
}
文件 37 的 64:InitializableImmutableAdminUpgradeabilityProxy.sol
pragma solidity 0.6.12;
import './BaseImmutableAdminUpgradeabilityProxy.sol';
import './InitializableUpgradeabilityProxy.sol';
contract InitializableImmutableAdminUpgradeabilityProxy is
BaseImmutableAdminUpgradeabilityProxy,
InitializableUpgradeabilityProxy
{
constructor(address admin) public BaseImmutableAdminUpgradeabilityProxy(admin) {}
function _willFallback() internal override(BaseImmutableAdminUpgradeabilityProxy, Proxy) {
BaseImmutableAdminUpgradeabilityProxy._willFallback();
}
}
文件 38 的 64:InitializableUpgradeabilityProxy.sol
pragma solidity 0.6.12;
import './BaseUpgradeabilityProxy.sol';
contract InitializableUpgradeabilityProxy is BaseUpgradeabilityProxy {
function initialize(address _logic, bytes memory _data) public payable {
require(_implementation() == address(0),"_implementation error!");
assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1));
_setImplementation(_logic);
if (_data.length > 0) {
(bool success, ) = _logic.delegatecall(_data);
require(success,"_logic.delegatecall error!");
}
}
}
文件 39 的 64:LeverOracle.sol
pragma solidity 0.6.12;
import {Ownable} from './Ownable.sol';
import {IERC20} from './IERC20.sol';
import {IPriceOracleGetter} from './IPriceOracleGetter.sol';
import {IChainlinkAggregator} from './IChainlinkAggregator.sol';
import {SafeERC20} from './SafeERC20.sol';
contract LeverOracle is IPriceOracleGetter, Ownable {
using SafeERC20 for IERC20;
event WethSet(address indexed weth);
event AssetSourceUpdated(address indexed asset, address indexed source);
event FallbackOracleUpdated(address indexed fallbackOracle);
mapping(address => IChainlinkAggregator) private assetsSources;
IPriceOracleGetter private _fallbackOracle;
address public immutable WETH;
constructor(
address[] memory assets,
address[] memory sources,
address fallbackOracle,
address weth
) public {
_setFallbackOracle(fallbackOracle);
_setAssetsSources(assets, sources);
WETH = weth;
emit WethSet(weth);
}
function setAssetSources(address[] calldata assets, address[] calldata sources)
external
onlyOwner
{
_setAssetsSources(assets, sources);
}
function setFallbackOracle(address fallbackOracle) external onlyOwner {
_setFallbackOracle(fallbackOracle);
}
function _setAssetsSources(address[] memory assets, address[] memory sources) internal {
require(assets.length == sources.length, 'INCONSISTENT_PARAMS_LENGTH');
for (uint256 i = 0; i < assets.length; i++) {
assetsSources[assets[i]] = IChainlinkAggregator(sources[i]);
emit AssetSourceUpdated(assets[i], sources[i]);
}
}
function _setFallbackOracle(address fallbackOracle) internal {
_fallbackOracle = IPriceOracleGetter(fallbackOracle);
emit FallbackOracleUpdated(fallbackOracle);
}
function getAssetPrice(address asset) public view override returns (uint256) {
IChainlinkAggregator source = assetsSources[asset];
if (asset == WETH) {
return 1 ether;
} else if (address(source) == address(0)) {
return _fallbackOracle.getAssetPrice(asset);
} else {
int256 price = IChainlinkAggregator(source).latestAnswer();
if (price > 0) {
return uint256(price);
} else {
return _fallbackOracle.getAssetPrice(asset);
}
}
}
function getAssetsPrices(address[] calldata assets) external view returns (uint256[] memory) {
uint256[] memory prices = new uint256[](assets.length);
for (uint256 i = 0; i < assets.length; i++) {
prices[i] = getAssetPrice(assets[i]);
}
return prices;
}
function getSourceOfAsset(address asset) external view returns (address) {
return address(assetsSources[asset]);
}
function getFallbackOracle() external view returns (address) {
return address(_fallbackOracle);
}
}
文件 40 的 64:MarginPool.sol
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import {SafeMath} from "./SafeMath.sol";
import {IERC20} from "./IERC20.sol";
import {SafeERC20} from "./SafeERC20.sol";
import {Address} from "./Address.sol";
import {IMarginPoolAddressesProvider} from "./IMarginPoolAddressesProvider.sol";
import {IXToken} from "./IXToken.sol";
import {IVariableDebtToken} from "./IVariableDebtToken.sol";
import {IPriceOracleGetter} from "./IPriceOracleGetter.sol";
import {IMarginPool} from "./IMarginPool.sol";
import {VersionedInitializable} from "./VersionedInitializable.sol";
import {Helpers} from "./Helpers.sol";
import {Errors} from "./Errors.sol";
import {WadRayMath} from "./WadRayMath.sol";
import {PercentageMath} from "./PercentageMath.sol";
import {ReserveLogic} from "./ReserveLogic.sol";
import {GenericLogic} from "./GenericLogic.sol";
import {ValidationLogic} from "./ValidationLogic.sol";
import {ReserveConfiguration} from "./ReserveConfiguration.sol";
import {UserConfiguration} from "./UserConfiguration.sol";
import {DataTypes} from "./DataTypes.sol";
import {MarginPoolStorage} from "./MarginPoolStorage.sol";
import {IUniswapV2Router02} from "./IUniswapV2Router02.sol";
interface ISwapMining {
function swapMint(
address account,
address input,
address output,
uint256 amount
) external returns (bool);
}
contract MarginPool is VersionedInitializable, IMarginPool, MarginPoolStorage {
using SafeMath for uint256;
using WadRayMath for uint256;
using PercentageMath for uint256;
using SafeERC20 for IERC20;
uint256 public constant MAX_NUMBER_RESERVES = 128;
uint256 public constant MARGINPOOL_REVISION = 0x1;
IUniswapV2Router02 public uniswaper;
IUniswapV2Router02 public sushiSwaper;
address public wethAddress;
address public constant inchor = 0x11111112542D85B3EF69AE05771c2dCCff4fAa26;
modifier whenNotPaused() {
_whenNotPaused();
_;
}
modifier onlyMarginPoolConfigurator() {
_onlyMarginPoolConfigurator();
_;
}
function _whenNotPaused() internal view {
require(!_paused, Errors.MP_IS_PAUSED);
}
function _onlyMarginPoolConfigurator() internal view {
require(
_addressesProvider.getMarginPoolConfigurator() == msg.sender,
Errors.MP_CALLER_NOT_MARGIN_POOL_CONFIGURATOR
);
}
function getRevision() internal pure override returns (uint256) {
return MARGINPOOL_REVISION;
}
function initialize(
IMarginPoolAddressesProvider provider,
IUniswapV2Router02 _uniswaper,
IUniswapV2Router02 _sushiSwaper,
address _weth
) public initializer {
_addressesProvider = provider;
uniswaper = _uniswaper;
sushiSwaper = _sushiSwaper;
wethAddress = _weth;
}
function deposit(
address asset,
uint256 amount,
address onBehalfOf
) external override whenNotPaused {
DataTypes.ReserveData storage reserve = _reserves[asset];
ValidationLogic.validateDeposit(reserve, amount);
address xToken = reserve.xTokenAddress;
reserve.updateState();
reserve.updateInterestRates(asset, xToken, amount, 0);
IERC20(asset).safeTransferFrom(msg.sender, xToken, amount);
_depositLogic(asset, amount, onBehalfOf, xToken, reserve);
}
function reDeposit(
address asset,
uint256 amount,
address onBehalfOf
) internal whenNotPaused {
DataTypes.ReserveData storage reserve = _reserves[asset];
ValidationLogic.validateDeposit(reserve, amount);
address xToken = reserve.xTokenAddress;
reserve.updateState();
reserve.updateInterestRates(asset, xToken, amount, 0);
IERC20(asset).safeTransfer(xToken, amount);
_depositLogic(asset, amount, onBehalfOf, xToken, reserve);
}
function _depositLogic(
address asset,
uint256 amount,
address onBehalfOf,
address xToken,
DataTypes.ReserveData storage reserve
) internal {
uint256 variableDebt = Helpers.getUserCurrentDebt(onBehalfOf, reserve);
if (variableDebt > 0) {
uint256 paybackAmount = variableDebt;
if (amount < paybackAmount) {
paybackAmount = amount;
}
IVariableDebtToken(reserve.variableDebtTokenAddress).burn(
onBehalfOf,
paybackAmount,
reserve.variableBorrowIndex
);
emit Repay(asset, onBehalfOf, msg.sender, paybackAmount);
if (variableDebt == paybackAmount) {
_usersConfig[onBehalfOf].setBorrowing(reserve.id, false);
}
if (amount > paybackAmount) {
bool isFirstDeposit =
IXToken(xToken).mint(
onBehalfOf,
amount.sub(paybackAmount),
reserve.liquidityIndex
);
if (isFirstDeposit) {
_usersConfig[onBehalfOf].setUsingAsCollateral(
reserve.id,
true
);
emit ReserveUsedAsCollateralEnabled(asset, onBehalfOf);
}
emit Deposit(
asset,
msg.sender,
onBehalfOf,
amount.sub(paybackAmount)
);
}
} else {
bool isFirstDeposit =
IXToken(xToken).mint(
onBehalfOf,
amount,
reserve.liquidityIndex
);
if (isFirstDeposit) {
_usersConfig[onBehalfOf].setUsingAsCollateral(reserve.id, true);
emit ReserveUsedAsCollateralEnabled(asset, onBehalfOf);
}
emit Deposit(asset, msg.sender, onBehalfOf, amount);
}
}
function withdraw(
address asset,
uint256 amount,
address to
) external override whenNotPaused returns (uint256) {
DataTypes.ReserveData storage reserve = _reserves[asset];
address xToken = reserve.xTokenAddress;
uint256 userBalance = IXToken(xToken).balanceOf(msg.sender);
uint256 amountToWithdraw = amount;
if (amount == type(uint256).max) {
amountToWithdraw = userBalance;
}
ValidationLogic.validateWithdraw(
asset,
amountToWithdraw,
userBalance,
_reserves,
_usersConfig[msg.sender],
_reservesList,
_reservesCount,
_addressesProvider.getPriceOracle()
);
reserve.updateState();
reserve.updateInterestRates(asset, xToken, 0, amountToWithdraw);
if (amountToWithdraw == userBalance) {
_usersConfig[msg.sender].setUsingAsCollateral(reserve.id, false);
emit ReserveUsedAsCollateralDisabled(asset, msg.sender);
}
IXToken(xToken).burn(
msg.sender,
to,
amountToWithdraw,
reserve.liquidityIndex
);
emit Withdraw(asset, msg.sender, to, amountToWithdraw);
return amountToWithdraw;
}
function borrow(
address asset,
uint256 amount,
address onBehalfOf
) external override whenNotPaused {
DataTypes.ReserveData storage reserve = _reserves[asset];
_executeBorrow(
ExecuteBorrowParams(
asset,
msg.sender,
onBehalfOf,
amount,
reserve.xTokenAddress,
true
)
);
}
function swapTokensForTokens(
uint256 amountIn,
uint256 amountOut,
address[] calldata path,
bool isExactIn,
bool isUni
) external override whenNotPaused {
_beforeSwap(path[0], amountIn);
IUniswapV2Router02 swaper = isUni ? uniswaper : sushiSwaper;
IERC20(path[0]).safeApprove(address(swaper), 0);
IERC20(path[0]).safeApprove(address(swaper), amountIn);
uint256[] memory awards;
if (isExactIn) {
awards = swaper.swapExactTokensForTokens(
amountIn,
amountOut,
path,
address(this),
block.timestamp
);
} else {
awards = swaper.swapTokensForExactTokens(
amountOut,
amountIn,
path,
address(this),
block.timestamp
);
}
reDeposit(path[path.length - 1], awards[awards.length - 1], msg.sender);
if (amountIn > awards[0]) {
reDeposit(path[0], amountIn.sub(awards[0]), msg.sender);
}
ValidationLogic.validateSwap(
msg.sender,
_reserves,
_usersConfig[msg.sender],
_reservesList,
_reservesCount,
_addressesProvider.getPriceOracle()
);
ISwapMining(_addressesProvider.getSwapMiner()).swapMint(
msg.sender,
path[0],
path[path.length - 1],
awards[awards.length - 1]
);
emit Swap(
msg.sender,
path[0],
path[path.length - 1],
awards[0],
awards[awards.length - 1]
);
}
function swapTokensForClosePosition(
uint256 amountIn,
uint256 amountOut,
address[] calldata path,
bool isExactIn,
bool isUni
) external override whenNotPaused {
_beforeClose(path[0], amountIn);
IUniswapV2Router02 swaper = isUni ? uniswaper : sushiSwaper;
IERC20(path[0]).safeApprove(address(swaper), 0);
IERC20(path[0]).safeApprove(address(swaper), amountIn);
uint256[] memory awards;
if (isExactIn) {
awards = swaper.swapExactTokensForTokens(
amountIn,
amountOut,
path,
address(this),
block.timestamp
);
} else {
awards = swaper.swapTokensForExactTokens(
amountOut,
amountIn,
path,
address(this),
block.timestamp
);
}
reDeposit(path[path.length - 1], awards[awards.length - 1], msg.sender);
if (amountIn > awards[0]) {
reDeposit(path[0], amountIn.sub(awards[0]), msg.sender);
}
ValidationLogic.validateSwap(
msg.sender,
_reserves,
_usersConfig[msg.sender],
_reservesList,
_reservesCount,
_addressesProvider.getPriceOracle()
);
ISwapMining(_addressesProvider.getSwapMiner()).swapMint(
msg.sender,
path[0],
path[path.length - 1],
awards[awards.length - 1]
);
emit Swap(
msg.sender,
path[0],
path[path.length - 1],
awards[0],
awards[awards.length - 1]
);
}
function swapWithAggregation(
address _reserve,
uint256 amount,
address _reserveTo,
bytes memory codes,
uint256 gas,
uint8 swapType
) external {
_beforeSwap(_reserve, amount);
IERC20(_reserve).safeApprove(inchor, 0);
IERC20(_reserve).safeApprove(inchor, amount);
(bool success, bytes memory result) = inchor.call{gas: gas}(codes);
require(success, "swap failed");
uint256 award;
if (swapType == 1) {
award = abi.decode(result, (uint256));
}
if (swapType == 2) {
(award, ) = abi.decode(result, (uint256, uint256));
}
if (swapType == 3) {
(award, , ) = abi.decode(result, (uint256, uint256, uint256));
}
reDeposit(_reserveTo, award, msg.sender);
ValidationLogic.validateSwap(
msg.sender,
_reserves,
_usersConfig[msg.sender],
_reservesList,
_reservesCount,
_addressesProvider.getPriceOracle()
);
ISwapMining(_addressesProvider.getSwapMiner()).swapMint(
msg.sender,
_reserve,
_reserveTo,
award
);
emit Swap(msg.sender, _reserve, _reserveTo, amount, award);
}
function closeWithAggregation(
address _reserve,
uint256 amountIn,
address _reserveTo,
bytes memory codes,
uint256 gas,
uint8 swapType
) external {
_beforeClose(_reserve, amountIn);
IERC20(_reserve).safeApprove(inchor, 0);
IERC20(_reserve).safeApprove(inchor, amountIn);
(bool success, bytes memory result) = inchor.call{gas: gas}(codes);
require(success, "swap failed");
uint256 award;
if (swapType == 1) {
award = abi.decode(result, (uint256));
}
if (swapType == 2) {
(award, ) = abi.decode(result, (uint256, uint256));
}
if (swapType == 3) {
(award, , ) = abi.decode(result, (uint256, uint256, uint256));
}
reDeposit(_reserveTo, award, msg.sender);
ValidationLogic.validateSwap(
msg.sender,
_reserves,
_usersConfig[msg.sender],
_reservesList,
_reservesCount,
_addressesProvider.getPriceOracle()
);
ISwapMining(_addressesProvider.getSwapMiner()).swapMint(
msg.sender,
_reserve,
_reserveTo,
award
);
emit Swap(msg.sender, _reserve, _reserveTo, amountIn, award);
}
function _beforeClose(address _reserve, uint256 amountIn) private {
DataTypes.ReserveData storage reserve = _reserves[_reserve];
ValidationLogic.validateDeposit(reserve, amountIn);
reserve.updateState();
uint256 userBalance =
IXToken(reserve.xTokenAddress).balanceOf(msg.sender);
reserve.updateInterestRates(
_reserve,
reserve.xTokenAddress,
0,
amountIn
);
IXToken(reserve.xTokenAddress).burn(
msg.sender,
address(this),
amountIn,
reserve.liquidityIndex
);
if (amountIn == userBalance) {
_usersConfig[msg.sender].setUsingAsCollateral(reserve.id, false);
emit ReserveUsedAsCollateralDisabled(_reserve, msg.sender);
}
}
function _beforeSwap(address _reserve, uint256 amountIn) private {
DataTypes.ReserveData storage reserve = _reserves[_reserve];
ValidationLogic.validateDeposit(reserve, amountIn);
DataTypes.UserConfigurationMap storage userConfig =
_usersConfig[msg.sender];
reserve.updateState();
bool isFirstBorrowing = false;
isFirstBorrowing = IVariableDebtToken(reserve.variableDebtTokenAddress)
.mint(
msg.sender,
msg.sender,
amountIn,
reserve.variableBorrowIndex
);
emit Borrow(
_reserve,
msg.sender,
msg.sender,
amountIn,
reserve.currentVariableBorrowRate
);
if (isFirstBorrowing) {
userConfig.setBorrowing(reserve.id, true);
}
reserve.updateInterestRates(
_reserve,
reserve.xTokenAddress,
0,
amountIn
);
IXToken(reserve.xTokenAddress).transferUnderlyingTo(
address(this),
amountIn
);
}
function repay(
address asset,
uint256 amount,
address onBehalfOf
) external override whenNotPaused returns (uint256) {
DataTypes.ReserveData storage reserve = _reserves[asset];
uint256 variableDebt = Helpers.getUserCurrentDebt(onBehalfOf, reserve);
address xToken = reserve.xTokenAddress;
uint256 userBalance = IERC20(xToken).balanceOf(msg.sender);
ValidationLogic.validateRepay(
reserve,
amount,
onBehalfOf,
variableDebt,
userBalance
);
uint256 paybackAmount = variableDebt;
if (amount < paybackAmount) {
paybackAmount = amount;
}
reserve.updateState();
IVariableDebtToken(reserve.variableDebtTokenAddress).burn(
onBehalfOf,
paybackAmount,
reserve.variableBorrowIndex
);
reserve.updateInterestRates(asset, xToken, 0, 0);
if (variableDebt.sub(paybackAmount) == 0) {
_usersConfig[onBehalfOf].setBorrowing(reserve.id, false);
}
if (paybackAmount == userBalance) {
_usersConfig[msg.sender].setUsingAsCollateral(reserve.id, false);
emit ReserveUsedAsCollateralDisabled(asset, msg.sender);
}
IXToken(xToken).burn(
msg.sender,
xToken,
paybackAmount,
reserve.liquidityIndex
);
emit Repay(asset, onBehalfOf, msg.sender, paybackAmount);
return paybackAmount;
}
function setUserUseReserveAsCollateral(address asset, bool useAsCollateral)
external
override
whenNotPaused
{
DataTypes.ReserveData storage reserve = _reserves[asset];
ValidationLogic.validateSetUseReserveAsCollateral(
reserve,
asset,
useAsCollateral,
_reserves,
_usersConfig[msg.sender],
_reservesList,
_reservesCount,
_addressesProvider.getPriceOracle()
);
_usersConfig[msg.sender].setUsingAsCollateral(
reserve.id,
useAsCollateral
);
if (useAsCollateral) {
emit ReserveUsedAsCollateralEnabled(asset, msg.sender);
} else {
emit ReserveUsedAsCollateralDisabled(asset, msg.sender);
}
}
struct LiquidationCallLocalVars {
uint256 variableDebt;
uint256 userBalance;
uint256 healthFactor;
uint256 maxCollateralToLiquidate;
uint256 collateralToSell;
uint256 liquidatorPreviousXTokenBalance;
}
function liquidationCall(
address collateralAsset,
address debtAsset,
address user,
uint256 debtToCover
) external override whenNotPaused {
LiquidationCallLocalVars memory vars;
DataTypes.ReserveData storage collateralReserve =
_reserves[collateralAsset];
DataTypes.ReserveData storage debtReserve = _reserves[debtAsset];
DataTypes.UserConfigurationMap storage userConfig = _usersConfig[user];
vars.variableDebt = Helpers.getUserCurrentDebt(user, debtReserve).div(
2
);
(, , , , vars.healthFactor) = GenericLogic.calculateUserAccountData(
user,
_reserves,
_usersConfig[user],
_reservesList,
_reservesCount,
_addressesProvider.getPriceOracle()
);
ValidationLogic.validateLiquidation(
collateralReserve,
debtReserve,
userConfig,
vars.healthFactor,
vars.variableDebt
);
vars.variableDebt = vars.variableDebt > debtToCover
? debtToCover
: vars.variableDebt;
vars.userBalance = IERC20(collateralReserve.xTokenAddress).balanceOf(
user
);
(vars.maxCollateralToLiquidate, vars.collateralToSell) = GenericLogic
.calculateAvailableCollateralToLiquidate(
collateralReserve,
debtReserve,
collateralAsset,
debtAsset,
vars.variableDebt,
vars.userBalance,
_addressesProvider.getPriceOracle()
);
collateralReserve.updateState();
vars.liquidatorPreviousXTokenBalance = IERC20(
collateralReserve
.xTokenAddress
)
.balanceOf(msg.sender);
IXToken(collateralReserve.xTokenAddress).transferOnLiquidation(
user,
msg.sender,
(vars.maxCollateralToLiquidate.sub(vars.collateralToSell))
);
if (vars.liquidatorPreviousXTokenBalance == 0) {
DataTypes.UserConfigurationMap storage liquidatorConfig =
_usersConfig[msg.sender];
liquidatorConfig.setUsingAsCollateral(collateralReserve.id, true);
emit ReserveUsedAsCollateralEnabled(collateralAsset, msg.sender);
}
if (vars.maxCollateralToLiquidate == vars.userBalance) {
userConfig.setUsingAsCollateral(collateralReserve.id, false);
emit ReserveUsedAsCollateralDisabled(collateralAsset, user);
}
if(collateralAsset == debtAsset) {
IVariableDebtToken(collateralReserve.variableDebtTokenAddress).burn(
user,
vars.collateralToSell,
collateralReserve.variableBorrowIndex
);
collateralReserve.updateInterestRates(collateralAsset, collateralReserve.xTokenAddress, 0, 0);
IXToken(collateralReserve.xTokenAddress).burn(
user,
collateralReserve.xTokenAddress,
vars.collateralToSell,
collateralReserve.liquidityIndex
);
emit LiquidationCall(
collateralAsset,
debtAsset,
user,
vars.collateralToSell,
vars.collateralToSell,
msg.sender
);
return;
}
collateralReserve.updateInterestRates(
collateralAsset,
collateralReserve.xTokenAddress,
0,
vars.collateralToSell
);
IXToken(collateralReserve.xTokenAddress).burn(
user,
address(this),
vars.collateralToSell,
collateralReserve.liquidityIndex
);
IERC20(collateralAsset).safeApprove(address(uniswaper), 0);
IERC20(collateralAsset).safeApprove(
address(uniswaper),
vars.collateralToSell
);
address[] memory path;
if (collateralAsset != wethAddress && debtAsset != wethAddress) {
path = new address[](3);
path[0] = collateralAsset;
path[1] = wethAddress;
path[2] = debtAsset;
} else {
path = new address[](2);
path[0] = collateralAsset;
path[1] = debtAsset;
}
uint256[] memory awards =
uniswaper.swapExactTokensForTokens(
vars.collateralToSell,
vars.variableDebt.mul(97).div(100),
path,
address(this),
block.timestamp
);
reDeposit(debtAsset, awards[awards.length - 1], user);
emit LiquidationCall(
collateralAsset,
debtAsset,
user,
awards[awards.length - 1],
vars.collateralToSell,
msg.sender
);
}
function getReserveData(address asset)
external
view
override
returns (DataTypes.ReserveData memory)
{
return _reserves[asset];
}
function getUserAccountData(address user)
external
view
override
returns (
uint256 totalCollateralETH,
uint256 totalDebtETH,
uint256 availableBorrowsETH,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
)
{
(
totalCollateralETH,
totalDebtETH,
ltv,
currentLiquidationThreshold,
healthFactor
) = GenericLogic.calculateUserAccountData(
user,
_reserves,
_usersConfig[user],
_reservesList,
_reservesCount,
_addressesProvider.getPriceOracle()
);
availableBorrowsETH = GenericLogic.calculateAvailableBorrowsETH(
totalCollateralETH,
totalDebtETH,
ltv
);
}
function getConfiguration(address asset)
external
view
override
returns (DataTypes.ReserveConfigurationMap memory)
{
return _reserves[asset].configuration;
}
function getUserConfiguration(address user)
external
view
override
returns (DataTypes.UserConfigurationMap memory)
{
return _usersConfig[user];
}
function getReserveNormalizedIncome(address asset)
external
view
virtual
override
returns (uint256)
{
return _reserves[asset].getNormalizedIncome();
}
function getReserveNormalizedVariableDebt(address asset)
external
view
override
returns (uint256)
{
return _reserves[asset].getNormalizedDebt();
}
function paused() external view override returns (bool) {
return _paused;
}
function getReservesList()
external
view
override
returns (address[] memory)
{
address[] memory _activeReserves = new address[](_reservesCount);
for (uint256 i = 0; i < _reservesCount; i++) {
_activeReserves[i] = _reservesList[i];
}
return _activeReserves;
}
function getAddressesProvider()
external
view
override
returns (IMarginPoolAddressesProvider)
{
return _addressesProvider;
}
function finalizeTransfer(
address asset,
address from,
address to,
uint256 amount,
uint256 balanceFromBefore,
uint256 balanceToBefore
) external override whenNotPaused {
require(
msg.sender == _reserves[asset].xTokenAddress,
Errors.MP_CALLER_MUST_BE_AN_XTOKEN
);
ValidationLogic.validateTransfer(
from,
_reserves,
_usersConfig[from],
_reservesList,
_reservesCount,
_addressesProvider.getPriceOracle()
);
uint256 reserveId = _reserves[asset].id;
if (from != to) {
if (balanceFromBefore.sub(amount) == 0) {
DataTypes.UserConfigurationMap storage fromConfig =
_usersConfig[from];
fromConfig.setUsingAsCollateral(reserveId, false);
emit ReserveUsedAsCollateralDisabled(asset, from);
}
if (balanceToBefore == 0 && amount != 0) {
DataTypes.UserConfigurationMap storage toConfig =
_usersConfig[to];
toConfig.setUsingAsCollateral(reserveId, true);
emit ReserveUsedAsCollateralEnabled(asset, to);
}
}
}
function initReserve(
address asset,
address xTokenAddress,
address variableDebtAddress,
address interestRateStrategyAddress
) external override onlyMarginPoolConfigurator {
require(Address.isContract(asset), Errors.MP_NOT_CONTRACT);
_reserves[asset].init(
xTokenAddress,
variableDebtAddress,
interestRateStrategyAddress
);
_addReserveToList(asset);
}
function setReserveInterestRateStrategyAddress(
address asset,
address rateStrategyAddress
) external override onlyMarginPoolConfigurator {
_reserves[asset].interestRateStrategyAddress = rateStrategyAddress;
}
function setConfiguration(address asset, uint256 configuration)
external
override
onlyMarginPoolConfigurator
{
_reserves[asset].configuration.data = configuration;
}
function setPause(bool val) external override onlyMarginPoolConfigurator {
_paused = val;
if (_paused) {
emit Paused();
} else {
emit Unpaused();
}
}
struct ExecuteBorrowParams {
address asset;
address user;
address onBehalfOf;
uint256 amount;
address xTokenAddress;
bool releaseUnderlying;
}
function _executeBorrow(ExecuteBorrowParams memory vars) internal {
DataTypes.ReserveData storage reserve = _reserves[vars.asset];
DataTypes.UserConfigurationMap storage userConfig =
_usersConfig[vars.onBehalfOf];
address oracle = _addressesProvider.getPriceOracle();
uint256 amountInETH =
IPriceOracleGetter(oracle)
.getAssetPrice(vars.asset)
.mul(vars.amount)
.div(10**reserve.configuration.getDecimals());
ValidationLogic.validateBorrow(
reserve,
vars.onBehalfOf,
vars.amount,
amountInETH,
_reserves,
userConfig,
_reservesList,
_reservesCount,
oracle
);
reserve.updateState();
bool isFirstBorrowing = false;
isFirstBorrowing = IVariableDebtToken(reserve.variableDebtTokenAddress)
.mint(
vars.user,
vars.onBehalfOf,
vars.amount,
reserve.variableBorrowIndex
);
if (isFirstBorrowing) {
userConfig.setBorrowing(reserve.id, true);
}
reserve.updateInterestRates(
vars.asset,
vars.xTokenAddress,
0,
vars.releaseUnderlying ? vars.amount : 0
);
if (vars.releaseUnderlying) {
IXToken(vars.xTokenAddress).transferUnderlyingTo(
vars.user,
vars.amount
);
}
emit Borrow(
vars.asset,
vars.user,
vars.onBehalfOf,
vars.amount,
reserve.currentVariableBorrowRate
);
}
function _addReserveToList(address asset) internal {
uint256 reservesCount = _reservesCount;
require(
reservesCount < MAX_NUMBER_RESERVES,
Errors.MP_NO_MORE_RESERVES_ALLOWED
);
bool reserveAlreadyAdded =
_reserves[asset].id != 0 || _reservesList[0] == asset;
if (!reserveAlreadyAdded) {
_reserves[asset].id = uint8(reservesCount);
_reservesList[reservesCount] = asset;
_reservesCount = reservesCount + 1;
}
}
}
文件 41 的 64:MarginPoolAddressesProvider.sol
pragma solidity 0.6.12;
import {Ownable} from './Ownable.sol';
import './Address.sol';
import {InitializableImmutableAdminUpgradeabilityProxy} from './InitializableImmutableAdminUpgradeabilityProxy.sol';
import {IMarginPoolAddressesProvider} from './IMarginPoolAddressesProvider.sol';
contract MarginPoolAddressesProvider is Ownable, IMarginPoolAddressesProvider {
mapping(bytes32 => address) private _addresses;
bytes32 private constant MARGIN_POOL = 'MARGIN_POOL';
bytes32 private constant MARGIN_POOL_CONFIGURATOR = 'MARGIN_POOL_CONFIGURATOR';
bytes32 private constant POOL_ADMIN = 'POOL_ADMIN';
bytes32 private constant EMERGENCY_ADMIN = 'EMERGENCY_ADMIN';
bytes32 private constant PRICE_ORACLE = 'PRICE_ORACLE';
bytes32 private constant LENDING_RATE_ORACLE = 'LENDING_RATE_ORACLE';
bytes32 private constant LEVER_TOKEN = 'LEVER_TOKEN';
bytes32 private constant TREASURY_ADDRESS = 'TREASURY_ADDRESS';
bytes32 private constant REWARDS_DISTRIBUTION = 'REWARDS_DISTRIBUTION';
bytes32 private constant SWAP_MINER = 'SWAP_MINER';
bytes32 private constant ORDER_BOOK = 'ORDER_BOOK';
constructor() public {
}
function setAddressAsProxy(bytes32 id, address implementationAddress)
external
override
onlyOwner
{
_updateImpl(id, implementationAddress);
emit AddressSet(id, implementationAddress, true);
}
function setAddress(bytes32 id, address newAddress) external override onlyOwner {
_addresses[id] = newAddress;
emit AddressSet(id, newAddress, false);
}
function getAddress(bytes32 id) public view override returns (address) {
return _addresses[id];
}
function getMarginPool() external view override returns (address) {
return getAddress(MARGIN_POOL);
}
function setMarginPoolImpl(address pool,address UniswapRouter, address SushiswapRouter,address _weth) external override onlyOwner {
_updatePoolImpl(MARGIN_POOL, pool, UniswapRouter,SushiswapRouter, _weth);
emit MarginPoolUpdated(pool);
}
function getMarginPoolConfigurator() external view override returns (address) {
return getAddress(MARGIN_POOL_CONFIGURATOR);
}
function setMarginPoolConfiguratorImpl(address configurator) external override onlyOwner {
_updateImpl(MARGIN_POOL_CONFIGURATOR, configurator);
emit MarginPoolConfiguratorUpdated(configurator);
}
function getPoolAdmin() external view override returns (address) {
return getAddress(POOL_ADMIN);
}
function setPoolAdmin(address admin) external override onlyOwner {
_addresses[POOL_ADMIN] = admin;
emit ConfigurationAdminUpdated(admin);
}
function getEmergencyAdmin() external view override returns (address) {
return getAddress(EMERGENCY_ADMIN);
}
function setEmergencyAdmin(address emergencyAdmin) external override onlyOwner {
_addresses[EMERGENCY_ADMIN] = emergencyAdmin;
emit EmergencyAdminUpdated(emergencyAdmin);
}
function getPriceOracle() external view override returns (address) {
return getAddress(PRICE_ORACLE);
}
function setPriceOracle(address priceOracle) external override onlyOwner {
_addresses[PRICE_ORACLE] = priceOracle;
emit PriceOracleUpdated(priceOracle);
}
function getLeverToken() external view override returns (address) {
return getAddress(LEVER_TOKEN);
}
function setLeverToken(address lever) external override onlyOwner {
_addresses[LEVER_TOKEN] = lever;
emit LeverTokenUpdated(lever);
}
function getTreasuryAddress() external view override returns (address) {
return getAddress(TREASURY_ADDRESS);
}
function setTreasuryAddress(address treasuryAddress) external override onlyOwner {
_addresses[TREASURY_ADDRESS] = treasuryAddress;
emit TreasuryAddressUpdated(treasuryAddress);
}
function getRewardsDistribution() external view override returns (address) {
return getAddress(REWARDS_DISTRIBUTION);
}
function setRewardsDistribution(address rewardsDistribution) external override onlyOwner {
_addresses[REWARDS_DISTRIBUTION] = rewardsDistribution;
emit RewardsDistributionUpdated(rewardsDistribution);
}
function getOrderBook() external view override returns (address) {
return getAddress(ORDER_BOOK);
}
function setOrderBookImpl(address orderBook, address UniswapRouter, address _weth) external override onlyOwner {
_updateImpl(ORDER_BOOK, orderBook, UniswapRouter, _weth);
emit OrderBookUpdated(orderBook);
}
function getSwapMiner() external view override returns (address) {
return getAddress(SWAP_MINER);
}
function setSwapMinerImpl(address swapMiner, address UniswapRouter, address _uniswapLevPairToken, address LeverUsdOracle) external override onlyOwner {
_updateSwapMinerImpl(SWAP_MINER, swapMiner, UniswapRouter, _uniswapLevPairToken, LeverUsdOracle);
emit SwapMinerUpdated(swapMiner);
}
function _updateImpl(bytes32 id, address newAddress) internal {
address payable proxyAddress = payable(_addresses[id]);
InitializableImmutableAdminUpgradeabilityProxy proxy =
InitializableImmutableAdminUpgradeabilityProxy(proxyAddress);
bytes memory params = abi.encodeWithSignature('initialize(address)', address(this));
if (proxyAddress == address(0)) {
proxy = new InitializableImmutableAdminUpgradeabilityProxy(address(this));
proxy.initialize(newAddress, params);
_addresses[id] = address(proxy);
emit ProxyCreated(id, address(proxy));
} else {
proxy.upgradeToAndCall(newAddress, params);
}
}
function _updateImpl(bytes32 id, address newAddress, address UniswapRouter,address _weth) internal {
address payable proxyAddress = payable(_addresses[id]);
InitializableImmutableAdminUpgradeabilityProxy proxy =
InitializableImmutableAdminUpgradeabilityProxy(proxyAddress);
bytes memory params = abi.encodeWithSignature('initialize(address,address,address)', address(this), UniswapRouter,_weth);
if (proxyAddress == address(0)) {
proxy = new InitializableImmutableAdminUpgradeabilityProxy(address(this));
proxy.initialize(newAddress, params);
_addresses[id] = address(proxy);
emit ProxyCreated(id, address(proxy));
} else {
proxy.upgradeToAndCall(newAddress, params);
}
}
function _updatePoolImpl(bytes32 id, address newAddress, address UniswapRouter, address SushiswapRouter,address _weth) internal {
address payable proxyAddress = payable(_addresses[id]);
InitializableImmutableAdminUpgradeabilityProxy proxy =
InitializableImmutableAdminUpgradeabilityProxy(proxyAddress);
bytes memory params = abi.encodeWithSignature('initialize(address,address,address,address)', address(this), UniswapRouter,SushiswapRouter, _weth);
if (proxyAddress == address(0)) {
proxy = new InitializableImmutableAdminUpgradeabilityProxy(address(this));
proxy.initialize(newAddress, params);
_addresses[id] = address(proxy);
emit ProxyCreated(id, address(proxy));
} else {
proxy.upgradeToAndCall(newAddress, params);
}
}
function _updateSwapMinerImpl(bytes32 id, address newAddress, address UniswapRouter,address _uniswapLevPairToken,address LeverUsdOracle) internal {
address payable proxyAddress = payable(_addresses[id]);
InitializableImmutableAdminUpgradeabilityProxy proxy =
InitializableImmutableAdminUpgradeabilityProxy(proxyAddress);
bytes memory params = abi.encodeWithSignature('initialize(address,address,address,address)', address(this), UniswapRouter,_uniswapLevPairToken,LeverUsdOracle);
if (proxyAddress == address(0)) {
proxy = new InitializableImmutableAdminUpgradeabilityProxy(address(this));
proxy.initialize(newAddress, params);
_addresses[id] = address(proxy);
emit ProxyCreated(id, address(proxy));
} else {
proxy.upgradeToAndCall(newAddress, params);
}
}
}
文件 42 的 64:MarginPoolConfigurator.sol
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import {SafeMath} from './SafeMath.sol';
import {VersionedInitializable} from './VersionedInitializable.sol';
import {ReserveConfiguration} from './ReserveConfiguration.sol';
import {IMarginPoolAddressesProvider} from './IMarginPoolAddressesProvider.sol';
import {IMarginPool} from './IMarginPool.sol';
import {ITokenConfiguration} from './ITokenConfiguration.sol';
import {IERC20Detailed} from './IERC20Detailed.sol';
import {Errors} from './Errors.sol';
import {PercentageMath} from './PercentageMath.sol';
import {DataTypes} from './DataTypes.sol';
contract MarginPoolConfigurator is VersionedInitializable {
using SafeMath for uint256;
using PercentageMath for uint256;
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
event ReserveInitialized(
address indexed asset,
address indexed xToken,
address variableDebtToken,
address interestRateStrategyAddress
);
event BorrowingDisabledOnReserve(address indexed asset);
event CollateralConfigurationChanged(
address indexed asset,
uint256 ltv,
uint256 liquidationThreshold,
uint256 liquidationBonus
);
event ReserveActivated(address indexed asset);
event ReserveDeactivated(address indexed asset);
event ReserveFrozen(address indexed asset);
event ReserveUnfrozen(address indexed asset);
event ReserveFactorChanged(address indexed asset, uint256 factor);
event ReserveDecimalsChanged(address indexed asset, uint256 decimals);
event ReserveInterestRateStrategyChanged(address indexed asset, address strategy);
event XTokenUpgraded(
address indexed asset,
address indexed proxy,
address indexed implementation
);
event VariableDebtTokenUpgraded(
address indexed asset,
address indexed proxy,
address indexed implementation
);
IMarginPoolAddressesProvider public addressesProvider;
IMarginPool public pool;
modifier onlyPoolAdmin {
require(addressesProvider.getPoolAdmin() == msg.sender, Errors.CALLER_NOT_POOL_ADMIN);
_;
}
modifier onlyEmergencyAdmin {
require(
addressesProvider.getEmergencyAdmin() == msg.sender,
Errors.MPC_CALLER_NOT_EMERGENCY_ADMIN
);
_;
}
uint256 internal constant CONFIGURATOR_REVISION = 0x1;
function getRevision() internal pure override returns (uint256) {
return CONFIGURATOR_REVISION;
}
function initialize(IMarginPoolAddressesProvider provider) public initializer {
addressesProvider = provider;
pool = IMarginPool(addressesProvider.getMarginPool());
}
function initReserve(
address xTokenImpl,
address variableDebtTokenImpl,
uint8 underlyingAssetDecimals,
address interestRateStrategyAddress
) public onlyPoolAdmin {
address asset = ITokenConfiguration(xTokenImpl).UNDERLYING_ASSET_ADDRESS();
require(
address(pool) == ITokenConfiguration(xTokenImpl).POOL(),
Errors.MPC_INVALID_XTOKEN_POOL_ADDRESS
);
require(
address(pool) == ITokenConfiguration(variableDebtTokenImpl).POOL(),
Errors.MPC_INVALID_VARIABLE_DEBT_TOKEN_POOL_ADDRESS
);
require(
asset == ITokenConfiguration(variableDebtTokenImpl).UNDERLYING_ASSET_ADDRESS(),
Errors.MPC_INVALID_VARIABLE_DEBT_TOKEN_UNDERLYING_ADDRESS
);
pool.initReserve(
asset,
xTokenImpl,
variableDebtTokenImpl,
interestRateStrategyAddress
);
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
currentConfig.setDecimals(underlyingAssetDecimals);
currentConfig.setActive(true);
currentConfig.setFrozen(false);
pool.setConfiguration(asset, currentConfig.data);
emit ReserveInitialized(
asset,
xTokenImpl,
variableDebtTokenImpl,
interestRateStrategyAddress
);
}
function enableBorrowingOnReserve(address asset)
external
onlyPoolAdmin
{
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
currentConfig.setBorrowingEnabled(true);
pool.setConfiguration(asset, currentConfig.data);
}
function disableBorrowingOnReserve(address asset) external onlyPoolAdmin {
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
currentConfig.setBorrowingEnabled(false);
pool.setConfiguration(asset, currentConfig.data);
emit BorrowingDisabledOnReserve(asset);
}
function configureReserveAsCollateral(
address asset,
uint256 ltv,
uint256 liquidationThreshold,
uint256 liquidationBonus
) external onlyPoolAdmin {
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
require(ltv <= liquidationThreshold, Errors.MPC_INVALID_CONFIGURATION);
if (liquidationThreshold != 0) {
require(
liquidationBonus > PercentageMath.PERCENTAGE_FACTOR,
Errors.MPC_INVALID_CONFIGURATION
);
require(
liquidationThreshold.percentMul(liquidationBonus) <= PercentageMath.PERCENTAGE_FACTOR,
Errors.MPC_INVALID_CONFIGURATION
);
} else {
require(liquidationBonus == 0, Errors.MPC_INVALID_CONFIGURATION);
_checkNoLiquidity(asset);
}
currentConfig.setLtv(ltv);
currentConfig.setLiquidationThreshold(liquidationThreshold);
currentConfig.setLiquidationBonus(liquidationBonus);
pool.setConfiguration(asset, currentConfig.data);
emit CollateralConfigurationChanged(asset, ltv, liquidationThreshold, liquidationBonus);
}
function activateReserve(address asset) external onlyPoolAdmin {
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
currentConfig.setActive(true);
pool.setConfiguration(asset, currentConfig.data);
emit ReserveActivated(asset);
}
function deactivateReserve(address asset) external onlyPoolAdmin {
_checkNoLiquidity(asset);
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
currentConfig.setActive(false);
pool.setConfiguration(asset, currentConfig.data);
emit ReserveDeactivated(asset);
}
function freezeReserve(address asset) external onlyPoolAdmin {
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
currentConfig.setFrozen(true);
pool.setConfiguration(asset, currentConfig.data);
emit ReserveFrozen(asset);
}
function unfreezeReserve(address asset) external onlyPoolAdmin {
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
currentConfig.setFrozen(false);
pool.setConfiguration(asset, currentConfig.data);
emit ReserveUnfrozen(asset);
}
function setReserveFactor(address asset, uint256 reserveFactor) external onlyPoolAdmin {
DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset);
currentConfig.setReserveFactor(reserveFactor);
pool.setConfiguration(asset, currentConfig.data);
emit ReserveFactorChanged(asset, reserveFactor);
}
function setReserveInterestRateStrategyAddress(address asset, address rateStrategyAddress)
external
onlyPoolAdmin
{
pool.setReserveInterestRateStrategyAddress(asset, rateStrategyAddress);
emit ReserveInterestRateStrategyChanged(asset, rateStrategyAddress);
}
function setPoolPause(bool val) external onlyEmergencyAdmin {
pool.setPause(val);
}
function _checkNoLiquidity(address asset) internal view {
DataTypes.ReserveData memory reserveData = pool.getReserveData(asset);
uint256 availableLiquidity = IERC20Detailed(asset).balanceOf(reserveData.xTokenAddress);
require(
availableLiquidity == 0 && reserveData.currentLiquidityRate == 0,
Errors.MPC_RESERVE_LIQUIDITY_NOT_0
);
}
}
文件 43 的 64:MarginPoolStorage.sol
pragma solidity 0.6.12;
import {UserConfiguration} from './UserConfiguration.sol';
import {ReserveConfiguration} from './ReserveConfiguration.sol';
import {ReserveLogic} from './ReserveLogic.sol';
import {IMarginPoolAddressesProvider} from './IMarginPoolAddressesProvider.sol';
import {DataTypes} from './DataTypes.sol';
contract MarginPoolStorage {
using ReserveLogic for DataTypes.ReserveData;
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
using UserConfiguration for DataTypes.UserConfigurationMap;
IMarginPoolAddressesProvider internal _addressesProvider;
mapping(address => DataTypes.ReserveData) internal _reserves;
mapping(address => DataTypes.UserConfigurationMap) internal _usersConfig;
mapping(uint256 => address) internal _reservesList;
uint256 internal _reservesCount;
bool internal _paused;
}
文件 44 的 64:MathUtils.sol
pragma solidity 0.6.12;
import {SafeMath} from './SafeMath.sol';
import {WadRayMath} from './WadRayMath.sol';
library MathUtils {
using SafeMath for uint256;
using WadRayMath for uint256;
uint256 internal constant SECONDS_PER_YEAR = 365 days;
function calculateLinearInterest(uint256 rate, uint40 lastUpdateTimestamp)
internal
view
returns (uint256)
{
uint256 timeDifference = block.timestamp.sub(uint256(lastUpdateTimestamp));
return (rate.mul(timeDifference) / SECONDS_PER_YEAR).add(WadRayMath.ray());
}
function calculateCompoundedInterest(
uint256 rate,
uint40 lastUpdateTimestamp,
uint256 currentTimestamp
) internal pure returns (uint256) {
uint256 exp = currentTimestamp.sub(uint256(lastUpdateTimestamp));
if (exp == 0) {
return WadRayMath.ray();
}
uint256 expMinusOne = exp - 1;
uint256 expMinusTwo = exp > 2 ? exp - 2 : 0;
uint256 ratePerSecond = rate / SECONDS_PER_YEAR;
uint256 basePowerTwo = ratePerSecond.rayMul(ratePerSecond);
uint256 basePowerThree = basePowerTwo.rayMul(ratePerSecond);
uint256 secondTerm = exp.mul(expMinusOne).mul(basePowerTwo) / 2;
uint256 thirdTerm = exp.mul(expMinusOne).mul(expMinusTwo).mul(basePowerThree) / 6;
return WadRayMath.ray().add(ratePerSecond.mul(exp)).add(secondTerm).add(thirdTerm);
}
function calculateCompoundedInterest(uint256 rate, uint40 lastUpdateTimestamp)
internal
view
returns (uint256)
{
return calculateCompoundedInterest(rate, lastUpdateTimestamp, block.timestamp);
}
}
文件 45 的 64:Migrations.sol
pragma solidity >=0.4.22 <0.9.0;
contract Migrations {
address public owner = msg.sender;
uint public last_completed_migration;
modifier restricted() {
require(
msg.sender == owner,
"This function is restricted to the contract's owner"
);
_;
}
function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}
}
文件 46 的 64:Ownable.sol
pragma solidity ^0.6.0;
import './Context.sol';
contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() internal {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
function owner() public view returns (address) {
return _owner;
}
modifier onlyOwner() {
require(_owner == _msgSender(), 'Ownable: caller is not the owner');
_;
}
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), 'Ownable: new owner is the zero address');
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
文件 47 的 64:PercentageMath.sol
pragma solidity 0.6.12;
import {Errors} from './Errors.sol';
library PercentageMath {
uint256 constant PERCENTAGE_FACTOR = 1e4;
uint256 constant HALF_PERCENT = PERCENTAGE_FACTOR / 2;
function percentMul(uint256 value, uint256 percentage) internal pure returns (uint256) {
if (value == 0 || percentage == 0) {
return 0;
}
require(
value <= (type(uint256).max - HALF_PERCENT) / percentage,
Errors.MATH_MULTIPLICATION_OVERFLOW
);
return (value * percentage + HALF_PERCENT) / PERCENTAGE_FACTOR;
}
function percentDiv(uint256 value, uint256 percentage) internal pure returns (uint256) {
require(percentage != 0, Errors.MATH_DIVISION_BY_ZERO);
uint256 halfPercentage = percentage / 2;
require(
value <= (type(uint256).max - halfPercentage) / PERCENTAGE_FACTOR,
Errors.MATH_MULTIPLICATION_OVERFLOW
);
return (value * PERCENTAGE_FACTOR + halfPercentage) / percentage;
}
}
文件 48 的 64:PriceOracle.sol
pragma solidity 0.6.12;
import {IPriceOracle} from './IPriceOracle.sol';
contract PriceOracle is IPriceOracle {
mapping(address => uint256) prices;
uint256 ethPriceUsd;
event AssetPriceUpdated(address _asset, uint256 _price, uint256 timestamp);
event EthPriceUpdated(uint256 _price, uint256 timestamp);
function getAssetPrice(address _asset) external view override returns (uint256) {
return prices[_asset];
}
function setAssetPrice(address _asset, uint256 _price) external override {
prices[_asset] = _price;
emit AssetPriceUpdated(_asset, _price, block.timestamp);
}
function getEthUsdPrice() external view returns (uint256) {
return ethPriceUsd;
}
function setEthUsdPrice(uint256 _price) external {
ethPriceUsd = _price;
emit EthPriceUpdated(_price, block.timestamp);
}
}
文件 49 的 64:Proxy.sol
pragma solidity ^0.6.0;
abstract contract Proxy {
fallback() external payable {
_fallback();
}
function _implementation() internal view virtual returns (address);
function _delegate(address implementation) internal {
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
function _willFallback() internal virtual {}
function _fallback() internal {
_willFallback();
_delegate(_implementation());
}
}
文件 50 的 64:ReserveConfiguration.sol
pragma solidity 0.6.12;
import {Errors} from './Errors.sol';
import {DataTypes} from './DataTypes.sol';
library ReserveConfiguration {
uint256 constant LTV_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000;
uint256 constant LIQUIDATION_THRESHOLD_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF;
uint256 constant LIQUIDATION_BONUS_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFF;
uint256 constant DECIMALS_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFF;
uint256 constant ACTIVE_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFF;
uint256 constant FROZEN_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFF;
uint256 constant BORROWING_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFF;
uint256 constant RESERVE_FACTOR_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFF;
uint256 constant LIQUIDATION_THRESHOLD_START_BIT_POSITION = 16;
uint256 constant LIQUIDATION_BONUS_START_BIT_POSITION = 32;
uint256 constant RESERVE_DECIMALS_START_BIT_POSITION = 48;
uint256 constant IS_ACTIVE_START_BIT_POSITION = 56;
uint256 constant IS_FROZEN_START_BIT_POSITION = 57;
uint256 constant BORROWING_ENABLED_START_BIT_POSITION = 58;
uint256 constant RESERVE_FACTOR_START_BIT_POSITION = 64;
uint256 constant MAX_VALID_LTV = 65535;
uint256 constant MAX_VALID_LIQUIDATION_THRESHOLD = 65535;
uint256 constant MAX_VALID_LIQUIDATION_BONUS = 65535;
uint256 constant MAX_VALID_DECIMALS = 255;
uint256 constant MAX_VALID_RESERVE_FACTOR = 65535;
function setLtv(DataTypes.ReserveConfigurationMap memory self, uint256 ltv) internal pure {
require(ltv <= MAX_VALID_LTV, Errors.RC_INVALID_LTV);
self.data = (self.data & LTV_MASK) | ltv;
}
function getLtv(DataTypes.ReserveConfigurationMap storage self) internal view returns (uint256) {
return self.data & ~LTV_MASK;
}
function setLiquidationThreshold(DataTypes.ReserveConfigurationMap memory self, uint256 threshold)
internal
pure
{
require(threshold <= MAX_VALID_LIQUIDATION_THRESHOLD, Errors.RC_INVALID_LIQ_THRESHOLD);
self.data =
(self.data & LIQUIDATION_THRESHOLD_MASK) |
(threshold << LIQUIDATION_THRESHOLD_START_BIT_POSITION);
}
function getLiquidationThreshold(DataTypes.ReserveConfigurationMap storage self) internal view returns (uint256) {
return (self.data & ~LIQUIDATION_THRESHOLD_MASK) >> LIQUIDATION_THRESHOLD_START_BIT_POSITION;
}
function setLiquidationBonus(DataTypes.ReserveConfigurationMap memory self, uint256 bonus)
internal
pure
{
require(bonus <= MAX_VALID_LIQUIDATION_BONUS, Errors.RC_INVALID_LIQ_BONUS);
self.data =
(self.data & LIQUIDATION_BONUS_MASK) |
(bonus << LIQUIDATION_BONUS_START_BIT_POSITION);
}
function getLiquidationBonus(DataTypes.ReserveConfigurationMap storage self)
internal
view
returns (uint256)
{
return (self.data & ~LIQUIDATION_BONUS_MASK) >> LIQUIDATION_BONUS_START_BIT_POSITION;
}
function setDecimals(DataTypes.ReserveConfigurationMap memory self, uint256 decimals)
internal
pure
{
require(decimals <= MAX_VALID_DECIMALS, Errors.RC_INVALID_DECIMALS);
self.data = (self.data & DECIMALS_MASK) | (decimals << RESERVE_DECIMALS_START_BIT_POSITION);
}
function getDecimals(DataTypes.ReserveConfigurationMap storage self)
internal
view
returns (uint256)
{
return (self.data & ~DECIMALS_MASK) >> RESERVE_DECIMALS_START_BIT_POSITION;
}
function setActive(DataTypes.ReserveConfigurationMap memory self, bool active) internal pure {
self.data =
(self.data & ACTIVE_MASK) |
(uint256(active ? 1 : 0) << IS_ACTIVE_START_BIT_POSITION);
}
function getActive(DataTypes.ReserveConfigurationMap storage self) internal view returns (bool) {
return (self.data & ~ACTIVE_MASK) != 0;
}
function setFrozen(DataTypes.ReserveConfigurationMap memory self, bool frozen) internal pure {
self.data =
(self.data & FROZEN_MASK) |
(uint256(frozen ? 1 : 0) << IS_FROZEN_START_BIT_POSITION);
}
function getFrozen(DataTypes.ReserveConfigurationMap storage self) internal view returns (bool) {
return (self.data & ~FROZEN_MASK) != 0;
}
function setBorrowingEnabled(DataTypes.ReserveConfigurationMap memory self, bool enabled)
internal
pure
{
self.data =
(self.data & BORROWING_MASK) |
(uint256(enabled ? 1 : 0) << BORROWING_ENABLED_START_BIT_POSITION);
}
function getBorrowingEnabled(DataTypes.ReserveConfigurationMap storage self)
internal
view
returns (bool)
{
return (self.data & ~BORROWING_MASK) != 0;
}
function setReserveFactor(DataTypes.ReserveConfigurationMap memory self, uint256 reserveFactor)
internal
pure
{
require(reserveFactor <= MAX_VALID_RESERVE_FACTOR, Errors.RC_INVALID_RESERVE_FACTOR);
self.data =
(self.data & RESERVE_FACTOR_MASK) |
(reserveFactor << RESERVE_FACTOR_START_BIT_POSITION);
}
function getReserveFactor(DataTypes.ReserveConfigurationMap storage self)
internal
view
returns (uint256)
{
return (self.data & ~RESERVE_FACTOR_MASK) >> RESERVE_FACTOR_START_BIT_POSITION;
}
function getFlags(DataTypes.ReserveConfigurationMap storage self)
internal
view
returns (
bool,
bool,
bool
)
{
uint256 dataLocal = self.data;
return (
(dataLocal & ~ACTIVE_MASK) != 0,
(dataLocal & ~FROZEN_MASK) != 0,
(dataLocal & ~BORROWING_MASK) != 0
);
}
function getParams(DataTypes.ReserveConfigurationMap storage self)
internal
view
returns (
uint256,
uint256,
uint256,
uint256,
uint256
)
{
uint256 dataLocal = self.data;
return (
dataLocal & ~LTV_MASK,
(dataLocal & ~LIQUIDATION_THRESHOLD_MASK) >> LIQUIDATION_THRESHOLD_START_BIT_POSITION,
(dataLocal & ~LIQUIDATION_BONUS_MASK) >> LIQUIDATION_BONUS_START_BIT_POSITION,
(dataLocal & ~DECIMALS_MASK) >> RESERVE_DECIMALS_START_BIT_POSITION,
(dataLocal & ~RESERVE_FACTOR_MASK) >> RESERVE_FACTOR_START_BIT_POSITION
);
}
function getParamsMemory(DataTypes.ReserveConfigurationMap memory self)
internal
pure
returns (
uint256,
uint256,
uint256,
uint256,
uint256
)
{
return (
self.data & ~LTV_MASK,
(self.data & ~LIQUIDATION_THRESHOLD_MASK) >> LIQUIDATION_THRESHOLD_START_BIT_POSITION,
(self.data & ~LIQUIDATION_BONUS_MASK) >> LIQUIDATION_BONUS_START_BIT_POSITION,
(self.data & ~DECIMALS_MASK) >> RESERVE_DECIMALS_START_BIT_POSITION,
(self.data & ~RESERVE_FACTOR_MASK) >> RESERVE_FACTOR_START_BIT_POSITION
);
}
function getFlagsMemory(DataTypes.ReserveConfigurationMap memory self)
internal
pure
returns (
bool,
bool,
bool
)
{
return (
(self.data & ~ACTIVE_MASK) != 0,
(self.data & ~FROZEN_MASK) != 0,
(self.data & ~BORROWING_MASK) != 0
);
}
}
文件 51 的 64:ReserveLogic.sol
pragma solidity 0.6.12;
import {SafeMath} from './SafeMath.sol';
import {IERC20} from './IERC20.sol';
import {SafeERC20} from './SafeERC20.sol';
import {IXToken} from './IXToken.sol';
import {IVariableDebtToken} from './IVariableDebtToken.sol';
import {IReserveInterestRateStrategy} from './IReserveInterestRateStrategy.sol';
import {ReserveConfiguration} from './ReserveConfiguration.sol';
import {MathUtils} from './MathUtils.sol';
import {WadRayMath} from './WadRayMath.sol';
import {PercentageMath} from './PercentageMath.sol';
import {Errors} from './Errors.sol';
import {DataTypes} from './DataTypes.sol';
library ReserveLogic {
using SafeMath for uint256;
using WadRayMath for uint256;
using PercentageMath for uint256;
using SafeERC20 for IERC20;
event ReserveDataUpdated(
address indexed asset,
uint256 liquidityRate,
uint256 variableBorrowRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex
);
using ReserveLogic for DataTypes.ReserveData;
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
function getNormalizedIncome(DataTypes.ReserveData storage reserve)
internal
view
returns (uint256)
{
uint40 timestamp = reserve.lastUpdateTimestamp;
if (timestamp == uint40(block.timestamp)) {
return reserve.liquidityIndex;
}
uint256 cumulated =
MathUtils.calculateLinearInterest(reserve.currentLiquidityRate, timestamp).rayMul(
reserve.liquidityIndex
);
return cumulated;
}
function getNormalizedDebt(DataTypes.ReserveData storage reserve)
internal
view
returns (uint256)
{
uint40 timestamp = reserve.lastUpdateTimestamp;
if (timestamp == uint40(block.timestamp)) {
return reserve.variableBorrowIndex;
}
uint256 cumulated =
MathUtils.calculateCompoundedInterest(reserve.currentVariableBorrowRate, timestamp).rayMul(
reserve.variableBorrowIndex
);
return cumulated;
}
function updateState(DataTypes.ReserveData storage reserve) internal {
uint256 scaledVariableDebt =
IVariableDebtToken(reserve.variableDebtTokenAddress).scaledTotalSupply();
uint256 previousVariableBorrowIndex = reserve.variableBorrowIndex;
uint256 previousLiquidityIndex = reserve.liquidityIndex;
uint40 lastUpdatedTimestamp = reserve.lastUpdateTimestamp;
(uint256 newLiquidityIndex, uint256 newVariableBorrowIndex) =
_updateIndexes(
reserve,
scaledVariableDebt,
previousLiquidityIndex,
previousVariableBorrowIndex,
lastUpdatedTimestamp
);
_mintToTreasury(
reserve,
scaledVariableDebt,
previousVariableBorrowIndex,
newLiquidityIndex,
newVariableBorrowIndex
);
}
function cumulateToLiquidityIndex(
DataTypes.ReserveData storage reserve,
uint256 totalLiquidity,
uint256 amount
) internal {
uint256 amountToLiquidityRatio = amount.wadToRay().rayDiv(totalLiquidity.wadToRay());
uint256 result = amountToLiquidityRatio.add(WadRayMath.ray());
result = result.rayMul(reserve.liquidityIndex);
require(result <= type(uint128).max, Errors.RL_LIQUIDITY_INDEX_OVERFLOW);
reserve.liquidityIndex = uint128(result);
}
function init(
DataTypes.ReserveData storage reserve,
address xTokenAddress,
address variableDebtTokenAddress,
address interestRateStrategyAddress
) external {
require(reserve.xTokenAddress == address(0), Errors.RL_RESERVE_ALREADY_INITIALIZED);
reserve.liquidityIndex = uint128(WadRayMath.ray());
reserve.variableBorrowIndex = uint128(WadRayMath.ray());
reserve.xTokenAddress = xTokenAddress;
reserve.variableDebtTokenAddress = variableDebtTokenAddress;
reserve.interestRateStrategyAddress = interestRateStrategyAddress;
}
struct UpdateInterestRatesLocalVars {
uint256 availableLiquidity;
uint256 newLiquidityRate;
uint256 newVariableRate;
uint256 totalVariableDebt;
}
function updateInterestRates(
DataTypes.ReserveData storage reserve,
address reserveAddress,
address xTokenAddress,
uint256 liquidityAdded,
uint256 liquidityTaken
) internal {
UpdateInterestRatesLocalVars memory vars;
vars.totalVariableDebt = IVariableDebtToken(reserve.variableDebtTokenAddress)
.scaledTotalSupply()
.rayMul(reserve.variableBorrowIndex);
vars.availableLiquidity = IERC20(reserveAddress).balanceOf(xTokenAddress);
(
vars.newLiquidityRate,
vars.newVariableRate
) = IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).calculateInterestRates(
vars.availableLiquidity.add(liquidityAdded).sub(liquidityTaken),
vars.totalVariableDebt,
reserve.configuration.getReserveFactor()
);
require(vars.newLiquidityRate <= type(uint128).max, Errors.RL_LIQUIDITY_RATE_OVERFLOW);
require(vars.newVariableRate <= type(uint128).max, Errors.RL_VARIABLE_BORROW_RATE_OVERFLOW);
reserve.currentLiquidityRate = uint128(vars.newLiquidityRate);
reserve.currentVariableBorrowRate = uint128(vars.newVariableRate);
emit ReserveDataUpdated(
reserveAddress,
vars.newLiquidityRate,
vars.newVariableRate,
reserve.liquidityIndex,
reserve.variableBorrowIndex
);
}
struct MintToTreasuryLocalVars {
uint256 currentVariableDebt;
uint256 previousVariableDebt;
uint256 totalDebtAccrued;
uint256 amountToMint;
uint256 reserveFactor;
}
function _mintToTreasury(
DataTypes.ReserveData storage reserve,
uint256 scaledVariableDebt,
uint256 previousVariableBorrowIndex,
uint256 newLiquidityIndex,
uint256 newVariableBorrowIndex
) internal {
MintToTreasuryLocalVars memory vars;
vars.reserveFactor = reserve.configuration.getReserveFactor();
if (vars.reserveFactor == 0) {
return;
}
vars.previousVariableDebt = scaledVariableDebt.rayMul(previousVariableBorrowIndex);
vars.currentVariableDebt = scaledVariableDebt.rayMul(newVariableBorrowIndex);
vars.totalDebtAccrued = vars
.currentVariableDebt
.sub(vars.previousVariableDebt);
vars.amountToMint = vars.totalDebtAccrued.percentMul(vars.reserveFactor);
if (vars.amountToMint != 0) {
IXToken(reserve.xTokenAddress).mintToTreasury(vars.amountToMint, newLiquidityIndex);
}
}
function _updateIndexes(
DataTypes.ReserveData storage reserve,
uint256 scaledVariableDebt,
uint256 liquidityIndex,
uint256 variableBorrowIndex,
uint40 timestamp
) internal returns (uint256, uint256) {
uint256 currentLiquidityRate = reserve.currentLiquidityRate;
uint256 newLiquidityIndex = liquidityIndex;
uint256 newVariableBorrowIndex = variableBorrowIndex;
if (currentLiquidityRate > 0) {
uint256 cumulatedLiquidityInterest =
MathUtils.calculateLinearInterest(currentLiquidityRate, timestamp);
newLiquidityIndex = cumulatedLiquidityInterest.rayMul(liquidityIndex);
require(newLiquidityIndex <= type(uint128).max, Errors.RL_LIQUIDITY_INDEX_OVERFLOW);
reserve.liquidityIndex = uint128(newLiquidityIndex);
if (scaledVariableDebt != 0) {
uint256 cumulatedVariableBorrowInterest =
MathUtils.calculateCompoundedInterest(reserve.currentVariableBorrowRate, timestamp);
newVariableBorrowIndex = cumulatedVariableBorrowInterest.rayMul(variableBorrowIndex);
require(
newVariableBorrowIndex <= type(uint128).max,
Errors.RL_VARIABLE_BORROW_INDEX_OVERFLOW
);
reserve.variableBorrowIndex = uint128(newVariableBorrowIndex);
}
}
reserve.lastUpdateTimestamp = uint40(block.timestamp);
return (newLiquidityIndex, newVariableBorrowIndex);
}
}
文件 52 的 64:SafeERC20.sol
pragma solidity 0.6.12;
import {IERC20} from './IERC20.sol';
import {SafeMath} from './SafeMath.sol';
import {Address} from './Address.sol';
library SafeERC20 {
using SafeMath for uint256;
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 callOptionalReturn(IERC20 token, bytes memory data) private {
require(address(token).isContract(), 'SafeERC20: call to non-contract');
(bool success, bytes memory returndata) = address(token).call(data);
require(success, 'SafeERC20: low-level call failed');
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), 'SafeERC20: ERC20 operation did not succeed');
}
}
}
文件 53 的 64:SafeMath.sol
pragma solidity 0.6.12;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, 'SafeMath: addition overflow');
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, 'SafeMath: subtraction overflow');
}
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, 'SafeMath: multiplication overflow');
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, 'SafeMath: division by zero');
}
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, 'SafeMath: modulo by zero');
}
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
文件 54 的 64:StringLib.sol
pragma solidity 0.6.12;
library StringLib {
function concat(string memory a, string memory b) internal pure returns (string memory) {
return string(abi.encodePacked(a, b));
}
}
文件 55 的 64:UpgradeabilityProxy.sol
pragma solidity 0.6.12;
import './BaseUpgradeabilityProxy.sol';
contract UpgradeabilityProxy is BaseUpgradeabilityProxy {
constructor(address _logic, bytes memory _data) public payable {
assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1));
_setImplementation(_logic);
if (_data.length > 0) {
(bool success, ) = _logic.delegatecall(_data);
require(success);
}
}
}
文件 56 的 64:UserConfiguration.sol
pragma solidity 0.6.12;
import {Errors} from './Errors.sol';
import {DataTypes} from './DataTypes.sol';
library UserConfiguration {
uint256 internal constant BORROWING_MASK =
0x5555555555555555555555555555555555555555555555555555555555555555;
function setBorrowing(
DataTypes.UserConfigurationMap storage self,
uint256 reserveIndex,
bool borrowing
) internal {
require(reserveIndex < 128, Errors.UL_INVALID_INDEX);
self.data =
(self.data & ~(1 << (reserveIndex * 2))) |
(uint256(borrowing ? 1 : 0) << (reserveIndex * 2));
}
function setUsingAsCollateral(
DataTypes.UserConfigurationMap storage self,
uint256 reserveIndex,
bool usingAsCollateral
) internal {
require(reserveIndex < 128, Errors.UL_INVALID_INDEX);
self.data =
(self.data & ~(1 << (reserveIndex * 2 + 1))) |
(uint256(usingAsCollateral ? 1 : 0) << (reserveIndex * 2 + 1));
}
function isUsingAsCollateralOrBorrowing(
DataTypes.UserConfigurationMap memory self,
uint256 reserveIndex
) internal pure returns (bool) {
require(reserveIndex < 128, Errors.UL_INVALID_INDEX);
return (self.data >> (reserveIndex * 2)) & 3 != 0;
}
function isBorrowing(DataTypes.UserConfigurationMap memory self, uint256 reserveIndex)
internal
pure
returns (bool)
{
require(reserveIndex < 128, Errors.UL_INVALID_INDEX);
return (self.data >> (reserveIndex * 2)) & 1 != 0;
}
function isUsingAsCollateral(DataTypes.UserConfigurationMap memory self, uint256 reserveIndex)
internal
pure
returns (bool)
{
require(reserveIndex < 128, Errors.UL_INVALID_INDEX);
return (self.data >> (reserveIndex * 2 + 1)) & 1 != 0;
}
function isBorrowingAny(DataTypes.UserConfigurationMap memory self) internal pure returns (bool) {
return self.data & BORROWING_MASK != 0;
}
function isEmpty(DataTypes.UserConfigurationMap memory self) internal pure returns (bool) {
return self.data == 0;
}
}
文件 57 的 64:ValidationLogic.sol
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import {SafeMath} from "./SafeMath.sol";
import {IERC20} from "./IERC20.sol";
import {ReserveLogic} from "./ReserveLogic.sol";
import {GenericLogic} from "./GenericLogic.sol";
import {WadRayMath} from "./WadRayMath.sol";
import {PercentageMath} from "./PercentageMath.sol";
import {SafeERC20} from "./SafeERC20.sol";
import {ReserveConfiguration} from "./ReserveConfiguration.sol";
import {UserConfiguration} from "./UserConfiguration.sol";
import {Errors} from "./Errors.sol";
import {Helpers} from "./Helpers.sol";
import {IReserveInterestRateStrategy} from "./IReserveInterestRateStrategy.sol";
import {DataTypes} from "./DataTypes.sol";
library ValidationLogic {
using ReserveLogic for DataTypes.ReserveData;
using SafeMath for uint256;
using WadRayMath for uint256;
using PercentageMath for uint256;
using SafeERC20 for IERC20;
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
using UserConfiguration for DataTypes.UserConfigurationMap;
uint256 public constant REBALANCE_UP_LIQUIDITY_RATE_THRESHOLD = 4000;
uint256 public constant REBALANCE_UP_USAGE_RATIO_THRESHOLD = 0.95 * 1e27;
function validateDeposit(DataTypes.ReserveData storage reserve, uint256 amount) external view {
(bool isActive, bool isFrozen,) = reserve.configuration.getFlags();
require(amount != 0, Errors.VL_INVALID_AMOUNT);
require(isActive, Errors.VL_NO_ACTIVE_RESERVE);
require(!isFrozen, Errors.VL_RESERVE_FROZEN);
}
function validateWithdraw(
address reserveAddress,
uint256 amount,
uint256 userBalance,
mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap storage userConfig,
mapping(uint256 => address) storage reserves,
uint256 reservesCount,
address oracle
) external view {
require(amount != 0, Errors.VL_INVALID_AMOUNT);
require(amount <= userBalance, Errors.VL_NOT_ENOUGH_AVAILABLE_USER_BALANCE);
(bool isActive, ,) = reservesData[reserveAddress].configuration.getFlags();
require(isActive, Errors.VL_NO_ACTIVE_RESERVE);
require(
GenericLogic.balanceDecreaseAllowed(
reserveAddress,
msg.sender,
amount,
reservesData,
userConfig,
reserves,
reservesCount,
oracle
),
Errors.VL_TRANSFER_NOT_ALLOWED
);
}
struct ValidateBorrowLocalVars {
uint256 currentLtv;
uint256 currentLiquidationThreshold;
uint256 amountOfCollateralNeededETH;
uint256 userCollateralBalanceETH;
uint256 userBorrowBalanceETH;
uint256 availableLiquidity;
uint256 healthFactor;
bool isActive;
bool isFrozen;
bool borrowingEnabled;
}
function validateBorrow(
DataTypes.ReserveData storage reserve,
address userAddress,
uint256 amount,
uint256 amountInETH,
mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap storage userConfig,
mapping(uint256 => address) storage reserves,
uint256 reservesCount,
address oracle
) external view {
ValidateBorrowLocalVars memory vars;
(vars.isActive, vars.isFrozen, vars.borrowingEnabled) = reserve
.configuration
.getFlags();
require(vars.isActive, Errors.VL_NO_ACTIVE_RESERVE);
require(!vars.isFrozen, Errors.VL_RESERVE_FROZEN);
require(amount != 0, Errors.VL_INVALID_AMOUNT);
require(vars.borrowingEnabled, Errors.VL_BORROWING_NOT_ENABLED);
(
vars.userCollateralBalanceETH,
vars.userBorrowBalanceETH,
vars.currentLtv,
vars.currentLiquidationThreshold,
vars.healthFactor
) = GenericLogic.calculateUserAccountData(
userAddress,
reservesData,
userConfig,
reserves,
reservesCount,
oracle
);
require(vars.userCollateralBalanceETH > 0, Errors.VL_COLLATERAL_BALANCE_IS_0);
require(vars.healthFactor > GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD, Errors.VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD);
vars.amountOfCollateralNeededETH = vars
.userBorrowBalanceETH
.add(amountInETH)
.percentDiv(vars.currentLtv);
require(
vars.amountOfCollateralNeededETH <= vars.userCollateralBalanceETH,
Errors.VL_COLLATERAL_CANNOT_COVER_NEW_BORROW
);
}
struct ValidateSwapLocalVars {
uint256 currentLtv;
uint256 amountOfCollateralNeededETH;
uint256 userCollateralBalanceETH;
uint256 userBorrowBalanceETH;
uint256 healthFactor;
}
function validateSwap(
address userAddress,
mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap storage userConfig,
mapping(uint256 => address) storage reserves,
uint256 reservesCount,
address oracle
) external view {
ValidateSwapLocalVars memory vars;
(
vars.userCollateralBalanceETH,
vars.userBorrowBalanceETH,
vars.currentLtv,
,
vars.healthFactor
) = GenericLogic.calculateUserAccountData(
userAddress,
reservesData,
userConfig,
reserves,
reservesCount,
oracle
);
require(vars.userCollateralBalanceETH > 0, Errors.VL_COLLATERAL_BALANCE_IS_0);
require(vars.healthFactor > GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD, Errors.VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD);
vars.amountOfCollateralNeededETH = vars.userBorrowBalanceETH.percentDiv(vars.currentLtv);
require(
vars.amountOfCollateralNeededETH <= vars.userCollateralBalanceETH,
Errors.VL_COLLATERAL_CANNOT_COVER_NEW_BORROW
);
}
function validateRepay(
DataTypes.ReserveData storage reserve,
uint256 amountSent,
address onBehalfOf,
uint256 variableDebt,
uint256 userBalance
) external view {
bool isActive = reserve.configuration.getActive();
require(isActive, Errors.VL_NO_ACTIVE_RESERVE);
require(amountSent > 0, Errors.VL_INVALID_AMOUNT);
require(variableDebt > 0, Errors.VL_NO_DEBT_OF_SELECTED_TYPE);
require(userBalance >= amountSent, "deposit is less than debt");
require(
amountSent != uint256(-1) || msg.sender == onBehalfOf,
Errors.VL_NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF
);
}
function validateSetUseReserveAsCollateral(
DataTypes.ReserveData storage reserve,
address reserveAddress,
bool useAsCollateral,
mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap storage userConfig,
mapping(uint256 => address) storage reserves,
uint256 reservesCount,
address oracle
) external view {
uint256 underlyingBalance = IERC20(reserve.xTokenAddress).balanceOf(msg.sender);
require(underlyingBalance > 0, Errors.VL_UNDERLYING_BALANCE_NOT_GREATER_THAN_0);
require(
useAsCollateral ||
GenericLogic.balanceDecreaseAllowed(
reserveAddress,
msg.sender,
underlyingBalance,
reservesData,
userConfig,
reserves,
reservesCount,
oracle
),
Errors.VL_DEPOSIT_ALREADY_IN_USE
);
}
function validateFlashloan(address[] memory assets, uint256[] memory amounts) internal pure {
require(assets.length == amounts.length, Errors.VL_INCONSISTENT_FLASHLOAN_PARAMS);
}
function validateLiquidation(
DataTypes.ReserveData storage collateralReserve,
DataTypes.ReserveData storage principalReserve,
DataTypes.UserConfigurationMap storage userConfig,
uint256 userHealthFactor,
uint256 userVariableDebt
) external view {
require(
collateralReserve.configuration.getActive() &&
principalReserve.configuration.getActive(),
Errors.VL_NO_ACTIVE_RESERVE
);
require(
userHealthFactor < GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
Errors.MPCM_HEALTH_FACTOR_NOT_BELOW_THRESHOLD
);
bool isCollateralEnabled =
collateralReserve.configuration.getLiquidationThreshold() > 0 &&
userConfig.isUsingAsCollateral(collateralReserve.id);
require(
isCollateralEnabled,
Errors.MPCM_COLLATERAL_CANNOT_BE_LIQUIDATED
);
require(
userVariableDebt > 0,
Errors.MPCM_SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER
);
}
function validateTransfer(
address from,
mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap storage userConfig,
mapping(uint256 => address) storage reserves,
uint256 reservesCount,
address oracle
) internal view {
(, , , , uint256 healthFactor) =
GenericLogic.calculateUserAccountData(
from,
reservesData,
userConfig,
reserves,
reservesCount,
oracle
);
require(
healthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
Errors.VL_TRANSFER_NOT_ALLOWED
);
}
}
文件 58 的 64:VariableDebtToken.sol
pragma solidity 0.6.12;
import {IVariableDebtToken} from "./IVariableDebtToken.sol";
import {WadRayMath} from "./WadRayMath.sol";
import {Errors} from "./Errors.sol";
import {DebtTokenBase} from "./DebtTokenBase.sol";
import {SafeMath} from "./SafeMath.sol";
import {
IMarginPoolAddressesProvider
} from "./IMarginPoolAddressesProvider.sol";
import {IERC20} from "./IERC20.sol";
import {SafeERC20} from "./SafeERC20.sol";
library Math {
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 / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2);
}
}
contract ReentrancyGuard {
uint256 private _guardCounter;
constructor() internal {
_guardCounter = 1;
}
modifier nonReentrant() {
_guardCounter += 1;
uint256 localCounter = _guardCounter;
_;
require(
localCounter == _guardCounter,
"ReentrancyGuard: reentrant call"
);
}
}
contract VariableDebtToken is DebtTokenBase, IVariableDebtToken, ReentrancyGuard {
using WadRayMath for uint256;
using SafeERC20 for IERC20;
uint256 public constant DEBT_TOKEN_REVISION = 0x1;
address public rewardsDistribution;
IERC20 public rewardsToken;
uint256 public periodFinish = 0;
uint256 public rewardRate = 0;
uint256 public rewardsDuration = 30 days;
uint256 public lastUpdateTime;
uint256 public rewardPerTokenStored;
mapping(address => uint256) public userRewardPerTokenPaid;
mapping(address => uint256) public rewards;
constructor(
address _addressesProvider,
address underlyingAsset,
string memory name,
string memory symbol,
uint8 decimals
)
public
DebtTokenBase(
IMarginPoolAddressesProvider(_addressesProvider).getMarginPool(),
underlyingAsset,
name,
symbol,
decimals
)
{
rewardsDistribution = IMarginPoolAddressesProvider(_addressesProvider).getRewardsDistribution();
rewardsToken = IERC20(IMarginPoolAddressesProvider(_addressesProvider).getLeverToken());
}
modifier updateReward(address account) {
rewardPerTokenStored = rewardPerToken();
lastUpdateTime = lastTimeRewardApplicable();
if (account != address(0)) {
rewards[account] = earned(account);
userRewardPerTokenPaid[account] = rewardPerTokenStored;
}
_;
}
modifier onlyRewardsDistribution() {
require(
msg.sender == rewardsDistribution,
"Caller is not RewardsDistribution contract"
);
_;
}
function balanceOf(address user)
public
view
virtual
override
returns (uint256)
{
uint256 scaledBalance = super.balanceOf(user);
if (scaledBalance == 0) {
return 0;
}
return
scaledBalance.rayMul(
POOL.getReserveNormalizedVariableDebt(UNDERLYING_ASSET_ADDRESS)
);
}
function mint(
address user,
address onBehalfOf,
uint256 amount,
uint256 index
) external override onlyMarginPool updateReward(onBehalfOf) returns (bool) {
if (user != onBehalfOf) {
_decreaseBorrowAllowance(onBehalfOf, user, amount);
}
uint256 previousBalance = super.balanceOf(onBehalfOf);
uint256 amountScaled = amount.rayDiv(index);
require(amountScaled != 0, Errors.CT_INVALID_MINT_AMOUNT);
_mint(onBehalfOf, amountScaled);
emit Transfer(address(0), onBehalfOf, amount);
emit Mint(user, onBehalfOf, amount, index);
return previousBalance == 0;
}
function burn(
address user,
uint256 amount,
uint256 index
) external override onlyMarginPool updateReward(user) {
uint256 amountScaled = amount.rayDiv(index);
require(amountScaled != 0, Errors.CT_INVALID_BURN_AMOUNT);
_burn(user, amountScaled);
emit Transfer(user, address(0), amount);
emit Burn(user, amount, index);
}
function scaledBalanceOf(address user)
public
view
virtual
override
returns (uint256)
{
return super.balanceOf(user);
}
function totalSupply() public view virtual override returns (uint256) {
return
super.totalSupply().rayMul(
POOL.getReserveNormalizedVariableDebt(UNDERLYING_ASSET_ADDRESS)
);
}
function scaledTotalSupply()
public
view
virtual
override
returns (uint256)
{
return super.totalSupply();
}
function getScaledUserBalanceAndSupply(address user)
external
view
override
returns (uint256, uint256)
{
return (super.balanceOf(user), super.totalSupply());
}
function _transfer(
address from,
address to,
uint256 amount
) internal override updateReward(from) updateReward(to) {
super._transfer(from, to, amount);
}
function lastTimeRewardApplicable() public view returns (uint256) {
return Math.min(block.timestamp, periodFinish);
}
function rewardPerToken() public view returns (uint256) {
if (totalSupply() == 0) {
return rewardPerTokenStored;
}
return
rewardPerTokenStored.add(
lastTimeRewardApplicable()
.sub(lastUpdateTime)
.mul(rewardRate)
.mul(1e18)
.div(totalSupply())
);
}
function earned(address account) public view returns (uint256) {
return
balanceOf(account)
.mul(rewardPerToken().sub(userRewardPerTokenPaid[account]))
.div(1e18)
.add(rewards[account]);
}
function getRewardForDuration() external view returns (uint256) {
return rewardRate.mul(rewardsDuration);
}
function getReward() public nonReentrant updateReward(msg.sender) {
uint256 reward = rewards[msg.sender];
require(reward > 0);
rewards[msg.sender] = 0;
rewardsToken.safeTransfer(msg.sender, reward);
emit RewardPaid(msg.sender, reward);
}
function notifyRewardAmount(uint256 reward, uint256 _rewardsDuration)
external
onlyRewardsDistribution
updateReward(address(0))
{
uint256 balance = rewardsToken.balanceOf(address(this));
if (block.timestamp >= periodFinish) {
rewardsDuration = _rewardsDuration;
rewardRate = reward.div(rewardsDuration);
require(
rewardRate <= balance.div(rewardsDuration),
"Provided reward too high"
);
periodFinish = block.timestamp.add(rewardsDuration);
} else {
uint256 remaining = periodFinish.sub(block.timestamp);
uint256 leftover = remaining.mul(rewardRate);
rewardRate = reward.add(leftover).div(remaining);
require(
rewardRate <= balance.div(remaining),
"Provided reward too high"
);
}
lastUpdateTime = block.timestamp;
emit RewardAdded(reward, _rewardsDuration);
}
event RewardAdded(uint256 reward, uint256 _rewardsDuration);
event RewardPaid(address indexed user, uint256 reward);
}
文件 59 的 64:VariableTokensHelper.sol
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import {VariableDebtToken} from './VariableDebtToken.sol';
import {Ownable} from './Ownable.sol';
import {StringLib} from './StringLib.sol';
contract VariableTokensHelper is Ownable {
address payable private pool;
address private addressesProvider;
event deployedContracts(address variableToken);
constructor(address payable _pool, address _addressesProvider) public {
pool = _pool;
addressesProvider = _addressesProvider;
}
function initDeployment(
address[] calldata tokens,
string[] calldata symbols,
uint8[] calldata decimals
) external onlyOwner {
require(tokens.length == symbols.length, 'Arrays not same length');
require(pool != address(0), 'Pool can not be zero address');
for (uint256 i = 0; i < tokens.length; i++) {
emit deployedContracts(
address(
new VariableDebtToken(
addressesProvider,
tokens[i],
StringLib.concat('Lever variable debt bearing ', symbols[i]),
StringLib.concat('d', symbols[i]),
decimals[i]
)
)
);
}
}
}
文件 60 的 64:VersionedInitializable.sol
pragma solidity 0.6.12;
abstract contract VersionedInitializable {
uint256 private lastInitializedRevision = 0;
bool private initializing;
modifier initializer() {
uint256 revision = getRevision();
require(
initializing || isConstructor() || revision > lastInitializedRevision,
'Contract instance has already been initialized'
);
bool isTopLevelCall = !initializing;
if (isTopLevelCall) {
initializing = true;
lastInitializedRevision = revision;
}
_;
if (isTopLevelCall) {
initializing = false;
}
}
function getRevision() internal pure virtual returns (uint256);
function isConstructor() private view returns (bool) {
uint256 cs;
assembly {
cs := extcodesize(address())
}
return cs == 0;
}
uint256[50] private ______gap;
}
文件 61 的 64:WETHGateway.sol
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import {Ownable} from './Ownable.sol';
import {IERC20} from './IERC20.sol';
import {IWETH} from './IWETH.sol';
import {IWETHGateway} from './IWETHGateway.sol';
import {IMarginPool} from './IMarginPool.sol';
import {IXToken} from './IXToken.sol';
import {ICreditDelegationToken} from './ICreditDelegationToken.sol';
import {ReserveConfiguration} from './ReserveConfiguration.sol';
import {UserConfiguration} from './UserConfiguration.sol';
import {Helpers} from './Helpers.sol';
import {DataTypes} from './DataTypes.sol';
contract WETHGateway is IWETHGateway, Ownable {
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
using UserConfiguration for DataTypes.UserConfigurationMap;
IWETH internal immutable WETH;
IMarginPool internal immutable POOL;
IXToken internal immutable xWETH;
ICreditDelegationToken internal immutable dWETH;
constructor(address weth, address pool) public {
IMarginPool poolInstance = IMarginPool(pool);
WETH = IWETH(weth);
POOL = poolInstance;
xWETH = IXToken(poolInstance.getReserveData(weth).xTokenAddress);
dWETH = ICreditDelegationToken(poolInstance.getReserveData(weth).variableDebtTokenAddress);
IWETH(weth).approve(pool, uint256(-1));
}
function depositETH(address onBehalfOf) external payable override {
WETH.deposit{value: msg.value}();
POOL.deposit(address(WETH), msg.value, onBehalfOf);
}
function withdrawETH(uint256 amount, address to) external override {
uint256 userBalance = xWETH.balanceOf(msg.sender);
uint256 amountToWithdraw = amount;
if (amount == type(uint256).max) {
amountToWithdraw = userBalance;
}
xWETH.transferFrom(msg.sender, address(this), amountToWithdraw);
POOL.withdraw(address(WETH), amountToWithdraw, address(this));
WETH.withdraw(amountToWithdraw);
_safeTransferETH(to, amountToWithdraw);
}
function borrowETH(
uint256 amount
) external override {
POOL.borrow(address(WETH), amount, msg.sender);
WETH.withdraw(amount);
_safeTransferETH(msg.sender, amount);
}
function _safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'ETH_TRANSFER_FAILED');
}
function emergencyTokenTransfer(
address token,
address to,
uint256 amount
) external onlyOwner {
IERC20(token).transfer(to, amount);
}
function emergencyEtherTransfer(address to, uint256 amount) external onlyOwner {
_safeTransferETH(to, amount);
}
function getWETHAddress() external view returns (address) {
return address(WETH);
}
function getXWETHAddress() external view returns (address) {
return address(xWETH);
}
function getMarginPoolAddress() external view returns (address) {
return address(POOL);
}
receive() external payable {
require(msg.sender == address(WETH), 'Receive not allowed');
}
fallback() external payable {
revert('Fallback not allowed');
}
}
文件 62 的 64:WadRayMath.sol
pragma solidity 0.6.12;
import {Errors} from './Errors.sol';
library WadRayMath {
uint256 internal constant WAD = 1e18;
uint256 internal constant halfWAD = WAD / 2;
uint256 internal constant RAY = 1e27;
uint256 internal constant halfRAY = RAY / 2;
uint256 internal constant WAD_RAY_RATIO = 1e9;
function ray() internal pure returns (uint256) {
return RAY;
}
function wad() internal pure returns (uint256) {
return WAD;
}
function halfRay() internal pure returns (uint256) {
return halfRAY;
}
function halfWad() internal pure returns (uint256) {
return halfWAD;
}
function wadMul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0 || b == 0) {
return 0;
}
require(a <= (type(uint256).max - halfWAD) / b, Errors.MATH_MULTIPLICATION_OVERFLOW);
return (a * b + halfWAD) / WAD;
}
function wadDiv(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, Errors.MATH_DIVISION_BY_ZERO);
uint256 halfB = b / 2;
require(a <= (type(uint256).max - halfB) / WAD, Errors.MATH_MULTIPLICATION_OVERFLOW);
return (a * WAD + halfB) / b;
}
function rayMul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0 || b == 0) {
return 0;
}
require(a <= (type(uint256).max - halfRAY) / b, Errors.MATH_MULTIPLICATION_OVERFLOW);
return (a * b + halfRAY) / RAY;
}
function rayDiv(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, Errors.MATH_DIVISION_BY_ZERO);
uint256 halfB = b / 2;
require(a <= (type(uint256).max - halfB) / RAY, Errors.MATH_MULTIPLICATION_OVERFLOW);
return (a * RAY + halfB) / b;
}
function rayToWad(uint256 a) internal pure returns (uint256) {
uint256 halfRatio = WAD_RAY_RATIO / 2;
uint256 result = halfRatio + a;
require(result >= halfRatio, Errors.MATH_ADDITION_OVERFLOW);
return result / WAD_RAY_RATIO;
}
function wadToRay(uint256 a) internal pure returns (uint256) {
uint256 result = a * WAD_RAY_RATIO;
require(result / WAD_RAY_RATIO == a, Errors.MATH_MULTIPLICATION_OVERFLOW);
return result;
}
}
文件 63 的 64:XToken.sol
pragma solidity 0.6.12;
import {IERC20} from "./IERC20.sol";
import {SafeERC20} from "./SafeERC20.sol";
import {IMarginPool} from "./IMarginPool.sol";
import {IXToken} from "./IXToken.sol";
import {WadRayMath} from "./WadRayMath.sol";
import {Errors} from "./Errors.sol";
import {IncentivizedERC20} from "./IncentivizedERC20.sol";
import {SafeMath} from "./SafeMath.sol";
import {
IMarginPoolAddressesProvider
} from "./IMarginPoolAddressesProvider.sol";
import {Address} from "./Address.sol";
library Math {
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 / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2);
}
}
contract ReentrancyGuard {
uint256 private _guardCounter;
constructor() internal {
_guardCounter = 1;
}
modifier nonReentrant() {
_guardCounter += 1;
uint256 localCounter = _guardCounter;
_;
require(
localCounter == _guardCounter,
"ReentrancyGuard: reentrant call"
);
}
}
contract XToken is
IncentivizedERC20,
IXToken,
ReentrancyGuard
{
using WadRayMath for uint256;
using SafeERC20 for IERC20;
IERC20 public rewardsToken;
uint256 public periodFinish = 0;
uint256 public rewardRate = 0;
uint256 public rewardsDuration = 30 days;
uint256 public lastUpdateTime;
uint256 public rewardPerTokenStored;
mapping(address => uint256) public userRewardPerTokenPaid;
mapping(address => uint256) public rewards;
bytes public constant EIP712_REVISION = bytes("1");
bytes32 internal constant EIP712_DOMAIN =
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
bytes32 public constant PERMIT_TYPEHASH =
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
);
uint256 public constant UINT_MAX_VALUE = uint256(-1);
address public immutable UNDERLYING_ASSET_ADDRESS;
address public immutable RESERVE_TREASURY_ADDRESS;
IMarginPool public immutable POOL;
IMarginPoolAddressesProvider public addressesProvider;
mapping(address => uint256) public _nonces;
bytes32 public DOMAIN_SEPARATOR;
modifier updateReward(address account) {
rewardPerTokenStored = rewardPerToken();
lastUpdateTime = lastTimeRewardApplicable();
if (account != address(0)) {
rewards[account] = earned(account);
userRewardPerTokenPaid[account] = rewardPerTokenStored;
}
_;
}
modifier onlyRewardsDistribution() {
require(
msg.sender == addressesProvider.getRewardsDistribution(),
"Caller is not RewardsDistribution contract"
);
_;
}
modifier onlyMarginPool {
require(
_msgSender() == address(POOL),
Errors.CT_CALLER_MUST_BE_MARGIN_POOL
);
_;
}
constructor(
address _addressesProvider,
address underlyingAssetAddress,
string memory tokenName,
string memory tokenSymbol,
uint8 decimals
) public IncentivizedERC20(tokenName, tokenSymbol, decimals) {
addressesProvider = IMarginPoolAddressesProvider(_addressesProvider);
POOL = IMarginPool(addressesProvider.getMarginPool());
UNDERLYING_ASSET_ADDRESS = underlyingAssetAddress;
RESERVE_TREASURY_ADDRESS = addressesProvider.getTreasuryAddress();
rewardsToken = IERC20(IMarginPoolAddressesProvider(_addressesProvider).getLeverToken());
}
function burn(
address user,
address receiverOfUnderlying,
uint256 amount,
uint256 index
) external override onlyMarginPool updateReward(user) {
uint256 amountScaled = amount.rayDiv(index);
require(amountScaled != 0, Errors.CT_INVALID_BURN_AMOUNT);
_burn(user, amountScaled);
if (receiverOfUnderlying != address(this)) {
IERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(
receiverOfUnderlying,
amount
);
}
emit Transfer(user, address(0), amount);
emit Burn(user, receiverOfUnderlying, amount, index);
}
function mint(
address user,
uint256 amount,
uint256 index
) external override onlyMarginPool updateReward(user) returns (bool) {
uint256 previousBalance = super.balanceOf(user);
uint256 amountScaled = amount.rayDiv(index);
require(amountScaled != 0, Errors.CT_INVALID_MINT_AMOUNT);
_mint(user, amountScaled);
emit Transfer(address(0), user, amount);
emit Mint(user, amount, index);
return previousBalance == 0;
}
function mintToTreasury(uint256 amount, uint256 index)
external
override
onlyMarginPool
updateReward(RESERVE_TREASURY_ADDRESS)
{
if (amount == 0) {
return;
}
_mint(RESERVE_TREASURY_ADDRESS, amount.rayDiv(index));
emit Transfer(address(0), RESERVE_TREASURY_ADDRESS, amount);
emit Mint(RESERVE_TREASURY_ADDRESS, amount, index);
}
function transferOnLiquidation(
address from,
address to,
uint256 value
) external override onlyMarginPool updateReward(from) updateReward(to) {
_transfer(from, to, value, false);
emit Transfer(from, to, value);
}
function balanceOf(address user)
public
view
override(IncentivizedERC20, IERC20)
returns (uint256)
{
return
super.balanceOf(user).rayMul(
POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS)
);
}
function scaledBalanceOf(address user)
external
view
override
returns (uint256)
{
return super.balanceOf(user);
}
function getScaledUserBalanceAndSupply(address user)
external
view
override
returns (uint256, uint256)
{
return (super.balanceOf(user), super.totalSupply());
}
function totalSupply()
public
view
override(IncentivizedERC20, IERC20)
returns (uint256)
{
uint256 currentSupplyScaled = super.totalSupply();
if (currentSupplyScaled == 0) {
return 0;
}
return
currentSupplyScaled.rayMul(
POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS)
);
}
function scaledTotalSupply()
public
view
virtual
override
returns (uint256)
{
return super.totalSupply();
}
function transferUnderlyingTo(address target, uint256 amount)
external
override
onlyMarginPool
returns (uint256)
{
IERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(target, amount);
return amount;
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
require(owner != address(0), "INVALID_OWNER");
require(block.timestamp <= deadline, "INVALID_EXPIRATION");
uint256 currentValidNonce = _nonces[owner];
bytes32 digest =
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(
abi.encode(
PERMIT_TYPEHASH,
owner,
spender,
value,
currentValidNonce,
deadline
)
)
)
);
require(owner == ecrecover(digest, v, r, s), "INVALID_SIGNATURE");
_nonces[owner] = currentValidNonce.add(1);
_approve(owner, spender, value);
}
function _transfer(
address from,
address to,
uint256 amount,
bool validate
) internal updateReward(from) updateReward(to) {
uint256 index =
POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS);
uint256 fromBalanceBefore = super.balanceOf(from).rayMul(index);
uint256 toBalanceBefore = super.balanceOf(to).rayMul(index);
super._transfer(from, to, amount.rayDiv(index));
if (validate) {
POOL.finalizeTransfer(
UNDERLYING_ASSET_ADDRESS,
from,
to,
amount,
fromBalanceBefore,
toBalanceBefore
);
}
emit BalanceTransfer(from, to, amount, index);
}
function _transfer(
address from,
address to,
uint256 amount
) internal override {
_transfer(from, to, amount, true);
}
function lastTimeRewardApplicable() public view returns (uint256) {
return Math.min(block.timestamp, periodFinish);
}
function rewardPerToken() public view returns (uint256) {
if (totalSupply() == 0) {
return rewardPerTokenStored;
}
return
rewardPerTokenStored.add(
lastTimeRewardApplicable()
.sub(lastUpdateTime)
.mul(rewardRate)
.mul(1e18)
.div(totalSupply())
);
}
function earned(address account) public view returns (uint256) {
return
balanceOf(account)
.mul(rewardPerToken().sub(userRewardPerTokenPaid[account]))
.div(1e18)
.add(rewards[account]);
}
function getRewardForDuration() external view returns (uint256) {
return rewardRate.mul(rewardsDuration);
}
function getReward() public nonReentrant updateReward(msg.sender) {
uint256 reward = rewards[msg.sender];
require(reward > 0);
rewards[msg.sender] = 0;
rewardsToken.safeTransfer(msg.sender, reward);
emit RewardPaid(msg.sender, reward);
}
function notifyRewardAmount(uint256 reward, uint256 _rewardsDuration)
external
onlyRewardsDistribution
updateReward(address(0))
{
uint256 balance = rewardsToken.balanceOf(address(this));
if (block.timestamp >= periodFinish) {
rewardsDuration = _rewardsDuration;
rewardRate = reward.div(rewardsDuration);
require(
rewardRate <= balance.div(rewardsDuration),
"Provided reward too high"
);
periodFinish = block.timestamp.add(rewardsDuration);
} else {
uint256 remaining = periodFinish.sub(block.timestamp);
uint256 leftover = remaining.mul(rewardRate);
rewardRate = reward.add(leftover).div(remaining);
require(
rewardRate <= balance.div(remaining),
"Provided reward too high"
);
}
lastUpdateTime = block.timestamp;
emit RewardAdded(reward, _rewardsDuration);
}
event RewardAdded(uint256 reward, uint256 _rewardsDuration);
event RewardPaid(address indexed user, uint256 reward);
}
文件 64 的 64:XTokensAndRatesHelper.sol
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import {IMarginPoolAddressesProvider} from './IMarginPoolAddressesProvider.sol';
import {MarginPoolConfigurator} from './MarginPoolConfigurator.sol';
import {XToken} from './XToken.sol';
import {
DefaultReserveInterestRateStrategy
} from './DefaultReserveInterestRateStrategy.sol';
import {Ownable} from './Ownable.sol';
import {StringLib} from './StringLib.sol';
contract XTokensAndRatesHelper is Ownable {
address payable private pool;
address private addressesProvider;
address private poolConfigurator;
event deployedContracts(address xToken, address strategy);
constructor(
address _addressesProvider,
address _poolConfigurator
) public {
addressesProvider = _addressesProvider;
poolConfigurator = _poolConfigurator;
}
function initDeployment(
address[] calldata assets,
string[] calldata symbols,
uint256[4][] calldata rates,
uint8[] calldata decimals
) external onlyOwner {
require(assets.length == symbols.length, 't Arrays not same length');
require(rates.length == symbols.length, 'r Arrays not same length');
for (uint256 i = 0; i < assets.length; i++) {
emit deployedContracts(
address(
new XToken(
addressesProvider,
assets[i],
StringLib.concat('Lever interest bearing ', symbols[i]),
StringLib.concat('x', symbols[i]),
decimals[i]
)
),
address(
new DefaultReserveInterestRateStrategy(
IMarginPoolAddressesProvider(addressesProvider),
rates[i][0],
rates[i][1],
rates[i][2],
rates[i][3]
)
)
);
}
}
function initReserve(
address[] calldata variables,
address[] calldata xTokens,
address[] calldata strategies,
uint8[] calldata reserveDecimals
) external onlyOwner {
require(xTokens.length == variables.length);
require(strategies.length == variables.length);
require(reserveDecimals.length == variables.length);
for (uint256 i = 0; i < variables.length; i++) {
MarginPoolConfigurator(poolConfigurator).initReserve(
xTokens[i],
variables[i],
reserveDecimals[i],
strategies[i]
);
}
}
function configureReserves(
address[] calldata assets,
uint256[] calldata baseLTVs,
uint256[] calldata liquidationThresholds,
uint256[] calldata liquidationBonuses,
uint256[] calldata reserveFactors
) external onlyOwner {
require(baseLTVs.length == assets.length);
require(liquidationThresholds.length == assets.length);
require(liquidationBonuses.length == assets.length);
require(reserveFactors.length == assets.length);
MarginPoolConfigurator configurator = MarginPoolConfigurator(poolConfigurator);
for (uint256 i = 0; i < assets.length; i++) {
configurator.configureReserveAsCollateral(
assets[i],
baseLTVs[i],
liquidationThresholds[i],
liquidationBonuses[i]
);
configurator.setReserveFactor(assets[i], reserveFactors[i]);
}
}
}
{
"compilationTarget": {
"XToken.sol": "XToken"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_addressesProvider","type":"address"},{"internalType":"address","name":"underlyingAssetAddress","type":"address"},{"internalType":"string","name":"tokenName","type":"string"},{"internalType":"string","name":"tokenSymbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"BalanceTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_rewardsDuration","type":"uint256"}],"name":"RewardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"RewardPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_REVISION","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"POOL","outputs":[{"internalType":"contract IMarginPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RESERVE_TREASURY_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UINT_MAX_VALUE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNDERLYING_ASSET_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"addressesProvider","outputs":[{"internalType":"contract IMarginPoolAddressesProvider","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"receiverOfUnderlying","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"earned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getRewardForDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getScaledUserBalanceAndSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastTimeRewardApplicable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"mintToTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"_rewardsDuration","type":"uint256"}],"name":"notifyRewardAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"periodFinish","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardPerTokenStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"scaledBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"scaledTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferOnLiquidation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferUnderlyingTo","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userRewardPerTokenPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]