@@ -19,21 +19,84 @@ const WEBSOCKET_URL = 'ws://localhost:8545';
1919 *
2020 * @param url - The URL to fetch the data from. This function assumes that the
2121 * provided URL is a JSON document.
22- * @returns There response as JSON.
22+ * @returns The response as JSON.
2323 * @throws If the provided URL is not a JSON document.
2424 */
2525async function getJson ( url : string ) {
2626 const response = await fetch ( url ) ;
2727 return await response . json ( ) ;
2828}
2929
30+ /**
31+ * Open a WebSocket connection to a local Ethereum node and subscribe to
32+ * block updates.
33+ *
34+ * @returns Null.
35+ * @throws If the WebSocket connection fails to open.
36+ */
37+ async function subscribe ( ) {
38+ const id = await snap . request ( {
39+ method : 'snap_openWebSocket' ,
40+ params : {
41+ url : WEBSOCKET_URL ,
42+ } ,
43+ } ) ;
44+
45+ const message = JSON . stringify ( {
46+ jsonrpc : '2.0' ,
47+ id : 1 ,
48+ method : 'eth_subscribe' ,
49+ params : [ 'newHeads' ] ,
50+ } ) ;
51+
52+ return snap . request ( {
53+ method : 'snap_sendWebSocketMessage' ,
54+ params : { id, message } ,
55+ } ) ;
56+ }
57+
58+ /**
59+ * Close a WebSocket connection to a local Ethereum node, if it exists.
60+ *
61+ * @returns Null.
62+ */
63+ async function unsubscribe ( ) {
64+ const sockets = await snap . request ( {
65+ method : 'snap_getWebSockets' ,
66+ } ) ;
67+
68+ if ( sockets . length === 0 ) {
69+ return null ;
70+ }
71+
72+ await snap . request ( {
73+ method : 'snap_setState' ,
74+ params : {
75+ key : 'blockNumber' ,
76+ value : null ,
77+ encrypted : false ,
78+ } ,
79+ } ) ;
80+
81+ const socket = sockets [ 0 ] ;
82+ return snap . request ( {
83+ method : 'snap_closeWebSocket' ,
84+ params : { id : socket . id } ,
85+ } ) ;
86+ }
87+
3088/**
3189 * Handle incoming JSON-RPC requests from the dapp, sent through the
32- * `wallet_invokeSnap` method. This handler handles a single method :
90+ * `wallet_invokeSnap` method. This handler handles four methods :
3391 *
3492 * - `fetch`: Fetch a JSON document from the provided URL. This demonstrates
3593 * that a snap can make network requests through the `fetch` function. Note that
3694 * the `endowment:network-access` permission must be enabled for this to work.
95+ * - `startWebSocket`: Open a WebSocket connection to a local Ethereum node
96+ * and subscribe to block updates.
97+ * - `closeWebSocket`: Close a WebSocket connection, if one exists.
98+ * - `getBlockNumber`: Get the latest block number from the WebSocket connection,
99+ * stored in the Snap state.
37100 *
38101 * @param params - The request parameters.
39102 * @param params.request - The JSON-RPC request object.
@@ -50,42 +113,11 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ request }) => {
50113 return await getJson ( params . url ) ;
51114 }
52115
53- case 'startWebSocket' : {
54- const id = await snap . request ( {
55- method : 'snap_openWebSocket' ,
56- params : {
57- url : WEBSOCKET_URL ,
58- } ,
59- } ) ;
60-
61- const message = JSON . stringify ( {
62- jsonrpc : '2.0' ,
63- id : 1 ,
64- method : 'eth_subscribe' ,
65- params : [ 'newHeads' ] ,
66- } ) ;
67-
68- return snap . request ( {
69- method : 'snap_sendWebSocketMessage' ,
70- params : { id, message } ,
71- } ) ;
72- }
73-
74- case 'stopWebSocket' : {
75- const sockets = await snap . request ( {
76- method : 'snap_getWebSockets' ,
77- } ) ;
116+ case 'startWebSocket' :
117+ return subscribe ( ) ;
78118
79- if ( sockets . length === 0 ) {
80- return null ;
81- }
82-
83- const socket = sockets [ 0 ] ;
84- return snap . request ( {
85- method : 'snap_closeWebSocket' ,
86- params : { id : socket . id } ,
87- } ) ;
88- }
119+ case 'stopWebSocket' :
120+ return unsubscribe ( ) ;
89121
90122 case 'getBlockNumber' : {
91123 return snap . request ( {
0 commit comments