# PartyA Liquidation

The PartyA Liquidation Facet handles the decentralized liquidation of insolvent PartyA accounts. Liquidators (addresses with `LIQUIDATOR_ROLE`) detect insolvency off-chain, then execute a multi-step on-chain process: initiate liquidation, set symbol prices, close positions, and settle with counterparty PartyBs.&#x20;

{% hint style="info" %}
**Note:** In v0.8.5, the following key changes apply:

* **Deferred Liquidation:** A new deferred liquidation flow (`deferredLiquidatePartyA` / `deferredSetSymbolsPrice`) allows the liquidation to reference a historical block and timestamp rather than the current one. This handles cases where the insolvency was detected earlier but the on-chain transaction was delayed.
* **Liquidation Insurance Vault:** A cap on per-position liquidator profit (`maxLiquidationProfitPerPosition`) redirects excess liquidation fees to a protocol insurance vault. This prevents disproportionately large liquidator payouts and creates protocol revenue that can cover future overdue liquidation deficits.
* **ClearingHouse Takeover:** If a PartyA liquidation gets stuck or enters a corrupted state, the ClearingHouse can take it over via `ClearingHouseFacet.takeoverPartyALiquidation`. Once taken over, all normal liquidation functions on this facet are blocked — only ClearingHouse functions can proceed. Auto-takeover also occurs when a cross PartyB liquidation encounters a PartyA that is mid-liquidation.
* **Dual LiquidatePositionsPartyA Event:** `liquidatePositionsPartyA` now emits two versions of the event — the legacy one and a new one that includes `averageClosedPrices`.
  {% endhint %}

***

### Overview

The PartyA Liquidation Facet provides the following key functionalities:

* **Initiate Liquidation:** Marks a PartyA as insolvent using a Muon signature, freezing the account.
* **Set Symbol Prices:** Provides oracle prices for symbols, classifies the liquidation type (NORMAL, LATE, OVERDUE), and applies the insurance vault cap.
* **Deferred Liquidation:** An alternative initiation path that references a historical point in time for the insolvency snapshot.
* **Liquidate Pending Positions:** Cancels all pending quotes, returning trading fees to the PartyA.
* **Liquidate Open Positions:** Closes open positions at the oracle-provided prices.
* **Settle Liquidation:** Distributes remaining funds to counterparty PartyBs and liquidators.
* **Resolve Dispute:** An admin function to correct settlement amounts when a liquidation is disputed.

***

### Liquidation Flow

The standard liquidation follows this sequence:

```
liquidatePartyA → setSymbolsPrice (repeatable) → liquidatePendingPositionsPartyA
→ liquidatePositionsPartyA (repeatable) → settlePartyALiquidation (per PartyB)
```

#### Liquidation Types

The liquidation is classified during `setSymbolsPrice` based on how much of the locked balance the deficit consumes:

| Type      | Condition               | Meaning                                                                |
| --------- | ----------------------- | ---------------------------------------------------------------------- |
| `NORMAL`  | deficit < LF            | Enough LF remains to pay liquidators (subject to insurance vault cap). |
| `LATE`    | LF ≤ deficit ≤ LF + CVA | LF is fully consumed; deficit eats into CVA.                           |
| `OVERDUE` | deficit > LF + CVA      | Both LF and CVA consumed; PartyBs absorb losses.                       |

#### Insurance Vault Cap (NORMAL liquidations only)

In NORMAL liquidations, the remaining LF (after covering the deficit) is capped at `maxLiquidationProfitPerPosition × partyAPositionsCount`. Any excess is credited to the `liquidationInsuranceVault` address. The capped amount is split equally between the two liquidators at settlement.

***

### liquidatePartyA()

Initiates the liquidation of a PartyA. The Muon signature provides the uPnL and total unrealized loss, which the contract uses to verify insolvency. Once called, the PartyA is frozen and no deposits, withdrawals, allocations, or trading operations are permitted.

**Function Signature:**

