@metamask/connect-evm 0.4.1 → 0.5.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.
@@ -18,16 +18,18 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
18
18
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
19
19
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
20
20
  };
21
- var _MetamaskConnectEVM_instances, _MetamaskConnectEVM_core, _MetamaskConnectEVM_provider, _MetamaskConnectEVM_sessionScopes, _MetamaskConnectEVM_eventHandlers, _MetamaskConnectEVM_sessionChangedHandler, _MetamaskConnectEVM_displayUriHandler, _MetamaskConnectEVM_removeNotificationHandler, _MetamaskConnectEVM_getCoreOptions, _MetamaskConnectEVM_createInvokeOptions, _MetamaskConnectEVM_trackWalletActionRequested, _MetamaskConnectEVM_trackWalletActionSucceeded, _MetamaskConnectEVM_trackWalletActionFailed, _MetamaskConnectEVM_getSelectedChainId, _MetamaskConnectEVM_requestInterceptor, _MetamaskConnectEVM_clearConnectionState, _MetamaskConnectEVM_addEthereumChain, _MetamaskConnectEVM_request, _MetamaskConnectEVM_cacheChainId, _MetamaskConnectEVM_onChainChanged, _MetamaskConnectEVM_onAccountsChanged, _MetamaskConnectEVM_onConnect, _MetamaskConnectEVM_onDisconnect, _MetamaskConnectEVM_onDisplayUri, _MetamaskConnectEVM_attemptSessionRecovery;
21
+ var _MetamaskConnectEVM_instances, _MetamaskConnectEVM_core, _MetamaskConnectEVM_provider, _MetamaskConnectEVM_sessionScopes, _MetamaskConnectEVM_eventHandlers, _MetamaskConnectEVM_sessionChangedHandler, _MetamaskConnectEVM_displayUriHandler, _MetamaskConnectEVM_removeNotificationHandler, _MetamaskConnectEVM_status, _MetamaskConnectEVM_getCoreOptions, _MetamaskConnectEVM_createInvokeOptions, _MetamaskConnectEVM_trackWalletActionRequested, _MetamaskConnectEVM_trackWalletActionSucceeded, _MetamaskConnectEVM_trackWalletActionFailed, _MetamaskConnectEVM_getSelectedChainId, _MetamaskConnectEVM_requestInterceptor, _MetamaskConnectEVM_clearConnectionState, _MetamaskConnectEVM_addEthereumChain, _MetamaskConnectEVM_request, _MetamaskConnectEVM_cacheChainId, _MetamaskConnectEVM_onSessionChanged, _MetamaskConnectEVM_onChainChanged, _MetamaskConnectEVM_onAccountsChanged, _MetamaskConnectEVM_onConnect, _MetamaskConnectEVM_onDisconnect, _MetamaskConnectEVM_onDisplayUri;
22
+ /* eslint-disable no-restricted-syntax -- Private class properties use established patterns */
22
23
  import { analytics } from '@metamask/analytics';
24
+ import { parseScopeString } from '@metamask/chain-agnostic-permission';
23
25
  import { createMultichainClient, getWalletActionAnalyticsProperties, isRejectionError, TransportType, } from '@metamask/connect-multichain';
24
- import { numberToHex, hexToNumber, isHexString as isHex, } from '@metamask/utils';
26
+ import { hexToNumber } from '@metamask/utils';
25
27
  import { IGNORED_METHODS } from './constants';
26
28
  import { enableDebug, logger } from './logger';
27
29
  import { EIP1193Provider } from './provider';
28
- import { getPermittedEthChainIds } from './utils/caip';
30
+ import { getEthAccounts, getPermittedEthChainIds } from './utils/caip';
29
31
  import { isAccountsRequest, isAddChainRequest, isChainIdRequest, isConnectRequest, isSwitchChainRequest, validSupportedChainsUrls, } from './utils/type-guards';
30
- const DEFAULT_CHAIN_ID = 1;
32
+ const DEFAULT_CHAIN_ID = '0x1';
31
33
  const CHAIN_STORE_KEY = 'cache_eth_chainId';
32
34
  /**
33
35
  * The MetamaskConnectEVM class provides an EIP-1193 compatible interface for connecting
@@ -47,13 +49,14 @@ const CHAIN_STORE_KEY = 'cache_eth_chainId';
47
49
  *
48
50
  * @example
49
51
  * ```typescript
50
- * const sdk = await createEVMClient({
52
+ * const client = await createEVMClient({
51
53
  * dapp: { name: 'My DApp', url: 'https://mydapp.com' }
52
54
  * });
53
55
  *
54
- * await sdk.connect({ chainId: 1 });
55
- * const provider = await sdk.getProvider();
56
- * const accounts = await provider.request({ method: 'eth_accounts' });
56
+ * const { accounts, chainId } = await client.connect({ chainIds: [1, 137] }); // Connect to Ethereum Mainnet, and Polygon
57
+ *
58
+ * const provider = client.getProvider();
59
+ * const signedMessage = await provider.request({ method: 'personal_sign', params: ['0x0', accounts[0]] });
57
60
  * ```
58
61
  */
