Core Contracts

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

Incorrect Rate Calculation in getBorrowRate and getLiquidityRate

01. Relevant GitHub Links

02. Summary

Two internal functions, getBorrowRate and getLiquidityRate, return rates based on an incorrect calculation of totalDebt. Instead of providing the actual total debt, they rely on getNormalizedDebt, which returns the usageIndex or an incorrect value. This leads to entirely wrong rate computations. Additionally, getLiquidityRate uses rateData.currentUsageRate rather than an updated value from getBorrowRate, further compounding inaccuracies.

03. Vulnerability Details

When these functions calculate the utilization rate, they use getNormalizedDebt. However, getNormalizedDebt is designed to compute debt growth over time and ends up returning the usageIndex (multiplied by compounded interest) rather than the current total debt. This results in an incorrect utilizationRate. Consequently, calculateBorrowRate and calculateLiquidityRate produce misleading values.

/**
* @notice Gets the current borrow rate of the reserve.
* @param reserve The reserve data.
* @param rateData The reserve rate parameters.
* @return The current borrow rate (in RAY).
*/
function getBorrowRate(ReserveData storage reserve,ReserveRateData storage rateData) internal view returns (uint256) {
@> uint256 totalDebt = getNormalizedDebt(reserve, rateData);
uint256 utilizationRate = calculateUtilizationRate(reserve.totalLiquidity, totalDebt);
return calculateBorrowRate(rateData.primeRate, rateData.baseRate, rateData.optimalRate, rateData.maxRate, rateData.optimalUtilizationRate, utilizationRate);
}
/**
* @notice Gets the current liquidity rate of the reserve.
* @param reserve The reserve data.
* @param rateData The reserve rate parameters.
* @return The current liquidity rate (in RAY).
*/
function getLiquidityRate(ReserveData storage reserve,ReserveRateData storage rateData) internal view returns (uint256) {
@> uint256 totalDebt = getNormalizedDebt(reserve, rateData);
uint256 utilizationRate = calculateUtilizationRate(reserve.totalLiquidity, totalDebt);
return calculateLiquidityRate(utilizationRate, rateData.currentUsageRate, rateData.protocolFeeRate, totalDebt);
}

Furthermore, because getLiquidityRate directly uses rateData.currentUsageRate instead of retrieving the latest borrow rate, it also fails to reflect the most recent state. These errors can cause incorrect interest distributions within the system if these functions are later utilized in new or updated contracts.

04. Impact

Currently, both functions are declared as internal and are not actively used. However, they exist in a core library (ReserveLibrary) and may be incorporated in future protocol updates or external services. If used as-is, the system could miscalculate borrowers’ and depositors’ rates, leading to inconsistent interest accrual and potential financial imbalances.

05. Tools Used

Manual Code Review and Foundry

07. Recommended Mitigation

/**
* @notice Gets the current borrow rate of the reserve.
* @param reserve The reserve data.
* @param rateData The reserve rate parameters.
* @return The current borrow rate (in RAY).
*/
function getBorrowRate(ReserveData storage reserve,ReserveRateData storage rateData) internal view returns (uint256) {
- uint256 totalDebt = getNormalizedDebt(reserve, rateData);
+ uint256 totalDebt = reserve.totalUsage
uint256 utilizationRate = calculateUtilizationRate(reserve.totalLiquidity, totalDebt);
return calculateBorrowRate(rateData.primeRate, rateData.baseRate, rateData.optimalRate, rateData.maxRate, rateData.optimalUtilizationRate, utilizationRate);
}
/**
* @notice Gets the current liquidity rate of the reserve.
* @param reserve The reserve data.
* @param rateData The reserve rate parameters.
* @return The current liquidity rate (in RAY).
*/
function getLiquidityRate(ReserveData storage reserve,ReserveRateData storage rateData) internal view returns (uint256) {
+ uint256 currentUsageRate = getBorrowRate()
- uint256 totalDebt = getNormalizedDebt(reserve, rateData);
+ uint256 totalDebt = reserve.totalUsage
uint256 utilizationRate = calculateUtilizationRate(reserve.totalLiquidity, totalDebt);
- return calculateLiquidityRate(utilizationRate, rateData.currentUsageRate, rateData.protocolFeeRate, totalDebt);
+ return calculateLiquidityRate(utilizationRate, currentUsageRate, rateData.protocolFeeRate, totalDebt);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 2 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
inallhonesty Lead Judge about 2 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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