# Clearing House Facet

The ClearingHouse Facet handles liquidation processes that require off-chain coordination and trusted execution. It supports two liquidation flows: cross PartyB liquidation and PartyA takeover — as well as a newer **soft liquidation** mechanism for PartyBs. All functions are restricted to designated roles (`CLEARING_HOUSE_ROLE` or `SOFT_LIQUIDATOR_ROLE`). The underlying logic is implemented in the `ClearingHouseFacetImpl` library.

Unlike the standard on-chain liquidation flow (which relies on Muon signatures and permissionless execution), the ClearingHouse operates with prices provided directly by the clearing house operator, without Muon signature verification. Read the [0.8.5 Changelog](https://docs.symm.io/contract-documentation/symmio-perps-v0.8.5-contract-upgrade) for more information.

***

### Overview

The ClearingHouse Facet provides the following key functionalities:

* **Cross PartyB Liquidation:** Liquidates a cross-margin PartyB, deallocating funds from the PartyB and distributing them to affected PartyAs and other receivers.
* **PartyA Takeover:** Takes over a stuck PartyA liquidation that normal liquidators have failed to complete, allowing the clearing house to process remaining positions and settle the liquidation.
* **Fund Deallocation & Distribution:** Generic primitives used by both flows to pull funds from parties and distribute them to receivers, with flexible allocation key routing.
* **Position Liquidation:** Liquidates both pending and open positions during a clearing house liquidation, with prices provided directly by the operator.
* **Soft Liquidation:** Applies graduated penalties to PartyBs whose liquidity is running low, providing a warning system before hard liquidation becomes necessary.

***

### liquidateCrossPartyB()

Initiates a clearing house liquidation for a cross-margin PartyB. This marks the PartyB as being in a clearing house liquidation state.

**Function Signature:**

```solidity
function liquidateCrossPartyB(
    address partyB,
    bytes memory liquidationId,
    int256 upnl,
    uint256 timestamp
) external whenNotLiquidationPaused notCrossLiquidatedPartyB(partyB) onlyRole(CLEARING_HOUSE_ROLE);
```

**Parameters:**

* `partyB`: The address of the PartyB to liquidate.
* `liquidationId`: A unique identifier for this liquidation event.
* `upnl`: PartyB's unrealized profit and loss at the time of liquidation.
* `timestamp`: The timestamp of the liquidation snapshot.

**Access:** Requires `CLEARING_HOUSE_ROLE`. PartyB must not already be in a cross liquidation.

**Events Emitted:**

* `LiquidateCrossPartyB(address liquidator, address partyB, bytes liquidationId, int256 upnl, uint256 timestamp)`

***

### takeoverPartyALiquidation()

Takes over a stuck PartyA liquidation. This can only be called when a PartyA is already being liquidated through the normal flow but the process has stalled. The clearing house clears the disputed flag, liquidation fee, and liquidators array, then assumes control of the liquidation. Once taken over, normal liquidation functions are blocked for this PartyA.

**Function Signature:**

```solidity
function takeoverPartyALiquidation(address partyA) external whenNotLiquidationPaused onlyRole(CLEARING_HOUSE_ROLE);
```

**Parameters:**

* `partyA`: The address of the PartyA whose liquidation is being taken over.

**Access:** Requires `CLEARING_HOUSE_ROLE`. PartyA must already be in an active liquidation.

**Events Emitted:**

* `TakeoverPartyALiquidation(address partyA, bytes liquidationId, uint256 timestamp)`

***

### deallocateForClearingHouse()

Deallocates (pulls) funds from specified parties during a clearing house liquidation. This is a generic primitive used by both cross PartyB liquidation and PartyA takeover flows.

The parameters are interpreted differently depending on the liquidation type:

* **Cross PartyB liquidation:** `subject` is the PartyB. `parties` contains the PartyB (to pull from its balances), and `allocationKeys` contains the PartyA addresses whose allocations should be reduced.
* **PartyA takeover:** `subject` is the PartyA. `parties` contains the PartyA and any PartyBs involved, and `allocationKeys` routes accordingly. The special allocation key `address(1)` pulls from `partyAReimbursement`.

**Function Signature:**

```solidity
function deallocateForClearingHouse(
    address subject,
    address[] memory parties,
    address[] memory allocationKeys,
    uint256[] memory amounts
) external whenNotLiquidationPaused onlyRole(CLEARING_HOUSE_ROLE);
```

**Parameters:**

* `subject`: The party being liquidated (PartyB for cross, PartyA for takeover).
* `parties`: The parties to pull funds from.
* `allocationKeys`: The allocation keys for each party, determining which balance bucket to debit.
* `amounts`: The amounts to pull from each party (in 18 decimals).

**Access:** Requires `CLEARING_HOUSE_ROLE`.

**Events Emitted:**

* `DeallocateForClearingHouse(address subject, address[] parties, address[] allocationKeys, uint256[] amounts)`

***

### distributeForClearingHouse()

Distributes funds to receivers during a clearing house liquidation. This is the counterpart to `deallocateForClearingHouse`.

Funds are routed based on the receiver type:

* **PartyB receivers:** Funds go to `partyBAllocatedBalances[receiver][allocationKey]`. Use `address(0)` as the allocation key for the cross-mode bucket, or a specific PartyA address for an isolated bucket.
* **Non-PartyB receivers** (PartyAs, insurance funds, etc.): Funds go to `allocatedBalances[receiver]`.

**Function Signature:**

```solidity
function distributeForClearingHouse(
    address subject,
    address[] memory receivers,
    address[] memory allocationKeys,
    uint256[] memory amounts
) external whenNotLiquidationPaused onlyRole(CLEARING_HOUSE_ROLE);
```

**Parameters:**

* `subject`: The party being liquidated (PartyB for cross, PartyA for takeover).
* `receivers`: The addresses to distribute funds to.
* `allocationKeys`: The allocation keys for each receiver (used for PartyB receivers).
* `amounts`: The amounts to distribute (in 18 decimals).

**Access:** Requires `CLEARING_HOUSE_ROLE`.

**Events Emitted:**

* `DistributeForClearingHouse(address subject, address[] receivers, address[] allocationKeys, uint256[] amounts)`

***

### liquidatePendingPositionsForClearingHouse()

Liquidates pending positions (quotes in PENDING, LOCKED, or CANCEL\_PENDING status) during a clearing house liquidation.

* **Cross PartyB liquidation:** `counterparties` specifies which PartyAs' pending positions to process.
* **PartyA takeover:** `counterparties` is ignored; all pending positions for the PartyA are processed.

**Function Signature:**

```solidity
function liquidatePendingPositionsForClearingHouse(
    address subject,
    address[] memory counterparties
) external whenNotLiquidationPaused onlyRole(CLEARING_HOUSE_ROLE);
```

**Parameters:**

* `subject`: The party being liquidated (PartyB for cross, PartyA for takeover).
* `counterparties`: The counterparties to process (only used for cross PartyB flow).

**Access:** Requires `CLEARING_HOUSE_ROLE`.

**Events Emitted:**

* `LiquidatePendingPositionsForClearingHouse(address subject, address[] counterparties, uint256[] liquidatedAmounts)`

***

### liquidatePositionsForClearingHouse()

Liquidates open positions during a clearing house liquidation. Prices are provided directly by the clearing house operator without Muon signature verification.

**Function Signature:**

```solidity
function liquidatePositionsForClearingHouse(
    address subject,
    uint256[] memory quoteIds,
    uint256[] memory prices
) external whenNotLiquidationPaused onlyRole(CLEARING_HOUSE_ROLE);
```

**Parameters:**

* `subject`: The party being liquidated (PartyB for cross, PartyA for takeover).
* `quoteIds`: The IDs of the quotes/positions to liquidate.
* `prices`: The prices to use for each position's liquidation. Must correspond 1:1 with `quoteIds`.

**Access:** Requires `CLEARING_HOUSE_ROLE`.

**Events Emitted:**

* `LiquidatePositionsForClearingHouse(address subject, uint256[] quoteIds, uint256[] liquidatedAmounts, uint256[] closeIds, uint256[] prices)`

***

### settlePartyATakeover()

Settles a PartyA takeover liquidation, clearing all liquidation state. This can only be called after all positions have been closed and all funds distributed. Also cleans up settlement states for PartyBs that may have been partially processed by the normal liquidation flow before the takeover.

**Function Signature:**

```solidity
function settlePartyATakeover(
    address partyA,
    address[] memory settledPartyBs
) external whenNotLiquidationPaused onlyRole(CLEARING_HOUSE_ROLE);
```

**Parameters:**

* `partyA`: The address of the PartyA whose takeover liquidation is being settled.
* `settledPartyBs`: PartyBs whose settlement states need cleanup (includes PartyBs that were processed by the normal flow before the takeover).

**Access:** Requires `CLEARING_HOUSE_ROLE`.

**Events Emitted:**

* `SettlePartyATakeover(address partyA, bytes liquidationId)`

***

### settleCrossPartyBLiquidation()

Settles a cross PartyB clearing house liquidation. All positions must be closed and all funds distributed before this can be called.

**Function Signature:**

```solidity
function settleCrossPartyBLiquidation(address partyB) external whenNotLiquidationPaused onlyRole(CLEARING_HOUSE_ROLE);
```

**Parameters:**

* `partyB`: The address of the PartyB whose liquidation is being settled.

**Access:** Requires `CLEARING_HOUSE_ROLE`.

**Events Emitted:**

* `SettleCrossPartyBLiquidation(address partyB)`

***

### softPartyBLiquidation()

Applies a soft liquidation penalty to a PartyB. Instead of immediately hard-liquidating a PartyB whose liquidity is running low, the system can impose graduated penalties at configurable thresholds — giving the PartyB an opportunity to replenish funds before a full liquidation is triggered.

Penalty tiers and amounts are configured off-chain, allowing different treatment for new versus well-established PartyBs. Penalty amounts are transferred to the configured `softLiquidationPenaltyCollector` address.

The `partyA` parameter controls which balance bucket the allocated penalty is drawn from:

* **Cross-mode PartyBs** (`partyA = address(0)`): Penalties are deducted from the PartyB's cross-allocated balance and/or unallocated balance.
* **Non-cross-mode PartyBs** (`partyA = specific address`): Penalties are deducted from the PartyB's allocation for that specific PartyA and/or their unallocated balance.

**Function Signature:**

```solidity
function softPartyBLiquidation(
    address partyB,
    address partyA,
    uint256 penaltyFromAllocated,
    uint256 penaltyFromBalance
) external onlyRole(SOFT_LIQUIDATOR_ROLE);
```

**Parameters:**

* `partyB`: The address of the PartyB being penalized.
* `partyA`: The PartyA whose allocation to deduct from. Pass `address(0)` for cross-mode PartyBs.
* `penaltyFromAllocated`: The penalty amount to deduct from PartyB's allocated balance.
* `penaltyFromBalance`: The penalty amount to deduct from PartyB's unallocated (deposit) balance.

**Access:** Requires `SOFT_LIQUIDATOR_ROLE`.

**Example:**

```solidity
// Soft-liquidate a cross-mode PartyB with a $50 penalty from allocated balance
symmioDiamond.softPartyBLiquidation(partyBAddress, address(0), 50e18, 0);
```

**Events Emitted:**

* `SoftPartyBLiquidation(address partyB, address partyA, uint256 penaltyFromAllocated, uint256 penaltyFromBalance)`