59
62
  export class MetamaskConnectEVM {
@@ -81,6 +84,8 @@ export class MetamaskConnectEVM {
81
84
  _MetamaskConnectEVM_displayUriHandler.set(this, void 0);
82
85
  /** The clean-up function for the notification handler */
83
86
  _MetamaskConnectEVM_removeNotificationHandler.set(this, void 0);
87
+ /** The current connection status */
88
+ _MetamaskConnectEVM_status.set(this, 'disconnected');
84
89
  __classPrivateFieldSet(this, _MetamaskConnectEVM_core, core, "f");
85
90
  __classPrivateFieldSet(this, _MetamaskConnectEVM_provider, new EIP1193Provider(core, __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_requestInterceptor).bind(this)), "f");
86
91
  __classPrivateFieldSet(this, _MetamaskConnectEVM_eventHandlers, eventHandlers, "f");
@@ -90,12 +95,9 @@ export class MetamaskConnectEVM {
90
95
  *
91
96
  * @param session - The session data
92
97
  */
93
- __classPrivateFieldSet(this, _MetamaskConnectEVM_sessionChangedHandler, (session) => {
94
- var _a;
95
- logger('event: wallet_sessionChanged', session);
96
- __classPrivateFieldSet(this, _MetamaskConnectEVM_sessionScopes, (_a = session === null || session === void 0 ? void 0 : session.sessionScopes) !== null && _a !== void 0 ? _a : {}, "f");
97
- }, "f");
98
- __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").on('wallet_sessionChanged', __classPrivateFieldGet(this, _MetamaskConnectEVM_sessionChangedHandler, "f").bind(this));
98
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
99
+ __classPrivateFieldSet(this, _MetamaskConnectEVM_sessionChangedHandler, __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onSessionChanged).bind(this), "f");
100
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").on('wallet_sessionChanged', __classPrivateFieldGet(this, _MetamaskConnectEVM_sessionChangedHandler, "f"));
99
101
  /**
100
102
  * Handles the display_uri event.
101
103
  * Forwards the QR code URI to the provider for custom UI implementations.
@@ -118,7 +120,7 @@ export class MetamaskConnectEVM {
118
120
  static create(options) {
119
121
  return __awaiter(this, void 0, void 0, function* () {
120
122
  const instance = new MetamaskConnectEVM(options);
121
- yield __classPrivateFieldGet(instance, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_attemptSessionRecovery).call(instance);
123
+ yield __classPrivateFieldGet(instance, _MetamaskConnectEVM_core, "f").emitSessionChanged();
122
124
  return instance;
123
125
  });
124
126
  }
@@ -126,64 +128,45 @@ export class MetamaskConnectEVM {
126
128
  * Connects to the wallet with the specified chain ID and optional account.
127
129
  *
128
130
  * @param options - The connection options
129
- * @param options.account - Optional specific account to connect to
130
- * @param options.forceRequest - Wwhether to force a request regardless of an existing session
131
- * @param options.chainIds - Array of chain IDs to connect to
131
+ * @param [options.account] - Optional param to specify an account to connect to
132
+ * @param [options.forceRequest] - Optional param to force a connection request regardless of whether there is a pre-existing session
133
+ * @param [options.chainIds] - Array of chain IDs to connect to (defaults to ethereum mainnet if not provided)
132
134
  * @returns A promise that resolves with the connected accounts and chain ID
133
135
  */
134
136
  connect() {
135
- return __awaiter(this, arguments, void 0, function* ({ account, forceRequest, chainIds } = {
136
- chainIds: [DEFAULT_CHAIN_ID],
137
- }) {
138
- var _a, _b;
137
+ return __awaiter(this, arguments, void 0, function* ({ account, forceRequest, chainIds = [DEFAULT_CHAIN_ID], } = {}) {
138
+ var _a;
139
139
  logger('request: connect', { account });
140
140
  if (!chainIds || chainIds.length === 0) {
141
141
  throw new Error('chainIds must be an array of at least one chain ID');
142
142
  }
143
- const caipChainIds = Array.from(new Set((_a = chainIds.concat(DEFAULT_CHAIN_ID)) !== null && _a !== void 0 ? _a : [DEFAULT_CHAIN_ID])).map((id) => `eip155:${id}`);
143
+ const caipChainIds = Array.from(new Set((_a = chainIds.concat(DEFAULT_CHAIN_ID)) !== null && _a !== void 0 ? _a : [DEFAULT_CHAIN_ID])).map((id) => `eip155:${hexToNumber(id)}`);
144
144
  const caipAccountIds = account
145
145
  ? caipChainIds.map((caipChainId) => `${caipChainId}:${account}`)
146
146
  : [];
147
- yield __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").connect(caipChainIds, caipAccountIds, undefined, forceRequest);
148
- const hexPermittedChainIds = getPermittedEthChainIds(__classPrivateFieldGet(this, _MetamaskConnectEVM_sessionScopes, "f"));
149
- const initialAccounts = yield __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").transport.sendEip1193Message({ method: 'eth_accounts', params: [] });
150
- const chainId = yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_getSelectedChainId).call(this, hexPermittedChainIds);
151
- __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onConnect).call(this, {
152
- chainId,
153
- accounts: initialAccounts.result,
154
- });
155
- // Remove previous notification handler if it exists
156
- (_b = __classPrivateFieldGet(this, _MetamaskConnectEVM_removeNotificationHandler, "f")) === null || _b === void 0 ? void 0 : _b.call(this);
157
- __classPrivateFieldSet(this, _MetamaskConnectEVM_removeNotificationHandler, __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").transport.onNotification((notification) => {
158
- var _a;
159
- // @ts-expect-error TODO: address this
160
- if ((notification === null || notification === void 0 ? void 0 : notification.method) === 'metamask_accountsChanged') {
161
- // @ts-expect-error TODO: address this
162
- const accounts = notification === null || notification === void 0 ? void 0 : notification.params;
163
- logger('transport-event: accountsChanged', accounts);
164
- __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onAccountsChanged).call(this, accounts);
165
- }
166
- // @ts-expect-error TODO: address this
167
- if ((notification === null || notification === void 0 ? void 0 : notification.method) === 'metamask_chainChanged') {
168
- // @ts-expect-error TODO: address this
169
- const notificationChainId = Number((_a = notification === null || notification === void 0 ? void 0 : notification.params) === null || _a === void 0 ? void 0 : _a.chainId);
170
- logger('transport-event: chainChanged', notificationChainId);
171
- // Cache the chainId for persistence across page refreshes
172
- __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_cacheChainId).call(this, notificationChainId).catch((error) => {
173
- logger('Error caching chainId in notification handler', error);
147
+ __classPrivateFieldSet(this, _MetamaskConnectEVM_status, 'connecting', "f");
148
+ try {
149
+ // Wait for the wallet_sessionChanged event to fire and set the provider properties
150
+ const result = new Promise((resolve) => {
151
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").once('connect', ({ chainId, accounts }) => {
152
+ logger('fulfilled-request: connect', {
153
+ chainId,
154
+ accounts,
155
+ });
156
+ resolve({
157
+ accounts,
158
+ chainId: chainId,
159
+ });
174
160
  });
175
- __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onChainChanged).call(this, notificationChainId);
176
- }
177
- }), "f");
178
- logger('fulfilled-request: connect', {
179
- chainId: chainIds[0],
180
- accounts: __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").accounts,
181
- });
182
- // TODO: update required here since accounts and chainId are now promises
183
- return {
184
- accounts: __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").accounts,
185
- chainId: hexToNumber(chainId),
186
- };
161
+ });
162
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").connect(caipChainIds, caipAccountIds, undefined, forceRequest);
163
+ return result;
164
+ }
165
+ catch (error) {
166
+ __classPrivateFieldSet(this, _MetamaskConnectEVM_status, 'disconnected', "f");
167
+ logger('Error connecting to wallet', error);
168
+ throw error;
169
+ }
187
170
  });
