@metamask/connect-evm 0.1.1 → 0.2.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.
@@ -0,0 +1,647 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
11
+ if (kind === "m") throw new TypeError("Private method is not writable");
12
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
13
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
14
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
15
+ };
16
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
17
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
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
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
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;
22
+ import { analytics } from '@metamask/analytics';
23
+ import { createMultichainClient, getWalletActionAnalyticsProperties, isRejectionError, TransportType, } from '@metamask/connect-multichain';
24
+ import { numberToHex, hexToNumber, isHexString as isHex, } from '@metamask/utils';
25
+ import { IGNORED_METHODS } from './constants';
26
+ import { enableDebug, logger } from './logger';
27
+ import { EIP1193Provider } from './provider';
28
+ import { getPermittedEthChainIds } from './utils/caip';
29
+ import { isAccountsRequest, isAddChainRequest, isConnectRequest, isSwitchChainRequest, validSupportedChainsUrls, } from './utils/type-guards';
30
+ const DEFAULT_CHAIN_ID = 1;
31
+ const CHAIN_STORE_KEY = 'cache_eth_chainId';
32
+ /**
33
+ * The MetamaskConnectEVM class provides an EIP-1193 compatible interface for connecting
34
+ * to MetaMask and interacting with Ethereum Virtual Machine (EVM) networks.
35
+ *
36
+ * This class serves as a modern replacement for MetaMask SDK V1, offering enhanced
37
+ * functionality and cross-platform compatibility. It wraps the Multichain SDK to provide
38
+ * a simplified, EIP-1193 compliant API for dapp developers.
39
+ *
40
+ * Key features:
41
+ * - EIP-1193 provider interface for seamless integration with existing dapp code
42
+ * - Automatic session recovery when reloading or opening in new tabs
43
+ * - Chain switching with automatic chain addition if not configured
44
+ * - Event-driven architecture with support for connect, disconnect, accountsChanged, and chainChanged events
45
+ * - Cross-platform support for browser extensions and mobile applications
46
+ * - Built-in handling of common Ethereum methods (eth_accounts, wallet_switchEthereumChain, etc.)
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * const sdk = await createEVMClient({
51
+ * dapp: { name: 'My DApp', url: 'https://mydapp.com' }
52
+ * });
53
+ *
54
+ * await sdk.connect({ chainId: 1 });
55
+ * const provider = await sdk.getProvider();
56
+ * const accounts = await provider.request({ method: 'eth_accounts' });
57
+ * ```
58
+ */
59
+ export class MetamaskConnectEVM {
60
+ /**
61
+ * Creates a new MetamaskConnectEVM instance.
62
+ *
63
+ * @param options - The options for the MetamaskConnectEVM instance
64
+ * @param options.core - The core instance of the Multichain SDK
65
+ * @param options.eventHandlers - Optional event handlers for EIP-1193 provider events
66
+ */
67
+ constructor({ core, eventHandlers }) {
68
+ _MetamaskConnectEVM_instances.add(this);
69
+ /** The core instance of the Multichain SDK */
70
+ _MetamaskConnectEVM_core.set(this, void 0);
71
+ /** An instance of the EIP-1193 provider interface */
72
+ _MetamaskConnectEVM_provider.set(this, void 0);
73
+ /** The session scopes currently permitted */
74
+ _MetamaskConnectEVM_sessionScopes.set(this, {});
75
+ /** Optional event handlers for the EIP-1193 provider events. */
76
+ _MetamaskConnectEVM_eventHandlers.set(this, void 0);
77
+ /** The handler for the wallet_sessionChanged event */
78
+ _MetamaskConnectEVM_sessionChangedHandler.set(this, void 0);
79
+ /** The handler for the display_uri event */
80
+ _MetamaskConnectEVM_displayUriHandler.set(this, void 0);
81
+ /** The clean-up function for the notification handler */
82
+ _MetamaskConnectEVM_removeNotificationHandler.set(this, void 0);
83
+ __classPrivateFieldSet(this, _MetamaskConnectEVM_core, core, "f");
84
+ __classPrivateFieldSet(this, _MetamaskConnectEVM_provider, new EIP1193Provider(core, __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_requestInterceptor).bind(this)), "f");
85
+ __classPrivateFieldSet(this, _MetamaskConnectEVM_eventHandlers, eventHandlers, "f");
86
+ /**
87
+ * Handles the wallet_sessionChanged event.
88
+ * Updates the internal connection state with the new session data.
89
+ *
90
+ * @param session - The session data
91
+ */
92
+ __classPrivateFieldSet(this, _MetamaskConnectEVM_sessionChangedHandler, (session) => {
93
+ var _a;
94
+ logger('event: wallet_sessionChanged', session);
95
+ __classPrivateFieldSet(this, _MetamaskConnectEVM_sessionScopes, (_a = session === null || session === void 0 ? void 0 : session.sessionScopes) !== null && _a !== void 0 ? _a : {}, "f");
96
+ }, "f");
97
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").on('wallet_sessionChanged', __classPrivateFieldGet(this, _MetamaskConnectEVM_sessionChangedHandler, "f").bind(this));
98
+ /**
99
+ * Handles the display_uri event.
100
+ * Forwards the QR code URI to the provider for custom UI implementations.
101
+ */
102
+ __classPrivateFieldSet(this, _MetamaskConnectEVM_displayUriHandler, __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onDisplayUri).bind(this), "f");
103
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").on('display_uri', __classPrivateFieldGet(this, _MetamaskConnectEVM_displayUriHandler, "f"));
104
+ // Attempt to set the permitted accounts if there's a valid previous session.
105
+ // TODO (wenfix): does it make sense to catch here?
106
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_attemptSessionRecovery).call(this).catch((error) => {
107
+ console.error('Error attempting session recovery', error);
108
+ });
109
+ logger('Connect/EVM constructor completed');
110
+ }
111
+ /**
112
+ * Connects to the wallet with the specified chain ID and optional account.
113
+ *
114
+ * @param options - The connection options
115
+ * @param options.account - Optional specific account to connect to
116
+ * @param options.forceRequest - Wwhether to force a request regardless of an existing session
117
+ * @param options.chainIds - Array of chain IDs to connect to
118
+ * @returns A promise that resolves with the connected accounts and chain ID
119
+ */
120
+ connect() {
121
+ return __awaiter(this, arguments, void 0, function* ({ account, forceRequest, chainIds } = {
122
+ chainIds: [DEFAULT_CHAIN_ID],
123
+ }) {
124
+ var _a, _b;
125
+ logger('request: connect', { account });
126
+ if (!chainIds || chainIds.length === 0) {
127
+ throw new Error('chainIds must be an array of at least one chain ID');
128
+ }
129
+ const caipChainIds = Array.from(new Set((_a = chainIds.concat(DEFAULT_CHAIN_ID)) !== null && _a !== void 0 ? _a : [DEFAULT_CHAIN_ID])).map((id) => `eip155:${id}`);
130
+ const caipAccountIds = account
131
+ ? caipChainIds.map((caipChainId) => `${caipChainId}:${account}`)
132
+ : [];
133
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").connect(caipChainIds, caipAccountIds, {}, forceRequest);
134
+ const hexPermittedChainIds = getPermittedEthChainIds(__classPrivateFieldGet(this, _MetamaskConnectEVM_sessionScopes, "f"));
135
+ const initialAccounts = yield __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").transport.sendEip1193Message({ method: 'eth_accounts', params: [] });
136
+ const chainId = yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_getSelectedChainId).call(this, hexPermittedChainIds);
137
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onConnect).call(this, {
138
+ chainId,
139
+ accounts: initialAccounts.result,
140
+ });
141
+ // Remove previous notification handler if it exists
142
+ (_b = __classPrivateFieldGet(this, _MetamaskConnectEVM_removeNotificationHandler, "f")) === null || _b === void 0 ? void 0 : _b.call(this);
143
+ __classPrivateFieldSet(this, _MetamaskConnectEVM_removeNotificationHandler, __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").transport.onNotification((notification) => {
144
+ var _a;
145
+ // @ts-expect-error TODO: address this
146
+ if ((notification === null || notification === void 0 ? void 0 : notification.method) === 'metamask_accountsChanged') {
147
+ // @ts-expect-error TODO: address this
148
+ const accounts = notification === null || notification === void 0 ? void 0 : notification.params;
149
+ logger('transport-event: accountsChanged', accounts);
150
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onAccountsChanged).call(this, accounts);
151
+ }
152
+ // @ts-expect-error TODO: address this
153
+ if ((notification === null || notification === void 0 ? void 0 : notification.method) === 'metamask_chainChanged') {
154
+ // @ts-expect-error TODO: address this
155
+ const notificationChainId = Number((_a = notification === null || notification === void 0 ? void 0 : notification.params) === null || _a === void 0 ? void 0 : _a.chainId);
156
+ logger('transport-event: chainChanged', notificationChainId);
157
+ // Cache the chainId for persistence across page refreshes
158
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_cacheChainId).call(this, notificationChainId).catch((error) => {
159
+ logger('Error caching chainId in notification handler', error);
160
+ });
161
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onChainChanged).call(this, notificationChainId);
162
+ }
163
+ }), "f");
164
+ logger('fulfilled-request: connect', {
165
+ chainId: chainIds[0],
166
+ accounts: __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").accounts,
167
+ });
168
+ // TODO: update required here since accounts and chainId are now promises
169
+ return {
170
+ accounts: __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").accounts,
171
+ chainId: hexToNumber(chainId),
172
+ };
173
+ });
174
+ }
175
+ /**
176
+ * Connects to the wallet and signs a message using personal_sign.
177
+ *
178
+ * @param options - The connection options
179
+ * @param options.message - The message to sign after connecting
180
+ * @param options.chainIds - Optional chain IDs to connect to (defaults to ethereum mainnet if not provided)
181
+ * @returns A promise that resolves with the signature
182
+ * @throws Error if the selected account is not available after timeout
183
+ */
184
+ connectAndSign(_a) {
185
+ return __awaiter(this, arguments, void 0, function* ({ message, chainIds, }) {
186
+ var _b, _c;
187
+ const { accounts, chainId } = yield this.connect({
188
+ chainIds: chainIds !== null && chainIds !== void 0 ? chainIds : [DEFAULT_CHAIN_ID],
189
+ });
190
+ const result = (yield __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").request({
191
+ method: 'personal_sign',
192
+ params: [accounts[0], message],
193
+ }));
194
+ (_c = (_b = __classPrivateFieldGet(this, _MetamaskConnectEVM_eventHandlers, "f")) === null || _b === void 0 ? void 0 : _b.connectAndSign) === null || _c === void 0 ? void 0 : _c.call(_b, {
195
+ accounts,
196
+ chainId,
197
+ signResponse: result,
198
+ });
199
+ return result;
200
+ });
201
+ }
202
+ /**
203
+ * Connects to the wallet and invokes a method with specified parameters.
204
+ *
205
+ * @param options - The options for connecting and invoking the method
206
+ * @param options.method - The method name to invoke
207
+ * @param options.params - The parameters to pass to the method, or a function that receives the account and returns params
208
+ * @param options.chainIds - Optional chain IDs to connect to (defaults to ethereum mainnet if not provided)
209
+ * @param options.account - Optional specific account to connect to
210
+ * @param options.forceRequest - Whether to force a request regardless of an existing session
211
+ * @returns A promise that resolves with the result of the method invocation
212
+ * @throws Error if the selected account is not available after timeout (for methods that require an account)
213
+ */
214
+ connectWith(_a) {
215
+ return __awaiter(this, arguments, void 0, function* ({ method, params, chainIds, account, forceRequest, }) {
216
+ var _b, _c;
217
+ const { accounts: connectedAccounts, chainId: connectedChainId } = yield this.connect({
218
+ chainIds: chainIds !== null && chainIds !== void 0 ? chainIds : [DEFAULT_CHAIN_ID],
219
+ account,
220
+ forceRequest,
221
+ });
222
+ const resolvedParams = typeof params === 'function' ? params(connectedAccounts[0]) : params;
223
+ const result = yield __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").request({
224
+ method,
225
+ params: resolvedParams,
226
+ });
227
+ (_c = (_b = __classPrivateFieldGet(this, _MetamaskConnectEVM_eventHandlers, "f")) === null || _b === void 0 ? void 0 : _b.connectWith) === null || _c === void 0 ? void 0 : _c.call(_b, {
228
+ accounts: connectedAccounts,
229
+ chainId: connectedChainId,
230
+ connectWithResponse: result,
231
+ });
232
+ return result;
233
+ });
234
+ }
235
+ /**
236
+ * Disconnects from the wallet by revoking the session and cleaning up event listeners.
237
+ *
238
+ * @returns A promise that resolves when disconnection is complete
239
+ */
240
+ disconnect() {
241
+ return __awaiter(this, void 0, void 0, function* () {
242
+ logger('request: disconnect');
243
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").disconnect();
244
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onDisconnect).call(this);
245
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_clearConnectionState).call(this);
246
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").off('wallet_sessionChanged', __classPrivateFieldGet(this, _MetamaskConnectEVM_sessionChangedHandler, "f"));
247
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").off('display_uri', __classPrivateFieldGet(this, _MetamaskConnectEVM_displayUriHandler, "f"));
248
+ if (__classPrivateFieldGet(this, _MetamaskConnectEVM_removeNotificationHandler, "f")) {
249
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_removeNotificationHandler, "f").call(this);
250
+ __classPrivateFieldSet(this, _MetamaskConnectEVM_removeNotificationHandler, undefined, "f");
251
+ }
252
+ logger('fulfilled-request: disconnect');
253
+ });
254
+ }
255
+ /**
256
+ * Switches the Ethereum chain. Will track state internally whenever possible.
257
+ *
258
+ * @param options - The options for the switch chain request
259
+ * @param options.chainId - The chain ID to switch to
260
+ * @param options.chainConfiguration - The chain configuration to use in case the chain is not present by the wallet
261
+ * @returns The result of the switch chain request
262
+ */
263
+ switchChain(_a) {
264
+ return __awaiter(this, arguments, void 0, function* ({ chainId, chainConfiguration, }) {
265
+ const method = 'wallet_switchEthereumChain';
266
+ const hexChainId = isHex(chainId) ? chainId : numberToHex(chainId);
267
+ const scope = `eip155:${isHex(chainId) ? hexToNumber(chainId) : chainId}`;
268
+ const params = [{ chainId: hexChainId }];
269
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_trackWalletActionRequested).call(this, method, scope, params);
270
+ // TODO (wenfix): better way to return here other than resolving.
271
+ if (this.selectedChainId === hexChainId) {
272
+ return Promise.resolve();
273
+ }
274
+ const permittedChainIds = getPermittedEthChainIds(__classPrivateFieldGet(this, _MetamaskConnectEVM_sessionScopes, "f"));
275
+ if (permittedChainIds.includes(hexChainId) &&
276
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").transportType === TransportType.MWP) {
277
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_cacheChainId).call(this, hexChainId);
278
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onChainChanged).call(this, hexChainId);
279
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_trackWalletActionSucceeded).call(this, method, scope, params);
280
+ return Promise.resolve();
281
+ }
282
+ try {
283
+ const result = yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_request).call(this, {
284
+ method: 'wallet_switchEthereumChain',
285
+ params,
286
+ });
287
+ // When using the MWP transport, the error is returned instead of thrown,
288
+ // so we force it into the catch block here.
289
+ const resultWithError = result;
290
+ if (resultWithError === null || resultWithError === void 0 ? void 0 : resultWithError.error) {
291
+ throw new Error(resultWithError.error.message);
292
+ }
293
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_trackWalletActionSucceeded).call(this, method, scope, params);
294
+ if (result.result === null) {
295
+ // result is successful we eagerly call onChainChanged to update the provider's selected chain ID.
296
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_cacheChainId).call(this, hexChainId);
297
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onChainChanged).call(this, hexChainId);
298
+ }
299
+ return result;
300
+ }
301
+ catch (error) {
302
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_trackWalletActionFailed).call(this, method, scope, params, error);
303
+ // Fallback to add the chain if its not configured in the wallet.
304
+ if (error.message.includes('Unrecognized chain ID')) {
305
+ return __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_addEthereumChain).call(this, chainConfiguration);
306
+ }
307
+ throw error;
308
+ }
309
+ });
310
+ }
311
+ /**
312
+ * Gets the EIP-1193 provider instance
313
+ *
314
+ * @returns The EIP-1193 provider instance
315
+ */
316
+ getProvider() {
317
+ return __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f");
318
+ }
319
+ /**
320
+ * Gets the currently selected chain ID on the wallet
321
+ *
322
+ * @returns The currently selected chain ID or undefined if no chain is selected
323
+ */
324
+ getChainId() {
325
+ return this.selectedChainId;
326
+ }
327
+ /**
328
+ * Gets the currently selected account on the wallet
329
+ *
330
+ * @returns The currently selected account or undefined if no account is selected
331
+ */
332
+ getAccount() {
333
+ return __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").selectedAccount;
334
+ }
335
+ // Convenience getters for the EIP-1193 provider
336
+ /**
337
+ * Gets the currently permitted accounts
338
+ *
339
+ * @returns The currently permitted accounts
340
+ */
341
+ get accounts() {
342
+ return __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").accounts;
343
+ }
344
+ /**
345
+ * Gets the currently selected account on the wallet
346
+ *
347
+ * @returns The currently selected account or undefined if no account is selected
348
+ */
349
+ get selectedAccount() {
350
+ return __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").selectedAccount;
351
+ }
352
+ /**
353
+ * Gets the currently selected chain ID on the wallet
354
+ *
355
+ * @returns The currently selected chain ID or undefined if no chain is selected
356
+ */
357
+ get selectedChainId() {
358
+ return __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").selectedChainId;
359
+ }
360
+ }
361
+ _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() {
362
+ return __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").options;
363
+ }, _MetamaskConnectEVM_createInvokeOptions = function _MetamaskConnectEVM_createInvokeOptions(method, scope, params) {
364
+ return {
365
+ scope,
366
+ request: { method, params },
367
+ };
368
+ }, _MetamaskConnectEVM_trackWalletActionRequested = function _MetamaskConnectEVM_trackWalletActionRequested(method, scope, params) {
369
+ return __awaiter(this, void 0, void 0, function* () {
370
+ const coreOptions = __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_getCoreOptions).call(this);
371
+ try {
372
+ const invokeOptions = __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_createInvokeOptions).call(this, method, scope, params);
373
+ const props = yield getWalletActionAnalyticsProperties(coreOptions, __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").storage, invokeOptions);
374
+ analytics.track('mmconnect_wallet_action_requested', props);
375
+ }
376
+ catch (error) {
377
+ logger('Error tracking mmconnect_wallet_action_requested event', error);
378
+ }
379
+ });
380
+ }, _MetamaskConnectEVM_trackWalletActionSucceeded = function _MetamaskConnectEVM_trackWalletActionSucceeded(method, scope, params) {
381
+ return __awaiter(this, void 0, void 0, function* () {
382
+ const coreOptions = __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_getCoreOptions).call(this);
383
+ try {
384
+ const invokeOptions = __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_createInvokeOptions).call(this, method, scope, params);
385
+ const props = yield getWalletActionAnalyticsProperties(coreOptions, __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").storage, invokeOptions);
386
+ analytics.track('mmconnect_wallet_action_succeeded', props);
387
+ }
388
+ catch (error) {
389
+ logger('Error tracking mmconnect_wallet_action_succeeded event', error);
390
+ }
391
+ });
392
+ }, _MetamaskConnectEVM_trackWalletActionFailed = function _MetamaskConnectEVM_trackWalletActionFailed(method, scope, params, error) {
393
+ return __awaiter(this, void 0, void 0, function* () {
394
+ const coreOptions = __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_getCoreOptions).call(this);
395
+ try {
396
+ const invokeOptions = __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_createInvokeOptions).call(this, method, scope, params);
397
+ const props = yield getWalletActionAnalyticsProperties(coreOptions, __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").storage, invokeOptions);
398
+ const isRejection = isRejectionError(error);
399
+ if (isRejection) {
400
+ analytics.track('mmconnect_wallet_action_rejected', props);
401
+ }
402
+ else {
403
+ analytics.track('mmconnect_wallet_action_failed', props);
404
+ }
405
+ }
406
+ catch (_a) {
407
+ logger('Error tracking wallet action rejected or failed event', error);
408
+ }
409
+ });
410
+ }, _MetamaskConnectEVM_getSelectedChainId = function _MetamaskConnectEVM_getSelectedChainId(permittedChainIds) {
411
+ return __awaiter(this, void 0, void 0, function* () {
412
+ try {
413
+ const cachedChainId = yield __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").storage.adapter.get(CHAIN_STORE_KEY);
414
+ if (cachedChainId) {
415
+ const chainId = JSON.parse(cachedChainId);
416
+ // Validate that the cached chainId is in the permitted chains list
417
+ if (permittedChainIds.includes(chainId)) {
418
+ return chainId;
419
+ }
420
+ }
421
+ }
422
+ catch (error) {
423
+ logger('Error retrieving cached chainId', error);
424
+ }
425
+ // Fallback to the first permitted chain if cache retrieval failed or returned an invalid chain
426
+ return permittedChainIds[0];
427
+ });
428
+ }, _MetamaskConnectEVM_requestInterceptor = function _MetamaskConnectEVM_requestInterceptor(request) {
429
+ return __awaiter(this, void 0, void 0, function* () {
430
+ logger(`Intercepting request for method: ${request.method}`);
431
+ if (IGNORED_METHODS.includes(request.method)) {
432
+ // TODO: replace with correct method unsupported provider error
433
+ return Promise.reject(new Error(`Method: ${request.method} is not supported by Metamask Connect/EVM`));
434
+ }
435
+ if (request.method === 'wallet_revokePermissions') {
436
+ return this.disconnect();
437
+ }
438
+ if (isConnectRequest(request)) {
439
+ // When calling wallet_requestPermissions, we need to force a new session request to prompt
440
+ // the user for accounts, because internally the Multichain SDK will check if
441
+ // the user is already connected and skip the request if so, unless we
442
+ // explicitly request a specific account. This is needed to workaround
443
+ // wallet_requestPermissions not requesting specific accounts.
444
+ const shouldForceConnectionRequest = request.method === 'wallet_requestPermissions';
445
+ const { method, params } = request;
446
+ const initiallySelectedChainId = DEFAULT_CHAIN_ID;
447
+ const scope = `eip155:${initiallySelectedChainId}`;
448
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_trackWalletActionRequested).call(this, method, scope, params);
449
+ try {
450
+ const result = yield this.connect({
451
+ chainIds: [initiallySelectedChainId],
452
+ forceRequest: shouldForceConnectionRequest,
453
+ });
454
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_trackWalletActionSucceeded).call(this, method, scope, params);
455
+ return result;
456
+ }
457
+ catch (error) {
458
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_trackWalletActionFailed).call(this, method, scope, params, error);
459
+ throw error;
460
+ }
461
+ }
462
+ if (isSwitchChainRequest(request)) {
463
+ return this.switchChain({
464
+ chainId: parseInt(request.params[0].chainId, 16),
465
+ });
466
+ }
467
+ if (isAddChainRequest(request)) {
468
+ return __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_addEthereumChain).call(this, request.params[0]);
469
+ }
470
+ if (isAccountsRequest(request)) {
471
+ const { method } = request;
472
+ const chainId = __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").selectedChainId
473
+ ? hexToNumber(__classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").selectedChainId)
474
+ : 1;
475
+ const scope = `eip155:${chainId}`;
476
+ const params = [];
477
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_trackWalletActionRequested).call(this, method, scope, params);
478
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_trackWalletActionSucceeded).call(this, method, scope, params);
479
+ return __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").accounts;
480
+ }
481
+ logger('Request not intercepted, forwarding to default handler', request);
482
+ return Promise.resolve();
483
+ });
484
+ }, _MetamaskConnectEVM_clearConnectionState = function _MetamaskConnectEVM_clearConnectionState() {
485
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").accounts = [];
486
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").selectedChainId = undefined;
487
+ }, _MetamaskConnectEVM_addEthereumChain = function _MetamaskConnectEVM_addEthereumChain(chainConfiguration) {
488
+ return __awaiter(this, void 0, void 0, function* () {
489
+ var _a;
490
+ logger('addEthereumChain called', { chainConfiguration });
491
+ const method = 'wallet_addEthereumChain';
492
+ if (!chainConfiguration) {
493
+ throw new Error('No chain configuration found.');
494
+ }
495
+ // Get chain ID from config or use current chain
496
+ const chainId = chainConfiguration.chainId
497
+ ? parseInt(chainConfiguration.chainId, 16)
498
+ : hexToNumber((_a = __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").selectedChainId) !== null && _a !== void 0 ? _a : '0x1');
499
+ const scope = `eip155:${chainId}`;
500
+ const params = [chainConfiguration];
501
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_trackWalletActionRequested).call(this, method, scope, params);
502
+ try {
503
+ const result = yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_request).call(this, {
504
+ method: 'wallet_addEthereumChain',
505
+ params,
506
+ });
507
+ if (result.result === null) {
508
+ // if result is successful we eagerly call onChainChanged to update the provider's selected chain ID.
509
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_cacheChainId).call(this, chainId);
510
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onChainChanged).call(this, chainId);
511
+ }
512
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_trackWalletActionSucceeded).call(this, method, scope, params);
513
+ }
514
+ catch (error) {
515
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_trackWalletActionFailed).call(this, method, scope, params, error);
516
+ throw error;
517
+ }
518
+ });
519
+ }, _MetamaskConnectEVM_request = function _MetamaskConnectEVM_request(request) {
520
+ return __awaiter(this, void 0, void 0, function* () {
521
+ logger('direct request to metamask-provider called', request);
522
+ const result = __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").transport.sendEip1193Message(request);
523
+ if (request.method === 'wallet_addEthereumChain' ||
524
+ request.method === 'wallet_switchEthereumChain') {
525
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").openDeeplinkIfNeeded();
526
+ }
527
+ return result;
528
+ });
529
+ }, _MetamaskConnectEVM_cacheChainId = function _MetamaskConnectEVM_cacheChainId(chainId) {
530
+ return __awaiter(this, void 0, void 0, function* () {
531
+ try {
532
+ const hexChainId = isHex(chainId) ? chainId : numberToHex(chainId);
533
+ yield __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").storage.adapter.set(CHAIN_STORE_KEY, JSON.stringify(hexChainId));
534
+ }
535
+ catch (error) {
536
+ logger('Error caching chainId', error);
537
+ }
538
+ });
539
+ }, _MetamaskConnectEVM_onChainChanged = function _MetamaskConnectEVM_onChainChanged(chainId) {
540
+ var _a, _b;
541
+ const hexChainId = isHex(chainId) ? chainId : numberToHex(chainId);
542
+ if (hexChainId === __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").selectedChainId) {
543
+ return;
544
+ }
545
+ logger('handler: chainChanged', { chainId });
546
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").selectedChainId = chainId;
547
+ (_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);
548
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").emit('chainChanged', hexChainId);
549
+ }, _MetamaskConnectEVM_onAccountsChanged = function _MetamaskConnectEVM_onAccountsChanged(accounts) {
550
+ var _a, _b;
551
+ logger('handler: accountsChanged', accounts);
552
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").accounts = accounts;
553
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").emit('accountsChanged', accounts);
554
+ (_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);
555
+ }, _MetamaskConnectEVM_onConnect = function _MetamaskConnectEVM_onConnect({ chainId, accounts, }) {
556
+ var _a, _b;
557
+ logger('handler: connect', { chainId, accounts });
558
+ const data = {
559
+ chainId: isHex(chainId) ? chainId : numberToHex(chainId),
560
+ accounts,
561
+ };
562
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").emit('connect', data);
563
+ (_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);
564
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onChainChanged).call(this, chainId);
565
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onAccountsChanged).call(this, accounts);
566
+ }, _MetamaskConnectEVM_onDisconnect = function _MetamaskConnectEVM_onDisconnect() {
567
+ var _a, _b;
568
+ logger('handler: disconnect');
569
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").emit('disconnect');
570
+ (_b = (_a = __classPrivateFieldGet(this, _MetamaskConnectEVM_eventHandlers, "f")) === null || _a === void 0 ? void 0 : _a.disconnect) === null || _b === void 0 ? void 0 : _b.call(_a);
571
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onAccountsChanged).call(this, []);
572
+ }, _MetamaskConnectEVM_onDisplayUri = function _MetamaskConnectEVM_onDisplayUri(uri) {
573
+ var _a, _b;
574
+ logger('handler: display_uri', uri);
575
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_provider, "f").emit('display_uri', uri);
576
+ (_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);
577
+ }, _MetamaskConnectEVM_attemptSessionRecovery = function _MetamaskConnectEVM_attemptSessionRecovery() {
578
+ return __awaiter(this, void 0, void 0, function* () {
579
+ // Skip session recovery if transport is not initialized yet.
580
+ // Transport is only initialized when there's a stored session or after connect() is called.
581
+ // Only attempt recovery if we're in a state where transport should be available.
582
+ if (__classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").status !== 'connected' && __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").status !== 'connecting') {
583
+ return;
584
+ }
585
+ try {
586
+ const response = yield __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").transport.request({
587
+ method: 'wallet_getSession',
588
+ });
589
+ const { sessionScopes } = response.result;
590
+ __classPrivateFieldSet(this, _MetamaskConnectEVM_sessionScopes, sessionScopes, "f");
591
+ const permittedChainIds = getPermittedEthChainIds(sessionScopes);
592
+ // Instead of using the accounts we get back from calling `wallet_getSession`
593
+ // we get permitted accounts from `eth_accounts` to make sure we have them ordered by last selected account
594
+ // and correctly set the currently selected account for the dapp
595
+ const permittedAccounts = yield __classPrivateFieldGet(this, _MetamaskConnectEVM_core, "f").transport.sendEip1193Message({ method: 'eth_accounts', params: [] });
596
+ const chainId = yield __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_getSelectedChainId).call(this, permittedChainIds);
597
+ if (permittedChainIds.length && permittedAccounts.result) {
598
+ __classPrivateFieldGet(this, _MetamaskConnectEVM_instances, "m", _MetamaskConnectEVM_onConnect).call(this, {
599
+ chainId,
600
+ accounts: permittedAccounts.result,
601
+ });
602
+ }
603
+ }
604
+ catch (error) {
605
+ console.error('Error attempting session recovery', error);
606
+ }
607
+ });
608
+ };
609
+ /**
610
+ * Creates a new Metamask Connect/EVM instance
611
+ *
612
+ * @param options - The options for the Metamask Connect/EVM layer
613
+ * @param options.dapp - Dapp identification and branding settings
614
+ * @param options.api - API configuration including read-only RPC map
615
+ * @param options.api.supportedNetworks - A map of CAIP chain IDs to RPC URLs for read-only requests
616
+ * @param options.eventEmitter - The event emitter to use for the Metamask Connect/EVM layer
617
+ * @param options.eventHandlers - The event handlers to use for the Metamask Connect/EVM layer
618
+ * @returns The Metamask Connect/EVM layer instance
619
+ */
620
+ export function createEVMClient(options) {
621
+ return __awaiter(this, void 0, void 0, function* () {
622
+ var _a;
623
+ enableDebug(options.debug);
624
+ logger('Creating Metamask Connect/EVM with options:', options);
625
+ // Validate that supportedNetworks is provided and not empty
626
+ if (!((_a = options.api) === null || _a === void 0 ? void 0 : _a.supportedNetworks) ||
627
+ Object.keys(options.api.supportedNetworks).length === 0) {
628
+ throw new Error('supportedNetworks is required and must contain at least one chain configuration');
629
+ }
630
+ validSupportedChainsUrls(options.api.supportedNetworks, 'supportedNetworks');
631
+ try {
632
+ const core = yield createMultichainClient(Object.assign(Object.assign({}, options), { api: {
633
+ supportedNetworks: options.api.supportedNetworks,
634
+ } }));
635
+ return new MetamaskConnectEVM({
636
+ core,
637
+ eventHandlers: options.eventHandlers,
638
+ supportedNetworks: options.api.supportedNetworks,
639
+ });
640
+ }
641
+ catch (error) {
642
+ console.error('Error creating Metamask Connect/EVM', error);
643
+ throw error;
644
+ }
645
+ });
646
+ }
647
+ //# sourceMappingURL=connect.js.map