web3-frontend
web3-frontend: フロントエンド Web3 統合スキル
フロントエンドアプリケーションからブロックチェーンと対話するための設計パターン、ライブラリ選択基準、実装ガイドを提供するスキル。viem / wagmi / RainbowKit を中心とした現代的な Web3 フロントエンドスタックを対象とする。
対象技術スタック
コアライブラリ
| ライブラリ | 役割 | 備考 |
|---|---|---|
| viem | 低レベル Ethereum クライアント | ethers.js の代替。TypeScript ファースト、tree-shakable |
| wagmi | React Hooks for Ethereum | viem ベース。React アプリの標準選択 |
| @tanstack/react-query | サーバー状態管理 | wagmi v2 の依存。キャッシュ・再検証を担当 |
| RainbowKit | ウォレット接続 UI | wagmi 統合済み。カスタマイズ性が高い |
| ConnectKit | ウォレット接続 UI(代替) | よりシンプルな API。小規模プロジェクト向け |
| WalletConnect v2 | マルチチェーンウォレット接続プロトコル | RainbowKit / ConnectKit の内部で使用 |
viem vs ethers.js 選択基準
| 判断基準 | viem 推奨 | ethers.js 推奨 |
|---|---|---|
| 新規プロジェクト | はい | — |
| TypeScript 型安全性 | 完全な型推論 | 部分的 |
| バンドルサイズ | tree-shakable(小さい) | モノリシック(大きい) |
| 既存の ethers.js コードベース | — | 移行コスト大 |
| wagmi との統合 | ネイティブ統合 | アダプター必要 |
| ドキュメント・コミュニティ | 成長中 | 成熟 |
判断ルール: 新規プロジェクトまたは wagmi 使用時は viem を推奨。既存 ethers.js プロジェクトの場合はユーザーに移行の意向を AskUserQuestion で確認する。
ワークフロー
Step 1: プロジェクト検出と技術スタック判定
package.jsonを読み込み、以下の依存関係を確認する:viem/ethers→ Ethereum クライアントの判定wagmi/@wagmi/core→ React hooks 使用有無@rainbow-me/rainbowkit/connectkit→ ウォレット UI の判定@tanstack/react-query→ 状態管理の確認next/react→ フレームワークの判定
tsconfig.jsonの存在で TypeScript プロジェクトか判定する。- 既存のウォレット接続コードを Grep で検出する:
createConfig,useAccount,useConnect→ wagmi 使用中ethers.providers,new ethers.Contract→ ethers.js 使用中
検証ゲート: package.json が存在し、少なくとも 1 つの Web3 ライブラリが検出されること。Web3 ライブラリが未検出の場合は、AskUserQuestion で使用するスタックを確認する。
Step 2: スタック選択とリファレンス読み込み
Step 1 の結果に基づき、必要なリファレンスを選択して読み込む:
| 状況 | 読み込むリファレンス |
|---|---|
| コントラクト操作 | references/viem-patterns.md から操作パターンを読み込み、read/write/event の該当セクションを選択 |
| React コンポーネント開発 | references/wagmi-hooks.md から hooks パターンを読み込み、該当カテゴリ(接続・読取・書込)を選択 |
| ウォレット接続実装 | references/wallet-connection.md からプロバイダー統合パターンを読み込み、使用ライブラリに合わせて選択 |
| トランザクション送信 | references/transaction-ux.md から UX パターンを読み込み、楽観的更新・エラー表示の該当パターンを選択 |
判断が不明な場合: 複数のアプローチが考えられる場合は AskUserQuestion で要件を確認してからリファレンスを選択する。
検証ゲート: 少なくとも 1 つのリファレンスファイルが正常に読み込めること。
Step 3: コード生成
- Step 2 で選択したパターンに基づきコードを生成する。
- 以下の共通原則を適用する:
- TypeScript の型安全性を最大限活用する(ABI からの型推論を含む)
- コントラクトアドレスはチェーン ID ごとに管理する
- エラーハンドリングはユーザーフレンドリーなメッセージに変換する
- ウォレット未接続状態を常に考慮する
- ABI の取り扱い:
as constアサーションで ABI を定義し、viem の型推論を有効にする- ABI は
abi/ディレクトリに分離配置を推奨
検証ゲート: 生成コードが TypeScript コンパイルを通ること(npx tsc --noEmit で確認可能)。
Step 4: テスト・動作確認
- ユニットテスト:
- hooks のテストは
@wagmi/testのモックプロバイダーを使用 - コントラクト操作のテストは viem の
createTestClientを使用
- hooks のテストは
- 統合テスト:
anvil(Foundry のローカルノード)でローカルチェーンを起動してテストcastでテストデータのセットアップ
検証ゲート: テストが全件パスすること。テストフレームワーク未導入の場合は AskUserQuestion でテスト方針を確認する。
使用例
例 1: ウォレット接続の実装
ユーザー入力: 「RainbowKit でウォレット接続を実装して」
アクション:
- Step 1:
package.jsonを確認 → wagmi + RainbowKit が依存に存在 - Step 2:
references/wallet-connection.mdを読み込み → RainbowKit セクションを選択 - Step 3: 以下を生成:
wagmi.config.ts— チェーン設定、トランスポート定義providers.tsx— WagmiProvider + QueryClientProvider + RainbowKitProvider のラッピングConnectButtonコンポーネントの配置
- Step 4: ローカルで接続テスト
結果: RainbowKit のウォレット接続 UI が動作し、接続後にアドレスが表示される。
例 2: ERC20 トークン残高表示
ユーザー入力: 「ユーザーのウォレットにある USDC 残高を表示したい」
アクション:
- Step 1: プロジェクト検出 → wagmi + viem を確認
- Step 2:
references/viem-patterns.md(コントラクト読取)+references/wagmi-hooks.md(useReadContract)を読み込み - Step 3: 以下を生成:
- ERC20 ABI(balanceOf, decimals, symbol のみ)を
as constで定義 useReadContractで balanceOf を呼び出すカスタム hookformatUnitsでデシマル変換した表示コンポーネント
- ERC20 ABI(balanceOf, decimals, symbol のみ)を
- Step 4: テストクライアントでモック残高を設定してテスト
結果: 接続ウォレットの USDC 残高が正しいデシマルで表示される。
例 3: トランザクション送信 UX
ユーザー入力: 「NFT ミントのトランザクション送信画面を作って。進捗表示もほしい」
アクション:
- Step 1: プロジェクト検出 → wagmi 確認
- Step 2:
references/transaction-ux.md(トランザクションライフサイクル)+references/wagmi-hooks.md(useWriteContract)を読み込み - Step 3: 以下を生成:
useWriteContract+useWaitForTransactionReceiptを組み合わせたカスタム hook- 4 段階の進捗表示: idle → pending(署名待ち)→ confirming(ブロック確認待ち)→ success / error
- ガス見積もりの事前表示(
estimateContractGas) - エラー時のリトライボタンとユーザーフレンドリーなエラーメッセージ
- Step 4: anvil でミントコントラクトをデプロイしてテスト
結果: NFT ミントの全ライフサイクルが視覚的にフィードバックされる UI が完成。
トラブルシューティング
1. ウォレット接続が失敗する
症状: ConnectButton を押してもウォレットが接続されない / エラーが出る
原因と対策:
- WalletConnect projectId 未設定: RainbowKit / ConnectKit は WalletConnect v2 の projectId が必須。
cloud.walletconnect.comでプロジェクトを作成し、環境変数で設定する。 - チェーン設定の不一致:
wagmi.config.tsのチェーン設定がウォレットの接続チェーンと一致しない。chains配列を確認する。 - SSR 環境での window 未定義: Next.js の SSR で
window.ethereumにアクセスしている。'use client'ディレクティブの付与と、動的インポートまたはmountedstate ガードを確認する。
2. チェーン切り替えが動作しない
症状: useSwitchChain が失敗する / ユーザーにチェーン追加プロンプトが出ない
原因と対策:
- wagmi 設定にターゲットチェーン未追加:
chains配列にターゲットチェーンが含まれているか確認する。 - カスタムチェーンの RPC URL 不正:
transportsでチェーン ID ごとに正しい RPC URL が設定されているか確認する。 - ウォレット側の制限: 一部のウォレットはプログラマティックなチェーン追加をサポートしない。
switchChainのエラーをキャッチし、手動切り替えの案内を表示する。
3. コントラクト呼び出しが reverted する
症状: useWriteContract が ContractFunctionRevertedError を返す
原因と対策:
- ABI の不一致: デプロイ済みコントラクトの ABI と定義した ABI が異なる。Etherscan / ブロックエクスプローラーから最新 ABI を取得する。
- 引数の型エラー: BigInt を期待する引数に Number を渡している。
parseEther,parseUnitsで正しく変換する。 - ガス不足:
estimateContractGasで事前にガスを見積もり、十分な残高があるか確認する。 - 権限不足: コントラクトの
onlyOwner等の修飾子に引っかかっている。接続アドレスの権限を確認する。
4. RPC レート制限エラー
症状: 429 Too Many Requests または接続タイムアウト
原因と対策:
- 公開 RPC の制限: 本番では Alchemy / Infura 等の有料 RPC プロバイダーを使用する。
- リクエストの過剰発行:
useReadContractのquery.refetchIntervalが短すぎる。適切な間隔(10-30秒)に設定する。 - フォールバック RPC:
fallbackトランスポートで複数の RPC エンドポイントを設定し、フェイルオーバーを実装する。
5. TypeScript の型エラー
症状: ABI から型が推論されない / unknown 型になる
原因と対策:
- ABI に
as constがない: ABI 定義にas constアサーションを付与する。外部ファイルからインポートする場合もsatisfies Abi+as constを使用する。 - wagmi / viem のバージョン不整合:
wagmiとviemのメジャーバージョンが対応しているか確認する(wagmi v2 は viem v2 が必要)。
注意事項
- 秘密鍵をフロントエンドに含めない: 秘密鍵の管理はウォレット側の責務。フロントエンドでは
writeContractでトランザクションを構築し、ウォレットに署名を委譲する。 - RPC エンドポイントの保護: 公開 RPC はレート制限あり。本番では API キー付きの RPC プロバイダーを使用し、サーバーサイドプロキシで API キーを隠蔽する。
- チェーン ID の型安全性: viem はチェーン ID を型レベルで管理する。
mainnet,sepolia等の定義済みチェーンオブジェクトを使用し、マジックナンバーを避ける。 - ethers.js v5 → v6 / viem への移行: 既存プロジェクトの移行は段階的に行う。viem は ethers.js と共存可能。
- 基盤的なスマートコントラクトの知識(Solidity 言語、セキュリティ、テスト)は
solidity-coreを参照する。 - DeFi / NFT / ガバナンス等のドメイン固有パターンは対応する Solidity スキルを参照する。