@mictonode/widget 0.3.22 → 0.3.23
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 +2 -2
- package/dist/{ConstantsUtil-df193f67.js → ConstantsUtil-f9dc60b6.js} +3 -3
- package/dist/{ConstantsUtil-1b0c0436.js → ConstantsUtil-fb0ff2e5.js} +1 -1
- package/dist/{ExchangeController-953f14bc.js → ExchangeController-173fd1dc.js} +2 -2
- package/dist/{HelpersUtil-3810bb58.js → HelpersUtil-4891ff5f.js} +4 -4
- package/dist/{ReownAuthentication-7c5b6e79.js → ReownAuthentication-bba89dc5.js} +2 -2
- package/dist/{SwapController-e1a7b5f8.js → SwapController-e8b097ca.js} +3 -3
- package/dist/{abis-61cccfbf.js → abis-96fed285.js} +1 -1
- package/dist/{assertCurrentChain-0c3d6c93.js → assertCurrentChain-b60aa59f.js} +1 -1
- package/dist/{ccip-80fe88fb.js → ccip-8f82ae2a.js} +6 -6
- package/dist/{data-capture-7edeb077.js → data-capture-7009ffa0.js} +8 -8
- package/dist/{email-40537ec5.js → email-d6e2da58.js} +12 -12
- package/dist/{embedded-wallet-f71f6169.js → embedded-wallet-48284179.js} +14 -14
- package/dist/{encodeFunctionData-91e7c0f6.js → encodeFunctionData-b24a0b2b.js} +2 -2
- package/dist/{fallback-1ab5a270.js → fallback-ae0315d4.js} +2 -2
- package/dist/features-82db0d52.js +8 -0
- package/dist/{hashTypedData-1e059dc4.js → hashTypedData-c13ba550.js} +2 -2
- package/dist/{http-d9e0a50a.js → http-90ef23f3.js} +2 -2
- package/dist/{index-d3f36c31.js → index-0ac134af.js} +34 -34
- package/dist/{index-2cd6a2b2.js → index-19f302c4.js} +3 -3
- package/dist/{index-78c5b9e2.js → index-22727038.js} +3 -3
- package/dist/{index-144edd3f.js → index-270ff8a2.js} +11 -11
- package/dist/{index-abb0ff46.js → index-29eb95bd.js} +3 -3
- package/dist/{index-9cc1116b.js → index-2a90711e.js} +2 -2
- package/dist/{index-289a865f.js → index-2de6c5bf.js} +4 -4
- package/dist/{index-fbced89b.js → index-3de7fa96.js} +3 -3
- package/dist/{index-26b53c8a.js → index-42a8a5ec.js} +15 -15
- package/dist/{index-58ec291c.js → index-4bd03aed.js} +7 -7
- package/dist/{index-85bc86d7.js → index-52edc95a.js} +2 -2
- package/dist/{index-04dd1ab3.js → index-577d2709.js} +4 -4
- package/dist/{index-4a4ee1e7.js → index-582e4199.js} +7 -7
- package/dist/{index-72706598.js → index-617b2147.js} +6 -6
- package/dist/{index-0b6166c5.js → index-6a0902fc.js} +2 -2
- package/dist/{index-a37d4c03.js → index-6d51f24f.js} +2 -2
- package/dist/{index-759b09b0.js → index-80954332.js} +3 -3
- package/dist/{index-0e2c49ad.js → index-95777860.js} +7 -7
- package/dist/{index-d9effd37.js → index-96729706.js} +13 -13
- package/dist/{index-39f31546.js → index-997bc756.js} +2 -2
- package/dist/{index-cb4d3345.js → index-a41841e6.js} +3 -3
- package/dist/{index-c10f5e72.js → index-adaa2ea4.js} +3 -3
- package/dist/{index-97b58f89.js → index-b37b670f.js} +11 -11
- package/dist/{index-0763de43.js → index-b8e2c282.js} +3 -3
- package/dist/{index-1f02e7d0.js → index-bb5e4071.js} +1 -1
- package/dist/{index-3678e7d8.js → index-bf40b971.js} +2 -2
- package/dist/{index-a4f054e9.js → index-cb69565e.js} +2 -2
- package/dist/{index-197dfd69.js → index-cbb6096a.js} +3 -3
- package/dist/{index-119c358f.js → index-ce6854ef.js} +14 -14
- package/dist/{index-4fdc7a25.js → index-d7e2a4a3.js} +2 -2
- package/dist/{index-0176180b.js → index-e7fbb597.js} +4 -4
- package/dist/{index-d5e3e4ba.js → index-f4cd8dd1.js} +3 -3
- package/dist/{index-a0c590f7.js → index-f886cf92.js} +2 -2
- package/dist/{index-95e1a01b.js → index-faade258.js} +3 -3
- package/dist/{localBatchGatewayRequest-8fd1b198.js → localBatchGatewayRequest-ade4aa2f.js} +3 -3
- package/dist/{main-7ddb238e.js → main-3b573cfc.js} +38694 -38472
- package/dist/{networks-d2ae1da7.js → networks-446d3512.js} +10 -10
- package/dist/{onramp-2966f1b1.js → onramp-57d19c5d.js} +19 -19
- package/dist/{parseSignature-fca372a1.js → parseSignature-783d626a.js} +8 -8
- package/dist/{pay-with-exchange-b0198b3f.js → pay-with-exchange-c59a5773.js} +22 -22
- package/dist/ping-widget.js +1 -1
- package/dist/ping-widget.umd.cjs +680 -680
- package/dist/{query.lcd-873499ca.js → query.lcd-447fb91a.js} +1 -1
- package/dist/{query.rpc.Query-d2bcf632.js → query.rpc.Query-97503d87.js} +1 -1
- package/dist/{receive-6fbb6662.js → receive-3073a49d.js} +6 -6
- package/dist/{ref-2c86b029.js → ref-6c3aabc7.js} +2 -2
- package/dist/{send-630ed203.js → send-42403797.js} +22 -22
- package/dist/{serializeAuthorizationList-e95a85d8.js → serializeAuthorizationList-70ec977c.js} +4 -4
- package/dist/{sha2-c04ffd62.js → sha2-249ae7eb.js} +2 -2
- package/dist/{socials-73a5efb0.js → socials-69b0cf18.js} +18 -18
- package/dist/{swaps-7b57265f.js → swaps-4e99bb0f.js} +18 -18
- package/dist/{transactions-876c066c.js → transactions-1d0c2669.js} +9 -9
- package/dist/{tx.rpc.msg-4d8bd1a4.js → tx.rpc.msg-8aa727ea.js} +1 -1
- package/dist/{tx.rpc.msg-d08b8ebe.js → tx.rpc.msg-a26b3557.js} +1 -1
- package/dist/{verifyHash-ee28e3d7.js → verifyHash-c8962067.js} +5 -5
- package/dist/{vue-bea1a08b.js → vue-9dc93a14.js} +10 -10
- package/dist/{w3m-modal-7d61c210.js → w3m-modal-291afec4.js} +25 -25
- package/dist/{zora-1091e7bb.js → zora-061565b0.js} +4 -4
- package/lib/components/ConnectWallet/index.vue +113 -31
- package/lib/wallet/KeplrSessionManager.ts +142 -0
- package/lib/wallet/WalletSessionManager.ts +111 -25
- package/lib/wallet/reown/EvmNetworkProvisioner.ts +97 -0
- package/lib/wallet/reown/ReownGateway.ts +22 -3
- package/package.json +1 -1
- package/test/components/ConnectWallet.test.ts +640 -2
- package/test/components/ConnectWalletStorage.test.ts +113 -3
- package/test/wallet/KeplrSessionManager.test.ts +269 -0
- package/test/wallet/WalletSessionManager.test.ts +901 -2
- package/test/wallet/reown/EvmNetworkProvisioner.test.ts +264 -0
- package/test/wallet/reown/ReownGateway.test.ts +66 -1
- package/dist/features-a2f2ff4f.js +0 -8
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { mount } from '@vue/test-utils';
|
|
1
|
+
import { flushPromises, mount } from '@vue/test-utils';
|
|
2
2
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
3
|
import ConnectWallet from '../../lib/components/ConnectWallet/index.vue';
|
|
4
4
|
import {
|
|
5
|
+
createWallet,
|
|
6
|
+
type ConnectedWallet,
|
|
5
7
|
WalletName,
|
|
6
8
|
readWallet,
|
|
7
9
|
removeWallet,
|
|
@@ -15,6 +17,12 @@ const sessionMocks = vi.hoisted(() => ({
|
|
|
15
17
|
start: vi.fn(async () => undefined),
|
|
16
18
|
}));
|
|
17
19
|
|
|
20
|
+
const keplrSessionMocks = vi.hoisted(() => ({
|
|
21
|
+
paths: [] as string[],
|
|
22
|
+
dispose: vi.fn(),
|
|
23
|
+
start: vi.fn(async () => undefined),
|
|
24
|
+
}));
|
|
25
|
+
|
|
18
26
|
vi.mock('../../lib/wallet/WalletSessionManager', () => ({
|
|
19
27
|
WalletSessionManager: class WalletSessionManager {
|
|
20
28
|
constructor(hdPath: string) {
|
|
@@ -27,6 +35,16 @@ vi.mock('../../lib/wallet/WalletSessionManager', () => ({
|
|
|
27
35
|
},
|
|
28
36
|
}));
|
|
29
37
|
|
|
38
|
+
vi.mock('../../lib/wallet/KeplrSessionManager', () => ({
|
|
39
|
+
KeplrSessionManager: class KeplrSessionManager {
|
|
40
|
+
constructor(hdPath: string) {
|
|
41
|
+
keplrSessionMocks.paths.push(hdPath);
|
|
42
|
+
}
|
|
43
|
+
dispose = keplrSessionMocks.dispose;
|
|
44
|
+
start = keplrSessionMocks.start;
|
|
45
|
+
},
|
|
46
|
+
}));
|
|
47
|
+
|
|
30
48
|
vi.mock('../../lib/wallet/Wallet', () => ({
|
|
31
49
|
WalletName: {
|
|
32
50
|
Keplr: 'Keplr',
|
|
@@ -51,6 +69,7 @@ interface MountWalletOptions {
|
|
|
51
69
|
hdPath?: string;
|
|
52
70
|
evmConfig?: string;
|
|
53
71
|
params?: string;
|
|
72
|
+
onDisconnect?: (payload: unknown) => void;
|
|
54
73
|
}
|
|
55
74
|
|
|
56
75
|
const evmConfig = JSON.stringify({
|
|
@@ -72,6 +91,16 @@ const evmConfig = JSON.stringify({
|
|
|
72
91
|
featuredWalletIds: [],
|
|
73
92
|
});
|
|
74
93
|
|
|
94
|
+
function deferred<T>() {
|
|
95
|
+
let resolve!: (value: T | PromiseLike<T>) => void;
|
|
96
|
+
let reject!: (reason?: unknown) => void;
|
|
97
|
+
const promise = new Promise<T>((resolvePromise, rejectPromise) => {
|
|
98
|
+
resolve = resolvePromise;
|
|
99
|
+
reject = rejectPromise;
|
|
100
|
+
});
|
|
101
|
+
return { promise, resolve, reject };
|
|
102
|
+
}
|
|
103
|
+
|
|
75
104
|
function mountWallet(options: MountWalletOptions = {}) {
|
|
76
105
|
return mount(ConnectWallet, {
|
|
77
106
|
props: {
|
|
@@ -81,6 +110,9 @@ function mountWallet(options: MountWalletOptions = {}) {
|
|
|
81
110
|
addrPrefix: 'warden',
|
|
82
111
|
evmConfig: options.evmConfig,
|
|
83
112
|
},
|
|
113
|
+
attrs: {
|
|
114
|
+
onDisconnect: options.onDisconnect,
|
|
115
|
+
},
|
|
84
116
|
global: {
|
|
85
117
|
stubs: {
|
|
86
118
|
Icon: true,
|
|
@@ -93,6 +125,7 @@ describe('ConnectWallet', () => {
|
|
|
93
125
|
beforeEach(() => {
|
|
94
126
|
vi.clearAllMocks();
|
|
95
127
|
sessionMocks.paths.length = 0;
|
|
128
|
+
keplrSessionMocks.paths.length = 0;
|
|
96
129
|
vi.mocked(readWallet).mockReturnValue({} as ReturnType<typeof readWallet>);
|
|
97
130
|
});
|
|
98
131
|
|
|
@@ -163,6 +196,211 @@ describe('ConnectWallet', () => {
|
|
|
163
196
|
);
|
|
164
197
|
});
|
|
165
198
|
|
|
199
|
+
it('revalidates a persisted Keplr session on mount', async () => {
|
|
200
|
+
const persisted = {
|
|
201
|
+
wallet: WalletName.Keplr,
|
|
202
|
+
cosmosAddress: 'cosmos1stored',
|
|
203
|
+
hdPath: "m/44'/118/0'/0/0",
|
|
204
|
+
};
|
|
205
|
+
vi.mocked(readWallet).mockReturnValue(persisted);
|
|
206
|
+
keplrSessionMocks.start.mockImplementationOnce(
|
|
207
|
+
async (_argument, onChange) => {
|
|
208
|
+
onChange(undefined);
|
|
209
|
+
onChange(persisted);
|
|
210
|
+
},
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
const wrapper = mountWallet();
|
|
214
|
+
|
|
215
|
+
await vi.waitFor(() =>
|
|
216
|
+
expect(keplrSessionMocks.start).toHaveBeenCalledWith(
|
|
217
|
+
expect.objectContaining({
|
|
218
|
+
chainId: 'barra_9191-1',
|
|
219
|
+
hdPath: persisted.hdPath,
|
|
220
|
+
prefix: 'warden',
|
|
221
|
+
}),
|
|
222
|
+
expect.any(Function),
|
|
223
|
+
expect.any(Function),
|
|
224
|
+
),
|
|
225
|
+
);
|
|
226
|
+
expect(wrapper.emitted('disconnect')).toEqual([
|
|
227
|
+
[{ value: undefined }],
|
|
228
|
+
]);
|
|
229
|
+
expect(wrapper.emitted('connect')).toEqual([
|
|
230
|
+
[{ value: persisted }],
|
|
231
|
+
]);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('routes manual Keplr connection through KeplrSessionManager', async () => {
|
|
235
|
+
const wrapper = mountWallet();
|
|
236
|
+
const option = wrapper
|
|
237
|
+
.findAll('li')
|
|
238
|
+
.find((item) => item.text().includes(WalletName.Keplr));
|
|
239
|
+
|
|
240
|
+
await option?.trigger('click');
|
|
241
|
+
await wrapper.get('.ping-connect-confirm').trigger('click');
|
|
242
|
+
|
|
243
|
+
expect(keplrSessionMocks.start).toHaveBeenCalledWith(
|
|
244
|
+
expect.objectContaining({
|
|
245
|
+
chainId: 'barra_9191-1',
|
|
246
|
+
hdPath: "m/44'/118/0'/0/0",
|
|
247
|
+
prefix: 'warden',
|
|
248
|
+
}),
|
|
249
|
+
expect.any(Function),
|
|
250
|
+
expect.any(Function),
|
|
251
|
+
);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('keeps the Keplr dialog open when manual validation fails', async () => {
|
|
255
|
+
keplrSessionMocks.start.mockImplementationOnce(
|
|
256
|
+
async (_argument, _onChange, onError) => {
|
|
257
|
+
onError({ message: 'Keplr unavailable' });
|
|
258
|
+
},
|
|
259
|
+
);
|
|
260
|
+
const wrapper = mountWallet();
|
|
261
|
+
|
|
262
|
+
await wrapper.get('#PingConnectWallet').setValue(true);
|
|
263
|
+
await wrapper.get('.ping-connect-confirm').trigger('click');
|
|
264
|
+
|
|
265
|
+
expect(
|
|
266
|
+
(wrapper.get('#PingConnectWallet').element as HTMLInputElement).checked,
|
|
267
|
+
).toBe(true);
|
|
268
|
+
expect(wrapper.text()).toContain('Keplr unavailable');
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('does not reopen the Keplr dialog for a later refresh failure', async () => {
|
|
272
|
+
let reportRefreshFailure!: (error: { message: string }) => void;
|
|
273
|
+
keplrSessionMocks.start.mockImplementationOnce(
|
|
274
|
+
async (_argument, _onChange, onError) => {
|
|
275
|
+
reportRefreshFailure = onError;
|
|
276
|
+
},
|
|
277
|
+
);
|
|
278
|
+
const wrapper = mountWallet();
|
|
279
|
+
|
|
280
|
+
await wrapper.get('#PingConnectWallet').setValue(true);
|
|
281
|
+
await wrapper.get('.ping-connect-confirm').trigger('click');
|
|
282
|
+
expect(
|
|
283
|
+
(wrapper.get('#PingConnectWallet').element as HTMLInputElement).checked,
|
|
284
|
+
).toBe(false);
|
|
285
|
+
|
|
286
|
+
reportRefreshFailure({ message: 'Keplr refresh unavailable' });
|
|
287
|
+
await flushPromises();
|
|
288
|
+
|
|
289
|
+
expect(
|
|
290
|
+
(wrapper.get('#PingConnectWallet').element as HTMLInputElement).checked,
|
|
291
|
+
).toBe(false);
|
|
292
|
+
expect(wrapper.text()).toContain('Keplr refresh unavailable');
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('isolates a replacement wallet from stale Keplr callbacks', async () => {
|
|
296
|
+
const wrapper = mountWallet();
|
|
297
|
+
await flushPromises();
|
|
298
|
+
sessionMocks.dispose.mockClear();
|
|
299
|
+
keplrSessionMocks.dispose.mockClear();
|
|
300
|
+
let staleChange!: (value: ConnectedWallet | undefined) => void;
|
|
301
|
+
let staleError!: (error: { message: string }) => void;
|
|
302
|
+
keplrSessionMocks.start.mockImplementationOnce(
|
|
303
|
+
async (_argument, onChange, onError) => {
|
|
304
|
+
staleChange = onChange;
|
|
305
|
+
staleError = onError;
|
|
306
|
+
onError({ message: 'Initial Keplr failure' });
|
|
307
|
+
},
|
|
308
|
+
);
|
|
309
|
+
vi.mocked(createWallet).mockReturnValue({
|
|
310
|
+
getAccounts: vi.fn(async () => [{
|
|
311
|
+
address: 'cosmos1ledger',
|
|
312
|
+
algo: 'secp256k1',
|
|
313
|
+
pubkey: new Uint8Array([1]),
|
|
314
|
+
}]),
|
|
315
|
+
} as unknown as ReturnType<typeof createWallet>);
|
|
316
|
+
|
|
317
|
+
await wrapper.get('.ping-connect-confirm').trigger('click');
|
|
318
|
+
const ledgerOption = wrapper
|
|
319
|
+
.findAll('li')
|
|
320
|
+
.find((item) => item.text().includes(WalletName.Ledger));
|
|
321
|
+
await ledgerOption?.trigger('click');
|
|
322
|
+
await wrapper.get('.ping-connect-confirm').trigger('click');
|
|
323
|
+
await vi.waitFor(() =>
|
|
324
|
+
expect(wrapper.text()).toContain('cosmos1ledger'),
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
staleChange({
|
|
328
|
+
wallet: WalletName.Keplr,
|
|
329
|
+
cosmosAddress: 'cosmos1stale',
|
|
330
|
+
hdPath: "m/44'/118/0'/0/0",
|
|
331
|
+
});
|
|
332
|
+
staleError({ message: 'Stale Keplr refresh' });
|
|
333
|
+
await flushPromises();
|
|
334
|
+
|
|
335
|
+
expect(keplrSessionMocks.dispose).toHaveBeenCalledTimes(2);
|
|
336
|
+
expect(sessionMocks.dispose).toHaveBeenCalledTimes(2);
|
|
337
|
+
expect(wrapper.text()).toContain('cosmos1ledger');
|
|
338
|
+
expect(wrapper.text()).not.toContain('cosmos1stale');
|
|
339
|
+
expect(wrapper.text()).not.toContain('Stale Keplr refresh');
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
it('isolates a replacement wallet from a pending Reown attempt', async () => {
|
|
343
|
+
const wrapper = mountWallet({
|
|
344
|
+
hdPath: "m/44'/60/0'/0/0",
|
|
345
|
+
evmConfig,
|
|
346
|
+
});
|
|
347
|
+
await flushPromises();
|
|
348
|
+
sessionMocks.dispose.mockClear();
|
|
349
|
+
keplrSessionMocks.dispose.mockClear();
|
|
350
|
+
const pending = deferred<void>();
|
|
351
|
+
let staleChange!: (value: ConnectedWallet | undefined) => void;
|
|
352
|
+
let staleError!: (error: { message: string }) => void;
|
|
353
|
+
sessionMocks.connect.mockImplementationOnce(
|
|
354
|
+
async (_config, _argument, onChange, onError) => {
|
|
355
|
+
staleChange = onChange;
|
|
356
|
+
staleError = onError;
|
|
357
|
+
await pending.promise;
|
|
358
|
+
},
|
|
359
|
+
);
|
|
360
|
+
vi.mocked(createWallet).mockReturnValue({
|
|
361
|
+
getAccounts: vi.fn(async () => [{
|
|
362
|
+
address: 'cosmos1ledger',
|
|
363
|
+
algo: 'secp256k1',
|
|
364
|
+
pubkey: new Uint8Array([1]),
|
|
365
|
+
}]),
|
|
366
|
+
} as unknown as ReturnType<typeof createWallet>);
|
|
367
|
+
const evmOption = wrapper
|
|
368
|
+
.findAll('li')
|
|
369
|
+
.find((item) => item.text().includes(WalletName.Evm));
|
|
370
|
+
await evmOption?.trigger('click');
|
|
371
|
+
await wrapper.get('.ping-connect-confirm').trigger('click');
|
|
372
|
+
await vi.waitFor(() => expect(sessionMocks.connect).toHaveBeenCalledOnce());
|
|
373
|
+
|
|
374
|
+
const ledgerOption = wrapper
|
|
375
|
+
.findAll('li')
|
|
376
|
+
.find((item) => item.text().includes(WalletName.Ledger));
|
|
377
|
+
await ledgerOption?.trigger('click');
|
|
378
|
+
await wrapper.get('.ping-connect-confirm').trigger('click');
|
|
379
|
+
await vi.waitFor(() =>
|
|
380
|
+
expect(wrapper.text()).toContain('cosmos1ledger'),
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
staleChange({
|
|
384
|
+
version: 2,
|
|
385
|
+
wallet: WalletName.Evm,
|
|
386
|
+
cosmosAddress: 'warden1stale',
|
|
387
|
+
hdPath: "m/44'/60/0'/0/0",
|
|
388
|
+
connector: {
|
|
389
|
+
source: 'reown',
|
|
390
|
+
name: 'Stale Wallet',
|
|
391
|
+
},
|
|
392
|
+
});
|
|
393
|
+
staleError({ message: 'Stale Reown callback' });
|
|
394
|
+
pending.reject(new Error('Stale Reown rejection'));
|
|
395
|
+
await flushPromises();
|
|
396
|
+
|
|
397
|
+
expect(keplrSessionMocks.dispose).toHaveBeenCalledTimes(2);
|
|
398
|
+
expect(sessionMocks.dispose).toHaveBeenCalledTimes(2);
|
|
399
|
+
expect(wrapper.text()).toContain('cosmos1ledger');
|
|
400
|
+
expect(wrapper.text()).not.toContain('warden1stale');
|
|
401
|
+
expect(wrapper.text()).not.toContain('Stale Reown');
|
|
402
|
+
});
|
|
403
|
+
|
|
166
404
|
it('clears storage and emits the previous connection on disconnect', async () => {
|
|
167
405
|
const connected = {
|
|
168
406
|
wallet: WalletName.Keplr,
|
|
@@ -170,13 +408,172 @@ describe('ConnectWallet', () => {
|
|
|
170
408
|
hdPath: "m/44'/118/0'/0/0",
|
|
171
409
|
};
|
|
172
410
|
vi.mocked(readWallet).mockReturnValue(connected);
|
|
411
|
+
keplrSessionMocks.start.mockImplementationOnce(
|
|
412
|
+
async (_argument, onChange) => {
|
|
413
|
+
onChange(undefined);
|
|
414
|
+
onChange(connected);
|
|
415
|
+
},
|
|
416
|
+
);
|
|
173
417
|
const wrapper = mountWallet();
|
|
174
418
|
|
|
419
|
+
await vi.waitFor(() =>
|
|
420
|
+
expect(wrapper.find('[data-testid="wallet-disconnect"]').exists()).toBe(true),
|
|
421
|
+
);
|
|
175
422
|
await wrapper.get('[data-testid="wallet-disconnect"]').trigger('click');
|
|
176
423
|
|
|
177
424
|
expect(removeWallet).toHaveBeenCalledWith(connected.hdPath);
|
|
178
|
-
|
|
425
|
+
const disconnectEvents = wrapper.emitted('disconnect')!;
|
|
426
|
+
expect(disconnectEvents[0]).toEqual([{ value: undefined }]);
|
|
427
|
+
expect(disconnectEvents[disconnectEvents.length - 1]).toEqual([
|
|
428
|
+
{ value: connected },
|
|
429
|
+
]);
|
|
430
|
+
expect(wrapper.text()).toContain('Connect Wallet');
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
it('fails closed once when a direct EVM disconnect rejects', async () => {
|
|
434
|
+
const hdPath = "m/44'/60/0'/0/0";
|
|
435
|
+
const connected = {
|
|
436
|
+
version: 2 as const,
|
|
437
|
+
wallet: WalletName.Evm,
|
|
438
|
+
cosmosAddress: 'warden1connected',
|
|
439
|
+
hdPath,
|
|
440
|
+
connector: {
|
|
441
|
+
source: 'reown' as const,
|
|
442
|
+
name: 'Rabby Wallet',
|
|
443
|
+
},
|
|
444
|
+
};
|
|
445
|
+
vi.mocked(readWallet).mockReturnValue(connected);
|
|
446
|
+
sessionMocks.start.mockImplementationOnce(
|
|
447
|
+
async (_config, _argument, onChange) => onChange(connected),
|
|
448
|
+
);
|
|
449
|
+
const pending = deferred<void>();
|
|
450
|
+
sessionMocks.disconnect.mockImplementationOnce(async () => {
|
|
451
|
+
await pending.promise;
|
|
452
|
+
});
|
|
453
|
+
const onDisconnect = vi.fn();
|
|
454
|
+
const wrapper = mountWallet({ hdPath, evmConfig, onDisconnect });
|
|
455
|
+
await vi.waitFor(() =>
|
|
456
|
+
expect(wrapper.find('[data-testid="wallet-disconnect"]').exists()).toBe(true),
|
|
457
|
+
);
|
|
458
|
+
const disconnectCount = onDisconnect.mock.calls.length;
|
|
459
|
+
|
|
460
|
+
await wrapper.get('[data-testid="wallet-disconnect"]').trigger('click');
|
|
461
|
+
await vi.waitFor(() =>
|
|
462
|
+
expect(sessionMocks.disconnect).toHaveBeenCalledOnce(),
|
|
463
|
+
);
|
|
464
|
+
pending.reject(new Error('provider failure'));
|
|
465
|
+
await flushPromises();
|
|
466
|
+
|
|
467
|
+
expect(onDisconnect).toHaveBeenCalledTimes(disconnectCount + 1);
|
|
468
|
+
expect(onDisconnect).toHaveBeenLastCalledWith({ value: connected });
|
|
179
469
|
expect(wrapper.text()).toContain('Connect Wallet');
|
|
470
|
+
expect(wrapper.text()).toContain('Wallet request failed');
|
|
471
|
+
wrapper.unmount();
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
it('ignores a stale direct disconnect after a replacement wallet connects', async () => {
|
|
475
|
+
const hdPath = "m/44'/60/0'/0/0";
|
|
476
|
+
const connected = {
|
|
477
|
+
version: 2 as const,
|
|
478
|
+
wallet: WalletName.Evm,
|
|
479
|
+
cosmosAddress: 'warden1connected',
|
|
480
|
+
hdPath,
|
|
481
|
+
connector: {
|
|
482
|
+
source: 'reown' as const,
|
|
483
|
+
name: 'Rabby Wallet',
|
|
484
|
+
},
|
|
485
|
+
};
|
|
486
|
+
vi.mocked(readWallet).mockReturnValue(connected);
|
|
487
|
+
sessionMocks.start.mockImplementationOnce(
|
|
488
|
+
async (_config, _argument, onChange) => onChange(connected),
|
|
489
|
+
);
|
|
490
|
+
const pending = deferred<void>();
|
|
491
|
+
sessionMocks.disconnect.mockImplementationOnce(async () => {
|
|
492
|
+
await pending.promise;
|
|
493
|
+
});
|
|
494
|
+
vi.mocked(createWallet).mockReturnValue({
|
|
495
|
+
getAccounts: vi.fn(async () => [{
|
|
496
|
+
address: 'cosmos1ledger',
|
|
497
|
+
algo: 'secp256k1',
|
|
498
|
+
pubkey: new Uint8Array([1]),
|
|
499
|
+
}]),
|
|
500
|
+
} as unknown as ReturnType<typeof createWallet>);
|
|
501
|
+
const onDisconnect = vi.fn();
|
|
502
|
+
const wrapper = mountWallet({ hdPath, evmConfig, onDisconnect });
|
|
503
|
+
await vi.waitFor(() =>
|
|
504
|
+
expect(wrapper.find('[data-testid="wallet-disconnect"]').exists()).toBe(true),
|
|
505
|
+
);
|
|
506
|
+
|
|
507
|
+
await wrapper.get('[data-testid="wallet-disconnect"]').trigger('click');
|
|
508
|
+
await vi.waitFor(() =>
|
|
509
|
+
expect(sessionMocks.disconnect).toHaveBeenCalledOnce(),
|
|
510
|
+
);
|
|
511
|
+
const ledgerOption = wrapper
|
|
512
|
+
.findAll('li')
|
|
513
|
+
.find((item) => item.text().includes(WalletName.Ledger));
|
|
514
|
+
await ledgerOption?.trigger('click');
|
|
515
|
+
await wrapper.get('.ping-connect-confirm').trigger('click');
|
|
516
|
+
await vi.waitFor(() =>
|
|
517
|
+
expect(wrapper.text()).toContain('cosmos1ledger'),
|
|
518
|
+
);
|
|
519
|
+
const disconnectCount = onDisconnect.mock.calls.length;
|
|
520
|
+
|
|
521
|
+
pending.reject(new Error('stale provider failure'));
|
|
522
|
+
await flushPromises();
|
|
523
|
+
|
|
524
|
+
expect(onDisconnect).toHaveBeenCalledTimes(disconnectCount);
|
|
525
|
+
expect(wrapper.text()).toContain('cosmos1ledger');
|
|
526
|
+
expect(wrapper.text()).not.toContain('Wallet request failed');
|
|
527
|
+
wrapper.unmount();
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
it('ignores a stale direct disconnect completion after unmount', async () => {
|
|
531
|
+
const hdPath = "m/44'/60/0'/0/0";
|
|
532
|
+
const connected = {
|
|
533
|
+
version: 2 as const,
|
|
534
|
+
wallet: WalletName.Evm,
|
|
535
|
+
cosmosAddress: 'warden1connected',
|
|
536
|
+
hdPath,
|
|
537
|
+
connector: {
|
|
538
|
+
source: 'reown' as const,
|
|
539
|
+
name: 'Rabby Wallet',
|
|
540
|
+
},
|
|
541
|
+
};
|
|
542
|
+
vi.mocked(readWallet).mockReturnValue(connected);
|
|
543
|
+
sessionMocks.start.mockImplementationOnce(
|
|
544
|
+
async (_config, _argument, onChange) => onChange(connected),
|
|
545
|
+
);
|
|
546
|
+
const pending = deferred<void>();
|
|
547
|
+
sessionMocks.disconnect.mockImplementationOnce(async () => {
|
|
548
|
+
await pending.promise;
|
|
549
|
+
});
|
|
550
|
+
const onDisconnect = vi.fn();
|
|
551
|
+
const wrapper = mountWallet({ hdPath, evmConfig, onDisconnect });
|
|
552
|
+
await vi.waitFor(() =>
|
|
553
|
+
expect(wrapper.find('[data-testid="wallet-disconnect"]').exists()).toBe(true),
|
|
554
|
+
);
|
|
555
|
+
|
|
556
|
+
await wrapper.get('[data-testid="wallet-disconnect"]').trigger('click');
|
|
557
|
+
await vi.waitFor(() =>
|
|
558
|
+
expect(sessionMocks.disconnect).toHaveBeenCalledOnce(),
|
|
559
|
+
);
|
|
560
|
+
const setupState = (wrapper.vm as unknown as {
|
|
561
|
+
$: {
|
|
562
|
+
setupState: {
|
|
563
|
+
connected: ConnectedWallet;
|
|
564
|
+
error: string;
|
|
565
|
+
};
|
|
566
|
+
};
|
|
567
|
+
}).$.setupState;
|
|
568
|
+
const disconnectCount = onDisconnect.mock.calls.length;
|
|
569
|
+
wrapper.unmount();
|
|
570
|
+
|
|
571
|
+
pending.reject(new Error('stale provider failure'));
|
|
572
|
+
await flushPromises();
|
|
573
|
+
|
|
574
|
+
expect(onDisconnect).toHaveBeenCalledTimes(disconnectCount);
|
|
575
|
+
expect(setupState.error).toBe('');
|
|
576
|
+
expect(setupState.connected.cosmosAddress).toBe('warden1connected');
|
|
180
577
|
});
|
|
181
578
|
|
|
182
579
|
it('disconnects a persisted EVM session after the explorer event', async () => {
|
|
@@ -209,6 +606,162 @@ describe('ConnectWallet', () => {
|
|
|
209
606
|
wrapper.unmount();
|
|
210
607
|
});
|
|
211
608
|
|
|
609
|
+
it('fails closed when external EVM disconnect rejects', async () => {
|
|
610
|
+
const hdPath = "m/44'/60/0'/0/0";
|
|
611
|
+
const connected = {
|
|
612
|
+
version: 2 as const,
|
|
613
|
+
wallet: WalletName.Evm,
|
|
614
|
+
cosmosAddress: 'warden1connected',
|
|
615
|
+
hdPath,
|
|
616
|
+
connector: {
|
|
617
|
+
source: 'reown' as const,
|
|
618
|
+
name: 'Rabby Wallet',
|
|
619
|
+
},
|
|
620
|
+
};
|
|
621
|
+
vi.mocked(readWallet).mockReturnValue(connected);
|
|
622
|
+
sessionMocks.start.mockImplementationOnce(
|
|
623
|
+
async (_config, _argument, onChange) => onChange(connected),
|
|
624
|
+
);
|
|
625
|
+
sessionMocks.disconnect.mockRejectedValueOnce(
|
|
626
|
+
new Error('provider failure'),
|
|
627
|
+
);
|
|
628
|
+
const onDisconnect = vi.fn();
|
|
629
|
+
const wrapper = mountWallet({ hdPath, evmConfig, onDisconnect });
|
|
630
|
+
await vi.waitFor(() =>
|
|
631
|
+
expect(wrapper.find('[data-testid="wallet-disconnect"]').exists()).toBe(true),
|
|
632
|
+
);
|
|
633
|
+
const disconnectCount = onDisconnect.mock.calls.length;
|
|
634
|
+
|
|
635
|
+
window.dispatchEvent(
|
|
636
|
+
new CustomEvent('mictonode:wallet-disconnect', {
|
|
637
|
+
detail: { hdPath },
|
|
638
|
+
}),
|
|
639
|
+
);
|
|
640
|
+
await vi.waitFor(() =>
|
|
641
|
+
expect(sessionMocks.disconnect).toHaveBeenCalledOnce(),
|
|
642
|
+
);
|
|
643
|
+
await flushPromises();
|
|
644
|
+
|
|
645
|
+
expect(onDisconnect).toHaveBeenCalledTimes(disconnectCount + 1);
|
|
646
|
+
expect(onDisconnect).toHaveBeenLastCalledWith({ value: undefined });
|
|
647
|
+
expect(wrapper.text()).toContain('Connect Wallet');
|
|
648
|
+
expect(wrapper.text()).toContain('Wallet request failed');
|
|
649
|
+
wrapper.unmount();
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
it('ignores a stale external disconnect after a replacement wallet connects', async () => {
|
|
653
|
+
const hdPath = "m/44'/60/0'/0/0";
|
|
654
|
+
const connected = {
|
|
655
|
+
version: 2 as const,
|
|
656
|
+
wallet: WalletName.Evm,
|
|
657
|
+
cosmosAddress: 'warden1connected',
|
|
658
|
+
hdPath,
|
|
659
|
+
connector: {
|
|
660
|
+
source: 'reown' as const,
|
|
661
|
+
name: 'Rabby Wallet',
|
|
662
|
+
},
|
|
663
|
+
};
|
|
664
|
+
vi.mocked(readWallet).mockReturnValue(connected);
|
|
665
|
+
sessionMocks.start.mockImplementationOnce(
|
|
666
|
+
async (_config, _argument, onChange) => onChange(connected),
|
|
667
|
+
);
|
|
668
|
+
const pending = deferred<void>();
|
|
669
|
+
sessionMocks.disconnect.mockImplementationOnce(async () => {
|
|
670
|
+
await pending.promise;
|
|
671
|
+
});
|
|
672
|
+
vi.mocked(createWallet).mockReturnValue({
|
|
673
|
+
getAccounts: vi.fn(async () => [{
|
|
674
|
+
address: 'cosmos1ledger',
|
|
675
|
+
algo: 'secp256k1',
|
|
676
|
+
pubkey: new Uint8Array([1]),
|
|
677
|
+
}]),
|
|
678
|
+
} as unknown as ReturnType<typeof createWallet>);
|
|
679
|
+
const onDisconnect = vi.fn();
|
|
680
|
+
const wrapper = mountWallet({ hdPath, evmConfig, onDisconnect });
|
|
681
|
+
await vi.waitFor(() =>
|
|
682
|
+
expect(wrapper.find('[data-testid="wallet-disconnect"]').exists()).toBe(true),
|
|
683
|
+
);
|
|
684
|
+
|
|
685
|
+
window.dispatchEvent(
|
|
686
|
+
new CustomEvent('mictonode:wallet-disconnect', {
|
|
687
|
+
detail: { hdPath },
|
|
688
|
+
}),
|
|
689
|
+
);
|
|
690
|
+
await vi.waitFor(() =>
|
|
691
|
+
expect(sessionMocks.disconnect).toHaveBeenCalledOnce(),
|
|
692
|
+
);
|
|
693
|
+
const ledgerOption = wrapper
|
|
694
|
+
.findAll('li')
|
|
695
|
+
.find((item) => item.text().includes(WalletName.Ledger));
|
|
696
|
+
await ledgerOption?.trigger('click');
|
|
697
|
+
await wrapper.get('.ping-connect-confirm').trigger('click');
|
|
698
|
+
await vi.waitFor(() =>
|
|
699
|
+
expect(wrapper.text()).toContain('cosmos1ledger'),
|
|
700
|
+
);
|
|
701
|
+
const disconnectCount = onDisconnect.mock.calls.length;
|
|
702
|
+
|
|
703
|
+
pending.reject(new Error('stale provider failure'));
|
|
704
|
+
await flushPromises();
|
|
705
|
+
|
|
706
|
+
expect(onDisconnect).toHaveBeenCalledTimes(disconnectCount);
|
|
707
|
+
expect(wrapper.text()).toContain('cosmos1ledger');
|
|
708
|
+
expect(wrapper.text()).not.toContain('Wallet request failed');
|
|
709
|
+
wrapper.unmount();
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
it('ignores a stale external disconnect completion after unmount', async () => {
|
|
713
|
+
const hdPath = "m/44'/60/0'/0/0";
|
|
714
|
+
const connected = {
|
|
715
|
+
version: 2 as const,
|
|
716
|
+
wallet: WalletName.Evm,
|
|
717
|
+
cosmosAddress: 'warden1connected',
|
|
718
|
+
hdPath,
|
|
719
|
+
connector: {
|
|
720
|
+
source: 'reown' as const,
|
|
721
|
+
name: 'Rabby Wallet',
|
|
722
|
+
},
|
|
723
|
+
};
|
|
724
|
+
vi.mocked(readWallet).mockReturnValue(connected);
|
|
725
|
+
sessionMocks.start.mockImplementationOnce(
|
|
726
|
+
async (_config, _argument, onChange) => onChange(connected),
|
|
727
|
+
);
|
|
728
|
+
const pending = deferred<void>();
|
|
729
|
+
sessionMocks.disconnect.mockImplementationOnce(async () => {
|
|
730
|
+
await pending.promise;
|
|
731
|
+
});
|
|
732
|
+
const onDisconnect = vi.fn();
|
|
733
|
+
const wrapper = mountWallet({ hdPath, evmConfig, onDisconnect });
|
|
734
|
+
await vi.waitFor(() =>
|
|
735
|
+
expect(wrapper.find('[data-testid="wallet-disconnect"]').exists()).toBe(true),
|
|
736
|
+
);
|
|
737
|
+
|
|
738
|
+
window.dispatchEvent(
|
|
739
|
+
new CustomEvent('mictonode:wallet-disconnect', {
|
|
740
|
+
detail: { hdPath },
|
|
741
|
+
}),
|
|
742
|
+
);
|
|
743
|
+
await vi.waitFor(() =>
|
|
744
|
+
expect(sessionMocks.disconnect).toHaveBeenCalledOnce(),
|
|
745
|
+
);
|
|
746
|
+
const setupState = (wrapper.vm as unknown as {
|
|
747
|
+
$: {
|
|
748
|
+
setupState: {
|
|
749
|
+
connected: ConnectedWallet;
|
|
750
|
+
error: string;
|
|
751
|
+
};
|
|
752
|
+
};
|
|
753
|
+
}).$.setupState;
|
|
754
|
+
const disconnectCount = onDisconnect.mock.calls.length;
|
|
755
|
+
wrapper.unmount();
|
|
756
|
+
|
|
757
|
+
pending.reject(new Error('stale provider failure'));
|
|
758
|
+
await flushPromises();
|
|
759
|
+
|
|
760
|
+
expect(onDisconnect).toHaveBeenCalledTimes(disconnectCount);
|
|
761
|
+
expect(setupState.error).toBe('');
|
|
762
|
+
expect(setupState.connected.cosmosAddress).toBe('warden1connected');
|
|
763
|
+
});
|
|
764
|
+
|
|
212
765
|
it('rebinds the session manager when the active chain HD path changes', async () => {
|
|
213
766
|
const evmHdPath = "m/44'/60/0'/0/0";
|
|
214
767
|
const evmWallet = {
|
|
@@ -248,4 +801,89 @@ describe('ConnectWallet', () => {
|
|
|
248
801
|
);
|
|
249
802
|
expect(sessionMocks.dispose).toHaveBeenCalled();
|
|
250
803
|
});
|
|
804
|
+
|
|
805
|
+
it('disposes both manager types when wallet context changes', async () => {
|
|
806
|
+
const wrapper = mountWallet();
|
|
807
|
+
|
|
808
|
+
await wrapper.setProps({
|
|
809
|
+
chainId: 'cosmoshub-4',
|
|
810
|
+
addrPrefix: 'cosmos',
|
|
811
|
+
});
|
|
812
|
+
await vi.waitFor(() => {
|
|
813
|
+
expect(keplrSessionMocks.dispose).toHaveBeenCalled();
|
|
814
|
+
expect(sessionMocks.dispose).toHaveBeenCalled();
|
|
815
|
+
});
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
it('ignores a stale Reown restore rejection after context replacement', async () => {
|
|
819
|
+
const oldHdPath = "m/44'/60/0'/0/0";
|
|
820
|
+
const newHdPath = "m/44'/118/0'/0/0";
|
|
821
|
+
const oldConnection = {
|
|
822
|
+
version: 2 as const,
|
|
823
|
+
wallet: WalletName.Evm,
|
|
824
|
+
cosmosAddress: 'warden1old',
|
|
825
|
+
hdPath: oldHdPath,
|
|
826
|
+
connector: {
|
|
827
|
+
source: 'reown' as const,
|
|
828
|
+
name: 'Rabby Wallet',
|
|
829
|
+
},
|
|
830
|
+
};
|
|
831
|
+
const replacement = {
|
|
832
|
+
wallet: WalletName.Ledger,
|
|
833
|
+
cosmosAddress: 'cosmos1replacement',
|
|
834
|
+
hdPath: newHdPath,
|
|
835
|
+
};
|
|
836
|
+
vi.mocked(readWallet).mockImplementation((path) =>
|
|
837
|
+
path === oldHdPath ? oldConnection : replacement,
|
|
838
|
+
);
|
|
839
|
+
const pending = deferred<void>();
|
|
840
|
+
sessionMocks.start.mockImplementationOnce(() => pending.promise);
|
|
841
|
+
const wrapper = mountWallet({ hdPath: oldHdPath, evmConfig });
|
|
842
|
+
await vi.waitFor(() => expect(sessionMocks.start).toHaveBeenCalledOnce());
|
|
843
|
+
|
|
844
|
+
await wrapper.setProps({
|
|
845
|
+
hdPath: newHdPath,
|
|
846
|
+
chainId: 'cosmoshub-4',
|
|
847
|
+
addrPrefix: 'cosmos',
|
|
848
|
+
evmConfig: undefined,
|
|
849
|
+
});
|
|
850
|
+
await vi.waitFor(() =>
|
|
851
|
+
expect(wrapper.text()).toContain('cosmos1replacement'),
|
|
852
|
+
);
|
|
853
|
+
vi.mocked(removeWallet).mockClear();
|
|
854
|
+
|
|
855
|
+
pending.reject(new Error('stale Reown restore'));
|
|
856
|
+
await flushPromises();
|
|
857
|
+
|
|
858
|
+
expect(removeWallet).not.toHaveBeenCalled();
|
|
859
|
+
expect(wrapper.text()).toContain('cosmos1replacement');
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
it('ignores a stale Reown restore rejection after unmount', async () => {
|
|
863
|
+
const hdPath = "m/44'/60/0'/0/0";
|
|
864
|
+
vi.mocked(readWallet).mockReturnValue({
|
|
865
|
+
version: 2,
|
|
866
|
+
wallet: WalletName.Evm,
|
|
867
|
+
cosmosAddress: 'warden1old',
|
|
868
|
+
hdPath,
|
|
869
|
+
connector: {
|
|
870
|
+
source: 'reown',
|
|
871
|
+
name: 'Rabby Wallet',
|
|
872
|
+
},
|
|
873
|
+
});
|
|
874
|
+
const pending = deferred<void>();
|
|
875
|
+
sessionMocks.start.mockImplementationOnce(() => pending.promise);
|
|
876
|
+
const onDisconnect = vi.fn();
|
|
877
|
+
const wrapper = mountWallet({ hdPath, evmConfig, onDisconnect });
|
|
878
|
+
await vi.waitFor(() => expect(sessionMocks.start).toHaveBeenCalledOnce());
|
|
879
|
+
const disconnectCount = onDisconnect.mock.calls.length;
|
|
880
|
+
vi.mocked(removeWallet).mockClear();
|
|
881
|
+
|
|
882
|
+
wrapper.unmount();
|
|
883
|
+
pending.reject(new Error('stale Reown restore'));
|
|
884
|
+
await flushPromises();
|
|
885
|
+
|
|
886
|
+
expect(removeWallet).not.toHaveBeenCalled();
|
|
887
|
+
expect(onDisconnect).toHaveBeenCalledTimes(disconnectCount);
|
|
888
|
+
});
|
|
251
889
|
});
|