NFT Minting Page Development

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
NFT Minting Page Development
Medium
~3-5 business days
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1214
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

NFT Minting Page Development

Typical situation: 10,000 token collection, launch in 48 hours. Contract ready, marketing done. Minting page written overnight — "Mint" button, MetaMask connection, done. At launch — 500 people simultaneously, MetaMask fails, transactions hang, whitelist not verifying, progress bar shows 0 even after 200 minted NFTs. Half the audience leaves. This isn't hype problem — it's frontend architecture problem under load.

Key Minting Page Components

Wallet Connection and Chain Management

wagmi v2 + viem — current standard for Web3 React apps. Connection via WalletConnect v2 (supports 300+ wallets), MetaMask, Coinbase Wallet. useConnect, useAccount, useNetwork hooks cover basic scenarios.

Critical moment: check and switch network. User connected to Ethereum, minting on Base. Need useSwitchChain with automatic switch request. If user declined — show blocking warning, don't let them try minting.

const { switchChain } = useSwitchChain()
const { chain } = useAccount()

if (chain?.id !== TARGET_CHAIN_ID) {
  return <SwitchNetworkPrompt onSwitch={() => switchChain({ chainId: TARGET_CHAIN_ID })} />
}

Whitelist Verification

Two approaches: on-chain mapping and Merkle proof.

On-chain mapping (mapping(address => bool) public whitelist) — expensive. Adding 5000 addresses to whitelist = 5000 transactions or one batch via multicall. Gas on mainnet can exceed 1 ETH just for setup.

Merkle proof — standard for large whitelists. Root stored on-chain (one bytes32), proof for each address — off-chain, passed at minting. Frontend gets proof via API or stores in public JSON.

Frontend verification before sending transaction:

import { MerkleTree } from 'merkletreejs'
import { keccak256 } from 'viem'

const proof = merkleTree.getHexProof(keccak256(address))
const isValid = merkleTree.verify(proof, keccak256(address), merkleRoot)

Important: frontend verification — only for UX (don't show button if address not in whitelist). Final check — in smart contract. Never trust frontend verification.

Progress Bar and Realtime Data

Stale data problem. totalSupply() changes with each minted NFT. If reading via useReadContract with default polling — data stale by 1–3 blocks. On hot drop means progress bar lies.

Solution: WebSocket subscription to Transfer events of contract. On each Transfer(address(0), to, tokenId) (mint) — increment counter locally. useWatchContractEvent from wagmi:

useWatchContractEvent({
  address: CONTRACT_ADDRESS,
  abi: NFT_ABI,
  eventName: 'Transfer',
  onLogs: (logs) => {
    const mints = logs.filter(log => log.args.from === zeroAddress)
    setMintedCount(prev => prev + mints.length)
  }
})

This gives realtime updates without polling.

Transaction States

User clicked "Mint" — what next? Minimum 4 states to show explicitly:

  1. Awaiting signature — MetaMask opened, waiting confirmation
  2. Transaction pending — transaction in mempool, show hash with Etherscan link
  3. Confirmed — transaction in block, show NFT or OpenSea link
  4. Failed — revert with understandable error message

useWriteContract + useWaitForTransactionReceipt from wagmi cover all states via isPending, isLoading, isSuccess, isError.

Typical mistake: show spinner without hash. User doesn't know if transaction passed, closes tab, thinks nothing happened — and mints again. Always show transaction hash as soon as it exists.

Handling Contract Errors

Revert messages from Solidity custom errors need decoding. viem does this automatically if ABI has error definitions. But you can't show user technical message like ERC721: transfer to non ERC721Receiver implementer.

Mapping contract errors to user-friendly text — separate task. Typical cases:

  • MaxSupplyReached → "All NFTs already minted"
  • NotWhitelisted → "Your address not in whitelist"
  • MintingPaused → "Minting temporarily paused"
  • InsufficientFunds → "Insufficient funds for minting"

Performance Under Load

At drop hundreds of users simultaneously hit RPC provider. Public RPC (Infura free tier) have rate limits, easily exceeded. Solution: Alchemy or QuickNode with paid plan + cache static data (totalSupply, mintPrice, whitelistRoot) in own backend with TTL 2–5 seconds.

Merkle proofs for whitelist — serve via CDN (Cloudflare), not backend. This removes load and gives sub-50ms response.

Development Process

Development (3–4 days). Next.js + wagmi + viem. Components: wallet connector, mint button with all states, progress bar with websocket updates, whitelist checker.

Contract Integration (1 day). ABI connection, testnet testing (Sepolia), edge case checks: wrong network, not whitelisted, sold out, paused.

Optimization (1 day). RPC caching, CDN for proofs, gas estimate before transaction.

Timeline Estimates

Standard minting page with whitelist and progress bar — 3–5 days. Complex with mint phases (presale, public), multiple wallet types and custom design — up to 2 weeks.

Cost calculated after clarifying functional requirements and design.