From 070143ba9a3c7d92ba2beaaee34918bccbd4a7f6 Mon Sep 17 00:00:00 2001
From: Florent Tapponnier <160007691+Flotapponnier@users.noreply.github.com>
Date: Sat, 15 Aug 2026 11:34:32 +0200
Subject: [PATCH 1/6] feat: inline Solana exec quality into /apps hub, remove
/apps/exec subpage
---
src/app/apps/exec/page.tsx | 77 --------------------------------------
src/app/apps/page.tsx | 36 ++++++++++++++----
2 files changed, 29 insertions(+), 84 deletions(-)
delete mode 100644 src/app/apps/exec/page.tsx
diff --git a/src/app/apps/exec/page.tsx b/src/app/apps/exec/page.tsx
deleted file mode 100644
index bc5cb0ec..00000000
--- a/src/app/apps/exec/page.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import type { Metadata } from "next";
-import { pageMetadata } from "@/lib/page-metadata";
-import { safeJsonLd, buildBreadcrumbJsonLd } from "@/lib/jsonld";
-import { SITE } from "@/data/site";
-import { fetchExecLeaderboard } from "@/lib/solana-exec";
-import { SolanaExecTable } from "@/components/solana-exec-table";
-
-const DESCRIPTION =
- "Solana trading platform execution quality: priority fees, Jito bundle rates, and platform fees — measured passively from on-chain data. Updated every hour.";
-
-export const metadata: Metadata = pageMetadata({
- path: "/apps/exec",
- title: "Solana Execution Quality — pump.fun, FOMO, Axiom, GMGN | OpenChainBench",
- description: DESCRIPTION,
-});
-
-export const revalidate = 60;
-
-export default async function SolanaExecPage() {
- const data = await fetchExecLeaderboard();
-
- const breadcrumb = {
- "@context": "https://schema.org",
- ...buildBreadcrumbJsonLd([
- { name: "Home", item: SITE.url },
- { name: "Apps", item: `${SITE.url}/apps` },
- { name: "Solana Execution", item: `${SITE.url}/apps/exec` },
- ]),
- };
-
- return (
-
-
-
-
- Solana execution quality.
-
-
- {DESCRIPTION}
-
-
-
-
-
-
-
-
- Priority fee = total transaction fee minus the 5 000-lamport base fee
- per signature. Paid by the user to compete for block space.
-
-
- CU price = priority fee ÷ compute units consumed (microlamports/CU).
- p50/p95 shows median and tail pressure on each platform.
-
-
- Jito rate = fraction of transactions that include a SOL tip to one of
- the 8 official Jito tip accounts. Higher = more MEV-sensitive routing.
-
-
- Platform fee = average SOL transferred to the platform's fee account
- per transaction. For pump.fun this is the 1% AMM fee recipient.
-
-
- Source: Helius enhanced transaction API. Passive monitoring via fee-account attribution
- — no synthetic trades, no on-chain footprint.
-
-
-
- );
-}
diff --git a/src/app/apps/page.tsx b/src/app/apps/page.tsx
index c7b580ca..f25aafa3 100644
--- a/src/app/apps/page.tsx
+++ b/src/app/apps/page.tsx
@@ -10,6 +10,7 @@ import { TRADING_APPS } from "@/lib/trading-apps-config";
import { fetchDeFiLlamaData } from "@/lib/defillama";
import { TradingAppsLeaderboard, type UnifiedAppRow } from "@/components/trading-apps-leaderboard";
import { RevenueSummary } from "@/components/revenue-summary";
+import { SolanaExecTable } from "@/components/solana-exec-table";
import Link from "next/link";
const DESCRIPTION =
@@ -38,7 +39,6 @@ export default async function AppsHubPage() {
fetchDeFiLlamaData(dlSlugMap),
]);
- // Market share = each platform's DL 24h fees / cohort total (active only)
const activeDlTotal = TRADING_APPS.filter((a) => !a.inactive && a.defillamaSlug)
.reduce((sum, a) => sum + (dlData.get(a.id)?.total24h ?? 0), 0);
@@ -69,7 +69,6 @@ export default async function AppsHubPage() {
const wData = solRow.windows[w];
if (wData) {
if (meta.solanaFeeIsUSDC) {
- // Fees collected in USDC (6 dec): raw units / 1e6 = USD directly
solanaFees = wData.sumPlatformFeeLamports / 1e6;
} else if (solPrice !== null) {
solanaFees = wData.sumPlatformFeeLamports / 1e9 * solPrice;
@@ -77,14 +76,11 @@ export default async function AppsHubPage() {
}
}
- // FOMO: supplement on-chain fees with off-chain relay fees from Dune
- // (relay accounts for ~96% of FOMO's actual revenue)
if (meta.id === "fomo" && fomoRelay) {
const relayFee = w === "24h" ? fomoRelay.fees24h : w === "7d" ? fomoRelay.fees7d : fomoRelay.fees30d;
solanaFees = (solanaFees ?? 0) + relayFee;
}
- // EVM: 24h adds native ETH/BNB in USD; 7d/30d stable only (no historical prices).
const evmStable = (chain: typeof ethChain) =>
!chain ? null : w === "24h" ? chain.stable24h : w === "7d" ? chain.stable7d : chain.stable30d;
const evmNative = (chain: typeof ethChain) =>
@@ -165,6 +161,32 @@ export default async function AppsHubPage() {
)}
+
+
Solana execution quality
+
+ Priority fees, Jito bundle rates, and platform fees per transaction — measured passively from on-chain data.
+
+
+
+
+ Priority fee = total tx fee minus the 5 000-lamport base fee per signature.
+
+
+ CU price = priority fee ÷ compute units consumed (microlamports/CU). p50/p95 shows median and tail pressure.
+
+
+ Jito rate = fraction of transactions tipping a Jito tip account. Higher = more MEV-sensitive routing.
+
+
+ Platform fee = avg SOL to the platform fee account per transaction.
+ Source: Helius enhanced transaction API. No synthetic trades, no on-chain footprint.
+
+
+
+
Related benchmarks
@@ -187,8 +209,8 @@ export default async function AppsHubPage() {
>
⚡
-
Execution Quality
-
Priority fees, Jito rates, platform fees
+
Execution Quality Bench
+
Priority fees, Jito rates, platform fees — full dataset
From 292faaa2783b50163cd0422033ab8617f24f022c Mon Sep 17 00:00:00 2001
From: Florent Tapponnier <160007691+Flotapponnier@users.noreply.github.com>
Date: Sat, 15 Aug 2026 11:59:30 +0200
Subject: [PATCH 2/6] fix: guard data.platforms spread in ExecBenchTable
against null
---
src/components/exec-bench-table.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/exec-bench-table.tsx b/src/components/exec-bench-table.tsx
index cb347233..ac95f11e 100644
--- a/src/components/exec-bench-table.tsx
+++ b/src/components/exec-bench-table.tsx
@@ -42,7 +42,7 @@ export function ExecBenchTable({
);
}
- const sorted = [...data.platforms].sort(
+ const sorted = [...(data.platforms ?? [])].sort(
(a, b) =>
(b.windows[win]?.txCount ?? 0) - (a.windows[win]?.txCount ?? 0),
);
From f4bff2b1aa154127f23b4d5d442933c865054a22 Mon Sep 17 00:00:00 2001
From: Florent Tapponnier <160007691+Flotapponnier@users.noreply.github.com>
Date: Sat, 15 Aug 2026 12:39:10 +0200
Subject: [PATCH 3/6] fix: remove emojis and Solana exec section from /apps hub
---
src/app/apps/page.tsx | 48 +++++++++----------------------------------
1 file changed, 10 insertions(+), 38 deletions(-)
diff --git a/src/app/apps/page.tsx b/src/app/apps/page.tsx
index f25aafa3..1e8c19c7 100644
--- a/src/app/apps/page.tsx
+++ b/src/app/apps/page.tsx
@@ -10,7 +10,6 @@ import { TRADING_APPS } from "@/lib/trading-apps-config";
import { fetchDeFiLlamaData } from "@/lib/defillama";
import { TradingAppsLeaderboard, type UnifiedAppRow } from "@/components/trading-apps-leaderboard";
import { RevenueSummary } from "@/components/revenue-summary";
-import { SolanaExecTable } from "@/components/solana-exec-table";
import Link from "next/link";
const DESCRIPTION =
@@ -161,58 +160,31 @@ export default async function AppsHubPage() {
)}
-
-
Solana execution quality
-
- Priority fees, Jito bundle rates, and platform fees per transaction — measured passively from on-chain data.
-
-
-
-
- Priority fee = total tx fee minus the 5 000-lamport base fee per signature.
-
-
- CU price = priority fee ÷ compute units consumed (microlamports/CU). p50/p95 shows median and tail pressure.
-
-
- Jito rate = fraction of transactions tipping a Jito tip account. Higher = more MEV-sensitive routing.
-
-
- Platform fee = avg SOL to the platform fee account per transaction.
- Source: Helius enhanced transaction API. No synthetic trades, no on-chain footprint.
-
-
-
-
Related benchmarks
-
+
-
⭐
-
App Store Ratings
-
iOS ratings for crypto trading apps, live
+
App Store Ratings
+
iOS ratings for crypto trading apps, live
-
+
+
- ⚡
-
Execution Quality Bench
-
Priority fees, Jito rates, platform fees — full dataset
+
Execution Quality
+
Priority fees, Jito rates, platform fees
-
+
From eea1f37accceba684c97e21c2d3d69fe93f4f01e Mon Sep 17 00:00:00 2001
From: Florent Tapponnier <160007691+Flotapponnier@users.noreply.github.com>
Date: Sat, 15 Aug 2026 13:06:27 +0200
Subject: [PATCH 4/6] =?UTF-8?q?remove=20/apps=20page,=20libs,=20components?=
=?UTF-8?q?=20=E2=80=94=20redirect=20/apps=20to=20/benchmarks?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
next.config.ts | 7 +-
src/app/apps/page.tsx | 195 ---------
.../benchmarks/trading-app-execution/page.tsx | 4 +-
src/components/revenue-summary.tsx | 128 ------
src/components/solana-exec-table.tsx | 156 --------
src/components/trading-apps-leaderboard.tsx | 370 ------------------
src/lib/defillama.ts | 76 ----
src/lib/dune.ts | 39 --
src/lib/evm-exec.ts | 61 ---
src/lib/sol-price.ts | 13 -
src/lib/trading-apps-config.ts | 36 --
11 files changed, 8 insertions(+), 1077 deletions(-)
delete mode 100644 src/app/apps/page.tsx
delete mode 100644 src/components/revenue-summary.tsx
delete mode 100644 src/components/solana-exec-table.tsx
delete mode 100644 src/components/trading-apps-leaderboard.tsx
delete mode 100644 src/lib/defillama.ts
delete mode 100644 src/lib/dune.ts
delete mode 100644 src/lib/evm-exec.ts
delete mode 100644 src/lib/sol-price.ts
delete mode 100644 src/lib/trading-apps-config.ts
diff --git a/next.config.ts b/next.config.ts
index 3e70417c..be6528ee 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -264,7 +264,12 @@ const nextConfig: NextConfig = {
},
{
source: "/apps/exec",
- destination: "/apps",
+ destination: "/benchmarks/trading-app-execution",
+ permanent: true,
+ },
+ {
+ source: "/apps",
+ destination: "/benchmarks",
permanent: true,
},
...chainRedirects,
diff --git a/src/app/apps/page.tsx b/src/app/apps/page.tsx
deleted file mode 100644
index 1e8c19c7..00000000
--- a/src/app/apps/page.tsx
+++ /dev/null
@@ -1,195 +0,0 @@
-import type { Metadata } from "next";
-import { pageMetadata } from "@/lib/page-metadata";
-import { safeJsonLd, buildBreadcrumbJsonLd } from "@/lib/jsonld";
-import { SITE } from "@/data/site";
-import { fetchEVMRevenue } from "@/lib/evm-exec";
-import { fetchExecLeaderboard } from "@/lib/solana-exec";
-import { fetchSolPrice } from "@/lib/sol-price";
-import { fetchFOMORelayFees } from "@/lib/dune";
-import { TRADING_APPS } from "@/lib/trading-apps-config";
-import { fetchDeFiLlamaData } from "@/lib/defillama";
-import { TradingAppsLeaderboard, type UnifiedAppRow } from "@/components/trading-apps-leaderboard";
-import { RevenueSummary } from "@/components/revenue-summary";
-import Link from "next/link";
-
-const DESCRIPTION =
- "Protocol fees collected by trading apps and meme trading terminals — Solana, Ethereum, BSC. On-chain data, updated every 5 min.";
-
-export const metadata: Metadata = pageMetadata({
- path: "/apps",
- title: "Trading App Revenue — pump.fun, Axiom, GMGN, BullX | OpenChainBench",
- description: DESCRIPTION,
-});
-
-export const revalidate = 300;
-
-const WINDOWS = ["24h", "7d", "30d"] as const;
-
-export default async function AppsHubPage() {
- const dlSlugMap = Object.fromEntries(
- TRADING_APPS.filter((a) => a.defillamaSlug).map((a) => [a.id, a.defillamaSlug!])
- );
-
- const [evmData, solanaData, solPrice, fomoRelay, dlData] = await Promise.all([
- fetchEVMRevenue(),
- fetchExecLeaderboard(),
- fetchSolPrice(),
- fetchFOMORelayFees(),
- fetchDeFiLlamaData(dlSlugMap),
- ]);
-
- const activeDlTotal = TRADING_APPS.filter((a) => !a.inactive && a.defillamaSlug)
- .reduce((sum, a) => sum + (dlData.get(a.id)?.total24h ?? 0), 0);
-
- const evmByPlatform = new Map(
- (evmData?.platforms ?? []).map((p) => [p.platform, p])
- );
-
- const solanaByPlatform = new Map(
- (solanaData?.platforms ?? []).map((p) => [p.platform, p])
- );
-
- const rows: UnifiedAppRow[] = TRADING_APPS.map((meta) => {
- const evmRow = meta.evmKey ? evmByPlatform.get(meta.evmKey) : undefined;
- const solRow = meta.solanaKey ? solanaByPlatform.get(meta.solanaKey) : undefined;
-
- const rhRow = meta.robinhoodKey ? evmByPlatform.get(meta.robinhoodKey) : undefined;
-
- const ethChain = evmRow?.chains["ethereum"];
- const bscChain = evmRow?.chains["bsc"];
- const baseChain = evmRow?.chains["base"];
- const rhChain = rhRow?.chains["robinhood"];
-
- const windows: UnifiedAppRow["windows"] = {};
-
- for (const w of WINDOWS) {
- let solanaFees: number | null = null;
- if (solRow) {
- const wData = solRow.windows[w];
- if (wData) {
- if (meta.solanaFeeIsUSDC) {
- solanaFees = wData.sumPlatformFeeLamports / 1e6;
- } else if (solPrice !== null) {
- solanaFees = wData.sumPlatformFeeLamports / 1e9 * solPrice;
- }
- }
- }
-
- if (meta.id === "fomo" && fomoRelay) {
- const relayFee = w === "24h" ? fomoRelay.fees24h : w === "7d" ? fomoRelay.fees7d : fomoRelay.fees30d;
- solanaFees = (solanaFees ?? 0) + relayFee;
- }
-
- const evmStable = (chain: typeof ethChain) =>
- !chain ? null : w === "24h" ? chain.stable24h : w === "7d" ? chain.stable7d : chain.stable30d;
- const evmNative = (chain: typeof ethChain) =>
- w === "24h" && chain ? (chain.native?.usd ?? 0) : 0;
-
- const ethFees = ethChain ? evmStable(ethChain)! + evmNative(ethChain) : null;
- const bscFees = bscChain ? evmStable(bscChain)! + evmNative(bscChain) : null;
- const baseFees = baseChain ? evmStable(baseChain)! + evmNative(baseChain) : null;
- const rhFees = rhChain ? evmStable(rhChain)! + evmNative(rhChain) : null;
- const evmTotal = (ethFees ?? 0) + (bscFees ?? 0) + (baseFees ?? 0) + (rhFees ?? 0);
-
- windows[w] = {
- solana: solanaFees,
- ethereum: ethFees,
- bsc: bscFees,
- base: baseFees,
- robinhood: rhFees,
- total: (solanaFees ?? 0) + evmTotal,
- };
- }
-
- const dl = dlData.get(meta.id) ?? null;
- const marketSharePct = dl && activeDlTotal > 0 && !meta.inactive
- ? (dl.total24h / activeDlTotal) * 100
- : null;
-
- return {
- meta,
- windows,
- stableOnly: {
- ethereum: ethChain?.coverage === "stable-only",
- bsc: bscChain?.coverage === "stable-only",
- base: baseChain?.coverage === "stable-only",
- robinhood: rhChain?.coverage === "stable-only",
- },
- dl,
- marketSharePct,
- };
- });
-
- const updatedAt = evmData?.updatedAt ?? solanaData?.updatedAt ?? null;
-
- const breadcrumb = {
- "@context": "https://schema.org",
- ...buildBreadcrumbJsonLd([
- { name: "Home", item: SITE.url },
- { name: "Apps", item: `${SITE.url}/apps` },
- ]),
- };
-
- return (
-
-
-
-
- Trading app revenue.
-
-
- {DESCRIPTION}
-
-
-
-
-
-
-
- Solana fees = sum(platform_fee) / 1e9 × SOL price .
- EVM fees = stable (USDC/USDT) + native where traceable, always 24h.
-
-
- {evmData && evmData.platforms.length > 0 && (
-
-
-
- )}
-
-
-
Related benchmarks
-
-
-
- App Store Ratings
- iOS ratings for crypto trading apps, live
-
-
-
-
-
-
-
-
- Execution Quality
- Priority fees, Jito rates, platform fees
-
-
-
-
-
-
-
-
- );
-}
diff --git a/src/app/benchmarks/trading-app-execution/page.tsx b/src/app/benchmarks/trading-app-execution/page.tsx
index babfe560..58d2415a 100644
--- a/src/app/benchmarks/trading-app-execution/page.tsx
+++ b/src/app/benchmarks/trading-app-execution/page.tsx
@@ -158,10 +158,10 @@ export default async function TradingAppExecutionPage() {
- Back to trading app revenue
+ Back to benchmarks
diff --git a/src/components/revenue-summary.tsx b/src/components/revenue-summary.tsx
deleted file mode 100644
index bca8351a..00000000
--- a/src/components/revenue-summary.tsx
+++ /dev/null
@@ -1,128 +0,0 @@
-"use client";
-
-import type { EVMPlatformRow, EVMRevenueResponse } from "@/lib/evm-exec";
-import {
- EVM_CHAINS,
- CHAIN_LABELS,
- fmtUSD,
- totalRevenue24h,
-} from "@/lib/evm-exec";
-import { PLATFORM_DISPLAY } from "@/lib/solana-exec";
-import Image from "next/image";
-import { logoPath } from "@/lib/logo-manifest";
-
-const LOGO_KEY: Record = {
- gmgn: "gmgn",
-};
-
-function Dash() {
- return — ;
-}
-
-function ChainCell({ row, chain }: { row: EVMPlatformRow; chain: string }) {
- const data = row.chains[chain];
- if (!data) return ;
-
- const usd = data.stable24h + (data.native?.usd ?? 0);
- const isPartial = data.coverage === "stable-only";
-
- return (
-
- 0 ? "text-ink font-semibold" : "text-ink-muted"}>
- {fmtUSD(usd)}
- {isPartial && usd > 0 && (
- °
- )}
-
-
- );
-}
-
-export function RevenueSummary({
- evm,
-}: {
- evm: EVMRevenueResponse | null;
-}) {
- if (!evm || evm.platforms.length === 0) return null;
-
- const sorted = [...evm.platforms].sort(
- (a, b) => totalRevenue24h(b) - totalRevenue24h(a),
- );
-
- return (
-
-
-
Revenue — last 24h
- {evm.updatedAt && (
-
- {new Date(evm.updatedAt).toLocaleString()}
-
- )}
-
-
-
-
-
-
-
- Platform
-
- {EVM_CHAINS.map((chain) => (
-
- {CHAIN_LABELS[chain]}
-
- ))}
-
- Total
-
-
-
-
- {sorted.map((row) => {
- const logo = logoPath(LOGO_KEY[row.platform] ?? row.platform);
- const total = totalRevenue24h(row);
-
- return (
-
-
-
- {logo && (
-
- )}
-
- {PLATFORM_DISPLAY[row.platform] ?? row.platform}
-
-
-
- {EVM_CHAINS.map((chain) => (
-
- ))}
-
- {fmtUSD(total)}
-
-
- );
- })}
-
-
-
-
-
- ° USDC only — native ETH not tracked on Base (no free trace API).
- Solana revenue column pending exact measurement.
-
-
- );
-}
diff --git a/src/components/solana-exec-table.tsx b/src/components/solana-exec-table.tsx
deleted file mode 100644
index d6cce78c..00000000
--- a/src/components/solana-exec-table.tsx
+++ /dev/null
@@ -1,156 +0,0 @@
-"use client";
-
-import { useState } from "react";
-import { logoPath } from "@/lib/logo-manifest";
-import Image from "next/image";
-import type { ExecPlatformRow, ExecWindowStats } from "@/lib/solana-exec";
-import { PLATFORM_DISPLAY, fmtCUPrice, lamportsToSOL } from "@/lib/solana-exec";
-
-const WINDOWS = [
- { key: "24h", label: "24h" },
- { key: "7d", label: "7d" },
- { key: "30d", label: "30d" },
-];
-
-const LOGO_KEY: Record = {
- "pump.fun": "pump-portal", // closest available logo
- "fomo": "fomo",
- "axiom": "axiom",
- "gmgn": "gmgn",
-};
-
-function Dash() {
- return — ;
-}
-
-function fmtCount(n: number): string {
- if (n === 0) return "—";
- if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
- if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
- return String(n);
-}
-
-function fmtPct(r: number): string {
- if (r === 0) return "—";
- return `${(r * 100).toFixed(1)}%`;
-}
-
-export function SolanaExecTable({
- platforms,
- updatedAt,
-}: {
- platforms: ExecPlatformRow[];
- updatedAt: string | null;
-}) {
- const [win, setWin] = useState("24h");
-
- if (platforms.length === 0) {
- return (
-
- No data yet — collector is warming up.
-
- );
- }
-
- const sorted = [...platforms].sort(
- (a, b) => (b.windows[win]?.txCount ?? 0) - (a.windows[win]?.txCount ?? 0),
- );
-
- return (
-
-
-
- {WINDOWS.map((w) => (
- setWin(w.key)}
- className={`px-3 py-2 text-sm font-mono border-b-2 transition-colors ${
- win === w.key
- ? "border-accent text-ink font-medium"
- : "border-transparent text-ink-muted hover:text-ink-soft"
- }`}
- >
- {w.label}
-
- ))}
-
- {updatedAt && (
-
- Updated {new Date(updatedAt).toLocaleString()}
-
- )}
-
-
-
-
-
-
- #
- Platform
- Txs
- Avg priority fee
- CU price p50/p95
- Jito rate
- Avg platform fee
-
-
-
- {sorted.map((p, i) => {
- const wm: ExecWindowStats | undefined = p.windows[win];
- const logo = logoPath(LOGO_KEY[p.platform] ?? p.platform);
-
- return (
-
-
- {i + 1}
-
-
-
- {logo && (
-
- )}
-
- {PLATFORM_DISPLAY[p.platform] ?? p.platform}
-
-
-
-
- {wm?.txCount ? fmtCount(wm.txCount) : }
-
-
- {wm?.avgPriorityFeeLamports
- ? `${Math.round(wm.avgPriorityFeeLamports).toLocaleString()} L`
- : }
-
-
- {wm?.p50CUPriceMicro
- ? `${fmtCUPrice(wm.p50CUPriceMicro)} / ${fmtCUPrice(wm.p95CUPriceMicro)}`
- : }
-
-
- {wm?.jitoRate != null && wm.jitoRate > 0 ? fmtPct(wm.jitoRate) : }
-
-
- {wm?.avgPlatformFeeLamports
- ? `${lamportsToSOL(wm.avgPlatformFeeLamports)} SOL`
- : }
-
-
- );
- })}
-
-
-
-
- );
-}
diff --git a/src/components/trading-apps-leaderboard.tsx b/src/components/trading-apps-leaderboard.tsx
deleted file mode 100644
index 1cba0e83..00000000
--- a/src/components/trading-apps-leaderboard.tsx
+++ /dev/null
@@ -1,370 +0,0 @@
-"use client";
-
-import Image from "next/image";
-import Link from "next/link";
-import { useState } from "react";
-import { logoPath } from "@/lib/logo-manifest";
-import type { AppMeta } from "@/lib/trading-apps-config";
-import type { DLPlatformData } from "@/lib/defillama";
-
-const NOW_MS = Date.now();
-
-type FeeWindow = {
- solana: number | null;
- ethereum: number | null;
- bsc: number | null;
- base: number | null;
- robinhood: number | null;
- total: number;
-};
-
-export type UnifiedAppRow = {
- meta: AppMeta;
- windows: Record;
- stableOnly: { ethereum: boolean; bsc: boolean; base: boolean; robinhood: boolean };
- dl: DLPlatformData | null;
- marketSharePct: number | null;
-};
-
-type TabKey = "all" | "trading-terminal" | "telegram-bot";
-type WindowKey = "24h" | "7d" | "30d";
-
-const TABS: { key: TabKey; label: string }[] = [
- { key: "all", label: "All" },
- { key: "trading-terminal", label: "Trading Terminals" },
- { key: "telegram-bot", label: "Telegram Bots" },
-];
-
-const WINDOWS: { key: WindowKey; label: string }[] = [
- { key: "24h", label: "24h" },
- { key: "7d", label: "7d" },
- { key: "30d", label: "30d" },
-];
-
-const CATEGORY_BADGE: Record = {
- "trading-terminal": "bg-orange-500/10 text-orange-400 border border-orange-500/20",
- "telegram-bot": "bg-blue-500/10 text-blue-400 border border-blue-500/20",
-};
-
-const FORM_FACTOR_ICON: Record = {
- web: "🌐",
- mobile: "📱",
- telegram: "✈️",
-};
-
-const CATEGORY_LABEL: Record = {
- "trading-terminal": "Terminal",
- "telegram-bot": "Bot",
-};
-
-function fmtUSD(n: number | null): string {
- if (n === null || n === 0) return "—";
- if (n >= 1_000_000) return `$${(n / 1_000_000).toFixed(2)}M`;
- if (n >= 1_000) return `$${(n / 1_000).toFixed(1)}K`;
- return `$${n.toFixed(0)}`;
-}
-
-function Dash() {
- return — ;
-}
-
-type ChainCellProps = {
- value: number | null;
- stableOnly?: boolean;
- hideBelow?: "md" | "lg";
-};
-
-const HIDE_CLASS: Record, string> = {
- md: "hidden md:table-cell",
- lg: "hidden lg:table-cell",
-};
-
-function ChainCell({ value, stableOnly, hideBelow }: ChainCellProps) {
- const hide = hideBelow ? ` ${HIDE_CLASS[hideBelow]}` : "";
- if (value === null) {
- return (
-
-
-
- );
- }
- return (
-
- 0 ? "text-ink" : "text-ink-muted"}>
- {fmtUSD(value)}
- {stableOnly && value > 0 && (
- °
- )}
-
-
- );
-}
-
-export function TradingAppsLeaderboard({
- rows,
- updatedAt,
- fomoLatestDate,
- fomoRelayAvailable,
-}: {
- rows: UnifiedAppRow[];
- updatedAt: string | null;
- fomoLatestDate: string | null;
- fomoRelayAvailable: boolean;
- activeDlTotal: number;
-}) {
- const [tab, setTab] = useState("all");
- const [window, setWindow] = useState("24h");
-
- const filtered = tab === "all" ? rows : rows.filter((r) => r.meta.category === tab);
- const sorted = [...filtered].sort((a, b) => {
- if (a.meta.inactive && !b.meta.inactive) return 1;
- if (!a.meta.inactive && b.meta.inactive) return -1;
- return (b.windows[window]?.total ?? 0) - (a.windows[window]?.total ?? 0);
- });
-
- const hasStableOnly = sorted.some(
- (r) => r.stableOnly.ethereum || r.stableOnly.bsc || r.stableOnly.base || r.stableOnly.robinhood
- );
-
- // Any active platform with >50% daily swing makes Share numbers unreliable for the whole cohort
- const hasExtremeMove = sorted.some(
- (r) => !r.meta.inactive && r.dl && Math.abs(r.dl.change_1d ?? 0) > 50
- );
-
- return (
-
-
-
- {TABS.map((t) => (
- setTab(t.key)}
- className={`px-3 py-2 text-sm font-mono border-b-2 transition-colors ${
- tab === t.key
- ? "border-accent text-ink font-medium"
- : "border-transparent text-ink-muted hover:text-ink-soft"
- }`}
- >
- {t.label}
-
- ))}
-
-
-
- {WINDOWS.map((w) => (
- setWindow(w.key)}
- className={`px-2.5 py-1 text-xs font-mono rounded transition-colors ${
- window === w.key
- ? "bg-paper text-ink shadow-sm"
- : "text-ink-muted hover:text-ink-soft"
- }`}
- >
- {w.label}
-
- ))}
-
- {updatedAt && (
-
- {new Date(updatedAt).toLocaleString()}
-
- )}
-
-
-
-
-
-
-
- #
- App
- Type
-
-
- Solana
-
-
- ETH/BSC/Base
- DL Rev
- 50% daily swing (possible data gap)" : undefined}
- >
- Share{hasExtremeMove ? " ⚠" : ""}
-
-
- Total {window}
-
-
-
-
- {sorted.map((row, i) => {
- const { meta, dl, marketSharePct } = row;
- const fees = row.windows[window] ?? { solana: null, ethereum: null, bsc: null, base: null, robinhood: null, total: 0 };
- const logo = meta.logoKey ? logoPath(meta.logoKey) : null;
- const evmTotal = (fees.ethereum ?? 0) + (fees.bsc ?? 0) + (fees.base ?? 0) + (fees.robinhood ?? 0);
-
- return (
-
-
- {i + 1}
-
-
-
-
- {logo && (
-
- )}
-
{meta.name}
-
- {meta.inactive && (
-
- Suspended
-
- )}
- {dl?.change_1d !== null && dl?.change_1d !== undefined && !meta.inactive && dl.total24h >= 5000 && (
- (() => {
- const extreme = Math.abs(dl.change_1d) > 50;
- return (
-
= 0
- ? "text-green-400 bg-green-500/10"
- : "text-red-400 bg-red-500/10"
- }`}
- title={extreme ? "Large move — possible data ingestion gap, not verified" : "DeFiLlama revenue 24h vs prior 24h"}
- >
- {extreme ? "⚠ " : dl.change_1d >= 0 ? "+" : ""}{dl.change_1d.toFixed(1)}%
-
- );
- })()
- )}
- {meta.benchUrl && (
-
-
-
-
-
- )}
-
-
-
-
- {FORM_FACTOR_ICON[meta.formFactor]}
-
- {CATEGORY_LABEL[meta.category]}
-
-
-
-
-
- {evmTotal > 0 ? (
- {fmtUSD(evmTotal)}
- ) : — }
-
-
- {dl && !meta.inactive ? (
-
- {fmtUSD(dl.total24h)}
- {meta.defillamaScope === "venue" && (
- ²
- )}
-
- ) : — }
-
-
- {marketSharePct !== null ? (
- (() => {
- const rowExtreme = !meta.inactive && dl && Math.abs(dl.change_1d ?? 0) > 50;
- return rowExtreme ? (
- ⚠
- ) : (
-
-
-
- {marketSharePct.toFixed(1)}%
-
-
- );
- })()
- ) : — }
-
-
- {fees.total > 0 ? fmtUSD(fees.total) : }
-
-
- );
- })}
-
-
-
-
- {hasStableOnly && (
-
- ° USDC only — native ETH/BNB not traceable for this platform.
- {window !== "24h" && " EVM 7d/30d shows USDC only; native ETH/BNB added for 24h."}
-
- )}
- {!hasStableOnly && window !== "24h" && (
-
- EVM 7d/30d shows USDC only; native ETH/BNB added for 24h.
-
- )}
- {fomoRelayAvailable && window === "24h" && (
-
- FOMO 24h relay = fees since midnight UTC (calendar day), not rolling window.
-
- )}
- {!fomoRelayAvailable && (
-
- FOMO relay data unavailable — showing on-chain fees only (~4% of actual revenue).
-
- )}
-
-
- DL Rev = net revenue per DeFiLlama (fees minus referral/cashback). ² Venue-level: bonding curve + creator slice, not frontend-only.
-
-
- );
-}
-
-function FOMODataNotice({ latestDate }: { latestDate: string | null }) {
- const ageHours = latestDate
- ? (NOW_MS - new Date(latestDate).getTime()) / 3_600_000
- : 0;
- if (!latestDate || ageHours <= 36) return null;
- return (
-
- FOMO relay data last updated {Math.round(ageHours)}h ago — figures may be stale.
-
- );
-}
diff --git a/src/lib/defillama.ts b/src/lib/defillama.ts
deleted file mode 100644
index 83ffbf02..00000000
--- a/src/lib/defillama.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-// DeFiLlama fees API — slugs verified against api.llama.fi/summary/fees/{slug} (2026-08)
-
-type DLBreakdown = Record>;
-
-type DLSummary = {
- total24h: number | null;
- total7d: number | null;
- total30d: number | null;
- change_1d: number | null;
- breakdown24h: DLBreakdown | null;
-};
-
-// Chains we surface in the leaderboard (normalized to lowercase)
-const TRACKED_CHAINS = new Set(["solana", "ethereum", "bsc", "base"]);
-
-export type DLPlatformData = {
- total24h: number;
- total7d: number;
- total30d: number;
- change_1d: number | null;
- // Per-chain 24h fees in USD (keys: solana, ethereum, bsc, base)
- chain24h: Partial>;
-};
-
-/** @deprecated use DLPlatformData */
-export type DLPlatformRevenue = DLPlatformData;
-
-function extractChain24h(breakdown: DLBreakdown | null): Partial> {
- if (!breakdown) return {};
- const result: Record = {};
- for (const [rawChain, data] of Object.entries(breakdown)) {
- const norm = rawChain.toLowerCase();
- if (!TRACKED_CHAINS.has(norm)) continue;
- const amount = Object.values(data).reduce((s, v) => s + v, 0);
- if (amount > 0) result[norm] = (result[norm] ?? 0) + amount;
- }
- return result;
-}
-
-async function fetchDLSummary(slug: string): Promise {
- try {
- const res = await fetch(
- `https://api.llama.fi/summary/fees/${encodeURIComponent(slug)}?dataType=dailyRevenue`,
- { next: { revalidate: 300 } }
- );
- if (!res.ok) return null;
- return res.json() as Promise;
- } catch {
- return null;
- }
-}
-
-export async function fetchDeFiLlamaData(slugMap: Record): Promise> {
- const entries = Object.entries(slugMap);
- const responses = await Promise.all(entries.map(([, slug]) => fetchDLSummary(slug)));
-
- const result = new Map();
- for (let i = 0; i < entries.length; i++) {
- const [appId] = entries[i];
- const data = responses[i];
- if (!data) continue;
- result.set(appId, {
- total24h: data.total24h ?? 0,
- total7d: data.total7d ?? 0,
- total30d: data.total30d ?? 0,
- change_1d: data.change_1d ?? null,
- chain24h: extractChain24h(data.breakdown24h),
- });
- }
- return result;
-}
-
-/** @deprecated use fetchDeFiLlamaData */
-export async function fetchDeFiLlamaRevenue(): Promise> {
- return new Map();
-}
diff --git a/src/lib/dune.ts b/src/lib/dune.ts
deleted file mode 100644
index 40a76b1f..00000000
--- a/src/lib/dune.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-// Dune query 8306192: FOMO relay fees — MAX(platform_fees) per fee_period (rows are cumulative snapshots)
-// Old query 8304081 summed all cumulative rows → ~8-16x inflation. Fixed by deduping with MAX.
-const FOMO_QUERY_ID = 8306192;
-
-export type FOMORelayFees = {
- fees24h: number;
- fees7d: number;
- fees30d: number;
- latestDate: string;
-};
-
-export async function fetchFOMORelayFees(): Promise {
- const apiKey = process.env.DUNE_API_KEY;
- if (!apiKey) return null;
-
- try {
- const res = await fetch(
- `https://api.dune.com/api/v1/query/${FOMO_QUERY_ID}/results`,
- {
- headers: { "X-Dune-API-Key": apiKey },
- next: { revalidate: 3600 },
- }
- );
- if (!res.ok) return null;
-
- const json = await res.json();
- const row = json?.result?.rows?.[0];
- if (!row) return null;
-
- return {
- fees24h: row.fees_24h ?? 0,
- fees7d: row.fees_7d ?? 0,
- fees30d: row.fees_30d ?? 0,
- latestDate: row.latest_date ?? "",
- };
- } catch {
- return null;
- }
-}
diff --git a/src/lib/evm-exec.ts b/src/lib/evm-exec.ts
deleted file mode 100644
index b5d8a940..00000000
--- a/src/lib/evm-exec.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-export type NativeRevenue = {
- symbol: string;
- amount: number;
- usd: number | null;
-};
-
-export type EVMChainRevenue = {
- stable24h: number;
- stable7d: number;
- stable30d: number;
- native: NativeRevenue | null; // 24h only
- coverage: "full" | "stable-only";
-};
-
-export type EVMPlatformRow = {
- platform: string;
- chains: Record;
-};
-
-export type EVMRevenueResponse = {
- updatedAt: string;
- platforms: EVMPlatformRow[];
-};
-
-const EXEC_API = "https://exec.openchainbench.com";
-
-export async function fetchEVMRevenue(): Promise {
- try {
- const res = await fetch(`${EXEC_API}/api/evm-revenue`, {
- next: { revalidate: 60 },
- });
- return res.ok ? res.json() : null;
- } catch {
- return null;
- }
-}
-
-/** Total 24h USD for a platform across all chains. */
-export function totalRevenue24h(row: EVMPlatformRow): number {
- let total = 0;
- for (const chain of Object.values(row.chains)) {
- total += chain.stable24h;
- if (chain.native?.usd != null) total += chain.native.usd;
- }
- return total;
-}
-
-export function fmtUSD(n: number): string {
- if (n === 0) return "—";
- if (n >= 1_000_000) return `$${(n / 1_000_000).toFixed(2)}M`;
- if (n >= 1_000) return `$${(n / 1_000).toFixed(1)}K`;
- return `$${n.toFixed(0)}`;
-}
-
-export const CHAIN_LABELS: Record = {
- ethereum: "Ethereum",
- bsc: "BSC",
- base: "Base",
-};
-
-export const EVM_CHAINS = ["ethereum", "bsc", "base"] as const;
diff --git a/src/lib/sol-price.ts b/src/lib/sol-price.ts
deleted file mode 100644
index abbaa92d..00000000
--- a/src/lib/sol-price.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-export async function fetchSolPrice(): Promise {
- try {
- const res = await fetch(
- "https://api.coingecko.com/api/v3/simple/price?ids=solana&vs_currencies=usd",
- { next: { revalidate: 300 } }
- );
- if (!res.ok) return null;
- const data = await res.json();
- return data?.solana?.usd ?? null;
- } catch {
- return null;
- }
-}
diff --git a/src/lib/trading-apps-config.ts b/src/lib/trading-apps-config.ts
deleted file mode 100644
index f6356968..00000000
--- a/src/lib/trading-apps-config.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-export type AppMeta = {
- id: string;
- name: string;
- category: "trading-terminal" | "telegram-bot";
- formFactor: "web" | "mobile" | "telegram";
- logoKey: string | null;
- productUrl: string;
- benchUrl: string | null;
- evmKey: string | null;
- solanaKey: string | null;
- robinhoodKey: string | null;
- defillamaSlug: string | null;
- /** "venue" = DL slug covers the whole protocol (bonding curve + creator fees), not a pure frontend */
- defillamaScope?: "venue";
- inactive?: boolean;
- inactiveSince?: string;
- /** When true, Solana fees are collected in USDC (6 dec raw units) not SOL lamports.
- * Frontend uses sumPlatformFeeLamports / 1e6 directly instead of / 1e9 * solPrice. */
- solanaFeeIsUSDC?: boolean;
-};
-
-export const TRADING_APPS: AppMeta[] = [
- { id: "pump.fun", name: "pump.fun", category: "trading-terminal", formFactor: "web", logoKey: "pump-fun", productUrl: "https://pump.fun", benchUrl: "/benchmarks/trading-app-execution", evmKey: "pumpfun", solanaKey: "pump.fun", robinhoodKey: null, defillamaSlug: "pump.fun", defillamaScope: "venue" },
- { id: "fomo", name: "FOMO", category: "trading-terminal", formFactor: "web", logoKey: "fomo", productUrl: "https://fomo.fund", benchUrl: "/benchmarks/trading-app-execution", evmKey: null, solanaKey: "fomo", robinhoodKey: null, defillamaSlug: "fomo", solanaFeeIsUSDC: true },
- { id: "phantom", name: "Phantom", category: "trading-terminal", formFactor: "mobile", logoKey: "phantom", productUrl: "https://phantom.com", benchUrl: null, evmKey: null, solanaKey: null, robinhoodKey: null, defillamaSlug: "phantom" },
- { id: "moonshot-money", name: "Moonshot", category: "trading-terminal", formFactor: "mobile", logoKey: null, productUrl: "https://moonshot.money", benchUrl: null, evmKey: null, solanaKey: null, robinhoodKey: null, defillamaSlug: "moonshot-money" },
- { id: "mevx", name: "MevX", category: "trading-terminal", formFactor: "web", logoKey: null, productUrl: "https://mevx.io", benchUrl: null, evmKey: null, solanaKey: null, robinhoodKey: null, defillamaSlug: "mevx" },
- { id: "bullx", name: "BullX", category: "trading-terminal", formFactor: "web", logoKey: "bullx", productUrl: "https://bullx.io", benchUrl: "/benchmarks/trading-app-execution", evmKey: null, solanaKey: "bullx", robinhoodKey: null, defillamaSlug: "bullx", inactive: true, inactiveSince: "2026-06-01" },
- { id: "photon", name: "Photon", category: "trading-terminal", formFactor: "web", logoKey: "photon", productUrl: "https://photon-sol.tinyastro.io", benchUrl: "/benchmarks/trading-app-execution", evmKey: null, solanaKey: "photon", robinhoodKey: null, defillamaSlug: "photon" },
- { id: "gmgn", name: "GMGN", category: "telegram-bot", formFactor: "telegram", logoKey: "gmgn", productUrl: "https://gmgn.ai", benchUrl: "/benchmarks/trading-app-execution", evmKey: "gmgn", solanaKey: "gmgn", robinhoodKey: "gmgn-robinhood", defillamaSlug: "gmgn" },
- { id: "axiom", name: "Axiom", category: "telegram-bot", formFactor: "telegram", logoKey: "axiom", productUrl: "https://axiom.trade", benchUrl: "/benchmarks/trading-app-execution", evmKey: "axiom", solanaKey: "axiom", robinhoodKey: null, defillamaSlug: "axiom" },
- { id: "bloom", name: "Bloom", category: "telegram-bot", formFactor: "telegram", logoKey: null, productUrl: "https://bloom.bot", benchUrl: null, evmKey: null, solanaKey: null, robinhoodKey: null, defillamaSlug: "bloom" },
- { id: "maestro", name: "Maestro", category: "telegram-bot", formFactor: "telegram", logoKey: "maestro", productUrl: "https://maestro.bots.gg", benchUrl: "/benchmarks/trading-app-execution", evmKey: "maestro", solanaKey: "maestro", robinhoodKey: "maestro-robinhood",defillamaSlug: "maestro" },
- { id: "banana-gun", name: "Banana Gun", category: "telegram-bot", formFactor: "telegram", logoKey: "banana-gun", productUrl: "https://t.me/BananaGunSniper_bot", benchUrl: "/benchmarks/trading-app-execution", evmKey: null, solanaKey: "banana-gun", robinhoodKey: null, defillamaSlug: "banana-gun" },
- { id: "trojan", name: "Trojan", category: "telegram-bot", formFactor: "telegram", logoKey: "trojan", productUrl: "https://trojan.bot", benchUrl: "/benchmarks/trading-app-execution", evmKey: null, solanaKey: "trojan", robinhoodKey: null, defillamaSlug: "trojan" },
-];
From 237d7f73d7d444f7a4cceb56f88842451a2465cf Mon Sep 17 00:00:00 2001
From: Florent Tapponnier <160007691+Flotapponnier@users.noreply.github.com>
Date: Sat, 15 Aug 2026 13:25:04 +0200
Subject: [PATCH 5/6] feat: add /trading-apps hub linking all 8 trading-app
benches
---
next.config.ts | 2 +-
src/app/trading-apps/page.tsx | 172 ++++++++++++++++++++++++++++++++++
2 files changed, 173 insertions(+), 1 deletion(-)
create mode 100644 src/app/trading-apps/page.tsx
diff --git a/next.config.ts b/next.config.ts
index be6528ee..ad07b9bb 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -269,7 +269,7 @@ const nextConfig: NextConfig = {
},
{
source: "/apps",
- destination: "/benchmarks",
+ destination: "/trading-apps",
permanent: true,
},
...chainRedirects,
diff --git a/src/app/trading-apps/page.tsx b/src/app/trading-apps/page.tsx
new file mode 100644
index 00000000..fc4743fe
--- /dev/null
+++ b/src/app/trading-apps/page.tsx
@@ -0,0 +1,172 @@
+import type { Metadata } from "next";
+import Link from "next/link";
+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, fees, execution quality, unique traders, and app store ratings.";
+
+export const metadata: Metadata = pageMetadata({
+ path: "/trading-apps",
+ title: "Trading App Benchmarks — pump.fun, Axiom, GMGN, FOMO | OpenChainBench",
+ description: DESCRIPTION,
+});
+
+export const revalidate = 3600;
+
+const GROUPS = [
+ {
+ label: "Volume & activity",
+ items: [
+ {
+ slug: "solana-trading-platform-wars",
+ title: "Trading platform volume",
+ description: "24h volume for pump.fun, GMGN, Axiom, FOMO and Telegram bots. Updated every 15 min.",
+ },
+ {
+ slug: "solana-dex-volume",
+ title: "DEX volume & protocol revenue",
+ description: "24h trading volume and protocol fees from DeFiLlama. Updated every 30 min.",
+ },
+ {
+ slug: "solana-unique-traders",
+ title: "Unique traders",
+ description: "Unique swap transactions per platform in the last 24h. Whale vs retail signal.",
+ },
+ {
+ slug: "solana-avg-trade-size",
+ title: "Average trade size",
+ description: "Average swap size in USD per platform — reveals trader profile.",
+ },
+ ],
+ },
+ {
+ label: "Launchpads",
+ items: [
+ {
+ slug: "solana-launchpad-wars",
+ title: "Launchpad volume",
+ description: "24h volume for pump.fun, Flap, Bankr and other bonding-curve programs.",
+ },
+ ],
+ },
+ {
+ label: "Fees & execution",
+ items: [
+ {
+ slug: "memecoin-platforms",
+ title: "Platform fee rates",
+ description: "Protocol fee revenue divided by volume — who earns most per dollar traded.",
+ },
+ {
+ slug: "trading-app-execution",
+ title: "Execution quality",
+ description: "Priority fees, Jito bundle rates, CU price and platform fee per transaction.",
+ },
+ ],
+ },
+ {
+ label: "App store",
+ items: [
+ {
+ slug: "app-store-ratings",
+ title: "iOS app store ratings",
+ description: "Live Apple App Store ratings for Coinbase, Robinhood, Crypto.com and more. Updated every 30 min.",
+ },
+ ],
+ },
+];
+
+export default function TradingAppsHubPage() {
+ const breadcrumb = {
+ "@context": "https://schema.org",
+ ...buildBreadcrumbJsonLd([
+ { name: "Home", item: SITE.url },
+ { name: "Trading Apps", item: `${SITE.url}/trading-apps` },
+ ]),
+ };
+
+ const itemList = {
+ "@context": "https://schema.org",
+ "@type": "ItemList",
+ name: "Trading app benchmarks — OpenChainBench",
+ numberOfItems: GROUPS.reduce((n, g) => n + g.items.length, 0),
+ itemListElement: GROUPS.flatMap((g, gi) =>
+ g.items.map((item, ii) => ({
+ "@type": "ListItem",
+ position: GROUPS.slice(0, gi).reduce((n, g2) => n + g2.items.length, 0) + ii + 1,
+ name: item.title,
+ url: `${SITE.url}/benchmarks/${item.slug}`,
+ }))
+ ),
+ };
+
+ return (
+
+
+
+
+
+ Trading app benchmarks.
+
+
+ {DESCRIPTION}
+
+
+
+ {GROUPS.map((group) => (
+
+
+ {group.label}
+
+
+ {group.items.map((item, i) => (
+
+ {i > 0 &&
}
+
+
+
+ {item.title}
+
+
+ {item.description}
+
+
+
+
+
+
+
+ ))}
+
+
+ ))}
+
+
+ );
+}
From a1d659aee3e79b30c8a6176ed9f305e185852398 Mon Sep 17 00:00:00 2001
From: Florent Tapponnier <160007691+Flotapponnier@users.noreply.github.com>
Date: Sat, 15 Aug 2026 13:39:31 +0200
Subject: [PATCH 6/6] feat: rebuild /trading-apps as rich hub with live KPIs,
product grid, grouped bench list
---
src/app/trading-apps/page.tsx | 420 +++++++++++++++++++++++++++-------
1 file changed, 342 insertions(+), 78 deletions(-)
diff --git a/src/app/trading-apps/page.tsx b/src/app/trading-apps/page.tsx
index fc4743fe..050557da 100644
--- a/src/app/trading-apps/page.tsx
+++ b/src/app/trading-apps/page.tsx
@@ -1,5 +1,6 @@
-import type { Metadata } from "next";
import Link from "next/link";
+import { ProviderLogo } from "@/components/provider-logo";
+import { readSnapshot } from "@/lib/snapshot";
import { pageMetadata } from "@/lib/page-metadata";
import { safeJsonLd, buildBreadcrumbJsonLd } from "@/lib/jsonld";
import { SITE } from "@/data/site";
@@ -7,13 +8,72 @@ 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.";
-export const metadata: Metadata = pageMetadata({
+export const metadata: import("next").Metadata = pageMetadata({
path: "/trading-apps",
- title: "Trading App Benchmarks — pump.fun, Axiom, GMGN, FOMO | OpenChainBench",
+ title: "Best Solana Trading Apps 2026, ranked by benchmark",
description: DESCRIPTION,
});
-export const revalidate = 3600;
+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",
+ "trading-app-execution",
+ "app-store-ratings",
+] as const;
+
+const PRODUCTS = [
+ {
+ slug: "pump-fun",
+ name: "pump.fun",
+ description: "Leading Solana memecoin launchpad and AMM",
+ },
+ {
+ slug: "fomo",
+ name: "FOMO",
+ description: "Multi-chain memecoin trading with social copy-trading",
+ },
+ {
+ slug: "gmgn",
+ name: "GMGN",
+ description: "Memecoin terminal with smart money tracking and Telegram bot",
+ },
+ {
+ slug: "axiom",
+ name: "Axiom",
+ description: "Telegram trading bot for Solana memecoins",
+ },
+ {
+ slug: "trojan",
+ name: "Trojan",
+ description: "Fast Solana Telegram bot with sniping and MEV protection",
+ },
+ {
+ slug: "photon",
+ name: "Photon",
+ description: "Advanced Solana trading terminal with wallet tracking",
+ },
+ {
+ slug: "maestro",
+ name: "Maestro",
+ description: "Multi-chain Telegram trading bot with limit orders",
+ },
+ {
+ slug: "banana-gun",
+ name: "Banana Gun",
+ description: "Multi-chain Telegram bot for memecoins and EVM tokens",
+ },
+ {
+ slug: "bullx",
+ name: "BullX",
+ description: "Multi-chain terminal for memecoins on Solana and EVM",
+ },
+] as const;
const GROUPS = [
{
@@ -22,22 +82,23 @@ const GROUPS = [
{
slug: "solana-trading-platform-wars",
title: "Trading platform volume",
- description: "24h volume for pump.fun, GMGN, Axiom, FOMO and Telegram bots. Updated every 15 min.",
+ description:
+ "24h volume for pump.fun, GMGN, Axiom, FOMO and Telegram bots",
},
{
slug: "solana-dex-volume",
title: "DEX volume & protocol revenue",
- description: "24h trading volume and protocol fees from DeFiLlama. Updated every 30 min.",
+ description: "24h trading volume and protocol fees from DeFiLlama",
},
{
slug: "solana-unique-traders",
title: "Unique traders",
- description: "Unique swap transactions per platform in the last 24h. Whale vs retail signal.",
+ description: "Unique swap transactions per platform in the last 24h",
},
{
slug: "solana-avg-trade-size",
title: "Average trade size",
- description: "Average swap size in USD per platform — reveals trader profile.",
+ description: "Average swap size in USD per platform",
},
],
},
@@ -47,7 +108,8 @@ const GROUPS = [
{
slug: "solana-launchpad-wars",
title: "Launchpad volume",
- description: "24h volume for pump.fun, Flap, Bankr and other bonding-curve programs.",
+ description:
+ "24h volume for pump.fun, Flap, Bankr and other bonding-curve programs",
},
],
},
@@ -57,12 +119,14 @@ const GROUPS = [
{
slug: "memecoin-platforms",
title: "Platform fee rates",
- description: "Protocol fee revenue divided by volume — who earns most per dollar traded.",
+ description:
+ "Protocol fee revenue divided by volume — who earns most per dollar traded",
},
{
slug: "trading-app-execution",
title: "Execution quality",
- description: "Priority fees, Jito bundle rates, CU price and platform fee per transaction.",
+ description:
+ "Priority fees, Jito bundle rates, CU price and platform fee per transaction",
},
],
},
@@ -72,14 +136,33 @@ const GROUPS = [
{
slug: "app-store-ratings",
title: "iOS app store ratings",
- description: "Live Apple App Store ratings for Coinbase, Robinhood, Crypto.com and more. Updated every 30 min.",
+ description:
+ "Live Apple App Store ratings for Coinbase, Robinhood, Crypto.com and more",
},
],
},
-];
+] as const;
+
+function fmtUSD(v: number): string {
+ 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)}`;
+}
+
+export default async function TradingAppsHubPage() {
+ const [volumeSnap, ratingsSnap] = await Promise.all([
+ readSnapshot("solana-trading-platform-wars"),
+ readSnapshot("app-store-ratings"),
+ ]);
-export default function TradingAppsHubPage() {
- const breadcrumb = {
+ const topVolumePlatform = volumeSnap?.results[0];
+ const topRatedApp = ratingsSnap?.results[0];
+ const platformsTracked = new Set(
+ PRODUCTS.map((p) => p.slug)
+ ).size;
+
+ const breadcrumbLd = {
"@context": "https://schema.org",
...buildBreadcrumbJsonLd([
{ name: "Home", item: SITE.url },
@@ -87,86 +170,267 @@ export default function TradingAppsHubPage() {
]),
};
- const itemList = {
+ const itemListLd = {
"@context": "https://schema.org",
"@type": "ItemList",
- name: "Trading app benchmarks — OpenChainBench",
- numberOfItems: GROUPS.reduce((n, g) => n + g.items.length, 0),
- itemListElement: GROUPS.flatMap((g, gi) =>
- g.items.map((item, ii) => ({
- "@type": "ListItem",
- position: GROUPS.slice(0, gi).reduce((n, g2) => n + g2.items.length, 0) + ii + 1,
- name: item.title,
- url: `${SITE.url}/benchmarks/${item.slug}`,
- }))
- ),
+ 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 (
-
+
-
- Trading app benchmarks.
-
-
- {DESCRIPTION}
-
+
+
+ Trading Apps
+
+
+ Solana trading app benchmarks
+
+
+ Eight independent benchmarks across four categories: 24h platform
+ volume, launchpad activity, execution fees, and app store ratings.
+ Every number is measured live from the same harness on the same
+ schedule. No marketing claims, just on-chain data.
+
+
+
+ {BENCH_SLUGS.slice(0, 5).map((slug) => (
+
+
+ Bench
+
+ {slug}
+
+ ))}
+ {BENCH_SLUGS.length > 5 && (
+
+ +{BENCH_SLUGS.length - 5} more
+
+ )}
+
+
+
+ {/* KPI strip */}
+
-
- {GROUPS.map((group) => (
-
-
- {group.label}
-
-
- {group.items.map((item, i) => (
-
- {i > 0 &&
}
-
-
-
- {item.title}
-
-
- {item.description}
-
-
-
+
+ Platforms covered
+
+
+ {PRODUCTS.map((product) => (
+
+
+
+ {product.description}
+
+
+ ))}
+
+
+
+ {/* Benchmarks grouped list */}
+
+
+ Benchmarks
+
+
+ {GROUPS.map((group) => (
+
+
+ {group.label}
+
+
+ {group.items.map((item, i) => (
+
- ))}
+
+
+ {item.title}
+
+
+ {item.description}
+
+
+
+
+
+
+
+ ))}
+
-
- ))}
-
+ ))}
+
+
+
+
+
+ Methodology
+
+
+ Volume figures are pulled from on-chain program activity and
+ DeFiLlama aggregates. Platform fee rates compare fee revenue to
+ reported volume over the same 24h window. Execution quality probes
+ submit a representative transaction per platform and records the
+ priority fee, Jito bundle cost, and compute unit price. App store
+ ratings are fetched directly from the Apple App Store API. All
+ harnesses are open source on{" "}
+
+ GitHub
+
+ . Data released under{" "}
+
+ CC BY 4.0
+
+ .
+
+
);
}
+
+function KpiCard({
+ label,
+ value,
+ accent,
+ tip,
+}: {
+ label: string;
+ value: string;
+ accent?: string;
+ tip?: string;
+}) {
+ return (
+
+
+ {accent && (
+
+ )}
+ {label}
+
+
+ {value}
+
+
+ );
+}