From 5408e6bc55452fb4f1e86b667c849cbf44e5837e Mon Sep 17 00:00:00 2001 From: Florent Tapponnier <160007691+Flotapponnier@users.noreply.github.com> Date: Wed, 19 Aug 2026 11:32:29 +0200 Subject: [PATCH 1/7] fix: trading-apps data accuracy (p50, Swap Tx label, Fomo+Flap volume, Bloom, remove broken exec link) --- src/app/trading-apps/page.tsx | 85 ++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/src/app/trading-apps/page.tsx b/src/app/trading-apps/page.tsx index f71ab7ce..80d240d9 100644 --- a/src/app/trading-apps/page.tsx +++ b/src/app/trading-apps/page.tsx @@ -7,7 +7,7 @@ import { safeJsonLd, buildBreadcrumbJsonLd } from "@/lib/jsonld"; import { SITE } from "@/data/site"; const DESCRIPTION = - "Live benchmarks for Solana trading platforms and Telegram bots — volume, fees, execution quality, unique traders, and app store ratings."; + "Live benchmarks for Solana trading platforms and Telegram bots — volume, fees, unique swap transactions, and app store ratings."; export const metadata: import("next").Metadata = pageMetadata({ path: "/trading-apps", @@ -24,7 +24,6 @@ const BENCH_SLUGS = [ "solana-avg-trade-size", "solana-launchpad-wars", "memecoin-platforms", - "trading-app-execution", "app-store-ratings", ] as const; @@ -35,24 +34,32 @@ const PLATFORMS = [ { slug: "fomo", name: "FOMO" }, { slug: "trojan", name: "Trojan" }, { slug: "photon", name: "Photon" }, + { slug: "bloom", name: "Bloom" }, { slug: "maestro", name: "Maestro" }, ] as const; +// Some platforms own a launchpad that runs under a different slug. +// Add the launchpad's volume to the platform's terminal volume so the +// "24h Volume" column reflects the full ecosystem (e.g. FOMO = terminal + Flap). +const LAUNCHPAD_COMPANION: Partial> = { + fomo: "flap", +}; + const COLUMNS = [ { key: "volume" as const, label: "24h Volume", bench: "solana-trading-platform-wars", fmt: fmtUSD, - tip: "Attributed 24h trading volume", + tip: "Terminal routing volume + owned launchpad volume (Mobula attribution)", higherBetter: true, }, { key: "traders" as const, - label: "Unique Traders", + label: "Swap Tx", bench: "solana-unique-traders", fmt: fmtCount, - tip: "Unique swap transactions in 24h", + tip: "Unique swap transactions in 24h (not unique wallets — active traders submit multiple tx/day)", higherBetter: true, }, { @@ -68,7 +75,7 @@ const COLUMNS = [ label: "Fee Rate", bench: "memecoin-platforms", fmt: fmtPct, - tip: "Protocol fee revenue ÷ volume (take rate)", + tip: "Observed take rate: on-chain fee revenue ÷ total attributed volume (lower bound — platforms with fee-exempt volume show lower rates)", higherBetter: false, }, { @@ -86,7 +93,7 @@ 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.mean; + out[r.slug] = r.ms.p50; } return out; } @@ -131,10 +138,9 @@ const GROUPS = [ items: [{ slug: "solana-launchpad-wars", title: "Launchpad volume" }], }, { - label: "Fees & execution", + label: "Fees", items: [ { slug: "memecoin-platforms", title: "Platform fee rates" }, - { slug: "trading-app-execution", title: "Execution quality" }, ], }, { @@ -144,9 +150,10 @@ const GROUPS = [ ] as const; export default async function TradingAppsHubPage() { - const [volBench, tradersBench, tradeSizeBench, feeBench, ratingsBench] = + const [volBench, launchpadBench, tradersBench, tradeSizeBench, feeBench, ratingsBench] = await Promise.all([ getBenchmark("solana-trading-platform-wars"), + getBenchmark("solana-launchpad-wars"), getBenchmark("solana-unique-traders"), getBenchmark("solana-avg-trade-size"), getBenchmark("memecoin-platforms"), @@ -154,6 +161,7 @@ export default async function TradingAppsHubPage() { ]); const volIdx = indexBySlug(volBench?.results); + const launchpadIdx = indexBySlug(launchpadBench?.results); const tradersIdx = indexBySlug(tradersBench?.results); const tradeSizeIdx = indexBySlug(tradeSizeBench?.results); const feeIdx = indexBySlug(feeBench?.results); @@ -169,17 +177,23 @@ export default async function TradingAppsHubPage() { 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)); + const matrix: Row[] = PLATFORMS.map((p) => { + const termVol = volIdx[p.slug] ?? null; + const companionSlug = LAUNCHPAD_COMPANION[p.slug]; + const lpVol = companionSlug ? (launchpadIdx[companionSlug] ?? null) : null; + const volume = + termVol !== null || lpVol !== null ? (termVol ?? 0) + (lpVol ?? 0) : null; + return { + slug: p.slug, + name: p.name, + volume, + 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)); - // Find the best value per column (for highlighting) 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; @@ -191,9 +205,12 @@ export default async function TradingAppsHubPage() { bests[col.key] = best(col.key, col.higherBetter); } - const topVolume = volBench?.results[0]; + const topVolumeRow = matrix.reduce( + (best, row) => ((row.volume ?? -1) > (best.volume ?? -1) ? row : best), + matrix[0], + ); const topRating = ratingsBench?.results.find((r) => - PLATFORMS.some((p) => p.slug === r.slug) + PLATFORMS.some((p) => p.slug === r.slug), ); const breadcrumbLd = { @@ -237,7 +254,6 @@ export default async function TradingAppsHubPage() { dangerouslySetInnerHTML={{ __html: safeJsonLd(itemListLd) }} /> - {/* Header */}

{PLATFORMS.length} platforms measured across {BENCH_SLUGS.length}{" "} - independent benchmarks: volume, unique traders, average trade size, fee + independent benchmarks: volume, swap transactions, average trade size, fee rates, and app store ratings. Live data, no marketing claims.

- {/* KPI strip */}
- {/* Comparison table */}

- {/* Benchmarks grouped list */}

- Volume and unique-trader figures are pulled from on-chain program - activity via Mobula Lighthouse and Dune Analytics. Fee rates compare - fee-wallet inflows to reported volume over the same 24h window. - Execution quality monitors Jito bundle rates, priority fees, and - compute unit price passively from fee accounts. App store ratings are - fetched from the Apple App Store API. All harnesses are open source on{" "} + Volume combines terminal routing volume (Mobula lighthouse byPlatform) + with owned launchpad volume where applicable (e.g. FOMO includes Flap). + Swap transaction counts are from Dune Analytics on-chain data. + Fee rates compare fee-wallet inflows to attributed volume. + App store ratings are fetched from the Apple App Store API. + All harnesses are open source on{" "} Date: Wed, 19 Aug 2026 12:27:03 +0200 Subject: [PATCH 2/7] fix: remove fee rate from table (stale/inconsistent), honest tooltips per column, drop launchpad companion --- src/app/trading-apps/page.tsx | 108 +++++++++++++--------------------- 1 file changed, 42 insertions(+), 66 deletions(-) diff --git a/src/app/trading-apps/page.tsx b/src/app/trading-apps/page.tsx index 80d240d9..ed7426fc 100644 --- a/src/app/trading-apps/page.tsx +++ b/src/app/trading-apps/page.tsx @@ -7,7 +7,7 @@ import { safeJsonLd, buildBreadcrumbJsonLd } from "@/lib/jsonld"; import { SITE } from "@/data/site"; const DESCRIPTION = - "Live benchmarks for Solana trading platforms and Telegram bots — volume, fees, unique swap transactions, and app store ratings."; + "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", @@ -27,6 +27,9 @@ const BENCH_SLUGS = [ "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" }, @@ -34,24 +37,20 @@ const PLATFORMS = [ { slug: "fomo", name: "FOMO" }, { slug: "trojan", name: "Trojan" }, { slug: "photon", name: "Photon" }, - { slug: "bloom", name: "Bloom" }, { slug: "maestro", name: "Maestro" }, ] as const; -// Some platforms own a launchpad that runs under a different slug. -// Add the launchpad's volume to the platform's terminal volume so the -// "24h Volume" column reflects the full ecosystem (e.g. FOMO = terminal + Flap). -const LAUNCHPAD_COMPANION: Partial> = { - fomo: "flap", -}; - +// Fee rate (memecoin-platforms) removed from the comparison table: the bench +// uses different data sources per platform (Dune on-chain vs DeFiLlama off-chain +// for FOMO), and the denominator (Mobula attributed volume) is inconsistent +// across platforms. Full detail available at /benchmarks/memecoin-platforms. const COLUMNS = [ { key: "volume" as const, label: "24h Volume", bench: "solana-trading-platform-wars", fmt: fmtUSD, - tip: "Terminal routing volume + owned launchpad volume (Mobula attribution)", + 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, }, { @@ -59,7 +58,7 @@ const COLUMNS = [ label: "Swap Tx", bench: "solana-unique-traders", fmt: fmtCount, - tip: "Unique swap transactions in 24h (not unique wallets — active traders submit multiple tx/day)", + 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, }, { @@ -67,15 +66,7 @@ const COLUMNS = [ label: "Avg Trade", bench: "solana-avg-trade-size", fmt: fmtUSD, - tip: "Average swap size in USD", - higherBetter: false, - }, - { - key: "feeRate" as const, - label: "Fee Rate", - bench: "memecoin-platforms", - fmt: fmtPct, - tip: "Observed take rate: on-chain fee revenue ÷ total attributed volume (lower bound — platforms with fee-exempt volume show lower rates)", + 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: false, }, { @@ -83,7 +74,7 @@ const COLUMNS = [ label: "App Rating", bench: "app-store-ratings", fmt: fmtRating, - tip: "Apple App Store rating (out of 5)", + tip: "Apple App Store all-time average rating. Axiom, Trojan, Photon and Maestro have no iOS app — they show —.", higherBetter: true, }, ] as const; @@ -113,11 +104,6 @@ function fmtCount(v: number | null): string { 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`; @@ -129,7 +115,7 @@ const GROUPS = [ items: [ { slug: "solana-trading-platform-wars", title: "Trading platform volume" }, { slug: "solana-dex-volume", title: "DEX volume & protocol revenue" }, - { slug: "solana-unique-traders", title: "Unique traders" }, + { slug: "solana-unique-traders", title: "Swap transactions" }, { slug: "solana-avg-trade-size", title: "Average trade size" }, ], }, @@ -139,9 +125,7 @@ const GROUPS = [ }, { label: "Fees", - items: [ - { slug: "memecoin-platforms", title: "Platform fee rates" }, - ], + items: [{ slug: "memecoin-platforms", title: "Platform fee rates" }], }, { label: "App store", @@ -150,21 +134,17 @@ const GROUPS = [ ] as const; export default async function TradingAppsHubPage() { - const [volBench, launchpadBench, tradersBench, tradeSizeBench, feeBench, ratingsBench] = + const [volBench, tradersBench, tradeSizeBench, ratingsBench] = await Promise.all([ getBenchmark("solana-trading-platform-wars"), - getBenchmark("solana-launchpad-wars"), getBenchmark("solana-unique-traders"), getBenchmark("solana-avg-trade-size"), - getBenchmark("memecoin-platforms"), getBenchmark("app-store-ratings"), ]); const volIdx = indexBySlug(volBench?.results); - const launchpadIdx = indexBySlug(launchpadBench?.results); const tradersIdx = indexBySlug(tradersBench?.results); const tradeSizeIdx = indexBySlug(tradeSizeBench?.results); - const feeIdx = indexBySlug(feeBench?.results); const ratingIdx = indexBySlug(ratingsBench?.results); type Row = { @@ -173,26 +153,17 @@ export default async function TradingAppsHubPage() { volume: number | null; traders: number | null; tradeSize: number | null; - feeRate: number | null; rating: number | null; }; - const matrix: Row[] = PLATFORMS.map((p) => { - const termVol = volIdx[p.slug] ?? null; - const companionSlug = LAUNCHPAD_COMPANION[p.slug]; - const lpVol = companionSlug ? (launchpadIdx[companionSlug] ?? null) : null; - const volume = - termVol !== null || lpVol !== null ? (termVol ?? 0) + (lpVol ?? 0) : null; - return { - slug: p.slug, - name: p.name, - volume, - 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)); + 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, + 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); @@ -206,10 +177,10 @@ export default async function TradingAppsHubPage() { } const topVolumeRow = matrix.reduce( - (best, row) => ((row.volume ?? -1) > (best.volume ?? -1) ? row : best), + (b, row) => ((row.volume ?? -1) > (b.volume ?? -1) ? row : b), matrix[0], ); - const topRating = ratingsBench?.results.find((r) => + const topRating = ratingsBench?.results.find((r: ProviderResult) => PLATFORMS.some((p) => p.slug === r.slug), ); @@ -266,8 +237,8 @@ export default async function TradingAppsHubPage() {

{PLATFORMS.length} platforms measured across {BENCH_SLUGS.length}{" "} - independent benchmarks: volume, swap transactions, average trade size, fee - rates, and app store ratings. Live data, no marketing claims. + independent benchmarks: volume, swap transactions, average trade size, + fee rates, and app store ratings. Live data, no marketing claims.

@@ -302,7 +273,7 @@ export default async function TradingAppsHubPage() { Platform comparison

- +
@@ -375,7 +346,7 @@ export default async function TradingAppsHubPage() {

Best value per column highlighted in green. Sorted by 24h volume. - Data refreshes every 60 s. + Hover column headers for methodology notes. Data refreshes every 60 s.

@@ -393,7 +364,7 @@ export default async function TradingAppsHubPage() { {group.label}

- {group.items.map((item, i) => ( + {group.items.map((item: { slug: string; title: string }, i: number) => (
{i > 0 &&
}

- Volume combines terminal routing volume (Mobula lighthouse byPlatform) - with owned launchpad volume where applicable (e.g. FOMO includes Flap). - Swap transaction counts are from Dune Analytics on-chain data. - Fee rates compare fee-wallet inflows to attributed volume. - App store ratings are fetched from the Apple App Store API. - All harnesses are open source on{" "} + Volume via Mobula lighthouse: pump.fun uses bonding-curve launchpad + attribution; terminals use referral-tag attribution — not directly + comparable across the two groups. Swap transaction counts from Dune + Analytics (pump.fun: dex-level; terminals: fee-wallet detection). + Average trade size = volume ÷ trade count, includes bots and MEV. + Fee rates available in the dedicated{" "} + + fee rates bench + + . App store ratings from the Apple iTunes lookup API. All harnesses + open source on{" "} GitHub - . Data released under{" "} + . Data under{" "} Date: Wed, 19 Aug 2026 12:45:57 +0200 Subject: [PATCH 3/7] fix: restore fee rate column with correct metric + fix prometheus scrape for memecoin-platforms --- src/app/trading-apps/page.tsx | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/app/trading-apps/page.tsx b/src/app/trading-apps/page.tsx index ed7426fc..95fdf542 100644 --- a/src/app/trading-apps/page.tsx +++ b/src/app/trading-apps/page.tsx @@ -40,10 +40,6 @@ const PLATFORMS = [ { slug: "maestro", name: "Maestro" }, ] as const; -// Fee rate (memecoin-platforms) removed from the comparison table: the bench -// uses different data sources per platform (Dune on-chain vs DeFiLlama off-chain -// for FOMO), and the denominator (Mobula attributed volume) is inconsistent -// across platforms. Full detail available at /benchmarks/memecoin-platforms. const COLUMNS = [ { key: "volume" as const, @@ -69,6 +65,14 @@ const COLUMNS = [ 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: false, }, + { + 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", @@ -104,6 +108,11 @@ function fmtCount(v: number | null): string { 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`; @@ -134,17 +143,19 @@ const GROUPS = [ ] as const; export default async function TradingAppsHubPage() { - const [volBench, tradersBench, tradeSizeBench, ratingsBench] = + 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 = { @@ -153,6 +164,7 @@ export default async function TradingAppsHubPage() { volume: number | null; traders: number | null; tradeSize: number | null; + feeRate: number | null; rating: number | null; }; @@ -162,6 +174,7 @@ export default async function TradingAppsHubPage() { 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)); From fe138ca7209c7e26e15b1c7f3a39a3cf7b058577 Mon Sep 17 00:00:00 2001 From: Florent Tapponnier <160007691+Flotapponnier@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:48:02 +0200 Subject: [PATCH 4/7] fix: update methodology footer for fee rate --- src/app/trading-apps/page.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/app/trading-apps/page.tsx b/src/app/trading-apps/page.tsx index 95fdf542..a8bd3716 100644 --- a/src/app/trading-apps/page.tsx +++ b/src/app/trading-apps/page.tsx @@ -425,12 +425,9 @@ export default async function TradingAppsHubPage() { comparable across the two groups. Swap transaction counts from Dune Analytics (pump.fun: dex-level; terminals: fee-wallet detection). Average trade size = volume ÷ trade count, includes bots and MEV. - Fee rates available in the dedicated{" "} - - fee rates bench - - . App store ratings from the Apple iTunes lookup API. All harnesses - open source on{" "} + Fee rate = on-chain fee revenue ÷ fee-paying volume (Dune tx join); + FOMO via DeFiLlama. App store ratings from the Apple iTunes lookup API. + All harnesses open source on{" "} Date: Wed, 19 Aug 2026 13:23:44 +0200 Subject: [PATCH 5/7] fix: higherBetter true for avg trade size column --- src/app/trading-apps/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/trading-apps/page.tsx b/src/app/trading-apps/page.tsx index a8bd3716..ea76cd87 100644 --- a/src/app/trading-apps/page.tsx +++ b/src/app/trading-apps/page.tsx @@ -63,7 +63,7 @@ const COLUMNS = [ 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: false, + higherBetter: true, }, { key: "feeRate" as const, From b4cd1f4479fd9788938b668d6562fc627f0fd381 Mon Sep 17 00:00:00 2001 From: Florent Tapponnier <160007691+Flotapponnier@users.noreply.github.com> Date: Wed, 19 Aug 2026 15:59:46 +0200 Subject: [PATCH 6/7] fix(rpc): replace Railway-blocked thirdweb/ecadinfra with working providers Tezos: ecadinfra (unresponsive) -> smartpy (mainnet.smartpy.io) Merlin: thirdweb (blocked) -> blockpi (merlin.blockpi.network) Viction: thirdweb (blocked) -> viction-rpc2 (rpc2.viction.xyz) ThunderCore: thirdweb (blocked) -> thundertoken (mainnet-rpc.thundertoken.net) OKTC: thirdweb (blocked) -> 1rpc (1rpc.io/oktc) Updates config.go, 5 benchmark YAMLs, provider-registry, brand colors, logo aliases. --- benchmarks/merlin-rpc.yml | 40 +++++++++---------- benchmarks/oktc-rpc.yml | 40 +++++++++---------- benchmarks/tezos-rpc.yml | 40 +++++++++---------- benchmarks/thundercore-rpc.yml | 40 +++++++++---------- benchmarks/viction-rpc.yml | 40 +++++++++---------- .../rpc-capabilities/cmd/script/config.go | 12 +++--- src/data/provider-registry.ts | 26 ++++++++++++ src/lib/brand.ts | 4 ++ src/lib/logo-manifest.ts | 4 +- 9 files changed, 139 insertions(+), 107 deletions(-) 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/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/data/provider-registry.ts b/src/data/provider-registry.ts index 84c9bcda..3e6ecbf1 100644 --- a/src/data/provider-registry.ts +++ b/src/data/provider-registry.ts @@ -2478,6 +2478,12 @@ export const PROVIDER_REGISTRY: Record = { "Merlin Chain official public EVM RPC node (rpc.merlinchain.io). Provides standard Ethereum JSON-RPC for the Merlin Chain Bitcoin L2, no API key required.", twitter: "@MerlinLayer2", }, + blockpi: { + url: "https://blockpi.io", + description: + "BlockPI multi-chain RPC provider offering public keyless endpoints across many EVM chains. Merlin Chain public endpoint: merlin.blockpi.network/v1/rpc/public.", + twitter: "@RealBlockPI", + }, // ─── Viction providers (bench 229) ──────────────────────────── "viction-official": { @@ -2486,6 +2492,12 @@ export const PROVIDER_REGISTRY: Record = { "Viction (formerly TomoChain) official public EVM RPC node (rpc.viction.xyz). Provides standard Ethereum JSON-RPC for the Viction L1, no API key required.", twitter: "@BuildOnViction", }, + "viction-rpc2": { + url: "https://viction.xyz", + description: + "Viction secondary public EVM RPC node (rpc2.viction.xyz). Redundant endpoint operated by the Viction foundation, no API key required.", + twitter: "@BuildOnViction", + }, // ─── ThunderCore providers (bench 230) ──────────────────────── "thundercore-official": { @@ -2494,6 +2506,20 @@ export const PROVIDER_REGISTRY: Record = { "ThunderCore official public EVM RPC node (mainnet-rpc.thundercore.com). Provides standard Ethereum JSON-RPC for ThunderCore mainnet, no API key required.", twitter: "@ThunderProtocol", }, + thundertoken: { + url: "https://www.thundercore.com", + description: + "ThunderToken public EVM RPC node (mainnet-rpc.thundertoken.net). Alternative keyless endpoint for ThunderCore mainnet operated by the ThunderToken project.", + twitter: "@ThunderProtocol", + }, + + // ─── Tezos providers (bench 222) ──────────────────────────── + smartpy: { + url: "https://smartpy.io", + description: + "SmartPy public Tezos mainnet RPC node (mainnet.smartpy.io). Open-source Tezos development toolkit; the public node is operated alongside their IDE and testing tools.", + twitter: "@SmartPy_io", + }, // ─── OKTC providers (bench 231) ─────────────────────────────── "oktc-official": { diff --git a/src/lib/brand.ts b/src/lib/brand.ts index 568b009f..fff67654 100644 --- a/src/lib/brand.ts +++ b/src/lib/brand.ts @@ -159,8 +159,12 @@ const BRANDS: Record = { "neon-p2p": { color: "#9333EA" }, // neon purple everstake: { color: "#00D4AA" }, // everstake teal "merlin-official": { color: "#F7A400" }, // merlin amber + blockpi: { color: "#3D5CFF" }, // blockpi blue "viction-official": { color: "#1D61DE" }, // viction blue + "viction-rpc2": { color: "#1D61DE" }, // viction blue (secondary node) "thundercore-official": { color: "#002868", dark: true }, // thundercore dark + thundertoken: { color: "#002868", dark: true }, // thundercore dark (thundertoken node) + smartpy: { color: "#2C7DF7" }, // smartpy blue (tezos ecosystem) "oktc-official": { color: "#101010", dark: true }, // okx dark // ─── Stellar ecosystem providers (bench № 210) ─── diff --git a/src/lib/logo-manifest.ts b/src/lib/logo-manifest.ts index 765c914e..fe0fd3d9 100644 --- a/src/lib/logo-manifest.ts +++ b/src/lib/logo-manifest.ts @@ -719,7 +719,7 @@ const ALIASES: Record = { "ecadinfra": "tezos", "tzbeta": "tezos", "tzkt": "tezos", - "greymass": "eos", + // greymass is on both EOS and WAX — no alias so it shows brand chip on both "eosnation": "eos", "alohaeos": "eos", "vechain-foundation": "vechain", @@ -733,7 +733,9 @@ const ALIASES: Record = { "neon-p2p": "neon", "merlin-official": "merlin", "viction-official": "viction", + "viction-rpc2": "viction", "thundercore-official": "thundercore", + thundertoken: "thundercore", "oktc-official": "oktc", }; From e8f894626a88db8da660c3cb5bf40451fce3f359 Mon Sep 17 00:00:00 2001 From: Florent Tapponnier <160007691+Flotapponnier@users.noreply.github.com> Date: Wed, 19 Aug 2026 16:00:19 +0200 Subject: [PATCH 7/7] fix(waves): rename WavesExchange provider to Waves Exchange Node --- benchmarks/waves-rpc.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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"})