CAIPs icon indicating copy to clipboard operation
CAIPs copied to clipboard

Add chain-agnostic RPC

Open danfinlay opened this issue 4 years ago • 13 comments


caip: title: Chain-Agnostic JSON-RPC Interface author: Dan Finlay [email protected] discussions-to: TBA status: Draft type: Interface Standard created: 2020-10-13

Simple Summary

As most Ethereum provider methods today use the eth_ prefix, we could further standardize this to allow any protocol prefix within a JSON-RPC method, and allow providers to support an arbitrarily extensible interface, like filecoin_, xDai_, starkware_, or any other protocol identifier.

Abstract

We will need some kind of standard protocol identifier to use as a prefix for any protocol, and I would stress that since this is only application-facing (and not user-facing) it does not need to be hotly contentious meriting a name system, and instead can even be strongly unique identifiers of a given interface. For example:

// Arbitrary protocol-specific identifier as prefix:
const PREFIX = 'aowiehafidhashaiuwehfa45729298';

const accounts = await provider.send({
  method: `${PREFIX}_accounts`
});

I'll leave the definition of these prefixes as out of the scope of this proposal, as I think arbitrary but unique prefixes can be safe and useful.

Any method with a reserved prefix would then be reserved for interacting with that given protocol. For example, while today eth_accounts can refer to any EVM chain, we might add some more specific prefixes, like EthMainnet_accounts or EthRopsten_accounts, or wallets could even support CAIP-2 compatible prefixes, like caip2:eip155:1_accounts.

While some new providers are being written without protocol prefixes, it is trivial to add a prefix to all methods of any given JSON-RPC interface, making it easy for a new provider to be constructed from a provider that is compatible with this proposal, and making it trivial for this proposal to wrap any given JSON-RPC interface.

Motivation

The Ethereum JSON-RPC protocol has established JSON-RPC as the standard for new blockchains, with new chains introducing their own JSON-RPC interfaces:

For wallets looking to support multiple protocols at once, a popular approach for the short-term has been for wallets to manage multiple networks (like in EIP-2015), but this has drawbacks:

  • It puts a UX burden on users to think about networks.
  • It prevents the creation of multi-chain applications, since each is connected to only a single network.
  • It creates race conditions in applications where the provider's chain could change definition while a method call is in-flight.

Two other approaches would be:

  • Allow the provider to return additional providers in response to methods.
  • Allow the provider to handle multiple simultaneous networks at once itself.

Allowing a provider to return additional providers is a nice developer experience, but it breaks outisde the scope of JSON-RPC, and so I would argue it should be built at the convenience library layer, and instead the JSON-RPC interface itself should define how to handle multiple providers.

Specification

The specification is very simple:

Providers that want to support multiple networks should use unique prefixes to namespace the methods for those various networks. As those prefixes and underlying interfaces are defined, they should be publicized so that they can be more widely adopted by other providers and wallets.

Additionally, the provider should allow detecting what interfaces are supported, and so I will suggest one feature detection method, which will return an array of the supported interface identifiers:

{
  method: 'getSupportedProtocols',
}

// returns:
['EtherMain', 'EtherRopsten', 'EtherXDai', 'Bitcoin']

Rationale

Opening this CAIP as a discussion point, there are many variations that could be adopted to the proposal; Maybe this proposal itself should be behind a namespace, for example. Otherwise, I think the Motivation above covers the rationale adequatel.

Backwards Compatibility

As long as new network identifiers do not overlap with existing prefixes, providers adopting this should be backwards compatible with older providers. This backwards compatibility safety could be enhanced by putting this proposal itself behind another namespace, like caipN_${PROTOCOL_PREFIX}_${METHOD}.

Links

This proposal was spurred by a question asked on Twitter by Philippe Castonguay.

Partly inspired by some work I was exploring with adding new protocols to MetaMask in our Snaps beta.

Copyright

Copyright and related rights waived via CC0.

danfinlay avatar Oct 13 '20 16:10 danfinlay

Personally I think that we should be able to design a CAIP authentication pattern instead.

EIP-1102 is ubiquitous but obviously it assumes EVM chains only. This assumptions comes with two standards in this interaction: EIP-155 chainId and EIP-1474 JSON-RPC methods

What if we created an equivalent to EIP-1102 that did not make no assumption of these standards. I've described something very similar here.

What I envision is something called caip_authenticate which included two parameters: requested chainId's (CAIP-2 compatible) and expected JSON-RPC methods. Here is how I envision for example the EIP-1102 being replicated in this JSON-RPC method

// Request
{
    "id": 1,
    "jsonrpc": "2.0",
    "method": "caip_authenticate",
    "params": {
        "chains": ["eip155:1"],
        "methods": ["eth_sendTransaction", "eth_signTransaction", "eth_sign", "personal_sign"]
    }
}


// Response
{
    "id": 1,
    "jsonrpc": "2.0",
    "result": {
        "accounts": ["0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb@eip155:1"],
    }
}

What are we achieving with this new method? Request accounts in a chain-agnostic manner and explicit permission of the JSON-RPC methods to be used for this "session"

