diff --git a/src/components/solana-exec-table.tsx b/src/components/solana-exec-table.tsx
new file mode 100644
index 00000000..d6cce78c
--- /dev/null
+++ b/src/components/solana-exec-table.tsx
@@ -0,0 +1,156 @@
+"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
index dd645631..1cba0e83 100644
--- a/src/components/trading-apps-leaderboard.tsx
+++ b/src/components/trading-apps-leaderboard.tsx
@@ -7,6 +7,8 @@ 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;
@@ -356,9 +358,10 @@ export function TradingAppsLeaderboard({
}
function FOMODataNotice({ latestDate }: { latestDate: string | null }) {
- if (!latestDate) return null;
- const ageHours = (Date.now() - new Date(latestDate).getTime()) / 3_600_000;
- if (ageHours <= 36) return 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/brand.ts b/src/lib/brand.ts
index 4876b8c0..6a572557 100644
--- a/src/lib/brand.ts
+++ b/src/lib/brand.ts
@@ -103,6 +103,7 @@ const BRANDS: Record = {
gmx: { color: "#4F8BFF" }, // royal blue
lighter: { color: "#FF2E63" }, // hot magenta
gains: { color: "#10E2A4" }, // emerald
+
};
const REGION_VALUES = new Set(["us-east", "eu-west", "ap-southeast", "sgp", "global"]);
diff --git a/src/lib/format.ts b/src/lib/format.ts
index 47d1b7dd..0e522411 100644
--- a/src/lib/format.ts
+++ b/src/lib/format.ts
@@ -96,6 +96,13 @@ export function fmtUnit(value: number, unit: string) {
// clean integers, not decimal noise.
return formatCompactCount(Math.round(value));
}
+ if (unit === "sol") {
+ if (value === 0) return "0 SOL";
+ if (value > 0 && value < 0.0001) return `${value.toExponential(2)} SOL`;
+ if (value < 0.001) return `${value.toFixed(6)} SOL`;
+ if (value < 1) return `${value.toFixed(4)} SOL`;
+ return `${value.toFixed(3)} SOL`;
+ }
if (unit === "gwei") {
// Same near-zero semantics as count (gas-estimation gaps converge
// toward zero), but the unit is carried so API consumers and the
@@ -177,6 +184,7 @@ export function unitSuffix(unit: string, value?: number): string {
if (unit === "count") return "";
if (unit === "gwei") return " gwei";
if (unit === "usd") return "";
+ if (unit === "sol") return " SOL";
return " ms";
}
diff --git a/src/lib/sitemap-builder.ts b/src/lib/sitemap-builder.ts
index b85fb33c..8f83305f 100644
--- a/src/lib/sitemap-builder.ts
+++ b/src/lib/sitemap-builder.ts
@@ -169,21 +169,34 @@ function staticHubRoutes(catalogTs: Date): MetadataRoute.Sitemap {
/** Last-resort sitemap, returned when even buildFullSitemap throws.
* Emits the static hubs + every chain hub + every answer URL because
- * those three paths are filesystem driven and never depend on KV. */
+ * those three paths are filesystem driven and never depend on KV.
+ * Only emits /chains/ when a matching bench YAML exists on disk
+ * (convention: -rpc.yml) so chains without bench pages don't
+ * land in the sitemap and fail the smoke gate. */
async function buildStaticFallback(): Promise {
const answers = await safeLoad(
"answers (fallback)",
() => loadAllAnswers(),
[],
);
- const fallback: MetadataRoute.Sitemap = [
- ...staticHubRoutes(BUILD_TIME),
- ...CHAINS.map((c) => ({
+ const benchesDir = path.join(process.cwd(), "benchmarks");
+ const chainRoutes: MetadataRoute.Sitemap = CHAINS.flatMap((c) => {
+ // Only emit the chain hub when a known bench YAML exists for it.
+ // Convention: -rpc.yml is the primary match.
+ const hasRpc = (() => {
+ try { readFileSync(path.join(benchesDir, `${c.slug}-rpc.yml`)); return true; } catch { return false; }
+ })();
+ if (!hasRpc) return [];
+ return [{
url: `${SITE.url}/chains/${c.slug}`,
lastModified: BUILD_TIME,
changeFrequency: "daily" as const,
priority: 0.85,
- })),
+ }];
+ });
+ const fallback: MetadataRoute.Sitemap = [
+ ...staticHubRoutes(BUILD_TIME),
+ ...chainRoutes,
...answers.map((a) => ({
url: `${SITE.url}/answers/${a.slug}`,
lastModified: BUILD_TIME,
@@ -412,12 +425,11 @@ async function buildFullSitemap(): Promise {
priority: 0.85,
};
} catch {
- return {
- url: `${SITE.url}/chains/${c.slug}`,
- lastModified: catalogTs,
- changeFrequency: "daily" as const,
- priority: 0.85,
- };
+ // Fail-safe: if we can't verify this chain has benches, omit it.
+ // Emitting unverified URLs causes smoke-test 404s that block every
+ // prod deploy. Chains with real bench data re-enter the sitemap on
+ // the next successful build.
+ return null;
}
}),
)
diff --git a/src/lib/snapshot.ts b/src/lib/snapshot.ts
index 96a4f5fe..ae2e16a7 100644
--- a/src/lib/snapshot.ts
+++ b/src/lib/snapshot.ts
@@ -58,6 +58,7 @@ const UnitSchema = z.enum([
"usd",
"gwei",
"x",
+ "sol",
]);
const StalenessMetaSchema = z.object({
diff --git a/src/lib/spec-schema.ts b/src/lib/spec-schema.ts
index b2d9018f..6e23d850 100644
--- a/src/lib/spec-schema.ts
+++ b/src/lib/spec-schema.ts
@@ -249,7 +249,7 @@ export const SpecSchema = z
/* Metric */
metric: z.string().min(1).max(100),
/** ms / s for latencies; pct for fees as percent of notional; bps for basis points; slots for Solana slot delta. */
- unit: z.enum(["ms", "s", "sec", "pct", "bps", "bp", "count", "slots", "usd", "gwei", "x"]),
+ unit: z.enum(["ms", "s", "sec", "pct", "bps", "bp", "count", "slots", "usd", "gwei", "x", "sol"]),
/** True when bigger numbers are better (coverage, count). Default false:
* latency, fees, drift. every existing bench is "lower is better". */
higher_is_better: z.boolean().default(false),
@@ -440,7 +440,7 @@ export const SpecSchema = z
/** The PromQL label that holds each provider's slug. Defaults to
* "builder"; other benches may use "provider", "venue", etc. */
label_key: z.string().min(1).max(40).default("builder"),
- unit: z.enum(["ms", "s", "sec", "pct", "bps", "bp", "count", "slots", "usd", "gwei", "x"]),
+ unit: z.enum(["ms", "s", "sec", "pct", "bps", "bp", "count", "slots", "usd", "gwei", "x", "sol"]),
higher_is_better: z.boolean().default(false),
/** When false the panel is data-only: it is loaded and can feed
* ledger_columns window variants, but renders no chart tab.
diff --git a/src/lib/views.ts b/src/lib/views.ts
index 7d6b9356..54051f79 100644
--- a/src/lib/views.ts
+++ b/src/lib/views.ts
@@ -45,6 +45,7 @@ const ALLOWED_BY_UNIT: Record = {
// a comparison bar, which is the at-a-glance read users want.
usd: ["countLeaderboard", "rankedBar", "donut", "distribution", "timeseries"],
x: ["countLeaderboard", "rankedBar", "donut", "distribution", "timeseries"],
+ sol: ["countLeaderboard", "rankedBar", "donut", "distribution", "timeseries"],
};
/**
diff --git a/src/types/benchmark.ts b/src/types/benchmark.ts
index 47b3f597..e0f1dae3 100644
--- a/src/types/benchmark.ts
+++ b/src/types/benchmark.ts
@@ -139,7 +139,7 @@ export type MetricPanel = {
label: string;
description?: string;
metric: string;
- unit: "ms" | "s" | "sec" | "pct" | "bps" | "bp" | "count" | "slots" | "usd" | "gwei" | "x";
+ unit: "ms" | "s" | "sec" | "pct" | "bps" | "bp" | "count" | "slots" | "usd" | "gwei" | "x" | "sol";
higherIsBetter: boolean;
/** When false the panel is data-only (feeds ledger column window
* variants) and renders no chart tab. */
@@ -233,7 +233,7 @@ export type Benchmark = {
dataConfidence?: "healthy" | "low" | "insufficient";
abstract: string;
metric: string;
- unit: "ms" | "s" | "sec" | "pct" | "bps" | "bp" | "count" | "slots" | "usd" | "gwei" | "x";
+ unit: "ms" | "s" | "sec" | "pct" | "bps" | "bp" | "count" | "slots" | "usd" | "gwei" | "x" | "sol";
higherIsBetter: boolean;
/** Optional drill-down dimensions exposed by the bench. When set, the
* bench page renders one tab selector per dimension and the queries get
@@ -313,7 +313,7 @@ export type LedgerColumn = {
panel?: string;
/** Display unit override; defaults to the panel's unit (panel columns)
* or the bench unit (slot columns). */
- unit?: "ms" | "s" | "sec" | "pct" | "bps" | "bp" | "count" | "slots" | "usd" | "gwei" | "x";
+ unit?: "ms" | "s" | "sec" | "pct" | "bps" | "bp" | "count" | "slots" | "usd" | "gwei" | "x" | "sol";
/** Per-window value sources for the ledger's timeframe toggle: window
* key to metric_panels id. Columns without a mapping keep their 24h
* value when a longer window is selected. */
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 03/11] 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 487b356eccafa6136cb2c28561c231e83745ef13 Mon Sep 17 00:00:00 2001
From: Flotapponnier <160007691+Flotapponnier@users.noreply.github.com>
Date: Sat, 15 Aug 2026 11:59:38 +0200
Subject: [PATCH 04/11] fix: guard data.platforms in ExecBenchTable (#1952)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* fix: codex auth chain — un.defined.fi + utls + sidecar fallback (#1819)
* fix: remove dead providers (BlastAPI shutdown, Ankr key-gated, dRPC/1RPC not supported)
* fix: remove dead providers (BlastAPI shutdown, Ankr key-gated, dRPC/1RPC not supported) (#1789)
* feat: add wave 7 chains to /chains hub (fantom, kusama, hydration, zetachain, haqq, etherlink, chiliz, wemix, songbird, etc-classic, telos, pulsechain, warden, oraichain, peaq)
* feat: add 15 wave 7 chains to /chains hub (#1790)
* fix: remove dead providers (BlastAPI shutdown, Ankr key-gated, dRPC/1RPC not supported)
* feat: add wave 7 chains to /chains hub (fantom, kusama, hydration, zetachain, haqq, etherlink, chiliz, wemix, songbird, etc-classic, telos, pulsechain, warden, oraichain, peaq)
* fix: remove drift and variational from perp venue meta (404 on /perp redirect)
* fix: filter non-provider result links in answers, add bridge to footer
* fix: drop dead RPC providers across 14 chains (DNS failures, 404s, paid-plan blocks)
* fix: hydration draft+placeholder provider, zetachain/songbird em-dash in findings
* fix: hydration draft+placeholder provider, zetachain/songbird em-dash in findings (#1794)
* feat: add /apps leaderboard foundation — specs, Go harness, Postgres schema, alerting
* fix: interface ctx type, float-free toMicroUSDC, goroutine error capture, pagination cursor
* feat: /apps leaderboard foundation (#1797)
* feat: add /apps leaderboard foundation — specs, Go harness, Postgres schema, alerting
* fix: interface ctx type, float-free toMicroUSDC, goroutine error capture, pagination cursor
* fix: dydx collector json key megavaultPnl, cumulative-to-delta PnL, Decimals=0
* feat: add Hyperliquid collector via DeFiLlama (perps/HLP/spot breakdown, 590 days)
* feat: /apps leaderboard page + Go API service (Hyperliquid $45M/30d, dYdX $25K/30d)
* feat(apps): first-party data sources — HL node fills + GMX Subsquid (#1801)
* feat(apps): switch HL collector to node fills, add hl-fills-agg
Replace DeFiLlama proxy with first-party Hyperliquid node fills.
- Reads fee/builderFee from node_fills_by_block on SGP (15.235.224.14)
- hl-fills-agg.py aggregates daily totals, runs as pm2 on SGP:2116
- net_usdc = gross - builder = amount flowing to AF + HLP + deployers
- Fills archive starts 2026-06-01, backfill runs automatically
* feat(apps): add GMX v2 collector (Arbitrum + Avalanche) via Subsquid
First-party data from GMX-operated Subsquid GraphQL endpoint.
Position fees (63% LP / 37% protocol) + swap fees split per governance.
Borrowing fees classified as LP revenue (pool-only, no protocol cut).
Amounts in GMX internal 1e30 precision, stored with Decimals=30.
* fix: dYdX collector — volume×fee-rate instead of MegaVault PnL
* feat: add Gains.trade collector (The Graph, needs THEGRAPH_API_KEY)
* feat: Gains.trade collector via DeFiLlama public API (no key needed)
* feat: gains-trade real-time WS collector via gTrade backend + eth_getTransactionReceipt
* fix: leaderboard UI polish + map treasury->burn bucket for Gains.trade
* feat: add logos + /perp links to apps leaderboard table
* chore: remove defillama gains collector, WS handles gains going forward
* fix: update codex/defined auth to use defined-attestation-token + CODEX_JWT bypass
* feat: add Drift, Jupiter Perps, Vertex to apps leaderboard via DeFiLlama (#1803)
- Generic DeFiLlama collector (defillama_generic.go): daily fees + revenue split into treasury/lp events
- Correct DeFiLlama slugs: drift-trade, jupiter-perpetual-exchange, vertex-perps
- Fix h24 window to 2 days so daily-bucket protocols show data (was missing for HL/GMX/dYdX)
- Add new deployments to materializer and API meta
- Frontend VENUE map updated with logos for all 3 new protocols
* fix: dYdX fee rate 5bps → 3.5bps (blended effective rate) (#1804)
* feat: add Drift, Jupiter Perps, Vertex to apps leaderboard via DeFiLlama
- Generic DeFiLlama collector (defillama_generic.go): daily fees + revenue split into treasury/lp events
- Correct DeFiLlama slugs: drift-trade, jupiter-perpetual-exchange, vertex-perps
- Fix h24 window to 2 days so daily-bucket protocols show data (was missing for HL/GMX/dYdX)
- Add new deployments to materializer and API meta
- Frontend VENUE map updated with logos for all 3 new protocols
* fix: dYdX fee rate 5bps -> 3.5bps (blended effective rate)
* fix: dYdX full history — 90d limit → 1000d (Nov 2023 launch) (#1805)
* feat: add Drift, Jupiter Perps, Vertex to apps leaderboard via DeFiLlama
- Generic DeFiLlama collector (defillama_generic.go): daily fees + revenue split into treasury/lp events
- Correct DeFiLlama slugs: drift-trade, jupiter-perpetual-exchange, vertex-perps
- Fix h24 window to 2 days so daily-bucket protocols show data (was missing for HL/GMX/dYdX)
- Add new deployments to materializer and API meta
- Frontend VENUE map updated with logos for all 3 new protocols
* fix: dYdX fee rate 5bps -> 3.5bps (blended effective rate)
* fix: dYdX full history backfill — limit 90d -> 1000d (covers Nov 2023 launch)
* perf: use recording rules for lz/bridge histogram queries, drop raw rate([24h])
* fix: truncate tron/token-quote methodology strings, telos em-dash in findings
* perf: recording rules for hyperlane histogram queries
* revert: layerzero back to raw queries
* fix(agg-head-lag): update Codex mint to new /api/codex/token endpoint
www.defined.fi/api (createApiTokens GraphQL mutation) is dead as of 2026-08.
New endpoint is /api/codex/token which returns JWE directly.
Still blocked by Vercel TLS checkpoint for Go HTTP — use CODEX_JWT env var
or DEFINED_TOKEN_SERVICE_URL sidecar (Paris box) for automatic refresh.
scrape-cookie: add awaitPromise fix, diagnostic headers, in-browser fetch test.
* revert: layerzero back to raw queries (lz rate24h rule too expensive for VPS)
* fix: remove em dashes in kaia-rpc and aurora-rpc findings
* fix(agg-head-lag): update Codex mint to new /api/codex/token endpoint
www.defined.fi/api (createApiTokens GraphQL mutation) is dead as of 2026-08.
New endpoint is /api/codex/token which returns JWE directly.
Still blocked by Vercel TLS checkpoint for Go HTTP — use CODEX_JWT env var
or DEFINED_TOKEN_SERVICE_URL sidecar (Paris box) for automatic refresh.
scrape-cookie: add awaitPromise fix, diagnostic headers, in-browser fetch test.
* revert: layerzero back to raw queries (lz rate24h rule too expensive for VPS)
* fix: agg head-lag uses DEFINED_TOKEN_SERVICE_URL sidecar for Codex JWE
* feat: add solana-exec harness (pump.fun passive collector) + /apps/exec page
* fix: materializer includes current hour, collector skips failed sigs, api 24h window correct
* fix: remove em dashes in kaia-rpc and aurora-rpc findings
* feat: add solana-exec harness + /apps/exec page (#1811)
* fix(agg-head-lag): update Codex mint to new /api/codex/token endpoint
www.defined.fi/api (createApiTokens GraphQL mutation) is dead as of 2026-08.
New endpoint is /api/codex/token which returns JWE directly.
Still blocked by Vercel TLS checkpoint for Go HTTP — use CODEX_JWT env var
or DEFINED_TOKEN_SERVICE_URL sidecar (Paris box) for automatic refresh.
scrape-cookie: add awaitPromise fix, diagnostic headers, in-browser fetch test.
* revert: layerzero back to raw queries (lz rate24h rule too expensive for VPS)
* fix: agg head-lag uses DEFINED_TOKEN_SERVICE_URL sidecar for Codex JWE
* feat: add solana-exec harness (pump.fun passive collector) + /apps/exec page
* fix: materializer includes current hour, collector skips failed sigs, api 24h window correct
* fix: remove em dashes in kaia-rpc and aurora-rpc findings
* fix(codex-ws): direct dialer + local JWE mint to fix 4403 IP mismatch
* fix: weighted avg for fee/jito metrics across hourly buckets
* fix: log warning when solana-exec collector hits sig limit (#1812)
* fix(agg-head-lag): update Codex mint to new /api/codex/token endpoint
www.defined.fi/api (createApiTokens GraphQL mutation) is dead as of 2026-08.
New endpoint is /api/codex/token which returns JWE directly.
Still blocked by Vercel TLS checkpoint for Go HTTP — use CODEX_JWT env var
or DEFINED_TOKEN_SERVICE_URL sidecar (Paris box) for automatic refresh.
scrape-cookie: add awaitPromise fix, diagnostic headers, in-browser fetch test.
* revert: layerzero back to raw queries (lz rate24h rule too expensive for VPS)
* fix: agg head-lag uses DEFINED_TOKEN_SERVICE_URL sidecar for Codex JWE
* feat: add solana-exec harness (pump.fun passive collector) + /apps/exec page
* fix: materializer includes current hour, collector skips failed sigs, api 24h window correct
* fix: remove em dashes in kaia-rpc and aurora-rpc findings
* fix(codex-ws): direct dialer + local JWE mint to fix 4403 IP mismatch
* fix: weighted avg for fee/jito metrics across hourly buckets
* fix(codex-ws): resolve merge conflict in defined_auth
* fix: log warning when sig limit hit on incremental poll
* feat: paginate getSignaturesForAddress for complete tx coverage (#1813)
* fix: remove dead RPC providers, allow optional p90/p99 for gauge benches
* feat: paginate getSignaturesForAddress for complete tx coverage
* fix(codex-ws): in-process chromedp scraper for fresh JWE every 5min
* fix: remove dead providers from xdc/etc-rpc, allow optional p90/p99 in load.ts
* remove: delete indexing-freshness bench
* feat: paginate getSignaturesForAddress for complete tx coverage
* fix(codex-ws): in-process chromedp scraper for fresh JWE every 5min
* fix: remove dead providers from xdc/etc-rpc, allow optional p90/p99 in load.ts
* feat(solana-exec): accurate tx volume via raw sig pagination + 100-sig enhanced cap
* remove: delete indexing-freshness bench (no data)
* remove: delete indexing-freshness bench
* feat: paginate getSignaturesForAddress for complete tx coverage
* fix(codex-ws): in-process chromedp scraper for fresh JWE every 5min
* fix: remove dead providers from xdc/etc-rpc, allow optional p90/p99 in load.ts
* feat(solana-exec): accurate tx volume via raw sig pagination + 100-sig enhanced cap
* remove: delete indexing-freshness bench (no data)
* fix(codex): utls scraper + GitHub Actions token push (#1818)
* fix(codex): utls scraper + GitHub Actions token push
* fix: use un.defined.fi legacy API for codex JWE minting
un.defined.fi/api createApiTokens still returns valid JWE tokens
without requiring session cookies or CSRF. Try this first via utls,
fall back to www.defined.fi/api/codex/token (needs page visit + CSRF).
generateDefinedJWTToken also switched to un.defined.fi.
* fix(codex-scraper): cap at 3 failures then disable to stop log spam (#1821)
* merge: dev -> main (bench 204 rebuild + all recent fixes) (#1919)
* fix: remove dead providers (BlastAPI shutdown, Ankr key-gated, dRPC/1RPC not supported)
* fix: remove dead providers (BlastAPI shutdown, Ankr key-gated, dRPC/1RPC not supported) (#1789)
* feat: add wave 7 chains to /chains hub (fantom, kusama, hydration, zetachain, haqq, etherlink, chiliz, wemix, songbird, etc-classic, telos, pulsechain, warden, oraichain, peaq)
* feat: add 15 wave 7 chains to /chains hub (#1790)
* fix: remove dead providers (BlastAPI shutdown, Ankr key-gated, dRPC/1RPC not supported)
* feat: add wave 7 chains to /chains hub (fantom, kusama, hydration, zetachain, haqq, etherlink, chiliz, wemix, songbird, etc-classic, telos, pulsechain, warden, oraichain, peaq)
* fix: remove drift and variational from perp venue meta (404 on /perp redirect)
* fix: filter non-provider result links in answers, add bridge to footer
* fix: drop dead RPC providers across 14 chains (DNS failures, 404s, paid-plan blocks)
* fix: hydration draft+placeholder provider, zetachain/songbird em-dash in findings
* fix: hydration draft+placeholder provider, zetachain/songbird em-dash in findings (#1794)
* feat: add /apps leaderboard foundation — specs, Go harness, Postgres schema, alerting
* fix: interface ctx type, float-free toMicroUSDC, goroutine error capture, pagination cursor
* feat: /apps leaderboard foundation (#1797)
* feat: add /apps leaderboard foundation — specs, Go harness, Postgres schema, alerting
* fix: interface ctx type, float-free toMicroUSDC, goroutine error capture, pagination cursor
* fix: dydx collector json key megavaultPnl, cumulative-to-delta PnL, Decimals=0
* feat: add Hyperliquid collector via DeFiLlama (perps/HLP/spot breakdown, 590 days)
* feat: /apps leaderboard page + Go API service (Hyperliquid $45M/30d, dYdX $25K/30d)
* feat(apps): first-party data sources — HL node fills + GMX Subsquid (#1801)
* feat(apps): switch HL collector to node fills, add hl-fills-agg
Replace DeFiLlama proxy with first-party Hyperliquid node fills.
- Reads fee/builderFee from node_fills_by_block on SGP (15.235.224.14)
- hl-fills-agg.py aggregates daily totals, runs as pm2 on SGP:2116
- net_usdc = gross - builder = amount flowing to AF + HLP + deployers
- Fills archive starts 2026-06-01, backfill runs automatically
* feat(apps): add GMX v2 collector (Arbitrum + Avalanche) via Subsquid
First-party data from GMX-operated Subsquid GraphQL endpoint.
Position fees (63% LP / 37% protocol) + swap fees split per governance.
Borrowing fees classified as LP revenue (pool-only, no protocol cut).
Amounts in GMX internal 1e30 precision, stored with Decimals=30.
* fix: dYdX collector — volume×fee-rate instead of MegaVault PnL
* feat: add Gains.trade collector (The Graph, needs THEGRAPH_API_KEY)
* feat: Gains.trade collector via DeFiLlama public API (no key needed)
* feat: gains-trade real-time WS collector via gTrade backend + eth_getTransactionReceipt
* fix: leaderboard UI polish + map treasury->burn bucket for Gains.trade
* feat: add logos + /perp links to apps leaderboard table
* chore: remove defillama gains collector, WS handles gains going forward
* fix: update codex/defined auth to use defined-attestation-token + CODEX_JWT bypass
* feat: add Drift, Jupiter Perps, Vertex to apps leaderboard via DeFiLlama (#1803)
- Generic DeFiLlama collector (defillama_generic.go): daily fees + revenue split into treasury/lp events
- Correct DeFiLlama slugs: drift-trade, jupiter-perpetual-exchange, vertex-perps
- Fix h24 window to 2 days so daily-bucket protocols show data (was missing for HL/GMX/dYdX)
- Add new deployments to materializer and API meta
- Frontend VENUE map updated with logos for all 3 new protocols
* fix: dYdX fee rate 5bps → 3.5bps (blended effective rate) (#1804)
* feat: add Drift, Jupiter Perps, Vertex to apps leaderboard via DeFiLlama
- Generic DeFiLlama collector (defillama_generic.go): daily fees + revenue split into treasury/lp events
- Correct DeFiLlama slugs: drift-trade, jupiter-perpetual-exchange, vertex-perps
- Fix h24 window to 2 days so daily-bucket protocols show data (was missing for HL/GMX/dYdX)
- Add new deployments to materializer and API meta
- Frontend VENUE map updated with logos for all 3 new protocols
* fix: dYdX fee rate 5bps -> 3.5bps (blended effective rate)
* fix: dYdX full history — 90d limit → 1000d (Nov 2023 launch) (#1805)
* feat: add Drift, Jupiter Perps, Vertex to apps leaderboard via DeFiLlama
- Generic DeFiLlama collector (defillama_generic.go): daily fees + revenue split into treasury/lp events
- Correct DeFiLlama slugs: drift-trade, jupiter-perpetual-exchange, vertex-perps
- Fix h24 window to 2 days so daily-bucket protocols show data (was missing for HL/GMX/dYdX)
- Add new deployments to materializer and API meta
- Frontend VENUE map updated with logos for all 3 new protocols
* fix: dYdX fee rate 5bps -> 3.5bps (blended effective rate)
* fix: dYdX full history backfill — limit 90d -> 1000d (covers Nov 2023 launch)
* perf: use recording rules for lz/bridge histogram queries, drop raw rate([24h])
* fix: truncate tron/token-quote methodology strings, telos em-dash in findings
* perf: recording rules for hyperlane histogram queries
* revert: layerzero back to raw queries
* fix(agg-head-lag): update Codex mint to new /api/codex/token endpoint
www.defined.fi/api (createApiTokens GraphQL mutation) is dead as of 2026-08.
New endpoint is /api/codex/token which returns JWE directly.
Still blocked by Vercel TLS checkpoint for Go HTTP — use CODEX_JWT env var
or DEFINED_TOKEN_SERVICE_URL sidecar (Paris box) for automatic refresh.
scrape-cookie: add awaitPromise fix, diagnostic headers, in-browser fetch test.
* revert: layerzero back to raw queries (lz rate24h rule too expensive for VPS)
* fix: remove em dashes in kaia-rpc and aurora-rpc findings
* fix(agg-head-lag): update Codex mint to new /api/codex/token endpoint
www.defined.fi/api (createApiTokens GraphQL mutation) is dead as of 2026-08.
New endpoint is /api/codex/token which returns JWE directly.
Still blocked by Vercel TLS checkpoint for Go HTTP — use CODEX_JWT env var
or DEFINED_TOKEN_SERVICE_URL sidecar (Paris box) for automatic refresh.
scrape-cookie: add awaitPromise fix, diagnostic headers, in-browser fetch test.
* revert: layerzero back to raw queries (lz rate24h rule too expensive for VPS)
* fix: agg head-lag uses DEFINED_TOKEN_SERVICE_URL sidecar for Codex JWE
* feat: add solana-exec harness (pump.fun passive collector) + /apps/exec page
* fix: materializer includes current hour, collector skips failed sigs, api 24h window correct
* fix: remove em dashes in kaia-rpc and aurora-rpc findings
* feat: add solana-exec harness + /apps/exec page (#1811)
* fix(agg-head-lag): update Codex mint to new /api/codex/token endpoint
www.defined.fi/api (createApiTokens GraphQL mutation) is dead as of 2026-08.
New endpoint is /api/codex/token which returns JWE directly.
Still blocked by Vercel TLS checkpoint for Go HTTP — use CODEX_JWT env var
or DEFINED_TOKEN_SERVICE_URL sidecar (Paris box) for automatic refresh.
scrape-cookie: add awaitPromise fix, diagnostic headers, in-browser fetch test.
* revert: layerzero back to raw queries (lz rate24h rule too expensive for VPS)
* fix: agg head-lag uses DEFINED_TOKEN_SERVICE_URL sidecar for Codex JWE
* feat: add solana-exec harness (pump.fun passive collector) + /apps/exec page
* fix: materializer includes current hour, collector skips failed sigs, api 24h window correct
* fix: remove em dashes in kaia-rpc and aurora-rpc findings
* fix(codex-ws): direct dialer + local JWE mint to fix 4403 IP mismatch
* fix: weighted avg for fee/jito metrics across hourly buckets
* fix: log warning when solana-exec collector hits sig limit (#1812)
* fix(agg-head-lag): update Codex mint to new /api/codex/token endpoint
www.defined.fi/api (createApiTokens GraphQL mutation) is dead as of 2026-08.
New endpoint is /api/codex/token which returns JWE directly.
Still blocked by Vercel TLS checkpoint for Go HTTP — use CODEX_JWT env var
or DEFINED_TOKEN_SERVICE_URL sidecar (Paris box) for automatic refresh.
scrape-cookie: add awaitPromise fix, diagnostic headers, in-browser fetch test.
* revert: layerzero back to raw queries (lz rate24h rule too expensive for VPS)
* fix: agg head-lag uses DEFINED_TOKEN_SERVICE_URL sidecar for Codex JWE
* feat: add solana-exec harness (pump.fun passive collector) + /apps/exec page
* fix: materializer includes current hour, collector skips failed sigs, api 24h window correct
* fix: remove em dashes in kaia-rpc and aurora-rpc findings
* fix(codex-ws): direct dialer + local JWE mint to fix 4403 IP mismatch
* fix: weighted avg for fee/jito metrics across hourly buckets
* fix(codex-ws): resolve merge conflict in defined_auth
* fix: log warning when sig limit hit on incremental poll
* feat: paginate getSignaturesForAddress for complete tx coverage (#1813)
* fix: remove dead RPC providers, allow optional p90/p99 for gauge benches
* feat: paginate getSignaturesForAddress for complete tx coverage
* fix(codex-ws): in-process chromedp scraper for fresh JWE every 5min
* fix: remove dead providers from xdc/etc-rpc, allow optional p90/p99 in load.ts
* remove: delete indexing-freshness bench
* feat: paginate getSignaturesForAddress for complete tx coverage
* fix(codex-ws): in-process chromedp scraper for fresh JWE every 5min
* fix: remove dead providers from xdc/etc-rpc, allow optional p90/p99 in load.ts
* feat(solana-exec): accurate tx volume via raw sig pagination + 100-sig enhanced cap
* remove: delete indexing-freshness bench (no data)
* remove: delete indexing-freshness bench
* feat: paginate getSignaturesForAddress for complete tx coverage
* fix(codex-ws): in-process chromedp scraper for fresh JWE every 5min
* fix: remove dead providers from xdc/etc-rpc, allow optional p90/p99 in load.ts
* feat(solana-exec): accurate tx volume via raw sig pagination + 100-sig enhanced cap
* remove: delete indexing-freshness bench (no data)
* fix(codex): utls scraper + GitHub Actions token push (#1818)
* fix(codex): utls scraper + GitHub Actions token push
* fix: use un.defined.fi legacy API for codex JWE minting
un.defined.fi/api createApiTokens still returns valid JWE tokens
without requiring session cookies or CSRF. Try this first via utls,
fall back to www.defined.fi/api/codex/token (needs page visit + CSRF).
generateDefinedJWTToken also switched to un.defined.fi.
* fix(codex-scraper): cap at 3 failures then disable to stop log spam (#1820)
* fix(codex): add sidecar fallback to metadata-coverage and pm-rate-limits (#1824)
* fix(squid): use fee+gas sum when USD amounts cancel out on stable pairs (#1825)
* fix(bridge-fee): add amount_usd=300 filter to all queries (#1827)
Without the filter the bench averaged ++ series together.
HyperCore at (Relay/Mobula ~24%, LiFi/Near 6-24%) was pulling every
provider p50 up to 2-16x its real value.
* fix: filter DeFiLlama null-amount entries in perp-longevity
* feat: paginate getSignaturesForAddress for complete tx coverage
* fix(codex-ws): in-process chromedp scraper for fresh JWE every 5min
* fix: remove dead providers from xdc/etc-rpc, allow optional p90/p99 in load.ts
* feat(solana-exec): accurate tx volume via raw sig pagination + 100-sig enhanced cap
* remove: delete indexing-freshness bench (no data)
* fix(codex): no Chromium in Dockerfile, guard scraper if Chrome absent
* fix(solana-exec): 100ms RPC sleep + strided sample for fee metrics
* feat(solana-exec): real p50/p95 via cu_samples table + sigLimit 1000
* fix(codex): add utls Chrome fingerprint scraper for /api/codex/token
* feat(solana-exec): split RPC/enhanced API — public endpoint for pagination, Helius only for quality sample
* test: GitHub Actions codex token push (test Azure IPs against Vercel)
* fix(solana-exec): idempotent raw counts, Materialize subquery, API time bound, purge cu_samples
* fix(solana-exec): retry GetSignaturesForAddress on 429 with backoff
* fix: use un.defined.fi legacy API for codex JWE minting
un.defined.fi/api createApiTokens still returns valid JWE tokens
without requiring session cookies or CSRF. Try this first via utls,
fall back to www.defined.fi/api/codex/token (needs page visit + CSRF).
generateDefinedJWTToken also switched to un.defined.fi.
* fix(solana-exec): idempotent cu_samples by sig, purge events 90d, purge cu_samples in materializer
* feat: add edge relay for codex token minting
* feat: utls+Tor SOCKS5 for Codex token via Paris box pm2
* fix(codex-scraper): cap at 3 failures then disable to stop log spam
* fix: skip DeFiLlama null-amount entries in perp-longevity
* feat: add EVM exec harness (GMGN ETH/BSC/Base) + revenue leaderboard
- harnesses/evm-exec: Go collector + materializer tracking GMGN fee collector
0xb8159ba378904f803639d274cec79f788931c9c8 across Ethereum, BSC, Base
- ETH native via Etherscan v2 txlist+txlistinternal; BSC BNB via NodeReal
nr_getAssetTransfers (paginated); ERC-20 USDC via eth_getLogs adaptive range
- All amounts use *big.Int end-to-end; event_key disambiguates intra-tx transfers
- Migration 004_evm_exec.sql: evm_exec_events, cursors, block_times, facts
- solana-exec-api: new /api/evm-revenue route with CoinGecko price cache (15min)
- UI: RevenueSummary card (platform x chain 24h USD), ExecChainTabs
(Solana/Ethereum/BSC/Base selector), updated /apps/exec page
* fix: evm-exec audit — withMetadata true, GetCursor error handling
* perf: use NodeReal blockTimestamp to skip eth_getBlockByNumber on BSC native
* fix: nodereal blockTimeStamp is top-level int64 not nested string
* fix: use Etherscan timeStamp for ETH native blocktime, switch to publicnode RPC
* perf: use blockTimestamp from eth_getLogs to skip getBlockByNumber, add -32614 range error
* fix: filter DeFiLlama entries with null/zero amount (hyperliquid false positive)
* feat(solana-exec): multi-platform support + drop Helius dependency
- Replace Helius enhanced API with standard getTransaction JSON-RPC
- Add pump.fun, photon, bullx, gmgn (9 accounts), axiom (20 accounts), fomo
- FOMO: USDC fee detection via SPL token balance diffs (FeeOwners + FeeToken)
- Per-account cursors keyed as plt:feeAccount for independent pagination
- v0 tx support: custom accountKey unmarshaler + loadedAddresses appended
- Sort allSigs by slot before stride-sample (fixes temporal bias on Axiom 20 accounts)
- Add from_cursor idempotency key to raw_counts (migration 003)
- Add solana_exec_cu_samples table + InsertCUSamples/PurgeCUSamples/PurgeEvents
- Materializer calls purge functions after each cycle
* fix(solana-exec): cu_price uses SetComputeUnitLimit, not consumed
Parse ComputeBudget::SetComputeUnitLimit (discriminator 0x03) from tx
instructions. Priority fee schedule is based on requested CU limit, not
actual consumption — dividing by consumed inflates price for over-provisioned txs.
Falls back to cu_consumed when the instruction is absent.
* fix(solana-exec): discriminator 0x02=CULimit 0x03=CUPrice, dedup raw_counts
- ComputeBudget disc 0x02=SetComputeUnitLimit(u32), 0x03=SetComputeUnitPrice(u64).
Previous code read 0x03 as u32 → CULimit was the low 32 bits of the price, random noise.
- CUPriceDeclared read directly from disc 0x03 instruction — no division, no estimation.
cuPriceMicro = CUPriceDeclared; 0 when instruction absent (base fee only, not a price).
- Raw counts now computed from merged+deduped allSigs, not per-account.
A tx touching 2 Axiom collectors was counted twice before; now exactly once.
from_cursor is a compound of all account cursors for idempotency on retry.
* fix(solana-exec): cap backfill at 30 pages per account to avoid unbounded first-run pagination
* feat: memecoin-platforms harness — Fomo vs pump.fun fee comparison via Mobula
* feat: memecoin-platforms harness — Fomo vs pump.fun fee comparison via Mobula (#1831)
* feat: bench 200 solana launchpad wars via Mobula lighthouse
* fix: solana-launchpad-wars unit usd casing
* feat: bench 201 solana trading platform wars (#1835)
* feat(evm-exec): add pump.fun Terminal fee collectors (ETH/BSC/Base)
* feat: add bench 201 solana trading platform wars (GMGN vs Axiom vs Fomo vs Trojan)
* fix: memecoin-platforms YAML spec validation errors (#1836)
* feat(evm-exec): add pump.fun Terminal fee collectors (ETH/BSC/Base)
* feat: add bench 201 solana trading platform wars (GMGN vs Axiom vs Fomo vs Trojan)
* fix: memecoin-platforms spec — correct category, providers format, remove invalid fields
* feat(evm-exec): expose pumpfun in evm-revenue coverage map
* fix: map platform:null to pump-fun — Mobula does not tag native trades
* chore: force staging redeploy for memecoin-platforms cache bust
* feat: add pump-fun, trojan, gmgn, maestro logos and registry entries
* feat: bench 202 app store ratings (#1840)
* feat(evm-exec): add FOMO Gnosis Safe fee wallet confirmed via Relay API
* feat: add bench 202 app store ratings (PumpFun vs Fomo vs GMGN vs Phantom vs Moonshot)
* feat(evm-exec): add FOMO Gnosis Safe fee wallet confirmed via Relay API (#1839)
* fix(evm-exec): remove FOMO — Relay API app filter invalid, address was Relay infra not FOMO
* feat(evm-exec): add Maestro + Banana Gun fee wallets confirmed via DeFiLlama
* fix(evm-exec): remove bad FOMO fee address (#1841)
* fix(evm-exec): remove FOMO — Relay API app filter invalid, address was Relay infra not FOMO
* feat(evm-exec): add Maestro + Banana Gun fee wallets confirmed via DeFiLlama
* feat: add logos and brand colors for app-store-ratings bench providers
* feat: logos for app-store-ratings bench providers (#1842)
* fix(evm-exec): remove FOMO — Relay API app filter invalid, address was Relay infra not FOMO
* feat(evm-exec): add Maestro + Banana Gun fee wallets confirmed via DeFiLlama
* feat: add logos and brand colors for app-store-ratings bench providers
* feat: add review count panel and ledger columns to bench 202 (#1844)
* feat(bench200): on-chain Solana fee parser, Phantom provider, dust filter
* fix: bench number 203 (200 taken by launchpad-wars)
* feat(evm-exec): add Axiom BSC fee receiver (DeFiLlama confirmed)
* fix: escape apostrophe in exec page
* feat: add review count panel and ledger columns to bench 202
* fix: healthz immediate, txCache eviction, drop custom min
* fix: rpc 220ms throttle, error field, 2h trade window
* fix: 1s rpc throttle, 50 trades/token, max 15 fresh lookups/poll
* fix: switch to publicnode rpc
* fix: 30min trade window to stay within rpc history
* feat(apps): unified trading apps leaderboard with per-chain fees
* fix: only rpc-fetch trades < 5min old, 10min mobula window
* fix: remove date field, silence not-found logs, restore 15-cap logic
* fix(apps): add missing logos for bullx, photon, banana-gun (#1848)
* fix(apps): remove perps from /apps page (#1849)
* fix(apps): add missing logos for bullx, photon, banana-gun
* feat: rotating proxy primary + helius fallback, 200ms sleep, 2h window
* fix(apps): remove perps, keep bots only
* feat(apps): window selector + bench links (#1850)
* fix(apps): add missing logos for bullx, photon, banana-gun
* feat: rotating proxy primary + helius fallback, 200ms sleep, 2h window
* fix(apps): remove perps, keep bots only
* feat(apps): 24h/7d/30d window selector, internal bench links, Solana header link
* feat(bench-202): replace Phantom/DEX Screener with Coinbase/Bybit/Kraken/Binance.US (#1852)
* fix(apps): add missing logos for bullx, photon, banana-gun
* feat: rotating proxy primary + helius fallback, 200ms sleep, 2h window
* fix(apps): remove perps, keep bots only
* feat(apps): 24h/7d/30d window selector, internal bench links, Solana header link
* feat(bench-202): swap to pure trading apps, add Coinbase/Bybit/Kraken/Binance.US, remove Phantom/DEX Screener
* fix(memecoin): isolate mobulaClient from HTTPS_PROXY, bump rpc timeouts to 30s
* fix(memecoin): isolate mobulaClient from HTTPS_PROXY, bump rpc timeouts to 30s (#1851)
* fix(memecoin): poll mutex, drop token_address label, sol price init, helius retry, yaml fixes (#1854)
* fix(rpc): correct probe method in UI copy, fix rank #0 display
* fix(l1-finality): exclude stale-gauge rows from ranking + dynamic SEO meta (#1853)
* fix(l1-finality): exclude stale-gauge rows from ranking + dynamic seo meta
- Add MIN_DISPLAY_SUCCESS_PCT=5 in provider-filters; Prom gauges retain
last value on harness failure so a chain at 0% success but non-zero
stale p50 ranked #1 on lower-is-better benches
- Apply filter in ledger-table sortedAll, ranked-bar-chart scored, and
[chain]/page sortLive so all display surfaces agree
- Guard buildKeyFacts against stale-gauge edge case (p50>0, bad rate)
- Add citation_* meta + robots/twitter to per-chain generateMetadata
(parity with parent bench page for academic/LLM citation)
- seo_description uses {{best_name}}/{{best_p50}} so meta reflects live
data instead of a hardcoded chain list
* fix: replace em dash in seo_description (validator)
* fix(test): update hl-history test slugs to canonical form
* fix(rpc-capabilities): sub-ms precision in latency measurement
* fix: add trojan/banana-gun/maestro solana accounts, fix banana-gun EVM addresses
* fix: sub-ms precision in mev/ws harnesses, rank #0 in rpc chains section
* fix(memecoin): 2h TTL on txCache, trim token symbol whitespace (#1857)
* fix(alternatives): twitter cards, noindex draft, remove duplicate ledger (#1858)
Quick wins:
- Add twitter:card/site/title/description/images to generateMetadata
(parity with /benchmarks/[slug] — all X shares were falling back to
the generic site-level twitter meta)
- Add robots noindex/follow when bench.status === "draft" so a
"Not measured yet" alternatives page cannot outrank its bench canonical
- Fix OG image: was missing, now points to /api/og/{bench.slug}
- Replace "Same data as /benchmarks/..." self-disqualification with a
neutral attribution line ("Measurements sourced from...")
Structural:
- Remove full LedgerTable from the page (both count and latency paths).
The complete ranked leaderboard lives on the canonical benchmark URL;
duplicating it here caused identical tables to compete for the same
query on 20+ /alternatives/ pages.
- Replace with a "View full benchmark" CTA card (provider count, metrics
listed) that routes readers to the source instead of re-serving the
data.
- CountLeaderboard kept for count-type benches (primary visualization,
no latency stats path).
- TimeSeriesChart kept (trend over time, distinct from a static table).
- topAlternatives section (top 5 cards, target excluded) kept as the
unique framing angle of the page.
* feat(apps): add related benchmarks section with app-store-ratings and exec links
* fix(memecoin): Trojan audit — skip programs, add maestro, update YAML methodology/FAQ (#1859)
* feat(bench-202): add product pages + binance-us SVG logo for app-store providers
* feat(bench-202): add product pages + binance-us SVG logo for app-store providers (#1860)
* feat(apps): merge exec into /apps, drop /apps/exec, redirect 301
* fix(compare): correct FAQ verbs, add related comparisons cross-links
* fix: use canonicalize for related pair names (ProviderRegistryEntry has no name)
* feat(memecoin): 25 tokens, 4h/100 trades window, fresh cap 40, 4h cache TTL, weighted avg queries (#1863)
* feat(bench-204): trading-app-execution bench + fix benchUrl (#1864)
* feat(bench-204): add trading-app-execution bench page + fix benchUrl
* fix(memecoin): global fresh lookup cap 300 + proxy timeout 5s
* feat(bench-202): add Robinhood + Crypto.com to app-store-ratings (#1865)
* feat(bench-204): add trading-app-execution bench page + fix benchUrl
* fix(memecoin): global fresh lookup cap 300 + proxy timeout 5s
* feat(bench-202): add Robinhood + Crypto.com to app-store-ratings bench
* feat(bench-202): upgrade fomo logo to SVG (#1866)
* feat(bench-204): add trading-app-execution bench page + fix benchUrl
* fix(memecoin): global fresh lookup cap 300 + proxy timeout 5s
* fix(memecoin): disable proxy on mobulaClient + Helius as primary RPC
* rename: meme-bot -> trading-terminal category (#1867)
* fix: pump.fun +8 missing fee wallets, BullX inactive badge
* fix: pump.fun +8 missing fee wallets, BullX inactive badge (#1868)
* feat(alternatives): restore LedgerTable for content density, adjust CTA
* feat: replace EVM harness with DeFiLlama, fix Solana sweep detection
- defillama.ts: fetch fees from DeFiLlama for all 9 platforms (pump.fun,
gmgn, axiom, maestro, banana-gun, photon, trojan, fomo, bullx)
- apps/page.tsx: use DeFiLlama for revenue leaderboard, drop fetchEVMRevenue
and fetchSolPrice, keep fetchExecLeaderboard for Solana exec metrics
- exec-chain-tabs: hide EVM tabs when evmData is null
- helius/client.go: populate SenderAccounts on EnhancedTx (accounts with
negative SOL balance change) for sweep detection
- collector/main.go: skip fee counting when a fee wallet appears as sender
(internal sweep filter); increase maxPages 30->300 for busy wallets
* fix: restore on-chain EVM harness, add Base native ETH scaffold
- apps/page.tsx: revert to fetchEVMRevenue + fetchSolPrice (our own data)
- exec-chain-tabs: show EVM tabs only when evmData available
- evm-exec etherscan.go: add chainID param to all Etherscan functions,
expose ChainIDEthereum/ChainIDBase constants
- evm-exec main.go: add Base native ETH support gated on BASESCAN_API_KEY,
rename collectNativeETH -> collectNativeEtherscan (handles ETH + Base)
- platforms.go: Base NativeEnabled=false until BASESCAN_API_KEY available
- defillama.ts: kept for reference but not used by the page
* feat: add FOMO relay fees via Dune + Base native ETH scaffold
- dune.ts: fetch FOMO relay fees from query 8304081 (dune.tryfomo.fomo_relay_fees)
adds 24h/7d/30d relay fees to FOMO Solana column (96% of FOMO revenue)
- apps/page.tsx: include fomoRelay in window computation
- etherscan.go: ChainIDBase='', BaseScan URL auto-selected when chainID empty
- evm-exec: Base NativeEnabled=true (active when BASESCAN_API_KEY set)
* feat: trading app revenue — on-chain harness + FOMO Dune relay fees
* fix: pump.fun +8 missing fee wallets, BullX inactive badge
* feat(alternatives): restore LedgerTable for content density, adjust CTA
* feat: replace EVM harness with DeFiLlama, fix Solana sweep detection
- defillama.ts: fetch fees from DeFiLlama for all 9 platforms (pump.fun,
gmgn, axiom, maestro, banana-gun, photon, trojan, fomo, bullx)
- apps/page.tsx: use DeFiLlama for revenue leaderboard, drop fetchEVMRevenue
and fetchSolPrice, keep fetchExecLeaderboard for Solana exec metrics
- exec-chain-tabs: hide EVM tabs when evmData is null
- helius/client.go: populate SenderAccounts on EnhancedTx (accounts with
negative SOL balance change) for sweep detection
- collector/main.go: skip fee counting when a fee wallet appears as sender
(internal sweep filter); increase maxPages 30->300 for busy wallets
* fix: restore on-chain EVM harness, add Base native ETH scaffold
- apps/page.tsx: revert to fetchEVMRevenue + fetchSolPrice (our own data)
- exec-chain-tabs: show EVM tabs only when evmData available
- evm-exec etherscan.go: add chainID param to all Etherscan functions,
expose ChainIDEthereum/ChainIDBase constants
- evm-exec main.go: add Base native ETH support gated on BASESCAN_API_KEY,
rename collectNativeETH -> collectNativeEtherscan (handles ETH + Base)
- platforms.go: Base NativeEnabled=false until BASESCAN_API_KEY available
- defillama.ts: kept for reference but not used by the page
* feat: add FOMO relay fees via Dune + Base native ETH scaffold
- dune.ts: fetch FOMO relay fees from query 8304081 (dune.tryfomo.fomo_relay_fees)
adds 24h/7d/30d relay fees to FOMO Solana column (96% of FOMO revenue)
- apps/page.tsx: include fomoRelay in window computation
- etherscan.go: ChainIDBase='', BaseScan URL auto-selected when chainID empty
- evm-exec: Base NativeEnabled=true (active when BASESCAN_API_KEY set)
* feat: add Robinhood Chain (USDG) for gmgn + maestro revenue tracking
* feat: add robinhood chain to evm-exec api (coingecko + native symbol maps)
* fix: audit v2 corrections — banana-gun native off, robinhood blockscout ETH, evm 7d/30d, axiom inactive
* fix(benchmarks): blast/monad co-location caveat, perp-cost-slope oracle note, zetachain probe failure
* fix: Solana fees use exact sum_platform_fee_lamports, not txCount×avg extrapolation
* fix: axiom solana re-activated, banana-gun evm nulled, evmCoverage complete, blockscout txlist added
* fix: numeric precision for token division, remove dead banana-gun evmCoverage entry
* feat(bench-202): add Invo to app-store-ratings bench
* feat(bench-202): add Invo to app-store-ratings (#1871)
* fix: axiom solana re-activated, banana-gun evm nulled, evmCoverage complete, blockscout txlist added
* fix: numeric precision for token division, remove dead banana-gun evmCoverage entry
* feat(bench-202): add Invo to app-store-ratings bench
* fix: banana-gun/base native disabled, Base via Etherscan V2 (drops BaseScan gate)
* fix: FOMO on-chain USDC formula, staleness alert >36h, Solana fee description
* fix: FOMO Dune query rows are cumulative — use MAX per period (8304081 → 8306192)
* feat: add RelatedProvidersSection to hyperliquid/[slug] page
* feat: add RelatedProvidersSection to hyperliquid/[slug] page (#1872)
* fix: axiom solana re-activated, banana-gun evm nulled, evmCoverage complete, blockscout txlist added
* fix: numeric precision for token division, remove dead banana-gun evmCoverage entry
* feat(bench-202): add Invo to app-store-ratings bench
* fix: banana-gun/base native disabled, Base via Etherscan V2 (drops BaseScan gate)
* fix: FOMO on-chain USDC formula, staleness alert >36h, Solana fee description
* fix: FOMO Dune query rows are cumulative — use MAX per period (8304081 → 8306192)
* feat: add RelatedProvidersSection to hyperliquid/[slug] page
* fix: scale Solana fee sum by raw/sampled ratio, FOMO relay null warning, 24h window note
* feat: add live bench appearances section to hl detail page (#1875)
* feat: add fomo-vs-pump-fun compare page + brand whitelist
* fix: unify pump-fun slug (was pumpfun) in app-store-ratings + registry
* fix: unify pump-fun slug + brand color + remove empty platform bench entry
* fix: FOMO + pump.fun canonical display names
* fix: compare page FAQ verb, verdict n=1, provisional badge, provider cards
* fix(memecoin): detect pump.fun AMM WSOL pool-intermediated fees (section 4)
* fix: compare page Lia V3 — verb/verdict/provisional/neutral/fee-disclaimer (#1882)
* feat: bench 205 solana-dex-volume (DeFiLlama, PumpSwap/Axiom/GMGN/Fomo/Trojan/Photon)
* fix: compare Lia V4 — provisional in scope table, split decision, FAQ verb, provider cards (#1884)
* fix: compare page Lia V3 — verb/verdict/provisional/neutral/fee-disclaimer
* fix: compare Lia V4 — provisional scope table, split decision, FAQ verb, provider cards
* fix(memecoin): Jito tip skip, Trojan fee owner, 1.5% cap on section 4
* fix: remove em/en dashes from bench 205 YAML (validator)
* fix: skip capped trades from fee% denominator in memecoin monitor
* fix: shortBenchTitle colon strip, verdict/A1 clean titles, provisional in FAQ, title plural
* fix: shortBenchTitle colon strip, verdict/A1 clean titles, provisional in FAQ, title plural (#1888)
* fix: main metric in scope table, compareTitle, fused verdict, disclaimer, median label
* fix: compare Lia V6 — scope table main column, compareTitle, fused verdict, disclaimer (#1890)
* fix: shortBenchTitle colon strip, verdict/A1 clean titles, provisional in FAQ, title plural
* fix: main metric in scope table, compareTitle, fused verdict, disclaimer, median label
* fix: avoid phantom n=0 platform entries when all trades are cap-skipped
* feat: bench 205 lia fixes - BullX, 7d metrics, take rate, dailyRevenue, layer tags (#1893)
* fix: bench 203/205 accuracy + YAML dash fixes (#1894)
* feat: bench 205 lia fixes - BullX, 7d metrics, take rate, dailyRevenue, layer tags
* fix: bench 203/205 accuracy — rename Cheapest to Explicit platform fees, remove sampleSize=fees from bench 205, soften Aug7 zero-fee claim, fix PumpSwap fee description
* fix: remove residual conflict markers from solana-dex-volume.yml (build broken)
* fix: remove all em-dashes from bench 204 YAML (Zod rejection) (#1895)
* feat(apps): Phantom + formFactor + DL market share + change_1d (#1892)
* feat(apps): add Phantom, formFactor, DL market share + change_1d
* fix: remove em dashes from memecoin-platforms and trading-app-execution YAMLs (Zod rejection)
* feat(apps): Bloom/MevX/Moonshot, dailyRevenue, extreme-move guards, venue footnote
* fix: em-dashes bench 203 YAML + bench 204 page.tsx (#1896)
* fix: remove all em-dashes from bench 204 YAML (Zod rejection)
* fix: em-dashes in bench 203 YAML + bench 204 page.tsx
* fix: drop PumpSwap from bench 205, keep terminals + pump.fun (#1897)
* fix: remove all em-dashes from bench 204 YAML (Zod rejection)
* fix: em-dashes in bench 203 YAML + bench 204 page.tsx
* fix: drop PumpSwap from bench 205, keep terminals + pump.fun launchpad
* feat: pump.fun bonding curve fee wallets + Section 1bis native SOL (#1898)
* feat: add pump.fun to bench 201 via byLaunchpad cross-publish (#1899)
* feat: bench 206 avg swap size + pump.fun in bench 201 + platformTrades24h (#1900)
* feat: add pump.fun to bench 201 via byLaunchpad cross-publish
* feat: bench 206 avg swap size + platformTrades24h gauge
* feat: bench 207 unique daily traders by Solana platform (Dune) (#1901)
* feat: add pump.fun to bench 201 via byLaunchpad cross-publish
* feat: bench 206 avg swap size + platformTrades24h gauge
* feat: add bench 207 unique daily traders by Solana platform via Dune
* fix: Fomo fees bench 201 via DeFiLlama instead of Mobula (#1902)
* feat: add pump.fun to bench 201 via byLaunchpad cross-publish
* feat: bench 206 avg swap size + platformTrades24h gauge
* feat: add bench 207 unique daily traders by Solana platform via Dune
* fix: use DeFiLlama fees for Fomo in bench 201 (Mobula was 9x understated)
* fix: bench 201 FAQ attribution contradiction + wrong source URL (#1904)
* fix: bench 201 editorial pass (no hardcoded numbers, PumpSwap, Fomo fees, FAQ)
* fix: bench 201 FAQ attribution contradiction + wrong source URL
* fix: add phantom logoKey
* fix: bench 201 remove hardcoded numbers, clarify PumpSwap scope, Fomo fees source, expand FAQ
* fix: bench 201 simplify methodology
* fix: remove Phantom from bench 201 (wallet, not trading platform)
* fix: remove marketing metric from Invo methodology bullet (#1908)
* fix: bench 202 editorial pass (#1909)
* fix: remove marketing metric from Invo methodology bullet
* fix: bench 202 editorial pass (dates, methodology, FAQ accuracy)
* fix: bench 203 pump.fun FAQ reflects 0% fee since Aug 7 2026 (#1910)
* fix: bench 203 editorial pass (#1911)
* fix: bench 203 pump.fun FAQ reflects 0% fee since Aug 7 2026
* fix: bench 203 editorial pass (overclaims, apply-equally, unattributed limitation)
* fix: bench 203 unattributed attribution + formula update (#1912)
* fix: bench 203 pump.fun FAQ reflects 0% fee since Aug 7 2026
* fix: bench 203 editorial pass (overclaims, apply-equally, unattributed limitation)
* fix: bench 203 unattributed trades no longer assigned to pump-fun bucket
* fix: bench 203 pump.fun attribution via poolType + editorial fixes (#1913)
* fix: bench 203 pump.fun attribution via poolAddress/bondingCurveAddress instead of empty platform tag
* fix: bench 203 pump.fun attribution via poolType (pumpfun/pumpswap)
* fix: bench 203 YAML methodology + pump.fun FAQ updated for poolType attribution
* fix: bench 203 poolType attribution + bench 201 seo_intro volume ranges (#1914)
* fix: bench 203 pump.fun attribution via poolAddress/bondingCurveAddress instead of empty platform tag
* fix: bench 203 pump.fun attribution via poolType (pumpfun/pumpswap)
* fix: bench 203 YAML methodology + pump.fun FAQ updated for poolType attribution
* fix: loosen bench 201 seo_intro volume ranges (GMGN >100M not 80-100M)
* fix: strip noisy heuristics from memecoin fee capture, use Mobula platformFeesUSD as fallback
* feat: rewrite bench 203 harness to use Dune fee wallet monitoring
* fix: bench 203 - use native SOL balance join + remove pump_fun_solana schema
* fix: bench 203 lighthouse - add byLaunchpad for pump-fun volume
* feat: bench 203 - add Fomo via DeFiLlama (off-chain relay not capturable on-chain)
* fix(203+204): fee-paying volume metric, PLATFORM_DISPLAY mapping, methodology corrections
* fix(204): PLATFORM_DISPLAY missing 5 platforms, findings outdated, FAQ drift
* fix: bench 203 - add data_freshness lag detector, fix pump-fun/Trojan methodology, rewrite YAML for new harness
* feat: bench 203 - add fee-paying volume metric via dex_solana.trades tx join
Implements the self-consistent denominator from the methodology review:
- Dune SQL: add fee_tx_ids + fee_paying_vol CTEs joining fee wallet inflows
to dex_solana.trades on tx_id, taking MAX(amount_usd) per tx to avoid
double-counting multi-hop swaps
- New metrics: fee_paying_rate_pct, coverage_pct, fee_paying_volume_usd_24h
- updateQuery() syncs feesSQL to Dune on startup; handles 404 no-execution
gracefully without dropping health to 0
- YAML: two-metric methodology documented, findings updated with live values
* fix: bench 203 YAML lint - trim disclaimer, strip em dashes
* feat: rebuild bench 204 — YAML-driven metadata, /metrics endpoint, clean ExecBenchTable (#1916)
* fix: bench 203/204/206/207 - editorial updates, bench 207 Dune SQL rework (#1917)
* fix(204): PLATFORM_DISPLAY missing 5 platforms, findings outdated, FAQ drift
* fix: bench 203 - add data_freshness lag detector, fix pump-fun/Trojan methodology, rewrite YAML for new harness
* feat: bench 203 - add fee-paying volume metric via dex_solana.trades tx join
Implements the self-consistent denominator from the methodology review:
- Dune SQL: add fee_tx_ids + fee_paying_vol CTEs joining fee wallet inflows
to dex_solana.trades on tx_id, taking MAX(amount_usd) per tx to avoid
double-counting multi-hop swaps
- New metrics: fee_paying_rate_pct, coverage_pct, fee_paying_volume_usd_24h
- updateQuery() syncs feesSQL to Dune on startup; handles 404 no-execution
gracefully without dropping health to 0
- YAML: two-metric methodology documented, findings updated with live values
* fix: bench 203 YAML lint - trim disclaimer, strip em dashes
* fix(207): rewrite Dune SQL - use dex_solana.trades for unique traders
Remove account_index approach (column unavailable), use fee wallet tx_ids
joined to dex_solana.trades.taker for unique daily trader count.
Remove pump_fun_solana.trades (Spellbook, premium-only).
* fix(207): simplify Dune SQL to COUNT(DISTINCT tx_id) per fee wallet
Remove complex joins (account_index unavailable, dex_solana.trades.taker
unverified). Use direct COUNT(DISTINCT tx_id) from solana.account_activity
— same proven pattern as bench 203. Counts unique fee-touching txs per
platform as proxy for daily active traders.
* fix(207): update YAML disclaimer to reflect tx-based proxy metric
* fix(204): restore ExecBenchTable page (#1924)
* revert: remove bench merges from prod — keep on staging only (#1929)
* feat: bench 202 app-store-ratings cherry-pick to prod (#1935)
* fix: sitemap omits chain URLs on error to prevent smoke-gate 404s (#1937)
* fix: sitemap static fallback filters chains without bench YAML (#1938)
* fix: sitemap omits chain URLs on error to prevent smoke-gate 404s
* fix: sitemap fallback filters chains without bench YAML
* fix: escape apostrophe in apps/exec page (lint) (#1939)
* fix: add missing logo manifest entries (pump-fun, gmgn, moonshot, bullx) (#1941)
* fix: resolve 6 validate-specs errors from dev merge (em-dashes, blast findings length, sol unit, trading-app providers) (#1943)
* fix: remove duplicate provider-registry entries from dev merge (#1944)
* fix: resolve 6 validate-specs errors from dev merge (em-dashes, blast findings length, sol unit, trading-app providers)
* fix: remove duplicate provider-registry entries (coinbase/kraken/etc introduced by dev merge)
* fix: remove duplicate logo-manifest and brand entries from dev merge (#1945)
* fix: resolve 6 validate-specs errors from dev merge (em-dashes, blast findings length, sol unit, trading-app providers)
* fix: remove duplicate provider-registry entries (coinbase/kraken/etc introduced by dev merge)
* fix: remove duplicate logo-manifest and brand entries from dev merge
* fix: add sol unit to views.ts and snapshot.ts (typecheck) (#1946)
* fix: resolve 6 validate-specs errors from dev merge (em-dashes, blast findings length, sol unit, trading-app providers)
* fix: remove duplicate provider-registry entries (coinbase/kraken/etc introduced by dev merge)
* fix: remove duplicate logo-manifest and brand entries from dev merge
* fix: add sol unit to views.ts and snapshot.ts UnitSchema
* fix: wrap Date.now() in useMemo (react-compiler lint) (#1947)
* fix: resolve 6 validate-specs errors from dev merge (em-dashes, blast findings length, sol unit, trading-app providers)
* fix: remove duplicate provider-registry entries (coinbase/kraken/etc introduced by dev merge)
* fix: remove duplicate logo-manifest and brand entries from dev merge
* fix: add sol unit to views.ts and snapshot.ts UnitSchema
* fix: wrap Date.now() in useMemo to satisfy react-compiler purity rule
* fix: move useMemo before early return (hooks rules) (#1948)
* fix: resolve 6 validate-specs errors from dev merge (em-dashes, blast findings length, sol unit, trading-app providers)
* fix: remove duplicate provider-registry entries (coinbase/kraken/etc introduced by dev merge)
* fix: remove duplicate logo-manifest and brand entries from dev merge
* fix: add sol unit to views.ts and snapshot.ts UnitSchema
* fix: wrap Date.now() in useMemo to satisfy react-compiler purity rule
* fix: move useMemo before early return in exec-bench-table (hooks order)
* fix: disable react-compiler for Date.now() in render (#1949)
* fix: resolve 6 validate-specs errors from dev merge (em-dashes, blast findings length, sol unit, trading-app providers)
* fix: remove duplicate provider-registry entries (coinbase/kraken/etc introduced by dev merge)
* fix: remove duplicate logo-manifest and brand entries from dev merge
* fix: add sol unit to views.ts and snapshot.ts UnitSchema
* fix: wrap Date.now() in useMemo to satisfy react-compiler purity rule
* fix: move useMemo before early return in exec-bench-table (hooks order)
* fix: disable react-compiler for Date.now() calls, remove unused useMemo imports
* fix: use module-level NOW_MS constant instead of Date.now() in render (#1950)
* fix: resolve 6 validate-specs errors from dev merge (em-dashes, blast findings length, sol unit, trading-app providers)
* fix: remove duplicate provider-registry entries (coinbase/kraken/etc introduced by dev merge)
* fix: remove duplicate logo-manifest and brand entries from dev merge
* fix: add sol unit to views.ts and snapshot.ts UnitSchema
* fix: wrap Date.now() in useMemo to satisfy react-compiler purity rule
* fix: move useMemo before early return in exec-bench-table (hooks order)
* fix: disable react-compiler for Date.now() calls, remove unused useMemo imports
* fix: use module-level NOW_MS constant instead of Date.now() during render
* feat: inline Solana exec quality into /apps hub, remove /apps/exec subpage
* 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 05/11] 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() {