diff --git a/public/logos/drift-perp.webp b/public/logos/drift-perp.webp deleted file mode 100644 index 959fbf7e..00000000 Binary files a/public/logos/drift-perp.webp and /dev/null differ diff --git a/public/logos/dydx-perp.svg b/public/logos/dydx-perp.svg deleted file mode 100644 index f142b1ec..00000000 --- a/public/logos/dydx-perp.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/public/logos/gains-network-perp.webp b/public/logos/gains-network-perp.webp deleted file mode 100644 index fed47676..00000000 Binary files a/public/logos/gains-network-perp.webp and /dev/null differ diff --git a/public/logos/gmx-perp.webp b/public/logos/gmx-perp.webp deleted file mode 100644 index 20a9ed2e..00000000 Binary files a/public/logos/gmx-perp.webp and /dev/null differ diff --git a/public/logos/hyperliquid-perp.webp b/public/logos/hyperliquid-perp.webp deleted file mode 100644 index 2720637f..00000000 Binary files a/public/logos/hyperliquid-perp.webp and /dev/null differ diff --git a/public/logos/ostium-perp.webp b/public/logos/ostium-perp.webp deleted file mode 100644 index 29731961..00000000 Binary files a/public/logos/ostium-perp.webp and /dev/null differ diff --git a/public/logos/synthetix-perp.webp b/public/logos/synthetix-perp.webp deleted file mode 100644 index 8c430bd7..00000000 Binary files a/public/logos/synthetix-perp.webp and /dev/null differ diff --git a/src/app/perp-tokens/page.tsx b/src/app/perp-tokens/page.tsx deleted file mode 100644 index 5f64b0a2..00000000 --- a/src/app/perp-tokens/page.tsx +++ /dev/null @@ -1,365 +0,0 @@ -import Link from "next/link"; -import Image from "next/image"; -import { pageMetadata } from "@/lib/page-metadata"; -import { safeJsonLd, buildBreadcrumbJsonLd } from "@/lib/jsonld"; -import { SITE } from "@/data/site"; - -const DESCRIPTION = - "Perp DEX token valuation: FDV, protocol revenue, and P/E ratio for Hyperliquid, GMX, dYdX, Gains Network and more. Live from DeFiLlama, updated hourly."; - -export const metadata: import("next").Metadata = pageMetadata({ - path: "/perp-tokens", - title: "Perp DEX token P/E ratios 2026: Hyperliquid, GMX, dYdX, GNS", - description: DESCRIPTION, -}); - -export const revalidate = 3600; - -const PROTOCOLS: { - slug: string; - name: string; - token: string; - llamaSlug: string; - cgId: string | null; - logo: string; - chains: string[]; -}[] = [ - { - slug: "hyperliquid", - name: "Hyperliquid", - token: "HYPE", - llamaSlug: "hyperliquid", - cgId: "hyperliquid", - logo: "/logos/hyperliquid-perp.webp", - chains: ["Hyperliquid L1"], - }, - { - slug: "gmx", - name: "GMX", - token: "GMX", - llamaSlug: "gmx", - cgId: "gmx", - logo: "/logos/gmx-perp.webp", - chains: ["Arbitrum", "Avalanche"], - }, - { - slug: "gains-network", - name: "Gains Network", - token: "GNS", - llamaSlug: "gains-network", - cgId: "gains-network", - logo: "/logos/gains-network-perp.webp", - chains: ["Arbitrum", "Polygon", "Base"], - }, - { - slug: "dydx", - name: "dYdX", - token: "DYDX", - llamaSlug: "dydx", - cgId: "dydx", - logo: "/logos/dydx-perp.svg", - chains: ["dYdX Chain", "Ethereum"], - }, - { - slug: "drift", - name: "Drift Protocol", - token: "DRIFT", - llamaSlug: "drift", - cgId: "drift-protocol", - logo: "/logos/drift-perp.webp", - chains: ["Solana"], - }, - { - slug: "ostium", - name: "Ostium", - token: "OST", - llamaSlug: "ostium", - cgId: null, - logo: "/logos/ostium-perp.webp", - chains: ["Arbitrum"], - }, -]; - -type ProtocolRow = { - slug: string; - name: string; - token: string; - logo: string; - chains: string[]; - llamaSlug: string; - fdv: number | null; - rev30dAvgDay: number | null; - annualRev: number | null; - pe: number | null; - rev24h: number | null; -}; - -async function fetchLlamaRevenue( - slug: string -): Promise<{ rev24h: number | null; avg30d: number | null }> { - try { - const res = await fetch( - `https://api.llama.fi/summary/fees/${slug}?dataType=dailyRevenue`, - { next: { revalidate: 3600 } } - ); - if (!res.ok) return { rev24h: null, avg30d: null }; - const d = await res.json(); - const rev24h: number | null = d.total24h ?? null; - const chart: [number, number][] = d.totalDataChart ?? []; - const last30 = chart.slice(-30).map(([, v]) => v).filter(Boolean); - const avg30d = - last30.length > 0 - ? last30.reduce((a, b) => a + b, 0) / last30.length - : null; - return { rev24h, avg30d }; - } catch { - return { rev24h: null, avg30d: null }; - } -} - -async function fetchCGFdv(cgId: string): Promise { - try { - const res = await fetch( - `https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&ids=${cgId}&per_page=1&sparkline=false`, - { next: { revalidate: 3600 } } - ); - if (!res.ok) return null; - const d = await res.json(); - const coin = d[0]; - if (!coin) return null; - return coin.fully_diluted_valuation ?? coin.market_cap ?? null; - } catch { - return null; - } -} - -function fmtB(v: number | null): string { - if (v === null) return "—"; - if (v >= 1e9) return `$${(v / 1e9).toFixed(1)}B`; - if (v >= 1e6) return `$${(v / 1e6).toFixed(0)}M`; - return `$${(v / 1e3).toFixed(0)}K`; -} - -function fmtPE(v: number | null): string { - if (v === null) return "—"; - return `${v.toFixed(1)}x`; -} - -export default async function PerpTokensPage() { - const rows: ProtocolRow[] = await Promise.all( - PROTOCOLS.map(async (p) => { - const [{ rev24h, avg30d }, fdv] = await Promise.all([ - fetchLlamaRevenue(p.llamaSlug), - p.cgId ? fetchCGFdv(p.cgId) : Promise.resolve(null), - ]); - const annualRev = avg30d ? avg30d * 365 : null; - const pe = - fdv && annualRev && annualRev > 0 ? fdv / annualRev : null; - return { - ...p, - fdv, - rev30dAvgDay: avg30d, - annualRev, - pe, - rev24h, - }; - }) - ); - - const sorted = [...rows].sort( - (a, b) => (b.annualRev ?? -1) - (a.annualRev ?? -1) - ); - - const breadcrumbLd = { - "@context": "https://schema.org", - ...buildBreadcrumbJsonLd([ - { name: "Home", item: SITE.url }, - { name: "Perp DEX tokens", item: `${SITE.url}/perp-tokens` }, - ]), - }; - - return ( -
-