This could be further improved with the work that Metamask is doing with JSON-RPC capabilities

pedrouid avatar Oct 13 '20 16:10 pedrouid

I think that we should be able to design a CAIP authentication pattern instead.

My impression is that these proposals are distinct and could be compatible, as long as the methods being requested are strongly linked to the chain they are associated with.

How would this pattern as you're imagining it support connections that require multiple blockchains? (imagine an ETH-xDai bridge, for example)

danfinlay avatar Oct 13 '20 17:10 danfinlay

Good point, my proposal makes the assumption that methods are uniquely to a chainId.

In that case I will make a separate CAIP proposal for authentication specifically as yours is regarding for the procedure of calling methods targetted to a chainId

Consequently we can create a third proposal for a CAIP provider API which inherits from these two standards and potentially includes events as well (analogous to EIP-1193)

pedrouid avatar Oct 13 '20 17:10 pedrouid

On that note would it be more beneficial to target requests to chainId's or accountId's??

A provider session could have two accounts exposed with the same chainId.

pedrouid avatar Oct 13 '20 17:10 pedrouid

Cool, thanks for the feedback, requested changes have been made.

danfinlay avatar Oct 23 '20 21:10 danfinlay

Would be good if there was a registry of well known prefixes. Could be a simple *.csv file in this repo?

oed avatar Oct 26 '20 13:10 oed

{ method: 'getSupportedProtocols', }

// returns: ['EtherMain', 'EtherRopsten', 'EtherXDai', 'Bitcoin']

This should be changed to be synonymous with other CAIPs including the recently proposed CAIP-25. Instead I would include a method prefixed with caip then I would use CAIP-2 chainId's:

// Response
{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "caip_getSupportedChains",
  "params": {}
}

// Result
{
  "id": 1,
  "jsonrpc": "2.0",
  "result": ["eip155:1", "eip155:3", "eip155:100", "bip122:000000000019d6689c085ae165831e93"]
}

pedrouid avatar Oct 26 '20 15:10 pedrouid

@pedrouid I didn't get a chance to comment on your other CAIP for getSupportedChains but I think it excludes use cases. For example, the did_* prefix is not associated with any particular "chain". Same things for L2s which are not really "chains". getSupportedProtocols seems more generic and inclusive.

oed avatar Oct 27 '20 07:10 oed

@pedrouid I didn't get a chance to comment on your other CAIP for getSupportedChains

should we leave the window open for longer? It is kind of a trade-off "waiting for feedback" vs. "getting CAIPs merged in time" - not yet sure if the current timing is OK - feedback welcome

ligi avatar Oct 27 '20 16:10 ligi

getSupportedChains but I think it excludes use cases. For example, the did_* prefix is not associated with any particular "chain". Same things for L2s which are not really "chains". getSupportedProtocols seems more generic and inclusive.

@oed I get your point but then we need to define some standard for protocol definition that isn't a chain. Technically CAIPs should be about blockchains hence its name but I would like to include other distributed network protocols given they have their own namespace and reference that could be compatible with CAIP-2 or similar.

For example, could it be reasonable that did is the namespace and the reference would be a DID method?

// Response
{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "caip_getSupportedProtocols",
  "params": {}
}

// Result
{
  "id": 1,
  "jsonrpc": "2.0",
  "result": ["did:3", "did:key"]
}

pedrouid avatar Oct 27 '20 19:10 pedrouid

Technically CAIPs should be about blockchains hence its name but I would like to include other distributed network protocols given they have their own namespace and reference that could be compatible with CAIP-2 or similar.

Yeah I think limiting it to blockchains is kind of arbitrary. CAIP is just the name that we ended up with, and I'd rather have this be more around any protocol where you have a wallet with keys that signs things.

Your example there makes sense except that you wouldn't need specific prefixes for different DID methods :)

oed avatar Oct 27 '20 19:10 oed

Alternatively why don't we just call it caip_getSupportedMethods?

No matter if you are specifying eip155:1 for Ethereum Mainnet or did for Decentralized Identities. You are not explicitly saying which methods you support.

The most common example on Ethereum is eth_signTypedData which is not finalized therefore it would technically not be part of Ethereum JSON-RPC API but it's still widely used and it should be expected by some applications.

I would proposed instead that similarly to CAIP-25 that it should explicitly describe all methods individually in an array.

// Response
{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "caip_getSupportedMethods",
  "params": {}
}

// Result
{
  "id": 1,
  "jsonrpc": "2.0",
  "result": ["eth_sendTransaction", "eth_signTransaction", "eth_sign", "personal_sign"]
}

pedrouid avatar Oct 27 '20 19:10 pedrouid

We should update this PR to introduce caip_getSupportedMethods and also add a new PR to add caip_getSupportedChains

pedrouid avatar Aug 03 '21 17:08 pedrouid

Largely overtaken by events-- see #25, #217 (updating 25 substantially after months of work in the RPC WG with MetaMask and others), and #104 for namespacing RPC methods across multiple VMs/types of chain

bumblefudge avatar Apr 12 '23 13:04 bumblefudge