テストネットとは

これまでHardhatのローカルネットワークで開発してきましたが、本章ではSepoliaテストネットにコントラクトをデプロイします。テストネットは、Ethereumメインネットと同じ仕組みで動作するテスト環境で、実際のETHを消費せずにコントラクトの動作を検証できます。

テストネットの種類

テストネット状態特徴
Sepolia推奨長期サポート、安定的
Goerli非推奨2024年に終了
Holesky利用可能バリデータテスト向け

本書ではSepoliaを使用します。

事前準備

1. MetaMaskの設定

MetaMaskにSepoliaテストネットを追加します(多くの場合、デフォルトで含まれています)。MetaMaskの設定で「テストネットを表示」を有効にしてください。

2. テスト用ETHの取得

Sepoliaテストネットでのトランザクションには、テスト用のETHが必要です。以下のFaucet(蛇口)サービスから取得できます。

3. RPCプロバイダーの設定

ブロックチェーンノードに接続するために、RPCプロバイダーが必要です。Alchemyまたはinfuraのアカウントを作成し、APIキーを取得します。

# Alchemy の場合
# https://dashboard.alchemy.com/ でアプリを作成
# Sepolia ネットワークを選択してAPIキーを取得

4. 環境変数の設定

秘密鍵やAPIキーをコードに直接書かないように、.env ファイルで管理します。

npm install --save-dev dotenv
# .env
SEPOLIA_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/YOUR_API_KEY
PRIVATE_KEY=your_metamask_private_key_here
ETHERSCAN_API_KEY=your_etherscan_api_key_here

:::message alert .env ファイルは必ず .gitignore に追加してください。秘密鍵がGitHubなどに公開されると、資産を失うリスクがあります。テストネットの秘密鍵であっても、本番用の鍵と共有しないでください。 :::

# .gitignore に追加
echo ".env" >> .gitignore

Hardhat設定ファイルの更新

hardhat.config.ts にSepoliaネットワークの設定を追加します。

// hardhat.config.ts
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
import * as dotenv from "dotenv";

dotenv.config();

const config: HardhatUserConfig = {
  solidity: "0.8.20",
  networks: {
    // ローカル開発用
    hardhat: {},
    localhost: {
      url: "http://127.0.0.1:8545",
    },
    // Sepoliaテストネット
    sepolia: {
      url: process.env.SEPOLIA_RPC_URL || "",
      accounts:
        process.env.PRIVATE_KEY !== undefined
          ? [process.env.PRIVATE_KEY]
          : [],
      chainId: 11155111,
    },
  },
  // Etherscan検証用
  etherscan: {
    apiKey: process.env.ETHERSCAN_API_KEY,
  },
};

export default config;

デプロイスクリプトの作成

テストネットにデプロイするスクリプトを作成します。

// scripts/deploy.ts
import { ethers } from "hardhat";

async function main() {
  // デプロイアカウントの情報
  const [deployer] = await ethers.getSigners();
  console.log("Deploying contracts with:", deployer.address);

  const balance = await ethers.provider.getBalance(deployer.address);
  console.log("Account balance:", ethers.formatEther(balance), "ETH");

  // コントラクトのデプロイ
  console.log("\nDeploying Greeter...");
  const Greeter = await ethers.getContractFactory("Greeter");
  const greeter = await Greeter.deploy("こんにちは、Sepolia!");

  // デプロイ完了を待機
  await greeter.waitForDeployment();

  const address = await greeter.getAddress();
  console.log("Greeter deployed to:", address);

  // デプロイ後の確認
  const greeting = await greeter.greet();
  console.log("Current greeting:", greeting);

  // デプロイ後の残高確認
  const newBalance = await ethers.provider.getBalance(deployer.address);
  console.log(
    "\nDeployment cost:",
    ethers.formatEther(balance - newBalance),
    "ETH"
  );
  console.log("Remaining balance:", ethers.formatEther(newBalance), "ETH");

  // Etherscan検証用の情報
  console.log("\n--- Etherscan verification ---");
  console.log(`npx hardhat verify --network sepolia ${address} "こんにちは、Sepolia!"`);
}

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

デプロイの実行

