-
Notifications
You must be signed in to change notification settings - Fork 229
[CAIP-25] Add CAIP-211 ("Rpc Authority Negotiation") as extension spec to CAIP-25 #211
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f3bbafb
efb9ee7
2016fa6
8703b01
1729b1b
ff0e0f2
ececfab
7d379d1
abf9961
c78fb02
32b38a7
f91abb1
6748a73
2c1394e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 | ||
| 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) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 😄
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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). | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
rpcEndpointsfield in an ordered manner like you mentioned forrpcDocuments. 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.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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...
There was a problem hiding this comment.
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"?