HackIndia Logo
HackathonsNewsSkillsGrowth
HackIndia LogoContact: +91 9910125804

General

  • Companies
  • Colleges
  • Board of Advisors
  • Brand Ambassadors
  • FAQ
  • Contact
  • Report a Bug

Hackathons

  • Upcoming Hackathons
  • Judges
  • Mentors
  • Partners
  • Participating Colleges
  • Testimonials

Resources

  • About Us
  • Branding
  • Latest News
  • Growth
  • Skills
  • Builders
  • Ecosystem
  • Forum
  • Ideas
  • Prompt Optimizer
  • Games

© 2026 HackIndia. All rights reserved.

Privacy PolicyTerms of ServiceCode of ConductSitemap

Build 2.139 · 05 Nov 2026, 10:27 UTC

    HackIndia
    HackathonsNewsInternshipsSkillsGrowthPro Perks
    ← Connect a Dapp to Ethereum

    All the reading

    Ethereum

    8 lessons, about 36 minutes. The check's questions come from these.

    Contents
    Setting up the app shell
    1. 1. How a Wallet Dapp Works
    2. 2. Set Up Wagmi React
    Connecting wallets and checking chains
    1. 3. Connect Wallets Safely
    2. 4. Handle Networks and Testnets
    Reading and writing contracts
    1. 5. Read Contract State
    2. 6. Write and Wait Transactions
    Handling errors and shipping
    1. 7. Handle Rejection and Pending Requests
    2. 8. Ship the Repo Project

    Setting up the app shell

    1. How a Wallet Dapp Works

    5 min

    In 30 seconds
    • Explain what a wallet dapp does before any React code.
    • Trace the path from connect to read, write, hash, receipt, and errors.
    • Plan the UI states your repo must show for a recruiter-ready dapp.
    Key point

    Core idea

    A dapp does not hold the user’s wallet. It asks the wallet for permission, then asks it to sign or send specific requests.

    Your React app is the screen. The wallet is the signer. The blockchain is the source of truth.

    The three parts

    A wallet dapp has three moving parts. Your React UI shows buttons, data, loading states, and errors. Wagmi gives React hooks for Ethereum work. Viem handles Ethereum requests and data under the hood.

    TanStack Query manages async state and caching. Since current Wagmi setup uses it directly, you should think in states: idle, loading, success, error, pending transaction, confirmed.

    Your to-do

    User flow

    Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.

    0 of 6 done

    Example

    Mental model

    This is not full code for the repo yet. Use it as a map for what each screen state must show later.

    User opens dapp
      -> sees Connect Wallet
    
    User connects wallet
      -> dapp shows address and chain
    
    Dapp reads contract
      -> UI shows current value
    
    User clicks write action
      -> wallet opens with signing or transaction details
    
    User confirms
      -> dapp gets transaction hash
      -> dapp shows Pending
      -> dapp waits for receipt
      -> dapp shows Confirmed or Failed
    
    User rejects
      -> dapp shows Request rejected
    
    User already has wallet popup open
      -> dapp shows Check your wallet, request already pending

    2. Set Up Wagmi React

    5 min

    In 30 seconds
    • Create a React dapp with the current Wagmi setup.
    • Wrap your app with WagmiProvider and TanStack Query.
    • Configure Ethereum mainnet and Sepolia using Viem transports.
    Key point

    One setup rule

    Wagmi is the React Hooks library you will use for Ethereum. In a React app, it needs two providers at the top: WagmiProvider for wallet and chain state, and QueryClientProvider for async caching.

    Do not follow old Wagmi v1 tutorials. In the current stack, TanStack Query is a dependency you install and configure yourself.

    What you install

    For this track, use Wagmi 3, Viem 2, and TanStack Query. The current versions in the brief are wagmi 3.7.7 and viem 2.56.8.

    Wagmi recommends starting new projects with create-wagmi. If you already have a React app, install the packages manually.

    Your to-do

    Start the app

    Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.

    0 of 5 done

    Connecting wallets and checking chains

    3. Connect Wallets Safely

    4 min

    In 30 seconds
    • Connect a wallet with Wagmi’s useConnect hook.
    • Show clear states: not connected, connecting, connected, failed.
    • Avoid unsafe assumptions about accounts and repeated wallet popups.
    Key point

    Main idea

    Connecting is a permission request. Your dapp asks the wallet for access to accounts, then your UI reacts to the result.

    Do not treat connection as a one-time button click. Show state, handle errors, and let Wagmi manage wallet connectors.

    What safe means

    A safe connect flow does not spam wallet popups. It tells the user what is happening and waits while the wallet is open.

    MetaMask and other injected wallets can change accounts after connection. Do not hard-code an address or assume an old accounts array is still correct.

    Your to-do

    Build the flow

    Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.

    Reading and writing contracts

    5. Read Contract State

    4 min

    In 30 seconds
    • Read a contract view function from React using useReadContract.
    • Show loading, error, and empty states without asking the user to sign.
    • Keep ABI, address, chain, and function name easy to verify in your repo.
    Key point

    Read, do not write

    A contract read calls a view or pure function. It does not change blockchain state, does not ask the user to pay gas, and does not open a wallet signature popup.

    Use reads for things like name, symbol, totalSupply, balanceOf, owner, proposal count, or a public mapping getter.

    What Wagmi does

    Wagmi is a React Hooks library for Ethereum. For reading contracts, you use useReadContract from wagmi.

    TanStack Query sits under this flow. It handles async state like loading, error, cached data, and refetching. Your UI should show those states clearly, not just console.log the result.

    Your to-do

    Pick a safe read

    Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.

    Handling errors and shipping

    7. Handle Rejection and Pending Requests

    5 min

    In 30 seconds
    • Turn wallet errors into clear messages users can act on.
    • Block double-clicks when a wallet request is already pending.
    • Show rejected, pending, and failed transaction states in your React UI.
    Key point

    One state machine

    Treat every wallet action as a small state machine: idle, waiting for wallet, rejected, pending on-chain, confirmed, or failed.

    Your UI should tell the user what is happening and what to do next. Never leave them guessing after they click a button.

    Two pending states

    There are two different waits. First, the wallet popup is waiting for the user to approve or reject. Second, the transaction hash is waiting to be included in a block.

    MetaMask error code -32002 means a wallet request is already open. Do not send another request. Ask the user to open MetaMask and respond.

    Your to-do

    Handle wallet errors

    Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.

    10 questions, 7 to pass.

    Sign in to take the test

    Reads versus writes

    A read calls a read-only Solidity function, usually view or pure. It does not change blockchain state and does not require the user to pay gas.

    A write changes blockchain state. The wallet must show the transaction. If the user confirms, the transaction is broadcast and your dapp receives a hash. A hash is not the same as confirmation.

    Common mistake

    Common mistake

    Beginners often stop after getting a transaction hash. That only means the transaction was submitted. Your UI still needs to wait until it is included in a block and then show the result.

    Another common mistake is hiding what the user signs. Good dapps show the action, contract, chain, and key values before the wallet popup opens.

    Tip

    Use AI well

    Ask an AI tool to draw your dapp state machine before coding. Then check that it includes connect, chain check, read, write, pending hash, receipt, rejected request, and pending wallet request.

    Do not accept code that uses old Wagmi v1 patterns or eth_sign examples. Current lessons in this track use Wagmi 3, Viem 2, and clear signing details.

    Prompt:
    I am building a React Ethereum dapp using Wagmi 3, Viem 2, and TanStack Query.
    Create a simple UI state machine for:
    connect wallet, check chain, read contract, send transaction, show hash, wait for receipt, handle user rejection, handle already pending wallet request.
    Keep it beginner-friendly.
    Your to-do

    Do this now

    Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.

    0 of 5 done

    npm create wagmi@latest
    Example

    Manual install

    Use this only if you already created a React app, such as with Vite. This installs the three pieces this track needs.

    npm install wagmi [email protected] @tanstack/react-query
    Example

    Create Wagmi config

    Keep config in its own file. It makes later lessons easier when you add network checks, contract reads, and transaction waits.

    This example configures mainnet and Sepolia. The http transport is keyed by each chain ID.

    // src/wagmi.ts
    import { createConfig, http } from 'wagmi'
    import { mainnet, sepolia } from 'wagmi/chains'
    
    export const config = createConfig({
      chains: [mainnet, sepolia],
      transports: {
        [mainnet.id]: http(),
        [sepolia.id]: http(),
      },
    })
    Example

    Wrap the app

    Your hooks will not work unless the providers wrap your components. Put this near the root, usually in main.tsx or main.jsx.

    The QueryClient should be created outside the component render path, so it is not recreated on every render.

    // src/main.tsx
    import React from 'react'
    import ReactDOM from 'react-dom/client'
    import { WagmiProvider } from 'wagmi'
    import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
    import { config } from './wagmi'
    import App from './App'
    
    const queryClient = new QueryClient()
    
    ReactDOM.createRoot(document.getElementById('root')!).render(
      <React.StrictMode>
        <WagmiProvider config={config}>
          <QueryClientProvider client={queryClient}>
            <App />
          </QueryClientProvider>
        </WagmiProvider>
      </React.StrictMode>,
    )
    Common mistake

    Common wrong setup

    A common mistake is copying an older tutorial that hides TanStack Query or uses Wagmi v1 patterns. That will break the project brief for this track.

    Another mistake is adding only mainnet. You need a testnet for hackathon demos, so include Sepolia from the start.

    Tip

    Use AI carefully

    You can ask ChatGPT or Gemini to check your setup. Paste your package.json, wagmi config, and main file.

    Check that the answer keeps Wagmi 3 style, imports WagmiProvider from wagmi, uses QueryClientProvider, and includes Sepolia. Reject answers that suggest eth_sign or old Wagmi v1 APIs.

    Prompt:
    Check this React Wagmi setup for a Wagmi 3 + Viem 2 dapp. Tell me if the providers, config, chains, and imports are correct. Do not rewrite it to Wagmi v1.
    Your to-do

    Do this now

    Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.

    0 of 5 done

    0 of 5 done

    Example

    Connect component

    Put this in a small component like src/ConnectWallet.jsx. It only connects and displays account state. Network checks come in the next lesson.

    import { useAccount, useConnect, useDisconnect } from 'wagmi'
    
    export function ConnectWallet() {
      const { address, isConnected, status } = useAccount()
      const { connectors, connect, isPending, error } = useConnect()
      const { disconnect } = useDisconnect()
    
      if (isConnected) {
        return (
          <section>
            <p>Wallet connected</p>
            <p>{address}</p>
            <button onClick={() => disconnect()}>Disconnect</button>
          </section>
        )
      }
    
      return (
        <section>
          <p>Status: {status}</p>
    
          {connectors.map((connector) => (
            <button
              key={connector.uid}
              disabled={isPending}
              onClick={() => connect({ connector })}
            >
              {isPending ? 'Check your wallet' : `Connect ${connector.name}`}
            </button>
          ))}
    
          {error ? <p>Could not connect: {error.message}</p> : null}
        </section>
      )
    }
    Tip

    Use clear copy

    Your button should not just say Loading. Say Check your wallet. That tells the user to open MetaMask, Rabby, or their mobile wallet prompt.

    For a college demo, this matters. Recruiters and judges should see that you understand wallet UX, not only hooks.

    Common mistake

    Avoid popup loops

    Beginners often call connect automatically when the page loads. Do not do that. Let the user click a button first.

    Also disable the button while isPending is true. MetaMask error code -32002 means a request is already pending, so the user must answer the open wallet prompt before you send another request.

    About wallet events

    Wallets expose provider events like accountsChanged and chainChanged. MetaMask sends chainChanged as a hex chain ID, such as 0x1.

    In this track, prefer Wagmi hooks for React state instead of manually wiring provider events. If you do add listeners later, remove only your specific listener, not every listener in the app.

    Your to-do

    Do this now

    Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.

    0 of 5 done

    4. Handle Networks and Testnets

    4 min

    In 30 seconds
    • Configure your dapp for mainnet and Sepolia using Wagmi chains.
    • Detect the connected chain and block actions on the wrong network.
    • Handle chainChanged values and unknown-chain errors without confusing users.
    Key point

    One rule

    Your dapp must know which chains it supports, and every contract action must run on the intended chain.

    For this track, use a testnet for building. Sepolia is safer than mainnet because mistakes do not cost real rupees.

    Why networks matter

    The same contract address can mean different things on different chains. A button that is safe on Sepolia may fail, or do something else, on mainnet.

    A recruiter checking your repo should see that you do not assume the wallet is on the right network. You verify it in the UI before reads and writes.

    Example

    Configure chains

    Wagmi config can include mainnet and sepolia. Transports are keyed by chain ID, so Wagmi knows where to send requests.

    Keep this in your config file, usually src/wagmi.ts or src/config/wagmi.ts.

    import { createConfig, http } from 'wagmi'
    import { mainnet, sepolia } from 'wagmi/chains'
    
    export const config = createConfig({
      chains: [mainnet, sepolia],
      transports: {
        [mainnet.id]: http(),
        [sepolia.id]: http(),
      },
    })
    Your to-do

    Show chain state

    Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.

    0 of 5 done

    Example

    Gate the UI

    This small component shows the pattern. It does not send a transaction. It only blocks the user from acting on the wrong network.

    Later lessons will use this same check before reads and writes.

    import { useAccount, useSwitchChain } from 'wagmi'
    import { sepolia } from 'wagmi/chains'
    
    export function NetworkGate({ children }: { children: React.ReactNode }) {
      const { chain } = useAccount()
      const { switchChain, isPending } = useSwitchChain()
    
      if (!chain) return <p>Connect your wallet first.</p>
    
      const isSepolia = chain.id === sepolia.id
    
      if (!isSepolia) {
        return (
          <div>
            <p>Wrong network: {chain.name}. Use Sepolia for this project.</p>
            <button
              disabled={isPending}
              onClick={() => switchChain({ chainId: sepolia.id })}
            >
              {isPending ? 'Check your wallet' : 'Switch to Sepolia'}
            </button>
          </div>
        )
      }
    
      return <>{children}</>
    }
    Common mistake

    Hex chain IDs

    Wallet events can report chain IDs as hex strings. MetaMask’s chainChanged event gives values like 0x1, not 1.

    Do not compare that directly with a decimal chain ID. Convert it first, or let Wagmi hooks manage chain state for your React UI.

    // 0x1 means Ethereum mainnet
    const decimalChainId = Number('0x1') // 1
    Tip

    Unknown chain flow

    If the wallet does not know a chain, MetaMask can return error code 4902. Your app should guide the user to add the chain or switch using a proper chain configuration.

    For this lesson, keep your supported chains to mainnet and Sepolia. Fewer networks means fewer support problems during a hackathon demo.

    Your to-do

    Do this now

    Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.

    0 of 5 done

    0 of 5 done

    Example

    Read totalSupply

    This component reads totalSupply from an ERC-20 style contract. Replace the address with your testnet contract address before committing.

    The result may be a bigint. Convert it before rendering. If the token uses decimals, format it properly later instead of pretending the raw number is human-friendly.

    import { useReadContract } from 'wagmi'
    
    const tokenAbi = [
      {
        type: 'function',
        name: 'totalSupply',
        stateMutability: 'view',
        inputs: [],
        outputs: [{ name: '', type: 'uint256' }],
      },
    ] as const
    
    const tokenAddress = '0x0000000000000000000000000000000000000000'
    
    export function TotalSupplyCard() {
      const {
        data,
        isLoading,
        isError,
        error,
        refetch,
      } = useReadContract({
        abi: tokenAbi,
        address: tokenAddress,
        functionName: 'totalSupply',
      })
    
      if (isLoading) return <p>Reading contract...</p>
    
      if (isError) {
        return (
          <section>
            <p>Could not read total supply.</p>
            <p>{error.message}</p>
            <button onClick={() => refetch()}>Try again</button>
          </section>
        )
      }
    
      return (
        <section>
          <h2>Total supply</h2>
          <p>{data?.toString() ?? 'No data returned'}</p>
          <button onClick={() => refetch()}>Refresh</button>
        </section>
      )
    }
    Common mistake

    Common read bugs

    Do not paste a full ABI if you only need one function. It makes code review harder during a hackathon and hides mistakes.

    Do not read from the wrong chain. The same address can mean different things on different networks. Your previous lesson handled network support; use that chain choice when testing reads.

    Tip

    Use AI carefully

    You can ask ChatGPT, Gemini, or Claude to reduce a contract ABI to one function. Then verify the function name, inputs, outputs, and stateMutability yourself.

    AI often guesses addresses or ABIs. Never trust those. Get the address and ABI from your own deployed contract, repo artifact, or a block explorer for the exact testnet.

    Your to-do

    Do this now

    Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.

    0 of 5 done

    6. Write and Wait Transactions

    4 min

    In 30 seconds
    • Send a contract write with Wagmi’s useWriteContract hook.
    • Use the returned transaction hash to show a pending state.
    • Wait for the receipt before telling the user the action is done.
    Key point

    One flow

    A write is not done when the wallet opens. It is not even done when the wallet returns a hash.

    The safe flow is: call the contract, get a transaction hash, show pending, wait for the receipt, then show success or failure.

    Write vs read

    A read calls a view or pure function. It does not change chain state and does not ask the user to pay gas.

    A write changes blockchain state. The wallet must show the transaction, the user must approve it, and the network must include it in a block.

    Your to-do

    What your UI tracks

    Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.

    0 of 5 done

    Example

    Write button example

    This example calls a simple contract function named increment. Replace the address, ABI, and function name with your own project contract.

    Keep the button text boring and clear. A recruiter should understand the transaction path in 10 seconds.

    import { useWriteContract, useWaitForTransactionReceipt } from 'wagmi'
    
    const counterAbi = [
      {
        type: 'function',
        name: 'increment',
        stateMutability: 'nonpayable',
        inputs: [],
        outputs: [],
      },
    ]
    
    const counterAddress = '0x0000000000000000000000000000000000000000'
    
    export function IncrementButton() {
      const {
        data: hash,
        writeContract,
        isPending: isWalletOpen,
        error: writeError,
      } = useWriteContract()
    
      const {
        isLoading: isConfirming,
        isSuccess: isConfirmed,
        error: receiptError,
      } = useWaitForTransactionReceipt({
        hash,
      })
    
      function sendIncrement() {
        writeContract({
          address: counterAddress,
          abi: counterAbi,
          functionName: 'increment',
        })
      }
    
      return (
        <section>
          <button onClick={sendIncrement} disabled={isWalletOpen || isConfirming}>
            {isWalletOpen ? 'Check wallet' : isConfirming ? 'Waiting for confirmation' : 'Increment counter'}
          </button>
    
          {hash && <p>Transaction hash: {hash}</p>}
          {isConfirmed && <p>Confirmed on-chain.</p>}
          {writeError && <p>Transaction was not sent: {writeError.message}</p>}
          {receiptError && <p>Transaction failed after sending: {receiptError.message}</p>}
        </section>
      )
    }
    Tip

    Show the hash

    Show the transaction hash as soon as you have it. It proves the wallet returned a broadcast transaction.

    For a hackathon demo, this also helps judges see that your dapp is not just changing local React state.

    Common mistake

    Do not fake success

    Beginners often show “Done” right after writeContract runs. That is too early.

    The transaction may still be waiting, may be replaced, or may revert. Wait for useWaitForTransactionReceipt before showing final success.

    What to explain

    Near the button, show the contract action in plain English. For example: “This sends one transaction to increment the counter on Sepolia.”

    Do not hide gas or chain details behind vague text. Users should know they are signing a real state-changing transaction.

    Your to-do

    Do this now

    Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.

    0 of 5 done

    0 of 5 done

    Example

    Error helper

    Put this helper near your transaction component or in a small utils file. It keeps your button code clean.

    Provider errors have a message, code, and sometimes data. For users, the code is usually enough.

    function getWalletErrorMessage(error: unknown) {
      const err = error as { code?: number; message?: string }
    
      if (err.code === 4001) {
        return 'You rejected the request in your wallet.'
      }
    
      if (err.code === -32002) {
        return 'A wallet request is already open. Open MetaMask and approve or reject it.'
      }
    
      return err.message || 'Something went wrong. Please try again.'
    }
    Example

    Safer write button

    This pattern blocks double-clicks and separates wallet approval from on-chain confirmation.

    useWriteContract sends the transaction. useWaitForTransactionReceipt waits for the hash to be included in a block.

    import { useState } from 'react'
    import { useWaitForTransactionReceipt, useWriteContract } from 'wagmi'
    
    export function MintButton({ abi, address }: { abi: any; address: `0x${string}` }) {
      const [hash, setHash] = useState<`0x${string}` | undefined>()
      const [message, setMessage] = useState('')
      const [waitingForWallet, setWaitingForWallet] = useState(false)
    
      const { writeContractAsync } = useWriteContract()
    
      const receipt = useWaitForTransactionReceipt({
        hash,
      })
    
      const busy = waitingForWallet || receipt.isLoading
    
      async function onMint() {
        if (busy) return
    
        setMessage('Check your wallet. You are about to send a transaction.')
        setWaitingForWallet(true)
    
        try {
          const txHash = await writeContractAsync({
            abi,
            address,
            functionName: 'mint',
            args: [],
          })
    
          setHash(txHash)
          setMessage('Transaction sent. Waiting for confirmation.')
        } catch (error) {
          setMessage(getWalletErrorMessage(error))
        } finally {
          setWaitingForWallet(false)
        }
      }
    
      return (
        <div>
          <button onClick={onMint} disabled={busy}>
            {waitingForWallet ? 'Waiting for wallet' : receipt.isLoading ? 'Confirming' : 'Mint'}
          </button>
          {hash && <p>Transaction hash: {hash}</p>}
          {receipt.isSuccess && <p>Confirmed.</p>}
          {receipt.isError && <p>Transaction failed or reverted.</p>}
          <p>{message}</p>
        </div>
      )
    }
    Common mistake

    Avoid retry spam

    A common bug is sending the same wallet request again because the user clicks twice or the popup is hidden behind another window.

    Disable the button while waiting. If you see -32002, do not auto-retry. Tell the user to finish the open request.

    Tip

    Write for recruiters

    Recruiters and judges may not test every edge case. Make the UI visible in your screenshots and README.

    Add a short note: “Handles user rejection, already-pending wallet requests, pending transaction confirmation, and failed receipts.” This shows you understand real dapp UX.

    Your to-do

    Do this now

    Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.

    0 of 5 done

    8. Ship the Repo Project

    5 min

    In 30 seconds
    • Turn your dapp into a repo a judge or recruiter can run.
    • Add clear proof for wallet, read, write, wait, errors, and testnet support.
    • Write a short README that shows what users sign before they confirm.
    Key point

    Ship for review

    Your repo is the proof. A reviewer should be able to install it, run it, connect a wallet, switch to a testnet, read contract state, send a transaction, and see the receipt state without asking you for help.

    What must be visible

    Do not hide the important Web3 parts inside a demo video only. Put them in code, UI text, and README screenshots or notes.

    Your project should clearly use Wagmi 3, Viem 2, and TanStack Query. Wagmi is a React Hooks library for Ethereum, and current setup uses TanStack Query as a peer dependency, not a hidden internal detail.

    Your to-do

    Repo checklist

    Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.

    0 of 5 done

    Example

    README skeleton

    Keep the README short, but make it runnable. Replace the placeholders with your actual contract and flow.

    Project: Campus Voting Dapp
    
    Stack
    - React
    - wagmi 3
    - viem 2
    - @tanstack/react-query
    
    Supported network
    - Sepolia
    - Chain ID: 11155111
    
    Run locally
    1. npm install
    2. cp .env.example .env
    3. Add any required RPC or contract values
    4. npm run dev
    
    Contract
    - Address: 0x...
    - Read function used: getVoteCount
    - Write function used: vote
    
    User flow
    1. Connect wallet
    2. Switch to Sepolia if needed
    3. Read current vote count
    4. Review signing details shown in the UI
    5. Confirm the transaction in wallet
    6. See transaction hash while pending
    7. See receipt after confirmation
    
    Error handling shown
    - User rejected request: 4001
    - Wallet request already pending: -32002
    
    Notes for reviewers
    - No mainnet funds are needed
    - Test with a Sepolia-funded wallet
    Common mistake

    Common shipping mistake

    Many teams build the flow but forget the reviewer experience. If the README does not say which chain, which contract, and which button to click, your good code may look broken.

    Also avoid copying old Wagmi v1 tutorials into your final repo. This track expects Wagmi 3 with Viem 2 and TanStack Query configured in the app.

    Tip

    Use AI carefully

    Ask an AI tool to review your README like a hackathon judge. Then check every suggestion against your actual code before you paste it.

    Good prompt: “Read this README and tell me if a reviewer can run this Wagmi 3 dapp, connect a wallet, use Sepolia, send a transaction, and verify error handling. Do not invent features.”

    Your to-do

    Final test pass

    Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.

    0 of 5 done

    Your to-do

    Do this now

    Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.

    0 of 5 done