diff --git a/contracts/interfaces/IPool.sol b/contracts/interfaces/IPool.sol index ddf1847c8..a080b16b0 100644 --- a/contracts/interfaces/IPool.sol +++ b/contracts/interfaces/IPool.sol @@ -657,20 +657,68 @@ interface IPool { ) external; /** - * @notice Configures a new category for the eMode. + * @notice Configures a new or alters an existing collateral configuration of an eMode. * @dev In eMode, the protocol allows very high borrowing power to borrow assets of the same category. * The category 0 is reserved as it's the default for volatile assets * @param id The id of the category * @param config The configuration of the category */ - function configureEModeCategory(uint8 id, DataTypes.EModeCategory memory config) external; + function configureEModeCategory( + uint8 id, + DataTypes.EModeCategoryBaseConfiguration memory config + ) external; + + /** + * @notice Replaces the current eMode collateralBitmap. + * @param id The id of the category + * @param collateralBitmap The collateralBitmap of the category + */ + function configureEModeCategoryCollateralBitmap(uint8 id, uint128 collateralBitmap) external; + + /** + * @notice Replaces the current eMode borrowableBitmap. + * @param id The id of the category + * @param borrowableBitmap The borrowableBitmap of the category + */ + function configureEModeCategoryBorrowableBitmap(uint8 id, uint128 borrowableBitmap) external; + + // /** + // * @notice Returns the data of an eMode category + // * @dev DEPRECATED use independent getters instead + // * @param id The id of the category + // * @return The configuration data of the category + // */ + // function getEModeCategoryData(uint8 id) external view returns (DataTypes.EModeCategory memory); + + /** + * @notice Returns the label of an eMode category + * @param id The id of the category + * @return The label of the category + */ + function getEModeCategoryLabel(uint8 id) external view returns (string memory); + + /** + * @notice Returns the collateral config of an eMode category + * @param id The id of the category + * @return The ltv,lt,lb of the category + */ + function getEModeCategoryCollateralConfig( + uint8 id + ) external view returns (DataTypes.CollateralConfig memory); + + /** + * @notice Returns the collateralBitmap of an eMode category + * @param id The id of the category + * @return The collateralBitmap of the category + */ + function getEModeCategoryCollateralBitmap(uint8 id) external view returns (uint128); /** - * @notice Returns the data of an eMode category + * @notice Returns the borrowableBitmap of an eMode category * @param id The id of the category - * @return The configuration data of the category + * @return The borrowableBitmap of the category */ - function getEModeCategoryData(uint8 id) external view returns (DataTypes.EModeCategory memory); + function getEModeCategoryBorrowableBitmap(uint8 id) external view returns (uint128); /** * @notice Allows a user to use the protocol in eMode diff --git a/contracts/interfaces/IPoolConfigurator.sol b/contracts/interfaces/IPoolConfigurator.sol index 53b96565b..cfacc4cb2 100644 --- a/contracts/interfaces/IPoolConfigurator.sol +++ b/contracts/interfaces/IPoolConfigurator.sol @@ -136,20 +136,28 @@ interface IPoolConfigurator { ); /** - * @dev Emitted when the category of an asset in eMode is changed. + * @dev Emitted when an collateral configuration of an asset in an eMode is changed. * @param asset The address of the underlying asset of the reserve - * @param oldCategoryId The old eMode asset category - * @param newCategoryId The new eMode asset category + * @param categoryId The eMode category + * @param collateral True if the asset is enabled as collateral in the eMode, false otherwise. */ - event EModeAssetCategoryChanged(address indexed asset, uint8 oldCategoryId, uint8 newCategoryId); + event AssetCollateralInEModeChanged(address indexed asset, uint8 categoryId, bool collateral); /** - * @dev Emitted when a new eMode category is added. + * @dev Emitted when the borrowable configuration of an asset in an eMode changed. + * @param asset The address of the underlying asset of the reserve + * @param categoryId The eMode category + * @param borrowable True if the asset is enabled as borrowable in the eMode, false otherwise. + */ + event AssetBorrowableInEModeChanged(address indexed asset, uint8 categoryId, bool borrowable); + + /** + * @dev Emitted when a new eMode category is added or an existing category is altered. * @param categoryId The new eMode category id * @param ltv The ltv for the asset category in eMode * @param liquidationThreshold The liquidationThreshold for the asset category in eMode * @param liquidationBonus The liquidationBonus for the asset category in eMode - * @param oracle The optional address of the price oracle specific for this category + * @param oracle DEPRECATED in v3.2.0 * @param label A human readable identifier for the category */ event EModeCategoryAdded( @@ -413,23 +421,28 @@ interface IPoolConfigurator { function setUnbackedMintCap(address asset, uint256 newUnbackedMintCap) external; /** - * @notice Assign an efficiency mode (eMode) category to asset. + * @notice Enables/disables an asset to be borrowable in a selected eMode. + * - eMode.borrowable always has less priority then reserve.borrowable * @param asset The address of the underlying asset of the reserve - * @param newCategoryId The new category id of the asset + * @param categoryId The eMode categoryId + * @param borrowable True if the asset should be borrowable in the given eMode category, false otherwise. */ - function setAssetEModeCategory(address asset, uint8 newCategoryId) external; + function setAssetBorrowableInEMode(address asset, uint8 categoryId, bool borrowable) external; /** - * @notice Adds a new efficiency mode (eMode) category. - * @dev If zero is provided as oracle address, the default asset oracles will be used to compute the overall debt and - * overcollateralization of the users using this category. - * @dev The new ltv and liquidation threshold must be greater than the base - * ltvs and liquidation thresholds of all assets within the eMode category + * @notice Enables/disables an asset to be collateral in a selected eMode. + * @param asset The address of the underlying asset of the reserve + * @param categoryId The eMode categoryId + * @param collateral True if the asset should be collateral in the given eMode category, false otherwise. + */ + function setAssetCollateralInEMode(address asset, uint8 categoryId, bool collateral) external; + + /** + * @notice Adds a new efficiency mode (eMode) category or alters a existing one. * @param categoryId The id of the category to be configured * @param ltv The ltv associated with the category * @param liquidationThreshold The liquidation threshold associated with the category * @param liquidationBonus The liquidation bonus associated with the category - * @param oracle The oracle associated with the category * @param label A label identifying the category */ function setEModeCategory( @@ -437,7 +450,6 @@ interface IPoolConfigurator { uint16 ltv, uint16 liquidationThreshold, uint16 liquidationBonus, - address oracle, string calldata label ) external; diff --git a/contracts/protocol/libraries/configuration/EModeConfiguration.sol b/contracts/protocol/libraries/configuration/EModeConfiguration.sol new file mode 100644 index 000000000..3bb69ef07 --- /dev/null +++ b/contracts/protocol/libraries/configuration/EModeConfiguration.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Errors} from '../helpers/Errors.sol'; +import {DataTypes} from '../types/DataTypes.sol'; +import {ReserveConfiguration} from './ReserveConfiguration.sol'; + +/** + * @title EModeConfiguration library + * @author BGD Labs + * @notice Implements the bitmap logic to handle the eMode configuration + */ +library EModeConfiguration { + /** + * @notice Sets a bit in a given bitmap that represents the reserve index range + * @dev The supplied bitmap is supposed to be a uint128 in which each bit represents a reserve + * @param bitmap The bitmap + * @param reserveIndex The index of the reserve in the bitmap + * @param enabled True if the reserveIndex should be enabled on the bitmap, false otherwise + * @return The altered bitmap + */ + function setReserveBitmapBit( + uint128 bitmap, + uint256 reserveIndex, + bool enabled + ) internal pure returns (uint128) { + unchecked { + require(reserveIndex < ReserveConfiguration.MAX_RESERVES_COUNT, Errors.INVALID_RESERVE_INDEX); + uint128 bit = uint128(1 << reserveIndex); + if (enabled) { + return bitmap | bit; + } else { + return bitmap & ~bit; + } + } + } + + /** + * @notice Validates if a reserveIndex is flagged as enabled on a given bitmap + * @param bitmap The bitmap + * @param reserveIndex The index of the reserve in the bitmap + * @return True if the reserveindex is flagged true + */ + function isReserveEnabledOnBitmap( + uint128 bitmap, + uint256 reserveIndex + ) internal pure returns (bool) { + unchecked { + require(reserveIndex < ReserveConfiguration.MAX_RESERVES_COUNT, Errors.INVALID_RESERVE_INDEX); + return (bitmap >> reserveIndex) & 1 != 0; + } + } +} diff --git a/contracts/protocol/libraries/types/DataTypes.sol b/contracts/protocol/libraries/types/DataTypes.sol index 1ef3d76cd..9d0c16718 100644 --- a/contracts/protocol/libraries/types/DataTypes.sol +++ b/contracts/protocol/libraries/types/DataTypes.sol @@ -74,11 +74,25 @@ library DataTypes { uint16 ltv; uint16 liquidationThreshold; uint16 liquidationBonus; - // each eMode category may or may not have a custom oracle to override the individual assets price oracles + uint128 collateralBitmap; + uint128 borrowableBitmap; address priceSource; string label; } + struct CollateralConfig { + uint16 ltv; + uint16 liquidationThreshold; + uint16 liquidationBonus; + } + + struct EModeCategoryBaseConfiguration { + uint16 ltv; + uint16 liquidationThreshold; + uint16 liquidationBonus; + string label; + } + enum InterestRateMode { NONE, STABLE, diff --git a/contracts/protocol/pool/Pool.sol b/contracts/protocol/pool/Pool.sol index 9bd2cbee0..4af282a01 100644 --- a/contracts/protocol/pool/Pool.sol +++ b/contracts/protocol/pool/Pool.sol @@ -28,9 +28,7 @@ import {PoolStorage} from './PoolStorage.sol'; * # Withdraw * # Borrow * # Repay - * # Swap their loans between variable and stable rate - * # Enable/disable their supplied assets as collateral rebalance stable rate borrow positions - * # Liquidate positions + * # Enable/disable their supplied assets as collateral * # Execute Flash Loans * @dev To be covered by a proxy contract, owned by the PoolAddressesProvider of the specific market * @dev All admin functions are callable by the PoolConfigurator contract defined also in the @@ -666,21 +664,66 @@ contract Pool is VersionedInitializable, PoolStorage, IPool { _flashLoanPremiumToProtocol = flashLoanPremiumToProtocol; } - /// @inheritdoc IPool function configureEModeCategory( uint8 id, - DataTypes.EModeCategory memory category + DataTypes.EModeCategoryBaseConfiguration memory category ) external virtual override onlyPoolConfigurator { // category 0 is reserved for volatile heterogeneous assets and it's always disabled require(id != 0, Errors.EMODE_CATEGORY_RESERVED); - _eModeCategories[id] = category; + _eModeCategories[id].ltv = category.ltv; + _eModeCategories[id].liquidationThreshold = category.liquidationThreshold; + _eModeCategories[id].liquidationBonus = category.liquidationBonus; + _eModeCategories[id].label = category.label; } /// @inheritdoc IPool - function getEModeCategoryData( - uint8 id - ) external view virtual override returns (DataTypes.EModeCategory memory) { - return _eModeCategories[id]; + function configureEModeCategoryCollateralBitmap( + uint8 id, + uint128 collateralBitmap + ) external virtual override onlyPoolConfigurator { + // category 0 is reserved for volatile heterogeneous assets and it's always disabled + require(id != 0, Errors.EMODE_CATEGORY_RESERVED); + _eModeCategories[id].collateralBitmap = collateralBitmap; + } + + /// @inheritdoc IPool + function configureEModeCategoryBorrowableBitmap( + uint8 id, + uint128 borrowableBitmap + ) external virtual override onlyPoolConfigurator { + // category 0 is reserved for volatile heterogeneous assets and it's always disabled + require(id != 0, Errors.EMODE_CATEGORY_RESERVED); + _eModeCategories[id].borrowableBitmap = borrowableBitmap; + } + + /// @inheritdoc IPool + // function getEModeCategoryData( + // uint8 id + // ) external view virtual override returns (DataTypes.EModeCategory memory) { + // DataTypes.EModeCategory memory category = _eModeCategories[id]; + // return + // DataTypes.EModeCategory({ + // ltv: category.ltv, + // liquidationThreshold: category.liquidationThreshold, + // liquidationBonus: category.liquidationBonus, + // priceSource: address(0), + // label: category.label + // }); + // } + + /// @inheritdoc IPool + function getEModeCategoryLabel(uint8 id) external view returns (string memory) { + return _eModeCategories[id].label; + } + + /// @inheritdoc IPool + function getEModeCategoryCollateralBitmap(uint8 id) external view returns (uint128) { + return _eModeCategories[id].collateralBitmap; + } + + /// @inheritdoc IPool + function getEModeCategoryBorrowableBitmap(uint8 id) external view returns (uint128) { + return _eModeCategories[id].borrowableBitmap; } /// @inheritdoc IPool @@ -699,6 +742,18 @@ contract Pool is VersionedInitializable, PoolStorage, IPool { ); } + /// @inheritdoc IPool + function getEModeCategoryCollateralConfig( + uint8 id + ) external view returns (DataTypes.CollateralConfig memory) { + return + DataTypes.CollateralConfig({ + ltv: _eModeCategories[id].ltv, + liquidationThreshold: _eModeCategories[id].liquidationThreshold, + liquidationBonus: _eModeCategories[id].liquidationBonus + }); + } + /// @inheritdoc IPool function getUserEMode(address user) external view virtual override returns (uint256) { return _usersEModeCategory[user]; diff --git a/contracts/protocol/pool/PoolConfigurator.sol b/contracts/protocol/pool/PoolConfigurator.sol index b577a0453..36d9a31f1 100644 --- a/contracts/protocol/pool/PoolConfigurator.sol +++ b/contracts/protocol/pool/PoolConfigurator.sol @@ -1,18 +1,19 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.12; -import {VersionedInitializable} from "../libraries/aave-upgradeability/VersionedInitializable.sol"; -import {ReserveConfiguration} from "../libraries/configuration/ReserveConfiguration.sol"; -import {IPoolAddressesProvider} from "../../interfaces/IPoolAddressesProvider.sol"; -import {Errors} from "../libraries/helpers/Errors.sol"; -import {PercentageMath} from "../libraries/math/PercentageMath.sol"; -import {DataTypes} from "../libraries/types/DataTypes.sol"; -import {ConfiguratorLogic} from "../libraries/logic/ConfiguratorLogic.sol"; -import {ConfiguratorInputTypes} from "../libraries/types/ConfiguratorInputTypes.sol"; -import {IPoolConfigurator} from "../../interfaces/IPoolConfigurator.sol"; -import {IPool} from "../../interfaces/IPool.sol"; -import {IACLManager} from "../../interfaces/IACLManager.sol"; -import {IPoolDataProvider} from "../../interfaces/IPoolDataProvider.sol"; +import {VersionedInitializable} from '../libraries/aave-upgradeability/VersionedInitializable.sol'; +import {ReserveConfiguration} from '../libraries/configuration/ReserveConfiguration.sol'; +import {EModeConfiguration} from 'contracts/protocol/libraries/configuration/EModeConfiguration.sol'; +import {IPoolAddressesProvider} from '../../interfaces/IPoolAddressesProvider.sol'; +import {Errors} from '../libraries/helpers/Errors.sol'; +import {PercentageMath} from '../libraries/math/PercentageMath.sol'; +import {DataTypes} from '../libraries/types/DataTypes.sol'; +import {ConfiguratorLogic} from '../libraries/logic/ConfiguratorLogic.sol'; +import {ConfiguratorInputTypes} from '../libraries/types/ConfiguratorInputTypes.sol'; +import {IPoolConfigurator} from '../../interfaces/IPoolConfigurator.sol'; +import {IPool} from '../../interfaces/IPool.sol'; +import {IACLManager} from '../../interfaces/IACLManager.sol'; +import {IPoolDataProvider} from '../../interfaces/IPoolDataProvider.sol'; /** * @title PoolConfigurator @@ -20,633 +21,507 @@ import {IPoolDataProvider} from "../../interfaces/IPoolDataProvider.sol"; * @dev Implements the configuration methods for the Aave protocol */ contract PoolConfigurator is VersionedInitializable, IPoolConfigurator { - using PercentageMath for uint256; - using ReserveConfiguration for DataTypes.ReserveConfigurationMap; - - IPoolAddressesProvider internal _addressesProvider; - IPool internal _pool; - - /** - * @dev Only pool admin can call functions marked by this modifier. - */ - modifier onlyPoolAdmin() { - _onlyPoolAdmin(); - _; - } - - /** - * @dev Only emergency admin can call functions marked by this modifier. - */ - modifier onlyEmergencyAdmin() { - _onlyEmergencyAdmin(); - _; - } - - /** - * @dev Only emergency or pool admin can call functions marked by this modifier. - */ - modifier onlyEmergencyOrPoolAdmin() { - _onlyPoolOrEmergencyAdmin(); - _; - } - - /** - * @dev Only asset listing or pool admin can call functions marked by this modifier. - */ - modifier onlyAssetListingOrPoolAdmins() { - _onlyAssetListingOrPoolAdmins(); - _; - } - - /** - * @dev Only risk or pool admin can call functions marked by this modifier. - */ - modifier onlyRiskOrPoolAdmins() { - _onlyRiskOrPoolAdmins(); - _; - } - - uint256 public constant CONFIGURATOR_REVISION = 0x4; - - /// @inheritdoc VersionedInitializable - function getRevision() internal pure virtual override returns (uint256) { - return CONFIGURATOR_REVISION; - } - - function initialize(IPoolAddressesProvider provider) public initializer { - _addressesProvider = provider; - _pool = IPool(_addressesProvider.getPool()); - } - - /// @inheritdoc IPoolConfigurator - function initReserves( - ConfiguratorInputTypes.InitReserveInput[] calldata input - ) external override onlyAssetListingOrPoolAdmins { - IPool cachedPool = _pool; - for (uint256 i = 0; i < input.length; i++) { - ConfiguratorLogic.executeInitReserve(cachedPool, input[i]); - } - } - - /// @inheritdoc IPoolConfigurator - function dropReserve(address asset) external override onlyPoolAdmin { - _pool.dropReserve(asset); - emit ReserveDropped(asset); - } - - /// @inheritdoc IPoolConfigurator - function updateAToken( - ConfiguratorInputTypes.UpdateATokenInput calldata input - ) external override onlyPoolAdmin { - ConfiguratorLogic.executeUpdateAToken(_pool, input); - } - - /// @inheritdoc IPoolConfigurator - function updateStableDebtToken( - ConfiguratorInputTypes.UpdateDebtTokenInput calldata input - ) external override onlyPoolAdmin { - ConfiguratorLogic.executeUpdateStableDebtToken(_pool, input); - } - - /// @inheritdoc IPoolConfigurator - function updateVariableDebtToken( - ConfiguratorInputTypes.UpdateDebtTokenInput calldata input - ) external override onlyPoolAdmin { - ConfiguratorLogic.executeUpdateVariableDebtToken(_pool, input); - } - - /// @inheritdoc IPoolConfigurator - function setReserveBorrowing( - address asset, - bool enabled - ) external override onlyRiskOrPoolAdmins { - DataTypes.ReserveConfigurationMap memory currentConfig = _pool - .getConfiguration(asset); - if (!enabled) { - require( - !currentConfig.getStableRateBorrowingEnabled(), - Errors.STABLE_BORROWING_ENABLED - ); - } - currentConfig.setBorrowingEnabled(enabled); - _pool.setConfiguration(asset, currentConfig); - emit ReserveBorrowing(asset, enabled); - } - - /// @inheritdoc IPoolConfigurator - function configureReserveAsCollateral( - address asset, - uint256 ltv, - uint256 liquidationThreshold, - uint256 liquidationBonus - ) external override onlyRiskOrPoolAdmins { - //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.INVALID_RESERVE_PARAMS); - - DataTypes.ReserveConfigurationMap memory currentConfig = _pool - .getConfiguration(asset); - - 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.INVALID_RESERVE_PARAMS - ); - - //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.INVALID_RESERVE_PARAMS - ); - } else { - require(liquidationBonus == 0, Errors.INVALID_RESERVE_PARAMS); - //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 supplied - _checkNoSuppliers(asset); - } - - currentConfig.setLtv(ltv); - currentConfig.setLiquidationThreshold(liquidationThreshold); - currentConfig.setLiquidationBonus(liquidationBonus); - - _pool.setConfiguration(asset, currentConfig); - - emit CollateralConfigurationChanged( - asset, - ltv, - liquidationThreshold, - liquidationBonus - ); - } - - /// @inheritdoc IPoolConfigurator - function setReserveStableRateBorrowing( - address asset, - bool enabled - ) external override onlyRiskOrPoolAdmins { - DataTypes.ReserveConfigurationMap memory currentConfig = _pool - .getConfiguration(asset); - if (enabled) { - require( - currentConfig.getBorrowingEnabled(), - Errors.BORROWING_NOT_ENABLED - ); - } - currentConfig.setStableRateBorrowingEnabled(enabled); - _pool.setConfiguration(asset, currentConfig); - emit ReserveStableRateBorrowing(asset, enabled); - } - - /// @inheritdoc IPoolConfigurator - function setReserveFlashLoaning( - address asset, - bool enabled - ) external override onlyRiskOrPoolAdmins { - DataTypes.ReserveConfigurationMap memory currentConfig = _pool - .getConfiguration(asset); - - currentConfig.setFlashLoanEnabled(enabled); - _pool.setConfiguration(asset, currentConfig); - emit ReserveFlashLoaning(asset, enabled); - } - - /// @inheritdoc IPoolConfigurator - function setReserveActive( - address asset, - bool active - ) external override onlyPoolAdmin { - if (!active) _checkNoSuppliers(asset); - DataTypes.ReserveConfigurationMap memory currentConfig = _pool - .getConfiguration(asset); - currentConfig.setActive(active); - _pool.setConfiguration(asset, currentConfig); - emit ReserveActive(asset, active); - } - - /// @inheritdoc IPoolConfigurator - function setReserveFreeze( - address asset, - bool freeze - ) external override onlyRiskOrPoolAdmins { - DataTypes.ReserveConfigurationMap memory currentConfig = _pool - .getConfiguration(asset); - currentConfig.setFrozen(freeze); - _pool.setConfiguration(asset, currentConfig); - emit ReserveFrozen(asset, freeze); - } - - /// @inheritdoc IPoolConfigurator - function setBorrowableInIsolation( - address asset, - bool borrowable - ) external override onlyRiskOrPoolAdmins { - DataTypes.ReserveConfigurationMap memory currentConfig = _pool - .getConfiguration(asset); - currentConfig.setBorrowableInIsolation(borrowable); - _pool.setConfiguration(asset, currentConfig); - emit BorrowableInIsolationChanged(asset, borrowable); - } - - /// @inheritdoc IPoolConfigurator - function setReservePause( - address asset, - bool paused - ) public override onlyEmergencyOrPoolAdmin { - DataTypes.ReserveConfigurationMap memory currentConfig = _pool - .getConfiguration(asset); - currentConfig.setPaused(paused); - _pool.setConfiguration(asset, currentConfig); - emit ReservePaused(asset, paused); - } - - /// @inheritdoc IPoolConfigurator - function setReserveFactor( - address asset, - uint256 newReserveFactor - ) external override onlyRiskOrPoolAdmins { - require( - newReserveFactor <= PercentageMath.PERCENTAGE_FACTOR, - Errors.INVALID_RESERVE_FACTOR - ); - DataTypes.ReserveConfigurationMap memory currentConfig = _pool - .getConfiguration(asset); - uint256 oldReserveFactor = currentConfig.getReserveFactor(); - currentConfig.setReserveFactor(newReserveFactor); - _pool.setConfiguration(asset, currentConfig); - emit ReserveFactorChanged(asset, oldReserveFactor, newReserveFactor); - } - - /// @inheritdoc IPoolConfigurator - function setDebtCeiling( - address asset, - uint256 newDebtCeiling - ) external override onlyRiskOrPoolAdmins { - DataTypes.ReserveConfigurationMap memory currentConfig = _pool - .getConfiguration(asset); - - uint256 oldDebtCeiling = currentConfig.getDebtCeiling(); - if (oldDebtCeiling == 0) { - _checkNoSuppliers(asset); - } - currentConfig.setDebtCeiling(newDebtCeiling); - _pool.setConfiguration(asset, currentConfig); - - if (newDebtCeiling == 0) { - _pool.resetIsolationModeTotalDebt(asset); - } - - emit DebtCeilingChanged(asset, oldDebtCeiling, newDebtCeiling); - } - - /// @inheritdoc IPoolConfigurator - function setSiloedBorrowing( - address asset, - bool newSiloed - ) external override onlyRiskOrPoolAdmins { - if (newSiloed) { - _checkNoBorrowers(asset); - } - DataTypes.ReserveConfigurationMap memory currentConfig = _pool - .getConfiguration(asset); - - bool oldSiloed = currentConfig.getSiloedBorrowing(); - - currentConfig.setSiloedBorrowing(newSiloed); - - _pool.setConfiguration(asset, currentConfig); - - emit SiloedBorrowingChanged(asset, oldSiloed, newSiloed); - } - - /// @inheritdoc IPoolConfigurator - function setBorrowCap( - address asset, - uint256 newBorrowCap - ) external override onlyRiskOrPoolAdmins { - DataTypes.ReserveConfigurationMap memory currentConfig = _pool - .getConfiguration(asset); - uint256 oldBorrowCap = currentConfig.getBorrowCap(); - currentConfig.setBorrowCap(newBorrowCap); - _pool.setConfiguration(asset, currentConfig); - emit BorrowCapChanged(asset, oldBorrowCap, newBorrowCap); - } - - /// @inheritdoc IPoolConfigurator - function setSupplyCap( - address asset, - uint256 newSupplyCap - ) external override onlyRiskOrPoolAdmins { - DataTypes.ReserveConfigurationMap memory currentConfig = _pool - .getConfiguration(asset); - uint256 oldSupplyCap = currentConfig.getSupplyCap(); - currentConfig.setSupplyCap(newSupplyCap); - _pool.setConfiguration(asset, currentConfig); - emit SupplyCapChanged(asset, oldSupplyCap, newSupplyCap); - } - - /// @inheritdoc IPoolConfigurator - function setLiquidationProtocolFee( - address asset, - uint256 newFee - ) external override onlyRiskOrPoolAdmins { - require( - newFee <= PercentageMath.PERCENTAGE_FACTOR, - Errors.INVALID_LIQUIDATION_PROTOCOL_FEE - ); - DataTypes.ReserveConfigurationMap memory currentConfig = _pool - .getConfiguration(asset); - uint256 oldFee = currentConfig.getLiquidationProtocolFee(); - currentConfig.setLiquidationProtocolFee(newFee); - _pool.setConfiguration(asset, currentConfig); - emit LiquidationProtocolFeeChanged(asset, oldFee, newFee); - } - - /// @inheritdoc IPoolConfigurator - function setEModeCategory( - uint8 categoryId, - uint16 ltv, - uint16 liquidationThreshold, - uint16 liquidationBonus, - address oracle, - string calldata label - ) external override onlyRiskOrPoolAdmins { - require(ltv != 0, Errors.INVALID_EMODE_CATEGORY_PARAMS); - require( - liquidationThreshold != 0, - Errors.INVALID_EMODE_CATEGORY_PARAMS - ); - - // 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.INVALID_EMODE_CATEGORY_PARAMS - ); - require( - liquidationBonus > PercentageMath.PERCENTAGE_FACTOR, - Errors.INVALID_EMODE_CATEGORY_PARAMS - ); - - // 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( - uint256(liquidationThreshold).percentMul(liquidationBonus) <= - PercentageMath.PERCENTAGE_FACTOR, - Errors.INVALID_EMODE_CATEGORY_PARAMS - ); - - address[] memory reserves = _pool.getReservesList(); - for (uint256 i = 0; i < reserves.length; i++) { - DataTypes.ReserveConfigurationMap memory currentConfig = _pool - .getConfiguration(reserves[i]); - if (categoryId == currentConfig.getEModeCategory()) { - require( - ltv > currentConfig.getLtv(), - Errors.INVALID_EMODE_CATEGORY_PARAMS - ); - require( - liquidationThreshold > - currentConfig.getLiquidationThreshold(), - Errors.INVALID_EMODE_CATEGORY_PARAMS - ); - } - } - - _pool.configureEModeCategory( - categoryId, - DataTypes.EModeCategory({ - ltv: ltv, - liquidationThreshold: liquidationThreshold, - liquidationBonus: liquidationBonus, - priceSource: oracle, - label: label - }) - ); - emit EModeCategoryAdded( - categoryId, - ltv, - liquidationThreshold, - liquidationBonus, - oracle, - label - ); - } - - /// @inheritdoc IPoolConfigurator - function setAssetEModeCategory( - address asset, - uint8 newCategoryId - ) external override onlyRiskOrPoolAdmins { - DataTypes.ReserveConfigurationMap memory currentConfig = _pool - .getConfiguration(asset); - - if (newCategoryId != 0) { - DataTypes.EModeCategory memory categoryData = _pool - .getEModeCategoryData(newCategoryId); - require( - categoryData.liquidationThreshold > - currentConfig.getLiquidationThreshold(), - Errors.INVALID_EMODE_CATEGORY_ASSIGNMENT - ); - } - uint256 oldCategoryId = currentConfig.getEModeCategory(); - currentConfig.setEModeCategory(newCategoryId); - _pool.setConfiguration(asset, currentConfig); - emit EModeAssetCategoryChanged( - asset, - uint8(oldCategoryId), - newCategoryId - ); - } - - /// @inheritdoc IPoolConfigurator - function setUnbackedMintCap( - address asset, - uint256 newUnbackedMintCap - ) external override onlyRiskOrPoolAdmins { - DataTypes.ReserveConfigurationMap memory currentConfig = _pool - .getConfiguration(asset); - uint256 oldUnbackedMintCap = currentConfig.getUnbackedMintCap(); - currentConfig.setUnbackedMintCap(newUnbackedMintCap); - _pool.setConfiguration(asset, currentConfig); - emit UnbackedMintCapChanged( - asset, - oldUnbackedMintCap, - newUnbackedMintCap - ); - } - - /// @inheritdoc IPoolConfigurator - function setReserveInterestRateStrategyAddress( - address asset, - address newRateStrategyAddress - ) external override onlyRiskOrPoolAdmins { - DataTypes.ReserveData memory reserve = _pool.getReserveData(asset); - address oldRateStrategyAddress = reserve.interestRateStrategyAddress; - _pool.setReserveInterestRateStrategyAddress( - asset, - newRateStrategyAddress - ); - emit ReserveInterestRateStrategyChanged( - asset, - oldRateStrategyAddress, - newRateStrategyAddress - ); - } - - /// @inheritdoc IPoolConfigurator - function setPoolPause(bool paused) external override onlyEmergencyAdmin { - address[] memory reserves = _pool.getReservesList(); - - for (uint256 i = 0; i < reserves.length; i++) { - if (reserves[i] != address(0)) { - setReservePause(reserves[i], paused); - } - } - } - - /// @inheritdoc IPoolConfigurator - function updateBridgeProtocolFee( - uint256 newBridgeProtocolFee - ) external override onlyPoolAdmin { - require( - newBridgeProtocolFee <= PercentageMath.PERCENTAGE_FACTOR, - Errors.BRIDGE_PROTOCOL_FEE_INVALID - ); - uint256 oldBridgeProtocolFee = _pool.BRIDGE_PROTOCOL_FEE(); - _pool.updateBridgeProtocolFee(newBridgeProtocolFee); - emit BridgeProtocolFeeUpdated( - oldBridgeProtocolFee, - newBridgeProtocolFee - ); - } - - /// @inheritdoc IPoolConfigurator - function updateFlashloanPremiumTotal( - uint128 newFlashloanPremiumTotal - ) external override onlyPoolAdmin { - require( - newFlashloanPremiumTotal <= PercentageMath.PERCENTAGE_FACTOR, - Errors.FLASHLOAN_PREMIUM_INVALID - ); - uint128 oldFlashloanPremiumTotal = _pool.FLASHLOAN_PREMIUM_TOTAL(); - _pool.updateFlashloanPremiums( - newFlashloanPremiumTotal, - _pool.FLASHLOAN_PREMIUM_TO_PROTOCOL() - ); - emit FlashloanPremiumTotalUpdated( - oldFlashloanPremiumTotal, - newFlashloanPremiumTotal - ); - } - - /// @inheritdoc IPoolConfigurator - function updateFlashloanPremiumToProtocol( - uint128 newFlashloanPremiumToProtocol - ) external override onlyPoolAdmin { - require( - newFlashloanPremiumToProtocol <= PercentageMath.PERCENTAGE_FACTOR, - Errors.FLASHLOAN_PREMIUM_INVALID - ); - uint128 oldFlashloanPremiumToProtocol = _pool - .FLASHLOAN_PREMIUM_TO_PROTOCOL(); - _pool.updateFlashloanPremiums( - _pool.FLASHLOAN_PREMIUM_TOTAL(), - newFlashloanPremiumToProtocol - ); - emit FlashloanPremiumToProtocolUpdated( - oldFlashloanPremiumToProtocol, - newFlashloanPremiumToProtocol - ); - } - - function _checkNoSuppliers(address asset) internal view { - ( - , - uint256 accruedToTreasury, - uint256 totalATokens, - , - , - , - , - , - , - , - , - - ) = IPoolDataProvider(_addressesProvider.getPoolDataProvider()) - .getReserveData(asset); - - require( - totalATokens == 0 && accruedToTreasury == 0, - Errors.RESERVE_LIQUIDITY_NOT_ZERO - ); - } - - function _checkNoBorrowers(address asset) internal view { - uint256 totalDebt = IPoolDataProvider( - _addressesProvider.getPoolDataProvider() - ).getTotalDebt(asset); - require(totalDebt == 0, Errors.RESERVE_DEBT_NOT_ZERO); - } - - function _onlyPoolAdmin() internal view { - IACLManager aclManager = IACLManager( - _addressesProvider.getACLManager() - ); - require( - aclManager.isPoolAdmin(msg.sender), - Errors.CALLER_NOT_POOL_ADMIN - ); - } - - function _onlyEmergencyAdmin() internal view { - IACLManager aclManager = IACLManager( - _addressesProvider.getACLManager() - ); - require( - aclManager.isEmergencyAdmin(msg.sender), - Errors.CALLER_NOT_EMERGENCY_ADMIN - ); - } - - function _onlyPoolOrEmergencyAdmin() internal view { - IACLManager aclManager = IACLManager( - _addressesProvider.getACLManager() - ); - require( - aclManager.isPoolAdmin(msg.sender) || - aclManager.isEmergencyAdmin(msg.sender), - Errors.CALLER_NOT_POOL_OR_EMERGENCY_ADMIN - ); - } - - function _onlyAssetListingOrPoolAdmins() internal view { - IACLManager aclManager = IACLManager( - _addressesProvider.getACLManager() - ); - require( - aclManager.isAssetListingAdmin(msg.sender) || - aclManager.isPoolAdmin(msg.sender), - Errors.CALLER_NOT_ASSET_LISTING_OR_POOL_ADMIN - ); - } - - function _onlyRiskOrPoolAdmins() internal view { - IACLManager aclManager = IACLManager( - _addressesProvider.getACLManager() - ); - require( - aclManager.isRiskAdmin(msg.sender) || - aclManager.isPoolAdmin(msg.sender), - Errors.CALLER_NOT_RISK_OR_POOL_ADMIN - ); - } + using PercentageMath for uint256; + using ReserveConfiguration for DataTypes.ReserveConfigurationMap; + + IPoolAddressesProvider internal _addressesProvider; + IPool internal _pool; + + /** + * @dev Only pool admin can call functions marked by this modifier. + */ + modifier onlyPoolAdmin() { + _onlyPoolAdmin(); + _; + } + + /** + * @dev Only emergency admin can call functions marked by this modifier. + */ + modifier onlyEmergencyAdmin() { + _onlyEmergencyAdmin(); + _; + } + + /** + * @dev Only emergency or pool admin can call functions marked by this modifier. + */ + modifier onlyEmergencyOrPoolAdmin() { + _onlyPoolOrEmergencyAdmin(); + _; + } + + /** + * @dev Only asset listing or pool admin can call functions marked by this modifier. + */ + modifier onlyAssetListingOrPoolAdmins() { + _onlyAssetListingOrPoolAdmins(); + _; + } + + /** + * @dev Only risk or pool admin can call functions marked by this modifier. + */ + modifier onlyRiskOrPoolAdmins() { + _onlyRiskOrPoolAdmins(); + _; + } + + uint256 public constant CONFIGURATOR_REVISION = 0x4; + + /// @inheritdoc VersionedInitializable + function getRevision() internal pure virtual override returns (uint256) { + return CONFIGURATOR_REVISION; + } + + function initialize(IPoolAddressesProvider provider) public initializer { + _addressesProvider = provider; + _pool = IPool(_addressesProvider.getPool()); + } + + /// @inheritdoc IPoolConfigurator + function initReserves( + ConfiguratorInputTypes.InitReserveInput[] calldata input + ) external override onlyAssetListingOrPoolAdmins { + IPool cachedPool = _pool; + for (uint256 i = 0; i < input.length; i++) { + ConfiguratorLogic.executeInitReserve(cachedPool, input[i]); + } + } + + /// @inheritdoc IPoolConfigurator + function dropReserve(address asset) external override onlyPoolAdmin { + _pool.dropReserve(asset); + emit ReserveDropped(asset); + } + + /// @inheritdoc IPoolConfigurator + function updateAToken( + ConfiguratorInputTypes.UpdateATokenInput calldata input + ) external override onlyPoolAdmin { + ConfiguratorLogic.executeUpdateAToken(_pool, input); + } + + /// @inheritdoc IPoolConfigurator + function updateStableDebtToken( + ConfiguratorInputTypes.UpdateDebtTokenInput calldata input + ) external override onlyPoolAdmin { + ConfiguratorLogic.executeUpdateStableDebtToken(_pool, input); + } + + /// @inheritdoc IPoolConfigurator + function updateVariableDebtToken( + ConfiguratorInputTypes.UpdateDebtTokenInput calldata input + ) external override onlyPoolAdmin { + ConfiguratorLogic.executeUpdateVariableDebtToken(_pool, input); + } + + /// @inheritdoc IPoolConfigurator + function setReserveBorrowing(address asset, bool enabled) external override onlyRiskOrPoolAdmins { + DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); + if (!enabled) { + require(!currentConfig.getStableRateBorrowingEnabled(), Errors.STABLE_BORROWING_ENABLED); + } + currentConfig.setBorrowingEnabled(enabled); + _pool.setConfiguration(asset, currentConfig); + emit ReserveBorrowing(asset, enabled); + } + + /// @inheritdoc IPoolConfigurator + function configureReserveAsCollateral( + address asset, + uint256 ltv, + uint256 liquidationThreshold, + uint256 liquidationBonus + ) external override onlyRiskOrPoolAdmins { + //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.INVALID_RESERVE_PARAMS); + + DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); + + 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.INVALID_RESERVE_PARAMS); + + //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.INVALID_RESERVE_PARAMS + ); + } else { + require(liquidationBonus == 0, Errors.INVALID_RESERVE_PARAMS); + //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 supplied + _checkNoSuppliers(asset); + } + + currentConfig.setLtv(ltv); + currentConfig.setLiquidationThreshold(liquidationThreshold); + currentConfig.setLiquidationBonus(liquidationBonus); + + _pool.setConfiguration(asset, currentConfig); + + emit CollateralConfigurationChanged(asset, ltv, liquidationThreshold, liquidationBonus); + } + + /// @inheritdoc IPoolConfigurator + function setReserveStableRateBorrowing( + address asset, + bool enabled + ) external override onlyRiskOrPoolAdmins { + DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); + if (enabled) { + require(currentConfig.getBorrowingEnabled(), Errors.BORROWING_NOT_ENABLED); + } + currentConfig.setStableRateBorrowingEnabled(enabled); + _pool.setConfiguration(asset, currentConfig); + emit ReserveStableRateBorrowing(asset, enabled); + } + + /// @inheritdoc IPoolConfigurator + function setReserveFlashLoaning( + address asset, + bool enabled + ) external override onlyRiskOrPoolAdmins { + DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); + + currentConfig.setFlashLoanEnabled(enabled); + _pool.setConfiguration(asset, currentConfig); + emit ReserveFlashLoaning(asset, enabled); + } + + /// @inheritdoc IPoolConfigurator + function setReserveActive(address asset, bool active) external override onlyPoolAdmin { + if (!active) _checkNoSuppliers(asset); + DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); + currentConfig.setActive(active); + _pool.setConfiguration(asset, currentConfig); + emit ReserveActive(asset, active); + } + + /// @inheritdoc IPoolConfigurator + function setReserveFreeze(address asset, bool freeze) external override onlyRiskOrPoolAdmins { + DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); + currentConfig.setFrozen(freeze); + _pool.setConfiguration(asset, currentConfig); + emit ReserveFrozen(asset, freeze); + } + + /// @inheritdoc IPoolConfigurator + function setBorrowableInIsolation( + address asset, + bool borrowable + ) external override onlyRiskOrPoolAdmins { + DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); + currentConfig.setBorrowableInIsolation(borrowable); + _pool.setConfiguration(asset, currentConfig); + emit BorrowableInIsolationChanged(asset, borrowable); + } + + /// @inheritdoc IPoolConfigurator + function setReservePause(address asset, bool paused) public override onlyEmergencyOrPoolAdmin { + DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); + currentConfig.setPaused(paused); + _pool.setConfiguration(asset, currentConfig); + emit ReservePaused(asset, paused); + } + + /// @inheritdoc IPoolConfigurator + function setReserveFactor( + address asset, + uint256 newReserveFactor + ) external override onlyRiskOrPoolAdmins { + require(newReserveFactor <= PercentageMath.PERCENTAGE_FACTOR, Errors.INVALID_RESERVE_FACTOR); + DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); + uint256 oldReserveFactor = currentConfig.getReserveFactor(); + currentConfig.setReserveFactor(newReserveFactor); + _pool.setConfiguration(asset, currentConfig); + emit ReserveFactorChanged(asset, oldReserveFactor, newReserveFactor); + } + + /// @inheritdoc IPoolConfigurator + function setDebtCeiling( + address asset, + uint256 newDebtCeiling + ) external override onlyRiskOrPoolAdmins { + DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); + + uint256 oldDebtCeiling = currentConfig.getDebtCeiling(); + if (oldDebtCeiling == 0) { + _checkNoSuppliers(asset); + } + currentConfig.setDebtCeiling(newDebtCeiling); + _pool.setConfiguration(asset, currentConfig); + + if (newDebtCeiling == 0) { + _pool.resetIsolationModeTotalDebt(asset); + } + + emit DebtCeilingChanged(asset, oldDebtCeiling, newDebtCeiling); + } + + /// @inheritdoc IPoolConfigurator + function setSiloedBorrowing( + address asset, + bool newSiloed + ) external override onlyRiskOrPoolAdmins { + if (newSiloed) { + _checkNoBorrowers(asset); + } + DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); + + bool oldSiloed = currentConfig.getSiloedBorrowing(); + + currentConfig.setSiloedBorrowing(newSiloed); + + _pool.setConfiguration(asset, currentConfig); + + emit SiloedBorrowingChanged(asset, oldSiloed, newSiloed); + } + + /// @inheritdoc IPoolConfigurator + function setBorrowCap( + address asset, + uint256 newBorrowCap + ) external override onlyRiskOrPoolAdmins { + DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); + uint256 oldBorrowCap = currentConfig.getBorrowCap(); + currentConfig.setBorrowCap(newBorrowCap); + _pool.setConfiguration(asset, currentConfig); + emit BorrowCapChanged(asset, oldBorrowCap, newBorrowCap); + } + + /// @inheritdoc IPoolConfigurator + function setSupplyCap( + address asset, + uint256 newSupplyCap + ) external override onlyRiskOrPoolAdmins { + DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); + uint256 oldSupplyCap = currentConfig.getSupplyCap(); + currentConfig.setSupplyCap(newSupplyCap); + _pool.setConfiguration(asset, currentConfig); + emit SupplyCapChanged(asset, oldSupplyCap, newSupplyCap); + } + + /// @inheritdoc IPoolConfigurator + function setLiquidationProtocolFee( + address asset, + uint256 newFee + ) external override onlyRiskOrPoolAdmins { + require(newFee <= PercentageMath.PERCENTAGE_FACTOR, Errors.INVALID_LIQUIDATION_PROTOCOL_FEE); + DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); + uint256 oldFee = currentConfig.getLiquidationProtocolFee(); + currentConfig.setLiquidationProtocolFee(newFee); + _pool.setConfiguration(asset, currentConfig); + emit LiquidationProtocolFeeChanged(asset, oldFee, newFee); + } + + /// @inheritdoc IPoolConfigurator + function setEModeCategory( + uint8 categoryId, + uint16 ltv, + uint16 liquidationThreshold, + uint16 liquidationBonus, + string calldata label + ) external override onlyRiskOrPoolAdmins { + require(ltv != 0, Errors.INVALID_EMODE_CATEGORY_PARAMS); + require(liquidationThreshold != 0, Errors.INVALID_EMODE_CATEGORY_PARAMS); + + // 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.INVALID_EMODE_CATEGORY_PARAMS); + require( + liquidationBonus > PercentageMath.PERCENTAGE_FACTOR, + Errors.INVALID_EMODE_CATEGORY_PARAMS + ); + + // 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( + uint256(liquidationThreshold).percentMul(liquidationBonus) <= + PercentageMath.PERCENTAGE_FACTOR, + Errors.INVALID_EMODE_CATEGORY_PARAMS + ); + + DataTypes.EModeCategoryBaseConfiguration memory categoryData; + categoryData.ltv = ltv; + categoryData.liquidationThreshold = liquidationThreshold; + categoryData.liquidationBonus = liquidationBonus; + categoryData.label = label; + + _pool.configureEModeCategory(categoryId, categoryData); + emit EModeCategoryAdded( + categoryId, + ltv, + liquidationThreshold, + liquidationBonus, + address(0), + label + ); + } + + /// @inheritdoc IPoolConfigurator + function setAssetCollateralInEMode( + address asset, + uint8 categoryId, + bool allowed + ) external override onlyRiskOrPoolAdmins { + uint128 collateralBitmap = _pool.getEModeCategoryCollateralBitmap(categoryId); + DataTypes.ReserveData memory reserveData = _pool.getReserveData(asset); + require(reserveData.id != 0 || _pool.getReservesList()[0] == asset, Errors.ASSET_NOT_LISTED); + collateralBitmap = EModeConfiguration.setReserveBitmapBit( + collateralBitmap, + reserveData.id, + allowed + ); + _pool.configureEModeCategoryCollateralBitmap(categoryId, collateralBitmap); + emit AssetCollateralInEModeChanged(asset, categoryId, allowed); + } + + /// @inheritdoc IPoolConfigurator + function setAssetBorrowableInEMode( + address asset, + uint8 categoryId, + bool borrowable + ) external override onlyRiskOrPoolAdmins { + uint128 borrowableBitmap = _pool.getEModeCategoryBorrowableBitmap(categoryId); + DataTypes.ReserveData memory reserveData = _pool.getReserveData(asset); + require(reserveData.id != 0 || _pool.getReservesList()[0] == asset, Errors.ASSET_NOT_LISTED); + borrowableBitmap = EModeConfiguration.setReserveBitmapBit( + borrowableBitmap, + reserveData.id, + borrowable + ); + _pool.configureEModeCategoryBorrowableBitmap(categoryId, borrowableBitmap); + emit AssetBorrowableInEModeChanged(asset, categoryId, borrowable); + } + + /// @inheritdoc IPoolConfigurator + function setUnbackedMintCap( + address asset, + uint256 newUnbackedMintCap + ) external override onlyRiskOrPoolAdmins { + DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); + uint256 oldUnbackedMintCap = currentConfig.getUnbackedMintCap(); + currentConfig.setUnbackedMintCap(newUnbackedMintCap); + _pool.setConfiguration(asset, currentConfig); + emit UnbackedMintCapChanged(asset, oldUnbackedMintCap, newUnbackedMintCap); + } + + /// @inheritdoc IPoolConfigurator + function setReserveInterestRateStrategyAddress( + address asset, + address newRateStrategyAddress + ) external override onlyRiskOrPoolAdmins { + DataTypes.ReserveData memory reserve = _pool.getReserveData(asset); + address oldRateStrategyAddress = reserve.interestRateStrategyAddress; + _pool.setReserveInterestRateStrategyAddress(asset, newRateStrategyAddress); + emit ReserveInterestRateStrategyChanged(asset, oldRateStrategyAddress, newRateStrategyAddress); + } + + /// @inheritdoc IPoolConfigurator + function setPoolPause(bool paused) external override onlyEmergencyAdmin { + address[] memory reserves = _pool.getReservesList(); + + for (uint256 i = 0; i < reserves.length; i++) { + if (reserves[i] != address(0)) { + setReservePause(reserves[i], paused); + } + } + } + + /// @inheritdoc IPoolConfigurator + function updateBridgeProtocolFee(uint256 newBridgeProtocolFee) external override onlyPoolAdmin { + require( + newBridgeProtocolFee <= PercentageMath.PERCENTAGE_FACTOR, + Errors.BRIDGE_PROTOCOL_FEE_INVALID + ); + uint256 oldBridgeProtocolFee = _pool.BRIDGE_PROTOCOL_FEE(); + _pool.updateBridgeProtocolFee(newBridgeProtocolFee); + emit BridgeProtocolFeeUpdated(oldBridgeProtocolFee, newBridgeProtocolFee); + } + + /// @inheritdoc IPoolConfigurator + function updateFlashloanPremiumTotal( + uint128 newFlashloanPremiumTotal + ) external override onlyPoolAdmin { + require( + newFlashloanPremiumTotal <= PercentageMath.PERCENTAGE_FACTOR, + Errors.FLASHLOAN_PREMIUM_INVALID + ); + uint128 oldFlashloanPremiumTotal = _pool.FLASHLOAN_PREMIUM_TOTAL(); + _pool.updateFlashloanPremiums(newFlashloanPremiumTotal, _pool.FLASHLOAN_PREMIUM_TO_PROTOCOL()); + emit FlashloanPremiumTotalUpdated(oldFlashloanPremiumTotal, newFlashloanPremiumTotal); + } + + /// @inheritdoc IPoolConfigurator + function updateFlashloanPremiumToProtocol( + uint128 newFlashloanPremiumToProtocol + ) external override onlyPoolAdmin { + require( + newFlashloanPremiumToProtocol <= PercentageMath.PERCENTAGE_FACTOR, + Errors.FLASHLOAN_PREMIUM_INVALID + ); + uint128 oldFlashloanPremiumToProtocol = _pool.FLASHLOAN_PREMIUM_TO_PROTOCOL(); + _pool.updateFlashloanPremiums(_pool.FLASHLOAN_PREMIUM_TOTAL(), newFlashloanPremiumToProtocol); + emit FlashloanPremiumToProtocolUpdated( + oldFlashloanPremiumToProtocol, + newFlashloanPremiumToProtocol + ); + } + + function _checkNoSuppliers(address asset) internal view { + (, uint256 accruedToTreasury, uint256 totalATokens, , , , , , , , , ) = IPoolDataProvider( + _addressesProvider.getPoolDataProvider() + ).getReserveData(asset); + + require(totalATokens == 0 && accruedToTreasury == 0, Errors.RESERVE_LIQUIDITY_NOT_ZERO); + } + + function _checkNoBorrowers(address asset) internal view { + uint256 totalDebt = IPoolDataProvider(_addressesProvider.getPoolDataProvider()).getTotalDebt( + asset + ); + require(totalDebt == 0, Errors.RESERVE_DEBT_NOT_ZERO); + } + + function _onlyPoolAdmin() internal view { + IACLManager aclManager = IACLManager(_addressesProvider.getACLManager()); + require(aclManager.isPoolAdmin(msg.sender), Errors.CALLER_NOT_POOL_ADMIN); + } + + function _onlyEmergencyAdmin() internal view { + IACLManager aclManager = IACLManager(_addressesProvider.getACLManager()); + require(aclManager.isEmergencyAdmin(msg.sender), Errors.CALLER_NOT_EMERGENCY_ADMIN); + } + + function _onlyPoolOrEmergencyAdmin() internal view { + IACLManager aclManager = IACLManager(_addressesProvider.getACLManager()); + require( + aclManager.isPoolAdmin(msg.sender) || aclManager.isEmergencyAdmin(msg.sender), + Errors.CALLER_NOT_POOL_OR_EMERGENCY_ADMIN + ); + } + + function _onlyAssetListingOrPoolAdmins() internal view { + IACLManager aclManager = IACLManager(_addressesProvider.getACLManager()); + require( + aclManager.isAssetListingAdmin(msg.sender) || aclManager.isPoolAdmin(msg.sender), + Errors.CALLER_NOT_ASSET_LISTING_OR_POOL_ADMIN + ); + } + + function _onlyRiskOrPoolAdmins() internal view { + IACLManager aclManager = IACLManager(_addressesProvider.getACLManager()); + require( + aclManager.isRiskAdmin(msg.sender) || aclManager.isPoolAdmin(msg.sender), + Errors.CALLER_NOT_RISK_OR_POOL_ADMIN + ); + } } diff --git a/contracts/protocol/pool/PoolStorage.sol b/contracts/protocol/pool/PoolStorage.sol index 08270178c..4c58e367d 100644 --- a/contracts/protocol/pool/PoolStorage.sol +++ b/contracts/protocol/pool/PoolStorage.sol @@ -44,10 +44,10 @@ contract PoolStorage { uint128 internal _flashLoanPremiumToProtocol; // Available liquidity that can be borrowed at once at stable rate, expressed in bps - uint64 internal _maxStableRateBorrowSizePercent; + uint64 internal _maxStableRateBorrowSizePercent; // TODO: This maxStableRate was deprecated on v3.2.0 // Maximum number of active reserves there have been in the protocol. It is the upper bound of the reserves list uint16 internal _reservesCount; - address public expressRelay; + address public expressRelay; // TODO: This was also removed }