Core Contracts

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

Incorrect Scaled Debt Calculation Leading to Underestimated User Debt

Summary

In the borrow function of the LendingPool contract where the calculation of the user's scaled debt balance incorrectly uses rayDiv instead of rayMul. This error leads to an underestimation of the user's debt, allowing borrowers to take out larger loans than their collateral should permit, potentially resulting in undercollateralized positions and protocol insolvency.

Vulnerability Details

The borrow function calculates the user's total debt after borrowing (userTotalDebt) by combining their existing scaled debt balance (converted to actual debt using rayMul) with the new borrowed amount. However, when updating the user's scaled debt balance, the new amount is divided by the usage index (rayDiv), which incorrectly scales down the borrowed amount. This results in a lower scaled debt balance than required, causing the actual debt to be inaccurately represented and allowing users to borrow more than their collateral should allow.

function borrow(uint256 amount) external nonReentrant whenNotPaused onlyValidAmount(amount) {
if (isUnderLiquidation[msg.sender]) revert CannotBorrowUnderLiquidation();
UserData storage user = userData[msg.sender];
uint256 collateralValue = getUserCollateralValue(msg.sender);
if (collateralValue == 0) revert NoCollateral();
// Update reserve state before borrowing
ReserveLibrary.updateReserveState(reserve, rateData);
// Ensure sufficient liquidity is available
_ensureLiquidity(amount);
// Fetch user's total debt after borrowing
@>> uint256 userTotalDebt = user.scaledDebtBalance.rayMul(reserve.usageIndex) + amount;
// Ensure the user has enough collateral to cover the new debt
@>> if (collateralValue < userTotalDebt.percentMul(liquidationThreshold)) {
revert NotEnoughCollateralToBorrow();
}
// Update user's scaled debt balance
@>> uint256 scaledAmount = amount.rayDiv(reserve.usageIndex);
// Mint DebtTokens to the user (scaled amount)
(bool isFirstMint, uint256 amountMinted, uint256 newTotalSupply) = IDebtToken(reserve.reserveDebtTokenAddress).mint(msg.sender, msg.sender, amount, reserve.usageIndex);
// Transfer borrowed amount to user
IRToken(reserve.reserveRTokenAddress).transferAsset(msg.sender, amount);
@>> user.scaledDebtBalance += scaledAmount;
// reserve.totalUsage += amount;
reserve.totalUsage = newTotalSupply;
// Update liquidity and interest rates
ReserveLibrary.updateInterestRatesAndLiquidity(reserve, rateData, 0, amount);
// Rebalance liquidity after borrowing
_rebalanceLiquidity();
emit Borrow(msg.sender, amount);
}

POC

  1. Initial Conditions:

    • reserve.usageIndex = 1e27 (RAY)

    • User has 0 debt and collateral worth 200 units.

  2. First Borrow:

    • User borrows 100 units.

    • userTotalDebt = 0 * 1e27 + 100 = 100 (correct).

    • scaledAmount = 100.rayDiv(1e27) = 100e18 * 1e27 / 1e27 = 100e18.

    • user.scaledDebtBalance becomes 100e18.

  3. Interest Accrual:

    • Over time, reserve.usageIndex increases to 2e27 due to interest.

  4. Second Borrow:

    • User attempts to borrow another 100 units.

    • userTotalDebt = (100e18.rayMul(2e27)) + 100 = 200 + 100 = 300.

    • Collateral check: 200 >= 300 * 80% → 200 < 240 → Should revert. But:

    • scaledAmount = 100.rayDiv(2e27) = 100e18 * 1e27 / 2e27 = 50e18.

    • user.scaledDebtBalance becomes 100e18 + 50e18 = 150e18.

    • Actual debt now: 150e18 * 2e27 / 1e27 = 300 units (correct).

Impact

The scaled debt were miscalculated (e.g., using rayMul), users could borrow beyond their collateral limits, leading to bad debt and protocol insolvency.

Tools Used

Manual review

Recommendations

Updates

Lead Judging Commences

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

LendingPool::borrow tracks debt as user.scaledDebtBalance += scaledAmount while DebtToken mints amount+interest, leading to accounting mismatch and preventing full debt repayment

Support

FAQs

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