Day7:本番・L2デプロイ/Etherscan検証/手動承認付きCI

← 目次 前: Day6 次: Day8

学習目的

  • 少額のテストネットまたはL2から始め、安全にデプロイする流れを手順として実行できるようになる。
  • ソース検証(Verify)と成果の可観測性を確保し、Explorerで確認できるようになる。
  • GitHub Actionsに手動承認ゲートを設け、誤デプロイを防げるようになる。

まず docs/curriculum/index.md の「共通の前提(動作確認済みバージョン含む)」を確認してから進める。


0. 前提

  • Hardhat構成はDay3までに完了。
  • .envに鍵とRPCを設定し、秘密情報はGitにコミットしない
  • 先に読む付録:docs/appendix/verify.md / docs/appendix/ci-github-actions.md
  • 触るファイル(主なもの):scripts/deploy-generic.ts / .github/workflows/deploy.yml / docs/DEPLOYMENTS.md / hardhat.config.ts(任意)
  • 今回触らないこと:いきなり多額で本番デプロイ(まずは少額・段階的に進める)
  • 最短手順(迷ったらここ):1章の deploy-generic.ts で少額デプロイ → 2章でVerify(任意)→ 4章で手動承認付きCIの要点を確認

0.1 このDayを始めてよい条件

  • npm test がローカルで通っている
  • PRIVATE_KEY に学習用の鍵だけを使っている
  • 最初の実行先を Mainnet ではなく Sepolia または Optimism にしている
  • デプロイ後に残す場所(docs/DEPLOYMENTS.mddocs/reports/)を決めている

.env.example

SEPOLIA_RPC_URL=
MAINNET_RPC_URL=
OPTIMISM_RPC_URL=
PRIVATE_KEY=0xYOUR_PRIVATE_KEY
ETHERSCAN_API_KEY=YOUR_ETHERSCAN_API_KEY
OPTIMISTIC_ETHERSCAN_API_KEY=YOUR_OPTIMISTIC_ETHERSCAN_API_KEY

1. デプロイスクリプトの汎用化

scripts/deploy-generic.ts

import { ethers, network } from 'hardhat';

// デプロイ対象とコンストラクタ引数は環境変数で指定可能
// 例: CONTRACT=MyToken ARGS=100000000000000000000 npx hardhat run ...
async function main() {
  const name = process.env.CONTRACT || 'Hello';
  const args = (process.env.ARGS || '').split(' ').filter(Boolean);
  console.log('network:', network.name, 'contract:', name, 'args:', args);
  const F = await ethers.getContractFactory(name);
  const c = await F.deploy(...(args as any));
  await c.waitForDeployment();
  console.log('deployed:', await c.getAddress());
}

main().catch((e) => {
  console.error(e);
  process.exit(1);
});

実行例(Sepolia に Hello をデプロイ:引数なし)

npx hardhat run scripts/deploy-generic.ts --network sepolia

実行例(OptimismにERC20を供給量指定で)

CONTRACT=MyToken ARGS=1000000000000000000000000 \
  npx hardhat run scripts/deploy-generic.ts --network optimism

Mainnet に出す場合もコマンドは同じ形で --network mainnet を指定するが、実費になるため少額・鍵管理・承認フローを必ず確認する。


2. Verify(ソース検証)

Hardhat Verifyプラグインを導入(Day5参照)。

コマンド例(Sepolia:Hello)

npx hardhat verify --network sepolia <DEPLOYED_ADDR>

コマンド例(Optimism:MyToken)

npx hardhat verify --network optimism <DEPLOYED_ADDR> 1000000000000000000000000

L2ごとにAPIキーが異なる。Blockscout系エクスプローラを使うチェーンでは別途設定が必要。つまずいたら docs/appendix/verify.md の「最短成功ルート」→「失敗時の切り分けルート」→「よくあるエラー表」を参照する。


