Bad debt liquidation simply Ignores the bad debts of users. This means that this negative margin balance(bad debt) is taken from the other users, however it is not socialized, meaning that the first users to withdraw will be able to do so, but the last users will be unable to withdraw because protocol won't have enough funds. This means that any large bad debt in the market can trigger a bank run with the last users to withdraw losing their funds.
The implementation of tradingAccount.deductAccountMargin()
:
As shown above, deductAccountMargin()
iterates through all of the user's margin types and attempts to deduct orderFee, settlementFee and pnl from the user's account.
It is worth noting that deductAccountMargin()
allows the difference between user's margin and (orderFee + settlementFee + pnl) to be skipped - if the user's available margin is insufficient to cover all three charges, then the function will exit normally and return the value of total margin deducted. In other words, the user's negative margin is directly zeroed out.
Consider the following scenario:
User1 and User2 are the only makers in the market each with maker=50 position and each with collateral=500. (price=$100)
A new user comes into the market and opens long=10 position with collateral=10.
Price drops to $90. Some liquidator liquidates the user, taking $10 liquidation fee. User is now left with the negative collateral = -$100
Since User1 and User2 were the other party for the user, each of them has a profit of $50 (both users have collateral=550)
At this point protocol has total funds from deposit of User1($500) + User2($500) + new user($10) - liquidator($10) = $1000. However, User1 and User2 have total collateral of 1100.
User1 closes position and withdraws $550. This succeeds. Protocol now has only $450 funds remaining and 550 collateral owed to User2.
User2 closes position and tries to withdraw $550, but fails, because protocol doesn't have enough funds. User2 can only withdraw $450, effectively losing $100.
Since all users know about this feature, after bad debt they will race to be the first to withdraw, triggering a bank run.
Likelihood: medium - such bad debt requires big price shift.
+
Impact: medium - After ANY bad debt, the protocol collateral for all users will be higher than protocol funds available, which can cause a bank run and a loss of funds for the users who are the last to withdraw.
=
Severity: medium
Manual review
When liquidated, if account is left with negative collateral, the bad debt should be added to the opposite position pnl (long position bad debt should be socialized between short position holders) or maybe to makers pnl only (socialized between makers). The account will have to be left with collateral = 0.
Implementation details for such solution can be tricky due to settlement in the future (pnl is not known at the time of liquidation initiation). Possibly a 2nd step of bad debt liquidation should be added: a keeper will call the user account to socialize bad debt and get some reward for this. Although this is not the best solution, because users who close their positions before the keeper socializes the bad debt, will be able to avoid this social loss. One of the solutions for this will be to introduce delayed withdrawals and delayed socialization (like withdrawals are allowed only after 5 oracle rounds and socialization is applied to all positions opened before socialization and still active or closed within 5 last oracle rounds), but it will make protocol much more complicated.
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.