From 601b6c73d0b05413ff1368b4294bfedd1f7e6f91 Mon Sep 17 00:00:00 2001
From: Florent Tapponnier <160007691+Flotapponnier@users.noreply.github.com>
Date: Wed, 12 Aug 2026 22:52:00 +0200
Subject: [PATCH 1/3] feat(apps): add Phantom, formFactor, DL market share +
change_1d
---
src/app/apps/page.tsx | 23 ++++++-
src/components/trading-apps-leaderboard.tsx | 76 +++++++++++++++++----
src/lib/defillama.ts | 36 +++++-----
src/lib/trading-apps-config.ts | 21 +++---
4 files changed, 111 insertions(+), 45 deletions(-)
diff --git a/src/app/apps/page.tsx b/src/app/apps/page.tsx
index 0db64487..a83010c0 100644
--- a/src/app/apps/page.tsx
+++ b/src/app/apps/page.tsx
@@ -7,13 +7,14 @@ 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, type DLPlatformData } from "@/lib/defillama";
import { TradingAppsLeaderboard, type UnifiedAppRow } from "@/components/trading-apps-leaderboard";
import { RevenueSummary } from "@/components/revenue-summary";
import { ExecChainTabs } from "@/components/exec-chain-tabs";
import Link from "next/link";
const DESCRIPTION =
- "Protocol fees collected by trading apps: meme bots and telegram bots. On-chain data, updated hourly.";
+ "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",
@@ -26,13 +27,22 @@ export const revalidate = 300;
const WINDOWS = ["24h", "7d", "30d"] as const;
export default async function AppsHubPage() {
- const [evmData, solanaData, solPrice, fomoRelay] = await Promise.all([
+ 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),
]);
+ // 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);
+
const evmByPlatform = new Map(
(evmData?.platforms ?? []).map((p) => [p.platform, p])
);
@@ -97,6 +107,11 @@ export default async function AppsHubPage() {
};
}
+ const dl = dlData.get(meta.id) ?? null;
+ const marketSharePct = dl && activeDlTotal > 0 && !meta.inactive
+ ? (dl.total24h / activeDlTotal) * 100
+ : null;
+
return {
meta,
windows,
@@ -106,6 +121,8 @@ export default async function AppsHubPage() {
base: baseChain?.coverage === "stable-only",
robinhood: rhChain?.coverage === "stable-only",
},
+ dl,
+ marketSharePct,
};
});
@@ -135,7 +152,7 @@ export default async function AppsHubPage() {
-
+
diff --git a/src/components/trading-apps-leaderboard.tsx b/src/components/trading-apps-leaderboard.tsx
index d4fc8a11..5a8ec3bf 100644
--- a/src/components/trading-apps-leaderboard.tsx
+++ b/src/components/trading-apps-leaderboard.tsx
@@ -5,6 +5,7 @@ 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";
type FeeWindow = {
solana: number | null;
@@ -19,6 +20,8 @@ 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";
@@ -41,9 +44,15 @@ const CATEGORY_BADGE: Record = {
"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": "Trading Terminal",
- "telegram-bot": "Telegram Bot",
+ "trading-terminal": "Terminal",
+ "telegram-bot": "Bot",
};
function fmtUSD(n: number | null): string {
@@ -99,6 +108,7 @@ export function TradingAppsLeaderboard({
updatedAt: string | null;
fomoLatestDate: string | null;
fomoRelayAvailable: boolean;
+ activeDlTotal: number;
}) {
const [tab, setTab] = useState("all");
const [window, setWindow] = useState("24h");
@@ -164,16 +174,15 @@ export function TradingAppsLeaderboard({
| # |
App |
- Category |
+ Type |
Solana
|
- Ethereum |
- BSC |
- Base |
- Robinhood |
+ ETH/BSC/Base |
+ DL 24h |
+ Share |
Total {window}
|
@@ -181,9 +190,10 @@ export function TradingAppsLeaderboard({
{sorted.map((row, i) => {
- const { meta, stableOnly } = row;
+ 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 (
)}
+ {dl?.change_1d !== null && dl?.change_1d !== undefined && !meta.inactive && (
+ = 0
+ ? "text-green-400 bg-green-500/10"
+ : "text-red-400 bg-red-500/10"
+ }`}
+ title="DeFiLlama 24h vs prior 24h"
+ >
+ {dl.change_1d >= 0 ? "+" : ""}{dl.change_1d.toFixed(1)}%
+
+ )}
{meta.benchUrl && (
|
-
- {CATEGORY_LABEL[meta.category]}
-
+
+ {FORM_FACTOR_ICON[meta.formFactor]}
+
+ {CATEGORY_LABEL[meta.category]}
+
+
|
-
-
-
-
+
+ {evmTotal > 0 ? (
+ {fmtUSD(evmTotal)}
+ ) : —}
+ |
+
+ {dl && !meta.inactive ? (
+ {fmtUSD(dl.total24h)}
+ ) : —}
+ |
+
+ {marketSharePct !== null ? (
+
+
+
+ {marketSharePct.toFixed(1)}%
+
+
+ ) : —}
+ |
{fees.total > 0 ? fmtUSD(fees.total) : }
|
diff --git a/src/lib/defillama.ts b/src/lib/defillama.ts
index 2936d139..c7e8b262 100644
--- a/src/lib/defillama.ts
+++ b/src/lib/defillama.ts
@@ -1,18 +1,4 @@
// DeFiLlama fees API — slugs verified against api.llama.fi/summary/fees/{slug} (2026-08)
-const DEFILLAMA_SLUG: Record = {
- "pump.fun": "pump.fun",
- "gmgn": "gmgn",
- "axiom": "axiom",
- "maestro": "maestro",
- "banana-gun": "banana-gun",
- "photon": "photon",
- "trojan": "trojan",
- "fomo": "fomo",
- "bullx": "bullx",
-};
-
-// Chains we surface in the leaderboard (normalized to lowercase)
-const TRACKED_CHAINS = new Set(["solana", "ethereum", "bsc", "base"]);
type DLBreakdown = Record>;
@@ -20,17 +6,25 @@ type DLSummary = {
total24h: number | null;
total7d: number | null;
total30d: number | null;
+ change_1d: number | null;
breakdown24h: DLBreakdown | null;
};
-export type DLPlatformRevenue = {
+// 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 = {};
@@ -55,11 +49,11 @@ async function fetchDLSummary(slug: string): Promise {
}
}
-export async function fetchDeFiLlamaRevenue(): Promise