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.
- package/README.md +13 -0
- package/dist/ble/framing.d.ts.map +1 -1
- package/dist/ble/framing.js +2 -2
- package/dist/ble/framing.js.map +1 -1
- package/dist/ble/index.d.ts +2 -2
- package/dist/ble/index.d.ts.map +1 -1
- package/dist/ble/index.js +2 -2
- package/dist/ble/index.js.map +1 -1
- package/dist/ble/web-ble-transport.d.ts +1 -1
- package/dist/ble/web-ble-transport.d.ts.map +1 -1
- package/dist/ble/web-ble-transport.js +23 -12
- package/dist/ble/web-ble-transport.js.map +1 -1
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +29 -12
- package/dist/crypto.js.map +1 -1
- package/dist/dapp-session.d.ts.map +1 -1
- package/dist/dapp-session.js +15 -5
- package/dist/dapp-session.js.map +1 -1
- package/dist/emitter.d.ts +1 -3
- package/dist/emitter.d.ts.map +1 -1
- package/dist/emitter.js +4 -2
- package/dist/emitter.js.map +1 -1
- package/dist/evm/eip1193.d.ts +2 -2
- package/dist/evm/eip1193.d.ts.map +1 -1
- package/dist/evm/eip1193.js +32 -18
- package/dist/evm/eip1193.js.map +1 -1
- package/dist/evm/index.d.ts +2 -2
- package/dist/evm/index.d.ts.map +1 -1
- package/dist/evm/index.js.map +1 -1
- package/dist/wallet-session.d.ts.map +1 -1
- package/dist/wallet-session.js +4 -3
- package/dist/wallet-session.js.map +1 -1
- package/dist/ws-transport.d.ts +3 -2
- package/dist/ws-transport.d.ts.map +1 -1
- package/dist/ws-transport.js +13 -4
- package/dist/ws-transport.js.map +1 -1
- package/package.json +20 -1
- package/src/__tests__/adversarial/crypto-attacks.test.ts +240 -233
- package/src/__tests__/adversarial/malicious-dapp.test.ts +228 -194
- package/src/__tests__/adversarial/malicious-relay.test.ts +292 -220
- package/src/__tests__/adversarial/malicious-wallet.test.ts +246 -180
- package/src/__tests__/spec-compliance/canonical-json.test.ts +105 -105
- package/src/__tests__/spec-compliance/crypto-vectors.test.ts +149 -154
- package/src/__tests__/spec-compliance/message-format.test.ts +180 -151
- package/src/__tests__/spec-compliance/sequence-numbers.test.ts +142 -149
- package/src/__tests__/spec-compliance/state-machine.test.ts +203 -180
- package/src/ble/framing.test.ts +122 -114
- package/src/ble/framing.ts +48 -51
- package/src/ble/index.ts +7 -7
- package/src/ble/web-ble-transport.test.ts +93 -84
- package/src/ble/web-ble-transport.ts +70 -57
- package/src/ble/web-bluetooth.d.ts +19 -19
- package/src/canonical-json.test.ts +301 -285
- package/src/crypto-directional.test.ts +155 -129
- package/src/crypto-hardening.test.ts +292 -283
- package/src/crypto.test.ts +364 -346
- package/src/crypto.ts +185 -175
- package/src/dapp-session.test.ts +522 -385
- package/src/dapp-session.ts +17 -11
- package/src/emitter.test.ts +122 -122
- package/src/emitter.ts +20 -18
- package/src/evm/eip1193.test.ts +283 -205
- package/src/evm/eip1193.ts +162 -138
- package/src/evm/index.ts +5 -5
- package/src/evm/wagmi.test.ts +1 -1
- package/src/integration.test.ts +329 -201
- package/src/security.test.ts +331 -238
- package/src/sequence-validation.test.ts +6 -9
- package/src/test-helpers.ts +102 -78
- package/src/types.test.ts +45 -50
- package/src/wallet-session.test.ts +611 -383
- package/src/wallet-session.ts +7 -9
- package/src/ws-transport.test.ts +141 -139
- package/src/ws-transport.ts +52 -41
package/src/integration.test.ts
CHANGED
|
@@ -11,28 +11,33 @@
|
|
|
11
11
|
* 7. Close
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import { describe,
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
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: {
|
|
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: {
|
|
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
|
|
72
|
+
const _parsed = parsePairingUri(pairingUri)
|
|
62
73
|
if ('setUrl' in walletTransport) {
|
|
63
|
-
(walletTransport as any).setUrl = () => {}
|
|
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({
|
|
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: {
|
|
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
|
-
|
|
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({
|
|
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: {
|
|
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({
|
|
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: {
|
|
194
|
-
|
|
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({
|
|
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: {
|
|
236
|
-
|
|
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({
|
|
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: {
|
|
266
|
-
|
|
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({
|
|
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: {
|
|
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({
|
|
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: {
|
|
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({
|
|
367
|
-
|
|
368
|
-
|
|
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: {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
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
|
+
})
|