[EIP747] ウォレット内で資金を簡単に追跡できる機能の追加提案を理解しよう！

# はじめに

初めまして。
**CryptoGames**というブロックチェーンゲーム企業でエンジニアをしている **cardene（かるでね）** です！
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。

https://cryptogames.co.jp/

代表的なゲームは**クリプトスペルズ**というブロックチェーンゲームです。

https://cryptospells.jp/

今回は、`wallet_watchAsset`という新しいRPCメソッドを追加し、ユーザーがウォレット内で簡単に資産を追跡できるようにする提案をしている**EIP747**についてまとめていきます！

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

https://eips.ethereum.org/EIPS/eip-747

他にも様々なEIPについてまとめています。

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4

# 概要

新しいウォレット向けのRPC(Remote Procedure Call)メソッド、`wallet_watchAsset`の標準化に関するEIPです。

RPCメソッドとは、ネットワーク上の他のコンピューターに対して、あたかもローカルで関数を実行しているかのように命令を出すための技術です。
ここでの`wallet_watchAsset`というメソッドは、クライアント（例えば、ウェブサイトやアプリケーション）がユーザーの仮想通貨ウォレットにトークンの追跡を提案するために使われます。

つまり、あるアプリケーションがこのメソッドを使用すると、ユーザーのイーサリアムウォレットに新しいトークン（例えば、新しい種類の仮想通貨やユニークなデジタルアセット）を「**監視（追跡）するよう提案**」できるということです。
ユーザーがこの提案を受け入れると、そのトークンがウォレットに追加され、バランスや取引履歴などの情報がウォレットアプリケーション内で表示されるようになります。

このEIPによって、ウォレットの機能が拡張され、ユーザーが様々なトークンをより簡単に管理できるようになるというメリットがあります。
また、アプリケーション開発者にとっても、ユーザー体験を向上させる新しい方法が提供されます。

# 動機

イーサリアムウォレットを使ってユーザーの資産を追跡するのが、今日では一般的な使い方の1つです。
このEIP（Ethereum Improvement Proposal、イーサリアム改善提案）がない状況では、ウォレットは資産を追跡するために二つの方法のいずれかを採用する必要があります。

### 事前に承認された資産のリストをプリロードする方法
この場合、ウォレットはそのリストを管理する責任と、ウォレット上で知られている資産を大量にポーリング（問い合わせ）するという帯域幅の負担を負うことになります。
セキュリティの面で言えば、ウォレットは承認された資産のリストを安全に保つ必要があります。
また、大量の資産を効率的に追跡するためには、多くのデータをやり取りする必要があり、これが帯域幅に負担をかけることになります。

### ユーザーが手動で資産をウォレットに追加する方法
この場合、ユーザー体験は非常に悪いものになります。
ユーザーが自分のウォレットに新しいトークンを追加したい時には、その都度、トークンのアドレスやその他の詳細情報を手動で入力する必要があります。
これは時間がかかる上に、誤った情報を入力してしまうリスクもあります。

このEIPが提案する`wallet_watchAsset`メソッドを採用することで、これらの問題を解決できます。
アプリケーションがユーザーのウォレットにトークンを追跡するよう提案できるようになるため、ユーザーは簡単に新しい資産をウォレットに追加できるようになり、ウォレット側の負担も大幅に軽減されます。

# 仕様

`wallet_watchAsset`という新しいRPCメソッドが導入されました。
このメソッドは、特定の資産をユーザーのウォレットにリストアップするよう要求します。
メソッドが呼び出された時、リクエストが有効であれば（つまり、フォーマットやパラメータが正しければ）、ユーザーに何かを提示する前に（即時に）、真（`true`）を返さなければなりません。
リクエストが無効な場合は、エラーを返します。

ここでの「**ユーザーのウォレットにリストアップされる**」という意味は、ウォレットの実装に依存します。
つまり、どのように資産がユーザーに表示されるか、または管理されるかは、使用しているウォレットの種類や設計によって異なります。