# Sepoliaテストネットにデプロイ
npx hardhat run scripts/deploy.ts --network sepolia

出力例:

DADGCDRnecerueeppcperpmxlolerlaouoteoiEhynyenyntaitirtmihrnnenedgbgdgngrhaertsaclGpebctoarlecaanneotolnvtceyisaeretentnvra:edg:ceicr:erft0.t0:iys..o.f5.:00iw0.c-iE024antTx39tehH147it:2S6ow3eE6no04pTrx5oHEk76lT47iHs28aed9p30o5alCbicca6d6e03fx411C2203354435.26.97.2859"a03abb8c4d4eBfSc1e92pe3o74l55i96a57f8"2bD18

Etherscanでのコントラクト検証

デプロイしたコントラクトのソースコードをEtherscanで公開・検証することで、誰でもコントラクトの内容を確認できるようになります。

# コントラクトの検証
npx hardhat verify --network sepolia \
  デプロイされたアドレス \
  "こんにちは、Sepolia!"

検証が成功すると、Sepolia Etherscanでコントラクトのソースコード、Read/Write機能が表示されるようになります。

ScfWShuooautcnrictcttcperviessaens:scrgs/ftif/usffusl/iolelGcrlpyrayoetvlseieviutoreabenir.mrfiei.oifttsncihtoaeeelttdrd:hisGeoccsrnoaoebnnuelrt.rtoericecsaoerkuc/ltacaetdotx.Gddp.rre0l.eexoesf1rtso2ee/r3rr04.xc.o1o.n2n.3tt4rh.ae.c.tb#lcoocdkeexplorer.

デプロイ情報の記録

デプロイしたコントラクトのアドレスを記録しておくと、フロントエンドとの連携時に便利です。

// scripts/deploy-and-save.ts
import { ethers } from "hardhat";
import * as fs from "fs";

async function main() {
  const Greeter = await ethers.getContractFactory("Greeter");
  const greeter = await Greeter.deploy("こんにちは!");
  await greeter.waitForDeployment();

  const address = await greeter.getAddress();
  const network = await ethers.provider.getNetwork();

  // デプロイ情報をJSONファイルに保存
  const deployInfo = {
    network: network.name,
    chainId: Number(network.chainId),
    contractAddress: address,
    deployedAt: new Date().toISOString(),
  };

  const filePath = `./deployments/${network.name}.json`;
  fs.mkdirSync("./deployments", { recursive: true });
  fs.writeFileSync(filePath, JSON.stringify(deployInfo, null, 2));

  console.log(`Deploy info saved to ${filePath}`);
}

main().catch(console.error);

デプロイ後の動作確認

Hardhatのコンソールを使って、テストネット上のコントラクトと対話します。

npx hardhat console --network sepolia
// テストネット上のコントラクトに接続
const greeter = await ethers.getContractAt(
  "Greeter",
  "デプロイされたアドレス"
);

// 読み取り(ガス不要)
await greeter.greet();
// => 'こんにちは、Sepolia!'

// 書き込み(ガスが必要、トランザクション送信)
const tx = await greeter.setGreeting("テストネットから変更");
console.log("TX hash:", tx.hash);

// トランザクション完了を待機
await tx.wait();

// 確認
await greeter.greet();
// => 'テストネットから変更'

よくあるトラブルと対処法

1. ガス不足

Error:insufficientfundsforintrinsictransactioncost

Faucetからテスト用ETHを追加で取得してください。

2. RPCエラー

Error:couldnotdetectnetwork

.envSEPOLIA_RPC_URL が正しいか確認してください。AlchemyやInfuraのダッシュボードでAPIキーが有効であることを確認します。

3. Nonce エラー

Error:noncetoolow

同じアカウントで複数のトランザクションを連続して送信した場合に発生することがあります。前のトランザクションの完了を待ってから再送信してください。

まとめ

本章では、Sepoliaテストネットへのコントラクトデプロイの手順を学びました。環境変数による秘密鍵管理、Hardhat設定、デプロイスクリプト、Etherscan検証という一連のワークフローを実践しました。

次章では、Next.js、wagmi、RainbowKitを使ったフロントエンドを構築し、デプロイしたコントラクトとブラウザから対話できるようにします。

関連記事