aave-protocol-v2/contracts/lendingpool/LendingPool.sol

804 lines
26 KiB
Solidity
Raw Normal View History

// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.6.8;
2020-07-23 15:18:06 +00:00
pragma experimental ABIEncoderV2;
2020-08-20 07:51:21 +00:00
import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol';
import {ReentrancyGuard} from '@openzeppelin/contracts/utils/ReentrancyGuard.sol';
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import {
VersionedInitializable
} from '../libraries/openzeppelin-upgradeability/VersionedInitializable.sol';
2020-08-21 12:03:17 +00:00
import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
import {IAToken} from '../tokenization/interfaces/IAToken.sol';
2020-08-20 07:51:21 +00:00
import {Helpers} from '../libraries/helpers/Helpers.sol';
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
import {ReserveLogic} from '../libraries/logic/ReserveLogic.sol';
import {GenericLogic} from '../libraries/logic/GenericLogic.sol';
import {ValidationLogic} from '../libraries/logic/ValidationLogic.sol';
import {ReserveConfiguration} from '../libraries/configuration/ReserveConfiguration.sol';
import {UserConfiguration} from '../libraries/configuration/UserConfiguration.sol';
import {IStableDebtToken} from '../tokenization/interfaces/IStableDebtToken.sol';
import {IVariableDebtToken} from '../tokenization/interfaces/IVariableDebtToken.sol';
import {IFlashLoanReceiver} from '../flashloan/interfaces/IFlashLoanReceiver.sol';
import {LendingPoolLiquidationManager} from './LendingPoolLiquidationManager.sol';
import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol';
2020-08-12 17:36:58 +00:00
import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/SafeERC20.sol';
import {ILendingPool} from '../interfaces/ILendingPool.sol';
/**
* @title LendingPool contract
* @notice Implements the actions of the LendingPool, and exposes accessory methods to fetch the users and reserve data
* @author Aave
**/
contract LendingPool is ReentrancyGuard, VersionedInitializable, ILendingPool {
using SafeMath for uint256;
using WadRayMath for uint256;
2020-07-08 22:16:05 +00:00
using ReserveLogic for ReserveLogic.ReserveData;
2020-07-23 15:18:06 +00:00
using ReserveConfiguration for ReserveConfiguration.Map;
2020-08-05 10:40:24 +00:00
using UserConfiguration for UserConfiguration.Map;
2020-08-21 12:03:17 +00:00
using SafeERC20 for IERC20;
//main configuration parameters
2020-08-21 12:03:17 +00:00
uint256 public constant REBALANCE_DOWN_RATE_DELTA = (1e27) / 5;
uint256 public constant MAX_STABLE_RATE_BORROW_SIZE_PERCENT = 25;
uint256 public constant FLASHLOAN_FEE_TOTAL = 9;
2020-08-21 12:03:17 +00:00
ILendingPoolAddressesProvider internal addressesProvider;
2020-08-21 11:15:29 +00:00
mapping(address => ReserveLogic.ReserveData) internal _reserves;
mapping(address => UserConfiguration.Map) internal _usersConfig;
2020-08-21 12:03:17 +00:00
address[] internal reservesList;
/**
* @dev only lending pools configurator can use functions affected by this modifier
**/
modifier onlyLendingPoolConfigurator {
require(addressesProvider.getLendingPoolConfigurator() == msg.sender, '30');
_;
}
uint256 public constant UINT_MAX_VALUE = uint256(-1);
uint256 public constant LENDINGPOOL_REVISION = 0x2;
function getRevision() internal override pure returns (uint256) {
return LENDINGPOOL_REVISION;
}
/**
* @dev this function is invoked by the proxy contract when the LendingPool contract is added to the
* AddressesProvider.
2020-08-21 11:15:29 +00:00
* @param provider the address of the LendingPoolAddressesProvider registry
**/
2020-08-21 12:03:17 +00:00
function initialize(ILendingPoolAddressesProvider provider) public initializer {
2020-08-21 11:15:29 +00:00
addressesProvider = provider;
}
/**
* @dev deposits The underlying asset into the reserve. A corresponding amount of the overlying asset (aTokens)
* is minted.
2020-08-21 11:15:29 +00:00
* @param asset the address of the reserve
* @param amount the amount to be deposited
* @param referralCode integrators are assigned a referral code and can potentially receive rewards.
**/
function deposit(
2020-08-21 11:15:29 +00:00
address asset,
uint256 amount,
uint16 referralCode
) external override nonReentrant {
2020-08-21 11:15:29 +00:00
ReserveLogic.ReserveData storage reserve = _reserves[asset];
2020-08-21 11:15:29 +00:00
ValidationLogic.validateDeposit(reserve, amount);
IAToken aToken = IAToken(reserve.aTokenAddress);
bool isFirstDeposit = aToken.balanceOf(msg.sender) == 0;
reserve.updateCumulativeIndexesAndTimestamp();
2020-08-21 11:15:29 +00:00
reserve.updateInterestRates(asset, amount, 0);
if (isFirstDeposit) {
2020-08-21 11:15:29 +00:00
_usersConfig[msg.sender].setUsingAsCollateral(reserve.index, true);
}
//minting AToken to user 1:1 with the specific exchange rate
2020-08-21 11:15:29 +00:00
aToken.mint(msg.sender, amount);
2020-07-10 17:16:04 +00:00
//transfer to the aToken contract
2020-08-21 11:15:29 +00:00
IERC20(asset).safeTransferFrom(msg.sender, address(aToken), amount);
//solium-disable-next-line
2020-08-21 11:15:29 +00:00
emit Deposit(asset, msg.sender, amount, referralCode);
}
/**
2020-08-21 11:15:29 +00:00
* @dev withdraws the _reserves of _user.
* @param asset the address of the reserve
* @param amount the underlying amount to be redeemed
**/
2020-08-21 11:15:29 +00:00
function withdraw(address asset, uint256 amount) external override nonReentrant {
ReserveLogic.ReserveData storage reserve = _reserves[asset];
IAToken aToken = IAToken(reserve.aTokenAddress);
2020-07-10 17:16:04 +00:00
2020-08-18 19:19:11 +00:00
uint256 userBalance = aToken.balanceOf(msg.sender);
2020-08-21 11:15:29 +00:00
uint256 amountToWithdraw = amount;
2020-08-18 19:19:11 +00:00
//if amount is equal to uint(-1), the user wants to redeem everything
2020-08-21 11:15:29 +00:00
if (amount == UINT_MAX_VALUE) {
2020-08-18 19:19:11 +00:00
amountToWithdraw = userBalance;
}
ValidationLogic.validateWithdraw(
2020-08-21 11:15:29 +00:00
asset,
2020-08-18 19:19:11 +00:00
address(aToken),
amountToWithdraw,
userBalance,
2020-08-21 11:15:29 +00:00
_reserves,
_usersConfig[msg.sender],
2020-08-18 19:19:11 +00:00
reservesList,
addressesProvider.getPriceOracle()
);
2020-07-10 17:16:04 +00:00
reserve.updateCumulativeIndexesAndTimestamp();
2020-08-21 11:15:29 +00:00
reserve.updateInterestRates(asset, 0, amountToWithdraw);
2020-07-10 17:16:04 +00:00
2020-08-18 19:19:11 +00:00
if (amountToWithdraw == userBalance) {
2020-08-21 11:15:29 +00:00
_usersConfig[msg.sender].setUsingAsCollateral(reserve.index, false);
}
aToken.burn(msg.sender, msg.sender, amountToWithdraw);
//solium-disable-next-line
2020-08-21 11:15:29 +00:00
emit Withdraw(asset, msg.sender, amount);
}
/**
* @dev Allows users to borrow a specific amount of the reserve currency, provided that the borrower
* already deposited enough collateral.
2020-08-21 11:15:29 +00:00
* @param asset the address of the reserve
* @param amount the amount to be borrowed
* @param interestRateMode the interest rate mode at which the user wants to borrow. Can be 0 (STABLE) or 1 (VARIABLE)
**/
function borrow(
2020-08-21 11:15:29 +00:00
address asset,
uint256 amount,
uint256 interestRateMode,
uint16 referralCode
) external override nonReentrant {
2020-08-21 11:15:29 +00:00
ReserveLogic.ReserveData storage reserve = _reserves[asset];
UserConfiguration.Map storage userConfig = _usersConfig[msg.sender];
uint256 amountInETH = IPriceOracleGetter(addressesProvider.getPriceOracle())
2020-08-21 11:15:29 +00:00
.getAssetPrice(asset)
.mul(amount)
2020-07-23 15:18:06 +00:00
.div(10**reserve.configuration.getDecimals()); //price is in ether
ValidationLogic.validateBorrow(
reserve,
2020-08-21 11:15:29 +00:00
asset,
amount,
amountInETH,
2020-08-21 11:15:29 +00:00
interestRateMode,
MAX_STABLE_RATE_BORROW_SIZE_PERCENT,
2020-08-21 11:15:29 +00:00
_reserves,
_usersConfig[msg.sender],
reservesList,
addressesProvider.getPriceOracle()
);
//caching the current stable borrow rate
uint256 userStableRate = reserve.currentStableBorrowRate;
reserve.updateCumulativeIndexesAndTimestamp();
2020-08-21 11:15:29 +00:00
if (ReserveLogic.InterestRateMode(interestRateMode) == ReserveLogic.InterestRateMode.STABLE) {
IStableDebtToken(reserve.stableDebtTokenAddress).mint(msg.sender, amount, userStableRate);
} else {
2020-08-21 11:15:29 +00:00
IVariableDebtToken(reserve.variableDebtTokenAddress).mint(msg.sender, amount);
}
2020-08-21 11:15:29 +00:00
reserve.updateInterestRates(asset, 0, amount);
2020-06-20 23:40:03 +00:00
2020-08-18 19:19:11 +00:00
if (!userConfig.isBorrowing(reserve.index)) {
2020-08-05 10:40:24 +00:00
userConfig.setBorrowing(reserve.index, true);
}
//if we reached this point, we can transfer
2020-08-21 11:15:29 +00:00
IAToken(reserve.aTokenAddress).transferUnderlyingTo(msg.sender, amount);
emit Borrow(
2020-08-21 11:15:29 +00:00
asset,
msg.sender,
2020-08-21 11:15:29 +00:00
amount,
interestRateMode,
ReserveLogic.InterestRateMode(interestRateMode) == ReserveLogic.InterestRateMode.STABLE
? userStableRate
: reserve.currentVariableBorrowRate,
2020-08-21 11:15:29 +00:00
referralCode
);
}
2020-08-20 07:51:21 +00:00
/**
* @notice repays a borrow on the specific reserve, for the specified amount (or for the whole amount, if uint256(-1) is specified).
* @dev the target user is defined by _onBehalfOf. If there is no repayment on behalf of another account,
* _onBehalfOf must be equal to msg.sender.
2020-08-21 11:15:29 +00:00
* @param asset the address of the reserve on which the user borrowed
* @param amount the amount to repay, or uint256(-1) if the user wants to repay everything
2020-08-20 07:51:21 +00:00
* @param _onBehalfOf the address for which msg.sender is repaying.
**/
function repay(
2020-08-21 11:15:29 +00:00
address asset,
uint256 amount,
uint256 _rateMode,
address _onBehalfOf
) external override nonReentrant {
2020-08-21 11:15:29 +00:00
ReserveLogic.ReserveData storage reserve = _reserves[asset];
2020-08-21 17:10:48 +00:00
(uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(_onBehalfOf, reserve);
2020-07-08 22:16:05 +00:00
ReserveLogic.InterestRateMode rateMode = ReserveLogic.InterestRateMode(_rateMode);
//default to max amount
2020-08-20 13:12:19 +00:00
uint256 paybackAmount = rateMode == ReserveLogic.InterestRateMode.STABLE
2020-08-21 17:10:48 +00:00
? stableDebt
: variableDebt;
2020-08-21 11:15:29 +00:00
if (amount != UINT_MAX_VALUE && amount < paybackAmount) {
paybackAmount = amount;
}
ValidationLogic.validateRepay(
reserve,
2020-08-21 11:15:29 +00:00
amount,
rateMode,
_onBehalfOf,
2020-08-20 13:12:19 +00:00
stableDebt,
variableDebt
);
reserve.updateCumulativeIndexesAndTimestamp();
//burns an equivalent amount of debt tokens
2020-07-08 22:16:05 +00:00
if (rateMode == ReserveLogic.InterestRateMode.STABLE) {
2020-08-20 13:12:19 +00:00
IStableDebtToken(reserve.stableDebtTokenAddress).burn(_onBehalfOf, paybackAmount);
} else {
2020-08-20 13:12:19 +00:00
IVariableDebtToken(reserve.variableDebtTokenAddress).burn(_onBehalfOf, paybackAmount);
}
2020-08-21 11:15:29 +00:00
reserve.updateInterestRates(asset, paybackAmount, 0);
2020-08-18 19:19:11 +00:00
2020-08-20 13:12:19 +00:00
if (stableDebt.add(variableDebt).sub(paybackAmount) == 0) {
2020-08-21 11:15:29 +00:00
_usersConfig[_onBehalfOf].setBorrowing(reserve.index, false);
2020-08-05 10:40:24 +00:00
}
2020-08-21 11:15:29 +00:00
IERC20(asset).safeTransferFrom(msg.sender, reserve.aTokenAddress, paybackAmount);
emit Repay(asset, _onBehalfOf, msg.sender, paybackAmount);
}
/**
* @dev borrowers can user this function to swap between stable and variable borrow rate modes.
2020-08-21 11:15:29 +00:00
* @param asset the address of the reserve on which the user borrowed
* @param _rateMode the rate mode that the user wants to swap
**/
2020-08-21 11:15:29 +00:00
function swapBorrowRateMode(address asset, uint256 _rateMode) external override nonReentrant {
ReserveLogic.ReserveData storage reserve = _reserves[asset];
2020-08-06 07:52:15 +00:00
(uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(msg.sender, reserve);
2020-07-08 22:16:05 +00:00
ReserveLogic.InterestRateMode rateMode = ReserveLogic.InterestRateMode(_rateMode);
2020-08-18 19:19:11 +00:00
ValidationLogic.validateSwapRateMode(
reserve,
2020-08-21 11:15:29 +00:00
_usersConfig[msg.sender],
2020-08-18 19:19:11 +00:00
stableDebt,
variableDebt,
rateMode
);
reserve.updateCumulativeIndexesAndTimestamp();
2020-07-08 22:16:05 +00:00
if (rateMode == ReserveLogic.InterestRateMode.STABLE) {
//burn stable rate tokens, mint variable rate tokens
2020-07-13 08:54:08 +00:00
IStableDebtToken(reserve.stableDebtTokenAddress).burn(msg.sender, stableDebt);
IVariableDebtToken(reserve.variableDebtTokenAddress).mint(msg.sender, stableDebt);
} else {
//do the opposite
IVariableDebtToken(reserve.variableDebtTokenAddress).burn(msg.sender, variableDebt);
IStableDebtToken(reserve.stableDebtTokenAddress).mint(
msg.sender,
variableDebt,
reserve.currentStableBorrowRate
);
}
2020-08-21 11:15:29 +00:00
reserve.updateInterestRates(asset, 0, 0);
emit Swap(
2020-08-21 11:15:29 +00:00
asset,
msg.sender,
//solium-disable-next-line
block.timestamp
);
}
/**
* @dev rebalances the stable interest rate of a user if current liquidity rate > user stable rate.
* this is regulated by Aave to ensure that the protocol is not abused, and the user is paying a fair
* rate. Anyone can call this function.
2020-08-21 11:15:29 +00:00
* @param asset the address of the reserve
* @param _user the address of the user to be rebalanced
**/
2020-08-21 11:15:29 +00:00
function rebalanceStableBorrowRate(address asset, address _user) external override nonReentrant {
ReserveLogic.ReserveData storage reserve = _reserves[asset];
IStableDebtToken stableDebtToken = IStableDebtToken(reserve.stableDebtTokenAddress);
uint256 stableBorrowBalance = IERC20(address(stableDebtToken)).balanceOf(_user);
2020-08-21 11:15:29 +00:00
// user must be borrowing on asset at a stable rate
require(stableBorrowBalance > 0, 'User does not have any stable rate loan for this reserve');
uint256 rebalanceDownRateThreshold = reserve.currentStableBorrowRate.rayMul(
WadRayMath.ray().add(REBALANCE_DOWN_RATE_DELTA)
);
2020-06-20 23:40:03 +00:00
//1. user stable borrow rate is below the current liquidity rate. The loan needs to be rebalanced,
//as this situation can be abused (user putting back the borrowed liquidity in the same reserve to earn on it)
//2. user stable rate is above the market avg borrow rate of a certain delta, and utilization rate is low.
//In this case, the user is paying an interest that is too high, and needs to be rescaled down.
uint256 userStableRate = stableDebtToken.getUserStableRate(_user);
require(
userStableRate < reserve.currentLiquidityRate || userStableRate > rebalanceDownRateThreshold,
'Interest rate rebalance conditions were not met'
);
2020-06-20 23:40:03 +00:00
//burn old debt tokens, mint new ones
2020-06-20 23:40:03 +00:00
reserve.updateCumulativeIndexesAndTimestamp();
2020-06-20 23:40:03 +00:00
stableDebtToken.burn(_user, stableBorrowBalance);
stableDebtToken.mint(_user, stableBorrowBalance, reserve.currentStableBorrowRate);
2020-06-20 23:40:03 +00:00
2020-08-21 11:15:29 +00:00
reserve.updateInterestRates(asset, 0, 0);
2020-06-20 23:40:03 +00:00
emit RebalanceStableBorrowRate(asset, _user);
return;
}
/**
* @dev allows depositors to enable or disable a specific deposit as collateral.
2020-08-21 11:15:29 +00:00
* @param asset the address of the reserve
* @param _useAsCollateral true if the user wants to user the deposit as collateral, false otherwise.
**/
2020-08-21 11:15:29 +00:00
function setUserUseReserveAsCollateral(address asset, bool _useAsCollateral)
external
override
nonReentrant
{
2020-08-21 11:15:29 +00:00
ReserveLogic.ReserveData storage reserve = _reserves[asset];
ValidationLogic.validateSetUseReserveAsCollateral(
reserve,
2020-08-21 11:15:29 +00:00
asset,
_reserves,
_usersConfig[msg.sender],
reservesList,
addressesProvider.getPriceOracle()
);
2020-08-21 11:15:29 +00:00
_usersConfig[msg.sender].setUsingAsCollateral(reserve.index, _useAsCollateral);
if (_useAsCollateral) {
2020-08-21 11:15:29 +00:00
emit ReserveUsedAsCollateralEnabled(asset, msg.sender);
} else {
2020-08-21 11:15:29 +00:00
emit ReserveUsedAsCollateralDisabled(asset, msg.sender);
2020-06-20 23:40:03 +00:00
}
}
/**
* @dev users can invoke this function to liquidate an undercollateralized position.
2020-08-21 11:15:29 +00:00
* @param asset the address of the collateral to liquidated
* @param asset the address of the principal reserve
* @param _user the address of the borrower
* @param _purchaseAmount the amount of principal that the liquidator wants to repay
* @param _receiveAToken true if the liquidators wants to receive the aTokens, false if
* he wants to receive the underlying asset directly
**/
function liquidationCall(
address _collateral,
2020-08-21 11:15:29 +00:00
address asset,
address _user,
uint256 _purchaseAmount,
bool _receiveAToken
) external override nonReentrant {
address liquidationManager = addressesProvider.getLendingPoolLiquidationManager();
//solium-disable-next-line
(bool success, bytes memory result) = liquidationManager.delegatecall(
abi.encodeWithSignature(
'liquidationCall(address,address,address,uint256,bool)',
_collateral,
2020-08-21 11:15:29 +00:00
asset,
_user,
_purchaseAmount,
_receiveAToken
)
);
2020-07-09 15:05:16 +00:00
require(success, 'Liquidation call failed');
2020-06-20 23:40:03 +00:00
(uint256 returnCode, string memory returnMessage) = abi.decode(result, (uint256, string));
2020-06-20 23:40:03 +00:00
if (returnCode != 0) {
//error found
revert(string(abi.encodePacked(returnMessage)));
2020-06-20 23:40:03 +00:00
}
}
/**
* @dev allows smartcontracts to access the liquidity of the pool within one transaction,
* as long as the amount taken plus a fee is returned. NOTE There are security concerns for developers of flashloan receiver contracts
* that must be kept into consideration. For further details please visit https://developers.aave.com
2020-08-21 11:15:29 +00:00
* @param receiverAddress The address of the contract receiving the funds. The receiver should implement the IFlashLoanReceiver interface.
* @param asset the address of the principal reserve
* @param amount the amount requested for this flashloan
**/
function flashLoan(
2020-08-21 11:15:29 +00:00
address receiverAddress,
address asset,
uint256 amount,
bytes calldata params
) external override nonReentrant {
2020-08-21 11:15:29 +00:00
ReserveLogic.ReserveData storage reserve = _reserves[asset];
address aTokenAddress = reserve.aTokenAddress;
2020-07-10 17:16:04 +00:00
//check that the reserve has enough available liquidity
2020-08-21 11:15:29 +00:00
uint256 availableLiquidityBefore = IERC20(asset).balanceOf(aTokenAddress);
//calculate amount fee
2020-08-21 11:15:29 +00:00
uint256 amountFee = amount.mul(FLASHLOAN_FEE_TOTAL).div(10000);
require(
2020-08-21 11:15:29 +00:00
availableLiquidityBefore >= amount,
'There is not enough liquidity available to borrow'
);
require(amountFee > 0, 'The requested amount is too small for a FlashLoan.');
2020-06-20 23:40:03 +00:00
//get the FlashLoanReceiver instance
2020-08-21 11:15:29 +00:00
IFlashLoanReceiver receiver = IFlashLoanReceiver(receiverAddress);
2020-06-20 23:40:03 +00:00
//transfer funds to the receiver
2020-08-21 11:15:29 +00:00
IAToken(aTokenAddress).transferUnderlyingTo(receiverAddress, amount);
2020-06-20 23:40:03 +00:00
//execute action of the receiver
2020-08-21 11:15:29 +00:00
receiver.executeOperation(asset, aTokenAddress, amount, amountFee, params);
2020-06-20 23:40:03 +00:00
//check that the actual balance of the core contract includes the returned amount
2020-08-21 11:15:29 +00:00
uint256 availableLiquidityAfter = IERC20(asset).balanceOf(aTokenAddress);
2020-06-20 23:40:03 +00:00
require(
availableLiquidityAfter == availableLiquidityBefore.add(amountFee),
'The actual balance of the protocol is inconsistent'
);
2020-06-20 23:40:03 +00:00
2020-08-21 13:13:08 +00:00
//compounding the cumulated interest
reserve.updateCumulativeIndexesAndTimestamp();
uint256 totalLiquidityBefore = availableLiquidityBefore
.add(IERC20(reserve.variableDebtTokenAddress).totalSupply())
.add(IERC20(reserve.stableDebtTokenAddress).totalSupply());
//compounding the received fee into the reserve
reserve.cumulateToLiquidityIndex(totalLiquidityBefore, amountFee);
2020-08-21 13:13:08 +00:00
//refresh interest rates
2020-08-21 14:00:51 +00:00
reserve.updateInterestRates(asset, amountFee, 0);
//solium-disable-next-line
2020-08-21 11:15:29 +00:00
emit FlashLoan(receiverAddress, asset, amount, amountFee);
}
/**
* @dev accessory functions to fetch data from the core contract
**/
2020-08-21 11:15:29 +00:00
function getReserveConfigurationData(address asset)
external
override
view
returns (
2020-07-08 15:26:50 +00:00
uint256 decimals,
uint256 ltv,
uint256 liquidationThreshold,
uint256 liquidationBonus,
address interestRateStrategyAddress,
bool usageAsCollateralEnabled,
bool borrowingEnabled,
bool stableBorrowRateEnabled,
bool isActive,
bool isFreezed
)
{
2020-08-21 11:15:29 +00:00
ReserveLogic.ReserveData storage reserve = _reserves[asset];
return (
2020-07-23 15:18:06 +00:00
reserve.configuration.getDecimals(),
reserve.configuration.getLtv(),
reserve.configuration.getLiquidationThreshold(),
reserve.configuration.getLiquidationBonus(),
reserve.interestRateStrategyAddress,
2020-07-23 15:18:06 +00:00
reserve.configuration.getLtv() != 0,
reserve.configuration.getBorrowingEnabled(),
reserve.configuration.getStableRateBorrowingEnabled(),
reserve.configuration.getActive(),
reserve.configuration.getFrozen()
);
}
2020-08-21 11:15:29 +00:00
function getReserveTokensAddresses(address asset)
2020-07-13 08:54:08 +00:00
external
override
2020-07-13 08:54:08 +00:00
view
returns (
address aTokenAddress,
address stableDebtTokenAddress,
address variableDebtTokenAddress
)
{
2020-08-21 11:15:29 +00:00
ReserveLogic.ReserveData storage reserve = _reserves[asset];
return (
reserve.aTokenAddress,
reserve.stableDebtTokenAddress,
2020-07-13 08:54:08 +00:00
reserve.variableDebtTokenAddress
);
}
2020-08-21 11:15:29 +00:00
function getReserveData(address asset)
external
override
view
returns (
uint256 availableLiquidity,
uint256 totalBorrowsStable,
uint256 totalBorrowsVariable,
uint256 liquidityRate,
uint256 variableBorrowRate,
uint256 stableBorrowRate,
uint256 averageStableBorrowRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex,
uint40 lastUpdateTimestamp
)
{
2020-08-21 11:15:29 +00:00
ReserveLogic.ReserveData memory reserve = _reserves[asset];
return (
2020-08-21 11:15:29 +00:00
IERC20(asset).balanceOf(reserve.aTokenAddress),
IERC20(reserve.stableDebtTokenAddress).totalSupply(),
IERC20(reserve.variableDebtTokenAddress).totalSupply(),
reserve.currentLiquidityRate,
reserve.currentVariableBorrowRate,
reserve.currentStableBorrowRate,
IStableDebtToken(reserve.stableDebtTokenAddress).getAverageStableRate(),
2020-08-21 14:00:51 +00:00
reserve.lastLiquidityIndex,
reserve.lastVariableBorrowIndex,
reserve.lastUpdateTimestamp
);
}
function getUserAccountData(address _user)
external
override
view
returns (
uint256 totalCollateralETH,
uint256 totalBorrowsETH,
uint256 availableBorrowsETH,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
)
{
(
totalCollateralETH,
totalBorrowsETH,
ltv,
currentLiquidationThreshold,
healthFactor
) = GenericLogic.calculateUserAccountData(
_user,
2020-08-21 11:15:29 +00:00
_reserves,
_usersConfig[_user],
reservesList,
addressesProvider.getPriceOracle()
);
2020-06-30 12:09:28 +00:00
availableBorrowsETH = GenericLogic.calculateAvailableBorrowsETH(
totalCollateralETH,
totalBorrowsETH,
2020-07-23 15:18:06 +00:00
ltv
);
}
2020-08-21 11:15:29 +00:00
function getUserReserveData(address asset, address _user)
external
override
view
returns (
uint256 currentATokenBalance,
uint256 currentStableDebt,
uint256 currentVariableDebt,
uint256 principalStableDebt,
uint256 principalVariableDebt,
uint256 stableBorrowRate,
uint256 liquidityRate,
uint256 variableBorrowIndex,
uint40 stableRateLastUpdated,
bool usageAsCollateralEnabled
)
{
2020-08-21 11:15:29 +00:00
ReserveLogic.ReserveData storage reserve = _reserves[asset];
currentATokenBalance = IERC20(reserve.aTokenAddress).balanceOf(_user);
2020-08-06 07:52:15 +00:00
(currentStableDebt, currentVariableDebt) = Helpers.getUserCurrentDebt(_user, reserve);
(principalStableDebt, principalVariableDebt) = Helpers.getUserPrincipalDebt(_user, reserve);
liquidityRate = reserve.currentLiquidityRate;
stableBorrowRate = IStableDebtToken(reserve.stableDebtTokenAddress).getUserStableRate(_user);
stableRateLastUpdated = IStableDebtToken(reserve.stableDebtTokenAddress).getUserLastUpdated(
_user
);
2020-08-21 11:15:29 +00:00
usageAsCollateralEnabled = _usersConfig[_user].isUsingAsCollateral(reserve.index);
variableBorrowIndex = IVariableDebtToken(reserve.variableDebtTokenAddress).getUserIndex(_user);
}
function getReserves() external override view returns (address[] memory) {
return reservesList;
}
receive() external payable {
2020-08-20 07:51:21 +00:00
revert();
}
/**
* @dev initializes a reserve
2020-08-21 11:15:29 +00:00
* @param asset the address of the reserve
* @param _aTokenAddress the address of the overlying aToken contract
* @param _interestRateStrategyAddress the address of the interest rate strategy contract
**/
function initReserve(
2020-08-21 11:15:29 +00:00
address asset,
address _aTokenAddress,
address _stableDebtAddress,
address _variableDebtAddress,
address _interestRateStrategyAddress
) external override onlyLendingPoolConfigurator {
2020-08-21 11:15:29 +00:00
_reserves[asset].init(
_aTokenAddress,
_stableDebtAddress,
_variableDebtAddress,
_interestRateStrategyAddress
);
2020-08-21 12:03:17 +00:00
_addReserveToList(asset);
}
/**
* @dev updates the address of the interest rate strategy contract
2020-08-21 11:15:29 +00:00
* @param asset the address of the reserve
2020-08-21 12:03:17 +00:00
* @param rateStrategyAddress the address of the interest rate strategy contract
**/
2020-08-21 12:03:17 +00:00
function setReserveInterestRateStrategyAddress(address asset, address rateStrategyAddress)
external
override
onlyLendingPoolConfigurator
{
2020-08-21 12:03:17 +00:00
_reserves[asset].interestRateStrategyAddress = rateStrategyAddress;
}
2020-08-21 12:03:17 +00:00
function setConfiguration(address asset, uint256 configuration)
external
override
onlyLendingPoolConfigurator
{
2020-08-21 12:03:17 +00:00
_reserves[asset].configuration.data = configuration;
}
2020-08-21 11:15:29 +00:00
function getConfiguration(address asset)
external
override
2020-07-23 15:18:06 +00:00
view
returns (ReserveConfiguration.Map memory)
{
2020-08-21 11:15:29 +00:00
return _reserves[asset].configuration;
}
/**
* @notice internal functions
**/
/**
2020-08-21 11:15:29 +00:00
* @dev adds a reserve to the array of the _reserves address
**/
2020-08-21 12:03:17 +00:00
function _addReserveToList(address asset) internal {
bool reserveAlreadyAdded = false;
for (uint256 i = 0; i < reservesList.length; i++)
2020-08-21 11:15:29 +00:00
if (reservesList[i] == asset) {
reserveAlreadyAdded = true;
}
2020-08-05 10:40:24 +00:00
if (!reserveAlreadyAdded) {
2020-08-21 11:15:29 +00:00
_reserves[asset].index = uint8(reservesList.length);
reservesList.push(asset);
2020-08-05 10:40:24 +00:00
}
}
2020-08-21 12:03:17 +00:00
/**
* @dev returns the normalized income per unit of asset
* @param asset the address of the reserve
* @return the reserve normalized income
2020-08-21 12:03:17 +00:00
*/
2020-08-21 11:15:29 +00:00
function getReserveNormalizedIncome(address asset) external override view returns (uint256) {
return _reserves[asset].getNormalizedIncome();
}
2020-08-21 12:03:17 +00:00
/**
* @dev returns the normalized variable debt per unit of asset
* @param asset the address of the reserve
* @return the reserve normalized debt
2020-08-21 12:03:17 +00:00
*/
2020-08-21 11:15:29 +00:00
function getReserveNormalizedVariableDebt(address asset)
external
override
view
returns (uint256)
{
2020-08-21 11:15:29 +00:00
return _reserves[asset].getNormalizedDebt();
}
2020-08-21 12:03:17 +00:00
/**
* @dev validate if a balance decrease for an asset is allowed
* @param asset the address of the reserve
* @param user the user related to the balance decrease
* @param amount the amount being transferred/redeemed
* @return true if the balance decrease can be allowed, false otherwise
2020-08-21 12:03:17 +00:00
*/
function balanceDecreaseAllowed(
2020-08-21 11:15:29 +00:00
address asset,
2020-08-21 12:03:17 +00:00
address user,
2020-08-21 11:15:29 +00:00
uint256 amount
) external override view returns (bool) {
return
GenericLogic.balanceDecreaseAllowed(
2020-08-21 11:15:29 +00:00
asset,
2020-08-21 12:03:17 +00:00
user,
2020-08-21 11:15:29 +00:00
amount,
_reserves,
2020-08-21 12:03:17 +00:00
_usersConfig[user],
reservesList,
addressesProvider.getPriceOracle()
);
}
2020-08-21 12:03:17 +00:00
2020-08-21 12:05:14 +00:00
/**
* @dev returns the list of the initialized reserves
**/
function getReservesList() external view returns (address[] memory) {
return reservesList;
2020-08-21 12:03:17 +00:00
}
2020-08-21 12:05:14 +00:00
/**
* @dev returns the addresses provider
**/
function getAddressesProvider() external view returns (ILendingPoolAddressesProvider) {
2020-08-21 12:03:17 +00:00
return addressesProvider;
}
}