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

# Streaming

# GoldRush Streaming on Solana

## Critical Rules

1. GraphQL WebSocket URL: `wss://streaming.goldrushdata.com/graphql`.
2. Chain enum: `SOLANA_MAINNET` (SCREAMING\_SNAKE\_CASE) - **not** `solana-mainnet` (that is the Foundational REST chain name).
3. `newPairs` on `SOLANA_MAINNET` covers Raydium AMM/CLMM, Orca Whirlpool, Meteora DLMM/Dynamic, Jupiter, and PumpFun on one subscription. Filter client-side on the `exchange` field.
4. PumpFun launches surface as `exchange: pumpfun`. Raydium graduations surface seconds later as `exchange: raydium-amm` with the same `base_token.address`.
5. `ohlcvCandlesForPair` takes pool addresses (base58); `ohlcvCandlesForToken` takes SPL mints and aggregates across every pool carrying that token.
6. `walletTxs` accepts thousands of wallet addresses per subscription on one WebSocket.
7. No rate limits on Streaming for Solana; no per-IP subscription cap.

## Common Recipes

| Goal                                      | Subscription                                              | Filter / Args                                         |
| ----------------------------------------- | --------------------------------------------------------- | ----------------------------------------------------- |
| New-pool firehose across every Solana DEX | `newPairs`                                                | `chain_name: SOLANA_MAINNET`                          |
| PumpFun launches only                     | `newPairs` → filter `exchange === "pumpfun"`              | client-side                                           |
| Graduation detection                      | `newPairs` → track `(base_token.address, exchange)` pairs | client-side                                           |
| Live OHLCV for a specific pool            | `ohlcvCandlesForPair`                                     | `pair_addresses: ["<pool-pubkey>"]`                   |
| Aggregated price for an SPL mint          | `ohlcvCandlesForToken`                                    | `token_addresses: ["<mint>"]`                         |
| Wallet activity firehose                  | `walletTxs`                                               | `chain_name: SOLANA_MAINNET, wallet_addresses: [...]` |

***

Discovering new Solana DEX pools used to mean polling per-protocol indexers or scanning every block for `InitializePool` instructions. GoldRush's `newDexPairs` subscription delivers every new pool the moment liquidity is added - across **Raydium, Orca, Meteora, Jupiter, and PumpFun** - on one WebSocket.

## What you get

* **Cross-protocol coverage** in one stream - no per-DEX fan-out.
* **Pre-decoded pool metadata** - exchange, pair address, base/quote mints, decimals, initial liquidity in USD.
* **Sub-second latency** from validator-peered Solana ingestion.
* **Zero rate limits** - subscribe permanently, no polling.

## Subscribe

```typescript GoldRush SDK theme={null}
import { GoldRushClient, StreamingChain } from "@covalenthq/client-sdk";

const client = new GoldRushClient(process.env.GOLDRUSH_API_KEY);

client.StreamingService.subscribeToNewPairs(
  { chain_name: StreamingChain.SOLANA_MAINNET },
  {
    next: (data) => {
      const pair = data.newPairs;
      console.log(
        `[${pair.exchange}] ${pair.base_token.symbol}/${pair.quote_token.symbol}`,
        `pool=${pair.pair_address}`,
        `liquidity=$${pair.initial_liquidity_usd}`
      );
    },
    error: (err) => console.error(err),
    complete: () => console.log("done"),
  }
);
```

```graphql GraphQL Subscription theme={null}
subscription {
  newPairs(chain_name: SOLANA_MAINNET) {
    block_signed_at
    exchange
    pair_address
    base_token {
      address
      symbol
      decimals
    }
    quote_token {
      address
      symbol
      decimals
    }
    initial_liquidity_usd
  }
}
```

```python Python theme={null}
import asyncio
import os
from gql import gql, Client
from gql.transport.websockets import WebsocketsTransport

WS_URL = "wss://streaming.goldrushdata.com/graphql"

SUBSCRIPTION = gql("""
subscription {
  newPairs(chain_name: SOLANA_MAINNET) {
    block_signed_at
    exchange
    pair_address
    base_token { address symbol decimals }
    quote_token { address symbol decimals }
    initial_liquidity_usd
  }
}
""")

async def main():
    transport = WebsocketsTransport(
        url=WS_URL,
        init_payload={"GOLDRUSH_API_KEY": os.environ["GOLDRUSH_API_KEY"]},
    )
    async with Client(transport=transport, fetch_schema_from_transport=False) as session:
        async for result in session.subscribe(SUBSCRIPTION):
            print(result["newPairs"])

asyncio.run(main())
```

