Mainnet Migration: LightChain Testnet v2 → Mainnet
This guide documents what changes when LightChallenge moves from LightChain testnet v2 (chain 8200) to mainnet. The verification architecture itself doesn’t change — we keep the lean ChallengePayLightchainAttestor + LightChain v2 worker network. The migration is mostly: address swaps, multi-sig signer rotation, attestor key rotation, and re-pointing the off-chain workers at mainnet endpoints.
Current State (Testnet v2, chain 8200)
| Component | What we control | Address / endpoint |
|---|---|---|
ChallengePay | Deployed by us | 0xeC651C299E978667fCDeF706Ef5Dd285e56EFd0b |
ChallengePayLightchainAttestor | Deployed by us | 0xb400770550Db25Af86b1c3CC380e92BC777E3360 |
Treasury | Deployed by us | 0xF8E32344CC311A82f20112484F686b1038122FF3 |
MultiSigWallet (protocol + admin recovery) | Deployed by us, 2-of-3 signers | 0xd9e56435290A2e8f93D6F8a0e329478D8E851469 |
| LightChain v2 gateway | Operated by LightChain Foundation | https://chat-api.testnet.lightchain.ai |
| LightChain v2 relay | Operated by LightChain Foundation | wss://relay.testnet.lightchain.ai/ws |
LightChain JobRegistry | Operated by LightChain Foundation | 0x531b3a87c5d785441b9cf55b98169f20fd9056a7 |
| Dispatcher signing key | LightChain Foundation | 0xd92d9989d6a7A5aEcB4Da59D414Fb0673aDC2519 |
The v1 archive (AIVMInferenceV2, LCAIValidatorRegistry, ChallengePayAivmPoiVerifier, ChallengeTaskRegistry) remains on testnet v2 chain but is unused. It will not be deployed to mainnet.
What we need from LightChain (mainnet launch)
| # | Item | Why |
|---|---|---|
| 1 | Mainnet chain ID | RPC config, Hardhat network config, wallet config |
| 2 | Mainnet RPC endpoint | All on-chain interactions |
| 3 | Mainnet gateway URL (SIWE auth) | judgeChallengeViaLightchain round-trip |
| 4 | Mainnet relay WSS URL | Encrypted response channel |
| 5 | Mainnet JobRegistry address | Job anchor + JobCompleted audit trail |
| 6 | Mainnet dispatcher signing key | prepareSession signature |
| 7 | Mainnet fee per job (current testnet: 0.02 LCAI) | Worker fee on submitJob |
| 8 | Active staked workers on mainnet | Without workers, jobs don’t get picked up |
| 9 | Disputer key / arbitration policy | For dispute resolution if a worker lies |
The contract surface is identical (same JobRegistry ABI on testnet and mainnet); only addresses + URLs change.
Code changes required
1. Environment variables
Update .env, webapp/.env.local, Vercel, and fly secrets:
# Chain
NEXT_PUBLIC_CHAIN_ID=<mainnet-chain-id>
NEXT_PUBLIC_RPC_URL=<mainnet-rpc-url>
LIGHTCHAIN_RPC=<mainnet-rpc-url>
NEXT_PUBLIC_EXPLORER_URL=<mainnet-explorer-url>
# Our redeployed contracts
NEXT_PUBLIC_CHALLENGEPAY_ADDR=<mainnet-challengepay>
CHALLENGEPAY_LIGHTCHAIN_ATTESTOR_ADDRESS=<mainnet-attestor>
NEXT_PUBLIC_TREASURY_ADDR=<mainnet-treasury>
NEXT_PUBLIC_MULTISIG_ADDR=<mainnet-multisig>
# LightChain v2 mainnet endpoints
LIGHTCHAIN_GATEWAY_URL=<mainnet-gateway>
LIGHTCHAIN_RELAY_WSS=<mainnet-relay-wss>
LIGHTCHAIN_JOB_REGISTRY=<mainnet-jobregistry>
# Worker wallet (must be funded on mainnet, registered as ChallengePay dispatcher + attestor)
LCAI_WORKER_PK=0x<funded-mainnet-key>2. Redeploy our contracts on mainnet
Same deploy sequence as testnet (see /guides/deploy). All our contracts are independent of LightChain’s v2 contracts at deploy time — ChallengePayLightchainAttestor doesn’t need any LightChain address as a constructor argument.
npx hardhat deploy --network lightchain-mainnet
RUN_POST_DEPLOY_CONFIG=true npx hardhat deploy --network lightchain-mainnet
npx tsx scripts/syncAbis.ts3. Multi-sig rotation
The 2-of-3 protocol multi-sig signers should be rotated for mainnet. The testnet signer keys (0x4480…, 0x74aD…, 0x3917…) are not appropriate for mainnet custody.
For each replacement, the existing signers submit a multi-sig tx calling replaceSigner(oldAddr, newAddr) on the wallet itself, then 2 of 3 confirm + execute. Repeat for each of the 3 slots.
4. Attestor key rotation
The LCAI_WORKER_PK testnet wallet should be rotated to a mainnet hot-wallet. The new wallet must be:
- Registered as a
ChallengePaydispatcher:setDispatcher(newAddr, true)(admin) - Authorised on the attestor:
attestor.setAttestor(newAddr, true)(attestor admin)
After rotation, deauthorise the old key:
attestor.setAttestor(oldAddr, false)setDispatcher(oldAddr, false)
5. Hardhat config
Add the mainnet network in hardhat.config.ts:
"lightchain-mainnet": {
url: process.env.MAINNET_RPC_URL,
chainId: <mainnet-chain-id>,
accounts: [process.env.DEPLOYER_PRIVATE_KEY],
},6. Database migrations
All migrations through 050_aivm_jobs_per_participant.sql apply equally to mainnet — no chain-specific data structures. Run npx tsx db/migrate.ts against the mainnet Postgres to apply.
Verification checklist
Before switching production traffic to mainnet:
Contracts
-
ChallengePay.admin()returns the expected mainnet admin -
ChallengePay.dispatchers(<LCAI_WORKER_PK_addr>)returns true -
ChallengePay’s default verifier (or per-challenge verifier) isChallengePayLightchainAttestor -
Treasury.hasRole(OPERATOR_ROLE, <ChallengePay>)returns true -
ChallengePayLightchainAttestor.attestor(<LCAI_WORKER_PK_addr>)returns true -
MultiSigWallet.signers()returns the rotated mainnet signer set
LightChain integration
-
judgeChallengeViaLightchainround-trip succeeds (runscripts/demoLightchainJudge.tsagainst mainnet) -
JobCompletedevent from a mainnet worker is observable for our jobs - Attestor
attest(...)succeeds (runscripts/demoChallengeLeanE2E.tsagainst mainnet) -
ChallengePay.submitProofForaccepts the proof and marks the participant as winner
End-to-end
-
scripts/demoChallengeFullLifecycle.tsagainst mainnet completes without errors - Winner receives funds via
autoDistribute - No-winner case routes correctly to the protocol multi-sig
Off-chain
- PM2 workers all
onlineafter restart with mainnet env -
claimsIndexerpicks up the test challenge’sWinnerClaimedevent - Webapp
/me/challengesshows the test challenge correctly (on-chain truth)
Files that reference chain-specific addresses
These files contain testnet addresses and must be updated during migration. Most are env-driven, but a few hold hard-coded references:
| File | What to update |
|---|---|
.env, webapp/.env.local | All NEXT_PUBLIC_*_ADDR, *_ADDRESS, RPC URLs |
webapp/public/deployments/lightchain.json | All contract addresses (regenerated by syncAbis.ts) |
| Vercel environment variables | Production env vars |
Fly.io secrets (fly secrets list) | Off-chain worker env |
scripts/ops/reimburseChallenge13.ts | Hard-coded MULTISIG constant — bump to mainnet multi-sig if reusing the script |
The chain redeploy runbook (docs/chain-redeploy-runbook.md) covers the 6 surfaces that hold chain identity (contracts, bundled JSON, local envs, Vercel envs, Fly secrets, DB rows). The helper script scripts/ops/syncChainAddresses.ts automates the env propagation.
Timeline estimate
| Phase | What | Blocked on |
|---|---|---|
| Phase 1 | LightChain Foundation provides mainnet endpoints + JobRegistry address | LightChain mainnet launch |
| Phase 2 | Deploy our contracts to mainnet, set up post-deploy config | Phase 1 |
| Phase 3 | Run smoke + lifecycle demos against mainnet | Phase 2 |
| Phase 4 | Rotate multi-sig signers + attestor key to mainnet hot wallets | Phase 3 |
| Phase 5 | Switch production traffic (DNS, Vercel env, Fly secrets) | Phase 4 |
The actual code changes are minimal (env vars + redeploy). The critical dependency is LightChain having an active worker network on mainnet.