Skip to content

Commit c4e24b1

Browse files
authored
fix(scan): honour ?network=mainnet|testnet on home + list pages (#57)
Audit on 2026-05-11 caught 22 client-side pages calling useNetwork() without the matching useNetworkFromQuery() — meaning a deeplink like https://scan.sentrixchain.com/?network=testnet rendered MAINNET data because the cookie never flipped. Detail pages already had the call (blocks/[height], tx/[hash], address/[addr], tokens/[addr]). Home + every list page + every leaderboard subpage was missing it. This PR adds the one-line call across all 22 sites with a consistent comment so future pages follow the pattern. Verified live before fix: GET /?network=testnet → page rendered height ~1,681,800 (mainnet) instead of ~3,172,785 (testnet) After fix the cookie flips on first render and the page swaps to the correct network's data. Typecheck clean.
1 parent e8ce951 commit c4e24b1

22 files changed

Lines changed: 50 additions & 22 deletions

File tree

apps/scan/app/[locale]/HomeContent.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { LiveTicker } from "@/components/home/LiveTicker";
2020
import { StickyStatsBar } from "@/components/home/StickyStatsBar";
2121
import { TxChart14d } from "@/components/home/TxChart14d";
2222
import { FreshnessChip } from "@/components/common/FreshnessChip";
23-
import { useNetwork } from "@/lib/network-context";
23+
import { useNetwork, useNetworkFromQuery } from "@/lib/network-context";
2424
import { useStats, useBlocks, useTransactions, useChainPerformance, useMempool, useCurrentEpoch, useChainStatus } from "@/lib/hooks";
2525
import { useLatestBlock, useLatestFinalized } from "@/lib/ws";
2626
import { formatNumber, formatSRX, toMillis } from "@/lib/format";
@@ -77,6 +77,10 @@ function estimateTotalTransactions(
7777
export function HomeContent({ initial }: { initial: HomeBundle }) {
7878
const t = useTranslations("home");
7979
const { network } = useNetwork();
80+
// Honour `?network=mainnet|testnet` deeplinks on the home page too —
81+
// without this, https://scan.sentrixchain.com/?network=testnet would
82+
// render mainnet because the cookie never flips.
83+
useNetworkFromQuery();
8084
const router = useRouter();
8185
const [query, setQuery] = useState("");
8286
const [perfRange, setPerfRange] = useState<"1m" | "5m" | "15m" | "1h" | "24h">("1h");

apps/scan/app/[locale]/accounts/page.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { Address } from "@/components/common/Address";
99
import { PageHeader } from "@/components/common/PageHeader";
1010
import { Pagination } from "@/components/common/Pagination";
1111
import { EmptyState } from "@/components/common/EmptyState";
12-
import { useNetwork } from "@/lib/network-context";
12+
import { useNetwork, useNetworkFromQuery } from "@/lib/network-context";
1313
import { useAccountsTop } from "@/lib/hooks";
1414
import { formatNumber, formatSRX } from "@/lib/format";
1515

@@ -21,6 +21,7 @@ const PAGE_SIZE = 25;
2121
// SentrixSafe surface their human names automatically.
2222
export default function AccountsPage() {
2323
const { network } = useNetwork();
24+
useNetworkFromQuery();
2425
const searchParams = useSearchParams();
2526
const router = useRouter();
2627
const pathname = usePathname();

apps/scan/app/[locale]/analytics/page.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Skeleton } from "@/components/ui/skeleton";
88
import { PageHeader } from "@/components/common/PageHeader";
99
import { StatCard } from "@/components/common/StatCard";
1010
import { EmptyState } from "@/components/common/EmptyState";
11-
import { useNetwork } from "@/lib/network-context";
11+
import { useNetwork, useNetworkFromQuery } from "@/lib/network-context";
1212
import { useStats, useChainPerformance, useValidators } from "@/lib/hooks";
1313
import { formatNumber, formatSRX } from "@/lib/format";
1414
import { fetchDailyStats } from "@/lib/api";
@@ -26,6 +26,7 @@ const AnalyticsCharts = dynamic(() => import("./charts").then((m) => m.Analytics
2626
// so no new API work is needed to light this up.
2727
export default function AnalyticsPage() {
2828
const { network } = useNetwork();
29+
useNetworkFromQuery();
2930
const { data: stats, loading: statsLoading } = useStats(network);
3031
const { data: perf } = useChainPerformance(network, "24h");
3132
const { data: validators } = useValidators(network);

apps/scan/app/[locale]/api-docs/page.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useState } from "react";
44
import { Code, Copy, ExternalLink, Check } from "lucide-react";
55
import { PageHeader } from "@/components/common/PageHeader";
66
import { DetailCard } from "@/components/common/DetailCard";
7-
import { useNetwork } from "@/lib/network-context";
7+
import { useNetwork, useNetworkFromQuery } from "@/lib/network-context";
88
import { cn } from "@/lib/utils";
99

1010
// DECISION: hand-curated API docs page rather than Mintlify or Swagger UI.
@@ -109,6 +109,7 @@ const WS_CHANNELS: Array<{ name: string; method: "eth_subscribe"; summary: strin
109109

110110
export default function ApiDocsPage() {
111111
const { network } = useNetwork();
112+
useNetworkFromQuery();
112113
const restBase = network === "mainnet" ? "https://rpc.sentrixchain.com" : "https://testnet-rpc.sentrixchain.com";
113114
const wsBase = network === "mainnet" ? "wss://rpc.sentrixchain.com/ws" : "wss://testnet-rpc.sentrixchain.com/ws";
114115

apps/scan/app/[locale]/blocks/page.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { Timestamp } from "@/components/common/Timestamp";
1111
import { Copyable } from "@/components/common/Copyable";
1212
import { Pagination } from "@/components/common/Pagination";
1313
import { PageHeader } from "@/components/common/PageHeader";
14-
import { useNetwork } from "@/lib/network-context";
14+
import { useNetwork, useNetworkFromQuery } from "@/lib/network-context";
1515
import { fetchBlocksPage, type BlockData } from "@/lib/api";
1616
import { shortenHash } from "@/lib/format";
1717

@@ -20,6 +20,8 @@ const PAGE_SIZE = 50; // server cap is 100; 50 is comfortable on a phone
2020
export default function BlocksPage() {
2121
const t = useTranslations("blocks");
2222
const { network } = useNetwork();
23+
// Deeplink network switch — same pattern as detail pages.
24+
useNetworkFromQuery();
2325
// Server-paginated against `/chain/blocks?page=N&limit=M`. Each page hits
2426
// the backend fresh so we get accurate "page N of M" semantics across the
2527
// full in-memory window (CHAIN_WINDOW_SIZE = 1000) — much deeper than the

apps/scan/app/[locale]/contracts/page.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { useEffect, useState } from "react";
66
import { PageHeader } from "@/components/common/PageHeader";
77
import { DetailCard } from "@/components/common/DetailCard";
88
import { Address } from "@/components/common/Address";
9-
import { useNetwork } from "@/lib/network-context";
9+
import { useNetwork, useNetworkFromQuery } from "@/lib/network-context";
1010
import { useSourcifyStatus } from "@/lib/sourcify";
1111
import { fetchRecentContracts, type RecentContract } from "@/lib/api";
1212

@@ -73,6 +73,7 @@ const CANONICAL: CanonicalEntry[] = [
7373

7474
export default function ContractsPage() {
7575
const { network } = useNetwork();
76+
useNetworkFromQuery();
7677
const [lookup, setLookup] = useState("");
7778
const [submitted, setSubmitted] = useState<string | null>(null);
7879

apps/scan/app/[locale]/epochs/page.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { PageHeader } from "@/components/common/PageHeader";
77
import { DetailCard } from "@/components/common/DetailCard";
88
import { InfoRow } from "@/components/common/InfoRow";
99
import { StatCard } from "@/components/common/StatCard";
10-
import { useNetwork } from "@/lib/network-context";
10+
import { useNetwork, useNetworkFromQuery } from "@/lib/network-context";
1111
import { useStats, useCurrentEpoch, useValidators } from "@/lib/hooks";
1212
import { formatNumber, formatSRX } from "@/lib/format";
1313

@@ -34,6 +34,7 @@ const PAST_TO_SHOW = 12;
3434

3535
export default function EpochsPage() {
3636
const { network } = useNetwork();
37+
useNetworkFromQuery();
3738
const { data: stats } = useStats(network);
3839
const { data: epoch } = useCurrentEpoch(network);
3940
const { data: validators } = useValidators(network);

apps/scan/app/[locale]/forks/page.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { GitFork, CheckCircle2, AlertTriangle, Clock } from "lucide-react";
44
import { PageHeader } from "@/components/common/PageHeader";
55
import { DetailCard } from "@/components/common/DetailCard";
6-
import { useNetwork } from "@/lib/network-context";
6+
import { useNetwork, useNetworkFromQuery } from "@/lib/network-context";
77
import { useStats } from "@/lib/hooks";
88
import { FORKS, forkStateAt, type ForkEntry } from "@/lib/forks/registry";
99
import { formatNumber } from "@/lib/format";
@@ -23,6 +23,7 @@ import { cn } from "@/lib/utils";
2323

2424
export default function ForksPage() {
2525
const { network } = useNetwork();
26+
useNetworkFromQuery();
2627
const { data: stats } = useStats(network);
2728
const height = stats?.height ?? 0;
2829

apps/scan/app/[locale]/gas/page.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Flame, Zap, Gauge, Turtle, Rabbit, Rocket } from "lucide-react";
55
import { PageHeader } from "@/components/common/PageHeader";
66
import { DetailCard } from "@/components/common/DetailCard";
77
import { StatCard } from "@/components/common/StatCard";
8-
import { useNetwork } from "@/lib/network-context";
8+
import { useNetwork, useNetworkFromQuery } from "@/lib/network-context";
99
import { useStats, useMempool } from "@/lib/hooks";
1010
import { formatNumber } from "@/lib/format";
1111
import { fetchBlocksPage, type BlockData } from "@/lib/api";
@@ -30,6 +30,7 @@ const SENTRI_PER_SRX = 100_000_000;
3030

3131
export default function GasPage() {
3232
const { network } = useNetwork();
33+
useNetworkFromQuery();
3334
const { data: stats } = useStats(network);
3435
const { data: mempool } = useMempool(network);
3536

apps/scan/app/[locale]/leaderboard/account/active/page.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ import { Skeleton } from "@/components/ui/skeleton";
77
import { Address } from "@/components/common/Address";
88
import { Pagination } from "@/components/common/Pagination";
99
import { RankBadge } from "@/components/common/RankBadge";
10-
import { useNetwork } from "@/lib/network-context";
10+
import { useNetwork, useNetworkFromQuery } from "@/lib/network-context";
1111
import { useActiveAccounts } from "@/lib/hooks";
1212
import { formatNumber } from "@/lib/format";
1313

1414
const PAGE_SIZE = 25;
1515

1616
export default function MostActiveAccountsPage() {
1717
const { network } = useNetwork();
18+
useNetworkFromQuery();
1819
const { data: accounts, loading } = useActiveAccounts(network, 100);
1920
const [page, setPage] = useState(1);
2021

0 commit comments

Comments
 (0)