@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.
Files changed (89) hide show
  1. package/README.md +2 -2
  2. package/dist/{ConstantsUtil-df193f67.js → ConstantsUtil-f9dc60b6.js} +3 -3
  3. package/dist/{ConstantsUtil-1b0c0436.js → ConstantsUtil-fb0ff2e5.js} +1 -1
  4. package/dist/{ExchangeController-953f14bc.js → ExchangeController-173fd1dc.js} +2 -2
  5. package/dist/{HelpersUtil-3810bb58.js → HelpersUtil-4891ff5f.js} +4 -4
  6. package/dist/{ReownAuthentication-7c5b6e79.js → ReownAuthentication-bba89dc5.js} +2 -2
  7. package/dist/{SwapController-e1a7b5f8.js → SwapController-e8b097ca.js} +3 -3
  8. package/dist/{abis-61cccfbf.js → abis-96fed285.js} +1 -1
  9. package/dist/{assertCurrentChain-0c3d6c93.js → assertCurrentChain-b60aa59f.js} +1 -1
  10. package/dist/{ccip-80fe88fb.js → ccip-8f82ae2a.js} +6 -6
  11. package/dist/{data-capture-7edeb077.js → data-capture-7009ffa0.js} +8 -8
  12. package/dist/{email-40537ec5.js → email-d6e2da58.js} +12 -12
  13. package/dist/{embedded-wallet-f71f6169.js → embedded-wallet-48284179.js} +14 -14
  14. package/dist/{encodeFunctionData-91e7c0f6.js → encodeFunctionData-b24a0b2b.js} +2 -2
  15. package/dist/{fallback-1ab5a270.js → fallback-ae0315d4.js} +2 -2
  16. package/dist/features-82db0d52.js +8 -0
  17. package/dist/{hashTypedData-1e059dc4.js → hashTypedData-c13ba550.js} +2 -2
  18. package/dist/{http-d9e0a50a.js → http-90ef23f3.js} +2 -2
  19. package/dist/{index-d3f36c31.js → index-0ac134af.js} +34 -34
  20. package/dist/{index-2cd6a2b2.js → index-19f302c4.js} +3 -3
  21. package/dist/{index-78c5b9e2.js → index-22727038.js} +3 -3
  22. package/dist/{index-144edd3f.js → index-270ff8a2.js} +11 -11
  23. package/dist/{index-abb0ff46.js → index-29eb95bd.js} +3 -3
  24. package/dist/{index-9cc1116b.js → index-2a90711e.js} +2 -2
  25. package/dist/{index-289a865f.js → index-2de6c5bf.js} +4 -4
  26. package/dist/{index-fbced89b.js → index-3de7fa96.js} +3 -3
  27. package/dist/{index-26b53c8a.js → index-42a8a5ec.js} +15 -15
  28. package/dist/{index-58ec291c.js → index-4bd03aed.js} +7 -7
  29. package/dist/{index-85bc86d7.js → index-52edc95a.js} +2 -2
  30. package/dist/{index-04dd1ab3.js → index-577d2709.js} +4 -4
  31. package/dist/{index-4a4ee1e7.js → index-582e4199.js} +7 -7
  32. package/dist/{index-72706598.js → index-617b2147.js} +6 -6
  33. package/dist/{index-0b6166c5.js → index-6a0902fc.js} +2 -2
  34. package/dist/{index-a37d4c03.js → index-6d51f24f.js} +2 -2
  35. package/dist/{index-759b09b0.js → index-80954332.js} +3 -3
  36. package/dist/{index-0e2c49ad.js → index-95777860.js} +7 -7
  37. package/dist/{index-d9effd37.js → index-96729706.js} +13 -13
  38. package/dist/{index-39f31546.js → index-997bc756.js} +2 -2
  39. package/dist/{index-cb4d3345.js → index-a41841e6.js} +3 -3
  40. package/dist/{index-c10f5e72.js → index-adaa2ea4.js} +3 -3
  41. package/dist/{index-97b58f89.js → index-b37b670f.js} +11 -11
  42. package/dist/{index-0763de43.js → index-b8e2c282.js} +3 -3
  43. package/dist/{index-1f02e7d0.js → index-bb5e4071.js} +1 -1
  44. package/dist/{index-3678e7d8.js → index-bf40b971.js} +2 -2
  45. package/dist/{index-a4f054e9.js → index-cb69565e.js} +2 -2
  46. package/dist/{index-197dfd69.js → index-cbb6096a.js} +3 -3
  47. package/dist/{index-119c358f.js → index-ce6854ef.js} +14 -14
  48. package/dist/{index-4fdc7a25.js → index-d7e2a4a3.js} +2 -2
  49. package/dist/{index-0176180b.js → index-e7fbb597.js} +4 -4
  50. package/dist/{index-d5e3e4ba.js → index-f4cd8dd1.js} +3 -3
  51. package/dist/{index-a0c590f7.js → index-f886cf92.js} +2 -2
  52. package/dist/{index-95e1a01b.js → index-faade258.js} +3 -3
  53. package/dist/{localBatchGatewayRequest-8fd1b198.js → localBatchGatewayRequest-ade4aa2f.js} +3 -3
  54. package/dist/{main-7ddb238e.js → main-3b573cfc.js} +38694 -38472
  55. package/dist/{networks-d2ae1da7.js → networks-446d3512.js} +10 -10
  56. package/dist/{onramp-2966f1b1.js → onramp-57d19c5d.js} +19 -19
  57. package/dist/{parseSignature-fca372a1.js → parseSignature-783d626a.js} +8 -8
  58. package/dist/{pay-with-exchange-b0198b3f.js → pay-with-exchange-c59a5773.js} +22 -22
  59. package/dist/ping-widget.js +1 -1
  60. package/dist/ping-widget.umd.cjs +680 -680
  61. package/dist/{query.lcd-873499ca.js → query.lcd-447fb91a.js} +1 -1
  62. package/dist/{query.rpc.Query-d2bcf632.js → query.rpc.Query-97503d87.js} +1 -1
  63. package/dist/{receive-6fbb6662.js → receive-3073a49d.js} +6 -6
  64. package/dist/{ref-2c86b029.js → ref-6c3aabc7.js} +2 -2
  65. package/dist/{send-630ed203.js → send-42403797.js} +22 -22
  66. package/dist/{serializeAuthorizationList-e95a85d8.js → serializeAuthorizationList-70ec977c.js} +4 -4
  67. package/dist/{sha2-c04ffd62.js → sha2-249ae7eb.js} +2 -2
  68. package/dist/{socials-73a5efb0.js → socials-69b0cf18.js} +18 -18
  69. package/dist/{swaps-7b57265f.js → swaps-4e99bb0f.js} +18 -18
  70. package/dist/{transactions-876c066c.js → transactions-1d0c2669.js} +9 -9
  71. package/dist/{tx.rpc.msg-4d8bd1a4.js → tx.rpc.msg-8aa727ea.js} +1 -1
  72. package/dist/{tx.rpc.msg-d08b8ebe.js → tx.rpc.msg-a26b3557.js} +1 -1
  73. package/dist/{verifyHash-ee28e3d7.js → verifyHash-c8962067.js} +5 -5
  74. package/dist/{vue-bea1a08b.js → vue-9dc93a14.js} +10 -10
  75. package/dist/{w3m-modal-7d61c210.js → w3m-modal-291afec4.js} +25 -25
  76. package/dist/{zora-1091e7bb.js → zora-061565b0.js} +4 -4
  77. package/lib/components/ConnectWallet/index.vue +113 -31
  78. package/lib/wallet/KeplrSessionManager.ts +142 -0
  79. package/lib/wallet/WalletSessionManager.ts +111 -25
  80. package/lib/wallet/reown/EvmNetworkProvisioner.ts +97 -0
  81. package/lib/wallet/reown/ReownGateway.ts +22 -3
  82. package/package.json +1 -1
  83. package/test/components/ConnectWallet.test.ts +640 -2
  84. package/test/components/ConnectWalletStorage.test.ts +113 -3
  85. package/test/wallet/KeplrSessionManager.test.ts +269 -0
  86. package/test/wallet/WalletSessionManager.test.ts +901 -2
  87. package/test/wallet/reown/EvmNetworkProvisioner.test.ts +264 -0
  88. package/test/wallet/reown/ReownGateway.test.ts +66 -1
  89. package/dist/features-a2f2ff4f.js +0 -8
