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/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) => (
-
- ))}
-
-
-
- {WINDOWS.map((w) => (
-
- ))}
-
- {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