walletpair-sdk 1.0.2 → 1.0.5

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.
Files changed (74) hide show
  1. package/README.md +13 -0
  2. package/dist/ble/framing.d.ts.map +1 -1
  3. package/dist/ble/framing.js +2 -2
  4. package/dist/ble/framing.js.map +1 -1
  5. package/dist/ble/index.d.ts +2 -2
  6. package/dist/ble/index.d.ts.map +1 -1
  7. package/dist/ble/index.js +2 -2
  8. package/dist/ble/index.js.map +1 -1
  9. package/dist/ble/web-ble-transport.d.ts +1 -1
  10. package/dist/ble/web-ble-transport.d.ts.map +1 -1
  11. package/dist/ble/web-ble-transport.js +23 -12
  12. package/dist/ble/web-ble-transport.js.map +1 -1
  13. package/dist/crypto.d.ts.map +1 -1
  14. package/dist/crypto.js +29 -12
  15. package/dist/crypto.js.map +1 -1
  16. package/dist/dapp-session.d.ts.map +1 -1
  17. package/dist/dapp-session.js +15 -5
  18. package/dist/dapp-session.js.map +1 -1
  19. package/dist/emitter.d.ts +1 -3
  20. package/dist/emitter.d.ts.map +1 -1
  21. package/dist/emitter.js +4 -2
  22. package/dist/emitter.js.map +1 -1
  23. package/dist/evm/eip1193.d.ts +2 -2
  24. package/dist/evm/eip1193.d.ts.map +1 -1
  25. package/dist/evm/eip1193.js +32 -18
  26. package/dist/evm/eip1193.js.map +1 -1
  27. package/dist/evm/index.d.ts +2 -2
  28. package/dist/evm/index.d.ts.map +1 -1
  29. package/dist/evm/index.js.map +1 -1
  30. package/dist/wallet-session.d.ts.map +1 -1
  31. package/dist/wallet-session.js +4 -3
  32. package/dist/wallet-session.js.map +1 -1
  33. package/dist/ws-transport.d.ts +3 -2
  34. package/dist/ws-transport.d.ts.map +1 -1
  35. package/dist/ws-transport.js +13 -4
  36. package/dist/ws-transport.js.map +1 -1
  37. package/package.json +20 -1
  38. package/src/__tests__/adversarial/crypto-attacks.test.ts +240 -233
  39. package/src/__tests__/adversarial/malicious-dapp.test.ts +228 -194
  40. package/src/__tests__/adversarial/malicious-relay.test.ts +292 -220
  41. package/src/__tests__/adversarial/malicious-wallet.test.ts +246 -180
  42. package/src/__tests__/spec-compliance/canonical-json.test.ts +105 -105
  43. package/src/__tests__/spec-compliance/crypto-vectors.test.ts +149 -154
  44. package/src/__tests__/spec-compliance/message-format.test.ts +180 -151
  45. package/src/__tests__/spec-compliance/sequence-numbers.test.ts +142 -149
  46. package/src/__tests__/spec-compliance/state-machine.test.ts +203 -180
  47. package/src/ble/framing.test.ts +122 -114
  48. package/src/ble/framing.ts +48 -51
  49. package/src/ble/index.ts +7 -7
  50. package/src/ble/web-ble-transport.test.ts +93 -84
  51. package/src/ble/web-ble-transport.ts +70 -57
  52. package/src/ble/web-bluetooth.d.ts +19 -19
  53. package/src/canonical-json.test.ts +301 -285
  54. package/src/crypto-directional.test.ts +155 -129
  55. package/src/crypto-hardening.test.ts +292 -283
  56. package/src/crypto.test.ts +364 -346
  57. package/src/crypto.ts +185 -175
  58. package/src/dapp-session.test.ts +522 -385
  59. package/src/dapp-session.ts +17 -11
  60. package/src/emitter.test.ts +122 -122
  61. package/src/emitter.ts +20 -18
  62. package/src/evm/eip1193.test.ts +283 -205
  63. package/src/evm/eip1193.ts +162 -138
  64. package/src/evm/index.ts +5 -5
  65. package/src/evm/wagmi.test.ts +1 -1
  66. package/src/integration.test.ts +329 -201
  67. package/src/security.test.ts +331 -238
  68. package/src/sequence-validation.test.ts +6 -9
  69. package/src/test-helpers.ts +102 -78
  70. package/src/types.test.ts +45 -50
  71. package/src/wallet-session.test.ts +611 -383
  72. package/src/wallet-session.ts +7 -9
  73. package/src/ws-transport.test.ts +141 -139
  74. package/src/ws-transport.ts +52 -41
