# View Facet Aggregate

The ViewFacet Aggregate provides read-only functions for querying pre-aggregated position and funding data. For example: if a party has 5,000 open positions spread across 50 symbols, the old system iterated through all 5,000 quotes. The aggregated system only iterates through the 50 symbols, since it maintains running totals per symbol. All functions are `view` and do not modify state.

This facet is new in v0.8.5. Previously, calculating uPnL required iterating through all individual quotes. With potentially thousands of quotes per party, this was computationally expensive. The aggregated system maintains running totals that are updated incrementally whenever positions are opened, closed, or funding is charged.

***

### Overview

The ViewFacet Aggregate is organized into the following categories:

* **Position Aggregates:** Aggregated open amounts and average open prices per symbol, grouped by position type (LONG/SHORT).
* **Funding Aggregates:** Weighted paid funding and computed funding debt per symbol.
* **Active Symbols:** Lists of symbol IDs where a party has open positions, enabling efficient iteration.
* **Paginated Batch Functions:** Positions and funding debt across all active symbols in paginated calls.
* **uPnL Data Functions:** Convenience functions that return position data and funding debt together, providing everything needed for off-chain uPnL calculation in a single call.

***

### Key Data Structures

```solidity
struct AggregatedPositionAmount {
    PositionType positionType;  // LONG or SHORT
    uint256 aggregatedAmount;   // Total open position size
    uint256 avgOpenPrice;       // aggregatedNotional / aggregatedAmount
}

struct AggregatedPositionBySymbol {
    uint256 symbolId;
    PositionType positionType;
    uint256 aggregatedOpenAmount;
    uint256 avgOpenPrice;
}

struct AggregatedFundingDebtBySymbol {
    uint256 symbolId;
    PositionType positionType;
    int256 fundingDebt;         // Positive = party owes, negative = party is owed
}

struct UpnlData {
    uint256 symbolId;
    PositionType positionType;
    uint256 aggregatedAmount;
    uint256 avgOpenPrice;
    int256 fundingDebt;
}
```

***

### uPnL Calculation Formula

With aggregated data, uPnL can be calculated off-chain per symbol:

```
LONG uPnL:  (currentPrice - avgOpenPrice) × aggregatedAmount / 1e18 - fundingDebt
SHORT uPnL: (avgOpenPrice - currentPrice) × aggregatedAmount / 1e18 - fundingDebt

Total uPnL = Σ(per-symbol uPnL for all active symbols)
```

PartyB's uPnL is the opposite of PartyA's (positions are mirrored).

***

### Position Aggregate Functions

Per-symbol aggregated positions, returning LONG and SHORT amounts with average open prices.

| Function                                                                 | Parameters             | Description                                                |
| ------------------------------------------------------------------------ | ---------------------- | ---------------------------------------------------------- |
| `getPartyBAggregatedPositionBySymbol(partyB, symbolId)`                  | PartyB, symbol         | PartyB's global position for a symbol (across all PartyAs) |
| `getPartyBAggregatedPositionBySymbolPerPartyA(partyB, partyA, symbolId)` | PartyB, PartyA, symbol | PartyB's position with a specific PartyA                   |
| `getPartyAAggregatedPositionBySymbolPerPartyB(partyA, partyB, symbolId)` | PartyA, PartyB, symbol | PartyA's position with a specific PartyB                   |

Each returns two `AggregatedPositionAmount` structs (one for LONG, one for SHORT).

***

### Funding Aggregate Functions

Raw weighted paid funding values and computed funding debt.

| Function                                                                      | Parameters                   | Returns                                   |
| ----------------------------------------------------------------------------- | ---------------------------- | ----------------------------------------- |
| `getPartyAAggregatedFundingPerPartyB(partyA, partyB, symbolId, positionType)` | PartyA, PartyB, symbol, type | `weightedPaidFunding` (raw aggregate)     |
| `getPartyBAggregatedFundingPerPartyA(partyB, partyA, symbolId, positionType)` | PartyB, PartyA, symbol, type | `weightedPaidFunding` (raw aggregate)     |
| `getPartyBAggregatedFunding(partyB, symbolId, positionType)`                  | PartyB, symbol, type         | Global `weightedPaidFunding` (cross mode) |
| `getPartyAAggregateFundingDebt(partyA, partyB, symbolId, positionType)`       | PartyA, PartyB, symbol, type | Computed funding debt (positive = owes)   |
| `getPartyBAggregateFundingDebt(partyB, partyA, symbolId, positionType)`       | PartyB, PartyA, symbol, type | Computed funding debt per PartyA          |
| `getPartyBGlobalAggregateFundingDebt(partyB, symbolId, positionType)`         | PartyB, symbol, type         | Global funding debt (cross mode)          |

