Core Contracts

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

Borrowers are unable to close liquidation even collateral value increased

Summary

The function LendingPool::closeLiquidation() does not take health factor into account, which can cause the borrower unable to close liquidation even though the collateral value increased

Vulnerability Details

The liquidation for a debt position can be initiated when health factor is lower than the threshold through function LendingPool::initiateLiquidation(). After the liquidation is initiated, there is a grace period in which the borrower can close the liquidation.

The problem arises when there is scenario that the position collateral value decreases, which can initiate a liquidation. But when the collateral value goes up again, the borrower is unable to close the liquidation. This is because the function LendingPool::closeLiquidation() does not check health factor but only check position's debt.

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);
}
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();
// there is no check for health factor at this execution step
isUnderLiquidation[userAddress] = false;
liquidationStartTime[userAddress] = 0;
emit LiquidationClosed(userAddress);
}

PoC

Add the test to file test/unit/core/pools/LendingPool/LendingPool.test.js

describe("Liquidation", function () {
...
it('Borrowers are unable to close liquidation even collateral value increased', async function() {
// @audit PoC health factor is not taken into account when closing liquidation
await raacHousePrices.setHousePrice(1, ethers.parseEther("90"));
await lendingPool.connect(user2).initiateLiquidation(user1.address)
await raacHousePrices.setHousePrice(1, ethers.parseEther("500"));
// can not close liquidation
await lendingPool.connect(user1).closeLiquidation();
})

Run the test and console shows:

LendingPool
Liquidation
1) Borrowers are unable to close liquidation even collateral value increased
0 passing (2s)
1 failing
1) LendingPool
Liquidation
Borrowers are unable to close liquidation even collateral value increased:
Error: VM Exception while processing transaction: reverted with custom error 'DebtNotZero()'
at LendingPool.closeLiquidation (contracts/core/pools/LendingPool/LendingPool.sol:533)

Impact

  • Borrowers unable to close liquidation in case the collateral value increases, which is unfair

Tools Used

Manual

Recommendations

Also add a health check in function LendingPool::closeLiquidation()

Updates

Lead Judging Commences

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