Skip to main content
Different parts of the index start on different dates, and some hours are missing outright. Both are measured below rather than asserted: the tables in the next two sections are generated from the live index by a script. They are a snapshot, not a live view. The snapshot’s time is shown at the top, and nothing refreshes it between runs, so a window may have been filled, or a new one opened, since then. Endpoints that depend on Phase 0 mint capture also return a coverage_note field when results are empty.
Snapshot as of 2026-09-10 03:22Z. Everything below was measured against the live index at that time by scripts/gen-data-gaps.py, which is run by hand, not on a schedule. Changes since then (a window backfilled, a new outage, a window ageing past upstream retention) do not show until it is run again.

Where the data starts

Three different dates get called “the start of the index”, and they measure different things. These are the current values, read from the tables that serve your queries: GET /api/v1/stats reports the candle figure as oldest_candle, computed from the same tables — it is the one to trust programmatically.

Candle retention ladder

Candle timeframes expire on different schedules, so “how far back can I go” depends on which timeframe you ask for. A finer timeframe is not available for the whole history: Daily bars are kept forever, so 1d is the timeframe to use for a full-history series.

Known data gaps

These windows were measured at 2026-09-10 03:22Z, and each status is as of that time: a window marked Backfill pending may since have been filled, or have aged past upstream retention. An ingestion outage leaves a venue with no rows at all for the affected hours — not partial data. Every window of 2 hours or more that was outstanding when this was measured is listed here. A window drops off this table at the first regeneration after it is backfilled. Backfill pending means the blocks were still inside our upstream provider’s retention window when this was measured, so the hole could be filled. Past upstream retention means the source blocks have aged out; those windows may never be filled, so treat them as permanent holes when you design around them.

Per-venue totals

Across each venue’s own indexed history — hours before a venue was added are not counted against it: A “degraded” hour carries under 10% of that venue’s median hour. On a thin venue that is often just a quiet hour rather than a fault, which is why only runs of 2+ fully-empty hours are listed as gaps above.

Supported venues

Dexploit indexes swaps from 10 Solana DEX programs. Each swap carries a dex field — an integer ID (1–10) on the raw /swaps surface, the canonical lower-snake string everywhere else. The authoritative, always-current list is GET /api/v1/protocols. Orca and the three Meteora venues — DBC, DLMM, and Pools — were added on 2026-06-09; swaps before that date aren’t indexed for those four. Pump.fun and Meteora DBC are bonding curves, so they have no add/remove-liquidity events (the curve is the liquidity).

SOL-quoted swaps only

Every venue except Pump.fun indexes only swaps where one side is wrapped SOL (So111…1112). Pools quoted in USDC, USDT, or another token are not indexed, and neither are the non-SOL legs of a multi-hop route. This matters most on the concentrated-liquidity venues — Raydium CLMM, Orca, and Meteora DLMM — which list many USDC-quoted pools, so a meaningful share of their on-chain activity falls outside the index. Pump.fun is SOL-native, so all of its trades are captured.

Price & liquidity quality

Which price field should I use?

A swap carries three numbers that look like a price. They mean different things, and only one of them is right for every venue and every date.

Start with price_per_token

price_per_token is the price the trade actually executed at, computed from the trade’s own two legs and nothing else — it is exactly sol_amount / token_amount. Because it never touches pool reserves, nothing about how a venue reports its reserves can bias it, which is what makes it the one price field that is correct on all ten venues and across all of history. It arrives as lamports per atomic token unit. Scale it once to get SOL per whole token:
The streaming feeds don’t carry the field, but they carry both legs, so the same number is sol_amount / token_amount from the frame you already have.
base_decimals and quote_decimals are the reverse of the usual convention. base_decimals is the SOL side and is 9 on every venue. quote_decimals holds the token’s own decimals, despite the name — commonly 6, but 9 and other values are normal. Read quote_decimals as “the token’s decimals” and the line above is the whole conversion.
For a USD price, multiply by the SOL/USD rate.

pool_price is a reserve ratio, not a quote

pool_price is the ratio of the pool’s reported SOL reserve to its reported token reserve, already scaled to SOL per whole token, and passed through as the venue published it. We serve it uncorrected on purpose: it is the faithful record of what the venue reported, which is what makes it useful for reserve and liquidity work. That same property is why it isn’t a price you can trade against:
  • On constant-product and bonding-curve pools the ratio is the pool’s marginal price, and it lands within about a fee of the executed price.
  • On concentrated-liquidity pools the reported reserves are the pool’s whole inventory across every tick or bin — not the liquidity at the active price. The ratio is an inventory statistic, and it can sit far from anything you could fill at.
  • On PumpSwap pools that graduated from the pump.fun bonding curve after mid-July 2026, about 17.58 SOL of quote sits outside the account whose balance the swap event reports. The ratio therefore understates the price by (sol_reserve + 17.58) / sol_reserve — under a percent on a well-funded pool, and much larger as the pool drains.
Per-venue numbers are in Data coverage.

price_impact_bps is null where it wasn’t computed

price_impact_bps is nullable on every surface that carries it. REST (/swaps* and /swaps/{signature}), GraphQL (Int, previously Int!) and WebSocket all return null where no impact was computed. (The gRPC streams don’t carry the field.) None of them returns 0 for that case, so on REST and GraphQL a 0 is a real reading. The WebSocket exception is below. It’s computed on these venues: It’s null:
  • on meteora_dbc and meteora_pools;
  • on the six venues in the second row, for swaps from before that venue started computing it, and for swaps that couldn’t be priced;
  • on trades made by pump.fun’s own Mayhem program (agent_trade = 2), and on older zero-fee pumpfun trades by the same program from before agent_trade existed;
  • on dust trades, where the smaller leg (sol_amount or token_amount, in base units) is under 10,000. At that size one unit of integer rounding moves the executed price by more than 1 bp, so any number would be rounding noise.