188
171
  }
189
172
  /**
@@ -191,7 +174,7 @@ export class MetamaskConnectEVM {
191
174
  *
192
175
  * @param options - The connection options
193
176
  * @param options.message - The message to sign after connecting
194
- * @param options.chainIds - Optional chain IDs to connect to (defaults to ethereum mainnet if not provided)
177
+ * @param [options.chainIds] - Optional hex chain IDs to connect to (defaults to ethereum mainnet if not provided)
195
178
  * @returns A promise that resolves with the signature
196
179
  * @throws Error if the selected account is not available after timeout
197
180
  */
@@ -219,9 +202,9 @@ export class MetamaskConnectEVM {
219
202
  * @param options - The options for connecting and invoking the method
220
203
  * @param options.method - The method name to invoke
221
204
  * @param options.params - The parameters to pass to the method, or a function that receives the account and returns params
222
- * @param options.chainIds - Optional chain IDs to connect to (defaults to ethereum mainnet if not provided)
223
- * @param options.account - Optional specific account to connect to
224
- * @param options.forceRequest - Whether to force a request regardless of an existing session
205
+ * @param [options.chainIds] - Optional hex chain IDs to connect to (defaults to ethereum mainnet if not provided)
206
+ * @param [options.account] - Optional specific account to connect to
207
+ * @param [options.forceRequest] - Whether to force a request regardless of an existing session
225
208
  * @returns A promise that resolves with the result of the method invocation
226
209
  * @throws Error if the selected account is not available after timeout (for methods that require an account)
227
210
  */
@@ -253,16 +236,22 @@ export class MetamaskConnectEVM {
253
236
  */
254
237
  disconnect() {
255
238
  return __awaiter(this, void 0, void 0, function* () {
239
+ var _a;
256
240
  logger('request: disconnect');
257
- yield __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").disconnect();
241
+ const sessionScopes = __classPrivateFieldGet(this, _MetamaskConnectEVM_sessionScopes, "f");
242
+ const eip155Scopes = Object.keys(sessionScopes).filter((scope) => {
243
+ const { namespace } = parseScopeString(scope);
244
+ return namespace === 'eip155';
245
+ });
246
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").disconnect(eip155Scopes);
258
247
  __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onDisconnect).call(this);
259
248
  __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_clearConnectionState).call(this);
260
- __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").off('wallet_sessionChanged', __classPrivateFieldGet(this, _MetamaskConnectEVM_sessionChangedHandler, "f"));
261
- __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").off('display_uri', __classPrivateFieldGet(this, _MetamaskConnectEVM_displayUriHandler, "f"));
262
- if (__classPrivateFieldGet(this, _MetamaskConnectEVM_removeNotificationHandler, "f")) {
263
- __classPrivateFieldGet(this, _MetamaskConnectEVM_removeNotificationHandler, "f").call(this);
264
- __classPrivateFieldSet(this, _MetamaskConnectEVM_removeNotificationHandler, undefined, "f");
265
- }
249
+ // Note: We intentionally do NOT remove the display_uri and wallet_sessionChanged
250
+ // listeners here. These are instance-scoped listeners that should remain active
251
+ // for the lifetime of the SDK instance, allowing reconnection to work properly.
252
+ // Session-scoped listeners (like the notification handler below) are removed.
253
+ (_a = __classPrivateFieldGet(this, _MetamaskConnectEVM_removeNotificationHandler, "f")) === null || _a === void 0 ? void 0 : _a.call(this);
254
+ __classPrivateFieldSet(this, _MetamaskConnectEVM_removeNotificationHandler, undefined, "f");
266
255
  logger('fulfilled-request: disconnect');
267
256
  });
268
257
  }
