Skip to content

Mainnet config audit + env-var diff

Last updated 2026-06-16. Pre-launch audit of scripts/localnet.sh and the per-service env vars needed when flipping testnet → mainnet.


Part 1 — scripts/localnet.sh audit

Run NETWORK=mainnet scripts/localnet.sh to build the mainnet genesis. Below is what the script branches on, what's hard-coded the same for both networks, and what to override.

What the mainnet branch already gets right

ParamValueSource
Chain IDsanect_7628-1NETWORK=mainnet branch
EVM chain ID7628NETWORK=mainnet branch
Moniker defaultsanect-mainnet-node0NETWORK=mainnet branch
Governance periodsWas wrong: SDK defaults are 2d voting / 2d deposit / 10⁷ base-unit deposit, not 14d. Mainnet genesis shipped with them. Fixed on chain by MsgUpdateParams (see scripts/mainnet/gov-params-update.md); localnet.sh now sets 14d / 14d / 1d expedited / 10,000 SNCT / 50,000 SNCT for mainnetexplicit mainnet block in localnet.sh

What's the same on both networks (intentional — verify these are still right for mainnet)

ParamValueNote
Bech32 prefixsnct / snctvaloper / snctvalconspubShould stay
Base denomasnctShould stay
Display denomsnct (1e18 base)Should stay
BASEFEE / MIN_GAS_PRICE1 gweiRecommend bumping mainnet to 5-10 gwei to discourage spam. Easy override: MIN_GAS_PRICE=10000000000.000000000000000000
max_validators50Stay
TOTAL_SUPPLY_BASE1,000,000,000 SNCTStay
GENTX_AMOUNT (self-bond)1000 SNCTStay
Block max_gas150,000,000Stay
Min self-delegation100 SNCTCLAUDE.md says mainnet should be 1000 SNCT (10²¹ asnct). Override: MIN_SELF_DELEGATION_BASE=1000000000000000000000
signed_blocks_window10,000Stay
slash_fraction_downtime0.0001Stay
slash_fraction_double_sign0.05Stay
community_tax0.02Stay
inflation_max0.20 (20%)Stay (Cosmos Hub curve)
inflation_min0.07 (7%)Stay
timeout_commit400msStay

What needs operator decisions before mainnet genesis

DecisionDefault if you don't setRecommended for mainnet
Single genesis address vs splitSingle $VAL_KEY gets full 1BUse post-genesis GenesisSplit Foundry script to distribute 1B → 3 Safes after genesis is built (testnet pattern)
Initial supply distributionAll to VAL_KEYSame — split via on-chain script after launch
BASE_FEE1 gwei5-10 gwei (override env)
MIN_GAS_PRICE1 gwei5-10 gwei (override env)
Validator self-stake at genesis1000 SNCT (one validator)Run separate gentx for each launch-day validator BEFORE collect-gentxs

Genesis build command for Day 0

bash
NETWORK=mainnet \
CHAIN_ID=sanect_7628-1 \
MIN_GAS_PRICE=10000000000.000000000000000000 \
BASE_FEE=10000000000.000000000000000000 \
BASEFEE=10000000000 \
MIN_SELF_DELEGATION_BASE=1000000000000000000000 \
HOMEDIR=/tmp/sanect-mainnet-genesis \
VAL_MNEMONIC="<the launch-day validator's mnemonic>" \
bash scripts/localnet.sh

After this builds, you have a genesis.json at /tmp/sanect-mainnet-genesis/config/genesis.json ready to ship with the Docker image.

What the script does NOT do for mainnet (manual steps)

  1. Doesn't run GenesisSplit.s.sol — do that on-chain at block N after launch.
  2. Doesn't include extra validators' gentx — those go through sanectd genesis add-genesis-account + gentx for each separately, OR via the new validator script.
  3. Doesn't bake any pre-deployed contracts. Privacy / DEX / Domain / Bridge contracts deploy via Foundry scripts post-genesis.

Part 2 — Per-service env-var diff (testnet → mainnet)

Each Railway service needs its env updated. Below is the COMPLETE delta per service.

Node services (primary, 2nd, 3rd, val-4, snapshot-publisher)

Env varTestnet valueMainnet value
CHAIN_IDsanect_76287-1sanect_7628-1
EVM_CHAIN_ID762877628
MONIKERper nodeper node, new
SEED_NODE_URLhttps://rpc.testnet.sanect.comhttps://rpc.sanect.com
SEED_NODE_IDtestnet primary node idmainnet primary node id
SEED_PEER_HOSTp2p.testnet.sanect.com:46430p2p.sanect.com:46430
EXTERNAL_P2P_ADDRESS (primary only)p2p.testnet.sanect.com:46430p2p.sanect.com:46430
MIN_GAS_PRICE100000000010000000000 (recommended)
EXPLORER_HEARTBEAT_URLtestnet explorermainnet explorer
PUBLIC_RPC_URLper testnet domainper mainnet domain

Snapshot publisher (separate mainnet instance)

Env varTestnet valueMainnet value
All the above (Node services row)testnetmainnet
R2_BUCKETsanect-snapshotssanect-snapshots-mainnet
R2_PUBLIC_URLhttps://sanect-snapshots.testnet.sanect.comhttps://snapshots.sanect.com
SNAPSHOT_PUBLISHERtruetrue
SNAPSHOT_UPLOAD_INTERVAL_HOURS66

staking-app

