Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 32 additions & 6 deletions benchmarks/aggregator-head-lag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

slug: aggregator-head-lag
number: "001"
title: Fastest crypto price API, live head lag across Mobula, Codex, GeckoTerminal
title: Fastest crypto price API, live head lag across Mobula, Codex, GeckoTerminal, Serialized
seo_title: "Fastest crypto price API 2026"
seo_description: "{{best_name}} leads fastest crypto price API at {{best_p50}} (cross-chain avg p50, 24h). Mobula WebSocket, Codex GraphQL, GeckoTerminal REST live across Base, BNB, Solana, Robinhood."
subtitle: Wall-clock head lag in seconds from on-chain swap event to API emission, measured live for Mobula, Codex and GeckoTerminal on Base, BNB Chain, Solana and Robinhood Chain.
seo_description: "{{best_name}} leads fastest crypto price API at {{best_p50}} (cross-chain avg p50, 24h). Mobula WebSocket, Codex GraphQL, GeckoTerminal REST, Serialized WebSocket live across Base, BNB, Solana, Robinhood."
subtitle: Wall-clock head lag in seconds from on-chain swap event to API emission, measured live for Mobula, Codex, GeckoTerminal and Serialized on Base, BNB Chain, Solana and Robinhood Chain.

per_chain_explainer:
- slug: base
Expand Down Expand Up @@ -37,7 +37,7 @@ seo_intro: |
chain and the same event appearing on the provider's feed. Marketing
pages quote "real-time" without a number; this page quotes the
number. Mobula's WebSocket, Codex's GraphQL feed, GeckoTerminal's
REST endpoint are watched
REST endpoint and Serialized's WebSocket trades stream are watched
from three regions (us-east, eu-west, sgp). On Base the zero point is
the sequencer's flashblock preconfirmation stream, which we hold
ourselves; on BNB Chain, Solana and Robinhood Chain it is the
Expand All @@ -63,7 +63,7 @@ abstract: |
same event.

methodology:
- "Aggregators measured: Mobula, Codex, GeckoTerminal."
- "Aggregators measured: Mobula, Codex, GeckoTerminal, Serialized."
- "Chains: Base, BNB Chain, Solana, Robinhood Chain."
- "Reference on BNB Chain and Robinhood Chain: archive nodes per chain, validated against block hashes. These carry no preconfirmation layer a provider consumes, and their chain-supplied timestamps sit within roughly 60 ms of the moment a trade is observable, so they keep the on-chain timestamp as the zero point."
- "Solana (since 2026-09-16): the headline is the lag behind the first feed to report the trade, our own node subscription included in the race. Solana has no on-chain timestamp with sub-second precision, so the timestamps providers send compare conventions: Mobula's `date` (its ingestion time) read as a constant 0.10 s, Serialized's `at` (blockTime, whole seconds) as 0.75 s, while against a common clock the two feeds are 10 to 30 ms apart."
Expand All @@ -87,7 +87,7 @@ findings:
- "On Base, what a provider reads matters more than how fast its pipeline is. A provider emitting from flashblock preconfirmations delivers a trade about 1.6 s (median over 21,538 transactions) before the sealed block carrying it becomes queryable, so a sealed-block reader carries that floor before any pipeline work. A preconfirmation is not final and can be reordered."
- "The Base spread is therefore mostly that floor: the providers' own pipelines sit within a few hundred milliseconds of each other. Read the Base column as a latency versus finality choice, not as a pure speed ranking."
- "{{name:geckoterminal}} trails on every chain. REST polling adds the poll interval to every read, so head lag tracks the publisher's chosen cadence rather than raw infrastructure speed."
- "p99 is the integration-grade number. The gap between p50 and {{p99:mobula}} / {{p99:codex}} / {{p99:geckoterminal}} is what a live UI feels when a chain spikes or a region's path degrades."
- "p99 is the integration-grade number. The gap between p50 and {{p99:mobula}} / {{p99:codex}} / {{p99:serialized}} / {{p99:geckoterminal}} is what a live UI feels when a chain spikes or a region's path degrades."

source: https://github.com/ChainBench/OpenChainBench/tree/main/harnesses/aggregator-head-lag

Expand Down Expand Up @@ -247,6 +247,32 @@ providers:
p50: avg by (aggregator) (quantile_over_time(0.50, head_lag_seconds{aggregator="codex", region="sgp"}[24h])) * 1000
series: avg_over_time(head_lag_seconds{aggregator="codex", region="sgp"}[1h]) * 1000 unless (changes(head_lag_seconds{aggregator="codex", region="sgp"}[15m]) == 0 and count_over_time(head_lag_seconds{aggregator="codex", region="sgp"}[15m]) > 5 and on(chain, region) sum by (chain, region) (changes(head_lag_seconds{region="sgp"}[15m])) > 5 and on(aggregator, region) avg_over_time(ws_connected{aggregator="codex", region="sgp", chain=""}[15m]) > 0.8)



