Core Contracts

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

`DebtToken::totalSupply()` incorrectly scales the total supply causing wrong utilization rate and borrow rates calculations

Summary

The DebtToken::totalSupply() function incorrectly scales the total supply using rayDiv instead of rayMul when applying the normalized debt factor. This causes the reported total supply to be significantly lower than the actual value, leading to incorrect utilization rate and borrow rates calculations

Vulnerability Details

The totalSupply() function is implemented as:

function totalSupply() public view override(ERC20, IERC20) returns (uint256) {
uint256 scaledSupply = super.totalSupply();
return scaledSupply.rayDiv(ILendingPool(_reservePool).getNormalizedDebt());
}

The function incorrectly uses rayDiv to scale the total supply with the normalized debt. This is incorrect because the normalized debt factor should multiply the supply to get the actual debt amount, not divide it. This is evident when comparing with the balanceOf() function which correctly uses rayMul:

function balanceOf(address account) public view override(ERC20, IERC20) returns (uint256) {
uint256 scaledBalance = super.balanceOf(account);
return scaledBalance.rayMul(ILendingPool(_reservePool).getNormalizedDebt());
}

The DebtToken::totalSupply() is assigned to the reserve.totalUsage variable in the LendingPool::borrow(), LendingPool::repay() and LendingPool::finalizeLiquidation(). The totalUsage is used to calculate the utilization rate which is used to calculate the borrow rate in ReserveLibrary::updateInterestRatesAndLiquidity().

Impact

The incorrect scaling leads to:

  • Significantly understated total debt supply

  • Wrong utilization rate calculations since total usage is derived from total supply

  • Incorrect borrow rates as they depend on utilization rate

This is a high severity issue because it directly affects core protocol economics and could lead to significant financial losses through incorrect interest rate calculations.

Tools Used

Manual Review

Proof of Concept

Add the following test case to the test/unit/core/tokens/DebtToken.test.js file:

it("totalSupply() is not scaled correctly by normalized debt", async function () {
const mintAmount = ethers.parseEther("100");
const index = RAY; // Initial index
await debtToken.connect(mockLendingPoolSigner).mint(user1.address, user1.address, mintAmount, index);
{
const balance = await debtToken.balanceOf(user1.address);
const totalSupply = await debtToken.totalSupply();
expect(balance).to.equal(mintAmount);
expect(balance).to.equal(totalSupply);
}
const newIndex = RAY * 11n / 10n; // 1.1 RAY = 10% increase
// Setting new normalized debt
await mockLendingPool.setNormalizedDebt(newIndex);
{
const userBalance = await debtToken.balanceOf(user1.address);
const expectedBalance = mintAmount * newIndex / RAY;
const totalSupply = await debtToken.totalSupply();
expect(userBalance).to.equal(expectedBalance);
// Should be the same but totalSupply is smaller because not correctly scaled by normalized debt
expect(userBalance).to.not.equal(totalSupply);
}
});

Recommendations

Change rayDiv to rayMul in the totalSupply() function:

function totalSupply() public view override(ERC20, IERC20) returns (uint256) {
uint256 scaledSupply = super.totalSupply();
- return scaledSupply.rayDiv(ILendingPool(_reservePool).getNormalizedDebt());
+ return scaledSupply.rayMul(ILendingPool(_reservePool).getNormalizedDebt());
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

DebtToken::totalSupply incorrectly uses rayDiv instead of rayMul, severely under-reporting total debt and causing lending protocol accounting errors

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

DebtToken::totalSupply incorrectly uses rayDiv instead of rayMul, severely under-reporting total debt and causing lending protocol accounting errors

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.