The RAACMinter contract is miscalculating the utilization rate and adjusting the emissions incorrectly as a result. This is due to a decimal precision mismatch.
The getUtilizationRate() function calculates the system utilization by dividing the normalized debt (totalBorrowed) by the total deposits. However, there is a unit mismatch: the normalized debt is expressed in ray precision (1e27), while total deposits are in standard token precision (1e18). This mismatch introduces an unintended scaling factor of 1e9, which can significantly skew the computed utilization rate. The miscalculation leads to incorrect emission rate adjustments, adversely affecting the protocol’s token distribution and economic incentives.
Note that this bug can also lead to a computed utilization rate of zero, even when the stability pool has deposits!
The issue arises because totalBorrowed is obtained via lendingPool.getNormalizedDebt(), which returns a value in ray precision (1e27), while totalDeposits is obtained via stabilityPool.getTotalDeposits(), which returns a value in standard token units (1e18). Calculation Issue:
This effectively multiplies the true utilization ratio by 1e9 (since 1e27 / 1e18 = 1e9). This leads to an erroneously inflated (or mis-truncated) utilization rate.
Potential Exploitation: An attacker could manipulate the denominator (for example, by using flash loans to temporarily lower the total deposits) to further skew the utilization calculation. This may result in improper emission rate adjustments, reducing token emissions and adversely affecting the protocol's economic incentives.
Note: We slightly modify the contract in order to be able to see the uint256 utilizationRate used by the calculateNewEmissionRate() in RAACMinter.sol:
Step 1: a) utilizationRate becomes a state variable. Modify calculateNewEmissionsRate() by removing "uint256"
b) calculateNewEmissionRate() is no longer view
Step 2: Add the state variable at the end of storage
Step 3: paste the following test into RAACMinter.test.js and run with:
npx hardhat test test/unit/core/minters/RAACMinter.test.js --show-stack-traces
**Utilization is Higher (or Lower) Than Reality: **If the contract expects 70% usage (0.7 token borrowed / 1 token deposited), it might see 70,000,000,000% instead of 70%. As a result, the RAACMinter incorrectly decides the system is well above its target utilization, so it applies its 5% upward adjustment (or downward, if the mismatch indicates artificially low usage).
**Repeated Misalignment Over Time: **Although each emission rate update is designed to change the rate by only 5%, that 5% can still accumulate across multiple updates. If the protocol frequently re-checks utilization (e.g., once per day), the error continuously nudges the emission rate away from what a correct calculation would produce.
**Economic Incentives Are Distorted: **Because the minter’s core logic (increase or decrease emissions) hinges on whether utilization is above or below the target, a miscalculated utilization can keep the emission rate rising or falling inappropriately. Liquidity providers or other participants may earn rewards higher or lower than intended. This, in turn, can shift user behavior—some might deposit less, or borrow more, because the returns / costs are not in line with the protocol’s intended targets.
Manual review, Hardhat
Standardize Units: Convert either the numerator or denominator so both are in the same unit. For example, if totalBorrowed is in ray (1e27) and totalDeposits is in token units (1e18), divide totalBorrowed by 1e9 before the calculation: solidity Copy uint256 normalizedBorrowed = totalBorrowed / 1e9; return (normalizedBorrowed * 100) / totalDeposits; Alternatively, adjust totalDeposits to ray precision.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.