はじめに

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

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

今回は、ウォレットからバッチトランザクションを実行したり、実行ステータスを確認できるJSON-RPCメソッドを追加する仕組みを提案しているEIP5792についてまとめていきます!

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

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

概要

この規格では新しいJSON-RPCメソッドを定義しています。 これにより、アプリケーションはMetamaskなどのウォレットにデータ更新のバッチ処理をリクエストし、それらのステータスを確認できます。

ここでのデータ更新とは、ブロックチェーン上のデータの更新のことを指します。 ERC20トークンのtransferやERC721トークンのmint、ETHの送金などです。

アプリケーションは、ウォレット内に定義されている機能を使用してデータ更新のバッ処理リクエストを送ることができます。 さらに、新しいウォレットRPCが定義されても、アプリケーションはウォレットがどのような機能を持っているかを事前に確認できます。

動機

現在(2022年10月当時)、ウォレットからトランザクションを送り、そのステータスを確認するためにはeth_sendTransactionやeth_getTransactionReceiptを使用する必要があります。 ただ、eth_sendTransactionなどはノードがウォレットとして機能していた時の名残であり、新しいトランザクション形式に対応していません。

開発者目線では、複数のトランザクションをアトミックに1つのRPCコールにまとめて実行したいと考えています。 ERC4337において、PayMaster(ガス代を別のアドレスが負担する仕組み)機能を使用したいと考えても、eth_sendTransactionでは利用することができません。

新しいwallet_RPCセットでは、ウォレットとアプリの役割を明確に分け、最小限の調整で新しい機能の追加を開発者が行えることを目標にしています。

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

仕組み

この提案では、4つの新しいJSON-RPC メソッドが追加されました。 うち3つはブロックチェーン上のデータを更新するためのバッチ処理ようで、残りの1つはウォレットが特定の機能をサポートしているか確認できるものです。 新しいバッチ処理用のメソッドを使用することができ、もしウォレットが新しい3つのメソッドに対応していない場合はeth_sendTransactionとeth_getTransactionReceiptが実行します。

wallet_sendCalls

複数のオンチェーン呼び出しを効率的に処理することができます。

以下の要件が求められます。

  • 指定された順序でトランザクションを送信。
  • リクエスト時に指定されたチェーンIDのチェーン上で全てのトランザクションを送信。
  • ユーザーがリクエストを拒否した場合、必ずトランザクションの送信を止める。
  • 1つでもトランザクションが失敗した場合、全てのトランザクションが失敗する。
  • リクエスト内のチェーンIDが現在選択されているチェーンIDと異なる場合や、送信元アドレスが有効なアカウントではない場合リクエストを拒否する場合がある。
  • バッチ内のトランザクションをシミュレートして失敗が想定される場合リクエストを拒否する場合がある。

wallet_sendCallsのRPC仕様

js
type SendCallsParams = {
  version: string;
  chainId: `0x${string}`; // Hex chain id
  from: `0x${string}`;
  calls: {
    to?: `0x${string}` | undefined;
    data?: `0x${string}` | undefined;
    value?: `0x${string}` | undefined; // Hex value
  }[];
  capabilities?: Record<string, any> | undefined;
};

type SendCallsResult = string;
  • from
    • 送信元アドレス
  • chainId
    • 実行したいブロックチェーンID
  • calls
    • 各トランザクションの詳細が格納されている配列。
  • capabilities
    • ウォレットがサポートする機能をアプリが指定します。
    • 例えば、ERC4337ウォレットにPayMasterサービスのURLを指定してもらい、そのサービスからPayMasterとデータを取得することができます。

wallet_sendCallsパラメータ例

json
[
  {
    "version": "1.0",
    "chainId": "0x01",
    "from": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
    "calls": [
      {
        "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
        "value": "0x9184e72a",
        "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
      },
      {
        "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
        "value": "0x182183",
        "data": "0xfbadbaf01"
      }
    ],
    "capabilities": {
      // Illustrative
      "paymasterService": {
        "url": "https://..."
      }
    }
  }
]

wallet_sendCallsの戻り値の例

処理実行中に、ユーザーが処理のステータスを取得ができる識別子です。

js
"0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"

wallet_getCallsStatus

wallet_sendCallsを使用して実行されたバッチトランザクションのステータスを返すためのJSON-RPCメソッドです。

複数トランザクションの場合、引数のreceiptsフィールドには各トランザクションのレシート(実行結果や詳細情報)が実行順に返されます。

単一のトランザクションの場合、1つのトランザクションレシートを返します。 receiptオブジェクトのlogsは、wallet_sendCallsで送信されたトランザクションに関連するものだけ含みます。 他のユーザー操作のログなどは含まれません。

wallet_getCallsStatusのRPC仕様

js
type GetCallsParams = string;

type GetCallsResult = {
  status: 'PENDING' | 'CONFIRMED';
  receipts?: {
    logs: {
      address: `0x${string}`;
      data: `0x${string}`;
      topics: `0x${string}`[];
    }[];
    status: `0x${string}`; // Hex 1 or 0 for success or failure, respectively
    blockHash: `0x${string}`;
    blockNumber: `0x${string}`;
    gasUsed: `0x${string}`;
    transactionHash: `0x${string}`;
  }[];
};

wallet_getCallsStatusのパラメータ例

json
[
  {
    "version": "1.0",
    "chainId": "0x01",
    "from": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
    "calls": [
      {
        "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
        "value": "0x9184e72a",
        "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
      },
      {
        "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
        "value": "0x182183",
        "data": "0xfbadbaf01"
      }
    ],
    "capabilities": {
      // Illustrative
      "paymasterService": {
        "url": "https://..."
      }
    }
  }
]

wallet_sendCallsの戻り値の例

