Skip to main content

How to track Solana DEX trades with the new swaps dataset

Comparing execution across Solana's DEXes is the same problem equities markets solved with the consolidated tape system. Here's how to get every swap into one uniform shape in your own ClickHouse, then measure effective price, spread, venue share, and routed flow.

How to track Solana DEX trades with the new swaps dataset cover image
image of Sek Fook
Sek Fook

Software Engineer

Solana has become one of the busiest venues for trading digital assets, aiming to be the internet's capital market. The question is whether onchain markets can deliver execution that stands up next to traditional venues, and attract the capital watching from the sidelines.

That comes down to what any trading desk measures a venue on: reliable fills, tight spreads, and low fees. But measuring them means getting clean trade data, which, on Solana is surprisingly hard to get!

Why tracking Solana DEX swaps is hard

A DEX (decentralized exchange) is a venue where trades settle onchain rather than through a broker and a clearing house. On Solana, each DEX is deployed as its own program: Solana's term for a smart contract, living at its own address, written by its own team.

There's no unified swap standard on Solana. Each program is built on its own framework, with its own instruction layout and event encoding.

The mechanics of how each venue prices a trade differ too. And developers update their programs, introducing new instructions, events, and fields to track.

So before you can ask about price or volume, you're maintaining a decoder for each venue and keeping it current.

This is the same problem that US equities had in the 1970s. There were dozens of venues, no common format, and no way to compare a fill on one against a fill on another. They solved it with the consolidated tape, the normalized stream that made execution analysis routine – and has run continuously since.

Goldsky's Solana DEX Trades dataset does the equivalent job.

Programs in the Solana DEX swaps dataset

solana.dex_swaps currently decodes swaps from seven programs:

DEX (project)Program ID
raydium_clmmCAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK
raydium_cpmmCPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C
orca_whirlpoolwhirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc
meteora_damm_v1Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB
meteora_damm_v2cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG
pump_ammpAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA
pumpfun6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P

Every row is a single swap from the trader's perspective. These columns are probably what you're most interested in:

  • token_bought_amount / token_sold_amount — What the trader received and paid.
    • These are already scaled by token decimals into human units. Onchain, token balances are stored as integers. USDC for example carries six decimals, so 1,000,000 base units is $1. The dataset does the division for you.
    • Raw base-unit integers (_amount_raw) are there too if you need exact arithmetic.
  • token_bought_mint_address / token_sold_mint_address — The SPL mints on each side of the trade.
  • project — The human-readable DEX label, so you can GROUP BY venue without memorizing program IDs.
  • trade_source — For top-level swaps, this is direct. For inner instructions, it's the program ID of the router/aggregator (e.g. Jupiter) that invoked the swap.
    • Routers are smart order routers in the conventional sense: a trader submits an order to the router, and it splits and forwards the fill across whichever venues offer the best price. This column tells you which flow arrived that way, which makes routing analysis easy.
  • block_timestamp, block_slot, tx_id, instruction_index — Everything you need to trace a row back onchain.

The suffixes describe pricing mechanics. Automated market makers (AMMs) quote against a fixed formula. Concentrated liquidity market makers (CLMMs) let providers deploy capital into specific price bands instead. Pump.fun's launchpad uses dynamic bonding curves, where price moves as supply is minted. The dataset normalizes all of them into the same row shape.

The full schema is in the docs.

Stream Solana DEX trades into ClickHouse

With Turbo, getting Solana DEX trades into your own ClickHouse is a single pipeline definition. Turbo creates the tables automatically with a ReplacingMergeTree engine. It deduplicates on the primary key, so replays and chain reorganizations resolve to one row per swap rather than accumulating duplicates:

name: solana-dex-swaps-clickhouse
resource_size: m

sources:
  dex_swaps:
    type: dataset
    dataset_name: solana.dex_swaps
    version: 1.0.0
    start_block: 426725306
    options:
      dex: raydium_clmm,orca_whirlpool,raydium_cpmm,pump_amm,pumpfun