@@ -11,28 +11,33 @@
11
11
  * 7. Close
12
12
  */
13
13
 
14
- import { describe, it, expect, vi } from 'vitest';
15
- import { DAppSession } from './dapp-session.js';
16
- import { WalletSession } from './wallet-session.js';
17
- import { MockTransport, MockRelay, parseSnapshot } from './test-helpers.js';
18
- import { parsePairingUri } from './crypto.js';
14
+ import { describe, expect, it, vi } from 'vitest'
15
+ import { parsePairingUri } from './crypto.js'
16
+ import { DAppSession } from './dapp-session.js'
17
+ import { MockRelay, MockTransport, parseSnapshot } from './test-helpers.js'
18
+ import { WalletSession } from './wallet-session.js'
19
19
 
20
20
  function wait(ms = 50): Promise<void> {
21
- return new Promise((r) => setTimeout(r, ms));
21
+ return new Promise((r) => setTimeout(r, ms))
22
22
  }
23
23
 
24
24
  describe('Integration: DApp ↔ Wallet full flow', () => {
25
25
  it('completes full pairing and request/response cycle', async () => {
26
26
  // Setup transports + relay
27
- const dappTransport = new MockTransport();
28
- const walletTransport = new MockTransport();
29
- const _relay = new MockRelay(dappTransport, walletTransport);
27
+ const dappTransport = new MockTransport()
28
+ const walletTransport = new MockTransport()
29
+ const _relay = new MockRelay(dappTransport, walletTransport)
30
30
 
31
31
  // Create sessions
32
32
  const dappSession = new DAppSession({
33
33
  transport: dappTransport,
34
- meta: { name: 'Test dApp', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' },
35
- });
34
+ meta: {
35
+ name: 'Test dApp',
36
+ description: 'Test',
37
+ url: 'https://test.com',
38
+ icon: 'https://test.com/icon.png',
39
+ },
40
+ })
36
41
 
37
42
  const walletSession = new WalletSession({
38
43
  transport: walletTransport,
@@ -41,345 +46,468 @@ describe('Integration: DApp ↔ Wallet full flow', () => {
41
46
  events: ['accountsChanged'],
42
47
  chains: ['eip155:1'],
43
48
  },
44
- meta: { name: 'Test Wallet', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png', address: '0xWalletAddr' },
45
- });
49
+ meta: {
50
+ name: 'Test Wallet',
51
+ description: 'Test',
52
+ url: 'https://test.com',
53
+ icon: 'https://test.com/icon.png',
54
+ address: '0xWalletAddr',
55
+ },
56
+ })
46
57
 
47
58
  // Track events
48
- const dappPhases: string[] = [];
49
- const walletPhases: string[] = [];
50
- dappSession.on('phase', (p) => dappPhases.push(p));
51
- walletSession.on('phase', (p) => walletPhases.push(p));
59
+ const dappPhases: string[] = []
60
+ const walletPhases: string[] = []
61
+ dappSession.on('phase', (p) => dappPhases.push(p))
62
+ walletSession.on('phase', (p) => walletPhases.push(p))
52
63
 
53
64
  // Step 1: DApp creates pairing
54
- const pairingUri = await dappSession.createPairing();
55
- expect(pairingUri).toContain('walletpair:?ch=');
56
- await wait();
57
- expect(dappSession.phase).toBe('waiting');
65
+ const pairingUri = await dappSession.createPairing()
66
+ expect(pairingUri).toContain('walletpair:?ch=')
67
+ await wait()
68
+ expect(dappSession.phase).toBe('waiting')
58
69
 
59
70
  // Step 2: Wallet joins
60
71
  // Need to set the walletTransport URL from the pairing URI
61
- const parsed = parsePairingUri(pairingUri);
72
+ const _parsed = parsePairingUri(pairingUri)
62
73
  if ('setUrl' in walletTransport) {
63
- (walletTransport as any).setUrl = () => {}; // mock
74
+ ;(walletTransport as any).setUrl = () => {} // mock
64
75
  }
65
76
 
66
- const sessionFingerprint = await walletSession.joinFromUri(pairingUri);
67
- await wait();
77
+ const sessionFingerprint = await walletSession.joinFromUri(pairingUri)
78
+ await wait()
68
79
 
69
- expect(sessionFingerprint).toMatch(/^\d{4}$/);
80
+ expect(sessionFingerprint).toMatch(/^\d{4}$/)
70
81
 
71
82
  // Step 3: Session fingerprints match
72
- expect(dappSession.sessionFingerprint).toBe(walletSession.sessionFingerprint);
83
+ expect(dappSession.sessionFingerprint).toBe(walletSession.sessionFingerprint)
73
84
 
74
85
  // Verify wallet capabilities were received
75
- expect(dappSession.walletCapabilities?.methods).toContain('wallet_getAccounts');
76
- expect(dappSession.walletMeta?.name).toBe('Test Wallet');
86
+ expect(dappSession.walletCapabilities?.methods).toContain('wallet_getAccounts')
87
+ expect(dappSession.walletMeta?.name).toBe('Test Wallet')
77
88
 
78
89
  // Step 4: DApp auto-accepts (no manual acceptWallet needed)
79
- await wait();
90
+ await wait()
80
91
 
81
- expect(dappSession.phase).toBe('connected');
82
- expect(walletSession.phase).toBe('connected');
92
+ expect(dappSession.phase).toBe('connected')
93
+ expect(walletSession.phase).toBe('connected')
83
94
 
84
95
  // Step 5: DApp sends request → wallet responds
85
96
  walletSession.on('request', ({ id, method, params }) => {
86
97
  if (method === 'wallet_getAccounts') {
87
- walletSession.approve(id, ['0xWalletAddr']);
98
+ walletSession.approve(id, ['0xWalletAddr'])
88
99
  }
89
- });
100
+ })
90
101
 
91
- const accounts = await dappSession.request('wallet_getAccounts');
92
- expect(accounts).toEqual(['0xWalletAddr']);
102
+ const accounts = await dappSession.request('wallet_getAccounts')
103
+ expect(accounts).toEqual(['0xWalletAddr'])
93
104
 
94
105
  // Step 6: Wallet pushes event → dApp receives
95
- const eventHandler = vi.fn();
96
- dappSession.on('event', eventHandler);
106
+ const eventHandler = vi.fn()
107
+ dappSession.on('event', eventHandler)
97
108
 
98
- walletSession.pushEvent('accountsChanged', { accounts: ['0xNewAddr'] });
99
- await wait();
109
+ walletSession.pushEvent('accountsChanged', { accounts: ['0xNewAddr'] })
110
+ await wait()
100
111
 
101
112
  expect(eventHandler).toHaveBeenCalledWith({
102
113
  event: 'accountsChanged',
103
114
  data: { accounts: ['0xNewAddr'] },
104
- });
115
+ })
105
116
 
