Go to production
Everything in the other guides works on a laptop. Production adds what a laptop never tests: several processes, restarts, a lying or lagging endpoint, a key that must never leak, and money that must never move twice. Production architecture shows how the pieces fit together; this page is the checklist to walk through before real money moves.
Production checklist
- [ ] One
new CryptoAio({ namespace })per tenant. Scopes are not tenant boundaries. - [ ]
lifecycle.requireIdempotencyKey: true, with keys taken from durable business records. - [ ] Durable, shared stores (operations, locks, sequences, cursors) that pass the contract suites. The memory stores are for tests and single processes.
- [ ]
sensitivefields encrypted at rest, with a retention policy. - [ ] Custody signers (
callbackSigner) for significant balances. Noexportablekeys. No keys in config files or source control. Every credential in aSecret. - [ ] An idempotent, short
beforeSignhook in front of your own policy engine. - [ ] Two or three independent providers per network, so proofs are cross-checked: with two, an outage of one leaves the other deciding alone, so use three for production proofs. No
publicpreset in production. - [ ] Tron: memos are public forever and cost a fee; never put personal data in one. Use the
trongridpreset with a key on mainnet (keyless TronGrid fails there), next to a second, independent provider. - [ ]
await bc.ready()at startup, to fail fast on a missing SDK or a misconfigured provider. - [ ]
aio.operations.recover()at startup, thenaio.monitor.start()workers. Alerts onoperation.stalled,nonce.gap,recovery.skippedandprovider.misconfigured. - [ ] Complete withdrawals only on
finalwithprovenevidence. Credit deposits, which areobservedin every family, only once readfinal, and automatically (or above your risk threshold) only once an independent provider reads the same transfer final (Crediting deposits). Dedupe deposits on the transfer id. On Bitcoin, skip a transfer whosetois among itsfromaddresses (change, a cancel's refund), and never use a scanned deposit address as a change address. - [ ]
await aio.close()on shutdown. - [ ] EVM:
maxFeePerGasandmaxGasLimitset to your fee policy (1,000 gwei per gas and 2^24 gas by default). - [ ] Bitcoin: your own Esplora, with two or three independent endpoints as the
provider;lifecycle.broadcastFanoutof 2 or more;nonWitnessUtxoleft on for hardware signers; andallowExternalChangeAddressonly for a verified address. - [ ] Solana: two or three independent keyed or self-hosted providers;
maxComputeUnitPriceset to your fee policy; a store that keeps each Attempt'sorderingwhole; after a refusal, retry only withrebroadcastor the same idempotency key; credit SPL deposits by the owner wallet (transfer.to). - [ ] TON: two or three independent toncenter-compatible pairs (
providerandindexer), archival where they serve proofs, with a key on toncenter, never thepublicpreset; wallets whose keys nothing else holds; a store that keeps each Attempt'sordering(TonSeqnoOrdering,validFromincluded) exactly; a server clock in sync (builds refused for chain-time skew mean fix the clock); and jetton deposits credited only from the arrival in the owner's jetton wallet's history, never from the owner's notification, deduped on that transfer id, not on the trace id; the independent read that confirms a TON deposit uses another provider and indexer pair.