`wallet_watchAsset`への成功した呼び出しは、ウォレットがリクエストを認識し、リクエストに問題がなかったことを示しますが、これはユーザーにプロンプト（確認や選択を求めるダイアログ）が表示されたか、または資産が実際にウォレットに追加されたかどうかを示すものではありません。
要するに、このメソッドの呼び出しが成功したからといって、その資産がユーザーのウォレットに確実に追加されるとは限らない、ということです。
ユーザーが資産を追加するかどうかは最終的にユーザーの選択に委ねられます。

## `wallet_watchAsset`パラメータ

`wallet_watchAsset`メソッドは、資産をウォレットに追加するための要求を行う時に使用され、このメソッドは単一のパラメーター、すなわち`WatchAssetParameters`オブジェクトを取ります。
このオブジェクトは以下のように定義されています。

- `type`
    - これは文字列で、資産のインターフェースを指します。
    - 例えば、**ERC1046**のように、資産のスマートコントラクトが実装しているインターフェースの一般的に受け入れられている名前を指定します。
- `options`
    - このフィールドは、資産の追加に必要な追加情報を含むことができます。
    - `options`の具体的な内容は資産のタイプによって異なるため、ここでは特に形式が定められていません。

:::note info
**ERC1046**については以下の記事を参考にしてください。
:::

https://qiita.com/cardene/items/90e8e7f6f1646f8c8cfe

`type`フィールドは、資産がどのような種類のインターフェース（契約）を実装しているかを示すために使用されます。
例えば、**ERC1046**という値は、資産が**ERC1046**インターフェースを実装していることを示します。
ERC1046はイーサリアムのスマートコントラクトの標準の一つで、特定の資産に関する情報を提供する方法を定義しています。

この`WatchAssetParameters`インターフェースは、資産のタイプに応じて拡張または変更されることが想定されています。
これらの変更は、別のEIP（Ethereum Improvement Proposal）で明確に指定される必要があります。
つまり、異なる種類の資産をサポートするためには、それぞれの資産タイプに特有の要件を定義する別の提案が必要になることがあります。

## `wallet_watchAsset`パラメータ

`wallet_watchAsset`メソッドは、資産追加のリクエストを受け取った時、即座にブーリアン値`true`を返すことで、リクエストが認識されたことを示します。
この返り値は、ユーザーに何かが提示されたかどうかに関わらず、リクエストが有効に処理されたことを意味します。
一方、リクエストが無効である場合はエラーを返します。

エラーが発生する可能性がある状況としては以下のような場面が考えられます。

### 資産のタイプが認識されない、またはサポートされていない場合
資産がウォレットによって認識されるためには、その資産のタイプ（例えば、特定のERC標準に準拠しているかどうか）がウォレットによってサポートされている必要があります。
サポートされていない資産タイプがリクエストされた場合、ウォレットはその資産を追加できず、エラーが発生します。

### 資産が許可リストや拒否リストによってブロックされた場合
ウォレットには、特定の資産を許可または拒否するためのリストがあり、リクエストされた資産がこれらのリストの条件に違反している場合、資産の追加がブロックされ、リクエストが無効とみなされます。
これは開発者が対応する必要がある根本原因によるものです。

### 画像のダウンロードに失敗した場合
資産をウォレットに表示する時には、その資産の画像が必要になることがあります。
画像のダウンロードが失敗すると、資産を適切に表示することができず、リクエストが無効となる可能性があります。

### SSRF攻撃に対抗するため、ウォレットが資産を表示するために必要な一部のメタデータをロードしなかった場合
SSRF攻撃（サーバーサイドリクエストフォージェリ）は、攻撃者がサーバーに対して不正なリクエストを送信し、機密情報を得たり、サーバーに不正な操作をさせる攻撃です。
ウォレットがこの種の攻撃から保護するために、特定のメタデータのロードを拒否する場合があり、その結果、資産の追加リクエストが無効となることがあります。

