Core Contracts

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

Unit mismatch in utilization rate calculation leads to incorrect reward distribution

Summary

The RAACMinter::getUtilizationRate() function incorrectly compares a normalized debt index against total deposits amount in StabilityPool, resulting in incorrect emission rate calculations and reward distributions.

Vulnerability Details

The getUtilizationRate() function is designed to calculate system utilization by comparing borrowed amounts to deposited amounts. However, there is a critical unit mismatch in the calculation:

function getUtilizationRate() internal view returns (uint256) {
uint256 totalBorrowed = lendingPool.getNormalizedDebt(); // Returns an index
uint256 totalDeposits = stabilityPool.getTotalDeposits(); // Returns token amount
if (totalDeposits == 0) return 0;
return (totalBorrowed * 100) / totalDeposits;
}

The issue arises because:

  1. getNormalizedDebt() returns a normalized debt index used for interest calculations

  2. getTotalDeposits() returns the actual token amount deposited

  3. These incompatible units are directly compared in the utilization calculation

The less the utilization rate is, the less the emission rate will be.
RaacMinter::calculateNewEmissionRate():

function calculateNewEmissionRate() internal view returns (uint256) {
uint256 utilizationRate = getUtilizationRate();
uint256 adjustment = (emissionRate * adjustmentFactor) / 100;
if (utilizationRate > utilizationTarget) { have more utilization
uint256 increasedRate = emissionRate + adjustment;
uint256 maxRate = increasedRate > benchmarkRate ? increasedRate : benchmarkRate;
return maxRate < maxEmissionRate ? maxRate : maxEmissionRate;
@> } else if (utilizationRate < utilizationTarget) { //* We decrease the emissionRate if we don't have enough utilization
uint256 decreasedRate = emissionRate > adjustment ? emissionRate - adjustment : 0;
uint256 minRate = decreasedRate < benchmarkRate ? decreasedRate : benchmarkRate;
return minRate > minEmissionRate ? minRate : minEmissionRate;
}
return emissionRate;
}

Which will also lead to less rewards being minted for the depositors in the StabilityPool.

RaacMinter::tick():

function tick() external nonReentrant whenNotPaused {
if (emissionUpdateInterval == 0 || block.timestamp >= lastEmissionUpdateTimestamp + emissionUpdateInterval) {
updateEmissionRate();
}
uint256 currentBlock = block.number;
uint256 blocksSinceLastUpdate = currentBlock - lastUpdateBlock;
if (blocksSinceLastUpdate > 0) {
@> uint256 amountToMint = emissionRate * blocksSinceLastUpdate;
if (amountToMint > 0) {
excessTokens += amountToMint;
lastUpdateBlock = currentBlock;
raacToken.mint(address(stabilityPool), amountToMint);
emit RAACMinted(amountToMint);
}
}
}

Proof of Concept

  1. Assume the lending pool has a normalized debt index of 1.5e18 (representing 150% interest accrual)

  2. The stability pool has 1000e18 tokens deposited

  3. Current calculation: (1.5e18 * 100) / 1000e18 = 0.15%

  4. This severely understates the actual utilization rate, which should be based on borrowed amounts

Impact

  • Incorrect utilization rate calculations lead to wrong emission rate adjustments, which will lead to wrong amount of rewards minted for the depositors in the StabilityPool.

  • Users will receive less rewards then they should, because the total supply of the DebtToken is much larger than the usage index.

Recommendations

Use the total supply of the DebtToken, instead of the usage index.

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

Note that this fix might require updates in some interfaces.

Updates

Lead Judging Commences

inallhonesty Lead Judge 6 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 6 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.