Core Contracts

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

Incorrect Debt Burning in DebtToken

Summary

The DebtToken's burn function incorrectly compares unscaled amount with scaled userBalance, leading to insufficient debt burning and allowing users to escape full debt repayment.

Vulnerability Details

In burn, amount is capped to userBalance but uses unscaled values, potentially under-burning.

DebtToken.sol#burn

DebtToken.sol#balanceOf

function burn(
address from,
uint256 amount,
uint256 index
) external override onlyReservePool returns (uint256, uint256, uint256, uint256) {
// Input validation
if (from == address(0)) revert InvalidAddress();
if (amount == 0) {
return (0, totalSupply(), 0, 0);
}
// Get current user balance
uint256 userBalance = balanceOf(from);
// Calculate balance increase from index changes
uint256 balanceIncrease = 0;
if (_userState[from].index != 0 && _userState[from].index < index) {
uint256 borrowIndex = ILendingPool(_reservePool).getNormalizedDebt();
balanceIncrease = userBalance.rayMul(borrowIndex) - userBalance.rayMul(_userState[from].index);
}
// Update user's index
_userState[from].index = index.toUint128();
// Cap burn amount to user balance
if(amount > userBalance){
amount = userBalance;
}
// Scale amount by current index
uint256 amountScaled = amount.rayDiv(index);
// Validate scaled amount
if (amountScaled == 0) revert InvalidAmount();
// Perform burn
_burn(from, amount.toUint128());
emit Burn(from, amountScaled, index);
return (amount, totalSupply(), amountScaled, balanceIncrease);
}
function balanceOf(address account) public view override returns (uint256) {
uint256 scaledBalance = super.balanceOf(account);
return scaledBalance.rayMul(ILendingPool(_reservePool).getNormalizedDebt());
}

Path:

  1. User has 100 scaled debt tokens (200 actual debt)

  2. Attempts to burn 150 tokens

  3. Comparison uses unscaled values

  4. Burns less than required debt

  5. Debt remains partially unpaid

Impact

Users may not repay full debt, causing bad debt accumulation.

Tools Used

manual

Recommendations

Ensure userBalance reflects the scaled value with the latest index.

function burn(address account, uint256 amount) external onlyOwner {
// Get normalized debt index from lending pool
uint256 debtIndex = ILendingPool(_reservePool).getNormalizedDebt();
// Scale amount to internal accounting units
uint256 scaledAmount = amount.rayDiv(debtIndex);
// Get user's scaled balance
uint256 scaledBalance = super.balanceOf(account);
// Calculate correct burn amount in scaled terms
uint256 burnAmount = scaledAmount > scaledBalance ? scaledBalance : scaledAmount;
// Burn the scaled amount
_burn(account, burnAmount);
emit DebtBurned(account, amount, burnAmount);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

DebtToken::burn caps amount to userBalance but internal _update applies further scaling, causing transaction reverts when burning full balances and breaking repayment/liquidation

The amount and userBalance are both in actual debt units, making the comparison valid. No reverts occur - the burn function works as intended by burning the correct scaled amount from storage.

inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

DebtToken::burn caps amount to userBalance but internal _update applies further scaling, causing transaction reverts when burning full balances and breaking repayment/liquidation

The amount and userBalance are both in actual debt units, making the comparison valid. No reverts occur - the burn function works as intended by burning the correct scaled amount from storage.

Support

FAQs

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