From 716d1ce68d14f5665d1388a63c3617bd8b0474bc Mon Sep 17 00:00:00 2001 From: Hadrien Charlanes Date: Thu, 1 Jul 2021 10:29:40 +0200 Subject: [PATCH] fix: protected against disable as collateral + withdraw/transfer --- .../protocol/lendingpool/LendingPool.sol | 5 +- .../libraries/logic/ValidationLogic.sol | 46 ++++++++++++------- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/contracts/protocol/lendingpool/LendingPool.sol b/contracts/protocol/lendingpool/LendingPool.sol index 57a60d8a..cb4bf47e 100644 --- a/contracts/protocol/lendingpool/LendingPool.sol +++ b/contracts/protocol/lendingpool/LendingPool.sol @@ -291,6 +291,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage } else { ValidationLogic.validateHFAndExposureCap( asset, + IERC20(reserveCache.aTokenAddress).balanceOf(msg.sender), msg.sender, _reserves, _usersConfig[msg.sender], @@ -632,6 +633,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage if (fromConfig.isBorrowingAny()) { ValidationLogic.validateHFAndExposureCap( asset, + 0, from, _reserves, _usersConfig[from], @@ -876,10 +878,11 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage reserveCache.nextLiquidityIndex ); - if (reserve.configuration.getLtv() > 0) { + if (userConfig.isUsingAsCollateral(reserve.id)) { if (userConfig.isBorrowingAny()) { ValidationLogic.validateHFAndExposureCap( asset, + 0, msg.sender, _reserves, userConfig, diff --git a/contracts/protocol/libraries/logic/ValidationLogic.sol b/contracts/protocol/libraries/logic/ValidationLogic.sol index 42fee42a..f653ad23 100644 --- a/contracts/protocol/libraries/logic/ValidationLogic.sol +++ b/contracts/protocol/libraries/logic/ValidationLogic.sol @@ -186,6 +186,7 @@ library ValidationLogic { vars.currentLtv, vars.currentLiquidationThreshold, vars.healthFactor, + ) = GenericLogic.calculateUserAccountData( userAddress, reservesData, @@ -507,6 +508,15 @@ library ValidationLogic { return (uint256(Errors.CollateralManagerErrors.NO_ERROR), Errors.LPCM_NO_ERRORS); } + struct validateHFAndExposureCapLocalVars { + uint256 healthFactor; + uint256 ltv; + uint256 uncappedLtv; + uint256 exposureCap; + uint256 reserveDecimals; + uint256 totalSupplyAtoken; + } + /** * @dev Validates the health factor of a user and the exposure cap for the asset being withdrawn * @param from The user from which the aTokens are being transferred @@ -518,6 +528,7 @@ library ValidationLogic { */ function validateHFAndExposureCap( address collateral, + uint256 collateralToBeWithdrawn, address from, mapping(address => DataTypes.ReserveData) storage reservesData, DataTypes.UserConfigurationMap storage userConfig, @@ -525,30 +536,31 @@ library ValidationLogic { uint256 reservesCount, address oracle ) external view { + validateHFAndExposureCapLocalVars memory vars; DataTypes.ReserveData memory reserve = reservesData[collateral]; - (, , uint256 ltv, uint256 liquidationThreshold, uint256 healthFactor, uint256 uncappedLtv) = - GenericLogic.calculateUserAccountData( - from, - reservesData, - userConfig, - reserves, - reservesCount, - oracle - ); - + (, , vars.ltv, , vars.healthFactor, vars.uncappedLtv) = GenericLogic.calculateUserAccountData( + from, + reservesData, + userConfig, + reserves, + reservesCount, + oracle + ); require( - healthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD, + vars.healthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD, Errors.VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD ); - uint256 exposureCap = reserve.configuration.getExposureCapMemory(); + vars.exposureCap = reserve.configuration.getExposureCapMemory(); - if (exposureCap != 0) { - if (ltv < uncappedLtv) { - uint256 totalSupplyAtoken = IERC20(reserve.aTokenAddress).totalSupply(); - (, , , uint256 reserveDecimals, ) = reserve.configuration.getParamsMemory(); - bool isAssetCapped = totalSupplyAtoken.div(10**reserveDecimals) >= exposureCap; + if (vars.exposureCap != 0) { + if (vars.ltv < vars.uncappedLtv) { + vars.totalSupplyAtoken = IERC20(reserve.aTokenAddress).totalSupply(); + (, , , vars.reserveDecimals, ) = reserve.configuration.getParamsMemory(); + bool isAssetCapped = + vars.totalSupplyAtoken.sub(collateralToBeWithdrawn).div(10**vars.reserveDecimals) >= + vars.exposureCap; require(isAssetCapped, Errors.VL_COLLATERAL_EXPOSURE_CAP_EXCEEDED); } }