diff --git a/.prettierrc b/.prettierrc index ec986c7a..2caa9822 100644 --- a/.prettierrc +++ b/.prettierrc @@ -3,6 +3,7 @@ "trailingComma": "es5", "semi": true, "singleQuote": true, + "tabWidth": 2, "overrides": [ { "files": "*.sol", diff --git a/contracts/lendingpool/LendingPool.sol b/contracts/lendingpool/LendingPool.sol index ea384125..be4b4d18 100644 --- a/contracts/lendingpool/LendingPool.sol +++ b/contracts/lendingpool/LendingPool.sol @@ -6,7 +6,7 @@ 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 + VersionedInitializable } from '../libraries/openzeppelin-upgradeability/VersionedInitializable.sol'; import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol'; import {IAToken} from '../tokenization/interfaces/IAToken.sol'; @@ -32,794 +32,779 @@ import {ILendingPool} from '../interfaces/ILendingPool.sol'; **/ contract LendingPool is ReentrancyGuard, VersionedInitializable, ILendingPool { - using SafeMath for uint256; - using WadRayMath for uint256; - using ReserveLogic for ReserveLogic.ReserveData; - using ReserveConfiguration for ReserveConfiguration.Map; - using UserConfiguration for UserConfiguration.Map; - using SafeERC20 for IERC20; + using SafeMath for uint256; + using WadRayMath for uint256; + using ReserveLogic for ReserveLogic.ReserveData; + using ReserveConfiguration for ReserveConfiguration.Map; + using UserConfiguration for UserConfiguration.Map; + using SafeERC20 for IERC20; - //main configuration parameters - 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; + //main configuration parameters + 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; - //require error messages - string private constant NOT_ENOUGH_STABLE_BORROW_BALANCE = '1'; // 'User does not have any stable rate loan for this reserve' - string private constant INTERESTRATE_REBALANCE_CONDITIONS_NOT_MET = '2'; // 'Interest rate rebalance conditions were not met' - string private constant LIQUIDATION_CALL_FAILED = '3'; // 'Liquidation call failed' - string private constant NOT_ENOUGH_LIQUIDITY_TO_BORROW = '4'; // 'There is not enough liquidity available to borrow' - string private constant REQUESTED_AMOUNT_TO_SMALL = '5'; // 'The requested amount is too small for a FlashLoan.' - string private constant INCONSISTENT_PROTOCOL_ACTUAL_BALANCE = '6'; // 'The actual balance of the protocol is inconsistent' + //require error messages + string private constant NOT_ENOUGH_STABLE_BORROW_BALANCE = '1'; // 'User does not have any stable rate loan for this reserve' + string private constant INTERESTRATE_REBALANCE_CONDITIONS_NOT_MET = '2'; // 'Interest rate rebalance conditions were not met' + string private constant LIQUIDATION_CALL_FAILED = '3'; // 'Liquidation call failed' + string private constant NOT_ENOUGH_LIQUIDITY_TO_BORROW = '4'; // 'There is not enough liquidity available to borrow' + string private constant REQUESTED_AMOUNT_TO_SMALL = '5'; // 'The requested amount is too small for a FlashLoan.' + string private constant INCONSISTENT_PROTOCOL_ACTUAL_BALANCE = '6'; // 'The actual balance of the protocol is inconsistent' - ILendingPoolAddressesProvider internal _addressesProvider; + ILendingPoolAddressesProvider internal _addressesProvider; - mapping(address => ReserveLogic.ReserveData) internal _reserves; - mapping(address => UserConfiguration.Map) internal _usersConfig; + mapping(address => ReserveLogic.ReserveData) internal _reserves; + mapping(address => UserConfiguration.Map) internal _usersConfig; - address[] internal _reservesList; + address[] internal _reservesList; - /** - * @dev only lending pools configurator can use functions affected by this modifier - **/ - modifier onlyLendingPoolConfigurator { - require(_addressesProvider.getLendingPoolConfigurator() == msg.sender, '30'); - _; + /** + * @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. + * @param provider the address of the LendingPoolAddressesProvider registry + **/ + function initialize(ILendingPoolAddressesProvider provider) public initializer { + _addressesProvider = provider; + } + + /** + * @dev deposits The underlying asset into the reserve. A corresponding amount of the overlying asset (aTokens) + * is minted. + * @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( + address asset, + uint256 amount, + uint16 referralCode + ) external override nonReentrant { + ReserveLogic.ReserveData storage reserve = _reserves[asset]; + + ValidationLogic.validateDeposit(reserve, amount); + + address aToken = reserve.aTokenAddress; + + reserve.updateCumulativeIndexesAndTimestamp(); + reserve.updateInterestRates(asset, aToken, amount, 0); + + bool isFirstDeposit = IAToken(aToken).balanceOf(msg.sender) == 0; + if (isFirstDeposit) { + _usersConfig[msg.sender].setUsingAsCollateral(reserve.index, true); } - uint256 public constant UINT_MAX_VALUE = uint256(-1); + //minting AToken to user 1:1 with the specific exchange rate + IAToken(aToken).mint(msg.sender, amount); - uint256 public constant LENDINGPOOL_REVISION = 0x2; + //transfer to the aToken contract + IERC20(asset).safeTransferFrom(msg.sender, aToken, amount); - function getRevision() internal override pure returns (uint256) { - return LENDINGPOOL_REVISION; + //solium-disable-next-line + emit Deposit(asset, msg.sender, amount, referralCode); + } + + /** + * @dev withdraws the _reserves of user. + * @param asset the address of the reserve + * @param amount the underlying amount to be redeemed + **/ + function withdraw(address asset, uint256 amount) external override nonReentrant { + ReserveLogic.ReserveData storage reserve = _reserves[asset]; + + address aToken = reserve.aTokenAddress; + + uint256 userBalance = IAToken(aToken).balanceOf(msg.sender); + + uint256 amountToWithdraw = amount; + + //if amount is equal to uint(-1), the user wants to redeem everything + if (amount == UINT_MAX_VALUE) { + amountToWithdraw = userBalance; } - /** - * @dev this function is invoked by the proxy contract when the LendingPool contract is added to the - * AddressesProvider. - * @param provider the address of the LendingPoolAddressesProvider registry - **/ - function initialize(ILendingPoolAddressesProvider provider) public initializer { - _addressesProvider = provider; + ValidationLogic.validateWithdraw( + asset, + aToken, + amountToWithdraw, + userBalance, + _reserves, + _usersConfig[msg.sender], + _reservesList, + _addressesProvider.getPriceOracle() + ); + + reserve.updateCumulativeIndexesAndTimestamp(); + + reserve.updateInterestRates(asset, aToken, 0, amountToWithdraw); + + if (amountToWithdraw == userBalance) { + _usersConfig[msg.sender].setUsingAsCollateral(reserve.index, false); } - /** - * @dev deposits The underlying asset into the reserve. A corresponding amount of the overlying asset (aTokens) - * is minted. - * @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( - address asset, - uint256 amount, - uint16 referralCode - ) external override nonReentrant { - ReserveLogic.ReserveData storage reserve = _reserves[asset]; + IAToken(aToken).burn(msg.sender, msg.sender, amountToWithdraw); - ValidationLogic.validateDeposit(reserve, amount); + //solium-disable-next-line + emit Withdraw(asset, msg.sender, amount); + } - address aToken = reserve.aTokenAddress; + /** + * @dev Allows users to borrow a specific amount of the reserve currency, provided that the borrower + * already deposited enough collateral. + * @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( + address asset, + uint256 amount, + uint256 interestRateMode, + uint16 referralCode + ) external override nonReentrant { + ReserveLogic.ReserveData storage reserve = _reserves[asset]; + UserConfiguration.Map storage userConfig = _usersConfig[msg.sender]; - reserve.updateCumulativeIndexesAndTimestamp(); - reserve.updateInterestRates(asset, aToken, amount, 0); + uint256 amountInETH = IPriceOracleGetter(_addressesProvider.getPriceOracle()) + .getAssetPrice(asset) + .mul(amount) + .div(10**reserve.configuration.getDecimals()); //price is in ether - bool isFirstDeposit = IAToken(aToken).balanceOf(msg.sender) == 0; - if (isFirstDeposit) { - _usersConfig[msg.sender].setUsingAsCollateral(reserve.index, true); - } + ValidationLogic.validateBorrow( + reserve, + asset, + amount, + amountInETH, + interestRateMode, + MAX_STABLE_RATE_BORROW_SIZE_PERCENT, + _reserves, + _usersConfig[msg.sender], + _reservesList, + _addressesProvider.getPriceOracle() + ); - //minting AToken to user 1:1 with the specific exchange rate - IAToken(aToken).mint(msg.sender, amount); + //caching the current stable borrow rate + uint256 userStableRate = reserve.currentStableBorrowRate; - //transfer to the aToken contract - IERC20(asset).safeTransferFrom(msg.sender, aToken, amount); + reserve.updateCumulativeIndexesAndTimestamp(); - //solium-disable-next-line - emit Deposit(asset, msg.sender, amount, referralCode); + if (ReserveLogic.InterestRateMode(interestRateMode) == ReserveLogic.InterestRateMode.STABLE) { + IStableDebtToken(reserve.stableDebtTokenAddress).mint(msg.sender, amount, userStableRate); + } else { + IVariableDebtToken(reserve.variableDebtTokenAddress).mint(msg.sender, amount); } - /** - * @dev withdraws the _reserves of user. - * @param asset the address of the reserve - * @param amount the underlying amount to be redeemed - **/ - function withdraw(address asset, uint256 amount) external override nonReentrant { - ReserveLogic.ReserveData storage reserve = _reserves[asset]; + address aToken = reserve.aTokenAddress; + reserve.updateInterestRates(asset, aToken, 0, amount); - address aToken = reserve.aTokenAddress; - - uint256 userBalance = IAToken(aToken).balanceOf(msg.sender); - - uint256 amountToWithdraw = amount; - - //if amount is equal to uint(-1), the user wants to redeem everything - if (amount == UINT_MAX_VALUE) { - amountToWithdraw = userBalance; - } - - ValidationLogic.validateWithdraw( - asset, - aToken, - amountToWithdraw, - userBalance, - _reserves, - _usersConfig[msg.sender], - _reservesList, - _addressesProvider.getPriceOracle() - ); - - reserve.updateCumulativeIndexesAndTimestamp(); - - reserve.updateInterestRates(asset, aToken, 0, amountToWithdraw); - - if (amountToWithdraw == userBalance) { - _usersConfig[msg.sender].setUsingAsCollateral(reserve.index, false); - } - - IAToken(aToken).burn(msg.sender, msg.sender, amountToWithdraw); - - //solium-disable-next-line - emit Withdraw(asset, msg.sender, amount); + uint256 reserveIndex = reserve.index; + if (!userConfig.isBorrowing(reserveIndex)) { + userConfig.setBorrowing(reserveIndex, true); } - /** - * @dev Allows users to borrow a specific amount of the reserve currency, provided that the borrower - * already deposited enough collateral. - * @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( - address asset, - uint256 amount, - uint256 interestRateMode, - uint16 referralCode - ) external override nonReentrant { - ReserveLogic.ReserveData storage reserve = _reserves[asset]; - UserConfiguration.Map storage userConfig = _usersConfig[msg.sender]; + //if we reached this point, we can transfer + IAToken(aToken).transferUnderlyingTo(msg.sender, amount); - uint256 amountInETH = IPriceOracleGetter(_addressesProvider.getPriceOracle()) - .getAssetPrice(asset) - .mul(amount) - .div(10**reserve.configuration.getDecimals()); //price is in ether + emit Borrow( + asset, + msg.sender, + amount, + interestRateMode, + ReserveLogic.InterestRateMode(interestRateMode) == ReserveLogic.InterestRateMode.STABLE + ? userStableRate + : reserve.currentVariableBorrowRate, + referralCode + ); + } - ValidationLogic.validateBorrow( - reserve, - asset, - amount, - amountInETH, - interestRateMode, - MAX_STABLE_RATE_BORROW_SIZE_PERCENT, - _reserves, - _usersConfig[msg.sender], - _reservesList, - _addressesProvider.getPriceOracle() - ); + /** + * @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. + * @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 + * @param onBehalfOf the address for which msg.sender is repaying. + **/ + function repay( + address asset, + uint256 amount, + uint256 rateMode, + address onBehalfOf + ) external override nonReentrant { + ReserveLogic.ReserveData storage reserve = _reserves[asset]; - //caching the current stable borrow rate - uint256 userStableRate = reserve.currentStableBorrowRate; + (uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(onBehalfOf, reserve); - reserve.updateCumulativeIndexesAndTimestamp(); + ReserveLogic.InterestRateMode interestRateMode = ReserveLogic.InterestRateMode(rateMode); - if ( - ReserveLogic.InterestRateMode(interestRateMode) == ReserveLogic.InterestRateMode.STABLE - ) { - IStableDebtToken(reserve.stableDebtTokenAddress).mint( - msg.sender, - amount, - userStableRate - ); - } else { - IVariableDebtToken(reserve.variableDebtTokenAddress).mint(msg.sender, amount); - } + //default to max amount + uint256 paybackAmount = interestRateMode == ReserveLogic.InterestRateMode.STABLE + ? stableDebt + : variableDebt; - address aToken = reserve.aTokenAddress; - reserve.updateInterestRates(asset, aToken, 0, amount); - - uint256 reserveIndex = reserve.index; - if (!userConfig.isBorrowing(reserveIndex)) { - userConfig.setBorrowing(reserveIndex, true); - } - - //if we reached this point, we can transfer - IAToken(aToken).transferUnderlyingTo(msg.sender, amount); - - emit Borrow( - asset, - msg.sender, - amount, - interestRateMode, - ReserveLogic.InterestRateMode(interestRateMode) == ReserveLogic.InterestRateMode.STABLE - ? userStableRate - : reserve.currentVariableBorrowRate, - referralCode - ); + if (amount != UINT_MAX_VALUE && amount < paybackAmount) { + paybackAmount = amount; } - /** - * @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. - * @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 - * @param onBehalfOf the address for which msg.sender is repaying. - **/ - function repay( - address asset, - uint256 amount, - uint256 rateMode, - address onBehalfOf - ) external override nonReentrant { - ReserveLogic.ReserveData storage reserve = _reserves[asset]; + ValidationLogic.validateRepay( + reserve, + amount, + interestRateMode, + onBehalfOf, + stableDebt, + variableDebt + ); - (uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt( - onBehalfOf, - reserve - ); + reserve.updateCumulativeIndexesAndTimestamp(); - ReserveLogic.InterestRateMode interestRateMode = ReserveLogic.InterestRateMode(rateMode); - - //default to max amount - uint256 paybackAmount = interestRateMode == ReserveLogic.InterestRateMode.STABLE - ? stableDebt - : variableDebt; - - if (amount != UINT_MAX_VALUE && amount < paybackAmount) { - paybackAmount = amount; - } - - ValidationLogic.validateRepay( - reserve, - amount, - interestRateMode, - onBehalfOf, - stableDebt, - variableDebt - ); - - reserve.updateCumulativeIndexesAndTimestamp(); - - //burns an equivalent amount of debt tokens - if (interestRateMode == ReserveLogic.InterestRateMode.STABLE) { - IStableDebtToken(reserve.stableDebtTokenAddress).burn(onBehalfOf, paybackAmount); - } else { - IVariableDebtToken(reserve.variableDebtTokenAddress).burn(onBehalfOf, paybackAmount); - } - - address aToken = reserve.aTokenAddress; - reserve.updateInterestRates(asset, aToken, paybackAmount, 0); - - if (stableDebt.add(variableDebt).sub(paybackAmount) == 0) { - _usersConfig[onBehalfOf].setBorrowing(reserve.index, false); - } - - IERC20(asset).safeTransferFrom(msg.sender, aToken, paybackAmount); - - emit Repay(asset, onBehalfOf, msg.sender, paybackAmount); + //burns an equivalent amount of debt tokens + if (interestRateMode == ReserveLogic.InterestRateMode.STABLE) { + IStableDebtToken(reserve.stableDebtTokenAddress).burn(onBehalfOf, paybackAmount); + } else { + IVariableDebtToken(reserve.variableDebtTokenAddress).burn(onBehalfOf, paybackAmount); } - /** - * @dev borrowers can user this function to swap between stable and variable borrow rate modes. - * @param asset the address of the reserve on which the user borrowed - * @param rateMode the rate mode that the user wants to swap - **/ - function swapBorrowRateMode(address asset, uint256 rateMode) external override nonReentrant { - ReserveLogic.ReserveData storage reserve = _reserves[asset]; + address aToken = reserve.aTokenAddress; + reserve.updateInterestRates(asset, aToken, paybackAmount, 0); - (uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt( - msg.sender, - reserve - ); - - ReserveLogic.InterestRateMode interestRateMode = ReserveLogic.InterestRateMode(rateMode); - - ValidationLogic.validateSwapRateMode( - reserve, - _usersConfig[msg.sender], - stableDebt, - variableDebt, - interestRateMode - ); - - reserve.updateCumulativeIndexesAndTimestamp(); - - if (interestRateMode == ReserveLogic.InterestRateMode.STABLE) { - //burn stable rate tokens, mint variable rate tokens - 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 - ); - } - - reserve.updateInterestRates(asset, reserve.aTokenAddress, 0, 0); - - emit Swap( - asset, - msg.sender, - //solium-disable-next-line - block.timestamp - ); + if (stableDebt.add(variableDebt).sub(paybackAmount) == 0) { + _usersConfig[onBehalfOf].setBorrowing(reserve.index, false); } - /** - * @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. - * @param asset the address of the reserve - * @param user the address of the user to be rebalanced - **/ - function rebalanceStableBorrowRate(address asset, address user) external override nonReentrant { - ReserveLogic.ReserveData storage reserve = _reserves[asset]; + IERC20(asset).safeTransferFrom(msg.sender, aToken, paybackAmount); - IStableDebtToken stableDebtToken = IStableDebtToken(reserve.stableDebtTokenAddress); + emit Repay(asset, onBehalfOf, msg.sender, paybackAmount); + } - uint256 stableBorrowBalance = IERC20(address(stableDebtToken)).balanceOf(user); + /** + * @dev borrowers can user this function to swap between stable and variable borrow rate modes. + * @param asset the address of the reserve on which the user borrowed + * @param rateMode the rate mode that the user wants to swap + **/ + function swapBorrowRateMode(address asset, uint256 rateMode) external override nonReentrant { + ReserveLogic.ReserveData storage reserve = _reserves[asset]; - // user must be borrowing on asset at a stable rate - require(stableBorrowBalance > 0, NOT_ENOUGH_STABLE_BORROW_BALANCE); + (uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(msg.sender, reserve); - uint256 rebalanceDownRateThreshold = reserve.currentStableBorrowRate.rayMul( - WadRayMath.ray().add(REBALANCE_DOWN_RATE_DELTA) - ); + ReserveLogic.InterestRateMode interestRateMode = ReserveLogic.InterestRateMode(rateMode); - //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. + ValidationLogic.validateSwapRateMode( + reserve, + _usersConfig[msg.sender], + stableDebt, + variableDebt, + interestRateMode + ); - uint256 userStableRate = stableDebtToken.getUserStableRate(user); + reserve.updateCumulativeIndexesAndTimestamp(); - require( - userStableRate < reserve.currentLiquidityRate || - userStableRate > rebalanceDownRateThreshold, - INTERESTRATE_REBALANCE_CONDITIONS_NOT_MET - ); - - //burn old debt tokens, mint new ones - - reserve.updateCumulativeIndexesAndTimestamp(); - - stableDebtToken.burn(user, stableBorrowBalance); - stableDebtToken.mint(user, stableBorrowBalance, reserve.currentStableBorrowRate); - - reserve.updateInterestRates(asset, reserve.aTokenAddress, 0, 0); - - emit RebalanceStableBorrowRate(asset, user); - - return; + if (interestRateMode == ReserveLogic.InterestRateMode.STABLE) { + //burn stable rate tokens, mint variable rate tokens + 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 + ); } - /** - * @dev allows depositors to enable or disable a specific deposit as collateral. - * @param asset the address of the reserve - * @param useAsCollateral true if the user wants to user the deposit as collateral, false otherwise. - **/ - function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) - external - override - nonReentrant - { - ReserveLogic.ReserveData storage reserve = _reserves[asset]; + reserve.updateInterestRates(asset, reserve.aTokenAddress, 0, 0); - ValidationLogic.validateSetUseReserveAsCollateral( - reserve, - asset, - _reserves, - _usersConfig[msg.sender], - _reservesList, - _addressesProvider.getPriceOracle() - ); + emit Swap( + asset, + msg.sender, + //solium-disable-next-line + block.timestamp + ); + } - _usersConfig[msg.sender].setUsingAsCollateral(reserve.index, useAsCollateral); + /** + * @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. + * @param asset the address of the reserve + * @param user the address of the user to be rebalanced + **/ + function rebalanceStableBorrowRate(address asset, address user) external override nonReentrant { + ReserveLogic.ReserveData storage reserve = _reserves[asset]; - if (useAsCollateral) { - emit ReserveUsedAsCollateralEnabled(asset, msg.sender); - } else { - emit ReserveUsedAsCollateralDisabled(asset, msg.sender); - } + IStableDebtToken stableDebtToken = IStableDebtToken(reserve.stableDebtTokenAddress); + + uint256 stableBorrowBalance = IERC20(address(stableDebtToken)).balanceOf(user); + + // user must be borrowing on asset at a stable rate + require(stableBorrowBalance > 0, NOT_ENOUGH_STABLE_BORROW_BALANCE); + + uint256 rebalanceDownRateThreshold = reserve.currentStableBorrowRate.rayMul( + WadRayMath.ray().add(REBALANCE_DOWN_RATE_DELTA) + ); + + //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, + INTERESTRATE_REBALANCE_CONDITIONS_NOT_MET + ); + + //burn old debt tokens, mint new ones + + reserve.updateCumulativeIndexesAndTimestamp(); + + stableDebtToken.burn(user, stableBorrowBalance); + stableDebtToken.mint(user, stableBorrowBalance, reserve.currentStableBorrowRate); + + reserve.updateInterestRates(asset, reserve.aTokenAddress, 0, 0); + + emit RebalanceStableBorrowRate(asset, user); + + return; + } + + /** + * @dev allows depositors to enable or disable a specific deposit as collateral. + * @param asset the address of the reserve + * @param useAsCollateral true if the user wants to user the deposit as collateral, false otherwise. + **/ + function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) + external + override + nonReentrant + { + ReserveLogic.ReserveData storage reserve = _reserves[asset]; + + ValidationLogic.validateSetUseReserveAsCollateral( + reserve, + asset, + _reserves, + _usersConfig[msg.sender], + _reservesList, + _addressesProvider.getPriceOracle() + ); + + _usersConfig[msg.sender].setUsingAsCollateral(reserve.index, useAsCollateral); + + if (useAsCollateral) { + emit ReserveUsedAsCollateralEnabled(asset, msg.sender); + } else { + emit ReserveUsedAsCollateralDisabled(asset, msg.sender); } + } - /** - * @dev users can invoke this function to liquidate an undercollateralized position. - * @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, - address asset, - address user, - uint256 purchaseAmount, - bool receiveAToken - ) external override nonReentrant { - address liquidationManager = _addressesProvider.getLendingPoolLiquidationManager(); + /** + * @dev users can invoke this function to liquidate an undercollateralized position. + * @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, + 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, - asset, - user, - purchaseAmount, - receiveAToken - ) - ); - require(success, LIQUIDATION_CALL_FAILED); + //solium-disable-next-line + (bool success, bytes memory result) = liquidationManager.delegatecall( + abi.encodeWithSignature( + 'liquidationCall(address,address,address,uint256,bool)', + collateral, + asset, + user, + purchaseAmount, + receiveAToken + ) + ); + require(success, LIQUIDATION_CALL_FAILED); - (uint256 returnCode, string memory returnMessage) = abi.decode(result, (uint256, string)); + (uint256 returnCode, string memory returnMessage) = abi.decode(result, (uint256, string)); - if (returnCode != 0) { - //error found - revert(string(abi.encodePacked(returnMessage))); - } + if (returnCode != 0) { + //error found + revert(string(abi.encodePacked(returnMessage))); } + } - /** - * @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 - * @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( - address receiverAddress, - address asset, - uint256 amount, - bytes calldata params - ) external override nonReentrant { - ReserveLogic.ReserveData storage reserve = _reserves[asset]; + /** + * @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 + * @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( + address receiverAddress, + address asset, + uint256 amount, + bytes calldata params + ) external override nonReentrant { + ReserveLogic.ReserveData storage reserve = _reserves[asset]; - address aTokenAddress = reserve.aTokenAddress; + address aTokenAddress = reserve.aTokenAddress; - //check that the reserve has enough available liquidity - uint256 availableLiquidityBefore = IERC20(asset).balanceOf(aTokenAddress); + //check that the reserve has enough available liquidity + uint256 availableLiquidityBefore = IERC20(asset).balanceOf(aTokenAddress); - //calculate amount fee - uint256 amountFee = amount.mul(FLASHLOAN_FEE_TOTAL).div(10000); + //calculate amount fee + uint256 amountFee = amount.mul(FLASHLOAN_FEE_TOTAL).div(10000); - require(availableLiquidityBefore >= amount, NOT_ENOUGH_LIQUIDITY_TO_BORROW); - require(amountFee > 0, REQUESTED_AMOUNT_TO_SMALL); + require(availableLiquidityBefore >= amount, NOT_ENOUGH_LIQUIDITY_TO_BORROW); + require(amountFee > 0, REQUESTED_AMOUNT_TO_SMALL); - //get the FlashLoanReceiver instance - IFlashLoanReceiver receiver = IFlashLoanReceiver(receiverAddress); + //get the FlashLoanReceiver instance + IFlashLoanReceiver receiver = IFlashLoanReceiver(receiverAddress); - //transfer funds to the receiver - IAToken(aTokenAddress).transferUnderlyingTo(receiverAddress, amount); + //transfer funds to the receiver + IAToken(aTokenAddress).transferUnderlyingTo(receiverAddress, amount); - //execute action of the receiver - receiver.executeOperation(asset, aTokenAddress, amount, amountFee, params); + //execute action of the receiver + receiver.executeOperation(asset, aTokenAddress, amount, amountFee, params); - //check that the actual balance of the core contract includes the returned amount - uint256 availableLiquidityAfter = IERC20(asset).balanceOf(aTokenAddress); + //check that the actual balance of the core contract includes the returned amount + uint256 availableLiquidityAfter = IERC20(asset).balanceOf(aTokenAddress); - require( - availableLiquidityAfter == availableLiquidityBefore.add(amountFee), - INCONSISTENT_PROTOCOL_ACTUAL_BALANCE - ); + require( + availableLiquidityAfter == availableLiquidityBefore.add(amountFee), + INCONSISTENT_PROTOCOL_ACTUAL_BALANCE + ); - //compounding the cumulated interest - reserve.updateCumulativeIndexesAndTimestamp(); + //compounding the cumulated interest + reserve.updateCumulativeIndexesAndTimestamp(); - uint256 totalLiquidityBefore = availableLiquidityBefore - .add(IERC20(reserve.variableDebtTokenAddress).totalSupply()) - .add(IERC20(reserve.stableDebtTokenAddress).totalSupply()); + uint256 totalLiquidityBefore = availableLiquidityBefore + .add(IERC20(reserve.variableDebtTokenAddress).totalSupply()) + .add(IERC20(reserve.stableDebtTokenAddress).totalSupply()); - //compounding the received fee into the reserve - reserve.cumulateToLiquidityIndex(totalLiquidityBefore, amountFee); + //compounding the received fee into the reserve + reserve.cumulateToLiquidityIndex(totalLiquidityBefore, amountFee); - //refresh interest rates - reserve.updateInterestRates(asset, aTokenAddress, amountFee, 0); + //refresh interest rates + reserve.updateInterestRates(asset, aTokenAddress, amountFee, 0); - //solium-disable-next-line - emit FlashLoan(receiverAddress, asset, amount, amountFee); + //solium-disable-next-line + emit FlashLoan(receiverAddress, asset, amount, amountFee); + } + + /** + * @dev accessory functions to fetch data from the core contract + **/ + + function getReserveConfigurationData(address asset) + external + override + view + returns ( + uint256 decimals, + uint256 ltv, + uint256 liquidationThreshold, + uint256 liquidationBonus, + address interestRateStrategyAddress, + bool usageAsCollateralEnabled, + bool borrowingEnabled, + bool stableBorrowRateEnabled, + bool isActive, + bool isFreezed + ) + { + ReserveLogic.ReserveData storage reserve = _reserves[asset]; + + return ( + reserve.configuration.getDecimals(), + reserve.configuration.getLtv(), + reserve.configuration.getLiquidationThreshold(), + reserve.configuration.getLiquidationBonus(), + reserve.interestRateStrategyAddress, + reserve.configuration.getLtv() != 0, + reserve.configuration.getBorrowingEnabled(), + reserve.configuration.getStableRateBorrowingEnabled(), + reserve.configuration.getActive(), + reserve.configuration.getFrozen() + ); + } + + function getReserveTokensAddresses(address asset) + external + override + view + returns ( + address aTokenAddress, + address stableDebtTokenAddress, + address variableDebtTokenAddress + ) + { + ReserveLogic.ReserveData storage reserve = _reserves[asset]; + + return ( + reserve.aTokenAddress, + reserve.stableDebtTokenAddress, + reserve.variableDebtTokenAddress + ); + } + + 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 + ) + { + ReserveLogic.ReserveData memory reserve = _reserves[asset]; + return ( + IERC20(asset).balanceOf(reserve.aTokenAddress), + IERC20(reserve.stableDebtTokenAddress).totalSupply(), + IERC20(reserve.variableDebtTokenAddress).totalSupply(), + reserve.currentLiquidityRate, + reserve.currentVariableBorrowRate, + reserve.currentStableBorrowRate, + IStableDebtToken(reserve.stableDebtTokenAddress).getAverageStableRate(), + 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, + _reserves, + _usersConfig[user], + _reservesList, + _addressesProvider.getPriceOracle() + ); + + availableBorrowsETH = GenericLogic.calculateAvailableBorrowsETH( + totalCollateralETH, + totalBorrowsETH, + ltv + ); + } + + 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 + ) + { + ReserveLogic.ReserveData storage reserve = _reserves[asset]; + + currentATokenBalance = IERC20(reserve.aTokenAddress).balanceOf(user); + (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 + ); + 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 { + revert(); + } + + /** + * @dev initializes a reserve + * @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( + address asset, + address aTokenAddress, + address stableDebtAddress, + address variableDebtAddress, + address interestRateStrategyAddress + ) external override onlyLendingPoolConfigurator { + _reserves[asset].init( + aTokenAddress, + stableDebtAddress, + variableDebtAddress, + interestRateStrategyAddress + ); + _addReserveToList(asset); + } + + /** + * @dev updates the address of the interest rate strategy contract + * @param asset the address of the reserve + * @param rateStrategyAddress the address of the interest rate strategy contract + **/ + + function setReserveInterestRateStrategyAddress(address asset, address rateStrategyAddress) + external + override + onlyLendingPoolConfigurator + { + _reserves[asset].interestRateStrategyAddress = rateStrategyAddress; + } + + function setConfiguration(address asset, uint256 configuration) + external + override + onlyLendingPoolConfigurator + { + _reserves[asset].configuration.data = configuration; + } + + function getConfiguration(address asset) + external + override + view + returns (ReserveConfiguration.Map memory) + { + return _reserves[asset].configuration; + } + + /** + * @notice internal functions + **/ + + /** + * @dev adds a reserve to the array of the _reserves address + **/ + function _addReserveToList(address asset) internal { + bool reserveAlreadyAdded = false; + for (uint256 i = 0; i < _reservesList.length; i++) + if (_reservesList[i] == asset) { + reserveAlreadyAdded = true; + } + if (!reserveAlreadyAdded) { + _reserves[asset].index = uint8(_reservesList.length); + _reservesList.push(asset); } + } - /** - * @dev accessory functions to fetch data from the core contract - **/ + /** + * @dev returns the normalized income per unit of asset + * @param asset the address of the reserve + * @return the reserve normalized income + */ + function getReserveNormalizedIncome(address asset) external override view returns (uint256) { + return _reserves[asset].getNormalizedIncome(); + } - function getReserveConfigurationData(address asset) - external - override - view - returns ( - uint256 decimals, - uint256 ltv, - uint256 liquidationThreshold, - uint256 liquidationBonus, - address interestRateStrategyAddress, - bool usageAsCollateralEnabled, - bool borrowingEnabled, - bool stableBorrowRateEnabled, - bool isActive, - bool isFreezed - ) - { - ReserveLogic.ReserveData storage reserve = _reserves[asset]; + /** + * @dev returns the normalized variable debt per unit of asset + * @param asset the address of the reserve + * @return the reserve normalized debt + */ + function getReserveNormalizedVariableDebt(address asset) + external + override + view + returns (uint256) + { + return _reserves[asset].getNormalizedDebt(); + } - return ( - reserve.configuration.getDecimals(), - reserve.configuration.getLtv(), - reserve.configuration.getLiquidationThreshold(), - reserve.configuration.getLiquidationBonus(), - reserve.interestRateStrategyAddress, - reserve.configuration.getLtv() != 0, - reserve.configuration.getBorrowingEnabled(), - reserve.configuration.getStableRateBorrowingEnabled(), - reserve.configuration.getActive(), - reserve.configuration.getFrozen() - ); - } + /** + * @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 + */ + function balanceDecreaseAllowed( + address asset, + address user, + uint256 amount + ) external override view returns (bool) { + return + GenericLogic.balanceDecreaseAllowed( + asset, + user, + amount, + _reserves, + _usersConfig[user], + _reservesList, + _addressesProvider.getPriceOracle() + ); + } - function getReserveTokensAddresses(address asset) - external - override - view - returns ( - address aTokenAddress, - address stableDebtTokenAddress, - address variableDebtTokenAddress - ) - { - ReserveLogic.ReserveData storage reserve = _reserves[asset]; + /** + * @dev returns the list of the initialized reserves + **/ + function getReservesList() external view returns (address[] memory) { + return _reservesList; + } - return ( - reserve.aTokenAddress, - reserve.stableDebtTokenAddress, - reserve.variableDebtTokenAddress - ); - } - - 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 - ) - { - ReserveLogic.ReserveData memory reserve = _reserves[asset]; - return ( - IERC20(asset).balanceOf(reserve.aTokenAddress), - IERC20(reserve.stableDebtTokenAddress).totalSupply(), - IERC20(reserve.variableDebtTokenAddress).totalSupply(), - reserve.currentLiquidityRate, - reserve.currentVariableBorrowRate, - reserve.currentStableBorrowRate, - IStableDebtToken(reserve.stableDebtTokenAddress).getAverageStableRate(), - 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, - _reserves, - _usersConfig[user], - _reservesList, - _addressesProvider.getPriceOracle() - ); - - availableBorrowsETH = GenericLogic.calculateAvailableBorrowsETH( - totalCollateralETH, - totalBorrowsETH, - ltv - ); - } - - 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 - ) - { - ReserveLogic.ReserveData storage reserve = _reserves[asset]; - - currentATokenBalance = IERC20(reserve.aTokenAddress).balanceOf(user); - (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 - ); - 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 { - revert(); - } - - /** - * @dev initializes a reserve - * @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( - address asset, - address aTokenAddress, - address stableDebtAddress, - address variableDebtAddress, - address interestRateStrategyAddress - ) external override onlyLendingPoolConfigurator { - _reserves[asset].init( - aTokenAddress, - stableDebtAddress, - variableDebtAddress, - interestRateStrategyAddress - ); - _addReserveToList(asset); - } - - /** - * @dev updates the address of the interest rate strategy contract - * @param asset the address of the reserve - * @param rateStrategyAddress the address of the interest rate strategy contract - **/ - - function setReserveInterestRateStrategyAddress(address asset, address rateStrategyAddress) - external - override - onlyLendingPoolConfigurator - { - _reserves[asset].interestRateStrategyAddress = rateStrategyAddress; - } - - function setConfiguration(address asset, uint256 configuration) - external - override - onlyLendingPoolConfigurator - { - _reserves[asset].configuration.data = configuration; - } - - function getConfiguration(address asset) - external - override - view - returns (ReserveConfiguration.Map memory) - { - return _reserves[asset].configuration; - } - - /** - * @notice internal functions - **/ - - /** - * @dev adds a reserve to the array of the _reserves address - **/ - function _addReserveToList(address asset) internal { - bool reserveAlreadyAdded = false; - for (uint256 i = 0; i < _reservesList.length; i++) - if (_reservesList[i] == asset) { - reserveAlreadyAdded = true; - } - if (!reserveAlreadyAdded) { - _reserves[asset].index = uint8(_reservesList.length); - _reservesList.push(asset); - } - } - - /** - * @dev returns the normalized income per unit of asset - * @param asset the address of the reserve - * @return the reserve normalized income - */ - function getReserveNormalizedIncome(address asset) external override view returns (uint256) { - return _reserves[asset].getNormalizedIncome(); - } - - /** - * @dev returns the normalized variable debt per unit of asset - * @param asset the address of the reserve - * @return the reserve normalized debt - */ - function getReserveNormalizedVariableDebt(address asset) - external - override - view - returns (uint256) - { - return _reserves[asset].getNormalizedDebt(); - } - - /** - * @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 - */ - function balanceDecreaseAllowed( - address asset, - address user, - uint256 amount - ) external override view returns (bool) { - return - GenericLogic.balanceDecreaseAllowed( - asset, - user, - amount, - _reserves, - _usersConfig[user], - _reservesList, - _addressesProvider.getPriceOracle() - ); - } - - /** - * @dev returns the list of the initialized reserves - **/ - function getReservesList() external view returns (address[] memory) { - return _reservesList; - } - - /** - * @dev returns the addresses provider - **/ - function getAddressesProvider() external view returns (ILendingPoolAddressesProvider) { - return _addressesProvider; - } + /** + * @dev returns the addresses provider + **/ + function getAddressesProvider() external view returns (ILendingPoolAddressesProvider) { + return _addressesProvider; + } } diff --git a/contracts/lendingpool/LendingPoolConfigurator.sol b/contracts/lendingpool/LendingPoolConfigurator.sol index 5a2d732b..8ed719c7 100644 --- a/contracts/lendingpool/LendingPoolConfigurator.sol +++ b/contracts/lendingpool/LendingPoolConfigurator.sol @@ -25,6 +25,10 @@ contract LendingPoolConfigurator is VersionedInitializable { using SafeMath for uint256; using ReserveConfiguration for ReserveConfiguration.Map; + //require error messages + string private constant CALLER_NOT_LENDING_POOL_MANAGER = '1'; // 'The caller must be a lending pool manager' + string private constant RESERVE_LIQUIDITY_NOT_0 = '2'; // 'The liquidity of the reserve needs to be 0' + /** * @dev emitted when a reserve is initialized. * @param asset the address of the reserve @@ -178,7 +182,7 @@ contract LendingPoolConfigurator is VersionedInitializable { modifier onlyLendingPoolManager { require( addressesProvider.getLendingPoolManager() == msg.sender, - 'The caller must be a lending pool manager' + CALLER_NOT_LENDING_POOL_MANAGER ); _; } @@ -425,7 +429,7 @@ contract LendingPoolConfigurator is VersionedInitializable { ) = pool.getReserveData(asset); require( availableLiquidity == 0 && totalBorrowsStable == 0 && totalBorrowsVariable == 0, - 'The liquidity of the reserve needs to be 0' + RESERVE_LIQUIDITY_NOT_0 ); ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset);