[EIP2696] Ethereum通信のためのJavaScript標準インターフェースの提案を理解しよう！

# はじめに

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

https://cryptogames.co.jp/

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

https://cryptospells.jp/

今回は、JavaScriptオブジェクトを介してEthereumプロバイダとクライアントが相互に通信できる標準を定義し、Ethereumブロックチェーンへのアクセスや署名ツールの提供方法について提案している**EIP2696**についてまとめていきます！

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

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

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

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

# 概要

この標準は、Ethereumプロバイダー（Ethereumブロックチェーンとの通信を提供するもの）とEthereumクライアント（Ethereumブロックチェーンに接続するもの）の間でのリモート手続き呼び出し（RPC）を定義しています。
両者が共有JavaScriptオブジェクトを介して相互作用できる状況を想定しています。

この標準では、JavaScriptアプリケーションがEthereumブロックチェーンと通信するために使用できるオブジェクトの説明が提供されています。
ただし、この標準はトランスポートメカニズムのみを説明し、有効なペイロードやクライアントやプロバイダーがペイロード内容についてどのように見つけたり合意したりするかについては具体的には定めていません。

また、このEthereumオブジェクトがどのように公開されるか、どこで利用可能になるかについての詳細は、将来の標準に委ねられています。

# 動機

JavaScriptランタイム（NodeJS、Electron、ブラウザなど）内で作業する場合、ランタイムまたはランタイムプラグインがオブジェクトをランタイムに注入することが可能です。
ランタイムやランタイムプラグインの開発者は、そのランタイム内で実行されているすべてのJavaScriptアプリやスクリプトに対してEthereumプロバイダーを公開することを選択するかもしれません。
これにより、Ethereumのようなブロックチェーンや、潜在的に署名ツールへの間接的なアクセスが提供されます。
プロバイダーとクライアントの間で最大の互換性を確保するために、そのオブジェクトの形状に関する標準が必要です。

:::note info
ランタイムは、コンピュータのプログラムが実行される環境を提供するソフトウェアのことです。
JavaScriptランタイムは、JavaScriptプログラムが実行されるための環境を提供します。
主なJavaScriptランタイムには、Node.js、ブラウザのJavaScriptエンジン（例：V8、SpiderMonkey、JavaScriptCoreなど）、Electronなどがあります。

ランタイムプラグインは、ランタイムに機能を追加するための拡張機能やモジュールです。
これにより、開発者は既存のランタイムに独自の機能や機能を追加することができます。
例えば、ブラウザのJavaScriptランタイムには、画像処理、データベースアクセス、ネットワーク通信などの機能を追加するためのプラグインが存在します。

具体的な例として、Node.jsの場合、npm（Node Package Manager）を使用して外部のパッケージやモジュールをインストールし、それらをプロジェクトに組み込むことができます。
これらのパッケージやモジュールは、Node.jsランタイムに追加の機能や機能を提供するためのプラグインとして機能します。

Electronの場合、開発者はElectronアプリケーションに機能を追加するために、外部のJavaScriptモジュールやライブラリを使用することができます。
これらのモジュールやライブラリは、Electronランタイムに組み込まれ、アプリケーションに新しい機能や機能を追加します。

要するに、ランタイムはプログラムが実行される環境を提供し、ランタイムプラグインはそのランタイムに追加の機能や機能を提供するための拡張機能やモジュールです。
:::

# 仕様

## インターフェース

以下はTypeScriptのインターフェース定義です。

```ts
interface RequestArguments {
	readonly method: string;
	readonly params?: readonly unknown[] | object;
}

interface EthereumProvider {
	request(args: RequestArguments): Promise<unknown>
}
```

`RequestArguments`というインターフェースは、リクエストの引数を定義しており、`method`（メソッド）と`params`（パラメータ）の2つのプロパティを持ちます。
`params`は任意の配列またはオブジェクトであり、`readonly`修飾子がついています。

また、EthereumProviderというインターフェースは、`request`というメソッドを持ち、`Promise<unknown>`を返します。
`request`メソッドは`RequestArguments`を引数に取ります。

ここで、このプロバイダーはEthereumProviderオブジェクトに`request`メソッドを実装しなければなりません。
`request`メソッドは、引数として上記で定義されたTypeScriptのインターフェースに従ったリクエスト引数を1つ受け取れるようになっています。

