fix: protected against disable as collateral + withdraw/transfer

This commit is contained in:
Hadrien Charlanes 2021-07-01 10:29:40 +02:00
parent 9f110e1d19
commit 716d1ce68d
2 changed files with 33 additions and 18 deletions

View File

@ -291,6 +291,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
} else { } else {
ValidationLogic.validateHFAndExposureCap( ValidationLogic.validateHFAndExposureCap(
asset, asset,
IERC20(reserveCache.aTokenAddress).balanceOf(msg.sender),
msg.sender, msg.sender,
_reserves, _reserves,
_usersConfig[msg.sender], _usersConfig[msg.sender],
@ -632,6 +633,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
if (fromConfig.isBorrowingAny()) { if (fromConfig.isBorrowingAny()) {
ValidationLogic.validateHFAndExposureCap( ValidationLogic.validateHFAndExposureCap(
asset, asset,
0,
from, from,
_reserves, _reserves,
_usersConfig[from], _usersConfig[from],
@ -876,10 +878,11 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
reserveCache.nextLiquidityIndex reserveCache.nextLiquidityIndex
); );
if (reserve.configuration.getLtv() > 0) { if (userConfig.isUsingAsCollateral(reserve.id)) {
if (userConfig.isBorrowingAny()) { if (userConfig.isBorrowingAny()) {
ValidationLogic.validateHFAndExposureCap( ValidationLogic.validateHFAndExposureCap(
asset, asset,
0,
msg.sender, msg.sender,
_reserves, _reserves,
userConfig, userConfig,

View File

@ -186,6 +186,7 @@ library ValidationLogic {
vars.currentLtv, vars.currentLtv,
vars.currentLiquidationThreshold, vars.currentLiquidationThreshold,
vars.healthFactor, vars.healthFactor,
) = GenericLogic.calculateUserAccountData( ) = GenericLogic.calculateUserAccountData(
userAddress, userAddress,
reservesData, reservesData,
@ -507,6 +508,15 @@ library ValidationLogic {
return (uint256(Errors.CollateralManagerErrors.NO_ERROR), Errors.LPCM_NO_ERRORS); 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 * @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 * @param from The user from which the aTokens are being transferred
@ -518,6 +528,7 @@ library ValidationLogic {
*/ */
function validateHFAndExposureCap( function validateHFAndExposureCap(
address collateral, address collateral,
uint256 collateralToBeWithdrawn,
address from, address from,
mapping(address => DataTypes.ReserveData) storage reservesData, mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap storage userConfig, DataTypes.UserConfigurationMap storage userConfig,
@ -525,30 +536,31 @@ library ValidationLogic {
uint256 reservesCount, uint256 reservesCount,
address oracle address oracle
) external view { ) external view {
validateHFAndExposureCapLocalVars memory vars;
DataTypes.ReserveData memory reserve = reservesData[collateral]; DataTypes.ReserveData memory reserve = reservesData[collateral];
(, , uint256 ltv, uint256 liquidationThreshold, uint256 healthFactor, uint256 uncappedLtv) = (, , vars.ltv, , vars.healthFactor, vars.uncappedLtv) = GenericLogic.calculateUserAccountData(
GenericLogic.calculateUserAccountData( from,
from, reservesData,
reservesData, userConfig,
userConfig, reserves,
reserves, reservesCount,
reservesCount, oracle
oracle );
);
require( require(
healthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD, vars.healthFactor >= GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
Errors.VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD Errors.VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD
); );
uint256 exposureCap = reserve.configuration.getExposureCapMemory(); vars.exposureCap = reserve.configuration.getExposureCapMemory();
if (exposureCap != 0) { if (vars.exposureCap != 0) {
if (ltv < uncappedLtv) { if (vars.ltv < vars.uncappedLtv) {
uint256 totalSupplyAtoken = IERC20(reserve.aTokenAddress).totalSupply(); vars.totalSupplyAtoken = IERC20(reserve.aTokenAddress).totalSupply();
(, , , uint256 reserveDecimals, ) = reserve.configuration.getParamsMemory(); (, , , vars.reserveDecimals, ) = reserve.configuration.getParamsMemory();
bool isAssetCapped = totalSupplyAtoken.div(10**reserveDecimals) >= exposureCap; bool isAssetCapped =
vars.totalSupplyAtoken.sub(collateralToBeWithdrawn).div(10**vars.reserveDecimals) >=
vars.exposureCap;
require(isAssetCapped, Errors.VL_COLLATERAL_EXPOSURE_CAP_EXCEEDED); require(isAssetCapped, Errors.VL_COLLATERAL_EXPOSURE_CAP_EXCEEDED);
} }
} }