106
117
  // Step 7: Close
107
- dappSession.close();
108
- expect(dappSession.phase).toBe('closed');
118
+ dappSession.close()
119
+ expect(dappSession.phase).toBe('closed')
109
120
 
110
121
  // Verify phase transitions
111
- expect(dappPhases).toContain('waiting');
112
- expect(dappPhases).toContain('connected');
113
- expect(dappPhases).toContain('closed');
122
+ expect(dappPhases).toContain('waiting')
123
+ expect(dappPhases).toContain('connected')
124
+ expect(dappPhases).toContain('closed')
114
125
 
115
- expect(walletPhases).toContain('waiting_accept');
116
- expect(walletPhases).toContain('connected');
117
- });
126
+ expect(walletPhases).toContain('waiting_accept')
127
+ expect(walletPhases).toContain('connected')
128
+ })
118
129
 
119
130
  it('wallet rejects request', async () => {
120
- const dappTransport = new MockTransport();
121
- const walletTransport = new MockTransport();
122
- const _relay = new MockRelay(dappTransport, walletTransport);
131
+ const dappTransport = new MockTransport()
132
+ const walletTransport = new MockTransport()
133
+ const _relay = new MockRelay(dappTransport, walletTransport)
123
134
 
124
- const dappSession = new DAppSession({ transport: dappTransport, meta: { name: 'Test dApp', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' } });
135
+ const dappSession = new DAppSession({
136
+ transport: dappTransport,
137
+ meta: {
138
+ name: 'Test dApp',
139
+ description: 'Test',
140
+ url: 'https://test.com',
141
+ icon: 'https://test.com/icon.png',
142
+ },
143
+ })
125
144
  const walletSession = new WalletSession({
126
145
  transport: walletTransport,
127
146
  capabilities: { methods: ['wallet_signMessage'], events: [], chains: ['eip155:1'] },
128
- meta: { name: 'Test Wallet', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' },
129
- });
147
+ meta: {
148
+ name: 'Test Wallet',
149
+ description: 'Test',
150
+ url: 'https://test.com',
151
+ icon: 'https://test.com/icon.png',
152
+ },
153
+ })
130
154
 
131
155
  // Connect (auto-accept)
132
- const uri = await dappSession.createPairing();
133
- await walletSession.joinFromUri(uri);
134
- await wait();
135
- await wait();
156
+ const uri = await dappSession.createPairing()
157
+ await walletSession.joinFromUri(uri)
158
+ await wait()
159
+ await wait()
136
160
 
137
161
  // Wallet rejects
138
162
  walletSession.on('request', ({ id }) => {
139
- walletSession.reject(id, 'user_rejected', 'No thanks');
140
- });
163
+ walletSession.reject(id, 'user_rejected', 'No thanks')
164
+ })
141
165
 
142
- await expect(dappSession.request('wallet_signMessage', { message: 'hi' }))
143
- .rejects.toThrow('No thanks');
144
- });
166
+ await expect(dappSession.request('wallet_signMessage', { message: 'hi' })).rejects.toThrow(
167
+ 'No thanks',
168
+ )
169
+ })
145
170
 