これらの状況は、ウォレットが資産追加のリクエストをどのように処理するか、そしてどのような場合にエラーが発生する可能性があるかを示しています。

## `ERC1046`タイプ

```ts
interface ERC1046WatchAssetOptions {
{
    address: string; // The hexadecimal address of the token contract
    chainId?: number; // The chain ID of the asset. If empty, defaults to the current chain ID.
  };
}
```

`ERC1046`タイプの資産をウォレットに追加するために`wallet_watchAsset`メソッドが使用する`options`フィールドについての説明です。

`ERC1046WatchAssetOptions`インターフェースは、`wallet_watchAsset`メソッドの`options`パラメーターで使用されるオブジェクトの形式を定義します。
このオブジェクトには次のフィールドが含まれます。

- `address`
    - これは必須フィールドで、トークンコントラクトの16進数アドレスを表します。
    - このアドレスは`0x`で始まるチェックサム付きの16進数表記でなければなりません。
- `chainId`
    - これはオプションのフィールドで、資産が属するチェーンのIDを表します。
    - このフィールドが空の場合、現在のチェーンIDがデフォルトとして使用されます。

アドレスのチェックサムが失敗する場合、リクエストは無効とみなされます。

ウォレットが`chainId`を認識しない場合、または`chainId`が空でウォレットが「**アクティブな**」チェーンの概念を持っていない場合、呼び出しは失敗しなければなりません。

`wallet_watchAsset`メソッドは、**ERC1046**トークンの`tokenURI`をフェッチし、その`interop`フィールドをチェックしてトークンのタイプを決定しなければなりません。
パースが失敗したり、タイプが不明な場合は、RPCコールはエラーとなります。

さらに、`wallet_watchAsset`は、名前とシンボルのフィールド、およびコントラクトアドレスと`chainId`を既知のトークンのリストと照合するべきです。
名前やシンボルがリスト上のものと似ているが、`chainId`/アドレスが一致しない場合、ユーザーに警告を提示すべきです。

ウォレットは、SSRF攻撃を避けるために、特定のポートやスキームをホワイトリストまたはブラックリストに登録するべきです。
これは、外部からの不正なリクエストを制限し、ウォレットの安全性を高めるための措置です。

## レガシー`ERC20`タイプ

```ts
interface ERC20WatchAssetOptions {
{
    address: string; // The hexadecimal address of the token contract
    chainId?: number; // The chain ID of the asset. If empty, defaults to the current chain ID.
  };
}
```

`wallet_watchAsset`メソッドにおける「**レガシーERC20タイプ**」のオプションフィールドのフォーマットについて説明します。
`ERC20WatchAssetOptions`インターフェースは、レガシーERC20トークンをウォレットに追加するために使用されるパラメータを定義します。
このインターフェースには次のフィールドが含まれます。

- `address`
    - トークンコントラクトの16進数アドレスです。このフィールドは必須であり、`0x`で始まるチェックサム付きの16進数表記である必要があります。
- `chainId`
    - 資産が属するチェーンのIDです。このフィールドはオプションで、指定されていない場合は現在のチェーンIDがデフォルト値として使用されます。

以下の場合、リクエストは無効と見なされます：

- アドレスのチェックサムが失敗した場合。
- ウォレットが`chainId`を認識しない場合、または`chainId`が空でウォレットに「**アクティブな**」チェーンの概念がない場合。

`wallet_watchAsset`メソッドは、名前とシンボルのフィールド、そしてコントラクトアドレスと`chainId`を既知のトークンのリストと照合するべきです。
名前やシンボルがリスト上のものと似ているが、`chainId`やアドレスが一致しない場合、ユーザーに対して警告を提示すべきです。

