mcpField
W
wagmi

wagmi

github.com/0xsardius開発0163 回インストール41 週間前に更新
リポジトリ

wagmi について

Ethereumアプリ開発者向けに、Wagmi 3.xのReactフックの使い方を案内するスキルです。設定、型安全なコントラクト操作、Reactでよくある問題を扱い、バージョン固有の情報も含みます。

主な機能

  1. 01Wagmi v3の設定とProvider
  2. 02ウォレット接続とアカウント用フック
  3. 03コントラクト読み書き用フック
  4. 04ABIの型安全性に関する指針
  5. 05Reactフックと状態管理の注意点
  6. 06v2からv3への移行情報

活用シーン

  1. 01ReactアプリでのWagmi設定
  2. 02ウォレット接続とアカウント情報の取得
  3. 03Ethereumコントラクトの読み書き
  4. 04Wagmi 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 フックを提供します。このスキルでは、プロバイダーの設定、フックの使用方法、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 の注意点: 依存関係をより適切に管理できるよう、コネクターは @wagmi/connectors パッケージに移動しました。

2. プロバイダーの設定
// 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>
  )
}

コアフック

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`
条件付きフック呼び出し(条件付きにしてはいけません)
// ❌ 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)からの connectorsuseConnectors() フック(v3)を使用します
useSwitchChain(v2)からの chainsuseChains() フック(v3)を使用します
条件付きフックquery: { enabled: bool } を使用します
QueryClientProvider の不足Wagmi には TanStack Query が必要です
hash を待機していないuseWaitForTransactionReceipt を使用します
文字列の数量BigInt を使用します:1000n
wagmi/connectors からのコネクター@wagmi/connectors パッケージ(v3)を使用します

参考資料

詳細なパターンについては、以下を参照してください:

コメント