LCOV - code coverage report
Current view: top level - protocol/libraries/logic - LiquidationLogic.sol (source / functions) Coverage Total Hit
Test: lcov.info.p Lines: 98.6 % 74 73
Test Date: 2024-09-24 09:34:24 Functions: 100.0 % 6 6
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 {GPv2SafeERC20} from '../../../dependencies/gnosis/contracts/GPv2SafeERC20.sol';
       6                 :             : import {PercentageMath} from '../../libraries/math/PercentageMath.sol';
       7                 :             : import {WadRayMath} from '../../libraries/math/WadRayMath.sol';
       8                 :             : import {DataTypes} from '../../libraries/types/DataTypes.sol';
       9                 :             : import {ReserveLogic} from './ReserveLogic.sol';
      10                 :             : import {ValidationLogic} from './ValidationLogic.sol';
      11                 :             : import {GenericLogic} from './GenericLogic.sol';
      12                 :             : import {IsolationModeLogic} from './IsolationModeLogic.sol';
      13                 :             : import {EModeLogic} from './EModeLogic.sol';
      14                 :             : import {UserConfiguration} from '../../libraries/configuration/UserConfiguration.sol';
      15                 :             : import {ReserveConfiguration} from '../../libraries/configuration/ReserveConfiguration.sol';
      16                 :             : import {EModeConfiguration} from '../../libraries/configuration/EModeConfiguration.sol';
      17                 :             : import {IAToken} from '../../../interfaces/IAToken.sol';
      18                 :             : import {IVariableDebtToken} from '../../../interfaces/IVariableDebtToken.sol';
      19                 :             : import {IPriceOracleGetter} from '../../../interfaces/IPriceOracleGetter.sol';
      20                 :             : 
      21                 :             : /**
      22                 :             :  * @title LiquidationLogic library
      23                 :             :  * @author Aave
      24                 :             :  * @notice Implements actions involving management of collateral in the protocol, the main one being the liquidations
      25                 :             :  */
      26                 :             : library LiquidationLogic {
      27                 :             :   using WadRayMath for uint256;
      28                 :             :   using PercentageMath for uint256;
      29                 :             :   using ReserveLogic for DataTypes.ReserveCache;
      30                 :             :   using ReserveLogic for DataTypes.ReserveData;
      31                 :             :   using UserConfiguration for DataTypes.UserConfigurationMap;
      32                 :             :   using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
      33                 :             :   using GPv2SafeERC20 for IERC20;
      34                 :             : 
      35                 :             :   // See `IPool` for descriptions
      36                 :             :   event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user);
      37                 :             :   event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user);
      38                 :             :   event LiquidationCall(
      39                 :             :     address indexed collateralAsset,
      40                 :             :     address indexed debtAsset,
      41                 :             :     address indexed user,
      42                 :             :     uint256 debtToCover,
      43                 :             :     uint256 liquidatedCollateralAmount,
      44                 :             :     address liquidator,
      45                 :             :     bool receiveAToken
      46                 :             :   );
      47                 :             : 
      48                 :             :   /**
      49                 :             :    * @dev Default percentage of borrower's debt to be repaid in a liquidation.
      50                 :             :    * @dev Percentage applied when the users health factor is above `CLOSE_FACTOR_HF_THRESHOLD`
      51                 :             :    * Expressed in bps, a value of 0.5e4 results in 50.00%
      52                 :             :    */
      53                 :             :   uint256 internal constant DEFAULT_LIQUIDATION_CLOSE_FACTOR = 0.5e4;
      54                 :             : 
      55                 :             :   /**
      56                 :             :    * @dev Maximum percentage of borrower's debt to be repaid in a liquidation
      57                 :             :    * @dev Percentage applied when the users health factor is below `CLOSE_FACTOR_HF_THRESHOLD`
      58                 :             :    * Expressed in bps, a value of 1e4 results in 100.00%
      59                 :             :    */
      60                 :             :   uint256 public constant MAX_LIQUIDATION_CLOSE_FACTOR = 1e4;
      61                 :             : 
      62                 :             :   /**
      63                 :             :    * @dev This constant represents below which health factor value it is possible to liquidate
      64                 :             :    * an amount of debt corresponding to `MAX_LIQUIDATION_CLOSE_FACTOR`.
      65                 :             :    * A value of 0.95e18 results in 0.95
      66                 :             :    */
      67                 :             :   uint256 public constant CLOSE_FACTOR_HF_THRESHOLD = 0.95e18;
      68                 :             : 
      69                 :             :   struct LiquidationCallLocalVars {
      70                 :             :     uint256 userCollateralBalance;
      71                 :             :     uint256 userTotalDebt;
      72                 :             :     uint256 actualDebtToLiquidate;
      73                 :             :     uint256 actualCollateralToLiquidate;
      74                 :             :     uint256 liquidationBonus;
      75                 :             :     uint256 healthFactor;
      76                 :             :     uint256 liquidationProtocolFeeAmount;
      77                 :             :     IAToken collateralAToken;
      78                 :             :     DataTypes.ReserveCache debtReserveCache;
      79                 :             :   }
      80                 :             : 
      81                 :             :   /**
      82                 :             :    * @notice Function to liquidate a position if its Health Factor drops below 1. The caller (liquidator)
      83                 :             :    * covers `debtToCover` amount of debt of the user getting liquidated, and receives
      84                 :             :    * a proportional amount of the `collateralAsset` plus a bonus to cover market risk
      85                 :             :    * @dev Emits the `LiquidationCall()` event
      86                 :             :    * @param reservesData The state of all the reserves
      87                 :             :    * @param reservesList The addresses of all the active reserves
      88                 :             :    * @param usersConfig The users configuration mapping that track the supplied/borrowed assets
      89                 :             :    * @param eModeCategories The configuration of all the efficiency mode categories
      90                 :             :    * @param params The additional parameters needed to execute the liquidation function
      91                 :             :    */
      92                 :             :   function executeLiquidationCall(
      93                 :             :     mapping(address => DataTypes.ReserveData) storage reservesData,
      94                 :             :     mapping(uint256 => address) storage reservesList,
      95                 :             :     mapping(address => DataTypes.UserConfigurationMap) storage usersConfig,
      96                 :             :     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
      97                 :             :     DataTypes.ExecuteLiquidationCallParams memory params
      98                 :             :   ) external {
      99                 :       14501 :     LiquidationCallLocalVars memory vars;
     100                 :             : 
     101                 :       14501 :     DataTypes.ReserveData storage collateralReserve = reservesData[params.collateralAsset];
     102                 :       14501 :     DataTypes.ReserveData storage debtReserve = reservesData[params.debtAsset];
     103                 :       14501 :     DataTypes.UserConfigurationMap storage userConfig = usersConfig[params.user];
     104                 :       14501 :     vars.debtReserveCache = debtReserve.cache();
     105                 :       14501 :     debtReserve.updateState(vars.debtReserveCache);
     106                 :             : 
     107                 :       14501 :     (, , , , vars.healthFactor, ) = GenericLogic.calculateUserAccountData(
     108                 :             :       reservesData,
     109                 :             :       reservesList,
     110                 :             :       eModeCategories,
     111                 :             :       DataTypes.CalculateUserAccountDataParams({
     112                 :             :         userConfig: userConfig,
     113                 :             :         reservesCount: params.reservesCount,
     114                 :             :         user: params.user,
     115                 :             :         oracle: params.priceOracle,
     116                 :             :         userEModeCategory: params.userEModeCategory
     117                 :             :       })
     118                 :             :     );
     119                 :             : 
     120                 :       14501 :     (vars.userTotalDebt, vars.actualDebtToLiquidate) = _calculateDebt(
     121                 :             :       vars.debtReserveCache,
     122                 :             :       params,
     123                 :             :       vars.healthFactor
     124                 :             :     );
     125                 :             : 
     126                 :       14501 :     ValidationLogic.validateLiquidationCall(
     127                 :             :       userConfig,
     128                 :             :       collateralReserve,
     129                 :             :       debtReserve,
     130                 :             :       DataTypes.ValidateLiquidationCallParams({
     131                 :             :         debtReserveCache: vars.debtReserveCache,
     132                 :             :         totalDebt: vars.userTotalDebt,
     133                 :             :         healthFactor: vars.healthFactor,
     134                 :             :         priceOracleSentinel: params.priceOracleSentinel
     135                 :             :       })
     136                 :             :     );
     137                 :             : 
     138                 :        8011 :     vars.collateralAToken = IAToken(collateralReserve.aTokenAddress);
     139                 :             :     if (
     140                 :        8011 :       params.userEModeCategory != 0 &&
     141                 :        1001 :       EModeConfiguration.isReserveEnabledOnBitmap(
     142                 :             :         eModeCategories[params.userEModeCategory].collateralBitmap,
     143                 :             :         collateralReserve.id
     144                 :             :       )
     145                 :             :     ) {
     146                 :        1001 :       vars.liquidationBonus = eModeCategories[params.userEModeCategory].liquidationBonus;
     147                 :             :     } else {
     148                 :        7010 :       vars.liquidationBonus = collateralReserve.configuration.getLiquidationBonus();
     149                 :             :     }
     150                 :             : 
     151                 :        8011 :     vars.userCollateralBalance = vars.collateralAToken.balanceOf(params.user);
     152                 :             : 
     153                 :        8011 :     (
     154                 :             :       vars.actualCollateralToLiquidate,
     155                 :             :       vars.actualDebtToLiquidate,
     156                 :             :       vars.liquidationProtocolFeeAmount
     157                 :             :     ) = _calculateAvailableCollateralToLiquidate(
     158                 :             :       collateralReserve,
     159                 :             :       vars.debtReserveCache,
     160                 :             :       params.collateralAsset,
     161                 :             :       params.debtAsset,
     162                 :             :       vars.actualDebtToLiquidate,
     163                 :             :       vars.userCollateralBalance,
     164                 :             :       vars.liquidationBonus,
     165                 :             :       IPriceOracleGetter(params.priceOracle)
     166                 :             :     );
     167                 :             : 
     168                 :        8011 :     if (vars.userTotalDebt == vars.actualDebtToLiquidate) {
     169                 :           2 :       userConfig.setBorrowing(debtReserve.id, false);
     170                 :             :     }
     171                 :             : 
     172                 :             :     // If the collateral being liquidated is equal to the user balance,
     173                 :             :     // we set the currency as not being used as collateral anymore
     174                 :             :     if (
     175                 :        8011 :       vars.actualCollateralToLiquidate + vars.liquidationProtocolFeeAmount ==
     176                 :             :       vars.userCollateralBalance
     177                 :             :     ) {
     178                 :        1006 :       userConfig.setUsingAsCollateral(collateralReserve.id, false);
     179                 :        1006 :       emit ReserveUsedAsCollateralDisabled(params.collateralAsset, params.user);
     180                 :             :     }
     181                 :             : 
     182                 :        8011 :     _burnDebtTokens(params, vars);
     183                 :             : 
     184                 :        8011 :     debtReserve.updateInterestRatesAndVirtualBalance(
     185                 :             :       vars.debtReserveCache,
     186                 :             :       params.debtAsset,
     187                 :             :       vars.actualDebtToLiquidate,
     188                 :             :       0
     189                 :             :     );
     190                 :             : 
     191                 :        8011 :     IsolationModeLogic.updateIsolatedDebtIfIsolated(
     192                 :             :       reservesData,
     193                 :             :       reservesList,
     194                 :             :       userConfig,
     195                 :             :       vars.debtReserveCache,
     196                 :             :       vars.actualDebtToLiquidate
     197                 :             :     );
     198                 :             : 
     199                 :        8011 :     if (params.receiveAToken) {
     200                 :           3 :       _liquidateATokens(reservesData, reservesList, usersConfig, collateralReserve, params, vars);
     201                 :             :     } else {
     202                 :        8008 :       _burnCollateralATokens(collateralReserve, params, vars);
     203                 :             :     }
     204                 :             : 
     205                 :             :     // Transfer fee to treasury if it is non-zero
     206                 :        8011 :     if (vars.liquidationProtocolFeeAmount != 0) {
     207                 :        8010 :       uint256 liquidityIndex = collateralReserve.getNormalizedIncome();
     208                 :        8010 :       uint256 scaledDownLiquidationProtocolFee = vars.liquidationProtocolFeeAmount.rayDiv(
     209                 :             :         liquidityIndex
     210                 :             :       );
     211                 :        8010 :       uint256 scaledDownUserBalance = vars.collateralAToken.scaledBalanceOf(params.user);
     212                 :             :       // To avoid trying to send more aTokens than available on balance, due to 1 wei imprecision
     213                 :        8010 :       if (scaledDownLiquidationProtocolFee > scaledDownUserBalance) {
     214                 :           0 :         vars.liquidationProtocolFeeAmount = scaledDownUserBalance.rayMul(liquidityIndex);
     215                 :             :       }
     216                 :        8010 :       vars.collateralAToken.transferOnLiquidation(
     217                 :             :         params.user,
     218                 :             :         vars.collateralAToken.RESERVE_TREASURY_ADDRESS(),
     219                 :             :         vars.liquidationProtocolFeeAmount
     220                 :             :       );
     221                 :             :     }
     222                 :             : 
     223                 :             :     // Transfers the debt asset being repaid to the aToken, where the liquidity is kept
     224                 :        8011 :     IERC20(params.debtAsset).safeTransferFrom(
     225                 :             :       msg.sender,
     226                 :             :       vars.debtReserveCache.aTokenAddress,
     227                 :             :       vars.actualDebtToLiquidate
     228                 :             :     );
     229                 :             : 
     230                 :        8011 :     IAToken(vars.debtReserveCache.aTokenAddress).handleRepayment(
     231                 :             :       msg.sender,
     232                 :             :       params.user,
     233                 :             :       vars.actualDebtToLiquidate
     234                 :             :     );
     235                 :             : 
     236                 :        8011 :     emit LiquidationCall(
     237                 :             :       params.collateralAsset,
     238                 :             :       params.debtAsset,
     239                 :             :       params.user,
     240                 :             :       vars.actualDebtToLiquidate,
     241                 :             :       vars.actualCollateralToLiquidate,
     242                 :             :       msg.sender,
     243                 :             :       params.receiveAToken
     244                 :             :     );
     245                 :             :   }
     246                 :             : 
     247                 :             :   /**
     248                 :             :    * @notice Burns the collateral aTokens and transfers the underlying to the liquidator.
     249                 :             :    * @dev   The function also updates the state and the interest rate of the collateral reserve.
     250                 :             :    * @param collateralReserve The data of the collateral reserve
     251                 :             :    * @param params The additional parameters needed to execute the liquidation function
     252                 :             :    * @param vars The executeLiquidationCall() function local vars
     253                 :             :    */
     254                 :             :   function _burnCollateralATokens(
     255                 :             :     DataTypes.ReserveData storage collateralReserve,
     256                 :             :     DataTypes.ExecuteLiquidationCallParams memory params,
     257                 :             :     LiquidationCallLocalVars memory vars
     258                 :             :   ) internal {
     259                 :        8008 :     DataTypes.ReserveCache memory collateralReserveCache = collateralReserve.cache();
     260                 :        8008 :     collateralReserve.updateState(collateralReserveCache);
     261                 :        8008 :     collateralReserve.updateInterestRatesAndVirtualBalance(
     262                 :             :       collateralReserveCache,
     263                 :             :       params.collateralAsset,
     264                 :             :       0,
     265                 :             :       vars.actualCollateralToLiquidate
     266                 :             :     );
     267                 :             : 
     268                 :             :     // Burn the equivalent amount of aToken, sending the underlying to the liquidator
     269                 :        8008 :     vars.collateralAToken.burn(
     270                 :             :       params.user,
     271                 :             :       msg.sender,
     272                 :             :       vars.actualCollateralToLiquidate,
     273                 :             :       collateralReserveCache.nextLiquidityIndex
     274                 :             :     );
     275                 :             :   }
     276                 :             : 
     277                 :             :   /**
     278                 :             :    * @notice Liquidates the user aTokens by transferring them to the liquidator.
     279                 :             :    * @dev   The function also checks the state of the liquidator and activates the aToken as collateral
     280                 :             :    *        as in standard transfers if the isolation mode constraints are respected.
     281                 :             :    * @param reservesData The state of all the reserves
     282                 :             :    * @param reservesList The addresses of all the active reserves
     283                 :             :    * @param usersConfig The users configuration mapping that track the supplied/borrowed assets
     284                 :             :    * @param collateralReserve The data of the collateral reserve
     285                 :             :    * @param params The additional parameters needed to execute the liquidation function
     286                 :             :    * @param vars The executeLiquidationCall() function local vars
     287                 :             :    */
     288                 :             :   function _liquidateATokens(
     289                 :             :     mapping(address => DataTypes.ReserveData) storage reservesData,
     290                 :             :     mapping(uint256 => address) storage reservesList,
     291                 :             :     mapping(address => DataTypes.UserConfigurationMap) storage usersConfig,
     292                 :             :     DataTypes.ReserveData storage collateralReserve,
     293                 :             :     DataTypes.ExecuteLiquidationCallParams memory params,
     294                 :             :     LiquidationCallLocalVars memory vars
     295                 :             :   ) internal {
     296                 :           3 :     uint256 liquidatorPreviousATokenBalance = IERC20(vars.collateralAToken).balanceOf(msg.sender);
     297                 :           3 :     vars.collateralAToken.transferOnLiquidation(
     298                 :             :       params.user,
     299                 :             :       msg.sender,
     300                 :             :       vars.actualCollateralToLiquidate
     301                 :             :     );
     302                 :             : 
     303                 :           3 :     if (liquidatorPreviousATokenBalance == 0) {
     304                 :           3 :       DataTypes.UserConfigurationMap storage liquidatorConfig = usersConfig[msg.sender];
     305                 :             :       if (
     306                 :           3 :         ValidationLogic.validateAutomaticUseAsCollateral(
     307                 :             :           reservesData,
     308                 :             :           reservesList,
     309                 :             :           liquidatorConfig,
     310                 :             :           collateralReserve.configuration,
     311                 :             :           collateralReserve.aTokenAddress
     312                 :             :         )
     313                 :             :       ) {
     314                 :           3 :         liquidatorConfig.setUsingAsCollateral(collateralReserve.id, true);
     315                 :           3 :         emit ReserveUsedAsCollateralEnabled(params.collateralAsset, msg.sender);
     316                 :             :       }
     317                 :             :     }
     318                 :             :   }
     319                 :             : 
     320                 :             :   /**
     321                 :             :    * @notice Burns the debt tokens of the user up to the amount being repaid by the liquidator.
     322                 :             :    * @dev The function alters the `debtReserveCache` state in `vars` to update the debt related data.
     323                 :             :    * @param params The additional parameters needed to execute the liquidation function
     324                 :             :    * @param vars the executeLiquidationCall() function local vars
     325                 :             :    */
     326                 :             :   function _burnDebtTokens(
     327                 :             :     DataTypes.ExecuteLiquidationCallParams memory params,
     328                 :             :     LiquidationCallLocalVars memory vars
     329                 :             :   ) internal {
     330                 :        8011 :     vars.debtReserveCache.nextScaledVariableDebt = IVariableDebtToken(
     331                 :             :       vars.debtReserveCache.variableDebtTokenAddress
     332                 :             :     ).burn(params.user, vars.actualDebtToLiquidate, vars.debtReserveCache.nextVariableBorrowIndex);
     333                 :             :   }
     334                 :             : 
     335                 :             :   /**
     336                 :             :    * @notice Calculates the total debt of the user and the actual amount to liquidate depending on the health factor
     337                 :             :    * and corresponding close factor.
     338                 :             :    * @dev If the Health Factor is below CLOSE_FACTOR_HF_THRESHOLD, the close factor is increased to MAX_LIQUIDATION_CLOSE_FACTOR
     339                 :             :    * @param debtReserveCache The reserve cache data object of the debt reserve
     340                 :             :    * @param params The additional parameters needed to execute the liquidation function
     341                 :             :    * @param healthFactor The health factor of the position
     342                 :             :    * @return The total debt of the user
     343                 :             :    * @return The actual debt to liquidate as a function of the closeFactor
     344                 :             :    */
     345                 :             :   function _calculateDebt(
     346                 :             :     DataTypes.ReserveCache memory debtReserveCache,
     347                 :             :     DataTypes.ExecuteLiquidationCallParams memory params,
     348                 :             :     uint256 healthFactor
     349                 :             :   ) internal view returns (uint256, uint256) {
     350                 :       14501 :     uint256 userVariableDebt = IERC20(debtReserveCache.variableDebtTokenAddress).balanceOf(
     351                 :             :       params.user
     352                 :             :     );
     353                 :             : 
     354                 :       14501 :     uint256 closeFactor = healthFactor > CLOSE_FACTOR_HF_THRESHOLD
     355                 :             :       ? DEFAULT_LIQUIDATION_CLOSE_FACTOR
     356                 :             :       : MAX_LIQUIDATION_CLOSE_FACTOR;
     357                 :             : 
     358                 :       14501 :     uint256 maxLiquidatableDebt = userVariableDebt.percentMul(closeFactor);
     359                 :             : 
     360                 :       14501 :     uint256 actualDebtToLiquidate = params.debtToCover > maxLiquidatableDebt
     361                 :             :       ? maxLiquidatableDebt
     362                 :             :       : params.debtToCover;
     363                 :             : 
     364                 :       14501 :     return (userVariableDebt, actualDebtToLiquidate);
     365                 :             :   }
     366                 :             : 
     367                 :             :   struct AvailableCollateralToLiquidateLocalVars {
     368                 :             :     uint256 collateralPrice;
     369                 :             :     uint256 debtAssetPrice;
     370                 :             :     uint256 maxCollateralToLiquidate;
     371                 :             :     uint256 baseCollateral;
     372                 :             :     uint256 bonusCollateral;
     373                 :             :     uint256 debtAssetDecimals;
     374                 :             :     uint256 collateralDecimals;
     375                 :             :     uint256 collateralAssetUnit;
     376                 :             :     uint256 debtAssetUnit;
     377                 :             :     uint256 collateralAmount;
     378                 :             :     uint256 debtAmountNeeded;
     379                 :             :     uint256 liquidationProtocolFeePercentage;
     380                 :             :     uint256 liquidationProtocolFee;
     381                 :             :   }
     382                 :             : 
     383                 :             :   /**
     384                 :             :    * @notice Calculates how much of a specific collateral can be liquidated, given
     385                 :             :    * a certain amount of debt asset.
     386                 :             :    * @dev This function needs to be called after all the checks to validate the liquidation have been performed,
     387                 :             :    *   otherwise it might fail.
     388                 :             :    * @param collateralReserve The data of the collateral reserve
     389                 :             :    * @param debtReserveCache The cached data of the debt reserve
     390                 :             :    * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
     391                 :             :    * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
     392                 :             :    * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
     393                 :             :    * @param userCollateralBalance The collateral balance for the specific `collateralAsset` of the user being liquidated
     394                 :             :    * @param liquidationBonus The collateral bonus percentage to receive as result of the liquidation
     395                 :             :    * @return The maximum amount that is possible to liquidate given all the liquidation constraints (user balance, close factor)
     396                 :             :    * @return The amount to repay with the liquidation
     397                 :             :    * @return The fee taken from the liquidation bonus amount to be paid to the protocol
     398                 :             :    */
     399                 :             :   function _calculateAvailableCollateralToLiquidate(
     400                 :             :     DataTypes.ReserveData storage collateralReserve,
     401                 :             :     DataTypes.ReserveCache memory debtReserveCache,
     402                 :             :     address collateralAsset,
     403                 :             :     address debtAsset,
     404                 :             :     uint256 debtToCover,
     405                 :             :     uint256 userCollateralBalance,
     406                 :             :     uint256 liquidationBonus,
     407                 :             :     IPriceOracleGetter oracle
     408                 :             :   ) internal view returns (uint256, uint256, uint256) {
     409                 :       12021 :     AvailableCollateralToLiquidateLocalVars memory vars;
     410                 :             : 
     411                 :       12021 :     vars.collateralPrice = oracle.getAssetPrice(collateralAsset);
     412                 :       12021 :     vars.debtAssetPrice = oracle.getAssetPrice(debtAsset);
     413                 :             : 
     414                 :       12021 :     vars.collateralDecimals = collateralReserve.configuration.getDecimals();
     415                 :       12021 :     vars.debtAssetDecimals = debtReserveCache.reserveConfiguration.getDecimals();
     416                 :             : 
     417                 :             :     unchecked {
     418                 :       12021 :       vars.collateralAssetUnit = 10 ** vars.collateralDecimals;
     419                 :       12021 :       vars.debtAssetUnit = 10 ** vars.debtAssetDecimals;
     420                 :             :     }
     421                 :             : 
     422                 :       12021 :     vars.liquidationProtocolFeePercentage = collateralReserve
     423                 :             :       .configuration
     424                 :             :       .getLiquidationProtocolFee();
     425                 :             : 
     426                 :             :     // This is the base collateral to liquidate based on the given debt to cover
     427                 :       12021 :     vars.baseCollateral =
     428                 :             :       ((vars.debtAssetPrice * debtToCover * vars.collateralAssetUnit)) /
     429                 :             :       (vars.collateralPrice * vars.debtAssetUnit);
     430                 :             : 
     431                 :       12021 :     vars.maxCollateralToLiquidate = vars.baseCollateral.percentMul(liquidationBonus);
     432                 :             : 
     433                 :       12021 :     if (vars.maxCollateralToLiquidate > userCollateralBalance) {
     434                 :        1011 :       vars.collateralAmount = userCollateralBalance;
     435                 :        1011 :       vars.debtAmountNeeded = ((vars.collateralPrice * vars.collateralAmount * vars.debtAssetUnit) /
     436                 :             :         (vars.debtAssetPrice * vars.collateralAssetUnit)).percentDiv(liquidationBonus);
     437                 :             :     } else {
     438                 :       11010 :       vars.collateralAmount = vars.maxCollateralToLiquidate;
     439                 :       11010 :       vars.debtAmountNeeded = debtToCover;
     440                 :             :     }
     441                 :             : 
     442                 :       12021 :     if (vars.liquidationProtocolFeePercentage != 0) {
     443                 :       12019 :       vars.bonusCollateral =
     444                 :             :         vars.collateralAmount -
     445                 :             :         vars.collateralAmount.percentDiv(liquidationBonus);
     446                 :             : 
     447                 :       12019 :       vars.liquidationProtocolFee = vars.bonusCollateral.percentMul(
     448                 :             :         vars.liquidationProtocolFeePercentage
     449                 :             :       );
     450                 :             : 
     451                 :       12019 :       return (
     452                 :             :         vars.collateralAmount - vars.liquidationProtocolFee,
     453                 :             :         vars.debtAmountNeeded,
     454                 :             :         vars.liquidationProtocolFee
     455                 :             :       );
     456                 :             :     } else {
     457                 :           2 :       return (vars.collateralAmount, vars.debtAmountNeeded, 0);
     458                 :             :     }
     459                 :             :   }
     460                 :             : }
        

Generated by: LCOV version 2.1-1