はじめに

『DApps開発入門』という本や色々記事を書いているかるでねです。

今回は、EIP712形式のデータをオンチェーンで解析し、ユーザーの資産にどのような影響が生じるかを分かりやすく示すことで、安全で理解しやすい取引体験を実現する仕組みを提案しているERC6865についてまとめていきます!

以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。

他にも様々なEIP・BIP・SLIP・CAIP・ENSIP・RFC・ACPについてまとめています。

概要

現在、多くのプロトコルや分散型アプリケーション(dApp)は、EIP712(構造化データを署名するための標準仕様)をそれぞれ独自の「スキーマ(データの項目名や型の定義)」で使っています。 しかし、各プロトコルごとにスキーマがバラバラなため、エコシステム全体として統一された見せ方ができず、どうしても「不整合」や「分かりづらさ」が発生してしまいます。

EIP712については以下の記事を参考にしてください。

そこで、ERC6865は、dAppが共通のインターフェースとして visualizeEIP712Message というコントラクトの読み取り関数を実装するという考え方を提案しています。

この関数は、以下のような役割を持ちます。

  • 入力として「ABIエンコードされた EIP712のメッセージ」(EIP712の構造化データを、Ethereumの標準的なエンコード方式でバイナリに変換したもの)を受け取る
  • そのメッセージをdApp / プロトコル自身が理解してパースし、「ユーザーの資産にどのような影響があるか」に重点を置いて整理した、共通フォーマットの構造化データを返す

ウォレット側は、この構造化データを受け取りユーザーにわかりやすいUIで表示できるようになります。 これにより、ウォレットごとにバラバラだったEIP712メッセージの表示が、dAppをまたいで一貫した体験として提供できるようになり、ユーザーはどのdAppとやり取りする場合でも「何が起こるのか」を共通の形式で理解しやすくなります。

動機

web3.0の拡大とユーザーリスク

web3.0が急速に広がることで、多くのチャンスや新しいサービスが生まれています。 一方で、それに伴ってフィッシング詐欺などのセキュリティリスクも増えています。

特に問題になるのは、ユーザーが「自分が署名しようとしている内容をきちんと理解できていない」状態になりがちな点です。 署名が意味する内容をユーザーがきちんと把握できれば、怪しいトランザクションを避けることができ、リスクをかなり減らせます。

オフチェーンSDKのアプローチとその課題

この課題に取り組むため、まずはウォレット側でEIP712を解釈して表示するための「オフチェーンSDK」が開発されました。 このSDKはオープンソースで、ウォレットがさまざまなプロトコルのメッセージを視覚的にわかりやすくすることを目的としています。

しかし、このオフチェーン方式には、以下のような大きな課題がありました。

観点 課題の内容
スケーラビリティ EIP712を使っているすべてのプロトコルを洗い出し、それぞれのビジネスロジックを理解するのはほぼ不可能に近いこと。新しいプロトコルやアップデートもどんどん出てくるため、オフチェーンSDKだけで全てをカバーするのは現実的ではありません。
信頼性 各プロトコルのビジネスロジックを外部の開発者が完全に理解するのは難しく、実装の意図を誤解する可能性があります。その結果、実際の動きとずれた誤った可視化をしてしまうことがあり、これは「何も表示しない」よりも危険な場合があります。
保守性 web3.0のエコシステムは変化が激しく、プロトコルは機能追加やバグ修正などで頻繁にアップグレードされます。そのたびにオフチェーン側のSDKも追従する必要があり、保守コストが高くなります。

このように、ウォレット側のオフチェーン SDK によってすべての EIP-712 メッセージを正しく、かつ継続的に可視化する、というアプローチには限界がありました。

オンチェーンでの標準化という解決策

これらの課題を解消するために、ERC6865は「オンチェーンで標準化された仕組み」を導入する考え方を取ります。 具体的には、EIP712メッセージの解釈と可視化の責任をウォレットからプロトコル側へ移す、という発想です。

プロトコルごとに visualizeEIP712Message を実装し、そのプロトコル自身がEIP-712メッセージを解析して、共通フォーマットの構造化データとして返すようにします。 これにより、以下のようなメリットが生まれます。

  • スケーラビリティ 新しいプロトコルが登場しても、そのプロトコル自身が visualizeEIP712Message を実装すればよく、ウォレットやSDKが個別に対応する必要がなくなります。
  • 信頼性 ビジネスロジックを一番正確に知っているのは、そのプロトコルの開発者自身です。プロトコル側が直接可視化用のデータを返すことで、「実装と可視化のずれ」が起こりにくくなります。
  • 保守性 プロトコルがアップグレードされた場合でも、そのプロトコルのコントラクト内で visualizeEIP712Message を更新すればよく、ウォレット側のコードを都度書き換える必要がありません。

