-
Notifications
You must be signed in to change notification settings - Fork 15
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
SIP-26: Non-EVM protocol support #147
Changes from all commits
df817e7
df59210
febeb1e
7709ea8
48b95a3
ed17dd3
da3182a
1a782b5
3848c61
d514496
33194a3
0c9bb3f
b4f6618
ea35e35
5260fba
9696ca7
cab089f
b81138d
7a99884
ddd9c7d
a0c782c
72fb0c2
739f165
f59f3cc
7b35ebc
8a0171a
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,197 @@ | ||
--- | ||
sip: 26 | ||
title: Non-EVM protocol support | ||
status: Draft | ||
author: Daniel Rocha (@danroc), Frederik Bolding (@FrederikBolding), Alex Donesky (@adonesky1) | ||
created: 2024-08-28 | ||
--- | ||
|
||
## Abstract | ||
|
||
This SIP presents an architecture to enable Snaps to expose blockchain-specific | ||
methods to dapps, extending MetaMask's functionality to support a multichain | ||
ecosystem. | ||
|
||
## Motivation | ||
|
||
Currently, MetaMask is limited to EVM-compatible networks. This proposal aims | ||
to empower developers, both first- and third-party, to use Snaps to add native | ||
support for non-EVM-compatible chains within MetaMask. | ||
|
||
## Specification | ||
|
||
> Formal specifications are written in TypeScript. | ||
|
||
### Language | ||
|
||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", | ||
"SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" written | ||
in uppercase in this document are to be interpreted as described in [RFC | ||
2119](https://www.ietf.org/rfc/rfc2119.txt). | ||
|
||
### High-Level architecture | ||
|
||
The diagram below represents a high-level architecture of how the RPC Router | ||
integrates inside MetaMask to allow Snaps to expose protocol methods to dapps | ||
and the MetaMask clients. | ||
|
||
![High-level architecture](../assets/sip-26/components-diagram.png) | ||
|
||
- **Account Snaps**: Snaps that implement the [Keyring API][keyring-api] and are responsible | ||
for signing requests and managing accounts. | ||
|
||
- **Protocol Snaps**: Snaps that implement protocol methods that do not require | ||
an account to be executed. | ||
|
||
- **RPC Router**: Native component that forwards RPC requests to the | ||
appropriate Protocol Snap or Account Snap. | ||
|
||
- **Keyring Controller**: Native component responsible for forwarding signing | ||
requests to the appropriate keyring implementation. | ||
|
||
- **Accounts Controller**: Native component responsible for managing accounts | ||
inside MetaMask. It stores all non-sensitive account information. | ||
|
||
- **Snaps Keyring**: Native component that acts as a bridge between the | ||
Keyring Controller and the Account Snaps. | ||
|
||
### Components | ||
|
||
Here is a brief description of the components involved in this architecture | ||
which will require to be implemented or modified. | ||
|
||
#### RPC Router | ||
|
||
The RPC Router will be a new native component responsible for routing JSON-RPC | ||
requests to the appropriate Snap or keyring. | ||
|
||
To route a request, the RPC Router MUST extract the method name and [CAIP-2 chainId][caip-2] | ||
from the request object. It then determines whether the method is supported by | ||
a Protocol Snap or an Account Snap, with Account Snaps taking precedence over | ||
Protocol Snaps. | ||
|
||
If the method is supported by an Account Snap, the RPC Router forwards the | ||
request to the Keyring Controller; otherwise, it forwards the request to the | ||
appropriate Protocol Snap. | ||
|
||
#### Snaps Keyring | ||
|
||
The Snaps Keyring is an existing native component that exposes the | ||
[snap_manageAccounts][snap-manage-accs] method, allowing Account Snaps to | ||
register, remove, and update accounts. | ||
|
||
For example, this code can be used by an Account Snap to register a new account | ||
with the Account Router: | ||
|
||
```typescript | ||
// This will notify the Account Router that a new account was created, and the | ||
// Account Router will register this account as available for signing requests | ||
// using the `eth_signTypedData_v4` method. | ||
await snap.request({ | ||
method: "snap_manageAccounts", | ||
params: { | ||
method: "notify:accountCreated", | ||
params: { | ||
account: { | ||
id: "74bb3393-f267-48ee-855a-2ba575291ab0", | ||
type: "eip155:eoa", | ||
address: "0x1234567890123456789012345678901234567890", | ||
methods: ["eth_signTypedData_v4"], | ||
Comment on lines
+97
to
+99
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. [nit] since this SIP is for non-evm snaps should we provide a non-evm example here? 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. Also I'm still wondering how we plan to standardize non-evm account types. Currently our documentation only appears to describe 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. I have been requesting this as well, we need a more generic type that allows any protocol. IIRC @danroc and team are thinking about how to do that. |
||
options: {}, | ||
}, | ||
}, | ||
}, | ||
}); | ||
``` | ||
|
||
Similar events are available to notify about the removal and update of | ||
accounts: `notify:accountRemoved` and `notify:accountUpdated`. | ||
|
||
Additionally, the Snaps Keyring expects the Account Snap to implement the | ||
Keyring API so it can forward signing requests to it through the | ||
[`keyring_submitRequest`][submit-request] method. | ||
|
||
#### Account Snaps | ||
|
||
As part of the Keyring API, non-EVM Account Snaps MUST also implement support | ||
for the `keyring_resolveAccountAddress` RPC method defined below. It is used | ||
by the RPC Router to extract the address of the account that should handle | ||
the signing request from the request object. | ||
|
||
```typescript | ||
type ResolveAccountAddressRequest = { | ||
method: "keyring_resolveAccountAddress"; | ||
params: { | ||
scope: CaipChainId; | ||
request: JsonRpcRequest; | ||
}; | ||
}; | ||
``` | ||
`scope` - The [CAIP-2][caip-2] chainId the request is targeting | ||
|
||
`request` - A `JsonRpcRequest` containing strictly JSON-serializable values. | ||
FrederikBolding marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
FrederikBolding marked this conversation as resolved.
Show resolved
Hide resolved
|
||
The implementation MUST return a value of the type `{ address: string }` or `null`. | ||
|
||
#### Protocol Snaps | ||
|
||
Protocol Snaps implement and expose methods that do not require an account to | ||
execute and MUST list their supported methods and notifications in their manifest file: | ||
|
||
```json5 | ||
"initialPermissions": { | ||
"endowment:protocol": { | ||
"scopes": { | ||
"<caip2_chainId>": { | ||
"methods": [ | ||
// List of supported methods | ||
], | ||
"notifications": [ | ||
// List of supported notifications | ||
] | ||
} | ||
} | ||
} | ||
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. same as below, should resemble caip-25 permission: https://github.com/MetaMask/SIPs/pull/147/files#r1777172390 |
||
} | ||
``` | ||
|
||
Additionally protocol Snaps MUST implement the `onProtocolRequest` handler: | ||
|
||
```typescript | ||
import { OnProtocolRequestHandler } from "@metamask/snap-sdk"; | ||
|
||
export const onProtocolRequest: OnProtocolRequestHandler = async ({ | ||
origin, | ||
scope, | ||
request, | ||
}) => { | ||
// Return protocol responses | ||
}; | ||
``` | ||
|
||
The interface for an `onProtocolRequest` handler function’s arguments is: | ||
|
||
```typescript | ||
interface OnProtocolRequestArguments { | ||
origin: string; | ||
scope: CaipChainId; | ||
request: JsonRpcRequest; | ||
} | ||
``` | ||
|
||
`origin` - The origin making the protocol request (i.e. a dapp). | ||
|
||
`scope` - The [CAIP-2][caip-2] chainId the request is targeting. | ||
|
||
`request` - A `JsonRpcRequest` containing strictly JSON-serializable values. | ||
|
||
Any JSON-serializable value is allowed as the return value for `onProtocolRequest`. | ||
|
||
## Copyright | ||
|
||
Copyright and related rights waived via [CC0](../LICENSE). | ||
|
||
[keyring-api]: https://github.com/MetaMask/accounts/tree/main/packages/keyring-api | ||
[snap-manage-accs]: https://docs.metamask.io/snaps/reference/snaps-api/#snap_manageaccounts | ||
[submit-request]: https://docs.metamask.io/snaps/reference/keyring-api/account-management/#keyring_submitrequest | ||
[caip-2]: https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md |
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.
Is it confusing to separate
keyring
from Snap here since all the keyrings we route to are Snap keyrings?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 dunno this isn't a big deal and maybe its better as is
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.
Personally I think this is fine as-is since we don't wanna route directly to keyring Snaps, but to the native keyring controlling them. It is a minor detail though