# Mainnet launch plan

Concrete sequence to get from current state (testnet-validated, internally reviewed) to live on mainnet. Ordered by dependency: earlier phases gate later phases.

**Critical-path estimate:** \~10–14 weeks elapsed time, dominated by audit (4–8 weeks) and trusted-setup ceremony (1–2 weeks). Phases 1 / 4 / parts of 7 prep can run in parallel.

**Hard rule:** do NOT compress the audit or ceremony timeline. Both are designed to surface issues that look like nothing until they don't.

***

## Phase 1: Pre-audit code freeze (\~1–2 weeks of dev work)

Get the codebase into a state where every known bug is resolved and every test is meaningful, so the audit doesn't have to relitigate housekeeping.

1. **Close the `it.todo` gaps**: write a sandbox test that uses `blockchain.getContract(addr).balance` state manipulation to force action-phase failure on the recipient + relayer-fee sends, proving the `+16 SEND_MODE_BOUNCE_ON_ACTION_FAIL` rollback empirically. Currently this is only static-review-verified. Two specific tests in [pool.withdraw.test.ts](https://github.com/tonadocash/monorepo/blob/main/apps/contracts/tests/pool.withdraw.test.ts): recipient send abort → nullifier NOT marked, and relayer-fee send abort → nullifier NOT marked.
2. **Restore the indexer/contract log-format invariant test**: current LOG\_WITHDRAW test inlines the parser; refactor `decodeLogWithdrawOutMessage` into [packages/core/src/indexer.ts](https://github.com/tonadocash/monorepo/blob/main/packages/core/src/indexer.ts) (single source of truth, mirroring the existing deposit decoder), have the relayer import it, then add a sandbox test that emits a real log and runs it through the shared decoder. Catches drift between contract emit and indexer decode in CI.
3. **L-5 doc cleanup**: purge remaining stale references to jetton / on-chain merkle from README, `docs/`, and the SDK surface. Listed as Open in the findings doc; needs to be Resolved before audit handoff.
4. **MIN\_WITHDRAW\_GAS tuning**: now that H-5 is fixed and refunds work correctly, the 0.2 TON gas floor has \~10× headroom. Lower to 0.05 TON (real measured cost is \~0.015 TON for compute + 2 sends + log). Smaller floor = less excess attached value flowing through the refund path = simpler accounting.
5. **N-2 / N-3 / N-4 defense-in-depth** (from the consolidated review):

   * `AdminRecoverStuck`: add `assert(!msg.to.isNone()) throw ERR_BAD_ADDR_FORMAT` (N-2)
   * `Withdraw`: add `assert(!core.recipient.isNone() && !core.relayer.isNone())` (N-3)
   * `AdminRecoverStuck`: add `assert(msg.amount > 0)` (N-4)
   * Document the permanent-owner stance explicitly in [threat-model.md](/protocol-reference/threat-model.md) (N-6)

   Cheap, removes audit noise.
6. **Decide on owner model**: current contract has no owner-rotation. The Tornado-EVM model burned the admin key. Three options:

   * **Burn-key:** deploy with `owner = address_none()`; admin handlers become permanently uncallable. Most credibly neutral. Loses pause + recover-stuck.
   * **Multisig owner:** deploy with `owner = <multisig contract>`. Retains admin paths under shared control.
   * **Single-key owner:** current model. Highest risk; only viable if you intend to publicly burn the key after launch.

   This affects audit scope and operational doc; settle it before audit.
7. **Freeze the contract.** Tag this commit. Every subsequent change requires either re-running the audit or accepting an unverified delta.

***

## Phase 2: Professional external audit (\~4–8 weeks elapsed)

8. **Choose an auditor** with both TON (Tolk/TVM) AND ZK (Groth16, BLS12-381) competence. Few firms have both. Candidates with TON experience: TON Society audits, SlowMist, Halborn (TON practice), CertiK (TON practice). Candidates with ZK competence: Trail of Bits, Veridise, Spearbit. Ideally one firm with both, otherwise dual audit.
9. **Hand off audit scope**:
   * Tolk contracts: `apps/contracts/contracts/**/*.tolk` (pool + auto-generated verifiers)
   * Circuits: `apps/contracts/circuits/**/*.circom`
   * TS crypto surface: `packages/core/src/{poseidon,merkleTree,commitment,notes,proof,tonClient}.ts`
   * Build pipeline: `apps/contracts/scripts/{compile-circuits,export-verifier,setup-ptau,deploy-pool}.ts`
   * The auto-generated `verifier.tolk` files: auditor should verify the codegen pipeline, not just the output
   * This codebase's internal review history at [tolk-security-findings.md](/security/tolk-security-findings.md)
10. **Independent cryptographer review** on Poseidon-BLS12-381 round constants. Circomlib's Poseidon was designed for BN254; the constants are field-independent in principle but a cryptographer should sign off that reducing them mod the BLS12-381 scalar field doesn't weaken algebraic attack resistance. Same for the merkle path bit-ordering convention.
11. **Address audit findings.** Every Critical/High must be Resolved. Mediums require resolution OR documented accepted risk with a written justification signed by the team. After fixes: spot re-audit on changed surface.

***

## Phase 3: Trusted setup ceremony (\~1–2 weeks; cannot start until Phase 2 contract is final)

This is the single most expensive irreversible step. Once done, the zkeys + verifier.tolk are pinned; any contract or circuit change forces re-doing this.

12. **Pick ≥3 independent contributors**: geographically distributed, with reputations to protect. Standard MPC ceremony assumption: ANY one honest contributor preserves soundness, so you only need to trust that at least one of them was uncorrupted.
13. **Phase-1 ptau ceremony**: BLS12-381 powers-of-tau (currently `setup-ptau.ts` runs locally with deterministic entropy). For mainnet: each contributor downloads the previous contributor's output, contributes their own entropy (ideally from `/dev/urandom` on an air-gapped machine), publishes their contribution hash + a signed attestation, hands off to the next. Use snarkjs `powersOfTau2nd contribute` with `--name`/contributor metadata. Beacon at the end with a verifiable random source (e.g., a Bitcoin block hash from a specified future height).
14. **Phase-2 ceremony**: for each of the two circuits (`withdraw`, `merkleUpdate`). Same flow: chain of contributors, beacon at the end. Each circuit's final zkey is what the deploy script will pin.
15. **Generate `MAINNET_ATTESTATION.txt`** at `deploy/ceremony/`:
    * SHA-256 of `withdraw_final.zkey`
    * SHA-256 of `merkleUpdate_final.zkey`
    * At least 3 `signed-by: <pgp-fingerprint>` lines from contributors
    * Beacon source + commitment

[deploy-pool.ts:46-48,211-275](https://github.com/tonadocash/monorepo/blob/main/apps/contracts/scripts/deploy-pool.ts) already enforces this gate; the file just needs to exist and parse.

16. **Re-run `pnpm verifier:export`** against the final zkeys. Commit the regenerated `verifier.tolk` and `verifier_merkle_update.tolk`. Then run `pnpm --filter @tonado/contracts run circuit-shape:update` and commit `apps/contracts/circuits/circuit-shape.json`; the CI circuit-shape guard will then catch any later circuit edit that lands without a re-snapshot.
17. **Publish ceremony transcript**: every contributor's intermediate hashes, attestations, and the final beacon, on a public, immutable medium (IPFS, GitHub release, etc.) so anyone can verify it later.

***

## Phase 4: Operational infrastructure (\~2–3 weeks; can run in parallel with Phase 3)

18. **Mainnet relayer deployment** at [apps/relayer](https://github.com/tonadocash/monorepo/blob/main/apps/relayer/README.md):
    * Provision Postgres (managed, with backups + point-in-time recovery)
    * Run migrations: `pnpm --filter @tonado/relayer run migrate`
    * Deploy the indexer worker as a long-running process (PM2 / systemd / k8s)
    * Configure DDoS protection in front of the REST API (Cloudflare, etc.)
    * Rate limit `/note/check` and `/withdraw` endpoints
19. **Relayer wallet handling**: this is THE highest-value secret in the system (pays for withdraws + holds the fee account):
    * Mnemonic in a secrets manager (AWS Secrets Manager / HashiCorp Vault / GCP Secret Manager), NEVER in `.env`
    * Daily balance-bound alert (drop in fee account triggers oncall)
    * Withdraw caps per hour to limit blast radius if the relayer is compromised
    * Cold reserve wallet that sweeps excess fees out of the hot relayer wallet
20. **Multi-relayer (optional but strongly recommended)**: Tornado-EVM had a relayer registry where users could choose among many relayers. This decentralises the operational risk and the censorship surface. Build the registry contract OR document that v1 ships with a single official relayer + clear path to user-self-relayed withdraws.
21. **Monitoring**: Grafana dashboards for: pool balance drift, nullifier dict size, deposit rate, withdraw rate, relayer wallet balance, indexer lag, proof generation latency. PagerDuty/OpsGenie on critical alerts.
22. **Public RPC fallback**: relayer + SDK should not be hard-coded to a single toncenter endpoint. List ≥2 mainnet TON RPC providers with failover.

***

## Phase 5: Pre-mainnet rehearsal (\~1 week)

23. **Fresh testnet deploy** with the FINAL post-audit contract bytecode + FINAL ceremony zkeys. Run [shell/testnet.sh](https://github.com/tonadocash/monorepo/blob/main/shell/testnet.sh) end-to-end. Manifest archived.
24. **Adversarial testnet exercise**: invite contributors / community to:
    * Deposit and try to withdraw to mismatched recipients
    * Submit malformed proofs / wrong roots
    * Try to drain the pool via admin paths from non-owner wallets
    * Generate ≥100 deposits, run withdraws against stale roots, verify privacy property holds

Document any unexpected behaviour. Bug bounty rates published before this exercise so community has incentive.

25. **Public bug bounty announcement**: before mainnet. Standard rates: Critical $50K–$250K, High $10K–$50K, Medium $1K–$10K. Funded reserve in a dedicated wallet. Immunefi or similar platform.

***

## Phase 6: Mainnet deployment (\~1 day for the deploy itself)

26. **Decide denomination set.** Tornado-EVM offered 0.1 / 1 / 10 / 100 ETH for native + similar tiers for ERC20s. Anonymity set scales with deposits per denomination, so fewer denominations = stronger anonymity. Suggested v1: just 1 TON and 10 TON (start small).
27. **Provision deployer wallet** with sufficient mainnet TON: per-pool storage reserve (\~0.5 TON) + gas + multisig setup costs. \~5 TON per pool minimum.
28. **Run `shell/mainnet.sh`**: the existing gated deploy. It will:
    * Refuse to run without `MAINNET_ATTESTATION.txt` present and verified (✓ already enforced)
    * Refuse to run without `TON_NETWORK=mainnet` explicitly set
    * Run `acton fmt --check`, `acton build`, full test suite as preflight
    * Deploy each pool sequentially
    * Patch `packages/core/src/deployments.ts` with mainnet addresses
    * Commit and tag the release
29. **Post-deploy verification**, for each pool:
    * `pnpm deploy:verify --network mainnet --asset ton --amount X` (get-methods return expected state)
    * Independent toncenter query confirms `state: active`, empty-tree root matches
    * Public announcement of pool addresses pinned in a signed git tag

***

## Phase 7: Soft launch (\~2–4 weeks)

30. **Internal smoke test on mainnet**: team deposits and withdraws small amounts to validate the live flow. Use REAL mainnet TON; smoke test is the cost of doing business.
31. **Limited rollout**: open to a small allowlist (community contributors, audit-period testers) for 1–2 weeks. Watch logs.
32. **Public launch**: coordinated announcement. Have the incident response plan ready.

***

## Non-blocking but worth thinking about now

* **Compliance/legal.** Tornado-EVM developers were indicted by the US DOJ; the protocol was OFAC-sanctioned. This is a real operational risk for the maintainer regardless of jurisdiction. Get qualified legal advice for the team's jurisdiction(s). Document the team's risk posture before any mainnet announcement carries a person's name.
* **Anonymity set seeding.** A fresh pool has 1-deposit anonymity (the most recent depositor is trivially identifiable). The team may want to pre-seed each pool with N "dummy" deposits paid for from a team wallet, where the notes are then burned (commitments deposited but nullifiers never spent). This commits team capital permanently. Tornado-EVM didn't do this; honest deposits accreted slowly.
* **Frontend.** Currently CLI-only. Most users won't tolerate that. A web UI is a separate \~4–6 week project; consider open-sourcing as a static site so multiple front-ends can serve the same pool addresses (IPFS-hosted is the Tornado-EVM model, survives takedowns).
* **Withdrawal note UX.** The note is a single-use private key; lose it = lose the deposit forever. Tornado-EVM addressed this with browser-stored notes + optional encrypted-to-self storage. Build something equivalent before public launch.
* **Relayer revenue model.** With H-5 fixed, the relayer is now properly refunded. But the relayer still pays gas (and storage rent on their own wallet). Either:

  * Set non-zero `fee` in the withdraw proof public inputs (user pays relayer from the denomination)
  * Run the relayer as a public good and absorb the cost
  * Charge a flat off-chain subscription

  Most viable: optional `fee` per withdraw, relayer-chosen rate published on `/relayers` endpoint.

***

## What's already DONE from sixth-review

| Mainnet prerequisite                                                        | Status                                                                                                       |
| --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| Mainnet ceremony gate at deploy-time                                        | ✓ ([deploy-pool.ts](https://github.com/tonadocash/monorepo/blob/main/apps/contracts/scripts/deploy-pool.ts)) |
| Circuit-shape CI guard                                                      | ✓ ([.github/workflows/ci.yml](https://github.com/tonadocash/monorepo/blob/main/.github/workflows/ci.yml))    |
| Poseidon TS↔circuit parity CI                                               | ✓                                                                                                            |
| Field-range checks on all reachable public inputs                           | ✓                                                                                                            |
| C-1 merge-proof remediation                                                 | ✓                                                                                                            |
| H-1 admin cap                                                               | ✓                                                                                                            |
| H-5 refund accounting (withdraw side)                                       | ✓                                                                                                            |
| H-6 empty-body bounce: false footgun (state-fresh heuristic + seed deposit) | ✓                                                                                                            |
| M-8 LOG\_WITHDRAW emission + shared decoder                                 | ✓                                                                                                            |
| L-4 indexer pagination                                                      | ✓                                                                                                            |
| `--burn-owner` deploy mode + sandbox tests                                  | ✓                                                                                                            |
| `MIN_WITHDRAW_GAS` lowered to 0.05 TON                                      | ✓                                                                                                            |
| Refund-correctness regression tests (huge / tiny / boundary overpay)        | ✓                                                                                                            |
| Bounce-on-action-fail behavioural tests (`+16` rollback)                    | ✓                                                                                                            |
| **131-test suite passing** (70 off-chain unit + 61 sandbox)                 | ✓                                                                                                            |
| Testnet e2e validated (pre- and post-H-5 fix)                               | ✓                                                                                                            |

## H-6 / state-fresh empty-body handler

The empty-body short-circuit in [`onInternalMessage`](https://github.com/tonadocash/monorepo/blob/main/apps/contracts/contracts/pool_native.tolk) now uses a state-fresh heuristic: if `nextIndex == 0 && nullifiersCount == 0`, the attached value is retained (this is the deploy state-init path); otherwise, the attached value minus `REFUND_RESERVE` is refunded to the sender via `BounceMode.NoBounce`.

This closes the bounce: false accidental-loss footgun under burn-key mainnet, where admin recovery is permanently unavailable. The pre-first-deposit window is operationally closed by a new **GATE 7 seed deposit** step in [`shell/mainnet.sh`](https://github.com/tonadocash/monorepo/blob/main/shell/mainnet.sh) (script: [`scripts/seed-pool.ts`](https://github.com/tonadocash/monorepo/blob/main/apps/contracts/scripts/seed-pool.ts)).

The seed deposit costs the operator one denomination, permanently locked in the pool. The script prints the note ONCE and discards it. After GATE 7 the pool is safe to advertise publicly.

`shell/mainnet.sh` refuses to exit without completing GATE 7. If the seed fails or is aborted, the pool is in a "pre-launch-unsafe" state and the script demands manual completion via `pnpm seed-pool` before announcement.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.tonadocash.com/operations/mainnet-launch-plan.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
