// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.6.12; 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'; import {IERC20Detailed} from '../../dependencies/openzeppelin/contracts/IERC20Detailed.sol'; 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 {ILendingPoolConfigurator} from '../../interfaces/ILendingPoolConfigurator.sol'; /** * @title LendingPoolConfigurator contract * @author Aave * @dev Implements the configuration methods for the Aave protocol **/ contract LendingPoolConfigurator is VersionedInitializable, ILendingPoolConfigurator { using SafeMath for uint256; using PercentageMath for uint256; using ReserveConfiguration for DataTypes.ReserveConfigurationMap; ILendingPoolAddressesProvider internal _addressesProvider; ILendingPool internal _pool; mapping(address => bool) private _riskAdmins; modifier onlyPoolAdmin { require(_addressesProvider.getPoolAdmin() == msg.sender, Errors.CALLER_NOT_POOL_ADMIN); _; } modifier onlyEmergencyAdmin { require( _addressesProvider.getEmergencyAdmin() == msg.sender, Errors.LPC_CALLER_NOT_EMERGENCY_ADMIN ); _; } modifier onlyEmergencyOrPoolAdmin { require( _addressesProvider.getEmergencyAdmin() == msg.sender || _addressesProvider.getPoolAdmin() == msg.sender, Errors.LPC_CALLER_NOT_EMERGENCY_OR_POOL_ADMIN ); _; } modifier onlyRiskOrPoolAdmins { require( _riskAdmins[msg.sender] || addressesProvider.getPoolAdmin() == msg.sender, Errors.LPC_CALLER_NOT_RISK_OR_POOL_ADMIN ); _; } uint256 internal constant CONFIGURATOR_REVISION = 0x1; function getRevision() internal pure override returns (uint256) { return CONFIGURATOR_REVISION; } function initialize(ILendingPoolAddressesProvider provider) public initializer { _addressesProvider = provider; _pool = ILendingPool(_addressesProvider.getLendingPool()); } /// @inheritdoc ILendingPoolConfigurator function batchInitReserve(InitReserveInput[] calldata input) external override onlyPoolAdmin { ILendingPool cachedPool = _pool; for (uint256 i = 0; i < input.length; i++) { _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 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) 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 ); } /// @inheritdoc ILendingPoolConfigurator function updateVariableDebtToken(UpdateDebtTokenInput 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.variableDebtTokenAddress, input.implementation, encodedCall ); emit VariableDebtTokenUpgraded( input.asset, reserveData.variableDebtTokenAddress, input.implementation ); } /// @inheritdoc ILendingPoolConfigurator function enableBorrowingOnReserve( address asset, uint256 borrowCap, 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 BorrowCapChanged(asset, borrowCap); emit BorrowingEnabledOnReserve(asset, 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); } /// @inheritdoc ILendingPoolConfigurator function configureReserveAsCollateral( address asset, uint256 ltv, uint256 liquidationThreshold, uint256 liquidationBonus ) external override onlyRiskOrPoolAdmins { DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); //validation of the parameters: the LTV can //only be lower or equal than the liquidation threshold //(otherwise a loan against the asset would cause instantaneous liquidation) require(ltv <= liquidationThreshold, Errors.LPC_INVALID_CONFIGURATION); if (liquidationThreshold != 0) { //liquidation bonus must be bigger than 100.00%, otherwise the liquidator would receive less //collateral than needed to cover the debt require( liquidationBonus > PercentageMath.PERCENTAGE_FACTOR, Errors.LPC_INVALID_CONFIGURATION ); //if threshold * bonus is less than PERCENTAGE_FACTOR, it's guaranteed that at the moment //a loan is taken there is enough collateral available to cover the liquidation bonus require( liquidationThreshold.percentMul(liquidationBonus) <= PercentageMath.PERCENTAGE_FACTOR, Errors.LPC_INVALID_CONFIGURATION ); } else { require(liquidationBonus == 0, Errors.LPC_INVALID_CONFIGURATION); //if the liquidation threshold is being set to 0, // the reserve is being disabled as collateral. To do so, //we need to ensure no liquidity is deposited _checkNoLiquidity(asset); } currentConfig.setLtv(ltv); currentConfig.setLiquidationThreshold(liquidationThreshold); currentConfig.setLiquidationBonus(liquidationBonus); _pool.setConfiguration(asset, currentConfig.data); emit CollateralConfigurationChanged(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); } /// @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); } /// @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); } /// @inheritdoc ILendingPoolConfigurator function deactivateReserve(address asset) external override onlyPoolAdmin { _checkNoLiquidity(asset); DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); currentConfig.setActive(false); _pool.setConfiguration(asset, currentConfig.data); emit ReserveDeactivated(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); } /// @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); } /// @inheritdoc ILendingPoolConfigurator function pauseReserve(address asset) external override onlyEmergencyOrPoolAdmin { DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); currentConfig.setPaused(true); _pool.setConfiguration(asset, currentConfig.data); emit ReservePaused(asset); } /// @inheritdoc ILendingPoolConfigurator function unpauseReserve(address asset) external override onlyEmergencyOrPoolAdmin { DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); currentConfig.setPaused(false); _pool.setConfiguration(asset, currentConfig.data); emit ReserveUnpaused(asset); } /// @inheritdoc ILendingPoolConfigurator function setReserveFactor(address asset, uint256 reserveFactor) external override onlyRiskOrPoolAdmins { DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); currentConfig.setReserveFactor(reserveFactor); _pool.setConfiguration(asset, currentConfig.data); emit ReserveFactorChanged(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); } ///@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); } ///@inheritdoc ILendingPoolConfigurator function setReserveInterestRateStrategyAddress(address asset, address rateStrategyAddress) external override onlyRiskOrPoolAdmins { _pool.setReserveInterestRateStrategyAddress(asset, rateStrategyAddress); emit ReserveInterestRateStrategyChanged(asset, rateStrategyAddress); } /// @inheritdoc ILendingPoolConfigurator function setPoolPause(bool val) external override onlyEmergencyAdmin { _pool.setPause(val); } function registerRiskAdmin(address admin) external override onlyPoolAdmin { _riskAdmins[admin] = true; emit RiskAdminRegistered(admin); } function unregisterRiskAdmin(address admin) external override onlyPoolAdmin { _riskAdmins[admin] = false; emit RiskAdminUnregistered(admin); } function isRiskAdmin(address admin) external view override onlyPoolAdmin returns (bool) { return _riskAdmins[admin]; } 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); uint256 availableLiquidity = IERC20Detailed(asset).balanceOf(reserveData.aTokenAddress); require( availableLiquidity == 0 && reserveData.currentLiquidityRate == 0, Errors.LPC_RESERVE_LIQUIDITY_NOT_0 ); } }