Transform: {}
sinks:
  clickhouse_swaps:
    type: clickhouse
    from: dex_swaps
    table: solana_dex_swaps
    primary_key: id
    secret_name: MY_CLICKHOUSE

With all the trade data in ClickHouse, we can run price execution research on the following token pair:

  • wSOL (So11111111111111111111111111111111111111112)
    • While SOL is Solana's native asset, it doesn't natively conform to the SPL token standard that DEX programs expect. So it's wrapped into a token that does conform (Wrapped SOL).
  • USDC (EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v)

to answer four sample questions:

  1. What was the effective price on each DEX?
  2. How wide was the spread across venues?
  3. Which DEX is winning market share?
  4. How much flow comes from aggregators vs. direct?

Example 1: Compare execution price for the same pair across DEXes

At any given minute, what was the effective SOL/USDC price on each venue? Every row carries both sides of the trade in human units, so price is just usdc / sol. The only work is normalizing trade direction: a row can be either "bought SOL with USDC" or "bought USDC with SOL".

sql
-- Minute-by-minute volume-weighted SOL/USDC price, per DEX, last 24h
SELECT
    toStartOfMinute(toDateTime(block_timestamp)) AS minute,
    project,
    sum(usdc_amount) / sum(sol_amount)           AS vwap_usdc_per_sol,
    count()                                      AS trades,
    sum(sol_amount)                              AS sol_volume
