Core Contracts

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

Users with cleared debt potentially remain queued for liquidation resulting stuck NFTs & inability to borrow

Summary

The current implementation allows users to clear their debts to a point below or equal to a defined DUST_THRESHOLD within a grace period. However, if a user successfully repays their debt but fails to call the closeLiquidation() function before the grace period expires (possibly due to timeout), they may remain queued for liquidation. This causes issues downstream.

Vulnerability Details

Users have grace period within which they can close liquidation after paying their debt to below or equal to DUST_THRESHOLD:

>> 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;

However, their is a chance that a user can repay their whole debt but just before they call closeLiquidation(), their grace period elapses blocking them from existing the liquidation train.

Now an issue comes when the liquidateBorrower() is invoked on a user.

>> if (userDebt == 0) revert InvalidAmount();

Notice that if the userDebt is 0, this operation will revert.
Now we have a situation where a user has no debt but is still queued for liquidation. This becomes a problem in the following manner:

Scenario:

  • Alice has cleared her debt i.e userDebt == 0 but is till staged for liquidation as time ran out before she could opt out.

  • When a manager or owner tries to liquidate her, this fails.

  • Also, the borrow() & withdrawNFT() functions both have this check:

if (isUnderLiquidation[msg.sender]) revert CannotWithdrawUnderLiquidation();
  • This means that Alice cannot take any loans or withdraw her NFTS.

Impact

The result is, a user remains unable to take loans, and their NFTs remain stuck in the contract. This is total loss.

Tools Used

Manual Review

Recommendations

Implement a check in the liquidateBorrower() function to ensure that users who have cleared their debts are removed from the liquidation queue.

1.Add a new function in the LendingPool contract to reset the liquidation status and start time

// Add this function to the LendingPool contract
+ function resetLiquidationStatus(address userAddress) external onlyStabilityPool {
+ isUnderLiquidation[userAddress] = false;
+ liquidationStartTime[userAddress] = 0;
+ }

2.Modify the liquidateBorrower() function in the StabilityPool contract to call this new function:

uint256 userDebt = lendingPool.getUserDebt(userAddress);
- if (userDebt == 0) revert InvalidAmount();
+ if (userDebt == 0) {
+ // Reset liquidation status and start time in LendingPool
+ lendingPool.resetLiquidationStatus(userAddress);
+ return; // Exit the function early
+ }
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!