diff --git a/apps/landing/.env.example b/apps/landing/.env.example index 4671c62..2c4940a 100644 --- a/apps/landing/.env.example +++ b/apps/landing/.env.example @@ -1,4 +1,4 @@ # Sentrix Chain mainnet RPC — used by Stats section to fetch live block data. # Defaults to the public production endpoint if unset. -NEXT_PUBLIC_MAINNET_RPC=https://sentrix-rpc.sentriscloud.com/rpc +NEXT_PUBLIC_MAINNET_RPC=https://rpc.sentrixchain.com NEXT_PUBLIC_MAINNET_CHAIN_ID=7119 diff --git a/apps/scan/.env.example b/apps/scan/.env.example index 9489304..93e6947 100644 --- a/apps/scan/.env.example +++ b/apps/scan/.env.example @@ -14,12 +14,12 @@ # ── Chain endpoints (public) ──────────────────────────────────────────────── # Mainnet NEXT_PUBLIC_MAINNET_CHAIN_ID=7119 -NEXT_PUBLIC_MAINNET_RPC=https://rpc.sentrixchain.com/rpc +NEXT_PUBLIC_MAINNET_RPC=https://rpc.sentrixchain.com NEXT_PUBLIC_MAINNET_API=https://api.sentrixchain.com # Testnet NEXT_PUBLIC_TESTNET_CHAIN_ID=7120 -NEXT_PUBLIC_TESTNET_RPC=https://testnet-rpc.sentrixchain.com/rpc +NEXT_PUBLIC_TESTNET_RPC=https://testnet-rpc.sentrixchain.com NEXT_PUBLIC_TESTNET_API=https://testnet-api.sentrixchain.com # Which network users land on by default (mainnet | testnet). diff --git a/apps/scan/README.md b/apps/scan/README.md index ab7921d..7d7fc16 100644 --- a/apps/scan/README.md +++ b/apps/scan/README.md @@ -72,11 +72,11 @@ Open http://localhost:3000 | Variable | Description | Default | |---|---|---| -| NEXT_PUBLIC_MAINNET_RPC | Mainnet JSON-RPC | sentrix-rpc.sentriscloud.com/rpc | -| NEXT_PUBLIC_MAINNET_API | Mainnet REST API | sentrix-api.sentriscloud.com | +| NEXT_PUBLIC_MAINNET_RPC | Mainnet JSON-RPC | https://rpc.sentrixchain.com | +| NEXT_PUBLIC_MAINNET_API | Mainnet REST API | https://api.sentrixchain.com | | NEXT_PUBLIC_MAINNET_CHAIN_ID | Mainnet chain ID | 7119 | -| NEXT_PUBLIC_TESTNET_RPC | Testnet JSON-RPC | testnet-rpc.sentriscloud.com/rpc | -| NEXT_PUBLIC_TESTNET_API | Testnet REST API | testnet-api.sentriscloud.com | +| NEXT_PUBLIC_TESTNET_RPC | Testnet JSON-RPC | https://testnet-rpc.sentrixchain.com | +| NEXT_PUBLIC_TESTNET_API | Testnet REST API | https://testnet-api.sentrixchain.com | | NEXT_PUBLIC_TESTNET_CHAIN_ID | Testnet chain ID | 7120 | | NEXT_PUBLIC_DEFAULT_NETWORK | Default network | mainnet | @@ -90,14 +90,14 @@ pnpm build ### Systemd -``` -Port 3006 (mainnet), Port 3007 (testnet) -HOSTNAME=127.0.0.1 (bind localhost only, Nginx reverse proxy) -``` +A single `sentrix-scan.service` runs `pnpm start` from this directory on +port 3005. Both networks are served by the same process; the network is +selected per-request via the cookie / `?network=` query / dedicated +subdomain (Caddy routes both subdomains to the same upstream). -### Nginx +### Caddy ``` -sentrixscan.sentriscloud.com → 127.0.0.1:3006 -testnet-scan.sentriscloud.com → 127.0.0.1:3007 +scan.sentrixchain.com → 127.0.0.1:3005 +scan-testnet.sentrixchain.com → 127.0.0.1:3005 ``` diff --git a/apps/scan/app/[locale]/blocks/[height]/page.tsx b/apps/scan/app/[locale]/blocks/[height]/page.tsx index 8101ab6..231ee87 100644 --- a/apps/scan/app/[locale]/blocks/[height]/page.tsx +++ b/apps/scan/app/[locale]/blocks/[height]/page.tsx @@ -34,7 +34,10 @@ export default function BlockDetailPage({ params }: { params: Promise<{ height: // often a hit on the other. Without this the user dead-ends instead of // getting a one-click switch. const otherNetwork = network === "mainnet" ? "testnet" : "mainnet"; - const { data: blockOther, loading: loadingOther } = useBlock(otherNetwork, blockHeight); + // Tight 2.5s timeout: this is a "is the same height also on the other + // chain?" side-probe. If the peer network is slow or down, we'd + // rather skip the cross-network indicator than block the page render. + const { data: blockOther, loading: loadingOther } = useBlock(otherNetwork, blockHeight, 2500); const [txPage, setTxPage] = useState(1); const [railFilter, setRailFilter] = useState("all"); diff --git a/apps/scan/app/[locale]/tokens/[addr]/page.tsx b/apps/scan/app/[locale]/tokens/[addr]/page.tsx index bed189e..ffde100 100644 --- a/apps/scan/app/[locale]/tokens/[addr]/page.tsx +++ b/apps/scan/app/[locale]/tokens/[addr]/page.tsx @@ -50,7 +50,9 @@ export default function TokenDetailPage({ params }: { params: Promise<{ addr: st useEffect(() => { setLoadingOther(true); - fetchToken(otherNetwork, addr).then((t) => { + // Tight 2.5s timeout: cross-network side-probe shouldn't block the + // primary render past a couple of seconds even if the peer is slow. + fetchToken(otherNetwork, addr, 2500).then((t) => { setTokenOther(t); setLoadingOther(false); }); diff --git a/apps/scan/app/[locale]/tx/[hash]/page.tsx b/apps/scan/app/[locale]/tx/[hash]/page.tsx index dddd7e2..b79c1be 100644 --- a/apps/scan/app/[locale]/tx/[hash]/page.tsx +++ b/apps/scan/app/[locale]/tx/[hash]/page.tsx @@ -42,7 +42,9 @@ export default function TxDetailPage({ params }: { params: Promise<{ hash: strin // "lives on Testnet, click to switch" wall. const { data: tx, loading } = useTransaction(network, hash); const otherNetwork = network === "mainnet" ? "testnet" : "mainnet"; - const { data: txOther, loading: loadingOther } = useTransaction(otherNetwork, hash); + // Tight 2.5s timeout for the cross-network side-probe — see + // blocks/[height]/page.tsx for the same rationale. + const { data: txOther, loading: loadingOther } = useTransaction(otherNetwork, hash, 2500); const autoSwitched = useRef(false); useEffect(() => { if (autoSwitched.current) return; diff --git a/apps/scan/lib/api.ts b/apps/scan/lib/api.ts index f767f21..2522cb3 100644 --- a/apps/scan/lib/api.ts +++ b/apps/scan/lib/api.ts @@ -316,8 +316,13 @@ function normalizeBlockTransactions(block: BlockData | null): BlockData | null { return block; } -export async function fetchBlock(network: NetworkId, index: number) { - const res = await apiFetch(network, `/chain/blocks/${index}`); +// timeoutMs lets callers tighten the budget for cross-network probes +// (block/tx detail pages fire a parallel "is this also on the other +// chain?" query — that side-probe shouldn't be allowed to delay the +// primary render past a couple of seconds even if the other network +// is slow or down). +export async function fetchBlock(network: NetworkId, index: number, timeoutMs?: number) { + const res = await apiFetch(network, `/chain/blocks/${index}`, timeoutMs); return normalizeBlockTransactions(res); } @@ -391,8 +396,10 @@ function normalizeTx(raw: RawTxDetail): TransactionData | null { }; } -export async function fetchTransaction(network: NetworkId, txId: string): Promise { - const res = await apiFetch(network, `/transactions/${normalizeTxHash(txId)}`); +// timeoutMs lets callers tighten the budget for cross-network probes +// (see fetchBlock above for the same rationale). +export async function fetchTransaction(network: NetworkId, txId: string, timeoutMs?: number): Promise { + const res = await apiFetch(network, `/transactions/${normalizeTxHash(txId)}`, timeoutMs); if (!res) return null; return normalizeTx(res); } @@ -813,14 +820,18 @@ function isPrintable(s: string): boolean { return true; } -export async function fetchToken(network: NetworkId, address: string): Promise { +// timeoutMs lets callers tighten the budget for cross-network probes. +export async function fetchToken(network: NetworkId, address: string, timeoutMs?: number): Promise { const addr = normalizeAddress(address); // Native first — `/tokens/{addr}` only resolves for native TokenOp. - const native = await apiFetch(network, `/tokens/${addr}`); + const native = await apiFetch(network, `/tokens/${addr}`, timeoutMs); if (native) return { ...native, standard: "tokenop" }; // Fall back to ERC-20 read-via-RPC for EVM contracts (TokenFactory-deployed // or any other ERC-20). Multicall would be tighter, but per-field calls // keep this readable + work without Multicall3 ABI in this file. + // The EVM RPC path has its own internal 8s timeout that callers can't + // override yet; this is fine because the cross-network probe falls + // through to it only when the native lookup fails fast. return await fetchEvmTokenFromChain(network, addr); } diff --git a/apps/scan/lib/hooks.ts b/apps/scan/lib/hooks.ts index df56d15..eb5ab00 100644 --- a/apps/scan/lib/hooks.ts +++ b/apps/scan/lib/hooks.ts @@ -171,11 +171,11 @@ export function useBlocks(network: NetworkId, count = 10, initial: BlockData[] | ); } -export function useBlock(network: NetworkId, height: number) { +export function useBlock(network: NetworkId, height: number, timeoutMs?: number) { return usePolling( - () => fetchBlock(network, height), + () => fetchBlock(network, height, timeoutMs), 0, - [network, height] + [network, height, timeoutMs ?? 0] ); } @@ -188,11 +188,11 @@ export function useTransactions(network: NetworkId, count = 10, initial: Transac ); } -export function useTransaction(network: NetworkId, hash: string) { +export function useTransaction(network: NetworkId, hash: string, timeoutMs?: number) { return usePolling( - () => fetchTransaction(network, hash), + () => fetchTransaction(network, hash, timeoutMs), 0, - [network, hash] + [network, hash, timeoutMs ?? 0] ); }