Core Contracts

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

`DebtToken::burn` accounts wrong interest and burns wrong amount

Summary

In the flow LendingPool::_repay the function calls DebtToken::burn. This function contains two issues in handling debt repayment:

  • interest accrual is not properly added to the repayment amount due to a redundant assignment (amount = amount)

  • the function burns the non-scaled amount instead of the scaled amount

leading to incorrect debt accounting.

Vulnerability Details

function burn(
address from,
uint256 amount,
uint256 index
) external override onlyReservePool returns (uint256, uint256, uint256, uint256) {
if (from == address(0)) revert InvalidAddress();
if (amount == 0) {
return (0, totalSupply(), 0, 0);
}
uint256 userBalance = balanceOf(from);
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;
}
_userState[from].index = index.toUint128();
if(amount > userBalance){
amount = userBalance;
}
uint256 amountScaled = amount.rayDiv(index);
if (amountScaled == 0) revert InvalidAmount();
@> _burn(from, amount.toUint128());
emit Burn(from, amountScaled, index);
return (amount, totalSupply(), amountScaled, balanceIncrease);
}

Impact

The burn function miss to add balanceIncrease to amount, causing accrued interest to be ignored. Additionally it uses amount instead of amountScaled causing incorrect token burning.
Users can repay less than their actual debt due to unaccounted interest. The protocol's total debt accounting becomes inaccurate over time.

Tools Used

Manual review

Recommendations

Fix interest accrual calculation and useScaled amount for burning.

function burn(
address from,
uint256 amount,
uint256 index
) external override onlyReservePool returns (uint256, uint256, uint256, uint256) {
if (from == address(0)) revert InvalidAddress();
if (amount == 0) {
return (0, totalSupply(), 0, 0);
}
uint256 userBalance = balanceOf(from);
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 + balanceIncrease;
- amount = amount;
}
_userState[from].index = index.toUint128();
if(amount > userBalance){
amount = userBalance;
}
uint256 amountScaled = amount.rayDiv(index);
if (amountScaled == 0) revert InvalidAmount();
- _burn(from, amount.toUint128());
+ _burn(from, amountScaled.toUint128());
emit Burn(from, amountScaled, index);
return (amount, totalSupply(), amountScaled, balanceIncrease);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

DebtToken::burn calculates balanceIncrease (interest) but never applies it, allowing borrowers to repay loans without paying accrued interest

Interest IS applied through the balanceOf() mechanism. The separate balanceIncrease calculation is redundant/wrong. Users pay full debt including interest via userBalance capping.

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

DebtToken::burn calculates balanceIncrease (interest) but never applies it, allowing borrowers to repay loans without paying accrued interest

Interest IS applied through the balanceOf() mechanism. The separate balanceIncrease calculation is redundant/wrong. Users pay full debt including interest via userBalance capping.

Support

FAQs

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

Give us feedback!