@@ -271,25 +260,24 @@ export class MetamaskConnectEVM {
271
260
  *
272
261
  * @param options - The options for the switch chain request
273
262
  * @param options.chainId - The chain ID to switch to
274
- * @param options.chainConfiguration - The chain configuration to use in case the chain is not present by the wallet
275
- * @returns The result of the switch chain request
263
+ * @param [options.chainConfiguration] - The chain configuration to use in case the chain is not present by the wallet
264
+ * @returns A promise that resolves when the chain has been switched
276
265
  */
277
266
  switchChain(_a) {
278
267
  return __awaiter(this, arguments, void 0, function* ({ chainId, chainConfiguration, }) {
279
268
  const method = 'wallet_switchEthereumChain';
280
- const hexChainId = isHex(chainId) ? chainId : numberToHex(chainId);
281
- const scope = `eip155:${isHex(chainId) ? hexToNumber(chainId) : chainId}`;
282
- const params = [{ chainId: hexChainId }];
269
+ const scope = `eip155:${hexToNumber(chainId)}`;
270
+ const params = [{ chainId }];
283
271
  yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_trackWalletActionRequested).call(this, method, scope, params);
284
272
  // TODO (wenfix): better way to return here other than resolving.
285
- if (this.selectedChainId === hexChainId) {
273
+ if (this.selectedChainId === chainId) {
286
274
  return Promise.resolve();
287
275
  }
288
276
  const permittedChainIds = getPermittedEthChainIds(__classPrivateFieldGet(this, _MetamaskConnectEVM_sessionScopes, "f"));
289
- if (permittedChainIds.includes(hexChainId) &&
277
+ if (permittedChainIds.includes(chainId) &&
290
278
  __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").transportType === TransportType.MWP) {
291
- yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_cacheChainId).call(this, hexChainId);
292
- __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onChainChanged).call(this, hexChainId);
279
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_cacheChainId).call(this, chainId);
280
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onChainChanged).call(this, chainId);
293
281
  yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_trackWalletActionSucceeded).call(this, method, scope, params);
294
282
  return Promise.resolve();
295
283
  }
@@ -307,10 +295,10 @@ export class MetamaskConnectEVM {
307
295
  yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_trackWalletActionSucceeded).call(this, method, scope, params);
308
296
  if (result.result === null) {
309
297
  // result is successful we eagerly call onChainChanged to update the provider's selected chain ID.
310
- yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_cacheChainId).call(this, hexChainId);
311
- __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onChainChanged).call(this, hexChainId);
298
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_cacheChainId).call(this, chainId);
299
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onChainChanged).call(this, chainId);
312
300
  }
313
- return result;
301
+ return Promise.resolve();
314
302
  }
315
303
  catch (error) {
316
304
  yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_trackWalletActionFailed).call(this, method, scope, params, error);
