Skip to content
Closed
276 changes: 276 additions & 0 deletions CAIPs/caip-211.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
---
caip: 211
title: JSON-RPC Authority Negotiation
author: Pedro Gomes (@pedrouid), Hassan Malik (@hmalik88)
discussions-to: https://github.com/ChainAgnostic/CAIPs/pull/207
status: Draft
type: Standard
created: 2023-02-02
updated: 2023-02-02
requires: [2, 10, 25, 171]
---

## Simple Summary

CAIP-211 extends CAIP-25 to allow callers and respondents to anchor feature
discovery in specific RPC semantics and to request the respondent route requests
to specific RPC endpoints.

## Abstract

CAIP-211 defines additional properties that enable progressive usage of CAIP-25
to layer custom or local RPC semantics and/or routing onto a session. Since
CAIP-25 respondents ignore unknown properties, respondents that conform to
CAIP-25 but not to CAIP-211 should be carefully considered and accomodated by
implementers.

## Motivation

While some core methods and notifications are foundational to entire namespaces
and thus almost universally defined out-of-band (meaning all callers and
respondents agree to them already), others are specific to chains or even to
subsets of wallets and dapps on a given chain. This requires scope objects in
CAIP-25 requests to negotiate semantic anchors and/or network routing
**before** authorization can occur in the confidence that both parties agree to
the syntax and semantics of a given method or notification, which may only be
available on certain RPC endpoints.

The concept of a custom RPC endpoint or definition presumes the existence of
"default" or universal endpoints and definitions, which can be hard to anchor in
explicit specifications unless a namespace profile of this CAIP has been
published. (This may be unnecessary in the case of younger namespaces without
customization built in at the per-chain or per-dapp layer). An empty array of
`rpcEndpoints` or `rpcDocuments` sent in either direction should be interpreted
differently than the absence of the array. Namely, either array being present
but empty in a request signals that a caller is requesting that custom endpoints
or definitions NOT be considered in CAIP-25 authorizations. Present but empty
arrays in a response confirms this behavior, while its absence can be taken to
mean the wallet either does not support custom endpoints/definitions or the user
has opted out of that degree of trust, which for privacy/fingerprinting reasons,
should not be handled by distinct codepaths (See Privacy Considerations).

## Specification

CAIP-211 adds two properties, either of which can be set in `requiredScopes` or
in `optionalScopes` and, if authorized, optionally returned in `sessionScopes`.
These are both [ordered] strings of arrays:

1. `rpcEndpoints` is an array of zero or more URLs of RPC endpoints that
the caller would prefer the respondent to use, ordered by preference. Each
must be a valid URL that addresses an RPC endpoint. The respondent may
return it empty, reordered, with less, the same, or even more conformant URLs
than received.
2. `rpcDocuments` is an array of zero or more URLs of machine-readable OpenRPC
documents that the caller would prefer the respondent to use, ordered by
preference. This set of documents defines the syntax (and optionally also the
semantics) of all the methods and/or notifications being requested and
authorized in a CAIP-25 authorization. The documents are listed in
descending heirarchical authority, i.e., documents later in the list extend
the first, but any terms already defined by a previous entry are dropped
rather than being redefined by the later documents. Each must be a valid URL
that addresses a valid openRPC document. The respondent may return it empty,
reordered, with less, the same, or even more conformant URLs than received.

### Request

A CAIP-211 request is a valid CAIP-25 except for the two additional properties.

Example:

```jsonc
{
"id": 1,
"jsonrpc": "2.0",
"method": "provider_authorization",
"params": {
"requiredScopes": {
"eip155": {
"chains": ["eip155:1", "eip155:137"],
"methods": ["eth_sendTransaction", "eth_signTransaction", "eth_sign", "get_balance", "personal_sign"],
"notifications": ["accountsChanged", "chainChanged"]
},
"eip155:42069": {
"methods": ["get_balance", "chainChanged", "42069_sEcReTbAlAnCe"],
"rpcDocuments": ["https://openrpc.42069-chain.org/", "https://raw.githubusercontent.com/ethereum/execution-apis/assembled-spec/refs-openrpc.json"],
"rpcEndpoints": ["https://node1.42069-chain.org/"]
},
"cosmos": {
...
}
},
"optionalScopes":{
"eip155:42161": {
"methods": ["eth_sendTransaction", "eth_signTransaction", "get_balance", "personal_sign"],
"events": ["accountsChanged", "chainChanged"]
},
"sessionProperties": {
"expiry": "2022-12-24T17:07:31+00:00",
"caip154-mandatory": "true"
}
}
}
```

