Whenever a user borrow() an amount of liquidity against their NFT collateral, and it's not their first time borrowing, they will be charged more interest due to an error in the way that the usage index is used in the mint() function of DebtToken.
The idea of an index-based system is to keep track of the interest accrued by a token via an index variable, this variable is updated before performing any operation with the token in order to account for the new interest.
With the implementation used, both DebtToken and RToken use this approach, the former to account for the interest accrued by the user towards the pool and the later from the pool to the user. In both cases a token trades 1:1 with their underlying at all times, ie to pay a debt of 1 DebtToken the user needs to provide 1 unit of the underlying asset.
The issue here is that the mint() function tries to perform the job already done by the index and adds increaseBalance to the amount to mint.
However this amount is already accounted for by the change in index, which is applied by multiplying the stored balance (which is index-agnostic since it's stored after being divided by the index in _update()) with the current index.
This only happens after the first mint by the user and if there's been an index change since the last mint, as shown by the condition _userState[onBehalfOf].index != 0 && _userState[onBehalfOf].index < index.
The increaseBalance variable doubles up on the adjustment performed by the index, increasing the amount of DebtToken per mint() beyond what's expected by the user, saddling them with unexpected debt and making the protocol less trustworthy and appealing to the participants.
Manual review.
The elegant solution is to clean-up the code by deleting all uses of the userState struct since it's only used to keep track of the index and to erroneously increase the debt balance as outlined.
The easiest solution is just to delete the line of code uint256 amountToMint = amount + balanceIncrease; and just using _mint(onBehalfOf, amount.toUint128()); instead of amountToMint.
As can be seen in the snippet, after the first mint, the interest is immediately charged for the second mint, making it impossible to immediately repay the debt without incurring any penalty. The longer the time between any two mints, the higher this value will be making it even more problematic.
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.