Connect via WebSocket at `wss://streaming.goldrushdata.com/graphql` with your API key in the connection parameters.

## Protocols covered

The `exchange` field on each new pair takes one of:

| Protocol          | Common pool shape                                              |
| ----------------- | -------------------------------------------------------------- |
| `raydium-amm`     | Constant-product AMM (CPAMM) pools.                            |
| `raydium-clmm`    | Concentrated-liquidity Raydium pools.                          |
| `orca-whirlpool`  | Orca's concentrated-liquidity pools.                           |
| `meteora-dlmm`    | Meteora dynamic-liquidity (binned) pools.                      |
| `meteora-dynamic` | Meteora dynamic-fee constant-product pools.                    |
| `jupiter`         | Jupiter aggregator-routed pools surfaced as venues.            |
| `pumpfun`         | PumpFun bonding-curve pools and post-graduation Raydium pools. |

Use the **PumpFun launchpad recipe** for the narrower PumpFun-only stream when you only care about the launchpad.

## Patterns

### "New pools" tab

Stream the firehose, dedupe by `pair_address`, drop pools with `initial_liquidity_usd < $X` to filter spam, and display chronologically. Subscribe to **`ohlcvCandlesForPair`** on the pools you want to chart.

### First-mover sniping

The moment a pool appears in `newDexPairs`, kick off:

1. A **`get-pool-spot-prices`** call to confirm the price.
2. A **`get-token-balances-for-address`** for your trading wallet to confirm size.
3. A trade against the new pool with a **recommended priority fee** from `p90`.

### Honeypot screening

Combine the firehose with **`walletTxs`** pinned to the new pool's creator wallet. If the creator removes liquidity within minutes, flag the pool as a likely rug.

### Cross-DEX arbitrage discovery

The same base/quote pair can launch on Raydium and Orca within minutes. Group new pools by `(base_token.address, quote_token.address)` to discover venues for arb routing.

## Production considerations

The happy path is enough to prototype. Three things to add before shipping:

* **Reconnect on close or error.** Wrap the subscribe call in a function and re-invoke on `error` / `complete` with a 1-2s backoff.
* **Dedupe by `pair_address`.** During brief reconnects you may see a recently-emitted pool twice; deduplicate on `pair_address`.
* **No backfill on reconnect.** The subscription delivers events from the moment it opens. For continuity across a gap, the warehouse **`swaps` entity** has every pool genesis recorded.

## Related

* **PumpFun launchpad** - the PumpFun-only narrower stream.
* **OHLCV markets** - real-time candles for pools you discover.
* **Pricing on Solana** - spot prices + price resolution path.
* **New DEX Pairs Stream reference** - full subscription schema.

***

PumpFun launches thousands of tokens per day on Solana. Each token starts on a bonding curve, accumulates swaps until graduation, then migrates to Raydium. GoldRush streams every step in real time via the DEX firehose, with decoded swap and graduation events delivered alongside Raydium / Orca / Meteora pools on the same subscription.

For warehouse-delivered PumpFun analytics (graduations, top swappers, virtual-reserve history), see the **Pipeline guide**.

## What you get

* **Token creates** - every new bonding-curve token the moment it's launched, with mint, creator, and initial bonding-curve parameters.
* **Swaps** - buy and sell on the bonding curve with virtual SOL / virtual Token reserves so you can reconstruct the curve.
* **Graduations** - the moment a token's bonding curve completes and it migrates to Raydium.
* **Post-graduation Raydium pool** - the new Raydium pool surfaces in the same firehose with `exchange: raydium-amm` and the same base mint.

## Real-time stream

PumpFun pools surface in the same **DEX firehose** subscription with `exchange: pumpfun`. Filter client-side on `exchange === "pumpfun"` to isolate PumpFun launches.