wallet_sendCallsの戻り値同様、ステータスを確認ができる識別子です。

js
[
  "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
]

wallet_showCallsStatus

wallet_sendCallsで送信されたバッチトランザクションの情報を、ウォレットに表示するリクエストを送るJSON-RPCメソッドです。 このメソッドは何も返さず、単にウォレットに情報表示を要求するだけです。

wallet_showCallsStatusのRPC仕様

js
type ShowCallsParams = string; // Call bundle identifier returned by wallet_sendCalls

wallet_showCallsStatusのパラメータ例

wallet_sendCalls実行時に返される識別子を受け取ります。

js
[
  "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
]

wallet_getCapabilities

アプリケーションがウォレットに対して、特定の機能がサポートされているか確認するリクエストを送るJSON-RPCメソッドです。 このメソッドは、アプリケーションと要求されたアドレス間の接続がユーザーによって承認されていない場合エラーを返します。 ウォレットの機能を確認する方法として、ウォレットに直接確認する方法以外にも以下の方法で確認ができます。

  • ウォレットの機能情報を外部に保存されたデータから取得する。
  • 現在のセッションに関連するうプロパティ情報に機能情報が保存されている。
  • 標準化されたインターフェースを通じて機能情報を取得。

wallet_getCapabilitiesのRPC仕様

js
type GetCapabilitiesParams = [`0x${string}`]; // Wallet address

type GetCapabilitiesResult = Record<`0x${string}`, <Record<string, any>>; // Hex chain id

wallet_getCapabilitiesのパラメータ例

js
["0xd46e8dd67c5d32be8058bb8eb970870f07244567"]

wallet_getCapabilitiesの戻り値の例

json
{
  "0x2105": {
    "paymasterService": {
      "supported": true
    },
    "sessionKeys": {
      "supported": true
    }
  },
  "0x14A34": {
    "paymasterService": {
      "supported": true
    }
  }
}

atomicBatch

ウォレットが複数のトランザクションを1つのトランザクションで実行できるかを返す機能です。 ウォレットがatomicBatch機能をサポートしている場合、wallet_sendCallsで送信された複数のトランザクションは必ず1つのトランザクションとして実行されます。

atomicBatchの機能仕様

js
type AtomicBatchCapability = {
  supported: true;
};

もし複数チェーンでトランザクションを送りたい場合は、チェーンごとにatomicBatch機能を含める必要があります。

atomicBatchを含むwallet_getCapabilitiesの戻り値の例

json
{
  "0x2105": {
    "atomicBatch": {
      "supported": true
    },
  },
  "0x14A34": {
    "atomicBatch": {
      "supported": true
    }
  }
}

補足

名前の選定

eth_sendTransactionは過去の機能の名残であるため、新しくwallet_というプレフィックスをつけることでより役割を明確にしました。 また、wallet_sendCallsは、EOAウォレットの場合複数のトランザクションを送信する可能性があり、ERC4337などのコントラクトウォレットの場合は複数のトランザクションを単一のトランザクションにまとめることがあり、どちらにも使用できる名前とのことで採用したそうです。

トランザクション実行のAtomicity

複数のトランザクションを1つのトランザクションで実行(バッチトランザクション)するとき、それがアトミック(順番通りに全て一度に)実行されることが求められます。 これに対応するatomicBatch機能を導入することで、複数のトランザクションはそのまま実行させつつ、バッチトランザクションを実行するときのみアトミックに実行されるように選択できます。

ガスリミット

最初、各トランザクションにはオプションとしてガスフィールドを含めていました。 しかし、ERC4337形式のコントラクトウォレットの場合はガスリミットを指定できず、単一のガス値を提案していました。 ただ、これはEOAウォレットに適しておらず、最終的にはガスフィールドを完全に削除しました。

互換性

新しいメソッドがウォレットでサポートされていないばあ、eth_sendTransactionを使用してトランザクションを順番に送ることができます。 また、ユーザーにはそのことを通知する必要があります。

セキュリティ

以下の点に注意してトランザクションを実行する必要があります。

  • バッチ内のトランザクション間で信頼できないトランザクションが追加される可能性があります。
  • バッチ内のトランザクションは連続してないブロックに含まれたり、時間的な制約がありません。
  • 一定時間内に実行されるという「デッドライン」や、特定の条件が時間内に満たされる必要がある「タイムライン」をコントラクトで設定して、予期しない遅延や失敗を防ぐことができます。
  • ウォレットがバッチトランザクションをサポートしていることをアプリケーションに示さない限り、単一のトランザクhそんで送信されると仮定する必要があります。

プライバシーの考慮

  • ウォレットへのアクセスをアプリ側に許可したり、トランザクション送信の許可をユーザーに求めることで、ユーザーが細かく権限の管理を行うことができます。
  • ウォレットが特定の機能をサポートしてないのか、ユーザーがアプリケーションとの接続を許可していないのかなど詳細なメッセージを返す。
  • ユーザーが許可したアプリケーションにのみ機能を公開する。
  • ウォレットの機能を過度にクエリしたり共有すると、ウォレットがどの機能を持っているか漏洩してしまうため避ける。

引用

Moody Salem (@moodysalem), Lukas Rosario (@lukasrosario), Wilson Cusack (@wilsoncusack), Dror Tirosh (@drortirosh), Jake Moxey (@jxom), Derek Rein (@arein), "EIP-5792: Wallet Call API [DRAFT]," Ethereum Improvement Proposals, no. 5792, October 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-5792.

最後に

今回は「ウォレットからバッチトランザクションを実行したり、実行ステータスを確認できるJSON-RPCメソッドを追加する仕組みを提案しているEIP5792」についてまとめてきました! いかがだったでしょうか?

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

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