Crypto contract verification is the definitive proof of identity in the DeFi ecosystem, transforming opaque bytecode into trusted logic. However, the process is often misunderstood, leading to frustration when the "Deterministic Black Box" of the compiler produces mismatching fingerprints. This article demystifies verification by visualizing it as a "Mirror Mechanism," where local compilation environments must accurately replicate the deployment conditions. We move beyond manual web uploads to establish a robust, automated workflow using CLI tools and the "Standard JSON Input" — the ultimate weapon against obscure verification errors. 最後に、我々は攻撃的なガスIR最適化と検証複雑さの間の重要な交換を分析し、あなたに耐久性 Introduction 暗号契約の検証は、Etherscanで緑色のチェックマークを取得するだけでなく、あなたのコードの究極のアイデンティティの証明です。 展開されると、契約は原始バイトコードに縮小され、効果的にその起源を奪われます。 源を証明し、信頼できない環境で所有権を確立するには、検証が義務付けられています。 それはDeFiエコシステムにおける透明性、セキュリティ、およびコンポーネビリティの基本的な要件です。 それがなければ、契約はヘクサデシマルバイトコードの曖昧なブロックであり、ユーザーには読めませんし、他の開発者には使用できません。 鏡の機械 検証エラーを克服するには、まず「検証」をタップすると実際に何が起こるかを理解する必要があります。それは誤解的に単純です:ブロックエクスプレーヤー(例えば、Etherscan)は、提供されたソースコードが連鎖に展開された同じバイトコードを生成することを証明するために、正確なコンパイル環境を再構築しなければなりません。 図 1 で示すように、このプロセスは「鏡のメカニズム」として機能します。 検証器は、ソースコードを独立してコンパイルし、出力バイトごとにチェーン上のデータと比較します。 たとえ1バイトでも異なる場合、検証は失敗します. これは私たちをすべてのSolidity開発者の核心闘争に導きます。 『Deterministic Black Box』 理論的には、「byte-perfect」のマッチングは簡単なように聞こえます。実践では、悪夢が始まる場所です。開発者は完璧に機能するdAppを持ち、100%の地元のテストを経過し、それでも検証リムボに閉じ込められています。 なぜ? Solidity コンパイラは Deterministic Black Box だからです. 図 2 に示すように、出力バイトコードはソースコードだけでは決定されません. それは、コンパイラのバージョン、最適化実行、メタデータハッシュ、および特定の EVM バージョンの数十の見えない変数の産物です。 異なる viaIR 設定や欠けているプロキシ構成など、Etherscan が仮定するものと対照的に、現地の hardhat.config.ts でわずかな差異は、完全に異なるバイトコードハッシュ(Bytecode B)を引き起こし、恐ろしい「Bytecode Mismatch」エラーを引き起こします。 このガイドは、検証が機能することを「希望する」開発者から、ブラックボックスを制御するマスターマインドにあなたを変えることを目指しています.We will explore the standard CLI flows, the manual overrides, and finally, present data-driven insights into how advanced optimizations impact this fragile process. The CLI Approach – Precision & Automation 前回のセクションでは、検証プロセスを「鏡のメカニズム」として視覚化しました(図1)。目的は、あなたのローカルコンパイルがリモート環境に完璧に一致することを保証することです。Web UIを通じて手動でこれを行うことはエラーの可能性があります。 コマンド ライン インターフェイス (CLI) ツールが輝く場所です. デプロイと検証の両方のために同じコンフィギュレーション ファイル (hardhat.config.ts または foundry.toml) を使用することで、CLI ツールは一貫性を強化し、「Deterministic Black Box」 ( 図 2) を管理可能なパイプラインに効率的に縮小します。 ハードコントロール ほとんどの開発者にとって、hardhat-verify プラグインは防衛の第一線であり、ビルドアーティファクトの抽出を自動化し、Etherscan APIと直接通信します。 それを有効にするには、hardhat.config.ts が etherscan 構成を含んでいることを確認してください. This is often where the first point of failure occurs: Network Mismatch. // hardhat.config.ts import "@nomicfoundation/hardhat-verify"; module.exports = { solidity: { version: "0.8.20", settings: { optimizer: { enabled: true, // Critical: Must match deployment! runs: 200, }, viaIR: true, // Often overlooked, causes huge bytecode diffs }, }, etherscan: { apiKey: { // Use different keys for different chains to avoid rate limits mainnet: "YOUR_ETHERSCAN_API_KEY", sepolia: "YOUR_ETHERSCAN_API_KEY", }, }, }; The Command: Once configured, the verification command is straightforward. It recompiles the contract locally to generate the artifacts and then submits the source code to Etherscan. Mastermind Tip: Always run npx hardhat clean before verifying. Stale artifacts (cached bytecode from a previous compile with different settings) are a silent killer of verification attempts. コマンドは、コマンドをローカルに生成し、ソースコードをEtherscanに提出します。 npx hardhat verify --network sepolia <DEPLOYED_CONTRACT_ADDRESS> <CONSTRUCTOR_ARGS> The Pitfall of Constructor Arguments(コンストラクターの論点) 契約に構築者がある場合、検証が大幅に難しくなります CLI は、作成コードの署名を再生するために、展開中に渡した正確な値を知る必要があります。 スクリプトを使用してデプロイした場合は、「単一の真実の源」を維持するために別々の議論ファイル(例えば、arguments.ts)を作成する必要があります。 // arguments.ts module.exports = [ "0x123...TokenAddress", // _token "My DAO Name", // _name 1000000n // _initialSupply (Use BigInt for uint256) ]; なぜこれが重要なのか: 一般的なエラーは「1000000(数字)」ではなく「1000000(文字列)」または「10000000n(BigInt)」です。CLI ツールはこれらを異なる方法で ABI Hex に暗号化します。 Foundry 検証 Foundry ツールチェーンを使用する人にとっては、検証が急速に進み、本質的に forge に組み込まれています。 プラグインが必要な Hardhat とは異なり、Foundry はこれを箱から処理します。 forge verify-contract \ --chain-id 11155111 \ --num-of-optimizations 200 \ --watch \ <CONTRACT_ADDRESS> \ src/MyContract.sol:MyContract \ <ETHERSCAN_API_KEY> The Power of --watch: Foundry's --watch flags acts as a "verbose mode," polling Etherscan for the status. It gives you immediate feedback on whether the submission was accepted or if it failed due to "Bytecode Mismatch", saving you from refreshing the browser window. 送信が受け入れられたか、または「Bytecode Mismatch」のせいで失敗したかについて、すぐにフィードバックを与えます。 完璧な設定でさえ、AggregateError または "Fail - Unable to verify" などの不透明なエラーに遭遇する可能性があります。 Chained Imports: Your contract imports 50+ files, and Etherscan's API times out processing the massive JSON payload. あなたの契約は50以上のファイルをインポートし、EtherscanのAPIは膨大なJSONのパイロードを処理します。 ライブラリリンク: 契約は、まだ検証されていない外部ライブラリに依存します。 これらの「コードレッド」シナリオでは、CLIは限界に達します。我々は自動スクリプトを放棄し、ソースコード自体で手動で操作しなければなりません。 Standard JSON Input hardhat-verify が不透明な AggregateError や遅いネットワーク接続のせいでタイムアウトを投げると、ほとんどの開発者はパニックに陥り、「Flattener」プラグインに頼り、50 ファイルを 1 つの巨大な .sol ファイルにスワイプしようとします。 Flattening はプロジェクトの構造を破壊し、輸入を破壊し、しばしばライセンス識別子を混乱させ、より多くの検証エラーを引き起こします。 正しい、プロフェッショナルなフィールバックは標準JSON入力です。 Solidity Compiler (solc) をマシンとして考えてください. それはあなたの VS コードのセットアップ、あなたの node_modules フォルダ、またはあなたのリメッピングを気にしません. それは、ソースコードと構成を含む特定の JSON オブジェクトの1つだけを気にします。 Standard JSON is the lingua franca (common language) of verification. それは、以下を含む単一のJSONファイルです。 タイトルは「Solidity」 設定: Optimizer run, EVM version, viaIR, remappings ソース:使用される各ファイル(OpenZeppelin 依存を含む)の辞書、そのコンテンツは文字列として埋め込まれている。 標準JSONを使用すると、コンパイラが必要とする正確な原料データのパイロードをEtherscanに送信します。 ハードハットから「ゴールデンチケット」を抽出 この JSON を手動で書き込む必要はありません Hardhat は、コンパイルするたびにそれを生成しますが、アーティファクト フォルダの奥深くにそれを隠します。 CLI 認証が失敗した場合は、以下の「緊急時にブレック・グラス」の手順に従ってください。 NPX hardhat compile を実行します。Artifacts/build-info へ移動します。ハッシュ名を持つ JSON ファイル(例えば a1b2c3...json)を見つけることができます。それを開きます。内部で、トップレベルの入力オブジェクトを探します。入力オブジェクト全体をコピーして verify.json として保存します。 Mastermind アドバイス: この verify.json は「真実のソース」です。 あなたの契約の文字通りのテキストとそれらをコンパイルするために使用された正確な設定が含まれています。 このファイルが地元でバイトコードを再生することを許可している場合は、Etherscan で動作する必要があります。 ビルド情報を見つけることができない場合、または非標準環境で作業している場合は、パニックになる必要はありません. You can generate the Standard JSON Input yourself using a simple Typescript snippet. このアプローチは、Etherscanに送信されるものに対する絶対的なコントロールを提供し、輸入やリマッピングを明示的に処理することができます。 // scripts/generate-verify-json.ts import * as fs from 'fs'; import * as path from 'path'; // 1. Define the Standard JSON Interface for type safety interface StandardJsonInput { language: string; sources: { [key: string]: { content: string } }; settings: { optimizer: { enabled: boolean; runs: number; }; evmVersion: string; viaIR?: boolean; // Optional but crucial if used outputSelection: { [file: string]: { [contract: string]: string[]; }; }; }; } // 2. Define your strict configuration const config: StandardJsonInput = { language: "Solidity", sources: {}, settings: { optimizer: { enabled: true, runs: 200, }, evmVersion: "paris", // ⚠️ Critical: Must match deployment! viaIR: true, // Don't forget this if you used it! outputSelection: { "*": { "*": ["abi", "evm.bytecode", "evm.deployedBytecode", "metadata"], }, }, }, }; // 3. Load your contract and its dependencies manually // Note: You must map the import path (key) to the file content (value) exactly. const files: string[] = [ "contracts/MyToken.sol", "node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol", "node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol", // ... list all dependencies here ]; files.forEach((filePath) => { // Logic to clean up import paths (e.g., removing 'node_modules/') // Etherscan expects the key to match the 'import' statement in Solidity const importPath = filePath.includes("node_modules/") ? filePath.replace("node_modules/", "") : filePath; if (fs.existsSync(filePath)) { config.sources[importPath] = { content: fs.readFileSync(filePath, "utf8"), }; } else { console.error(`❌ File not found: ${filePath}`); process.exit(1); } }); // 4. Write the Golden Ticket const outputPath = path.resolve(__dirname, "../verify.json"); fs.writeFileSync(outputPath, JSON.stringify(config, null, 2)); console.log(`✅ Standard JSON generated at: ${outputPath}`); なぜいつもこれが効くのか Standard JSON の使用は、メタデータのハッシュを保存するため、フラットニングよりも優れている。 ファイルをフラットする際には、技術的にソースコードを変更します(インポートを削除し、ラインを再編成します)。これにより、結果としてバイトコードのメタデータが変化し、指紋の不一致につながります。 標準JSON検証が失敗した場合、問題はソースコードではなく、設定(図2)の100%にあります。 The viaIR Trade-off 包装する前に、私たちは部屋の象に取り組まなければなりません: viaIR. 近代的な Solidity 開発 (特に v0.8.20+) では、 viaIR を可能にすることは最小限のガスコストを達成するための標準となっています。 パイプライン Shift なぜ単純な真実/偽の旗がこのような混乱を引き起こすのでしょうか? なぜなら、それはコンパイルパスを根本的に変えるからです。 Legacy Pipeline: Solidity を直接 Opcode に翻訳します。 IR パイプライン: 最初に Solidity を Yul (Intermediate Representation) に翻訳します. The optimizer then aggressively rewrites this Yul code — inlining functions and rearranging stack operations — before generating bytecode. バイトコードを生成する前に、この Yul コードを攻撃的に書き直します。 図 3 に示すように、ByteCode B は構造的にByteCode A とは異なります. You cannot verify a contract deployed with the IR pipeline using a legacy configuration. それはバイナリ コミットメントです。 ガス効率 vs. 検証 viaIR を有効にするという決定は、Ethereum 開発のコスト構造の根本的な変化を表しています. それは単にコンパイラの旗ではなく、実行効率とコンパイラの安定性の間の妥協です。 伝統的なパイプラインでは、コンパイラは主に翻訳者として機能し、Solidityの発言をローカルで最適化されたオプコードに変換しました. 結果としてのバイトコードは予測可能で、ソースコードの構文構造を密接に反映しました. しかし、このアプローチは上限に達しました. 複雑なDeFiプロトコルはしばしば「Stack Too Deep」エラーに遭遇し、クロス機能の最適化を実行することができなかったため、ユーザーは不効率なスタック管理のために支払っていた。 IRパイプラインは、コードベース全体の過剰なスタック操作を排除し、インライン機能を攻撃的に再編し、エンドユーザーのトランザクションを大幅に安くする結果となる。 しかしながら、この最適化は開発者にとって急激な価格となります。ソースコードとマシンコードの「距離」は劇的に広がります。 Structural Divergence: Because the optimizer rewrites the logic flow to save gas, the resulting bytecode is structurally unrecognizable compared to the source. Two semantically equivalent functions may compile into vastly different bytecode sequences depending on how they are called elsewhere in the contract. 構造的な差異: オプティマザーはガスを節約するために論理的な流れを書き換えるため、生成されたバイトコードは、ソースと比較して構造的に認識されません。 「バターフライ効果」 : IRパイプラインでは、グローバルな構成の小さな変化(例えば、200から201までのランニングの変更)が、Yulの最適化ツリー全体を通して広がります。 したがって、viaIR を有効にすることは負荷の移転である。我々は開発者への負担(より長いコンパイル時間、脆弱な検証、厳格なコンフィギング管理)を自発的に増やすことで、ユーザーへの負担(ガス料金の低下)を軽減します。 Conclusion デフィの闇の森では、コードは法律ですが、検証されたコードはアイデンティティです。 我々は、検証プロセスを魔法のボタンではなく「鏡のメカニズム」として視覚化することから始めた(図1)。我々は「決定的なブラックボックス」(図2)を解析し、最適化パラドックスに直面した。 Web UI は便利ですが、それらに頼ることは人間のエラーを導入します。プロの暗号契約エンジニアとして、あなたの検証戦略は3つの柱に基づいて構築されるべきです。 Automation First: Always start with CLI tools (hardhat-verify or forge verify) to enforce consistency between your deployment and verification configurations. 常にCLIツール(hardhat-verifyまたはforge verify)から始めて、デプロイと検証の構成の間の一貫性を強化してください。 正確な構成: hardhat.config.ts を生産資産として扱う. viaIR、optimizer を実行し、Constructor Arguments がバージョン制御され、展開アーティファクトと同一であることを確認します。 “Standard JSON” Fallback: 自動プラグインが壁に打たれたとき(timeouts または AggregateError)は、契約を平らにしないでください。 標準 JSON 入力(「ゴールデンチケット」)を抽出して手動で手動でアップロードしてください。 検証は、展開後5分後に処理されることのできる後思考ではありません。それは品質エンジニアリングの最終的な印章であり、ブロックチェーン上で実行されているコードが正確にあなたが書いたコードであることを証明します。