このように、オンチェーンでの標準化を行うことで、拡張性・信頼性・保守性のいずれの観点からも状態が改善され、変化が激しい web3.0 の世界にも対応しやすくなります。

ウォレットエコシステム全体への効果

ERC6865が広く採用されると、ウォレット開発者にとっては以下のようなメリットがあります。

  • 各プロトコルごとの独自実装をウォレット側で追いかける必要が減る
  • 新しいプロトコルへの対応が早くなり、カバー範囲も広げやすくなる
  • メンテナンスにかかる負担を大きく減らせる

そしてこれは、そのままユーザー体験の向上につながります。 ユーザーは、どのウォレット・どのプロトコルを使っていても、EIP712メッセージの内容を「同じような形式」で理解できるようになり、自分の資産がどう動くのかをより正確に把握できます。 結果として、セキュリティ面の向上と、全体としての使いやすさの向上の両方が期待できます。

現状のウォレット表示と「可視化」後の違い

現在、多くのウォレットはEIP712メッセージを、かなり機械的な情報として表示しています。 例えば、型情報やフィールド名、値がそのまま並んでいるだけで、ユーザーにとって「何が起こるのか」を直感的に理解しにくいUIになっていることが多いです。

これに対して、ERC6865の仕組みを使って visualizeEIP712Message から構造化データを受け取り、それに基づいて表示すると、ユーザーには以下のような形で「意味のある情報」を出せるようになります。

観点 現在の表示 ERC6865 採用後の表示イメージ
情報の粒度 フィールド名と値が生のまま並ぶ 「どのトークンが、誰から誰へ、いくら動くか」、「どんなポジションが開かれるか」など、ユーザーの資産への影響を中心に整理された情報
理解のしやすさ 技術者でないと理解が難しい 一般ユーザーでも直感的に理解しやすい表現
一貫性 プロトコルごとに表示の雰囲気がバラバラ プロトコルが違っても、ウォレット側は共通フォーマットをもとに一貫したUIを提供可能

仕様

ERC6865では、EIP712のメッセージを署名する時、ユーザーが「メッセージの内容を理解できない」問題を解消するため、ウォレットがオンチェーンから可視化用データを取得できる仕組みを定めています。

verifyingContract と chainId の扱い

EIP712のメッセージには「ドメインセパレーター」という識別情報があり、その中に以下の2つが含まれます。

項目 説明
verifyingContract メッセージを検証するコントラクトのアドレス。
chainId どのネットワークで有効なメッセージかを識別する値。

ERC6865では、ウォレットがユーザーに署名を求められたとき、以下の条件が満たされていればコントラクトを呼び出して可視化データを取得できます。

  • verifyingContract が指定されていること
  • chainId が指定されていること

もしメッセージにこれらが含まれていない場合、ウォレットは可視化処理を無視するべきとされています。

visualizeEIP712Message の役割

visualizeEIP712Message は、ERC6865の中心となる関数です。 プロトコル側がこの関数を実装することで、ウォレットはオフチェーンで複雑な解析をせずとも、オンチェーンで正確な可視化情報を得ることができます。

この関数は、ABIでエンコードされたEIP712メッセージを受け取り、以下の3種類の情報を返します。

  • ユーザーが受け取る資産(assetsIn)
  • ユーザーが提供する資産(assetsOut)
  • メッセージの有効期間(liveness)

これらをウォレットがUIに表示することで、ユーザーは「どの資産が増え、どの資産が減り、いつまで有効なのか」を明確に理解できます。

パラメータ説明

encodedMessage

ABI 形式でエンコードされた EIP712メッセージです。 abi.decode を用いて元の構造化データに復元できます。

domainHash

EIP712の定義に沿って計算されたドメインセパレーターのハッシュ値です。 ウォレット側が対象コントラクトを確認するために使います。

出力仕様

js
struct Liveness {
  uint256 from;
  uint256 to;
}

struct UserAssetMovement {
  address assetTokenAddress;
  uint256 id;
  uint256[] amounts;
}

struct Result {
  UserAssetMovement[] assetsIn;
  UserAssetMovement[] assetsOut;
  Liveness liveness;
}

関数はResultを返します。 Result は以下の3要素で構成されます。

Liveness

メッセージがいつ有効かを示すタイムスタンプです。

フィールド 説明
from メッセージの有効開始時刻。
to メッセージの有効終了時刻。

from < to である必要があります。

有効期間のある署名メッセージはDeFiプロトコルに多く、ウォレットがこれを表示することで、ユーザーは期限切れリスクを直感的に理解できます。

UserAssetMovement

