# LibMuon (0.8.4)

## LibMuon Library (0.8.4)

The **LibMuon** library provides essential cryptographic functions for the SYMM ecosystem. Its primary responsibility is to verify signed data used by SYMM contracts. This includes validating uPNL calculations, price data, liquidation events, and settlement data. It relies on trusted Muon signatures (via a TSS mechanism) and gateway signature verification to ensure that all data is authentic and has not been tampered with.

***

### Core Functions

#### getChainId

**Description:**\
Retrieves the unique chain ID of the blockchain on which the contract is executing. This value is used to ensure that data is tied to the correct network context.

**Implementation:**

```solidity
function getChainId() internal view returns (uint256 id) {
    assembly {
        id := chainid()
    }
}
```

***

#### verifyTSSAndGateway

**Description:**\
Performs dual signature verification:

1. **TSS Verification:**\
   Uses the Muon TSS (via `LibMuonV04ClientBase.muonVerify`) to verify that the data’s hash is signed by the correct Muon public key.
2. **Gateway Signature Verification:**\
   Converts the hash to an Ethereum signed message hash and recovers the signer’s address. This address must match the valid gateway address stored in MuonStorage.

**Parameters:**

* `hash`: The hash of the data to verify.
* `sign`: A `SchnorrSign` structure containing the TSS signature.
* `gatewaySignature`: The gateway signature as a byte array.

**Implementation:**

```solidity
function verifyTSSAndGateway(
    bytes32 hash,
    SchnorrSign memory sign,
    bytes memory gatewaySignature
) internal view {
    bool verified = LibMuonV04ClientBase.muonVerify(uint256(hash), sign, MuonStorage.layout().muonPublicKey);
    require(verified, "LibMuon: TSS not verified");

    hash = hash.toEthSignedMessageHash();
    address gatewaySignatureSigner = hash.recover(gatewaySignature);
    require(gatewaySignatureSigner == MuonStorage.layout().validGateway, "LibMuon: Gateway is not valid");
}
```

***

#### verifyPartyBUpnl

**Description:**\
Verifies the uPNL data for Party B. This function checks that the provided signature has not expired, constructs a hash from key parameters (including Party B’s nonce, the uPNL value, and the current chain ID), and then calls `verifyTSSAndGateway` for final verification.

**Parameters:**

* `upnlSig`: A `SingleUpnlSig` structure containing uPNL data and signature details.
* `partyB`: Address of Party B.
* `partyA`: Address of Party A.

**Implementation:**

```solidity
function verifyPartyBUpnl(SingleUpnlSig memory upnlSig, address partyB, address partyA) internal view {
    MuonStorage.Layout storage muonLayout = MuonStorage.layout();
    require(block.timestamp <= upnlSig.timestamp + muonLayout.upnlValidTime, "LibMuon: Expired signature");
    bytes32 hash = keccak256(
        abi.encodePacked(
            muonLayout.muonAppId,
            upnlSig.reqId,
            address(this),
            partyB,
            partyA,
            AccountStorage.layout().partyBNonces[partyB][partyA],
            upnlSig.upnl,
            upnlSig.timestamp,
            getChainId()
        )
    );
    verifyTSSAndGateway(hash, upnlSig.sigs, upnlSig.gatewaySignature);
}
```

***

### LibMuonAccount

#### verifyPartyAUpnl

**Description:**\
Verifies the uPNL data for Party A. Constructs a hash using Party A’s nonce and uPNL value, then validates it using the TSS and gateway verification.

**Parameters:**

* `upnlSig`: A `SingleUpnlSig` structure.
* `partyA`: Address of Party A.

**Implementation:**

```solidity
function verifyPartyAUpnl(SingleUpnlSig memory upnlSig, address partyA) internal view {
    MuonStorage.Layout storage muonLayout = MuonStorage.layout();
    require(block.timestamp <= upnlSig.timestamp + muonLayout.upnlValidTime, "LibMuon: Expired signature");
    bytes32 hash = keccak256(
        abi.encodePacked(
            muonLayout.muonAppId,
            upnlSig.reqId,
            address(this),
            partyA,
            AccountStorage.layout().partyANonces[partyA],
            upnlSig.upnl,
            upnlSig.timestamp,
            LibMuon.getChainId()
        )
    );
    LibMuon.verifyTSSAndGateway(hash, upnlSig.sigs, upnlSig.gatewaySignature);
}
```

#### verifyPartyBUpnl (in LibMuonAccount)

**Description:**\
Delegates to the core `verifyPartyBUpnl` function from LibMuon to validate Party B’s uPNL data.

```solidity
function verifyPartyBUpnl(SingleUpnlSig memory upnlSig, address partyB, address partyA) internal view {
    LibMuon.verifyPartyBUpnl(upnlSig, partyB, partyA);
}
```

***

### LibMuonForceActions

#### verifyHighLowPrice

**Description:**\
Verifies that the provided high, low, current, and average price data (contained in a `HighLowPriceSig` structure) are authentic and within valid time limits. It constructs a hash that includes nonces and market price data and verifies the signature.

**Parameters:**

