Core Contracts

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

Incorrect Return Value in ReserveLibrary::getNormalizedDebt Function

01. Relevant GitHub Links

02. Summary

ReserveLibrary::getNormalizedDebt is intended to return the NormalizedDebt value. However, when timeDelta < 1, it returns reserve.totalUsage instead of reserve.usageIndex. By contrast, getNormalizedIncome correctly returns reserve.liquidityIndex in the same scenario. This mismatch can cause confusion or errors in calculations that rely on getNormalizedDebt.

03. Vulnerability Details

If timeDelta < 1, the function returns reserve.totalUsage instead of reserve.usageIndex, which may lead to incorrect debt values.

function getNormalizedDebt(ReserveData storage reserve, ReserveRateData storage rateData) internal view returns (uint256) {
uint256 timeDelta = block.timestamp - uint256(reserve.lastUpdateTimestamp);
if (timeDelta < 1) {
return reserve.totalUsage;
}
return calculateCompoundedInterest(rateData.currentUsageRate, timeDelta).rayMul(reserve.usageIndex);
}

Meanwhile, getNormalizedIncome properly returns reserve.liquidityIndex under similar conditions.

function getNormalizedIncome(ReserveData storage reserve, ReserveRateData storage rateData) internal view returns (uint256) {
uint256 timeDelta = block.timestamp - uint256(reserve.lastUpdateTimestamp);
if (timeDelta < 1) {
return reserve.liquidityIndex;
}
return calculateLinearInterest(rateData.currentLiquidityRate, timeDelta, reserve.liquidityIndex).rayMul(reserve.liquidityIndex);
}

04. Impact

While getBorrowRate (which uses getNormalizedDebt) is not currently in use, this incorrect behavior in the library could cause issues in other protocols or future upgrades. It might produce unexpected debt calculations, potentially leading to interest rate or utilization mismatches.

05. Tools Used

Manual Code Review and Foundry

06. Recommended Mitigation

function getNormalizedDebt(ReserveData storage reserve, ReserveRateData storage rateData) internal view returns (uint256) {
uint256 timeDelta = block.timestamp - uint256(reserve.lastUpdateTimestamp);
if (timeDelta < 1) {
- return reserve.totalUsage;
+ return reserve.usageIndex;
}
return calculateCompoundedInterest(rateData.currentUsageRate, timeDelta).rayMul(reserve.usageIndex);
}
Updates

Lead Judging Commences

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

getNormalizedDebt returns totalUsage (amount) instead of usageIndex (rate) when timeDelta < 1, breaking interest calculations across the protocol

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

getNormalizedDebt returns totalUsage (amount) instead of usageIndex (rate) when timeDelta < 1, breaking interest calculations across the protocol

Support

FAQs

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