@@ -380,7 +368,7 @@ export class MetamaskConnectEVM {
380
368
  return __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").status;
381
369
  }
382
370
  }
383
- _MetamaskConnectEVM_core = new WeakMap(), _MetamaskConnectEVM_provider = new WeakMap(), _MetamaskConnectEVM_sessionScopes = new WeakMap(), _MetamaskConnectEVM_eventHandlers = new WeakMap(), _MetamaskConnectEVM_sessionChangedHandler = new WeakMap(), _MetamaskConnectEVM_displayUriHandler = new WeakMap(), _MetamaskConnectEVM_removeNotificationHandler = new WeakMap(), _MetamaskConnectEVM_instances = new WeakSet(), _MetamaskConnectEVM_getCoreOptions = function _MetamaskConnectEVM_getCoreOptions() {
371
+ _MetamaskConnectEVM_core = new WeakMap(), _MetamaskConnectEVM_provider = new WeakMap(), _MetamaskConnectEVM_sessionScopes = new WeakMap(), _MetamaskConnectEVM_eventHandlers = new WeakMap(), _MetamaskConnectEVM_sessionChangedHandler = new WeakMap(), _MetamaskConnectEVM_displayUriHandler = new WeakMap(), _MetamaskConnectEVM_removeNotificationHandler = new WeakMap(), _MetamaskConnectEVM_status = new WeakMap(), _MetamaskConnectEVM_instances = new WeakSet(), _MetamaskConnectEVM_getCoreOptions = function _MetamaskConnectEVM_getCoreOptions() {
384
372
  return __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").options;
385
373
  }, _MetamaskConnectEVM_createInvokeOptions = function _MetamaskConnectEVM_createInvokeOptions(method, scope, params) {
386
374
  return {
@@ -449,6 +437,7 @@ _MetamaskConnectEVM_core = new WeakMap(), _MetamaskConnectEVM_provider = new Wea
449
437
  });
450
438
  }, _MetamaskConnectEVM_requestInterceptor = function _MetamaskConnectEVM_requestInterceptor(request) {
451
439
  return __awaiter(this, void 0, void 0, function* () {
440
+ var _a;
452
441
  logger(`Intercepting request for method: ${request.method}`);
453
442
  if (IGNORED_METHODS.includes(request.method)) {
454
443
  // TODO: replace with correct method unsupported provider error
@@ -483,7 +472,7 @@ _MetamaskConnectEVM_core = new WeakMap(), _MetamaskConnectEVM_provider = new Wea
483
472
  }
484
473
  if (isSwitchChainRequest(request)) {
485
474
  return this.switchChain({
486
- chainId: parseInt(request.params[0].chainId, 16),
475
+ chainId: request.params[0].chainId,
487
476
  });
488
477
  }
489
478
  if (isAddChainRequest(request)) {
@@ -491,10 +480,8 @@ _MetamaskConnectEVM_core = new WeakMap(), _MetamaskConnectEVM_provider = new Wea
491
480
  }
492
481
  if (isAccountsRequest(request)) {
493
482
  const { method } = request;
494
- const chainId = __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").selectedChainId
495
- ? hexToNumber(__classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").selectedChainId)
496
- : 1;
497
- const scope = `eip155:${chainId}`;
483
+ const decimalChainId = hexToNumber((_a = __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").selectedChainId) !== null && _a !== void 0 ? _a : '0x1');
484
+ const scope = `eip155:${decimalChainId}`;
498
485
  const params = [];
499
486
  yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_trackWalletActionRequested).call(this, method, scope, params);
500
487
  yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_trackWalletActionSucceeded).call(this, method, scope, params);
@@ -511,17 +498,17 @@ _MetamaskConnectEVM_core = new WeakMap(), _MetamaskConnectEVM_provider = new Wea
511
498
  __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").selectedChainId = undefined;
512
499
  }, _MetamaskConnectEVM_addEthereumChain = function _MetamaskConnectEVM_addEthereumChain(chainConfiguration) {
513
500
  return __awaiter(this, void 0, void 0, function* () {
514
- var _a;
515
501
  logger('addEthereumChain called', { chainConfiguration });
516
502
  const method = 'wallet_addEthereumChain';
517
503
  if (!chainConfiguration) {
518
504
  throw new Error('No chain configuration found.');
519
505
  }
520
506
  // Get chain ID from config or use current chain
521
- const chainId = chainConfiguration.chainId
522
- ? parseInt(chainConfiguration.chainId, 16)
523
- : hexToNumber((_a = __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").selectedChainId) !== null && _a !== void 0 ? _a : '0x1');
524
- const scope = `eip155:${chainId}`;
507
+ const chainId = chainConfiguration.chainId ||
508
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").selectedChainId ||
509
+ '0x1';
510
+ const decimalChainId = hexToNumber(chainId);
511
+ const scope = `eip155:${decimalChainId}`;
525
512
  const params = [chainConfiguration];
526
513
  yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_trackWalletActionRequested).call(this, method, scope, params);
527
514
  try {
@@ -547,89 +534,124 @@ _MetamaskConnectEVM_core = new WeakMap(), _MetamaskConnectEVM_provider = new Wea
547
534
  const result = __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").transport.sendEip1193Message(request);
548
535
  if (request.method === 'wallet_addEthereumChain' ||
549
536
  request.method === 'wallet_switchEthereumChain') {
550
- __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").openDeeplinkIfNeeded();
537
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").openSimpleDeeplinkIfNeeded();
551
538
  }
552
539
  return result;
553
540
  });
554
541
  }, _MetamaskConnectEVM_cacheChainId = function _MetamaskConnectEVM_cacheChainId(chainId) {
555
542
  return __awaiter(this, void 0, void 0, function* () {
556
543
  try {
557
- const hexChainId = isHex(chainId) ? chainId : numberToHex(chainId);
558
- yield __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").storage.adapter.set(CHAIN_STORE_KEY, JSON.stringify(hexChainId));
544
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").storage.adapter.set(CHAIN_STORE_KEY, JSON.stringify(chainId));
559
545
  }
560
546
  catch (error) {
561
547
  logger('Error caching chainId', error);
562
548
  }
563
549
  });
550
+ }, _MetamaskConnectEVM_onSessionChanged = function _MetamaskConnectEVM_onSessionChanged(session) {
551
+ return __awaiter(this, void 0, void 0, function* () {
552
+ var _a;
553
+ logger('event: wallet_sessionChanged', session);
554
+ __classPrivateFieldSet(this, _MetamaskConnectEVM_sessionScopes, (_a = session === null || session === void 0 ? void 0 : session.sessionScopes) !== null && _a !== void 0 ? _a : {}, "f");
555
+ const hexPermittedChainIds = getPermittedEthChainIds(__classPrivateFieldGet(this, _MetamaskConnectEVM_sessionScopes, "f"));
556
+ if (hexPermittedChainIds.length === 0) {
557
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onDisconnect).call(this);
558
+ }
559
+ else {
560
+ let initialAccounts = [];
561
+ if (__classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").status === 'connected') {
562
+ const ethAccountsResponse = yield __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").transport.sendEip1193Message({
563
+ method: 'eth_accounts',
564
+ params: [],
565
+ });
566
+ initialAccounts = ethAccountsResponse.result;
567
+ }
568
+ else {
569
+ initialAccounts = getEthAccounts(__classPrivateFieldGet(this, _MetamaskConnectEVM_sessionScopes, "f"));
570
+ }
571
+ const chainId = yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_getSelectedChainId).call(this, hexPermittedChainIds);
572
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onConnect).call(this, {
573
+ chainId,
574
+ accounts: initialAccounts,
575
+ });
576
+ }
577
+ });
564
578
  }, _MetamaskConnectEVM_onChainChanged = function _MetamaskConnectEVM_onChainChanged(chainId) {
565
579
  var _a, _b;
566
- const hexChainId = isHex(chainId) ? chainId : numberToHex(chainId);
567
- if (hexChainId === __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").selectedChainId) {
580
+ if (chainId === __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").selectedChainId) {
568
581
  return;
569
582
  }
570
583
  logger('handler: chainChanged', { chainId });
571
584
  __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").selectedChainId = chainId;
572
- (_b = (_a = __classPrivateFieldGet(this, _MetamaskConnectEVM_eventHandlers, "f")) === null || _a === void 0 ? void 0 : _a.chainChanged) === null || _b === void 0 ? void 0 : _b.call(_a, hexChainId);
573
- __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").emit('chainChanged', hexChainId);
585
+ (_b = (_a = __classPrivateFieldGet(this, _MetamaskConnectEVM_eventHandlers, "f")) === null || _a === void 0 ? void 0 : _a.chainChanged) === null || _b === void 0 ? void 0 : _b.call(_a, chainId);
586
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").emit('chainChanged', chainId);
574
587
  }, _MetamaskConnectEVM_onAccountsChanged = function _MetamaskConnectEVM_onAccountsChanged(accounts) {
575
588
  var _a, _b;
589
+ const accountsUnchanged = accounts.length === __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").accounts.length &&
590
+ accounts.every((acct, idx) => acct === __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").accounts[idx]);
591
+ if (accountsUnchanged) {
592
+ return;
593
+ }
576
594
  logger('handler: accountsChanged', accounts);
577
595
  __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").accounts = accounts;
578
596
  __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").emit('accountsChanged', accounts);
579
597
  (_b = (_a = __classPrivateFieldGet(this, _MetamaskConnectEVM_eventHandlers, "f")) === null || _a === void 0 ? void 0 : _a.accountsChanged) === null || _b === void 0 ? void 0 : _b.call(_a, accounts);
580
598
  }, _MetamaskConnectEVM_onConnect = function _MetamaskConnectEVM_onConnect({ chainId, accounts, }) {
581
- var _a, _b;
599
+ var _a, _b, _c;
582
600
  logger('handler: connect', { chainId, accounts });
583
601
  const data = {
584
- chainId: isHex(chainId) ? chainId : numberToHex(chainId),
602
+ chainId,
585
603
  accounts,
586
604
  };
587
- __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").emit('connect', data);
588
- (_b = (_a = __classPrivateFieldGet(this, _MetamaskConnectEVM_eventHandlers, "f")) === null || _a === void 0 ? void 0 : _a.connect) === null || _b === void 0 ? void 0 : _b.call(_a, data);
605
+ if (__classPrivateFieldGet(this, _MetamaskConnectEVM_status, "f") !== 'connected') {
606
+ __classPrivateFieldSet(this, _MetamaskConnectEVM_status, 'connected', "f");
607
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").emit('connect', data);
608
+ (_b = (_a = __classPrivateFieldGet(this, _MetamaskConnectEVM_eventHandlers, "f")) === null || _a === void 0 ? void 0 : _a.connect) === null || _b === void 0 ? void 0 : _b.call(_a, data);
609
+ (_c = __classPrivateFieldGet(this, _MetamaskConnectEVM_removeNotificationHandler, "f")) === null || _c === void 0 ? void 0 : _c.call(this);
610
+ // TODO: Verify if #core.on('metamask_accountsChanged') and #core.on('metamask_chainChanged')
611
+ // would work here instead
612
+ __classPrivateFieldSet(this, _MetamaskConnectEVM_removeNotificationHandler, __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").transport.onNotification((notification) => {
613
+ var _a;
614
+ // @ts-expect-error TODO: address this
615
+ if ((notification === null || notification === void 0 ? void 0 : notification.method) === 'metamask_accountsChanged') {
616
+ // @ts-expect-error TODO: address this
617
+ const notificationAccounts = notification === null || notification === void 0 ? void 0 : notification.params;
618
+ logger('transport-event: accountsChanged', notificationAccounts);
619
+ // why are we not caching the accounts here?
620
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onAccountsChanged).call(this, notificationAccounts);
621
+ }
622
+ // @ts-expect-error TODO: address this
623
+ if ((notification === null || notification === void 0 ? void 0 : notification.method) === 'metamask_chainChanged') {
624
+ // @ts-expect-error TODO: address this
625
+ const notificationChainId = (_a = notification === null || notification === void 0 ? void 0 : notification.params) === null || _a === void 0 ? void 0 : _a.chainId;
626
+ logger('transport-event: chainChanged', notificationChainId);
627
+ // Cache the chainId for persistence across page refreshes
628
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_cacheChainId).call(this, notificationChainId).catch((error) => {
629
+ logger('Error caching chainId in notification handler', error);
630
+ });
631
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onChainChanged).call(this, notificationChainId);
632
+ }
633
+ }), "f");
634
+ }
589
635
  __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onChainChanged).call(this, chainId);
