# Events

> Canonical: https://docs.velocity.exchange/developers/velocity-sdk/events

The program emits its events into transaction logs. `EventSubscriber` tails those logs, deserializes each event into a typed object, emits it in real time, and keeps a bounded buffer of recent ones that can be read without waiting for the next arrival.

## Event types

Every name below is a key of `EventMap`, which is what `eventTypes` accepts and what `event.eventType` returns.

| Event Type | Description |
|---|---|
| `DepositRecord` | A user depositing or withdrawing funds from the protocol |
| `FundingPaymentRecord` | A user paying or receiving funding payments |
| `LiquidationRecord` | A user being liquidated |
| `OrderRecord` | A user placing an order (includes all order parameters) |
| `OrderActionRecord` | A user action on an order: place, cancel, or fill |
| `FundingRateRecord` | The funding rate changing for a market |
| `NewUserRecord` | A new user account being created |
| `DeleteUserRecord` | A user account being deleted |
| `SettlePnlRecord` | A user settling their perp PnL |
| `InsuranceFundRecord` | The insurance fund balance changing |
| `SpotInterestRecord` | Spot interest accruing |
| `InsuranceFundStakeRecord` | A user staking or unstaking from the insurance fund |
| `AmmCurveChanged` | The AMM curve parameters updating |
| `SwapRecord` | A Jupiter or Titan swap executed through a Velocity account |
| `SpotMarketVaultDepositRecord` | An external deposit landing directly in a spot market vault |
| `SignedMsgOrderRecord` | A signed ([Swift](/developers/velocity-sdk/swift.md)) order being placed |
| `LPMintRedeemRecord` | A user minting or redeeming Velocity liquidity pool tokens |
| `LPSettleRecord` | A Velocity liquidity pool settling PnL against its constituents |
| `LPSwapRecord` | A swap between constituents inside a Velocity liquidity pool |
| `LPBorrowLendDepositRecord` | A Velocity liquidity pool borrow/lend deposit or withdrawal against a constituent |
| `PerpMarketFeeSweepRecord` | A streaming sweep of a perp market's fee ledger into the insurance, protocol, and AMM fee pools |
| `ProtocolFeeWithdrawRecord` | An admin withdrawal from a perp or spot market's protocol fee pool |
| `RevenueShareSettleRecord` | A builder or referrer revenue-share settlement for a market |
| `TransferFeeAndPnlPoolRecord` | An admin transfer between a perp market's fee pool and PnL pool |
| `AcceleratedReferralStatusChangedRecord` | An authority's Accelerated referral status changing, by automatic enrollment or an admin grant or revoke |

> **Info:**
>
> `CurveRecord` was renamed to `AmmCurveChanged`, and its fields changed with it. `LPRecord` (vAMM and BAMM LP shares) no longer exists: passive liquidity now flows through the Velocity liquidity pool module, whose activity is split across `LPMintRedeemRecord`, `LPSettleRecord`, `LPSwapRecord`, and `LPBorrowLendDepositRecord`.
>
> `PerpMarketFeeSweepRecord`, `ProtocolFeeWithdrawRecord`, `RevenueShareSettleRecord`, and `TransferFeeAndPnlPoolRecord` have long been emitted onchain but were only recently registered in the SDK's event map. Older SDK versions dropped them from `EventSubscriber` silently.

## Subscribing to events

Construct an `EventSubscriber` with the connection, the client's Anchor program, and the options. `newEvent` is the only real-time emitter: it fires once for every incoming event that matches the `eventTypes` filter, and handlers branch on `event.eventType` from there.

  
```ts
import { EventSubscriber, EventSubscriptionOptions } from "@velocity-exchange/sdk";

const options: EventSubscriptionOptions = {
  eventTypes: ["OrderActionRecord", "DepositRecord", "LiquidationRecord"],
  maxTx: 4096,           // transactions retained for getEventsByTx
  maxEventsPerType: 4096, // per-type buffer size
  orderBy: "blockchain",
  orderDir: "asc",
  commitment: "confirmed",
  logProviderConfig: { type: "websocket" },
};

const eventSubscriber = new EventSubscriber(connection, velocityClient.program, options);
await eventSubscriber.subscribe();

eventSubscriber.eventEmitter.on("newEvent", (event) => {
  console.log(event.eventType, event);
});

await eventSubscriber.unsubscribe();
```
  

Options left unset are merged over `DefaultEventSubscriptionOptions`, so omitting `eventTypes` entirely subscribes to every type in the table above. Narrow it deliberately: each extra type costs buffer memory and deserialization work on every matching transaction.

### Filtering events

Enum-valued fields on an event, such as `marketType` and `action`, are Anchor enums rather than strings, so compare them with `isVariant` instead of `===`. Plain fields like `marketIndex` and `eventType` compare directly.

  
```js
import { isVariant } from "@velocity-exchange/sdk";

const marketIndex = 0;

// Perp fills on one market: eventType and marketIndex compare directly,
// marketType and action are enums and need isVariant.
const isPerpFill = (event) =>
  event.eventType === "OrderActionRecord" &&
  event.marketIndex === marketIndex &&
  isVariant(event.marketType, "perp") &&
  isVariant(event.action, "fill");

eventSubscriber.eventEmitter.on("newEvent", (event) => {
  if (isPerpFill(event)) console.log("perp fill on market", marketIndex, event);
});
```
  

> **Warning:**
>
> In TypeScript, checking `event.eventType` does not narrow `event`. `WrappedEvent` is generic over `EventType`, so the compiler cannot correlate the discriminant with the rest of the shape. Cast explicitly after the check: `const orderEvent = event as WrappedEvent<"OrderActionRecord">`.

## Querying stored events

The subscriber keeps a rolling, size-bounded buffer per event type, plus a per-transaction index. Both are readable at any time without waiting for a new event.

  
```js
// A snapshot copy of every buffered event of one type.
const events = eventSubscriber.getEventsArray("OrderActionRecord");

// The live, size-bounded EventList the subscriber inserts into.
// Prefer this when iterating: it does not copy.
const eventList = eventSubscriber.getEventList("OrderActionRecord");

// Everything emitted by one transaction, in emission order.
const txSig = "3dq5PtQ3VnNTkQRrHhQ1nRACWZaFVvSBKs1RLXM8WvCqLHTzTuVGc7XER5awoLFLTdJ4kqZiNmo7e8b3pXaEGaoo";
const txEvents = eventSubscriber.getEventsByTx(txSig);
```
  

All three return `undefined` or an empty result rather than throwing when nothing matches, and the buffer only holds what arrived since `subscribe()`: it is not a historical backfill.
