# Muon Architecture

Muon is the off-chain computation layer that provides cryptographically signed data to Symmio. All critical operation in the protocol — opening positions, closing positions, liquidations, deallocations — requires a valid Muon signature proving the current state of prices and unrealized PnL.

### Why Symmio Needs an Oracle

Symmio is a bilateral derivatives protocol. At any moment, the protocol needs to know:

* **Current prices** for all trading symbols
* **Unrealized PnL (uPnL)** for PartyA and PartyB
* **Whether a party is solvent** and can execute their requested action

Calculating uPnL on-chain would require iterating through all open positions and fetching current prices — prohibitively expensive on most chains. Muon solves this by performing calculations off-chain and delivering signed attestations that the contracts can verify cheaply.

### Dual-Layer Signature Verification

Symmio doesn't trust a single signer. Every Muon signature passes through **two independent verification layers** before the contract accepts it.

#### Layer 1: TSS (Threshold Signature Scheme)

Muon operates a distributed network of nodes. When a signature request comes in, multiple nodes independently:

1. Fetch price data from exchanges
2. Calculate the requested values (uPnL, solvency, etc.)
3. Contribute to a threshold signature

The result is a Schnorr signature that proves a threshold of nodes agreed on the data. The contract verifies this against the stored `muonPublicKey` in MuonStorage.

```solidity
// Verification happens in LibMuonV04ClientBase.muonVerify()
// Checks Schnorr signature against muonLayout.muonPublicKey
```

#### Layer 2: Gateway ECDSA

After TSS verification, the contract performs a second check: it recovers the signer from a standard ECDSA signature and verifies it matches the registered `validGateway` address.

```solidity
// In LibMuon.verifyTSSAndGateway()
address gatewayRecovered = hash.recover(gatewaySignature);
require(gatewayRecovered == muonLayout.validGateway, "Invalid gateway");
```

### What Gets Signed

Different operations require different signature types. Each includes specific data fields that get hashed and signed.

#### SingleUpnlSig

Used for: `deallocate()`, `sendQuote()`

Contains:

* `partyA` address
* `nonce` (replay protection)
* `uPnL` value
* `timestamp`
* `chainId`

#### SingleUpnlAndPriceSig

Used for: `sendQuote()` (with price validation)

Contains everything in SingleUpnlSig plus:

* `symbolId`
* `price` for that symbol

#### PairUpnlSig

Used for: `openPosition()`, `fillCloseRequest()`

Contains:

* `partyA` address
* `partyB` address
* `partyA nonce`
* `partyB nonce`
* `partyA uPnL`
* `partyB uPnL`
* `timestamp`
* `chainId`

#### PairUpnlAndPriceSig

Used for: Position operations requiring price verification

Contains everything in PairUpnlSig plus:

* `symbolId`
* `price`

#### LiquidationSig

Used for: `liquidatePartyA()`, `liquidatePartyB()`

Contains:

* Party addresses
* Nonces
* Liquidation prices for all relevant symbols
* Total uPnL
* Symbol IDs array
* `timestamp`
* `chainId`

### Replay Protection via Nonces

Muon signatures include **two distinct identifiers** that serve different purposes:

#### reqId (Muon Request ID)

Each Muon request generates a unique `reqId`. This is included in the signed hash:

```solidity
bytes32 hash = keccak256(
    abi.encodePacked(
        muonLayout.muonAppId,
        upnlSig.reqId,           // <-- Muon request ID
        address(this),
        partyA,
        ...
    )
);
```

The `reqId` serves as request identification within the Muon network&#x20;

#### Contract Nonces (On-Chain State Binding)

The contract maintains nonce counters in AccountStorage:

```solidity
mapping(address => uint256) public partyANonces;
mapping(address => mapping(address => uint256)) public partyBNonces;
```

This nonce is included in the signed hash. The contract then verifies the signature was made with the **current** nonce value:

```solidity
bytes32 hash = keccak256(
    abi.encodePacked(
        ...
        AccountStorage.layout().partyANonces[partyA],  // Current on-chain nonce
        ...
    )
);
```

#### How Replay Protection Works

1. Muon reads current on-chain nonce (e.g., `5`)
2. Muon signs data including that nonce
3. User submits signature to contract
4. Contract verifies signature hash includes current nonce (`5`) ✓
5. State changes → nonce increments to `6`

***

### Signature Expiration

Signatures have a limited validity window defined by `upnlValidTime` in MuonStorage:

```solidity
require(
    block.timestamp <= signature.timestamp + muonLayout.upnlValidTime,
    "Signature expired"
);
```

This prevents old signatures from being used after market conditions have changed significantly.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.symm.io/security-and-architecture/muon-architecture.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
