Core Contracts

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

Debt Accrual Logic Overstates User Debt

Summary

The mint function in the DebtToken contract incorrectly adds the balance increase (accrued interest) to the amountToMint, which results in overstated user debt. This is because the user's debt balance is already updated by the index increase . The amountToMint should only include the principal amount being borrowed, not the accrued interest. This flaw leads to incorrect debt calculations and could cause users to owe more than they should.

Vulnerability Details

The mint function calculates the balanceIncrease (accrued interest) as:

uint256 balanceIncrease = 0;
if (_userState[onBehalfOf].index != 0 && _userState[onBehalfOf].index < index) {
balanceIncrease = scaledBalance.rayMul(index) - scaledBalance.rayMul(_userState[onBehalfOf].index);
}
_userState[onBehalfOf].index = index.toUint128();
uint256 amountToMint = amount + balanceIncrease;
_mint(onBehalfOf, amountToMint.toUint128());

The user's debt balance is already updated by the index changes when balanceOf is called. The balanceIncrease is already reflected in the scaled balance. By adding the balanceIncrease to the amountToMint, the user's debt is double-counted, leading to an overstated debt balance.

it("should show user dept is higher than it should be", async function () {
// @audit user borrow 100 ether
const mintAmount = ethers.parseEther("100");
const index1 = ethers.getBigInt("1000000000000000000000000000"); // 1e27
const index2 = ethers.getBigInt("1100000000000000000000000000"); // 1.1 RAY
await mockLendingPool.setNormalizedDebt(index1); // Set initial normalized debt to 1
const tx = await debtToken.connect(mockLendingPoolSigner).mint(user1.address, user1.address, mintAmount, index1);
const receipt = await tx.wait();
const balance = await debtToken.balanceOf(user1.address);
console.log("User balance after mint:", balance.toString());
expect(balance).to.equal(mintAmount);
//@audit increase index to 1.1 RAY and check if user's debt is higher
await mockLendingPool.setNormalizedDebt(index2); // Set initial normalized debt to 1
//@audit user dept should be %10 higher
const balance2 = await debtToken.balanceOf(user1.address);
console.log("User balance after mint:", balance2.toString());
expect(balance2).to.equal(mintAmount * 11n / 10n);
const tx2 = await debtToken.connect(mockLendingPoolSigner).mint(user1.address, user1.address, mintAmount, index2);
const receipt2 = await tx2.wait();
//@audit total dept should be 100 + 10 + 100 (new mint) but it is higher
const balance3 = await debtToken.balanceOf(user1.address);
console.log("User balance after mint:", balance3.toString());
expect(balance3).to.greaterThan(mintAmount * 11n / 10n + mintAmount);
// @audit new dept is : 221000000000000000000
// @audit it should be: 220000000000000000000
});

Impact

Users will owe more than they should because the accrued interest is added twice

Tools Used

Manual

Recommendations

The amountToMint should only include the principal amount (amount), not the accrued interest (balanceIncrease)

Updates

Lead Judging Commences

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

DebtToken::mint miscalculates debt by applying interest twice, inflating borrow amounts and risking premature liquidations

Support

FAQs

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