diff --git a/src/app/apps/page.tsx b/src/app/apps/page.tsx
index c849bc20..7b9d9905 100644
--- a/src/app/apps/page.tsx
+++ b/src/app/apps/page.tsx
@@ -20,6 +20,8 @@ export const metadata: Metadata = pageMetadata({
export const revalidate = 300;
+const WINDOWS = ["24h", "7d", "30d"] as const;
+
export default async function AppsHubPage() {
const [evmData, solanaData, solPrice] = await Promise.all([
fetchEVMRevenue(),
@@ -43,30 +45,39 @@ export default async function AppsHubPage() {
const bscChain = evmRow?.chains["bsc"];
const baseChain = evmRow?.chains["base"];
+ // EVM fees are always 24h — we don't have multi-window EVM data.
const ethFees = ethChain ? ethChain.stable24h + (ethChain.native?.usd ?? 0) : null;
const bscFees = bscChain ? bscChain.stable24h + (bscChain.native?.usd ?? 0) : null;
const baseFees = baseChain ? baseChain.stable24h + (baseChain.native?.usd ?? 0) : null;
+ const evmTotal = (ethFees ?? 0) + (bscFees ?? 0) + (baseFees ?? 0);
+
+ const windows: UnifiedAppRow["windows"] = {};
- let solanaFees: number | null = null;
- if (solRow && solPrice !== null) {
- const window24h = solRow.windows["24h"];
- if (window24h) {
- solanaFees = (window24h.txCount * window24h.avgPlatformFeeLamports) / 1e9 * solPrice;
+ for (const w of WINDOWS) {
+ let solanaFees: number | null = null;
+ if (solRow && solPrice !== null) {
+ const wData = solRow.windows[w];
+ if (wData) {
+ solanaFees = (wData.txCount * wData.avgPlatformFeeLamports) / 1e9 * solPrice;
+ }
}
+ windows[w] = {
+ solana: solanaFees,
+ ethereum: ethFees,
+ bsc: bscFees,
+ base: baseFees,
+ total: (solanaFees ?? 0) + evmTotal,
+ };
}
- const total24h =
- (solanaFees ?? 0) + (ethFees ?? 0) + (bscFees ?? 0) + (baseFees ?? 0);
-
return {
meta,
- fees: { solana: solanaFees, ethereum: ethFees, bsc: bscFees, base: baseFees },
+ windows,
stableOnly: {
ethereum: ethChain?.coverage === "stable-only",
bsc: bscChain?.coverage === "stable-only",
base: baseChain?.coverage === "stable-only",
},
- total24h,
};
});
@@ -101,7 +112,7 @@ export default async function AppsHubPage() {
Solana fees = txCount × avgPlatformFeeLamports / 1e9 × SOL price.
- EVM fees = stable (USDC/USDT) + native where traceable.{" "}
+ EVM fees = stable (USDC/USDT) + native where traceable, always 24h.{" "}
Detailed execution metrics →
diff --git a/src/components/trading-apps-leaderboard.tsx b/src/components/trading-apps-leaderboard.tsx
index ea80b9cf..d15ccc37 100644
--- a/src/components/trading-apps-leaderboard.tsx
+++ b/src/components/trading-apps-leaderboard.tsx
@@ -1,23 +1,27 @@
"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";
+type FeeWindow = {
+ solana: number | null;
+ ethereum: number | null;
+ bsc: number | null;
+ base: number | null;
+ total: number;
+};
+
export type UnifiedAppRow = {
meta: AppMeta;
- fees: {
- solana: number | null;
- ethereum: number | null;
- bsc: number | null;
- base: number | null;
- };
+ windows: Record;
stableOnly: { ethereum: boolean; bsc: boolean; base: boolean };
- total24h: number;
};
type TabKey = "all" | "meme-bot" | "telegram-bot";
+type WindowKey = "24h" | "7d" | "30d";
const TABS: { key: TabKey; label: string }[] = [
{ key: "all", label: "All" },
@@ -25,6 +29,12 @@ const TABS: { key: TabKey; label: string }[] = [
{ 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 = {
"meme-bot": "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",
@@ -79,9 +89,12 @@ export function TradingAppsLeaderboard({
updatedAt: string | null;
}) {
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) => b.total24h - a.total24h);
+ const sorted = [...filtered].sort(
+ (a, b) => (b.windows[window]?.total ?? 0) - (a.windows[window]?.total ?? 0)
+ );
const hasStableOnly = sorted.some(
(r) => r.stableOnly.ethereum || r.stableOnly.bsc || r.stableOnly.base
@@ -106,11 +119,29 @@ export function TradingAppsLeaderboard({
))}
- {updatedAt && (
-
- Updated {new Date(updatedAt).toLocaleString()}
-
- )}
+
+
+ {WINDOWS.map((w) => (
+
+ ))}
+
+ {updatedAt && (
+
+ {new Date(updatedAt).toLocaleString()}
+
+ )}
+
@@ -120,16 +151,23 @@ export function TradingAppsLeaderboard({
# |
App |
Category |
-
Solana |
+
+
+ Solana
+
+ |
Ethereum |
BSC |
Base |
-
Total 24h |
+
+ Total {window}
+ |
{sorted.map((row, i) => {
- const { meta, fees, stableOnly } = row;
+ const { meta, stableOnly } = row;
+ const fees = row.windows[window] ?? { solana: null, ethereum: null, bsc: null, base: null, total: 0 };
const logo = meta.logoKey ? logoPath(meta.logoKey) : null;
return (
@@ -141,23 +179,37 @@ export function TradingAppsLeaderboard({
{i + 1}
-
- {logo && (
-
+
+
+ {logo && (
+
+ )}
+ {meta.name}
+
+ {meta.benchUrl && (
+
+
+
)}
- {meta.name}
-
+
|
@@ -169,7 +221,7 @@ export function TradingAppsLeaderboard({
|
- {row.total24h > 0 ? fmtUSD(row.total24h) : }
+ {fees.total > 0 ? fmtUSD(fees.total) : }
|
);
@@ -181,6 +233,12 @@ export function TradingAppsLeaderboard({
{hasStableOnly && (
° USDC only (no native trace on Base).
+ {window !== "24h" && " EVM fees are always 24h — only Solana has multi-window data."}
+
+ )}
+ {!hasStableOnly && window !== "24h" && (
+
+ EVM fees (ETH/BSC/Base) are always 24h — only Solana has multi-window data.
)}
diff --git a/src/lib/trading-apps-config.ts b/src/lib/trading-apps-config.ts
index 65d07c44..8195d67e 100644
--- a/src/lib/trading-apps-config.ts
+++ b/src/lib/trading-apps-config.ts
@@ -10,13 +10,13 @@ export type AppMeta = {
};
export const TRADING_APPS: AppMeta[] = [
- { id: "pump.fun", name: "pump.fun", category: "meme-bot", logoKey: "pump-fun", productUrl: "https://pump.fun", benchUrl: null, evmKey: "pumpfun", solanaKey: "pump.fun" },
- { id: "fomo", name: "FOMO", category: "meme-bot", logoKey: "fomo", productUrl: "https://fomo.fund", benchUrl: null, evmKey: null, solanaKey: "fomo" },
- { id: "bullx", name: "BullX", category: "meme-bot", logoKey: "bullx", productUrl: "https://bullx.io", benchUrl: null, evmKey: null, solanaKey: "bullx" },
- { id: "photon", name: "Photon", category: "meme-bot", logoKey: "photon", productUrl: "https://photon-sol.tinyastro.io", benchUrl: null, evmKey: null, solanaKey: "photon" },
- { id: "gmgn", name: "GMGN", category: "telegram-bot", logoKey: "gmgn", productUrl: "https://gmgn.ai", benchUrl: null, evmKey: "gmgn", solanaKey: "gmgn" },
- { id: "axiom", name: "Axiom", category: "telegram-bot", logoKey: "axiom", productUrl: "https://axiom.trade", benchUrl: null, evmKey: "axiom", solanaKey: "axiom" },
- { id: "maestro", name: "Maestro", category: "telegram-bot", logoKey: "maestro", productUrl: "https://maestro.bots.gg", benchUrl: null, evmKey: "maestro", solanaKey: null },
- { id: "banana-gun", name: "Banana Gun", category: "telegram-bot", logoKey: "banana-gun", productUrl: "https://t.me/BananaGunSniper_bot", benchUrl: null, evmKey: "banana-gun", solanaKey: null },
- { id: "trojan", name: "Trojan", category: "telegram-bot", logoKey: "trojan", productUrl: "https://trojan.bot", benchUrl: null, evmKey: null, solanaKey: "trojan" },
+ { id: "pump.fun", name: "pump.fun", category: "meme-bot", logoKey: "pump-fun", productUrl: "https://pump.fun", benchUrl: "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/apps/exec", evmKey: "pumpfun", solanaKey: "pump.fun" },
+ { id: "fomo", name: "FOMO", category: "meme-bot", logoKey: "fomo", productUrl: "https://fomo.fund", benchUrl: "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/apps/exec", evmKey: null, solanaKey: "fomo" },
+ { id: "bullx", name: "BullX", category: "meme-bot", logoKey: "bullx", productUrl: "https://bullx.io", benchUrl: "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/apps/exec", evmKey: null, solanaKey: "bullx" },
+ { id: "photon", name: "Photon", category: "meme-bot", logoKey: "photon", productUrl: "https://photon-sol.tinyastro.io", benchUrl: "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/apps/exec", evmKey: null, solanaKey: "photon" },
+ { id: "gmgn", name: "GMGN", category: "telegram-bot", logoKey: "gmgn", productUrl: "https://gmgn.ai", benchUrl: "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/apps/exec", evmKey: "gmgn", solanaKey: "gmgn" },
+ { id: "axiom", name: "Axiom", category: "telegram-bot", logoKey: "axiom", productUrl: "https://axiom.trade", benchUrl: "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/apps/exec", evmKey: "axiom", solanaKey: "axiom" },
+ { id: "maestro", name: "Maestro", category: "telegram-bot", logoKey: "maestro", productUrl: "https://maestro.bots.gg", benchUrl: "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/apps/exec", evmKey: "maestro", solanaKey: null },
+ { id: "banana-gun", name: "Banana Gun", category: "telegram-bot", logoKey: "banana-gun", productUrl: "https://t.me/BananaGunSniper_bot", benchUrl: "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/apps/exec", evmKey: "banana-gun", solanaKey: null },
+ { id: "trojan", name: "Trojan", category: "telegram-bot", logoKey: "trojan", productUrl: "https://trojan.bot", benchUrl: "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/apps/exec", evmKey: null, solanaKey: "trojan" },
];