590
636
  __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onAccountsChanged).call(this, accounts);
591
637
  }, _MetamaskConnectEVM_onDisconnect = function _MetamaskConnectEVM_onDisconnect() {
592
638
  var _a, _b;
639
+ if (__classPrivateFieldGet(this, _MetamaskConnectEVM_status, "f") === 'disconnected') {
640
+ return;
641
+ }
642
+ __classPrivateFieldSet(this, _MetamaskConnectEVM_status, 'disconnected', "f");
593
643
  logger('handler: disconnect');
594
644
  __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").emit('disconnect');
595
645
  (_b = (_a = __classPrivateFieldGet(this, _MetamaskConnectEVM_eventHandlers, "f")) === null || _a === void 0 ? void 0 : _a.disconnect) === null || _b === void 0 ? void 0 : _b.call(_a);
596
646
  __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onAccountsChanged).call(this, []);
597
647
  }, _MetamaskConnectEVM_onDisplayUri = function _MetamaskConnectEVM_onDisplayUri(uri) {
598
648
  var _a, _b;
649
+ if (__classPrivateFieldGet(this, _MetamaskConnectEVM_status, "f") !== 'connecting') {
650
+ return;
651
+ }
599
652
  logger('handler: display_uri', uri);
600
653
  __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").emit('display_uri', uri);
601
654
  (_b = (_a = __classPrivateFieldGet(this, _MetamaskConnectEVM_eventHandlers, "f")) === null || _a === void 0 ? void 0 : _a.displayUri) === null || _b === void 0 ? void 0 : _b.call(_a, uri);
602
- }, _MetamaskConnectEVM_attemptSessionRecovery = function _MetamaskConnectEVM_attemptSessionRecovery() {
603
- return __awaiter(this, void 0, void 0, function* () {
604
- // Skip session recovery if transport is not initialized yet.
605
- // Transport is only initialized when there's a stored session or after connect() is called.
606
- // Only attempt recovery if we're in a state where transport should be available.
607
- if (__classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").status !== 'connected' && __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").status !== 'connecting') {
608
- return;
609
- }
610
- try {
611
- const response = yield __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").transport.request({
612
- method: 'wallet_getSession',
613
- });
614
- const { sessionScopes } = response.result;
615
- __classPrivateFieldSet(this, _MetamaskConnectEVM_sessionScopes, sessionScopes, "f");
616
- const permittedChainIds = getPermittedEthChainIds(sessionScopes);
617
- // Instead of using the accounts we get back from calling `wallet_getSession`
618
- // we get permitted accounts from `eth_accounts` to make sure we have them ordered by last selected account
619
- // and correctly set the currently selected account for the dapp
620
- const permittedAccounts = yield __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").transport.sendEip1193Message({ method: 'eth_accounts', params: [] });
621
- const chainId = yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_getSelectedChainId).call(this, permittedChainIds);
622
- if (permittedChainIds.length && permittedAccounts.result) {
623
- __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onConnect).call(this, {
624
- chainId,
625
- accounts: permittedAccounts.result,
626
- });
627
- }
628
- }
629
- catch (error) {
630
- console.error('Error attempting session recovery', error);
631
- }
632
- });
633
655
  };