```solidity
function liquidatePartyA(
    address partyA,
    LiquidationSig memory liquidationSig
) external whenNotLiquidationPaused notLiquidatedPartyA(partyA) onlyRole(LIQUIDATOR_ROLE);
```

**Parameters:**

* `partyA`: The address of the PartyA to liquidate.
* `liquidationSig`: The Muon signature containing uPnL, total unrealized loss, symbol IDs, prices, and a unique liquidation ID.

**Access:** Requires `LIQUIDATOR_ROLE`. PartyA must not already be in liquidation.

**Events Emitted:**

* `LiquidatePartyA(address liquidator, address partyA, uint256 allocatedBalance, int256 upnl, int256 totalUnrealizedLoss, bytes liquidationId)`

***

### setSymbolsPrice()

Sets the oracle prices for symbols at the time of liquidation. Must be called after `liquidatePartyA`. The Muon signature's `liquidationId` must match the one from the initiation call. This step classifies the liquidation type (NORMAL/LATE/OVERDUE) and applies the insurance vault cap if applicable. This can be called multiple times to set prices for different batches of symbols.

**Function Signature:**

```solidity
function setSymbolsPrice(
    address partyA,
    LiquidationSig memory liquidationSig
) external whenNotLiquidationPaused onlyRole(LIQUIDATOR_ROLE);
```

**Parameters:**

* `partyA`: The address of the PartyA in liquidation.
* `liquidationSig`: The Muon signature containing symbol IDs and their corresponding prices, with a matching liquidation ID.

**Access:** Requires `LIQUIDATOR_ROLE`.

**Events Emitted:**

* `SetSymbolsPrices(address liquidator, address partyA, uint256[] symbolIds, uint256[] prices, bytes liquidationId)`

***

### deferredLiquidatePartyA()

An alternative initiation path that references a historical block number and timestamp for the insolvency snapshot. This handles cases where insolvency was detected at an earlier point but the liquidation transaction was delayed (e.g., due to network congestion). The Muon signature includes the historical block number, timestamp, and the allocated balance at that point.

**Function Signature:**

```solidity
function deferredLiquidatePartyA(
    address partyA,
    DeferredLiquidationSig memory liquidationSig
) external whenNotLiquidationPaused notLiquidatedPartyA(partyA) onlyRole(LIQUIDATOR_ROLE);
```

**Parameters:**

* `partyA`: The address of the PartyA to liquidate.
* `liquidationSig`: The Muon deferred signature containing uPnL, total unrealized loss, liquidation ID, the historical block number, timestamp, and allocated balance.

**Access:** Requires `LIQUIDATOR_ROLE`.

**Events Emitted:**

* `DeferredLiquidatePartyA(address liquidator, address partyA, uint256 allocatedBalance, int256 upnl, int256 totalUnrealizedLoss, bytes liquidationId, uint256 liquidationBlockNumber, uint256 liquidationTimestamp, uint256 liquidationAllocatedBalance)`

***

### deferredSetSymbolsPrice()

Sets symbol prices for a deferred liquidation. Functions identically to `setSymbolsPrice` but uses the `DeferredLiquidationSig` structure. The `liquidationId` must match the one from `deferredLiquidatePartyA`.

**Function Signature:**

```solidity
function deferredSetSymbolsPrice(
    address partyA,
    DeferredLiquidationSig memory liquidationSig
) external whenNotLiquidationPaused onlyRole(LIQUIDATOR_ROLE);
```

**Parameters:**

* `partyA`: The address of the PartyA in deferred liquidation.
* `liquidationSig`: The Muon deferred signature containing symbol IDs, prices, and matching liquidation ID.

**Access:** Requires `LIQUIDATOR_ROLE`.

**Events Emitted:**

* `SetSymbolsPrices(address liquidator, address partyA, uint256[] symbolIds, uint256[] prices, bytes liquidationId)`

***

### liquidatePendingPositionsPartyA()

Cancels all pending quotes for the PartyA in liquidation. For each pending quote, the opening trading fee is returned to the PartyA's allocated balance. Quote statuses are set to `LIQUIDATED_PENDING`.

**Function Signature:**

