3MIKAN
DeFi直コン

直コンとは?verified contract・ABI・simulationを安全に確認

直コンでコントラクトを操作する前に、chain・公式address・verified source・proxy・ABI・approve/revoke・simulation・receiptを確認する順番を解説します。

コントラクトのaddress、ABI、simulation、receiptを順に確認する記事画像

「直コン」は、dappの画面を経由せず、Block ExplorerのRead / Write画面やコードからコントラクト関数を直接呼ぶことです。画面が省かれるだけで、コントラクトの権限、停止条件、残高、期限、手数料を回避できるわけではありません。

この記事では、接続や署名より先に、読む・照合する・simulationする順番を扱います。Ethereum mainnetのCircle USDCを公開画面の例に使いますが、特定トークンの取得や操作を勧めるものではありません。掲載画面ではwallet接続、入力、署名、transaction送信を行っていません。

verifiedは安全証明ではない

Source Code Verifiedは、公開されたsourceとcompiler設定からon-chain bytecodeを再現できたことを示します。公式プロジェクト、安全、監査済み、変更不能を意味しません。

公式addressの照合からABI、Read、simulation、署名確認、receipt確認へ進む直コンの安全確認フロー

最初に確認する6項目

Explorerで関数名を探す前に、次の6項目を一つのメモへ固定します。

項目 確認する内容 間違えたときの影響
chain Ethereum、Arbitrum、Baseなど対象network 同じ形式のaddressでも別のcontractを参照する
address project公式docsとExplorerのaddressが一致するか 偽物や別versionを操作する
verification exact matchか、similar matchか、未検証か source・ABIを誤って信用する
proxy proxyか、現在のimplementationとadminは何か 表示sourceと実行codeを取り違える
call function、引数、native tokenのvalue 別の権限・数量・送付を実行する
account 読み取り対象、署名account、nonce 別walletのstateでsimulationする

トークンaddressは検索結果やSNS投稿だけで決めません。たとえばCircleはchain別のUSDC contract addressを公式docsで公開しています。Explorerのlabelは補助情報として使い、chainとaddressはproject側の一次情報でも照合します。

verified contractで分かること

Etherscanの説明では、contract verificationはデプロイ済みcontractのsource codeを公開・照合する仕組みです。Exact Matchなら、source、compiler version、optimizerなどの設定が対象bytecodeと一致しています。

EtherscanのContractタブにSource Code Verified、Exact Match、Proxy、implementationが表示されたUSDC公開画面
2026年8月28日のEtherscan公開画面。Ethereum mainnetのUSDC proxyをログアウト状態で確認。verificationは安全性の証明ではありません。

2026-08-28にEthereum mainnetのUSDC公開ページを確認した時点では、次の表示がありました。

  • Source Code VerifiedExact Match
  • contract name FiatTokenProxy
  • Proxyと現在のimplementation address
  • Read as ProxyWrite as ProxyPast Implementations

これは「このaddressにあるproxyのcodeを読める」という証拠です。Etherscan自身も、source verifiedは安全に操作できるという意味ではないと説明しています。監査の有無、owner権限、停止機能、upgrade権限、経済設計は別に確認します。

proxyならimplementationも追う

proxyはstateを保持したまま、別のimplementationへ処理を委譲できます。OpenZeppelinの解説にあるように、upgrade可能な構成ではimplementationが後から変わる場合があります。

確認時は次を記録します。

  1. 操作先のproxy address
  2. 現在のimplementation address
  3. implementationのverification状態とABI
  4. upgradeを実行できるadmin、owner、governance
  5. 確認日時とchain

EtherscanのRead as Proxy / Write as Proxyは、検出したimplementationのABIをproxy addressに対して使うための表示です。表示されたcodeが将来も同じとは限らないので、署名前にもう一度確認します。

Read Contractから始める

Readは通常eth_callで実行され、stateを変えず、transactionも送信しません。wallet接続が不要な読み取りは、書き込み条件を把握する入口になります。

EtherscanのRead as Proxyにallowance、balanceOf、decimalsなどの読み取り関数が並ぶUSDC公開画面
Read as Proxyの公開画面。walletを接続せず、allowance、balanceOf、decimalsなどの関数名を確認しました。

ERC-20なら、少なくとも次の値を確認します。

