mcpField
W
wagmi

wagmi

github.com/0xsardius开发0163 次安装41 周前更新
代码仓库

关于 wagmi

为开发者提供 Wagmi 3.x React hooks 使用指导,面向 Ethereum 应用开发。内容涵盖配置、类型安全的合约交互和常见 React 问题,并提供针对版本的说明。

主要功能

  1. 01Wagmi v3 配置与 Provider
  2. 02钱包连接和账户 hooks
  3. 03合约读取与写入 hooks
  4. 04ABI 类型安全指导
  5. 05React hooks 与状态问题
  6. 06v2 至 v3 迁移说明

适用场景

  1. 01在 React 应用中配置 Wagmi
  2. 02连接钱包并读取账户信息
  3. 03读取或写入 Ethereum 合约
  4. 04将代码从 Wagmi v2 更新

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/0xsardius/onchain-typescript-skills --skill wagmi

安装后在 Claude Code 中输入/wagmi确认已加载。

附带文件references/hooks-guide.mdreferences/react-patterns.md

详细介绍

Wagmi 技能

版本: Wagmi 3.x | 官方文档 | 需要 TypeScript 5.7.3+

Wagmi 提供用于 Ethereum 的 React hooks。此技能可确保正确使用 provider 设置、hooks,并规避 React 特有的问题。

快速设置(Wagmi v3)

1. 配置设置
// 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 注意: Connectors 现在位于 @wagmi/connectors 包中,以便更好地控制依赖项。

2. Provider 设置
// 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>
  )
}

核心 Hooks

useAccount
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>
}
useConnect / useDisconnect / useConnectors
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>
  )
}
useReadContract(替代 useContractRead)
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>
}
useWriteContract(替代 useContractWrite)
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>
  )
}

关键模式

ABI 类型安全(重要)
// ✅ 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`
条件调用 Hook(绝不可条件调用)
// ❌ 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
    })
  }
}

常见错误

错误修正方式
useContractRead(v1)使用 useReadContract
useContractWrite(v1)使用 useWriteContract
来自 useConnect(v2)的 connectors使用 useConnectors() hook(v3)
来自 useSwitchChain(v2)的 chains使用 useChains() hook(v3)
条件调用 hooks使用 query: { enabled: bool }
缺少 QueryClientProviderWagmi 需要 TanStack Query
未等待 hash使用 useWaitForTransactionReceipt
字符串金额使用 BigInt:1000n
来自 wagmi/connectors 的 Connectors使用 @wagmi/connectors 包(v3)

参考资料

有关详细模式,请参阅:

评论

支持 Markdown