When the borrowers borrows reserveAssets via borrow function, they are minted with debtTokens and when the borrowes decide to repay their loan, those debtTokens minted at the time of borrow are burned and reserveAssets that they borrowed are supposed to be taken back from them with some additional interest accrued on their loan that they are supposed to pay along with the borrowedAmount. However due to flaws in the logic that accrued interest is not charged or taken from them
When the borrowers borrows reserveAssets via borrow function, they are minted with debtTokens and when the borrows decide to repay their loan, those debtTokens minted at the time of borrow are burned and reserveAssets that they borrowed are supposed to be taken back from them with some additional interest accrued on their loan that they are supposed to pay along with the borrowedAmount. This interest that is accrued is computed and accrued accordingly on the basis of a gloabl reserve.usageIndex and the index of the user i.e UserState.index The usageIndex keeps increasing as the liquidity is used from the reserve and based on this some interest is accrued that is supposed to be charged to the borrower at the time of repaying the loan along with borrowed amount. This accrued amount or interest is computed as balanceIncrease here when the DebtToken's burn function is called in the LendingPool's _repay function. Now what the DebtToken.burn function does is that it computes that accrued amount that is to be charged from the borrower as balanceIncrease and along with this the DebtTokens are burned from the borrower that were minted at the time of borrow and after burning the those tokens this function(burn) returns a few things to the LendingPool's _repay function and one of these are the balanceIncrease var i.e the interest that the borrower is supposed to pay along with the amount at the time of repayment. But the issue, here is that this balanceIncrease is computed but when the amount is transferred back from the user to the reserve here in line of code only the amount that was passed in by the user is taken from him and the balanceIncrease that was computed and was supposed to be charged is not included in this transfer. This is very clearly wrong and unexpected behaviour as the borrower just basically got a loan at literally 0 interest. Lets take an example of how much the borrower paid back and how much was supposed to be charged from him. --> lets say that a borrower borrowed 10000e18 crvUsd from the reserve and at that time lets say: usageIndex = 1e27 and UserState.index = 1e27 initially. But time passed and users kept coming and interacting with the LendingPool contract. Now providing that the global reserve.usageIndex is updated everytime a core function of the contract is called, so lets say that when the borrower decided to repay is debt he called the repay function and at that time the usageIndex got to = 1000712723634978242463146739. Now the balIncrease calculation willbe like-: balanceIncrease = userBalance.rayMul(borrowIndex) - userBalance.rayMul(_userState[from].index); the userBal here will be 10000e18 as mentioned above. -> 10000e18.rayMul(1000712723634978242463146739) - 10000e18.rayMul(1e27) = 7127236349782424631(7e18 approx) As can be seen that this is the interest that was accrued over the time but was not charged to the borrower
The impact here is quite good, the reasoning for that is that even though the loss for the protocol is not that much, but still the fact that this is basically a crucial invariant for the protocol, like first of all the borrower gets a loan without any interest which does not make much sense and also the fact that the interest that was accrued was supposed to be for the reserve, and reserve didnt get that because of tis vulnerability and flawed logic.
Manual Review
add the balanceIncrease that was computed in the Debttoken.burn function to the safeTransferFrom function, where the reserve assets are taken back from the user. Like This:-
Interest IS applied through the balanceOf() mechanism. The separate balanceIncrease calculation is redundant/wrong. Users pay full debt including interest via userBalance capping.
Interest IS applied through the balanceOf() mechanism. The separate balanceIncrease calculation is redundant/wrong. Users pay full debt including interest via userBalance capping.
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.