3MIKAN
仮想通貨直コン

ERC-6492とは?未デプロイsmart accountの署名を検証する

ERC-6492のwrapper、CREATE2予定address、rollback検証、trusted factory方針、deploy後のERC-1271までをローカル環境で確認します。

3MIKANのブランドキャラクターが未建設のaccount boothの予定地で封印済みの封筒とfabrication pressを照合するERC-6492の記事画像

ERC-6492は、まだcodeがない予定addressのsignatureを、factoryによる準備とERC-1271検証へつなぐwrapper規則です。結論から言えば、signer.code.length == 0だけでEOAと決めず、ERC-6492の32-byte suffixを先に検出します。

ただし、ERC-6492がfactory、calldata、digestの意味を安全にしてくれるわけではありません。汎用validatorの処理と、applicationが許可するfactory・予定signer・digest・期限・nonceの方針を分けてreviewします。

codeがないaddressはEOAとは限らない

同じcode.length == 0でも、意味は一つではありません。

signerの状態 通常の検証 見落としやすい点
EOA ECDSA recovery digestの用途、chain、nonce、deadlineは別に必要
deployed contract account ERC-1271 isValidSignature 現在のownerやthresholdなどstateに依存する
undeployed counterfactual account factoryで準備してERC-1271 検証時点では予定addressにcodeがない

ERC-1271の署名検証だけでは、call先にcodeがない段階を直接扱えません。そこでERC-6492は、deploymentまたはaccount準備に必要なcallと、本来のERC-1271 signatureを一つに包みます。

ERC-6492 wrapperの中身

ERC-6492のwrapperは次の形です。

abi.encode(factory, factoryCalldata, originalERC1271Signature)
|| 0x6492649264926492649264926492649264926492649264926492649264926492

末尾は正確に32 bytesです。validatorは通常のERC-1271やECDSAより先にこのsuffixを調べます。

field 役割 ERC-6492が保証しないもの
factory 準備callの宛先 信頼済みfactoryであること
factoryCalldata accountを使える状態にする任意calldata selector、owner、salt、init codeの意味
originalERC1271Signature accountへ渡す内側signature digestの用途、nonce、deadline
detection suffix wrapperだと識別するmarker wrapper全体の正当性

ERC-6492は、factoryCalldataをCREATE2のowner, salt形式へ標準化していません。factory interfaceに依存しないため、proxy準備や既存accountの追加設定も表現できる一方、application側のallowlistとcalldata解析は別policyです。

CREATE2予定addressと期待signerを対応させる

今回の再現例では、説明を固定するためCREATE2 factoryを使います。EIP-1014の予定addressは、deployer、salt、init code hashから決まります。

predicted = last20(
  keccak256(0xff || factory || salt || keccak256(accountInitCode))
)

検証者は「wrapperに書かれたfactoryが何か」だけでなく、calldataのownersaltから得た予定addressが、外から受け取った期待signerと一致するかを確認します。signatureから勝手にsignerを採用すると、別accountの有効なsignatureを目的のaccountへ取り違える余地が残ります。

ERC-6492 suffixを先に検出し、trusted factory policyと準備callを経てERC-1271へ進む検証順

検証順はsuffix、準備、ERC-1271、EOA

実装では次の順序を崩しません。

  1. signature末尾のERC-6492 suffixを先に検出する
  2. wrapperならfactory, factoryCalldata, innerSignatureをデコードする
  3. application policyでfactory、calldata、期待signerを照合する
  4. signerが未デプロイならfactory callを実行可能な文脈で試す
  5. signerへinner signatureを渡し、ERC-1271 magic value 0x1626ba7eを確認する
  6. wrapperでなく、signerにcodeがあれば通常のERC-1271へ進む
  7. wrapperでなく、codeもなければ最後にEOAのECDSAを試す

code.lengthを最初の分類にすると、未デプロイcontract accountをEOA経路へ落としてしまいます。反対に、suffixがあるだけでvalidにもできません。デコード失敗、factory revert、wrong magic、短いreturn、内側signature不一致はいずれも失敗です。

ローカル環境で5段階を確認した

固定した再現結果を公開しています。Foundry / Anvil 1.8.0、Solidity 0.8.36、OpenZeppelin Contracts 5.6.1、viem 2.56.0、local chain ID 31337だけを使い、public RPCや実在walletには接続していません。

予定accountは0xc7401d0A1FCf6838deE56c8414f0CD8a70Ca833eです。これはtest-only keyとlocal deploymentから得た検証用addressで、利用推奨addressではありません。

phase code bytes result 永続化
predicted 0 未検証 なし
rollback validation 0 true account codeは残らない
explicit deploy 821 true receipt success、codeが残る
post-deploy ERC-1271 821 true 通常signatureで検証
post-deploy wrapped 821 true wrapperも引き続き検証可能

Foundry 11 tests passedです。wrapperのデコード、naiveなcode-length判定、rollback、明示deploy、deploy後ERC-1271、deploy後wrapper、EOA fallback、wrong factory、wrong salt、bad inner signature、malformed wrapper、factory revertを分けて確認しています。

rollback検証と明示deployを分ける

未デプロイaccountを検証するには、EVMの中でfactory callとERC-1271 callを実行する必要があります。しかし、read目的の検証がaccountを永続deployすると、検証だけの呼び出しに予想外のside effectが混ざります。

