Events
Every state change PairStreet records about a Pair Market lands in one insert-only stream: activity_events. Each row names what happened, which objects it concerns, and the transaction that proves it.
The event row
An event is one row in activity_events. The type column is a Postgres enum; the identifier columns link the event to the token, the Pair MarketPair MarketThe canonical pairing of an internet asset with a financial Pair: TOKEN × PAIR INSTRUMENT, plus the Pair Vault, configuration and accounting that connect them., the Pair InstrumentPair InstrumentThe financial exposure a Pair Market is paired with, such as Tokyo Residential or Swiss Government Debt. A catalog object with a provider, an eligibility policy and a status. and the wallet it concerns; usdValue and amountRaw carry the quantity; txSignature points at the Solana transaction when one exists; payload holds the type-specific fields.
export const activityEvents = pgTable(
"activity_events",
{
id: uuid("id").primaryKey().defaultRandom(),
type: activityTypeEnum("type").notNull(),
tokenId: uuid("token_id").references(() => tokens.id, { onDelete: "cascade" }),
pairMarketId: uuid("pair_market_id").references(() => pairMarkets.id, { onDelete: "cascade" }),
instrumentId: uuid("instrument_id").references(() => pairInstruments.id),
wallet: text("wallet"),
usdValue: numeric("usd_value", { precision: 24, scale: 6 }),
amountRaw: numeric("amount_raw", { precision: 40, scale: 0 }),
txSignature: text("tx_signature"),
payload: jsonb("payload").$type<Record<string, unknown>>().notNull().default({}),
ledgerMode: ledgerModeEnum("ledger_mode").notNull(),
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
},
(t) => [
index("activity_created_idx").on(t.createdAt),
index("activity_token_idx").on(t.tokenId, t.createdAt),
index("activity_instrument_idx").on(t.instrumentId, t.createdAt),
index("activity_wallet_idx").on(t.wallet, t.createdAt),
index("activity_type_idx").on(t.type, t.createdAt),
],
);- ·Amounts are stored as integer base units in
amountRaw;usdValueis a display figure computed at the time of the event. - ·Every row carries a Ledger modeLedger modeEvery financial ledger row carries live or development. Production reads and writes live rows only.. Production reads and writes
liverows only. - ·The five indexes serve the feeds PairStreet renders: global, per token, per instrument, per wallet, and per type, each ordered by time.
- ·Events are written inside the same database transaction as the state change they describe, so an event never exists without the state change it reports.
Event catalog
Twelve event types are defined. Three are emitted on Solana mainnet today. The settlement family is emitted by the settlement engine and goes live per Pair Instrument with its settlement route. The status column says which.
| Event | Trigger | Identifiers | Payload | Status |
|---|---|---|---|---|
TOKEN_CREATED | Launch confirmed on chain through POST /api/launch/confirm, in the transaction that registers the Pair Market. | tokenIdpairMarketIdinstrumentIdwallet (creator)txSignature (launch) | { symbol } | Live |
PAIR_SELECTED | Same database transaction, stamped 1 ms after TOKEN_CREATED. Records the Pair Instrument the creator chose. | tokenIdpairMarketIdinstrumentIdwallet (creator) | { instrument } | Live |
PAIR_REQUESTED | A counted vote on a Pair Request through POST /api/pair-requests. A repeat vote by the same voter is not counted and emits nothing. | wallet (when connected) | { title, count } | Live |
TOKEN_TRADE | A trade on the coin’s market. Mainnet trades enter through the Pump program event stream. | tokenIdpairMarketIdinstrumentIdwallettxSignature | { side, priceUsd } | In integration |
GRADUATED | The bonding curve completes and the coin moves to PumpSwap. Mainnet graduation is already detected from the curve account and recorded on the market; the event joins the indexer stream. | tokenIdpairMarketIdinstrumentId | { venue } | In integration |
PAIR_VAULT_FUNDED | Settlement asset credited to a Pair VaultPair VaultThe account that receives settlement value allocated to one Pair Market, holds it until conversion, and holds the acquired Pair Asset until it is allocated to holders., alongside its pair_vault_fundings row. | tokenIdpairMarketIdinstrumentIdusdValue | { source } | Activates per route |
PAIR_ASSET_PURCHASED | The settlement engine confirms an acquisition (runSettlement). | tokenIdpairMarketIdinstrumentIdtxSignatureusdValue (output)amountRaw (units) | { routeMode, priceUsd, quoteSource } | Activates per route |
PAIR_SETTLEMENT | Same transaction, stamped 1 s after the purchase. Closes the settlement. | tokenIdpairMarketIdinstrumentIdusdValue (input) | { sequence } | Activates per route |
PAIR_REWARD_ALLOCATED | Same transaction, stamped 2 s after the purchase, when the epoch has eligible holders. The epoch is written finalized with its allocations. | tokenIdpairMarketIdinstrumentIdusdValue (pool)amountRaw (pool) | { epoch, holders, methodology, root } | Activates per route |
PAIR_REWARD_CLAIMED | A holder’s claim settles through POST /api/rewards/claim. Live claims run through the Merkle distributor. | tokenIdpairMarketIdinstrumentIdwallettxSignatureusdValueamountRaw | { } | Activates per route |
PAIR_INSTRUMENT_ADDED | An instrument enters the registry. | instrumentId | { provider } | Planned |
PAIR_INSTRUMENT_PAUSED | An instrument’s status moves to paused. | instrumentId | { reason } | Planned |
Planned for the two instrument events means the enum values exist and the activity feed renders them; emission from the catalog sync that upserts the registry is the remaining step. The Pair Requests chapter covers the demand events in context.
Event names across the documentation
The architecture chapters describe the lifecycle with descriptive event names. Each maps to a stored type, or to a ledger row where the stored type is planned.
| Lifecycle name | Recorded as | Status |
|---|---|---|
| PAIR_MARKET_CREATED | PAIR_SELECTED, written in the transaction that inserts the pair_markets row | Live |
| SETTLEMENT_OPENED | A pair_settlements row and its status; a dedicated event type is planned | Planned |
| PAIR_SETTLEMENT_FINALIZED | PAIR_SETTLEMENT | Activates per route |
| REWARD_EPOCH_FUNDED | PAIR_REWARD_ALLOCATED; the epoch is funded and allocated in one step | Activates per route |
| REWARD_ALLOCATED | PAIR_REWARD_ALLOCATED | Activates per route |
| REWARD_CLAIMED | PAIR_REWARD_CLAIMED | Activates per route |
| PAIR_PAUSED | The pair_markets.status value paused; a dedicated event type is planned | Planned |
| INSTRUMENT_STATUS_CHANGED | PAIR_INSTRUMENT_PAUSED covers the move to paused; a general status-change event is planned | Planned |
A settlement in the stream
One settlement produces three events, written in a single database transaction in a fixed order: the purchase, the settlement, and the reward allocation. A reader of the stream sees them together or not at all.
- 12:02:14PAIR_ASSET_PURCHASEDusdValue $14,218.00 · Tokyo Residential553.01 units · priceUsd 25.7102 · routeMode ONCHAIN_SWAP
- 12:02:18PAIR_SETTLEMENTsequence 184$TOKYO × Tokyo Residential
- 12:03:02PAIR_REWARD_ALLOCATEDepoch 184 · 7,291 unitsmethodology time_weighted_balance · root <allocation-root>
Figure summary: Example stream. 12:02:14 PAIR_ASSET_PURCHASED, 14,218 dollars of Tokyo Residential, 553.01 units at 25.7102 dollars per unit, route ONCHAIN_SWAP. 12:02:18 PAIR_SETTLEMENT, sequence 184. 12:03:02 PAIR_REWARD_ALLOCATED, epoch 184, 7,291 units, time-weighted balance, with an allocation root.
Tokyo Residential here is a Pair Instrument representing the target financial exposure configured for the Pair Market. The purchase row carries the units acquired and their value at the execution price ($14,218.00 ÷ 553.01 ≈ $25.7102 per unit); the settlement row carries the sequence that ties all three rows to pair_settlements; the allocation row carries the epoch number and the Merkle root holders verify their claims against. See Accounting for the full chain.
Reading the stream
GET /api/activity returns events newest first, with the token and instrument joined in. Production returns live rows only.
| Parameter | Meaning |
|---|---|
| group | all, pair, trades, launches, rewards or instruments. Each group is a fixed set of event types. |
| token | Mint address. Restricts to one token’s events. |
| instrument | Instrument slug. Restricts to one Pair Instrument. |
| wallet | Wallet address. Restricts to events that name the wallet. |
| before | ISO timestamp cursor. Pass the previous page’s nextCursor. |
| limit | 1 to 100, default 30. |
GET /api/activity?group=pair&token=<mint>&limit=30
200 OK
cache-control: no-store
{
"items": [
{
"id": "<uuid>",
"type": "PAIR_SELECTED",
"createdAt": "<iso-8601>",
"wallet": "<creator-wallet>",
"usdValue": null,
"amountRaw": null,
"txSignature": null,
"ledgerMode": "live",
"payload": { "instrument": "tokyo-residential" },
"token": { "mint": "<mint>", "symbol": "TOKYO", "name": "<name>", "imageUrl": "<url>" },
"instrument": { "slug": "tokyo-residential", "name": "Tokyo Residential", "shortName": "Tokyo Residential", "icon": "<icon>", "country": "JP" }
}
],
"nextCursor": "<iso-8601 of the last item, or null>"
}Groups
| Group | Types |
|---|---|
| launches | TOKEN_CREATED, PAIR_SELECTED, GRADUATED |
| pair | PAIR_VAULT_FUNDED, PAIR_ASSET_PURCHASED, PAIR_SETTLEMENT, PAIR_REWARD_ALLOCATED, PAIR_REWARD_CLAIMED |
| rewards | PAIR_REWARD_ALLOCATED, PAIR_REWARD_CLAIMED |
| trades | TOKEN_TRADE |
| instruments | PAIR_REQUESTED, PAIR_INSTRUMENT_ADDED, PAIR_INSTRUMENT_PAUSED |