In rare cases a stream frame carries 0 for a swap that REST and GraphQL serve as null: a swap on one of the six venues in the second row whose computed value landed on exactly 0. Treat both as unknown. On pumpswap the comparison is corrected for the SOL a pump.fun-migrated pool holds outside the account the swap reports, so it does not inherit the understatement described for pool_price. The same correction is applied on REST, GraphQL and WebSocket, so the surfaces agree for a given swap, apart from the rare 0 above and one more documented limit: REST and GraphQL clamp price_impact_bps to the Int16 range (−32,768 to 32,767), while the WebSocket feed carries the full value, so beyond that range they differ by design. It measures impact relative to the pool, not slippage against an external reference — for that, compare price_per_token to a reference you control.

For a price series, use candles

Candle prices are written when the bar closes and served back verbatim — stored bars are never re-derived at read time. So a change in how a venue’s price is derived reaches bars written from the day it ships forward; bars that closed earlier keep the value they were written with. One case is worth a number. On PumpSwap, daily closes written before the fix shipped carry the reserve-ratio understatement described above. Over the seven days 2026-08-31 to 2026-09-06 inclusive, across 153,174 PumpSwap daily bucket-closes, 39.5% (60,474) would take a different value once the migrated pool’s off-vault SOL is accounted for. Most of those moves are small; the largest single one in that window was 135×, on a pool drained to near-zero SOL, where the fixed shortfall dominates whatever is left. When you need a price you can act on, derive it from price_per_token over the swaps in the window rather than reading the bar close.

1 How far pool_price sits from the executed price

On the constant-product and bonding-curve venues a pool’s reserve ratio should land within roughly a swap fee of the price a trade actually executed at, and on raydium_amm, raydium_cpmm and pumpfun it does. On orca, meteora_dlmm and meteora_dbc it does not, and the gap is not a tail risk — it is the normal case. These are concentrated-liquidity venues: the reserves reported on a swap are the pool’s total inventory across every price range, not the liquidity sitting at the price you traded at. The ratio of those totals is an inventory statistic, and on individual rows we have measured it diverging from the executed price by more than an order of magnitude, in both directions. On pumpswap, the ratio is a genuine pre-trade constant-product price, but pump.fun-migrated pools hold part of their SOL side outside the account the swap reports. The shortfall is a fixed amount, so the error is negligible on a deep pool and grows without bound as the pool drains. Do not use pool_price as a price on any venue. Use price_per_token scaled by 10^(quote_decimals − base_decimals), which comes from the trade itself and is correct on every venue and for all history.

2 PumpSwap pools migrated from pump.fun

PumpSwap pools that graduated from the pump.fun bonding curve after mid-July 2026 hold about 17.58 SOL of quote outside the account whose balance the swap event reports, so the ratio understates the price by (sol_reserve + 17.58) / sol_reserve. That is a fraction of a percent on a pool holding a few hundred SOL, and it grows as the pool drains: on a live row from a pool reporting 0.56 SOL of reserve, pool_price sat 32.6× below the price the same trade filled at — exactly the factor the formula predicts. Pools that graduated before that date, and manually-created PumpSwap pools, carry no such offset. price_per_token is unaffected either way.

3 Vault-ratio venues and TVL-like reserves

On raydium_clmm, orca, meteora_damm_v2, and meteora_dlmm the reserve fields are whole-pool totals (TVL-like), not active-tick liquidity — don’t use them as a constant-product price oracle. raydium_clmm reports a true spot pool_price from the pool’s sqrt-price rather than the vault ratio. meteora_damm_v2 now does the same, but there is a cutover you need to know about if you read history: every row from 2026-09-04 onward is priced from the pool’s own post-swap sqrt price; every row before it carries the vault ratio instead. There is no per-row fallback — the date is the whole rule. Rows on either side of it are not comparable as a price series. orca, meteora_dlmm, and meteora_dbc report the vault ratio.

4 Meteora Dynamic AMM (Pools)

On meteora_pools, liquidity sits in dynamic vaults shared across many pools, so no per-pool reserve is derivable from a swap: real_sol_reserves and real_token_reserves come back 0, not absent. pool_price is populated, but on this venue it is not a pool ratio at all — it is that swap’s own executed price, decimals-adjusted, so it equals price_per_token × 10^(quote_decimals − base_decimals) exactly. Add/remove-liquidity events for this venue aren’t published yet.

Endpoints affected

/deployer/{wallet}

Only ~5% of mints currently in our index have a non-empty creator field — older mints predate Phase 0. New mints (post-2026-05-26) all have creator captured. If you query /deployer/{wallet} for a wallet that deployed before Phase 0, you may see empty results. The response will include:

/tokens/{mint}/ath

Sources ohlcv_1d, which is populated from day 1 of the candle ingestion pipeline. No coverage gap.

/price/history*

Sources ohlcv_{1m,5m,1h,1d}. Same coverage as /api/v1/candles — see the OHLCV docs.

Actor charts (Phase 3)

token_actor_history snapshots begin at Phase 3 launch (2026-05-28). There is no pre-launch backfill — upstream holder balances aren’t retained historically, so accurate reconstruction isn’t possible. Charts fill forward as a mint trades. A mint that doesn’t trade for several hours has gaps (not zeros) in its chart for those hours — holder counts don’t change when nothing trades. Frontends should forward-fill the last known value. bundler_count / bundler_pct are 0 until the Phase 5 bundler tagger ships.