walletpair-sdk 1.0.0
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/LICENSE +21 -0
- package/README.md +415 -0
- package/dist/ble/framing.d.ts +23 -0
- package/dist/ble/framing.d.ts.map +1 -0
- package/dist/ble/framing.js +83 -0
- package/dist/ble/framing.js.map +1 -0
- package/dist/ble/index.d.ts +9 -0
- package/dist/ble/index.d.ts.map +1 -0
- package/dist/ble/index.js +9 -0
- package/dist/ble/index.js.map +1 -0
- package/dist/ble/web-ble-transport.d.ts +29 -0
- package/dist/ble/web-ble-transport.d.ts.map +1 -0
- package/dist/ble/web-ble-transport.js +93 -0
- package/dist/ble/web-ble-transport.js.map +1 -0
- package/dist/crypto.d.ts +102 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +279 -0
- package/dist/crypto.js.map +1 -0
- package/dist/dapp-session.d.ts +106 -0
- package/dist/dapp-session.d.ts.map +1 -0
- package/dist/dapp-session.js +918 -0
- package/dist/dapp-session.js.map +1 -0
- package/dist/emitter.d.ts +16 -0
- package/dist/emitter.d.ts.map +1 -0
- package/dist/emitter.js +41 -0
- package/dist/emitter.js.map +1 -0
- package/dist/evm/eip1193.d.ts +83 -0
- package/dist/evm/eip1193.d.ts.map +1 -0
- package/dist/evm/eip1193.js +270 -0
- package/dist/evm/eip1193.js.map +1 -0
- package/dist/evm/index.d.ts +8 -0
- package/dist/evm/index.d.ts.map +1 -0
- package/dist/evm/index.js +8 -0
- package/dist/evm/index.js.map +1 -0
- package/dist/evm/wagmi.d.ts +118 -0
- package/dist/evm/wagmi.d.ts.map +1 -0
- package/dist/evm/wagmi.js +205 -0
- package/dist/evm/wagmi.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +225 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +31 -0
- package/dist/types.js.map +1 -0
- package/dist/wallet-session.d.ts +107 -0
- package/dist/wallet-session.d.ts.map +1 -0
- package/dist/wallet-session.js +794 -0
- package/dist/wallet-session.js.map +1 -0
- package/dist/ws-transport.d.ts +29 -0
- package/dist/ws-transport.d.ts.map +1 -0
- package/dist/ws-transport.js +79 -0
- package/dist/ws-transport.js.map +1 -0
- package/package.json +55 -0
- package/src/__tests__/adversarial/crypto-attacks.test.ts +557 -0
- package/src/__tests__/adversarial/malicious-dapp.test.ts +505 -0
- package/src/__tests__/adversarial/malicious-relay.test.ts +528 -0
- package/src/__tests__/adversarial/malicious-wallet.test.ts +467 -0
- package/src/__tests__/spec-compliance/canonical-json.test.ts +227 -0
- package/src/__tests__/spec-compliance/crypto-vectors.test.ts +321 -0
- package/src/__tests__/spec-compliance/message-format.test.ts +356 -0
- package/src/__tests__/spec-compliance/sequence-numbers.test.ts +300 -0
- package/src/__tests__/spec-compliance/state-machine.test.ts +364 -0
- package/src/ble/framing.test.ts +196 -0
- package/src/ble/framing.ts +100 -0
- package/src/ble/index.ts +18 -0
- package/src/ble/web-ble-transport.test.ts +192 -0
- package/src/ble/web-ble-transport.ts +116 -0
- package/src/ble/web-bluetooth.d.ts +47 -0
- package/src/canonical-json.test.ts +612 -0
- package/src/crypto-directional.test.ts +263 -0
- package/src/crypto-hardening.test.ts +529 -0
- package/src/crypto.test.ts +635 -0
- package/src/crypto.ts +405 -0
- package/src/dapp-session.test.ts +647 -0
- package/src/dapp-session.ts +1004 -0
- package/src/emitter.test.ts +169 -0
- package/src/emitter.ts +45 -0
- package/src/evm/eip1193.test.ts +365 -0
- package/src/evm/eip1193.ts +346 -0
- package/src/evm/index.ts +19 -0
- package/src/evm/wagmi.test.ts +396 -0
- package/src/evm/wagmi.ts +321 -0
- package/src/index.ts +86 -0
- package/src/integration.test.ts +385 -0
- package/src/security.test.ts +430 -0
- package/src/sequence-validation.test.ts +1185 -0
- package/src/test-helpers.ts +216 -0
- package/src/types.test.ts +82 -0
- package/src/types.ts +305 -0
- package/src/wallet-session.test.ts +683 -0
- package/src/wallet-session.ts +922 -0
- package/src/ws-transport.test.ts +231 -0
- package/src/ws-transport.ts +92 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration test: full dApp ↔ wallet flow through MockRelay.
|
|
3
|
+
*
|
|
4
|
+
* Verifies the complete lifecycle:
|
|
5
|
+
* 1. DApp creates pairing
|
|
6
|
+
* 2. Wallet joins via URI
|
|
7
|
+
* 3. Pairing codes match
|
|
8
|
+
* 4. DApp accepts → both connected
|
|
9
|
+
* 5. DApp sends request → wallet receives → wallet approves → dApp gets response
|
|
10
|
+
* 6. Wallet pushes event → dApp receives
|
|
11
|
+
* 7. Close
|
|
12
|
+
*/
|
|
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';
|
|
19
|
+
|
|
20
|
+
function wait(ms = 50): Promise<void> {
|
|
21
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
describe('Integration: DApp ↔ Wallet full flow', () => {
|
|
25
|
+
it('completes full pairing and request/response cycle', async () => {
|
|
26
|
+
// Setup transports + relay
|
|
27
|
+
const dappTransport = new MockTransport();
|
|
28
|
+
const walletTransport = new MockTransport();
|
|
29
|
+
const _relay = new MockRelay(dappTransport, walletTransport);
|
|
30
|
+
|
|
31
|
+
// Create sessions
|
|
32
|
+
const dappSession = new DAppSession({
|
|
33
|
+
transport: dappTransport,
|
|
34
|
+
meta: { name: 'Test dApp', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' },
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const walletSession = new WalletSession({
|
|
38
|
+
transport: walletTransport,
|
|
39
|
+
capabilities: {
|
|
40
|
+
methods: ['wallet_getAccounts', 'wallet_signMessage'],
|
|
41
|
+
events: ['accountsChanged'],
|
|
42
|
+
chains: ['eip155:1'],
|
|
43
|
+
},
|
|
44
|
+
meta: { name: 'Test Wallet', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png', address: '0xWalletAddr' },
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// 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));
|
|
52
|
+
|
|
53
|
+
// 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');
|
|
58
|
+
|
|
59
|
+
// Step 2: Wallet joins
|
|
60
|
+
// Need to set the walletTransport URL from the pairing URI
|
|
61
|
+
const parsed = parsePairingUri(pairingUri);
|
|
62
|
+
if ('setUrl' in walletTransport) {
|
|
63
|
+
(walletTransport as any).setUrl = () => {}; // mock
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const sessionFingerprint = await walletSession.joinFromUri(pairingUri);
|
|
67
|
+
await wait();
|
|
68
|
+
|
|
69
|
+
expect(sessionFingerprint).toMatch(/^\d{4}$/);
|
|
70
|
+
|
|
71
|
+
// Step 3: Session fingerprints match
|
|
72
|
+
expect(dappSession.sessionFingerprint).toBe(walletSession.sessionFingerprint);
|
|
73
|
+
|
|
74
|
+
// Verify wallet capabilities were received
|
|
75
|
+
expect(dappSession.walletCapabilities?.methods).toContain('wallet_getAccounts');
|
|
76
|
+
expect(dappSession.walletMeta?.name).toBe('Test Wallet');
|
|
77
|
+
|
|
78
|
+
// Step 4: DApp auto-accepts (no manual acceptWallet needed)
|
|
79
|
+
await wait();
|
|
80
|
+
|
|
81
|
+
expect(dappSession.phase).toBe('connected');
|
|
82
|
+
expect(walletSession.phase).toBe('connected');
|
|
83
|
+
|
|
84
|
+
// Step 5: DApp sends request → wallet responds
|
|
85
|
+
walletSession.on('request', ({ id, method, params }) => {
|
|
86
|
+
if (method === 'wallet_getAccounts') {
|
|
87
|
+
walletSession.approve(id, ['0xWalletAddr']);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const accounts = await dappSession.request('wallet_getAccounts');
|
|
92
|
+
expect(accounts).toEqual(['0xWalletAddr']);
|
|
93
|
+
|
|
94
|
+
// Step 6: Wallet pushes event → dApp receives
|
|
95
|
+
const eventHandler = vi.fn();
|
|
96
|
+
dappSession.on('event', eventHandler);
|
|
97
|
+
|
|
98
|
+
walletSession.pushEvent('accountsChanged', { accounts: ['0xNewAddr'] });
|
|
99
|
+
await wait();
|
|
100
|
+
|
|
101
|
+
expect(eventHandler).toHaveBeenCalledWith({
|
|
102
|
+
event: 'accountsChanged',
|
|
103
|
+
data: { accounts: ['0xNewAddr'] },
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Step 7: Close
|
|
107
|
+
dappSession.close();
|
|
108
|
+
expect(dappSession.phase).toBe('closed');
|
|
109
|
+
|
|
110
|
+
// Verify phase transitions
|
|
111
|
+
expect(dappPhases).toContain('waiting');
|
|
112
|
+
expect(dappPhases).toContain('connected');
|
|
113
|
+
expect(dappPhases).toContain('closed');
|
|
114
|
+
|
|
115
|
+
expect(walletPhases).toContain('waiting_accept');
|
|
116
|
+
expect(walletPhases).toContain('connected');
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('wallet rejects request', async () => {
|
|
120
|
+
const dappTransport = new MockTransport();
|
|
121
|
+
const walletTransport = new MockTransport();
|
|
122
|
+
const _relay = new MockRelay(dappTransport, walletTransport);
|
|
123
|
+
|
|
124
|
+
const dappSession = new DAppSession({ transport: dappTransport, meta: { name: 'Test dApp', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' } });
|
|
125
|
+
const walletSession = new WalletSession({
|
|
126
|
+
transport: walletTransport,
|
|
127
|
+
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
|
+
});
|
|
130
|
+
|
|
131
|
+
// Connect (auto-accept)
|
|
132
|
+
const uri = await dappSession.createPairing();
|
|
133
|
+
await walletSession.joinFromUri(uri);
|
|
134
|
+
await wait();
|
|
135
|
+
await wait();
|
|
136
|
+
|
|
137
|
+
// Wallet rejects
|
|
138
|
+
walletSession.on('request', ({ id }) => {
|
|
139
|
+
walletSession.reject(id, 'user_rejected', 'No thanks');
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
await expect(dappSession.request('wallet_signMessage', { message: 'hi' }))
|
|
143
|
+
.rejects.toThrow('No thanks');
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('multiple sequential requests', async () => {
|
|
147
|
+
const dappTransport = new MockTransport();
|
|
148
|
+
const walletTransport = new MockTransport();
|
|
149
|
+
const _relay = new MockRelay(dappTransport, walletTransport);
|
|
150
|
+
|
|
151
|
+
const dappSession = new DAppSession({ transport: dappTransport, meta: { name: 'Test dApp', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' } });
|
|
152
|
+
const walletSession = new WalletSession({
|
|
153
|
+
transport: walletTransport,
|
|
154
|
+
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
|
+
});
|
|
157
|
+
|
|
158
|
+
const uri = await dappSession.createPairing();
|
|
159
|
+
await walletSession.joinFromUri(uri);
|
|
160
|
+
await wait();
|
|
161
|
+
await wait();
|
|
162
|
+
|
|
163
|
+
let callCount = 0;
|
|
164
|
+
walletSession.on('request', ({ id, method }) => {
|
|
165
|
+
callCount++;
|
|
166
|
+
walletSession.approve(id, { call: callCount });
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const r1 = await dappSession.request('wallet_getAccounts');
|
|
170
|
+
const r2 = await dappSession.request('wallet_getAccounts');
|
|
171
|
+
const r3 = await dappSession.request('wallet_getAccounts');
|
|
172
|
+
|
|
173
|
+
expect(r1).toEqual({ call: 1 });
|
|
174
|
+
expect(r2).toEqual({ call: 2 });
|
|
175
|
+
expect(r3).toEqual({ call: 3 });
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// ---------------------------------------------------------------------------
|
|
180
|
+
// Directional key integration tests
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
|
|
183
|
+
describe('Integration: Bidirectional flow with directional keys', () => {
|
|
184
|
+
|
|
185
|
+
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);
|
|
189
|
+
|
|
190
|
+
const dappSession = new DAppSession({ transport: dappTransport, meta: { name: 'BiDi dApp', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' } });
|
|
191
|
+
const walletSession = new WalletSession({
|
|
192
|
+
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
|
+
});
|
|
196
|
+
|
|
197
|
+
const uri = await dappSession.createPairing();
|
|
198
|
+
await walletSession.joinFromUri(uri);
|
|
199
|
+
await wait();
|
|
200
|
+
|
|
201
|
+
// Verify session fingerprints match
|
|
202
|
+
expect(dappSession.sessionFingerprint).toBe(walletSession.sessionFingerprint);
|
|
203
|
+
|
|
204
|
+
await wait();
|
|
205
|
+
|
|
206
|
+
expect(dappSession.phase).toBe('connected');
|
|
207
|
+
expect(walletSession.phase).toBe('connected');
|
|
208
|
+
|
|
209
|
+
// Wallet handles requests
|
|
210
|
+
walletSession.on('request', ({ id, method, params }) => {
|
|
211
|
+
if (method === 'wallet_getAccounts') {
|
|
212
|
+
walletSession.approve(id, ['0xBiDi']);
|
|
213
|
+
} else if (method === 'wallet_signMessage') {
|
|
214
|
+
walletSession.approve(id, { signature: '0xSIG' });
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// DApp sends request (uses dappToWalletKey), wallet decrypts (uses dappToWalletKey as recvKey)
|
|
219
|
+
const accounts = await dappSession.request('wallet_getAccounts');
|
|
220
|
+
expect(accounts).toEqual(['0xBiDi']);
|
|
221
|
+
|
|
222
|
+
// 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
|
+
});
|
|
226
|
+
|
|
227
|
+
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);
|
|
231
|
+
|
|
232
|
+
const dappSession = new DAppSession({ transport: dappTransport, meta: { name: 'Test dApp', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' } });
|
|
233
|
+
const walletSession = new WalletSession({
|
|
234
|
+
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
|
+
});
|
|
238
|
+
|
|
239
|
+
const uri = await dappSession.createPairing();
|
|
240
|
+
await walletSession.joinFromUri(uri);
|
|
241
|
+
await wait();
|
|
242
|
+
await wait();
|
|
243
|
+
|
|
244
|
+
const events: Array<{ event: string; data: unknown }> = [];
|
|
245
|
+
dappSession.on('event', (evt) => events.push(evt));
|
|
246
|
+
|
|
247
|
+
// Push multiple events
|
|
248
|
+
walletSession.pushEvent('accountsChanged', { accounts: ['0xNew'] });
|
|
249
|
+
walletSession.pushEvent('chainChanged', { chainId: 'eip155:137' });
|
|
250
|
+
await wait();
|
|
251
|
+
|
|
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
|
+
});
|
|
256
|
+
|
|
257
|
+
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);
|
|
261
|
+
|
|
262
|
+
const dappSession = new DAppSession({ transport: dappTransport, meta: { name: 'Test dApp', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' } });
|
|
263
|
+
const walletSession = new WalletSession({
|
|
264
|
+
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
|
+
});
|
|
268
|
+
|
|
269
|
+
const uri = await dappSession.createPairing();
|
|
270
|
+
await walletSession.joinFromUri(uri);
|
|
271
|
+
await wait();
|
|
272
|
+
await wait();
|
|
273
|
+
|
|
274
|
+
// Wallet responds to each request with method-specific data, but with a delay
|
|
275
|
+
walletSession.on('request', ({ id, method }) => {
|
|
276
|
+
if (method === 'wallet_getAccounts') {
|
|
277
|
+
// Respond immediately
|
|
278
|
+
walletSession.approve(id, ['0xABC']);
|
|
279
|
+
} else if (method === 'wallet_signMessage') {
|
|
280
|
+
// Respond slightly delayed
|
|
281
|
+
setTimeout(() => walletSession.approve(id, '0xSIG123'), 10);
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
// Fire both concurrently
|
|
286
|
+
const [accounts, signature] = await Promise.all([
|
|
287
|
+
dappSession.request('wallet_getAccounts'),
|
|
288
|
+
dappSession.request('wallet_signMessage', { message: 'hello' }),
|
|
289
|
+
]);
|
|
290
|
+
|
|
291
|
+
expect(accounts).toEqual(['0xABC']);
|
|
292
|
+
expect(signature).toBe('0xSIG123');
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('session serialization preserves directional keys', async () => {
|
|
296
|
+
const dappTransport = new MockTransport();
|
|
297
|
+
const walletTransport = new MockTransport();
|
|
298
|
+
const _relay = new MockRelay(dappTransport, walletTransport);
|
|
299
|
+
|
|
300
|
+
const dappSession = new DAppSession({ transport: dappTransport, meta: { name: 'Persist dApp', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' } });
|
|
301
|
+
const walletSession = new WalletSession({
|
|
302
|
+
transport: walletTransport,
|
|
303
|
+
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
|
+
});
|
|
306
|
+
|
|
307
|
+
const uri = await dappSession.createPairing();
|
|
308
|
+
await walletSession.joinFromUri(uri);
|
|
309
|
+
await wait();
|
|
310
|
+
await wait();
|
|
311
|
+
|
|
312
|
+
// Serialize both sessions
|
|
313
|
+
const dappJson = dappSession.serialize();
|
|
314
|
+
const walletJson = walletSession.serialize();
|
|
315
|
+
|
|
316
|
+
// Parse and verify directional keys are stored
|
|
317
|
+
const dappState = parseSnapshot(dappJson);
|
|
318
|
+
const walletState = parseSnapshot(walletJson);
|
|
319
|
+
|
|
320
|
+
expect(dappState.sendKey).toBeTruthy();
|
|
321
|
+
expect(dappState.recvKey).toBeTruthy();
|
|
322
|
+
expect(walletState.sendKey).toBeTruthy();
|
|
323
|
+
expect(walletState.recvKey).toBeTruthy();
|
|
324
|
+
|
|
325
|
+
// DApp sendKey (dappToWalletKey) == Wallet recvKey (dappToWalletKey)
|
|
326
|
+
expect(dappState.sendKey).toBe(walletState.recvKey);
|
|
327
|
+
// DApp recvKey (walletToDappKey) == Wallet sendKey (walletToDappKey)
|
|
328
|
+
expect(dappState.recvKey).toBe(walletState.sendKey);
|
|
329
|
+
|
|
330
|
+
// sendKey != recvKey (directional)
|
|
331
|
+
expect(dappState.sendKey).not.toBe(dappState.recvKey);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it('restored session can still communicate', async () => {
|
|
335
|
+
const dappTransport = new MockTransport();
|
|
336
|
+
const walletTransport = new MockTransport();
|
|
337
|
+
const _relay = new MockRelay(dappTransport, walletTransport);
|
|
338
|
+
|
|
339
|
+
const dappSession = new DAppSession({ transport: dappTransport, meta: { name: 'Restore dApp', description: 'Test', url: 'https://test.com', icon: 'https://test.com/icon.png' } });
|
|
340
|
+
const walletSession = new WalletSession({
|
|
341
|
+
transport: walletTransport,
|
|
342
|
+
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
|
+
});
|
|
345
|
+
|
|
346
|
+
const uri = await dappSession.createPairing();
|
|
347
|
+
await walletSession.joinFromUri(uri);
|
|
348
|
+
await wait();
|
|
349
|
+
await wait();
|
|
350
|
+
|
|
351
|
+
// 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');
|
|
355
|
+
|
|
356
|
+
// Serialize
|
|
357
|
+
const dappJson = dappSession.serialize();
|
|
358
|
+
const walletJson = walletSession.serialize();
|
|
359
|
+
|
|
360
|
+
// 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';
|
|
369
|
+
|
|
370
|
+
const restoredWallet = new WalletSession({
|
|
371
|
+
transport: newWalletTransport,
|
|
372
|
+
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';
|
|
377
|
+
|
|
378
|
+
// Set up request handler on restored wallet
|
|
379
|
+
restoredWallet.on('request', ({ id }) => restoredWallet.approve(id, 'restored'));
|
|
380
|
+
|
|
381
|
+
// Restored dApp sends request through linked transports
|
|
382
|
+
const r2 = await restoredDapp.request('wallet_getAccounts');
|
|
383
|
+
expect(r2).toBe('restored');
|
|
384
|
+
});
|
|
385
|
+
});
|