146
171
  it('multiple sequential requests', async () => {
147
- const dappTransport = new MockTransport();
148
- const walletTransport = new MockTransport();
149
- const _relay = new MockRelay(dappTransport, walletTransport);
172
+ const dappTransport = new MockTransport()
173
+ const walletTransport = new MockTransport()
174
+ const _relay = new MockRelay(dappTransport, walletTransport)
150
175
 
151
- const dappSession = new DAppSession({ transport: dappTransport, meta: { name: 'Test dApp', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' } });
176
+ const dappSession = new DAppSession({
177
+ transport: dappTransport,
178
+ meta: {
179
+ name: 'Test dApp',
180
+ description: 'Test',
181
+ url: 'https://test.com',
182
+ icon: 'https://test.com/icon.png',
183
+ },
184
+ })
152
185
  const walletSession = new WalletSession({
153
186
  transport: walletTransport,
154
187
  capabilities: { methods: ['wallet_getAccounts'], events: [], chains: ['eip155:1'] },
155
- meta: { name: 'Test Wallet', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' },
156
- });
188
+ meta: {
189
+ name: 'Test Wallet',
190
+ description: 'Test',
191
+ url: 'https://test.com',
192
+ icon: 'https://test.com/icon.png',
193
+ },
194
+ })
157
195
 
158
- const uri = await dappSession.createPairing();
159
- await walletSession.joinFromUri(uri);
160
- await wait();
161
- await wait();
196
+ const uri = await dappSession.createPairing()
197
+ await walletSession.joinFromUri(uri)
198
+ await wait()
199
+ await wait()
162
200
 
163
- let callCount = 0;
201
+ let callCount = 0
164
202
  walletSession.on('request', ({ id, method }) => {
165
- callCount++;
166
- walletSession.approve(id, { call: callCount });
167
- });
203
+ callCount++
204
+ walletSession.approve(id, { call: callCount })
205
+ })
168
206
 
169
- const r1 = await dappSession.request('wallet_getAccounts');
170
- const r2 = await dappSession.request('wallet_getAccounts');
171
- const r3 = await dappSession.request('wallet_getAccounts');
207
+ const r1 = await dappSession.request('wallet_getAccounts')
208
+ const r2 = await dappSession.request('wallet_getAccounts')
209
+ const r3 = await dappSession.request('wallet_getAccounts')
172
210
 
173
- expect(r1).toEqual({ call: 1 });
174
- expect(r2).toEqual({ call: 2 });
175
- expect(r3).toEqual({ call: 3 });
176
- });
177
- });
211
+ expect(r1).toEqual({ call: 1 })
212
+ expect(r2).toEqual({ call: 2 })
213
+ expect(r3).toEqual({ call: 3 })
214
+ })
215
+ })
178
216
 
179
217
  // ---------------------------------------------------------------------------
180
218
  // Directional key integration tests
181
219
  // ---------------------------------------------------------------------------
182
220
 
