# Pairs and events

> Which pairs Somnia Price Feeds tracks, the events it emits each tick, and how to request a new pair.

## Tracked pairs

Read the live set from the contract: `symbols()` for the list of pairs, `activeIndices()` with `symbolOf(index)` for the indexed form, and `isTracked(pair)` for a single check. The current sets, as an indication only:

| Network | Pairs (as of 10 Aug 2026; read the contract, this list drifts) |
| --- | --- |
| Mainnet | 10 pairs: `BTC/USDC`, `ETH/USDC`, `SOL/USDC`, `SOMI/USDC`, `HYPE/USDC`, `XRP/USDC`, `DOGE/USDC`, `BNB/USDC`, `ADA/USDC`, `SUI/USDC` |
| Testnet | 28 pairs: the mainnet ten plus `LINK/USDC`, `AVAX/USDC`, `XLM/USDC`, `NEAR/USDC`, `ZEC/USDC`, `WLD/USDC`, `TAO/USDC`, `FIL/USDC`, `AAVE/USDC`, `LTC/USDC`, `ENA/USDC`, `UNI/USDC`, `ONDO/USDC`, `PEPE/USDC`, `XMR/USDC`, `PUMP/USDC`, `ASTER/USDC`, `BCH/USDT` |

Changes emit `SymbolAdded(index, symbol)` and `SymbolRemoved(index, symbol)`. A removal retires its index rather than reusing it, so a cached `index → pair` mapping never shifts.

The one case that **does** invalidate your cache is `setSymbols`, which replaces the whole set: every pair is retired and added again under a *new* index, even one that appears in both lists. It emits `SymbolsReplaced(newCount)` alongside the events for each pair. If you cache indices, watch for it and resolve them again.

## Events

| Event | When |
| --- | --- |
| `PricesUpdated(requestId, updatedAtMs, indices[], prices[], marks[], sourceUpdatedAtsMs[], resyncedBits)` | Once per tick: **one batched log covering every pair written** |
| `SymbolAdded(index, symbol)` / `SymbolRemoved(index, symbol)` | A pair is added or removed |
| `SymbolsReplaced(newCount)` | The whole set is replaced |

The `PricesUpdated` arrays line up by position. **Only pairs priced in this tick appear**: a tracked pair the agents left unpriced is simply missing, and its absence is the signal that it went unpriced. Bit `p` of `resyncedBits` is set when the mark of `indices[p]` resynced. `sourceUpdatedAtsMs` here is at full precision, taken before the onchain age cap, so offchain consumers get exact market ages.

Other events, such as `AgentRequestKicked`, `SubscriptionScheduled`, `SubscriptionChainBroken` and `AgentResponseDropped`, are for operators and are not part of what consumers can rely on.

## Requesting a new pair

Adding a pair is an owner-only onchain call made by the protocol multisig, so you can't add one yourself. Ask in the `#dev-chat` channel of the [Somnia Discord](https://discord.com/invite/somnia) with:

1. **The pair**, ccxt-style, with the quote asset you want (`SOL/USDC`, not `SOL`). Ask for `USDC` unless you need another quote: every mainnet pair is quoted in `USDC`, and testnet has a single exception, `BCH/USDT`.
2. **The venues** you consider authoritative, and any you want excluded.
3. **What you're building**: settlement, liquidation or display. This sets how much thin-book behaviour matters for the pair.
4. **The network**: mainnet, testnet or both.

What to expect:

- **A liquidity check.** A pair with thin or single-venue depth is often priced by one exchange alone, and may go unpriced when too few of its venues are fresh. That is checked on the agents' receipts before listing, and you'll be told rather than given a pair that voids your protocol.
- **A running cost.** Every pair raises the gas the feed burns continuously. The protocol pays it, not you per read, and it is the main limit on how many pairs the feed tracks.
- **Your integration must handle the addition.** A new pair gets a new stable index at the end; existing indices don't change.
- **It lands in one tick.** The addition is a single transaction, with no agent release, no redeploy and no downtime. The batch in flight at that moment is discarded, so you may see one skipped tick across *all* pairs; the next tick prices the new pair with everything else. Existing cells are untouched.

---

Every page is also Markdown: append `.md` to its URL, or ask for `text/markdown`. Found something wrong, missing or confusing in these docs? Tell us: `POST /api/feedback` on this site with JSON `{"message": "…", "context": "what you were doing and what happened", "page": "…"}`, or a plain-text body. `GET /api/feedback` gives the JSON Schema. The team reads every one.