Read 入力 分かること
balanceOf(account) 対象account contractが認識するtoken残高
allowance(owner, spender) ownerとspender spenderが使える上限
decimals() なし raw amountを人が読む桁へ直す基準
paused()など contractごと 書き込み停止状態。ただし関数がない場合もある
role / owner系 contractごと 特定functionを実行できる主体

Readが成功しても、同名のWriteが成功するとは限りません。Writeではmsg.sender、残高、allowance、期限、role、現在blockのstateが追加条件になります。

ABIとfunction selectorを照合する

ABIは、function名、引数の型、返り値、eventを機械が読むためのinterfaceです。Explorerの入力欄を見ただけで判断せず、現在のimplementationに対応するABIでcalldataをencode / decodeします。

たとえばERC-20のapprove(address,uint256)は、先頭4 bytesのfunction selectorが0x095ea7b3です。しかしselectorだけでは、対象chain、contract address、spender、amountが正しいとは分かりません。

calldataとevent logsの読み方はABI・function selector・calldata・event logsを手で読む方法で、固定した例と一緒に確認できます。

Write Contractを開いても、すぐ接続しない

Write as Proxyにはstateを変えるfunctionが並びます。公開画面を読むだけなら、walletを接続する必要はありません。

EtherscanのWrite as Proxyにapproveのspenderとvalue、その他の書き込み関数が並ぶUSDC公開画面
Write as Proxyの公開画面。approveのspenderとvalueを観察し、wallet接続、入力、署名、transaction送信は行っていません。

署名画面へ進む前に、予定するcallを次の形で書き出します。

chain      = Ethereum mainnet
to         = proxy address
function   = approve(address,uint256)
arguments  = spender, amount
value      = 0 ETH
account    = owner address
ABI source = current verified implementation

toはtokenの移転先とは限りません。approveの場合、transactionのtoはtoken contractで、引数のspenderが利用権限を渡す相手です。この2つを混同すると、意図しないcontractへ権限を残します。

approve・allowance・revokeを分けて考える

ERC-20のowner、token contract、spenderとallowanceの関係を示す図

ERC-20では、approve(spender, value)がspenderの利用上限を設定し、allowance(owner, spender)で現在値を読み取ります。

  • owner: tokenを持ち、承認を出すaccount
  • spender: ownerに代わってtransferFromできるaddress
  • amount: tokenの最小単位で表した上限
  • token contract: allowanceを保存するcontract

「サイトとの接続解除」と「allowanceの取消」は別です。allowanceは変更されるまでon-chainに残ります。

MetaMaskのSpending cap requestでtoken・spender・amount・chainを照合し、PortfolioやExplorerからrevoke後のallowanceを確認する手順は、MetaMaskのSpending cap・approve・revokeを安全に確認する方法で詳しく説明しています。

revokeの確認順

  1. allowance(owner, spender)で現在値と正確なspenderを読む
  2. tokenが標準的なERC-20動作か、特殊な制約がないか確認する
  3. walletの承認管理画面、またはverified contractのapprove(spender, 0)を候補にする
  4. chain、token、spender、0の桁をsimulationする
  5. 署名後はreceiptの成功と、更新後のallowanceが0かを再度読む

approve(spender, 0)は一般的なERC-20でallowanceを0へ更新する方法ですが、token固有の実装やproxy変更があるため万能な手順ではありません。MetaMask Portfolioのspending capsからrevokeする場合も、on-chain transactionなのでnetwork feeが必要です。

また、permitなどの署名でallowanceを作るcontractもあります。「gasが表示されない署名だから安全」と判断せず、typed dataのdomain、chainId、verifying contract、spender、value、deadlineを読みます。

simulationでrevertと入力を先に確認する

viemのsimulateContractは、eth_callを使ってcontract callを検証し、stateを変更せずにresultやrevertを確認します。

const { request, result } = await publicClient.simulateContract({
  address: tokenAddress,
  abi: erc20Abi,
  functionName: 'approve',
  args: [spender, amount],
  account: owner,
})

// ここでは送信しない。
// request.address / functionName / args / accountを別途照合する。