- slug: serialized
name: Serialized
tag: WebSocket trades stream
formula: "Median seconds between an on-chain swap on the bench pools and the same trade arriving on Serialized's WebSocket trades stream (subscribed per pool by its token side), sampled every 15s over 24h."
queries:
p50: avg by (aggregator) (quantile_over_time(0.50, head_lag_seconds{aggregator="serialized"}[24h])) * 1000
p90: avg by (aggregator) (quantile_over_time(0.90, head_lag_seconds{aggregator="serialized"}[24h])) * 1000
p99: avg by (aggregator) (quantile_over_time(0.99, head_lag_seconds{aggregator="serialized"}[24h])) * 1000
mean: avg by (aggregator) (avg_over_time(head_lag_seconds{aggregator="serialized"}[24h])) * 1000
success: clamp_max(avg by (aggregator) (count_over_time(head_lag_seconds{aggregator="serialized"}[24h]) / 2880), 1)
sample_size: sum(count_over_time(head_lag_seconds{aggregator="serialized"}[24h]))
series: avg_over_time(head_lag_seconds{aggregator="serialized"}[1h]) * 1000 unless (changes(head_lag_seconds{aggregator="serialized"}[15m]) == 0 and count_over_time(head_lag_seconds{aggregator="serialized"}[15m]) > 5 and on(chain, region) sum by (chain, region) (changes(head_lag_seconds{}[15m])) > 5 and on(aggregator, region) avg_over_time(ws_connected{aggregator="serialized", chain=""}[15m]) > 0.8)
live_activity: sum(changes(head_lag_seconds{aggregator="serialized"}[15m]))
regions:
- region: us-east
p50: avg by (aggregator) (quantile_over_time(0.50, head_lag_seconds{aggregator="serialized", region="us-east"}[24h])) * 1000
series: avg_over_time(head_lag_seconds{aggregator="serialized", region="us-east"}[1h]) * 1000 unless (changes(head_lag_seconds{aggregator="serialized", region="us-east"}[15m]) == 0 and count_over_time(head_lag_seconds{aggregator="serialized", region="us-east"}[15m]) > 5 and on(chain, region) sum by (chain, region) (changes(head_lag_seconds{region="us-east"}[15m])) > 5 and on(aggregator, region) avg_over_time(ws_connected{aggregator="serialized", region="us-east", chain=""}[15m]) > 0.8)
- region: eu-west
p50: avg by (aggregator) (quantile_over_time(0.50, head_lag_seconds{aggregator="serialized", region="eu-west"}[24h])) * 1000
series: avg_over_time(head_lag_seconds{aggregator="serialized", region="eu-west"}[1h]) * 1000 unless (changes(head_lag_seconds{aggregator="serialized", region="eu-west"}[15m]) == 0 and count_over_time(head_lag_seconds{aggregator="serialized", region="eu-west"}[15m]) > 5 and on(chain, region) sum by (chain, region) (changes(head_lag_seconds{region="eu-west"}[15m])) > 5 and on(aggregator, region) avg_over_time(ws_connected{aggregator="serialized", region="eu-west", chain=""}[15m]) > 0.8)
- region: ap-southeast
p50: avg by (aggregator) (quantile_over_time(0.50, head_lag_seconds{aggregator="serialized", region="sgp"}[24h])) * 1000
series: avg_over_time(head_lag_seconds{aggregator="serialized", region="sgp"}[1h]) * 1000 unless (changes(head_lag_seconds{aggregator="serialized", region="sgp"}[15m]) == 0 and count_over_time(head_lag_seconds{aggregator="serialized", region="sgp"}[15m]) > 5 and on(chain, region) sum by (chain, region) (changes(head_lag_seconds{region="sgp"}[15m])) > 5 and on(aggregator, region) avg_over_time(ws_connected{aggregator="serialized", region="sgp", chain=""}[15m]) > 0.8)

- slug: geckoterminal
name: GeckoTerminal
tag: REST feed
Expand Down
13 changes: 13 additions & 0 deletions benchmarks/asset-registry-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,19 @@ providers:
sample_size: networks_supported_total{provider="coingecko"}
series: networks_supported_total{provider="coingecko"}

- slug: serialized
name: Serialized
tag: Own indexers, 18 EVM + Solana
formula: "Count of chains returned as live by Serialized's `/v1/meta/chains` endpoint, refreshed every 6 hours."
queries:
p50: networks_supported_total{provider="serialized"}
p90: networks_supported_total{provider="serialized"}
p99: networks_supported_total{provider="serialized"}
mean: networks_supported_total{provider="serialized"}
success: clamp_max(networks_supported_total{provider="serialized"} > bool 0, 1)
sample_size: networks_supported_total{provider="serialized"}
series: networks_supported_total{provider="serialized"}

- slug: coinpaprika
name: CoinPaprika
tag: Market-data API asset registry
Expand Down
13 changes: 13 additions & 0 deletions benchmarks/dex-network-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,19 @@ providers:
sample_size: networks_supported_total{provider="geckoterminal"}
series: networks_supported_total{provider="geckoterminal"}

