Core Contracts

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

Incorrect utilization rate calculation due to wrong decimal handling leads to distorted emission rates

Description

The RAACMinter::getUtilizationRate function incorrectly uses LendingPool::getNormalizedDebt which returns a 27-decimals value (reserve.usageIndex) instead of using the 18-decimals reserve.totalUsage value. This results in a miscalculated utilization rate that is orders of magnitude larger than actual borrowing activity, leading to incorrect emission rate adjustments.

Proof of Concept

  1. LendingPool reports normalized debt as 1e27 (RAY) through getNormalizedDebt()

  2. StabilityPool has 100,000e18 deposits (1e23)

  3. Utilization rate calculation becomes: (1e27 / 1e23) = 10,000%

  4. Emission rate adjustments use this inflated utilization rate. For example, in this line, calculated utilizationRate is compared with utilizationTarget (default set to 70) to determine new emission rate

Relevant code snippet:

// RAACMinter.sol
function getUtilizationRate() public view returns (uint256) {
uint256 totalBorrowed = ILendingPool(lendingPool).getNormalizedDebt(); // Returns 27-decimals
uint256 totalDeposits = IStabilityPool(stabilityPool).getTotalDeposits(); // 18-decimals
return (totalBorrowed * 100) / totalDeposits;
}

Test case to demonstrate vulnerability:

In RAACMinter.test.js, add this test and run npx hardhat test --grep "should show incorrect utilization due to decimal mismatch"

// test/unit/core/minters/RAACMinter.test.js
it("should show incorrect utilization due to decimal mismatch", async function () {
// Setup deposits first
await stabilityPool.mockGetTotalDeposits(ethers.parseEther("100000"));
// Setup borrowed amount (1 RAY = 1e27 wei)
await lendingPool.mockGetNormalizedDebt(10n ** 27n); // 1 RAY
const reportedBorrowed = await lendingPool.getNormalizedDebt();
const totalDeposits = await stabilityPool.getTotalDeposits();
const utilization = (reportedBorrowed * 100n) / totalDeposits;
// (1e27 * 100) / 1e23 = 1e6 (1,000,000%)
expect(utilization).to.equal(1000000n);
});

Impact

High severity. The emission rate calculations for RAAC tokens become fundamentally incorrect, leading to unbounded token inflation if utilization appears permanently high. This disrupts the protocol's core tokenomics and economic incentives.

Recommendation

  • Use correct borrowing metric:

- uint256 totalBorrowed = ILendingPool(lendingPool).getNormalizedDebt();
+ uint256 totalBorrowed = ILendingPool(lendingPool).totalUsage();
  • Add explicit interface for total usage:

// LendingPool.sol
function getTotalUsage() external view returns (uint256) {
return reserve.totalUsage;
}
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.