Core Contracts

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

Borrowers can't ever fully repay their loans

Summary

Due to a logic error, users will still have scaledDebtBalance despite burning all of their debt tokens.

Details

Assume Alice borrows 100 rTokens at usageIndex = 2
Alice is minted 100 debtTokens, scaledDebtBalance = 100 / 2 = 50
Some time passes, usageIndex = 3 and Alice wants to repay her loan
Alice invokes repay with amount = type(uint256).max
amount is checked against user's total debt balance and capped against it in DebtToken.sol

uint256 userBalance = balanceOf(from);
** SNIP **
if(amount > userBalance){
amount = userBalance;
}

Afterwards the amount is burnt and the method returns some values

uint256 amountScaled = amount.rayDiv(index); // 100 / 3 = ~33.3
if (amountScaled == 0) revert InvalidAmount();
_burn(from, amount.toUint128()); // burn all debt tokens
return (amount, totalSupply(), amountScaled, balanceIncrease);

One of the return values is amountScaled = 100 / 3 = 33,(3) which is the root of the issue.

(uint256 amountScaled, uint256 newTotalSupply, uint256 amountBurned, uint256 balanceIncrease) =
IDebtToken(reserve.reserveDebtTokenAddress).burn(onBehalfOf, amount, reserve.usageIndex);
IERC20(reserve.reserveAssetAddress).safeTransferFrom(msg.sender, reserve.reserveRTokenAddress, amountScaled);
reserve.totalUsage = newTotalSupply;
user.scaledDebtBalance -= amountBurned;

amountScaled is returned in LendingPool as amountBurned and then deducted from user.scaledDebtBalance
However scaledDebtBalance = 50 while amountBurned = 33 - user successfully burnt all of their debt tokens however there is still debt left. User can't repay the rest since there aren't any debt tokens to burn. This debt continues accruing interest which degrades user's health factor which affects future borrows and will lead to liquidation and seize of their collateral even when they have 0 debt tokens.

Impact

Loss of funds, unfair liquidations, broken core functionality

Mitigation

Complete rehaul of the method is needed

Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
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.

LendingPool::borrow tracks debt as user.scaledDebtBalance += scaledAmount while DebtToken mints amount+interest, leading to accounting mismatch and preventing full debt repayment

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
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.

LendingPool::borrow tracks debt as user.scaledDebtBalance += scaledAmount while DebtToken mints amount+interest, leading to accounting mismatch and preventing full debt repayment

Support

FAQs

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

Give us feedback!