Skip to content

Latest commit

 

History

History
106 lines (74 loc) · 4.4 KB

066.md

File metadata and controls

106 lines (74 loc) · 4.4 KB

Tiny Licorice Loris

Medium

Allowing partial liquidations when all of user's collateral balance will be consumed will create false bad debts.

Summary

actualDebtToLiquidate will not == userReserveDebt in partial liquidations even when all of user's collateral balance will be consumed in the liquidation https://github.com/sherlock-audit/2025-01-aave-v3-3/blob/main/aave-v3-origin/src/contracts/protocol/libraries/logic/LiquidationLogic.sol#L546 https://github.com/sherlock-audit/2025-01-aave-v3-3/blob/main/aave-v3-origin/src/contracts/protocol/libraries/logic/LiquidationLogic.sol#L551 https://github.com/sherlock-audit/2025-01-aave-v3-3/blob/main/aave-v3-origin/src/contracts/protocol/libraries/logic/LiquidationLogic.sol#L580

Root Cause

The root cause of this issue is that whenever vars.totalCollateralInBaseCurrency == vars.collateralToLiquidateInBaseCurrency in LiquidationLogic.executeLiquidationCall(), hasNoCollateralLeft is set to true

 bool hasNoCollateralLeft = vars.totalCollateralInBaseCurrency ==
      vars.collateralToLiquidateInBaseCurrency;

Now when _burnDebtTokens() is called and hasNoCollateralLeft is true, all of user's debt is burnt (userReserveDebt).

  function _burnDebtTokens(
    DataTypes.ReserveCache memory debtReserveCache,
    DataTypes.ReserveData storage debtReserve,
    DataTypes.UserConfigurationMap storage userConfig,
    address user,
    address debtAsset,
    uint256 userReserveDebt,
    uint256 actualDebtToLiquidate,
    bool hasNoCollateralLeft
  ) internal {
    // Prior v3.1, there were cases where, after liquidation, the `isBorrowing` flag was left on
    // even after the user debt was fully repaid, so to avoid this function reverting in the `_burnScaled`
    // (see ScaledBalanceTokenBase contract), we check for any debt remaining.
    if (userReserveDebt != 0) {
      debtReserveCache.nextScaledVariableDebt = IVariableDebtToken(
        debtReserveCache.variableDebtTokenAddress
      ).burn(
          user,
          hasNoCollateralLeft ? userReserveDebt : actualDebtToLiquidate,//@audit
          debtReserveCache.nextVariableBorrowIndex
        );
    }

The issue lies in how outstandingDebt is calculated.

 uint256 outstandingDebt = userReserveDebt - actualDebtToLiquidate;//@audit-issue partial liquidations can create false bad debts. (happens if partial liquidations is attempted on a user whose whole collateral will be consumed on liquidation.) 

if liquidation is a partial one, actualDebtToLiquidate which is liquidator's specified debt to cover won't == userReserveDebt. Now although all of user's debt(userReserveDebt) was burnt and taken care of, outstandingDebt will !=0 which is wrong.

The wrong and false outstandingDebt will be added to debtReserve.deficit

Here's a more vivid explanation:

  • Total of Ben's debt(userReserveDebt) is == 1000$

  • Ben's position is liquidatable, so i decide to liquidate 500$ for him.(actualDebtToLiquidate) (Partial liquidation)

  • Now the liquidation will consume all of Ben's collateral, so hasNoCollateralLeft is set to true

  • when _burnDebtTokens() is called, since hasNoCollateralLeft is true, Ben's 1000$ is burnt

if (userReserveDebt != 0) {
      debtReserveCache.nextScaledVariableDebt = IVariableDebtToken(
        debtReserveCache.variableDebtTokenAddress
      ).burn(
          user,
          hasNoCollateralLeft ? userReserveDebt : actualDebtToLiquidate,//@audit
          debtReserveCache.nextVariableBorrowIndex
        );
  • When outstandingDebt is calculated, my 500$(actualDebtToLiquidate) is deducted from the Total of Ben's debt(userReserveDebt) which is 1000$.. leaving outstandingDebt as 500$ when in reality the whole 1000$ was burnt.

Internal Pre-conditions

  1. vars.totalCollateralInBaseCurrency needs to == vars.collateralToLiquidateInBaseCurrency in LiquidationLogic.executeLiquidationCall(), so hasNoCollateralLeft is set to true

External Pre-conditions

  1. Liquidation needs to be a partial liquidation.

Attack Path

No response

Impact

Allowing partial liquidations when all of user's collateral balance will be consumed will create false bad debts.

This will make Umbrella lose money by spending it on eliminating false bad debts and reserve deficits

PoC

No response

Mitigation

whenever liquidations will consume all of user's collateral balance don't allow partial liquidations