```typescript GoldRush SDK theme={null}
import { GoldRushClient, StreamingChain } from "@covalenthq/client-sdk";

const client = new GoldRushClient(process.env.GOLDRUSH_API_KEY);

client.StreamingService.subscribeToNewPairs(
  { chain_name: StreamingChain.SOLANA_MAINNET },
  {
    next: (data) => {
      const pair = data.newPairs;
      if (pair.exchange !== "pumpfun") return;
      console.log(
        `pump.fun mint=${pair.base_token.address}`,
        `liquidity=$${pair.initial_liquidity_usd}`,
        `at=${pair.block_signed_at}`
      );
    },
    error: (err) => console.error(err),
    complete: () => console.log("done"),
  }
);
```

```graphql GraphQL Subscription theme={null}
subscription {
  newPairs(chain_name: SOLANA_MAINNET) {
    block_signed_at
    exchange
    pair_address
    base_token { address symbol decimals }
    quote_token { address symbol decimals }
    initial_liquidity_usd
  }
}
```

For tick-by-tick swaps on a specific PumpFun token, subscribe to **`ohlcvCandlesForPair`** with the bonding-curve pair address you got from `newDexPairs`.

## Graduation watch

Tokens that complete the bonding curve migrate to Raydium. The migration emits two events in the firehose within seconds of each other:

1. A PumpFun completion (visible in the warehouse `sol_pf_complete` table - not currently surfaced as a typed streaming event).
2. A new Raydium pool with `exchange: raydium-amm` and the **same base mint** as the PumpFun token.

To detect graduations in the streaming layer, watch for `exchange: raydium-amm` events whose `base_token.address` you previously saw in a `exchange: pumpfun` event.

```typescript theme={null}
const pumpFunMints = new Set();

client.StreamingService.subscribeToNewPairs(
  { chain_name: StreamingChain.SOLANA_MAINNET },
  {
    next: (data) => {
      const pair = data.newPairs;
      if (pair.exchange === "pumpfun") {
        pumpFunMints.add(pair.base_token.address);
      } else if (
        pair.exchange === "raydium-amm" &&
        pumpFunMints.has(pair.base_token.address)
      ) {
        console.log(`🎓 GRADUATED: ${pair.base_token.address} → ${pair.pair_address}`);
      }
    },
    error: (err) => console.error(err),
  }
);
```

## Patterns

### Live PumpFun screener

Filter the firehose to `exchange: pumpfun`, sort by `block_signed_at`, and display a chronological feed. For each row, subscribe to **`ohlcvCandlesForPair`** on the bonding curve to render a live sparkline.

### Sniper bot

The moment a PumpFun pool appears in `newDexPairs`:

1. Apply your honeypot filter (deployer reputation, social signal, prior rugs).
2. Look up **`get-pool-spot-prices`** for the bonding-curve pair address.
3. Submit a buy with a **`p90` priority fee**.

### Backtesting & analytics

Real-time is for execution; backtests need history. The **Pipeline normalizer** lands every PumpFun create, swap, complete, and withdraw into your warehouse (`sol_pf_create`, `sol_pf_swap`, `sol_pf_complete`, `sol_pf_withdraw`). See **Track PumpFun Swaps on Solana** for the SQL recipes.

## Reading the bonding curve

PumpFun's price curve is a function of virtual SOL and virtual Token reserves. The Pipeline `sol_pf_swap` table exposes both per-swap so you can reconstruct price and slippage exactly:

```sql theme={null}
SELECT
  block_time,
  direction,
  sol_amount,
  token_amount,
  virtual_sol_reserves,
  virtual_token_reserves,
  virtual_sol_reserves / virtual_token_reserves AS implied_price_sol_per_token
FROM sol_pf_swap
WHERE mint = ''
ORDER BY block_time;
```

The streaming layer doesn't expose the virtual reserves directly today; for that depth, pair the live stream with the warehouse table.

## Production considerations

* **Reconnect on close or error.** Wrap subscribe in a function and re-invoke with 1-2s backoff.
* **Spam pools.** PumpFun emits high volume; if you only care about pools that get past their first 30 seconds, hold each new pool in a buffer and only act once it accumulates N swaps.
* **Mint reuse on graduation.** The same SPL mint appears in both the PumpFun pool and the Raydium pool post-graduation - track `(mint, exchange)` as your key, not `mint` alone.

