Settlement Facet (0.8.4)

Overview

In Symmio, users can use their unrealized profits to open new positions, effectively allowing their UPNL to back them up from being liquidated. While this provides greater flexibility and leverage for users, it introduces a potential issue during the closing of positions. When a position is closed, the losing party must pay the profit to the winning party from their allocated balances, i.e., realized PNL, not from UPNL.

Consider a scenario where a user has multiple positions:

  • Position A: Significant unrealized profit.

  • Position B: New position opened using the unrealized profit from Position A.

If Position B incurs a loss, the user may not have sufficient allocated balance to cover the loss when closing Position B, even though their overall UPNL is positive. This situation prevents the hedger (counterparty) from being able to fill the close request, as the required funds are not available in the user's allocated balance.

Previously, we mitigated this by warning users through the frontend that they couldn't close certain positions due to insufficient realized PNL, advising them to close profitable positions first. However, with the introduction of automated features like stop-loss and take-profit bots (e.g., in IntentX), this manual intervention is no longer feasible.

Additionally, users could exploit the force close option by quickly allocating more funds and forcing the close of their positions, potentially leading to losses for hedgers if they cannot react in time.

To resolve these issues, we've introduced the settleUpnl method, which allows hedgers to settle a portion of the user's unrealized PNL, effectively converting it into realized PNL. This enables the hedger to fill the user's close requests, even when the user lacks sufficient allocated balance.

The settleUpnl method functions similarly to our implementation for funding rates, where we updated the openedPrice of quotes.

Detailed Example

Let's illustrate how the settleUpnl method works with a detailed example.

Scenario

Bob (Party A) has three open positions and zero allocated balance:

  1. Position 1 with Rasa Hedger (Party B1):

    • Unrealized Profit: $300

    • Quote ID: 1

  2. Position 2 with PerpsHub Hedger (Party B2):

    • Unrealized Profit: $100

    • Quote ID: 2

  3. Position 3 with PerpsHub Hedger (Party B2):

    • Unrealized Loss: $250

    • Quote ID: 3

Bob wants to close Position 3, which has an unrealized loss of $250. However, since Bob has zero allocated balance, he cannot cover this loss upon closing.

Problem

PerpsHub Hedger (Party B2) cannot fill Bob's close request for Position 3 because Bob doesn't have enough allocated balance to cover the $250 loss. Even though Bob has an overall positive UPNL ($150 net profit), his profits are unrealized and cannot be used to settle the loss directly.

Solution with settleUpnl

To enable the closing of Position 3, PerpsHub Hedger needs to settle Bob's unrealized profits from Positions 1 and 2, converting them into realized profits. This will increase Bob's allocated balance sufficiently to cover the loss.

  1. PerpsHub only needs to settle enough unrealized profit to cover the $250 loss. They can achieve this by settling Position 2 and part of Position 1. Hedgers should prioritize settling UPNLs from their own positions with users, as they face a cooldown period when settling positions involving other hedgers.

  2. PerpsHub initiates settleUpnl for Position1 and Position2:

SettlementSig memory settleSig = SettlementSig({
    reqId: bytes("uniqueRequestId"),
    timestamp: block.timestamp,
    quotesSettlementsData: [
        QuoteSettlementData({quoteId: 1, currentPrice: currentPricePos1, partyBUpnlIndex: 0}),
        QuoteSettlementData({quoteId: 2, currentPrice: currentPricePos2, partyBUpnlIndex: 1})
    ],
    upnlPartyBs: [-300, 150], // Rasa's upnl change, PerpsHub's upnl change
    upnlPartyA: 150, // Bob's total upnl being settled
    gatewaySignature: muonSignature,
    sigs: schnorrSignature
});

uint256[] memory updatedPrices = [newPricePos1, newPricePos2];