183
221
  describe('Integration: Bidirectional flow with directional keys', () => {
184
-
185
222
  it('full bidirectional flow: dApp sends request, wallet receives, wallet responds, dApp receives', async () => {
186
- const dappTransport = new MockTransport();
187
- const walletTransport = new MockTransport();
188
- const _relay = new MockRelay(dappTransport, walletTransport);
223
+ const dappTransport = new MockTransport()
224
+ const walletTransport = new MockTransport()
225
+ const _relay = new MockRelay(dappTransport, walletTransport)
189
226
 
190
- const dappSession = new DAppSession({ transport: dappTransport, meta: { name: 'BiDi dApp', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' } });
227
+ const dappSession = new DAppSession({
228
+ transport: dappTransport,
229
+ meta: {
230
+ name: 'BiDi dApp',
231
+ description: 'Test',
232
+ url: 'https://test.com',
233
+ icon: 'https://test.com/icon.png',
234
+ },
235
+ })
191
236
  const walletSession = new WalletSession({
192
237
  transport: walletTransport,
193
- capabilities: { methods: ['wallet_getAccounts', 'wallet_signMessage'], events: ['accountsChanged'], chains: ['eip155:1'] },
194
- meta: { name: 'BiDi Wallet', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png', address: '0xBiDi' },
195
- });
238
+ capabilities: {
239
+ methods: ['wallet_getAccounts', 'wallet_signMessage'],
240
+ events: ['accountsChanged'],
241
+ chains: ['eip155:1'],
242
+ },
243
+ meta: {
244
+ name: 'BiDi Wallet',
245
+ description: 'Test',
246
+ url: 'https://test.com',
247
+ icon: 'https://test.com/icon.png',
248
+ address: '0xBiDi',
249
+ },
250
+ })
196
251
 
197
- const uri = await dappSession.createPairing();
198
- await walletSession.joinFromUri(uri);
199
- await wait();
252
+ const uri = await dappSession.createPairing()
253
+ await walletSession.joinFromUri(uri)
254
+ await wait()
200
255
 
201
256
  // Verify session fingerprints match
202
- expect(dappSession.sessionFingerprint).toBe(walletSession.sessionFingerprint);
257
+ expect(dappSession.sessionFingerprint).toBe(walletSession.sessionFingerprint)
203
258
 
204
- await wait();
259
+ await wait()
205
260
 
206
- expect(dappSession.phase).toBe('connected');
207
- expect(walletSession.phase).toBe('connected');
261
+ expect(dappSession.phase).toBe('connected')
262
+ expect(walletSession.phase).toBe('connected')
208
263
 
209
264
  // Wallet handles requests
210
265
  walletSession.on('request', ({ id, method, params }) => {
211
266
  if (method === 'wallet_getAccounts') {
212
- walletSession.approve(id, ['0xBiDi']);
267
+ walletSession.approve(id, ['0xBiDi'])
213
268
  } else if (method === 'wallet_signMessage') {
214
- walletSession.approve(id, { signature: '0xSIG' });
269
+ walletSession.approve(id, { signature: '0xSIG' })
215
270
  }
216
- });
271
+ })
217
272
 
218
273
  // DApp sends request (uses dappToWalletKey), wallet decrypts (uses dappToWalletKey as recvKey)
219
- const accounts = await dappSession.request('wallet_getAccounts');
220
- expect(accounts).toEqual(['0xBiDi']);
274
+ const accounts = await dappSession.request('wallet_getAccounts')
275
+ expect(accounts).toEqual(['0xBiDi'])
221
276
 
222
277
  // Wallet responds (uses walletToDappKey), dApp decrypts (uses walletToDappKey as recvKey)
223
- const sig = await dappSession.request('wallet_signMessage', { message: 'test' });
224
- expect(sig).toEqual({ signature: '0xSIG' });
225
- });
278
+ const sig = await dappSession.request('wallet_signMessage', { message: 'test' })
279
+ expect(sig).toEqual({ signature: '0xSIG' })
280
+ })
226
281
 