変数は、先に固定したchain、official address、current ABI、owner、spender、amountから作ります。simulation後は次を確認します。

  • 実行したRPCのchainId
  • request.addressと予定したto
  • calldataをdecodeしたfunction名と引数
  • native tokenを送る場合のvalue
  • resultまたはrevert reason / custom error
  • simulationに使ったaccountとblock時点

simulation成功は安全や本番成功の保証ではない

simulationと実transactionの間に、price、balance、allowance、nonce、deadline、paused状態、proxy implementationが変わることがあります。simulationは「その時点・そのaccount・その入力で再現した結果」であり、悪意あるcontractを安全に変えるものでもありません。

gas estimationやrevertの切り分けはestimateGasが失敗する理由とsimulationの確認順、custom errorはrevert dataをデコードする方法も参照してください。

walletの署名画面で最後に止まる

署名要求が出たら、Explorerやdappで見た内容をwallet側でも照合します。

  1. network / chainId
  2. signing account
  3. transactionのto
  4. functionと引数のデコード表示
  5. token、spender、spending cap
  6. native tokenのvalueとnetwork fee
  7. warningやsimulation結果

walletが内容をdecodeできず、blind signingに近い表示になるなら、先へ進まずcalldataを別のdecoderで確認します。急ぐ理由、限定キャンペーン、supportを名乗るDMは、確認項目を省略する理由になりません。

送信後はreceiptと最終stateを確認する

transaction hashが表示されても、成功とは限りません。receiptを取得し、少なくとも次を残します。

const receipt = await publicClient.getTransactionReceipt({ hash })

console.log({
  status: receipt.status,
  blockNumber: receipt.blockNumber,
  transactionHash: receipt.transactionHash,
  logs: receipt.logs,
})
  • receipt.status
  • chain、block number、transaction hash
  • transactionのtoとinput calldata
  • 発行元addressを含むevent logs
  • approveならApproval eventと更新後のallowance
  • transferやwithdrawなら、関係する残高の更新

eventが見えただけで全体成功を断定しません。別contractが同名eventを出す場合や、期待したstateが更新されていない場合があります。receipt・calldata・logsを追う確認順で、失敗transactionを含む見方を確認できます。

よくある失敗を切り分ける

症状 最初に確認すること それでも分からないとき
sourceが未検証 official address、bytecode、projectの公開repo ABIを推測して書き込まない
exact matchではなくsimilar 対象addressのruntime bytecode 別contractのsourceを根拠にしない
Readは成功、Writeはrevert account、role、balance、allowance、paused、deadline revert data / custom errorをdecodeする
simulation成功後に失敗 state、nonce、deadline、gas、implementationの変化 同じblock条件との差分を記録する
関数名は同じだが結果が違う current implementationとABI proxy upgrade履歴とadmin eventを見る
revokeしたのに残る token、owner、spender、receipt.status pending / failed tx、別spender、permitを確認する
数量が大きすぎる・小さすぎる decimals()とraw units 表示値だけで再送しない

サイトが消えても、資金回収を保証できない

front-endが停止していても、verified contractのRead / Writeから状態を確認できる場合はあります。しかし直コンはcontractの条件を迂回しません。

  • withdraw functionがない、または対象accountに権利がない
  • contractがpausedされている
  • owner / adminがimplementationや権限を変更した
  • tokenやLPに流動性・価値がない
  • blacklist、deadline、lock、feeなどの条件がある
  • 悪意あるcallしか残っていない

このような場合、Explorerから直接呼んでも資金を取り戻せるとは限りません。追加approveや不明な署名を止め、official address、transaction hash、receipt、allowance、proxy履歴を保存して状況を整理します。

最終チェックリスト

  • chainとofficial addressを一次情報で照合した
  • exact match / similar / unverifiedを区別した
  • proxy、current implementation、upgrade権限を確認した
  • Readでbalance、allowance、decimals、必要条件を確認した
  • ABIでfunction、args、selector、valueを照合した
  • approveならowner、token、spender、amountを分けて記録した
  • 同じaccount・chain・入力でsimulationした
  • simulation成功を安全保証として扱っていない
  • wallet画面のto、function、args、spending capを再確認した
  • 送信後にreceipt.status、logs、最終stateを確認した

直コンで大切なのは、早く送ることではありません。addressからreceiptまで、同じcallを説明できる状態にしてから判断することです。

確認した一次情報