Core Contracts

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

The repayment process is paused, but liquidation process is not

Summary

The protocol can enter the state where the repayment for borrowers is paused, but their liquidation is still possible.

Vulnerability Details

Inside the LendingPool contract, users can borrow funds against their collateral. The liquidation process occurs in two steps. First, liquidation is initiated, marking the user's position as liquidatable. However, the user has a three-day grace period to repay their debt and close the liquidation. If the debt remains unpaid after three days, the user can no longer repay it, and the StabilityPool can call finalizeLiquidation() to finalize the liquidation.

This process ensures fairness and efficiency. However, if the LendingPool is paused for any reason after liquidation has been initiated, the user is unable to repay their debt due to whenNotPaused modifier on the repay functions. Once the grace period expires, the StabilityPool can still finalize the liquidation since this function does not have the whenNotPaused modifier. This creates an unfair situation for borrowers, as they are prevented from repaying their debts while their positions can still be liquidated.

POC

Add the following test to the LendingPool.test.js

it("should not allow Stability Pool to close liquidation after grace period if the Lending Pool is paused", async function () {
// Decrease house price and initiate liquidation
// FIXME: we are using price oracle and therefore the price should be changed from the oracle.
await raacHousePrices.setHousePrice(1, ethers.parseEther("90"));
await lendingPool.connect(user2).initiateLiquidation(user1.address);
// Fund the stability pool with crvUSD
await crvusd.connect(owner).mint(owner.address, ethers.parseEther("1000"));
// Set Stability Pool address (using owner for this test)
await lendingPool.connect(owner).setStabilityPool(owner.address);
await lendingPool.connect(owner).pause();
// Advance time beyond grace period (72 hours)
await ethers.provider.send("evm_increaseTime", [72 * 60 * 60 + 1]);
await ethers.provider.send("evm_mine");
const debtAmount = await debtToken.balanceOf(user1.address);
await crvusd.connect(user1).approve(rToken.target, debtAmount + ethers.parseEther("0.000001"));
const repayAmount = debtAmount + ethers.parseEther("1");
await expect(lendingPool.connect(user1).repay(repayAmount)).to.be.reverted;
// Finalize liquidation from stability pool even if the user has no chance to repay his debt
// this will work because the liquidation does not have "whenNotPaused" modifier
await expect(lendingPool.connect(owner).finalizeLiquidation(user1.address))
.to.emit(lendingPool, "LiquidationFinalized")
// Verify that the user is no longer under liquidation
expect(await lendingPool.isUnderLiquidation(user1.address)).to.be.false;
// Verify that the NFT has been transferred to the Stability Pool
expect(await raacNFT.ownerOf(1)).to.equal(owner.address);
// Verify that the user's debt has been repaid
const userClosedLiquidationDebt = await lendingPool.getUserDebt(user1.address);
expect(userClosedLiquidationDebt).to.equal(0);
});

Impact

High as it creates unfair situation for borrowers by being able to liquidate them while the contract is paused

Tools Used

Manual Review

Recommendations

Either add whenNotPaused modifier to the finalizeLiquidation() function as well, or remove it from the repay() function so users have the ability to repay their debts even if the contract is paused.

Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Unfair Liquidation As Repayment / closeLiquidation Paused While Liquidations Enabled

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Unfair Liquidation As Repayment / closeLiquidation Paused While Liquidations Enabled

Support

FAQs

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