Closed sherlock-admin2 closed 5 months ago
1 comment(s) were left on this issue during the judging contest.
takarez commented:
valid: high(5)
This has been resolved in issue #186 fix. Test scenario added here: https://github.com/dhedge/flatcoin-v1/pull/266/commits/3a95a5b932fb9dcd770afd589751ecfd151360a8
The protocol team fixed this issue in PR/commit https://github.com/dhedge/flatcoin-v1/pull/266.
Escalate
This issue is actually a duplicate of #180.
Issue #180 describes the vulnerability in a generalized way. The impact may be different but the root cause is the same: an incorrect handling of PnL during liquidation. Also, the fix is the same so this issue should be duplicate of #180.
Escalate
This issue is actually a duplicate of #180.
Issue #180 describes the vulnerability in a generalized way. The impact may be different but the root cause is the same: an incorrect handling of PnL during liquidation. Also, the fix is the same so this issue should be duplicate of #180.
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.
Would like @nevillehuang to double check.
Planning to accept the escalation and duplicate this with #180.
Would like @nevillehuang to double check.
Planning to accept the escalation and duplicate this with #180.
Agree, should be duplicates, both issues arises due to the incorrect handling of profitLossTotal
causing different impacts
Result: High Duplicate of #180
xiaoming90
high
Liquidation will result in an underflow revert
Summary
Liquidation will result in an underflow revert. Liquidation is the core component of the protocol and is important to the solvency of the protocol. If the liquidation cannot be executed due to the revert described in the above scenario, underwater positions and bad debt will accumulate in the protocol, threatening the solvency of the protocol.
In addition, the proper function of the protocol relies on the correct accounting of the collateral in the vault and collateral owned by long traders and LPs. If the accounting is off, the vault will be broken.
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.
Since the liquidated position's settledMargin is less than 0, the code at Line 142 below will be executed.
After the
updateStableCollateralTotal
function is executed, thestableCollateralTotal
will become 15 ETH (12 + 3), theGlobalPositions.marginDepositedTotal
will remain at 8 ETH, and the total balance of ETH in the vault will remain at 20 ETH.https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/LiquidationModule.sol#L85
Subsequently, the
vault.updateGlobalPositionData
will be executed. ThemarginDelta
will be set to -3 ETH, as shown below:Line 179 below within the
updateGlobalPositionData
function will compute the total PnL of all the opened long positions.At Line 184 below, the
newMarginDepositedTotal
will be set to as follows:As
newMarginDepositedTotal
is less than zero, the code at Line 192 will trigger a revert, causing the liquidation TX to revert.https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/FlatcoinVault.sol#L173
Let's assume that there is no revert for the sake of verifying the correctness of the accounting used in the later portion of the code within the liquidation function.
In this case, the latest
marginDepositedTotal
will be set to -3 ETH.Next, the
_updateStableCollateralTotal(-profitLossTotal);
at Line 205 above will be executed, and thestableCollateralTotal
will be set to 23 ETH.This shows that accounting is incorrect, as it is not possible for the LPs to own 23 ETH when there are only 20 ETH balance as collateral in the vault.
In conclusion, there are two (2) issues identified here:
Impact
Liquidation is the core component of the protocol and is important to the solvency of the protocol. If the liquidation cannot be executed due to the revert described in the above scenario, underwater positions and bad debt will accumulate in the protocol, threatening the solvency of the protocol.
In addition, the proper function of the protocol relies on the correct accounting of the collateral in the vault and collateral owned by long traders and LPs. If the accounting is off, the vault will be broken.
Code Snippet
https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/LiquidationModule.sol#L85
https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/FlatcoinVault.sol#L173
Tool used
Manual Review
Recommendation
In the above scenario, to prevent an underflow revert when computing the new
newMarginDepositedTotal
and fixing the incorrect balance issue, theprofitLossTotal
should be excluded within theupdateGlobalPositionData
function during liquidation.The existing
updateGlobalPositionData
function still needs to be used for other functions besides liquidation. As such, consider creating a separate new function (e.g., updateGlobalPositionDataDuringLiquidation) solely for use during the liquidation that includes the above fixes.Verification of solution
Let's verify if the fixes work as intended using the same example in the report.
The following means that the Initial Deposited Margin (3 ETH) of Alice's position is being transferred to the LPs.
After the
updateStableCollateralTotal
function is executed, thestableCollateralTotal
will become 15 ETH (12 + 3), theGlobalPositions.marginDepositedTotal
will remain at 8 ETH, and the total balance of ETH in the vault will remain at 20 ETH.The same values as the earlier example, except that the formula has changed. The
newMarginDepositedTotal
is left with 5 ETH, which is correct because this represents the ETH margin deposited by Bob's existing position in the system.The
newMarginDepositedTotal
is above 0, so there is no revert, which is good.In the end,
newMarginDepositedTotal
is 5 ETH andstableCollateralTotal
is 15 ETH. There are 20 ETH balance as collateral in the vault.Thus, they are in sync now. Also, there is no revert or underflow error.
Duplicate of #180