The DebtToken.mint() function incorrectly inflates user debt by double-counting accrued interest since the last borrowing action when minting debt tokens. Specifically, the function adds balanceIncrease to amountToMint, causing users to receive more debt tokens than intended. This artificially increases the user’s outstanding debt, leading to excessive interest accrual and unfairly higher repayments over time. The issue worsens exponentially as interest compounds on an already inflated debt balance.
balanceOf() in DebtToken.sol already applies interest scaling using rayMul(reserve.usageIndex), meaning that the returned balance includes all accumulated interest since the last borrowing action associated with the accumulatively minted debt tokens:
balanceIncrease is calculated based on balanceOf() multiplied by the delta of indices, so it already reflects the accrued interest since the last mint. It's meant merely to be emitted for this specifically additional info.
However, instead of minting only amount, the function adds balanceIncrease to amountToMint, artificially increasing the user's debt balance.
But fortunately, user.scaledDebtBalanc is incremented with scaledAmount, i.e. amount.rayDiv(reserve.usageIndex) instead of amountMinted (matched by amountToMint):
Here's the first issue. When user attempting to make a full repayment, they will simply input an arbitrarily big amount (similar to some other protocol logic that will have an input amount of type(unit256).max) since it's going to be capped here:
So, amountScaled is going to match up with amountBurned and then deducted from user.scaledDebtBalance:
As expected, it's going to incur an underflow revert.
The next issue will be more pronounced. This is because debt token totalSupply() is also inflated by balanceIncrease. As such, reserve.totalUsage as assigned by it via the returned newTotalSupply when borrowing,
is going affect the calculation when ReserveLibrary.updateInterestRatesAndLiquidity() is invoked at the end of the borrow logic:
calculateUtilizationRate() is going to return a larger utilizationRate than intended and correspondingly render rateData.currentUsageRate, rateData.currentLiquidityRate larger than expected:
In the end, reserve.liquidityIndex and reserve.usageIndex (the frequently referenced indices) will be calculated larger than expected too.
Borrowers are minted excessive debt tokens when multiple mintings of debt tokens are involved at different time, rendering likely revert when making full repayment that will be crucial in timing to close a liquidation.
This issue increases systemic debt while over benefiting the lenders due to the inflated indices, potentially making loans unrepayable, prone to liquidation, and destabilizing the lending/borrowing market.
Note: The only way a user could avoid such issue is borrowing the second time or subsequently using a different and new address, albeit with another set of NFTs needed as collateral.
Manual
Consider making the following refactoring:
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.