HomeEIPsNewsletter
EIPsEIP-5792
EIP-5792

Wallet Call API

Adds JSON-RPC methods for sending multiple calls from the user's wallet, and checking their status
ReviewStandards Track: Interface
Created: 2022-10-17
Moody Salem (@moodysalem), Lukas Rosario (@lukasrosario), Wilson Cusack (@wilsoncusack), Dror Tirosh (@drortirosh), Jake Moxey (@jxom), Derek Rein (@arein), Alex Forshtat (@forshtat), Sam Wilson (@SamWilsn) <sam@binarycake.ca>, Borislav Itskov (@Oxbobby)
Discussions ForumOriginal Proposal LinkEdit
1 min read

EIP-5792, titled "Wallet Function Call API," proposes a new API for Ethereum wallets to allow dApps to make multiple function calls in a single transaction. This proposal aims to improve the user experience by reducing the number of confirmations required and enabling more complex interactions with contracts. The proposal introduces two new RPC methods: wallet_sendFunctionCallBundle and wallet_getBundleStatus. The wallet_sendFunctionCallBundle method allows dApps to send a bundle of function calls from the user's wallet. The wallet_getBundleStatus method returns the status of a bundle that was sent via wallet_sendFunctionCallBundle. The document also introduces a new RPC method, wallet_showBundleStatus, which requests the wallet to show the status of a given bundle. This allows dApps to delegate the display of the function call status to the wallet, which can most accurately render the current status of the bundle. The rationale behind this proposal is to enhance the user experience by reducing the number of confirmations required and enabling more complex interactions with contracts. The document mentions that there are no known backward compatibility issues associated with this proposal. The test cases, reference implementation, and security considerations are yet to be determined.

Video
Anyone may contribute to propose contents.
Go propose
Original

Abstract

Defines new JSON-RPC methods which enable apps to ask a wallet to process a batch of onchain write calls and to check on the status of those calls. Applications can specify that these onchain calls be executed taking advantage of specific capabilities previously expressed by the wallet; an additional, a novel wallet RPC is defined to enable apps to query the wallet for those capabilities.

Motivation

The current methods used to send transactions from the user wallet and check their status are eth_sendTransaction and eth_getTransactionReceipt.

The current methods used to send transactions from the user wallet and check their status do not meet modern developer demands and cannot accommodate new transaction formats. Even the name–- eth_sendTransaction-– is an artifact of a time when nodes served as wallets.

Today, developers want to send multiple calls batched together in a single RPC call, which many smart accounts can, in turn, execute atomically in a single transaction. Developers also want to make use of features afforded by new transaction formats, like paymasters in ERC-4337 transactions. eth_sendTransaction offers no way to do these things.

In updating to a new set of wallet_ RPCs, our main goals are to enforce a clean separation of wallet and app concerns, enable developers to make use of things like paymasters and batch transactions, and to create a clear way for more safely discoverable features to be added over time with minimal coordination.

Specification

Four new JSON-RPC methods are added: three are for handling batches of onchain calls, and one is for querying support for wallet capabilities, such as to make better use of the three batching methods. Apps may begin using these first three methods immediately, falling back to eth_sendTransaction and eth_getTransactionReceipt when they are not available.

wallet_sendCalls

Requests that a wallet submits a batch of calls. from and chainId are identified by EIP-155 integers expressed in hexadecimal notation, with 0x prefix and no leading zeroes for the chainId value. The items in the calls field are simple {to, data, value} tuples.

The capabilities field is how an app can communicate with a wallet about capabilities a wallet supports. For example, this is where an app can specify a paymaster service URL from which an ERC-4337 wallet can request a paymasterAndData input for a user operation.

Each capability defined in the "capabilities" member can define global or call specific fields. These fields are set inside this capability's entry in the capabilities object. Each entity in the calls field may contain an optional capabilities object. This object allows the applications to attach a capability-specific metadata to individual calls.

Unless these requirements are explicitly overriden by a certain capability, the wallet must adhere to the following rules. Note that such a capability is not in the scope of this EIP and should be defined in its own ERC.