資産の種類・数量・時間軸ごとの変動量を表す構造です。

フィールド 説明
assetTokenAddress トークンのアドレス。ゼロアドレスはネイティブコイン。
id NFTのトークンID。NFTでない場合は無視。
amounts 有効期間に対応した資産量。最初が from、最後が to。ほとんどのケースでは 1 要素のみ。

NFT かどうかに応じて意味が変わる点が特徴です。

assetsIn

ユーザーが「最低限受け取るはずの資産」を意味します。 プロトコルが期待する結果ではなく、ユーザー視点での最小量という点が重要です。

assetsOut

ユーザーが「最大で支払う必要のある資産」を意味します。 ウォレットは assetsOut を強調表示することで、ユーザーが不注意な署名を回避できます。

インターフェース

js
/**
* @notice This function processes an EIP-712 payload message and returns a structured data format emphasizing the potential impact on users' assets.
* @dev The function returns assetsOut (assets the user is offering), assetsIn (assets the user would receive), and liveness (validity duration of the EIP-712 message).
* @param encodedMessage The ABI-encoded EIP-712 message (abi.encode(types, params)).
* @param domainHash The hash of the EIP-712 domain separator as defined in the EIP-712 proposal; see https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator.
* @return Result struct containing the user's assets impact and message liveness.
*/
function visualizeEIP712Message(
    bytes memory encodedMessage,
    bytes32 domainHash
) external view returns (Result memory);

struct Liveness {
  uint256 from;
  uint256 to;
}

struct UserAssetMovement {
  address assetTokenAddress;
  uint256 id;
  uint256[] amounts;
}

struct Result {
  UserAssetMovement[] assetsIn;
  UserAssetMovement[] assetsOut;
  Liveness liveness;
}

構造体

Liveness
javascript
struct Liveness {
  uint256 from;
  uint256 to;
}

メッセージが有効な期間を示す構造体。 署名メッセージの有効期間を表し、開始時刻と終了時刻の2つの値を保持します。from は必ず to より小さくなります。

パラメータ

  • from
    • 有効開始時刻。
  • to
    • 有効終了時刻。
UserAssetMovement
javascript
struct UserAssetMovement {
  address assetTokenAddress;
  uint256 id;
  uint256[] amounts;
}

ユーザーの資産量を時間軸で示す構造体。 ERC20・ERC721・ERC1155などの資産の識別と、時間ごとの数量を示すために使われます。 NFTの場合は id が意味を持ちます。

ERC20については以下の記事を参考にしてください。

ERC721については以下の記事を参考にしてください。

ERC1155については以下の記事を参考にしてください。

パラメータ

  • assetTokenAddress
    • 資産のトークンアドレス。
    • ゼロアドレスはネイティブコイン。
  • id
    • NFTのトークンID。
  • amounts
    • 各タイムスタンプ時点の資産量。
Result
javascript
struct Result {
  UserAssetMovement[] assetsIn;
  UserAssetMovement[] assetsOut;
  Liveness liveness;
}

ユーザーの資産の入出、そしてメッセージ有効期間をまとめた構造体。 ウォレットがUI表示する際に必要な情報を1つに合わせた形式です。 受け取る資産、提供する資産、有効期間の3つが含まれます。

パラメータ

  • assetsIn
    • 最低限受け取る資産。
  • assetsOut
    • 最大で提供する資産。
  • liveness
    • メッセージの有効期間。

関数

visualizeEIP712Message
javascript
function visualizeEIP712Message(
    bytes memory encodedMessage,
    bytes32 domainHash
) external view returns (Result memory);

EIP712メッセージを解析して資産変動を返す関数。 ウォレットが署名前にユーザーへ視覚的な説明を行うための情報を、オンチェーンから取得するための関数です。 プロトコル自身がこの関数を実装するため、ビジネスロジックとの乖離が発生しません。

引数

  • encodedMessage
    • EIP712メッセージをABIエンコードしたもの。
  • domainHash
    • ドメインセパレーターのハッシュ。

戻り値

  • Result
    • 資産の移動情報と有効期間。

補足

on-chainの必要性

EIP712の可視化は一見するとオフチェーンでも実現できそうに思えますが、実際の運用経験からはオンチェーンで仕組みを提供する必要があります。 特にERC6865では、開発者が直接コントラクト内で可視化ロジックを実装することに意味があります。 これは、実際にオフチェーン SDK(TypeScript)を開発して分かった限界が根拠となっています。

以下がその理由です。

信頼性の問題

プロトコルの仕組みを最も理解しているのは、そのプロトコルを実装した開発者です。 第三者が外部で可視化処理を作ると、仕様理解が不十分なまま実装してしまう可能性があり、可視化結果が実際の挙動とずれることがあります。 このずれは、ユーザーに誤った情報を提示することにつながり、セキュリティ上も危険です。

