Overview
There is an entirely separate, self-contained "platform statistics" subsystem — src/app/api/stats/route.ts, src/lib/stats.ts, and src/hooks/useStats.ts — that is completely disconnected from the rest of the app and permanently returns fabricated data. lib/stats.ts's fetchStats():
export async function fetchStats(): Promise<StatsData> {
const factoryId = process.env.NEXT_PUBLIC_FACTORY_CONTRACT_ID;
if (factoryId) {
// TODO: wire to Soroban RPC when the factory contract is deployed.
// Steps: 1. import sorobanRpcUrl ... 6. Return source: "live" once real data is flowing.
}
// ── Demo mode ──────────────────────────────────────────────────────────────
const BASE_TVL_MILLIONS = 302;
const BASE_USERS = 30_738;
const sparkline = buildSparkline(BASE_TVL_MILLIONS);
...
return { tvl: formatUsd(tvlRaw), tvlRaw, totalUsers: BASE_USERS, sparkline, lastUpdated: ..., source: "demo" };
}
The if (factoryId) block contains only comments — no return statement — so execution always falls through to the "Demo mode" section regardless of whether a real factory contract is configured. Even once a future contributor follows the TODO's own numbered steps and adds real RPC calls inside that if block, unless they also remember to add a return, their real data will be silently computed and then overwritten by the demo fallback that unconditionally runs immediately afterward — the TODO instructs what to build but the surrounding control flow doesn't leave a slot for it to actually take effect. Separately, and more immediately: nothing in the app currently uses this subsystem at all. grep -rln "useStats" src finds only useStats.ts itself; no page or component imports the useStats() hook. The homepage (src/app/page.tsx) gets its stats from usePlatformStats() (useSorobanQuery.ts), a completely different, already-real (factory-driven) code path. /api/stats is a live, deployed, cached (revalidate = 60) Next.js route with detailed, professional-looking JSDoc ("all clients see fresh data without hammering the RPC") that is reachable by anyone (curl /api/stats) and returns deterministic pseudo-random fake numbers forever, while doing and being used by nothing in the actual product.
Requirements
- Either wire this subsystem into an actual consumer (fix the missing
return and genuinely implement the "live" branch, then use useStats() somewhere), or remove it entirely (route.ts, stats.ts, useStats.ts) if usePlatformStats() is the intended long-term source of truth for platform stats.
- If kept, fix the unreachable-
return structural bug so the TODO's instructions can actually take effect once implemented.
- If kept but still in demo mode,
/api/stats's response should not claim to be live/cached-for-freshness in its own documentation without a source: "demo" field surfaced somewhere a caller can act on (it does return source, but nothing downstream reads or displays it, since nothing downstream exists).
Acceptance Criteria
Additional Notes
More precise references
src/lib/stats.ts:53-91 (fetchStats) — confirmed the if (factoryId) { ...only comments... } block (lines 56-72) has no return, and the demo-mode code (lines 74-91) executes unconditionally afterward.
src/app/api/stats/route.ts:1-27 — confirmed this is a real, deployed Next.js route (export const revalidate = 60) with JSDoc describing production-grade caching behavior ("Response is cached by Next.js and revalidated every 60 seconds so all clients see fresh data without hammering the RPC").
src/hooks/useStats.ts:1-30 — confirmed via grep -rln "useStats" src --include="*.ts*" (excluding the file itself) that this hook has zero consumers anywhere in src/app or src/components.
src/app/page.tsx:16-18,83-98 — confirmed the homepage instead uses usePlatformStats/useTotalUserCredits from useSorobanQuery.ts, a wholly separate, factory-driven data path with no relationship to lib/stats.ts.
- Confirmed no
stats.test.ts exists anywhere (find src -iname "*stats*test*" returns nothing), so this entire subsystem — dead or not — has zero test coverage either way.
Additional edge cases
useStats.ts's own JSDoc describes a fallback story for static export ("When /api/stats is unavailable (e.g. static GitHub Pages export), the queryFn falls back to calling fetchStats() directly from the browser") — this is a real, thoughtful design for a deployment mode (output: "export") that next.config.ts/README.md reference elsewhere in the project, which makes the complete lack of any consumer even more likely to be an oversight (half-built infrastructure) rather than intentionally-retired code.
- If this subsystem is kept and wired up, note that
BASE_USERS = 30_738 and BASE_TVL_MILLIONS = 302 are the exact same numbers hardcoded independently in src/components/Navbar/Navbar.tsx ("30,738", "$302M") — see the separate Navbar hardcoded-stats issue in this batch; the two should not be fixed independently of each other without noticing they're currently coincidentally-identical fake numbers from two unrelated files.
Implementation sketch (if kept)
if (factoryId) {
try {
const { sorobanRpcUrl } = await import("@/config");
const rpc = new SorobanRpc.Server(sorobanRpcUrl);
const poolIds = await invokeView(rpc, factoryId, "get_pools", []);
const lockedTotals = await Promise.all(poolIds.map((id) => invokeView(rpc, id, "get_total_locked", [])));
const tvlRaw = /* sum + USD conversion */;
return { tvl: formatUsd(tvlRaw), tvlRaw, totalUsers: /* real count */, sparkline: /* real or omitted */, lastUpdated: new Date().toISOString(), source: "live" };
} catch (err) {
console.warn("[SmartDrop] live stats fetch failed, falling back to demo:", err);
// fall through to demo mode intentionally
}
}
// demo mode as today
Test/reproduction plan
fetchStats() with NEXT_PUBLIC_FACTORY_CONTRACT_ID set and RPC mocked to return real pool data asserts source === "live" and tvl/totalUsers reflect the mocked values, not BASE_TVL_MILLIONS/BASE_USERS.
- If removed instead: confirm
next build succeeds with the route deleted and no remaining imports reference lib/stats.ts/useStats.ts.
Cross-references
Overview
There is an entirely separate, self-contained "platform statistics" subsystem —
src/app/api/stats/route.ts,src/lib/stats.ts, andsrc/hooks/useStats.ts— that is completely disconnected from the rest of the app and permanently returns fabricated data.lib/stats.ts'sfetchStats():The
if (factoryId)block contains only comments — noreturnstatement — so execution always falls through to the "Demo mode" section regardless of whether a real factory contract is configured. Even once a future contributor follows the TODO's own numbered steps and adds real RPC calls inside thatifblock, unless they also remember to add areturn, their real data will be silently computed and then overwritten by the demo fallback that unconditionally runs immediately afterward — the TODO instructs what to build but the surrounding control flow doesn't leave a slot for it to actually take effect. Separately, and more immediately: nothing in the app currently uses this subsystem at all.grep -rln "useStats" srcfinds onlyuseStats.tsitself; no page or component imports theuseStats()hook. The homepage (src/app/page.tsx) gets its stats fromusePlatformStats()(useSorobanQuery.ts), a completely different, already-real (factory-driven) code path./api/statsis a live, deployed, cached (revalidate = 60) Next.js route with detailed, professional-looking JSDoc ("all clients see fresh data without hammering the RPC") that is reachable by anyone (curl /api/stats) and returns deterministic pseudo-random fake numbers forever, while doing and being used by nothing in the actual product.Requirements
returnand genuinely implement the "live" branch, then useuseStats()somewhere), or remove it entirely (route.ts,stats.ts,useStats.ts) ifusePlatformStats()is the intended long-term source of truth for platform stats.returnstructural bug so the TODO's instructions can actually take effect once implemented./api/stats's response should not claim to be live/cached-for-freshness in its own documentation without asource: "demo"field surfaced somewhere a caller can act on (it does returnsource, but nothing downstream reads or displays it, since nothing downstream exists).Acceptance Criteria
useStats()is actually consumed by a real page/component, or the entire/api/stats+lib/stats.ts+useStats.tssubsystem is removed.NEXT_PUBLIC_FACTORY_CONTRACT_IDand implementing the TODO's steps actually results infetchStats()returningsource: "live"data — i.e. theif (factoryId)block has a realreturnpath, not a fallthrough.fetchStats()live-branch test, or removal is reflected by deletingstats.test.ts-shaped gaps rather than leaving orphaned untested code).Additional Notes
More precise references
src/lib/stats.ts:53-91(fetchStats) — confirmed theif (factoryId) { ...only comments... }block (lines 56-72) has noreturn, and the demo-mode code (lines 74-91) executes unconditionally afterward.src/app/api/stats/route.ts:1-27— confirmed this is a real, deployed Next.js route (export const revalidate = 60) with JSDoc describing production-grade caching behavior ("Response is cached by Next.js and revalidated every 60 seconds so all clients see fresh data without hammering the RPC").src/hooks/useStats.ts:1-30— confirmed viagrep -rln "useStats" src --include="*.ts*"(excluding the file itself) that this hook has zero consumers anywhere insrc/apporsrc/components.src/app/page.tsx:16-18,83-98— confirmed the homepage instead usesusePlatformStats/useTotalUserCreditsfromuseSorobanQuery.ts, a wholly separate, factory-driven data path with no relationship tolib/stats.ts.stats.test.tsexists anywhere (find src -iname "*stats*test*"returns nothing), so this entire subsystem — dead or not — has zero test coverage either way.Additional edge cases
useStats.ts's own JSDoc describes a fallback story for static export ("When/api/statsis unavailable (e.g. static GitHub Pages export), the queryFn falls back to callingfetchStats()directly from the browser") — this is a real, thoughtful design for a deployment mode (output: "export") thatnext.config.ts/README.mdreference elsewhere in the project, which makes the complete lack of any consumer even more likely to be an oversight (half-built infrastructure) rather than intentionally-retired code.BASE_USERS = 30_738andBASE_TVL_MILLIONS = 302are the exact same numbers hardcoded independently insrc/components/Navbar/Navbar.tsx("30,738","$302M") — see the separate Navbar hardcoded-stats issue in this batch; the two should not be fixed independently of each other without noticing they're currently coincidentally-identical fake numbers from two unrelated files.Implementation sketch (if kept)
Test/reproduction plan
fetchStats()withNEXT_PUBLIC_FACTORY_CONTRACT_IDset and RPC mocked to return real pool data assertssource === "live"andtvl/totalUsersreflect the mocked values, notBASE_TVL_MILLIONS/BASE_USERS.next buildsucceeds with the route deleted and no remaining imports referencelib/stats.ts/useStats.ts.Cross-references
onlineUsers = totalUsers * 0.1) withinSorobanService.getPlatformStats(), the code path actually used by the homepage. This issue is about a wholly separate, entirely-unused, 100%-fabricated subsystem that nothing in the product currently reads from at all.