```solidity
function liquidatePendingPositionsPartyA(address partyA) external whenNotLiquidationPaused onlyRole(LIQUIDATOR_ROLE);
```

**Parameters:**

* `partyA`: The address of the PartyA whose pending positions will be liquidated.

**Access:** Requires `LIQUIDATOR_ROLE`.

**Events Emitted:**

* `LiquidatePendingPositionsPartyA(address liquidator, address partyA, uint256[] pendingQuoteIds, uint256[] liquidatedAmounts, bytes liquidationId)`

***

### liquidatePositionsPartyA()

Closes open positions at the previously set oracle prices. Can be called in batches. If the accumulated settlement amounts diverge from the Muon-reported uPnL beyond an acceptable threshold, the liquidation enters a `disputed` state, requiring admin intervention via `resolveLiquidationDispute`.

**Function Signature:**

```solidity
function liquidatePositionsPartyA(
    address partyA,
    uint256[] memory quoteIds
) external whenNotLiquidationPaused onlyRole(LIQUIDATOR_ROLE);
```

**Parameters:**

* `partyA`: The address of the PartyA whose positions will be liquidated.
* `quoteIds`: An array of quote IDs to liquidate in this batch.

**Access:** Requires `LIQUIDATOR_ROLE`.

**Events Emitted:**

* `LiquidatePositionsPartyA(address liquidator, address partyA, uint256[] quoteIds, uint256[] liquidatedAmounts, uint256[] closeIds, bytes liquidationId)` — legacy event
* `LiquidatePositionsPartyA(address liquidator, address partyA, uint256[] quoteIds, uint256[] liquidatedAmounts, uint256[] closeIds, uint256[] averageClosedPrices, bytes liquidationId)` — new event with average closed prices
* `LiquidationDisputed(address partyA, bytes liquidationId)` — if settlement diverges from reported uPnL

***

### settlePartyALiquidation()

Settles the liquidation for one or more counterparty PartyBs. Distributes remaining funds based on the liquidation type and settlement amounts computed during position liquidation. The capped liquidation fee is split equally between the two liquidators (the one who called `liquidatePartyA` and the one who called `setSymbolsPrice`).

Can be called by anyone (no role restriction). When all PartyBs are settled, the PartyA exits liquidation state and a `FullyLiquidatedPartyA` event is emitted.

**Important:** Settlement with a PartyB that is in cross liquidation is blocked — the ClearingHouse must handle that PartyB's settlement through its own flow.

**Function Signature:**

```solidity
function settlePartyALiquidation(address partyA, address[] memory partyBs) external whenNotLiquidationPaused;
```

**Parameters:**

* `partyA`: The address of the PartyA to settle.
* `partyBs`: An array of PartyB addresses to settle with.

**Events Emitted:**

* `SettlePartyALiquidation(address partyA, address[] partyBs, int256[] settleAmounts, bytes liquidationId)`
* `FullyLiquidatedPartyA(address partyA, bytes liquidationId)` — when all PartyBs have been settled

***

### resolveLiquidationDispute()

Resolves a liquidation dispute by providing corrected settlement amounts. Called by an admin with `DISPUTE_ROLE` when the accumulated settlement during position liquidation diverges from the Muon-reported uPnL. The admin can set the `disputed` flag to `true` to keep the dispute open for further resolution, or `false` to clear it.

**Function Signature:**

```solidity
function resolveLiquidationDispute(
    address partyA,
    address[] memory partyBs,
    int256[] memory amounts,
    bool disputed
) external onlyRole(DISPUTE_ROLE);
```

**Parameters:**

* `partyA`: The address of the PartyA in the disputed liquidation.
* `partyBs`: An array of PartyB addresses involved in the dispute.
* `amounts`: Corrected settlement amounts for each PartyB.
* `disputed`: Whether the liquidation should remain in disputed state after this resolution.

**Access:** Requires `DISPUTE_ROLE`.

**Events Emitted:**

* `ResolveLiquidationDispute(address partyA, address[] partyBs, int256[] amounts, bool disputed, bytes liquidationId)`