FROM
(
    SELECT
        block_timestamp,
        project,
        if(token_bought_mint_address = 'So11111111111111111111111111111111111111112',
           token_bought_amount, token_sold_amount)  AS sol_amount,
        if(token_bought_mint_address = 'So11111111111111111111111111111111111111112',
           token_sold_amount, token_bought_amount)  AS usdc_amount
    FROM solana_dex_swaps FINAL
    WHERE (
            (token_bought_mint_address = 'So11111111111111111111111111111111111111112'
             AND token_sold_mint_address = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v')
         OR (token_bought_mint_address = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'
             AND token_sold_mint_address = 'So11111111111111111111111111111111111111112')
          )
      AND block_timestamp >= toUnixTimestamp(now() - INTERVAL 24 HOUR)
      AND token_sold_amount > 0
      AND token_bought_amount > 0
)
GROUP BY minute, project
ORDER BY minute, project;
Chart of SOL/USDC execution price by DEX

Example 2: Quantify the cross-DEX spread (and find who's cheapest)

You can build on the same subquery to collapse the per-DEX prices into a single cross-venue spread series. This gives a direct measure of arbitrage opportunity and market efficiency. The wider and more persistent the gap, the more a naive fill costs.

sql
-- Per-minute spread between the cheapest and most expensive venue, in bps
WITH venue_prices AS
(
    SELECT
        toStartOfMinute(toDateTime(block_timestamp)) AS minute,
        project,
        sum(if(token_bought_mint_address = 'So11111111111111111111111111111111111111112',
               token_sold_amount, token_bought_amount))
      / sum(if(token_bought_mint_address = 'So11111111111111111111111111111111111111112',
               token_bought_amount, token_sold_amount)) AS vwap
    FROM solana_dex_swaps FINAL
    WHERE (
            (token_bought_mint_address = 'So11111111111111111111111111111111111111112'
             AND token_sold_mint_address = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v')
         OR (token_bought_mint_address = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'
             AND token_sold_mint_address = 'So11111111111111111111111111111111111111112')
          )
      AND block_timestamp >= toUnixTimestamp(now() - INTERVAL 24 HOUR)
    GROUP BY minute, project
    HAVING count() >= 3   -- require a few trades so thin minutes don't skew the spread
)
SELECT
    minute,
    argMin(project, vwap)                          AS cheapest_venue,
    argMax(project, vwap)                          AS priciest_venue,
    min(vwap)                                      AS min_price,
    max(vwap)                                      AS max_price,
    round((max(vwap) - min(vwap)) / min(vwap) * 10000, 2) AS spread_bps
FROM venue_prices
GROUP BY minute
HAVING count() >= 2       -- only minutes where at least two venues traded
ORDER BY minute;
Graph of SOL cross-DEX spread

Example 3: Solana DEX market share over time

Which venue is actually winning the flow? SOL-denominated volume is a clean common denominator, since the vast majority of pairs route through SOL:

sql
-- Daily SOL-denominated volume and swap count per DEX, last 30 days
SELECT
    toDate(toDateTime(block_timestamp)) AS day,
    project,
    count()                             AS swaps,
    round(sumIf(token_bought_amount,
          token_bought_mint_address = 'So11111111111111111111111111111111111111112')
        + sumIf(token_sold_amount,
          token_sold_mint_address   = 'So11111111111111111111111111111111111111112'), 0) AS sol_volume,
    uniqExact(trader_id)                AS unique_traders
FROM solana_dex_swaps FINAL
WHERE block_timestamp >= toUnixTimestamp(now() - INTERVAL 30 DAY)
  AND (token_bought_mint_address = 'So11111111111111111111111111111111111111112'
    OR token_sold_mint_address   = 'So11111111111111111111111111111111111111112')
GROUP BY day, project
ORDER BY day, sol_volume DESC;
Chart of DEX market share over time

Example 4: How much flow comes from aggregators vs. direct?

trade_source makes this a one-liner. Direct swaps carry the literal string direct. Anything else is the program ID of the router that invoked the DEX. Jupiter v6, for instance, is JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4.

sql
SELECT
    project,
    if(trade_source = 'direct', 'direct', 'router') AS flow,
    count()                                          AS swaps,
    round(100.0 * count() / sum(count()) OVER (PARTITION BY project), 1) AS pct_of_dex
FROM solana_dex_swaps FINAL
WHERE block_timestamp >= toUnixTimestamp(now() - INTERVAL 7 DAY)
GROUP BY project, flow
ORDER BY project, flow;

And to rank the routers themselves:

sql
-- Top routers by swaps delivered, last 7 days
SELECT
    trade_source AS router_program_id,
    count()      AS swaps,
    uniqExact(project) AS venues_reached
FROM solana_dex_swaps FINAL
WHERE trade_source != 'direct'
  AND block_timestamp >= toUnixTimestamp(now() - INTERVAL 7 DAY)
GROUP BY router_program_id
ORDER BY swaps DESC
LIMIT 10;
Chart of DEX flow from aggregators vs direct on Solana

Benefits of Goldsky's DEX swaps dataset

Solana's DEX landscape is fragmented by design. Each venue is its own program with its own quirks.

  • Goldsky's solana.dex_swaps dataset flattens that mess into one uniform shape.
  • Every swap is one row. Both sides come denominated in human units, tagged with the venue and the router that delivered the flow.
  • Goldsky handles the decoding, the decimal scaling, and the routing attribution for you.
  • Get full unlimited historical access back to the genesis block.
  • Datasets stay up-to-date for you as new programs and instruction layouts ship.

That leaves you free to focus on the questions you and your customers care about. Where's the best price? How wide is the spread? Who's winning the volume? How much flow is aggregated?

These become ordinary SQL against your own ClickHouse.

Reproduce this in your own ClickHouse

Want to reproduce any of this? The fastest way is to spin up a Solana DEX trade pipeline with Turbo pipeline above. Check out our documentation for the full schema and latest information on our Solana DEX trade datasets: https://docs.goldsky.com/turbo-pipelines/sources/solana-dex-trades

If the DEX trade dataset you're looking for isn't listed, please contact [email protected]

© Endless Sky Inc. All rights reserved.

PrivacyTermsSecurity

System status