From 9c7458242b286d648683114eb4ad6a9519490bc7 Mon Sep 17 00:00:00 2001 From: Hadrien Charlanes Date: Wed, 26 May 2021 20:11:48 +0200 Subject: [PATCH] feat: added drop reserve main capability --- contracts/interfaces/ILendingPool.sol | 2 + .../protocol/lendingpool/LendingPool.sol | 52 +++++++++++++++---- .../lendingpool/LendingPoolConfigurator.sol | 4 ++ .../protocol/libraries/helpers/Errors.sol | 3 ++ .../protocol/libraries/logic/ReserveLogic.sol | 17 ++++++ .../libraries/logic/ValidationLogic.sol | 2 +- test-suites/test-aave/__setup.spec.ts | 1 + 7 files changed, 70 insertions(+), 11 deletions(-) diff --git a/contracts/interfaces/ILendingPool.sol b/contracts/interfaces/ILendingPool.sol index c5801065..9449db3f 100644 --- a/contracts/interfaces/ILendingPool.sol +++ b/contracts/interfaces/ILendingPool.sol @@ -396,6 +396,8 @@ interface ILendingPool { address interestRateStrategyAddress ) external; + function dropReserve(address reserve) external; + function setReserveInterestRateStrategyAddress(address reserve, address rateStrategyAddress) external; diff --git a/contracts/protocol/lendingpool/LendingPool.sol b/contracts/protocol/lendingpool/LendingPool.sol index a675253d..5479e5a2 100644 --- a/contracts/protocol/lendingpool/LendingPool.sol +++ b/contracts/protocol/lendingpool/LendingPool.sol @@ -665,15 +665,29 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage } /** - * @dev Returns the list of the initialized reserves + * @dev Returns the list of the initialized reserves, does not contain dropped reserves **/ function getReservesList() external view override returns (address[] memory) { - address[] memory _activeReserves = new address[](_reservesCount); + uint256 reserveListCount = _reservesCount; + uint256 droppedReservesCount = 0; + address[] memory reserves = new address[](reserveListCount); - for (uint256 i = 0; i < _reservesCount; i++) { - _activeReserves[i] = _reservesList[i]; + for (uint256 i = 0; i < reserveListCount; i++) { + if (_reservesList[i] != address(0)) { + reserves[i - droppedReservesCount] = _reservesList[i]; + } else { + droppedReservesCount++; + } } - return _activeReserves; + + if (droppedReservesCount == 0) return reserves; + + address[] memory undroppedReserves = new address[](reserveListCount - droppedReservesCount); + for (uint256 i = 0; i < reserveListCount - droppedReservesCount; i++) { + undroppedReserves[i] = reserves[i]; + } + + return undroppedReserves; } /** @@ -783,6 +797,16 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage _addReserveToList(asset); } + /** + * @dev Drop a reserve + * - Only callable by the LendingPoolConfigurator contract + * @param asset The address of the underlying asset of the reserve + **/ + function dropReserve(address asset) external override onlyLendingPoolConfigurator { + _reserves[asset].dropReserve(); + _removeReserveFromList(asset); + } + /** * @dev Updates the address of the interest rate strategy contract * - Only callable by the LendingPoolConfigurator contract @@ -1067,7 +1091,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage return paybackAmount; } - function _addReserveToList(address asset) internal { + function _addReserveToList(address asset) internal returns (uint8) { uint256 reservesCount = _reservesCount; require(reservesCount < _maxNumberOfReserves, Errors.LP_NO_MORE_RESERVES_ALLOWED); @@ -1075,10 +1099,18 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage bool reserveAlreadyAdded = _reserves[asset].id != 0 || _reservesList[0] == asset; if (!reserveAlreadyAdded) { - _reserves[asset].id = uint8(reservesCount); - _reservesList[reservesCount] = asset; - - _reservesCount = reservesCount + 1; + for (uint8 i = 0; i <= reservesCount; i++) { + if (_reservesList[i] == address(0)) { + _reserves[asset].id = i; + _reservesList[i] = asset; + _reservesCount = reservesCount + 1; + return i; + } + } } } + + function _removeReserveFromList(address asset) internal { + _reservesList[_reserves[asset].id] = address(0); + } } diff --git a/contracts/protocol/lendingpool/LendingPoolConfigurator.sol b/contracts/protocol/lendingpool/LendingPoolConfigurator.sol index 80ca2410..cf5bbaec 100644 --- a/contracts/protocol/lendingpool/LendingPoolConfigurator.sol +++ b/contracts/protocol/lendingpool/LendingPoolConfigurator.sol @@ -161,6 +161,10 @@ contract LendingPoolConfigurator is VersionedInitializable, ILendingPoolConfigur ); } + function dropReserve(address asset) external onlyPoolAdmin { + pool.dropReserve(asset); + } + /** * @dev Updates the aToken implementation for the reserve **/ diff --git a/contracts/protocol/libraries/helpers/Errors.sol b/contracts/protocol/libraries/helpers/Errors.sol index 8a2e7653..1b984270 100644 --- a/contracts/protocol/libraries/helpers/Errors.sol +++ b/contracts/protocol/libraries/helpers/Errors.sol @@ -109,6 +109,9 @@ library Errors { string public constant LPC_CALLER_NOT_EMERGENCY_OR_POOL_ADMIN = '85'; string public constant VL_RESERVE_PAUSED = '86'; string public constant LPC_CALLER_NOT_RISK_OR_POOL_ADMIN = '87'; + string public constant RL_ATOKEN_SUPPLY_NOT_NULL = '88'; + string public constant RL_STABLE_DEBT_NOT_NULL = '89'; + string public constant RL_VARIABLE_DEBT_SUPPLY_NOT_NULL = '90'; enum CollateralManagerErrors { NO_ERROR, diff --git a/contracts/protocol/libraries/logic/ReserveLogic.sol b/contracts/protocol/libraries/logic/ReserveLogic.sol index 2b5b2cf4..183aa3a6 100644 --- a/contracts/protocol/libraries/logic/ReserveLogic.sol +++ b/contracts/protocol/libraries/logic/ReserveLogic.sol @@ -178,6 +178,23 @@ library ReserveLogic { reserve.interestRateStrategyAddress = interestRateStrategyAddress; } + /** + * @dev drop a reserve + * @param reserve The reserve object + **/ + function dropReserve(DataTypes.ReserveData storage reserve) external { + require(IERC20(reserve.aTokenAddress).totalSupply() == 0, Errors.RL_ATOKEN_SUPPLY_NOT_NULL); + require( + IERC20(reserve.stableDebtTokenAddress).totalSupply() == 0, + Errors.RL_STABLE_DEBT_NOT_NULL + ); + require( + IERC20(reserve.variableDebtTokenAddress).totalSupply() == 0, + Errors.RL_VARIABLE_DEBT_SUPPLY_NOT_NULL + ); + reserve.id = type(uint8).max; + } + struct UpdateInterestRatesLocalVars { address stableDebtTokenAddress; uint256 availableLiquidity; diff --git a/contracts/protocol/libraries/logic/ValidationLogic.sol b/contracts/protocol/libraries/logic/ValidationLogic.sol index ca22b7ff..d170f94b 100644 --- a/contracts/protocol/libraries/logic/ValidationLogic.sol +++ b/contracts/protocol/libraries/logic/ValidationLogic.sol @@ -119,7 +119,7 @@ library ValidationLogic { mapping(uint256 => address) storage reserves, uint256 reservesCount, address oracle - ) internal view { + ) external view { ValidateBorrowLocalVars memory vars; ( diff --git a/test-suites/test-aave/__setup.spec.ts b/test-suites/test-aave/__setup.spec.ts index f8ff2fbe..121607c7 100644 --- a/test-suites/test-aave/__setup.spec.ts +++ b/test-suites/test-aave/__setup.spec.ts @@ -267,6 +267,7 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { ); await configureReservesByHelper(reservesParams, allReservesAddresses, testHelpers, admin); + lendingPoolConfiguratorProxy.dropReserve(mockTokens.KNC.address); const collateralManager = await deployLendingPoolCollateralManager(); await waitForTx(