OSSブロックチェーン開発ツール比較:Hardhat vs Foundry vs Truffle でスマートコントラクトを開発する
オープンソースラボ編集部 ・ 2026年6月14日
OSSブロックチェーン開発ツール比較:Hardhat vs Foundry vs Truffle でスマートコントラクトを開発する
Ethereum・EVM互換チェーンでのスマートコントラクト開発では、Hardhat(JavaScript/TypeScript・豊富なプラグイン)・Foundry(Rust製・高速・Solidity記述テスト)・Truffle(元祖・Ganache統合)の3つがOSSスマートコントラクト開発フレームワークのデファクトスタンダードです。
OSSブロックチェーン開発ツールを選ぶ理由
- コスト: Remix IDE(クラウド)・Alchemy Supernode(月$49〜)に対してHardhat/Foundryはローカルで$0
- フルコントロール: テスト・デプロイ・検証・フォークをローカルで完結させてガス代と依存を減らす
- CI/CD統合: GitHub ActionsでスマートコントラクトのUnit Test→Slither静的解析→Deployを自動化
- フォーク機能: 本番Ethereum mainnetをローカルにフォークして既存プロトコルとのインタラクションをテスト
主要ツールの概要
Hardhat
2018年公開、TypeScript製のOSSです。GitHubスター7k+。最も広く使われているEVM開発フレームワークで、TypeScript/JavaScriptで記述したテストスクリプト・タスク・プラグインで開発ワークフローを自動化します。Hardhat Network(ローカルEVMノード)でブロックチェーンをローカルエミュレートできます。
# Hardhatプロジェクトのセットアップ
mkdir my-nft-project && cd my-nft-project
npm init -y
npm install --save-dev hardhat
npx hardhat init
# TypeScript projectを選択
# 必要パッケージを追加
npm install --save-dev @nomicfoundation/hardhat-toolbox @openzeppelin/contracts dotenv
// contracts/MyNFT.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract MyNFT is ERC721, ERC721URIStorage, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
uint256 public mintPrice = 0.01 ether;
uint256 public maxSupply = 10000;
constructor(address initialOwner)
ERC721("MyNFT", "MNFT")
Ownable(initialOwner)
{}
function safeMint(address to, string memory uri) public payable {
require(msg.value >= mintPrice, "Insufficient payment");
require(_tokenIdCounter.current() < maxSupply, "Max supply reached");
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}
function withdraw() external onlyOwner {
(bool success, ) = payable(owner()).call{value: address(this).balance}("");
require(success, "Withdrawal failed");
}
// ERC721URIStorage overrides
function tokenURI(uint256 tokenId)
public view override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}
function supportsInterface(bytes4 interfaceId)
public view override(ERC721, ERC721URIStorage)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
// test/MyNFT.ts - Hardhat + ethers.js テスト
import { expect } from "chai";
import hre from "hardhat";
import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers";
describe("MyNFT", function () {
async function deployNFTFixture() {
const [owner, buyer, other] = await hre.ethers.getSigners();
const MyNFT = await hre.ethers.getContractFactory("MyNFT");
const nft = await MyNFT.deploy(owner.address);
return { nft, owner, buyer, other };
}
it("正常にミントできる", async function () {
const { nft, buyer } = await loadFixture(deployNFTFixture);
const mintPrice = await nft.mintPrice();
await expect(
nft.connect(buyer).safeMint(buyer.address, "ipfs://QmTest123", {
value: mintPrice,
})
).to.emit(nft, "Transfer");
});
it("支払い不足でミント失敗", async function () {
const { nft, buyer } = await loadFixture(deployNFTFixture);
await expect(
nft.connect(buyer).safeMint(buyer.address, "ipfs://QmTest123", {
value: hre.ethers.parseEther("0.001"),
})
).to.be.revertedWith("Insufficient payment");
});
it("withdrawはownerのみ", async function () {
const { nft, other } = await loadFixture(deployNFTFixture);
await expect(nft.connect(other).withdraw()).to.be.revertedWithCustomError(
nft,
"OwnableUnauthorizedAccount"
);
});
});
// scripts/deploy.ts - デプロイスクリプト
import hre from "hardhat";
async function main() {
const [deployer] = await hre.ethers.getSigners();
console.log("デプロイアカウント:", deployer.address);
console.log("残高:", hre.ethers.formatEther(await hre.ethers.provider.getBalance(deployer.address)), "ETH");
const MyNFT = await hre.ethers.getContractFactory("MyNFT");
const nft = await MyNFT.deploy(deployer.address);
await nft.waitForDeployment();
console.log("MyNFT デプロイ完了:", await nft.getAddress());
// Etherscanで検証(ETHERSCAN_API_KEYが必要)
if (process.env.ETHERSCAN_API_KEY) {
await hre.run("verify:verify", {
address: await nft.getAddress(),
constructorArguments: [deployer.address],
});
}
}
main().catch(console.error);
Foundry
2021年公開、Rust製のOSSです。GitHubスター8k+。コンパイル・テストが非常に高速(Rustネイティブ)で、テストもSolidityで記述するフレームワークです。forge(ビルド・テスト)・cast(チェーン操作CLI)・anvil(ローカルノード)・chisel(Solidity REPL)の4ツールで構成されます。
# Foundryのインストールとプロジェクト初期化
curl -L https://foundry.paradigm.xyz | bash
foundryup
forge init my-foundry-project
cd my-foundry-project
# OpenZeppelinをインストール
forge install OpenZeppelin/openzeppelin-contracts
# テスト実行(並列・ガスレポート付き)
forge test --gas-report -vvv
# mainnetをフォークして既存プロトコルとインタラクション
forge test --fork-url https://eth-mainnet.g.alchemy.com/v2/$ALCHEMY_KEY -vvv
// test/MyNFT.t.sol - Foundry テスト(Solidityで記述)
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import "../src/MyNFT.sol";
contract MyNFTTest is Test {
MyNFT nft;
address owner = address(this);
address buyer = makeAddr("buyer");
function setUp() public {
nft = new MyNFT(owner);
vm.deal(buyer, 10 ether); // buyerにETHを付与
}
function test_MintSuccess() public {
uint256 mintPrice = nft.mintPrice();
vm.prank(buyer); // 次のトランザクションをbuyerとして実行
nft.safeMint{value: mintPrice}(buyer, "ipfs://QmTest123");
assertEq(nft.balanceOf(buyer), 1);
}
function test_RevertInsufficientPayment() public {
vm.prank(buyer);
vm.expectRevert("Insufficient payment");
nft.safeMint{value: 0.001 ether}(buyer, "ipfs://QmTest123");
}
function testFuzz_MintMultiple(uint8 count) public {
// ファジングテスト: ランダムなcount回ミント
count = uint8(bound(count, 1, 100));
uint256 mintPrice = nft.mintPrice();
for (uint i = 0; i < count; i++) {
vm.prank(buyer);
nft.safeMint{value: mintPrice}(buyer, "ipfs://test");
}
assertEq(nft.balanceOf(buyer), count);
}
}
Truffle
2015年公開、JavaScript製のOSSです。GitHubスター14k+。最も歴史が長いEVM開発フレームワークですが、2023年にConsenSysによるメンテナンス終了が発表されました。Ganache(ローカルブロックチェーン)と統合されていて、マイグレーションシステムでのデプロイ管理が特徴でした。現在は新規プロジェクトにはHardhat/Foundryを推奨します。
// truffle-config.js(参考:Truffle設定)
module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 7545, // Ganache
network_id: "*",
},
sepolia: {
provider: () => new HDWalletProvider(
process.env.MNEMONIC,
'https://sepolia.infura.io/v3/' + process.env.INFURA_KEY
),
network_id: 11155111,
gas: 5500000,
},
},
compilers: {
solc: { version: "0.8.20" }
},
};
機能比較表
| 比較項目 | Hardhat | Foundry | Truffle |
|---|---|---|---|
| テスト言語 | JS/TS | Solidity | JS |
| コンパイル速度 | 中 | 高速(Rust) | 遅い |
| mainnetフォーク | ✅ | ✅ | △ |
| ファジングテスト | △ | ✅ | ❌ |
| プラグインエコシステム | ✅ | 少ない | △ |
| 保守状況 | ✅ | ✅ | ❌(終了) |
ブロックチェーン開発はDevOpsカテゴリ/categories/devopsのCI/CD・コンテナ技術と組み合わせてコントラクトデプロイを自動化します。セキュリティカテゴリ/categories/securityのSlither(静的解析)・Echidna(ファジングテスト)をGitHub Actionsに統合してスマートコントラクトの脆弱性を自動検出します。
FAQ
Q. HardhatとFoundryどちらを選ぶべきですか?
A. フロントエンドとの統合・大きなエコシステム・TypeScript開発者ならHardhat、テストの実行速度・ファジング・Solidityのみで完結させたいならFoundryが向いています。実際の大規模プロジェクト(Uniswap・Aave等)ではHardhat+Foundryを併用してHardhatでデプロイスクリプト・Foundryでテスト(高速・ファジング)という使い方も一般的です。転職・フリーランス市場ではHardhatの求人・チュートリアルが多く学習リソースが豊富です。
Q. スマートコントラクトのセキュリティ監査ツールは何がありますか?
A. OSS静的解析ツールの組み合わせが標準です。主要ツール: ①Slither(Trail of Bits製・Python・50+の脆弱性パターン検知・pip install slither-analyzer)②Mythril(Consensys製・シンボリック実行・pip install mythril)③Echidna(Trail of Bits製・Haskell・プロパティベースファジング)④4naly3er(Foundryプロジェクト向けに自動で実行)。GitHub Actionsに組み込み例: slither . --hardhat-compilation-skip false --filter-paths "node_modules,test"をPRのたびに実行してセキュリティ問題を自動検知します。重大な脆弱性(reentrancy・integer overflow・access control)はOpenZeppelin Contractsのインポートで大部分を防止できます。
Q. テストネットとmainnetへのデプロイフローを教えてください。
A. 推奨フロー: ①Hardhat Network(ローカル)でUnit Test②Anvil mainnet fork(forge test --fork-url)で既存プロトコルとのインタラクションテスト③Sepolia testnetにデプロイしてE2Eテスト(ウォレット・フロントエンドとの統合確認)④Etherscan/Blockscoutでコントラクト検証(ソースコード公開)⑤mainnetにデプロイ。Hardhatデプロイ: npx hardhat run scripts/deploy.ts --network sepolia(.envにPRIVATE_KEY・ALCHEMY_KEY・ETHERSCAN_API_KEYを設定)。マルチシグ(Gnosis Safe)でデプロイ権限を管理してOwnership transferを実施します。
Q. ガス最適化のベストプラクティスは?
A. データ型・ストレージ・ループの最適化が基本です。主要テクニック: ①uint256よりuint128等の小さい型を使う(スロットパッキング)②storage変数へのアクセスを最小化(ループ前にローカル変数にキャッシュ)③イベント(emit)をストレージの代替として利用④immutableとconstantでデプロイ時に値を確定⑤calldataをmemoryの代わりに使う(external関数の引数)⑥uncheckedブロックでオーバーフローチェック不要な演算のガスを節約(Solidity 0.8.0以降)。Hardhatのガスレポート(hardhat-gas-reporter)とforge test --gas-reportでガス使用量を定量的に計測して最適化効果を確認します。
まとめ
| ユースケース | 推奨ツール |
|---|---|
| TypeScript・大きなエコシステム・デプロイ自動化 | Hardhat |
| 高速テスト・ファジング・Solidityテスト | Foundry |
| 新規プロジェクト(2024年以降) | Hardhat or Foundry(Truffleは非推奨) |