Core Contracts

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

`DebtToken::burn` is burning the wrong amount

Summary

When users repay their debt, an equivalent of DebtToken is burned. But the current implementation does not factor in the borrow rate which increases their debt over time, and simply erase it.

Vulnerability details

Every time the DebtToken::burn function is called, the balance increase due to the borrow rate (represented by the index) is computed as balanceIncrease. This value should be added to the user total debt, which is in fact the user balance of DebtToken

But this value balanceIncrease is never used and registered in the user debt balance, neither in the DebtToken::burn function or in the calling functions LendingPool::_repay or LendingPool::finalizeLiquidation

If we check the burn function, wee see L196 that balanceIncrease is computed from last user index and current index, then L200 the user index is updated to the current index.

But then, the burnt amount L210 is based solely on the amount repaid, and does not factor in the new debt relative to the borrowing rate:

File: contracts/core/tokens/DebtToken.sol
181: function burn(
182: address from,
183: uint256 amount,
184: uint256 index
185: ) external override onlyReservePool returns (uint256, uint256, uint256, uint256) {
186: if (from == address(0)) revert InvalidAddress();
187: if (amount == 0) {
188: return (0, totalSupply(), 0, 0);
189: }
190:
191: uint256 userBalance = balanceOf(from); // scaled balance
192:
193: uint256 balanceIncrease = 0;
194: if (_userState[from].index != 0 && _userState[from].index < index) {
195: uint256 borrowIndex = ILendingPool(_reservePool).getNormalizedDebt();
196: balanceIncrease = userBalance.rayMul(borrowIndex) - userBalance.rayMul(_userState[from].index);
197: amount = amount;
198: }
199:
200: _userState[from].index = index.toUint128();
201:
202: if(amount > userBalance){
203: amount = userBalance;
204: }
205:
206: uint256 amountScaled = amount.rayDiv(index);
207:
208: if (amountScaled == 0) revert InvalidAmount();
209:
210: _burn(from, amount.toUint128());
211: emit Burn(from, amountScaled, index);
212:
213: return (amount, totalSupply(), amountScaled, balanceIncrease);
214: }

Same in the _repay function which only registers the amount relative to the repaid debt.

Impact

Repaying a debt simply erase the debt increase due to the borrow rate, nullifying the borrow rate.

Recommended Mitigation Steps

The increase in debt shouldn't be burned:

function burn(
address from,
uint256 amount,
uint256 index
) external override onlyReservePool returns (uint256, uint256, uint256, uint256) {
//* -------- some code -------- *//
+ uint256 amountToBurn = amount - balanceIncrease;
- _burn(from, amount.toUint128());
+ _burn(from, amountToBurn.toUint128());
emit Burn(from, amountScaled, index);
return (amount, totalSupply(), amountScaled, balanceIncrease);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 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 4 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.