634
656
  /**
635
657
  * Creates a new Metamask Connect/EVM instance
@@ -637,19 +659,27 @@ _MetamaskConnectEVM_core = new WeakMap(), _MetamaskConnectEVM_provider = new Wea
637
659
  * @param options - The options for the Metamask Connect/EVM layer
638
660
  * @param options.dapp - Dapp identification and branding settings
639
661
  * @param options.api - API configuration including read-only RPC map
640
- * @param options.api.supportedNetworks - A map of CAIP chain IDs to RPC URLs for read-only requests
641
- * @param options.ui - UI configuration options
642
- * @param options.ui.headless - Whether to run without UI
643
- * @param options.ui.preferExtension - Whether to prefer browser extension
644
- * @param options.ui.showInstallModal - Whether to render installation modal for desktop extension
645
- * @param options.eventEmitter - The event emitter to use for the Metamask Connect/EVM layer
646
- * @param options.eventHandlers - The event handlers to use for the Metamask Connect/EVM layer
647
- * @returns The Metamask Connect/EVM layer instance
662
+ * @param options.api.supportedNetworks - A map of hex chain IDs to RPC URLs for read-only requests
663
+ * @param [options.ui] - UI configuration options
664
+ * @param [options.ui.headless] - Whether to run without UI
665
+ * @param [options.ui.preferExtension] - Whether to prefer browser extension
666
+ * @param [options.ui.showInstallModal] - Whether to render installation modal for desktop extension
667
+ * @param [options.mobile] - Mobile configuration options
668
+ * @param [options.mobile.preferredOpenLink] - Custom handler for opening deeplinks (useful for React Native, etc.)
669
+ * @param [options.mobile.useDeeplink] - Whether to use native deeplinks instead of universal links
670
+ * @param [options.transport] - Transport configuration (e.g., extensionId, notification handler)
671
+ * @param [options.transport.extensionId] - Extension ID for browser extension transport
672
+ * @param [options.transport.onNotification] - Callback for receiving transport notifications
673
+ * @param [options.eventHandlers] - Event handlers for the Metamask Connect/EVM layer
674
+ * @param [options.debug] - Enable debug logging
675
+ * @returns The Metamask-Connect EVM client instance
648
676
  */