3. リスクを下げる運用チェックリスト

  • 少額デプロイで動作確認後に本量を配布。
  • onlyOwnerや役割権限(AccessControl)を最小権限で発行。
  • 緊急停止(Pausable)や引当金上限などのセーフティガードを有効化。
  • マルチシグ(Safe等)で管理鍵を保管。単独鍵は避ける。
  • ソース検証(Verify を実施し、アドレス・ABI・TxHashをREADMEに残す。
  • すべての機能に単体テストとカバレッジ(Day6)を要求。

4. GitHub Actions:手動承認付きデプロイ

4.1 環境(Environment)で承認者を設定

GitHub > Settings > Environments > production を作成し、Required reviewers に承認者を登録。Secrets もここに保存。

  • PRODUCTION_MAINNET_RPC_URL
  • PRODUCTION_OPTIMISM_RPC_URL
  • PRODUCTION_PRIVATE_KEY
  • ETHERSCAN_API_KEY
  • OPTIMISTIC_ETHERSCAN_API_KEY

4.2 ワークフロー(手動トリガ + 承認ゲート)

このリポジトリでは .github/workflows/deploy.yml を同梱している。必要に応じて編集する。

.github/workflows/deploy.yml を開いて確認する。

ポイント:

  • workflow_dispatchnetwork/contract/args を受け取る。
  • environment: production により、実行前にGitHub上での人間承認が必須になる。
  • Secrets を hardhat.config.ts が参照する環境変数名(MAINNET_RPC_URL / OPTIMISM_RPC_URL など)に揃えて渡す。

承認が出ない/Secretsが読めない等で詰まったら docs/appendix/ci-github-actions.md の「最短成功ルート」→「失敗時の切り分け」→「よくあるエラー表」を参照する。


5. デプロイ前後のドキュメント化

docs/DEPLOYMENTS.md(同梱。追記して使う)

# Deployments

## 例:<YYYY-MM-DD> <network> MyToken v1.0.0
- contract: MyToken
- network: <network>
- address: 0x....
- txHash: 0x....
- compiler: 0.8.24
- verified: etherscan ✅
- owner: Gnosis Safe(2/3) 0x....
- notes: 初期供給 1,000,000 MTK

6. 本番デプロイ手順(最小)

  1. 少額でL2(例:Optimism)へ先行デプロイ。
  2. Etherscan/BlockscoutでVerify。
  3. DApp・サブグラフ・モニタを接続して動作確認(Day10以降)。
  4. 必要な確認を終えたら、本番環境(例: Mainnet)へデプロイする。docs/DEPLOYMENTS.md を更新し、リリースタグを付与する。

7. つまずきポイント

症状 原因 対処
insufficient funds 手数料不足 少額ETHを補充。maxFee確認
nonce too low ノンス衝突 --networkとアカウントの送信履歴を確認
Verify失敗 コンパイラ設定不一致/引数違い hardhat.config.tsの設定と引数を合わせる。詰まったら docs/appendix/verify.md
承認が出ない Environment reviewers未設定 Settings > Environments を再確認。詰まったら docs/appendix/ci-github-actions.md

8. まとめ

  • デプロイをスクリプト化し、対象コントラクトと引数を環境変数で切り替えられる形にした。
  • Verify と docs/DEPLOYMENTS.md により、アドレスと根拠(TxHash/設定)を後から追える状態を作った。
  • GitHub Actions に手動承認ゲートを入れ、誤デプロイを防ぐ運用の入口を整えた。

理解チェック(3問)

  • Q1. デプロイスクリプトを「汎用化」する狙いは何か?(手動操作との比較で)
  • Q2. docs/DEPLOYMENTS.md に残すべき情報を3つ挙げる(Verify/再現の観点で)。
  • Q3. GitHub Actions の手動承認ゲートは、どんな事故を防ぐための仕組みか?

解答例(短く)

  • A1. 同じ手順を安全に繰り返せるようにし、引数や対象コントラクトの差し替えも明示できる。人手によるミス(ネットワーク違い、引数違い等)を減らす。
  • A2. 例:network/chainId、コントラクト名とアドレス、デプロイTxHash(加えてsolc/optimizer設定があるとさらに良い)。
  • A3. 誤ったブランチ/タイミングで本番やL2へデプロイしてしまう事故を減らす(人間の確認ポイントを作る)。

確認コマンド(最小)

# 要 .env(SEPOLIA_RPC_URL / PRIVATE_KEY)。少額で。
npx hardhat run scripts/deploy-generic.ts --network sepolia

# 任意(Verify:要 ETHERSCAN_API_KEY とデプロイ済みアドレス。Hello はコンストラクタ引数なし)
npx hardhat verify --network sepolia <DEPLOYED_ADDR>

9. 提出物

  • デプロイログ一式(ネットワーク、アドレス、TxHash)
  • Etherscan/BlockscoutのVerifyリンク
  • docs/DEPLOYMENTS.md の追記差分
  • GitHub Actions実行ページのスクリーンショット(承認→完了)

10. 実行例