@aztec/wallet-sdk 0.0.1-commit.fce3e4f → 0.0.1-commit.fffb133c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +228 -331
- package/dest/base-wallet/base_wallet.d.ts +23 -13
- package/dest/base-wallet/base_wallet.d.ts.map +1 -1
- package/dest/base-wallet/base_wallet.js +59 -24
- package/dest/crypto.d.ts +192 -0
- package/dest/crypto.d.ts.map +1 -0
- package/dest/crypto.js +394 -0
- package/dest/emoji_alphabet.d.ts +35 -0
- package/dest/emoji_alphabet.d.ts.map +1 -0
- package/dest/emoji_alphabet.js +299 -0
- package/dest/extension/handlers/background_connection_handler.d.ts +158 -0
- package/dest/extension/handlers/background_connection_handler.d.ts.map +1 -0
- package/dest/extension/handlers/background_connection_handler.js +258 -0
- package/dest/extension/handlers/content_script_connection_handler.d.ts +56 -0
- package/dest/extension/handlers/content_script_connection_handler.d.ts.map +1 -0
- package/dest/extension/handlers/content_script_connection_handler.js +174 -0
- package/dest/extension/handlers/index.d.ts +12 -0
- package/dest/extension/handlers/index.d.ts.map +1 -0
- package/dest/extension/handlers/index.js +10 -0
- package/dest/extension/handlers/internal_message_types.d.ts +63 -0
- package/dest/extension/handlers/internal_message_types.d.ts.map +1 -0
- package/dest/extension/handlers/internal_message_types.js +22 -0
- package/dest/extension/provider/extension_provider.d.ts +107 -0
- package/dest/extension/provider/extension_provider.d.ts.map +1 -0
- package/dest/extension/provider/extension_provider.js +160 -0
- package/dest/extension/provider/extension_wallet.d.ts +131 -0
- package/dest/extension/provider/extension_wallet.d.ts.map +1 -0
- package/dest/extension/provider/extension_wallet.js +271 -0
- package/dest/extension/provider/index.d.ts +3 -0
- package/dest/extension/provider/index.d.ts.map +1 -0
- package/dest/manager/index.d.ts +2 -7
- package/dest/manager/index.d.ts.map +1 -1
- package/dest/manager/index.js +0 -4
- package/dest/manager/types.d.ts +108 -5
- package/dest/manager/types.d.ts.map +1 -1
- package/dest/manager/types.js +17 -1
- package/dest/manager/wallet_manager.d.ts +50 -7
- package/dest/manager/wallet_manager.d.ts.map +1 -1
- package/dest/manager/wallet_manager.js +178 -29
- package/dest/types.d.ts +123 -0
- package/dest/types.d.ts.map +1 -0
- package/dest/types.js +11 -0
- package/package.json +15 -12
- package/src/base-wallet/base_wallet.ts +82 -41
- package/src/crypto.ts +499 -0
- package/src/emoji_alphabet.ts +317 -0
- package/src/extension/handlers/background_connection_handler.ts +423 -0
- package/src/extension/handlers/content_script_connection_handler.ts +246 -0
- package/src/extension/handlers/index.ts +25 -0
- package/src/extension/handlers/internal_message_types.ts +69 -0
- package/src/extension/provider/extension_provider.ts +233 -0
- package/src/extension/provider/extension_wallet.ts +321 -0
- package/src/extension/provider/index.ts +7 -0
- package/src/manager/index.ts +3 -15
- package/src/manager/types.ts +112 -4
- package/src/manager/wallet_manager.ts +204 -31
- package/src/types.ts +132 -0
- package/dest/providers/extension/extension_provider.d.ts +0 -17
- package/dest/providers/extension/extension_provider.d.ts.map +0 -1
- package/dest/providers/extension/extension_provider.js +0 -56
- package/dest/providers/extension/extension_wallet.d.ts +0 -23
- package/dest/providers/extension/extension_wallet.d.ts.map +0 -1
- package/dest/providers/extension/extension_wallet.js +0 -96
- package/dest/providers/extension/index.d.ts +0 -4
- package/dest/providers/extension/index.d.ts.map +0 -1
- package/dest/providers/types.d.ts +0 -67
- package/dest/providers/types.d.ts.map +0 -1
- package/dest/providers/types.js +0 -3
- package/src/providers/extension/extension_provider.ts +0 -72
- package/src/providers/extension/extension_wallet.ts +0 -124
- package/src/providers/extension/index.ts +0 -3
- package/src/providers/types.ts +0 -71
- /package/dest/{providers/extension → extension/provider}/index.js +0 -0
package/README.md
CHANGED
|
@@ -4,421 +4,318 @@ This guide explains how to integrate your wallet with the Aztec Wallet SDK, enab
|
|
|
4
4
|
|
|
5
5
|
## Available Types
|
|
6
6
|
|
|
7
|
-
All types and utilities needed for wallet integration are exported from `@aztec/wallet-sdk/
|
|
7
|
+
All types and utilities needed for wallet integration are exported from `@aztec/wallet-sdk/types`:
|
|
8
8
|
|
|
9
9
|
```typescript
|
|
10
10
|
import type {
|
|
11
|
-
ChainInfo,
|
|
12
11
|
DiscoveryRequest,
|
|
13
12
|
DiscoveryResponse,
|
|
13
|
+
KeyExchangeRequest,
|
|
14
|
+
KeyExchangeResponse,
|
|
14
15
|
WalletInfo,
|
|
15
16
|
WalletMessage,
|
|
16
17
|
WalletResponse,
|
|
17
|
-
} from '@aztec/wallet-sdk/
|
|
18
|
-
import { ChainInfoSchema, WalletSchema, jsonStringify } from '@aztec/wallet-sdk/manager';
|
|
18
|
+
} from '@aztec/wallet-sdk/types';
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
The Wallet SDK uses a **request-based discovery** model:
|
|
24
|
-
|
|
25
|
-
1. **dApp requests wallets** for a specific chain/version via `WalletManager.getAvailableWallets({ chainInfo })`
|
|
26
|
-
2. **SDK broadcasts** a discovery message with chain information
|
|
27
|
-
3. **Your wallet responds** ONLY if it supports that specific network
|
|
28
|
-
4. **dApp receives** only compatible wallets
|
|
29
|
-
5. **dApp calls wallet methods** which your wallet handles and responds to
|
|
30
|
-
|
|
31
|
-
### Transport Mechanisms
|
|
32
|
-
|
|
33
|
-
This guide uses **browser extension wallets** as the primary example, which communicate via `window.postMessage`. However, the same message protocol can be used with other transport mechanisms:
|
|
34
|
-
|
|
35
|
-
- **Extension wallets**: Use `window.postMessage` (examples shown throughout this guide)
|
|
36
|
-
- **Web wallets**: Could use WebSockets, HTTP, or other protocols (see comments in examples for hypothetical WebSocket usage)
|
|
37
|
-
- **Mobile wallets**: Could use deep links, app-to-app communication, or custom protocols
|
|
38
|
-
|
|
39
|
-
The message format remains the same regardless of transport - only the delivery mechanism changes.
|
|
40
|
-
|
|
41
|
-
## Discovery Protocol
|
|
42
|
-
|
|
43
|
-
### 1. Listen for Discovery Requests
|
|
44
|
-
|
|
45
|
-
**Extension wallet example:**
|
|
21
|
+
Cryptographic utilities for secure channel establishment are exported from `@aztec/wallet-sdk/crypto`:
|
|
46
22
|
|
|
47
23
|
```typescript
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// Using WebSocket:
|
|
61
|
-
// websocket.on('message', (message) => {
|
|
62
|
-
// const data = JSON.parse(message);
|
|
63
|
-
// if (data.type === 'aztec-wallet-discovery') {
|
|
64
|
-
// handleDiscovery(data);
|
|
65
|
-
// }
|
|
66
|
-
// });
|
|
24
|
+
import type { EncryptedPayload, ExportedPublicKey } from '@aztec/wallet-sdk/crypto';
|
|
25
|
+
import {
|
|
26
|
+
decrypt,
|
|
27
|
+
deriveSessionKeys,
|
|
28
|
+
encrypt,
|
|
29
|
+
exportPublicKey,
|
|
30
|
+
generateKeyPair,
|
|
31
|
+
hashToEmoji,
|
|
32
|
+
importPublicKey,
|
|
33
|
+
} from '@aztec/wallet-sdk/crypto';
|
|
67
34
|
```
|
|
68
35
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
Discovery messages have this structure:
|
|
36
|
+
**For extension wallets**, pre-built connection handlers are available:
|
|
72
37
|
|
|
73
38
|
```typescript
|
|
74
|
-
{
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
chainId: Fr, // Chain ID
|
|
79
|
-
version: Fr // Protocol version
|
|
80
|
-
}
|
|
81
|
-
}
|
|
39
|
+
import {
|
|
40
|
+
BackgroundConnectionHandler,
|
|
41
|
+
ContentScriptConnectionHandler,
|
|
42
|
+
} from '@aztec/wallet-sdk/extension/handlers';
|
|
82
43
|
```
|
|
83
44
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
Before responding, verify your wallet supports the requested network:
|
|
87
|
-
|
|
88
|
-
```typescript
|
|
89
|
-
import { ChainInfoSchema } from '@aztec/wallet-sdk/manager';
|
|
90
|
-
|
|
91
|
-
function handleDiscovery(message: any) {
|
|
92
|
-
const { requestId, chainInfo } = message;
|
|
93
|
-
|
|
94
|
-
// Parse and validate chain info
|
|
95
|
-
const { chainId, version } = ChainInfoSchema.parse(chainInfo);
|
|
96
|
-
|
|
97
|
-
// Check if your wallet supports this network
|
|
98
|
-
const isSupported = checkNetworkSupport(chainId, version);
|
|
99
|
-
|
|
100
|
-
if (!isSupported) {
|
|
101
|
-
// Do NOT respond if you don't support this network
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Respond if supported
|
|
106
|
-
respondToDiscovery(requestId);
|
|
107
|
-
}
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
### 4. Respond to Discovery
|
|
45
|
+
## Overview
|
|
111
46
|
|
|
112
|
-
|
|
47
|
+
The Wallet SDK uses a **two-phase connection model** with **end-to-end encryption**:
|
|
113
48
|
|
|
114
|
-
|
|
49
|
+
### Phase 1: Discovery
|
|
115
50
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const response = {
|
|
121
|
-
type: 'aztec-wallet-discovery-response',
|
|
122
|
-
requestId,
|
|
123
|
-
walletInfo: {
|
|
124
|
-
id: 'my-aztec-wallet', // Unique wallet identifier
|
|
125
|
-
name: 'My Aztec Wallet', // Display name
|
|
126
|
-
icon: 'https://example.com/icon.png', // Optional icon URL
|
|
127
|
-
version: '1.0.0', // Wallet version
|
|
128
|
-
},
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
// Send as JSON string via window.postMessage
|
|
132
|
-
window.postMessage(jsonStringify(response), '*');
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Using WebSocket:
|
|
136
|
-
// websocket.send(jsonStringify(response));
|
|
137
|
-
```
|
|
51
|
+
1. **dApp broadcasts** a discovery request with chain information (NO public keys)
|
|
52
|
+
2. **Your wallet shows** a pending connection request to the user
|
|
53
|
+
3. **User approves** the connection request
|
|
54
|
+
4. **Your wallet responds** with basic wallet info and a MessagePort
|
|
138
55
|
|
|
139
|
-
|
|
56
|
+
### Phase 2: Secure Channel Establishment
|
|
140
57
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
58
|
+
5. **dApp initiates key exchange** by sending its ECDH public key over the MessagePort
|
|
59
|
+
6. **Wallet generates** ephemeral key pair and derives session keys using HKDF
|
|
60
|
+
7. **Both parties compute** the same verification hash independently
|
|
61
|
+
8. **User verifies** the has matches on both sides. A util for conversion to an emoji grid is provided
|
|
62
|
+
9. **User confirms** the connection in the dApp
|
|
63
|
+
10. **All subsequent communication** is encrypted using AES-256-GCM
|
|
145
64
|
|
|
146
|
-
|
|
65
|
+
### Key Security Features
|
|
147
66
|
|
|
148
|
-
|
|
67
|
+
- **User approval required**: Wallet never reveals itself without explicit user consent
|
|
68
|
+
- **Ephemeral keys**: New key pairs generated for each session
|
|
69
|
+
- **Anti-MITM verification**: 3x3 emoji grid (72 bits of security) for visual confirmation
|
|
149
70
|
|
|
150
|
-
|
|
71
|
+
## Architecture for Extension Wallets
|
|
151
72
|
|
|
152
|
-
```typescript
|
|
153
|
-
{
|
|
154
|
-
type: string, // Wallet method name from the Wallet interface
|
|
155
|
-
messageId: string, // UUID for tracking this request
|
|
156
|
-
args: unknown[], // Method arguments
|
|
157
|
-
chainInfo: {
|
|
158
|
-
chainId: Fr, // Same chain that was used in discovery
|
|
159
|
-
version: Fr
|
|
160
|
-
},
|
|
161
|
-
appId: string, // Application identifier
|
|
162
|
-
walletId: string // Your wallet's ID (from discovery response)
|
|
163
|
-
}
|
|
164
73
|
```
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
### Wallet Method Response
|
|
174
|
-
|
|
175
|
-
Your wallet must respond with:
|
|
176
|
-
|
|
177
|
-
```typescript
|
|
178
|
-
{
|
|
179
|
-
messageId: string, // MUST match the request's messageId
|
|
180
|
-
result?: unknown, // Method result (if successful)
|
|
181
|
-
error?: unknown, // Error (if failed)
|
|
182
|
-
walletId: string // Your wallet's ID
|
|
183
|
-
}
|
|
74
|
+
┌─────────────┐ window.postMessage ┌─────────────────┐ browser.runtime ┌──────────────────┐
|
|
75
|
+
│ dApp │◄──(discovery + port)────►│ Content Script │◄────────────────────►│ Background Script│
|
|
76
|
+
│ (web page) │ │ (message relay)│ │ (crypto+state) │
|
|
77
|
+
└─────────────┘ └─────────────────┘ └──────────────────┘
|
|
78
|
+
│ │
|
|
79
|
+
│ MessagePort │
|
|
80
|
+
└──────────(key exchange + encrypted)──────┘
|
|
184
81
|
```
|
|
185
82
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
### 1. Set Up Message Listener
|
|
83
|
+
**Security model:**
|
|
189
84
|
|
|
190
|
-
|
|
85
|
+
- The MessagePort is transferred via `window.postMessage` - other scripts on the page could intercept it
|
|
86
|
+
- **Security comes from encryption**: After key exchange, all communication is AES-256-GCM encrypted
|
|
87
|
+
- Content script never has access to private keys or session secrets
|
|
88
|
+
- All cryptographic operations happen in the background script (service worker)
|
|
89
|
+
- Anti-MITM verification (emoji grid) ensures both parties derived the same keys
|
|
191
90
|
|
|
192
|
-
|
|
193
|
-
window.addEventListener('message', event => {
|
|
194
|
-
if (event.source !== window) {
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
let data;
|
|
199
|
-
try {
|
|
200
|
-
data = JSON.parse(event.data);
|
|
201
|
-
} catch {
|
|
202
|
-
return; // Not a valid JSON message
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Handle discovery
|
|
206
|
-
if (data.type === 'aztec-wallet-discovery') {
|
|
207
|
-
handleDiscovery(data);
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Handle wallet methods
|
|
212
|
-
if (data.messageId && data.type && data.walletId === 'my-aztec-wallet') {
|
|
213
|
-
handleWalletMethod(data);
|
|
214
|
-
}
|
|
215
|
-
});
|
|
91
|
+
## Using Pre-built Connection Handlers
|
|
216
92
|
|
|
217
|
-
|
|
218
|
-
// websocket.on('message', (message) => {
|
|
219
|
-
// const data = JSON.parse(message);
|
|
220
|
-
// if (data.type === 'aztec-wallet-discovery') {
|
|
221
|
-
// handleDiscovery(data);
|
|
222
|
-
// } else if (data.messageId && data.type) {
|
|
223
|
-
// handleWalletMethod(data);
|
|
224
|
-
// }
|
|
225
|
-
// });
|
|
226
|
-
```
|
|
93
|
+
The SDK provides `BackgroundConnectionHandler` and `ContentScriptConnectionHandler` to handle the connection flow. These are the recommended way to build extension wallets.
|
|
227
94
|
|
|
228
|
-
###
|
|
95
|
+
### Background Script Setup
|
|
229
96
|
|
|
230
97
|
```typescript
|
|
231
|
-
import {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
98
|
+
import {
|
|
99
|
+
BackgroundConnectionHandler,
|
|
100
|
+
type BackgroundConnectionConfig,
|
|
101
|
+
type BackgroundConnectionCallbacks,
|
|
102
|
+
type BackgroundTransport,
|
|
103
|
+
} from '@aztec/wallet-sdk/extension/handlers';
|
|
104
|
+
import { hashToEmoji } from '@aztec/wallet-sdk/crypto';
|
|
105
|
+
|
|
106
|
+
// Configuration for your wallet
|
|
107
|
+
const config: BackgroundConnectionConfig = {
|
|
108
|
+
walletId: 'my-aztec-wallet',
|
|
109
|
+
walletName: 'My Aztec Wallet',
|
|
110
|
+
walletVersion: '1.0.0',
|
|
111
|
+
walletIcon: 'https://example.com/icon.png',
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// Transport for browser extension APIs
|
|
115
|
+
const transport: BackgroundTransport = {
|
|
116
|
+
sendToTab: (tabId, message) => browser.tabs.sendMessage(tabId, message),
|
|
117
|
+
addContentListener: (handler) => browser.runtime.onMessage.addListener(handler),
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// Event callbacks (all optional)
|
|
121
|
+
const callbacks: BackgroundConnectionCallbacks = {
|
|
122
|
+
// Called when a new discovery request is received
|
|
123
|
+
onPendingDiscovery: (discovery) => {
|
|
124
|
+
// Show pending connection in wallet UI
|
|
125
|
+
// Check if wallet supports this network (chainId AND version)
|
|
126
|
+
const supported = supportedNetworks.some(
|
|
127
|
+
n => n.chainId === discovery.chainInfo.chainId.toString() &&
|
|
128
|
+
n.version === discovery.chainInfo.version.toString()
|
|
129
|
+
);
|
|
130
|
+
if (supported) {
|
|
131
|
+
// Show the user so they can approve or reject
|
|
246
132
|
}
|
|
133
|
+
},
|
|
247
134
|
|
|
248
|
-
|
|
249
|
-
|
|
135
|
+
// Called when key exchange completes and session is ready
|
|
136
|
+
onSessionEstablished: (session) => {
|
|
137
|
+
// Display verification emojis for user reference
|
|
138
|
+
console.log('Session emojis:', hashToEmoji(session.verificationHash));
|
|
139
|
+
},
|
|
250
140
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
sendError(messageId, walletId, error);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
```
|
|
141
|
+
// Called when a session is terminated
|
|
142
|
+
onSessionTerminated: (requestId) => {
|
|
143
|
+
console.log('Session terminated:', requestId);
|
|
144
|
+
},
|
|
259
145
|
|
|
260
|
-
|
|
146
|
+
// Called when a decrypted wallet message is received
|
|
147
|
+
onWalletMessage: (session, message) => {
|
|
148
|
+
// Forward to your wallet backend
|
|
149
|
+
wallet.postMessage(message);
|
|
150
|
+
},
|
|
151
|
+
};
|
|
261
152
|
|
|
262
|
-
|
|
153
|
+
const handler = new BackgroundConnectionHandler(config, transport, callbacks);
|
|
263
154
|
|
|
264
|
-
|
|
265
|
-
|
|
155
|
+
// Initialize the handler to start listening
|
|
156
|
+
handler.initialize();
|
|
266
157
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
walletId,
|
|
272
|
-
};
|
|
158
|
+
// User approves connection from wallet UI
|
|
159
|
+
function approveConnection(requestId: string) {
|
|
160
|
+
handler.approveDiscovery(requestId);
|
|
161
|
+
}
|
|
273
162
|
|
|
274
|
-
|
|
275
|
-
|
|
163
|
+
// User denies connection
|
|
164
|
+
function denyConnection(requestId: string) {
|
|
165
|
+
handler.rejectDiscovery(requestId);
|
|
276
166
|
}
|
|
277
167
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
error: {
|
|
282
|
-
message: error.message,
|
|
283
|
-
stack: error.stack,
|
|
284
|
-
},
|
|
285
|
-
walletId,
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
window.postMessage(jsonStringify(response), '*');
|
|
168
|
+
// Send response back to dApp
|
|
169
|
+
async function sendWalletResponse(requestId: string, response: WalletResponse) {
|
|
170
|
+
await handler.sendResponse(requestId, response);
|
|
289
171
|
}
|
|
290
172
|
|
|
291
|
-
//
|
|
292
|
-
|
|
173
|
+
// Clean up on tab close/navigate
|
|
174
|
+
browser.tabs.onRemoved.addListener((tabId) => {
|
|
175
|
+
handler.terminateForTab(tabId);
|
|
176
|
+
});
|
|
293
177
|
```
|
|
294
178
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
### Using Zod Schemas
|
|
298
|
-
|
|
299
|
-
Use the provided Zod schemas to parse and validate incoming messages:
|
|
179
|
+
### Content Script Setup
|
|
300
180
|
|
|
301
181
|
```typescript
|
|
302
|
-
import {
|
|
182
|
+
import {
|
|
183
|
+
ContentScriptConnectionHandler,
|
|
184
|
+
type ContentScriptTransport,
|
|
185
|
+
} from '@aztec/wallet-sdk/extension/handlers';
|
|
303
186
|
|
|
304
|
-
|
|
305
|
-
|
|
187
|
+
const transport: ContentScriptTransport = {
|
|
188
|
+
sendToBackground: (message) => browser.runtime.sendMessage(message),
|
|
189
|
+
addBackgroundListener: (handler) => browser.runtime.onMessage.addListener(handler),
|
|
190
|
+
};
|
|
306
191
|
|
|
307
|
-
|
|
308
|
-
const accountsResult = await wallet.getAccounts(...args);
|
|
309
|
-
// The SDK handles schema validation on the client side
|
|
310
|
-
```
|
|
192
|
+
const handler = new ContentScriptConnectionHandler(transport);
|
|
311
193
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
### Error Response Format
|
|
194
|
+
// Start listening for discovery requests and background messages
|
|
195
|
+
handler.start();
|
|
196
|
+
```
|
|
317
197
|
|
|
318
|
-
|
|
198
|
+
## Testing Your Integration (dApp Side)
|
|
319
199
|
|
|
320
|
-
|
|
321
|
-
{
|
|
322
|
-
messageId: string, // Match the request
|
|
323
|
-
error: {
|
|
324
|
-
message: string, // Error message
|
|
325
|
-
code?: string, // Optional error code
|
|
326
|
-
stack?: string // Optional stack trace
|
|
327
|
-
},
|
|
328
|
-
walletId: string
|
|
329
|
-
}
|
|
330
|
-
```
|
|
200
|
+
The `WalletManager` supports two patterns for consuming discovered wallets.
|
|
331
201
|
|
|
332
|
-
###
|
|
202
|
+
### Async Iterator Pattern
|
|
333
203
|
|
|
334
204
|
```typescript
|
|
335
|
-
import {
|
|
205
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
206
|
+
import { WalletManager } from '@aztec/wallet-sdk/manager';
|
|
207
|
+
import { hashToEmoji } from '@aztec/wallet-sdk/crypto';
|
|
336
208
|
|
|
337
|
-
|
|
338
|
-
|
|
209
|
+
const discovery = WalletManager.configure({
|
|
210
|
+
extensions: { enabled: true },
|
|
211
|
+
}).getAvailableWallets({
|
|
212
|
+
chainInfo: {
|
|
213
|
+
chainId: new Fr(31337),
|
|
214
|
+
version: new Fr(1),
|
|
215
|
+
},
|
|
216
|
+
appId: 'my-dapp',
|
|
217
|
+
timeout: 60000,
|
|
218
|
+
});
|
|
339
219
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
220
|
+
// Iterate over discovered wallets as they're approved
|
|
221
|
+
for await (const provider of discovery.wallets) {
|
|
222
|
+
console.log(`Found: ${provider.name}`);
|
|
343
223
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
throw new Error('Network not supported by wallet');
|
|
347
|
-
}
|
|
224
|
+
// Establish secure channel (key exchange)
|
|
225
|
+
const pending = await provider.establishSecureChannel('my-dapp');
|
|
348
226
|
|
|
349
|
-
|
|
350
|
-
|
|
227
|
+
// Display verification emojis to user
|
|
228
|
+
const emojis = hashToEmoji(pending.verificationHash);
|
|
229
|
+
console.log('Verify this matches your wallet:', emojis);
|
|
351
230
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
throw new Error(`Unknown wallet method: ${type}`);
|
|
355
|
-
}
|
|
231
|
+
// User confirms emojis match
|
|
232
|
+
const wallet = await pending.confirm();
|
|
356
233
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
} catch (error) {
|
|
361
|
-
sendError(messageId, walletId, error);
|
|
362
|
-
}
|
|
234
|
+
// All calls are now encrypted
|
|
235
|
+
const accounts = await wallet.getAccounts();
|
|
236
|
+
console.log('Accounts:', accounts);
|
|
363
237
|
}
|
|
364
|
-
```
|
|
365
238
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
If a user rejects an action:
|
|
369
|
-
|
|
370
|
-
```typescript
|
|
371
|
-
{
|
|
372
|
-
messageId: 'abc-123',
|
|
373
|
-
error: {
|
|
374
|
-
message: 'User rejected the request',
|
|
375
|
-
code: 'USER_REJECTED'
|
|
376
|
-
},
|
|
377
|
-
walletId: 'my-wallet'
|
|
378
|
-
}
|
|
239
|
+
// Cancel discovery when done or on cleanup
|
|
240
|
+
discovery.cancel();
|
|
379
241
|
```
|
|
380
242
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
### WalletManager
|
|
384
|
-
|
|
385
|
-
In a dApp using the Wallet SDK:
|
|
243
|
+
### Callback Pattern
|
|
386
244
|
|
|
387
245
|
```typescript
|
|
388
246
|
import { Fr } from '@aztec/foundation/fields';
|
|
389
|
-
import { WalletManager } from '@aztec/wallet-sdk/manager';
|
|
247
|
+
import { WalletManager, type WalletProvider } from '@aztec/wallet-sdk/manager';
|
|
248
|
+
import { hashToEmoji } from '@aztec/wallet-sdk/crypto';
|
|
390
249
|
|
|
391
|
-
const
|
|
392
|
-
extensions: { enabled: true },
|
|
393
|
-
});
|
|
250
|
+
const discoveredProviders: WalletProvider[] = [];
|
|
394
251
|
|
|
395
|
-
|
|
396
|
-
|
|
252
|
+
const discovery = WalletManager.configure({
|
|
253
|
+
extensions: { enabled: true },
|
|
254
|
+
}).getAvailableWallets({
|
|
397
255
|
chainInfo: {
|
|
398
256
|
chainId: new Fr(31337),
|
|
399
|
-
version: new Fr(
|
|
257
|
+
version: new Fr(1),
|
|
258
|
+
},
|
|
259
|
+
appId: 'my-dapp',
|
|
260
|
+
timeout: 60000,
|
|
261
|
+
// Callback fires as each wallet is discovered
|
|
262
|
+
onWalletDiscovered: (provider) => {
|
|
263
|
+
discoveredProviders.push(provider);
|
|
264
|
+
updateUI(); // Your UI update function
|
|
400
265
|
},
|
|
401
|
-
timeout: 2000,
|
|
402
266
|
});
|
|
403
267
|
|
|
404
|
-
|
|
268
|
+
// Wait for discovery to complete (or cancel early with discovery.cancel())
|
|
269
|
+
await discovery.done;
|
|
270
|
+
console.log('Discovery complete, found:', discoveredProviders.length);
|
|
405
271
|
|
|
406
|
-
// Connect to
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
const wallet = await walletProvider.connect('test-app');
|
|
272
|
+
// Connect to a selected provider
|
|
273
|
+
async function connectToWallet(provider: WalletProvider) {
|
|
274
|
+
const pending = await provider.establishSecureChannel('my-dapp');
|
|
410
275
|
|
|
411
|
-
//
|
|
412
|
-
const
|
|
413
|
-
|
|
276
|
+
// Show verification UI
|
|
277
|
+
const emojis = hashToEmoji(pending.verificationHash);
|
|
278
|
+
showVerificationDialog(emojis);
|
|
414
279
|
|
|
415
|
-
|
|
416
|
-
|
|
280
|
+
// User confirms
|
|
281
|
+
const wallet = await pending.confirm();
|
|
282
|
+
return wallet;
|
|
417
283
|
}
|
|
418
284
|
```
|
|
419
285
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
For a complete reference implementation, see the demo wallet at:
|
|
286
|
+
### React Hook Example
|
|
423
287
|
|
|
424
|
-
|
|
288
|
+
```typescript
|
|
289
|
+
function useWalletDiscovery(chainInfo: ChainInfo, appId: string) {
|
|
290
|
+
const [providers, setProviders] = useState<WalletProvider[]>([]);
|
|
291
|
+
const [isDiscovering, setIsDiscovering] = useState(true);
|
|
292
|
+
const discoveryRef = useRef<DiscoverySession | null>(null);
|
|
293
|
+
|
|
294
|
+
useEffect(() => {
|
|
295
|
+
setProviders([]);
|
|
296
|
+
setIsDiscovering(true);
|
|
297
|
+
|
|
298
|
+
const discovery = WalletManager.configure({
|
|
299
|
+
extensions: { enabled: true },
|
|
300
|
+
}).getAvailableWallets({
|
|
301
|
+
chainInfo,
|
|
302
|
+
appId,
|
|
303
|
+
timeout: 60000,
|
|
304
|
+
onWalletDiscovered: (provider) => {
|
|
305
|
+
setProviders(prev => [...prev, provider]);
|
|
306
|
+
},
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
discoveryRef.current = discovery;
|
|
310
|
+
|
|
311
|
+
discovery.done.then(() => setIsDiscovering(false));
|
|
312
|
+
|
|
313
|
+
return () => {
|
|
314
|
+
discovery.cancel();
|
|
315
|
+
discoveryRef.current = null;
|
|
316
|
+
};
|
|
317
|
+
}, [chainInfo.chainId.toString(), chainInfo.version.toString(), appId]);
|
|
318
|
+
|
|
319
|
+
return { providers, isDiscovering, cancel: () => discoveryRef.current?.cancel() };
|
|
320
|
+
}
|
|
321
|
+
```
|