もしプロバイダーが他の場所で指定されたようなJSON-RPCリクエストをサポートしている場合、リクエストはJSON-RPCメソッドに対応する`RequestArguments.method`引数と、RPC呼び出しの`params`オブジェクトに一致する`RequestArguments.params`で呼び出されなければなりません。
`RequestArguments.params`は、通常はJSON-RPCを転送する時にJSON文字列としてエンコードされるのではなく、指定されたJSON-RPCタイプに一致するJavaScriptオブジェクトとしてエンコードされるべきです。

### 例

この例では、JSON-RPCリクエストとその対応する`EthereumProvider.request`呼び出しが示されています。

まず、JSON-RPCリクエストのペイロードは次のようになっています。

```json
{ "jsonrpc": "2.0", "id": 1, "method": "do_work", "params": [ 5, "hello" ] }
```

これに対応する`EthereumProvider.request`の呼び出しは次のようになります。

```javascript
provider.request({ method: 'do_work', params: [ 5, 'hello' ] })
```

## 結果
プロバイダーがJSON-RPCリクエストをサポートしている場合、そのプロバイダーは関連するJSON-RPCリクエストの期待される結果定義に一致するオブジェクトを返さなければなりません。


### 例
```json
{ "jsonrpc": "2.0", "id": 1, "result": { "color": "red", "value": 5 } }
```

これに対応する`EthereumProvider.request`のレスポンスは次のようになります。

```javascript
{ color: 'red', value: 5 }
```

## エラー

以下は、提供されたエラーコードとその意味を示す表です。

| code | message               | meaning                                                     |
|------|-----------------------|-------------------------------------------------------------|
| `4001` | User Rejected Request | ユーザーがリクエストを拒否しました。                       |
| `4100` | Unauthorized          | ユーザーによってリクエストされたメソッドやアカウントが認可されていません。 |
| `4200` | Unsupported Method    | プロバイダーがリクエストされたメソッドをサポートしていません。   |
| `4900` | Disconnected          | プロバイダーがすべてのチェーンから切断されています。            |
| `4901` | Chain Disconnected    | プロバイダーがリクエストされたチェーンに接続されていません。       |

プロバイダーが何らかの理由でリクエストを処理できない場合、エラーが発生したことを示すために、プロミスをエラーとして解決します。
解決されたエラーは、可能な限り上記で定義された`ProviderRpcError`の形状に準拠しなければなりません。
JavaScriptアプリケーションがメモリ不足やスタックオーバーフローのエラーを発生させないことを保証することは不可能ですが、できる限りプロミスの拒否が上記の形状に準拠するように注意する必要があります。

提供されたコードが上記のリストやJSON-RPC仕様、または従っている関連するJSON-RPCリクエスト標準に記載されている場合、エラーの理由はそのコードの確立された意味と一致しなければなりません。
また、メッセージは提供されたメッセージと一致しなければなりません。
データフィールドには、エラーに関連する任意のデータやエラーの理解やトラブルシューティングに役立つ情報を含めることができます。

# 補足

この標準は、アプリケーションとブロックチェーンの間での通信において、最も優れたメカニズムではないかもしれませんが、コミュニティ内で確立された実践に密接に沿っており、既存のシステムからこの標準への移行は比較的容易であるべきです。

現在、ほとんどの通信はJSON-RPCを介して行われているため、JSON-RPC標準との整合性を図ることは、既存のシステムとの迅速な統合を可能にするために望ましいものでした。

つまり、この標準は、既存のシステムとの互換性を重視しながら、コミュニティ内で確立された実践に沿っており、既存のJSON-RPCベースのシステムとの移行が比較的容易であることを目指しています。

# セキュリティ

Ethereumのプロバイダーとクライアントの関係は信頼された関係です。
つまり、ユーザーは暗黙的にEthereumプロバイダーを信頼していると仮定されます。
これは、プロバイダーがクライアントに注入されたり、クライアントが明示的にその接続を取り込んだりすることで達成されます。

具体的には、ユーザーはEthereumプロバイダーが提供するサービスや機能に対して信頼を持っており、そのためクライアントに注入されたプロバイダーやクライアントが明示的にプロバイダーとの接続を設定した場合でも、ユーザーはそれらのプロバイダーとの間での通信が安全であると信じています。

# 引用

Micah Zoltu (@MicahZoltu), Erik Marks (@rekmarks), "EIP-2696: JavaScript `request` method RPC transport," Ethereum Improvement Proposals, no. 2696, June 2020. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-2696.

# 最後に

今回は「JavaScriptオブジェクトを介してEthereumプロバイダとクライアントが相互に通信できる標準を定義し、Ethereumブロックチェーンへのアクセスや署名ツールの提供方法について提案している**EIP2696**」についてまとめてきました！
いかがだったでしょうか？

質問などがある方は以下の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