Closed code423n4 closed 1 year ago
chechu marked the issue as sponsor disputed
We are actually deducted the repayAmount + badDebt from user’s borrow balance. https://github.com/code-423n4/2023-05-venus/blob/8be784ed9752b80e6f1b8b781e2e6251748d0d7e/contracts/VToken.sol#L407 and https://github.com/code-423n4/2023-05-venus/blob/8be784ed9752b80e6f1b8b781e2e6251748d0d7e/contracts/VToken.sol#L416
0xean marked the issue as unsatisfactory: Invalid
Lines of code
https://github.com/code-423n4/2023-05-venus/blob/8be784ed9752b80e6f1b8b781e2e6251748d0d7e/contracts/VToken.sol#L426
Vulnerability details
Impact
TotalBorrowed in VToken is not accounted properly when healAccount() is called.
Proof of Concept
Comptroller#healAccount() intends to forgive the debt of the account if the debt goes far too underwater. When that happens, the collateral is seized, some of the debt is paid off and the rest of the debt is left to become bad debt in the protocol.
Here is the function of healBorrow() in VToken, where all the accounting happens.
When an account is healed, the borrowedAmount from that account should be taken away because it is translated into bad debt. However, the borrowedAmount is not reduced appropriately.
Let's use an example to illustrate the problem clearly.
Let's say user deposits 1000 ABC tokens worth 1000 USD with 60% LTV and 65% liquidation threshold. User borrows a maximum amount of 600 USD worth. A short while later, ABC token crashes by half instantly, and 1000 ABC tokens is now worth 500. The position is now instantly liquitable, but its too far underwater to break even. (500 < 600). Protocol decides to heal the user's account. The 500 worth of collateral of ABC token is seized, and x amount is paid to cover the debt (let's say 450 is paid, but actual calculation is
collateral/(borrows*liquidationIncentive)
). 50 is left to be pocketed, and now the protocol has 600 - 450 = 150 as bad debt. The user's account is remade whole and its borrow position should be 0.In the function healBorrow(), the borrow position is not reset.
accountBorrowsPrev
is the borrow amount of the borrower.totalBorrowsNew
is thetotalBorrows
in the protocol. When account is made whole, the totalBorrows should be subtracted by the accountBorrowPrev. Instead,badDebtDelta
is calculated by subtractingaccountBorrowsPrev
withactualRepayAmount
(600 - 450 = 150 in the example above). Then,totalBorrowsNew
is calculated by subtracting itself frombadDebtDelta
. (Let's saytotalBorrow
in the protocol is 2000, with one person borrowing 1400 and the user borrowing 600) (2000 - 150 = 1850, but it should be 2000 - 600 = 1400)The totalBorrowed should completely subtract the user's borrow because the user's borrow has been translated into bad debt already. When
_borrowBalanceStored()
is called for the user afterhealAccount()
, sinceborrowSnapshot.principal
is set to 0,_borrowBalanceStored()
will return 0 but thetotalBorrow
balance still accounts for the user's previous borrow that has already been forgiven.Tools Used
VSCode
Recommended Mitigation Steps
Recommend removing the total borrows from the user completely from
totalBorrows
variable when the user's account is healed.Assessed type
Math