skills/wagmi/SKILL.md
React hooks for Ethereum and EVM blockchain interactions using Wagmi v3. Use when building React or Next.js apps with wallet connections, contract reads/writes, or blockchain state. Triggers on useAccount, useConnect, useContractRead, useContractWrite, WagmiProvider, ConnectKit, RainbowKit, or any React blockchain hooks. Do NOT use for Node scripts or non-React code (use viem skill instead).
npx skillsauth add 0xsardius/onchain-typescript-skills wagmiInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Version: Wagmi 3.x | Official Docs | Requires TypeScript 5.7.3+
Wagmi provides React hooks for Ethereum. This skill ensures correct patterns for provider setup, hooks usage, and React-specific pitfalls.
// config.ts
import { http, createConfig } from 'wagmi'
import { mainnet, polygon, arbitrum } from 'wagmi/chains'
// v3: Install connectors separately: npm i @wagmi/connectors
import { injected, coinbaseWallet, walletConnect } from '@wagmi/connectors'
export const config = createConfig({
chains: [mainnet, polygon, arbitrum],
connectors: [
injected(),
coinbaseWallet({ appName: 'My App' }),
walletConnect({ projectId: 'YOUR_PROJECT_ID' }),
],
transports: {
[mainnet.id]: http('https://eth-mainnet.g.alchemy.com/v2/KEY'),
[polygon.id]: http('https://polygon-mainnet.g.alchemy.com/v2/KEY'),
[arbitrum.id]: http('https://arb-mainnet.g.alchemy.com/v2/KEY'),
},
})
v3 Note: Connectors are now in
@wagmi/connectorspackage for better dependency control.
// providers.tsx
'use client' // Required for Next.js App Router
import { WagmiProvider } from 'wagmi'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { config } from './config'
const queryClient = new QueryClient()
export function Providers({ children }: { children: React.ReactNode }) {
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
</WagmiProvider>
)
}
import { useAccount } from 'wagmi'
function Profile() {
const { address, isConnected, isConnecting, chain } = useAccount()
if (isConnecting) return <div>Connecting...</div>
if (!isConnected) return <div>Not connected</div>
return <div>Connected: {address} on {chain?.name}</div>
}
import { useAccount, useConnect, useDisconnect, useConnectors } from 'wagmi'
function ConnectButton() {
// v3: Use useConnectors() hook instead of getting from useConnect()
const connectors = useConnectors()
const { connect, isPending } = useConnect()
const { disconnect } = useDisconnect()
const { isConnected } = useAccount()
if (isConnected) {
return <button onClick={() => disconnect()}>Disconnect</button>
}
return (
<div>
{connectors.map((connector) => (
<button
key={connector.id}
onClick={() => connect({ connector })}
disabled={isPending}
>
{connector.name}
</button>
))}
</div>
)
}
import { useReadContract } from 'wagmi'
function Balance() {
const { data, isLoading, error, refetch } = useReadContract({
address: '0x...',
abi, // Use `as const` for type safety
functionName: 'balanceOf',
args: ['0x...'],
})
if (isLoading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
return <div>Balance: {data?.toString()}</div>
}
import { useWriteContract, useWaitForTransactionReceipt } from 'wagmi'
function Transfer() {
const { data: hash, writeContract, isPending, error } = useWriteContract()
const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({
hash,
})
async function handleTransfer() {
writeContract({
address: '0x...',
abi,
functionName: 'transfer',
args: ['0x...', 1000n],
})
}
return (
<div>
<button onClick={handleTransfer} disabled={isPending}>
{isPending ? 'Confirming...' : 'Transfer'}
</button>
{isConfirming && <div>Waiting for confirmation...</div>}
{isSuccess && <div>Transaction confirmed!</div>}
{error && <div>Error: {error.message}</div>}
</div>
)
}
// ✅ CORRECT - as const for full type inference
const abi = [
{
name: 'transfer',
type: 'function',
stateMutability: 'nonpayable',
inputs: [
{ name: 'to', type: 'address' },
{ name: 'amount', type: 'uint256' },
],
outputs: [{ name: '', type: 'bool' }],
},
] as const
// ❌ WRONG - no type inference
const abi = [{ ... }] // Missing `as const`
// ❌ WRONG - Violates Rules of Hooks
function BadComponent({ shouldFetch }) {
if (shouldFetch) {
const { data } = useReadContract({ ... })
}
}
// ✅ CORRECT - Use enabled option
function GoodComponent({ shouldFetch }) {
const { data } = useReadContract({
...params,
query: { enabled: shouldFetch },
})
}
// ❌ WRONG - Captures stale values
function BadComponent() {
const [amount, setAmount] = useState(0n)
const { writeContract } = useWriteContract()
// This captures `amount` at render time!
const handleClick = () => {
writeContract({
...params,
args: [amount], // May be stale!
})
}
}
// ✅ CORRECT - Pass fresh values
function GoodComponent() {
const [amount, setAmount] = useState(0n)
const { writeContract } = useWriteContract()
const handleClick = () => {
writeContract({
...params,
args: [amount], // Fresh from closure
})
}
}
| Mistake | Fix |
|---------|-----|
| useContractRead (v1) | Use useReadContract |
| useContractWrite (v1) | Use useWriteContract |
| connectors from useConnect (v2) | Use useConnectors() hook (v3) |
| chains from useSwitchChain (v2) | Use useChains() hook (v3) |
| Conditional hooks | Use query: { enabled: bool } |
| Missing QueryClientProvider | Wagmi requires TanStack Query |
| Not awaiting hash | Use useWaitForTransactionReceipt |
| String amounts | Use BigInt: 1000n |
| Connectors from wagmi/connectors | Use @wagmi/connectors package (v3) |
For detailed patterns, see:
references/hooks-guide.md - Complete hooks referencereferences/react-patterns.md - React-specific patterns and SSRtools
TypeScript patterns for low-level EVM blockchain interactions using Viem. Use when writing Node scripts, CLI tools, or backend services that read/write to Ethereum or EVM chains. Triggers on contract interactions, wallet operations, transaction signing, event watching, ABI encoding, or any non-React blockchain TypeScript code. Do NOT use for React/Next.js apps with hooks (use wagmi skill instead).
development
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.
development
Maintainer workflow for OpenClaw releases, prereleases, changelog release notes, and publish validation. Use when Codex needs to prepare or verify stable or beta release steps, align version naming, assemble release notes, check release auth requirements, or validate publish-time commands and artifacts.
development
Run, watch, debug, and extend OpenClaw QA testing with qa-lab and qa-channel. Use when Codex needs to execute the repo-backed QA suite, inspect live QA artifacts, debug failing scenarios, add new QA scenarios, or explain the OpenClaw QA workflow. Prefer the live OpenAI lane with regular openai/gpt-5.4 in fast mode; do not use gpt-5.4-pro or gpt-5.4-mini unless the user explicitly overrides that policy.