Skip to content
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

CAIP-282 - Browser Wallet Messaging Interface #282

Open
wants to merge 31 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
9ac3552
Merge pull request #7 from ChainAgnostic/main
pedrouid May 28, 2024
8d509b6
add caip
pedrouid May 30, 2024
f0fe3c2
add caip number, discussions and update created date
pedrouid May 30, 2024
b051f62
...
pedrouid May 30, 2024
e41796a
Update CAIPs/caip-282.md
pedrouid May 30, 2024
7a81a4c
Update CAIPs/caip-282.md
pedrouid May 30, 2024
9fe4147
update event names
pedrouid May 30, 2024
3ef35dd
Merge branch 'browser-wallet-messaging-interface' of https://github.c…
pedrouid May 30, 2024
6ac99d4
Update CAIPs/caip-282.md
pedrouid Jun 6, 2024
42c645c
Update CAIPs/caip-282.md
pedrouid Jun 6, 2024
4986b61
Update CAIPs/caip-282.md
pedrouid Jun 6, 2024
0869e0d
Update CAIPs/caip-282.md
pedrouid Jun 6, 2024
f076f22
add missing sections
pedrouid Jun 6, 2024
eb13968
add test cases
pedrouid Jun 6, 2024
1cb66fd
tweak
pedrouid Jun 6, 2024
46c13a6
Update CAIPs/caip-282.md
pedrouid Jun 6, 2024
d2254ba
Update CAIPs/caip-282.md
pedrouid Jun 7, 2024
9f5029f
Update CAIPs/caip-282.md
pedrouid Jun 8, 2024
d0562ea
Apply suggestions from code review
pedrouid Jun 8, 2024
2eb5f0c
clean up and introduction of CAIP-217 scopes
pedrouid Jun 8, 2024
19a443c
WIP
pedrouid Jun 21, 2024
f2389e8
move to jsonrpc
pedrouid Jun 24, 2024
b6ced5c
add separate caips for extensions and iframes
pedrouid Jun 26, 2024
630a3e1
dispatchEvent and postMessage
pedrouid Jun 26, 2024
c2b6ff0
update dates
pedrouid Jun 26, 2024
3ea7bde
Update CAIPs/caip-282.md
pedrouid Jul 2, 2024
374e710
Update CAIPs/caip-282.md
pedrouid Jul 2, 2024
0f17dd3
Update CAIPs/caip-282.md
pedrouid Jul 2, 2024
c1e833f
Update CAIPs/caip-282.md
pedrouid Jul 2, 2024
02f119f
add extensionId for externally_connectable
adonesky1 Aug 2, 2024
bc49428
Merge pull request #8 from adonesky1/ad/caip-294-externally_connectable
pedrouid Aug 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 183 additions & 0 deletions CAIPs/caip-282.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
---
caip: 282
title: Browser Wallet Discovery Interface
author: Pedro Gomes (@pedrouid)
discussions-to: https://github.com/ChainAgnostic/CAIPs/pull/282
status: Draft
type: Standard
created: 2024-05-30
requires: 25, 27, 217, 275
---

## Simple Summary

CAIP-282 defines a standardized interface for browser wallet discovery

## Abstract

To interface with a Decentralized Application (dapp), users install browser wallets to manage their blockchain accounts, which are required to sign messages and transactions. Leveraging existing browser messaging APIs, these are used to initiate a dapp-wallet connection in a browser environment.

## Motivation

Currently, in order for Decentralized Applications to be able to support all users they need to support all browser wallet APIs. Similarly, in order for browser wallets to support all Decentralized Applications they need to support all APIs. This is not only complicated but also results in a larger bundle size of applications.
Copy link
Contributor

Choose a reason for hiding this comment

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

Currently, in order for Decentralized Applications to be able to support all users they need to support all browser wallet APIs.

This is unclear since not all DApps need to use all browser wallet APIs. Should it be that "...for all wallets to be able to support all DApps..."?


Users are already installing a wallet application on their devices, and given its presence in the browser environment, it should be unnecessary for application developers to install extra software to support these Wallet Providers. This situation is only present due to the lack of standardization and interoperability between interfaces and discovery mechanisms for different Wallet Providers.

