Core Contracts

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

A user's position never be liquidated again if it passes the grace period.

Summary

Contract - LendingPool.sol

The initiateLiquidation() function is used to start user's position liquidation.

function initiateLiquidation(address userAddress) external nonReentrant whenNotPaused {
@-> if (isUnderLiquidation[userAddress]) revert UserAlreadyUnderLiquidation();
// update state
ReserveLibrary.updateReserveState(reserve, rateData);
UserData storage user = userData[userAddress];
uint256 healthFactor = calculateHealthFactor(userAddress);
if (healthFactor >= healthFactorLiquidationThreshold) revert HealthFactorTooLow();
isUnderLiquidation[userAddress] = true;
liquidationStartTime[userAddress] = block.timestamp;
emit LiquidationInitiated(msg.sender, userAddress);
}

The closeLiquidation() function is used to liquidate user's position, it can be called by anyone.

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();
isUnderLiquidation[userAddress] = false;
liquidationStartTime[userAddress] = 0;
emit LiquidationClosed(userAddress);
}

Vulnerability Details

  1. Suppose grace period passed; now USER_A wants to liquidate the position, but he won't be able to achieve this because of condition -

if (block.timestamp > liquidationStartTime[userAddress] + liquidationGracePeriod) {
revert GracePeriodExpired();
}
  1. Now USER_A tries to initilize liquidation again, but he won't be able to because of check(below) inside initiateLiquidation() -

if (isUnderLiquidation[userAddress]) revert UserAlreadyUnderLiquidation();
  1. so if grace period passed without any liquidation, then user's position will be freezed forever because all 3 functions initiateLiquidation(), closeLiquidation() and finalizeLiquidation() will revert.

Impact

  • User positions will never be liquidated, if it's not done in grace period.

  • If user's position not liquidated, means it can lead to very drastic loss to protocol.

Tools Used

Manual

Recommendations

  • change the current architecture of liquidation.

  • instead of reverting modify changes to state variables associated with liquidation, so the operations like re-initialization
    can be performed, and position can be liquidated in other attempts.

Updates

Lead Judging Commences

inallhonesty Lead Judge
6 months ago
inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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