Upon mint being called, interest is unnecessarily double counted.
In my opinion the best way to look at this vulnerability is to initially look at how userTotalDebt is calculated. In LendingPool::borrow userTotalDebt is calculated through:
uint256 userTotalDebt = user.scaledDebtBalance.rayMul(reserve.usageIndex) + amount;
Therefore, it is clear that when user debt is calculated, the scaled balance is taken, and then it multiplied by the usage index to accout for interest accrual.
However, the logic in DebtToken::mint contradicts this logic.
https://github.com/Cyfrin/2025-02-raac/blob/main/contracts/core/tokens/DebtToken.sol#L154-L160
This is from DebtToken::mint, this function calculates the balanceIncrease and adds it to amountToMint. The additional minting gives extra debt to the user. This increase should not be added onto amountToMint, this is managed correctly in RToken::mint https://github.com/Cyfrin/2025-02-raac/blob/main/contracts/core/tokens/RToken.sol#L102-L141 but here it is not managed correctly.
Also, this is clearly wrong because this code is inspired by aave v3, and aave is a highly audited protocol that doesn't add the balanceIncrease onto amountToMint. balanceIncrease is only used for events purposes.
Here's aave's code:
Also now just to further make this issue clear, here is an example.
(in the context of calling mint) let:
(parameter) amount = 100e18
scaledBalance = 500e18
index = 1.02e27
_userState[onBehalfOf].index = 1.01e27
balanceIncrease = 500e18.rayMul(1.02e27) - 500e18.rayMul(1.01e27) = 5e18
amountToMint = 100e18 + 5e18 = 105e18
_mint(msg.sender, 105e18)
now the msg.sender has a balance of 605e18
Then during this calculation in LendingPool::borrow:
uint256 userTotalDebt = user.scaledDebtBalance.rayMul(reserve.usageIndex) + amount;
Ignoring the additional amount variable the 500e18 scaledBalance value is scaled in this function too with the most recent reserve.usageIndex value, therefore, the debt is double counted due to:
the scaling here with the usage index
the balanceIncrease being added through the mint function
As a result, userTotalDebt is higher than it should be, preventing users from borrowing as much as they should be entitled to, or even resulting in early unfair liquidations and a loss of user funds.
Depositors have less ability to borrow against their nft due to their increased debt balance. Here is where the borrows would be prevented (LendingPool::borrow).
Manual review
Don't add the balanceIncrease to amountToMint, alike what is done in RToken::mint.
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.