***

### Active Symbols Functions

Lists of symbol IDs where a party has open positions. All paginated functions accept `start` and `size` parameters.

| Function                                                       | Parameters                 | Returns                                  |
| -------------------------------------------------------------- | -------------------------- | ---------------------------------------- |
| `getPartyBActiveSymbolsCount(partyB)`                          | PartyB                     | Count of globally active symbols         |
| `getPartyBActiveSymbols(partyB, start, size)`                  | PartyB, pagination         | Paginated array of symbol IDs            |
| `getPartyBActiveSymbolsCountPerPartyA(partyB, partyA)`         | PartyB, PartyA             | Count of active symbols with this PartyA |
| `getPartyBActiveSymbolsPerPartyA(partyB, partyA, start, size)` | PartyB, PartyA, pagination | Paginated symbol IDs with this PartyA    |
| `getPartyAActiveSymbolsCountPerPartyB(partyA, partyB)`         | PartyA, PartyB             | Count of active symbols with this PartyB |
| `getPartyAActiveSymbolsPerPartyB(partyA, partyB, start, size)` | PartyA, PartyB, pagination | Paginated symbol IDs with this PartyB    |

***

### Paginated Batch Functions

These iterate through active symbols and return aggregated data in bulk. Each accepts `start` and `size` for pagination over the active symbols array. Results only include symbols/position types with non-zero open amounts.

#### Position Batches

| Function                                                                            | Parameters                 | Returns                                                         |
| ----------------------------------------------------------------------------------- | -------------------------- | --------------------------------------------------------------- |
| `getPartyBAggregatedPositionsByActiveSymbols(partyB, start, size)`                  | PartyB, pagination         | `AggregatedPositionBySymbol[]` — global positions               |
| `getPartyAAggregatedPositionsByActiveSymbolsPerPartyB(partyA, partyB, start, size)` | PartyA, PartyB, pagination | `AggregatedPositionBySymbol[]` — PartyA's positions with PartyB |
| `getPartyBAggregatedPositionsByActiveSymbolsPerPartyA(partyB, partyA, start, size)` | PartyB, PartyA, pagination | `AggregatedPositionBySymbol[]` — PartyB's positions with PartyA |

#### Funding Debt Batches

| Function                                                                    | Parameters                 | Returns                                        |
| --------------------------------------------------------------------------- | -------------------------- | ---------------------------------------------- |
| `getPartyAAggregateFundingDebtByActiveSymbols(partyA, partyB, start, size)` | PartyA, PartyB, pagination | `AggregatedFundingDebtBySymbol[]`              |
| `getPartyBAggregateFundingDebtByActiveSymbols(partyB, partyA, start, size)` | PartyB, PartyA, pagination | `AggregatedFundingDebtBySymbol[]`              |
| `getPartyBGlobalAggregateFundingDebtByActiveSymbols(partyB, start, size)`   | PartyB, pagination         | `AggregatedFundingDebtBySymbol[]` — cross mode |

***

### uPnL Data Functions (Recommended)

These convenience functions return **both position data and funding debt in a single call**, providing everything needed for off-chain uPnL calculation. They are the recommended entry point for integrators.

| Function                                         | Parameters                 | Returns      | uPnL Formula                                       |
| ------------------------------------------------ | -------------------------- | ------------ | -------------------------------------------------- |
| `getPartyAUpnlData(partyA, partyB, start, size)` | PartyA, PartyB, pagination | `UpnlData[]` | LONG: `(price - avgOpen) × amount / 1e18 - debt`   |
| `getPartyBUpnlData(partyB, partyA, start, size)` | PartyB, PartyA, pagination | `UpnlData[]` | LONG: `(avgOpen - price) × amount / 1e18 - debt`   |
| `getPartyBGlobalUpnlData(partyB, start, size)`   | PartyB, pagination         | `UpnlData[]` | Same as PartyB but across all PartyAs (cross mode) |

Note that PartyB's position uPnL is the opposite of PartyA's (the counterparty relationship is mirrored).

#### Usage Example

```javascript
let totalUpnl = 0n;
let start = 0;

while (true) {
    const data = await viewFacet.getPartyAUpnlData(partyA, partyB, start, 100);
    if (data.length === 0) break;

    for (const d of data) {
        const price = await getPrice(d.symbolId);
        const positionUpnl = d.positionType === LONG
            ? (price - d.avgOpenPrice) * d.aggregatedAmount / 1e18n
            : (d.avgOpenPrice - price) * d.aggregatedAmount / 1e18n;
        totalUpnl += positionUpnl - d.fundingDebt;
    }
    start += 100;
}
```