227
282
  it('wallet pushes event, dApp receives with correct key', async () => {
228
- const dappTransport = new MockTransport();
229
- const walletTransport = new MockTransport();
230
- const _relay = new MockRelay(dappTransport, walletTransport);
283
+ const dappTransport = new MockTransport()
284
+ const walletTransport = new MockTransport()
285
+ const _relay = new MockRelay(dappTransport, walletTransport)
231
286
 
232
- const dappSession = new DAppSession({ transport: dappTransport, meta: { name: 'Test dApp', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' } });
287
+ const dappSession = new DAppSession({
288
+ transport: dappTransport,
289
+ meta: {
290
+ name: 'Test dApp',
291
+ description: 'Test',
292
+ url: 'https://test.com',
293
+ icon: 'https://test.com/icon.png',
294
+ },
295
+ })
233
296
  const walletSession = new WalletSession({
234
297
  transport: walletTransport,
235
- capabilities: { methods: ['wallet_getAccounts'], events: ['accountsChanged', 'chainChanged'], chains: ['eip155:1'] },
236
- meta: { name: 'Test Wallet', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' },
237
- });
298
+ capabilities: {
299
+ methods: ['wallet_getAccounts'],
300
+ events: ['accountsChanged', 'chainChanged'],
301
+ chains: ['eip155:1'],
302
+ },
303
+ meta: {
304
+ name: 'Test Wallet',
305
+ description: 'Test',
306
+ url: 'https://test.com',
307
+ icon: 'https://test.com/icon.png',
308
+ },
309
+ })
238
310
 
239
- const uri = await dappSession.createPairing();
240
- await walletSession.joinFromUri(uri);
241
- await wait();
242
- await wait();
311
+ const uri = await dappSession.createPairing()
312
+ await walletSession.joinFromUri(uri)
313
+ await wait()
314
+ await wait()
243
315
 
244
- const events: Array<{ event: string; data: unknown }> = [];
245
- dappSession.on('event', (evt) => events.push(evt));
316
+ const events: Array<{ event: string; data: unknown }> = []
317
+ dappSession.on('event', (evt) => events.push(evt))
246
318
 
247
319
  // Push multiple events
248
- walletSession.pushEvent('accountsChanged', { accounts: ['0xNew'] });
249
- walletSession.pushEvent('chainChanged', { chainId: 'eip155:137' });
250
- await wait();
320
+ walletSession.pushEvent('accountsChanged', { accounts: ['0xNew'] })
321
+ walletSession.pushEvent('chainChanged', { chainId: 'eip155:137' })
322
+ await wait()
251
323
 
252
- expect(events).toHaveLength(2);
253
- expect(events[0]).toEqual({ event: 'accountsChanged', data: { accounts: ['0xNew'] } });
254
- expect(events[1]).toEqual({ event: 'chainChanged', data: { chainId: 'eip155:137' } });
255
- });
324
+ expect(events).toHaveLength(2)
325
+ expect(events[0]).toEqual({ event: 'accountsChanged', data: { accounts: ['0xNew'] } })
326
+ expect(events[1]).toEqual({ event: 'chainChanged', data: { chainId: 'eip155:137' } })
327
+ })
256
328
 
257
329
  it('multiple concurrent requests do not interfere', async () => {
258
- const dappTransport = new MockTransport();
259
- const walletTransport = new MockTransport();
260
- const _relay = new MockRelay(dappTransport, walletTransport);
330
+ const dappTransport = new MockTransport()
331
+ const walletTransport = new MockTransport()
332
+ const _relay = new MockRelay(dappTransport, walletTransport)
261
333
 
262
- const dappSession = new DAppSession({ transport: dappTransport, meta: { name: 'Test dApp', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' } });
334
+ const dappSession = new DAppSession({
335
+ transport: dappTransport,
336
+ meta: {
337
+ name: 'Test dApp',
338
+ description: 'Test',
339
+ url: 'https://test.com',
340
+ icon: 'https://test.com/icon.png',
341
+ },
342
+ })
263
343
  const walletSession = new WalletSession({
264
344
  transport: walletTransport,
265
- capabilities: { methods: ['wallet_getAccounts', 'wallet_signMessage'], events: [], chains: ['eip155:1'] },
266
- meta: { name: 'Test Wallet', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' },
267
- });
345
+ capabilities: {
346
+ methods: ['wallet_getAccounts', 'wallet_signMessage'],
347
+ events: [],
348
+ chains: ['eip155:1'],
349
+ },
350
+ meta: {
351
+ name: 'Test Wallet',
352
+ description: 'Test',
353
+ url: 'https://test.com',
354
+ icon: 'https://test.com/icon.png',
355
+ },
356
+ })
268
357
 
269
- const uri = await dappSession.createPairing();
270
- await walletSession.joinFromUri(uri);
271
- await wait();
272
- await wait();
358
+ const uri = await dappSession.createPairing()
359
+ await walletSession.joinFromUri(uri)
360
+ await wait()
361
+ await wait()
273
362
 
274
363
  // Wallet responds to each request with method-specific data, but with a delay
275
364
  walletSession.on('request', ({ id, method }) => {
276
365
  if (method === 'wallet_getAccounts') {
277
366
  // Respond immediately
278
- walletSession.approve(id, ['0xABC']);
367
+ walletSession.approve(id, ['0xABC'])
279
368
  } else if (method === 'wallet_signMessage') {
280
369
  // Respond slightly delayed
281
- setTimeout(() => walletSession.approve(id, '0xSIG123'), 10);
370
+ setTimeout(() => walletSession.approve(id, '0xSIG123'), 10)
282
371
  }
283
- });
372
+ })
284
373
 
285
374
  // Fire both concurrently
286
375
  const [accounts, signature] = await Promise.all([
287
376
  dappSession.request('wallet_getAccounts'),
288
377
  dappSession.request('wallet_signMessage', { message: 'hello' }),
289
- ]);
378
+ ])
290
379
 
