イーサリアム上のトークンも、NFTコレクションも、レンディング市場もブリッジも、その正体はすべてスマートコントラクトです。あるアドレスに保存されたバイトコードが、すべてのノードで書かれたとおりに実行されています。イーサリアムのスマートコントラクト・エクスプローラーは、ブロックエクスプローラーの中でも、そのバイトコードを人間が調べられる形に戻してくれる部分です。作者が公開していればソースコードを表示し、コードを1行も書かずに関数を呼び出させてくれ、コントラクトが発行したイベントを一覧にし、誰がデプロイしたのかを教えてくれます。
使いこなすのに、Solidityの開発者である必要はありません。「検証済み」が本当は何を意味するのか、プロキシをどう見分けるのか、管理者キーがどこにあるのか。この3点を知っているだけで、かなりの種類のリスクを避けられます。このガイドでは、コントラクトページをタブごとに順番に見ていき、最後に5ステップの確認手順をまとめます。保有者の集中度やハニーポットといったトークン特有のチェックについては、姉妹編のトークン・エクスプローラーのガイドをご覧ください。
Etherscan・Sourcify・Blockscoutでいう「検証済みソースコード」とは
コントラクトアドレスに保存されているのは、バイトコードだけです。「このSolidityファイルからこのバイトコードができた」と主張するのは誰にでもできます。その主張をエクスプローラーが確かめる仕組みが「検証(verification)」です。作者はソースファイル、コンパイラーのバージョン、オプティマイザーの設定、コンストラクター引数を提出します。エクスプローラーはそれをコンパイルし、結果をチェーン上のバイトコードと突き合わせます。一致すれば、緑のチェックマークとともにソースコードがコントラクトの横に公開されます。
Etherscanは、作者のコードとコンストラクター引数でデプロイ済みコントラクトを再現できたExact Matchと、Similar Matchを区別しています。後者は、新しいコントラクトのバイトコードがすでに検証済みのものと一致したときにEtherscanが自動で付けるものです。ファクトリーから大量にデプロイされるクローンには便利ですが、コンストラクター引数は考慮されません。そしてコンストラクター引数次第で、コントラクトの振る舞いは変わり得ます。大きな金額がかかっているときは、Exact Matchのほうを信頼してください。
Sourcifyは、もともとイーサリアム財団のもとで育ったオープンソースの検証サービスで、Solidityコンパイラーがバイトコードの末尾にハッシュとして埋め込むメタデータファイルを利用します。現在は結果をexact matchとmatchの2種類で呼んでいますが、多くのツールでは今も旧名の「full」「partial」が表示されます。exact matchは、コメントやファイルパスを含めてすべてがバイト単位で同一であることを意味します。matchは、実行コードは同一でもメタデータが異なる状態です。どちらもロジックを証明しており、名称が変わったのは「partial(部分的)」という言葉のせいで未検証だと誤解する人が多かったからです。
Blockscoutは独自の検証方法(フラット化したソース、Standard JSON Input、Hardhat・Foundryのプラグイン)に対応し、さらにSourcifyとも連携しているため、Sourcifyで検証されたコントラクトはBlockscout上でも検証済みとして表示されることがあります。詳しくはBlockscoutのレビューで解説しています。
Read ContractとWrite Contractタブの読み方
コントラクトが検証されると、エクスプローラーはそのABIを把握し、2つの入力フォームを自動で用意します。Read Contractには、viewとpureの関数がすべて並びます。呼び出しは無料で、ウォレットも不要、返ってくるのはチェーン上の現在の値です。トークンのtotalSupply()、ボールトのowner()、プロトコルがpaused()になっているかどうか。誰かが作ったダッシュボードを信用せずに、コントラクトに関する事実を確かめるいちばん速い方法です。
Write Contractには、状態を変更する関数が並びます。エクスプローラーはウォレットの接続を求め、入力したパラメーターを本物のトランザクションに組み立てて、署名のためにウォレットへ渡します。プロジェクトのWebサイトが落ちていて資金を引き出したいとき、あるいは第三者のサイトを使わずに承認(approve)を取り消したいときには、本当に役立ちます。一方で、ミスが起きやすい場所でもあります。金額はトークンの最小単位で入力するため、1 USDCは1000000、1 WETHは1000000000000000000です。開発者でない方にとってWriteタブは、クリックするより「読む」ために使うほうが有益です。状態を変える関数の一覧を見れば、オーナーや利用者に何ができるのかがわかります。
ABIと関数セレクターをやさしく解説
ABI(アプリケーション・バイナリー・インターフェース)は、コントラクトの関数とイベントを記述したJSONです。関数名、引数の型、戻り値の型が書かれており、エクスプローラーはこれを使ってトランザクションをデコードします。コントラクトにトランザクションを送るとき、入力データ(input data)の先頭には4バイトの関数セレクターが入ります。これは関数シグネチャのkeccak-256ハッシュの先頭4バイトです。セレクターの後ろはすべて引数で、それぞれ32バイトに詰め物(パディング)されています。
// ERC-20の3つの関数と、それぞれの4バイトのセレクター
function transfer(address to, uint256 amount) external returns (bool); // 0xa9059cbb
function approve(address spender, uint256 amount) external returns (bool); // 0x095ea7b3
function balanceOf(address account) external view returns (uint256); // 0x70a08231
// セレクター = keccak256("transfer(address,uint256)") の先頭4バイト
// transferのcalldata:
// 0xa9059cbb
// 000000000000000000000000<送付先アドレス、20バイト>
// <金額を32バイトの符号なし整数で表したもの>
だからこそ、エクスプローラーは未検証コントラクトへのトランザクションでもtransferと表示できるのです。コントラクトのABIがなくても、公開されている署名データベースから0xa9059cbbを認識できるからです。これはフィッシングの手口の説明にもなります。セレクターはたった4バイトなので、攻撃者は意味のない名前を持ちながら、よく知られたセレクターと衝突する関数を作ることができますし、悪意のある関数にclaimRewardsと名付けることもできます。デコードされた関数名はあくまでヒントであり、真実は検証済みのソースコードにあります。実際のトランザクションで入力データをデコードする手順は、トランザクション・エクスプローラーのガイドで紹介しています。
プロキシ:EIP-1967、UUPS、そして実装アドレス
コントラクトはデプロイ後に書き換えられません。そのため、アップグレード可能なシステムは2つに分かれています。状態を保持し、利用者がやり取りするアドレスとなる小さなプロキシと、コードを保持する実装(ロジック)コントラクトです。プロキシはすべての呼び出しをdelegatecallで実装側に転送し、アップグレードとはプロキシの向き先を新しい実装に切り替えることを指します。わかりやすい実例がUSDCです。0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48はプロキシで、トークンのロジックはCircleが差し替え可能な別の実装コントラクトに置かれています。
EIP-1967は、プロキシがその向き先をどこに保存するかを標準化しました。実装アドレスはストレージスロット0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcに、管理者は0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103に置かれます。スロットが固定されているので、エクスプローラーはプロキシを検出し、実装側のABIを使う「Read as Proxy」「Write as Proxy」タブを表示できます。
トランスペアレント・プロキシでは、アップグレード関数はプロキシ側にあり、管理者だけが呼び出せます。UUPSプロキシ(ERC-1822由来)では、アップグレード関数が実装コントラクト自身に置かれます。プロキシを軽く保てる反面、実装にバグがあるとアップグレード自体ができなくなる恐れがあります。ビーコン・プロキシは、多数のプロキシを1つの「ビーコン」に向け、そのビーコンが実装を指定する方式です。
安全確認という観点でのポイントは単純です。プロキシを読んでいるとき、あなたは実際に動くコードを読んでいません。実装アドレスをクリックして、それが検証済みであることを確かめ、次にアップグレードを呼び出せるのが誰かを突き止めてください。そのキーを握る者が、コントラクト内のすべてのトークンを握っています。
イベント、ログ、バイトコード
コントラクトは、何が起きたかを記録するためにイベントを発行します。Transfer、Approval、OwnershipTransferred、Upgraded、Pausedなどです。各イベントはトランザクションのレシートにログとして残り、最大4つのインデックス付きトピックと1つのデータ欄を持ちます。コントラクトページのEventsタブはこうしたログの時系列フィードで、セキュリティの観点からはまさに宝の山です。2日前のUpgradedイベント、見知らぬアドレスへの新たなRoleGranted、作られたばかりのウォレットへのOwnershipTransferred。事故の前触れになるのは、まさにこうした変化です。
バイトコードタブには、デプロイされた生のコードが表示されます。未検証のコントラクトでは、手がかりはこれしかありません。ツールを使えば大まかな疑似コードに逆コンパイルでき、Otterscanなどのセルフホスト型エクスプローラーを使えば自分のノード上でトレースすることもできます。2025年5月のPectraアップグレード以降は、もう1つ見分けるべきケースが加わりました。普通のウォレットアドレスに、0xef0100の後ろにアドレスが続く短いコードが入っていたら、それはEIP-7702の委任(デリゲーション)です。つまり、そのアカウントは現在、別のコントラクトのコードを実行しています。最近のエクスプローラーはこれにラベルを付けてくれますが、ほかのコントラクトと同じくらい慎重に調べる価値があります。
コントラクトの作成者と作成トランザクション
どのコントラクトページにも、誰がどのトランザクションで作成したのかが表示されています。この1行だけで、驚くほど多くの疑問に答えが出ます。チームの既知のデプロイ用アドレスから作られたのか、それとも1時間前に取引所から資金を受け取ったばかりのアドレスから作られたのか。直接デプロイされたのか、UniswapのプールやSafeウォレットのようにファクトリーコントラクト経由で作られたのか。どんなコンストラクター引数が渡されたのか。作成者をクリックすれば、そのアドレスがほかに何をデプロイしたのかも見えます。放置されたトークンがずらりと並んでいるなら、それは偶然ではなくパターンです。ウォレットの素性を手早く調べる方法は、アドレス・エクスプローラーのガイドで解説しています。