Summary
RAACMinter manage RAAC emission based on utilization ratio but in calculation normalizedDebt is used instead of totalUsage
Vulnerability Details
RAACMinter contract manages emission rate based on the utilization ratio. you can see that in calculateNewEmissionRate which is called from updateEmissionRate .
function calculateNewEmissionRate() internal view returns (uint256) {
@-> uint256 utilizationRate = getUtilizationRate();
uint256 adjustment = (emissionRate * adjustmentFactor) / 100;
if (utilizationRate > utilizationTarget) {
uint256 increasedRate = emissionRate + adjustment;
uint256 maxRate = increasedRate > benchmarkRate ? increasedRate : benchmarkRate;
return maxRate < maxEmissionRate ? maxRate : maxEmissionRate;
} else if (utilizationRate < utilizationTarget) {
uint256 decreasedRate = emissionRate > adjustment ? emissionRate - adjustment : 0;
uint256 minRate = decreasedRate < benchmarkRate ? decreasedRate : benchmarkRate;
return minRate > minEmissionRate ? minRate : minEmissionRate;
}
return emissionRate;
}
If we look at the getUtilizationRate function
* @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;
}
Here code is basically trying to get the ratio between totalDeposits and total borrowed funds and convert it to % terms.
totalBorrowed is using getNormalizedDebt which is just a borrow interest and not the whole borrowed amount. because of this, the calculation here is wrong.
* @notice Gets the reserve's normalized debt
* @return The normalized debt (usage index)
*/
function getNormalizedDebt() external view returns (uint256) {
return reserve.usageIndex;
}
The correct calculation for utilization rate can be found in ReserveLibrary:updateInterestRatesAndLiquidity where totalUsage is used instead of normalized debt.
uint256 utilizationRate = calculateUtilizationRate(
reserve.totalLiquidity,
reserve.totalUsage
);
Impact
Incorrect utilization will lead to the incorrect reward emission, which will be 0 in most cases or way lower than expected
Recommendations
use totalUsage instead of usageIndex from getNormalizedDebt