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

528 lines
17 KiB
Solidity

// 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);
}
/// @inheritdoc ILendingPoolConfigurator
function registerRiskAdmin(address admin) external override onlyPoolAdmin {
_riskAdmins[admin] = true;
emit RiskAdminRegistered(admin);
}
/// @inheritdoc ILendingPoolConfigurator
function unregisterRiskAdmin(address admin) external override onlyPoolAdmin {
_riskAdmins[admin] = false;
emit RiskAdminUnregistered(admin);
}
/// @inheritdoc ILendingPoolConfigurator
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
);
}
}