### Response

The wallet can respond to this method with either a success result or an error message.

#### Success

A succesful result will be a conformant successful result according to
[CAIP-25][], with the additional presence (if authorized) of the new properties

@hmalik88 hmalik88 Feb 17, 2023

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if it makes sense to include the new properties in the response, what use is it to spit back what the dapp has requested from you? The OpenRPC doc would be just used by the wallet for discovery.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my thinking was that the ORDERING of the array might be changed by the wallet (i.e., I'll trust this RPC extension doc, but wherever it redefines something in my core doc, e.g. execution-apis, I'll take the latter's definition). This allows for some flexibility between binary accepting/rejecting each element in the array.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On further thought, it might make sense to include the rpcEndpoints field in an ordered manner like you mentioned for rpcDocuments. If a provider so chooses to use the provided endpoints, it can specify usage + fallbacks in order or otherwise return an empty array (if its using endpoints of its own choice).

Ideally, there should only be one source of truth for the rpcDocument, lets call it that because well it should be one. Imagine a scenario where for some reason the multiple endpoints are not updated to be in line with each other, we have a scenario where the wallet doesn't know what document to trust. Anytime a request has an OpenRPC doc, the provider should be using that to determine/provide functionality, including for core-apis.

@bumblefudge bumblefudge Mar 2, 2023

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I guess I was assuming that multiple RPC docs don't necessarily undermine THE RPC Doc.

Example: custom endpoints and/or proprietary, feature-rich wallets might find it useful to have RPCDocs reinforcing or making more explicit what's custom about them-- whether the custom RPC doc overrides The One is a matter of policy, easily expressed in ordering? Why not let additional RPC docs extend THE RPC Doc, like a class?

Maybe that's too footgunny, though. The real question is whether that ordering mechanism is too prone to human error or too hackable... let's talk about it at the next meeting and see what others in the group have to say, maybe? Feel free to bring Shane or anyone at MM who has opinions and/or topical devrel experience from EthDenver :D

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See also this exchange with ligi, which refers to a discussion with TimDaub about eth clients at the last editorial meeting:
#206 (comment)

It seems multiple only very slightly different RPC documents might be useful until there is 100% conformance across all eth clients! I can definitely imagine that on other namespaces (e.g. Polkadot) where chains can customize their runtimes and add crates/pallets, it would be very useful for cross-chain apps to have multiple RPC docs...

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps namespace-specific profiles of 211 would be the place to recommend (or even constrain) behavior here, like "never authorize more than 1 RPC Doc" or "Never put any RPC ahead of The One when authorizing"?

in one or more scope objects.

An example of a successful response follows:

```jsonc
{
"id": 1,
"jsonrpc": "2.0",
"result": {
"sessionId": "0xdeadbeef",
"sessionScopes": {
"eip155": {
"chains": ["eip155:1", "eip155:137"],
"methods": ["eth_sendTransaction", "eth_signTransaction", "get_balance", "eth_sign", "personal_sign"]
"events": ["accountsChanged", "chainChanged"],
"accounts": ["eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb", "eip155:137:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb"]
},
"eip155:10": {
"methods": ["get_balance"],
"events": ["accountsChanged", "chainChanged"],
"accounts:" []
},
"eip155:42069": {
"methods": ["get_balance", "chainChanged", "42069_sEcReTbAlAnCe"],
"rpcDocuments": ["https://raw.githubusercontent.com/ethereum/execution-apis/assembled-spec/refs-openrpc.json", "https://openrpc.42069-chain.org/"],
"rpcEndpoints": ["https://node1.42069-chain.org/"]
}
//...
},
"sessionProperties": {
"expiry": "2022-11-31T17:07:31+00:00"
}
}
}
```

Note:
* The response re-ordered the RPC documents array, which still allows the
42069-chain docs to define new methods such as the namespaced secret-balance
method example. However, since the ordinality of the array prioritizes earlier
authorities in any case where two define the same term, the chain-specific
authority is effectively prevented from redefining any methods defined in the
eip155-wide standard, even in the limited scope of the 42069 chain. This is
purely for illustrative purposes and not normative.

#### Failure States

##### TODO:

An example of an error response should match the following format:

```jsonc
{
"id": 1,
"jsonrpc": "2.0",
"error": {
"code": 5000,
"message": "Unknown error"
}
}
```

The additional error messages codes to be supported in addition to CAIP-25s are the following:

##### TODO: replace following with novel errors

Possible error messages (to be discussed with WG):
- rpcDocuments not conformant syntactically (not openRPC, not served as mime type JSON, etc)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's an OpenRPC doc to describe the OpenRPC spec, that would be helpful 😄

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure! The error message could even LINK to it (some WC error messages currently link to CAIP URLs!) although I'm not sure where to draw the normativity line on things like error messages


Are these error messages required at protocol level or are they implementation-specific?
- ~~rpcDocuments rejected by user input OR wallet does not support custom RPC documents~~
- ^ no response in either case
- rpcDocuments rejected by policy/in principle
- rpcDocuments unreachable/404
- ~~rpcEndpoints rejected by user input OR wallet does not support custom RPC documents~~
- ^ no response in either case
- rpcEndpoints rejected by policy/in principle
- rpcEndpoints unreachable/404
- rpcEndpoints URL malformed

* Unknown error OR no requested scopes were authorized
* code = 5000
* message = "Unknown error"
* When user disapproves accepting calls with the request methods
* code = 5001
* message = "User disapproved requested methods"
* When user disapproves accepting calls with the request events
* code = 5002
* message = "User disapproved requested events"
* When wallet evaluates requested chains to not be supported
* code = 5100
* message = "Requested chains are not supported"
* When wallet evaluates requested methods to not be supported
* code = 5101
* message = "Requested methods are not supported"
* When wallet evaluates requested events to not be supported
* code = 5102
* message = "Requested events are not supported"
* When a badly-formed request includes a `chainId` mismatched to scope
* code = 5103
* message = "Scope/chain mismatch"
* When a badly-formed request defines one `chainId` two ways
* code = 5104
* message = "ChainId defined in two different scopes"
* Invalid Session Properties Object
* code = 5200
* message = "Invalid Session Properties requested"
* Session Properties requested outside of Session Properties Object
* code = 5201
* message = "Session Properties can only be optional and global"

## Security Considerations

##### TODO
- what happens if wallet reorders Documents and dapp ignores that? should we
make more explicit how important the ordering of those arrays is, and that
neither party can guarantee how the other is ordering them?

## Privacy Considerations

The trust model of custom RPC endpoints and/or definition documents is complex
and reputation/discovery systems are still emerging on a per-chain basis in many
ecosystems. For this reason, iterations of CAIP-25 should be considered a
delicate negotiation best done progressively to avoid malicious dapps partially
deanonymizing wallets by profiling their support for custom RPCs (i.e.
overasking). For this reason, as with the initial CAIP-25 exchange, discovery
requests rejected due to user input, due to security policy, and due to
non-support at the wallet software level should not be distinguished as the RPC
level.

##### TODO

## Changelog

## Links

- [CAIP-2][] - Chain ID Specification
- [CAIP-10][] - Account ID Specification
- [CAIP-25][] - JSON-RPC Provider Request
- [CAIP-75][] - Blockchain Reference for the Hedera namespace
- [CAIP-171][] - Session Identifier Specification

[CAIP-2]: https://chainagnostic.org/CAIPs/caip-2
[CAIP-10]: https://chainagnostic.org/CAIPs/caip-10
[CAIP-25]: https://chainagnostic.org/CAIPs/caip-25
[CAIP-75]: https://chainagnostic.org/CAIPs/caip-75
[CAIP-104]: https://chainagnostic.org/CAIPs/caip-104
[CAIP-171]: https://chainagnostic.org/CAIPs/caip-171
[namespaces]: https://namespaces.chainagnostic.org
[RFC3339]: https://datatracker.ietf.org/doc/html/rfc3339#section-5.6
[CAIP-170]: https://chainagnostic.org/CAIPs/caip-170

## Copyright

Copyright and related rights waived via [CC0](../LICENSE).
35 changes: 33 additions & 2 deletions CAIPs/caip-25.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ discussions-to: https://github.com/ChainAgnostic/CAIPs/pull/25
status: Review
type: Standard
created: 2020-10-14
updated: 2022-10-26
requires: [2, 10, 171]
updated: 2023-02-02
requires: [2, 10, 25, 171]
---

## Simple Summary
Expand Down Expand Up @@ -110,9 +110,16 @@ Example:
}
},
"optionalScopes":{
"eip155": {
"methods": ["eth_sign","eth_signTypedData","eth_signTypedData_v3","eth_signTypedData_v4","wallet_switchEthereumChain","wallet_addEthereumChain"]
},
"eip155:42161": {
"methods": ["eth_sendTransaction", "eth_signTransaction", "get_balance", "personal_sign"],
"notifications": ["accountsChanged", "chainChanged"]
},
"wallet" {
"method": ["creds_present", "creds_store"]
}
},
"sessionProperties": {
"expiry": "2022-12-24T17:07:31+00:00",
Expand All @@ -138,6 +145,14 @@ Each scope object contains the following parameters:
The `requiredScopes` array MUST contain 1 or more of these objects, if present;
the `optionalScopes` array MUST contain 1 or more of them, if present.

There is one special-case scope object, named `wallet`, which refers to methods
and events independent of CASA namespace. This off-chain scope objects exists
for callers and respondents to negotiate support for chain-agnostic primitives
like W3C decentralized identifiers, W3C Verifiable Credentials, JWTs, IPFS,
webCrypto, and other cryptographic standards. At time or writing, the only CAIP
that specifies `wallet` methods so far is [CAIP-169][], although others may be
in progress.

A third object is the `sessionProperties` object, all of whose properties MUST
be in the interpreted as optional, since requesting applications cannot mandate
session variables to providers. Because they are optional, providers MAY respond
Expand Down Expand Up @@ -201,6 +216,7 @@ An example of a successful response follows:
"methods": ["personal_sign"],
"notifications": ["accountsChanged", "chainChanged"],
"accounts":["eip155:42161:0x0910e12C68d02B561a34569E1367c9AAb42bd810"]
},
"cosmos": {
...
}
Expand Down Expand Up @@ -298,6 +314,17 @@ Note: respondents are RECOMMENDED to implement support for core RPC Documents
per each supported namespace to avoid sending error messages 5201 and 5202 in
cases where 0, 5101 or 5102 would be more appropriate.