pedrouid marked this conversation as resolved.
Show resolved Hide resolved
This results not only in a degraded user experience but also increases the barrier to entry for new Wallet Providers as users are incentivized to use more popular Wallet Providers that are more widely supported in more applications.

This situation is further aggravated by differences between blockchain networks such as Ethereum, Cosmos, Solana, Tezos, etc. While some solutions attempt to solve this, such as WalletConnect, [EIP-6963][eip-6963], Solana Wallet Protocol, etc., they do not cover all wallets and are not chain-angostic.

In this proposal, we present a solution focused on optimizing interoperability for multiple Wallet Providers, fostering fairer competition by reducing the barriers to entry for new Wallet Providers, and enhancing user experience across all blockchain networks.

## Specification

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in [RFC-2119].

### Definitions

Wallet Provider: A user agent that manages accounts and facilitates transactions with a blockchain.
pedrouid marked this conversation as resolved.
Show resolved Hide resolved

Decentralized Application (dapp): A web page that relies upon one or many Web3 platform APIs which are exposed to the web page via the Wallet.

Blockchain Library: A library or piece of software that assists a dapp to interact with a blockchain and interface with the Wallet.

#### Discovery

Both Wallet Providers and blockchain libraries must listen to incoming messages that might be published after their initialization. Additionally both Wallet Providers and blockchain libraries must publish a message to both announce themselves and their intent to connect, respectively.

Choose a reason for hiding this comment

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

Does this specific CAIP only deal with wallets that announce themselves after the blockchain library loads and can receive wallet_announce messages?

Copy link
Member Author

Choose a reason for hiding this comment

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

The wallet WILL announce itself in two instances:

  1. when it loads
  2. when it receives a wallet_prompt message

This prevents any async problems that might arise from wallet and library to load at different stages

This pattern is inspired by the work done by EIP-6963:
https://eips.ethereum.org/EIPS/eip-6963#window-events

pedrouid marked this conversation as resolved.
Show resolved Hide resolved

This discovery would use the following JSON-RPC request params:

```typescript
// for "wallet_prompt" method
interface WalletPromptRequestParams {
chains?: string[]; // compatible with CAIP-2
Copy link

Choose a reason for hiding this comment

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

The behavior for chains is undefined, should a wallet only reply if it has a chain in this list?

Copy link
Member Author

Choose a reason for hiding this comment

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

Well we can't guarantee that behavior ALWAYS

If the wallet announces itself before the library is able to send wallet_prompt message then it can't evaluate the chains

But if the wallet does receive the wallet_prompt and chains field is specified then it would make sense to not announce itself

Copy link

@kewde kewde Jul 2, 2024

Choose a reason for hiding this comment

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

Should we clear that up by putting it in the specification?

Copy link
Contributor

@adonesky1 adonesky1 Jul 16, 2024

Choose a reason for hiding this comment

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

Would networks be a more generic and flexible term here?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure networks would be helpful since everything is a network when we are talking about the internet

Here we are referring to Blockchain Networks defined by CAIP-2 identifiers

Copy link
Collaborator

Choose a reason for hiding this comment

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

see next comment

Choose a reason for hiding this comment

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

in caip-25 this is now called scopes

Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
chains?: string[]; // compatible with CAIP-2
scopes?: string[]; // compatible with CAIP-2

good catch, i think it's chains in pedro's prod implementation 😅

authName?: string; // compatible with CAIP-275
}

// for "wallet_announce" method
interface WalletAnnounceRequestParams {
uuid: string;
name: string;
icon: string;
Copy link

@kewde kewde Jul 2, 2024

Choose a reason for hiding this comment

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

Can we specify the allowed formats and URI?

export type WalletIcon = `data:image/${'svg+xml' | 'webp' | 'png' | 'gif'};base64,${string}`;

Is what wallet standard recommends, I think the data URIs should be the mandatory format.

Do we want to allow or specifically forbid remote images?

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually yes... that is missing here!

We definitely want to forbid remote images

rdns: string;
scopes?: AuthorizationScopes;
}
```

Whenever a new Wallet Provider is discovered the Blockchain Library would index them in order for the Decentralized Application to display them and prompt the user for selecting their wallet of choice for this connection.

The parameters `name` and `icon` are used to display to the user to be easily recognizable while the `rdns` and `uuid` are only used internally for de-duping while they must always be unique, the `rdns` will always be the same but `uuid` is ephemeral per browser session.