* `sig`: A `HighLowPriceSig` structure.
* `partyB`: Address of Party B.
* `partyA`: Address of Party A.
* `symbolId`: Identifier of the trading symbol.

**Implementation:**

```solidity
function verifyHighLowPrice(HighLowPriceSig memory sig, address partyB, address partyA, uint256 symbolId) internal view {
    MuonStorage.Layout storage muonLayout = MuonStorage.layout();
    require(block.timestamp <= sig.timestamp + muonLayout.upnlValidTime, "LibMuon: Expired signature");
    bytes32 hash = keccak256(
        abi.encodePacked(
            muonLayout.muonAppId,
            sig.reqId,
            address(this),
            partyB,
            partyA,
            AccountStorage.layout().partyBNonces[partyB][partyA],
            AccountStorage.layout().partyANonces[partyA],
            sig.upnlPartyB,
            sig.upnlPartyA,
            symbolId,
            sig.currentPrice,
            sig.startTime,
            sig.endTime,
            sig.lowest,
            sig.highest,
            sig.averagePrice,
            sig.timestamp,
            LibMuon.getChainId()
        )
    );
    LibMuon.verifyTSSAndGateway(hash, sig.sigs, sig.gatewaySignature);
}
```

***

### LibMuonFundingRate

#### verifyPairUpnl

**Description:**\
Verifies the pair uPNL data used for funding rate calculations by constructing a hash that includes both Party B and Party A's uPNL values along with their nonces and verifying the signature.

**Parameters:**

* `upnlSig`: A `PairUpnlSig` structure.
* `partyB`: Address of Party B.
* `partyA`: Address of Party A.

**Implementation:**

```solidity
function verifyPairUpnl(PairUpnlSig memory upnlSig, address partyB, address partyA) internal view {
    MuonStorage.Layout storage muonLayout = MuonStorage.layout();
    require(block.timestamp <= upnlSig.timestamp + muonLayout.upnlValidTime, "LibMuon: Expired signature");
    bytes32 hash = keccak256(
        abi.encodePacked(
            muonLayout.muonAppId,
            upnlSig.reqId,
            address(this),
            partyB,
            partyA,
            AccountStorage.layout().partyBNonces[partyB][partyA],
            AccountStorage.layout().partyANonces[partyA],
            upnlSig.upnlPartyB,
            upnlSig.upnlPartyA,
            upnlSig.timestamp,
            LibMuon.getChainId()
        )
    );
    LibMuon.verifyTSSAndGateway(hash, upnlSig.sigs, upnlSig.gatewaySignature);
}
```

***

### LibMuonLiquidation

#### verifyLiquidationSig

**Description:**\
Validates the liquidation signal for Party A by ensuring that the prices and symbol IDs arrays have matching lengths, then constructing a hash from key liquidation parameters (including the liquidation ID, uPNL values, and nonce) and verifying it.

**Parameters:**

* `liquidationSig`: A `LiquidationSig` structure.
* `partyA`: Address of Party A.

**Implementation:**

```solidity
function verifyLiquidationSig(LiquidationSig memory liquidationSig, address partyA) internal view {
    MuonStorage.Layout storage muonLayout = MuonStorage.layout();
    require(liquidationSig.prices.length == liquidationSig.symbolIds.length, "LibMuon: Invalid length");
    bytes32 hash = keccak256(
        abi.encodePacked(
            muonLayout.muonAppId,
            liquidationSig.reqId,
            liquidationSig.liquidationId,
            address(this),
            "verifyLiquidationSig",
            partyA,
            AccountStorage.layout().partyANonces[partyA],
            liquidationSig.upnl,
            liquidationSig.totalUnrealizedLoss,
            liquidationSig.symbolIds,
            liquidationSig.prices,
            liquidationSig.timestamp,
            LibMuon.getChainId()
        )
    );
    LibMuon.verifyTSSAndGateway(hash, liquidationSig.sigs, liquidationSig.gatewaySignature);
}
```

#### verifyDeferredLiquidationSig

**Description:**\
Verifies a deferred liquidation signature by including additional parameters (e.g. liquidation block number, timestamp, and allocated balance) in the hash. This ensures that deferred liquidation data is valid and securely signed.

**Parameters:**

* `liquidationSig`: A `DeferredLiquidationSig` structure.
* `partyA`: Address of Party A.

**Implementation:**

```solidity
function verifyDeferredLiquidationSig(DeferredLiquidationSig memory liquidationSig, address partyA) internal view {
    MuonStorage.Layout storage muonLayout = MuonStorage.layout();
    require(liquidationSig.prices.length == liquidationSig.symbolIds.length, "LibMuon: Invalid length");
    bytes32 hash = keccak256(
        abi.encodePacked(
            muonLayout.muonAppId,
            liquidationSig.reqId,
            liquidationSig.liquidationId,
            address(this),
            "verifyDeferredLiquidationSig",
            partyA,
            AccountStorage.layout().partyANonces[partyA],
            liquidationSig.upnl,
            liquidationSig.totalUnrealizedLoss,
            liquidationSig.symbolIds,
            liquidationSig.prices,
            liquidationSig.timestamp,
            liquidationSig.liquidationBlockNumber,
            liquidationSig.liquidationTimestamp,
            liquidationSig.liquidationAllocatedBalance,
            LibMuon.getChainId()
        )
    );
    LibMuon.verifyTSSAndGateway(hash, liquidationSig.sigs, liquidationSig.gatewaySignature);
}
```

