Wagmi v2 - How to Generate Instant, Type-Safe Hooks for Your Smart Contracts

In the fast-moving world of Web3, developer experience (DX) used to be an afterthought. We spent hours copy-pasting JSON ABIs, manually typing contract addresses, and wrestling with hex-encoded data.
Then came Wagmi.
Wagmi v2, paired with the Wagmi CLI, has fundamentally changed the game. Instead of manual setup, you can now generate type-safe React hooks that "know" your smart contract's functions before you even finish typing them.
Step 1: Installation
First, we need the core Wagmi library, its peer dependency Viem (the lightweight alternative to ethers.js), and TanStack Query for state management.
bash1pnpm install wagmi viem @tanstack/react-query
Next, install the Wagmi CLI as a development dependency. This is the magic tool that will handle your ABIs.
bash1pnpm install --save-dev @wagmi/cli
Step 2: Configure Wagmi
Before we get to the CLI, we need a standard configuration for our app. Create a file named wagmi.ts (or config.ts).
typescript1// config/config.ts 2import { http, createConfig } from "wagmi"; 3import { mainnet, sepolia } from "wagmi/chains"; 4import { injected, metaMask } from "wagmi/connectors"; 5 6export const config = createConfig({ 7 chains: [mainnet, sepolia], 8 connectors: [injected(), metaMask()], 9 transports: { 10 [mainnet.id]: http(), 11 [sepolia.id]: http(), 12 }, 13});
Step 3: Initialize the Wagmi CLI
The CLI needs its own configuration file to know where to fetch your ABIs and where to output the generated code. Run the following command:
bash1npx wagmi init
This creates a wagmi.config.ts file. This is where you tell Wagmi about your smart contracts.
Automating ABI Generation
You have two main ways to get your ABIs:
- From a local project (Hardhat/Foundry)
- From a block explorer (Etherscan)
Here is a powerhouse configuration that fetches an ABI directly from Etherscan and generates React hooks for it:
typescript1import { defineConfig, loadEnv } from "@wagmi/cli"; 2import { etherscan, react } from "@wagmi/cli/plugins"; 3import { mainnet } from "wagmi/chains"; 4 5export default defineConfig(() => { 6 const env = loadEnv({ 7 envDir: process.cwd(), 8 }); 9 10 return { 11 out: "lib/generated.ts", 12 plugins: [ 13 etherscan({ 14 apiKey: env.ETHERSCAN_API_KEY!, 15 chainId: mainnet.id, 16 contracts: [ 17 { 18 name: "MyContract", 19 // Your smart contract address 20 address: "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", 21 }, 22 ], 23 }), 24 react(), // This generates the custom hooks! 25 ], 26 }; 27});
Step 4: Run the Generator
Once your config is ready, run the generation command:
bash1npx wagmi generate
Wagmi will now:
- Reach out to Etherscan
- Grab the ABI for the
MyContract - Create a file at
lib/generated.tscontaining custom hooks likeuseReadEnsRegistryOwner
Step 5: Put it All Together
Create a config/providers.tsx file, and wrap your application with the WagmiProvider and the QueryClientProvider.
typescript1// config/providers.tsx 2"use client"; 3 4import { WagmiProvider } from "wagmi"; 5import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; 6import { config } from "./config"; 7import { ReactNode, useState } from "react"; 8 9export function Providers({ children }: { children: ReactNode }) { 10 const [queryClient] = useState(() => new QueryClient()); 11 12 return ( 13 <WagmiProvider config={config}> 14 <QueryClientProvider client={queryClient}> 15 {children} 16 </QueryClientProvider> 17 </WagmiProvider> 18 ); 19}
typescript1// app/layout.tsx 2export default function RootLayout({ 3 children, 4}: Readonly<{ 5 children: React.ReactNode; 6}>) { 7 return ( 8 <html lang="en"> 9 <body> 10 <Providers>{children}</Providers> 11 </body> 12 </html> 13 ); 14}
Using Your Generated Hook
Now, instead of writing useReadContract and passing in a messy ABI object, you can do this:
typescript1import { useReadEnsRegistryOwner } from './generated' 2 3function MyComponent() { 4 const { data, isLoading } = useReadEnsRegistryOwner({ 5 args: ['0x...'], // Your arguments are now type-checked! 6 }) 7 8 if (isLoading) return <div>Loading...</div> 9 10 return <div>Owner: {data}</div> 11}
Why This Matters
By using the CLI to generate your ABIs and hooks:
- Type Safety: If a function name changes or you pass the wrong number of arguments, TypeScript will throw an error immediately.
- Speed: No more manual JSON imports.
- Maintainability: If you update your contract, just run
npx wagmi generateagain, and your entire frontend updates its types.
References
-
Wagmi Documentation
- https://wagmi.sh
- Official Wagmi library documentation and guides
-
Wagmi CLI Plugin Documentation
- https://wagmi.sh/cli
- Complete reference for CLI configuration and plugins
-
Viem Documentation
- https://viem.sh
- Lightweight Ethereum library as alternative to ethers.js
-
TanStack Query (React Query)
- https://tanstack.com/query/latest
- State management library for fetching and caching data
-
Etherscan API
- https://docs.etherscan.io
- Reference for retrieving smart contract ABIs from Etherscan