Core Contracts

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

Incorrect Collateral-to-Debt Comparison in Borrowing and NFT Withdrawal

Summary

The borrow() and withdrawNFT() functions in LendingPool.sol incorrectly compare the user's collateral value to their debt threshold using percentage multiplication (percentMul) instead of percentage division (percentDiv). This mistake underestimates the required collateral, allowing users to borrow or withdraw NFTs while being undercollateralized, potentially leading to unexpected liquidations.

Vulnerability Details

liquidationThreshold is initialized to BASE_LIQUIDATION_THRESHOLD = 80 * 1e2; // 80% in basis points:

// Initialize liquidation parameters
liquidationThreshold = BASE_LIQUIDATION_THRESHOLD;

If it's updated, it requires newValue <= 100_00, i.e. less or equal to 100% in basis point:

LendingPool.sol#L129-L133

if (param == OwnerParameter.LiquidationThreshold) {
require(newValue <= 100_00, "Invalid liquidation threshold");
liquidationThreshold = newValue;
emit LiquidationParametersUpdated(liquidationThreshold, healthFactorLiquidationThreshold, liquidationGracePeriod);
}

Now, here's the obvious flaw in borrow():

LendingPool.sol#L343-L346

// Ensure the user has enough collateral to cover the new debt
if (collateralValue < userTotalDebt.percentMul(liquidationThreshold)) {
revert NotEnoughCollateralToBorrow();
}

userTotalDebt.percentMul(liquidationThreshold) reduces the debt instead of properly scaling up prior to comparing it with the required collateral.

The correct formula should divide debt by the liquidation threshold, scaling the userTotalDebt more than 100% to determine the required collateral.

Similar flawed logic is unfortunately exhibited in withdrawNFT() too:

LendingPool.sol#L302-L304

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

Impact

  • Users can withdraw NFTs or borrow beyond safe limits, leaving their positions undercollateralized.

  • This leads to unexpected liquidations where users may lose their collateral even when they believed they were safe.

  • The system could become insolvent, as borrowers may be unable to fully repay their debts with a trend of easy money easy go.

Tools Used

Manual

Recommendations

Consider making the following refactoring:

LendingPool.sol#L302-L304

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

LendingPool.sol#L343-L346

// Ensure the user has enough collateral to cover the new debt
- if (collateralValue < userTotalDebt.percentMul(liquidationThreshold)) {
+ if (collateralValue < userTotalDebt.percentDiv(liquidationThreshold)) {
revert NotEnoughCollateralToBorrow();
}
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.