## Extensibility and Additional Properties

Any other properties present in a request MUST be ignored by respondents, UNLESS
they are defined by an extension specification to CAIP-25 (such as, for example,
the methods defined in [CAIP-169][]). Since unsuccesful authorizations return
nothing, it is recommended that requests for potentially unstable or
authority-specific terms be handled progressively, i.e., requesting initial
authorization or feature discovery first, then negotiating authorities on any
local or versioned authorization terms (using, for example, [CAIP-207][]), and
only then requesting authorization of those terms.

## Security Considerations

The crucial security function of a shared session negotiated and maintained by a
Expand Down Expand Up @@ -365,13 +392,17 @@ was in violation of policy).
- [CAIP-25][] - JSON-RPC Provider Request
- [CAIP-75][] - Blockchain Reference for the Hedera namespace
- [CAIP-171][] - Session Identifier Specification
- [CAIP-207][] - Extension to CAIP-25 that enables explicit negotiation of RPC
authorities and semantics

[CAIP-2]: https://chainagnostic.org/CAIPs/caip-2
[CAIP-10]: https://chainagnostic.org/CAIPs/caip-10
[CAIP-25]: https://chainagnostic.org/CAIPs/caip-25
[CAIP-75]: https://chainagnostic.org/CAIPs/caip-75
[CAIP-104]: https://chainagnostic.org/CAIPs/caip-104
[CAIP-169]: https://chainagnostic.org/CAIPs/caip-169
[CAIP-171]: https://chainagnostic.org/CAIPs/caip-171
[CAIP-207]: https://chainagnostic.org/CAIPs/caip-207
[namespaces]: https://namespaces.chainagnostic.org
[RFC3339]: https://datatracker.ietf.org/doc/html/rfc3339#section-5.6
[CAIP-170]: https://chainagnostic.org/CAIPs/caip-170
Expand Down