Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: medium
Valid

Failure to Close Liquidation Due to Edge Case Timing Issues

Summary

The LendingPool contract requires borrowers to manually invoke closeLiquidation after repaying their debt during the liquidation grace period. An edge case arises when a borrower repays their debt at the last moment of the grace period but does not have enough time to call closeLiquidation before the grace period expires. This leads to an unintended liquidation, even though the borrower has fully repaid their debt.


Vulnerability Details

Issue Explanation

  1. Manual Closure of Liquidation Required

    function closeLiquidation() external nonReentrant whenNotPaused {
    address userAddress = msg.sender;
    if (!isUnderLiquidation[userAddress]) revert NotUnderLiquidation();
    if (block.timestamp > liquidationStartTime[userAddress] + liquidationGracePeriod) {
    revert GracePeriodExpired();
    }
    UserData storage user = userData[userAddress];
    uint256 userDebt = user.scaledDebtBalance.rayMul(reserve.usageIndex);
    if (userDebt > DUST_THRESHOLD) revert DebtNotZero();
    isUnderLiquidation[userAddress] = false;
    liquidationStartTime[userAddress] = 0;
    emit LiquidationClosed(userAddress);
    }
    • Edge Case: The function enforces a strict grace period check:

      if (block.timestamp > liquidationStartTime[userAddress] + liquidationGracePeriod) {
      revert GracePeriodExpired();
      }
    • Problem: If the borrower repays at the last moment of the grace period, the grace period may expire before they manage to call closeLiquidation().

    • This results in an unfair liquidation, even though the borrower has repaid their debt in full.


Edge Case Scenario Leading to the Issue

  1. The user is flagged for liquidation and provided with a grace period to repay their debt.

  2. The user repays the full debt at the very last moment of the grace period.

  3. The grace period expires immediately after repayment, preventing the borrower from calling closeLiquidation().

  4. As closeLiquidation() cannot be called after the grace period expires, the borrower remains flagged for liquidation even after repayment.

  5. The borrower is unfairly liquidated, as they had no opportunity to remove the liquidation flag.


Impact

  • Unfair Liquidations: Borrowers may be liquidated despite fully repaying their debt due to timing issues.

  • Loss of Collateral: Borrowers lose their collateral despite having cleared their debt.


Recommendations

Solution 1: Automatically Call closeLiquidation in repay

  • Modify the repay function to automatically call **closeLiquidation**if user who is paying debt is already liquidated, which prevents them to call the function twice.

  • Fix:

    function repay(uint256 amount) external nonReentrant whenNotPaused onlyValidAmount(amount) {
    _repay(amount, msg.sender);
    // Automatically close liquidation if debt is cleared
    if (userData[msg.sender].scaledDebtBalance.rayMul(reserve.usageIndex) <= DUST_THRESHOLD) {
    closeLiquidation();
    }
    }

Solution 2: Add Health Factor Check in closeLiquidation

  • Instead of enforcing a strict grace period check, validate the borrower's health factor before finalizing liquidation, like how its done in intiate liquidation, because user collateral value may get increase, then they don't need to repay any amount

    function closeLiquidation() external nonReentrant whenNotPaused {
    address userAddress = msg.sender;
    if (!isUnderLiquidation[userAddress]) revert NotUnderLiquidation();
    uint256 healthFactor = getHealthFactor(userAddress);
    if (healthFactor >= SAFE_THRESHOLD) { // Ensure borrower is solvent
    isUnderLiquidation[userAddress] = false;
    liquidationStartTime[userAddress] = 0;
    emit LiquidationClosed(userAddress);
    return;
    }
    if (block.timestamp > liquidationStartTime[userAddress] + liquidationGracePeriod) {
    revert GracePeriodExpired();
    }
    }
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

A borrower can LendingPool::repay to avoid liquidation but might not be able to call LendingPool::closeLiquidation successfully due to grace period check, loses both funds and collateral

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!