## Related

* **DEX firehose** - parent stream covering all Solana DEX protocols.
* **Track PumpFun Swaps (Pipeline)** - warehouse-delivered PumpFun lifecycle events.
* **OHLCV markets** - tick-level candles for any PumpFun bonding curve.
* **Pricing on Solana** - spot prices for pools after they exist.

***

The `walletTxs` subscription delivers every signed transaction for the wallets you subscribe to, in real time, with decoded details for common transaction types (SPL transfers, DEX swaps, native SOL movements). One WebSocket can carry thousands of wallets.

## What you get

* **Many wallets, one connection.** Pass an array of base58 wallet addresses; updates for any of them arrive on the same stream.
* **Pre-decoded events.** SPL transfers (Token + Token-2022) and DEX swaps come through as typed GraphQL union members - no parsing.
* **Sub-second latency.** Tokyo-colocated, validator-peered Solana ingestion.
* **No rate limits.**

## Subscribe

```typescript GoldRush SDK theme={null}
import { GoldRushClient, StreamingChain } from "@covalenthq/client-sdk";

const client = new GoldRushClient(process.env.GOLDRUSH_API_KEY);

const SUBSCRIPTION_QUERY = `
  subscription {
    walletTxs(
      wallet_addresses: [
        "4ZJhPQAgUseCsWhKvJLTmmRRUV74fdoTpQLNfKoekbPY",
        "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM"
      ]
      chain_name: SOLANA_MAINNET
    ) {
      tx_hash
      block_signed_at
      from_address
      successful
      decoded_details {
        ... on SwapTransaction {
          protocol_name
          pool_address
          base_token { address symbol }
          quote_token { address symbol }
          base_amount
          quote_amount
          price_usd
        }
        ... on TransferTransaction {
          token_address
          from_address
          to_address
          amount
          token_symbol
        }
      }
    }
  }
`;

client.StreamingService.rawQuery(
  SUBSCRIPTION_QUERY,
  {},
  {
    next: (data) => console.log(JSON.stringify(data, null, 2)),
    error: (err) => console.error(err),
    complete: () => console.log("done"),
  }
);
```

```python Python theme={null}
import asyncio
import os
from gql import gql, Client
from gql.transport.websockets import WebsocketsTransport

WS_URL = "wss://streaming.goldrushdata.com/graphql"

SUBSCRIPTION = gql("""
subscription {
  walletTxs(
    wallet_addresses: [
      "4ZJhPQAgUseCsWhKvJLTmmRRUV74fdoTpQLNfKoekbPY"
    ]
    chain_name: SOLANA_MAINNET
  ) {
    tx_hash
    block_signed_at
    successful
    decoded_details {
      ... on SwapTransaction {
        protocol_name pool_address
        base_token { address symbol }
        quote_token { address symbol }
        base_amount quote_amount price_usd
      }
      ... on TransferTransaction {
        token_address from_address to_address amount token_symbol
      }
    }
  }
}
""")

async def main():
    transport = WebsocketsTransport(
        url=WS_URL,
        init_payload={"GOLDRUSH_API_KEY": os.environ["GOLDRUSH_API_KEY"]},
    )
    async with Client(transport=transport, fetch_schema_from_transport=False) as session:
        async for result in session.subscribe(SUBSCRIPTION):
            print(result)

asyncio.run(main())
```

The chain enum is `SOLANA_MAINNET` (SCREAMING\_SNAKE\_CASE), not `solana-mainnet`. The Streaming API uses the enum; the Foundational REST API uses the kebab-case form.

## Patterns

### Copy-trading

Subscribe to a curated list of high-performing wallets. Filter the stream on `SwapTransaction`, then mirror `(pool_address, base_amount, quote_amount)` to your own execution layer with a **`p90` priority fee**.

### Whale watch

Subscribe to top SPL holders (from **`get-token-holders-as-of-any-block-height-v2`**) and surface every fill and large transfer in a live tape.

### Compliance / AML alerts

Subscribe to flagged addresses. Filter on `TransferTransaction` events and alert when amount exceeds a threshold.

