Core Contracts

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

Unrepayable Interest Debt Due to Incorrect Burn Implementation

Summary

The DebtToken.sol's burn function only reduces the base debt while ignoring accrued interest, leading to a situation where users cannot fully repay their debt. Once the base debt becomes zero, the remaining interest becomes permanently unrepayable, creating bad debt for the protocol.

Vulnerability Details

The vulnerability exists in the burn function:

function burn(address from, uint256 amount, uint256 index) external {
uint256 userBalance = balanceOf(from); // Shows full debt (base + interest)
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);
amount = amount; // no-op, interest is calculated but never used
}
if(amount > userBalance){
amount = userBalance;
}
_burn(from, amount.toUint128()); // Only burns base debt
}

The issue manifests in three key components:

  • Interest Calculation:
    The function calculates interest (balanceIncrease) but never uses it

  • The no-op line amount = amount suggests missing interest handling logic

  • Debt Display vs Reality:
    balanceOf() shows the full debt (base * index)
    But burn() only reduces the base debt
    Creates a mismatch between displayed and burnable debt

  • Unrepayable State:

    function balanceOf(address account) returns (uint256) {
    uint256 scaledBalance = super.balanceOf(account); // If 0, interest can't be paid
    return scaledBalance.rayMul(ILendingPool(_reservePool).getNormalizedDebt());

}

  • When base debt becomes 0:

  • balanceOf returns 0 (0 * any_index = 0)

  • Interest debt becomes invisible and unrepayable

  • Further interest may still accrue but can never be paid

Impact

  • Protocol Level:
    Accumulation of bad debt
    Inaccurate total debt accounting
    Potential protocol insolvency
    Affects liquidation calculations

  • User Level:
    Unable to fully repay debts
    Trapped in debt positions
    Multiple transactions needed for partial repayments

  • Economic:
    Interest keeps accruing on unpayable debt
    Protocol's economic model becomes unsustainable
    Potential for strategic defaults

Tools Used

  • Manual code review

Recommendations

  • Fix Interest Handling:

function burn(
address from,
uint256 amount,
uint256 index
) external override onlyReservePool returns (uint256, uint256, uint256, uint256) {
uint256 userBalance = balanceOf(from);
uint256 scaledBalance = super.balanceOf(from);
uint256 balanceIncrease = 0;
if (_userState[from].index != 0 && _userState[from].index < index) {
uint256 borrowIndex = ILendingPool(_reservePool).getNormalizedDebt();
balanceIncrease = scaledBalance.rayMul(borrowIndex - _userState[from].index);
amount += balanceIncrease; // Add accrued interest to burn amount
}
_userState[from].index = index.toUint128();
uint256 amountScaled = amount.rayDiv(index);
_burn(from, amountScaled.toUint128()); // Burn scaled amount
emit Burn(from, amount, index);
return (amountScaled, totalSupply(), amount, balanceIncrease);
}
Updates

Lead Judging Commences

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

DebtToken::burn incorrectly burns amount (asset units) instead of amountScaled (token units), breaking token economics and interest-accrual mechanism

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

DebtToken::burn incorrectly burns amount (asset units) instead of amountScaled (token units), breaking token economics and interest-accrual mechanism

Support

FAQs

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

Give us feedback!