Core Contracts

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

`RAACMinter::updateEmissionRate` function will always increase the emission rate no matter what

Summary

This happens due to the denomination of totalBorrowed variable returned by the getNormalizedDebt function

Vulnerability Details

By investingating the flow of the updateEmissionRate function, we see the it calls the calculateNewEmissionRate function:

function updateEmissionRate() public whenNotPaused {
if (
emissionUpdateInterval > 0 &&
block.timestamp <
lastEmissionUpdateTimestamp + emissionUpdateInterval
) {
revert EmissionUpdateTooFrequent();
}
@> uint256 newRate = calculateNewEmissionRate();
emissionRate = newRate;
lastEmissionUpdateTimestamp = block.timestamp;
emit EmissionRateUpdated(newRate);
}

In its pretty first line, the calculateNewEmissionRate function calls the getUtilizationRate function, that looks like this:

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

The problem here is that the LendingPool::getNormalizedDebt function, returns the usageIndex variable, which is denominated in RAY (27 decimals). This will make the (totalBorrowed * 100) / totalDeposits equation to always return an enormous percentages, which is going to make the calculateNewEmissionRate to increase the emissionRate every time. As can be seen in the RAACMinter:tick function, the emission rate is one of the main components for computing the amount minted for stability pool. This practically means that the users will receive more RAACToken rewards in the `StabilityPool` than they deserve

Impact

Leads to wrong calculations of emission rate, which leads to wrong rewards minted to the `StabilityPool` as can be seen here:

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);
}
}
}

Tools Used

Manual Review

Recommendations

Since the returned value from getTotalDeposits function is 18 decimals, normalise the returned value from getNormalizedDebt to 18 decimals

Updates

Lead Judging Commences

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

Give us feedback!