### Push vs pull

Use **`get-paginated-transactions-for-address-v3`** for historical backfill and `walletTxs` here for the tip. The two share enough field shape that you can normalize into one internal type after fetching.

## Production considerations

* **Reconnect on close or error.** Wrap subscribe in a function; re-invoke with 1-2s backoff on `error` / `complete`.
* **Validate addresses up front.** Malformed base58 can tear down the whole subscription. Pre-filter with a base58 validator before passing in.
* **No gap-fill on reconnect.** Events that occurred during a disconnect are not replayed. For continuity across the gap, query **`get-paginated-transactions-for-address-v3`** over the disconnect window.

## Scaling

| Scale                   | Approach                                                                                     |
| ----------------------- | -------------------------------------------------------------------------------------------- |
| Up to \~1,000 wallets   | One subscription with the full address list.                                                 |
| 1,000 - 10,000+ wallets | Shard across multiple subscriptions on the same connection. The SDK reuses one WebSocket.    |
| Live cohort changes     | Unsubscribe and resubscribe with the new address list - no need to tear down the connection. |

## Related

* **Wallet endpoints** - REST companion for historical balances and transfers.
* **Transactions on Solana** - REST companion for paginated history.
* **Wallet Activity Stream reference** - full subscription schema.

***

GoldRush exposes two OHLCV streams on `SOLANA_MAINNET`:

* **`ohlcvCandlesForPair`** - candles for a specific pool address (Raydium AMM, Orca Whirlpool, Meteora DLMM / Dynamic).
* **`ohlcvCandlesForToken`** - candles aggregated across **every** pool carrying that SPL mint.

Both deliver candles in real time over WebSocket as new swaps land in the pool.

## Stream candles for a specific pool

Best for "chart this exact pool" UIs (the one your bot trades on, the deepest USDC pool, etc.).

```typescript GoldRush SDK theme={null}
import {
  GoldRushClient,
  StreamingChain,
  StreamingInterval,
  StreamingTimeframe,
} from "@covalenthq/client-sdk";

const client = new GoldRushClient(process.env.GOLDRUSH_API_KEY);

client.StreamingService.subscribeToOHLCVPairs(
  {
    chain_name: StreamingChain.SOLANA_MAINNET,
    pair_addresses: ["58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2"],
    interval: StreamingInterval.ONE_MINUTE,
    timeframe: StreamingTimeframe.ONE_HOUR,
  },
  {
    next: (data) => console.log("OHLCV:", data),
    error: (err) => console.error(err),
    complete: () => console.log("done"),
  }
);
```

```graphql GraphQL Subscription theme={null}
subscription {
  ohlcvCandlesForPair(
    chain_name: SOLANA_MAINNET
    pair_addresses: ["58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2"]
    interval: ONE_MINUTE
    timeframe: ONE_HOUR
  ) {
    pair_address
    timestamp
    open
    high
    low
    close
    volume_usd
  }
}
```

`pair_addresses` is an array of base58 pool addresses. You can subscribe to multiple pools on one subscription - useful for arbitrage monitoring across the same pair on Raydium and Orca.

## Stream candles for a token (across all pools)

Best for "what's the canonical USD price of TOKEN" - GoldRush aggregates across every pool carrying that mint, weighted by liquidity.

```typescript theme={null}
client.StreamingService.subscribeToOHLCVTokens(
  {
    chain_name: StreamingChain.SOLANA_MAINNET,
    token_addresses: ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"], // USDC
    interval: StreamingInterval.ONE_MINUTE,
    timeframe: StreamingTimeframe.ONE_HOUR,
  },
  {
    next: (data) => console.log("Token OHLCV:", data),
    error: (err) => console.error(err),
  }
);
```

The aggregation includes Raydium AMM/CLMM, Orca Whirlpool, Meteora DLMM/Dynamic, and PumpFun bonding curves where applicable.

## When to use pairs vs tokens

