Core Contracts

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

Incorrect collateralization check in LendingPool.sol allows users to borrow more than intended

Summary

In LendingPool.sol, the collateralization checks in both borrow() and withdrawNFT() functions incorrectly apply the liquidation threshold by multiplying it with the debt instead of the collateral. This backwards calculation makes the debt requirement artificially lower, allowing users to borrow more than the protocol intends and creating under collateralized positions.

Vulnerability Details

The protocol aims to ensure that a user's debt never exceeds a certain percentage of their collateral value (defined by the liquidation threshold). However, the current implementation in LendingPool.sol applies this threshold incorrectly.

In borrow():

function borrow(uint256 amount) external nonReentrant whenNotPaused onlyValidAmount(amount) {
// SNIP
// ...
uint256 userTotalDebt = user.scaledDebtBalance.rayMul(reserve.usageIndex) + amount;
// Incorrect check
if (collateralValue < userTotalDebt.percentMul(liquidationThreshold)) {
revert NotEnoughCollateralToBorrow();
}
// ...
}

In withdrawNFT():

function withdrawNFT(uint256 tokenId) external nonReentrant whenNotPaused {
// SNIP
// ...
if (collateralValue - nftValue < userDebt.percentMul(liquidationThreshold)) {
revert WithdrawalWouldLeaveUserUnderCollateralized();
}
// ...
}

The fundamental issue is that multiplying the debt by the threshold (which is less than 100%) makes the debt requirement smaller than it should be.

Intended Formula:

Collateral * Threshold >= Debt
Example with 80% threshold:
$100 collateral * 80% = $80 maximum allowed debt

Current Incorrect Formula:

Collateral >= Debt * Threshold
Example with 80% threshold:
$100 collateral >= $100 debt * 80% = $80
This incorrectly allows $125 of debt ($100/0.8) against $100 of collateral!

Impact

Critical. This vulnerability allows:

  1. Users to borrow up to 125% of their collateral value (1/0.8) instead of the intended 80%

  2. Creation of undercollateralized positions from the start

  3. Potential bad debt that cannot be fully recovered through liquidation

  4. Protocol insolvency risk

For example, with a $500,000 collateral deposit:

  • Users can borrow up to $625,000 (125% of collateral) instead of the intended $400,000 (80% of collateral).

  • This represents an excess borrowing of $225,000 (56.25% more).

  • If liquidated, the $500,000 collateral cannot cover the $625,000 debt.

  • Results in minimum $125,000 bad debt per position of this size.

Tools Used

Manual Review

Recommendations

Modify the collateralization checks to apply the threshold to the collateral value:

For borrow():

// Correct check
if (collateralValue.percentMul(liquidationThreshold) < userTotalDebt) {
revert NotEnoughCollateralToBorrow();
}

For withdrawNFT():

if ((collateralValue - nftValue).percentMul(liquidationThreshold) < userDebt) {
revert WithdrawalWouldLeaveUserUnderCollateralized();
}

This ensures the protocol maintains its intended maximum loan-to-value ratio and prevents undercollateralized positions.

Updates

Lead Judging Commences

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

LendingPool::borrow as well as withdrawNFT() reverses collateralization check, comparing collateral < debt*0.8 instead of collateral*0.8 > debt, allowing 125% borrowing vs intended 80%

Support

FAQs

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