diff --git a/contracts/interfaces/ILendingPoolConfigurator.sol b/contracts/interfaces/ILendingPoolConfigurator.sol index e7f855a1..f4362417 100644 --- a/contracts/interfaces/ILendingPoolConfigurator.sol +++ b/contracts/interfaces/ILendingPoolConfigurator.sol @@ -2,44 +2,9 @@ pragma solidity 0.6.12; pragma experimental ABIEncoderV2; +import {ConfiguratorInputTypes} from '../protocol/libraries/types/ConfiguratorInputTypes.sol'; + interface ILendingPoolConfigurator { - struct InitReserveInput { - address aTokenImpl; - address stableDebtTokenImpl; - address variableDebtTokenImpl; - uint8 underlyingAssetDecimals; - address interestRateStrategyAddress; - address underlyingAsset; - address treasury; - address incentivesController; - string underlyingAssetName; - string aTokenName; - string aTokenSymbol; - string variableDebtTokenName; - string variableDebtTokenSymbol; - string stableDebtTokenName; - string stableDebtTokenSymbol; - bytes params; - } - - struct UpdateATokenInput { - address asset; - address treasury; - address incentivesController; - string name; - string symbol; - address implementation; - bytes params; - } - - struct UpdateDebtTokenInput { - address asset; - address incentivesController; - string name; - string symbol; - address implementation; - bytes params; - } /** * @dev Emitted when a reserve is initialized. @@ -132,12 +97,6 @@ interface ILendingPoolConfigurator { **/ event ReserveUnpaused(address indexed asset); - /** - * @dev Emitted when a reserve is dropped - * @param asset The address of the underlying asset of the reserve - **/ - event ReserveDropped(address indexed asset); - /** * @dev Emitted when a reserve factor is updated * @param asset The address of the underlying asset of the reserve @@ -249,25 +208,25 @@ interface ILendingPoolConfigurator { * @dev Initializes reserves in batch * @param input The array of reserves initialization parameters **/ - function batchInitReserve(InitReserveInput[] calldata input) external; + function batchInitReserve(ConfiguratorInputTypes.InitReserveInput[] calldata input) external; /** * @dev Updates the aToken implementation for the reserve * @param input The aToken update paramenters **/ - function updateAToken(UpdateATokenInput calldata input) external; + function updateAToken(ConfiguratorInputTypes.UpdateATokenInput calldata input) external; /** * @dev Updates the stable debt token implementation for the reserve * @param input The stableDebtToken update parameters **/ - function updateStableDebtToken(UpdateDebtTokenInput calldata input) external; + function updateStableDebtToken(ConfiguratorInputTypes.UpdateDebtTokenInput calldata input) external; /** * @dev Updates the variable debt token implementation for the asset * @param input The variableDebtToken update parameters **/ - function updateVariableDebtToken(UpdateDebtTokenInput calldata input) external; + function updateVariableDebtToken(ConfiguratorInputTypes.UpdateDebtTokenInput calldata input) external; /** * @dev Enables borrowing on a reserve diff --git a/contracts/protocol/lendingpool/LendingPool.sol b/contracts/protocol/lendingpool/LendingPool.sol index 661dff93..b78b6bdb 100644 --- a/contracts/protocol/lendingpool/LendingPool.sol +++ b/contracts/protocol/lendingpool/LendingPool.sol @@ -27,6 +27,9 @@ import {UserConfiguration} from '../libraries/configuration/UserConfiguration.so import {DataTypes} from '../libraries/types/DataTypes.sol'; import {LendingPoolStorage} from './LendingPoolStorage.sol'; +import {LendingPoolBaseLogic} from '../libraries/logic/LendingPoolBaseLogic.sol'; +import {LendingPoolOtherLogic} from '../libraries/logic/LendingPoolOtherLogic.sol'; + /** * @title LendingPool contract * @dev Main point of interaction with an Aave protocol's market @@ -135,7 +138,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage address onBehalfOf ) external override { _executeBorrow( - ExecuteBorrowParams( + DataTypes.ExecuteBorrowParams( asset, msg.sender, onBehalfOf, @@ -183,90 +186,29 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage ///@inheritdoc ILendingPool function swapBorrowRateMode(address asset, uint256 rateMode) external override { DataTypes.ReserveData storage reserve = _reserves[asset]; - DataTypes.ReserveCache memory reserveCache = reserve.cache(); - - (uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(msg.sender, reserve); - - DataTypes.InterestRateMode interestRateMode = DataTypes.InterestRateMode(rateMode); - - ValidationLogic.validateSwapRateMode( - reserve, - reserveCache, - _usersConfig[msg.sender], - stableDebt, - variableDebt, - interestRateMode - ); - - reserve.updateState(reserveCache); - - if (interestRateMode == DataTypes.InterestRateMode.STABLE) { - IStableDebtToken(reserveCache.stableDebtTokenAddress).burn(msg.sender, stableDebt); - IVariableDebtToken(reserveCache.variableDebtTokenAddress).mint( - msg.sender, - msg.sender, - stableDebt, - reserveCache.nextVariableBorrowIndex - ); - reserveCache.refreshDebt(0, stableDebt, stableDebt, 0); - } else { - IVariableDebtToken(reserveCache.variableDebtTokenAddress).burn( - msg.sender, - variableDebt, - reserveCache.nextVariableBorrowIndex - ); - IStableDebtToken(reserveCache.stableDebtTokenAddress).mint( - msg.sender, - msg.sender, - variableDebt, - reserve.currentStableBorrowRate - ); - reserveCache.refreshDebt(variableDebt, 0, 0, variableDebt); - } - - reserve.updateInterestRates(reserveCache, asset, 0, 0); - - emit Swap(asset, msg.sender, rateMode); + DataTypes.UserConfigurationMap storage userConfig = _usersConfig[msg.sender]; + LendingPoolOtherLogic.swapBorrowRateMode(reserve, userConfig, asset, rateMode); } ///@inheritdoc ILendingPool function rebalanceStableBorrowRate(address asset, address user) external override { DataTypes.ReserveData storage reserve = _reserves[asset]; - DataTypes.ReserveCache memory reserveCache = reserve.cache(); - - IERC20 stableDebtToken = IERC20(reserveCache.stableDebtTokenAddress); - IERC20 variableDebtToken = IERC20(reserveCache.variableDebtTokenAddress); - uint256 stableDebt = IERC20(stableDebtToken).balanceOf(user); - - ValidationLogic.validateRebalanceStableBorrowRate( - reserve, - reserveCache, - asset, - stableDebtToken, - variableDebtToken, - reserveCache.aTokenAddress - ); - - reserve.updateState(reserveCache); - - IStableDebtToken(address(stableDebtToken)).burn(user, stableDebt); - IStableDebtToken(address(stableDebtToken)).mint( - user, - user, - stableDebt, - reserve.currentStableBorrowRate - ); - - reserveCache.refreshDebt(stableDebt, stableDebt, 0, 0); - - reserve.updateInterestRates(reserveCache, asset, 0, 0); - - emit RebalanceStableBorrowRate(asset, user); + LendingPoolOtherLogic.rebalanceStableBorrowRate(reserve, asset, user); } ///@inheritdoc ILendingPool function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external override { - DataTypes.ReserveData storage reserve = _reserves[asset]; + DataTypes.UserConfigurationMap storage userConfig = _usersConfig[msg.sender]; + LendingPoolOtherLogic.setUserUseReserveAsCollateral( + _reserves, + userConfig, + asset, + useAsCollateral, + _reservesList, + _reservesCount, + _addressesProvider.getPriceOracle() + ); + /* DataTypes.ReserveData storage reserve = _reserves[asset]; DataTypes.ReserveCache memory reserveCache = reserve.cache(); uint256 userBalance = IERC20(reserveCache.aTokenAddress).balanceOf(msg.sender); @@ -289,7 +231,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage ); emit ReserveUsedAsCollateralDisabled(asset, msg.sender); - } + }*/ } ///@inheritdoc ILendingPool @@ -303,17 +245,16 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage address collateralManager = _addressesProvider.getLendingPoolCollateralManager(); //solium-disable-next-line - (bool success, bytes memory result) = - collateralManager.delegatecall( - abi.encodeWithSignature( - 'liquidationCall(address,address,address,uint256,bool)', - collateralAsset, - debtAsset, - user, - debtToCover, - receiveAToken - ) - ); + (bool success, bytes memory result) = collateralManager.delegatecall( + abi.encodeWithSignature( + 'liquidationCall(address,address,address,uint256,bool)', + collateralAsset, + debtAsset, + user, + debtToCover, + receiveAToken + ) + ); require(success, Errors.LP_LIQUIDATION_CALL_FAILED); @@ -410,7 +351,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage // If the user chose to not return the funds, the system checks if there is enough collateral and // eventually opens a debt position _executeBorrow( - ExecuteBorrowParams( + DataTypes.ExecuteBorrowParams( vars.currentAsset, msg.sender, onBehalfOf, @@ -714,23 +655,29 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage _flashLoanPremiumToProtocol = flashLoanPremiumToProtocol; } - struct ExecuteBorrowParams { - address asset; - address user; - address onBehalfOf; - uint256 amount; - uint256 interestRateMode; - uint16 referralCode; - bool releaseUnderlying; + function _executeDeposit( + address asset, + uint256 amount, + address onBehalfOf, + uint16 referralCode + ) internal { + DataTypes.ReserveData storage reserve = _reserves[asset]; + LendingPoolBaseLogic._executeDeposit( + reserve, + _usersConfig[onBehalfOf], + asset, + amount, + onBehalfOf, + referralCode + ); } - function _executeBorrow(ExecuteBorrowParams memory vars) internal { + function _executeBorrow(DataTypes.ExecuteBorrowParams memory vars) internal { DataTypes.ReserveData storage reserve = _reserves[vars.asset]; - DataTypes.UserConfigurationMap storage userConfig = _usersConfig[vars.onBehalfOf]; DataTypes.ReserveCache memory reserveCache = reserve.cache(); + DataTypes.UserConfigurationMap storage userConfig = _usersConfig[vars.onBehalfOf]; reserve.updateState(reserveCache); - ValidationLogic.validateBorrow( reserveCache, vars.asset, @@ -745,86 +692,10 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage _addressesProvider.getPriceOracle() ); - uint256 currentStableRate = 0; - bool isFirstBorrowing = false; - - if (DataTypes.InterestRateMode(vars.interestRateMode) == DataTypes.InterestRateMode.STABLE) { - currentStableRate = reserve.currentStableBorrowRate; - - isFirstBorrowing = IStableDebtToken(reserveCache.stableDebtTokenAddress).mint( - vars.user, - vars.onBehalfOf, - vars.amount, - currentStableRate - ); - reserveCache.refreshDebt(vars.amount, 0, 0, 0); - } else { - isFirstBorrowing = IVariableDebtToken(reserveCache.variableDebtTokenAddress).mint( - vars.user, - vars.onBehalfOf, - vars.amount, - reserveCache.nextVariableBorrowIndex - ); - reserveCache.refreshDebt(0, 0, vars.amount, 0); - } - - if (isFirstBorrowing) { - userConfig.setBorrowing(reserve.id, true); - } - - reserve.updateInterestRates( - reserveCache, - vars.asset, - 0, - vars.releaseUnderlying ? vars.amount : 0 - ); + LendingPoolBaseLogic._executeBorrow(_reserves, reserveCache, userConfig, vars); _lastBorrower = vars.user; _lastBorrowTimestamp = uint40(block.timestamp); - - if (vars.releaseUnderlying) { - IAToken(reserveCache.aTokenAddress).transferUnderlyingTo(vars.user, vars.amount); - } - - emit Borrow( - vars.asset, - vars.user, - vars.onBehalfOf, - vars.amount, - vars.interestRateMode, - DataTypes.InterestRateMode(vars.interestRateMode) == DataTypes.InterestRateMode.STABLE - ? currentStableRate - : reserve.currentVariableBorrowRate, - vars.referralCode - ); - } - - function _executeDeposit( - address asset, - uint256 amount, - address onBehalfOf, - uint16 referralCode - ) internal { - DataTypes.ReserveData storage reserve = _reserves[asset]; - DataTypes.ReserveCache memory reserveCache = reserve.cache(); - - reserve.updateState(reserveCache); - - ValidationLogic.validateDeposit(reserveCache, amount); - - reserve.updateInterestRates(reserveCache, asset, amount, 0); - - IERC20(asset).safeTransferFrom(msg.sender, reserveCache.aTokenAddress, amount); - - bool isFirstDeposit = - IAToken(reserveCache.aTokenAddress).mint(onBehalfOf, amount, reserveCache.nextLiquidityIndex); - - if (isFirstDeposit) { - _usersConfig[onBehalfOf].setUsingAsCollateral(reserve.id, true); - emit ReserveUsedAsCollateralEnabled(asset, onBehalfOf); - } - - emit Deposit(asset, msg.sender, onBehalfOf, amount, referralCode); } function _executeWithdraw( @@ -832,56 +703,18 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage uint256 amount, address to ) internal returns (uint256) { - DataTypes.ReserveData storage reserve = _reserves[asset]; DataTypes.UserConfigurationMap storage userConfig = _usersConfig[msg.sender]; - DataTypes.ReserveCache memory reserveCache = reserve.cache(); - - reserve.updateState(reserveCache); - - uint256 userBalance = - IAToken(reserveCache.aTokenAddress).scaledBalanceOf(msg.sender).rayMul( - reserveCache.nextLiquidityIndex + return + LendingPoolBaseLogic._executeWithdraw( + _reserves, + userConfig, + asset, + amount, + to, + _reservesList, + _reservesCount, + _addressesProvider.getPriceOracle() ); - - uint256 amountToWithdraw = amount; - - if (amount == type(uint256).max) { - amountToWithdraw = userBalance; - } - - ValidationLogic.validateWithdraw(reserveCache, amountToWithdraw, userBalance); - - reserve.updateInterestRates(reserveCache, asset, 0, amountToWithdraw); - - IAToken(reserveCache.aTokenAddress).burn( - msg.sender, - to, - amountToWithdraw, - reserveCache.nextLiquidityIndex - ); - - if (userConfig.isUsingAsCollateral(reserve.id)) { - if (userConfig.isBorrowingAny()) { - ValidationLogic.validateHFAndLtv( - asset, - msg.sender, - _reserves, - userConfig, - _reservesList, - _reservesCount, - _addressesProvider.getPriceOracle() - ); - } - - if (amountToWithdraw == userBalance) { - userConfig.setUsingAsCollateral(reserve.id, false); - emit ReserveUsedAsCollateralDisabled(asset, msg.sender); - } - } - - emit Withdraw(asset, msg.sender, to, amountToWithdraw); - - return amountToWithdraw; } function _executeRepay( @@ -891,57 +724,18 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage address onBehalfOf ) internal returns (uint256) { DataTypes.ReserveData storage reserve = _reserves[asset]; - DataTypes.ReserveCache memory reserveCache = reserve.cache(); - - (uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(onBehalfOf, reserve); - - DataTypes.InterestRateMode interestRateMode = DataTypes.InterestRateMode(rateMode); - - ValidationLogic.validateRepay( - _lastBorrower, - _lastBorrowTimestamp, - reserveCache, - amount, - interestRateMode, - onBehalfOf, - stableDebt, - variableDebt - ); - - uint256 paybackAmount = - interestRateMode == DataTypes.InterestRateMode.STABLE ? stableDebt : variableDebt; - - if (amount < paybackAmount) { - paybackAmount = amount; - } - - reserve.updateState(reserveCache); - - if (interestRateMode == DataTypes.InterestRateMode.STABLE) { - IStableDebtToken(reserveCache.stableDebtTokenAddress).burn(onBehalfOf, paybackAmount); - reserveCache.refreshDebt(0, paybackAmount, 0, 0); - } else { - IVariableDebtToken(reserveCache.variableDebtTokenAddress).burn( + DataTypes.UserConfigurationMap storage userConfig = _usersConfig[msg.sender]; + return + LendingPoolBaseLogic._executeRepay( + reserve, + userConfig, + asset, + amount, + rateMode, onBehalfOf, - paybackAmount, - reserveCache.nextVariableBorrowIndex + _lastBorrower, + _lastBorrowTimestamp ); - reserveCache.refreshDebt(0, 0, 0, paybackAmount); - } - - reserve.updateInterestRates(reserveCache, asset, paybackAmount, 0); - - if (stableDebt.add(variableDebt).sub(paybackAmount) == 0) { - _usersConfig[onBehalfOf].setBorrowing(reserve.id, false); - } - - IERC20(asset).safeTransferFrom(msg.sender, reserveCache.aTokenAddress, paybackAmount); - - IAToken(reserveCache.aTokenAddress).handleRepayment(msg.sender, paybackAmount); - - emit Repay(asset, onBehalfOf, msg.sender, paybackAmount); - - return paybackAmount; } function _addReserveToList(address asset) internal returns (uint8) { @@ -966,4 +760,4 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage function _removeReserveFromList(address asset) internal { _reservesList[_reserves[asset].id] = address(0); } -} +} \ No newline at end of file diff --git a/contracts/protocol/lendingpool/LendingPoolConfigurator.sol b/contracts/protocol/lendingpool/LendingPoolConfigurator.sol index 79367945..5940dca5 100644 --- a/contracts/protocol/lendingpool/LendingPoolConfigurator.sol +++ b/contracts/protocol/lendingpool/LendingPoolConfigurator.sol @@ -4,9 +4,6 @@ pragma experimental ABIEncoderV2; import {SafeMath} from '../../dependencies/openzeppelin/contracts/SafeMath.sol'; import {VersionedInitializable} from '../libraries/aave-upgradeability/VersionedInitializable.sol'; -import { - InitializableImmutableAdminUpgradeabilityProxy -} from '../libraries/aave-upgradeability/InitializableImmutableAdminUpgradeabilityProxy.sol'; import {ReserveConfiguration} from '../libraries/configuration/ReserveConfiguration.sol'; import {ILendingPoolAddressesProvider} from '../../interfaces/ILendingPoolAddressesProvider.sol'; import {ILendingPool} from '../../interfaces/ILendingPool.sol'; @@ -14,10 +11,9 @@ import {IERC20Detailed} from '../../dependencies/openzeppelin/contracts/IERC20De import {Errors} from '../libraries/helpers/Errors.sol'; import {PercentageMath} from '../libraries/math/PercentageMath.sol'; import {DataTypes} from '../libraries/types/DataTypes.sol'; -import {IInitializableDebtToken} from '../../interfaces/IInitializableDebtToken.sol'; -import {IInitializableAToken} from '../../interfaces/IInitializableAToken.sol'; -import {IAaveIncentivesController} from '../../interfaces/IAaveIncentivesController.sol'; +import {ConfiguratorInputTypes} from '../libraries/types/ConfiguratorInputTypes.sol'; import {ILendingPoolConfigurator} from '../../interfaces/ILendingPoolConfigurator.sol'; +import {ConfiguratorLogic} from '../libraries/logic/ConfiguratorLogic.sol'; /** * @title LendingPoolConfigurator contract @@ -29,6 +25,7 @@ contract LendingPoolConfigurator is VersionedInitializable, ILendingPoolConfigur using SafeMath for uint256; using PercentageMath for uint256; using ReserveConfiguration for DataTypes.ReserveConfigurationMap; + using ConfiguratorLogic for DataTypes.ReserveConfigurationMap; ILendingPoolAddressesProvider internal _addressesProvider; ILendingPool internal _pool; @@ -77,191 +74,47 @@ contract LendingPoolConfigurator is VersionedInitializable, ILendingPoolConfigur } /// @inheritdoc ILendingPoolConfigurator - function batchInitReserve(InitReserveInput[] calldata input) external override onlyPoolAdmin { + function batchInitReserve(ConfiguratorInputTypes.InitReserveInput[] calldata input) + external + override + onlyPoolAdmin + { ILendingPool cachedPool = _pool; for (uint256 i = 0; i < input.length; i++) { - _initReserve(cachedPool, input[i]); + ConfiguratorLogic._initReserve(cachedPool, input[i]); } } - function _initReserve(ILendingPool pool, InitReserveInput calldata input) internal { - address aTokenProxyAddress = - _initTokenWithProxy( - input.aTokenImpl, - abi.encodeWithSelector( - IInitializableAToken.initialize.selector, - pool, - input.treasury, - input.underlyingAsset, - IAaveIncentivesController(input.incentivesController), - input.underlyingAssetDecimals, - input.aTokenName, - input.aTokenSymbol, - input.params - ) - ); - - address stableDebtTokenProxyAddress = - _initTokenWithProxy( - input.stableDebtTokenImpl, - abi.encodeWithSelector( - IInitializableDebtToken.initialize.selector, - pool, - input.underlyingAsset, - IAaveIncentivesController(input.incentivesController), - input.underlyingAssetDecimals, - input.stableDebtTokenName, - input.stableDebtTokenSymbol, - input.params - ) - ); - - address variableDebtTokenProxyAddress = - _initTokenWithProxy( - input.variableDebtTokenImpl, - abi.encodeWithSelector( - IInitializableDebtToken.initialize.selector, - pool, - input.underlyingAsset, - IAaveIncentivesController(input.incentivesController), - input.underlyingAssetDecimals, - input.variableDebtTokenName, - input.variableDebtTokenSymbol, - input.params - ) - ); - - pool.initReserve( - input.underlyingAsset, - aTokenProxyAddress, - stableDebtTokenProxyAddress, - variableDebtTokenProxyAddress, - input.interestRateStrategyAddress - ); - - DataTypes.ReserveConfigurationMap memory currentConfig = - pool.getConfiguration(input.underlyingAsset); - - currentConfig.setDecimals(input.underlyingAssetDecimals); - - currentConfig.setActive(true); - currentConfig.setPaused(false); - currentConfig.setFrozen(false); - - pool.setConfiguration(input.underlyingAsset, currentConfig.data); - - emit ReserveInitialized( - input.underlyingAsset, - aTokenProxyAddress, - stableDebtTokenProxyAddress, - variableDebtTokenProxyAddress, - input.interestRateStrategyAddress - ); - } - /// @inheritdoc ILendingPoolConfigurator function dropReserve(address asset) external override onlyPoolAdmin { - _pool.dropReserve(asset); - emit ReserveDropped(asset); + ConfiguratorLogic.dropReserve(_pool, asset); } /// @inheritdoc ILendingPoolConfigurator - function updateAToken(UpdateATokenInput calldata input) external override onlyPoolAdmin { - ILendingPool cachedPool = _pool; - - DataTypes.ReserveData memory reserveData = cachedPool.getReserveData(input.asset); - - (, , , uint256 decimals, ) = cachedPool.getConfiguration(input.asset).getParamsMemory(); - - bytes memory encodedCall = - abi.encodeWithSelector( - IInitializableAToken.initialize.selector, - cachedPool, - input.treasury, - input.asset, - input.incentivesController, - decimals, - input.name, - input.symbol, - input.params - ); - - _upgradeTokenImplementation(reserveData.aTokenAddress, input.implementation, encodedCall); - - emit ATokenUpgraded(input.asset, reserveData.aTokenAddress, input.implementation); - } - - /// @inheritdoc ILendingPoolConfigurator - function updateStableDebtToken(UpdateDebtTokenInput calldata input) + function updateAToken(ConfiguratorInputTypes.UpdateATokenInput calldata input) external override onlyPoolAdmin { - ILendingPool cachedPool = _pool; - - DataTypes.ReserveData memory reserveData = cachedPool.getReserveData(input.asset); - - (, , , uint256 decimals, ) = cachedPool.getConfiguration(input.asset).getParamsMemory(); - - bytes memory encodedCall = - abi.encodeWithSelector( - IInitializableDebtToken.initialize.selector, - cachedPool, - input.asset, - input.incentivesController, - decimals, - input.name, - input.symbol, - input.params - ); - - _upgradeTokenImplementation( - reserveData.stableDebtTokenAddress, - input.implementation, - encodedCall - ); - - emit StableDebtTokenUpgraded( - input.asset, - reserveData.stableDebtTokenAddress, - input.implementation - ); + ConfiguratorLogic.updateAToken(_pool, input); } /// @inheritdoc ILendingPoolConfigurator - function updateVariableDebtToken(UpdateDebtTokenInput calldata input) + function updateStableDebtToken(ConfiguratorInputTypes.UpdateDebtTokenInput calldata input) external override onlyPoolAdmin { - ILendingPool cachedPool = _pool; - DataTypes.ReserveData memory reserveData = cachedPool.getReserveData(input.asset); + ConfiguratorLogic.updateStableDebtToken(_pool, input); + } - (, , , uint256 decimals, ) = cachedPool.getConfiguration(input.asset).getParamsMemory(); - - bytes memory encodedCall = - abi.encodeWithSelector( - IInitializableDebtToken.initialize.selector, - cachedPool, - input.asset, - input.incentivesController, - decimals, - input.name, - input.symbol, - input.params - ); - - _upgradeTokenImplementation( - reserveData.variableDebtTokenAddress, - input.implementation, - encodedCall - ); - - emit VariableDebtTokenUpgraded( - input.asset, - reserveData.variableDebtTokenAddress, - input.implementation - ); + /// @inheritdoc ILendingPoolConfigurator + function updateVariableDebtToken(ConfiguratorInputTypes.UpdateDebtTokenInput calldata input) + external + override + onlyPoolAdmin + { + ConfiguratorLogic.updateStableDebtToken(_pool, input); } /// @inheritdoc ILendingPoolConfigurator @@ -271,24 +124,13 @@ contract LendingPoolConfigurator is VersionedInitializable, ILendingPoolConfigur bool stableBorrowRateEnabled ) external override onlyRiskOrPoolAdmins { DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); - - currentConfig.setBorrowingEnabled(true); - currentConfig.setBorrowCap(borrowCap); - currentConfig.setStableRateBorrowingEnabled(stableBorrowRateEnabled); - - _pool.setConfiguration(asset, currentConfig.data); - - emit BorrowingEnabledOnReserve(asset, stableBorrowRateEnabled); + currentConfig.enableBorrowingOnReserve(_pool, asset, borrowCap, stableBorrowRateEnabled); } /// @inheritdoc ILendingPoolConfigurator function disableBorrowingOnReserve(address asset) external override onlyRiskOrPoolAdmins { DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); - - currentConfig.setBorrowingEnabled(false); - - _pool.setConfiguration(asset, currentConfig.data); - emit BorrowingDisabledOnReserve(asset); + currentConfig.disableBorrowingOnReserve(_pool, asset); } /// @inheritdoc ILendingPoolConfigurator @@ -327,46 +169,25 @@ contract LendingPoolConfigurator is VersionedInitializable, ILendingPoolConfigur _checkNoLiquidity(asset); } - currentConfig.setLtv(ltv); - currentConfig.setLiquidationThreshold(liquidationThreshold); - currentConfig.setLiquidationBonus(liquidationBonus); - - _pool.setConfiguration(asset, currentConfig.data); - - emit CollateralConfigurationChanged(asset, ltv, liquidationThreshold, liquidationBonus); + currentConfig.configureReserveAsCollateral(_pool, asset, ltv, liquidationThreshold, liquidationBonus); } /// @inheritdoc ILendingPoolConfigurator function enableReserveStableRate(address asset) external override onlyRiskOrPoolAdmins { DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); - - currentConfig.setStableRateBorrowingEnabled(true); - - _pool.setConfiguration(asset, currentConfig.data); - - emit StableRateEnabledOnReserve(asset); + currentConfig.enableReserveStableRate(_pool, asset); } /// @inheritdoc ILendingPoolConfigurator function disableReserveStableRate(address asset) external override onlyRiskOrPoolAdmins { DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); - - currentConfig.setStableRateBorrowingEnabled(false); - - _pool.setConfiguration(asset, currentConfig.data); - - emit StableRateDisabledOnReserve(asset); + currentConfig.disableReserveStableRate(_pool, asset); } /// @inheritdoc ILendingPoolConfigurator function activateReserve(address asset) external override onlyPoolAdmin { DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); - - currentConfig.setActive(true); - - _pool.setConfiguration(asset, currentConfig.data); - - emit ReserveActivated(asset); + currentConfig.activateReserve(_pool, asset); } /// @inheritdoc ILendingPoolConfigurator @@ -374,49 +195,25 @@ contract LendingPoolConfigurator is VersionedInitializable, ILendingPoolConfigur _checkNoLiquidity(asset); DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); - - currentConfig.setActive(false); - - _pool.setConfiguration(asset, currentConfig.data); - - emit ReserveDeactivated(asset); + currentConfig.deactivateReserve(_pool, asset); } /// @inheritdoc ILendingPoolConfigurator function freezeReserve(address asset) external override onlyRiskOrPoolAdmins { DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); - - currentConfig.setFrozen(true); - - _pool.setConfiguration(asset, currentConfig.data); - - emit ReserveFrozen(asset); + currentConfig.freezeReserve(_pool, asset); } /// @inheritdoc ILendingPoolConfigurator function unfreezeReserve(address asset) external override onlyRiskOrPoolAdmins { DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); - - currentConfig.setFrozen(false); - - _pool.setConfiguration(asset, currentConfig.data); - - emit ReserveUnfrozen(asset); + currentConfig.unfreezeReserve(_pool, asset); } /// @inheritdoc ILendingPoolConfigurator function setReservePause(address asset, bool paused) public override onlyEmergencyOrPoolAdmin { DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); - - currentConfig.setPaused(paused); - - _pool.setConfiguration(asset, currentConfig.data); - - if (paused) { - emit ReservePaused(asset); - } else { - emit ReserveUnpaused(asset); - } + currentConfig.setReservePause(_pool, asset, paused); } /// @inheritdoc ILendingPoolConfigurator @@ -426,34 +223,19 @@ contract LendingPoolConfigurator is VersionedInitializable, ILendingPoolConfigur onlyRiskOrPoolAdmins { DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); - - currentConfig.setReserveFactor(reserveFactor); - - _pool.setConfiguration(asset, currentConfig.data); - - emit ReserveFactorChanged(asset, reserveFactor); + currentConfig.setReserveFactor(_pool, asset, reserveFactor); } ///@inheritdoc ILendingPoolConfigurator function setBorrowCap(address asset, uint256 borrowCap) external override onlyRiskOrPoolAdmins { DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); - - currentConfig.setBorrowCap(borrowCap); - - _pool.setConfiguration(asset, currentConfig.data); - - emit BorrowCapChanged(asset, borrowCap); + currentConfig.setBorrowCap(_pool, asset, borrowCap); } ///@inheritdoc ILendingPoolConfigurator function setSupplyCap(address asset, uint256 supplyCap) external override onlyRiskOrPoolAdmins { DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); - - currentConfig.setSupplyCap(supplyCap); - - _pool.setConfiguration(asset, currentConfig.data); - - emit SupplyCapChanged(asset, supplyCap); + currentConfig.setSupplyCap(_pool, asset, supplyCap); } ///@inheritdoc ILendingPoolConfigurator @@ -471,7 +253,8 @@ contract LendingPoolConfigurator is VersionedInitializable, ILendingPoolConfigur address[] memory reserves = _pool.getReservesList(); for (uint256 i = 0; i < reserves.length; i++) { - if (reserves[i] != address(0)) { //might happen is a reserve was dropped + if (reserves[i] != address(0)) { + //might happen is a reserve was dropped setReservePause(reserves[i], paused); } } @@ -542,29 +325,6 @@ contract LendingPoolConfigurator is VersionedInitializable, ILendingPoolConfigur emit FlashloanPremiumToProcolUpdated(flashloanPremiumToProtocol); } - function _initTokenWithProxy(address implementation, bytes memory initParams) - internal - returns (address) - { - InitializableImmutableAdminUpgradeabilityProxy proxy = - new InitializableImmutableAdminUpgradeabilityProxy(address(this)); - - proxy.initialize(implementation, initParams); - - return address(proxy); - } - - function _upgradeTokenImplementation( - address proxyAddress, - address implementation, - bytes memory initParams - ) internal { - InitializableImmutableAdminUpgradeabilityProxy proxy = - InitializableImmutableAdminUpgradeabilityProxy(payable(proxyAddress)); - - proxy.upgradeToAndCall(implementation, initParams); - } - function _checkNoLiquidity(address asset) internal view { DataTypes.ReserveData memory reserveData = _pool.getReserveData(asset); diff --git a/contracts/protocol/libraries/logic/ConfiguratorLogic.sol b/contracts/protocol/libraries/logic/ConfiguratorLogic.sol new file mode 100644 index 00000000..3ab42543 --- /dev/null +++ b/contracts/protocol/libraries/logic/ConfiguratorLogic.sol @@ -0,0 +1,606 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import {ILendingPool} from '../../../interfaces/ILendingPool.sol'; +import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol'; +import {DataTypes} from '../types/DataTypes.sol'; +import {ConfiguratorInputTypes} from '../types/ConfiguratorInputTypes.sol'; +import {IInitializableAToken} from '../../../interfaces/IInitializableAToken.sol'; +import {IInitializableDebtToken} from '../../../interfaces/IInitializableDebtToken.sol'; +import {IAaveIncentivesController} from '../../../interfaces/IAaveIncentivesController.sol'; +import {InitializableImmutableAdminUpgradeabilityProxy} from '../aave-upgradeability/InitializableImmutableAdminUpgradeabilityProxy.sol'; + +/** + * @title ConfiguratorLogic library + * @author Aave + * @notice Implements the logic for CONFIGURATOR + */ +library ConfiguratorLogic { + using ReserveConfiguration for DataTypes.ReserveConfigurationMap; + + function _initReserve(ILendingPool pool, ConfiguratorInputTypes.InitReserveInput calldata input) + public + { + address aTokenProxyAddress = _initTokenWithProxy( + input.aTokenImpl, + abi.encodeWithSelector( + IInitializableAToken.initialize.selector, + pool, + input.treasury, + input.underlyingAsset, + IAaveIncentivesController(input.incentivesController), + input.underlyingAssetDecimals, + input.aTokenName, + input.aTokenSymbol, + input.params + ) + ); + + address stableDebtTokenProxyAddress = _initTokenWithProxy( + input.stableDebtTokenImpl, + abi.encodeWithSelector( + IInitializableDebtToken.initialize.selector, + pool, + input.underlyingAsset, + IAaveIncentivesController(input.incentivesController), + input.underlyingAssetDecimals, + input.stableDebtTokenName, + input.stableDebtTokenSymbol, + input.params + ) + ); + + address variableDebtTokenProxyAddress = _initTokenWithProxy( + input.variableDebtTokenImpl, + abi.encodeWithSelector( + IInitializableDebtToken.initialize.selector, + pool, + input.underlyingAsset, + IAaveIncentivesController(input.incentivesController), + input.underlyingAssetDecimals, + input.variableDebtTokenName, + input.variableDebtTokenSymbol, + input.params + ) + ); + + pool.initReserve( + input.underlyingAsset, + aTokenProxyAddress, + stableDebtTokenProxyAddress, + variableDebtTokenProxyAddress, + input.interestRateStrategyAddress + ); + + DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration( + input.underlyingAsset + ); + + currentConfig.setDecimals(input.underlyingAssetDecimals); + + currentConfig.setActive(true); + currentConfig.setPaused(false); + currentConfig.setFrozen(false); + + pool.setConfiguration(input.underlyingAsset, currentConfig.data); + + emit ReserveInitialized( + input.underlyingAsset, + aTokenProxyAddress, + stableDebtTokenProxyAddress, + variableDebtTokenProxyAddress, + input.interestRateStrategyAddress + ); + } + + function dropReserve(ILendingPool pool, address asset) external { + pool.dropReserve(asset); + emit ReserveDropped(asset); + } + + /** + * @dev Updates the aToken implementation for the reserve + **/ + function updateAToken( + ILendingPool cachedPool, + ConfiguratorInputTypes.UpdateATokenInput calldata input + ) public { + DataTypes.ReserveData memory reserveData = cachedPool.getReserveData(input.asset); + + (, , , uint256 decimals, ) = cachedPool.getConfiguration(input.asset).getParamsMemory(); + + bytes memory encodedCall = abi.encodeWithSelector( + IInitializableAToken.initialize.selector, + cachedPool, + input.treasury, + input.asset, + input.incentivesController, + decimals, + input.name, + input.symbol, + input.params + ); + + _upgradeTokenImplementation(reserveData.aTokenAddress, input.implementation, encodedCall); + + emit ATokenUpgraded(input.asset, reserveData.aTokenAddress, input.implementation); + } + + /** + * @dev Updates the stable debt token implementation for the reserve + **/ + function updateStableDebtToken( + ILendingPool cachedPool, + ConfiguratorInputTypes.UpdateDebtTokenInput calldata input + ) public { + DataTypes.ReserveData memory reserveData = cachedPool.getReserveData(input.asset); + + (, , , uint256 decimals, ) = cachedPool.getConfiguration(input.asset).getParamsMemory(); + + bytes memory encodedCall = abi.encodeWithSelector( + IInitializableDebtToken.initialize.selector, + cachedPool, + input.asset, + input.incentivesController, + decimals, + input.name, + input.symbol, + input.params + ); + + _upgradeTokenImplementation( + reserveData.stableDebtTokenAddress, + input.implementation, + encodedCall + ); + + emit StableDebtTokenUpgraded( + input.asset, + reserveData.stableDebtTokenAddress, + input.implementation + ); + } + + /** + * @dev Updates the variable debt token implementation for the asset + **/ + function updateVariableDebtToken( + ILendingPool cachedPool, + ConfiguratorInputTypes.UpdateDebtTokenInput calldata input + ) public { + DataTypes.ReserveData memory reserveData = cachedPool.getReserveData(input.asset); + + (, , , uint256 decimals, ) = cachedPool.getConfiguration(input.asset).getParamsMemory(); + + bytes memory encodedCall = abi.encodeWithSelector( + IInitializableDebtToken.initialize.selector, + cachedPool, + input.asset, + input.incentivesController, + decimals, + input.name, + input.symbol, + input.params + ); + + _upgradeTokenImplementation( + reserveData.variableDebtTokenAddress, + input.implementation, + encodedCall + ); + + emit VariableDebtTokenUpgraded( + input.asset, + reserveData.variableDebtTokenAddress, + input.implementation + ); + } + + function _initTokenWithProxy(address implementation, bytes memory initParams) + internal + returns (address) + { + + InitializableImmutableAdminUpgradeabilityProxy proxy + = new InitializableImmutableAdminUpgradeabilityProxy(address(this)); + + proxy.initialize(implementation, initParams); + + return address(proxy); + } + + function _upgradeTokenImplementation( + address proxyAddress, + address implementation, + bytes memory initParams + ) internal { + + InitializableImmutableAdminUpgradeabilityProxy proxy + = InitializableImmutableAdminUpgradeabilityProxy(payable(proxyAddress)); + + proxy.upgradeToAndCall(implementation, initParams); + } + + // Reserve + + function enableBorrowingOnReserve( + DataTypes.ReserveConfigurationMap memory currentConfig, + ILendingPool pool, + address asset, + uint256 borrowCap, + bool stableBorrowRateEnabled + ) external { + currentConfig.setBorrowingEnabled(true); + currentConfig.setBorrowCap(borrowCap); + currentConfig.setStableRateBorrowingEnabled(stableBorrowRateEnabled); + + pool.setConfiguration(asset, currentConfig.data); + + emit BorrowingEnabledOnReserve(asset, stableBorrowRateEnabled); + } + + function disableBorrowingOnReserve( + DataTypes.ReserveConfigurationMap memory currentConfig, + ILendingPool pool, + address asset + ) external { + currentConfig.setBorrowingEnabled(false); + + pool.setConfiguration(asset, currentConfig.data); + emit BorrowingDisabledOnReserve(asset); + } + + function configureReserveAsCollateral( + DataTypes.ReserveConfigurationMap memory currentConfig, + ILendingPool pool, + address asset, + uint256 ltv, + uint256 liquidationThreshold, + uint256 liquidationBonus + ) external { + currentConfig.setLtv(ltv); + currentConfig.setLiquidationThreshold(liquidationThreshold); + currentConfig.setLiquidationBonus(liquidationBonus); + + pool.setConfiguration(asset, currentConfig.data); + + emit CollateralConfigurationChanged(asset, ltv, liquidationThreshold, liquidationBonus); + } + + function enableReserveStableRate( + DataTypes.ReserveConfigurationMap memory currentConfig, + ILendingPool pool, + address asset + ) external { + currentConfig.setStableRateBorrowingEnabled(true); + + pool.setConfiguration(asset, currentConfig.data); + + emit StableRateEnabledOnReserve(asset); + } + + function disableReserveStableRate( + DataTypes.ReserveConfigurationMap memory currentConfig, + ILendingPool pool, + address asset + ) external { + currentConfig.setStableRateBorrowingEnabled(false); + + pool.setConfiguration(asset, currentConfig.data); + + emit StableRateDisabledOnReserve(asset); + } + + function activateReserve( + DataTypes.ReserveConfigurationMap memory currentConfig, + ILendingPool pool, + address asset + ) external { + currentConfig.setActive(true); + + pool.setConfiguration(asset, currentConfig.data); + + emit ReserveActivated(asset); + } + + function deactivateReserve( + DataTypes.ReserveConfigurationMap memory currentConfig, + ILendingPool pool, + address asset + ) external { + currentConfig.setActive(false); + + pool.setConfiguration(asset, currentConfig.data); + + emit ReserveDeactivated(asset); + } + + function freezeReserve( + DataTypes.ReserveConfigurationMap memory currentConfig, + ILendingPool pool, + address asset + ) external { + currentConfig.setFrozen(true); + + pool.setConfiguration(asset, currentConfig.data); + + emit ReserveFrozen(asset); + } + + function unfreezeReserve( + DataTypes.ReserveConfigurationMap memory currentConfig, + ILendingPool pool, + address asset + ) external { + currentConfig.setFrozen(false); + + pool.setConfiguration(asset, currentConfig.data); + + emit ReserveUnfrozen(asset); + } + + function setReservePause( + DataTypes.ReserveConfigurationMap memory currentConfig, + ILendingPool pool, + address asset, + bool paused + ) public { + DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset); + + currentConfig.setPaused(paused); + + pool.setConfiguration(asset, currentConfig.data); + + if (paused) { + emit ReservePaused(asset); + } else { + emit ReserveUnpaused(asset); + } + } + + function setReserveFactor( + DataTypes.ReserveConfigurationMap memory currentConfig, + ILendingPool pool, + address asset, + uint256 reserveFactor + ) external { + currentConfig.setReserveFactor(reserveFactor); + + pool.setConfiguration(asset, currentConfig.data); + + emit ReserveFactorChanged(asset, reserveFactor); + } + + function setBorrowCap( + DataTypes.ReserveConfigurationMap memory currentConfig, + ILendingPool pool, + address asset, + uint256 borrowCap + ) external { + currentConfig.setBorrowCap(borrowCap); + + pool.setConfiguration(asset, currentConfig.data); + + emit BorrowCapChanged(asset, borrowCap); + } + + function setSupplyCap( + DataTypes.ReserveConfigurationMap memory currentConfig, + ILendingPool pool, + address asset, + uint256 supplyCap + ) external { + currentConfig.setSupplyCap(supplyCap); + + pool.setConfiguration(asset, currentConfig.data); + + emit SupplyCapChanged(asset, supplyCap); + } + + /// + + /** + * @dev Emitted when a reserve is initialized. + * @param asset The address of the underlying asset of the reserve + * @param aToken The address of the associated aToken contract + * @param stableDebtToken The address of the associated stable rate debt token + * @param variableDebtToken The address of the associated variable rate debt token + * @param interestRateStrategyAddress The address of the interest rate strategy for the reserve + **/ + event ReserveInitialized( + address indexed asset, + address indexed aToken, + address stableDebtToken, + address variableDebtToken, + address interestRateStrategyAddress + ); + + /** + * @dev Emitted when borrowing is enabled on a reserve + * @param asset The address of the underlying asset of the reserve + * @param stableRateEnabled True if stable rate borrowing is enabled, false otherwise + **/ + event BorrowingEnabledOnReserve(address indexed asset, bool stableRateEnabled); + + /** + * @dev Emitted when borrowing is disabled on a reserve + * @param asset The address of the underlying asset of the reserve + **/ + event BorrowingDisabledOnReserve(address indexed asset); + + /** + * @dev Emitted when the collateralization risk parameters for the specified asset are updated. + * @param asset The address of the underlying asset of the reserve + * @param ltv The loan to value of the asset when used as collateral + * @param liquidationThreshold The threshold at which loans using this asset as collateral will be considered undercollateralized + * @param liquidationBonus The bonus liquidators receive to liquidate this asset + **/ + event CollateralConfigurationChanged( + address indexed asset, + uint256 ltv, + uint256 liquidationThreshold, + uint256 liquidationBonus + ); + + /** + * @dev Emitted when stable rate borrowing is enabled on a reserve + * @param asset The address of the underlying asset of the reserve + **/ + event StableRateEnabledOnReserve(address indexed asset); + + /** + * @dev Emitted when stable rate borrowing is disabled on a reserve + * @param asset The address of the underlying asset of the reserve + **/ + event StableRateDisabledOnReserve(address indexed asset); + + /** + * @dev Emitted when a reserve is activated + * @param asset The address of the underlying asset of the reserve + **/ + event ReserveActivated(address indexed asset); + + /** + * @dev Emitted when a reserve is deactivated + * @param asset The address of the underlying asset of the reserve + **/ + event ReserveDeactivated(address indexed asset); + + /** + * @dev Emitted when a reserve is frozen + * @param asset The address of the underlying asset of the reserve + **/ + event ReserveFrozen(address indexed asset); + + /** + * @dev Emitted when a reserve is unfrozen + * @param asset The address of the underlying asset of the reserve + **/ + event ReserveUnfrozen(address indexed asset); + + /** + * @dev Emitted when a reserve is paused + * @param asset The address of the underlying asset of the reserve + **/ + event ReservePaused(address indexed asset); + + /** + * @dev Emitted when a reserve is unpaused + * @param asset The address of the underlying asset of the reserve + **/ + event ReserveUnpaused(address indexed asset); + + /** + * @dev Emitted when a reserve is dropped + * @param asset The address of the underlying asset of the reserve + **/ + event ReserveDropped(address indexed asset); + + /** + * @dev Emitted when a reserve factor is updated + * @param asset The address of the underlying asset of the reserve + * @param factor The new reserve factor + **/ + event ReserveFactorChanged(address indexed asset, uint256 factor); + + /** + * @dev Emitted when the borrow cap of a reserve is updated + * @param asset The address of the underlying asset of the reserve + * @param borrowCap The new borrow cap + **/ + event BorrowCapChanged(address indexed asset, uint256 borrowCap); + + /** + * @dev Emitted when the supply cap of a reserve is updated + * @param asset The address of the underlying asset of the reserve + * @param supplyCap The new supply cap + **/ + event SupplyCapChanged(address indexed asset, uint256 supplyCap); + + /** + * @dev Emitted when the reserve decimals are updated + * @param asset The address of the underlying asset of the reserve + * @param decimals The new decimals + **/ + event ReserveDecimalsChanged(address indexed asset, uint256 decimals); + + /** + * @dev Emitted when a reserve interest strategy contract is updated + * @param asset The address of the underlying asset of the reserve + * @param strategy The new address of the interest strategy contract + **/ + event ReserveInterestRateStrategyChanged(address indexed asset, address strategy); + + /** + * @dev Emitted when an aToken implementation is upgraded + * @param asset The address of the underlying asset of the reserve + * @param proxy The aToken proxy address + * @param implementation The new aToken implementation + **/ + event ATokenUpgraded( + address indexed asset, + address indexed proxy, + address indexed implementation + ); + + /** + * @dev Emitted when the implementation of a stable debt token is upgraded + * @param asset The address of the underlying asset of the reserve + * @param proxy The stable debt token proxy address + * @param implementation The new aToken implementation + **/ + event StableDebtTokenUpgraded( + address indexed asset, + address indexed proxy, + address indexed implementation + ); + + /** + * @dev Emitted when the implementation of a variable debt token is upgraded + * @param asset The address of the underlying asset of the reserve + * @param proxy The variable debt token proxy address + * @param implementation The new aToken implementation + **/ + event VariableDebtTokenUpgraded( + address indexed asset, + address indexed proxy, + address indexed implementation + ); + + /** + * @dev Emitted when a new borrower is authorized (fees = 0) + * @param flashBorrower The address of the authorized borrower + **/ + event FlashBorrowerAuthorized(address indexed flashBorrower); + + /** + * @dev Emitted when a borrower is unauthorized + * @param flashBorrower The address of the unauthorized borrower + **/ + event FlashBorrowerUnauthorized(address indexed flashBorrower); + + /** + * @dev Emitted when a new risk admin is registered + * @param admin the newly registered admin + **/ + event RiskAdminRegistered(address indexed admin); + + /** + * @dev Emitted when a risk admin is unregistered + * @param admin the unregistered admin + **/ + event RiskAdminUnregistered(address indexed admin); + + /** + * @dev Emitted when a the total premium on flashloans is updated + * @param flashloanPremiumTotal the new premium + **/ + event FlashloanPremiumTotalUpdated(uint256 flashloanPremiumTotal); + + /** + * @dev Emitted when a the part of the premium that goes to protoco lis updated + * @param flashloanPremiumToProtocol the new premium + **/ + event FlashloanPremiumToProcolUpdated(uint256 flashloanPremiumToProtocol); +} diff --git a/contracts/protocol/libraries/logic/LendingPoolBaseLogic.sol b/contracts/protocol/libraries/logic/LendingPoolBaseLogic.sol new file mode 100644 index 00000000..7eecd8fd --- /dev/null +++ b/contracts/protocol/libraries/logic/LendingPoolBaseLogic.sol @@ -0,0 +1,351 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import {IERC20} from '../../../dependencies/openzeppelin/contracts/IERC20.sol'; +import {SafeMath} from '../../../dependencies/openzeppelin/contracts/SafeMath.sol'; +import {SafeERC20} from '../../../dependencies/openzeppelin/contracts/SafeERC20.sol'; +import {IAToken} from '../../../interfaces/IAToken.sol'; +import {Helpers} from '../helpers/Helpers.sol'; +import {ValidationLogic} from './ValidationLogic.sol'; +import {ReserveLogic} from './ReserveLogic.sol'; +import {DataTypes} from './../types/DataTypes.sol'; + +import {IStableDebtToken} from '../../../interfaces/IStableDebtToken.sol'; +import {IVariableDebtToken} from '../../../interfaces/IVariableDebtToken.sol'; + +import {UserConfiguration} from './../configuration/UserConfiguration.sol'; + +import {WadRayMath} from '../math/WadRayMath.sol'; + +/** + * @title LendingPoolBaseLogic Library + * @author Aave + * @title Implements lendingpool basic logic to perform actions to limit the contract size. + */ + +library LendingPoolBaseLogic { + using ReserveLogic for DataTypes.ReserveCache; + using ReserveLogic for DataTypes.ReserveData; + using UserConfiguration for DataTypes.UserConfigurationMap; + using SafeMath for uint256; + using SafeERC20 for IERC20; + using WadRayMath for uint256; + + /** + * @dev Emitted on deposit() + * @param reserve The address of the underlying asset of the reserve + * @param user The address initiating the deposit + * @param onBehalfOf The beneficiary of the deposit, receiving the aTokens + * @param amount The amount deposited + * @param referral The referral code used + **/ + event Deposit( + address indexed reserve, + address user, + address indexed onBehalfOf, + uint256 amount, + uint16 indexed referral + ); + + /** + * @dev Emitted on withdraw() + * @param reserve The address of the underlyng asset being withdrawn + * @param user The address initiating the withdrawal, owner of aTokens + * @param to Address that will receive the underlying + * @param amount The amount to be withdrawn + **/ + event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount); + + /** + * @dev Emitted on borrow() and flashLoan() when debt needs to be opened + * @param reserve The address of the underlying asset being borrowed + * @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just + * initiator of the transaction on flashLoan() + * @param onBehalfOf The address that will be getting the debt + * @param amount The amount borrowed out + * @param borrowRateMode The rate mode: 1 for Stable, 2 for Variable + * @param borrowRate The numeric rate at which the user has borrowed + * @param referral The referral code used + **/ + event Borrow( + address indexed reserve, + address user, + address indexed onBehalfOf, + uint256 amount, + uint256 borrowRateMode, + uint256 borrowRate, + uint16 indexed referral + ); + + /** + * @dev Emitted on repay() + * @param reserve The address of the underlying asset of the reserve + * @param user The beneficiary of the repayment, getting his debt reduced + * @param repayer The address of the user initiating the repay(), providing the funds + * @param amount The amount repaid + **/ + event Repay( + address indexed reserve, + address indexed user, + address indexed repayer, + uint256 amount + ); + + /** + * @dev Emitted on setUserUseReserveAsCollateral() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user enabling the usage as collateral + **/ + event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user); + + /** + * @dev Emitted on setUserUseReserveAsCollateral() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user enabling the usage as collateral + **/ + event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user); + + function _executeDeposit( + DataTypes.ReserveData storage reserve, + DataTypes.UserConfigurationMap storage userConfig, + address asset, + uint256 amount, + address onBehalfOf, + uint16 referralCode + ) public { + DataTypes.ReserveCache memory reserveCache = reserve.cache(); + + reserve.updateState(reserveCache); + + ValidationLogic.validateDeposit(reserveCache, amount); + + reserve.updateInterestRates(reserveCache, asset, amount, 0); + + IERC20(asset).safeTransferFrom(msg.sender, reserveCache.aTokenAddress, amount); + + bool isFirstDeposit = + IAToken(reserveCache.aTokenAddress).mint(onBehalfOf, amount, reserveCache.nextLiquidityIndex); + + if (isFirstDeposit) { + userConfig.setUsingAsCollateral(reserve.id, true); + emit ReserveUsedAsCollateralEnabled(asset, onBehalfOf); + } + + emit Deposit(asset, msg.sender, onBehalfOf, amount, referralCode); + } + + function _executeWithdraw( + mapping(address => DataTypes.ReserveData) storage reserves, + DataTypes.UserConfigurationMap storage userConfig, + address asset, + uint256 amount, + address to, + mapping(uint256 => address) storage reservesList, + uint256 reservesCount, + address priceOracle + ) public returns (uint256) { + DataTypes.ReserveData storage reserve = reserves[asset]; + DataTypes.ReserveCache memory reserveCache = reserve.cache(); + + reserve.updateState(reserveCache); + + uint256 userBalance = + IAToken(reserveCache.aTokenAddress).scaledBalanceOf(msg.sender).rayMul( + reserveCache.nextLiquidityIndex + ); + + uint256 amountToWithdraw = amount; + + if (amount == type(uint256).max) { + amountToWithdraw = userBalance; + } + + ValidationLogic.validateWithdraw(reserveCache, amountToWithdraw, userBalance); + + reserve.updateInterestRates(reserveCache, asset, 0, amountToWithdraw); + + IAToken(reserveCache.aTokenAddress).burn( + msg.sender, + to, + amountToWithdraw, + reserveCache.nextLiquidityIndex + ); + + if (userConfig.isUsingAsCollateral(reserve.id)) { + if (userConfig.isBorrowingAny()) { + _validateHFAndLtv(asset, reserves, userConfig, reservesList, reservesCount, priceOracle); + } + + if (amountToWithdraw == userBalance) { + userConfig.setUsingAsCollateral(reserve.id, false); + emit ReserveUsedAsCollateralDisabled(asset, msg.sender); + } + } + + emit Withdraw(asset, msg.sender, to, amountToWithdraw); + + return amountToWithdraw; + } + + function _validateHFAndLtv( + address asset, + mapping(address => DataTypes.ReserveData) storage reserves, + DataTypes.UserConfigurationMap storage userConfig, + mapping(uint256 => address) storage reservesList, + uint256 reservesCount, + address priceOracle + ) public { + ValidationLogic.validateHFAndLtv( + asset, + msg.sender, + reserves, + userConfig, + reservesList, + reservesCount, + priceOracle + ); + } + + function _executeBorrow( + mapping(address => DataTypes.ReserveData) storage reserves, + DataTypes.ReserveCache memory reserveCache, + DataTypes.UserConfigurationMap storage userConfig, + DataTypes.ExecuteBorrowParams memory vars + ) public { + DataTypes.ReserveData storage reserve = reserves[vars.asset]; + + uint256 currentStableRate = 0; + bool isFirstBorrowing = false; + + if (DataTypes.InterestRateMode(vars.interestRateMode) == DataTypes.InterestRateMode.STABLE) { + currentStableRate = reserve.currentStableBorrowRate; + isFirstBorrowing = IStableDebtToken(reserveCache.stableDebtTokenAddress).mint( + vars.user, + vars.onBehalfOf, + vars.amount, + currentStableRate + ); + reserveCache.refreshDebt(vars.amount, 0, 0, 0); + } else { + isFirstBorrowing = IVariableDebtToken(reserveCache.variableDebtTokenAddress).mint( + vars.user, + vars.onBehalfOf, + vars.amount, + reserveCache.nextVariableBorrowIndex + ); + reserveCache.refreshDebt(0, 0, vars.amount, 0); + } + + if (isFirstBorrowing) { + userConfig.setBorrowing(reserve.id, true); + } + + reserve.updateInterestRates( + reserveCache, + vars.asset, + 0, + vars.releaseUnderlying ? vars.amount : 0 + ); + + if (vars.releaseUnderlying) { + IAToken(reserveCache.aTokenAddress).transferUnderlyingTo(vars.user, vars.amount); + } + + emit Borrow( + vars.asset, + vars.user, + vars.onBehalfOf, + vars.amount, + vars.interestRateMode, + DataTypes.InterestRateMode(vars.interestRateMode) == DataTypes.InterestRateMode.STABLE + ? currentStableRate + : reserve.currentVariableBorrowRate, + vars.referralCode + ); + } + + function _executeRepay( + DataTypes.ReserveData storage reserve, + DataTypes.UserConfigurationMap storage userConfig, + address asset, + uint256 amount, + uint256 rateMode, + address onBehalfOf, + address lastBorrower, + uint40 lastBorrowTimestamp + ) public returns (uint256) { + DataTypes.ReserveCache memory reserveCache = reserve.cache(); + (uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(onBehalfOf, reserve); + DataTypes.InterestRateMode interestRateMode = DataTypes.InterestRateMode(rateMode); + + ValidationLogic.validateRepay( + lastBorrower, + lastBorrowTimestamp, + reserveCache, + amount, + interestRateMode, + onBehalfOf, + stableDebt, + variableDebt + ); + + uint256 paybackAmount = + interestRateMode == DataTypes.InterestRateMode.STABLE ? stableDebt : variableDebt; + + if (amount < paybackAmount) { + paybackAmount = amount; + } + + reserve.updateState(reserveCache); + + if (interestRateMode == DataTypes.InterestRateMode.STABLE) { + IStableDebtToken(reserveCache.stableDebtTokenAddress).burn(onBehalfOf, paybackAmount); + reserveCache.refreshDebt(0, paybackAmount, 0, 0); + } else { + IVariableDebtToken(reserveCache.variableDebtTokenAddress).burn( + onBehalfOf, + paybackAmount, + reserveCache.nextVariableBorrowIndex + ); + reserveCache.refreshDebt(0, 0, 0, paybackAmount); + } + + return + _executeRepayHelper( + reserve, + reserveCache, + userConfig, + asset, + onBehalfOf, + paybackAmount, + variableDebt, + stableDebt + ); + } + + function _executeRepayHelper( + DataTypes.ReserveData storage reserve, + DataTypes.ReserveCache memory reserveCache, + DataTypes.UserConfigurationMap storage userConfig, + address asset, + address onBehalfOf, + uint256 paybackAmount, + uint256 variableDebt, + uint256 stableDebt + ) public returns (uint256) { + reserve.updateInterestRates(reserveCache, asset, paybackAmount, 0); + + if (stableDebt.add(variableDebt).sub(paybackAmount) == 0) { + userConfig.setBorrowing(reserve.id, false); + } + + IERC20(asset).safeTransferFrom(msg.sender, reserveCache.aTokenAddress, paybackAmount); + + IAToken(reserveCache.aTokenAddress).handleRepayment(msg.sender, paybackAmount); + + emit Repay(asset, onBehalfOf, msg.sender, paybackAmount); + + return paybackAmount; + } +} \ No newline at end of file diff --git a/contracts/protocol/libraries/logic/LendingPoolOtherLogic.sol b/contracts/protocol/libraries/logic/LendingPoolOtherLogic.sol new file mode 100644 index 00000000..fc6dcca2 --- /dev/null +++ b/contracts/protocol/libraries/logic/LendingPoolOtherLogic.sol @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import {IERC20} from '../../../dependencies/openzeppelin/contracts/IERC20.sol'; +import {SafeMath} from '../../../dependencies/openzeppelin/contracts/SafeMath.sol'; +import {SafeERC20} from '../../../dependencies/openzeppelin/contracts/SafeERC20.sol'; +import {IAToken} from '../../../interfaces/IAToken.sol'; +import {Helpers} from '../helpers/Helpers.sol'; +import {ValidationLogic} from './ValidationLogic.sol'; +import {ReserveLogic} from './ReserveLogic.sol'; +import {DataTypes} from './../types/DataTypes.sol'; + +import {IStableDebtToken} from '../../../interfaces/IStableDebtToken.sol'; +import {IVariableDebtToken} from '../../../interfaces/IVariableDebtToken.sol'; + +import {UserConfiguration} from './../configuration/UserConfiguration.sol'; + +import {WadRayMath} from '../math/WadRayMath.sol'; + +library LendingPoolOtherLogic { + using ReserveLogic for DataTypes.ReserveCache; + using ReserveLogic for DataTypes.ReserveData; + using UserConfiguration for DataTypes.UserConfigurationMap; + using SafeMath for uint256; + using SafeERC20 for IERC20; + using WadRayMath for uint256; + + /** + * @dev Emitted on setUserUseReserveAsCollateral() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user enabling the usage as collateral + **/ + event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user); + + /** + * @dev Emitted on setUserUseReserveAsCollateral() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user enabling the usage as collateral + **/ + event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user); + + /** + * @dev Emitted on rebalanceStableBorrowRate() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user for which the rebalance has been executed + **/ + event RebalanceStableBorrowRate(address indexed reserve, address indexed user); + + /** + * @dev Emitted on swapBorrowRateMode() + * @param reserve The address of the underlying asset of the reserve + * @param user The address of the user swapping his rate mode + * @param rateMode The rate mode that the user wants to swap to + **/ + event Swap(address indexed reserve, address indexed user, uint256 rateMode); + + function rebalanceStableBorrowRate( + DataTypes.ReserveData storage reserve, + address asset, + address user + ) public { + DataTypes.ReserveCache memory reserveCache = reserve.cache(); + + IERC20 stableDebtToken = IERC20(reserveCache.stableDebtTokenAddress); + IERC20 variableDebtToken = IERC20(reserveCache.variableDebtTokenAddress); + uint256 stableDebt = IERC20(stableDebtToken).balanceOf(user); + + ValidationLogic.validateRebalanceStableBorrowRate( + reserve, + reserveCache, + asset, + stableDebtToken, + variableDebtToken, + reserveCache.aTokenAddress + ); + + reserve.updateState(reserveCache); + + IStableDebtToken(address(stableDebtToken)).burn(user, stableDebt); + IStableDebtToken(address(stableDebtToken)).mint( + user, + user, + stableDebt, + reserve.currentStableBorrowRate + ); + + reserveCache.refreshDebt(stableDebt, stableDebt, 0, 0); + + reserve.updateInterestRates(reserveCache, asset, 0, 0); + + emit RebalanceStableBorrowRate(asset, user); + } + + function swapBorrowRateMode( + DataTypes.ReserveData storage reserve, + DataTypes.UserConfigurationMap storage userConfig, + address asset, + uint256 rateMode + ) public { + DataTypes.ReserveCache memory reserveCache = reserve.cache(); + + (uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(msg.sender, reserve); + + DataTypes.InterestRateMode interestRateMode = DataTypes.InterestRateMode(rateMode); + + ValidationLogic.validateSwapRateMode( + reserve, + reserveCache, + userConfig, + stableDebt, + variableDebt, + interestRateMode + ); + + reserve.updateState(reserveCache); + + if (interestRateMode == DataTypes.InterestRateMode.STABLE) { + IStableDebtToken(reserveCache.stableDebtTokenAddress).burn(msg.sender, stableDebt); + IVariableDebtToken(reserveCache.variableDebtTokenAddress).mint( + msg.sender, + msg.sender, + stableDebt, + reserveCache.nextVariableBorrowIndex + ); + reserveCache.refreshDebt(0, stableDebt, stableDebt, 0); + } else { + IVariableDebtToken(reserveCache.variableDebtTokenAddress).burn( + msg.sender, + variableDebt, + reserveCache.nextVariableBorrowIndex + ); + IStableDebtToken(reserveCache.stableDebtTokenAddress).mint( + msg.sender, + msg.sender, + variableDebt, + reserve.currentStableBorrowRate + ); + reserveCache.refreshDebt(variableDebt, 0, 0, variableDebt); + } + + reserve.updateInterestRates(reserveCache, asset, 0, 0); + + emit Swap(asset, msg.sender, rateMode); + } + + function setUserUseReserveAsCollateral( + mapping(address => DataTypes.ReserveData) storage reserves, + DataTypes.UserConfigurationMap storage userConfig, + address asset, + bool useAsCollateral, + mapping(uint256 => address) storage reservesList, + uint256 reservesCount, + address priceOracle + ) public { + DataTypes.ReserveData storage reserve = reserves[asset]; + DataTypes.ReserveCache memory reserveCache = reserve.cache(); + + uint256 userBalance = IERC20(reserveCache.aTokenAddress).balanceOf(msg.sender); + + ValidationLogic.validateSetUseReserveAsCollateral(reserveCache, userBalance); + + userConfig.setUsingAsCollateral(reserve.id, useAsCollateral); + + if (useAsCollateral) { + emit ReserveUsedAsCollateralEnabled(asset, msg.sender); + } else { + ValidationLogic.validateHFAndLtv( + asset, + msg.sender, + reserves, + userConfig, + reservesList, + reservesCount, + priceOracle + ); + + emit ReserveUsedAsCollateralDisabled(asset, msg.sender); + } + } +} \ No newline at end of file diff --git a/contracts/protocol/libraries/types/ConfiguratorInputTypes.sol b/contracts/protocol/libraries/types/ConfiguratorInputTypes.sol new file mode 100644 index 00000000..12077c3e --- /dev/null +++ b/contracts/protocol/libraries/types/ConfiguratorInputTypes.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: agpl-3.0 +pragma solidity 0.6.12; + +library ConfiguratorInputTypes { + struct InitReserveInput { + address aTokenImpl; + address stableDebtTokenImpl; + address variableDebtTokenImpl; + uint8 underlyingAssetDecimals; + address interestRateStrategyAddress; + address underlyingAsset; + address treasury; + address incentivesController; + string underlyingAssetName; + string aTokenName; + string aTokenSymbol; + string variableDebtTokenName; + string variableDebtTokenSymbol; + string stableDebtTokenName; + string stableDebtTokenSymbol; + bytes params; + } + + struct UpdateATokenInput { + address asset; + address treasury; + address incentivesController; + string name; + string symbol; + address implementation; + bytes params; + } + + struct UpdateDebtTokenInput { + address asset; + address incentivesController; + string name; + string symbol; + address implementation; + bytes params; + } +} diff --git a/contracts/protocol/libraries/types/DataTypes.sol b/contracts/protocol/libraries/types/DataTypes.sol index 1ed05d5d..6766b503 100644 --- a/contracts/protocol/libraries/types/DataTypes.sol +++ b/contracts/protocol/libraries/types/DataTypes.sol @@ -73,4 +73,14 @@ library DataTypes { uint40 reserveLastUpdateTimestamp; uint40 stableDebtLastUpdateTimestamp; } + + struct ExecuteBorrowParams { + address asset; + address user; + address onBehalfOf; + uint256 amount; + uint256 interestRateMode; + uint16 referralCode; + bool releaseUnderlying; + } }