| Use case                                                           | Stream                                         |
| ------------------------------------------------------------------ | ---------------------------------------------- |
| Chart a single Raydium pool                                        | `ohlcvCandlesForPair` with the pool address    |
| Track arbitrage between Raydium and Orca for the same pair         | `ohlcvCandlesForPair` with both pool addresses |
| Get "the" USD price of a token                                     | `ohlcvCandlesForToken`                         |
| Aggregate across all PumpFun + Raydium pools for a graduated token | `ohlcvCandlesForToken`                         |

## Patterns

### TradingView chart

Subscribe to `ohlcvCandlesForPair` at the user's selected interval; push candles into TradingView's UDF datafeed adapter. The `timestamp / open / high / low / close / volume_usd` fields map 1:1 to UDF.

### Discovery → chart

Pair this stream with the **DEX firehose**: when a new pool appears in `newDexPairs`, automatically subscribe to its OHLCV. Limit to pools above an `initial_liquidity_usd` threshold to avoid spam.

### Pricing service

Use **`ohlcvCandlesForToken`** on `1d` candles for the canonical USD price; pair with the REST **`get-historical-token-prices`** for backfill.

## Related

* **Pricing on Solana** - REST companion for historical and spot prices.
* **DEX firehose** - discover new pools to subscribe to.
* **OHLCV Pairs Stream reference** - full subscription schema.
* **OHLCV Tokens Stream reference** - full subscription schema.

***

> **Note:** **Coming soon.** A dedicated NFT-mint subscription for Solana is on the **roadmap**. Until it ships, the patterns below cover what you can build today with the existing wallet and warehouse surfaces.

## What it will deliver

When the subscription ships, it will surface every Metaplex Token Metadata mint and every Bubblegum cNFT mint in real time, with:

* The new NFT's mint pubkey (Metaplex) or Merkle leaf index (cNFT).
* The collection mint or tree address.
* The initial owner (wallet that received the mint).
* The metadata URI and parsed JSON (name, image, attributes).
* A `compressed` flag to disambiguate.

## What you can do today

### Track mints via the wallet activity stream

Subscribe to `walletTxs` on the collection creator's wallet or on the candy machine / Bubblegum tree authority. Filter on `TransferTransaction` events where the source is the mint authority and the destination is a new wallet.

```typescript theme={null}
client.StreamingService.rawQuery(
  `subscription {
    walletTxs(
      wallet_addresses: [""]
      chain_name: SOLANA_MAINNET
    ) {
      tx_hash
      block_signed_at
      decoded_details {
        ... on TransferTransaction {
          token_address from_address to_address amount
        }
      }
    }
  }`,
  {},
  { next: console.log, error: console.error }
);
```

See **Wallet activity** for the full pattern.

### Backfill mints via the warehouse

The Pipeline **`transfers`** normalizer captures every SPL transfer including initial mints. Filter on `source_owner = ''` and `is_raw_amount = true, amount = 1` to isolate NFT mints from a specific candy machine or tree.

```sql theme={null}
SELECT block_time, mint, destination_owner, source_owner
FROM transfers
WHERE source_owner = ''
  AND amount = 1
  AND is_raw_amount = true
ORDER BY block_time DESC
LIMIT 100;
```

### Ownership lookup

Once you've spotted a mint, use **`check-ownership-in-nft-collection`** or **`check-ownership-in-nft-collection-token`** for gating logic.

## Related

* **NFTs on Solana (Foundational)** - REST endpoints for Metaplex + cNFT lookups today.
* **Wallet activity** - live transfer firehose, including mint transfers.
* **Roadmap** - tracking the dedicated NFT-mint stream.

***

# Warehouse Recipes

The `swaps` normalizer streams every decoded Solana DEX trade into your warehouse. One table covers Raydium AMM/CLMM, Orca Whirlpool, Meteora DLMM/Dynamic, Jupiter, and PumpFun bonding-curve trades - with unified fields across protocols so you don't write per-DEX adapters.

## Why warehouse delivery

Streaming and REST are great for live execution and lookups, but every retention cohort, churn model, token analytics dashboard, and tax export lives in your data warehouse - not in HTTP responses. The Pipeline API streams Solana data continuously into customer-managed destinations with no ETL on your side.

## Pipeline configuration

**Create a pipeline**

