Core Contracts

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

Incorrect Utilization Rate Calculation Leads to Much Reduced Emissions

Summary

The getUtilizationRate() function in RAACMinter.sol incorrectly calculates the system’s utilization rate by assigning totalBorrowed to lendingPool.getNormalizedDebt(), which only represents the reserve's usage index, not the actual total debt borrowed. This leads to an highly underestimated utilization rate, resulting in incorrect emissions calculations and misallocated rewards.

Vulnerability Details

The function currently sets totalBorrowed as lendingPool.getNormalizedDebt():

RAACMinter.sol#L237-L246

/**
* @dev Calculates the current system utilization rate
* @return The utilization rate as a percentage (0-100)
*/
function getUtilizationRate() internal view returns (uint256) {
uint256 totalBorrowed = lendingPool.getNormalizedDebt();
uint256 totalDeposits = stabilityPool.getTotalDeposits();
if (totalDeposits == 0) return 0;
return (totalBorrowed * 100) / totalDeposits;
}

However, lendingPool.getNormalizedDebt() only returns reserve.usageIndex, which is a scaling factor, not the actual borrowed amount:

LendingPool.sol#L610

/**
* @notice Gets the reserve's normalized debt
* @return The normalized debt (usage index)
*/
function getNormalizedDebt() external view returns (uint256) {
return reserve.usageIndex;
}

Consequently, the numerator, (totalBorrowed * 100) in the returned value is very much diminished and leads to a dwarfed emisionRate in calculateNewEmissionRate().

In the end, amountToMint to stabilityPool is so much diminished with very little RAAC rewards to distribute to the rToken depositors.

RAACMinter.sol#L265-L274

if (blocksSinceLastUpdate > 0) {
uint256 amountToMint = emissionRate * blocksSinceLastUpdate;
if (amountToMint > 0) {
excessTokens += amountToMint;
lastUpdateBlock = currentBlock;
raacToken.mint(address(stabilityPool), amountToMint);
emit RAACMinted(amountToMint);
}
}

Impact

Since totalBorrowed is not properly scaled, the reported utilization rate is artificially lower than reality. This results in lower-than-expected rewards for rToken stakers in Stability Pool. The RAAC token incentives fail to properly incentivize participation, leading to a less attractive rToken locking. As such, more lenders will be prone to withdrawing their rTokens from LendingPool.sol, leading to less reserve token liquidity for lending.

Tools Used

Manual

Recommendations

Consider making the following refactoring making sure the actualDebt is proportionately calculated:

RAACMinter.sol#L241-L246

function getUtilizationRate() internal view returns (uint256) {
- uint256 totalBorrowed = lendingPool.getNormalizedDebt();
uint256 totalDeposits = stabilityPool.getTotalDeposits();
+ uint256 actualDebt = ((lendingPool.reserve.totalUsage * totalDeposits) / lendingPool.reserve.reserveRTokenAddress.totalSupply()).rayMul(lendingPool.getNormalizedDebt());
+ uint256 totalBorrowed = actualDebt;
if (totalDeposits == 0) return 0;
return (totalBorrowed * 100) / totalDeposits;
}
Updates

Lead Judging Commences

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

RAACMinter::getUtilizationRate incorrectly mixes stability pool deposits with lending pool debt index instead of using proper lending pool metrics

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

RAACMinter::getUtilizationRate incorrectly mixes stability pool deposits with lending pool debt index instead of using proper lending pool metrics

Support

FAQs

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