可能であれば、画像やカスタムメタデータをサポートしている`ERC1046`タイプの使用が推奨されます。`ERC1046`タイプは、より豊富な情報とビジュアルをトークンに関連付けることを可能にするため、より優れたユーザーエクスペリエンスを提供する可能性があります。レガシーERC20タイプは基本的な機能のみをサポートしていますが、`ERC1046`タイプはトークンの表示と管理をさらに拡張します。

# 補足

現代のDApp（分散型アプリケーション）のユーザーは、自分の資産を表示する基本的な機能を期待しています。
多くのウォレットは現在、クライアント側に自身の資産リストを管理しているか、または中央集権的なAPIを通じて残高を照会しています。
後者の方法は分散化を減少させ、アカウント保持者をIPアドレスと関連付けることが可能になります。
さらに、ネットワークから資産リストを定期的に更新・ポーリングすることは、特に帯域幅が限られているデバイスではコストがかかります。
また、資産リストを維持することは政治的行為になり得て、不明瞭な資産をリストに加えるための圧力や嫌がらせを引き起こす可能性があります。

資産を自動的にリストアップすることは、資産を一種のスパムメールに変えてしまいます。
ユーザーは突然、関心のない新しい資産をウォレットで見ることになります。
これは、望まない情報の送信や、フィッシング詐欺を行うために利用される可能性があります。
この現象は、エアドロップされたトークンによるもので、新しいトークンで人々をスパムすることがこれまでユーザーの注目を集めることにつながっていたため、ネットワークの混雑の主な原因となっています。

ユーザーが手動で資産を追加する場合、その資産について以前にウェブサイトから学んでいた可能性が高いです。
その時点で、両方の当事者がユーザーにトークンを追跡してほしいと望んでいたため、利害の一致がありました。
これは、これらの当事者が協力しやすくするためのAPIを導入する自然な時点です。

# セキュリティ

`wallet_watchAsset`のようなウォレット機能を実装する時のセキュリティ上の考慮事項について説明しています。
特に、サーバーサイドリクエストフォージェリ（SSRF）、バリデーション、フィンガープリンティングという3つの主要な領域に焦点を当てています。

## サーバーサイドリクエストフォージェリ（SSRF）
ウォレットは任意のURLへのリクエストを行う時に注意が必要です。
ウォレットが不正に操作されて、例えばローカルにホストされているredisデータベースのデータを変更するように仕向けられる可能性があります。
そのため、特定のスキームやポートをホワイトリストに登録してURIを無害化することが推奨されます。

## バリデーション
ウォレットは、シンボルや名前が他のトークンと一致するか、類似している場合にユーザーに警告するべきです。
これは、フィッシング詐欺を避けるための重要な措置です。
ユーザーが誤って偽のトークンを追加しないようにするためです。

## フィンガープリンティング
ウォレットの動作やリストされた資産に基づくフィンガープリンティングを避けるために、RPCコールは、ユーザーにプロンプトが表示されたりエラーが発生したりした直後に返る必要があります。
これは、ユーザーがプロンプトを承諾または拒否するのを待たずに行うべきです。
これにより、ウォレットの挙動からユーザーを特定することが難しくなります。

これらのセキュリティ上の考慮事項は、ウォレットがユーザーの安全を確保し、不正な行為に対して保護するために重要です。
ウォレット開発者はこれらのガイドラインに従って、安全なウォレット機能を実装するべきです。

# 引用

Dan Finlay (@danfinlay), Esteban Mino (@estebanmino), Gavin John (@Pandapip1), "EIP-747: wallet_watchAsset RPC Method," Ethereum Improvement Proposals, no. 747, August 2018. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-747.

# 最後に

今回は「`wallet_watchAsset`という新しいRPCメソッドを追加し、ユーザーがウォレット内で簡単に資産を追跡できるようにする提案をしている**EIP747**」についてまとめてきました！
いかがだったでしょうか？

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

[Twitter @cardene777](https://twitter.com/cardene777)

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

https://chaldene.net/

https://zenn.dev/heku

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4