- slug: serialized
name: Serialized
tag: Own indexers, 18 EVM + Solana
formula: "Count of chains returned as live by Serialized's `/v1/meta/chains` endpoint; every listed chain carries DEX pool indexing. Refreshed every 6 hours."
queries:
p50: networks_supported_total{provider="serialized"}
p90: networks_supported_total{provider="serialized"}
p99: networks_supported_total{provider="serialized"}
mean: networks_supported_total{provider="serialized"}
success: clamp_max(networks_supported_total{provider="serialized"} > bool 0, 1)
sample_size: networks_supported_total{provider="serialized"}
series: networks_supported_total{provider="serialized"}

- slug: codex
name: Codex
tag: Defined.fi DEX data API
Expand Down
13 changes: 13 additions & 0 deletions benchmarks/metadata-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,19 @@ providers:
sample_size: sum(increase(metadata_coverage_checks_total{provider="codex"}[24h]))
series: 100 * sum(rate(metadata_coverage_success_total{provider="codex"}[1h])) / sum(rate(metadata_coverage_checks_total{provider="codex"}[1h]))

- slug: serialized
name: Serialized
tag: REST `/v1/token/metadata`
formula: "Median of hourly coverage rate (populated logo/description/twitter/website fields divided by total field checks) on Serialized `/v1/token/metadata` for fresh tokens, p50 over 24h."
queries:
p50: quantile_over_time(0.50, (100 * sum(rate(metadata_coverage_success_total{provider="serialized"}[1h])) / sum(rate(metadata_coverage_checks_total{provider="serialized"}[1h])))[24h:1h])
p90: quantile_over_time(0.90, (100 * sum(rate(metadata_coverage_success_total{provider="serialized"}[1h])) / sum(rate(metadata_coverage_checks_total{provider="serialized"}[1h])))[24h:1h])
p99: quantile_over_time(0.99, (100 * sum(rate(metadata_coverage_success_total{provider="serialized"}[1h])) / sum(rate(metadata_coverage_checks_total{provider="serialized"}[1h])))[24h:1h])
mean: 100 * sum(rate(metadata_coverage_success_total{provider="serialized"}[24h])) / sum(rate(metadata_coverage_checks_total{provider="serialized"}[24h]))
success: clamp_max(sum(rate(metadata_coverage_checks_total{provider="serialized"}[24h])) / scalar(sum(rate(metadata_coverage_checks_total{provider="mobula"}[24h]))), 1)
sample_size: sum(increase(metadata_coverage_checks_total{provider="serialized"}[24h]))
series: 100 * sum(rate(metadata_coverage_success_total{provider="serialized"}[1h])) / sum(rate(metadata_coverage_checks_total{provider="serialized"}[1h]))

- slug: jupiter
name: Jupiter
tag: REST `/v6/tokens` (Solana)
Expand Down
18 changes: 18 additions & 0 deletions benchmarks/wallet-labels-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@ prometheus:
# Default is `eoa` because the contract tab is trivially easy for explorers
# and saturates near 100%; the EOA tab is where curated entity coverage
# actually differentiates providers.
# Scored on contested chains only: stellar, xrp and bitcoin carry a single
# measured provider each, and a cross-chain average that counts them puts a
# provider first for a chain nobody else reported. See spec-schema.ts.
score_scope: contested_chains

dimensions:
kind:
- { value: eoa, label: EOA }
Expand Down Expand Up @@ -194,6 +199,19 @@ providers:
sample_size: sum(increase(wallet_labels_checks_total{provider="mobula"}[24h]))
series: 100 * sum(rate(wallet_labels_success_total{provider="mobula"}[1h])) / sum(rate(wallet_labels_checks_total{provider="mobula"}[1h]))

- slug: serialized
name: Serialized
tag: Identity graph, 18 EVM chains + Solana, API key required
formula: "Share of anchor addresses for which Serialized /v1/wallet/profile returns a non-generic identity name, success_total ÷ checks_total over 24h."
queries:
p50: 100 * sum(increase(wallet_labels_success_total{provider="serialized"}[24h])) / sum(increase(wallet_labels_checks_total{provider="serialized"}[24h]))
p90: 100 * sum(increase(wallet_labels_success_total{provider="serialized"}[24h])) / sum(increase(wallet_labels_checks_total{provider="serialized"}[24h]))
p99: 100 * sum(increase(wallet_labels_success_total{provider="serialized"}[24h])) / sum(increase(wallet_labels_checks_total{provider="serialized"}[24h]))
mean: 100 * sum(increase(wallet_labels_success_total{provider="serialized"}[24h])) / sum(increase(wallet_labels_checks_total{provider="serialized"}[24h]))
success: clamp_min(1 - (sum(increase(wallet_labels_fetch_errors_total{provider="serialized"}[24h])) or vector(0)) / clamp_min(sum(increase(wallet_labels_checks_total{provider="serialized"}[24h])), 1), 0)
sample_size: sum(increase(wallet_labels_checks_total{provider="serialized"}[24h]))
series: 100 * sum(rate(wallet_labels_success_total{provider="serialized"}[1h])) / sum(rate(wallet_labels_checks_total{provider="serialized"}[1h]))

- slug: helius
name: Helius
tag: Solana specialist, native program graph, API key required
Expand Down
Loading
Loading