diff --git a/benchmarks/merlin-rpc.yml b/benchmarks/merlin-rpc.yml index 94e7952f..8a4b4701 100644 --- a/benchmarks/merlin-rpc.yml +++ b/benchmarks/merlin-rpc.yml @@ -14,7 +14,7 @@ unit: ms higher_is_better: false seo_intro: | - Merlin Chain is an EVM-compatible Bitcoin Layer 2 network (chain ID 4200) that uses ZK-Rollup technology to inherit Bitcoin security while enabling smart contracts and DeFi. It exposes a standard Ethereum JSON-RPC interface. Public EVM endpoints are available without an API key from Merlin Official, dRPC and Thirdweb. Every provider was live-verified with consecutive eth_getBlockByNumber probes at launch. + Merlin Chain is an EVM-compatible Bitcoin Layer 2 network (chain ID 4200) that uses ZK-Rollup technology to inherit Bitcoin security while enabling smart contracts and DeFi. It exposes a standard Ethereum JSON-RPC interface. Public EVM endpoints are available without an API key from Merlin Official, dRPC and BlockPI. Every provider was live-verified with consecutive eth_getBlockByNumber probes at launch. abstract: | Per-chain member of the RPC latency cluster, extended to Merlin Chain. @@ -33,7 +33,7 @@ methodology: - "Latency: client-side round-trip delta in milliseconds, exposed as both a gauge and a histogram (buckets 50 ms to 10 s), so percentiles are computed via Prometheus quantile_over_time over the last 24 hours." - "Call-result classification: ok (HTTP 200 + parsable block number), http_err, jsonrpc_err, stale, timeout. Latency without reliability is a misleading ranking signal." - "This page is part of the per-chain RPC cluster derived from the cross-chain rpc-capabilities benchmark; the identical harness, cadence and exclusion rules apply on every chain." - - "Chain scope: every query on this page is pinned to chain=merlin. Provider coverage at launch: 3 endpoints (Merlin Official, dRPC, Thirdweb)." + - "Chain scope: every query on this page is pinned to chain=merlin. Provider coverage at launch: 3 endpoints (Merlin Official, dRPC, BlockPI)." findings: - "{{best_name}} currently leads Merlin Chain RPC at {{best_p50}} (eth_getBlockByNumber p50, 24h) across 3 measured providers." @@ -42,7 +42,7 @@ faq: - q: "What is the fastest free Merlin Chain RPC right now?" a: "{{best_name}} currently leads at {{best_p50}} (Merlin Chain block number p50 over the last 24h), measured against 3 providers probed every 60 seconds from us-east, eu-west and Singapore. The leaderboard re-sorts continuously against fresh Prometheus samples." - q: "Which Merlin Chain RPC endpoints work without an API key?" - a: "3 endpoints sustain continuous keyless probing at launch: Merlin Official (rpc.merlinchain.io), dRPC (merlin.drpc.org) and Thirdweb (4200.rpc.thirdweb.com). Every listed endpoint was live-verified with an eth_getBlockByNumber call returning a parsable block number before inclusion." + a: "3 endpoints sustain continuous keyless probing at launch: Merlin Official (rpc.merlinchain.io), dRPC (merlin.drpc.org) and BlockPI (merlin.blockpi.network). Every listed endpoint was live-verified with an eth_getBlockByNumber call returning a parsable block number before inclusion." - q: "Does the fastest Merlin Chain RPC change by region?" a: "Often. Public infra concentrates in specific regions; a gateway that wins from Amsterdam can lose from Singapore by multiples. The region tabs at the top of the page re-scope every number to a single origin." - q: "How is Merlin Chain RPC latency measured here, technically?" @@ -110,25 +110,25 @@ providers: p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="drpc", chain="merlin", region="sgp"}) series: avg_over_time(rpc_latency_milliseconds{provider="drpc", chain="merlin", region="sgp"}[1h]) - - slug: thirdweb - name: Thirdweb - tag: Thirdweb public Merlin Chain RPC (chain 4200), no key required - formula: "50th percentile over 24h of client-side round-trip latency (ms) for an eth_getBlockByNumber POST sent every 60s from 3 regions to 4200.rpc.thirdweb.com." + - slug: blockpi + name: BlockPI + tag: BlockPI public Merlin Chain RPC, keyless + formula: "50th percentile over 24h of client-side round-trip latency (ms) for an eth_getBlockByNumber POST sent every 60s from 3 regions to merlin.blockpi.network/v1/rpc/public." queries: - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thirdweb", chain="merlin"}) - p90: avg(ocb:rpc_latency_milliseconds:p90_24h{provider="thirdweb", chain="merlin"}) - p99: avg(ocb:rpc_latency_milliseconds:p99_24h{provider="thirdweb", chain="merlin"}) - mean: avg(ocb:rpc_latency_milliseconds:mean_24h{provider="thirdweb", chain="merlin"}) - success: sum(ocb:rpc_call:ok_rate_24h{provider="thirdweb", chain="merlin"}) / sum(ocb:rpc_call:rate_24h{provider="thirdweb", chain="merlin"}) - sample_size: sum(ocb:rpc_call:increase_24h{provider="thirdweb", chain="merlin"}) - series: avg(avg_over_time(rpc_latency_milliseconds{provider="thirdweb", chain="merlin"}[1h])) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="blockpi", chain="merlin"}) + p90: avg(ocb:rpc_latency_milliseconds:p90_24h{provider="blockpi", chain="merlin"}) + p99: avg(ocb:rpc_latency_milliseconds:p99_24h{provider="blockpi", chain="merlin"}) + mean: avg(ocb:rpc_latency_milliseconds:mean_24h{provider="blockpi", chain="merlin"}) + success: sum(ocb:rpc_call:ok_rate_24h{provider="blockpi", chain="merlin"}) / sum(ocb:rpc_call:rate_24h{provider="blockpi", chain="merlin"}) + sample_size: sum(ocb:rpc_call:increase_24h{provider="blockpi", chain="merlin"}) + series: avg(avg_over_time(rpc_latency_milliseconds{provider="blockpi", chain="merlin"}[1h])) regions: - region: us-east - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thirdweb", chain="merlin", region="us-east"}) - series: avg_over_time(rpc_latency_milliseconds{provider="thirdweb", chain="merlin", region="us-east"}[1h]) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="blockpi", chain="merlin", region="us-east"}) + series: avg_over_time(rpc_latency_milliseconds{provider="blockpi", chain="merlin", region="us-east"}[1h]) - region: eu-west - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thirdweb", chain="merlin", region="eu-west"}) - series: avg_over_time(rpc_latency_milliseconds{provider="thirdweb", chain="merlin", region="eu-west"}[1h]) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="blockpi", chain="merlin", region="eu-west"}) + series: avg_over_time(rpc_latency_milliseconds{provider="blockpi", chain="merlin", region="eu-west"}[1h]) - region: ap-southeast - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thirdweb", chain="merlin", region="sgp"}) - series: avg_over_time(rpc_latency_milliseconds{provider="thirdweb", chain="merlin", region="sgp"}[1h]) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="blockpi", chain="merlin", region="sgp"}) + series: avg_over_time(rpc_latency_milliseconds{provider="blockpi", chain="merlin", region="sgp"}[1h]) diff --git a/benchmarks/oktc-rpc.yml b/benchmarks/oktc-rpc.yml index 66781bd3..95070fb2 100644 --- a/benchmarks/oktc-rpc.yml +++ b/benchmarks/oktc-rpc.yml @@ -14,7 +14,7 @@ unit: ms higher_is_better: false seo_intro: | - OKTC (OKX Token Chain, formerly OKChain) is an EVM-compatible Layer 1 blockchain (chain ID 66) developed by OKX, targeting high throughput and low fees for DeFi applications. It exposes a standard Ethereum JSON-RPC interface. Public EVM endpoints are available without an API key from OKX Chain Official, Thirdweb and dRPC. Every provider was live-verified with consecutive eth_getBlockByNumber probes at launch. + OKTC (OKX Token Chain, formerly OKChain) is an EVM-compatible Layer 1 blockchain (chain ID 66) developed by OKX, targeting high throughput and low fees for DeFi applications. It exposes a standard Ethereum JSON-RPC interface. Public EVM endpoints are available without an API key from OKX Chain Official, 1RPC and dRPC. Every provider was live-verified with consecutive eth_getBlockByNumber probes at launch. abstract: | Per-chain member of the RPC latency cluster, extended to OKTC. @@ -33,7 +33,7 @@ methodology: - "Latency: client-side round-trip delta in milliseconds, exposed as both a gauge and a histogram (buckets 50 ms to 10 s), so percentiles are computed via Prometheus quantile_over_time over the last 24 hours." - "Call-result classification: ok (HTTP 200 + parsable block number), http_err, jsonrpc_err, stale, timeout. Latency without reliability is a misleading ranking signal." - "This page is part of the per-chain RPC cluster derived from the cross-chain rpc-capabilities benchmark; the identical harness, cadence and exclusion rules apply on every chain." - - "Chain scope: every query on this page is pinned to chain=oktc. Provider coverage at launch: 3 endpoints (OKX Chain Official, Thirdweb, dRPC)." + - "Chain scope: every query on this page is pinned to chain=oktc. Provider coverage at launch: 3 endpoints (OKX Chain Official, 1RPC, dRPC)." findings: - "{{best_name}} currently leads OKTC RPC at {{best_p50}} (eth_getBlockByNumber p50, 24h) across 3 measured providers." @@ -42,7 +42,7 @@ faq: - q: "What is the fastest free OKTC RPC right now?" a: "{{best_name}} currently leads at {{best_p50}} (OKTC block number p50 over the last 24h), measured against 3 providers probed every 60 seconds from us-east, eu-west and Singapore. The leaderboard re-sorts continuously against fresh Prometheus samples." - q: "Which OKTC RPC endpoints work without an API key?" - a: "3 endpoints sustain continuous keyless probing at launch: OKX Chain Official (exchainrpc.okex.org), Thirdweb (66.rpc.thirdweb.com) and dRPC (oktc.drpc.org). Every listed endpoint was live-verified with an eth_getBlockByNumber call returning a parsable block number before inclusion." + a: "3 endpoints sustain continuous keyless probing at launch: OKX Chain Official (exchainrpc.okex.org), 1RPC (1rpc.io/oktc) and dRPC (oktc.drpc.org). Every listed endpoint was live-verified with an eth_getBlockByNumber call returning a parsable block number before inclusion." - q: "Does the fastest OKTC RPC change by region?" a: "Often. Public infra concentrates in specific regions; a gateway that wins from Amsterdam can lose from Singapore by multiples. The region tabs at the top of the page re-scope every number to a single origin." - q: "How is OKTC RPC latency measured here, technically?" @@ -87,28 +87,28 @@ providers: p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="oktc-official", chain="oktc", region="sgp"}) series: avg_over_time(rpc_latency_milliseconds{provider="oktc-official", chain="oktc", region="sgp"}[1h]) - - slug: thirdweb - name: Thirdweb - tag: Thirdweb public OKTC RPC (chain 66), no key required - formula: "50th percentile over 24h of client-side round-trip latency (ms) for an eth_getBlockByNumber POST sent every 60s from 3 regions to 66.rpc.thirdweb.com." + - slug: 1rpc + name: 1RPC + tag: 1RPC privacy-preserving public OKTC endpoint, keyless + formula: "50th percentile over 24h of client-side round-trip latency (ms) for an eth_getBlockByNumber POST sent every 60s from 3 regions to 1rpc.io/oktc." queries: - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thirdweb", chain="oktc"}) - p90: avg(ocb:rpc_latency_milliseconds:p90_24h{provider="thirdweb", chain="oktc"}) - p99: avg(ocb:rpc_latency_milliseconds:p99_24h{provider="thirdweb", chain="oktc"}) - mean: avg(ocb:rpc_latency_milliseconds:mean_24h{provider="thirdweb", chain="oktc"}) - success: sum(ocb:rpc_call:ok_rate_24h{provider="thirdweb", chain="oktc"}) / sum(ocb:rpc_call:rate_24h{provider="thirdweb", chain="oktc"}) - sample_size: sum(ocb:rpc_call:increase_24h{provider="thirdweb", chain="oktc"}) - series: avg(avg_over_time(rpc_latency_milliseconds{provider="thirdweb", chain="oktc"}[1h])) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="1rpc", chain="oktc"}) + p90: avg(ocb:rpc_latency_milliseconds:p90_24h{provider="1rpc", chain="oktc"}) + p99: avg(ocb:rpc_latency_milliseconds:p99_24h{provider="1rpc", chain="oktc"}) + mean: avg(ocb:rpc_latency_milliseconds:mean_24h{provider="1rpc", chain="oktc"}) + success: sum(ocb:rpc_call:ok_rate_24h{provider="1rpc", chain="oktc"}) / sum(ocb:rpc_call:rate_24h{provider="1rpc", chain="oktc"}) + sample_size: sum(ocb:rpc_call:increase_24h{provider="1rpc", chain="oktc"}) + series: avg(avg_over_time(rpc_latency_milliseconds{provider="1rpc", chain="oktc"}[1h])) regions: - region: us-east - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thirdweb", chain="oktc", region="us-east"}) - series: avg_over_time(rpc_latency_milliseconds{provider="thirdweb", chain="oktc", region="us-east"}[1h]) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="1rpc", chain="oktc", region="us-east"}) + series: avg_over_time(rpc_latency_milliseconds{provider="1rpc", chain="oktc", region="us-east"}[1h]) - region: eu-west - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thirdweb", chain="oktc", region="eu-west"}) - series: avg_over_time(rpc_latency_milliseconds{provider="thirdweb", chain="oktc", region="eu-west"}[1h]) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="1rpc", chain="oktc", region="eu-west"}) + series: avg_over_time(rpc_latency_milliseconds{provider="1rpc", chain="oktc", region="eu-west"}[1h]) - region: ap-southeast - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thirdweb", chain="oktc", region="sgp"}) - series: avg_over_time(rpc_latency_milliseconds{provider="thirdweb", chain="oktc", region="sgp"}[1h]) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="1rpc", chain="oktc", region="sgp"}) + series: avg_over_time(rpc_latency_milliseconds{provider="1rpc", chain="oktc", region="sgp"}[1h]) - slug: drpc name: dRPC diff --git a/benchmarks/tezos-rpc.yml b/benchmarks/tezos-rpc.yml index 2cb38bf1..a6c6b067 100644 --- a/benchmarks/tezos-rpc.yml +++ b/benchmarks/tezos-rpc.yml @@ -14,7 +14,7 @@ unit: ms higher_is_better: false seo_intro: | - Tezos is a self-amending proof-of-stake blockchain using Liquid Proof of Stake (LPoS) and an on-chain governance mechanism that allows protocol upgrades without hard forks. It targets roughly one block every 30 seconds on mainnet. Public REST endpoints are available without an API key from ECADinfra, TezBeta and TzKT (Baking Bad). Every provider was live-verified with consecutive block header probes at launch. + Tezos is a self-amending proof-of-stake blockchain using Liquid Proof of Stake (LPoS) and an on-chain governance mechanism that allows protocol upgrades without hard forks. It targets roughly one block every 30 seconds on mainnet. Public REST endpoints are available without an API key from SmartPy, TezBeta and TzKT (Baking Bad). Every provider was live-verified with consecutive block header probes at launch. abstract: | Per-chain member of the RPC latency cluster, extended to Tezos. @@ -34,7 +34,7 @@ methodology: - "Latency: client-side round-trip delta in milliseconds, exposed as both a gauge and a histogram (buckets 50 ms to 10 s), so percentiles are computed via Prometheus quantile_over_time over the last 24 hours." - "Call-result classification: ok (HTTP 200 + parsable level integer), http_err, jsonrpc_err, stale (block more than 10 behind the cross-provider tip), timeout. Latency without reliability is a misleading ranking signal." - "This page is part of the per-chain RPC cluster derived from the cross-chain rpc-capabilities benchmark; the identical harness, cadence and exclusion rules apply on every chain." - - "Chain scope: every query on this page is pinned to chain=tezos. Provider coverage at launch: 3 endpoints (ECADinfra, TezBeta, TzKT)." + - "Chain scope: every query on this page is pinned to chain=tezos. Provider coverage at launch: 3 endpoints (SmartPy, TezBeta, TzKT)." findings: - "{{best_name}} currently leads Tezos RPC at {{best_p50}} (block level REST p50, 24h) across 3 measured providers." @@ -43,7 +43,7 @@ faq: - q: "What is the fastest free Tezos RPC right now?" a: "{{best_name}} currently leads at {{best_p50}} (Tezos block level p50 over the last 24h), measured against 3 providers probed every 60 seconds from us-east, eu-west and Singapore. The leaderboard re-sorts continuously against fresh Prometheus samples." - q: "Which Tezos RPC endpoints work without an API key?" - a: "3 endpoints sustain continuous keyless probing at launch: ECADinfra (mainnet.ecadinfra.com), TezBeta (rpc.tzbeta.net) and TzKT by Baking Bad (rpc.tzkt.io/mainnet). Every listed endpoint was live-verified with a block header call returning a parsable level before inclusion." + a: "3 endpoints sustain continuous keyless probing at launch: SmartPy (mainnet.smartpy.io), TezBeta (rpc.tzbeta.net) and TzKT by Baking Bad (rpc.tzkt.io/mainnet). Every listed endpoint was live-verified with a block header call returning a parsable level before inclusion." - q: "Does the fastest Tezos RPC change by region?" a: "Often. Public infra concentrates in specific regions; a gateway that wins from Amsterdam can lose from Singapore by multiples. The region tabs at the top of the page re-scope every number to a single origin." - q: "How is Tezos RPC latency measured here, technically?" @@ -65,28 +65,28 @@ dimensions: - { value: sgp, label: Singapore } providers: - - slug: ecadinfra - name: ECADinfra - tag: ECADinfra public Tezos mainnet RPC, keyless - formula: "50th percentile over 24h of client-side round-trip latency (ms) for a GET /chains/main/blocks/head/header sent every 60s from 3 regions to mainnet.ecadinfra.com." + - slug: smartpy + name: SmartPy + tag: SmartPy public Tezos mainnet RPC, keyless + formula: "50th percentile over 24h of client-side round-trip latency (ms) for a GET /chains/main/blocks/head/header sent every 60s from 3 regions to mainnet.smartpy.io." queries: - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="ecadinfra", chain="tezos"}) - p90: avg(ocb:rpc_latency_milliseconds:p90_24h{provider="ecadinfra", chain="tezos"}) - p99: avg(ocb:rpc_latency_milliseconds:p99_24h{provider="ecadinfra", chain="tezos"}) - mean: avg(ocb:rpc_latency_milliseconds:mean_24h{provider="ecadinfra", chain="tezos"}) - success: sum(ocb:rpc_call:ok_rate_24h{provider="ecadinfra", chain="tezos"}) / sum(ocb:rpc_call:rate_24h{provider="ecadinfra", chain="tezos"}) - sample_size: sum(ocb:rpc_call:increase_24h{provider="ecadinfra", chain="tezos"}) - series: avg(avg_over_time(rpc_latency_milliseconds{provider="ecadinfra", chain="tezos"}[1h])) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="smartpy", chain="tezos"}) + p90: avg(ocb:rpc_latency_milliseconds:p90_24h{provider="smartpy", chain="tezos"}) + p99: avg(ocb:rpc_latency_milliseconds:p99_24h{provider="smartpy", chain="tezos"}) + mean: avg(ocb:rpc_latency_milliseconds:mean_24h{provider="smartpy", chain="tezos"}) + success: sum(ocb:rpc_call:ok_rate_24h{provider="smartpy", chain="tezos"}) / sum(ocb:rpc_call:rate_24h{provider="smartpy", chain="tezos"}) + sample_size: sum(ocb:rpc_call:increase_24h{provider="smartpy", chain="tezos"}) + series: avg(avg_over_time(rpc_latency_milliseconds{provider="smartpy", chain="tezos"}[1h])) regions: - region: us-east - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="ecadinfra", chain="tezos", region="us-east"}) - series: avg_over_time(rpc_latency_milliseconds{provider="ecadinfra", chain="tezos", region="us-east"}[1h]) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="smartpy", chain="tezos", region="us-east"}) + series: avg_over_time(rpc_latency_milliseconds{provider="smartpy", chain="tezos", region="us-east"}[1h]) - region: eu-west - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="ecadinfra", chain="tezos", region="eu-west"}) - series: avg_over_time(rpc_latency_milliseconds{provider="ecadinfra", chain="tezos", region="eu-west"}[1h]) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="smartpy", chain="tezos", region="eu-west"}) + series: avg_over_time(rpc_latency_milliseconds{provider="smartpy", chain="tezos", region="eu-west"}[1h]) - region: ap-southeast - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="ecadinfra", chain="tezos", region="sgp"}) - series: avg_over_time(rpc_latency_milliseconds{provider="ecadinfra", chain="tezos", region="sgp"}[1h]) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="smartpy", chain="tezos", region="sgp"}) + series: avg_over_time(rpc_latency_milliseconds{provider="smartpy", chain="tezos", region="sgp"}[1h]) - slug: tzbeta name: TezBeta diff --git a/benchmarks/thundercore-rpc.yml b/benchmarks/thundercore-rpc.yml index 1e5242a4..da46c54f 100644 --- a/benchmarks/thundercore-rpc.yml +++ b/benchmarks/thundercore-rpc.yml @@ -14,7 +14,7 @@ unit: ms higher_is_better: false seo_intro: | - ThunderCore is an EVM-compatible Layer 1 blockchain (chain ID 108) designed for high throughput, producing approximately one block per second with fast finality. It runs a modified version of Ethereum with the Thunder consensus protocol and exposes a standard JSON-RPC interface. Public EVM endpoints are available without an API key from ThunderCore Official, Thirdweb and dRPC. Every provider was live-verified with consecutive eth_getBlockByNumber probes at launch. + ThunderCore is an EVM-compatible Layer 1 blockchain (chain ID 108) designed for high throughput, producing approximately one block per second with fast finality. It runs a modified version of Ethereum with the Thunder consensus protocol and exposes a standard JSON-RPC interface. Public EVM endpoints are available without an API key from ThunderCore Official, ThunderToken and dRPC. Every provider was live-verified with consecutive eth_getBlockByNumber probes at launch. abstract: | Per-chain member of the RPC latency cluster, extended to ThunderCore. @@ -33,7 +33,7 @@ methodology: - "Latency: client-side round-trip delta in milliseconds, exposed as both a gauge and a histogram (buckets 50 ms to 10 s), so percentiles are computed via Prometheus quantile_over_time over the last 24 hours." - "Call-result classification: ok (HTTP 200 + parsable block number), http_err, jsonrpc_err, stale, timeout. Latency without reliability is a misleading ranking signal." - "This page is part of the per-chain RPC cluster derived from the cross-chain rpc-capabilities benchmark; the identical harness, cadence and exclusion rules apply on every chain." - - "Chain scope: every query on this page is pinned to chain=thundercore. Provider coverage at launch: 3 endpoints (ThunderCore Official, Thirdweb, dRPC)." + - "Chain scope: every query on this page is pinned to chain=thundercore. Provider coverage at launch: 3 endpoints (ThunderCore Official, ThunderToken, dRPC)." findings: - "{{best_name}} currently leads ThunderCore RPC at {{best_p50}} (eth_getBlockByNumber p50, 24h) across 3 measured providers." @@ -42,7 +42,7 @@ faq: - q: "What is the fastest free ThunderCore RPC right now?" a: "{{best_name}} currently leads at {{best_p50}} (ThunderCore block number p50 over the last 24h), measured against 3 providers probed every 60 seconds from us-east, eu-west and Singapore. The leaderboard re-sorts continuously against fresh Prometheus samples." - q: "Which ThunderCore RPC endpoints work without an API key?" - a: "3 endpoints sustain continuous keyless probing at launch: ThunderCore Official (mainnet-rpc.thundercore.com), Thirdweb (108.rpc.thirdweb.com) and dRPC (thundercore.drpc.org). Every listed endpoint was live-verified with an eth_getBlockByNumber call returning a parsable block number before inclusion." + a: "3 endpoints sustain continuous keyless probing at launch: ThunderCore Official (mainnet-rpc.thundercore.com), ThunderToken (mainnet-rpc.thundertoken.net) and dRPC (thundercore.drpc.org). Every listed endpoint was live-verified with an eth_getBlockByNumber call returning a parsable block number before inclusion." - q: "Does the fastest ThunderCore RPC change by region?" a: "Often. Public infra concentrates in specific regions; a gateway that wins from Amsterdam can lose from Singapore by multiples. The region tabs at the top of the page re-scope every number to a single origin." - q: "How is ThunderCore RPC latency measured here, technically?" @@ -87,28 +87,28 @@ providers: p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thundercore-official", chain="thundercore", region="sgp"}) series: avg_over_time(rpc_latency_milliseconds{provider="thundercore-official", chain="thundercore", region="sgp"}[1h]) - - slug: thirdweb - name: Thirdweb - tag: Thirdweb public ThunderCore RPC (chain 108), no key required - formula: "50th percentile over 24h of client-side round-trip latency (ms) for an eth_getBlockByNumber POST sent every 60s from 3 regions to 108.rpc.thirdweb.com." + - slug: thundertoken + name: ThunderToken + tag: ThunderToken public ThunderCore RPC, keyless + formula: "50th percentile over 24h of client-side round-trip latency (ms) for an eth_getBlockByNumber POST sent every 60s from 3 regions to mainnet-rpc.thundertoken.net." queries: - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thirdweb", chain="thundercore"}) - p90: avg(ocb:rpc_latency_milliseconds:p90_24h{provider="thirdweb", chain="thundercore"}) - p99: avg(ocb:rpc_latency_milliseconds:p99_24h{provider="thirdweb", chain="thundercore"}) - mean: avg(ocb:rpc_latency_milliseconds:mean_24h{provider="thirdweb", chain="thundercore"}) - success: sum(ocb:rpc_call:ok_rate_24h{provider="thirdweb", chain="thundercore"}) / sum(ocb:rpc_call:rate_24h{provider="thirdweb", chain="thundercore"}) - sample_size: sum(ocb:rpc_call:increase_24h{provider="thirdweb", chain="thundercore"}) - series: avg(avg_over_time(rpc_latency_milliseconds{provider="thirdweb", chain="thundercore"}[1h])) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thundertoken", chain="thundercore"}) + p90: avg(ocb:rpc_latency_milliseconds:p90_24h{provider="thundertoken", chain="thundercore"}) + p99: avg(ocb:rpc_latency_milliseconds:p99_24h{provider="thundertoken", chain="thundercore"}) + mean: avg(ocb:rpc_latency_milliseconds:mean_24h{provider="thundertoken", chain="thundercore"}) + success: sum(ocb:rpc_call:ok_rate_24h{provider="thundertoken", chain="thundercore"}) / sum(ocb:rpc_call:rate_24h{provider="thundertoken", chain="thundercore"}) + sample_size: sum(ocb:rpc_call:increase_24h{provider="thundertoken", chain="thundercore"}) + series: avg(avg_over_time(rpc_latency_milliseconds{provider="thundertoken", chain="thundercore"}[1h])) regions: - region: us-east - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thirdweb", chain="thundercore", region="us-east"}) - series: avg_over_time(rpc_latency_milliseconds{provider="thirdweb", chain="thundercore", region="us-east"}[1h]) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thundertoken", chain="thundercore", region="us-east"}) + series: avg_over_time(rpc_latency_milliseconds{provider="thundertoken", chain="thundercore", region="us-east"}[1h]) - region: eu-west - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thirdweb", chain="thundercore", region="eu-west"}) - series: avg_over_time(rpc_latency_milliseconds{provider="thirdweb", chain="thundercore", region="eu-west"}[1h]) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thundertoken", chain="thundercore", region="eu-west"}) + series: avg_over_time(rpc_latency_milliseconds{provider="thundertoken", chain="thundercore", region="eu-west"}[1h]) - region: ap-southeast - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thirdweb", chain="thundercore", region="sgp"}) - series: avg_over_time(rpc_latency_milliseconds{provider="thirdweb", chain="thundercore", region="sgp"}[1h]) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thundertoken", chain="thundercore", region="sgp"}) + series: avg_over_time(rpc_latency_milliseconds{provider="thundertoken", chain="thundercore", region="sgp"}[1h]) - slug: drpc name: dRPC diff --git a/benchmarks/viction-rpc.yml b/benchmarks/viction-rpc.yml index 2e8303dc..439088e8 100644 --- a/benchmarks/viction-rpc.yml +++ b/benchmarks/viction-rpc.yml @@ -14,7 +14,7 @@ unit: ms higher_is_better: false seo_intro: | - Viction (formerly TomoChain) is a proof-of-stake-voting EVM L1 blockchain (chain ID 88) with 2-second block times, targeting low fees and high throughput for DeFi and NFTs. It exposes a standard Ethereum JSON-RPC interface. Public EVM endpoints are available without an API key from Viction Official, Thirdweb and dRPC. Every provider was live-verified with consecutive eth_getBlockByNumber probes at launch. + Viction (formerly TomoChain) is a proof-of-stake-voting EVM L1 blockchain (chain ID 88) with 2-second block times, targeting low fees and high throughput for DeFi and NFTs. It exposes a standard Ethereum JSON-RPC interface. Public EVM endpoints are available without an API key from Viction Official, Viction RPC2 and dRPC. Every provider was live-verified with consecutive eth_getBlockByNumber probes at launch. abstract: | Per-chain member of the RPC latency cluster, extended to Viction. @@ -33,7 +33,7 @@ methodology: - "Latency: client-side round-trip delta in milliseconds, exposed as both a gauge and a histogram (buckets 50 ms to 10 s), so percentiles are computed via Prometheus quantile_over_time over the last 24 hours." - "Call-result classification: ok (HTTP 200 + parsable block number), http_err, jsonrpc_err, stale, timeout. Latency without reliability is a misleading ranking signal." - "This page is part of the per-chain RPC cluster derived from the cross-chain rpc-capabilities benchmark; the identical harness, cadence and exclusion rules apply on every chain." - - "Chain scope: every query on this page is pinned to chain=viction. Provider coverage at launch: 3 endpoints (Viction Official, Thirdweb, dRPC)." + - "Chain scope: every query on this page is pinned to chain=viction. Provider coverage at launch: 3 endpoints (Viction Official, Viction RPC2, dRPC)." findings: - "{{best_name}} currently leads Viction RPC at {{best_p50}} (eth_getBlockByNumber p50, 24h) across 3 measured providers." @@ -42,7 +42,7 @@ faq: - q: "What is the fastest free Viction RPC right now?" a: "{{best_name}} currently leads at {{best_p50}} (Viction block number p50 over the last 24h), measured against 3 providers probed every 60 seconds from us-east, eu-west and Singapore. The leaderboard re-sorts continuously against fresh Prometheus samples." - q: "Which Viction RPC endpoints work without an API key?" - a: "3 endpoints sustain continuous keyless probing at launch: Viction Official (rpc.viction.xyz), Thirdweb (88.rpc.thirdweb.com) and dRPC (viction.drpc.org). Every listed endpoint was live-verified with an eth_getBlockByNumber call returning a parsable block number before inclusion." + a: "3 endpoints sustain continuous keyless probing at launch: Viction Official (rpc.viction.xyz), Viction RPC2 (rpc2.viction.xyz) and dRPC (viction.drpc.org). Every listed endpoint was live-verified with an eth_getBlockByNumber call returning a parsable block number before inclusion." - q: "Does the fastest Viction RPC change by region?" a: "Often. Public infra concentrates in specific regions; a gateway that wins from Amsterdam can lose from Singapore by multiples. The region tabs at the top of the page re-scope every number to a single origin." - q: "How is Viction RPC latency measured here, technically?" @@ -87,28 +87,28 @@ providers: p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="viction-official", chain="viction", region="sgp"}) series: avg_over_time(rpc_latency_milliseconds{provider="viction-official", chain="viction", region="sgp"}[1h]) - - slug: thirdweb - name: Thirdweb - tag: Thirdweb public Viction RPC (chain 88), no key required - formula: "50th percentile over 24h of client-side round-trip latency (ms) for an eth_getBlockByNumber POST sent every 60s from 3 regions to 88.rpc.thirdweb.com." + - slug: viction-rpc2 + name: Viction RPC2 + tag: Viction secondary public RPC (rpc2.viction.xyz), keyless + formula: "50th percentile over 24h of client-side round-trip latency (ms) for an eth_getBlockByNumber POST sent every 60s from 3 regions to rpc2.viction.xyz." queries: - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thirdweb", chain="viction"}) - p90: avg(ocb:rpc_latency_milliseconds:p90_24h{provider="thirdweb", chain="viction"}) - p99: avg(ocb:rpc_latency_milliseconds:p99_24h{provider="thirdweb", chain="viction"}) - mean: avg(ocb:rpc_latency_milliseconds:mean_24h{provider="thirdweb", chain="viction"}) - success: sum(ocb:rpc_call:ok_rate_24h{provider="thirdweb", chain="viction"}) / sum(ocb:rpc_call:rate_24h{provider="thirdweb", chain="viction"}) - sample_size: sum(ocb:rpc_call:increase_24h{provider="thirdweb", chain="viction"}) - series: avg(avg_over_time(rpc_latency_milliseconds{provider="thirdweb", chain="viction"}[1h])) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="viction-rpc2", chain="viction"}) + p90: avg(ocb:rpc_latency_milliseconds:p90_24h{provider="viction-rpc2", chain="viction"}) + p99: avg(ocb:rpc_latency_milliseconds:p99_24h{provider="viction-rpc2", chain="viction"}) + mean: avg(ocb:rpc_latency_milliseconds:mean_24h{provider="viction-rpc2", chain="viction"}) + success: sum(ocb:rpc_call:ok_rate_24h{provider="viction-rpc2", chain="viction"}) / sum(ocb:rpc_call:rate_24h{provider="viction-rpc2", chain="viction"}) + sample_size: sum(ocb:rpc_call:increase_24h{provider="viction-rpc2", chain="viction"}) + series: avg(avg_over_time(rpc_latency_milliseconds{provider="viction-rpc2", chain="viction"}[1h])) regions: - region: us-east - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thirdweb", chain="viction", region="us-east"}) - series: avg_over_time(rpc_latency_milliseconds{provider="thirdweb", chain="viction", region="us-east"}[1h]) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="viction-rpc2", chain="viction", region="us-east"}) + series: avg_over_time(rpc_latency_milliseconds{provider="viction-rpc2", chain="viction", region="us-east"}[1h]) - region: eu-west - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thirdweb", chain="viction", region="eu-west"}) - series: avg_over_time(rpc_latency_milliseconds{provider="thirdweb", chain="viction", region="eu-west"}[1h]) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="viction-rpc2", chain="viction", region="eu-west"}) + series: avg_over_time(rpc_latency_milliseconds{provider="viction-rpc2", chain="viction", region="eu-west"}[1h]) - region: ap-southeast - p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="thirdweb", chain="viction", region="sgp"}) - series: avg_over_time(rpc_latency_milliseconds{provider="thirdweb", chain="viction", region="sgp"}[1h]) + p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="viction-rpc2", chain="viction", region="sgp"}) + series: avg_over_time(rpc_latency_milliseconds{provider="viction-rpc2", chain="viction", region="sgp"}[1h]) - slug: drpc name: dRPC diff --git a/benchmarks/waves-rpc.yml b/benchmarks/waves-rpc.yml index 27098a3c..88927c07 100644 --- a/benchmarks/waves-rpc.yml +++ b/benchmarks/waves-rpc.yml @@ -111,8 +111,8 @@ providers: series: avg_over_time(rpc_latency_milliseconds{provider="wx-network", chain="waves", region="sgp"}[1h]) - slug: waves-exchange - name: WavesExchange - tag: WavesExchange public node (nodes.waves.exchange), keyless + name: Waves Exchange Node + tag: Waves Exchange public node (nodes.waves.exchange), keyless formula: "50th percentile over 24h of client-side round-trip latency (ms) for a GET /blocks/last sent every 60s from 3 regions to nodes.waves.exchange." queries: p50: avg(ocb:rpc_latency_milliseconds:p50_24h{provider="waves-exchange", chain="waves"}) diff --git a/harnesses/rpc-capabilities/cmd/script/config.go b/harnesses/rpc-capabilities/cmd/script/config.go index 0eeaa976..31311ff2 100644 --- a/harnesses/rpc-capabilities/cmd/script/config.go +++ b/harnesses/rpc-capabilities/cmd/script/config.go @@ -1622,7 +1622,7 @@ func chains() []Chain { Name: "Tezos", Kind: "tezos", Providers: []Provider{ - {Slug: "ecadinfra", Name: "ECADinfra", URL: envDefault("RPC_URL_TEZOS_ECADINFRA", "https://mainnet.ecadinfra.com")}, + {Slug: "smartpy", Name: "SmartPy", URL: envDefault("RPC_URL_TEZOS_SMARTPY", "https://mainnet.smartpy.io")}, {Slug: "tzbeta", Name: "TezBeta", URL: envDefault("RPC_URL_TEZOS_TZBETA", "https://rpc.tzbeta.net")}, {Slug: "tzkt", Name: "TzKT (Baking Bad)", URL: envDefault("RPC_URL_TEZOS_TZKT", "https://rpc.tzkt.io/mainnet")}, }, @@ -1657,7 +1657,7 @@ func chains() []Chain { Providers: []Provider{ {Slug: "wavesnodes", Name: "Waves Foundation", URL: envDefault("RPC_URL_WAVES_WAVESNODES", "https://nodes.wavesnodes.com")}, {Slug: "wx-network", Name: "Waves.Exchange", URL: envDefault("RPC_URL_WAVES_WX", "https://nodes.wx.network")}, - {Slug: "waves-exchange", Name: "WavesExchange", URL: envDefault("RPC_URL_WAVES_EXCHANGE", "https://nodes.waves.exchange")}, + {Slug: "waves-exchange", Name: "Waves Exchange Node", URL: envDefault("RPC_URL_WAVES_EXCHANGE", "https://nodes.waves.exchange")}, }, }, // 2026-08-18 wave-8. WAX gaming blockchain (Antelope) — REST GET /v1/chain/get_info, ~0.5 s/block. 3 keyless providers. @@ -1688,7 +1688,7 @@ func chains() []Chain { Providers: []Provider{ {Slug: "merlin-official", Name: "Merlin Official", URL: envDefault("RPC_URL_MERLIN_OFFICIAL", "https://rpc.merlinchain.io")}, {Slug: "drpc", Name: "dRPC", URL: envDefault("RPC_URL_MERLIN_DRPC", "https://merlin.drpc.org")}, - {Slug: "thirdweb", Name: "Thirdweb", URL: envDefault("RPC_URL_MERLIN_THIRDWEB", "https://4200.rpc.thirdweb.com")}, + {Slug: "blockpi", Name: "BlockPI", URL: envDefault("RPC_URL_MERLIN_BLOCKPI", "https://merlin.blockpi.network/v1/rpc/public")}, }, }, // 2026-08-18 wave-8. Viction (TomoChain) — EVM L1 (chain 88), eth_getBlockByNumber probe. 3 keyless providers. @@ -1697,7 +1697,7 @@ func chains() []Chain { Name: "Viction", Providers: []Provider{ {Slug: "viction-official", Name: "Viction Official", URL: envDefault("RPC_URL_VICTION_OFFICIAL", "https://rpc.viction.xyz")}, - {Slug: "thirdweb", Name: "Thirdweb", URL: envDefault("RPC_URL_VICTION_THIRDWEB", "https://88.rpc.thirdweb.com")}, + {Slug: "viction-rpc2", Name: "Viction RPC2", URL: envDefault("RPC_URL_VICTION_RPC2", "https://rpc2.viction.xyz")}, {Slug: "drpc", Name: "dRPC", URL: envDefault("RPC_URL_VICTION_DRPC", "https://viction.drpc.org")}, }, }, @@ -1707,7 +1707,7 @@ func chains() []Chain { Name: "ThunderCore", Providers: []Provider{ {Slug: "thundercore-official", Name: "ThunderCore Official", URL: envDefault("RPC_URL_THUNDERCORE_OFFICIAL", "https://mainnet-rpc.thundercore.com")}, - {Slug: "thirdweb", Name: "Thirdweb", URL: envDefault("RPC_URL_THUNDERCORE_THIRDWEB", "https://108.rpc.thirdweb.com")}, + {Slug: "thundertoken", Name: "ThunderToken", URL: envDefault("RPC_URL_THUNDERCORE_THUNDERTOKEN", "https://mainnet-rpc.thundertoken.net")}, {Slug: "drpc", Name: "dRPC", URL: envDefault("RPC_URL_THUNDERCORE_DRPC", "https://thundercore.drpc.org")}, }, }, @@ -1717,7 +1717,7 @@ func chains() []Chain { Name: "OKTC", Providers: []Provider{ {Slug: "oktc-official", Name: "OKX Chain Official", URL: envDefault("RPC_URL_OKTC_OFFICIAL", "https://exchainrpc.okex.org")}, - {Slug: "thirdweb", Name: "Thirdweb", URL: envDefault("RPC_URL_OKTC_THIRDWEB", "https://66.rpc.thirdweb.com")}, + {Slug: "1rpc", Name: "1RPC", URL: envDefault("RPC_URL_OKTC_1RPC", "https://1rpc.io/oktc")}, {Slug: "drpc", Name: "dRPC", URL: envDefault("RPC_URL_OKTC_DRPC", "https://oktc.drpc.org")}, }, }, diff --git a/src/app/trading-apps/page.tsx b/src/app/trading-apps/page.tsx new file mode 100644 index 00000000..ea76cd87 --- /dev/null +++ b/src/app/trading-apps/page.tsx @@ -0,0 +1,483 @@ +import Link from "next/link"; +import { ProviderLogo } from "@/components/provider-logo"; +import { getBenchmark } from "@/data/benchmarks"; +import type { ProviderResult } from "@/types/benchmark"; +import { pageMetadata } from "@/lib/page-metadata"; +import { safeJsonLd, buildBreadcrumbJsonLd } from "@/lib/jsonld"; +import { SITE } from "@/data/site"; + +const DESCRIPTION = + "Live benchmarks for Solana trading platforms and Telegram bots — volume, swap transactions, average trade size, and app store ratings."; + +export const metadata: import("next").Metadata = pageMetadata({ + path: "/trading-apps", + title: "Best Solana Trading Apps 2026, ranked by benchmark", + description: DESCRIPTION, +}); + +export const revalidate = 60; + +const BENCH_SLUGS = [ + "solana-trading-platform-wars", + "solana-dex-volume", + "solana-unique-traders", + "solana-avg-trade-size", + "solana-launchpad-wars", + "memecoin-platforms", + "app-store-ratings", +] as const; + +// pump.fun is tracked via byLaunchpad (bonding curve, no referral tag system). +// All other platforms are tracked via byPlatform (referral tags). Volume is +// not directly comparable across the two groups — tooltip discloses this. +const PLATFORMS = [ + { slug: "pump-fun", name: "pump.fun" }, + { slug: "gmgn", name: "GMGN" }, + { slug: "axiom", name: "Axiom" }, + { slug: "fomo", name: "FOMO" }, + { slug: "trojan", name: "Trojan" }, + { slug: "photon", name: "Photon" }, + { slug: "maestro", name: "Maestro" }, +] as const; + +const COLUMNS = [ + { + key: "volume" as const, + label: "24h Volume", + bench: "solana-trading-platform-wars", + fmt: fmtUSD, + tip: "Mobula attribution. pump.fun = bonding-curve launchpad volume. All others = terminal routing volume via referral tag. Not directly comparable across the two groups.", + higherBetter: true, + }, + { + key: "traders" as const, + label: "Swap Tx", + bench: "solana-unique-traders", + fmt: fmtCount, + tip: "Unique swap transactions in 24h via Dune. pump.fun uses dex_solana.trades (all swaps incl. 0-fee). Terminals use fee-wallet detection (fee-generating swaps only). Methods differ.", + higherBetter: true, + }, + { + key: "tradeSize" as const, + label: "Avg Trade", + bench: "solana-avg-trade-size", + fmt: fmtUSD, + tip: "24h volume ÷ trade count via Mobula. Includes bots and MEV — platforms with heavy bot sniping (notably pump.fun) show lower averages than human-only baselines.", + higherBetter: true, + }, + { + key: "feeRate" as const, + label: "Fee Rate", + bench: "memecoin-platforms", + fmt: fmtPct, + tip: "Observed take rate: fee revenue ÷ fee-paying volume (Dune tx join). Comparable across platforms. FOMO uses DeFiLlama (includes off-chain relay fees). pump.fun cut trading fees to 0% in Aug 2026.", + higherBetter: false, + }, + { + key: "rating" as const, + label: "App Rating", + bench: "app-store-ratings", + fmt: fmtRating, + tip: "Apple App Store all-time average rating. Axiom, Trojan, Photon and Maestro have no iOS app — they show —.", + higherBetter: true, + }, +] as const; + +type ColKey = (typeof COLUMNS)[number]["key"]; + +function indexBySlug(results: ProviderResult[] | undefined): Record { + const out: Record = {}; + for (const r of results ?? []) { + out[r.slug] = r.ms.p50; + } + return out; +} + +function fmtUSD(v: number | null): string { + if (v === null) return "—"; + if (v >= 1_000_000_000) return `$${(v / 1_000_000_000).toFixed(1)}B`; + if (v >= 1_000_000) return `$${(v / 1_000_000).toFixed(0)}M`; + if (v >= 1_000) return `$${(v / 1_000).toFixed(0)}K`; + return `$${v.toFixed(0)}`; +} + +function fmtCount(v: number | null): string { + if (v === null) return "—"; + if (v >= 1_000_000) return `${(v / 1_000_000).toFixed(1)}M`; + if (v >= 1_000) return `${(v / 1_000).toFixed(0)}K`; + return v.toFixed(0); +} + +function fmtPct(v: number | null): string { + if (v === null) return "—"; + return `${v.toFixed(2)}%`; +} + +function fmtRating(v: number | null): string { + if (v === null) return "—"; + return `${v.toFixed(1)} / 5`; +} + +const GROUPS = [ + { + label: "Volume & activity", + items: [ + { slug: "solana-trading-platform-wars", title: "Trading platform volume" }, + { slug: "solana-dex-volume", title: "DEX volume & protocol revenue" }, + { slug: "solana-unique-traders", title: "Swap transactions" }, + { slug: "solana-avg-trade-size", title: "Average trade size" }, + ], + }, + { + label: "Launchpads", + items: [{ slug: "solana-launchpad-wars", title: "Launchpad volume" }], + }, + { + label: "Fees", + items: [{ slug: "memecoin-platforms", title: "Platform fee rates" }], + }, + { + label: "App store", + items: [{ slug: "app-store-ratings", title: "iOS app store ratings" }], + }, +] as const; + +export default async function TradingAppsHubPage() { + const [volBench, tradersBench, tradeSizeBench, feeBench, ratingsBench] = + await Promise.all([ + getBenchmark("solana-trading-platform-wars"), + getBenchmark("solana-unique-traders"), + getBenchmark("solana-avg-trade-size"), + getBenchmark("memecoin-platforms"), + getBenchmark("app-store-ratings"), + ]); + + const volIdx = indexBySlug(volBench?.results); + const tradersIdx = indexBySlug(tradersBench?.results); + const tradeSizeIdx = indexBySlug(tradeSizeBench?.results); + const feeIdx = indexBySlug(feeBench?.results); + const ratingIdx = indexBySlug(ratingsBench?.results); + + type Row = { + slug: string; + name: string; + volume: number | null; + traders: number | null; + tradeSize: number | null; + feeRate: number | null; + rating: number | null; + }; + + const matrix: Row[] = PLATFORMS.map((p) => ({ + slug: p.slug, + name: p.name, + volume: volIdx[p.slug] ?? null, + traders: tradersIdx[p.slug] ?? null, + tradeSize: tradeSizeIdx[p.slug] ?? null, + feeRate: feeIdx[p.slug] ?? null, + rating: ratingIdx[p.slug] ?? null, + })).sort((a, b) => (b.volume ?? -1) - (a.volume ?? -1)); + + function best(key: ColKey, higherBetter: boolean): number | null { + const vals = matrix.map((r) => r[key]).filter((v): v is number => v !== null); + if (!vals.length) return null; + return higherBetter ? Math.max(...vals) : Math.min(...vals); + } + + const bests: Partial> = {}; + for (const col of COLUMNS) { + bests[col.key] = best(col.key, col.higherBetter); + } + + const topVolumeRow = matrix.reduce( + (b, row) => ((row.volume ?? -1) > (b.volume ?? -1) ? row : b), + matrix[0], + ); + const topRating = ratingsBench?.results.find((r: ProviderResult) => + PLATFORMS.some((p) => p.slug === r.slug), + ); + + const breadcrumbLd = { + "@context": "https://schema.org", + ...buildBreadcrumbJsonLd([ + { name: "Home", item: SITE.url }, + { name: "Trading Apps", item: `${SITE.url}/trading-apps` }, + ]), + }; + + const itemListLd = { + "@context": "https://schema.org", + "@type": "ItemList", + name: "Trading app benchmarks by OpenChainBench", + description: DESCRIPTION, + numberOfItems: BENCH_SLUGS.length, + itemListElement: BENCH_SLUGS.map((slug, i) => ({ + "@type": "ListItem", + position: i + 1, + name: slug, + url: `${SITE.url}/benchmarks/${slug}`, + })), + }; + + return ( +
+