291
- expect(accounts).toEqual(['0xABC']);
292
- expect(signature).toBe('0xSIG123');
293
- });
380
+ expect(accounts).toEqual(['0xABC'])
381
+ expect(signature).toBe('0xSIG123')
382
+ })
294
383
 
295
384
  it('session serialization preserves directional keys', async () => {
296
- const dappTransport = new MockTransport();
297
- const walletTransport = new MockTransport();
298
- const _relay = new MockRelay(dappTransport, walletTransport);
385
+ const dappTransport = new MockTransport()
386
+ const walletTransport = new MockTransport()
387
+ const _relay = new MockRelay(dappTransport, walletTransport)
299
388
 
300
- const dappSession = new DAppSession({ transport: dappTransport, meta: { name: 'Persist dApp', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' } });
389
+ const dappSession = new DAppSession({
390
+ transport: dappTransport,
391
+ meta: {
392
+ name: 'Persist dApp',
393
+ description: 'Test',
394
+ url: 'https://test.com',
395
+ icon: 'https://test.com/icon.png',
396
+ },
397
+ })
301
398
  const walletSession = new WalletSession({
302
399
  transport: walletTransport,
303
400
  capabilities: { methods: ['wallet_getAccounts'], events: [], chains: ['eip155:1'] },
304
- meta: { name: 'Persist Wallet', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' },
305
- });
401
+ meta: {
402
+ name: 'Persist Wallet',
403
+ description: 'Test',
404
+ url: 'https://test.com',
405
+ icon: 'https://test.com/icon.png',
406
+ },
407
+ })
306
408
 
307
- const uri = await dappSession.createPairing();
308
- await walletSession.joinFromUri(uri);
309
- await wait();
310
- await wait();
409
+ const uri = await dappSession.createPairing()
410
+ await walletSession.joinFromUri(uri)
411
+ await wait()
412
+ await wait()
311
413
 
312
414
  // Serialize both sessions
313
- const dappJson = dappSession.serialize();
314
- const walletJson = walletSession.serialize();
415
+ const dappJson = dappSession.serialize()
416
+ const walletJson = walletSession.serialize()
315
417
 
316
418
  // Parse and verify directional keys are stored
317
- const dappState = parseSnapshot(dappJson);
318
- const walletState = parseSnapshot(walletJson);
419
+ const dappState = parseSnapshot(dappJson)
420
+ const walletState = parseSnapshot(walletJson)
319
421
 
320
- expect(dappState.sendKey).toBeTruthy();
321
- expect(dappState.recvKey).toBeTruthy();
322
- expect(walletState.sendKey).toBeTruthy();
323
- expect(walletState.recvKey).toBeTruthy();
422
+ expect(dappState.sendKey).toBeTruthy()
423
+ expect(dappState.recvKey).toBeTruthy()
424
+ expect(walletState.sendKey).toBeTruthy()
425
+ expect(walletState.recvKey).toBeTruthy()
324
426
 
325
427
  // DApp sendKey (dappToWalletKey) == Wallet recvKey (dappToWalletKey)
326
- expect(dappState.sendKey).toBe(walletState.recvKey);
428
+ expect(dappState.sendKey).toBe(walletState.recvKey)
327
429
  // DApp recvKey (walletToDappKey) == Wallet sendKey (walletToDappKey)
328
- expect(dappState.recvKey).toBe(walletState.sendKey);
430
+ expect(dappState.recvKey).toBe(walletState.sendKey)
329
431
 
330
432
  // sendKey != recvKey (directional)
331
- expect(dappState.sendKey).not.toBe(dappState.recvKey);
332
- });
433
+ expect(dappState.sendKey).not.toBe(dappState.recvKey)
434
+ })
333
435
 
