Playbook

Mainnet Web3Modal and Wallet Hardening (Mainnet Web3modal Wallet Hardening)

From MetaMask-only to Web3Modal + WalletConnect + Coinbase WalletLink; harden chainId, gas, and addresses.

NFT Collection Mint & Mainnet Hardening

Part 4 of 4

CBD All-Stars and Confident Gorillas mint surfaces: WIP whitelist funnel, IPFS metadata, placeholder→reveal pipeline, and Web3Modal mainnet wallet hardening.

NFT mint and mainnet architecture diagram

Mainnet breaks the single-wallet assumption

Gorillas mainnet 1.8 drops the All-Stars/1.4 window.ethereum.enable() path. Web3Modal opens with cacheProvider; WalletConnect (Infura id) and custom Coinbase WalletLink (chainId: 1) join providerOptions. ConnectWeb3 → ethers Web3Provider → address; contract instances speak through the modal provider.

Before (All-Stars / early)
  window.ethereum only → Web3

After (mainnet 1.8)
  Web3Modal
    ├─ WalletConnect (Infura)
    ├─ WalletLink / Coinbase (chainId 1)
    └─ injected (MetaMask)
         ↓
  provider → ethers Web3Provider
         ↓
  getNftContract(Web3(provider))

This part closes the series with a mainnet readiness checklist: wallet diversity, network asserts, gas, and address/ABI discipline.

Concepts, defined where they first appear

📦 Web3Modal
Multi-wallet connect UI; WalletConnect/WalletLink injected via providerOptions.

📦 WalletConnect
QR / mobile wallet bridge; needs an Infura (or RPC) id.

📦 WalletLink
Coinbase Wallet connector; configured with appName, networkUrl, chainId.

📦 cacheProvider
Remembers the last successful provider; reconnect UX with stale-session risk.

RPC / Infura project ids are configuration — never secrets in the playbook. Keys live in env, not the repo.

Why MetaMask-only is not enough

Landing FAQ may still say MetaMask; mainnet users want Coinbase Wallet and mobile WalletConnect. A single injected path cuts conversion. 1.8 decision: multi-connector modal, network: 'mainnet'.

User segments
  Desktop MetaMask
  Mobile WC
  Coinbase WalletLink
       ↓
  one ConnectWeb3() API

Connection lifecycle

ConnectWeb3: web3Modal.connect() → Web3Provider → getAddress. DisconnectWeb3: clearCachedProvider + provider.disconnect + reload. getNetwork reads netId from the provider. Contract getters build Web3.eth.Contract from initialState.provider — the old appWeb3() Infura fallback must not be the mainnet signing path.

connect → address
getNetwork → chainId check
mint/reveal only if chainId OK
disconnect → clear cache → reload

ADR: Web3Modal as wallet facade

Decision: mint/reveal utils must not bind directly to window.ethereum; the modal facade supplies address and provider. Plus: adding a connector is a product decision. Minus: dual ethers + web3 stack and cacheProvider staleness. Mitigation: assert chainId before mint; clear cache on disconnect.

ADR-04 Web3Modal facade
  UI → ConnectWeb3 / DisconnectWeb3
  Utils → provider from modal state
  Guard → chainId === 1 before send
  Reject → wrong net / no provider

Mainnet failure playbook

  1. Stub contract addresses in production — tx looks fine, state is wrong. 2) Wrong network — sign on Rinkeby/Goerli, mainnet supply unchanged. 3) gasPrice: 0 — underpriced in the mempool. 4) ABI mismatch — multipleMint/reveal encode fails. 5) Pinata/Infura keys in the client bundle — secret leak (never commit).
Hardening checklist
  ✓ real mainnet addresses
  ✓ chainId === 1 gate
  ✓ dynamic gas / tip
  ✓ ABI ↔ deployment lock
  ✓ secrets in env only

The mappings that get confused most often

❌ window.ethereum is enough; modal is luxury
✓ Multi-connector is a mainnet conversion requirement

❌ cacheProvider means always stay connected
✓ Clear stale providers with disconnect + clearCachedProvider

❌ Put Infura/Pinata keys in constants
✓ Keys in env/secret store; minimal scope to the client

A checklist for auditing your own system

  1. After connect, do you assert chainId === 1?
  2. Is provider non-null before mint send?
  3. Did gasPrice: 0 survive into the production build?
  4. Are nft/reserve/auction addresses distinct and mainnet?
  5. Were WalletConnect / WalletLink tried on real devices?

What to take away from this part

  1. The 1.8 jump: MetaMask-only → Web3Modal multi-wallet facade.
  2. Mainnet hardening is address, network, gas, ABI, and secret discipline.
  3. Disconnect and cache clear are part of reconnect UX.

Connecting a wallet is not a feature; signing on the wrong network is a silent production incident.

FAQ

Frequently asked questions

What is Web3Modal?

Multi-wallet connect UI; WalletConnect/WalletLink injected via providerOptions.

What is WalletConnect?

QR / mobile wallet bridge; needs an Infura (or RPC) id.

Is it true that "window.ethereum is enough; modal is luxury"?

Multi-connector is a mainnet conversion requirement

What does this part lock in?

This part closes the series with a mainnet readiness checklist: wallet diversity, network asserts, gas, and address/ABI discipline. Gorillas mainnet 1.8 drops the All-Stars/1.4 window.ethereum.enable() path. Web3Modal opens with cacheProvider; WalletConnect (Infura id) and custom Coinbase WalletLink (chainId: 1) join providerOptions. ConnectWeb3 → ethers Web3Provider → address; contract instances speak through the modal provider.

Engineering Principles Learned

  • Put mint utils behind one wallet facade.
  • Assert chainId, address, and gas before every send.
  • Keep secrets out of the bundle; prove connectors on real devices.

Continue reading

Continue reading

Next in series

Same series

Same series

Paylaş