Open sherlock-admin2 opened 5 months ago
1 comment(s) were left on this issue during the judging contest.
takarez commented:
valid: high(7)
Escalate
Invalid (maybe medium if I'm missing something, clearly not high)
Isn't described scenario is just a speculation? Why Alice's long position was not liquidated earlier? Even if price dropped that significant in ~1 minute there is still enough time to liquidate.
Escalate
Invalid (maybe medium if I'm missing something, clearly not high)
Isn't described scenario is just a speculation? Why Alice's long position was not liquidated earlier? Even if price dropped that significant in ~1 minute there is still enough time to liquidate.
You've created a valid escalation!
To remove the escalation from consideration: Delete your comment.
You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final.
The judge should consider whether the scenario or the assumed system state (the value of some variables) described in a report will actually occur or not. This is important.
The scenario described in this report is unlikely to occur. Because Alice's position should have been liquidated before T1, why did it have to wait until bad debts occurred before it was liquidated? If the protocol has only one keeper, then such a scenario may occur when the keeper goes down. However, the protocol has multiple keepers: from third parties and from the protocol itself. It is impossible for all keepers going down.
The issue stands valid and remains high as it leads to a loss of assets for the long traders, as described in the "impact" section of the report.
The scenario is a valid example to demonstrate the issue on hand. The points related to the timing of the liquidation in the escalation are irrelevant, as the bugs will be triggered when liquidation is executed.
Also, we cannot expect the liquidator keeper always to liquidate the accounts before the settled margin falls below zero (bad debt) under all circumstances due to many reasons (e.g., the price dropped too fast, delay due to too many TX queues at sequencer, time delay between the oracle and market price)
The scenario where the settled margin falls below zero (bad debt) is absolutely something that will happen in the real world. In the code of the liquidation function here, even the protocol expected that the settled margin could fall below zero (bad debt) under some conditions and implement logic to handle this scenario.
// If the settled margin is -ve then the LPs have to bear the cost.
// Adjust the stable collateral total to account for user's profit/loss and the negative margin.
// Note: We are adding `settledMargin` and `profitLoss` instead of subtracting because of their sign (which will be -ve).
vault.updateStableCollateralTotal(settledMargin - positionSummary.profitLoss);
#
Would like sponsors to comment on this issue @D-Ig @itsermin @rashtrakoff – is it unintended? @nevillehuang any thoughts?
Given that this occurs on accrual of bad debt, I think it should be classified at most as a Medium severity issue.
The old math (that is math being used in the audit version of contracts) had this side effect. The new math fixes this along with other issues.
Thank you @rashtrakoff.
Planning to accept the escalation and consider this a Medium severity issue.
Thank you @rashtrakoff.
Planning to accept the escalation and consider this a Medium severity issue.
Agree to downgrade to medium severity
Result: Medium Unique
The protocol team fixed this issue in PR/commit https://github.com/dhedge/flatcoin-v1/pull/266.
The Lead Senior Watson signed off on the fix.
xiaoming90
high
Losses of some long traders can eat into the margins of others
Summary
The losses of some long traders can eat into the margins of others, resulting in those affected long traders being unable to withdraw their margin and profits, leading to a loss of assets for the long traders.
Vulnerability Detail
At $T0$, the current price of ETH is \$1000 and assume the following state:
Margin = 3 ETH
Last Price (entry price) = \$1000
Margin = 5 ETH
Last Price (entry price) = \$1000
stableCollateralTotal
will be 12 ETHGlobalPositions.marginDepositedTotal
will be 8 ETH (3 + 5)globalPosition.sizeOpenedTotal
will be 12 ETH (6 + 6)As this is a perfectly hedged market, the accrued fee will be zero, and ignored in this report for simplicity's sake.
At $T1$, the price of the ETH drops from \$1000 to \$600. At this point, the settle margin of both long positions will be as follows:
PnL = (Position Size priceShift) / Current Price = (6 ETH -\$400) / \$400 = -4 ETH
settleMargin = marginDeposited + PnL = 3 ETH + (-4 ETH) = -1 ETH
settleMargin = marginDeposited + PnL = 5 ETH + (-4 ETH) = 1 ETH
Alice's long position is underwater (settleMargin < 0), so it can be liquidated. When the liquidation is triggered, it will internally call the
updateGlobalPositionData
function. Even if the liquidation does not occur, any of the following actions will also trigger theupdateGlobalPositionData
function internally:The purpose of the
updateGlobalPositionData
function is to update the global position data. This includes getting the total profit loss of all long traders (Alice & Bob), and updating the margin deposited total + stable collateral total accordingly.Assume that the
updateGlobalPositionData
function is triggered by one of the above-mentioned functions. Line 179 below will compute the total PnL of all the opened long positions.The
profitLossTotal
is -8 ETH. This is aligned with what we have calculated earlier, where Alice's PnL is -4 ETH and Bob's PnL is -4 ETH (total = -8 ETH loss).At Line 184 below, the
newMarginDepositedTotal
will be set to as follows (ignoring the_marginDelta
for simplicity's sake)What happened above is that 8 ETH collateral is deducted from the long traders and transferred to LP. When
newMarginDepositedTotal
is zero, this means that the long trader no longer owns any collateral. This is incorrect, as Bob's position should still contribute 1 ETH remaining margin to the long trader's pool.Let's review Alice's Long Position 1: Her position's settled margin is -1 ETH. When the settled margin is -ve then the LPs have to bear the cost of loss per the comment here. However, in this case, we can see that it is Bob (long trader) instead of LPs who are bearing the cost of Alice's loss, which is incorrect.
Let's review Bob's Long Position 2: His position's settled margin is 1 ETH. If his position's liquidation margin is $LM$, Bob should be able to withdraw $1\ ETH - LM$ of his position's margin. However, in this case, the
marginDepositedTotal
is already zero, so there is no more collateral left on the long trader pool for Bob to withdraw, which is incorrect.With the current implementation, the losses of some long traders can eat into the margins of others, resulting in those affected long traders being unable to withdraw their margin and profits.
https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/FlatcoinVault.sol#L173
Impact
Loss of assets for the long traders as the losses of some long traders can eat into the margins of others, resulting in those affected long traders being unable to withdraw their margin and profits.
Code Snippet
https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/FlatcoinVault.sol#L173
Tool used
Manual Review
Recommendation
The following are the two issues identified earlier and the recommended fixes:
Issue 1
Fix: Alice -1 ETH loss should be borne by the LP, not the long traders. The stable collateral total of LP should be deducted by 1 ETH to bear the cost of the loss.
Issue 2
Fix: Bob should be able to withdraw $1\ ETH - LM$ of his position's margin regardless of the PnL of other long traders. Bob's margin should be isolated from Alice's loss.