In the [GoldRush Platform](https://goldrush.dev/platform/), navigate to **Manage Pipelines** and click **Create Pipeline**. Name it `solana-swaps`.

**Pick Solana + Swaps**

Choose **Solana** as the chain and **Swaps** as the data type.

**Configure your destination**

Connect ClickHouse, BigQuery, Postgres, Kafka, S3/GCS/R2, SQS, or a Webhook. ClickHouse is recommended for high-volume analytical queries over swaps.

```yaml theme={null}
destination:
  type: "clickhouse"
  url: "https://your-cluster.clickhouse.cloud:8443"
  user: "${CH_USER}"
  password: "${CH_PASSWORD}"
  database: "solana_swaps"
  batch_size: 5000
```

**Optional: SQL transform**

Filter or reshape rows before they land. Example: keep only swaps over \$100 of volume.

```yaml theme={null}
transforms:
  swaps: >
    SELECT *
    FROM swaps
    WHERE volume_usd >= 100
```

**Deploy**

Decoded swaps begin flowing within seconds.

## Schema

The `swaps` table is documented in full on the **Solana Normalizers page**. Key columns:

* `block_slot`, `block_time`, `tx_id` (signature), `signer`.
* `pool_address`, `base_mint`, `quote_mint`, `base_vault`, `quote_vault`.
* `base_amount`, `quote_amount`, `price`, `price_usd`, `volume_usd`.
* `protocol_name` - `raydium-amm`, `raydium-clmm`, `orca-whirlpool`, `meteora-dlmm`, `meteora-dynamic`, `jupiter`, `pumpfun`.
* `outer_program`, `inner_program`, `instruction_type` for CPI attribution.

## Sample analytical queries

### Top tokens by 24h volume

```sql theme={null}
SELECT
  base_mint,
  SUM(volume_usd) AS volume_24h
FROM swaps
WHERE block_time >= now() - INTERVAL 1 DAY
GROUP BY base_mint
ORDER BY volume_24h DESC
LIMIT 50;
```

### Per-protocol market share by token

```sql theme={null}
SELECT
  protocol_name,
  SUM(volume_usd) AS volume_24h,
  COUNT(*) AS swap_count
FROM swaps
WHERE base_mint = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'
  AND block_time >= now() - INTERVAL 1 DAY
GROUP BY protocol_name
ORDER BY volume_24h DESC;
```

### Whale activity

```sql theme={null}
SELECT
  signer,
  SUM(volume_usd) AS volume_24h,
  COUNT(*) AS swap_count
FROM swaps
WHERE block_time >= now() - INTERVAL 1 DAY
GROUP BY signer
HAVING volume_24h > 1000000
ORDER BY volume_24h DESC;
```

### Jupiter routing through Raydium and Orca

```sql theme={null}
SELECT
  tx_id,
  protocol_name,
  outer_program,
  inner_program,
  base_mint,
  quote_mint,
  volume_usd
FROM swaps
WHERE outer_program = 'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4' -- Jupiter v6
  AND block_time >= now() - INTERVAL 1 HOUR
ORDER BY tx_id, instruction_index;
```

## Production tips

* **ClickHouse for high-volume analytics.** Solana swap volume is significant; analytical queries over millions of rows are much faster on ClickHouse than Postgres.
* **Partition by `block_date`.** Most analytical queries are time-bounded.
* **Materialized views for per-token metrics.** Build hourly / daily roll-ups in ClickHouse materialized views to keep dashboards snappy.

## Related

* **Solana Normalizers (full schema)** - column-level reference for `swaps` and other Solana entities.
* **SPL Transfers warehouse recipe** - companion table for transfer-side analytics.
* **DEX firehose (streaming)** - real-time push for the same data shape.
* **Track PumpFun Swaps** - PumpFun-specific tables on top of this same pipeline.

***

The `transfers` normalizer streams every decoded SPL token transfer on Solana into your warehouse - both classic Token Program and Token-2022. Each row carries full source/destination account context (owner, balance pre/post, UI amount) so you can build wallet-centric, token-centric, or compliance-oriented analytics without re-deriving from raw txs.

## Pipeline configuration

**Create a pipeline**

In the [GoldRush Platform](https://goldrush.dev/platform/), navigate to **Manage Pipelines** and click **Create Pipeline**. Name it `solana-spl-transfers`.

**Pick Solana + Transfers**

Choose **Solana** as the chain and **Transfers** as the data type.

**Configure your destination**

Connect ClickHouse, BigQuery, Postgres, Kafka, S3/GCS/R2, SQS, or a Webhook.

```yaml theme={null}
destination:
  type: "postgres"
  url: "postgresql://your-host:5432/solana_data"
  user: "${PG_USER}"
  password: "${PG_PASSWORD}"
  batch_size: 1000
```

**Optional: SQL transform**

Filter rows before they land. Example: keep only stablecoin transfers.

```yaml theme={null}
transforms:
  transfers: >
    SELECT *
    FROM transfers
    WHERE mint IN (
      'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',  -- USDC
      'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'   -- USDT
    )
```

**Deploy**

Decoded transfers begin flowing within seconds.

## Schema

The `transfers` table is documented in full on the **Solana Normalizers page**. Key columns:

* `block_slot`, `slot`, `block_time`, `tx_hash` (signature).
* `mint`, `amount` (raw uint64), `token_decimals`, `is_raw_amount`.
* `source_address` (token account), `source_owner` (wallet pubkey).
* `destination_address`, `destination_owner`.
* Pre/post balances on both sides (`*_pre_balance`, `*_post_balance`) plus UI-amount variants.
* `transfer_index` for ordering within a transaction.

## Sample analytical queries

### Daily stablecoin volume by mint

```sql theme={null}
SELECT
  date_trunc('day', to_timestamp(block_time)) AS day,
  mint,
  SUM(amount::numeric / power(10, token_decimals)) AS volume_tokens
FROM transfers
WHERE mint IN (
  'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
  'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'
)
  AND block_time >= extract(epoch from now() - interval '30 days')
GROUP BY day, mint
ORDER BY day DESC, volume_tokens DESC;
```

### Net flow per wallet for a token

```sql theme={null}
WITH inflow AS (
  SELECT destination_owner AS wallet, mint, SUM(amount::numeric) AS in_amount
  FROM transfers
  WHERE mint = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'
  GROUP BY destination_owner, mint
),
outflow AS (
  SELECT source_owner AS wallet, mint, SUM(amount::numeric) AS out_amount
  FROM transfers
  WHERE mint = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'
  GROUP BY source_owner, mint
)
SELECT
  COALESCE(i.wallet, o.wallet) AS wallet,
  COALESCE(i.in_amount, 0) - COALESCE(o.out_amount, 0) AS net
FROM inflow i
FULL OUTER JOIN outflow o ON i.wallet = o.wallet AND i.mint = o.mint
ORDER BY net DESC
LIMIT 100;
```

### Exchange deposit attribution

Maintain a table of known exchange wallets; join against `destination_owner` to attribute deposits.

```sql theme={null}
SELECT
  ex.exchange_name,
  t.mint,
  date_trunc('day', to_timestamp(t.block_time)) AS day,
  SUM(t.amount::numeric / power(10, t.token_decimals)) AS deposits
FROM transfers t
JOIN known_exchanges ex ON t.destination_owner = ex.wallet
WHERE t.block_time >= extract(epoch from now() - interval '7 days')
GROUP BY ex.exchange_name, t.mint, day
ORDER BY day DESC, deposits DESC;
```

## Production tips

* **`source_owner` and `destination_owner`** are the *wallet* pubkeys, not the SPL token-account pubkeys. Index on these for wallet-centric queries.
* **`amount` is raw uint64.** Always divide by `power(10, token_decimals)` (or use the `*_ui` balance columns) for human-readable amounts.
* **Token-2022 mints arrive in the same table** as classic SPL mints. If you only want classic SPL, filter on a known-Token-2022 mint allow/deny list.
* **High-volume mints (USDC, USDT, WSOL).** Partition by `block_date` and consider materialized views per top-N mint for fast dashboarding.

## Related

* **Solana Normalizers (full schema)** - column-level reference for `transfers` and other Solana entities.
* **DEX Swaps warehouse recipe** - companion table for DEX-trade analytics.
* **Stablecoin Transfers (cross-chain)** - multi-chain pattern; works for Solana too.
* **Wallet endpoints (REST)** - REST lookups for the same transfer history.
