Core Contracts

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

`DebtToken::burn()` event parameters and return values ​​are incorrect

Summary

The DebtToken::burn() function emits incorrect event parameters and returns improperly ordered values, which can lead to inconsistencies in downstream contract logic.

Vulnerability Details

As indicated by the @>1 marker, the function emits the Burn event using amountScaled, while the event documentation specifies that it should emit the amount burned in underlying asset units (amount).

Incorrect Event Emission

// DebtToken::event Burn()
/**
* @notice Emitted when debt tokens are burned
* @param from The address from which tokens are burned
@>1 * @param amount The amount burned (in underlying asset units)
* @param index The usage index at the time of burning
*/
event Burn(address indexed from, uint256 amount, uint256 index);
// DebtToken::burn()
/**
* @notice Burns debt tokens from a user
* @param from The address from which tokens are burned
* @param amount The amount to burn (in underlying asset units)
* @param index The usage index at the time of burning
* @return A tuple containing:
@>2 * - uint256: The amount of scaled tokens burned
* - uint256: The new total supply after burning
@>2 * - uint256: The amount of underlying tokens burned
* - uint256: The balance increase due to interest
*/
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());
@>1 emit Burn(from, amountScaled, index);
@>2 return (amount, totalSupply(), amountScaled, balanceIncrease);
}

Incorrect Return Values

As indicated by @>2, the function returns values in an incorrect order. The contract returns (amount, totalSupply(), amountScaled, balanceIncrease), but in the LendingPool contract, it is expected that amountScaled should be the first return value.

Downstream Impact in LendingPool Contract
The DebtToken::burn() function is invoked in the LendingPool contract, where the order of return values is expected as (amountScaled, newTotalSupply, amountBurned, balanceIncrease), which does not match the actual return order of burn().

Code Snippet from LendingPool

// LendingPool::_repay()
function _repay(uint256 amount, address onBehalfOf) internal {
// SNIP...
@> (uint256 amountScaled, uint256 newTotalSupply, uint256 amountBurned, uint256 balanceIncrease) =
IDebtToken(reserve.reserveDebtTokenAddress).burn(onBehalfOf, amount, reserve.usageIndex);
// SNIP...
}
// LendingPool::finalizeLiquidation()
function finalizeLiquidation(address userAddress) external nonReentrant onlyStabilityPool {
// SNIP...
@> (uint256 amountScaled, uint256 newTotalSupply, uint256 amountBurned, uint256 balanceIncrease) = IDebtToken(reserve.reserveDebtTokenAddress).burn(userAddress, userDebt, reserve.usageIndex);
// SNIP...
}

Impact

Incorrect event emission: The event logs misleading data, as it emits amountScaled instead of amount (which represents the actual amount burned in underlying asset units). This could lead to incorrect accounting in off-chain tracking systems.
Misaligned return values: Functions in LendingPool rely on a specific return order from burn(). Since the actual order is different, it could cause miscalculations or unintended behavior in downstream contract logic.

Tools Used

Manual Review

Recommendations

Update burn() to ensure the event emission and return values match expected behavior.

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);
+ emit Burn(from, amount, index);
- return (amount, totalSupply(), amountScaled, balanceIncrease);
+ return (amountScaled, totalSupply(), amount, balanceIncrease);
}
Updates

Lead Judging Commences

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

DebtToken::burn emits Burn event with scaled amount instead of raw amount, contradicting documentation and causing incorrect off-chain data

DebtToken::burn returns items in the wrong order

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

DebtToken::burn emits Burn event with scaled amount instead of raw amount, contradicting documentation and causing incorrect off-chain data

DebtToken::burn returns items in the wrong order

Support

FAQs

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