CAIP-345: Wallet Service URL property
Author | Chris Smith |
---|---|
Discussions-To | https://github.com/ChainAgnostic/CAIPs/discussions/345 |
Status | Draft |
Type | Standard |
Created | 2025-02-17 |
Updated | 2025-06-24 |
Requires | 25 |
Table of Contents
Simple Summary
Handling of wallet JSON-RPC requests by wallet-provided HTTP endpoint.
Abstract
This proposal defines the wallet service property, caip345
, for use in CAIP-25. Wallets set this to indicate that certain methods, instead of being handled by the CAIP-25 session, will instead be sent to a JSON-RPC HTTP endpoint. Compatible apps that support this will be able to call these RPC methods, without interactivity with the actual wallet application or user.
Motivation
It is sub-optimal UX to redirect the user to their wallet in order to handle RPC requests that are non-actionable to them. This is especially relevant for protocols such as WalletConnect which is used in more distributed environments such as mobile wallets or custodial solutions. In these contexts, actioning a wallet RPC request can involve significant effort.
Examples of non-actionable wallet requests include:
- EIP-5792
wallet_getCapabilities
- EIP-5792
wallet_getCallsStatus
- ERC-7836
wallet_prepareCalls
andwallet_sendPreparedCalls
- ERC-7811
wallet_getAssets
By defining a way for wallets to send requests to an out-of-band endpoint, the requests can be satisfied without needing the wallet app to be open.
Specification
Wallet Service
A “wallet service” is a JSON-RPC-compatible HTTP endpoint that can be used to satisfy certain wallet RPC methods. This service may be developed, hosted, and maintained by the same organization developing the wallet app, or by a third-party. It is up to the wallet to determine what server should be responsible for handling wallet RPCs.
The wallet service can be specified as a URL, and a list of JSON-RPC methods for which to use the URL. methods
SHOULD NOT be empty. The endpoint MUST be JSON-RPC compatible and support POST
requests.
type WalletService = {
methods: string[],
url: string,
};
Wallets MAY provide query params as part of the URL. These params could be useful for many things such as providing an authentication token, connection ID, identifying the chain being used, or providing other necessary details to fulfil the request.
The endpoint SHOULD enable CORS (Cross-Origin-Resource-Sharing) to allow arbitrary app domains to access the endpoint.
The wallet service MAY respond with a Cache-Control
header, indicating the cacheability of the response. Apps SHOULD set the JSON-RPC id
field to 0
, increasing the chance of a cache-hit.
Wallets MUST NOT set multiple wallet service entries for the same method. Apps SHOULD NOT attempt to recover from multiple or conflicting wallet service URLs, but MAY use the first URL available for the method as a convenience for implementation.
Apps SHOULD use the wallet service when available for a method, instead of calling the wallet directly.
Here is an example implementation:
const jsonRpc = { ... };
const handler = walletService.find(s => s.methods.includes(jsonRpc.method));
if (handler) {
jsonRpc.id = 0; // optional
return fetch(handler.url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(jsonRpc)
});
} else {
// fallback to sending directly to wallet
}
Usage in CAIP-25
The caip345
property can be used in both sessionProperties
and scopedProperties
, depending on what scopes the methods are supported on.
// scoped or session properties
type Caip25Properties = {
caip345: WalletService[],
[key: string]: any, // other properties
};
If a method is included in the caip345
property, then the same method MUST be included in the CAIP-25 session for the same scopes. Wallets MUST implement fallback handling for all wallet service methods, in case the app does not implement this CAIP.
Below is an unverified, non-normative, example for wallet_getAssets
which is only supported in the eip155
scope:
"scopedProperties": {
"eip155": {
"caip345": [{
"methods": ["wallet_getAssets"],
"url": "https://wallet-service.example.com/rpc"
}],
}
}
Below is an unverifed, non-normative, example for ERC-7836, which is also only valid in the eip155
scope:
"scopedProperties": {
"eip155": {
"caip345": [{
"methods": ["wallet_prepareCalls", "wallet_sendPreparedCalls"],
"url": "https://wallet-service.example.com/rpc"
}],
}
}
Rationale
Support for multiple wallet service URLs
Supporting an array of wallet services increases flexibility. Allowing different URLs (servers or parameters) to be used for different methods or use cases.
There must still be 1 canonical wallet service URL for a given method (if available at all).
Different wallet service depending on account
There was consideration for being able to specify different wallet service URLs for different accounts. However, this would not make sense in the context of CAIP-25 because there is no mechanism to scope the methods to particular accounts. If this CAIP provided a way to scope the methods to particular accounts, the app may still try to send the method requests for non-listed accounts directly to the wallet.
Map methods to wallet services, instead of methods in array
There was consideration for defining the standard to have a separate wallet service URL for every single method. However, this would cause excessive bandwidth consumption if the same URL were to be used for multiple methods which we think is the more likely case.
Not supporting custom headers
Specifying custom headers to use in the wallet service request is not supported. This is because in browsers, custom headers will create pre-flight OPTIONS
requests, increasing bandwidth and server load. Instead, the necessary parameters should be passed via query params.
Web apps using connect-src
in Content-Security-Policy
Many web apps specify connect-src
in their CSP which prevents the app and its libraries from connecting to URLs that aren’t pre-specified. Since each wallet may use their own wallet service hosted on unique origins, it’s not possible/advisable to dynamically set the connect-src
value as-necessary.
However to support this use case, such apps can consume a minimal proxy service (such as a server function) which will forward the wallet RPC request to the destination wallet service. This proxy service is known by the app, and has a fixed origin URL, which allows placing it in connect-src
. The proxy service could be implemented by the app, or by a third-party.
The mechanism by which this proxy service is implemented or consumed is outside the scope of this CAIP.
Test Cases
Valid wallet service:
{
"methods": ["wallet_prepareCalls", "wallet_sendPreparedCalls"],
"url": "https://wallet-service.example.com/rpc"
}
Invalid wallet service:
{
"url": "https://wallet-service.example.com/rpc"
}
Security Considerations
The wallet service would bear the security responsibility of responding to these wallet RPC requests. Wallets should make informed decisions about which providers they use for this.
Privacy Considerations
Similarly, the wallet service would have visibility into the wallet RPC requests being sent to it.
Backwards Compatibility
This new property is fully backwards-compatible with CAIP-25.
As also mentioned above, wallets MUST implement fallback handling for all wallet service methods, in case the app does not implement this CAIP.
References
- CAIP-25 is where this property is used
Copyright
Copyright and related rights waived via CC0.
Citation
Please cite this document as:
Chris Smith, "CAIP-345: Wallet Service URL property [DRAFT]," Chain Agnostic Improvement Proposals, no. 345, February 2025. [Online serial]. Available: https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-345.md