#### verifyQuotePrices

**Description:**\
Ensures the integrity of quote price data by verifying that the prices array matches the quote IDs array, constructing a corresponding hash, and then validating the signatures.

**Parameters:**

* `priceSig`: A `QuotePriceSig` structure containing arrays of quote IDs and their prices.

**Implementation:**

```solidity
function verifyQuotePrices(QuotePriceSig memory priceSig) internal view {
    MuonStorage.Layout storage muonLayout = MuonStorage.layout();
    require(priceSig.prices.length == priceSig.quoteIds.length, "LibMuon: Invalid length");
    bytes32 hash = keccak256(
        abi.encodePacked(
            muonLayout.muonAppId,
            priceSig.reqId,
            address(this),
            priceSig.quoteIds,
            priceSig.prices,
            priceSig.timestamp,
            LibMuon.getChainId()
        )
    );
    LibMuon.verifyTSSAndGateway(hash, priceSig.sigs, priceSig.gatewaySignature);
}
```

***

### LibMuonPartyB

#### verifyPairUpnlAndPrice

**Description:**\
Verifies combined uPNL data and price information for both Party B and Party A for a specific symbol. It constructs a hash using the nonces, uPNL values, and the price, then validates the signatures.

**Parameters:**

* `upnlSig`: A `PairUpnlAndPriceSig` structure.
* `partyB`: Address of Party B.
* `partyA`: Address of Party A.
* `symbolId`: Identifier of the trading symbol.

**Implementation:**

```solidity
function verifyPairUpnlAndPrice(
    PairUpnlAndPriceSig memory upnlSig,
    address partyB,
    address partyA,
    uint256 symbolId
) internal view {
    MuonStorage.Layout storage muonLayout = MuonStorage.layout();
    require(block.timestamp <= upnlSig.timestamp + muonLayout.upnlValidTime, "LibMuon: Expired signature");
    bytes32 hash = keccak256(
        abi.encodePacked(
            muonLayout.muonAppId,
            upnlSig.reqId,
            address(this),
            partyB,
            partyA,
            AccountStorage.layout().partyBNonces[partyB][partyA],
            AccountStorage.layout().partyANonces[partyA],
            upnlSig.upnlPartyB,
            upnlSig.upnlPartyA,
            symbolId,
            upnlSig.price,
            upnlSig.timestamp,
            LibMuon.getChainId()
        )
    );
    LibMuon.verifyTSSAndGateway(hash, upnlSig.sigs, upnlSig.gatewaySignature);
}
```

#### verifyPartyBUpnl (LibMuonPartyB)

**Description:**\
Delegates to the core LibMuon function to verify Party B’s uPNL data.

**Implementation:**

```solidity
function verifyPartyBUpnl(
    SingleUpnlSig memory upnlSig,
    address partyB,
    address partyA
) internal view {
    LibMuon.verifyPartyBUpnl(upnlSig, partyB, partyA);
}
```

***

### LibMuonSettlement

#### verifySettlement

**Description:**\
Validates the settlement data for a set of quotes by constructing a hash that aggregates critical settlement details (including quote settlement data, nonces, and uPNL values) and then verifying the signature with the TSS and gateway mechanisms.

**Parameters:**

* `settleSig`: A `SettlementSig` structure containing:
  * `reqId`, an array of `quotesSettlementsData`, `upnlPartyBs`, `upnlPartyA`, `timestamp`, and signature data.
* `partyA`: Address of Party A.

**Implementation:**

```solidity
function verifySettlement(SettlementSig memory settleSig, address partyA) internal view {
    MuonStorage.Layout storage muonLayout = MuonStorage.layout();
    uint256 length = settleSig.quotesSettlementsData.length;
    bytes memory encodedData;
    uint256[] memory nonces = new uint256[](length);
    for (uint8 i = 0; i < length; i++) {
        nonces[i] = AccountStorage.layout().partyBNonces[QuoteStorage.layout().quotes[settleSig.quotesSettlementsData[i].quoteId].partyB][partyA];
        encodedData = abi.encodePacked(
            encodedData,
            settleSig.quotesSettlementsData[i].quoteId,
            settleSig.quotesSettlementsData[i].currentPrice,
            settleSig.quotesSettlementsData[i].partyBUpnlIndex
        );
    }
    bytes32 hash = keccak256(
        abi.encodePacked(
            muonLayout.muonAppId,
            settleSig.reqId,
            address(this),
            "verifySettlement",
            nonces,
            AccountStorage.layout().partyANonces[partyA],
            encodedData,
            settleSig.upnlPartyBs,
            settleSig.upnlPartyA,
            settleSig.timestamp,
            LibMuon.getChainId()
        )
    );
    LibMuon.verifyTSSAndGateway(hash, settleSig.sigs, settleSig.gatewaySignature);
}
```
