← Back to blog
BlockchainWeb3Engineering

From Testnet to Mainnet: What Deploying a Real Smart Contract Actually Teaches You

XERES TECH·August 17, 2026·7 min read

Most blockchain demos live on a testnet. Free faucet ETH, no real stakes, no real users. Moment Crystal — our product that seals a procedurally-generated crystal on-chain for every date/time/word combination a user submits — runs its oracle contract on Base Mainnet, with real ETH covering every transaction. That one decision changes almost everything about how you build.

Determinism versus "true randomness" is a real product decision

The original spec wanted a "true quantum randomness" narrative — pull entropy from a live quantum random number generator, market it as unrepeatable. But the product's core promise is "the same input always produces the same crystal," so it can be verified and recreated. Those two ideas are incompatible: you cannot market irreproducible quantum randomness and guarantee reproducibility in the same sentence. We chose determinism — entropy derived via SHA3-512 over the timestamp, the input words, and a salt — and said so plainly in the UI: "Cryptographic Entropy (SHA3-derived)," not "Quantum." A smaller, honest claim beats a bigger claim that falls apart under a support ticket.

Every generation call now costs real money

Once `sealCommit` is a mainnet call, every crystal a user generates burns real gas from an oracle wallet we fund. That reframes rate limiting from a nice-to-have into a financial control. A naive per-IP limiter that resets on every cold start is fine for a testnet demo. On mainnet, it's a wallet-draining bug waiting for a bored visitor with a VPN. We shipped Phase 1 with the simpler limiter in place and flagged the gap explicitly rather than pretending it doesn't exist — a hard spend cap and wallet-balance alerting are the next thing we're adding before this scales past its current audience.

Serverless breaks assumptions your local dev environment never tests

The first storage layer was a disk-based store — fine locally, where the same process handles every request. On Vercel, each API route runs as an isolated serverless function with no shared filesystem. The result: every crystal became unlookupable outside the single request that created it. The share link, the verify page, the image download — all 404, except the original generate response. This is a bug that a local dev server will never surface, because a local dev server doesn't horizontally scale across isolated processes. We rewrote storage against Neon Postgres via Prisma, verified all five routes end-to-end, and treated 'works locally' as informative, not sufficient.

Verification isn't optional if you want anyone to trust the contract

A deployed-but-unverified contract is a black box — anyone inspecting it on Basescan sees bytecode, not source. Verification (via `hardhat verify`) is what lets a skeptical user, auditor, or investor actually read what the contract does instead of taking our word for it. It sounds like a formality until you're the one asking a project to prove their contract does what they say — then it's the entire trust model.

The takeaway

Shipping to mainnet doesn't just mean swapping an RPC URL. It means every assumption that was free to get wrong on a testnet — determinism, rate limits, storage architecture, verification — now has a real cost attached. That's the actual skill in production Web3 work, and it's the same discipline we bring to any system handling money, identity, or trust, blockchain or not.

Have a project in mind?

Talk to us →