Day9:DApp フロント(React + ethers)— ウォレット接続/ネットワーク切替/残高・送金UI
| ← 目次 | 前: Day8 | 次: Day10 |
学習目的
- ブラウザから MetaMask 等に接続し、アカウント・ネットワークを取得できるようになる。
- ネットワーク切替(Local/Sepolia/Optimism)とエラー処理の考え方を理解し、典型的な失敗を切り分けできるようになる。
- ETH 残高、ERC‑20残高の表示と送金UIを動かして確認できるようになる。
まず
docs/curriculum/index.mdの「共通の前提(動作確認済みバージョン含む)」を確認してから進める。
0. 前提
- フロントエンドは
dapp/に同梱してある(新規作成不要)。 - Day5 で
MyTokenをデプロイして、アドレスを控えている。 - ブラウザに MetaMask 等のウォレット拡張が入っている。
- ミニプロジェクト(通しで作るもの):Day14 を“完成”としてつなぐ(全体像:
docs/curriculum/Project.md) - 先に読む付録:
docs/appendix/glossary.md(用語に迷ったとき) - 触るファイル(主なもの):
dapp/.env.local/dapp/src/App.tsx/dapp/src/lib/web3.ts - 今回触らないこと:UI/UXの作り込み(接続と切り分けが主題)
- 最短手順(迷ったらここ):localhost を起動 → MyToken を deploy → 専用の学習用 wallet へ ETH / token を送る →
.env.localに chainId / address を設定 → Connect / 残高 / Send を確認
0.1 どのチェーンで動かすか
- ローカル(推奨):Hardhat node(chainId=31337)
- テストネット:Sepolia(chainId=11155111)
- L2:Optimism(chainId=10)
1. DApp の設定ファイルを用意する
npm run dapp:ci:safe
cp dapp/.env.example dapp/.env.local
dapp/.env.local を編集する:
VITE_CHAIN_ID=31337
VITE_TOKEN_ADDRESS=0x... # MyToken(同じチェーン上)のアドレス
VITE_EVENT_TOKEN= # 任意:Day10で使う
VITE_TOKEN_ADDRESS は 2章で deploy した後に設定する。このファイルは DApp の公開設定であり、秘密鍵を置かない。
2. ローカルで動かす(Hardhat node)
2.1 Hardhat node を起動する
npx hardhat node
期待される出力(最小例):
Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/
Hardhat node は chain ID 31337 で、複数の unlocked development accounts を持つ。localhost deploy は先頭の unlocked account で署名されるため、リポジトリルートの .env も PRIVATE_KEY も不要である。node が表示する開発用秘密鍵は公開済みの既知情報であり、コピーや browser wallet への import は行わない。
2.2 MetaMask にローカルチェーンを追加する
MetaMask のネットワーク追加で次を設定する:
- RPC URL:
http://127.0.0.1:8545 - Chain ID:
31337
専用のブラウザプロファイルで新しい学習用 account を作り、その公開 address を控える。実資産を持つ account や通常利用のブラウザプロファイルは使わない。
2.3 MyToken をローカルへデプロイする
別ターミナルでリポジトリルートから deploy する。localhost は unlocked account を使うため root .env は作らない。
npx hardhat run scripts/deploy-token.ts --network localhost
期待される出力(最小例):
MTK: 0x...
出力された MyToken のアドレスを dapp/.env.local の VITE_TOKEN_ADDRESS に入れる。
2.4 学習用 wallet へ ETH / MyToken を送る
ブラウザ wallet で選択中の公開 address と、deploy 直後の token address を指定する。補助 script は --network localhost / chain ID 31337 以外では失敗し、秘密鍵を受け取らない。
LOCAL_WALLET_ADDRESS=0xYOUR_LEARNING_WALLET \
TOKEN_ADDRESS=0xDEPLOYED_MYTOKEN \
npm run fund:localhost
既定では unlocked deployer から 10 test ETH と 1,000 MTK を送る。量を変える場合だけ LOCAL_ETH_AMOUNT / LOCAL_TOKEN_AMOUNT を追加する。これらは localhost の test asset であり、価値を持たない。
2.5 設定と画面を順に確認する
- wallet の接続 network が
Localhost 8545、chain ID が31337であることを確認する。 dapp/.env.localのVITE_CHAIN_ID=31337とVITE_TOKEN_ADDRESSが deploy 結果に一致することを確認する。-
DApp を起動する。
npm --prefix dapp run dev Connect Wallet後に、画面の接続 address が資金を送った学習用 address と一致することを確認する。Refresh Balancesで ETH と MTK が 0 でないことを確認してから、localhost 内だけで少額のSendを試す。
Vite が表示した URL(通常 http://localhost:5173/)を開く。ポートが使用中なら表示された別の URL を使う。
3. 実装の読みどころ
dapp/src/lib/web3.ts:BrowserProvider取得、eth_requestAccounts、chainId取得、wallet_switchEthereumChaindapp/src/App.tsx:残高取得(getBalance/balanceOf)、ERC‑20 transfer、UI状態管理dapp/src/hooks/useEvents.ts:イベント購読(Day10)
4. つまずきポイント
| 症状 | 原因 | 対処 |
|---|---|---|
No injected provider detected |
MetaMask 等が入っていない | 拡張機能を入れて再読み込みする |
| Switch が失敗する | チェーンが未追加 / 許可がない | 先に MetaMask 側でネットワークを追加してから再実行する |
Token contract not configured |
VITE_TOKEN_ADDRESS 未設定 |
.env.local を見直す |
| ETH / トークン残高が 0 | 学習用 wallet への送付前、address / chain 不一致 | fund:localhost の宛先、chain ID、VITE_TOKEN_ADDRESS を順に確認する |
call revert / execution reverted |
アドレスが違う / コントラクトが存在しない | チェーン ID とアドレスの組み合わせを確認する |
5. 追加課題
- 送金フォームに入力検証(アドレス形式、数量、負数/空文字)を追加する。
- UI のエラーハンドリングを
alertからトーストに置き換える。 permit(EIP‑2612)を使った「署名→中継」送金のUI案を考える(実装は発展)。
6. まとめ
dapp/を起動し、ウォレット接続→chainId確認→残高取得までの流れを動かした。dapp/.env.localの chainId とコントラクトアドレスが、動作の成否を決める前提を押さえた。- 典型的なエラー(provider未検出、チェーン不一致、アドレス不一致)の切り分け観点を整理した。
理解チェック(3問)
- Q1. DApp が injected provider(MetaMask 等)を使うとき、何が前提になるか?
- Q2.
VITE_CHAIN_IDと MetaMask 側のチェーンが不一致だと、どんな症状が起きやすいか? - Q3.
dapp/.env.localのVITE_*を分けて管理する利点は何か?
解答例(短く)
- A1. ブラウザにウォレット拡張があり、ユーザーが接続/承認する前提になる(勝手に送金できない)。
- A2. コントラクトが見つからない、残高が0に見える、イベントが読めないなど「別チェーンを見ている」症状が起きやすい。
- A3. チェーン ID やアドレスなど環境依存の設定をコードから切り離し、切り替えミスやコミット事故を減らせる。
確認コマンド(最小)
# Terminal A(ローカルチェーン)
npx hardhat node
# Terminal B(MyToken をローカルへデプロイ)
npx hardhat run scripts/deploy-token.ts --network localhost
# Terminal B(表示された token address と学習用 wallet address を指定)
LOCAL_WALLET_ADDRESS=0x... TOKEN_ADDRESS=0x... npm run fund:localhost
# Terminal C(chain ID / token address を dapp/.env.local に設定済み)
npm run dapp:ci:safe
test -f dapp/.env.local || cp dapp/.env.example dapp/.env.local
npm --prefix dapp run dev
7. 提出物
- 稼働中スクリーンショット(接続、chainId、残高表示、送金ログ)
- 使用した
VITE_CHAIN_IDとネットワーク名(鍵は伏せる) - 実行した送金TxHash(Explorerリンクがあるとよい)
8. 実行例
- 実行ログ例:
docs/reports/Day09.md