@@ -0,0 +1,142 @@
1
+ import {
2
+ createWallet,
3
+ removeWallet,
4
+ WalletName,
5
+ writeWallet,
6
+ type AbstractWallet,
7
+ type ConnectedWallet,
8
+ type WalletArgument,
9
+ } from './Wallet';
10
+ import {
11
+ normalizeWalletError,
12
+ type WalletUserError,
13
+ } from './WalletError';
14
+
15
+ export const KEPLR_KEYSTORE_EVENT = 'keplr_keystorechange';
16
+
17
+ export interface WalletEventTarget {
18
+ addEventListener(type: string, listener: EventListener): void;
19
+ removeEventListener(type: string, listener: EventListener): void;
20
+ }
21
+
22
+ type KeplrWalletFactory = (argument: WalletArgument) => AbstractWallet;
23
+
24
+ function defaultFactory(argument: WalletArgument): AbstractWallet {
25
+ return createWallet(WalletName.Keplr, argument);
26
+ }
27
+
28
+ export class KeplrSessionManager {
29
+ private listener?: EventListener;
30
+ private argument?: WalletArgument;
31
+ private onChange?: (wallet: ConnectedWallet | undefined) => void;
32
+ private onError: (error: WalletUserError) => void = () => undefined;
33
+ private lifecycleGeneration = 0;
34
+ private refreshGeneration = 0;
35
+ private refreshPromise?: Promise<void>;
36
+ private refreshQueued = false;
37
+ private refreshScheduled = false;
38
+
39
+ constructor(
40
+ private readonly hdPath: string,
41
+ private readonly walletFactory: KeplrWalletFactory = defaultFactory,
42
+ private readonly eventTarget: WalletEventTarget = window,
43
+ ) {}
44
+
45
+ async start(
46
+ argument: WalletArgument,
47
+ onChange: (wallet: ConnectedWallet | undefined) => void,
48
+ onError: (error: WalletUserError) => void = () => undefined,
49
+ ): Promise<void> {
50
+ this.dispose();
51
+ this.argument = argument;
52
+ this.onChange = onChange;
53
+ this.onError = onError;
54
+ const listenerLifecycleGeneration = this.lifecycleGeneration;
55
+ this.listener = () => {
56
+ if (listenerLifecycleGeneration !== this.lifecycleGeneration) return;
57
+ if (this.refreshScheduled) return;
58
+ this.refreshScheduled = true;
59
+ queueMicrotask(() => {
60
+ if (listenerLifecycleGeneration !== this.lifecycleGeneration) return;
61
+ this.refreshScheduled = false;
62
+ void this.refresh();
63
+ });
64
+ };
65
+ this.eventTarget.addEventListener(KEPLR_KEYSTORE_EVENT, this.listener);
66
+ await this.refresh();
67
+ }
68
+
69
+ async refresh(): Promise<void> {
70
+ if (!this.argument || !this.onChange) return;
71
+ if (this.refreshPromise) {
72
+ this.refreshGeneration += 1;
73
+ this.refreshQueued = true;
74
+ await this.refreshPromise;
75
+ return;
76
+ }
77
+
78
+ const lifecycleGeneration = this.lifecycleGeneration;
79
+ const refreshGeneration = ++this.refreshGeneration;
80
+ const argument = this.argument;
81
+ const onChange = this.onChange;
82
+ onChange(undefined);
83
+
84
+ const refreshing = (async () => {
85
+ try {
86
+ const [account] = await this.walletFactory(argument).getAccounts();
87
+ if (
88
+ lifecycleGeneration !== this.lifecycleGeneration ||
89
+ refreshGeneration !== this.refreshGeneration
90
+ ) {
91
+ return;
92
+ }
93
+ if (!account || typeof account.address !== 'string' || !account.address.trim()) {
94
+ throw new Error('Keplr returned no active account');
95
+ }
96
+ const connected: ConnectedWallet = {
97
+ wallet: WalletName.Keplr,
98
+ cosmosAddress: account.address,
99
+ hdPath: this.hdPath,
100
+ };
101
+ writeWallet(connected, this.hdPath);
102
+ onChange(connected);
103
+ } catch (error) {
104
+ if (
105
+ lifecycleGeneration !== this.lifecycleGeneration ||
106
+ refreshGeneration !== this.refreshGeneration
107
+ ) {
108
+ return;
109
+ }
110
+ removeWallet(this.hdPath);
111
+ this.onError(normalizeWalletError(error));
112
+ }
113
+ })().finally(() => {
114
+ if (this.refreshPromise !== refreshing) return;
115
+ this.refreshPromise = undefined;
116
+ if (
117
+ this.refreshQueued &&
118
+ lifecycleGeneration === this.lifecycleGeneration
119
+ ) {
120
+ this.refreshQueued = false;
121
+ void this.refresh();
122
+ }
123
+ });
124
+
125
+ this.refreshPromise = refreshing;
126
+ return refreshing;
127
+ }
128
+
129
+ dispose(): void {
130
+ this.lifecycleGeneration += 1;
131
+ this.refreshGeneration += 1;
132
+ if (this.listener) {
133
+ this.eventTarget.removeEventListener(KEPLR_KEYSTORE_EVENT, this.listener);
134
+ }
135
+ this.listener = undefined;
136
+ this.argument = undefined;
137
+ this.onChange = undefined;
138
+ this.refreshPromise = undefined;
139
+ this.refreshQueued = false;
140
+ this.refreshScheduled = false;
141
+ }
142
+ }
@@ -21,6 +21,7 @@ import {
21
21
  getReownGateway,
22
22
  type ReownAccountState,
23
23
  type ReownGateway,
24
+ type ReownNetworkState,
24
25
  } from './reown/ReownGateway';