Env varTestnet valueMainnet value
NEXT_PUBLIC_CHAIN_IDsanect_76287-1sanect_7628-1
NEXT_PUBLIC_EVM_CHAIN_ID762877628
NEXT_PUBLIC_NODE_URLhttps://rpc.testnet.sanect.comhttps://rpc.sanect.com
NEXT_PUBLIC_EXPLORER_URLtestnethttps://scan.sanect.com
NEXT_PUBLIC_SHIELDED_POOL_ADDRESStestnet poolmainnet pool (deploy after launch)
FAUCET_PRIVATE_KEYtestnet hot walletUNSET (no mainnet faucet)
FAUCET_RPC_URLtestnet RPCUNSET
FAUCET_DRIP_SNCT100UNSET
Branding"TESTNET" bannerRemove banner from staking-app/components/Header.tsx

dex-app

Env varTestnet valueMainnet value
NEXT_PUBLIC_EVM_CHAIN_ID762877628
NEXT_PUBLIC_NODE_URLtestnet RPCmainnet RPC
NEXT_PUBLIC_EXPLORER_URLtestnetmainnet
NEXT_PUBLIC_DEX_FACTORYtestnetmainnet (post-launch deploy)
NEXT_PUBLIC_DEX_ROUTERtestnetmainnet (post-launch deploy)
NEXT_PUBLIC_WSNCTtestnetmainnet (post-launch deploy)
NEXT_PUBLIC_DEX_INIT_CODE_HASHtestnetmainnet (post-launch deploy, will be different)
NEXT_PUBLIC_MASTERCHEFtestnetmainnet (post-launch deploy)
NEXT_PUBLIC_TREASURY_EMITTERtestnetmainnet (post-launch deploy)
NEXT_PUBLIC_TEST_* (TUSD/TUSDC/TWBTC/TWETH)testnet test tokensUNSET — mainnet has no test tokens
NEXT_PUBLIC_SEPOLIA_RPCsepoliamainnet ETH RPC (after Ethereum-mainnet bridge deploy)
NEXT_PUBLIC_SANECT_BRIDGE_ADAPTERtestnet adaptermainnet adapter (post-launch deploy)
NEXT_PUBLIC_SEPOLIA_BRIDGE_SYNTHETICsepolia syntheticETH-mainnet synthetic (post-launch deploy)

explorer-backend

Env varTestnet valueMainnet value
NODE_URLhttps://rpc.testnet.sanect.comhttps://rpc.sanect.com
DATABASE_URLtestnet PGmainnet PG (new DB or reset volume)
KNOWN_NODEStestnet validator listmainnet validator list
SHIELDED_POOL_ADDRESStestnet poolmainnet pool (post-launch deploy)
NAME_REGISTRY_ADDRESStestnetmainnet .snct (post-launch deploy)
NAME_RESOLVER_ADDRESStestnetmainnet (post-launch deploy)
NAME_REVERSE_REGISTRAR_ADDRESStestnetmainnet (post-launch deploy)

explorer-frontend

Env varTestnet valueMainnet value
Chain banner / "TESTNET" red barshownhidden (remove from explorer/frontend/app/layout.tsx)
NEXT_PUBLIC_API_URLtestnet backend URLmainnet backend URL
NEXT_PUBLIC_RPC_URLtestnetmainnet

Hyperlane relayer container

ConfigTestnet valueMainnet value
HYP_RELAYCHAINSsanect,sepoliasanect,ethereum
HYP_DEFAULTSIGNER_KEYDEPLOYER (testnet)NEW rotated key (P0 #4)
~/.hyperlane/chains/sanect/metadata.yamltestnet chainmainnet chain entry
~/.hyperlane/chains/sanect/addresses.yamltestnet Mailbox + ISMmainnet Mailbox + ISM
Sepolia → Ethereum chain switchyesyes

Custom domains (Cloudflare DNS)

DomainTargetPurpose
rpc.sanect.commainnet primary Railway / Vultr proxyEVM RPC
scan.sanect.commainnet explorer-frontend RailwayExplorer
app.sanect.commainnet staking-app RailwayStaking dApp
swap.sanect.commainnet dex-app RailwaySwap dApp
domain.sanect.commainnet domain dApp Railway.snct dApp
snapshots.sanect.comR2 bucket sanect-snapshots-mainnetSnapshot manifest
p2p.sanect.com (CNAME, DNS-only)mainnet primary's Railway TCP proxyCometBFT P2P
docs.sanect.comdocs VitePressDocs (same as testnet, no change)

Part 3 — Order of operations on Day 0

  1. Run mainnet genesis builder locally — produces genesis.json
  2. Deploy primary mainnet validator container with the new genesis baked in
  3. Stand up 3 more validators (use scripts/spin-up-mainnet-validator.sh once it's written) pointing at primary as seed
  4. Wait for all 4 to reach height = 1 (primary self-stakes at gentx)
  5. Deploy protocol contracts in this order:
    • ShieldedPool (with 0x7cB61D… as initial owner)
    • HonkVerifier
    • DEX (Factory, Router, WSNCT, init code hash)
    • .snct registry + resolvers
    • Hyperlane core deploy (Mailbox + default ISM)
    • SanectHypAdapter + StubIgp + TrustedRelayerIsm
  6. Deploy 3 Gnosis Safes on the live mainnet
  7. Run GenesisSplit Foundry script — transfers all contract ownerships to GOVERNANCE_SAFE + sends initial balances to TREASURY_SAFE / OPS_SAFE
  8. Rotate Hyperlane relayer key — generate fresh keypair, fund, redeploy relayer container
  9. Update all Railway env vars per the diffs above, redeploy each service
  10. Verify every app loads + connects + chain functions: swap, bridge, stake, register .snct name, shield, unshield
  11. Snapshot publisher redeploy with mainnet R2 + SNAPSHOT_PUBLISHER=true
  12. Public announcement (per docs/launch-announcements.md when that PR lands)
  13. Pre-commit Phase 1 airdrop snapshot block publicly (Tweet + Telegram)