334
436
  it('restored session can still communicate', async () => {
335
- const dappTransport = new MockTransport();
336
- const walletTransport = new MockTransport();
337
- const _relay = new MockRelay(dappTransport, walletTransport);
437
+ const dappTransport = new MockTransport()
438
+ const walletTransport = new MockTransport()
439
+ const _relay = new MockRelay(dappTransport, walletTransport)
338
440
 
339
- const dappSession = new DAppSession({ transport: dappTransport, meta: { name: 'Restore dApp', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' } });
441
+ const dappSession = new DAppSession({
442
+ transport: dappTransport,
443
+ meta: {
444
+ name: 'Restore dApp',
445
+ description: 'Test',
446
+ url: 'https://test.com',
447
+ icon: 'https://test.com/icon.png',
448
+ },
449
+ })
340
450
  const walletSession = new WalletSession({
341
451
  transport: walletTransport,
342
452
  capabilities: { methods: ['wallet_getAccounts'], events: [], chains: ['eip155:1'] },
343
- meta: { name: 'Restore Wallet', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' },
344
- });
453
+ meta: {
454
+ name: 'Restore Wallet',
455
+ description: 'Test',
456
+ url: 'https://test.com',
457
+ icon: 'https://test.com/icon.png',
458
+ },
459
+ })
345
460
 
346
- const uri = await dappSession.createPairing();
347
- await walletSession.joinFromUri(uri);
348
- await wait();
349
- await wait();
461
+ const uri = await dappSession.createPairing()
462
+ await walletSession.joinFromUri(uri)
463
+ await wait()
464
+ await wait()
350
465
 
351
466
  // Exchange one message to advance sequence counters
352
- walletSession.on('request', ({ id }) => walletSession.approve(id, 'first'));
353
- const r1 = await dappSession.request('wallet_getAccounts');
354
- expect(r1).toBe('first');
467
+ walletSession.on('request', ({ id }) => walletSession.approve(id, 'first'))
468
+ const r1 = await dappSession.request('wallet_getAccounts')
469
+ expect(r1).toBe('first')
355
470
 
356
471
  // Serialize
357
- const dappJson = dappSession.serialize();
358
- const walletJson = walletSession.serialize();
472
+ const dappJson = dappSession.serialize()
473
+ const walletJson = walletSession.serialize()
359
474
 
360
475
  // Restore dApp session to a new transport that is linked to the wallet transport
361
- const newDappTransport = new MockTransport();
362
- const newWalletTransport = new MockTransport();
363
- newDappTransport.peer = newWalletTransport;
364
- newWalletTransport.peer = newDappTransport;
365
-
366
- const restoredDapp = new DAppSession({ transport: newDappTransport, meta: { name: 'Restore dApp', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' } });
367
- expect(restoredDapp.restore(dappJson)).toBe(true);
368
- (restoredDapp as any).phase = 'connected';
476
+ const newDappTransport = new MockTransport()
477
+ const newWalletTransport = new MockTransport()
478
+ newDappTransport.peer = newWalletTransport
479
+ newWalletTransport.peer = newDappTransport
480
+
481
+ const restoredDapp = new DAppSession({
482
+ transport: newDappTransport,
483
+ meta: {
484
+ name: 'Restore dApp',
485
+ description: 'Test',
486
+ url: 'https://test.com',
487
+ icon: 'https://test.com/icon.png',
488
+ },
489
+ })
490
+ expect(restoredDapp.restore(dappJson)).toBe(true)
491
+ ;(restoredDapp as any).phase = 'connected'
369
492
 
370
493
  const restoredWallet = new WalletSession({
371
494
  transport: newWalletTransport,
372
495
  capabilities: { methods: ['wallet_getAccounts'], events: [], chains: ['eip155:1'] },
373
- meta: { name: 'Restore Wallet', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' },
374
- });
375
- expect(restoredWallet.restore(walletJson)).toBe(true);
376
- (restoredWallet as any).phase = 'connected';
496
+ meta: {
497
+ name: 'Restore Wallet',
498
+ description: 'Test',
499
+ url: 'https://test.com',
500
+ icon: 'https://test.com/icon.png',
501
+ },
502
+ })
503
+ expect(restoredWallet.restore(walletJson)).toBe(true)
504
+ ;(restoredWallet as any).phase = 'connected'
377
505
 
378
506
  // Set up request handler on restored wallet
379
- restoredWallet.on('request', ({ id }) => restoredWallet.approve(id, 'restored'));
507
+ restoredWallet.on('request', ({ id }) => restoredWallet.approve(id, 'restored'))
380
508
 
381
509
  // Restored dApp sends request through linked transports
382
- const r2 = await restoredDapp.request('wallet_getAccounts');
383
- expect(r2).toBe('restored');
384
- });
385
- });
510
+ const r2 = await restoredDapp.request('wallet_getAccounts')
511
+ expect(r2).toBe('restored')
512
+ })
513
+ })