CAIP-25: Wallet Create Session JSON-RPC Method
Author | Pedro Gomes, Hassan Malik, Alex Donesky, Jiexi Luan |
---|---|
Discussions-To | https://github.com/ChainAgnostic/CAIPs/pull/25 |
Status | Review |
Type | Standard |
Created | 2020-10-14 |
Updated | 2025-08-11 |
Requires | 2, 10, 171, 217, 285, 311, 312 |
Table of Contents
Simple Summary
CAIP-25 defines an authorization procedure for a chain agnostic provider to interface with a wallet as part of their initialization and/or “handshake” protocol.
Abstract
This proposal defines a standard procedure for decentralized applications to interface with chain agnostic cryptocurrency wallets and other user agents that govern identities (including accounts) across multiple cryptographic systems. It specifies a lightweight protocol for negotiating and persisting authorizations during a session managed either by an in-DOM provider construct, by a securely-addressed browser extensions, or by a distinct user-agent.
Motivation
The absence of standardized interfaces and abstractions for reading from and writing to blockchains such as consistent account models and JSON-RPC method specifications has fragmented application and wallet interactions. CAIP-25 resolves this by defining a unified, session-based interface that standardizes communication between applications and wallets.
Specification
Language
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” are interpreted as described in RFC-2119.
Definition
Session Lifecycle
The session is proposed by a caller and accepted by the respondent. The respondent may return a sessionId
which both parties then persist along with session properties and authorization scopes. See CAIP-316 for guidance on session lifecycles with and without sessionId
s.
If a wallet does not return a sessionId
, it MUST track session data internally. The caller is not required to persist any session state but may query or revoke sessions via wallet_getSession
, wallet_revokeSession
, or receive updates via wallet_sessionChanged
.
Subsequent wallet_createSession
calls may:
- Update an existing session by including the same
sessionId
- Create a new session if no
sessionId
is provided (discouraged)
Session updates initiated by the wallet must notify the caller using wallet_sessionChanged
.
Callers may revoke sessions using wallet_revokeSession
, passing the sessionId
parameter if it was returned by the initial response.
Session Data and Metadata
Authorization requests are expressed as a top-level object scopes
containing keyed scopeObjects.
Each scopeObject
is keyed by a CAIP-2 or CAIP-104 identifiers. A null reference can be used to refer to a scope that applies to ANY chain within that namespace (eg. eip155:0
)
Wallets MAY authorize a subset of scopes or scope properties as requested, and MAY also authorize additional scopes or scope properties. This enables granular control and flexibility on the part of the respondent.
Upon successful negotiation, the response includes a unified scopes
object containing all granted scopes. Identically-keyed scopeObjects
from multiple requests MUST be merged. No duplicate scopes with identical keys are allowed.
Respondents MUST NOT restructure scope formats (e.g., converting chain-specific keys into namespace-wide keys).
If a connection is rejected, the wallet MAY respond with a generic error or silently ignore the request to minimize fingerprinting risk (see Privacy Considerations).
Request
interface CAIP25JsonRpcRequest {
id: number;
jsonrpc: "2.0";
method: "wallet_createSession";
params: {
scopes: {
[scopeKey: string]: {
chains?: string[];
accounts?: string[];
methods: string[];
notifications: string[];
};
};
properties?: {
[propertyKey: string]: any;
};
};
}
The scopes
object MUST contain one or more scopeObjects.
The properties
object MAY be included for global session metadata.
Response
Success
interface CAIP25JsonRpcResponse {
id: number;
jsonrpc: "2.0";
result: {
scopes: {
[scopeKey: string]: {
chains?: string[];
accounts: string[];
methods: string[];
notifications: string[];
capabilities?: {
[capabilityKey: string]: any;
};
};
};
properties?: {
[propertyKey: string]: any;
};
};
}
Each entry within scopes
object MAY contain accounts
and capabilities
as part of its object for success response.
Error Codes
The wallet MAY return generic or specific error messages depending on trust. Trusted responses may include codes like:
5000
: Unknown error5001
: User disapproved requested methods5002
: User disapproved requested notifications5100-5102
: Unsupported chains, methods, or notifications5201-5302
: Malformed requests
Examples
Example 1
For request, we define a very simple scope for 10 EVM chains with the exact same scope.
// JSON-RPC REQUEST
{
"id": 1,
"jsonrpc": "2.0",
"method": "wallet_createSession",
"params": {
"scopes": {
"eip155": {
"chains": [
"1",
"10",
"130",
"324",
"2741",
"8453",
"42161",
"59144",
"534352",
"747474"
],
"methods": ["eth_sendTransaction", "personal_sign"],
"notifications": ["accountsChanged", "chainChanged"]
}
},
"properties": {
"expiry": "2022-12-24T17:07:31+00:00"
}
}
}
For response, we also keep it quite simple with no wallet capabilities or special scopes.
// JSON-RPC RESPONSE
{
"id": 1,
"jsonrpc": "2.0",
"result": {
"scopes": {
"eip155": {
"chains": [
"1",
"10",
"130",
"324",
"2741",
"8453",
"42161",
"59144",
"534352",
"747474"
],
"accounts": ["0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb"],
"methods": ["eth_sendTransaction", "personal_sign"],
"notifications": ["accountsChanged", "chainChanged"]
}
},
"properties": {
"expiry": "2022-12-24T17:07:31+00:00"
}
}
}
Example 2
For the request, we define the expectation of 5 EVM chains with similar scope and additonally we have 2 Solana chains with similar scope
// JSON-RPC REQUEST
{
"id": 1,
"jsonrpc": "2.0",
"method": "wallet_createSession",
"params": {
"scopes": {
"eip155": {
"chains": ["1", "10", "324", "8453", "42161"],
"methods": [
"eth_sendTransaction",
"personal_sign",
"wallet_grantPermissions",
"wallet_getAssets",
"wallet_sendCalls"
],
"notifications": ["accountsChanged", "chainChanged"]
},
"solana": {
"chains": [
"5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
"4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z"
],
"methods": [
"solana_signMessage",
"solana_signTransaction",
"solana_signAndSendTransaction"
],
"notifications": []
}
},
"properties": {
"expiry": "2022-12-24T17:07:31+00:00"
}
}
}
For the response, we match the same scopes as the request but separate 2 out of 5 EVM chains into individual scopes because of non-overlapping accounts, capabilities or methods.
Additionaly we have the two Solana chains returning the same scopes but returning two different account addresses for each chain including a unique capability for one of the chains
Finally the wallet has provided within properties with its walletInfo per CAIP-372.
// JSON-RPC RESPONSE
{
"id": 1,
"jsonrpc": "2.0",
"result": {
"sessionId": "0xdeadbeef",
"scopes": {
"eip155": {
"chains": ["1", "10", "324"],
"accounts": ["0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb"],
"methods": [
"eth_sendTransaction",
"personal_sign",
"wallet_addEthereumChain",
"wallet_grantPermissions",
"wallet_getAssets",
"wallet_sendCalls"
],
"notifications": ["accountsChanged", "chainChanged"],
"capabilities": {
"walletService": "https://wallet-service.example.com/rpc"
}
},
"eip155:8453": {
"accounts": ["0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb"],
"methods": [
"eth_sendTransaction",
"personal_sign",
"wallet_grantPermissions",
"wallet_getAssets",
"wallet_sendCalls"
],
"notifications": ["accountsChanged", "chainChanged"],
"capabilities": {
"atomic": {
"status": "supported"
}
}
},
"eip155:42161": {
"accounts": [
"0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb",
"0x0495766cD136138Fc492Dd499B8DC87A92D6685b"
],
"methods": [
"eth_sendTransaction",
"personal_sign",
"wallet_grantPermissions",
"wallet_getAssets",
"wallet_sendCalls"
],
"notifications": ["accountsChanged", "chainChanged"],
"capabilities": {
"atomic": {
"status": "supported"
},
"paymasterService": {
"url": "https://...",
"optional": true
}
}
},
"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": {
"accounts": [],
"methods": [
"solana_signMessage",
"solana_signTransaction",
"solana_signAndSendTransaction"
],
"notifications": [],
"capabilities": {
"supportedTransactionVersions": ["legacy", "0"]
}
},
"solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z": {
"accounts": ["6LmSRCiu3z6NCSpF19oz1pHXkYkN4jWbj9K1nVELpDkT"],
"methods": [
"solana_signMessage",
"solana_signTransaction",
"solana_signAndSendTransaction"
],
"notifications": [],
"capabilities": {
"supportedTransactionVersions": ["legacy"]
}
}
},
"properties": {
"expiry": "2022-12-24T17:07:31+00:00",
"walletInfo": {
"uuid": "350670db-19fa-4704-a166-e52e178b59d2",
"name": "Example Wallet",
"icon": "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'/>",
"rdns": "com.example.wallet"
}
}
}
}
Security Considerations
To avoid ambiguity in authorizations, scopes
MUST retain their original keyed structure using CAIP-2 or CAIP-104 identifiers. This ensures clarity in what is authorized and prevents accidental scope merging or misinterpretation.
Privacy Considerations
To mitigate fingerprinting risks, wallets should prefer uniform or silent failure responses. Avoid leaking timing or error detail that may help malicious actors identify users or wallets. Progressive, minimal scope requests and updates are encouraged.
Changelog
- 2025-08-07: Remove
capababilities
from request AND remove CAIP-2 prefix fromaccounts
- 2025-08-04: Merged
capabilities
(fkascopedProperties
) intoscopeObjects
- 2025-08-03: Removed Namespace-scoped
scopeObjects
and retained only Chain-scopedscopeObjects
- 2025-07-31: Removed
requiredScopes
and retained onlyscopes
(fkaoptionalScopes
). - 2025-07-30: Renamed
optionalScopes
toscopes
,scopedProperties
tocapabilities
andsessionProperties
toproperties
- 2024-07-29: Added lifecycle management methods and notification for single session connections
- 2024-07-16: Redefined scope negotiation behavior
- 2023-03-29: Refactored
scopeObject
syntax to CAIP-217 - 2022-11-26: Introduced mandatory
sessionId
usage (CAIP-171) - 2022-10-26: Updated session param syntax post community gathering
Links
- CAIP-2 - Chain ID Specification
- CAIP-10 - Account ID Specification
- CAIP-104 - Definition of Chain Agnostic Namespaces or CANs
- CAIP-171 - Session Identifier, i.e. syntax and usage of
sessionId
s - CAIP-217 - Authorization Scopes, i.e. syntax for
scopeObject
s - CAIP-285 -
wallet_revokeSession
Specification - CAIP-312 -
wallet_getSession
Specification - CAIP-311 -
wallet_sessionChanged
Specification - CAIP-316 - Session Lifecycle Management equivalence chart and diagrams
- CAIP-372 - Wallet Information Metadata Standard
- RFC-2119 - Key words for use in RFCs to Indicate Requirement Levels
Copyright
Copyright and related rights waived via CC0.
Citation
Please cite this document as:
Pedro Gomes, Hassan Malik, Alex Donesky, Jiexi Luan, "CAIP-25: Wallet Create Session JSON-RPC Method," Chain Agnostic Improvement Proposals, no. 25, October 2020. [Online serial]. Available: https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-25.md