diff --git a/answers/which-crypto-data-api-covers-the-most-blockchains.yml b/answers/which-crypto-data-api-covers-the-most-blockchains.yml index c9cfa616..7b51973a 100644 --- a/answers/which-crypto-data-api-covers-the-most-blockchains.yml +++ b/answers/which-crypto-data-api-covers-the-most-blockchains.yml @@ -1,38 +1,38 @@ slug: which-crypto-data-api-covers-the-most-blockchains question: "Which crypto data API covers the most blockchains in 2026?" short_answer: | - {{best_name}} currently leads the network coverage leaderboard at {{best_p50}} unique mainnets supported, measured live every 6 hours from each provider's own supported networks endpoint across GeckoTerminal, Codex, Mobula, CoinPaprika, CoinStats and Dune (via Sim API). + {{best_name}} currently leads the asset-registry coverage leaderboard at {{best_p50}} unique mainnets, measured live every 6 hours from each provider's own registry endpoint across CoinGecko, CoinPaprika, Mobula and CoinStats. DEX-pool coverage is a different question with a separate leaderboard (GeckoTerminal, Codex, DefiLlama, DexPaprika, Sim by Dune). -benchmark: network-coverage +benchmark: asset-registry-coverage intro: | - Every onchain product roadmap eventually hits the same gate: which data provider do we integrate so the SDK speaks every chain we need without us rolling a custom indexer per network. Marketing pages quote round numbers (250+, 100+, 50+ chains) without a list a reader can verify, and the gap between a claimed count and the actual queryable surface is where integration timelines slip. This page answers one question with live data. How many mainnets does each major crypto data API officially support today, read directly from each provider's own supported networks endpoint and deduplicated by chain id. The OpenChainBench network-coverage harness polls GeckoTerminal's `/api/v2/networks`, Codex GraphQL `getNetworks`, Mobula's `/api/1/blockchains`, CoinPaprika's `/v1/contracts`, CoinStats's `/wallet/blockchains` and Dune's Sim API `/v1/evm/supported-chains` every 6 hours, counts the unique chain ids returned, and publishes the result as the Prometheus gauge `networks_supported_total{provider}`. Mainnets only, testnets are filtered server side because providers list them inconsistently and a builder shipping to production needs the production count. + Every onchain product roadmap eventually hits the same gate: which data provider do we integrate so the SDK speaks every chain we need. The honest answer requires two leaderboards, not one, because two very different products get lumped together in the marketing copy. Asset-registry coverage answers the question "on how many chains does this API know tokens for contract-address lookup", that is the number a market-data API cares about (CoinGecko, CoinPaprika, Mobula, CoinStats). DEX-pool coverage answers the question "on how many chains does this API index DEX pools + swap volumes", that is the number a DEX-facing product cares about (GeckoTerminal, Codex, DefiLlama, DexPaprika, Sim by Dune). Comparing a token-registry chain count against a DEX-indexer chain count is not apples-to-apples, and putting both on one leaderboard makes the number meaningless. This page is the asset-registry answer, backed by the OpenChainBench `asset-registry-coverage` bench which polls CoinGecko's `/asset_platforms`, CoinPaprika's `/v1/contracts`, CoinStats's `/wallet/blockchains` and Mobula's `/blockchains` every 6 hours, dedupes per platform, and publishes the count. For the DEX-indexing question read the sister bench `dex-network-coverage`. methodology: | - Each provider is polled at its public supported networks endpoint every 6 hours from a single eu-west origin. GeckoTerminal pagination is followed through every page of `/api/v2/networks` (no auth required). Codex's GraphQL `getNetworks` query runs against `https://graph.codex.io/graphql` with an official API key. Mobula reads `/api/1/blockchains` with an Authorization header. CoinPaprika lists supported platforms through the public `/v1/contracts` endpoint (no auth). CoinStats reads `/wallet/blockchains` with `X-API-KEY`. Dune (via the Sim API) reads `/v1/evm/supported-chains` no auth, EVM only, mainnets filtered via the `mainnet` tag. Counting is the same shape for every provider: one count per unique chain id per response, mainnet only. Failures (network errors, rate limits, auth errors) leave the previous count in place and increment `fetch_errors_total`; the page falls back to its last successful sample so a transient outage does not silently drop a provider off the leaderboard. + Each provider is polled at its public asset-registry endpoint every 6 hours from a single eu-west origin. CoinGecko reads `/api/v3/asset_platforms` (no auth) which lists every chain CoinGecko can resolve contract addresses on. CoinPaprika reads the public `/v1/contracts` endpoint (no auth) listing platforms supported for contract lookup. CoinStats reads `/wallet/blockchains` with `X-API-KEY`. Mobula reads `/api/1/blockchains` with an Authorization header. Counting is the same shape for every provider: one count per unique chain id or platform slug per response, mainnet only. Failures (network errors, rate limits, auth errors) leave the previous count in place and increment `fetch_errors_total`; the page falls back to its last successful sample so a transient outage does not silently drop a provider off the leaderboard. The companion DEX-indexing leaderboard uses a separate set of endpoints (`/api/v2/networks`, Codex `getNetworks`, `api.llama.fi/chains`, `api.dexpaprika.com/networks`, `sim.dune.com/v1/evm/supported-chains`) and lives on the `dex-network-coverage` bench. limitations: - - "Breadth is one dimension of a data provider's product, not a ranking on quality. A provider with 200 chains and shallow per chain depth can rank above one with 80 chains and full DEX, metadata and event coverage on each. Use this benchmark for the breadth question; head lag (aggregator-head-lag) and metadata completeness (metadata-coverage) answer the depth question. A serious integration decision reads all three." + - "Asset-registry coverage measures token-lookup breadth, not DEX-pool breadth. A market-data API can know tokens on 300 chains through a metadata pipeline while running DEX pool indexing on only a dozen. Read the `dex-network-coverage` bench for the DEX-indexing view." + - "Breadth is one dimension of a data provider's product, not a ranking on quality. A provider with 200 chains and shallow per chain depth can rank above one with 80 chains and full metadata and event coverage on each. Use this benchmark for the breadth question; head lag (`aggregator-head-lag`) and metadata completeness (`metadata-coverage`) answer the depth question." - "Mainnet only. Testnet listings are inconsistent across providers (some list every devnet ever spun up, others list none), and the production count is the one builders integrate against. The harness filters server side using each provider's own testnet flag where available." - - "Dune coverage is EVM only via the Sim API endpoint. Non EVM chains a Dune integration could reach through other product surfaces are not on the gauge because the `/v1/evm/supported-chains` endpoint is scoped to EVM by construction." - - "CoinPaprika is counted by platform slugs returned by `/v1/contracts`, which lists platforms supported for contract lookup. That is the closest comparable to a supported networks count for CoinPaprika's product surface but it is not identical in shape to the dedicated `getNetworks` style endpoints other providers expose." - - "A provider can technically reach a chain through a custom integration without listing it on the public supported networks endpoint. This bench measures what each API officially publishes as queryable, which is what a builder evaluating the SDK actually sees, not the absolute coverage envelope including private integrations." + - "CoinPaprika is counted by platform slugs returned by `/v1/contracts`, which lists platforms supported for contract lookup. CoinPaprika's DEX product (DexPaprika, a separate networks endpoint) is measured on the `dex-network-coverage` bench, not here." + - "A provider can technically reach a chain through a custom integration without listing it on the public asset-registry endpoint. This bench measures what each API officially publishes as queryable for token lookups, which is what a builder evaluating the SDK actually sees." faq: - - q: "Which crypto data API supports the most blockchains right now?" - a: "{{best_name}} currently leads at {{best_p50}} unique mainnets across the 6 measured providers. The count is read every 6 hours directly from each provider's own supported networks endpoint and deduplicated by chain id, so the leaderboard reflects what each API actually publishes as queryable, not a claim from a marketing page. The headline value updates as providers add chains in production." - - q: "Does Mobula support more chains than GeckoTerminal or Codex?" - a: "On this benchmark the three have different coverage philosophies. Mobula indexes EVM, Solana, Bitcoin and a long tail of non EVM chains under a single API. GeckoTerminal grows alongside CoinGecko's DEX rollout, which is deep on the major chains and slower on niche L2s. Codex (Defined.fi) historically prioritises depth on EVM and Solana DEX coverage rather than breadth across niche chains, which surfaces as a tighter count with stronger per chain DEX data than a raw breadth ranking implies. Read the live numbers from the leaderboard plus the head lag and metadata benches to compare full product surface." + - q: "Which crypto data API covers the most blockchains for token lookups?" + a: "{{best_name}} currently leads at {{best_p50}} unique mainnets across the measured providers. The count is read every 6 hours directly from each provider's own asset-registry endpoint (CoinGecko `/asset_platforms`, CoinPaprika `/v1/contracts`, CoinStats `/wallet/blockchains`, Mobula `/blockchains`) and deduplicated per platform, so the leaderboard reflects what each API actually publishes as queryable for contract-address lookup, not a claim from a marketing page." + - q: "Why is this split into two leaderboards (asset-registry vs DEX-indexing)?" + a: "Because they answer two different questions. CoinPaprika lists 300+ chains via `/v1/contracts` because it indexes token metadata on every chain it knows. GeckoTerminal lists ~265 chains via `/networks` because it actively indexes DEX pools + swap volumes there. Putting them on the same leaderboard makes the number meaningless: a market-data API always wins on chain count while a DEX indexer always wins on pool-level depth. Splitting the bench into `asset-registry-coverage` (this page) and `dex-network-coverage` (the sister bench) makes each ranking apples-to-apples." + - q: "Does Mobula support more chains than CoinGecko for token lookups?" + a: "On this benchmark {{name:mobula}} returns {{p50:mobula}} chains and {{name:coingecko}} returns {{p50:coingecko}} chains. CoinGecko has been building its asset-platforms registry for a decade and covers every chain where a token has ever been listed. Mobula is a younger aggregator focused on breadth-with-quality across EVM, Solana, Bitcoin and non-EVM chains under a single API with an intent-layer wrapping around it. Read the live numbers from the leaderboard, plus the head lag and metadata benches for the depth axes." - q: "Why exclude testnets from the count?" - a: "Testnet listings are inconsistent across providers. Some publish every devnet the engineering team ever spun up, others publish none, and a tool that ranked providers on a testnet inflated number would penalise the providers with disciplined network registries. Mainnets are what a builder shipping to production actually integrates against, so the comparison is restricted to mainnets only and filtered server side using each provider's own testnet flag." + a: "Testnet listings are inconsistent across providers. Some publish every devnet the engineering team ever spun up, others publish none, and a ranking that included testnets would penalise the providers with disciplined network registries. Mainnets are what a builder shipping to production actually integrates against, so the comparison is restricted to mainnets only and filtered server side using each provider's own testnet flag." - q: "Is having more chains always better?" - a: "Breadth and depth are independent dimensions. A provider with 200 chains might only index price ticks on most of them and full DEX swap history on a dozen. A provider with 60 chains might cover every chain end to end (pools, swaps, holders, metadata). Use this benchmark for the breadth question; head lag answers how fresh the data is on each chain, metadata coverage answers how complete the per token surface is. A serious integration decision reads all three." + a: "Breadth and depth are independent dimensions. A provider with 200 chains might only index basic metadata on most of them and full historical price + swap history on a dozen. A provider with 60 chains might cover every chain end to end (metadata, prices, pools, holders). Use this benchmark for the token-registry breadth question; the `dex-network-coverage` bench for DEX-pool breadth; `aggregator-head-lag` for how fresh the data is on each chain. A serious integration decision reads all three." - q: "How is a mainnet counted?" - a: "Any chain a provider lists as a queryable production environment, identified by a unique chain id. Ethereum mainnet, Solana mainnet, Base, Arbitrum, BNB Chain, Bitcoin and so on each count once regardless of how the provider labels them internally. Bridged variants of a token on different chains are not the same chain. The chain id is the deduplication key, which is why a provider cannot game the count by listing wrapped representations." + a: "Any chain a provider lists as a production platform for token lookups, identified by a unique chain id or platform slug. Ethereum, Solana, Base, Arbitrum, BNB, Bitcoin and so on each count once regardless of how the provider labels them internally. Bridged variants of the same token on different chains are not the same chain, the chain id is the deduplication key." - q: "How often does the leaderboard refresh?" - a: "Every 6 hours. The harness hits each provider's supported networks endpoint, parses the response, deduplicates by chain id and updates the `networks_supported_total{provider}` gauge. Failures (network errors, rate limits, auth errors) leave the previous count in place and increment `fetch_errors_total`, so a temporary outage does not silently drop a provider off the leaderboard." - - q: "Where does Dune fit on this list and why is it EVM only?" - a: "Dune is included via the Sim API, which exposes a `/v1/evm/supported-chains` endpoint scoped to EVM by construction. Non EVM chains a Dune integration could reach through other product surfaces are not on the gauge because the bench measures one canonical supported networks endpoint per provider. The EVM only label is surfaced honestly on the Dune row so a reader does not mistake a narrower scope for a smaller integration footprint." + a: "Every 6 hours. The harness hits each provider's asset-registry endpoint, parses the response, deduplicates by chain id or platform slug and updates the `networks_supported_total{provider}` gauge. Failures leave the previous count in place and increment `fetch_errors_total`, so a temporary outage does not silently drop a provider off the leaderboard." related: - which-crypto-price-api-is-the-fastest @@ -40,10 +40,10 @@ related: - which-crypto-oracle-is-the-most-accurate seo_title: "Which crypto data API covers the most blockchains in 2026?" -seo_description: "{{best_name}} leads at {{best_p50}} unique mainnets across GeckoTerminal, Codex, Mobula, CoinPaprika, CoinStats and Dune, audited every 6 hours by OpenChainBench." +seo_description: "{{best_name}} leads the asset-registry coverage leaderboard at {{best_p50}} unique mainnets across CoinGecko, CoinPaprika, Mobula and CoinStats, audited every 6 hours by OpenChainBench. Separate DEX-indexing leaderboard for GeckoTerminal, Codex, DefiLlama, DexPaprika and Sim by Dune." status: live expert_take: | - Chain coverage is a single-axis metric on a two-axis problem. Breadth (how many chain ids the provider lists) and depth (how completely each chain is indexed: pools, swaps, holders, metadata, historical range) are independently priced inside every data platform, and one can grow at the expense of the other. A provider that ships adapters for every new EVM chain within a week can look excellent on a network count while carrying only price ticks on the long tail; a provider with a shorter list may cover every listed chain end to end. Readers should also treat testnet inclusion with suspicion, since testnet registries are inconsistent across vendors and inflate the count without adding integratable surface. The right way to use this ranking is as one input alongside head lag on the chains that matter to the integration, and metadata completeness for the tokens the product will surface. A common misread is treating a coverage leader as automatically the right pick; the shortlist should be built from the intersection of breadth, depth and freshness. + Chain coverage is not one number, it is two, and treating them as a single leaderboard is the most common misread of the space. Asset-registry coverage measures how many chains a provider knows tokens on for contract-address lookup, the number a market-data API is optimised for. DEX-pool coverage measures how many chains a provider actively indexes DEX pools and swap events on, the number a DEX-facing product is optimised for. A market-data API can list tokens on 300 chains through a lightweight metadata pipeline while running DEX pool indexing on a dozen; a DEX indexer can cover 200+ chains of pools while carrying only a subset of the token registry. Comparing them on one leaderboard rewards the wrong axis for either product. Beyond the split, breadth is still only one axis. Depth (per-chain freshness, metadata completeness, pool coverage on each listed chain) is independently priced and can grow at the expense of breadth. The right shortlist reads the asset-registry ranking, the DEX-network ranking, the head-lag bench, and the metadata-coverage bench together, not one number in isolation. expert_take_reviewed: "2026-07-16" diff --git a/benchmarks/asset-registry-coverage.yml b/benchmarks/asset-registry-coverage.yml new file mode 100644 index 00000000..c29a75d7 --- /dev/null +++ b/benchmarks/asset-registry-coverage.yml @@ -0,0 +1,135 @@ +# OpenChainBench. Bench № 005 (successor to legacy bench 005 network-coverage) + +slug: asset-registry-coverage +number: "005" +title: Crypto data API with most blockchains in asset registry, live coverage ranking +seo_title: "Crypto data API most chains 2026 (asset registry)" +seo_description: "Which crypto data API knows tokens on the most blockchains? Live asset-registry coverage ranking across CoinGecko, CoinPaprika, Mobula and CoinStats." +subtitle: Number of blockchains where each major crypto data API knows tokens (contract-address lookups), audited every six hours against each provider's public asset-registry endpoint. +category: Aggregators +status: live +metric: Asset-registry chains +unit: count +higher_is_better: true + +seo_intro: | + This benchmark counts how many blockchains each major crypto data API + officially knows tokens on, audited live every six hours from each + provider's public asset-registry endpoint. The number is what a + builder integrating a market-data API cares about at token-lookup + time: given a chain and a contract address, can this API give me + price, market cap, metadata and history for a token on that chain. + Coverage is measured against each provider's own listing endpoint + (CoinGecko `/asset_platforms`, CoinPaprika `/v1/contracts`, CoinStats + `/wallet/blockchains`, Mobula `/blockchains`). Mainnets only. + Asset-registry coverage is the aggregator dimension of the product, + DEX-pool coverage is a different question measured on the companion + bench dex-network-coverage. + +abstract: | + We benchmark how many blockchains each major crypto data provider + supports in its public asset registry (the endpoint used for token + lookups by contract address). The harness fetches the official + listing every six hours from four providers (CoinGecko, CoinPaprika, + CoinStats, Mobula), deduplicates by platform slug or chain id and + counts. Mainnet only. DEX-pool indexing coverage is measured + separately on bench dex-network-coverage because the two questions + are not comparable, an API can know tokens on 300 chains through a + market-data pipeline while indexing DEX pools on only a dozen. This + bench answers the asset-registry question, the sister bench answers + the DEX-indexing question. + +methodology: + - "Source: each provider's public asset-registry endpoint." + - "CoinGecko: GET /api/v3/asset_platforms (public, no auth). Every chain CoinGecko can look up tokens on by contract address." + - "CoinPaprika: GET /v1/contracts (no auth). Lists every platform supported for contract-address lookup." + - "CoinStats: GET /wallet/blockchains with X-API-KEY. Chains CoinStats indexes for wallet portfolio and token metadata." + - "Mobula: GET /api/1/blockchains with an Authorization key. Chains Mobula covers for token metadata + market data." + - "Cadence: full refresh every 6 hours." + - "Counting: one count per unique chain (platform slug or chain id, whichever the provider exposes); mainnet only." + - "Failures (network errors, rate limits, auth errors) leave the previous count in place and increment a fetch_errors counter. the page falls back to its last successful sample." + +findings: + - "{{best_name}} currently leads at {{best_p50}} chains across {{count}} measured providers. The count is read live from each provider's asset-registry endpoint and deduplicated per platform slug, so the number reflects what is queryable through the API today for token-lookup workflows." + - "{{name:coingecko}} exposes {{p50:coingecko}} chains via `/asset_platforms`, which is the reference every downstream tool (CoinGecko Terminal, aggregators, wallets) resolves contract addresses against." + - "{{name:coinpaprika}} lists {{p50:coinpaprika}} platforms via `/v1/contracts`. Broader than dedicated DEX indexers because the endpoint covers every chain where the provider indexes token metadata, not only chains with pool-level coverage." + - "{{name:mobula}} returns {{p50:mobula}} chains via `/blockchains`. Includes EVM, Solana, Bitcoin, TON and non-EVM chains under a single API with an intent-layer wrapping around it." + - "Asset-registry coverage is the aggregator-view dimension of a data API. DEX-pool coverage (bench dex-network-coverage) and per-chain freshness (bench aggregator-head-lag) measure the other two dimensions a serious integration decision needs." + +source: https://github.com/ChainBench/OpenChainBench/tree/main/harnesses/network-coverage + +prometheus: + window: 24h + expected_freshness_seconds: 43200 + +faq: + - q: "Which crypto data API knows tokens on the most blockchains?" + a: "{{best_name}} currently leads at {{best_p50}} chains across {{count}} measured providers. The count is read every six hours directly from each provider's own asset-registry endpoint (CoinGecko `/asset_platforms`, CoinPaprika `/v1/contracts`, CoinStats `/wallet/blockchains`, Mobula `/blockchains`) and deduplicated per platform, so the leaderboard reflects what each API actually publishes as queryable for token-lookup workflows." + - q: "Why is this bench separate from dex-network-coverage?" + a: "Asset-registry coverage (how many chains a provider knows tokens on for contract-address lookup) and DEX-pool coverage (how many chains a provider indexes DEX pools and swap volumes on) are two different products, not a single metric. CoinPaprika lists 300+ chains in `/v1/contracts` because it indexes token metadata everywhere, but CoinPaprika does not run its own DEX pool indexer, that product lives at DexPaprika with its own separate `/networks` endpoint. Comparing them on a single leaderboard makes the number meaningless. This bench answers the asset-registry question, the sister bench answers the DEX-indexing question." + - q: "Does Mobula support more chains than CoinGecko for token lookups?" + a: "On this benchmark {{name:mobula}} returns {{p50:mobula}} chains and {{name:coingecko}} returns {{p50:coingecko}} chains. The two have different coverage philosophies. CoinGecko has been building its asset-platforms registry for a decade and covers every chain where a token has ever been listed. Mobula is a younger aggregator focused on breadth-with-quality across EVM, Solana, Bitcoin and non-EVM chains under a single API. Read the live numbers directly from the leaderboard." + - q: "Why doesn't this benchmark include GeckoTerminal, Codex or DefiLlama?" + a: "Those providers are measured on the sister bench dex-network-coverage because their product is DEX-pool indexing (not token-registry coverage). GeckoTerminal's `/networks` endpoint lists chains where GeckoTerminal actively indexes DEX pools; that is not the same question as `which chains does an API know tokens on`. Putting GeckoTerminal in an asset-registry leaderboard would compare a DEX-indexer's chain list against a token-registry chain list, which is apples-vs-oranges and inflates or deflates depending on the provider's product surface." + - q: "How often is the chain count refreshed?" + a: "Every six hours. The harness hits each provider's asset-registry endpoint, parses the response, deduplicates by chain id or platform slug, and updates the Prometheus gauge `networks_supported_total{provider}`. Failures (network errors, rate limits, auth errors) leave the previous count in place and increment a `fetch_errors_total` counter, so a temporary outage does not silently drop a provider off the leaderboard." + - q: "What counts as a mainnet in this benchmark?" + a: "Any chain a provider lists as a production platform for token lookups, identified by a unique chain id or platform slug. Ethereum, Solana, Base, Arbitrum, BNB, Bitcoin and so on each count once regardless of how the provider labels them internally. Bridged variants of the same token on different chains are not the same chain, the chain id is the deduplication key. Testnet listings are filtered server-side where the provider exposes a testnet flag." + +# Real metrics exposed by the network-coverage harness: +# networks_supported_total{provider="coingecko"|"coinpaprika"| +# "coinstats"|"mobula"} +# -> gauge, the unique-chain count from the latest successful refresh. + +providers: + - slug: coingecko + name: CoinGecko + tag: Reference asset-platform registry + formula: "Count of chains returned by CoinGecko's public `/api/v3/asset_platforms` endpoint, refreshed every 6 hours." + queries: + p50: networks_supported_total{provider="coingecko"} + p90: networks_supported_total{provider="coingecko"} + p99: networks_supported_total{provider="coingecko"} + mean: networks_supported_total{provider="coingecko"} + success: clamp_max(networks_supported_total{provider="coingecko"} > bool 0, 1) + sample_size: networks_supported_total{provider="coingecko"} + series: networks_supported_total{provider="coingecko"} + + - slug: coinpaprika + name: CoinPaprika + tag: Market-data API asset registry + formula: "Count of platforms returned by CoinPaprika's public `/v1/contracts` endpoint (chains supported for contract-address lookup), refreshed every 6 hours." + queries: + p50: networks_supported_total{provider="coinpaprika"} + p90: networks_supported_total{provider="coinpaprika"} + p99: networks_supported_total{provider="coinpaprika"} + mean: networks_supported_total{provider="coinpaprika"} + success: clamp_max(networks_supported_total{provider="coinpaprika"} > bool 0, 1) + sample_size: networks_supported_total{provider="coinpaprika"} + series: networks_supported_total{provider="coinpaprika"} + + - slug: mobula + name: Mobula + tag: Aggregator + intent layer + formula: "Count of chains returned by Mobula's `/api/1/blockchains` endpoint, refreshed every 6 hours." + queries: + p50: networks_supported_total{provider="mobula"} + p90: networks_supported_total{provider="mobula"} + p99: networks_supported_total{provider="mobula"} + mean: networks_supported_total{provider="mobula"} + success: clamp_max(networks_supported_total{provider="mobula"} > bool 0, 1) + sample_size: networks_supported_total{provider="mobula"} + series: networks_supported_total{provider="mobula"} + + - slug: coinstats + name: CoinStats + tag: Portfolio + market data + formula: "Count of blockchains returned by CoinStats's `/wallet/blockchains` endpoint (chains covered for wallet + token lookups), refreshed every 6 hours." + queries: + p50: networks_supported_total{provider="coinstats"} + p90: networks_supported_total{provider="coinstats"} + p99: networks_supported_total{provider="coinstats"} + mean: networks_supported_total{provider="coinstats"} + success: clamp_max(networks_supported_total{provider="coinstats"} > bool 0, 1) + sample_size: networks_supported_total{provider="coinstats"} + series: networks_supported_total{provider="coinstats"} diff --git a/benchmarks/dex-network-coverage.yml b/benchmarks/dex-network-coverage.yml new file mode 100644 index 00000000..29b361bd --- /dev/null +++ b/benchmarks/dex-network-coverage.yml @@ -0,0 +1,148 @@ +# OpenChainBench. Bench № 090 (companion split from legacy bench 005 network-coverage) + +slug: dex-network-coverage +number: "090" +title: DEX indexer with most blockchains, live coverage ranking +seo_title: "DEX indexer most chains 2026" +seo_description: "Which DEX indexer supports the most blockchains? Live coverage ranking across GeckoTerminal, Codex, DefiLlama, DexPaprika and Sim by Dune." +subtitle: Number of blockchains where each major DEX indexer actively indexes pools + swap volumes, audited every six hours against each provider's public networks endpoint. +category: Aggregators +status: live +metric: DEX-indexed chains +unit: count +higher_is_better: true + +seo_intro: | + This benchmark counts how many blockchains each major DEX indexer + officially indexes pools + swap volumes on, audited live every six + hours from each provider's public networks endpoint. The number is + what a DEX-facing builder actually cares about: given a chain, + can this API return pool addresses, live swap events, OHLCV candles + and trending pools. Providers on this leaderboard run their own DEX + pool indexer as a product (GeckoTerminal `/networks`, Codex + `getNetworks`, DefiLlama `/chains`, DexPaprika `/networks`, Sim by + Dune `/evm/supported-chains`). Asset-registry coverage (chains where + an API knows tokens for contract-address lookup) is a different + question measured on the sister bench asset-registry-coverage. + +abstract: | + We benchmark how many networks each major DEX indexer publishes as + actively indexed for pools + swap volumes. The harness fetches the + official listing every six hours from five providers (GeckoTerminal, + Codex, DefiLlama, DexPaprika, Sim by Dune), deduplicates by chain id + or platform slug and counts. Mainnet only. Asset-registry coverage + (chains where the provider knows tokens for contract-address lookups) + is measured on bench asset-registry-coverage because it answers a + different question, an API can list tokens on 300 chains through a + market-data pipeline while running DEX pool indexing on only a + dozen. Both leaderboards live under Aggregators so a reader can + compare a provider on the axis that matches their product. + +methodology: + - "Source: each provider's public DEX-indexer networks endpoint." + - "GeckoTerminal: GET /api/v2/networks (paginated, no auth). Chains where GeckoTerminal actively indexes DEX pools + trades." + - "Codex: GraphQL `getNetworks` query at https://graph.codex.io/graphql with an official API key. Chains covered by Defined.fi's DEX data pipeline." + - "DefiLlama: GET https://api.llama.fi/chains (no auth). Chains tracked by DefiLlama's TVL crawler, every chain with at least one indexed DeFi protocol, DEX chains are a subset." + - "DexPaprika: GET https://api.dexpaprika.com/networks (no auth). CoinPaprika's dedicated DEX tracker product, separate from the market-data API." + - "Sim by Dune: GET https://api.sim.dune.com/v1/evm/supported-chains (no auth). EVM only, mainnets filtered via the `mainnet` tag." + - "Cadence: full refresh every 6 hours." + - "Counting: a provider's network is counted once per unique chain id or slug; mainnet only." + - "Failures (network errors, rate limits, auth errors) leave the previous count in place and increment a fetch_errors counter. the page falls back to its last successful sample." + +findings: + - "{{best_name}} currently leads at {{best_p50}} chains across {{count}} measured providers. The count is read live from each provider's DEX-networks endpoint, so the number reflects where each API actively indexes DEX pools + swap volumes today, not a marketing claim." + - "{{name:geckoterminal}} sits at {{p50:geckoterminal}} chains via `/api/v2/networks`. GeckoTerminal indexes wherever CoinGecko's DEX pipeline reaches, so the count tracks the CoinGecko DEX-rollout roadmap rather than a standalone listing decision." + - "{{name:codex}} clocks {{p50:codex}} chains via `getNetworks`. Defined.fi historically prioritises depth on EVM + Solana DEX coverage rather than breadth across niche chains, which surfaces here as a tighter count with stronger per-chain DEX quality than a raw breadth ranking implies." + - "{{name:defillama}} publishes {{p50:defillama}} chains via `/chains`. Broader than DEX-only (includes lending, LSTs, restaking, bridges) because the endpoint tracks every chain with at least one indexed DeFi protocol, DEX chains are a subset. The count is the canonical open reference for chains with meaningful onchain financial activity." + - "DEX-indexer breadth is one axis of a data API. Asset-registry breadth (bench asset-registry-coverage) and per-chain head lag (bench aggregator-head-lag) measure the other axes a serious DEX-integration decision needs." + +source: https://github.com/ChainBench/OpenChainBench/tree/main/harnesses/network-coverage + +prometheus: + window: 24h + expected_freshness_seconds: 43200 + +faq: + - q: "Which DEX indexer supports the most blockchains right now?" + a: "{{best_name}} currently leads at {{best_p50}} chains across {{count}} measured providers. The count is read every six hours directly from each provider's own DEX-networks endpoint and deduplicated by chain id, so the leaderboard reflects where each API actively indexes DEX pools + swap volumes today, not a claim from a marketing page." + - q: "Why is this bench separate from asset-registry-coverage?" + a: "DEX-pool coverage and asset-registry coverage are two different products, not a single metric. GeckoTerminal indexes DEX pools on ~265 chains via `/networks`; CoinPaprika lists 300+ chains in `/v1/contracts` because it indexes token metadata everywhere. Comparing them on one leaderboard makes the number meaningless, a market-data API always wins on chain count while a DEX indexer always wins on pool-level depth. This bench answers the DEX-indexing question. The sister bench asset-registry-coverage answers the token-lookup question." + - q: "Does DefiLlama really index DEX pools on 400+ chains?" + a: "DefiLlama's `/chains` endpoint tracks every chain with at least one indexed DeFi protocol (DEXes, lending, LSTs, restaking, bridges, oracles), so the count is broader than DEX-only. DEX chains are a subset. DefiLlama sits on the leaderboard because the same crawler backs their DEX-volumes aggregator, and the endpoint is the canonical open reference for `chains with meaningful onchain financial activity`. Read alongside the more DEX-specific counts from GeckoTerminal, Codex and DexPaprika for the DEX-only view." + - q: "Why isn't CoinGecko / Mobula / CoinPaprika on this leaderboard?" + a: "Those providers are measured on the sister bench asset-registry-coverage because their product is chain-scoped token metadata + market data, not DEX pool indexing. CoinGecko powers GeckoTerminal on the DEX side, but the token-registry number and the DEX-indexed number are measured separately because they answer different questions. Mobula and CoinPaprika are market-data APIs, not DEX pool indexers, DexPaprika is CoinPaprika's dedicated DEX product and is on this leaderboard." + - q: "How often is the chain count refreshed?" + a: "Every six hours. The harness hits each provider's DEX-networks endpoint, parses the response, deduplicates by chain id, and updates the Prometheus gauge `networks_supported_total{provider}`. Failures leave the previous count in place and increment a `fetch_errors_total` counter, so a temporary outage does not silently drop a provider off the leaderboard." + - q: "What counts as a mainnet in this benchmark?" + a: "Any chain a provider lists as a production network for DEX indexing, identified by a unique chain id or slug. Ethereum, Solana, Base, Arbitrum, BNB, Avalanche and so on each count once regardless of how the provider labels them internally. Testnet listings are filtered server-side where the provider exposes a testnet flag. Sim by Dune is EVM only by construction of the `/v1/evm/supported-chains` endpoint." + +# Real metrics exposed by the network-coverage harness: +# networks_supported_total{provider="geckoterminal"|"codex"| +# "defillama"|"dexpaprika"|"dune"} +# -> gauge, the unique-chain count from the latest successful refresh. + +providers: + - slug: geckoterminal + name: GeckoTerminal + tag: CoinGecko's DEX index + formula: "Count of unique mainnet chain ids returned by GeckoTerminal's `/api/v2/networks` paginated endpoint, refreshed every 6 hours." + queries: + p50: networks_supported_total{provider="geckoterminal"} + p90: networks_supported_total{provider="geckoterminal"} + p99: networks_supported_total{provider="geckoterminal"} + mean: networks_supported_total{provider="geckoterminal"} + success: clamp_max(networks_supported_total{provider="geckoterminal"} > bool 0, 1) + sample_size: networks_supported_total{provider="geckoterminal"} + series: networks_supported_total{provider="geckoterminal"} + + - slug: codex + name: Codex + tag: Defined.fi DEX data API + formula: "Count of unique mainnet chain ids returned by Codex's GraphQL `getNetworks` query, refreshed every 6 hours." + queries: + p50: networks_supported_total{provider="codex"} + p90: networks_supported_total{provider="codex"} + p99: networks_supported_total{provider="codex"} + mean: networks_supported_total{provider="codex"} + success: clamp_max(networks_supported_total{provider="codex"} > bool 0, 1) + sample_size: networks_supported_total{provider="codex"} + series: networks_supported_total{provider="codex"} + + - slug: defillama + name: DefiLlama + tag: TVL + DEX-volumes aggregator + formula: "Count of chains returned by DefiLlama's public `/chains` endpoint (chains with at least one indexed DeFi protocol; DEX chains are a subset), refreshed every 6 hours." + queries: + p50: networks_supported_total{provider="defillama"} + p90: networks_supported_total{provider="defillama"} + p99: networks_supported_total{provider="defillama"} + mean: networks_supported_total{provider="defillama"} + success: clamp_max(networks_supported_total{provider="defillama"} > bool 0, 1) + sample_size: networks_supported_total{provider="defillama"} + series: networks_supported_total{provider="defillama"} + + - slug: dexpaprika + name: DexPaprika + tag: CoinPaprika's DEX product + formula: "Count of chains returned by DexPaprika's public `/networks` endpoint (CoinPaprika's dedicated DEX tracker, separate from the market-data API), refreshed every 6 hours." + queries: + p50: networks_supported_total{provider="dexpaprika"} + p90: networks_supported_total{provider="dexpaprika"} + p99: networks_supported_total{provider="dexpaprika"} + mean: networks_supported_total{provider="dexpaprika"} + success: clamp_max(networks_supported_total{provider="dexpaprika"} > bool 0, 1) + sample_size: networks_supported_total{provider="dexpaprika"} + series: networks_supported_total{provider="dexpaprika"} + + - slug: dune + name: Sim by Dune + tag: Onchain analytics + Sim API + formula: "Count of EVM chains tagged `mainnet` by Sim by Dune's `/v1/evm/supported-chains` endpoint, refreshed every 6 hours. EVM only." + queries: + p50: networks_supported_total{provider="dune"} + p90: networks_supported_total{provider="dune"} + p99: networks_supported_total{provider="dune"} + mean: networks_supported_total{provider="dune"} + success: clamp_max(networks_supported_total{provider="dune"} > bool 0, 1) + sample_size: networks_supported_total{provider="dune"} + series: networks_supported_total{provider="dune"} diff --git a/benchmarks/network-coverage.yml b/benchmarks/network-coverage.yml deleted file mode 100644 index 82dedfed..00000000 --- a/benchmarks/network-coverage.yml +++ /dev/null @@ -1,168 +0,0 @@ -# OpenChainBench. Bench № 005 - -slug: network-coverage -number: "005" -title: Crypto data API with most blockchains supported, live coverage ranking -seo_title: "Crypto data API most chains 2026" -seo_description: "Which crypto data API supports the most blockchains? Live coverage ranking across CoinPaprika, GeckoTerminal, Mobula, Dune and every major aggregator." -subtitle: Number of blockchains each major crypto data API officially supports, audited every six hours against each provider's public network endpoint. -category: Aggregators -status: live -metric: Networks supported -unit: count -higher_is_better: true - -seo_intro: | - This benchmark counts how many blockchains each major onchain data - API officially supports, audited live from each provider's own - "supported networks" endpoint every six hours. The number is what a - builder integrating an SDK actually cares about. how many chains can - I query without rolling my own indexer. Provider marketing pages - quote round numbers (250+, 100+, 50+ chains) without a list a reader - can verify; this benchmark reads the list from the API itself and - publishes the unique-chain count, refreshed against the source of - truth. Mainnets only. Testnets are excluded because providers list - them inconsistently and a builder shipping to production needs the - mainnet count, not a longer list inflated with chains nobody trades - on. Coverage breadth is one dimension of a data API's product; head - lag and metadata completeness sit on separate benches (№ 001 and - № 004) so a provider strong on raw count can be checked against the - quality dimensions too. - -abstract: | - We benchmark how many networks each major onchain data provider lists - in its public "supported networks" endpoint. The harness fetches the - official listing every six hours from six providers (GeckoTerminal, - Codex, Mobula, CoinPaprika, CoinStats and Dune via Sim API), - deduplicates by chain id and counts. Mainnet only, - testnets are excluded because providers list them inconsistently and - the comparison is meant to reflect what a builder can integrate against - in production. Coverage breadth is one dimension of a data provider's - product, not a ranking on quality. Latency, freshness and metadata - completeness are measured separately by benches № 001 and № 004. - -methodology: - - "Source: each provider's public supported-networks endpoint." - - "GeckoTerminal: GET /api/v2/networks (paginated, no auth)." - - "Codex: GraphQL `getNetworks` query at https://graph.codex.io/graphql with an official API key." - - "Mobula: GET /api/1/blockchains with an Authorization API key." - - "CoinPaprika: GET /v1/contracts (no auth). Lists platforms supported for contract lookup." - - "CoinStats: GET /wallet/blockchains with X-API-KEY." - - "Dune (via Sim API): GET https://api.sim.dune.com/v1/evm/supported-chains (no auth). EVM only, mainnets filtered via the `mainnet` tag." - - "Cadence: full refresh every 6 hours." - - "Counting: a provider's network is counted once per unique chain id; mainnet only." - - "Failures (network errors, rate limits, auth errors) leave the previous count in place and increment a fetch_errors counter. the page falls back to its last successful sample." - -findings: - - "{{best_name}} currently leads at {{best_p50}} mainnets across {{count}} measured providers. The count is read live from each provider's own networks endpoint and deduplicated by chain id, so the number reflects what is queryable through the API today, not what marketing pages claim." - - "{{name:mobula}} returns {{p50:mobula}} mainnets. The breadth includes long-tail EVM L2s, Solana, Bitcoin and non-EVM chains, which is the coverage shape an aggregator pursues when the product is a single API across the full multichain surface." - - "{{name:codex}} clocks {{p50:codex}} mainnets. Defined.fi historically prioritises depth on EVM and Solana DEX coverage rather than breadth across niche chains, which surfaces here as a tighter count with stronger per-chain DEX data than a raw breadth ranking implies." - - "{{name:geckoterminal}} sits at {{p50:geckoterminal}} mainnets. GeckoTerminal indexes wherever CoinGecko already tracks tokens, so the count tracks closely with CoinGecko's DEX coverage rollout rather than a standalone listing decision." - - "Raw chain count is one dimension of a data API's product. A provider with 200 chains and shallow per-chain depth can rank above one with 80 chains and full DEX, metadata and event coverage on each. Latency (bench № 001) and metadata completeness (bench № 004) measure the other dimensions." - -source: https://github.com/ChainBench/OpenChainBench/tree/main/harnesses/network-coverage - -prometheus: - window: 24h - expected_freshness_seconds: 43200 - -faq: - - q: "Which crypto data API supports the most blockchains?" - a: "{{best_name}} currently leads at {{best_p50}} mainnets across {{count}} measured providers. The count is read every six hours directly from each provider's own supported-networks endpoint and deduplicated by chain id, so the leaderboard reflects what each API actually publishes as queryable, not a claim from a marketing page." - - q: "Does Mobula support more chains than CoinGecko's GeckoTerminal?" - a: "On this benchmark {{name:mobula}} returns {{p50:mobula}} mainnets and {{name:geckoterminal}} returns {{p50:geckoterminal}} mainnets. The two have different coverage philosophies. Mobula indexes EVM, Solana, Bitcoin and a long tail of non-EVM chains under a single API. GeckoTerminal grows alongside CoinGecko's DEX rollout, which is deep on the major chains and slower on niche L2s." - - q: "Why doesn't this benchmark include testnets?" - a: "Testnet listings are inconsistent across providers. Some list every devnet the engineering team ever spun up, others list none. Mainnets are what a builder shipping to production actually integrates against, so the comparison is restricted to mainnets only. The harness reads the full network list from each API and filters server-side." - - q: "Is having more chains supported always better?" - a: "Breadth and depth are independent dimensions. A provider with 200 chains might only index price ticks on most of them and full DEX swap history on a dozen. A provider with 60 chains might cover every chain end-to-end (pools, swaps, holders, metadata). Use this benchmark for the breadth question; head lag (bench № 001) and metadata coverage (bench № 004) answer the depth question. A serious integration decision reads all three." - - q: "How often is the network count refreshed?" - a: "Every six hours. The harness hits each provider's supported-networks endpoint, parses the response, deduplicates by chain id and updates the Prometheus gauge `networks_supported_total{provider}`. Failures (network errors, rate limits, auth errors) leave the previous count in place and increment a `fetch_errors_total` counter, so a temporary outage does not silently drop a provider off the leaderboard." - - q: "What counts as a 'mainnet' in this benchmark?" - a: "Any chain a provider lists as a queryable production environment, identified by a unique chain id. Ethereum mainnet, Solana mainnet, Base, Arbitrum, BNB Chain, Bitcoin and so on each count once regardless of how the provider labels them internally. Bridged variants of a token on different chains are not the same chain. The chain id is the deduplication key." - -# Real metrics exposed by the network-coverage harness: -# networks_supported_total{provider="geckoterminal"|"codex"|"mobula"| -# "coinpaprika"|"coinstats"|"dune"} -# -> gauge, the unique-chain count from the latest successful refresh. -# network_supported{provider, chain_id, slug, name} -> gauge (1 per -# network; useful for diff queries on the site if we add a -# "missing chains" panel later). - -providers: - - slug: geckoterminal - name: GeckoTerminal - tag: CoinGecko's DEX index - formula: "Count of unique mainnet chain ids returned by GeckoTerminal's `/api/v2/networks` paginated endpoint, refreshed every 6 hours." - queries: - p50: networks_supported_total{provider="geckoterminal"} - p90: networks_supported_total{provider="geckoterminal"} - p99: networks_supported_total{provider="geckoterminal"} - mean: networks_supported_total{provider="geckoterminal"} - success: clamp_max(networks_supported_total{provider="geckoterminal"} > bool 0, 1) - sample_size: networks_supported_total{provider="geckoterminal"} - series: networks_supported_total{provider="geckoterminal"} - - - slug: codex - name: Codex - tag: Defined.fi data API - formula: "Count of unique mainnet chain ids returned by Codex's GraphQL `getNetworks` query, refreshed every 6 hours." - queries: - p50: networks_supported_total{provider="codex"} - p90: networks_supported_total{provider="codex"} - p99: networks_supported_total{provider="codex"} - mean: networks_supported_total{provider="codex"} - success: clamp_max(networks_supported_total{provider="codex"} > bool 0, 1) - sample_size: networks_supported_total{provider="codex"} - series: networks_supported_total{provider="codex"} - - - slug: mobula - name: Mobula - tag: Aggregator + intent layer - formula: "Count of unique mainnet chain ids returned by Mobula's `/api/1/blockchains` endpoint, refreshed every 6 hours." - queries: - p50: networks_supported_total{provider="mobula"} - p90: networks_supported_total{provider="mobula"} - p99: networks_supported_total{provider="mobula"} - mean: networks_supported_total{provider="mobula"} - success: clamp_max(networks_supported_total{provider="mobula"} > bool 0, 1) - sample_size: networks_supported_total{provider="mobula"} - series: networks_supported_total{provider="mobula"} - - - slug: coinpaprika - name: CoinPaprika - tag: Market data API - formula: "Count of platform slugs returned by CoinPaprika's public `/v1/contracts` endpoint, refreshed every 6 hours." - queries: - p50: networks_supported_total{provider="coinpaprika"} - p90: networks_supported_total{provider="coinpaprika"} - p99: networks_supported_total{provider="coinpaprika"} - mean: networks_supported_total{provider="coinpaprika"} - success: clamp_max(networks_supported_total{provider="coinpaprika"} > bool 0, 1) - sample_size: networks_supported_total{provider="coinpaprika"} - series: networks_supported_total{provider="coinpaprika"} - - - slug: coinstats - name: CoinStats - tag: Portfolio + market data - formula: "Count of blockchains returned by CoinStats's `/wallet/blockchains` endpoint, refreshed every 6 hours." - queries: - p50: networks_supported_total{provider="coinstats"} - p90: networks_supported_total{provider="coinstats"} - p99: networks_supported_total{provider="coinstats"} - mean: networks_supported_total{provider="coinstats"} - success: clamp_max(networks_supported_total{provider="coinstats"} > bool 0, 1) - sample_size: networks_supported_total{provider="coinstats"} - series: networks_supported_total{provider="coinstats"} - - - slug: dune - name: Dune - tag: Onchain analytics + Sim API - formula: "Count of EVM chains tagged `mainnet` in Sim by Dune's `/v1/evm/supported-chains` endpoint, refreshed every 6 hours. EVM-only." - queries: - p50: networks_supported_total{provider="dune"} - p90: networks_supported_total{provider="dune"} - p99: networks_supported_total{provider="dune"} - mean: networks_supported_total{provider="dune"} - success: clamp_max(networks_supported_total{provider="dune"} > bool 0, 1) - sample_size: networks_supported_total{provider="dune"} - series: networks_supported_total{provider="dune"} diff --git a/harnesses/network-coverage/cmd/script/coingecko.go b/harnesses/network-coverage/cmd/script/coingecko.go new file mode 100644 index 00000000..4839335e --- /dev/null +++ b/harnesses/network-coverage/cmd/script/coingecko.go @@ -0,0 +1,58 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "time" +) + +// CoinGecko exposes an authoritative list of every "asset platform" it +// knows about — i.e. every chain where it can look up token metadata by +// contract address. Public no-key endpoint; the free-tier rate limit +// (~30 req/min) is not a concern at a 6h sweep cadence. +const coinGeckoAssetPlatformsURL = "https://api.coingecko.com/api/v3/asset_platforms" + +type coingeckoPlatform struct { + ID string `json:"id"` + Name string `json:"name"` + Shortname string `json:"shortname"` + ChainIdentifier any `json:"chain_identifier"` // number for EVM chains, null elsewhere +} + +func fetchCoinGecko(_ *Config) ProviderResult { + res := ProviderResult{Provider: "coingecko"} + client := &http.Client{Timeout: 15 * time.Second} + req, _ := http.NewRequest("GET", coinGeckoAssetPlatformsURL, nil) + req.Header.Set("Accept", "application/json") + req.Header.Set("User-Agent", "OpenChainBench/1.0 (+https://openchainbench.com)") + + resp, err := client.Do(req) + if err != nil { + res.Err = fmt.Sprintf("request_error: %v", err) + return res + } + defer resp.Body.Close() + body, _ := io.ReadAll(resp.Body) + + if resp.StatusCode != 200 { + res.Err = fmt.Sprintf("status_%d", resp.StatusCode) + return res + } + + var parsed []coingeckoPlatform + if err := json.Unmarshal(body, &parsed); err != nil { + res.Err = fmt.Sprintf("parse_error: %v", err) + return res + } + + for _, p := range parsed { + res.Networks = append(res.Networks, Network{ + ChainID: fmt.Sprintf("%v", p.ChainIdentifier), + Slug: p.ID, + Name: p.Name, + }) + } + return res +} diff --git a/harnesses/network-coverage/cmd/script/defillama.go b/harnesses/network-coverage/cmd/script/defillama.go new file mode 100644 index 00000000..4a28310a --- /dev/null +++ b/harnesses/network-coverage/cmd/script/defillama.go @@ -0,0 +1,60 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "time" +) + +// DefiLlama tracks TVL across every chain with at least one indexed +// protocol. Broader than "DEX-only" (includes lending, LSTs, restaking, +// bridges, oracles), but it is the canonical open reference for +// "chains with meaningful on-chain financial activity" — and the same +// crawler backs their DEX-volumes aggregator, so DEX chains are a +// subset of what /chains returns. +const defiLlamaChainsURL = "https://api.llama.fi/chains" + +type defiLlamaChain struct { + Name string `json:"name"` + ChainID any `json:"chainId"` // number for EVM chains, null elsewhere + Gecko string `json:"gecko_id"` + TVL float64 `json:"tvl"` + CMCID string `json:"cmcId"` + TokenSym string `json:"tokenSymbol"` +} + +func fetchDefiLlama(_ *Config) ProviderResult { + res := ProviderResult{Provider: "defillama"} + client := &http.Client{Timeout: 15 * time.Second} + req, _ := http.NewRequest("GET", defiLlamaChainsURL, nil) + req.Header.Set("Accept", "application/json") + req.Header.Set("User-Agent", "OpenChainBench/1.0 (+https://openchainbench.com)") + + resp, err := client.Do(req) + if err != nil { + res.Err = fmt.Sprintf("request_error: %v", err) + return res + } + defer resp.Body.Close() + body, _ := io.ReadAll(resp.Body) + if resp.StatusCode != 200 { + res.Err = fmt.Sprintf("status_%d", resp.StatusCode) + return res + } + + var parsed []defiLlamaChain + if err := json.Unmarshal(body, &parsed); err != nil { + res.Err = fmt.Sprintf("parse_error: %v", err) + return res + } + for _, c := range parsed { + res.Networks = append(res.Networks, Network{ + ChainID: fmt.Sprintf("%v", c.ChainID), + Slug: c.Gecko, + Name: c.Name, + }) + } + return res +} diff --git a/harnesses/network-coverage/cmd/script/dexpaprika.go b/harnesses/network-coverage/cmd/script/dexpaprika.go new file mode 100644 index 00000000..d68a6d4a --- /dev/null +++ b/harnesses/network-coverage/cmd/script/dexpaprika.go @@ -0,0 +1,55 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "time" +) + +// DexPaprika is CoinPaprika's dedicated DEX tracker product (separate +// from the main CoinPaprika asset-registry API). /networks returns the +// chains where they actively index DEX pools + trade volumes, which is +// what the reader coming from a "which DEX aggregator supports the most +// chains" search actually wants. +const dexPaprikaNetworksURL = "https://api.dexpaprika.com/networks" + +type dexpaprikaNetwork struct { + ID string `json:"id"` + DisplayName string `json:"display_name"` +} + +func fetchDexPaprika(_ *Config) ProviderResult { + res := ProviderResult{Provider: "dexpaprika"} + client := &http.Client{Timeout: 15 * time.Second} + req, _ := http.NewRequest("GET", dexPaprikaNetworksURL, nil) + req.Header.Set("Accept", "application/json") + req.Header.Set("User-Agent", "OpenChainBench/1.0 (+https://openchainbench.com)") + + resp, err := client.Do(req) + if err != nil { + res.Err = fmt.Sprintf("request_error: %v", err) + return res + } + defer resp.Body.Close() + body, _ := io.ReadAll(resp.Body) + if resp.StatusCode != 200 { + res.Err = fmt.Sprintf("status_%d", resp.StatusCode) + return res + } + + var parsed []dexpaprikaNetwork + if err := json.Unmarshal(body, &parsed); err != nil { + res.Err = fmt.Sprintf("parse_error: %v", err) + return res + } + for _, n := range parsed { + res.Networks = append(res.Networks, Network{ + ChainID: "", + Slug: n.ID, + Name: n.DisplayName, + }) + } + return res +} diff --git a/harnesses/network-coverage/cmd/script/main.go b/harnesses/network-coverage/cmd/script/main.go index b8c544c4..4133fe1f 100644 --- a/harnesses/network-coverage/cmd/script/main.go +++ b/harnesses/network-coverage/cmd/script/main.go @@ -74,6 +74,9 @@ func fetchAll(cfg *Config) { {"coinpaprika", fetchCoinPaprika}, {"dune", fetchSimDune}, {"coinstats", fetchCoinStats}, + {"coingecko", fetchCoinGecko}, + {"defillama", fetchDefiLlama}, + {"dexpaprika", fetchDexPaprika}, } var wg sync.WaitGroup diff --git a/src/data/bench-published.json b/src/data/bench-published.json index 5bcb930d..e4506e1e 100644 --- a/src/data/bench-published.json +++ b/src/data/bench-published.json @@ -29,7 +29,8 @@ "metadata-coverage": "2026-05-01T15:22:33.000Z", "monad-rpc": "2026-07-08T07:36:17.000Z", "moonbeam-rpc": "2026-07-03T22:44:42.000Z", - "network-coverage": "2026-05-05T14:15:05.000Z", + "asset-registry-coverage": "2026-05-05T14:15:05.000Z", + "dex-network-coverage": "2026-07-24T00:00:00.000Z", "network-fees": "2026-06-02T13:30:08.000Z", "nft-collection-metadata": "2026-06-15T15:07:26.000Z", "optimism-rpc": "2026-07-03T14:33:15.000Z", diff --git a/src/lib/logo-manifest.ts b/src/lib/logo-manifest.ts index 38122e2b..11d8a1c4 100644 --- a/src/lib/logo-manifest.ts +++ b/src/lib/logo-manifest.ts @@ -220,7 +220,8 @@ const RAW: Record = { quicknode: "/logos/quicknode.svg", "the-graph": "/logos/the-graph.svg", - // ─── network-coverage bench providers (bench № 005 expansion) ─── + // ─── asset-registry-coverage + dex-network-coverage bench providers + // (bench № 005 split into 005a/005b) ─── coinpaprika: "/logos/coinpaprika.svg", coinstats: "/logos/coinstats.svg", diff --git a/src/lib/removed-benches.ts b/src/lib/removed-benches.ts index 6e2ae915..4e653817 100644 --- a/src/lib/removed-benches.ts +++ b/src/lib/removed-benches.ts @@ -15,6 +15,31 @@ * Moving a bench to production = remove its slug here, bump the * bench-set cache keys in src/lib/spec.ts, ship dev to main. */ +/** + * Bench slugs renamed / split, mapped to their canonical successor. + * Middleware issues a 301 (permanent) redirect on prod so external + * backlinks and previously-indexed URLs keep their PageRank pointing + * at the current page instead of hitting a 410 / 404. + * + * Enforced in src/middleware.ts BEFORE the REMOVED_BENCH_SLUGS check + * so a slug listed here always wins the 301 over a 410. Only list a + * slug here when the successor bench genuinely covers the same reader + * intent — do not redirect to unrelated pages. + */ +export const RENAMED_BENCH_SLUGS: Record = { + // network-coverage split (2026-07-24) into 2 apple-to-apple benches: + // - asset-registry-coverage (which chains a data API knows tokens on) + // - dex-network-coverage (which chains a data API indexes DEX pools on) + // The original bench mixed the two definitions, flagged on Twitter by + // @sooneggg after CoinPaprika #1 with 307 (asset registry via + // /v1/contracts) landed next to GeckoTerminal 265 (DEX indexing via + // /networks). CoinPaprika's #1 claim reflects the asset-registry + // framing, so 301 the legacy URL there; DEX-only readers reach the + // dex-network-coverage bench via the cross-link at the top of the + // successor page. + "network-coverage": "asset-registry-coverage", +}; + /** * Answer pages (answers/.yml) whose referenced benchmark is in * REMOVED_BENCH_SLUGS. Same treatment: 410 on prod direct hits, dropped diff --git a/src/middleware.ts b/src/middleware.ts index d2194e71..ef9a4715 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -51,6 +51,7 @@ const CANONICAL_NO_QUERY = new Set([ import { REMOVED_ANSWER_SLUGS, REMOVED_BENCH_SLUGS, + RENAMED_BENCH_SLUGS, } from "@/lib/removed-benches"; export { REMOVED_BENCH_SLUGS }; @@ -75,6 +76,14 @@ export function middleware(req: NextRequest) { if (process.env.VERCEL_ENV === "production") { const m = pathname.match(BENCH_PATH); const a = pathname.match(ANSWER_PATH); + // Renamed / split bench: 301 to the successor before the 410 check + // fires. Preserves external backlink PageRank + keeps human visitors + // landing on the current bench instead of a Gone page. + if (m && RENAMED_BENCH_SLUGS[m[1]]) { + const url = req.nextUrl.clone(); + url.pathname = `/benchmarks/${RENAMED_BENCH_SLUGS[m[1]]}`; + return NextResponse.redirect(url, 301); + } if ( (m && REMOVED_BENCH_SLUGS.has(m[1])) || (a && REMOVED_ANSWER_SLUGS.has(a[1]))