Core Contracts

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

Borrowers can't close liquidation process even if their healthFactor is healty

Summary

Vulnerability Details

Liquidation process in LendingPool consists in 2 steps: initiateLiquidation where a liquidationStartTime counter is started and, after liquidationGracePeriod has expired, finalizeLiquidation can be called to settle the liquidation.
Liquidation can be started if collatera-to-debt ratio, named healthFactor, falls under a specific value.

The borrower who is under liquidation can repay his debt or depositNFT to deposit more collateral and close the liquidation process by calling closeLiquidation

In closeLiquidation, if userDebt is smaller than some dust amount, liquidation can be closed.

// LendingPool.sol
function closeLiquidation() external nonReentrant whenNotPaused {
address userAddress = msg.sender;
if (!isUnderLiquidation[userAddress]) revert NotUnderLiquidation();
// update state
ReserveLibrary.updateReserveState(reserve, rateData);
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(); // @audit check healthFactor to be healty instead of debt amount
isUnderLiquidation[userAddress] = false;
liquidationStartTime[userAddress] = 0;
emit LiquidationClosed(userAddress);
}

This is problematic. Liquidation is started based on a healthFactor. Borrower could :

i. partial repay his debt, enough to make his healthFactor healthy again OR

ii. deposit more RAACNft as colateral to make his healthFactor healthy.

Even if borrower repaid/ added more colateral and he doesn't meet liquidation condition anymore, he can't close the liquidation. After grace period expires he will be liquidated.

Impact

Borrowers may be liquidated unfairly loosing their collateral even if they hold almost no debt (close to DUST_THRESHOLD).

Tools Used

Recommendations

Update closeLiquidation and check user's health factor instead of user's debt.

function closeLiquidation() external nonReentrant whenNotPaused {
...
UserData storage user = userData[userAddress];
- uint256 userDebt = user.scaledDebtBalance.rayMul(reserve.usageIndex);
- if (userDebt > DUST_THRESHOLD) revert DebtNotZero();
+ uint256 healthFactor = calculateHealthFactor(userAddress);
+ if (healthFactor < healthFactorLiquidationThreshold) revert HealthFactorTooLow();
isUnderLiquidation[userAddress] = false;
liquidationStartTime[userAddress] = 0;
emit LiquidationClosed(userAddress);
}
Updates

Lead Judging Commences

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

LendingPool::finalizeLiquidation() never checks if debt is still unhealthy

Support

FAQs

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