-
Notifications
You must be signed in to change notification settings - Fork 17
Update proposal for SIP-20 to enable two-way communication between Snap and WebSockets #149
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
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 |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| --- | ||
| sip: 20 | ||
| title: External data entry point | ||
| title: Advanced external communication and events | ||
| status: Draft | ||
| author: David Drazic (@david0xd) | ||
| created: 2023-12-15 | ||
|
|
@@ -12,11 +12,11 @@ This SIP proposes a new permission that enables Snaps to receive data from exter | |
|
|
||
| In the initial version, this SIP proposes support for WebSockets, but it can be extended to support other data sources like blockchain events in the future. | ||
| The Snap can specify the external data source in the Snap manifest. The client then connects to the external data source and sends the data to the Snap. | ||
| The Snap can then do whatever it wants with the data. This initial version only supports one-way communication from the external source to the Snap. The Snap can't send any data back to the external source. | ||
| The Snap can then do whatever it wants with the data, and can send data back to the external source if supported (e.g., a WebSocket connection). | ||
|
|
||
| ## Motivation | ||
|
|
||
| Snaps are currently limited in their ability to receive data from external sources; they have to rely on user actions or cron jobs to fetch data, so they can't react to events in real time. Snaps also cannot use WebSocket connections to receive data from external sources, and are limited to HTTP requests. | ||
| Snaps are currently limited in their ability to communicate with external sources; they have to rely on user actions or cron jobs to fetch data, so they can't react to events in real time. Snaps also cannot use WebSocket connections for bidirectional communication, and are limited to HTTP requests. | ||
|
|
||
| ## Specification | ||
|
|
||
|
|
@@ -111,6 +111,33 @@ The caveats MUST NOT have duplicate objects with the same `url` properties. | |
|
|
||
| The `url` MUST start with `wss://` which is a protocol indicator for secure WebSocket connection. | ||
|
|
||
| ### RPC Methods | ||
|
|
||
| This SIP introduces a new RPC method for sending data to the external connections (if supported). | ||
|
|
||
| #### snap_sendData | ||
|
|
||
| Snap can use `snap_sendData` RPC method to send data specified within request params. | ||
| The proposed RPC method `snap_sendData` SHOULD be a restricted RPC method. The RPC method SHOULD only be available to Snaps. | ||
| Snap MUST specify destination which is URL identifier of an external connection (e.g. websocket). Destination MUST be exact match of some of the URLs defined in manifest's permission caveats within `endowment:external-data`. | ||
|
Member
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. In theory the same URL can be used twice, in which case it would be ambiguous which one to use.
Contributor
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. Should we disallow that in our validation steps or you think we need to design it in a different way? 🤔 |
||
|
|
||
| The `snap_sendData` JSON-RPC method takes an object as parameters, which has `data` and `destination` properties. | ||
|
|
||
| Example: | ||
| ```json | ||
| { | ||
| "method": "snap_sendData", | ||
| "params": { | ||
| "data": { | ||
| "foo": "bar" | ||
| }, | ||
| "destination": "wss://example.com/text/endpoint" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| The method returns a `boolean`, `true` in case of successful delivery of a message to the WebSocket. If delivery was unsuccessful, error is thrown. | ||
|
|
||
| ### Snap implementation | ||
|
|
||
| This SIP introduces a new `onExternalData` function export that MAY be implemented by the Snap. The function is called every time the WebSocket client receives some data. The function SHOULD accept an object parameter that MUST have `data`, `type` and `source` properties. | ||
|
|
@@ -123,7 +150,7 @@ The specification of types of `onExternalData` and its parameters: | |
|
|
||
| ```typescript | ||
| /** | ||
| * A text message received from a WebSocket. | ||
| * WebSocket text message. | ||
| * | ||
| * @property type - The type of the message. | ||
| * @property message - The message as a string. | ||
|
|
@@ -134,7 +161,7 @@ type WebSocketTextMessage = { | |
| }; | ||
|
|
||
| /** | ||
| * A binary message received from a WebSocket. | ||
| * WebSocket binary message. | ||
| * | ||
| * @property type - The type of the message. | ||
| * @property message - The message as an ArrayBuffer. | ||
|
|
@@ -144,6 +171,21 @@ type WebSocketBinaryMessage = { | |
| message: ArrayBuffer; | ||
| }; | ||
|
|
||
| /** | ||
| * Incoming Websocket message. | ||
| * | ||
| */ | ||
| type WebSocketIncomingMessage = WebSocketTextMessage | WebSocketBinaryMessage; | ||
|
|
||
| /** | ||
| * Outgoing Websocket message. | ||
| * | ||
| * @property destination - The destination web socket URL as a string. | ||
| */ | ||
| type WebSocketOutgoingMessage = WebSocketIncomingMessage & { | ||
| destination: string; | ||
| }; | ||
|
|
||
| /** | ||
| * A message received from a WebSocket. | ||
| * | ||
|
|
@@ -153,7 +195,7 @@ type WebSocketBinaryMessage = { | |
| */ | ||
| type WebSocketData = { | ||
| type: 'websocket'; | ||
| data: WebSocketTextMessage | WebSocketBinaryMessage; | ||
| message: WebSocketIncomingMessage; | ||
| }; | ||
|
|
||
| /** | ||
|
|
@@ -177,12 +219,21 @@ type OnExternalDataHandler = (args: OnExternalDataHandlerArgs) => Promise<void>; | |
| import { OnExternalDataHandler } from '@metamask/snaps-types'; | ||
| import { assert } from '@metamask/utils'; | ||
|
|
||
| export const onExternalData: OnExternalDataHandler = ({ type, data, source }) => { | ||
| export const onExternalData: OnExternalDataHandler = async ({ type, data, source }) => { | ||
| assert(type === 'websocket'); // `data` is inferred as `WebSocketData`. | ||
| assert(data.type === 'text'); // `message` is inferred as `string`. | ||
|
|
||
| // Now the Snap can do whatever is needed with the message. | ||
| const json = JSON.parse(data.message); | ||
|
|
||
| // Send message back | ||
| await snap.request({ | ||
| method: 'snap_sendData', | ||
| params: { | ||
| type: 'text', | ||
| message: 'Message received successfully', | ||
| destination: 'wss://example.com/text/endpoint', | ||
| }, | ||
| }); | ||
| }; | ||
| ``` | ||
|
|
||
|
|
||
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.
Feels like the name is not reflecting what this SIP really is anymore? Looking for advice to change it if possible. Updated with one of the ideas I had.