Losses of some long traders can eat into the margins of others
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.\\nAt $T0$, the current price of ETH is $1000 and assume the following state:\\nAlice's Long Position 1 Bob's Long Position 2 Charles (LP)\\nPosition Size = 6 ETH\\nMargin = 3 ETH\\nLast Price (entry price) = $1000 Position Size = 6 ETH\\nMargin = 5 ETH\\nLast Price (entry price) = $1000 Deposited 12 ETH\\nThe `stableCollateralTotal` will be 12 ETH\\nThe `GlobalPositions.marginDepositedTotal` will be 8 ETH (3 + 5)\\nThe `globalPosition.sizeOpenedTotal` will be 12 ETH (6 + 6)\\nThe total balance of ETH in the vault is 20 ETH.\\nAs this is a perfectly hedged market, the accrued fee will be zero, and ignored in this report for simplicity's sake.\\nAt $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:\\nAlice's Long Position 1 Bob's Long Position 2\\npriceShift = Current Price - Last Price = $600 - $1000 = -$400\\nPnL = (Position Size * priceShift) / Current Price = (6 ETH * -$400) / $400 = -4 ETH\\nsettleMargin = marginDeposited + PnL = 3 ETH + (-4 ETH) = -1 ETH PnL = -4 ETH (Same calculation)\\nsettleMargin = marginDeposited + PnL = 5 ETH + (-4 ETH) = 1 ETH\\nAlice'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 the `updateGlobalPositionData` function internally:\\nexecuteOpen\\nexecuteAdjust\\nexecuteClose\\nThe 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.\\nAssume 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.\\n```\\npriceShift = current price - last price\\npriceShift = $600 - $1000 = -$400\\n\\nprofitLossTotal = (globalPosition.sizeOpenedTotal * priceShift) / current price\\nprofitLossTotal = (12 ETH * -$400) / $600\\nprofitLossTotal = -8 ETH\\n```\\n\\nThe `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).\\nAt Line 184 below, the `newMarginDepositedTotal` will be set to as follows (ignoring the `_marginDelta` for simplicity's sake)\\n```\\nnewMarginDepositedTotal = _globalPositions.marginDepositedTotal + _marginDelta + profitLossTotal\\nnewMarginDepositedTotal = 8 ETH + 0 + (-8 ETH) = 0 ETH\\n```\\n\\nWhat 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.\\nLet'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.\\nLet'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.\\nWith 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.\\n```\\nbeing File: FlatcoinVault.sol\\n    function updateGlobalPositionData(\\n        uint256 _price,\\n        int256 _marginDelta,\\n        int256 _additionalSizeDelta\\n    ) external onlyAuthorizedModule {\\n        // Get the total profit loss and update the margin deposited total.\\n        int256 profitLossTotal = PerpMath._profitLossTotal({globalPosition: _globalPositions, price: _price});\\n\\n        // Note that technically, even the funding fees should be accounted for when computing the margin deposited total.\\n        // However, since the funding fees are settled at the same time as the global position data is updated,\\n        // we can ignore the funding fees here.\\n        int256 newMarginDepositedTotal = int256(_globalPositions.marginDepositedTotal) + _marginDelta + profitLossTotal;\\n\\n        // Check that the sum of margin of all the leverage traders is not negative.\\n        // Rounding errors shouldn't result in a negative margin deposited total given that\\n        // we are rounding down the profit loss of the position.\\n        // If anything, after closing the last position in the system, the `marginDepositedTotal` should can be positive.\\n        // The margin may be negative if liquidations are not happening in a timely manner.\\n        if (newMarginDepositedTotal < 0) {\\n            revert FlatcoinErrors.InsufficientGlobalMargin();\\n        }\\n\\n        _globalPositions = FlatcoinStructs.GlobalPositions({\\n            marginDepositedTotal: uint256(newMarginDepositedTotal),\\n            sizeOpenedTotal: (int256(_globalPositions.sizeOpenedTotal) + _additionalSizeDelta).toUint256(),\\n            lastPrice: _price\\n        });\\n\\n        // Profit loss of leverage traders has to be accounted for by adjusting the stable collateral total.\\n        // Note that technically, even the funding fees should be accounted for when computing the stable collateral total.\\n        // However, since the funding fees are settled at the same time as the global position data is updated,\\n        // we can ignore the funding fees here\\n        _updateStableCollateralTotal(-profitLossTotal);\\n    }\\n```\\n
The following are the two issues identified earlier and the recommended fixes:\\nIssue 1\\nLet'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.\\nFix: 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.\\nIssue 2\\nLet'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.\\nFix: 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.
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.
```\\npriceShift = current price - last price\\npriceShift = $600 - $1000 = -$400\\n\\nprofitLossTotal = (globalPosition.sizeOpenedTotal * priceShift) / current price\\nprofitLossTotal = (12 ETH * -$400) / $600\\nprofitLossTotal = -8 ETH\\n```\\n