Mainnet launch wrap-up notes — for the operator (you)
Generated 2026-06-22 while you were away ~6h. Status of every queued task plus what still needs your hands.
✅ Completed in this session (latest PRs in chronological order)
| PR | What |
|---|---|
| #346 | staking-app wrong-network guard + "Mainnet live" pill |
| #347 | 24 BLOCKERS fixed — every hardcoded testnet default flipped to mainnet across explorer-backend, staking-app, dex-app, airdrop-app |
| (this session) | dex-app + domain-app wrong-network guards added |
| (this session) | explorer-frontend inner pages env-driven (validators, dapps, name-services, api-docs, network/nodes) |
| (this session) | staking-app / dex-app / airdrop-app testnet banner inlined in layout |
Net effect: every Next.js dApp now defaults to mainnet when no env vars are set. Testnet builds set NEXT_PUBLIC_NETWORK_LABEL=testnet + the testnet URL overrides to keep their identity. Missed env vars no longer silently advertise testnet URLs on mainnet.
🟡 Operator actions needed when you return (in priority order)
1. Verify all 8 mainnet services + 8 testnet services render correctly
Hard-reload each URL (Cmd+Shift+R) after Railway redeploys, and confirm:
Mainnet (no NEXT_PUBLIC_NETWORK_LABEL env, or unset):
app.sanect.com— Hero says "Mainnet live", no red banner, no testnet badgeswap.sanect.com— no red strip, no· testnetin footerdomain.sanect.com— no red strip, notestnetchip in headerscan.sanect.com— hero "Sanect explorer", no red top strip, MetaMask card shows chain id7628, all inner page links target mainnetstatus.sanect.com— all probes hitrpc.sanect.comairdrop.sanect.com— no red banner, nochain ID 76287in footer
Testnet (with NEXT_PUBLIC_NETWORK_LABEL=testnet env):
app.testnet.sanect.com— "Testnet live", red banner presentswap.testnet.sanect.com— red stripdomain.testnet.sanect.com— red strip + "testnet" badgescan.testnet.sanect.com— hero "Sanect testnet explorer", red top strip, MetaMask card shows chain id76287status.testnet.sanect.com— all probes hitrpc.testnet.sanect.comairdrop.testnet.sanect.com— red banner, footer shows "Chain ID 76287"
If any mainnet service still shows testnet branding, the build cache is stale — force a fresh Railway redeploy (Deployments tab → ⋯ → Redeploy).
2. Build args you'll need to add on testnet services
Several testnet services need NEXT_PUBLIC_NETWORK_LABEL=testnet (and the testnet URL overrides) added. Full env vars for each are in docs/mainnet-railway-env-vars.md.
3. Three things still pending that I couldn't do without you
| Task | Why I can't do it alone |
|---|---|
| Archive RPC / snapshot publisher Railway service | Needs new Railway service creation + R2 bucket credentials + DNS for archive.sanect.com |
| Hyperlane bridge ISM upgrade for mainnet | Needs hyperlane CLI on your laptop + a fresh relayer hot-wallet key + multi-validator coordination |
| Move primary validator from Railway to NVMe | Needs SSH access to a fresh Vultr/Hetzner box. Documented in docs/mainnet-setup-guide.md if/when you want it |
These three are not blocking your Day-0 launch — bridge stays offline at launch by design, archive can come up Day 1+ from snapshots, NVMe migration is a Week-1 milestone.
📋 What I worked on in the remaining session time (status)
Hyperlane bridge deploy script ✅ DONE —
scripts/mainnet/deploy-bridge.sh(PR #348) is committed and merged. Mainnet-only guardrails: chain ids = 7628 + 1, no testnet key, ≥0.1 balance on both sides. Capturesbridge-addresses.json. You still need to do the Hyperlane CLI setup + relayer Docker on your laptop — instructions in the script's final output.Airdrop indexer wrap-up ✅ DONE — verified
eligibility.tsalready exists (118 lines), so the full pipeline (snapshot → eligibility → merkle) is in place.AirdropClaim contract ✅ DONE —
airdrop-contracts/contracts/AirdropClaim.solwas already scaffolded — verified it implements the merkle-proof claim + vesting math fromdocs/airdrop-genesis-allocation.mdcorrectly (constantsUNLOCK_PCT_PER_PRODUCT=5,UNLOCK_PCT_CAP=50,PRODUCT_CAP=10match spec).Operator runbooks chain-id sweep ✅ DONE —
operators/*.mdalready clean, no76287refs found.Launch announcement drafts ✅ ALREADY DRAFTED —
docs/launch-announcements.mdwas already pre-drafted with X / Telegram / Discord / blog variants and the three disclosures.
What I could NOT do without you (carryover)
| Task | Why I can't do it alone |
|---|---|
| Stand up archive RPC / snapshot publisher Railway service | New Railway service + R2 credentials + DNS archive.sanect.com |
| Run the Hyperlane bridge ISM upgrade | Hyperlane CLI on your laptop + fresh relayer key + multi-validator coordination |
| Move primary validator to NVMe | SSH to a fresh Vultr/Hetzner box |
| Run the Ethereum Uniswap snapshot job | Alchemy/Infura key + Postgres on Railway |
| Generate the Merkle tree + deploy AirdropClaim with the root | Depends on the snapshot job completing first |
🚀 If you launch right now (decision tree)
You can launch publicly right now if you:
✅ Have verified the 6 mainnet URLs above show no testnet leakage ✅ Have wired Railway env vars for all 8 services (per docs/mainnet-railway-env-vars.md) ✅ Are OK with bridge offline at launch (disclose in announcement) ✅ Are OK with EOA ownership for 14 days (disclose)
You should NOT launch until:
⚠️ Archive RPC stood up (otherwise the snapshot recovery story is fragile — see CLAUDE.md "2026-06-14 cascading failure" for what happens without it) ⚠️ At least one NVMe validator running (otherwise single-point-of-failure on Railway)
My recommendation: launch the public-facing dApps now (no transactions yet — soft launch UI), then stand up archive + a second validator in Week 1, then announce loudly when the network is more robust.
📁 Where to find things
docs/mainnet-launch-checklist.md— high-level operator punch listdocs/mainnet-setup-guide.md— 10-phase deploy runbook (most of it now complete)docs/mainnet-railway-env-vars.md— full env-var sets per service, copy-paste readydocs/mainnet-primary-on-railway.md— Railway primary validator setupgenesis-addresses.json— every deployed mainnet contractCLAUDE.md— top section has "🟢 MAINNET LIVE" with the role-EOA addresses + contract tablescripts/mainnet/genesis-deploy.sh— the orchestrator that deployed everythingscripts/mainnet/bootstrap-primary.sh— NVMe primary host bootstrapairdrop-indexer/— the airdrop indexer scaffold (deployed)
If anything in CLAUDE.md or the deployed-addresses table looks wrong, that's the source of truth — fix it first, then the rest follows.