オンチェーンでプロトコル自身が可視化を提供することで、実装との矛盾が生まれず、より正確な情報を提供できます。

スケーラビリティの問題

web3のプロトコルは非常に速いペースで増えています。 ウォレットや第三者がすべてのプロトコルを理解し、EIP712メッセージの可視化ロジックを個別に実装していくのは現実的ではありません。

  • 新しいプロトコルの登場
  • プロトコルのアップグレード
  • ビジネスロジックの変更

これらすべてに外部が追従するのは困難であり、可視化の網羅性も維持しづらくなります。 オンチェーンでプロトコル自身が対応する仕組みを持てば、ウォレット側は統一仕様に従うだけで良くなり、対応範囲と速度は大きく改善されます。

保守性の問題

多くのプロトコルはアップグレード可能なスマートコントラクトを採用しています。 そのため、外部がオフチェーン可視化を実装しても、プロトコルがバージョンアップすると挙動が変わり、外部実装が正しくなくなることがあります。

このズレは信頼性を損ない、メンテナンスコストも高くなります。 オンチェーンで可視化を提供する形なら、プロトコルが内部的に更新するだけで常に最新の正しい情報を返せるため、保守性が大幅に向上します。

DomainHash の役割

domainHash は、EIP712メッセージのドメインセパレーターをハッシュ化したものです。 ERC6865では、この値が非常に重要な意味を持っています。

理由は以下です。

異なるバージョンの判別

プロトコルが複数のEIP712仕様をサポートしている場合、domainHash によって使用すべきバージョンを区別できます。 もし domainHash が対応していないものであれば、処理を中断して誤った実装を実行しないようにできます。

他プロトコルとの混同防止

異なるプロトコルの domainHash が使われた場合、誤った期待値を返す危険があります。 これを防ぐために、domainHash が一致しなければリバートし、正しいプロトコルでないことを明確にできます。

既存プロトコルの将来的な再ルーティングへの対応

将来的に、既にデプロイ済みでアップグレードできないプロトコルを外部レジストリでルーティングする仕組みができた場合、domainHash はプロトコル識別に利用できる指標になります。

Amounts Arrayを採用する理由

ERC6865では amounts を uint256[](配列)として定義しています。 これは単に「複数の値を扱えるようにする」ためではありません。

主な理由は、NFT系のプロトコルでよく使われるオークションを扱うためです。

オークションでは、価格や必要資産量が時間によって変動します。 そのため、以下の点が重要になります。

要素 意味
最初の値(amounts[0]) liveness.from 時点の必要量
最後の値(amounts[last]) liveness.to 時点の必要量
中間に値が入る可能性 オークションの価格曲線に合わせるため

ほとんどのケースでは amounts は1要素ですが、オークションのように時間変化するプロトコルにも柔軟に対応できるように配列形式が採用されています。

セキュリティ

ERC6865では、ユーザーが署名するEIP712メッセージの内容を「正しく、信頼できる形で表示する」ことを目的としています。 そのため、以下の点がセキュリティ上特に重要になります。

visualizeEIP712Message の信頼性

visualizeEIP712Message が返す情報は、ユーザーが何に署名するかを判断するうえで非常に重要です。 この結果が間違っていた場合、ユーザー資産が予期しない形で移動する危険があります。

そのため、プロトコルは正確で最新の情報を返すように実装しなければなりません。

verifyingContract の信頼性に依存する

この仕組みでは、可視化関数は verifyingContract と同じアドレスで動作します。 つまり、署名メッセージの検証に使われるコントラクトと、可視化結果を返すコントラクトは同一です。

これは以下の意味を持ちます。

  • verifyingContract が信頼できるプロトコルであれば、可視化結果も信頼できる
  • verifyingContract 自体が怪しいプロトコルであれば、可視化結果も信用してはいけない

ウォレット側は、可視化関数の信頼性を単独で判断するのではなく、必ずverifyingContract の信用度を基準として扱う必要があります。

引用

Abderrahmen Hanafi (@a6-dou), "ERC-6865: On-Chain EIP-712 Visualization [DRAFT]," Ethereum Improvement Proposals, no. 6865, April 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-6865.

最後に

今回は「EIP712形式のデータをオンチェーンで解析し、ユーザーの資産にどのような影響が生じるかを分かりやすく示すことで、安全で理解しやすい取引体験を実現する仕組みを提案しているERC6865」についてまとめてきました! いかがだったでしょうか?

質問などがある方は以下のTwitterのDMなどからお気軽に質問してください!

他の媒体でも情報発信しているのでぜひ他も見ていってください!