The wallet:

  • MUST send the calls in the order specified in the request
  • MUST send the calls on the same chain identified by the request's chainId property
  • MUST send the calls from the address specified in the request's from property, if provided
    • If from is not provided the wallet SHOULD present the user with an opportunity to view and select the from address during confirmation
  • MUST NOT await for any calls to be finalized to complete the batch
  • MUST submit multiple calls as an atomic unit in a single transaction
  • MUST NOT send any calls from the request if the user rejects the request
  • MAY revert all calls if any call fails
  • MUST not execute any further calls after a failed call
  • MAY reject the request if the from address does not match the enabled account
  • MAY reject the request if one or more calls in the batch is expected to fail, when simulated sequentially
  • MUST reject the request if it contains a capability (either top-level or call-level) that is not supported by the wallet and the capability is not explicitly marked as optional.
    • Applications may mark a capability as optional by setting optional to true. See the RPC Specification section below for details.

If provided, the wallet MUST respect the id field and return it in the response.

Identifiers, whether provided by the app or generated by the wallet, MUST be a unique string up to 4096 bytes (8194 characters including leading 0x).

App-provided ids MUST be unique per sender per app, where each "app" SHOULD be identified by their domain.

Wallets MUST reject requests with duplicate ids.

Within 24 hours from the corresponding wallet_sendCalls, wallets SHOULD return a call-batch status when wallet_getCallsStatus is called with the same id.

The capabilities response object allows the wallets to attach a capability-specific metadata to the response.

wallet_sendCalls RPC Specification

