diff --git a/contracts/interfaces/ILendingPoolConfigurator.sol b/contracts/interfaces/ILendingPoolConfigurator.sol index fea5560c..fd3bcb19 100644 --- a/contracts/interfaces/ILendingPoolConfigurator.sol +++ b/contracts/interfaces/ILendingPoolConfigurator.sol @@ -120,6 +120,18 @@ interface ILendingPoolConfigurator { **/ 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 factor is updated * @param asset The address of the underlying asset of the reserve diff --git a/contracts/misc/AaveProtocolDataProvider.sol b/contracts/misc/AaveProtocolDataProvider.sol index d07a5f1b..95deb6ea 100644 --- a/contracts/misc/AaveProtocolDataProvider.sol +++ b/contracts/misc/AaveProtocolDataProvider.sol @@ -64,7 +64,7 @@ contract AaveProtocolDataProvider { return aTokens; } - // not returning borrow and supply caps for compatibility + // not returning borrow and supply caps for compatibility, nor pause flag function getReserveConfigurationData(address asset) external view @@ -87,7 +87,7 @@ contract AaveProtocolDataProvider { (ltv, liquidationThreshold, liquidationBonus, decimals, reserveFactor) = configuration.getParamsMemory(); - (isActive, isFrozen, borrowingEnabled, stableBorrowRateEnabled) = + (isActive, isFrozen, borrowingEnabled, stableBorrowRateEnabled, ) = configuration.getFlagsMemory(); usageAsCollateralEnabled = liquidationThreshold > 0; @@ -103,6 +103,13 @@ contract AaveProtocolDataProvider { .getCapsMemory(); } + function getPaused(address asset) external view returns (bool isPaused) { + (, , , , isPaused) = + ILendingPool(ADDRESSES_PROVIDER.getLendingPool()) + .getConfiguration(asset) + .getFlagsMemory(); + } + function getReserveData(address asset) external view diff --git a/contracts/misc/UiPoolDataProvider.sol b/contracts/misc/UiPoolDataProvider.sol index 2a1b6bae..4e4641c3 100644 --- a/contracts/misc/UiPoolDataProvider.sol +++ b/contracts/misc/UiPoolDataProvider.sol @@ -122,7 +122,8 @@ contract UiPoolDataProvider is IUiPoolDataProvider { reserveData.isActive, reserveData.isFrozen, reserveData.borrowingEnabled, - reserveData.stableBorrowRateEnabled + reserveData.stableBorrowRateEnabled, + reserveData.isPaused ) = baseData.configuration.getFlagsMemory(); reserveData.usageAsCollateralEnabled = reserveData.baseLTVasCollateral != 0; ( diff --git a/contracts/misc/WalletBalanceProvider.sol b/contracts/misc/WalletBalanceProvider.sol index 3d4a9288..22a6f55e 100644 --- a/contracts/misc/WalletBalanceProvider.sol +++ b/contracts/misc/WalletBalanceProvider.sol @@ -96,7 +96,7 @@ contract WalletBalanceProvider { DataTypes.ReserveConfigurationMap memory configuration = pool.getConfiguration(reservesWithEth[j]); - (bool isActive, , , ) = configuration.getFlagsMemory(); + (bool isActive, , , , ) = configuration.getFlagsMemory(); if (!isActive) { balances[j] = 0; diff --git a/contracts/misc/interfaces/IUiPoolDataProvider.sol b/contracts/misc/interfaces/IUiPoolDataProvider.sol index 5ea96464..ac7d344a 100644 --- a/contracts/misc/interfaces/IUiPoolDataProvider.sol +++ b/contracts/misc/interfaces/IUiPoolDataProvider.sol @@ -22,6 +22,7 @@ interface IUiPoolDataProvider { bool stableBorrowRateEnabled; bool isActive; bool isFrozen; + bool isPaused; // base data uint128 liquidityIndex; uint128 variableBorrowIndex; diff --git a/contracts/protocol/lendingpool/LendingPoolConfigurator.sol b/contracts/protocol/lendingpool/LendingPoolConfigurator.sol index 4b8662c7..b0e8c37e 100644 --- a/contracts/protocol/lendingpool/LendingPoolConfigurator.sol +++ b/contracts/protocol/lendingpool/LendingPoolConfigurator.sol @@ -46,6 +46,16 @@ contract LendingPoolConfigurator is VersionedInitializable, ILendingPoolConfigur _; } + modifier onlyEmergencyOrPoolAdmin { + require( + addressesProvider.getEmergencyAdmin() == msg.sender + || addressesProvider.getPoolAdmin() == msg.sender, + Errors.LPC_CALLER_NOT_EMERGENCY_OR_POOL_ADMIN + ); + _; + } + + uint256 internal constant CONFIGURATOR_REVISION = 0x1; function getRevision() internal pure override returns (uint256) { @@ -128,6 +138,7 @@ contract LendingPoolConfigurator is VersionedInitializable, ILendingPoolConfigur currentConfig.setDecimals(input.underlyingAssetDecimals); currentConfig.setActive(true); + currentConfig.setPaused(false); currentConfig.setFrozen(false); pool.setConfiguration(input.underlyingAsset, currentConfig.data); @@ -414,6 +425,34 @@ contract LendingPoolConfigurator is VersionedInitializable, ILendingPoolConfigur emit ReserveUnfrozen(asset); } + /** + * @dev Pauses a reserve. A paused reserve allow now user moves such as deposit, borrow, repay, swap interestrate, liquidate + * @param asset The address of the underlying asset of the reserve + **/ + function pauseReserve(address asset) external onlyEmergencyOrPoolAdmin { + DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset); + + currentConfig.setPaused(true); + + pool.setConfiguration(asset, currentConfig.data); + + emit ReservePaused(asset); + } + + /** + * @dev Unpauses a reserve + * @param asset The address of the underlying asset of the reserve + **/ + function unpauseReserve(address asset) external onlyEmergencyOrPoolAdmin { + DataTypes.ReserveConfigurationMap memory currentConfig = pool.getConfiguration(asset); + + currentConfig.setPaused(false); + + pool.setConfiguration(asset, currentConfig.data); + + emit ReserveUnpaused(asset); + } + /** * @dev Updates the reserve factor of a reserve * @param asset The address of the underlying asset of the reserve diff --git a/contracts/protocol/libraries/configuration/ReserveConfiguration.sol b/contracts/protocol/libraries/configuration/ReserveConfiguration.sol index 567ee93b..91d8bc50 100644 --- a/contracts/protocol/libraries/configuration/ReserveConfiguration.sol +++ b/contracts/protocol/libraries/configuration/ReserveConfiguration.sol @@ -18,6 +18,7 @@ library ReserveConfiguration { uint256 constant FROZEN_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFF; // prettier-ignore uint256 constant BORROWING_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFF; // prettier-ignore uint256 constant STABLE_BORROWING_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFF; // prettier-ignore + uint256 constant PAUSED_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFF; // prettier-ignore uint256 constant RESERVE_FACTOR_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFF; // prettier-ignore uint256 constant BORROW_CAP_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000FFFFFFFFFFFFFFFFFFFF; // prettier-ignore uint256 constant SUPPLY_CAP_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFF000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore @@ -30,6 +31,8 @@ library ReserveConfiguration { uint256 constant IS_FROZEN_START_BIT_POSITION = 57; uint256 constant BORROWING_ENABLED_START_BIT_POSITION = 58; uint256 constant STABLE_BORROWING_ENABLED_START_BIT_POSITION = 59; + uint256 constant IS_PAUSED_START_BIT_POSITION = 60; + // bits 61 62 63 unused yet uint256 constant RESERVE_FACTOR_START_BIT_POSITION = 64; uint256 constant BORROW_CAP_START_BIT_POSITION = 80; uint256 constant SUPPLY_CAP_START_BIT_POSITION = 116; @@ -187,6 +190,26 @@ library ReserveConfiguration { return (self.data & ~FROZEN_MASK) != 0; } + /** + * @dev Sets the paused state of the reserve + * @param self The reserve configuration + * @param paused The paused state + **/ + function setPaused(DataTypes.ReserveConfigurationMap memory self, bool paused) internal pure { + self.data = + (self.data & PAUSED_MASK) | + (uint256(paused ? 1 : 0) << IS_PAUSED_START_BIT_POSITION); + } + + /** + * @dev Gets the paused state of the reserve + * @param self The reserve configuration + * @return The paused state + **/ + function getPaused(DataTypes.ReserveConfigurationMap storage self) internal view returns (bool) { + return (self.data & ~PAUSED_MASK) != 0; + } + /** * @dev Enables or disables borrowing on the reserve * @param self The reserve configuration @@ -336,6 +359,7 @@ library ReserveConfiguration { bool, bool, bool, + bool, bool ) { @@ -345,7 +369,8 @@ library ReserveConfiguration { (dataLocal & ~ACTIVE_MASK) != 0, (dataLocal & ~FROZEN_MASK) != 0, (dataLocal & ~BORROWING_MASK) != 0, - (dataLocal & ~STABLE_BORROWING_MASK) != 0 + (dataLocal & ~STABLE_BORROWING_MASK) != 0, + (dataLocal & ~PAUSED_MASK) != 0 ); } @@ -447,6 +472,7 @@ library ReserveConfiguration { bool, bool, bool, + bool, bool ) { @@ -454,7 +480,8 @@ library ReserveConfiguration { (self.data & ~ACTIVE_MASK) != 0, (self.data & ~FROZEN_MASK) != 0, (self.data & ~BORROWING_MASK) != 0, - (self.data & ~STABLE_BORROWING_MASK) != 0 + (self.data & ~STABLE_BORROWING_MASK) != 0, + (self.data & ~PAUSED_MASK) != 0 ); } diff --git a/contracts/protocol/libraries/helpers/Errors.sol b/contracts/protocol/libraries/helpers/Errors.sol index 34e3521f..9fa7e96e 100644 --- a/contracts/protocol/libraries/helpers/Errors.sol +++ b/contracts/protocol/libraries/helpers/Errors.sol @@ -106,6 +106,8 @@ library Errors { string public constant RC_INVALID_BORROW_CAP = '82'; string public constant VL_SUPPLY_CAP_EXCEEDED = '83'; string public constant RC_INVALID_SUPPLY_CAP = '84'; + string public constant LPC_CALLER_NOT_EMERGENCY_OR_POOL_ADMIN = '85'; + string public constant VL_RESERVE_PAUSED = '86'; enum CollateralManagerErrors { NO_ERROR, diff --git a/contracts/protocol/libraries/logic/ValidationLogic.sol b/contracts/protocol/libraries/logic/ValidationLogic.sol index 0c0b7028..177300b7 100644 --- a/contracts/protocol/libraries/logic/ValidationLogic.sol +++ b/contracts/protocol/libraries/logic/ValidationLogic.sol @@ -40,11 +40,16 @@ library ValidationLogic { * @param reserve The reserve object on which the user is depositing * @param amount The amount to be deposited */ +<<<<<<< HEAD function validateDeposit(DataTypes.ReserveData storage reserve, uint256 amount) internal view { DataTypes.ReserveConfigurationMap memory reserveConfiguration = reserve.configuration; (bool isActive, bool isFrozen, , ) = reserveConfiguration.getFlagsMemory(); (, , , uint256 reserveDecimals, ) = reserveConfiguration.getParamsMemory(); uint256 supplyCap = reserveConfiguration.getSupplyCapMemory(); +======= + function validateDeposit(DataTypes.ReserveData storage reserve, uint256 amount) external view { + (bool isActive, bool isFrozen, , , ) = reserve.configuration.getFlags(); +>>>>>>> 2e1af3c (feat: added bool isPaused in data reserve config) require(amount != 0, Errors.VL_INVALID_AMOUNT); require(isActive, Errors.VL_NO_ACTIVE_RESERVE); @@ -71,7 +76,7 @@ library ValidationLogic { require(amount != 0, Errors.VL_INVALID_AMOUNT); require(amount <= userBalance, Errors.VL_NOT_ENOUGH_AVAILABLE_USER_BALANCE); - (bool isActive, , , ) = reserve.configuration.getFlags(); + (bool isActive, , , , ) = reservesData[reserveAddress].configuration.getFlags(); require(isActive, Errors.VL_NO_ACTIVE_RESERVE); } @@ -89,6 +94,7 @@ library ValidationLogic { uint256 borrowCap; bool isActive; bool isFrozen; + bool isPaused; bool borrowingEnabled; bool stableRateBorrowingEnabled; } @@ -124,6 +130,7 @@ library ValidationLogic { ) internal view { ValidateBorrowLocalVars memory vars; +<<<<<<< HEAD DataTypes.ReserveConfigurationMap memory reserveConfiguration = reserve.configuration; (, , , vars.reserveDecimals, ) = reserveConfiguration.getParamsMemory(); @@ -133,8 +140,14 @@ library ValidationLogic { vars.borrowingEnabled, vars.stableRateBorrowingEnabled ) = reserveConfiguration.getFlagsMemory(); +======= + (vars.isActive, vars.isFrozen, vars.borrowingEnabled, vars.stableRateBorrowingEnabled, vars.isPaused) = reserve + .configuration + .getFlags(); +>>>>>>> 2e1af3c (feat: added bool isPaused in data reserve config) require(vars.isActive, Errors.VL_NO_ACTIVE_RESERVE); + require(!vars.isPaused, Errors.VL_RESERVE_PAUSED); require(!vars.isFrozen, Errors.VL_RESERVE_FROZEN); require(amount != 0, Errors.VL_INVALID_AMOUNT); @@ -273,9 +286,10 @@ library ValidationLogic { uint256 variableDebt, DataTypes.InterestRateMode currentRateMode ) external view { - (bool isActive, bool isFrozen, , bool stableRateEnabled) = reserve.configuration.getFlags(); + (bool isActive, bool isFrozen, , bool stableRateEnabled, bool isPaused) = reserve.configuration.getFlags(); require(isActive, Errors.VL_NO_ACTIVE_RESERVE); + require(!isPaused, Errors.VL_RESERVE_PAUSED); require(!isFrozen, Errors.VL_RESERVE_FROZEN); if (currentRateMode == DataTypes.InterestRateMode.STABLE) { @@ -317,9 +331,10 @@ library ValidationLogic { IERC20 variableDebtToken, address aTokenAddress ) external view { - (bool isActive, , , ) = reserve.configuration.getFlags(); + (bool isActive, , , , bool isPaused) = reserve.configuration.getFlags(); require(isActive, Errors.VL_NO_ACTIVE_RESERVE); + require(!isPaused, Errors.VL_RESERVE_PAUSED); //if the usage ratio is below 95%, no rebalances are needed uint256 totalDebt = diff --git a/contracts/protocol/libraries/types/DataTypes.sol b/contracts/protocol/libraries/types/DataTypes.sol index 5c620eaa..d6399a58 100644 --- a/contracts/protocol/libraries/types/DataTypes.sol +++ b/contracts/protocol/libraries/types/DataTypes.sol @@ -36,7 +36,8 @@ library DataTypes { //bit 57: reserve is frozen //bit 58: borrowing is enabled //bit 59: stable rate borrowing enabled - //bit 60-63: reserved + //bit 60: asset is paused + //bit 61-63: reserved //bit 64-79: reserve factor //bit 80-115 borrow cap, borrowCap == 0 => disabled //bit 116-152 supply cap, supplyCap == 0 => disabled