The only optional parameter is `scps` which is defined by CAIP-217 authorization specs that enables early discoverability and filtering of wallets based on RPC methods, notifications, documents and endpoints but also optional discovery of supported chains and even accounts.

Choose a reason for hiding this comment

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

Nit: I think this should be scopes

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed 👍

pedrouid marked this conversation as resolved.
Show resolved Hide resolved

```typescript
// Defined by CAIP-217
interface AuthorizationScopes {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to freeze these in some way to prevent privilege escalation attacks? E.g. it seems like we'd want this to be set and enforced wallet side and to not allow the site or other extensions to further escalate the authorization permissions defined here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes but at the same time... is this something that should be defined on the CAIP-282 for the RPC spec or should it dependent on each transport spec such as CAIP-294, CAIP-295 or CAIP-296

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, I'm not familiar with the delineation between the two or how we're splitting them. I hadn't caught those details when reviewing this. Do we expect to ever have a transport method that doesn't rely on browser JS ever to communicate between a page? If not, then it seems like a common point shared between the various transport methods would be useful and reinforced in the specs as well.

[scopeString: string]: {
scopes?: string[];
methods: string[];
notifications: string[];
accounts?: string[];
rpcDocuments?: string[];
rpcEndpoints?: string[];
};
}
```

#### UUIDs

The generation of UUIDs is crucial for this messaging interface to work seamlessly for the users.
Copy link

@kewde kewde Jul 2, 2024

Choose a reason for hiding this comment

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

Can we explain why are uuid's crucial?

Copy link
Member Author

Choose a reason for hiding this comment

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

UUID is local and ephemeral

RDNS is global and permanent

The two identifiers together allow wallets to be identifiable but also de-duplicated if necessary

Either one by itself would not meet those requirements


A Wallet Provider MUST always generate UUIDs distinctly for each web page loaded, and they must not be re-used without a session being established between the application and the wallet with the user's consent.

A UUID can be re-used as a `sessionId` if and only if the [CAIP-25][caip-25] procedure has been prompted to the user and the user has approved its permissions to allow the application to make future signing requests.

Once established, the UUID is used as `sessionId` for the [CAIP-27][caip-27] payloads, which can verify that incoming messages are being routed through the appropriate channels.
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this might open the door to steal a UUID as an object capability to privilege escalate a page by using an incorrect UUID on a different page so that the new page can have the privileges of the UUID of the old page. It's hard to tell based on the spec, but is likely something we should be paying attention to in implementations so should have some form of wording for it on the spec if my understanding isn't off here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually there have been discussions on the RPC working group to make this sessionId optional since it can be fixed for each wallet

Plus it's not necessarily required for all transports

Copy link
Contributor

Choose a reason for hiding this comment

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

When I wrote this I was thinking more along the context of WalletAnnoucementRequestParams.UUID property. I'm not following why a sessionId would be fixed either so I'm likely missing some context here.


## Rationale

Browser wallets differentiate themselves because they can be installed by users without the application developer requiring any further integration. Therefore, we optimize for a messaging interface that leverages the two-way communication available to browser wallets to make themselves discoverable, and negotiate a set of parameters that enable not only easy human readability with a clear name and icon but also machine-readability using strong identifiers with uuids and rdns.

The choice for using `window.postMessage` is motivated by expanding the range of Wallet Providers it can support, including browser extensions that can alternatively use `window.dispatchEvent` but instead it would also cover Inline Frames, Service Workers, Shared Workers, and more.

The use of UUID for message routing is important because while RDNS is useful for identifying the Wallet Provider, it causes issues when it comes to the session management of different webpages connected to the same Wallet Provider or even managing stale sessions, which can be out-of-sync. Since UUID generation is derived dynamically on page load, Wallet Providers can track these sessions more granularly rather than making assumptions around the webpage URL and RDNS relationship.

The existing standards around wallet session creation (CAIP-25) are fundamental to this experience because they create clear intents for a wallet to "connect" with a webpage url after it's been discovered. This standard does not enforce either one but strongly recommends these standards as the preferred interface for connecting or authenticating a wallet.