perpsHubHedger.settleUpnl(settleSig, updatedPrices, bobAddress);
  1. This call will:

    • Update the opened prices for Position1 and Position2

    • Realize $150 profit for Position1 and $100 profit for Position2

    • Adjust Bob's allocated balance: +$150 +$100 = $250 increase

    • Adjust Rasa's and PerpsHub's allocated balances accordingly

  2. After settlement, Bob's state:

    • Allocated balance: $250

    • Position2 has fully settled profit

    • Position1 has partially settled profit ($150 out of $300)

    • Position3 remains unchanged

  3. PerpsHub can now successfully fill the close request for Position3, as Bob has sufficient allocated balance ($250) to cover the loss ($250).


Overview

The Settlement Facet allows Party B to finalize the settlement of UPnL for Party A’s positions. During settlement, the UPnL data is verified using a Muon signature and then processed to adjust the open prices for the affected quotes. The resulting changes update Party A’s allocated balance and yield new allocated balances for the involved Party Bs. This process ensures that the financial state of the positions reflects the latest market conditions.


settleUpnl

Description: The settleUpnl function allows Party B to settle the UPnL for a set of quotes associated with Party A. It processes settlement data provided in the SettlementSig structure along with an array of updated prices. Once the settlement is completed, the function emits an event with the settlement details and the new allocated balances.

Function Signature:

function settleUpnl(
    SettlementSig memory settlementSig,
    uint256[] memory updatedPrices,
    address partyA
) external whenNotPartyBActionsPaused onlyPartyB notLiquidatedPartyA(partyA);

Parameters:

  • settlementSig: A structure containing the settlement data. Its fields include:

    • reqId: Request identifier.

    • timestamp: The timestamp when the settlement request was made.

    • quotesSettlementsData: An array of QuoteSettlementData structures that detail settlement data for each quote.

    • upnlPartyBs: An array of UPnL values for the Party Bs.

    • upnlPartyA: The UPnL value for Party A.

    • gatewaySignature: A Muon gateway signature.

    • SettlementSig: A structure with signature data including aSchnorrSign .

    struct SettlementSig {
    	bytes reqId;
    	uint256 timestamp;
    	QuoteSettlementData[] quotesSettlementsData;
    	int256[] upnlPartyBs;
    	int256 upnlPartyA;
    	bytes gatewaySignature;
    	SchnorrSign sigs;
    }
  • updatedPrices: An array of new prices to be applied as the new openedPrice for the specified quotes. These should be fetched from the appropriate muon query. More information here

  • partyA: The address of Party A whose position settlement is being processed.

Example Usage:

// Prepare settlement data (this would typically be obtained off-chain)
SettlementSig memory settleSig = SettlementSig({
    reqId: "unique-request-id",
    timestamp: block.timestamp,
    quotesSettlementsData: settlementDataArray,  // An array of QuoteSettlementData structs from Muon
    upnlPartyBs: new int256[](numberOfPartyBs),
    upnlPartyA: -500,  // Example UPnL for Party A
    gatewaySignature: "0x...",
    sigs: schnorrSignatureData  // A SchnorrSign struct
});

uint256[] memory newPrices = new uint256[](settlementDataArray.prices);
address partyAAddress = 0x...; //partyA

// Party B calls settleUpnl to finalize the settlement for Party A's positions
diamond.settleUpnl(settleSig, newPrices, partyAAddress);

Internal Processing:

  • The function:

    • Verifies the settlement signature via LibMuonSettlement.verifySettlement.

    • Calls LibSettlement.settleUpnl to process the settlement and update balances.

    • Returns an array of new allocated balances for Party Bs.

  • The function then emits the settlement event with the settlement details.


Settlement Event

Event Emitted:

event SettleUpnl(
    QuoteSettlementData[] settlementData,
    uint256[] updatedPrices,
    address partyA,
    uint256 newPartyAAllocatedBalance,
    uint256[] newPartyBsAllocatedBalances
);

Event Details:

  • settlementData: An array of QuoteSettlementData structures detailing the settlement for each quote.

  • updatedPrices: The array of new prices applied to the quotes.

  • partyA: The address of Party A whose allocated balance is updated.

  • newPartyAAllocatedBalance: The new allocated balance for Party A after settlement.

  • newPartyBsAllocatedBalances: An array representing the new allocated balances for each of the Party Bs involved.

Last updated