> ## Documentation Index
> Fetch the complete documentation index at: https://docs.picon.finance/llms.txt
> Use this file to discover all available pages before exploring further.

# Events

> Subscribing to and decoding on-chain program events

Event decoding and subscriptions are a separate, opt-in feature under the `events` namespace —
independent of `DlmmProgram`/`Pool`/`Position`/`BinArray`.

```ts theme={null}
import { createSolanaRpcSubscriptions } from "@solana/kit";
import { events } from "@picon-finance/dlmm-sdk";

const rpcSubscriptions = createSolanaRpcSubscriptions("wss://api.mainnet-beta.solana.com");

// Omit programAddress to target mainnet, same default as DlmmProgram. Testing against devnet
// instead? Import DEVNET_PROGRAM_ADDRESS and pass it as { programAddress: DEVNET_PROGRAM_ADDRESS }.
const unsubscribe = await events.onEvent(rpcSubscriptions, (event) => {
  console.log(event.name, event.data);
});

// unsubscribe() when done.
```

`address` defaults to `programAddress` — every pool the program touches. Pass a specific pool
address to scope the subscription to just that pool.

## Event types

The SDK decodes all seven events the program emits:

| Event                | Fired by                           | Key fields                                                                                                                        |
| -------------------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `CreatePoolEvent`    | `create_pool`                      | `pool`, `binStep`, `feeRate`, `tokenMintX`, `tokenMintY`                                                                          |
| `OpenPositionEvent`  | `open_position`                    | `pool`, `position`, `owner`, `lowerBinId`, `upperBinId`                                                                           |
| `ClosePositionEvent` | `close_position`                   | `pool`, `position`, `owner`, `lowerBinId`, `upperBinId`                                                                           |
| `DepositEvent`       | `deposit_by_weight`                | + `amountX`, `amountY`, `transferFeeX`, `transferFeeY`                                                                            |
| `WithdrawEvent`      | `withdraw`                         | + `bpsRemoved`, `amountX`, `amountY`, `transferFeeX`, `transferFeeY`                                                              |
| `ClaimFeeEvent`      | `claim_fee`                        | + `amountX`, `amountY`, `transferFeeX`, `transferFeeY`                                                                            |
| `SwapEvent`          | `swap_exact_in` / `swap_exact_out` | `pool`, `xToY`, `preBinId`, `postBinId`, `amountIn`, `amountOut`, `inputTransferFee`, `outputTransferFee`, `lpFee`, `protocolFee` |

Every amount field on these events is **gross** — before any Token-2022 transfer fee, which is
reported separately via the matching `transferFee*`/`*TransferFee` field rather than netted
out. This matches the convention used everywhere else in the protocol: reporting a net amount
here would silently disagree with what actually moved for a leg that paid a transfer fee, and
would make the same field mean different things depending on whether the mint happened to carry
the extension.

`event.name` is a discriminated union tag — narrow on it to get the correctly-typed `data`:

```ts theme={null}
events.onEvent(rpcSubscriptions, (event) => {
  if (event.name === "SwapEvent") {
    console.log(`${event.data.amountIn} in, ${event.data.amountOut} out, fee ${event.data.lpFee + event.data.protocolFee}`);
  }
});
```

## Scoping to one pool, and handling stream errors

Pass `address` to watch a single pool instead of every pool the program touches, and `onError`
to observe stream-level failures (e.g. a dropped WebSocket) without an unhandled rejection — a
`handler` throw only drops that one event and doesn't stop the subscription, so `onError` is
specifically for the transport, not for errors your own `handler` raises:

```ts theme={null}
const unsubscribe = await events.onEvent(
  rpcSubscriptions,
  (event) => handleEvent(event),
  {
    address: poolAddress,
    commitment: "confirmed",
    onError: (error) => console.error("event stream error", error),
  },
);
```