25
26
  import { EvmEip712Wallet } from './wallets/EvmEip712Wallet';
26
27
  import { ethermintToEth } from '../utils/format';
@@ -92,6 +93,7 @@ export class WalletSessionManager {
92
93
  walletArgument: WalletArgument,
93
94
  onChange: (connected: ConnectedWallet | undefined) => void,
94
95
  onError: (error: WalletUserError) => void = () => undefined,
96
+ provisionNetwork = false,
95
97
  ): Promise<ReownGateway> {
96
98
  this.dispose();
97
99
  const lifecycleGeneration = this.lifecycleGeneration;
@@ -105,6 +107,16 @@ export class WalletSessionManager {
105
107
 
106
108
  let pendingAddress: string | undefined;
107
109
  let verifiedAddress: string | undefined;
110
+ let authoritativeAddress: string | undefined;
111
+ let networkValid = true;
112
+ let provisioningAvailable = provisionNetwork;
113
+ let provisioningPending = false;
114
+ let provisioningFailed = false;
115
+ const clearVisibleState = () => {
116
+ clearRuntimeWallet(this.hdPath);
117
+ removeWallet(this.hdPath);
118
+ onChange(undefined);
119
+ };
108
120
  const synchronizeAccount = async (state: ReownAccountState) => {
109
121
  const evmAddress =
110
122
  state.isConnected && state.address
@@ -112,23 +124,60 @@ export class WalletSessionManager {
112
124
  : undefined;
113
125
  if (!evmAddress) {
114
126
  this.accountGeneration += 1;
127
+ authoritativeAddress = undefined;
115
128
  pendingAddress = undefined;
116
129
  verifiedAddress = undefined;
117
- clearRuntimeWallet(this.hdPath);
118
- removeWallet(this.hdPath);
119
- onChange(undefined);
130
+ clearVisibleState();
120
131
  return;
121
132
  }
133
+ if (evmAddress !== authoritativeAddress) {
134
+ this.accountGeneration += 1;
135
+ authoritativeAddress = evmAddress;
136
+ pendingAddress = undefined;
137
+ clearVisibleState();
138
+ }
139
+ if (provisioningPending || provisioningFailed) return;
140
+ if (!networkValid && !provisioningAvailable) return;
122
141
  if (
123
142
  evmAddress === pendingAddress ||
124
- (evmAddress === verifiedAddress && runtimeWallets.has(this.hdPath))
143
+ (evmAddress === verifiedAddress &&
144
+ pendingAddress === undefined &&
145
+ runtimeWallets.has(this.hdPath))
125
146
  ) {
126
147
  return;
127
148
  }
128
149
 
150
+ const shouldProvision = provisioningAvailable;
151
+ if (shouldProvision) {
152
+ provisioningAvailable = false;
153
+ provisioningPending = true;
154
+ }
129
155
  const accountGeneration = ++this.accountGeneration;
130
156
  pendingAddress = evmAddress;
157
+ const ownsProvisioning = () =>
158
+ lifecycleGeneration === this.lifecycleGeneration &&
159
+ accountGeneration === this.accountGeneration &&
160
+ authoritativeAddress === evmAddress &&
161
+ provisioningPending;
131
162
  try {
163
+ if (shouldProvision) {
164
+ await gateway.ensureNetwork(ownsProvisioning);
165
+ if (!ownsProvisioning()) {
166
+ provisioningPending = false;
167
+ provisioningFailed = true;
168
+ return;
169
+ }
170
+ provisioningPending = false;
171
+ networkValid = true;
172
+ }
173
+ if (
174
+ lifecycleGeneration !== this.lifecycleGeneration ||
175
+ accountGeneration !== this.accountGeneration ||
176
+ authoritativeAddress !== evmAddress ||
177
+ !networkValid
178
+ ) {
179
+ return;
180
+ }
132
181
  const provider = gateway.getProvider();
133
182
  if (!provider) throw new Error('EVM wallet provider is unavailable');
134
183
  const wallet = this.walletFactory({
@@ -139,7 +188,9 @@ export class WalletSessionManager {
139
188
  const accounts = await wallet.getAccounts();
140
189
  if (
141
190
  lifecycleGeneration !== this.lifecycleGeneration ||
142
- accountGeneration !== this.accountGeneration
191
+ accountGeneration !== this.accountGeneration ||
192
+ authoritativeAddress !== evmAddress ||
193
+ !networkValid
143
194
  ) {
144
195
  return;
145
196
  }
@@ -168,6 +219,10 @@ export class WalletSessionManager {
168
219
  writeWallet(connected, this.hdPath);
169
220
  onChange(connected);
170
221
  } catch (error) {
222
+ if (shouldProvision) {
223
+ provisioningPending = false;
224
+ provisioningFailed = true;
225
+ }
171
226
  if (
172
227
  lifecycleGeneration !== this.lifecycleGeneration ||
173
228
  accountGeneration !== this.accountGeneration
@@ -180,6 +235,9 @@ export class WalletSessionManager {
180
235
  onChange(undefined);
181
236
  onError(normalizeWalletError(error));
182
237
  } finally {
238
+ if (shouldProvision) {
239
+ provisioningPending = false;
240
+ }
183
241
  if (
184
242
  accountGeneration === this.accountGeneration &&
185
243
  pendingAddress === evmAddress
@@ -189,29 +247,57 @@ export class WalletSessionManager {
189
247
  }
190
248
  };
191
249
 
192
- this.unsubscribe.push(
193
- gateway.subscribeAccount((state) => void synchronizeAccount(state)),
194
- );
195
- this.unsubscribe.push(
196
- gateway.subscribeNetwork((state) => {
197
- const networkId = state.caipNetworkId;
250
+ const synchronizeNetwork = (state: ReownNetworkState) => {
251
+ const networkId = state.caipNetworkId;
252
+ if (networkId === undefined) return;
253
+ const nextNetworkValid = isExpectedNetwork(networkId, config);
254
+ if (!nextNetworkValid) {
255
+ if (!networkValid) return;
256
+ networkValid = false;
198
257
  if (
199
- networkId !== undefined &&
200
- !isExpectedNetwork(networkId, config)
258
+ provisioningPending ||
259
+ (provisioningAvailable && authoritativeAddress === undefined)
201
260
  ) {
261
+ return;
262
+ }
263
+ if (!provisioningPending) {
202
264
  this.accountGeneration += 1;
203
265
  pendingAddress = undefined;
204
- verifiedAddress = undefined;
205
- clearRuntimeWallet(this.hdPath);
206
- removeWallet(this.hdPath);
207
- onChange(undefined);
208
- onError(normalizeWalletError({ code: 4901 }));
209
266
  }
267
+ verifiedAddress = undefined;
268
+ clearVisibleState();
269
+ onError(normalizeWalletError({ code: 4901 }));
270
+ return;
271
+ }
272
+ if (networkValid) return;
273
+ networkValid = true;
274
+ const current = gateway.getAccount();
275
+ if (current) void synchronizeAccount(current);
276
+ };
277
+
278
+ this.unsubscribe.push(
279
+ gateway.subscribeAccount((state) => {
280
+ if (lifecycleGeneration !== this.lifecycleGeneration) return;
281
+ void synchronizeAccount(state);
282
+ }),
283
+ );
284
+ this.unsubscribe.push(
285
+ gateway.subscribeNetwork((state) => {
286
+ if (lifecycleGeneration !== this.lifecycleGeneration) return;
287
+ synchronizeNetwork(state);
210
288
  }),
211
289
  );
212
290
 
291
+ const currentNetwork = gateway.getNetwork();
292
+ if (currentNetwork) synchronizeNetwork(currentNetwork);
213
293
  const current = gateway.getAccount();
214
294
  if (current?.isConnected) await synchronizeAccount(current);
295
+ if (lifecycleGeneration !== this.lifecycleGeneration) {
296
+ throw new WalletUserError(
297
+ 'disconnected',
298
+ 'Wallet session changed before connection completed',
299
+ );
300
+ }
215
301
  return gateway;
216
302
  }
217
303
 
@@ -226,19 +312,18 @@ export class WalletSessionManager {
226
312
  walletArgument,
227
313
  onChange,
228
314
  onError,
315
+ true,
229
316
  );
230
- await gateway.open();
317
+ if (!gateway.getAccount()?.isConnected) {
318
+ await gateway.open();
319
+ }
231
320
  }
232
321
 
233
322
  async disconnect(config: ReownWalletConfig): Promise<void> {
234
323
  this.dispose();
324
+ removeWallet(this.hdPath);
235
325
  const gateway = await this.gatewayFactory(config);
236
- try {
237
- await gateway.disconnect();
238
- } finally {
239
- clearRuntimeWallet(this.hdPath);
240
- removeWallet(this.hdPath);
241
- }
326
+ await gateway.disconnect();
242
327
  }
243
328
 
244
329
  dispose(): void {
@@ -246,5 +331,6 @@ export class WalletSessionManager {
246
331
  this.accountGeneration += 1;
247
332
  for (const unsubscribe of this.unsubscribe) unsubscribe();
248
333
  this.unsubscribe = [];
334
+ clearRuntimeWallet(this.hdPath);
249
335
  }
250
336
  }
@@ -0,0 +1,97 @@
1
+ import type { Eip1193Provider } from '../providers/Eip1193Provider';
2
+ import type { ReownNetwork } from './ReownConfig';
3
+
4
+ function isUnknownChainError(error: unknown): boolean {
5
+ type Match = 'none' | 'unknown-chain' | 'user-rejected';
6
+ const visited = new Set<object>();
7
+ const inspect = (candidate: unknown, depth: number): Match => {
8
+ if (
9
+ typeof candidate !== 'object' ||
10
+ candidate === null ||
11
+ depth > 4 ||
12
+ visited.has(candidate)
13
+ ) {
14
+ return 'none';
15
+ }
16
+ visited.add(candidate);
17
+
18
+ try {
19
+ const code = 'code' in candidate
20
+ ? String(candidate.code).trim()
21
+ : undefined;
22
+ if (code === '4001') {
23
+ return 'user-rejected';
24
+ }
25
+ let match: Match = code === '4902' ? 'unknown-chain' : 'none';
26
+ for (const key of ['cause', 'error', 'data', 'originalError']) {
27
+ if (key in candidate) {
28
+ const nested = inspect(candidate[key], depth + 1);
29
+ if (nested === 'user-rejected') return nested;
30
+ if (nested === 'unknown-chain') match = nested;
31
+ }
32
+ }
33
+ return match;
34
+ } catch {
35
+ return 'none';
36
+ }
37
+ };
38
+
39
+ return inspect(error, 0) === 'unknown-chain';
40
+ }
41
+
42
+ export async function ensureEvmNetwork(
43
+ provider: Eip1193Provider,
44
+ network: ReownNetwork,
45
+ isActive: () => boolean = () => true,
46
+ ): Promise<void> {
47
+ const chainId = `0x${network.id.toString(16)}`;
48
+ const isExpectedChain = (value: unknown) =>
49
+ typeof value === 'string' && value.toLowerCase() === chainId;
50
+ const assertActive = () => {
51
+ if (!isActive()) {
52
+ throw new Error('EVM network request is no longer active');
53
+ }
54
+ };
55
+
56
+ assertActive();
57
+ const currentChain = await provider.request({ method: 'eth_chainId' });
58
+ assertActive();
59
+ if (isExpectedChain(currentChain)) {
60
+ return;
61
+ }
62
+
63
+ const switchRequest = {
64
+ method: 'wallet_switchEthereumChain',
65
+ params: [{ chainId }],
66
+ } as const;
67
+
68
+ try {
69
+ await provider.request(switchRequest);
70
+ assertActive();
71
+ } catch (error) {
72
+ assertActive();
73
+ if (!isUnknownChainError(error)) throw error;
74
+
75
+ await provider.request({
76
+ method: 'wallet_addEthereumChain',
77
+ params: [{
78
+ chainId,
79
+ chainName: network.name,
80
+ nativeCurrency: network.nativeCurrency,
81
+ rpcUrls: [network.rpcUrl],
82
+ ...(network.explorerUrl
83
+ ? { blockExplorerUrls: [network.explorerUrl] }
84
+ : {}),
85
+ }],
86
+ });
87
+ assertActive();
88
+ await provider.request(switchRequest);
89
+ assertActive();
90
+ }
91
+
92
+ const verifiedChain = await provider.request({ method: 'eth_chainId' });
93
+ assertActive();
94
+ if (!isExpectedChain(verifiedChain)) {
95
+ throw new Error('EVM wallet did not switch to configured network');
96
+ }
97
+ }
@@ -1,6 +1,7 @@
1
1
  import type { AppKit } from '@reown/appkit/vue';
2
2
  import type { Eip1193Provider } from '../providers/Eip1193Provider';
3
3
  import type { ReownWalletConfig } from './ReownConfig';
4
+ import { ensureEvmNetwork } from './EvmNetworkProvisioner';
4
5
 
5
6
  export interface ReownAccountState {
6
7
  address?: string;
@@ -21,8 +22,10 @@ export interface ReownWalletInfo {
21
22
  export interface ReownGateway {
22
23
  open(): Promise<void>;
23
24
  disconnect(): Promise<void>;
25
+ ensureNetwork(isCurrent?: () => boolean): Promise<void>;
24
26
  getProvider(): Eip1193Provider | undefined;
25
27
  getAccount(): ReownAccountState | undefined;
28
+ getNetwork(): ReownNetworkState | undefined;
26
29
  getWalletInfo(): ReownWalletInfo | undefined;
27
30
  subscribeAccount(
28
31
  callback: (account: ReownAccountState) => void,
@@ -59,7 +62,7 @@ export async function getReownGateway(
59
62
  async function createGateway(
60
63
  config: ReownWalletConfig,
61
64
  ): Promise<ReownGateway> {
62
- const [{ createAppKit }, { EthersAdapter }, { defineChain }] =
65
+ const [{ createAppKit }, { EthersAdapter }, { defineChain, mainnet }] =
63
66
  await Promise.all([
64
67
  import('@reown/appkit/vue'),
65
68
  import('@reown/appkit-adapter-ethers'),
@@ -87,8 +90,10 @@ async function createGateway(
87
90
 
88
91
  const appKit: AppKit = createAppKit({
89
92
  adapters: [new EthersAdapter()],
90
- networks: [network],
91
- defaultNetwork: network,
93
+ networks: [network, mainnet],
94
+ defaultNetwork: mainnet,
95
+ allowUnsupportedChain: true,
96
+ enableNetworkSwitch: false,
92
97
  projectId: config.projectId,
93
98
  metadata: config.metadata,
94
99
  featuredWalletIds: config.featuredWalletIds,
@@ -117,6 +122,14 @@ async function createGateway(
117
122
  await appKit.open({ view: 'Connect', namespace: 'eip155' });
118
123
  },
119
124
  disconnect: () => appKit.disconnect('eip155'),
125
+ ensureNetwork: async (isCurrent) => {
126
+ const provider =
127
+ appKit.getProvider<Eip1193Provider>('eip155');
128
+ if (!provider) {
129
+ throw new Error('EVM wallet provider is unavailable');
130
+ }
131
+ await ensureEvmNetwork(provider, config.network, isCurrent);
132
+ },
120
133
  getProvider: () => appKit.getProvider<Eip1193Provider>('eip155'),
121
134
  getAccount: () => {
122
135
  const account = appKit.getAccount('eip155');
@@ -128,6 +141,12 @@ async function createGateway(
128
141
  }
129
142
  : undefined;
130
143
  },
144
+ getNetwork: () => {
145
+ const network = appKit.getCaipNetwork('eip155');
146
+ return network
147
+ ? { caipNetworkId: network.caipNetworkId }
148
+ : undefined;
149
+ },
131
150
  getWalletInfo: () => {
132
151
  const info = appKit.getWalletInfo('eip155');
133
152
  return info
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mictonode/widget",
3
3
  "private": false,
4
- "version": "0.3.22",
4
+ "version": "0.3.23",
5
5
  "packageManager": "yarn@1.22.22",
6
6
  "type": "module",
7
7
  "main": "dist/ping-widget.js",