<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Hardhat</title>
	<atom:link href="https://techgrowup.net/tag/hardhat/feed/" rel="self" type="application/rss+xml" />
	<link>https://techgrowup.net</link>
	<description>エンジニアを強くする</description>
	<lastBuildDate>Sun, 20 Apr 2025 23:00:00 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://techgrowup.net/wp-content/uploads/2021/05/hp-icon-150x150.png</url>
	<title>Hardhat</title>
	<link>https://techgrowup.net</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>ブロックチェーンテスト攻略──単体・統合・セキュリティ・性能を網羅する実践ガイド</title>
		<link>https://techgrowup.net/blockchain-test-guide/</link>
					<comments>https://techgrowup.net/blockchain-test-guide/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[techgrowup]]></dc:creator>
		<pubDate>Sun, 20 Apr 2025 23:00:00 +0000</pubDate>
				<category><![CDATA[ブロックチェーン]]></category>
		<category><![CDATA[Foundry]]></category>
		<category><![CDATA[Hardhat]]></category>
		<category><![CDATA[Slither]]></category>
		<category><![CDATA[スマートコントラクト]]></category>
		<category><![CDATA[セキュリティテスト]]></category>
		<category><![CDATA[ブロックチェーンテスト]]></category>
		<category><![CDATA[単体テスト]]></category>
		<category><![CDATA[性能テスト]]></category>
		<category><![CDATA[統合テスト]]></category>
		<guid isPermaLink="false">https://techgrowup.net/?p=2795</guid>

					<description><![CDATA[はじめに ビットコインから続くブロックチェーンの10余年の歩みは「コード＝資産」という新しい常識を生みました。しかし一度デプロイしたスマートコントラクトは簡単に修正できず、1行のバグが数億円規模の損失になる事例が後を絶ち [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h1 class="wp-block-heading">はじめに</h1>



<p class="wp-block-paragraph">ビットコインから続くブロックチェーンの10余年の歩みは「コード＝資産」という新しい常識を生みました。しかし一度デプロイしたスマートコントラクトは簡単に修正できず、<strong>1行のバグが数億円規模の損失</strong>になる事例が後を絶ちません。LogRocket の「Complete guide to blockchain testing」は、ブロックチェーン特有のテスト課題と解決策を体系的に整理しています 。本記事ではその内容を深掘りし、<strong>ブロックチェーンテストの全体像と実践方法</strong>を解説します。</p>



<h2 class="wp-block-heading">ブロックチェーンテストの全体設計</h2>



<h3 class="wp-block-heading">主要テストレイヤー</h3>



<figure class="wp-block-table"><div class="scrollable-table"><table class="has-fixed-layout"><thead><tr><th>レイヤー</th><th>目的</th><th>代表ツール</th></tr></thead><tbody><tr><td><strong>単体テスト</strong></td><td>関数単位のロジック検証</td><td>Hardhat/Chai, Foundry/Forge, Brownie/PyTest</td></tr><tr><td><strong>統合テスト</strong></td><td>複数コントラクト間の相互作用</td><td>Hardhat&nbsp;Network&nbsp;fork, Deployment&nbsp;scripts</td></tr><tr><td><strong>ノード/ネットワークテスト</strong></td><td>コンセンサス、フォークハンドリング</td><td>Ganache, Anvil, Geth&nbsp;dev&nbsp;net</td></tr><tr><td><strong>セキュリティテスト</strong></td><td>再入可能性・整数演算・権限漏れ</td><td>Slither, Mythril, Echidna, Manticore</td></tr><tr><td><strong>性能テスト</strong></td><td>TPS、Gas効率、スループット</td><td>Hardhat‑gas‑reporter, Hyperledger&nbsp;Caliper</td></tr></tbody></table></div></figure>



<h3 class="wp-block-heading">テストフェーズ</h3>



<ol class="wp-block-list">
<li><strong>テスト計画</strong>：脅威モデル作成、成功基準(KPI)を定義</li>



<li><strong>テストデザイン</strong>：シナリオ、エッジケース、ファズ入力を設計</li>



<li><strong>実装</strong>：テストコード＋モック＋スタブを作成</li>



<li><strong>実行</strong>：ローカル→テストネット→シミュレーション環境で段階的実行</li>



<li><strong>レポート</strong>：カバレッジ、Gas使用量、失敗ケースを可視化</li>
</ol>



<h2 class="wp-block-heading">単体テストを極める</h2>



<h3 class="wp-block-heading">Hardhat × Chai 基本例</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
contract Counter {
    uint256 public n;
    function inc() external { n += 1; }
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">// SPDX-License-Identifier: MIT</span></span>
<span class="line"><span style="color: #C586C0">pragma</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">solidity</span><span style="color: #D4D4D4"> ^0.8.23;</span></span>
<span class="line"><span style="color: #569CD6">contract</span><span style="color: #4EC9B0"> Counter</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #4EC9B0">uint256</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> n;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">inc</span><span style="color: #D4D4D4">() </span><span style="color: #569CD6">external</span><span style="color: #D4D4D4"> { n += </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">; }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="// test/Counter.ts
import { expect } from &quot;chai&quot;;
import { ethers } from &quot;hardhat&quot;;
describe(&quot;Counter&quot;, () =&gt; {
  it(&quot;増分ロジック&quot;, async () =&gt; {
    const Counter = await ethers.getContractFactory(&quot;Counter&quot;);
    const c = await Counter.deploy();
    await c.inc();
    expect(await c.n()).to.equal(1);
  });
});" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">// test/Counter.ts</span></span>
<span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">expect</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;chai&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">ethers</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;hardhat&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #DCDCAA">describe</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;Counter&quot;</span><span style="color: #D4D4D4">, () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">it</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;増分ロジック&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">Counter</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">ethers</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getContractFactory</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;Counter&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">c</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Counter</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">deploy</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">c</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">inc</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">expect</span><span style="color: #D4D4D4">(</span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">c</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">n</span><span style="color: #D4D4D4">()).</span><span style="color: #9CDCFE">to</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">equal</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">  });</span></span>
<span class="line"><span style="color: #D4D4D4">});</span></span></code></pre></div>



<ul class="wp-block-list">
<li><code>npx hardhat test</code> で高速実行</li>



<li><code>evm_snapshot/evm_revert</code>で状態ロールバックしテスト独立性を確保</li>
</ul>



<h3 class="wp-block-heading">Foundry で Fuzz &amp; Invariant</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="import &quot;forge-std/Test.sol&quot;;
contract CounterTest is Test {
    Counter c;
    function setUp() public { c = new Counter(); }
    function testFuzz(uint256 x) public {
        vm.assume(x &lt; 1000);
        uint256 before = c.n();
        c.inc();
        assertEq(c.n(), before + 1);
    }
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;forge-std/Test.sol&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #9CDCFE">contract</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">CounterTest</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">is</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Test</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">Counter</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">c</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">setUp</span><span style="color: #D4D4D4">() </span><span style="color: #DCDCAA">public</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">c</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Counter</span><span style="color: #D4D4D4">(); }</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">testFuzz</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">uint256</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">x</span><span style="color: #D4D4D4">) </span><span style="color: #DCDCAA">public</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">vm</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">assume</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">x</span><span style="color: #D4D4D4"> &lt; </span><span style="color: #B5CEA8">1000</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">uint256</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">before</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">c</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">n</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">c</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">inc</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">assertEq</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">c</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">n</span><span style="color: #D4D4D4">(), </span><span style="color: #9CDCFE">before</span><span style="color: #D4D4D4"> + </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph"><code>forge test --fuzz-runs 500</code> で500ケース自動生成。異常系を自動発見しやすい。</p>



<h2 class="wp-block-heading">統合テストとフォークシミュレーション</h2>



<h3 class="wp-block-heading">Mainnet Fork</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="module.exports = {
  networks: {
    fork: {
      url: &quot;https://eth-mainnet.g.alchemy.com/v2/&lt;API_KEY&gt;&quot;,
      forking: { blockNumber: 19000000 }
    }
  }
};" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #4EC9B0">module</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">exports</span><span style="color: #D4D4D4"> = {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">networks:</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">fork:</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #9CDCFE">url:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;https://eth-mainnet.g.alchemy.com/v2/&lt;API_KEY&gt;&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #9CDCFE">forking:</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">blockNumber:</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">19000000</span><span style="color: #D4D4D4"> }</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"><span style="color: #D4D4D4">};</span></span></code></pre></div>



<ul class="wp-block-list">
<li>実際のUniswap V3コントラクトと自作戦略コントラクトをローカル統合</li>



<li>価格オラクルの再入攻撃など<strong>実戦さながら</strong>の検証が可能</li>
</ul>



<h3 class="wp-block-heading">Mock &amp; Stub</h3>



<ul class="wp-block-list">
<li>Chainlink AggregatorV3Interface をダミー実装し価格を固定</li>



<li>ERC20 Permit をスタブして署名検証をスキップしガス測定に集中</li>
</ul>



<h2 class="wp-block-heading">セキュリティテストツールの活用</h2>



<figure class="wp-block-table"><div class="scrollable-table"><table class="has-fixed-layout"><thead><tr><th>ツール</th><th>テスト種別</th><th>強み</th></tr></thead><tbody><tr><td>Slither</td><td>静的解析</td><td>20+ルール、CI統合容易</td></tr><tr><td>Mythril</td><td>バイトコードSWC検査</td><td>SMTベースで深いパス探索</td></tr><tr><td>Echidna</td><td>Fuzz &amp; Invariant</td><td>Solidityでプロパティ定義、見落とし低減</td></tr><tr><td>Manticore</td><td>代数的実行</td><td>低レイヤー応用、複雑パス発見</td></tr></tbody></table></div></figure>



<p class="wp-block-paragraph"><strong>例：Slither CI</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="run-slither:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v3
    - name: Slither
      uses: crytic/slither-action@v0.2.0
      with:
        truffle-version: 5.9.0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">run-slither</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">runs-on</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">ubuntu-latest</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">steps</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    - </span><span style="color: #569CD6">uses</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">actions/checkout@v3</span></span>
<span class="line"><span style="color: #D4D4D4">    - </span><span style="color: #569CD6">name</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">Slither</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">uses</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">crytic/slither-action@v0.2.0</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">with</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">truffle-version</span><span style="color: #D4D4D4">: </span><span style="color: #B5CEA8">5.9.0</span></span></code></pre></div>



<p class="wp-block-paragraph">PRごとにセキュリティ静的解析を自動実行し、リスクを早期検知。</p>



<h2 class="wp-block-heading">性能テストとガス最適化</h2>



<h3 class="wp-block-heading">Hardhat‑gas‑reporter</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="npm i --save-dev hardhat-gas-reporter" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">npm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">i</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">--save-dev</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">hardhat-gas-reporter</span></span></code></pre></div>



<p class="wp-block-paragraph"><code>hardhat.config.js</code></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="require(&quot;hardhat-gas-reporter&quot;);
module.exports = {
  gasReporter: { currency: &quot;USD&quot;, coinmarketcap: &quot;&lt;KEY&gt;&quot; }
};" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;hardhat-gas-reporter&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #4EC9B0">module</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">exports</span><span style="color: #D4D4D4"> = {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">gasReporter:</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">currency:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;USD&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">coinmarketcap:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;&lt;KEY&gt;&quot;</span><span style="color: #D4D4D4"> }</span></span>
<span class="line"><span style="color: #D4D4D4">};</span></span></code></pre></div>



<ul class="wp-block-list">
<li>単体テストと同時にGasコスト一覧をMarkdown出力</li>



<li>コスト重い関数を把握→Unchecked Math・Constant Caching で最適化</li>
</ul>



<h3 class="wp-block-heading">Hyperledger&nbsp;Caliper でTPS測定</h3>



<ul class="wp-block-list">
<li>ノード数やBlockGasLimitを変化させ、Peak TPSとレイテンシを計測</li>



<li>結果をPrometheus + Grafanaで可視化し、Bottleneck分析</li>
</ul>



<h2 class="wp-block-heading">CI/CD パイプラインに組み込む</h2>



<ol class="wp-block-list">
<li><strong>Lint</strong>：Solhint / Prettier でスタイル統一</li>



<li><strong>Unit Test</strong>：Hardhat or Foundry with Coverage≥90%</li>



<li><strong>Security Scan</strong>：Slither &amp; Mythril</li>



<li><strong>Fuzz</strong>：Echidna 1k runs (nightly)</li>



<li><strong>Gas Report</strong>：PRコメントに自動投稿</li>



<li><strong>Testnet Deploy</strong>：成功時のみSepoliaへ自動デプロイ</li>



<li><strong>Etherscan Verify</strong>：APIで自動検証し透明性を担保</li>
</ol>



<h2 class="wp-block-heading">現実のトラブル事例と教訓</h2>



<ul class="wp-block-list">
<li><strong>DAO Hack</strong>：再帰呼び出しを想定した単体テスト不備</li>



<li><strong>bZx Protocol</strong>：価格フィードモックが単一Oracleで多重価格を見落とし</li>



<li><strong>Sushi MISO</strong>：ステート変数初期化未テスト→一括NFT購入バグ</li>
</ul>



<p class="wp-block-paragraph"><strong>教訓</strong>：テストは「想定どおり動くか」より「想定外で止まるか」を検証することが重要。</p>



<h2 class="wp-block-heading">まとめ</h2>



<p class="wp-block-paragraph">ブロックチェーン・スマートコントラクトのテストは「単体→統合→セキュリティ→性能」という多層防御が欠かせません。HardhatやFoundryでの高速テスト、Slither/Echidnaでの自動脆弱性検査、Caliperでの性能測定を組み合わせることで、品質と開発速度を両立できます。LogRocketが指摘するように、テスト漏れは開発者の信頼を一瞬で失います 。本記事で紹介したツールと手法をCI/CDに組み込み、<strong>デプロイ前に壊れないことを証明する</strong>文化をチーム全体で育てましょう。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://techgrowup.net/blockchain-test-guide/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>スマートコントラクト単体テストガイド──Hardhat・Foundry・Brownieで学ぶ堅牢なEthereum開発フロー</title>
		<link>https://techgrowup.net/blockchain-unit-test/</link>
					<comments>https://techgrowup.net/blockchain-unit-test/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[techgrowup]]></dc:creator>
		<pubDate>Sat, 19 Apr 2025 23:00:00 +0000</pubDate>
				<category><![CDATA[ブロックチェーン]]></category>
		<category><![CDATA[Brownie]]></category>
		<category><![CDATA[Foundry]]></category>
		<category><![CDATA[Fuzzing]]></category>
		<category><![CDATA[Hardhat]]></category>
		<category><![CDATA[Solidity]]></category>
		<category><![CDATA[カバレッジ]]></category>
		<category><![CDATA[スマートコンタクト]]></category>
		<category><![CDATA[単体テスト]]></category>
		<guid isPermaLink="false">https://techgrowup.net/?p=2792</guid>

					<description><![CDATA[はじめに DeFiプロトコルやNFTプロジェクトが相次いでハッキング被害を受ける中、スマートコントラクトの単体テスト（Unit Testing）は「開発者の保険」ではなく必須条件になりました。オンチェーンにデプロイしたコ [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h1 class="wp-block-heading">はじめに</h1>



<p class="wp-block-paragraph">DeFiプロトコルやNFTプロジェクトが相次いでハッキング被害を受ける中、スマートコントラクトの<strong>単体テスト（Unit Testing）は「開発者の保険」ではなく必須条件</strong>になりました。オンチェーンにデプロイしたコードは基本的に変更不可能であり、1行のバグが数百万ドルを失わせる事例も珍しくありません。Ethereum.orgの公式ドキュメントは、Hardhat・Truffle・Foundry・Brownieなど主要フレームワークを用いたテスト戦略を紹介しています。本記事ではその内容を深掘りし、「何を・どうテストすればよいか」を体系的にまとめます。</p>



<h2 class="wp-block-heading">単体テストの目的と3つの分類</h2>



<h3 class="wp-block-heading">機能検証（Functional&nbsp;Tests）</h3>



<ul class="wp-block-list">
<li>関数の返値・状態変化が仕様どおりか</li>



<li>リバート条件が適切か（<code>require</code>／<code>revert</code>）</li>
</ul>



<h3 class="wp-block-heading">セキュリティ検証（Security&nbsp;Tests）</h3>



<ul class="wp-block-list">
<li>再入可能性・整数オーバーフロー・アクセス制御漏れ</li>



<li>想定外のキャッシュ汚染／ストレージ衝突</li>
</ul>



<h3 class="wp-block-heading">経済設計検証（Economic&nbsp;Tests）</h3>



<ul class="wp-block-list">
<li>金利計算・報酬分配・トークン供給が意図どおりか</li>



<li>oracle操作やフラッシュローン攻撃耐性</li>
</ul>



<h2 class="wp-block-heading">Hardhatで学ぶJavaScript/TypeScriptテスト基礎</h2>



<h3 class="wp-block-heading">セットアップ</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="npm init -y
npm i --save-dev hardhat @nomiclabs/hardhat-ethers ethers chai
npx hardhat # 「JavaScriptプロジェクト」を選択" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">npm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">init</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-y</span></span>
<span class="line"><span style="color: #DCDCAA">npm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">i</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">--save-dev</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">hardhat</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">@nomiclabs/hardhat-ethers</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">ethers</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">chai</span></span>
<span class="line"><span style="color: #DCDCAA">npx</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">hardhat</span><span style="color: #D4D4D4"> </span><span style="color: #6A9955"># 「JavaScriptプロジェクト」を選択</span></span></code></pre></div>



<h3 class="wp-block-heading">コントラクト（Lock.sol）</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="pragma solidity ^0.8.20;
contract Lock {
  uint public unlockTime;
  constructor(uint _unlockTime) payable {
    unlockTime = _unlockTime;
  }
  function withdraw() external {
    require(block.timestamp &gt;= unlockTime, &quot;locked&quot;);
    payable(msg.sender).transfer(address(this).balance);
  }
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">pragma</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">solidity</span><span style="color: #D4D4D4"> ^0.8.20;</span></span>
<span class="line"><span style="color: #569CD6">contract</span><span style="color: #4EC9B0"> Lock</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #4EC9B0">uint</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> unlockTime;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">constructor</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">uint</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">_unlockTime</span><span style="color: #D4D4D4">) payable {</span></span>
<span class="line"><span style="color: #D4D4D4">    unlockTime = _unlockTime;</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">withdraw</span><span style="color: #D4D4D4">() </span><span style="color: #569CD6">external</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">require</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">block</span><span style="color: #D4D4D4">.timestamp &gt;= unlockTime, </span><span style="color: #CE9178">&quot;locked&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">payable</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">msg.sender</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">transfer</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">address</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">).balance);</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<h3 class="wp-block-heading">単体テスト（test/Lock.ts）</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="import { expect } from &quot;chai&quot;;
import { ethers } from &quot;hardhat&quot;;

describe(&quot;Lock&quot;, () =&gt; {
  it(&quot;ロック解除前はrevert&quot;, async () =&gt; {
    const [alice] = await ethers.getSigners();
    const Lock = await ethers.getContractFactory(&quot;Lock&quot;);
    const lock = await Lock.deploy((await ethers.provider.getBlock(&quot;latest&quot;)).timestamp + 60, { value: 1 });
    await expect(lock.withdraw()).to.be.revertedWith(&quot;locked&quot;);
  });

  it(&quot;ロック解除後に送金&quot;, async () =&gt; {
    const [alice] = await ethers.getSigners();
    const Lock = await ethers.getContractFactory(&quot;Lock&quot;);
    const unlockAt = (await ethers.provider.getBlock(&quot;latest&quot;)).timestamp + 60;
    const lock = await Lock.deploy(unlockAt, { value: 1 });
    await ethers.provider.send(&quot;evm_setNextBlockTimestamp&quot;, [unlockAt + 1]);
    await lock.withdraw();
    expect(await ethers.provider.getBalance(lock.address)).to.eq(0);
  });
});" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">expect</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;chai&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">ethers</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;hardhat&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #DCDCAA">describe</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;Lock&quot;</span><span style="color: #D4D4D4">, () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">it</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;ロック解除前はrevert&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> [</span><span style="color: #4FC1FF">alice</span><span style="color: #D4D4D4">] = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">ethers</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getSigners</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">Lock</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">ethers</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getContractFactory</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;Lock&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">lock</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Lock</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">deploy</span><span style="color: #D4D4D4">((</span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">ethers</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">provider</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getBlock</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;latest&quot;</span><span style="color: #D4D4D4">)).</span><span style="color: #9CDCFE">timestamp</span><span style="color: #D4D4D4"> + </span><span style="color: #B5CEA8">60</span><span style="color: #D4D4D4">, { </span><span style="color: #9CDCFE">value:</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4"> });</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">expect</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">lock</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">withdraw</span><span style="color: #D4D4D4">()).</span><span style="color: #9CDCFE">to</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">be</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">revertedWith</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;locked&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">  });</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">it</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;ロック解除後に送金&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> [</span><span style="color: #4FC1FF">alice</span><span style="color: #D4D4D4">] = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">ethers</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getSigners</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">Lock</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">ethers</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getContractFactory</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;Lock&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">unlockAt</span><span style="color: #D4D4D4"> = (</span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">ethers</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">provider</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getBlock</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;latest&quot;</span><span style="color: #D4D4D4">)).</span><span style="color: #9CDCFE">timestamp</span><span style="color: #D4D4D4"> + </span><span style="color: #B5CEA8">60</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">lock</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Lock</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">deploy</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">unlockAt</span><span style="color: #D4D4D4">, { </span><span style="color: #9CDCFE">value:</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4"> });</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">ethers</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">provider</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">send</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;evm_setNextBlockTimestamp&quot;</span><span style="color: #D4D4D4">, [</span><span style="color: #9CDCFE">unlockAt</span><span style="color: #D4D4D4"> + </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">]);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">lock</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">withdraw</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">expect</span><span style="color: #D4D4D4">(</span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">ethers</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">provider</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getBalance</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">lock</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">address</span><span style="color: #D4D4D4">)).</span><span style="color: #9CDCFE">to</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">eq</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">  });</span></span>
<span class="line"><span style="color: #D4D4D4">});</span></span></code></pre></div>



<h3 class="wp-block-heading">ポイント</h3>



<ul class="wp-block-list">
<li><code>evm_setNextBlockTimestamp</code>でブロック時間を操作し時間依存ロジックをテスト</li>



<li><code>chai</code>の<code>expect().to.be.revertedWith()</code>でリバート理由まで検証</li>
</ul>



<h2 class="wp-block-heading">Foundryで高速Fuzz&amp;Invariantテスト</h2>



<h3 class="wp-block-heading">インストール</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="curl -L https://foundry.paradigm.xyz | bash
foundryup
forge init foundry-demo &amp;&amp; cd foundry-demo" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">curl</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-L</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">https://foundry.paradigm.xyz</span><span style="color: #D4D4D4"> | </span><span style="color: #DCDCAA">bash</span></span>
<span class="line"><span style="color: #DCDCAA">foundryup</span></span>
<span class="line"><span style="color: #DCDCAA">forge</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">init</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">foundry-demo</span><span style="color: #D4D4D4"> &amp;&amp; </span><span style="color: #DCDCAA">cd</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">foundry-demo</span></span></code></pre></div>



<h3 class="wp-block-heading">Fuzzテスト例（Counter.t.sol）</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="pragma solidity ^0.8.23;
import &quot;forge-std/Test.sol&quot;;

contract Counter {
  uint256 public num;
  function inc(uint256 x) external { num += x; }
}

contract CounterTest is Test {
  Counter c = new Counter();

  function testFuzz_Inc(uint256 x) public {
    vm.assume(x &lt; 1e18);
    uint256 before = c.num();
    c.inc(x);
    assertEq(c.num(), before + x);
  }
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">pragma</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">solidity</span><span style="color: #D4D4D4"> ^0.8.23;</span></span>
<span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;forge-std/Test.sol&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">contract</span><span style="color: #4EC9B0"> Counter</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #4EC9B0">uint256</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> num;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">inc</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">uint256</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">x</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">external</span><span style="color: #D4D4D4"> { num += x; }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">contract</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">CounterTest</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Test</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  Counter c = </span><span style="color: #C586C0">new</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Counter</span><span style="color: #D4D4D4">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">testFuzz_Inc</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">uint256</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">x</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    vm.</span><span style="color: #DCDCAA">assume</span><span style="color: #D4D4D4">(x &lt; </span><span style="color: #B5CEA8">1e18</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #4EC9B0">uint256</span><span style="color: #D4D4D4"> before = c.</span><span style="color: #DCDCAA">num</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    c.</span><span style="color: #DCDCAA">inc</span><span style="color: #D4D4D4">(x);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">assertEq</span><span style="color: #D4D4D4">(c.</span><span style="color: #DCDCAA">num</span><span style="color: #D4D4D4">(), before + x);</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<ul class="wp-block-list">
<li><code>forge test -vvvv</code>は100件以上のランダム入力で検証</li>



<li><code>vm.assume</code>で現実的な入力に制限し不要なガス浪費を抑制</li>
</ul>



<h3 class="wp-block-heading">Invariantテスト</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="contract Invariant is Test {
  Counter c = new Counter();

  function invariant_sumNotOverflow() public {
    assertLe(c.num(), type(uint256).max / 2);
  }
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">contract</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Invariant</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Test</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  Counter c = </span><span style="color: #C586C0">new</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Counter</span><span style="color: #D4D4D4">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">invariant_sumNotOverflow</span><span style="color: #D4D4D4">() </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">assertLe</span><span style="color: #D4D4D4">(c.</span><span style="color: #DCDCAA">num</span><span style="color: #D4D4D4">(), </span><span style="color: #569CD6">type</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">uint256</span><span style="color: #D4D4D4">).max / </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">Foundryは状態を保存しながら数千回ランダムシーケンスを実行、インバリアント破壊ケースを自動検出します。</p>



<h2 class="wp-block-heading">Brownie（Python）でのテスト&amp;カバレッジ</h2>



<h3 class="wp-block-heading">インストール</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="pip install eth-brownie
brownie init" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">pip</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">install</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">eth-brownie</span></span>
<span class="line"><span style="color: #DCDCAA">brownie</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">init</span></span></code></pre></div>



<h3 class="wp-block-heading">PyTest記法</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="import pytest
def test_withdraw(accounts, Lock):
    alice = accounts[0]
    lock = Lock.deploy(0, {'from': alice, 'value': '1 ether'})
    with pytest.reverts(&quot;locked&quot;):
        lock.withdraw({'from': alice})" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> pytest</span></span>
<span class="line"><span style="color: #569CD6">def</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">test_withdraw</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">accounts</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">Lock</span><span style="color: #D4D4D4">):</span></span>
<span class="line"><span style="color: #D4D4D4">    alice = accounts[</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">]</span></span>
<span class="line"><span style="color: #D4D4D4">    lock = Lock.deploy(</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">, {</span><span style="color: #CE9178">&#39;from&#39;</span><span style="color: #D4D4D4">: alice, </span><span style="color: #CE9178">&#39;value&#39;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;1 ether&#39;</span><span style="color: #D4D4D4">})</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">with</span><span style="color: #D4D4D4"> pytest.reverts(</span><span style="color: #CE9178">&quot;locked&quot;</span><span style="color: #D4D4D4">):</span></span>
<span class="line"><span style="color: #D4D4D4">        lock.withdraw({</span><span style="color: #CE9178">&#39;from&#39;</span><span style="color: #D4D4D4">: alice})</span></span></code></pre></div>



<h3 class="wp-block-heading">カバレッジ測定</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="brownie test --coverage" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">brownie</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">test</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">--coverage</span></span></code></pre></div>



<p class="wp-block-paragraph">HTMLレポートで行単位の未テスト箇所を可視化。Solidityファイルが赤色ならテスト追加が必要です。</p>



<h2 class="wp-block-heading">モック &amp; スタブ技法</h2>



<figure class="wp-block-table"><div class="scrollable-table"><table class="has-fixed-layout"><thead><tr><th>シナリオ</th><th>手法</th><th>フレームワーク</th></tr></thead><tbody><tr><td>Oracle価格を固定</td><td>MockAggregatorV3をデプロイ</td><td>Hardhat/Foundry</td></tr><tr><td>ERC20転送成功/失敗</td><td>FakeTokenで<code>transfer</code>を戻り値操作</td><td>Hardhat</td></tr><tr><td>Chainlink&nbsp;VRF</td><td><code>vm.roll</code>で乱数固定</td><td>Foundry</td></tr></tbody></table></div></figure>



<p class="wp-block-paragraph">外部コントラクトをモック化することで、単体テストは<strong>純粋関数的</strong>になり失敗箇所特定が迅速になります。</p>



<h2 class="wp-block-heading">CI/CD統合ベストプラクティス</h2>



<ol class="wp-block-list">
<li><strong>GitHub Actions</strong>で<code>forge test</code>や<code>npx hardhat test</code>を実行</li>



<li>カバレッジ閾値（例:90%）未満ならPRブロック</li>



<li><code>actions/cache</code>でFoundryキャッシュ・node_modulesを高速化</li>



<li>Solidity静的解析（Slither）・Lint（Solhint）を並列ジョブで追加</li>



<li>テスト通過後のみ<code>hardhat-deploy</code>または<code>forge script</code>でTestnetへ自動デプロイ</li>
</ol>



<h2 class="wp-block-heading">よくある落とし穴と対策</h2>



<figure class="wp-block-table"><div class="scrollable-table"><table class="has-fixed-layout"><thead><tr><th>問題</th><th>症状</th><th>対策</th></tr></thead><tbody><tr><td>ForkテストのRPC制限</td><td>Alchemy/Etherscanエラー</td><td><code>ALCHEMY_MAX_CALL=30</code>に増枠プラン・<code>--fork-block-number</code>固定</td></tr><tr><td>フラッシュローン攻撃検出漏れ</td><td>テストが単一Tx</td><td>Hardhat&nbsp;Networkで<code>autoMine=false</code>にし複数呼び出し</td></tr><tr><td>時間依存テストの不安定</td><td>CIで偶発fail</td><td>ブロックタイムを固定＆<code>evm_increaseTime</code> instead of <code>sleep</code></td></tr></tbody></table></div></figure>



<h2 class="wp-block-heading">まとめ</h2>



<p class="wp-block-paragraph">スマートコントラクトの単体テストは<strong>機能・セキュリティ・経済設計</strong>の3軸を網羅する必要があります。Remixで概念を掴み、HardhatやFoundryで高速なローカルテストを構築し、BrownieやPythonの資産を活かして統計解析を行う――この多段構成が2025年現在の“最強パターン”です。<br>CIにテストと静的解析を組み込み、カバレッジとFuzzingで抜け漏れを潰せば、メインネットデプロイ後に重大バグが見つかるリスクを大幅に下げられます。この記事を参考に、まずは<code>forge init</code>や<code>npx hardhat</code>を実行し、あなたのコントラクトを徹底的に叩き上げてみてください。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://techgrowup.net/blockchain-unit-test/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>イーサリアム開発IDE──RemixからFoundryまで比較し最適な環境を選ぶ</title>
		<link>https://techgrowup.net/blockchain-ethurium-ide/</link>
					<comments>https://techgrowup.net/blockchain-ethurium-ide/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[techgrowup]]></dc:creator>
		<pubDate>Fri, 18 Apr 2025 23:00:00 +0000</pubDate>
				<category><![CDATA[ブロックチェーン]]></category>
		<category><![CDATA[Brownie]]></category>
		<category><![CDATA[Foundry]]></category>
		<category><![CDATA[Hardhat]]></category>
		<category><![CDATA[IDE]]></category>
		<category><![CDATA[Remix]]></category>
		<category><![CDATA[Solidity]]></category>
		<category><![CDATA[Truffle]]></category>
		<category><![CDATA[VS Code]]></category>
		<category><![CDATA[イーサリアム開発]]></category>
		<guid isPermaLink="false">https://techgrowup.net/?p=2788</guid>

					<description><![CDATA[はじめに イーサリアムのスマートコントラクト開発は数年前より格段に多様化しました。オンラインで学習できるRemixから、高度なCI/CDに対応したHardhat＋VS Code、超高速ビルドのFoundryまで、用途に応 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h1 class="wp-block-heading">はじめに</h1>



<p class="wp-block-paragraph">イーサリアムのスマートコントラクト開発は数年前より格段に多様化しました。オンラインで学習できる<strong>Remix</strong>から、高度なCI/CDに対応した<strong>Hardhat＋VS Code</strong>、超高速ビルドの<strong>Foundry</strong>まで、用途に応じたIDE（Integrated Development Environment）が選択できます。本記事ではEthereum.orgの「IDEs」ドキュメントを基に、主要ツールの特徴・インストール手順・実践コード例を詳しく紹介し、5“自分に最適な開発環境”を選ぶヒントを提供します。</p>



<h2 class="wp-block-heading">Remix&nbsp;IDE ―― ブラウザだけで完結する学習とプロトタイプの王道</h2>



<h3 class="wp-block-heading">特徴</h3>



<ul class="wp-block-list">
<li><strong>インストール不要</strong>：ブラウザを開くだけでSolidityエディタ・コンパイラ・デプロイUIが揃う</li>



<li><strong>プラグインアーキテクチャ</strong>：Slither解析、Gas Profiler、Sol Hintなどボタン一つで拡張</li>



<li><strong>ネットワーク接続</strong>：MetaMask経由でテストネット／メインネットに直接デプロイ可能</li>
</ul>



<h3 class="wp-block-heading">使いどころ</h3>



<ul class="wp-block-list">
<li>スマートコントラクトの<strong>チュートリアル学習</strong></li>



<li>ハッカソンの短時間プロトタイプ</li>



<li>セキュリティ監査前の<strong>事前チェック</strong>（Slither &amp; MythX Plugin）</li>
</ul>



<h3 class="wp-block-heading">Tips</h3>



<p class="wp-block-paragraph">「Settings&nbsp;→&nbsp;Solidity&nbsp;Compiler」で自動コンパイルをOFFにすると、GasProfiler実行時のブラウザ負荷を抑えられます。</p>



<h2 class="wp-block-heading">Hardhat + VS&nbsp;Code ―― 拡張性と自動化に優れた“実務標準”</h2>



<h3 class="wp-block-heading">なぜHardhatが選ばれるか</h3>



<ol class="wp-block-list">
<li><strong>JS/TS API</strong> が充実し、ethers.jsと統合しやすい</li>



<li><strong>プラグイン豊富</strong>：Gas Reporter、Typechain、Tenderly Verify 等</li>



<li><strong>Hardhat Network</strong> によるフォーク機能でメインネット状態をローカル再現</li>
</ol>



<h3 class="wp-block-heading">環境構築</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="mkdir myToken &amp;&amp; cd $_
npm init -y
npm i --save-dev hardhat @nomiclabs/hardhat-ethers ethers
npx hardhat                         # プロジェクト生成" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">mkdir</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">myToken</span><span style="color: #D4D4D4"> &amp;&amp; </span><span style="color: #DCDCAA">cd</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">$_</span></span>
<span class="line"><span style="color: #DCDCAA">npm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">init</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-y</span></span>
<span class="line"><span style="color: #DCDCAA">npm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">i</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">--save-dev</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">hardhat</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">@nomiclabs/hardhat-ethers</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">ethers</span></span>
<span class="line"><span style="color: #DCDCAA">npx</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">hardhat</span><span style="color: #D4D4D4">                         </span><span style="color: #6A9955"># プロジェクト生成</span></span></code></pre></div>



<p class="wp-block-paragraph"><code>hardhat.config.ts</code></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="import { HardhatUserConfig } from &quot;hardhat/config&quot;;
import &quot;@nomiclabs/hardhat-ethers&quot;;
const config: HardhatUserConfig = {
  solidity: &quot;0.8.23&quot;,
  networks: {
    sepolia: {
      url: &quot;https://sepolia.infura.io/v3/&lt;API_KEY&gt;&quot;,
      accounts: [process.env.PRIVATE_KEY as string]
    }
  }
};
export default config;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">HardhatUserConfig</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;hardhat/config&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;@nomiclabs/hardhat-ethers&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">config</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">HardhatUserConfig</span><span style="color: #D4D4D4"> = {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">solidity:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;0.8.23&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">networks:</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">sepolia:</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #9CDCFE">url:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;https://sepolia.infura.io/v3/&lt;API_KEY&gt;&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #9CDCFE">accounts:</span><span style="color: #D4D4D4"> [</span><span style="color: #9CDCFE">process</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">env</span><span style="color: #D4D4D4">.</span><span style="color: #4FC1FF">PRIVATE_KEY</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">as</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">string</span><span style="color: #D4D4D4">]</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"><span style="color: #D4D4D4">};</span></span>
<span class="line"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">default</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">config</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<p class="wp-block-paragraph">デプロイスクリプト</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="async function main() {
  const Token = await ethers.getContractFactory(&quot;ERC20PresetMinterPauser&quot;);
  const token = await Token.deploy(&quot;Demo&quot;, &quot;DMT&quot;);
  await token.deployed();
  console.log(&quot;Token:&quot;, token.address);
}
main();" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">main</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">Token</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">ethers</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">getContractFactory</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;ERC20PresetMinterPauser&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">token</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Token</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">deploy</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;Demo&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;DMT&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">token</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">deployed</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">console</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">log</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;Token:&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">token</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">address</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"><span style="color: #DCDCAA">main</span><span style="color: #D4D4D4">();</span></span></code></pre></div>



<h3 class="wp-block-heading">VS&nbsp;Code拡張</h3>



<ul class="wp-block-list">
<li><strong>solidity</strong>：シンタックスハイライト＋Lint</li>



<li><strong>Hardhat Runner</strong>：タスクをGUI実行</li>



<li><strong>Foundry for VS Code</strong>：後述環境と併用可能</li>
</ul>



<h2 class="wp-block-heading">Foundry ―― 超高速Rust実装で開発フローを刷新</h2>



<h3 class="wp-block-heading">コアツール</h3>



<figure class="wp-block-table"><div class="scrollable-table"><table class="has-fixed-layout"><thead><tr><th>コマンド</th><th>機能</th></tr></thead><tbody><tr><td><code>forge</code></td><td>ビルド・テスト・デプロイ（SolidityネイティブUnitTest）</td></tr><tr><td><code>cast</code></td><td>CLIでチェーンと対話</td></tr><tr><td><code>anvil</code></td><td>高速EVMローカルノード（フォーク/チェッカブル）</td></tr></tbody></table></div></figure>



<h3 class="wp-block-heading">インストール</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="curl -L https://foundry.paradigm.xyz | bash
foundryup" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">curl</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-L</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">https://foundry.paradigm.xyz</span><span style="color: #D4D4D4"> | </span><span style="color: #DCDCAA">bash</span></span>
<span class="line"><span style="color: #DCDCAA">foundryup</span></span></code></pre></div>



<h3 class="wp-block-heading">テスト例</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="pragma solidity ^0.8.19;
import &quot;forge-std/Test.sol&quot;;
import &quot;../src/Counter.sol&quot;;

contract CounterTest is Test {
    Counter c;
    function setUp() public { c = new Counter(); }
    function testInc() public {
        c.inc();
        assertEq(c.number(), 1);
    }
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">pragma</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">solidity</span><span style="color: #D4D4D4"> ^0.8.19;</span></span>
<span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;forge-std/Test.sol&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;../src/Counter.sol&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">contract</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">CounterTest</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">is</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Test</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    Counter c;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">setUp</span><span style="color: #D4D4D4">() </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> { c = </span><span style="color: #C586C0">new</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Counter</span><span style="color: #D4D4D4">(); }</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">testInc</span><span style="color: #D4D4D4">() </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        c.</span><span style="color: #DCDCAA">inc</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">assertEq</span><span style="color: #D4D4D4">(c.</span><span style="color: #DCDCAA">number</span><span style="color: #D4D4D4">(), </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph"><code>forge test -vv</code> 実行で1000&nbsp;tx規模でも数秒で完走。CI時間を大幅圧縮できます。</p>



<h3 class="wp-block-heading">選定指針</h3>



<ul class="wp-block-list">
<li>大規模テスト／Fuzz／Property-Based Testing重視→Foundry</li>



<li>TypeScriptフロント統合やmigrations文化維持→Hardhat</li>
</ul>



<h2 class="wp-block-heading">Truffle &amp; Ganache ―― いまでも有効なクラシックスタック</h2>



<ul class="wp-block-list">
<li><strong>Truffle</strong> はmigrationスクリプト文化とチュートリアルの豊富さで学習者に人気</li>



<li><strong>Ganache</strong> はクリックだけでローカルチェーンを起動可能（GUI版は22年で開発終了、CLIは存続）</li>



<li>Hardhat/F oundry登場でメインストリームからは離れつつも、Legacy DAppの保守やOpenZeppelin Upgradesプラグインとの相性で根強い需要があります。</li>
</ul>



<h2 class="wp-block-heading">WebIDE &amp; SaaS型IDEの新潮流</h2>



<figure class="wp-block-table"><div class="scrollable-table"><table class="has-fixed-layout"><thead><tr><th>プラットフォーム</th><th>特徴</th><th>料金モデル</th></tr></thead><tbody><tr><td>Ethereum&nbsp;Studio</td><td>Remixをクラウド保存＆チームコラボ対応</td><td>無料</td></tr><tr><td>StackBlitz&nbsp;Web3</td><td>TypeScript＋HardhatをブラウザVMで実行</td><td>Freemium</td></tr><tr><td>Gitpod Web3</td><td>devcontainerにFoundry/Hardhatをプリセット</td><td>従量課金</td></tr></tbody></table></div></figure>



<p class="wp-block-paragraph">企業チームは<strong>Gitpod＋Foundry＋Anvil</strong>でエフェメラル環境をCIに組み込むケースが増えています。</p>



<h2 class="wp-block-heading">IDE選定チャート</h2>



<ol class="wp-block-list">
<li><strong>学習フェーズ</strong>
<ul class="wp-block-list">
<li>ブラウザ完結 → Remix</li>



<li>Python好き → Brownie</li>
</ul>
</li>



<li><strong>PoC〜ハッカソン</strong>
<ul class="wp-block-list">
<li>迅速なUI：Remix or Hardhat local</li>
</ul>
</li>



<li><strong>商用開発</strong>
<ul class="wp-block-list">
<li>高速テスト・CI：Foundry</li>



<li>フロントJS統合：Hardhat</li>
</ul>
</li>



<li><strong>研究・監査</strong>
<ul class="wp-block-list">
<li>Fuzz／Invariant：Foundry</li>



<li>Formal Verification：Remix Slither Plugin＋MythX</li>
</ul>
</li>
</ol>



<h2 class="wp-block-heading">ベストプラクティスと実用Tips</h2>



<ul class="wp-block-list">
<li><strong>VS Code Remote Containers</strong>でHardhatとFoundryを両立</li>



<li><strong>Slither + Forge</strong>：<code>forge coverage</code>でカバレッジ生成→Slither解析を一気通貫</li>



<li><strong>Prettier-plugin-solidity</strong>でコードフォーマットを統一</li>



<li><strong>GitHub Actions</strong>：<code>actions/cache</code>に<code>.foundry/cache</code>を指定しCI高速化</li>



<li><strong>Tenderly</strong>でトランザクションシミュレーションを自動コメント（PRレビュー品質向上）</li>
</ul>



<h2 class="wp-block-heading">今後の展望</h2>



<ul class="wp-block-list">
<li><strong>Foundry v2</strong>：SwayやMoveなどEVM外VMへのクロスコンパイル計画</li>



<li><strong>Hardhat Profiler</strong>：AIベースGas最適提案機能をベータ搭載</li>



<li><strong>Remix Desktop</strong>：Electron版がRoadmapに追加、オフラインでも学習環境を維持</li>
</ul>



<h2 class="wp-block-heading">まとめ</h2>



<p class="wp-block-paragraph">イーサリアム開発IDEは「学習特化のRemix」「TypeScriptエコシステムと親和性が高いHardhat」「超高速・高機能のFoundry」という3大トレンドを形成しつつ、Truffle/Brownie/クラウドIDEがニッチを補完しています。<br>自分の<strong>言語嗜好・チーム規模・CI要件</strong>を整理し、最適なIDEを選択することがプロダクト成功への第一歩です。本記事を参考に、ぜひローカルで<code>npx hardhat</code>や<code>forge init</code>を実行し、最適な開発体験を手に入れてください。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://techgrowup.net/blockchain-ethurium-ide/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Disk: Enhanced  を使用したページ キャッシュ

Served from: techgrowup.net @ 2026-07-04 08:38:35 by W3 Total Cache
-->