Core Contracts

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

No Partial Repayment Option During Liquidation Grace Period

Summary

The closeLiquidation function forces users to repay their entire debt to avoid liquidation, preventing partial repayments that could restore position health and save the collateral.

Vulnerability Details

The function requires debt to be completely repaid (below DUST_THRESHOLD) rather than allowing partial repayments that could bring the health factor back above the liquidation threshold:

function closeLiquidation() external nonReentrant whenNotPaused {
address userAddress = msg.sender;
if (!isUnderLiquidation[userAddress]) revert NotUnderLiquidation();
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();
}

Impact

  • Users who could partially repay to restore health factor lose their entire collateral

  • Forces unnecessary full repayments when partial ones would suffice

  • Reduces protocol capital efficiency

  • This may lead to more liquidations than necessary

Tools Used

Manual review

Recommendations

Allow partial repayments during the grace period and add repayment parameter to closeLiquidation

function closeLiquidation(uint256 repayAmount) external nonReentrant whenNotPaused {
address userAddress = msg.sender;
if (!isUnderLiquidation[userAddress]) revert NotUnderLiquidation();
ReserveLibrary.updateReserveState(reserve, rateData);
// First try to repay the specified amount
_repay(repayAmount, userAddress);
// Check if health factor is restored
uint256 healthFactor = calculateHealthFactor(userAddress);
if (healthFactor >= healthFactorLiquidationThreshold) {
isUnderLiquidation[userAddress] = false;
liquidationStartTime[userAddress] = 0;
emit LiquidationClosed(userAddress);
} else {
revert HealthFactorNotRestored();
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 6 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.