type Capability = { [key: string]: unknown; optional?: boolean; } type SendCallsParams = { version: string; id?: string; from?: `0x${string}`; chainId: `0x${string}`; // Hex chain id calls: { to?: `0x${string}`; data?: `0x${string}`; value?: `0x${string}`; // Hex value capabilities?: Record<string, Capability>; }[]; capabilities?: Record<string, Capability>; }; type SendCallsResult = { id: string; capabilities?: Record<string, any>; };
wallet_sendCalls Example Parameters
[ { "version": "1.0", "from": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", "chainId": "0x01", "calls": [ { "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", "value": "0x9184e72a", "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" }, { "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", "value": "0x182183", "data": "0xfbadbaf01" } ], "capabilities": { "paymasterService": { "url": "https://...", "optional": true } } } ]

Note that since the paymasterService capability is marked as optional, wallets that do not support it will still process and handle the request as if the capability had not been present. If this optional field were set to false or absent from the request, wallets that do not support the capability MUST reject the request.

wallet_sendCalls Example Return Value
{ "id": "0x00000000000000000000000000000000000000000000000000000000000000000e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", }

wallet_getCallsStatus

Returns the status of a call batch that was sent via wallet_sendCalls. The identifier of the batch is the value returned from the wallet_sendCalls RPC. Note that the receipts objects of this method's response is a strict subset of the object returned by eth_getTransactionReceipt.

The capabilities object allows the wallets to attach a capability-specific metadata to the response.

  • The receipts in the receipts field MUST be in the order that they are included onchain.
  • If a wallet executes multiple calls atomically in a single transaction, wallet_getCallsStatus MUST return an object with a receipts field that contains a single transaction receipt, corresponding to the transaction in which the calls were included.
  • If a wallet executes multiple calls non-atomically through some capability defined elsewhere, wallet_getCallsStatus MUST return an object with a receipts field that contains an array of receipts for all transactions containing batch calls that were included onchain. This includes the batch calls that were included on-chain but eventually reverted.
  • The logs in the receipt objects MUST only include logs relevant to the calls submitted using wallet_sendCalls. For example, in the case of a transaction submitted onchain by an ERC-4337 bundler, the logs must only include those relevant to the user operation constructed using the calls submitted via wallet_sendCalls. I.e. the logs should not include those from other unrelated user operations submitted in the same bundle.

wallet_getCallsStatus RPC Specification

type GetCallsParams = string; type GetCallsResult = { version: string; id: `0x${string}`; chainId: `0x${string}`; status: number; // See "Status Codes" 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}`; }[]; capabilities?: Record<string, any>; };
Status Codes for status field

The purpose of the status field is to provide a short summary of the current status of the batch. It provides some off-chain context to the array of inner transaction receipts.

Status codes follow these categories:

  • 1xx: Pending states
  • 2xx: Confirmed states
  • 4xx: Offchain failures
  • 5xx: Chain rules failures
CodeDescription
100Batch has been received by the wallet but has not completed execution onchain (pending)
200Batch has been included onchain without reverts, receipts array contains info of all calls (confirmed)
400Batch has not been included onchain and wallet will not retry (offchain failure)
500Batch reverted completely and only changes related to gas charge may have been included onchain (chain rules failure)
600Batch reverted partially and some changes related to batch calls may have been included onchain (partial chain rules failure)

More specific status codes within these categories should be proposed and agreed upon in separate ERCs.

wallet_getCallsStatus Example Parameters

The id batch identifier is a unique 64 bytes represented as a hex encoded string returned from wallet_sendCalls.

[ "0x00000000000000000000000000000000000000000000000000000000000000000e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331" ]
wallet_getCallsStatus Example Return Value
{ "version": "1.0", "chainId": "0x01", "id": "0x00000000000000000000000000000000000000000000000000000000000000000e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", "status": 200, "receipts": [ { "logs": [ { "address": "0xa922b54716264130634d6ff183747a8ead91a40b", "topics": [ "0x5a2a90727cc9d000dd060b1132a5c977c9702bb3a52afe360c9c22f0e9451a68" ], "data": "0xabcd" } ], "status": "0x1", "blockHash": "0xf19bbafd9fd0124ec110b848e8de4ab4f62bf60c189524e54213285e7f540d4a", "blockNumber": "0xabcd", "gasUsed": "0xdef", "transactionHash": "0x9b7bb827c2e5e3c1a0a44dc53e573aa0b3af3bd1f9f5ed03071b100bb039eaff" } ] }

wallet_showCallsStatus

Requests that a wallet shows information about a given call bundle that was sent with wallet_sendCalls. Note that this method does not return anything for a known id batch identifier. If the identifier is not known, or in case of any other failure to execute wallet_showCallsStatus returns an RPC call error.

wallet_showCallsStatus RPC Specification

type ShowCallsParams = string; // Call bundle identifier returned by wallet_sendCalls
wallet_showCallsStatus Example Parameters

This method accepts a call bundle identifier returned by a wallet_sendCalls call.

["0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"]

wallet_getCapabilities

This RPC allows an application to request capabilities from a wallet (e.g. batch transactions, paymaster communication), without distinct discovery and permission requests. For more on the difference between requesting capabilities and discovering features, see the "Privacy Considerations" section.

This method SHOULD return an 4100 Unauthorized error if the user has not already authorized a connection between the application and the requested address.

We expect the community to align on the definition of additional capabilities in separate ERCs over time.

Note that in addition to, or instead of, querying the wallet directly for capabilities, the same capability objects MAY be exposed out-of-band, such as in a sessionProperty.capabilities object persisted in a CAIP-25-conformant wallet provider interface, or in a well-known location (such as a URL derived from an EIP-6963 rdns identifier). Provider abstractions MAY also cache capabilities from previous requests or otherwise inject them from out-of-band to facilitate better user experience. If any of these supplemental expressions of capabilities are contradicted by capabilities expressed in live wallet RPC responses, these latter values SHOULD be taken as the canonical and current expression of capabilities.

wallet_getCapabilities RPC Specification

Capabilities are returned in key/value pairs, with the key naming a capability and a value conforming to a shape defined for that name, in an object keyed to the relevant EIP-155 chainId expressed in hexadecimal notation. Capabilities are nested in per-chain objects because wallets may support different capabilities across multiple chains authorized in a given session. Capabilities that the wallet supports on all the chains SHOULD be included only once, using a special chainID value "0x0", and SHOULD NOT be repeated in nested per-chain objects.

type GetCapabilitiesParams = [`0x${string}`, [`0x${string}`]]; // Wallet address, array of queried chain ids (optional) type GetCapabilitiesResult = Record<`0x${string}`, <Record<string, any>>; // Hex chain id
wallet_getCapabilities Example Parameters
["0xd46e8dd67c5d32be8058bb8eb970870f07244567", ["0x2105", "0x14A34"]]
wallet_getCapabilities Example Return Value

The capabilities below are for illustrative purposes.

{ "0x0": { "flow-control": { "supported": true } }, "0x2105": { "paymasterService": { "supported": true }, "sessionKeys": { "supported": true } }, "0x14A34": { "auxiliaryFunds": { "supported": true } } }

Rationale

On Naming

We considered modifying eth_sendTransaction to add support for these new capabilities, but the method is ultimately an artifact of when nodes were used to sign transactions. We decided it is better to move forward with wallet_-namespaced methods that better describe what they are used for.

We also debated whether the methods should be called wallet_sendTransaction, wallet_sendCalls, or something else. We ultimately landed on wallet_sendCalls because in the case of EOA wallets the wallet_send* method might send more than one transaction. Similarly, we decided against wallet_sendTransactions because in the case of other wallet implementations (e.g. ERC-4337) multiple calls could result in a single transaction.

Call Execution Atomicity

The wallet_sendCalls method accepts an array of calls and by default requires that these calls be executed as part of a single transaction. That said, we expect that in some cases app developers might want to submit batched calls if and only if they can be executed non-atomically. This would enable EOA wallets to accept multiple calls as well over the same interface. A definition of this behaviour may be proposed as a separate capability ERC.

Call Gas Limit

Our initial proposal included an optional gas field for each call in the calls field accepted by the walletSendCalls method. However, we realized this could be misleading because in the case of ERC-4337 wallets you cannot specify a gas limit per call, only a single gas limit for all calls in the user operation. We then proposed a single gas value that would apply to all of the calls. This works for ERC-4337 wallets, but not for EOA wallets. When we decided that EOA wallets should be able to handle multiple calls, the common gas field became untenable across use cases and we removed it altogether.

Backwards Compatibility

Wallets that do not support the methods defined here SHOULD return error responses when these new JSON-RPC methods are called. Apps MAY attempt to send the same batch of calls serially via eth_sendTransaction when a call to these methods fails for lack of wallet support, or they MAY indicate to the user that their wallet is not supported and the request was not processed.

Security Considerations

App developers MUST NOT assume that all calls will be sent in a single transaction if they were submitted to a wallet with a capability defining how to execute the calls non-atomically. The exact behavior of non-atomically executed calls is to be defined in separate ERCs.

Wallets MUST ensure that batch identifiers returned by wallet_sendCalls are unpredictable to prevent malicious apps from inferring information about other users' transactions.

Wallets MUST NOT leak sensitive information in wallet_getCallsStatus capabilities responses.

Privacy Considerations

Progressive authorization and progressive consent paradigms are important to modern user experience, as well as to preserving the anonymity of user agents. To protect these patterns from the cross-incentives of feature-discovery that enables better user experiences, capability semantics are used and the difference between lack of feature support and lack of feature permission explicitly occluded in the design of the wallet_ RPC for querying capabilities.

Furthermore, wallets are recommended to avoid exposing capabilities to untrusted callers or to more callers than necessary, as this may allow their "user-agent" (i.e. client software) to be "fingerprinted" or probabilistically identified, which combined with other deanonymization vectors inherent to the web platform could contribute to the deanonymization of the individual user or to the deanonymization of all users of a given client in aggregate. Similarly, applications over-querying capabilities or incentivizing capability oversharing (including third-party capability oversharing) is an anti-pattern to be avoided in the implementation of capability exchanges serving to discover features.

Copyright and related rights waived via CC0.

Further reading
Anyone may contribute to propose contents.
Go propose

Not miss a beat of EIPs' update?

Subscribe EIPs Fun to receive the latest updates of EIPs Good for Buidlers to follow up.

View all
Serve Ethereum Builders, Scale the Community.
Resources
GitHub
Supported by