ForceCloseSteps
The ForceCloseSteps Facet provides a step-based force close flow that supports both normal (isolated) and cross-mode PartyBs. It was introduced because the legacy single-transaction forceClosePosition on the ForceActionsFacet cannot handle cross-mode PartyBs, where settlement requires a UnifiedSettlementSig covering multiple PartyAs and the settlement + close must use consistent price snapshots.
Overview
The ForceCloseSteps Facet provides two ways to execute a force close:
3-Step Flow:
initializeForceClose→settleUpnlForForceClose(optional) →finalizeForceClose. Each step is a separate transaction, allowing large settlements to be broken across multiple calls.Convenience Function:
forceCloseAndSettlePositionsUnifiedcombines all three steps into a single transaction when the settlement data is small enough to fit within gas limits.
Behavioral Differences by PartyB Mode
Insolvency handling
Reserve vault fallback → PartyB liquidation
Close with uPnL ignored → CLOSED_INSOLVENT status
Settlement scope
Same PartyB, same PartyA only
Same PartyB, any PartyA (shared pool)
On insolvency event
LiquidatePartyB
ForceClosePosition + ForceClosePartyBInsolvent
Reserve vault used
Yes
No
Cross-mode PartyBs are never liquidated during force close. If PartyB is insolvent, the position either closes (marked CLOSED_INSOLVENT) or the transaction reverts with insufficient balance.
initializeForceClose()
Step 1. Validates force-close conditions and computes the close price. The quote must be in CLOSE_PENDING status with a LIMIT order type, the force-close cooldown must have elapsed, and the close price must have been reached within the signature's high/low price range. Checks that PartyA remains solvent after the close.
Stores a ForceCloseDetail snapshot containing the computed close price, PartyB's uPnL, and the current market price. This snapshot is used by subsequent steps and does not change after initialization.
Function Signature:
Parameters:
quoteId: The ID of the quote to force-close.sig: The MuonHighLowPriceSigcontaining high/low prices used to calculate the close price with penalty.
Example:
Events Emitted:
ForceCloseInitialized(address caller, address partyB, uint256 quoteId, bytes reqId, uint256 closePrice, uint256 timestamp)
settleUpnlForForceClose()
Step 2. Settles unrealized PnL using UnifiedSettlementSig to fund the close when either party lacks sufficient available balance. This step can be called multiple times if the settlement needs to be spread across several transactions.
Which positions can be settled depends on the scenario:
PartyA lacks funds: Settle PartyA's profitable positions with any other PartyB (not the force-close quote's PartyB). This increases PartyA's allocated balance.
PartyB (non-cross) lacks funds: Settle the same PartyB's profitable positions, but only with the force-close quote's PartyA. In isolated mode, each per-PartyA bucket is separate, so the contract enforces that only one PartyA is included in the settlement.
PartyB (cross) lacks funds: Settle the same PartyB's positions with any PartyA. Everything goes to the shared
address(0)pool.
After settlement, the stored upnlPartyB snapshot is adjusted by the settlement delta (only when the settlement targets the force-close quote's PartyB), ensuring consistency for the finalize step.
Function Signature:
Parameters:
quoteId: The ID of the quote in the force-close workflow.settlementSig: TheUnifiedSettlementSigcontaining uPnL data and pricing for settlement.updatedPrices: New prices to set asopenedPricefor the settled quotes.
Events Emitted:
SettleUpnlUnified(bytes reqId, QuotesSettlementsData[] data, uint256[] updatedPrices, address partyB, address[] partyAs, uint256[] newPartyAsAllocatedBalances, uint256 newPartyBAllocatedBalance)
finalizeForceClose()
Step 3. Refreshes the uPnL and current price snapshot with a fresh Muon signature (ensuring PartyA solvency at the latest prices), then closes the position.
The close behavior differs by PartyB mode:
Normal PartyB: If PartyB is solvent after close, emits
ForceClosePosition. If insolvent, attempts the reserve vault fallback. If the reserve vault covers the deficit, the position closes. If not, triggers PartyB liquidation and emitsLiquidatePartyB.Cross-Mode PartyB: Always emits
ForceClosePosition. If PartyB is insolvent, the position still closes (markedCLOSED_INSOLVENT) and additionally emitsForceClosePartyBInsolvent. If even the "ignore uPnL" fallback is insufficient, the transaction reverts.
Function Signature:
Parameters:
quoteId: The ID of the quote to finalize the force close for.sig: A fresh MuonPairUpnlAndPriceSigto refresh the uPnL and current price snapshot.
Events Emitted (normal PartyB, solvent):
ForceClosePosition(uint256 quoteId, address partyA, address partyB, uint256 filledAmount, uint256 closePrice, QuoteStatus status, uint256 closeId)
Events Emitted (normal PartyB, insolvent):
LiquidatePartyB(address liquidator, address partyB, address partyA, uint256 partyBAllocatedBalance, int256 upnlPartyB)
Events Emitted (cross PartyB, solvent):
ForceClosePosition(...)
Events Emitted (cross PartyB, insolvent):
ForceClosePosition(...)ForceClosePartyBInsolvent(uint256 quoteId, address partyA, address partyB, uint256 closePrice, uint256 currentPrice, int256 upnlPartyB, int256 partyBAvailableAfterClose)
forceCloseAndSettlePositionsUnified()
Convenience function that combines all three steps — initialize, settle (optional), and finalize — into a single transaction. Unlike the step-by-step flow, the finalize here does not take a fresh PairUpnlAndPriceSig. It uses the uPnL and current price values from the init signature directly (adjusted by any settlement delta).
Settlement is skipped if updatedPrices is empty.
Function Signature:
Parameters:
quoteId: The ID of the quote to force-close.sig: The MuonHighLowPriceSigfor calculating the close price.settlementSig: TheUnifiedSettlementSigfor settlement. Ignored ifupdatedPricesis empty.updatedPrices: New prices for settled quotes. Pass an empty array to skip settlement.
Events Emitted:
ForceCloseInitialized(...)— from the init stepSettleUpnlUnified(...)— from the settle step (only ifupdatedPricesis non-empty)ForceClosePosition(...)and/orForceClosePartyBInsolvent(...)orLiquidatePartyB(...)— from the finalize step
Last updated

