Core Contracts

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

Incorrect Collateral Check in Borrow Function Allows Undercollateralized Positions

Summary

The borrow() function in the LendingPool contract uses percentMul instead of percentDiv when checking if a user has sufficient collateral, allowing users to borrow more than they should and create undercollateralized positions.

Vulnerability Details

The key issue lies in this check in the borrow() function:

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

This is incorrect because:
The liquidationThreshold is set to 80% (8000 basis points) in the contract:

uint256 public constant BASE_LIQUIDATION_THRESHOLD = 80 * 1e2; // 80% in basis points

When using percentMul, the calculation effectively becomes:

userTotalDebt * (80/100) = userTotalDebt * 0.8

This means the check is verifying if:

collateralValue < (userTotalDebt * 0.8)

The difference is significant:

  • Current (incorrect): For 100 tokens of debt, only needs 80 tokens of collateral

  • Correct: For 100 tokens of debt, needs 125 tokens of collateral (100/0.8)

This check in borrow function also does not align with the health factor calculation in the contract:

function calculateHealthFactor(address userAddress) public view returns (uint256) {
uint256 collateralValue = getUserCollateralValue(userAddress);
uint256 userDebt = getUserDebt(userAddress);
if (userDebt < 1) return type(uint256).max;
uint256 collateralThreshold = collateralValue.percentMul(liquidationThreshold);
return (collateralThreshold * 1e18) / userDebt;
}

The health factor formula shows that to maintain a health factor ≥ 1; (collateralValue * 0.8) / debt ≥ 1 which simplifies to collateralValue ≥ debt / 0.8 but the check in borrow function uses collateralValue < (userTotalDebt * 0.8) which is wrong;

PoC

  1. Alice has 100 tokens worth of NFT collateral

  2. The liquidation threshold is 80%

  3. Alice attempts to borrow 100 tokens

  4. Current check: 100 < 100 * 0.8 (80) - This passes

  5. Alice receives 100 tokens loan

  6. Alice's health factor: (100 * 0.8) / 100 = 0.8 - Undercollateralized

Impact

Users can create undercollateralized positions from the start, putting the protocol at immediate risk of bad debt.

Tools Used

Manual Review

Recommendations

Change the check in the borrow() function to use percentDiv instead of percentMul:

if (collateralValue < userTotalDebt.percentDiv(liquidationThreshold)) {
revert NotEnoughCollateralToBorrow();
}
Updates

Lead Judging Commences

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

Give us feedback!