649
677
  export function createEVMClient(options) {
650
678
  return __awaiter(this, void 0, void 0, function* () {
651
679
  var _a;
652
- enableDebug(options.debug);
680
+ if (options.debug) {
681
+ enableDebug();
682
+ }
653
683
  logger('Creating Metamask Connect/EVM with options:', options);
654
684
  // Validate that supportedNetworks is provided and not empty
655
685
  if (!((_a = options.api) === null || _a === void 0 ? void 0 : _a.supportedNetworks) ||
@@ -657,9 +687,15 @@ export function createEVMClient(options) {
657
687
  throw new Error('supportedNetworks is required and must contain at least one chain configuration');
658
688
  }
659
689
  validSupportedChainsUrls(options.api.supportedNetworks, 'supportedNetworks');
690
+ const supportedNetworksCaipChainId = Object.entries(options.api.supportedNetworks).reduce((acc, [hexChainId, url]) => {
691
+ const decimalChainId = parseInt(hexChainId, 16);
692
+ const caip2ChainId = `eip155:${decimalChainId}`;
693
+ acc[caip2ChainId] = url;
694
+ return acc;
695
+ }, {});
660
696
  try {
661
697
  const core = yield createMultichainClient(Object.assign(Object.assign({}, options), { api: {
662
- supportedNetworks: options.api.supportedNetworks,
698
+ supportedNetworks: supportedNetworksCaipChainId,
663
699
  } }));
664
700
  return MetamaskConnectEVM.create({
665
701
  core,