再現例のnon-side-effecting経路は、内側callで一時的にdeployしてERC-1271結果を1 byteのrevert dataへ載せ、外側でその値だけを読むERC-6492 reference techniqueです。結果がtrueでも、終了後の予定addressはcode 0 bytesのままです。

eth_callもstate transitionをシミュレートできますが、RPC call終了後にstateを永続化しません。local viem実行ではrollback validation後のcodeが0、明示的なside-effecting transaction後は821 bytesになりました。

未デプロイ予定addressをrollback検証し、明示deploy後は通常ERC-1271とERC-6492 wrapperの両方を検証する段階

stateを残す経路をon-chainで提供する場合は、任意factory call、reentrancy、gas、front-run、重複deploy、factory upgradeを含む別の脅威modelが必要です。read-only APIとdeployment APIを同じendpointへ曖昧に混ぜません。

trusted factory policyはERC-6492の外側に置く

公開例のUniversalSigValidatorは標準の検証順を再現します。別contractのTrustedFactory6492Verifierは、このsample固有の制限として次を確認します。

  • wrapperのfactoryが固定allowlistと一致する
  • calldata selectorがcreateAccount(address,bytes32)である
  • calldataから読むownerとsaltで予測したaddressが期待signerと一致する
  • malformed calldataを実行前に拒否する

この制限を「ERC-6492標準の必須format」と説明してはいけません。productionのfactory interfaceが違えば解析方法も違います。proxy、module設定、account migrationなどを許すなら、許可するselector、実装version、code hash、upgrade主体、再実行時の挙動をそのfactoryの仕様に合わせて固定します。

失敗ケースはcodeとresultを両方読む

case validation 予定signerへcodeが残るか
wrong factory false いいえ
wrong salt / 別予定address false いいえ
bad inner signature false いいえ
malformed wrapper false いいえ
factory revert error いいえ

factory.callが成功したこととsignatureがvalidであることは別です。factoryが何もdeployせず成功を返す場合も、予定signerのERC-1271 magic valueを得られなければ成功にしません。revertをfalseへ変換するかerrorとして返すかはAPI契約ですが、trueへ変えてはいけません。

deploy後もwrapperを先に検出する

ERC-6492 wrapperは、accountがdeployされた後も有効な形式です。validatorが「codeがあるから通常ERC-1271」と先に分岐してwrapper全体をaccountへ渡すと、内側signatureとしてデコードされず失敗します。

そのためsuffix検出を常に先に行い、deploy済みなら通常はfactory callを省略してinner signatureをERC-1271へ渡します。accountが追加準備を必要とする場合は、ERC-1271が失敗した後にwrapperのprepare callを試す経路も仕様にあります。

ただし、過去にvalidだったsignatureが永久にvalidという意味ではありません。ERC-1271は現在stateを読むため、owner、threshold、credential、許可hashなどが変われば結果も変わります。

digest、replay、deadlineは別レイヤー

ERC-6492は、渡されたbytes32 digestの意味を定義しません。少なくとも次をapplicationの署名対象とstateへ結びつけます。

  • actionと引数
  • chain IDとverifying contract
  • 期待するsmart-account address
  • application nonce
  • deadline
  • sessionや権限scope

EIP-712のdomain separatorとreplay対策はdigestの作り方を担当し、ERC-6492は未デプロイsignerへ検証を届けます。wrapperにfactory情報が入っていても、digestへ用途や期限が入る保証はありません。

login用途では、SIWEをnonce・domain・URI・chain IDからsessionまで実装する方法がERC-4361 messageとsingle-use challengeを担当します。counterfactual signer対応を足す場合も、SIWE field policyとERC-6492 factory policyを同じtrueへ省略しません。

ERC-4337とPasskeyへつなぐ境界

ERC-4337 UserOperationでは、未デプロイaccountのfactoryfactoryDataをEntryPoint経路で扱います。一方、ERC-6492はoff-chain messageや別contractがcounterfactual account signatureを検証する形式です。両方が同じfactoryを使えても、UserOperation validation成功と任意messageの有効性は同じ証拠ではありません。

Passkey smart accountの検証を内側signatureに使う場合は、ERC-6492の外側をデコードした後、account側でWebAuthn challenge、origin、RP ID、flags、credential state、P-256 signatureを確認します。ERC-6492 suffixがこれらを代行することはありません。

実装前のチェックリスト

  • ERC-6492 suffixをERC-1271 / ECDSAより先に検出した
  • wrapperを厳密にデコードし、malformed inputを拒否した
  • 外から受け取った期待signerを基準に検証した
  • 許可するfactory、selector、calldata、予定addressのpolicyを明示した
  • rollback検証と永続deploy APIを分離した
  • ERC-1271 call成功だけでなく0x1626ba7eを厳密に確認した
  • deploy後のwrapped signatureもtestした
  • wrong factory、wrong salt、bad inner signature、factory revertをtestした
  • factory callのreentrancy、gas、upgrade、再実行をreviewした
  • digestへaction、chain、account、nonce、deadlineを結びつけた
  • local検証結果を実在walletやchain対応の証拠にしていない

ERC-6492対応の中心は「deployしてから確認する」ことではありません。wrapperを先に識別し、期待signerと許可した準備callを対応させ、side effectを制御してからERC-1271の現在結果を読むことです。

この記事にスポンサー、affiliate、wallet作成、署名要求、deployment、資産移動のCTAはありません。将来、smart-account SDK、factory service、validator、auditの広告を置く場合も広告であることを明示し、仕様、検証結果、failure matrix、security reviewから独立させます。

確認した一次情報