Finally the use of CAIP-27 leverages the work above to properly target signing requests that are intended to be prompt to wallet users which will include a `sessionId` and `chainId` in parallel with the pre-established sessions using either CAIP-25.

## Test Cases

Here are some illustrative examples for both JSON-RPC request params:

```typescript
// Example for wallet_prompt
{
id: 1,
jsonrpc: "2.0"
method: "wallet_prompt",
params: {
chains: ["chain:777", "chain:888", "chain:999"] // optional
// if the Blockchain Library supports CAIP-275 then it can include a name
authName: "johndoe.chain", // optional
}
}


// Example for wallet_prompt

Choose a reason for hiding this comment

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

Nit: I think this should be Example for wallet_announce

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch... fixed

pedrouid marked this conversation as resolved.
Show resolved Hide resolved
{
id: 2,
jsonrpc: "2.0"
method: "wallet_announce",
params: {
uuid: "350670db-19fa-4704-a166-e52e178b59d2",
name: "Example Wallet",
icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",
rdns: "com.example.wallet",
}
}
```

## Security Considerations

Regarding security considerations it's important to consider that the WalletData can be imitated and/or manipulated by cross-site scripting and additionally we must consider the following:

### Wallet Imitation and Manipulation

Application developers are expected to actively detect for misbehavior of properties or functions being modified in order to tamper with or modify other wallets. One way this can be easily achieved is to look for when the uuid property within two WalletData objects match. Applications and Libraries are expected to consider other potential methods that the WalletData objects are being tampered with and consider additional mitigation techniques to prevent this as well in order to protect the user.

### Prevent SVG Javascript Execution

The use of SVG images introduces a cross-site scripting risk as they can include JavaScript code. This JavaScript executes within the context of the page and can modify the page or the contents of the page. So, when considering the experience of rendering the icons, dapps need to take into consideration how they’ll approach handling these concerns in order to prevent an image from being used as an obfuscation technique to hide malicious modifications to the page or to other wallets.

## Privacy Considerations

Any form of wallet discoverability must alwasys take in consideration wallet fingerprinting that can happen by malicious webpages or extensions that attempt to capture user information. Wallet Providers can abstain from publishing "Announce" messages on every page load and wait for incoming "Prompt" messages. Yet this opens the possibility for race conditions where Wallet Providers could be initialized after the "Prompt" message was published and therefore be undiscoverable. It is recommended that Wallet Providers offer this more "private connect" feature that users only enable optionally, rather than set by default.

Choose a reason for hiding this comment

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

Typo: alwasys -> always
Maybe also "always take into consideration"?

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed 👍

pedrouid marked this conversation as resolved.
Show resolved Hide resolved

## Backwards Compatibility

It's important to note that existing blockchain ecosystems already have standards that overlap with the scope of this standard and backwards-compatibility must be considered for a smooth adoption by both wallet and application developers.

For the EIP155 (Ethereum) ecosystem there are already interfaces for the discoverability of browser wallets through either legacy `window.ethereum` or [EIP-6963][eip-6963] events. These existing mechanisms should be supported in parallel without conflict with this new discovery interface.

Similarly the Solana and BIP122 (Bitcoin) ecosystems have used similar patterns around `window.solana` and `window.bitcoin` respectively plus the wallet-standard events. Yet these can also be supported in parallel without conflict with this new discovery interface.

The WalletData exposed in this messaging interface is also compatible with EIP-6963 and wallet-standard interfaces therefore Wallet Providers can re-use the same identifiers and assets already being used in these existing integrations.

## Links

- [EIP-6963][eip-6963] - Multi Injected Provider Discovery
- [CAIP-27][caip-27] - Blockchain ID Specification
- [CAIP-25][caip-25] - Blockchain ID Specification
- [CAIP-217][caip-217] - Provider Authorization Scopes
- [CAIP-275][caip-275] - Domain Wallet Authentication

[eip-6963]: https://eips.ethereum.org/EIPS/eip-6963
[caip-27]: https://chainagnostic.org/CAIPs/caip-27
[caip-25]: https://chainagnostic.org/CAIPs/caip-25
[caip-217]: https://chainagnostic.org/CAIPs/caip-217
[caip-275]: https://chainagnostic.org/CAIPs/caip-275

## Copyright

Copyright and related rights waived via [CC0](../LICENSE).
Loading