LCOV - code coverage report
Current view: top level - protocol/libraries/logic - ValidationLogic.sol (source / functions) Coverage Total Hit
Test: lcov.info.p Lines: 100.0 % 110 110
Test Date: 2024-09-24 09:34:24 Functions: 100.0 % 15 15
Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : // SPDX-License-Identifier: BUSL-1.1
       2                 :             : pragma solidity ^0.8.10;
       3                 :             : 
       4                 :             : import {IERC20} from '../../../dependencies/openzeppelin/contracts/IERC20.sol';
       5                 :             : import {Address} from '../../../dependencies/openzeppelin/contracts/Address.sol';
       6                 :             : import {GPv2SafeERC20} from '../../../dependencies/gnosis/contracts/GPv2SafeERC20.sol';
       7                 :             : import {IReserveInterestRateStrategy} from '../../../interfaces/IReserveInterestRateStrategy.sol';
       8                 :             : import {IScaledBalanceToken} from '../../../interfaces/IScaledBalanceToken.sol';
       9                 :             : import {IPriceOracleGetter} from '../../../interfaces/IPriceOracleGetter.sol';
      10                 :             : import {IAToken} from '../../../interfaces/IAToken.sol';
      11                 :             : import {IPriceOracleSentinel} from '../../../interfaces/IPriceOracleSentinel.sol';
      12                 :             : import {IPoolAddressesProvider} from '../../../interfaces/IPoolAddressesProvider.sol';
      13                 :             : import {IAccessControl} from '../../../dependencies/openzeppelin/contracts/IAccessControl.sol';
      14                 :             : import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol';
      15                 :             : import {UserConfiguration} from '../configuration/UserConfiguration.sol';
      16                 :             : import {EModeConfiguration} from '../configuration/EModeConfiguration.sol';
      17                 :             : import {Errors} from '../helpers/Errors.sol';
      18                 :             : import {WadRayMath} from '../math/WadRayMath.sol';
      19                 :             : import {PercentageMath} from '../math/PercentageMath.sol';
      20                 :             : import {DataTypes} from '../types/DataTypes.sol';
      21                 :             : import {ReserveLogic} from './ReserveLogic.sol';
      22                 :             : import {GenericLogic} from './GenericLogic.sol';
      23                 :             : import {SafeCast} from '../../../dependencies/openzeppelin/contracts/SafeCast.sol';
      24                 :             : import {IncentivizedERC20} from '../../tokenization/base/IncentivizedERC20.sol';
      25                 :             : 
      26                 :             : /**
      27                 :             :  * @title ReserveLogic library
      28                 :             :  * @author Aave
      29                 :             :  * @notice Implements functions to validate the different actions of the protocol
      30                 :             :  */
      31                 :             : library ValidationLogic {
      32                 :             :   using ReserveLogic for DataTypes.ReserveData;
      33                 :             :   using WadRayMath for uint256;
      34                 :             :   using PercentageMath for uint256;
      35                 :             :   using SafeCast for uint256;
      36                 :             :   using GPv2SafeERC20 for IERC20;
      37                 :             :   using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
      38                 :             :   using UserConfiguration for DataTypes.UserConfigurationMap;
      39                 :             :   using Address for address;
      40                 :             : 
      41                 :             :   // Factor to apply to "only-variable-debt" liquidity rate to get threshold for rebalancing, expressed in bps
      42                 :             :   // A value of 0.9e4 results in 90%
      43                 :             :   uint256 public constant REBALANCE_UP_LIQUIDITY_RATE_THRESHOLD = 0.9e4;
      44                 :             : 
      45                 :             :   // Minimum health factor allowed under any circumstance
      46                 :             :   // A value of 0.95e18 results in 0.95
      47                 :             :   uint256 public constant MINIMUM_HEALTH_FACTOR_LIQUIDATION_THRESHOLD = 0.95e18;
      48                 :             : 
      49                 :             :   /**
      50                 :             :    * @dev Minimum health factor to consider a user position healthy
      51                 :             :    * A value of 1e18 results in 1
      52                 :             :    */
      53                 :             :   uint256 public constant HEALTH_FACTOR_LIQUIDATION_THRESHOLD = 1e18;
      54                 :             : 
      55                 :             :   /**
      56                 :             :    * @dev Role identifier for the role allowed to supply isolated reserves as collateral
      57                 :             :    */
      58                 :             :   bytes32 public constant ISOLATED_COLLATERAL_SUPPLIER_ROLE =
      59                 :             :     keccak256('ISOLATED_COLLATERAL_SUPPLIER');
      60                 :             : 
      61                 :             :   /**
      62                 :             :    * @notice Validates a supply action.
      63                 :             :    * @param reserveCache The cached data of the reserve
      64                 :             :    * @param amount The amount to be supplied
      65                 :             :    */
      66                 :             :   function validateSupply(
      67                 :             :     DataTypes.ReserveCache memory reserveCache,
      68                 :             :     DataTypes.ReserveData storage reserve,
      69                 :             :     uint256 amount,
      70                 :             :     address onBehalfOf
      71                 :             :   ) internal view {
      72                 :       44531 :     require(amount != 0, Errors.INVALID_AMOUNT);
      73                 :             : 
      74                 :       44530 :     (bool isActive, bool isFrozen, , bool isPaused) = reserveCache.reserveConfiguration.getFlags();
      75                 :       44530 :     require(isActive, Errors.RESERVE_INACTIVE);
      76                 :       44529 :     require(!isPaused, Errors.RESERVE_PAUSED);
      77                 :       44528 :     require(!isFrozen, Errors.RESERVE_FROZEN);
      78                 :       44527 :     require(onBehalfOf != reserveCache.aTokenAddress, Errors.SUPPLY_TO_ATOKEN);
      79                 :             : 
      80                 :       44526 :     uint256 supplyCap = reserveCache.reserveConfiguration.getSupplyCap();
      81                 :       44526 :     require(
      82                 :             :       supplyCap == 0 ||
      83                 :             :         ((IAToken(reserveCache.aTokenAddress).scaledTotalSupply() +
      84                 :             :           uint256(reserve.accruedToTreasury)).rayMul(reserveCache.nextLiquidityIndex) + amount) <=
      85                 :             :         supplyCap * (10 ** reserveCache.reserveConfiguration.getDecimals()),
      86                 :             :       Errors.SUPPLY_CAP_EXCEEDED
      87                 :             :     );
      88                 :             :   }
      89                 :             : 
      90                 :             :   /**
      91                 :             :    * @notice Validates a withdraw action.
      92                 :             :    * @param reserveCache The cached data of the reserve
      93                 :             :    * @param amount The amount to be withdrawn
      94                 :             :    * @param userBalance The balance of the user
      95                 :             :    */
      96                 :             :   function validateWithdraw(
      97                 :             :     DataTypes.ReserveCache memory reserveCache,
      98                 :             :     uint256 amount,
      99                 :             :     uint256 userBalance
     100                 :             :   ) internal pure {
     101                 :        2044 :     require(amount != 0, Errors.INVALID_AMOUNT);
     102                 :        2043 :     require(amount <= userBalance, Errors.NOT_ENOUGH_AVAILABLE_USER_BALANCE);
     103                 :             : 
     104                 :        2042 :     (bool isActive, , , bool isPaused) = reserveCache.reserveConfiguration.getFlags();
     105                 :        2042 :     require(isActive, Errors.RESERVE_INACTIVE);
     106                 :        2041 :     require(!isPaused, Errors.RESERVE_PAUSED);
     107                 :             :   }
     108                 :             : 
     109                 :             :   struct ValidateBorrowLocalVars {
     110                 :             :     uint256 currentLtv;
     111                 :             :     uint256 collateralNeededInBaseCurrency;
     112                 :             :     uint256 userCollateralInBaseCurrency;
     113                 :             :     uint256 userDebtInBaseCurrency;
     114                 :             :     uint256 availableLiquidity;
     115                 :             :     uint256 healthFactor;
     116                 :             :     uint256 totalDebt;
     117                 :             :     uint256 totalSupplyVariableDebt;
     118                 :             :     uint256 reserveDecimals;
     119                 :             :     uint256 borrowCap;
     120                 :             :     uint256 amountInBaseCurrency;
     121                 :             :     uint256 assetUnit;
     122                 :             :     address siloedBorrowingAddress;
     123                 :             :     bool isActive;
     124                 :             :     bool isFrozen;
     125                 :             :     bool isPaused;
     126                 :             :     bool borrowingEnabled;
     127                 :             :     bool siloedBorrowingEnabled;
     128                 :             :   }
     129                 :             : 
     130                 :             :   /**
     131                 :             :    * @notice Validates a borrow action.
     132                 :             :    * @param reservesData The state of all the reserves
     133                 :             :    * @param reservesList The addresses of all the active reserves
     134                 :             :    * @param eModeCategories The configuration of all the efficiency mode categories
     135                 :             :    * @param params Additional params needed for the validation
     136                 :             :    */
     137                 :             :   function validateBorrow(
     138                 :             :     mapping(address => DataTypes.ReserveData) storage reservesData,
     139                 :             :     mapping(uint256 => address) storage reservesList,
     140                 :             :     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
     141                 :             :     DataTypes.ValidateBorrowParams memory params
     142                 :             :   ) internal view {
     143                 :       16110 :     require(params.amount != 0, Errors.INVALID_AMOUNT);
     144                 :             : 
     145                 :       16109 :     ValidateBorrowLocalVars memory vars;
     146                 :             : 
     147                 :       16109 :     (vars.isActive, vars.isFrozen, vars.borrowingEnabled, vars.isPaused) = params
     148                 :             :       .reserveCache
     149                 :             :       .reserveConfiguration
     150                 :             :       .getFlags();
     151                 :             : 
     152                 :       16109 :     require(vars.isActive, Errors.RESERVE_INACTIVE);
     153                 :       16108 :     require(!vars.isPaused, Errors.RESERVE_PAUSED);
     154                 :       16107 :     require(!vars.isFrozen, Errors.RESERVE_FROZEN);
     155                 :       16106 :     require(vars.borrowingEnabled, Errors.BORROWING_NOT_ENABLED);
     156                 :       15106 :     require(
     157                 :             :       !params.reserveCache.reserveConfiguration.getIsVirtualAccActive() ||
     158                 :             :         IERC20(params.reserveCache.aTokenAddress).totalSupply() >= params.amount,
     159                 :             :       Errors.INVALID_AMOUNT
     160                 :             :     );
     161                 :             : 
     162                 :       15105 :     require(
     163                 :             :       params.priceOracleSentinel == address(0) ||
     164                 :             :         IPriceOracleSentinel(params.priceOracleSentinel).isBorrowAllowed(),
     165                 :             :       Errors.PRICE_ORACLE_SENTINEL_CHECK_FAILED
     166                 :             :     );
     167                 :             : 
     168                 :             :     //validate interest rate mode
     169                 :       15104 :     require(
     170                 :             :       params.interestRateMode == DataTypes.InterestRateMode.VARIABLE,
     171                 :             :       Errors.INVALID_INTEREST_RATE_MODE_SELECTED
     172                 :             :     );
     173                 :             : 
     174                 :       15102 :     vars.reserveDecimals = params.reserveCache.reserveConfiguration.getDecimals();
     175                 :       15102 :     vars.borrowCap = params.reserveCache.reserveConfiguration.getBorrowCap();
     176                 :             :     unchecked {
     177                 :       15102 :       vars.assetUnit = 10 ** vars.reserveDecimals;
     178                 :             :     }
     179                 :             : 
     180                 :       15102 :     if (vars.borrowCap != 0) {
     181                 :           7 :       vars.totalSupplyVariableDebt = params.reserveCache.currScaledVariableDebt.rayMul(
     182                 :             :         params.reserveCache.nextVariableBorrowIndex
     183                 :             :       );
     184                 :             : 
     185                 :           7 :       vars.totalDebt = vars.totalSupplyVariableDebt + params.amount;
     186                 :             : 
     187                 :             :       unchecked {
     188                 :           7 :         require(vars.totalDebt <= vars.borrowCap * vars.assetUnit, Errors.BORROW_CAP_EXCEEDED);
     189                 :             :       }
     190                 :             :     }
     191                 :             : 
     192                 :       15099 :     if (params.isolationModeActive) {
     193                 :             :       // check that the asset being borrowed is borrowable in isolation mode AND
     194                 :             :       // the total exposure is no bigger than the collateral debt ceiling
     195                 :          11 :       require(
     196                 :             :         params.reserveCache.reserveConfiguration.getBorrowableInIsolation(),
     197                 :             :         Errors.ASSET_NOT_BORROWABLE_IN_ISOLATION
     198                 :             :       );
     199                 :             : 
     200                 :          10 :       require(
     201                 :             :         reservesData[params.isolationModeCollateralAddress].isolationModeTotalDebt +
     202                 :             :           (params.amount /
     203                 :             :             10 ** (vars.reserveDecimals - ReserveConfiguration.DEBT_CEILING_DECIMALS))
     204                 :             :             .toUint128() <=
     205                 :             :           params.isolationModeDebtCeiling,
     206                 :             :         Errors.DEBT_CEILING_EXCEEDED
     207                 :             :       );
     208                 :             :     }
     209                 :             : 
     210                 :       15096 :     if (params.userEModeCategory != 0) {
     211                 :        4006 :       require(
     212                 :             :         EModeConfiguration.isReserveEnabledOnBitmap(
     213                 :             :           eModeCategories[params.userEModeCategory].borrowableBitmap,
     214                 :             :           reservesData[params.asset].id
     215                 :             :         ),
     216                 :             :         Errors.NOT_BORROWABLE_IN_EMODE
     217                 :             :       );
     218                 :             :     }
     219                 :             : 
     220                 :       15095 :     (
     221                 :             :       vars.userCollateralInBaseCurrency,
     222                 :             :       vars.userDebtInBaseCurrency,
     223                 :             :       vars.currentLtv,
     224                 :             :       ,
     225                 :             :       vars.healthFactor,
     226                 :             : 
     227                 :             :     ) = GenericLogic.calculateUserAccountData(
     228                 :             :       reservesData,
     229                 :             :       reservesList,
     230                 :             :       eModeCategories,
     231                 :             :       DataTypes.CalculateUserAccountDataParams({
     232                 :             :         userConfig: params.userConfig,
     233                 :             :         reservesCount: params.reservesCount,
     234                 :             :         user: params.userAddress,
     235                 :             :         oracle: params.oracle,
     236                 :             :         userEModeCategory: params.userEModeCategory
     237                 :             :       })
     238                 :             :     );
     239                 :             : 
     240                 :       15095 :     require(vars.userCollateralInBaseCurrency != 0, Errors.COLLATERAL_BALANCE_IS_ZERO);
     241                 :       15094 :     require(vars.currentLtv != 0, Errors.LTV_VALIDATION_FAILED);
     242                 :             : 
     243                 :       15094 :     require(
     244                 :             :       vars.healthFactor > HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
     245                 :             :       Errors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD
     246                 :             :     );
     247                 :             : 
     248                 :       15093 :     vars.amountInBaseCurrency =
     249                 :             :       IPriceOracleGetter(params.oracle).getAssetPrice(params.asset) *
     250                 :             :       params.amount;
     251                 :             :     unchecked {
     252                 :       15093 :       vars.amountInBaseCurrency /= vars.assetUnit;
     253                 :             :     }
     254                 :             : 
     255                 :             :     //add the current already borrowed amount to the amount requested to calculate the total collateral needed.
     256                 :       15093 :     vars.collateralNeededInBaseCurrency = (vars.userDebtInBaseCurrency + vars.amountInBaseCurrency)
     257                 :             :       .percentDiv(vars.currentLtv); //LTV is calculated in percentage
     258                 :             : 
     259                 :       15093 :     require(
     260                 :             :       vars.collateralNeededInBaseCurrency <= vars.userCollateralInBaseCurrency,
     261                 :             :       Errors.COLLATERAL_CANNOT_COVER_NEW_BORROW
     262                 :             :     );
     263                 :             : 
     264                 :       15092 :     if (params.userConfig.isBorrowingAny()) {
     265                 :           7 :       (vars.siloedBorrowingEnabled, vars.siloedBorrowingAddress) = params
     266                 :             :         .userConfig
     267                 :             :         .getSiloedBorrowingState(reservesData, reservesList);
     268                 :             : 
     269                 :           7 :       if (vars.siloedBorrowingEnabled) {
     270                 :           1 :         require(vars.siloedBorrowingAddress == params.asset, Errors.SILOED_BORROWING_VIOLATION);
     271                 :             :       } else {
     272                 :           6 :         require(
     273                 :             :           !params.reserveCache.reserveConfiguration.getSiloedBorrowing(),
     274                 :             :           Errors.SILOED_BORROWING_VIOLATION
     275                 :             :         );
     276                 :             :       }
     277                 :             :     }
     278                 :             :   }
     279                 :             : 
     280                 :             :   /**
     281                 :             :    * @notice Validates a repay action.
     282                 :             :    * @param reserveCache The cached data of the reserve
     283                 :             :    * @param amountSent The amount sent for the repayment. Can be an actual value or uint(-1)
     284                 :             :    * @param onBehalfOf The address of the user msg.sender is repaying for
     285                 :             :    * @param debt The borrow balance of the user
     286                 :             :    */
     287                 :             :   function validateRepay(
     288                 :             :     DataTypes.ReserveCache memory reserveCache,
     289                 :             :     uint256 amountSent,
     290                 :             :     DataTypes.InterestRateMode interestRateMode,
     291                 :             :     address onBehalfOf,
     292                 :             :     uint256 debt
     293                 :             :   ) internal view {
     294                 :        5030 :     require(amountSent != 0, Errors.INVALID_AMOUNT);
     295                 :        5029 :     require(
     296                 :             :       interestRateMode == DataTypes.InterestRateMode.VARIABLE,
     297                 :             :       Errors.INVALID_INTEREST_RATE_MODE_SELECTED
     298                 :             :     );
     299                 :        5028 :     require(
     300                 :             :       amountSent != type(uint256).max || msg.sender == onBehalfOf,
     301                 :             :       Errors.NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF
     302                 :             :     );
     303                 :             : 
     304                 :        5027 :     (bool isActive, , , bool isPaused) = reserveCache.reserveConfiguration.getFlags();
     305                 :        5027 :     require(isActive, Errors.RESERVE_INACTIVE);
     306                 :        5026 :     require(!isPaused, Errors.RESERVE_PAUSED);
     307                 :             : 
     308                 :        5025 :     require(debt != 0, Errors.NO_DEBT_OF_SELECTED_TYPE);
     309                 :             :   }
     310                 :             : 
     311                 :             :   /**
     312                 :             :    * @notice Validates the action of setting an asset as collateral.
     313                 :             :    * @param reserveCache The cached data of the reserve
     314                 :             :    * @param userBalance The balance of the user
     315                 :             :    */
     316                 :             :   function validateSetUseReserveAsCollateral(
     317                 :             :     DataTypes.ReserveCache memory reserveCache,
     318                 :             :     uint256 userBalance
     319                 :             :   ) internal pure {
     320                 :          43 :     require(userBalance != 0, Errors.UNDERLYING_BALANCE_ZERO);
     321                 :             : 
     322                 :          41 :     (bool isActive, , , bool isPaused) = reserveCache.reserveConfiguration.getFlags();
     323                 :          41 :     require(isActive, Errors.RESERVE_INACTIVE);
     324                 :          39 :     require(!isPaused, Errors.RESERVE_PAUSED);
     325                 :             :   }
     326                 :             : 
     327                 :             :   /**
     328                 :             :    * @notice Validates a flashloan action.
     329                 :             :    * @param reservesData The state of all the reserves
     330                 :             :    * @param assets The assets being flash-borrowed
     331                 :             :    * @param amounts The amounts for each asset being borrowed
     332                 :             :    */
     333                 :             :   function validateFlashloan(
     334                 :             :     mapping(address => DataTypes.ReserveData) storage reservesData,
     335                 :             :     address[] memory assets,
     336                 :             :     uint256[] memory amounts
     337                 :             :   ) internal view {
     338                 :        1011 :     require(assets.length == amounts.length, Errors.INCONSISTENT_FLASHLOAN_PARAMS);
     339                 :        1011 :     for (uint256 i = 0; i < assets.length; i++) {
     340                 :        1012 :       for (uint256 j = i + 1; j < assets.length; j++) {
     341                 :        1001 :         require(assets[i] != assets[j], Errors.INCONSISTENT_FLASHLOAN_PARAMS);
     342                 :             :       }
     343                 :          12 :       validateFlashloanSimple(reservesData[assets[i]], amounts[i]);
     344                 :             :     }
     345                 :             :   }
     346                 :             : 
     347                 :             :   /**
     348                 :             :    * @notice Validates a flashloan action.
     349                 :             :    * @param reserve The state of the reserve
     350                 :             :    */
     351                 :             :   function validateFlashloanSimple(
     352                 :             :     DataTypes.ReserveData storage reserve,
     353                 :             :     uint256 amount
     354                 :             :   ) internal view {
     355                 :          23 :     DataTypes.ReserveConfigurationMap memory configuration = reserve.configuration;
     356                 :          23 :     require(!configuration.getPaused(), Errors.RESERVE_PAUSED);
     357                 :          22 :     require(configuration.getActive(), Errors.RESERVE_INACTIVE);
     358                 :          21 :     require(configuration.getFlashLoanEnabled(), Errors.FLASHLOAN_DISABLED);
     359                 :          20 :     require(
     360                 :             :       !configuration.getIsVirtualAccActive() ||
     361                 :             :         IERC20(reserve.aTokenAddress).totalSupply() >= amount,
     362                 :             :       Errors.INVALID_AMOUNT
     363                 :             :     );
     364                 :             :   }
     365                 :             : 
     366                 :             :   struct ValidateLiquidationCallLocalVars {
     367                 :             :     bool collateralReserveActive;
     368                 :             :     bool collateralReservePaused;
     369                 :             :     bool principalReserveActive;
     370                 :             :     bool principalReservePaused;
     371                 :             :     bool isCollateralEnabled;
     372                 :             :   }
     373                 :             : 
     374                 :             :   /**
     375                 :             :    * @notice Validates the liquidation action.
     376                 :             :    * @param userConfig The user configuration mapping
     377                 :             :    * @param collateralReserve The reserve data of the collateral
     378                 :             :    * @param debtReserve The reserve data of the debt
     379                 :             :    * @param params Additional parameters needed for the validation
     380                 :             :    */
     381                 :             :   function validateLiquidationCall(
     382                 :             :     DataTypes.UserConfigurationMap storage userConfig,
     383                 :             :     DataTypes.ReserveData storage collateralReserve,
     384                 :             :     DataTypes.ReserveData storage debtReserve,
     385                 :             :     DataTypes.ValidateLiquidationCallParams memory params
     386                 :             :   ) internal view {
     387                 :       14501 :     ValidateLiquidationCallLocalVars memory vars;
     388                 :             : 
     389                 :       14501 :     (vars.collateralReserveActive, , , vars.collateralReservePaused) = collateralReserve
     390                 :             :       .configuration
     391                 :             :       .getFlags();
     392                 :             : 
     393                 :       14501 :     (vars.principalReserveActive, , , vars.principalReservePaused) = params
     394                 :             :       .debtReserveCache
     395                 :             :       .reserveConfiguration
     396                 :             :       .getFlags();
     397                 :             : 
     398                 :       14501 :     require(vars.collateralReserveActive && vars.principalReserveActive, Errors.RESERVE_INACTIVE);
     399                 :       14500 :     require(!vars.collateralReservePaused && !vars.principalReservePaused, Errors.RESERVE_PAUSED);
     400                 :             : 
     401                 :       14499 :     require(
     402                 :             :       params.priceOracleSentinel == address(0) ||
     403                 :             :         params.healthFactor < MINIMUM_HEALTH_FACTOR_LIQUIDATION_THRESHOLD ||
     404                 :             :         IPriceOracleSentinel(params.priceOracleSentinel).isLiquidationAllowed(),
     405                 :             :       Errors.PRICE_ORACLE_SENTINEL_CHECK_FAILED
     406                 :             :     );
     407                 :             : 
     408                 :       14498 :     require(
     409                 :             :       collateralReserve.liquidationGracePeriodUntil < uint40(block.timestamp) &&
     410                 :             :         debtReserve.liquidationGracePeriodUntil < uint40(block.timestamp),
     411                 :             :       Errors.LIQUIDATION_GRACE_SENTINEL_CHECK_FAILED
     412                 :             :     );
     413                 :             : 
     414                 :        8014 :     require(
     415                 :             :       params.healthFactor < HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
     416                 :             :       Errors.HEALTH_FACTOR_NOT_BELOW_THRESHOLD
     417                 :             :     );
     418                 :             : 
     419                 :        8013 :     vars.isCollateralEnabled =
     420                 :             :       collateralReserve.configuration.getLiquidationThreshold() != 0 &&
     421                 :             :       userConfig.isUsingAsCollateral(collateralReserve.id);
     422                 :             : 
     423                 :             :     //if collateral isn't enabled as collateral by user, it cannot be liquidated
     424                 :        8013 :     require(vars.isCollateralEnabled, Errors.COLLATERAL_CANNOT_BE_LIQUIDATED);
     425                 :        8012 :     require(params.totalDebt != 0, Errors.SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER);
     426                 :             :   }
     427                 :             : 
     428                 :             :   /**
     429                 :             :    * @notice Validates the health factor of a user.
     430                 :             :    * @param reservesData The state of all the reserves
     431                 :             :    * @param reservesList The addresses of all the active reserves
     432                 :             :    * @param eModeCategories The configuration of all the efficiency mode categories
     433                 :             :    * @param userConfig The state of the user for the specific reserve
     434                 :             :    * @param user The user to validate health factor of
     435                 :             :    * @param userEModeCategory The users active efficiency mode category
     436                 :             :    * @param reservesCount The number of available reserves
     437                 :             :    * @param oracle The price oracle
     438                 :             :    */
     439                 :             :   function validateHealthFactor(
     440                 :             :     mapping(address => DataTypes.ReserveData) storage reservesData,
     441                 :             :     mapping(uint256 => address) storage reservesList,
     442                 :             :     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
     443                 :             :     DataTypes.UserConfigurationMap memory userConfig,
     444                 :             :     address user,
     445                 :             :     uint8 userEModeCategory,
     446                 :             :     uint256 reservesCount,
     447                 :             :     address oracle
     448                 :             :   ) internal view returns (uint256, bool) {
     449                 :        8637 :     (, , , , uint256 healthFactor, bool hasZeroLtvCollateral) = GenericLogic
     450                 :             :       .calculateUserAccountData(
     451                 :             :         reservesData,
     452                 :             :         reservesList,
     453                 :             :         eModeCategories,
     454                 :             :         DataTypes.CalculateUserAccountDataParams({
     455                 :             :           userConfig: userConfig,
     456                 :             :           reservesCount: reservesCount,
     457                 :             :           user: user,
     458                 :             :           oracle: oracle,
     459                 :             :           userEModeCategory: userEModeCategory
     460                 :             :         })
     461                 :             :       );
     462                 :             : 
     463                 :        8637 :     require(
     464                 :             :       healthFactor >= HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
     465                 :             :       Errors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD
     466                 :             :     );
     467                 :             : 
     468                 :        7631 :     return (healthFactor, hasZeroLtvCollateral);
     469                 :             :   }
     470                 :             : 
     471                 :             :   /**
     472                 :             :    * @notice Validates the health factor of a user and the ltv of the asset being withdrawn.
     473                 :             :    * @param reservesData The state of all the reserves
     474                 :             :    * @param reservesList The addresses of all the active reserves
     475                 :             :    * @param eModeCategories The configuration of all the efficiency mode categories
     476                 :             :    * @param userConfig The state of the user for the specific reserve
     477                 :             :    * @param asset The asset for which the ltv will be validated
     478                 :             :    * @param from The user from which the aTokens are being transferred
     479                 :             :    * @param reservesCount The number of available reserves
     480                 :             :    * @param oracle The price oracle
     481                 :             :    * @param userEModeCategory The users active efficiency mode category
     482                 :             :    */
     483                 :             :   function validateHFAndLtv(
     484                 :             :     mapping(address => DataTypes.ReserveData) storage reservesData,
     485                 :             :     mapping(uint256 => address) storage reservesList,
     486                 :             :     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
     487                 :             :     DataTypes.UserConfigurationMap memory userConfig,
     488                 :             :     address asset,
     489                 :             :     address from,
     490                 :             :     uint256 reservesCount,
     491                 :             :     address oracle,
     492                 :             :     uint8 userEModeCategory
     493                 :             :   ) internal view {
     494                 :          23 :     DataTypes.ReserveData memory reserve = reservesData[asset];
     495                 :             : 
     496                 :          23 :     (, bool hasZeroLtvCollateral) = validateHealthFactor(
     497                 :             :       reservesData,
     498                 :             :       reservesList,
     499                 :             :       eModeCategories,
     500                 :             :       userConfig,
     501                 :             :       from,
     502                 :             :       userEModeCategory,
     503                 :             :       reservesCount,
     504                 :             :       oracle
     505                 :             :     );
     506                 :             : 
     507                 :          19 :     require(
     508                 :             :       !hasZeroLtvCollateral || reserve.configuration.getLtv() == 0,
     509                 :             :       Errors.LTV_VALIDATION_FAILED
     510                 :             :     );
     511                 :             :   }
     512                 :             : 
     513                 :             :   /**
     514                 :             :    * @notice Validates a transfer action.
     515                 :             :    * @param reserve The reserve object
     516                 :             :    */
     517                 :             :   function validateTransfer(DataTypes.ReserveData storage reserve) internal view {
     518                 :       17042 :     require(!reserve.configuration.getPaused(), Errors.RESERVE_PAUSED);
     519                 :             :   }
     520                 :             : 
     521                 :             :   /**
     522                 :             :    * @notice Validates a drop reserve action.
     523                 :             :    * @param reservesList The addresses of all the active reserves
     524                 :             :    * @param reserve The reserve object
     525                 :             :    * @param asset The address of the reserve's underlying asset
     526                 :             :    */
     527                 :             :   function validateDropReserve(
     528                 :             :     mapping(uint256 => address) storage reservesList,
     529                 :             :     DataTypes.ReserveData storage reserve,
     530                 :             :     address asset
     531                 :             :   ) internal view {
     532                 :           9 :     require(asset != address(0), Errors.ZERO_ADDRESS_NOT_VALID);
     533                 :           8 :     require(reserve.id != 0 || reservesList[0] == asset, Errors.ASSET_NOT_LISTED);
     534                 :           7 :     require(
     535                 :             :       IERC20(reserve.variableDebtTokenAddress).totalSupply() == 0,
     536                 :             :       Errors.VARIABLE_DEBT_SUPPLY_NOT_ZERO
     537                 :             :     );
     538                 :           6 :     require(
     539                 :             :       IERC20(reserve.aTokenAddress).totalSupply() == 0 && reserve.accruedToTreasury == 0,
     540                 :             :       Errors.UNDERLYING_CLAIMABLE_RIGHTS_NOT_ZERO
     541                 :             :     );
     542                 :             :   }
     543                 :             : 
     544                 :             :   /**
     545                 :             :    * @notice Validates the action of setting efficiency mode.
     546                 :             :    * @param eModeCategories a mapping storing configurations for all efficiency mode categories
     547                 :             :    * @param userConfig the user configuration
     548                 :             :    * @param reservesCount The total number of valid reserves
     549                 :             :    * @param categoryId The id of the category
     550                 :             :    */
     551                 :             :   function validateSetUserEMode(
     552                 :             :     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
     553                 :             :     DataTypes.UserConfigurationMap memory userConfig,
     554                 :             :     uint256 reservesCount,
     555                 :             :     uint8 categoryId
     556                 :             :   ) internal view {
     557                 :        9617 :     DataTypes.EModeCategory storage eModeCategory = eModeCategories[categoryId];
     558                 :             :     // category is invalid if the liq threshold is not set
     559                 :        9617 :     require(
     560                 :             :       categoryId == 0 || eModeCategory.liquidationThreshold != 0,
     561                 :             :       Errors.INCONSISTENT_EMODE_CATEGORY
     562                 :             :     );
     563                 :             : 
     564                 :             :     // eMode can always be enabled if the user hasn't supplied anything
     565                 :        9616 :     if (userConfig.isEmpty()) {
     566                 :        6611 :       return;
     567                 :             :     }
     568                 :             : 
     569                 :             :     // if user is trying to set another category than default we require that
     570                 :             :     // either the user is not borrowing, or it's borrowing assets of categoryId
     571                 :        3005 :     if (categoryId != 0) {
     572                 :             :       unchecked {
     573                 :        3002 :         for (uint256 i = 0; i < reservesCount; i++) {
     574                 :        8006 :           if (userConfig.isBorrowing(i)) {
     575                 :        3002 :             require(
     576                 :             :               EModeConfiguration.isReserveEnabledOnBitmap(eModeCategory.borrowableBitmap, i),
     577                 :             :               Errors.NOT_BORROWABLE_IN_EMODE
     578                 :             :             );
     579                 :             :           }
     580                 :             :         }
     581                 :             :       }
     582                 :             :     }
     583                 :             :   }
     584                 :             : 
     585                 :             :   /**
     586                 :             :    * @notice Validates the action of activating the asset as collateral.
     587                 :             :    * @dev Only possible if the asset has non-zero LTV and the user is not in isolation mode
     588                 :             :    * @param reservesData The state of all the reserves
     589                 :             :    * @param reservesList The addresses of all the active reserves
     590                 :             :    * @param userConfig the user configuration
     591                 :             :    * @param reserveConfig The reserve configuration
     592                 :             :    * @return True if the asset can be activated as collateral, false otherwise
     593                 :             :    */
     594                 :             :   function validateUseAsCollateral(
     595                 :             :     mapping(address => DataTypes.ReserveData) storage reservesData,
     596                 :             :     mapping(uint256 => address) storage reservesList,
     597                 :             :     DataTypes.UserConfigurationMap storage userConfig,
     598                 :             :     DataTypes.ReserveConfigurationMap memory reserveConfig
     599                 :             :   ) internal view returns (bool) {
     600                 :       59411 :     if (reserveConfig.getLtv() == 0) {
     601                 :           3 :       return false;
     602                 :             :     }
     603                 :       59408 :     if (!userConfig.isUsingAsCollateralAny()) {
     604                 :       58324 :       return true;
     605                 :             :     }
     606                 :        1084 :     (bool isolationModeActive, , ) = userConfig.getIsolationModeState(reservesData, reservesList);
     607                 :             : 
     608                 :        1084 :     return (!isolationModeActive && reserveConfig.getDebtCeiling() == 0);
     609                 :             :   }
     610                 :             : 
     611                 :             :   /**
     612                 :             :    * @notice Validates if an asset should be automatically activated as collateral in the following actions: supply,
     613                 :             :    * transfer, mint unbacked, and liquidate
     614                 :             :    * @dev This is used to ensure that isolated assets are not enabled as collateral automatically
     615                 :             :    * @param reservesData The state of all the reserves
     616                 :             :    * @param reservesList The addresses of all the active reserves
     617                 :             :    * @param userConfig the user configuration
     618                 :             :    * @param reserveConfig The reserve configuration
     619                 :             :    * @return True if the asset can be activated as collateral, false otherwise
     620                 :             :    */
     621                 :             :   function validateAutomaticUseAsCollateral(
     622                 :             :     mapping(address => DataTypes.ReserveData) storage reservesData,
     623                 :             :     mapping(uint256 => address) storage reservesList,
     624                 :             :     DataTypes.UserConfigurationMap storage userConfig,
     625                 :             :     DataTypes.ReserveConfigurationMap memory reserveConfig,
     626                 :             :     address aTokenAddress
     627                 :             :   ) internal view returns (bool) {
     628                 :       59404 :     if (reserveConfig.getDebtCeiling() != 0) {
     629                 :             :       // ensures only the ISOLATED_COLLATERAL_SUPPLIER_ROLE can enable collateral as side-effect of an action
     630                 :          12 :       IPoolAddressesProvider addressesProvider = IncentivizedERC20(aTokenAddress)
     631                 :             :         .POOL()
     632                 :             :         .ADDRESSES_PROVIDER();
     633                 :             :       if (
     634                 :          12 :         !IAccessControl(addressesProvider.getACLManager()).hasRole(
     635                 :             :           ISOLATED_COLLATERAL_SUPPLIER_ROLE,
     636                 :             :           msg.sender
     637                 :             :         )
     638                 :          12 :       ) return false;
     639                 :             :     }
     640                 :       59392 :     return validateUseAsCollateral(reservesData, reservesList, userConfig, reserveConfig);
     641                 :             :   }
     642                 :             : }
        

Generated by: LCOV version 2.1-1