Core Contracts

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

Incorrect Liquidation Finalization Analysis

Description

After reviewing LendingPool.sol, the report is valid but needs more precise technical details. The issue lies in the finalizeLiquidation function lacking health factor validation at liquidation execution time.

Vulnerable Code

function finalizeLiquidation(address userAddress) external nonReentrant onlyStabilityPool {
if (!isUnderLiquidation[userAddress]) revert NotUnderLiquidation();
// Only checks grace period, not current health factor
if (block.timestamp <= liquidationStartTime[userAddress] + liquidationGracePeriod) {
revert GracePeriodNotExpired();
}
// Proceeds with liquidation without revalidating position health
UserData storage user = userData[userAddress];
// ...transfer NFTs and handle debt...
}

Impact

  1. Financial Loss Risk

    • Users whose positions recover during grace period still get liquidated

    • NFT collateral could be seized despite improved health factor

    • No consideration of market price improvements

  2. Protocol Risk

    • Unfair liquidations damage protocol reputation

    • Potential regulatory issues from improper liquidation practices

    • Legal exposure from affected users

Proof of Concept

function proveIncorrectLiquidation() public {
// 1. User position becomes unhealthy
// health factor < liquidationThreshold
lendingPool.initiateLiquidation(user);
// 2. During grace period:
// - NFT prices increase significantly
// - User's position recovers above threshold
mockPriceOracle.setNFTPrice(tokenId, newHigherPrice);
// 3. Liquidation still executes without checking current health
lendingPool.finalizeLiquidation(user); // Should revert but doesn't
}

Recommended Mitigation

function finalizeLiquidation(address userAddress) external nonReentrant onlyStabilityPool {
if (!isUnderLiquidation[userAddress]) revert NotUnderLiquidation();
// Check grace period
if (block.timestamp <= liquidationStartTime[userAddress] + liquidationGracePeriod) {
revert GracePeriodNotExpired();
}
// Add health factor revalidation
uint256 currentHealthFactor = calculateHealthFactor(userAddress);
if (currentHealthFactor >= healthFactorLiquidationThreshold) {
revert PositionHealthyCannotLiquidate();
}
// Record liquidation price data
emit LiquidationPrices(
userAddress,
getUserCollateralValue(userAddress),
getUserDebt(userAddress),
currentHealthFactor
);
// Continue with existing liquidation logic
UserData storage user = userData[userAddress];
// ...existing code...
}

Additional Recommendations

  1. Add snapshot of health metrics at liquidation initiation

  2. Implement price oracle staleness checks

  3. Add events for liquidation state changes

  4. Consider graceful liquidation cancellation if position recovers

Updates

Lead Judging Commences

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

Give us feedback!