@metamask/connect-multichain 0.1.0 → 0.2.1

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 (83) hide show
  1. package/CHANGELOG.md +35 -1
  2. package/dist/browser/es/connect-multichain.d.mts +67 -13
  3. package/dist/browser/es/connect-multichain.mjs +895 -384
  4. package/dist/browser/es/connect-multichain.mjs.map +1 -1
  5. package/dist/browser/es/metafile-esm.json +1 -1
  6. package/dist/browser/iife/connect-multichain.d.ts +67 -13
  7. package/dist/browser/iife/connect-multichain.js +21636 -14459
  8. package/dist/browser/iife/connect-multichain.js.map +1 -1
  9. package/dist/browser/iife/metafile-iife.json +1 -1
  10. package/dist/browser/umd/connect-multichain.d.ts +67 -13
  11. package/dist/browser/umd/connect-multichain.js +893 -382
  12. package/dist/browser/umd/connect-multichain.js.map +1 -1
  13. package/dist/browser/umd/metafile-cjs.json +1 -1
  14. package/dist/node/cjs/connect-multichain.d.ts +67 -13
  15. package/dist/node/cjs/connect-multichain.js +898 -385
  16. package/dist/node/cjs/connect-multichain.js.map +1 -1
  17. package/dist/node/cjs/metafile-cjs.json +1 -1
  18. package/dist/node/es/connect-multichain.d.mts +67 -13
  19. package/dist/node/es/connect-multichain.mjs +898 -387
  20. package/dist/node/es/connect-multichain.mjs.map +1 -1
  21. package/dist/node/es/metafile-esm.json +1 -1
  22. package/dist/react-native/es/connect-multichain.d.mts +67 -13
  23. package/dist/react-native/es/connect-multichain.mjs +897 -386
  24. package/dist/react-native/es/connect-multichain.mjs.map +1 -1
  25. package/dist/react-native/es/metafile-esm.json +1 -1
  26. package/dist/src/domain/events/index.d.ts +26 -0
  27. package/dist/src/domain/events/index.d.ts.map +1 -1
  28. package/dist/src/domain/events/index.js +35 -0
  29. package/dist/src/domain/events/index.js.map +1 -1
  30. package/dist/src/domain/multichain/index.d.ts +7 -5
  31. package/dist/src/domain/multichain/index.d.ts.map +1 -1
  32. package/dist/src/domain/multichain/index.js +2 -2
  33. package/dist/src/domain/multichain/index.js.map +1 -1
  34. package/dist/src/domain/multichain/types.d.ts +9 -7
  35. package/dist/src/domain/multichain/types.d.ts.map +1 -1
  36. package/dist/src/domain/platform/index.js +3 -3
  37. package/dist/src/domain/platform/index.js.map +1 -1
  38. package/dist/src/domain/ui/factory.d.ts +1 -1
  39. package/dist/src/domain/ui/factory.d.ts.map +1 -1
  40. package/dist/src/domain/utils/index.d.ts +1 -0
  41. package/dist/src/domain/utils/index.d.ts.map +1 -1
  42. package/dist/src/domain/utils/index.js +1 -0
  43. package/dist/src/domain/utils/index.js.map +1 -1
  44. package/dist/src/multichain/index.d.ts +5 -2
  45. package/dist/src/multichain/index.d.ts.map +1 -1
  46. package/dist/src/multichain/index.js +124 -38
  47. package/dist/src/multichain/index.js.map +1 -1
  48. package/dist/src/multichain/rpc/handlers/rpcClient.d.ts +2 -1
  49. package/dist/src/multichain/rpc/handlers/rpcClient.d.ts.map +1 -1
  50. package/dist/src/multichain/rpc/handlers/rpcClient.js +16 -17
  51. package/dist/src/multichain/rpc/handlers/rpcClient.js.map +1 -1
  52. package/dist/src/multichain/rpc/requestRouter.d.ts +1 -0
  53. package/dist/src/multichain/rpc/requestRouter.d.ts.map +1 -1
  54. package/dist/src/multichain/rpc/requestRouter.js +71 -15
  55. package/dist/src/multichain/rpc/requestRouter.js.map +1 -1
  56. package/dist/src/multichain/transports/constants.d.ts +3 -0
  57. package/dist/src/multichain/transports/constants.d.ts.map +1 -0
  58. package/dist/src/multichain/transports/constants.js +3 -0
  59. package/dist/src/multichain/transports/constants.js.map +1 -0
  60. package/dist/src/multichain/transports/default/index.d.ts +4 -0
  61. package/dist/src/multichain/transports/default/index.d.ts.map +1 -1
  62. package/dist/src/multichain/transports/default/index.js +137 -13
  63. package/dist/src/multichain/transports/default/index.js.map +1 -1
  64. package/dist/src/multichain/transports/mwp/index.d.ts +10 -1
  65. package/dist/src/multichain/transports/mwp/index.d.ts.map +1 -1
  66. package/dist/src/multichain/transports/mwp/index.js +138 -10
  67. package/dist/src/multichain/transports/mwp/index.js.map +1 -1
  68. package/dist/src/multichain/utils/analytics.d.ts +39 -0
  69. package/dist/src/multichain/utils/analytics.d.ts.map +1 -0
  70. package/dist/src/multichain/utils/analytics.js +83 -0
  71. package/dist/src/multichain/utils/analytics.js.map +1 -0
  72. package/dist/src/multichain/utils/index.d.ts +0 -1
  73. package/dist/src/multichain/utils/index.d.ts.map +1 -1
  74. package/dist/src/multichain/utils/index.js +1 -16
  75. package/dist/src/multichain/utils/index.js.map +1 -1
  76. package/dist/src/ui/index.d.ts +1 -1
  77. package/dist/src/ui/index.d.ts.map +1 -1
  78. package/dist/src/ui/index.js +35 -19
  79. package/dist/src/ui/index.js.map +1 -1
  80. package/dist/src/ui/modals/web/install.js +1 -1
  81. package/dist/src/ui/modals/web/install.js.map +1 -1
  82. package/dist/types/connect-multichain.d.ts +67 -13
  83. package/package.json +12 -9
@@ -32,6 +32,7 @@ var __export = (target, all) => {
32
32
  var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
33
33
  var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
34
34
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
35
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
35
36
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
36
37
  var __async = (__this, __arguments, generator) => {
37
38
  return new Promise((resolve, reject) => {
@@ -176,6 +177,41 @@ var init_events = __esm({
176
177
  off(eventName, handler) {
177
178
  __privateGet(this, _emitter).off(eventName, handler);
178
179
  }
180
+ /**
181
+ * Removes a specific event handler for the specified event.
182
+ * Added for compatibility as some libraries use this method name.
183
+ *
184
+ * @template TEventName - The name of the event to remove the handler from (must be a key of TEvents)
185
+ * @param eventName - The name of the event to remove the handler from
186
+ * @param handler - The specific handler function to remove
187
+ */
188
+ removeListener(eventName, handler) {
189
+ __privateGet(this, _emitter).off(eventName, handler);
190
+ }
191
+ /**
192
+ * Registers an event handler for the specified event that will only be called once.
193
+ *
194
+ * @template TEventName - The name of the event to listen for (must be a key of TEvents)
195
+ * @param eventName - The name of the event to listen for
196
+ * @param handler - The function to call when the event is emitted (only once)
197
+ * @returns A function to remove the listener
198
+ */
199
+ once(eventName, handler) {
200
+ __privateGet(this, _emitter).once(eventName, handler);
201
+ return () => {
202
+ this.off(eventName, handler);
203
+ };
204
+ }
205
+ /**
206
+ * Returns the number of listeners registered for the specified event.
207
+ *
208
+ * @template TEventName - The name of the event to count listeners for (must be a key of TEvents)
209
+ * @param eventName - The name of the event to count listeners for
210
+ * @returns The number of listeners registered for the event
211
+ */
212
+ listenerCount(eventName) {
213
+ return __privateGet(this, _emitter).listenerCount(eventName);
214
+ }
179
215
  };
180
216
  _emitter = new WeakMap();
181
217
  }
@@ -340,7 +376,7 @@ function getTransportType(type) {
340
376
  case "browser":
341
377
  return "browser" /* Browser */;
342
378
  case "mwp":
343
- return "mwp" /* MPW */;
379
+ return "mwp" /* MWP */;
344
380
  default:
345
381
  return "unknown" /* UNKNOWN */;
346
382
  }
@@ -354,7 +390,7 @@ var init_multichain = __esm({
354
390
  init_infura();
355
391
  TransportType = /* @__PURE__ */ ((TransportType2) => {
356
392
  TransportType2["Browser"] = "browser";
357
- TransportType2["MPW"] = "mwp";
393
+ TransportType2["MWP"] = "mwp";
358
394
  TransportType2["UNKNOWN"] = "unknown";
359
395
  return TransportType2;
360
396
  })(TransportType || {});
@@ -368,7 +404,7 @@ var init_multichain = __esm({
368
404
  });
369
405
 
370
406
  // src/domain/platform/index.ts
371
- import { parse } from "bowser";
407
+ import Bowser from "bowser";
372
408
  function isNotBrowser() {
373
409
  var _a;
374
410
  if (typeof window === "undefined") {
@@ -397,7 +433,7 @@ function isMetaMaskMobileWebView() {
397
433
  }
398
434
  function isMobile() {
399
435
  var _a, _b;
400
- const browser = parse(window.navigator.userAgent);
436
+ const browser = Bowser.parse(window.navigator.userAgent);
401
437
  return ((_a = browser == null ? void 0 : browser.platform) == null ? void 0 : _a.type) === "mobile" || ((_b = browser == null ? void 0 : browser.platform) == null ? void 0 : _b.type) === "tablet";
402
438
  }
403
439
  function getPlatformType() {
@@ -462,8 +498,8 @@ var init_platform = __esm({
462
498
  window.removeEventListener("eip6963:announceProvider", handler);
463
499
  const hasMetaMask = providers.some(
464
500
  (provider) => {
465
- var _a;
466
- return ((_a = provider == null ? void 0 : provider.info) == null ? void 0 : _a.rdns) === "io.metamask";
501
+ var _a, _b;
502
+ return (_b = (_a = provider == null ? void 0 : provider.info) == null ? void 0 : _a.rdns) == null ? void 0 : _b.startsWith("io.metamask");
467
503
  }
468
504
  );
469
505
  resolve(hasMetaMask);
@@ -547,13 +583,265 @@ var init_ui = __esm({
547
583
  }
548
584
  });
549
585
 
586
+ // src/multichain/utils/index.ts
587
+ import { deflate } from "pako";
588
+ import {
589
+ parseCaipAccountId,
590
+ parseCaipChainId
591
+ } from "@metamask/utils";
592
+ function base64Encode(str) {
593
+ if (typeof btoa !== "undefined") {
594
+ return btoa(str);
595
+ } else if (typeof Buffer !== "undefined") {
596
+ return Buffer.from(str).toString("base64");
597
+ }
598
+ throw new Error("No base64 encoding method available");
599
+ }
600
+ function compressString(str) {
601
+ const compressed = deflate(str);
602
+ const binaryString = String.fromCharCode.apply(null, Array.from(compressed));
603
+ return base64Encode(binaryString);
604
+ }
605
+ function getDappId(dapp) {
606
+ var _a, _b;
607
+ if (typeof window === "undefined" || typeof window.location === "undefined") {
608
+ return (_b = (_a = dapp == null ? void 0 : dapp.name) != null ? _a : dapp == null ? void 0 : dapp.url) != null ? _b : "N/A";
609
+ }
610
+ return window.location.hostname;
611
+ }
612
+ function openDeeplink(options, deeplink, universalLink) {
613
+ const { mobile } = options;
614
+ const useDeeplink = mobile && mobile.useDeeplink !== void 0 ? mobile.useDeeplink : true;
615
+ if (useDeeplink) {
616
+ if (typeof window !== "undefined") {
617
+ window.location.href = deeplink;
618
+ }
619
+ } else if (typeof document !== "undefined") {
620
+ const link = document.createElement("a");
621
+ link.href = universalLink;
622
+ link.target = "_self";
623
+ link.rel = "noreferrer noopener";
624
+ link.click();
625
+ }
626
+ }
627
+ function getOptionalScopes(scopes) {
628
+ return scopes.reduce(
629
+ (prev, scope) => __spreadProps(__spreadValues({}, prev), {
630
+ [scope]: {
631
+ methods: [],
632
+ notifications: [],
633
+ accounts: []
634
+ }
635
+ }),
636
+ {}
637
+ );
638
+ }
639
+ function setupDappMetadata(options) {
640
+ var _a;
641
+ const platform = getPlatformType();
642
+ const isBrowser = platform === "web-desktop" /* DesktopWeb */ || platform === "web-mobile" /* MobileWeb */ || platform === "in-app-browser" /* MetaMaskMobileWebview */;
643
+ if (!((_a = options.dapp) == null ? void 0 : _a.url)) {
644
+ if (isBrowser) {
645
+ options.dapp = __spreadProps(__spreadValues({}, options.dapp), {
646
+ url: `${window.location.protocol}//${window.location.host}`
647
+ });
648
+ } else {
649
+ throw new Error("You must provide dapp url");
650
+ }
651
+ }
652
+ const BASE_64_ICON_MAX_LENGTH = 163400;
653
+ const urlPattern = /^(http|https):\/\/[^\s]*$/;
654
+ if (options.dapp) {
655
+ if ("iconUrl" in options.dapp) {
656
+ if (options.dapp.iconUrl && !urlPattern.test(options.dapp.iconUrl)) {
657
+ console.warn(
658
+ "Invalid dappMetadata.iconUrl: URL must start with http:// or https://"
659
+ );
660
+ options.dapp.iconUrl = void 0;
661
+ }
662
+ }
663
+ if ("base64Icon" in options.dapp) {
664
+ if (options.dapp.base64Icon && options.dapp.base64Icon.length > BASE_64_ICON_MAX_LENGTH) {
665
+ console.warn(
666
+ "Invalid dappMetadata.base64Icon: Base64-encoded icon string length must be less than 163400 characters"
667
+ );
668
+ options.dapp.base64Icon = void 0;
669
+ }
670
+ }
671
+ if (options.dapp.url && !urlPattern.test(options.dapp.url)) {
672
+ console.warn(
673
+ "Invalid dappMetadata.url: URL must start with http:// or https://"
674
+ );
675
+ }
676
+ const favicon = extractFavicon();
677
+ if (favicon && !("iconUrl" in options.dapp) && !("base64Icon" in options.dapp)) {
678
+ const faviconUrl = `${window.location.protocol}//${window.location.host}${favicon}`;
679
+ options.dapp.iconUrl = faviconUrl;
680
+ }
681
+ }
682
+ return options;
683
+ }
684
+ function isSameScopesAndAccounts(currentScopes, proposedScopes, walletSession, proposedCaipAccountIds) {
685
+ const isSameScopes = currentScopes.every((scope) => proposedScopes.includes(scope)) && proposedScopes.every((scope) => currentScopes.includes(scope));
686
+ if (!isSameScopes) {
687
+ return false;
688
+ }
689
+ const existingAccountIds = Object.values(
690
+ walletSession.sessionScopes
691
+ ).filter(({ accounts }) => Boolean(accounts)).flatMap(({ accounts }) => accounts != null ? accounts : []);
692
+ const allProposedAccountsIncluded = proposedCaipAccountIds.every(
693
+ (proposedAccountId) => existingAccountIds.includes(proposedAccountId)
694
+ );
695
+ return allProposedAccountsIncluded;
696
+ }
697
+ function getValidAccounts(caipAccountIds) {
698
+ return caipAccountIds.reduce(
699
+ (caipAccounts, caipAccountId) => {
700
+ try {
701
+ return [...caipAccounts, parseCaipAccountId(caipAccountId)];
702
+ } catch (err) {
703
+ const stringifiedAccountId = JSON.stringify(caipAccountId);
704
+ console.error(`Invalid CAIP account ID: ${stringifiedAccountId}`, err);
705
+ return caipAccounts;
706
+ }
707
+ },
708
+ []
709
+ );
710
+ }
711
+ function addValidAccounts(optionalScopes, validAccounts) {
712
+ var _a;
713
+ if (!optionalScopes || !(validAccounts == null ? void 0 : validAccounts.length)) {
714
+ return optionalScopes;
715
+ }
716
+ const result = Object.fromEntries(
717
+ Object.entries(optionalScopes).map(([scope, scopeData]) => {
718
+ var _a2, _b, _c;
719
+ return [
720
+ scope,
721
+ {
722
+ methods: [...(_a2 = scopeData == null ? void 0 : scopeData.methods) != null ? _a2 : []],
723
+ notifications: [...(_b = scopeData == null ? void 0 : scopeData.notifications) != null ? _b : []],
724
+ accounts: [...(_c = scopeData == null ? void 0 : scopeData.accounts) != null ? _c : []]
725
+ }
726
+ ];
727
+ })
728
+ );
729
+ const accountsByChain = /* @__PURE__ */ new Map();
730
+ for (const account of validAccounts) {
731
+ const chainKey = `${account.chain.namespace}:${account.chain.reference}`;
732
+ const accountId = `${account.chainId}:${account.address}`;
733
+ if (!accountsByChain.has(chainKey)) {
734
+ accountsByChain.set(chainKey, []);
735
+ }
736
+ (_a = accountsByChain.get(chainKey)) == null ? void 0 : _a.push(accountId);
737
+ }
738
+ for (const [scopeKey, scopeData] of Object.entries(result)) {
739
+ if (!(scopeData == null ? void 0 : scopeData.accounts)) {
740
+ continue;
741
+ }
742
+ try {
743
+ const scope = scopeKey;
744
+ const scopeDetails = parseCaipChainId(scope);
745
+ const chainKey = `${scopeDetails.namespace}:${scopeDetails.reference}`;
746
+ const matchingAccounts = accountsByChain.get(chainKey);
747
+ if (matchingAccounts) {
748
+ const existingAccounts = new Set(scopeData.accounts);
749
+ const newAccounts = matchingAccounts.filter(
750
+ (account) => !existingAccounts.has(account)
751
+ );
752
+ scopeData.accounts.push(...newAccounts);
753
+ }
754
+ } catch (error) {
755
+ console.error(`Invalid scope format: ${scopeKey}`, error);
756
+ }
757
+ }
758
+ return result;
759
+ }
760
+ var extractFavicon;
761
+ var init_utils = __esm({
762
+ "src/multichain/utils/index.ts"() {
763
+ "use strict";
764
+ init_domain();
765
+ extractFavicon = () => {
766
+ var _a;
767
+ if (typeof document === "undefined") {
768
+ return void 0;
769
+ }
770
+ let favicon;
771
+ const nodeList = document.getElementsByTagName("link");
772
+ for (let i = 0; i < nodeList.length; i++) {
773
+ if (nodeList[i].getAttribute("rel") === "icon" || nodeList[i].getAttribute("rel") === "shortcut icon") {
774
+ favicon = (_a = nodeList[i].getAttribute("href")) != null ? _a : void 0;
775
+ }
776
+ }
777
+ return favicon;
778
+ };
779
+ }
780
+ });
781
+
782
+ // src/multichain/utils/analytics.ts
783
+ function isRejectionError(error) {
784
+ var _a, _b;
785
+ if (typeof error !== "object" || error === null) {
786
+ return false;
787
+ }
788
+ const errorObj = error;
789
+ const errorCode = errorObj.code;
790
+ const errorMessage = (_b = (_a = errorObj.message) == null ? void 0 : _a.toLowerCase()) != null ? _b : "";
791
+ return errorCode === 4001 || // User rejected request (common EIP-1193 code)
792
+ errorCode === 4100 || // Unauthorized (common rejection code)
793
+ errorMessage.includes("reject") || errorMessage.includes("denied") || errorMessage.includes("cancel") || errorMessage.includes("user");
794
+ }
795
+ function getBaseAnalyticsProperties(options, storage) {
796
+ return __async(this, null, function* () {
797
+ var _a, _b;
798
+ const version = getVersion();
799
+ const dappId = getDappId(options.dapp);
800
+ const platform = getPlatformType();
801
+ const anonId = yield storage.getAnonId();
802
+ const integrationType = (_b = (_a = options.analytics) == null ? void 0 : _a.integrationType) != null ? _b : "unknown" /* UNKNOWN */;
803
+ return {
804
+ mmconnect_version: version,
805
+ dapp_id: dappId,
806
+ platform,
807
+ integration_type: integrationType,
808
+ anon_id: anonId
809
+ };
810
+ });
811
+ }
812
+ function getWalletActionAnalyticsProperties(options, storage, invokeOptions) {
813
+ return __async(this, null, function* () {
814
+ var _a, _b;
815
+ const version = getVersion();
816
+ const dappId = getDappId(options.dapp);
817
+ const anonId = yield storage.getAnonId();
818
+ const integrationType = (_b = (_a = options.analytics) == null ? void 0 : _a.integrationType) != null ? _b : "unknown";
819
+ return {
820
+ mmconnect_version: version,
821
+ dapp_id: dappId,
822
+ method: invokeOptions.request.method,
823
+ integration_type: integrationType,
824
+ caip_chain_id: invokeOptions.scope,
825
+ anon_id: anonId
826
+ };
827
+ });
828
+ }
829
+ var init_analytics = __esm({
830
+ "src/multichain/utils/analytics.ts"() {
831
+ "use strict";
832
+ init_utils();
833
+ init_domain();
834
+ }
835
+ });
836
+
550
837
  // src/domain/utils/index.ts
551
838
  function getVersion() {
552
839
  return "0.0.0";
553
840
  }
554
- var init_utils = __esm({
841
+ var init_utils2 = __esm({
555
842
  "src/domain/utils/index.ts"() {
556
843
  "use strict";
844
+ init_analytics();
557
845
  }
558
846
  });
559
847
 
@@ -568,7 +856,7 @@ var init_domain = __esm({
568
856
  init_platform();
569
857
  init_store();
570
858
  init_ui();
571
- init_utils();
859
+ init_utils2();
572
860
  }
573
861
  });
574
862
 
@@ -591,7 +879,7 @@ function shouldLogCountdown(remainingSeconds) {
591
879
  return remainingSeconds % 60 === 0;
592
880
  }
593
881
  }
594
- var init_utils2 = __esm({
882
+ var init_utils3 = __esm({
595
883
  "src/ui/modals/base/utils.ts"() {
596
884
  "use strict";
597
885
  }
@@ -603,7 +891,7 @@ var init_AbstractInstallModal = __esm({
603
891
  "src/ui/modals/base/AbstractInstallModal.ts"() {
604
892
  "use strict";
605
893
  init_domain();
606
- init_utils2();
894
+ init_utils3();
607
895
  logger3 = createLogger("metamask-sdk:ui");
608
896
  AbstractInstallModal = class extends Modal {
609
897
  constructor() {
@@ -753,276 +1041,70 @@ __export(rn_exports, {
753
1041
  var init_rn = __esm({
754
1042
  "src/ui/modals/rn/index.ts"() {
755
1043
  "use strict";
756
- init_install();
757
- init_otp();
758
- }
759
- });
760
-
761
- // src/store/adapters/rn.ts
762
- var rn_exports2 = {};
763
- __export(rn_exports2, {
764
- StoreAdapterRN: () => StoreAdapterRN
765
- });
766
- import AsyncStorage from "@react-native-async-storage/async-storage";
767
- var StoreAdapterRN;
768
- var init_rn2 = __esm({
769
- "src/store/adapters/rn.ts"() {
770
- "use strict";
771
- init_domain();
772
- StoreAdapterRN = class extends StoreAdapter {
773
- constructor() {
774
- super(...arguments);
775
- this.platform = "rn";
776
- }
777
- get(key) {
778
- return __async(this, null, function* () {
779
- return AsyncStorage.getItem(key);
780
- });
781
- }
782
- set(key, value) {
783
- return __async(this, null, function* () {
784
- return AsyncStorage.setItem(key, value);
785
- });
786
- }
787
- delete(key) {
788
- return __async(this, null, function* () {
789
- return AsyncStorage.removeItem(key);
790
- });
791
- }
792
- };
793
- }
794
- });
795
-
796
- // src/multichain/index.ts
797
- import { analytics } from "@metamask/analytics";
798
- import {
799
- ErrorCode,
800
- ProtocolError,
801
- SessionStore as SessionStore2,
802
- WebSocketTransport
803
- } from "@metamask/mobile-wallet-protocol-core";
804
- import { DappClient } from "@metamask/mobile-wallet-protocol-dapp-client";
805
- import {
806
- getMultichainClient
807
- } from "@metamask/multichain-api-client";
808
-
809
- // src/config/index.ts
810
- var MWP_RELAY_URL = "wss://mm-sdk-relay.api.cx.metamask.io/connection/websocket";
811
- var METAMASK_CONNECT_BASE_URL = "https://metamask.app.link/connect";
812
- var METAMASK_DEEPLINK_BASE = "metamask://connect";
813
-
814
- // src/multichain/index.ts
815
- init_domain();
816
- init_logger();
817
- init_multichain();
818
- init_platform();
819
-
820
- // src/multichain/rpc/requestRouter.ts
821
- init_domain();
822
-
823
- // src/multichain/utils/index.ts
824
- init_domain();
825
- import { deflate } from "pako";
826
- import {
827
- parseCaipAccountId,
828
- parseCaipChainId
829
- } from "@metamask/utils";
830
- function base64Encode(str) {
831
- if (typeof btoa !== "undefined") {
832
- return btoa(str);
833
- } else if (typeof Buffer !== "undefined") {
834
- return Buffer.from(str).toString("base64");
835
- }
836
- throw new Error("No base64 encoding method available");
837
- }
838
- function compressString(str) {
839
- const compressed = deflate(str);
840
- const binaryString = String.fromCharCode.apply(null, Array.from(compressed));
841
- return base64Encode(binaryString);
842
- }
843
- function getDappId(dapp) {
844
- var _a, _b;
845
- if (typeof window === "undefined" || typeof window.location === "undefined") {
846
- return (_b = (_a = dapp == null ? void 0 : dapp.name) != null ? _a : dapp == null ? void 0 : dapp.url) != null ? _b : "N/A";
847
- }
848
- return window.location.hostname;
849
- }
850
- function openDeeplink(options, deeplink, universalLink) {
851
- const { mobile } = options;
852
- const useDeeplink = mobile && mobile.useDeeplink !== void 0 ? mobile.useDeeplink : true;
853
- if (useDeeplink) {
854
- if (typeof window !== "undefined") {
855
- window.location.href = deeplink;
856
- }
857
- } else if (typeof document !== "undefined") {
858
- const link = document.createElement("a");
859
- link.href = universalLink;
860
- link.target = "_self";
861
- link.rel = "noreferrer noopener";
862
- link.click();
863
- }
864
- }
865
- function getOptionalScopes(scopes) {
866
- return scopes.reduce(
867
- (prev, scope) => __spreadProps(__spreadValues({}, prev), {
868
- [scope]: {
869
- methods: [],
870
- notifications: [],
871
- accounts: []
872
- }
873
- }),
874
- {}
875
- );
876
- }
877
- var extractFavicon = () => {
878
- var _a;
879
- if (typeof document === "undefined") {
880
- return void 0;
881
- }
882
- let favicon;
883
- const nodeList = document.getElementsByTagName("link");
884
- for (let i = 0; i < nodeList.length; i++) {
885
- if (nodeList[i].getAttribute("rel") === "icon" || nodeList[i].getAttribute("rel") === "shortcut icon") {
886
- favicon = (_a = nodeList[i].getAttribute("href")) != null ? _a : void 0;
887
- }
888
- }
889
- return favicon;
890
- };
891
- function setupInfuraProvider(options) {
892
- var _a, _b;
893
- const infuraAPIKey = (_a = options.api) == null ? void 0 : _a.infuraAPIKey;
894
- if (!infuraAPIKey) {
895
- return options;
896
- }
897
- const urlsWithToken = getInfuraRpcUrls(infuraAPIKey);
898
- if ((_b = options.api) == null ? void 0 : _b.readonlyRPCMap) {
899
- options.api.readonlyRPCMap = __spreadValues(__spreadValues({}, options.api.readonlyRPCMap), urlsWithToken);
900
- } else if (options.api) {
901
- options.api.readonlyRPCMap = urlsWithToken;
902
- }
903
- return options;
904
- }
905
- function setupDappMetadata(options) {
906
- var _a;
907
- const platform = getPlatformType();
908
- const isBrowser = platform === "web-desktop" /* DesktopWeb */ || platform === "web-mobile" /* MobileWeb */ || platform === "in-app-browser" /* MetaMaskMobileWebview */;
909
- if (!((_a = options.dapp) == null ? void 0 : _a.url)) {
910
- if (isBrowser) {
911
- options.dapp = __spreadProps(__spreadValues({}, options.dapp), {
912
- url: `${window.location.protocol}//${window.location.host}`
913
- });
914
- } else {
915
- throw new Error("You must provide dapp url");
916
- }
917
- }
918
- const BASE_64_ICON_MAX_LENGTH = 163400;
919
- const urlPattern = /^(http|https):\/\/[^\s]*$/;
920
- if (options.dapp) {
921
- if ("iconUrl" in options.dapp) {
922
- if (options.dapp.iconUrl && !urlPattern.test(options.dapp.iconUrl)) {
923
- console.warn(
924
- "Invalid dappMetadata.iconUrl: URL must start with http:// or https://"
925
- );
926
- options.dapp.iconUrl = void 0;
927
- }
928
- }
929
- if ("base64Icon" in options.dapp) {
930
- if (options.dapp.base64Icon && options.dapp.base64Icon.length > BASE_64_ICON_MAX_LENGTH) {
931
- console.warn(
932
- "Invalid dappMetadata.base64Icon: Base64-encoded icon string length must be less than 163400 characters"
933
- );
934
- options.dapp.base64Icon = void 0;
935
- }
936
- }
937
- if (options.dapp.url && !urlPattern.test(options.dapp.url)) {
938
- console.warn(
939
- "Invalid dappMetadata.url: URL must start with http:// or https://"
940
- );
941
- }
942
- const favicon = extractFavicon();
943
- if (favicon && !("iconUrl" in options.dapp) && !("base64Icon" in options.dapp)) {
944
- const faviconUrl = `${window.location.protocol}//${window.location.host}${favicon}`;
945
- options.dapp.iconUrl = faviconUrl;
946
- }
947
- }
948
- return options;
949
- }
950
- function isSameScopesAndAccounts(currentScopes, proposedScopes, walletSession, proposedCaipAccountIds) {
951
- const isSameScopes = currentScopes.every((scope) => proposedScopes.includes(scope)) && proposedScopes.every((scope) => currentScopes.includes(scope));
952
- if (!isSameScopes) {
953
- return false;
954
- }
955
- const existingAccountIds = Object.values(
956
- walletSession.sessionScopes
957
- ).filter(({ accounts }) => Boolean(accounts)).flatMap(({ accounts }) => accounts != null ? accounts : []);
958
- const allProposedAccountsIncluded = proposedCaipAccountIds.every(
959
- (proposedAccountId) => existingAccountIds.includes(proposedAccountId)
960
- );
961
- return allProposedAccountsIncluded;
962
- }
963
- function getValidAccounts(caipAccountIds) {
964
- return caipAccountIds.reduce(
965
- (caipAccounts, caipAccountId) => {
966
- try {
967
- return [...caipAccounts, parseCaipAccountId(caipAccountId)];
968
- } catch (err) {
969
- const stringifiedAccountId = JSON.stringify(caipAccountId);
970
- console.error(`Invalid CAIP account ID: ${stringifiedAccountId}`, err);
971
- return caipAccounts;
972
- }
973
- },
974
- []
975
- );
976
- }
977
- function addValidAccounts(optionalScopes, validAccounts) {
978
- var _a;
979
- if (!optionalScopes || !(validAccounts == null ? void 0 : validAccounts.length)) {
980
- return optionalScopes;
981
- }
982
- const result = Object.fromEntries(
983
- Object.entries(optionalScopes).map(([scope, scopeData]) => {
984
- var _a2, _b, _c;
985
- return [
986
- scope,
987
- {
988
- methods: [...(_a2 = scopeData == null ? void 0 : scopeData.methods) != null ? _a2 : []],
989
- notifications: [...(_b = scopeData == null ? void 0 : scopeData.notifications) != null ? _b : []],
990
- accounts: [...(_c = scopeData == null ? void 0 : scopeData.accounts) != null ? _c : []]
991
- }
992
- ];
993
- })
994
- );
995
- const accountsByChain = /* @__PURE__ */ new Map();
996
- for (const account of validAccounts) {
997
- const chainKey = `${account.chain.namespace}:${account.chain.reference}`;
998
- const accountId = `${account.chainId}:${account.address}`;
999
- if (!accountsByChain.has(chainKey)) {
1000
- accountsByChain.set(chainKey, []);
1001
- }
1002
- (_a = accountsByChain.get(chainKey)) == null ? void 0 : _a.push(accountId);
1003
- }
1004
- for (const [scopeKey, scopeData] of Object.entries(result)) {
1005
- if (!(scopeData == null ? void 0 : scopeData.accounts)) {
1006
- continue;
1007
- }
1008
- try {
1009
- const scope = scopeKey;
1010
- const scopeDetails = parseCaipChainId(scope);
1011
- const chainKey = `${scopeDetails.namespace}:${scopeDetails.reference}`;
1012
- const matchingAccounts = accountsByChain.get(chainKey);
1013
- if (matchingAccounts) {
1014
- const existingAccounts = new Set(scopeData.accounts);
1015
- const newAccounts = matchingAccounts.filter(
1016
- (account) => !existingAccounts.has(account)
1017
- );
1018
- scopeData.accounts.push(...newAccounts);
1044
+ init_install();
1045
+ init_otp();
1046
+ }
1047
+ });
1048
+
1049
+ // src/store/adapters/rn.ts
1050
+ var rn_exports2 = {};
1051
+ __export(rn_exports2, {
1052
+ StoreAdapterRN: () => StoreAdapterRN
1053
+ });
1054
+ import AsyncStorage from "@react-native-async-storage/async-storage";
1055
+ var StoreAdapterRN;
1056
+ var init_rn2 = __esm({
1057
+ "src/store/adapters/rn.ts"() {
1058
+ "use strict";
1059
+ init_domain();
1060
+ StoreAdapterRN = class extends StoreAdapter {
1061
+ constructor() {
1062
+ super(...arguments);
1063
+ this.platform = "rn";
1019
1064
  }
1020
- } catch (error) {
1021
- console.error(`Invalid scope format: ${scopeKey}`, error);
1022
- }
1065
+ get(key) {
1066
+ return __async(this, null, function* () {
1067
+ return AsyncStorage.getItem(key);
1068
+ });
1069
+ }
1070
+ set(key, value) {
1071
+ return __async(this, null, function* () {
1072
+ return AsyncStorage.setItem(key, value);
1073
+ });
1074
+ }
1075
+ delete(key) {
1076
+ return __async(this, null, function* () {
1077
+ return AsyncStorage.removeItem(key);
1078
+ });
1079
+ }
1080
+ };
1023
1081
  }
1024
- return result;
1025
- }
1082
+ });
1083
+
1084
+ // src/multichain/index.ts
1085
+ import { analytics as analytics2 } from "@metamask/analytics";
1086
+ import {
1087
+ ErrorCode,
1088
+ ProtocolError,
1089
+ SessionStore as SessionStore2,
1090
+ WebSocketTransport
1091
+ } from "@metamask/mobile-wallet-protocol-core";
1092
+ import { DappClient } from "@metamask/mobile-wallet-protocol-dapp-client";
1093
+ import {
1094
+ getMultichainClient
1095
+ } from "@metamask/multichain-api-client";
1096
+
1097
+ // src/config/index.ts
1098
+ var MWP_RELAY_URL = "wss://mm-sdk-relay.api.cx.metamask.io/connection/websocket";
1099
+ var METAMASK_CONNECT_BASE_URL = "https://metamask.app.link/connect";
1100
+ var METAMASK_DEEPLINK_BASE = "metamask://connect";
1101
+
1102
+ // src/multichain/index.ts
1103
+ init_domain();
1104
+ init_analytics();
1105
+ init_logger();
1106
+ init_multichain();
1107
+ init_platform();
1026
1108
 
1027
1109
  // src/multichain/rpc/handlers/rpcClient.ts
1028
1110
  init_domain();
@@ -1041,6 +1123,7 @@ var RpcClient = class {
1041
1123
  }
1042
1124
  /**
1043
1125
  * Routes the request to a configured RPC node.
1126
+ * @param options - The invoke method options
1044
1127
  */
1045
1128
  request(options) {
1046
1129
  return __async(this, null, function* () {
@@ -1052,46 +1135,45 @@ var RpcClient = class {
1052
1135
  id: getNextRpcId()
1053
1136
  });
1054
1137
  const rpcEndpoint = this.getRpcEndpoint(options.scope);
1055
- const rpcRequest = yield this.fetch(rpcEndpoint, body, "POST", this.getHeaders(rpcEndpoint));
1138
+ const rpcRequest = yield this.fetchWithTimeout(rpcEndpoint, body, "POST", this.getHeaders(rpcEndpoint), 3e4);
1056
1139
  const response = yield this.parseResponse(rpcRequest);
1057
1140
  return response;
1058
1141
  });
1059
1142
  }
1060
1143
  getRpcEndpoint(scope) {
1061
- var _a, _b, _c, _d, _e;
1062
- let infuraAPIKey = (_b = (_a = this.config) == null ? void 0 : _a.api) == null ? void 0 : _b.infuraAPIKey;
1063
- let readonlyRPCMap = (_e = (_d = (_c = this.config) == null ? void 0 : _c.api) == null ? void 0 : _d.readonlyRPCMap) != null ? _e : {};
1064
- if (infuraAPIKey) {
1065
- const urlsWithToken = getInfuraRpcUrls(infuraAPIKey);
1066
- if (readonlyRPCMap) {
1067
- readonlyRPCMap = __spreadValues(__spreadValues({}, urlsWithToken), readonlyRPCMap);
1068
- } else {
1069
- readonlyRPCMap = urlsWithToken;
1070
- }
1071
- }
1072
- const rpcEndpoint = readonlyRPCMap[scope];
1144
+ var _a, _b, _c;
1145
+ const supportedNetworks = (_c = (_b = (_a = this.config) == null ? void 0 : _a.api) == null ? void 0 : _b.supportedNetworks) != null ? _c : {};
1146
+ const rpcEndpoint = supportedNetworks[scope];
1073
1147
  if (!rpcEndpoint) {
1074
1148
  throw new MissingRpcEndpointErr(`No RPC endpoint found for scope ${scope}`);
1075
1149
  }
1076
1150
  return rpcEndpoint;
1077
1151
  }
1078
- fetch(endpoint, body, method, headers) {
1152
+ fetchWithTimeout(endpoint, body, method, headers, timeout) {
1079
1153
  return __async(this, null, function* () {
1154
+ const controller = new AbortController();
1155
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
1080
1156
  try {
1081
1157
  const response = yield fetch(endpoint, {
1082
1158
  method,
1083
1159
  headers,
1084
- body
1160
+ body,
1161
+ signal: controller.signal
1085
1162
  });
1163
+ clearTimeout(timeoutId);
1086
1164
  if (!response.ok) {
1087
1165
  throw new RPCHttpErr(endpoint, method, response.status);
1088
1166
  }
1089
1167
  return response;
1090
1168
  } catch (error) {
1169
+ clearTimeout(timeoutId);
1091
1170
  if (error instanceof RPCHttpErr) {
1092
1171
  throw error;
1093
1172
  }
1094
- throw new RPCReadonlyRequestErr(error.message);
1173
+ if (error instanceof Error && error.name === "AbortError") {
1174
+ throw new RPCReadonlyRequestErr(`Request timeout after ${timeout}ms`);
1175
+ }
1176
+ throw new RPCReadonlyRequestErr(error instanceof Error ? error.message : "Unknown error");
1095
1177
  }
1096
1178
  });
1097
1179
  }
@@ -1120,11 +1202,17 @@ var RpcClient = class {
1120
1202
  };
1121
1203
 
1122
1204
  // src/multichain/rpc/requestRouter.ts
1205
+ import { analytics } from "@metamask/analytics";
1206
+ init_domain();
1207
+ init_utils();
1208
+ init_analytics();
1209
+ var _RequestRouter_instances, withAnalyticsTracking_fn, trackWalletActionRequested_fn, trackWalletActionSucceeded_fn, trackWalletActionFailed_fn, trackWalletActionRejected_fn;
1123
1210
  var RequestRouter = class {
1124
1211
  constructor(transport, rpcClient, config) {
1125
1212
  this.transport = transport;
1126
1213
  this.rpcClient = rpcClient;
1127
1214
  this.config = config;
1215
+ __privateAdd(this, _RequestRouter_instances);
1128
1216
  }
1129
1217
  /**
1130
1218
  * The main entry point for invoking an RPC method.
@@ -1148,15 +1236,15 @@ var RequestRouter = class {
1148
1236
  */
1149
1237
  handleWithWallet(options) {
1150
1238
  return __async(this, null, function* () {
1151
- try {
1239
+ return __privateMethod(this, _RequestRouter_instances, withAnalyticsTracking_fn).call(this, options, () => __async(this, null, function* () {
1152
1240
  const request = this.transport.request({
1153
1241
  method: "wallet_invokeMethod",
1154
1242
  params: options
1155
1243
  });
1156
1244
  const { ui, mobile } = this.config;
1157
- const { preferDesktop = false } = ui != null ? ui : {};
1245
+ const { showInstallModal = false } = ui != null ? ui : {};
1158
1246
  const secure = isSecure();
1159
- const shouldOpenDeeplink = secure && !preferDesktop;
1247
+ const shouldOpenDeeplink = secure && !showInstallModal;
1160
1248
  if (shouldOpenDeeplink) {
1161
1249
  setTimeout(() => {
1162
1250
  if (mobile == null ? void 0 : mobile.preferredOpenLink) {
@@ -1171,9 +1259,7 @@ var RequestRouter = class {
1171
1259
  throw new RPCInvokeMethodErr(`RPC Request failed with code ${response.error.code}: ${response.error.message}`);
1172
1260
  }
1173
1261
  return response.result;
1174
- } catch (error) {
1175
- throw new RPCInvokeMethodErr(error.message);
1176
- }
1262
+ }));
1177
1263
  });
1178
1264
  }
1179
1265
  /**
@@ -1181,14 +1267,16 @@ var RequestRouter = class {
1181
1267
  */
1182
1268
  handleWithRpcNode(options) {
1183
1269
  return __async(this, null, function* () {
1184
- try {
1185
- return yield this.rpcClient.request(options);
1186
- } catch (error) {
1187
- if (error instanceof MissingRpcEndpointErr) {
1188
- return this.handleWithWallet(options);
1270
+ return __privateMethod(this, _RequestRouter_instances, withAnalyticsTracking_fn).call(this, options, () => __async(this, null, function* () {
1271
+ try {
1272
+ return yield this.rpcClient.request(options);
1273
+ } catch (error) {
1274
+ if (error instanceof MissingRpcEndpointErr) {
1275
+ return this.handleWithWallet(options);
1276
+ }
1277
+ throw error;
1189
1278
  }
1190
- throw error;
1191
- }
1279
+ }));
1192
1280
  });
1193
1281
  }
1194
1282
  /**
@@ -1201,13 +1289,64 @@ var RequestRouter = class {
1201
1289
  });
1202
1290
  }
1203
1291
  };
1292
+ _RequestRouter_instances = new WeakSet();
1293
+ withAnalyticsTracking_fn = function(options, execute) {
1294
+ return __async(this, null, function* () {
1295
+ var _a, _b, _c;
1296
+ if ((_a = this.config.analytics) == null ? void 0 : _a.enabled) {
1297
+ yield __privateMethod(this, _RequestRouter_instances, trackWalletActionRequested_fn).call(this, options);
1298
+ }
1299
+ try {
1300
+ const result = yield execute();
1301
+ if ((_b = this.config.analytics) == null ? void 0 : _b.enabled) {
1302
+ yield __privateMethod(this, _RequestRouter_instances, trackWalletActionSucceeded_fn).call(this, options);
1303
+ }
1304
+ return result;
1305
+ } catch (error) {
1306
+ if ((_c = this.config.analytics) == null ? void 0 : _c.enabled) {
1307
+ const isRejection = isRejectionError(error);
1308
+ if (isRejection) {
1309
+ yield __privateMethod(this, _RequestRouter_instances, trackWalletActionRejected_fn).call(this, options);
1310
+ } else {
1311
+ yield __privateMethod(this, _RequestRouter_instances, trackWalletActionFailed_fn).call(this, options);
1312
+ }
1313
+ }
1314
+ throw new RPCInvokeMethodErr(error.message);
1315
+ }
1316
+ });
1317
+ };
1318
+ trackWalletActionRequested_fn = function(options) {
1319
+ return __async(this, null, function* () {
1320
+ const props = yield getWalletActionAnalyticsProperties(this.config, this.config.storage, options);
1321
+ analytics.track("mmconnect_wallet_action_requested", props);
1322
+ });
1323
+ };
1324
+ trackWalletActionSucceeded_fn = function(options) {
1325
+ return __async(this, null, function* () {
1326
+ const props = yield getWalletActionAnalyticsProperties(this.config, this.config.storage, options);
1327
+ analytics.track("mmconnect_wallet_action_succeeded", props);
1328
+ });
1329
+ };
1330
+ trackWalletActionFailed_fn = function(options) {
1331
+ return __async(this, null, function* () {
1332
+ const props = yield getWalletActionAnalyticsProperties(this.config, this.config.storage, options);
1333
+ analytics.track("mmconnect_wallet_action_failed", props);
1334
+ });
1335
+ };
1336
+ trackWalletActionRejected_fn = function(options) {
1337
+ return __async(this, null, function* () {
1338
+ const props = yield getWalletActionAnalyticsProperties(this.config, this.config.storage, options);
1339
+ analytics.track("mmconnect_wallet_action_rejected", props);
1340
+ });
1341
+ };
1204
1342
 
1205
1343
  // src/multichain/transports/default/index.ts
1344
+ init_utils();
1206
1345
  import {
1207
1346
  getDefaultTransport
1208
1347
  } from "@metamask/multichain-api-client";
1209
1348
  var DEFAULT_REQUEST_TIMEOUT = 60 * 1e3;
1210
- var _notificationCallbacks, _transport, _defaultRequestOptions, _DefaultTransport_instances, notifyCallbacks_fn;
1349
+ var _notificationCallbacks, _transport, _defaultRequestOptions, _reqId, _pendingRequests, _handleResponseListener, _handleNotificationListener, _DefaultTransport_instances, notifyCallbacks_fn, isMetamaskProviderEvent_fn, handleResponse_fn, handleNotification_fn, setupMessageListener_fn;
1211
1350
  var DefaultTransport = class {
1212
1351
  constructor() {
1213
1352
  __privateAdd(this, _DefaultTransport_instances);
@@ -1216,10 +1355,52 @@ var DefaultTransport = class {
1216
1355
  __privateAdd(this, _defaultRequestOptions, {
1217
1356
  timeout: DEFAULT_REQUEST_TIMEOUT
1218
1357
  });
1358
+ // Use timestamp-based ID to avoid conflicts across disconnect/reconnect cycles
1359
+ __privateAdd(this, _reqId, Date.now());
1360
+ __privateAdd(this, _pendingRequests, /* @__PURE__ */ new Map());
1361
+ __privateAdd(this, _handleResponseListener);
1362
+ __privateAdd(this, _handleNotificationListener);
1363
+ }
1364
+ sendEip1193Message(payload, options) {
1365
+ return __async(this, null, function* () {
1366
+ __privateMethod(this, _DefaultTransport_instances, setupMessageListener_fn).call(this);
1367
+ __privateSet(this, _reqId, __privateGet(this, _reqId) + 1);
1368
+ const requestId = `${__privateGet(this, _reqId)}`;
1369
+ const request = __spreadValues({
1370
+ jsonrpc: "2.0",
1371
+ id: requestId
1372
+ }, payload);
1373
+ return new Promise((resolve, reject) => {
1374
+ var _a;
1375
+ const timeout = setTimeout(() => {
1376
+ __privateGet(this, _pendingRequests).delete(requestId);
1377
+ reject(new Error("Request timeout"));
1378
+ }, (_a = options == null ? void 0 : options.timeout) != null ? _a : __privateGet(this, _defaultRequestOptions).timeout);
1379
+ __privateGet(this, _pendingRequests).set(requestId, {
1380
+ resolve: (response) => {
1381
+ resolve(response);
1382
+ },
1383
+ reject,
1384
+ timeout
1385
+ });
1386
+ window.postMessage(
1387
+ {
1388
+ target: "metamask-contentscript",
1389
+ data: {
1390
+ name: "metamask-provider",
1391
+ data: request
1392
+ }
1393
+ },
1394
+ // eslint-disable-next-line no-restricted-globals
1395
+ location.origin
1396
+ );
1397
+ });
1398
+ });
1219
1399
  }
1220
1400
  connect(options) {
1221
1401
  return __async(this, null, function* () {
1222
1402
  var _a, _b, _c, _d, _e, _f, _g;
1403
+ __privateMethod(this, _DefaultTransport_instances, setupMessageListener_fn).call(this);
1223
1404
  yield __privateGet(this, _transport).connect();
1224
1405
  const sessionRequest = yield this.request(
1225
1406
  { method: "wallet_getSession" },
@@ -1229,7 +1410,7 @@ var DefaultTransport = class {
1229
1410
  throw new Error(sessionRequest.error.message);
1230
1411
  }
1231
1412
  let walletSession = sessionRequest.result;
1232
- if (walletSession && options) {
1413
+ if (walletSession && options && !options.forceRequest) {
1233
1414
  const currentScopes = Object.keys(
1234
1415
  (_a = walletSession == null ? void 0 : walletSession.sessionScopes) != null ? _a : {}
1235
1416
  );
@@ -1250,9 +1431,11 @@ var DefaultTransport = class {
1250
1431
  getOptionalScopes((_d = options == null ? void 0 : options.scopes) != null ? _d : []),
1251
1432
  getValidAccounts((_e = options == null ? void 0 : options.caipAccountIds) != null ? _e : [])
1252
1433
  );
1253
- const sessionRequest2 = { optionalScopes };
1434
+ const createSessionParams = {
1435
+ optionalScopes
1436
+ };
1254
1437
  const response = yield this.request(
1255
- { method: "wallet_createSession", params: sessionRequest2 },
1438
+ { method: "wallet_createSession", params: createSessionParams },
1256
1439
  __privateGet(this, _defaultRequestOptions)
1257
1440
  );
1258
1441
  if (response.error) {
@@ -1260,14 +1443,16 @@ var DefaultTransport = class {
1260
1443
  }
1261
1444
  walletSession = response.result;
1262
1445
  }
1263
- } else if (!walletSession) {
1446
+ } else if (!walletSession || (options == null ? void 0 : options.forceRequest)) {
1264
1447
  const optionalScopes = addValidAccounts(
1265
1448
  getOptionalScopes((_f = options == null ? void 0 : options.scopes) != null ? _f : []),
1266
1449
  getValidAccounts((_g = options == null ? void 0 : options.caipAccountIds) != null ? _g : [])
1267
1450
  );
1268
- const sessionRequest2 = { optionalScopes };
1451
+ const createSessionParams = {
1452
+ optionalScopes
1453
+ };
1269
1454
  const response = yield this.request(
1270
- { method: "wallet_createSession", params: sessionRequest2 },
1455
+ { method: "wallet_createSession", params: createSessionParams },
1271
1456
  __privateGet(this, _defaultRequestOptions)
1272
1457
  );
1273
1458
  if (response.error) {
@@ -1284,6 +1469,16 @@ var DefaultTransport = class {
1284
1469
  disconnect() {
1285
1470
  return __async(this, null, function* () {
1286
1471
  __privateGet(this, _notificationCallbacks).clear();
1472
+ yield this.request({ method: "wallet_revokeSession", params: {} });
1473
+ if (__privateGet(this, _handleResponseListener)) {
1474
+ window.removeEventListener("message", __privateGet(this, _handleResponseListener));
1475
+ __privateSet(this, _handleResponseListener, void 0);
1476
+ }
1477
+ for (const [, request] of __privateGet(this, _pendingRequests)) {
1478
+ clearTimeout(request.timeout);
1479
+ request.reject(new Error("Transport disconnected"));
1480
+ }
1481
+ __privateGet(this, _pendingRequests).clear();
1287
1482
  return __privateGet(this, _transport).disconnect();
1288
1483
  });
1289
1484
  }
@@ -1306,33 +1501,101 @@ var DefaultTransport = class {
1306
1501
  _notificationCallbacks = new WeakMap();
1307
1502
  _transport = new WeakMap();
1308
1503
  _defaultRequestOptions = new WeakMap();
1504
+ _reqId = new WeakMap();
1505
+ _pendingRequests = new WeakMap();
1506
+ _handleResponseListener = new WeakMap();
1507
+ _handleNotificationListener = new WeakMap();
1309
1508
  _DefaultTransport_instances = new WeakSet();
1310
1509
  notifyCallbacks_fn = function(data) {
1311
- for (const cb of __privateGet(this, _notificationCallbacks)) {
1510
+ for (const callback of __privateGet(this, _notificationCallbacks)) {
1312
1511
  try {
1313
- cb(data);
1314
- } catch (err) {
1315
- console.log("[WindowPostMessageTransport] notifyCallbacks error:", err);
1512
+ callback(data);
1513
+ } catch (error) {
1514
+ console.log(
1515
+ "[WindowPostMessageTransport] notifyCallbacks error:",
1516
+ error
1517
+ );
1518
+ }
1519
+ }
1520
+ };
1521
+ isMetamaskProviderEvent_fn = function(event) {
1522
+ var _a, _b;
1523
+ return ((_b = (_a = event == null ? void 0 : event.data) == null ? void 0 : _a.data) == null ? void 0 : _b.name) === "metamask-provider" && // eslint-disable-next-line no-restricted-globals
1524
+ event.origin === location.origin;
1525
+ };
1526
+ handleResponse_fn = function(event) {
1527
+ var _a, _b;
1528
+ if (!__privateMethod(this, _DefaultTransport_instances, isMetamaskProviderEvent_fn).call(this, event)) {
1529
+ return;
1530
+ }
1531
+ const responseData = (_b = (_a = event == null ? void 0 : event.data) == null ? void 0 : _a.data) == null ? void 0 : _b.data;
1532
+ if (typeof responseData === "object" && responseData !== null && "method" in responseData) {
1533
+ return;
1534
+ }
1535
+ if (typeof responseData === "object" && responseData !== null && "id" in responseData && ("result" in responseData || "error" in responseData)) {
1536
+ const responseId = String(responseData.id);
1537
+ const pendingRequest = __privateGet(this, _pendingRequests).get(responseId);
1538
+ if (pendingRequest) {
1539
+ clearTimeout(pendingRequest.timeout);
1540
+ __privateGet(this, _pendingRequests).delete(responseId);
1541
+ const response = responseData;
1542
+ if ("error" in response && response.error) {
1543
+ pendingRequest.reject(
1544
+ new Error(response.error.message || "Request failed")
1545
+ );
1546
+ } else {
1547
+ pendingRequest.resolve(response);
1548
+ }
1316
1549
  }
1317
1550
  }
1318
1551
  };
1552
+ handleNotification_fn = function(event) {
1553
+ var _a, _b;
1554
+ if (!__privateMethod(this, _DefaultTransport_instances, isMetamaskProviderEvent_fn).call(this, event)) {
1555
+ return;
1556
+ }
1557
+ const responseData = (_b = (_a = event == null ? void 0 : event.data) == null ? void 0 : _a.data) == null ? void 0 : _b.data;
1558
+ if (typeof responseData === "object" && responseData.method === "metamask_chainChanged" || responseData.method === "metamask_accountsChanged") {
1559
+ __privateMethod(this, _DefaultTransport_instances, notifyCallbacks_fn).call(this, responseData);
1560
+ }
1561
+ };
1562
+ setupMessageListener_fn = function() {
1563
+ if (__privateGet(this, _handleResponseListener)) {
1564
+ return;
1565
+ }
1566
+ __privateSet(this, _handleResponseListener, __privateMethod(this, _DefaultTransport_instances, handleResponse_fn).bind(this));
1567
+ __privateSet(this, _handleNotificationListener, __privateMethod(this, _DefaultTransport_instances, handleNotification_fn).bind(this));
1568
+ window.addEventListener("message", __privateGet(this, _handleResponseListener));
1569
+ window.addEventListener("message", __privateGet(this, _handleNotificationListener));
1570
+ };
1319
1571
 
1320
1572
  // src/multichain/transports/mwp/index.ts
1321
1573
  init_domain();
1574
+ init_utils();
1322
1575
  import { SessionStore } from "@metamask/mobile-wallet-protocol-core";
1323
1576
  import {
1324
1577
  TransportTimeoutError
1325
1578
  } from "@metamask/multichain-api-client";
1579
+
1580
+ // src/multichain/transports/constants.ts
1581
+ var MULTICHAIN_PROVIDER_STREAM_NAME = "metamask-multichain-provider";
1582
+
1583
+ // src/multichain/transports/mwp/index.ts
1326
1584
  var DEFAULT_REQUEST_TIMEOUT2 = 60 * 1e3;
1327
1585
  var CONNECTION_GRACE_PERIOD = 60 * 1e3;
1328
1586
  var DEFAULT_CONNECTION_TIMEOUT = DEFAULT_REQUEST_TIMEOUT2 + CONNECTION_GRACE_PERIOD;
1329
1587
  var SESSION_STORE_KEY = "cache_wallet_getSession";
1588
+ var ACCOUNTS_STORE_KEY = "cache_eth_accounts";
1589
+ var CHAIN_STORE_KEY = "cache_eth_chainId";
1330
1590
  var CACHED_METHOD_LIST = [
1331
1591
  "wallet_getSession",
1332
1592
  "wallet_createSession",
1333
1593
  "wallet_sessionChanged"
1334
1594
  ];
1335
- var CACHED_RESET_METHOD_LIST = ["wallet_revokeSession"];
1595
+ var CACHED_RESET_METHOD_LIST = [
1596
+ "wallet_revokeSession",
1597
+ "wallet_revokePermissions"
1598
+ ];
1336
1599
  var logger = createLogger("metamask-sdk:transport");
1337
1600
  var MWPTransport = class {
1338
1601
  constructor(dappClient, kvstore, options = {
@@ -1396,6 +1659,22 @@ var MWPTransport = class {
1396
1659
  this.pendingRequests.delete(messagePayload.id);
1397
1660
  }
1398
1661
  } else {
1662
+ if (message.data.method === "metamask_chainChanged") {
1663
+ this.kvstore.set(
1664
+ CHAIN_STORE_KEY,
1665
+ JSON.stringify(
1666
+ message.data.params.chainId
1667
+ )
1668
+ );
1669
+ }
1670
+ if (message.data.method === "metamask_accountsChanged") {
1671
+ this.kvstore.set(
1672
+ ACCOUNTS_STORE_KEY,
1673
+ JSON.stringify(
1674
+ message.data.params
1675
+ )
1676
+ );
1677
+ }
1399
1678
  this.notifyCallbacks(message.data);
1400
1679
  }
1401
1680
  }
@@ -1466,6 +1745,40 @@ var MWPTransport = class {
1466
1745
  }
1467
1746
  });
1468
1747
  }
1748
+ // TODO: Rename this
1749
+ sendEip1193Message(payload, options) {
1750
+ return __async(this, null, function* () {
1751
+ const request = __spreadValues({
1752
+ jsonrpc: "2.0",
1753
+ id: `${this.__reqId++}`
1754
+ }, payload);
1755
+ const cachedWalletSession = yield this.getCachedResponse(request);
1756
+ if (cachedWalletSession) {
1757
+ this.notifyCallbacks(cachedWalletSession);
1758
+ return cachedWalletSession;
1759
+ }
1760
+ return new Promise((resolve, reject) => {
1761
+ var _a;
1762
+ const timeout = setTimeout(() => {
1763
+ this.rejectRequest(request.id, new TransportTimeoutError());
1764
+ }, (_a = options == null ? void 0 : options.timeout) != null ? _a : this.options.requestTimeout);
1765
+ this.pendingRequests.set(request.id, {
1766
+ request,
1767
+ method: request.method,
1768
+ resolve: (response) => __async(this, null, function* () {
1769
+ yield this.storeWalletSession(request, response);
1770
+ return resolve(response);
1771
+ }),
1772
+ reject,
1773
+ timeout
1774
+ });
1775
+ this.dappClient.sendRequest({
1776
+ name: "metamask-provider",
1777
+ data: request
1778
+ }).catch(reject);
1779
+ });
1780
+ });
1781
+ }
1469
1782
  connect(options) {
1470
1783
  return __async(this, null, function* () {
1471
1784
  const { dappClient, kvstore } = this;
@@ -1519,17 +1832,23 @@ var MWPTransport = class {
1519
1832
  if (messagePayload.error) {
1520
1833
  return rejectConnection(messagePayload.error);
1521
1834
  }
1522
- this.notifyCallbacks(message.data);
1523
1835
  yield this.storeWalletSession(
1524
1836
  request,
1525
1837
  messagePayload
1526
1838
  );
1839
+ this.notifyCallbacks(messagePayload);
1527
1840
  return resolveConnection();
1528
1841
  }
1529
1842
  }
1530
1843
  }
1531
1844
  }));
1532
- dappClient.connect({ mode: "trusted", initialPayload: request }).catch(rejectConnection);
1845
+ dappClient.connect({
1846
+ mode: "trusted",
1847
+ initialPayload: {
1848
+ name: MULTICHAIN_PROVIDER_STREAM_NAME,
1849
+ data: request
1850
+ }
1851
+ }).catch(rejectConnection);
1533
1852
  }
1534
1853
  );
1535
1854
  }
@@ -1556,6 +1875,9 @@ var MWPTransport = class {
1556
1875
  window.removeEventListener("focus", this.windowFocusHandler);
1557
1876
  this.windowFocusHandler = void 0;
1558
1877
  }
1878
+ this.kvstore.delete(SESSION_STORE_KEY);
1879
+ this.kvstore.delete(ACCOUNTS_STORE_KEY);
1880
+ this.kvstore.delete(CHAIN_STORE_KEY);
1559
1881
  return this.dappClient.disconnect();
1560
1882
  });
1561
1883
  }
@@ -1567,7 +1889,39 @@ var MWPTransport = class {
1567
1889
  isConnected() {
1568
1890
  return this.dappClient.state === "CONNECTED";
1569
1891
  }
1570
- fetchCachedWalletSession(request) {
1892
+ /**
1893
+ * Attempts to re-establish a connection via DappClient
1894
+ *
1895
+ * @returns Nothing
1896
+ */
1897
+ // TODO: We should re-evaluate adding this to the WebSocketTransport layer from `@metamask/mobile-wallet-protocol-core`
1898
+ // ticket: https://consensyssoftware.atlassian.net/browse/WAPI-862
1899
+ attemptResumeSession() {
1900
+ return __async(this, null, function* () {
1901
+ try {
1902
+ yield this.dappClient.reconnect();
1903
+ yield new Promise((resolve, reject) => {
1904
+ const timeout = setTimeout(() => {
1905
+ reject(new Error("Resume timeout"));
1906
+ }, 2e3);
1907
+ if (this.isConnected()) {
1908
+ clearTimeout(timeout);
1909
+ resolve();
1910
+ } else {
1911
+ this.dappClient.once("connected", () => {
1912
+ clearTimeout(timeout);
1913
+ resolve();
1914
+ });
1915
+ }
1916
+ });
1917
+ } catch (error) {
1918
+ return Promise.reject(
1919
+ new Error(`Failed to resume session: ${error.message}`)
1920
+ );
1921
+ }
1922
+ });
1923
+ }
1924
+ getCachedResponse(request) {
1571
1925
  return __async(this, null, function* () {
1572
1926
  var _a;
1573
1927
  if (request.method === "wallet_getSession") {
@@ -1578,6 +1932,27 @@ var MWPTransport = class {
1578
1932
  id: request.id,
1579
1933
  jsonrpc: "2.0",
1580
1934
  result: (_a = walletSession.params) != null ? _a : walletSession.result,
1935
+ // "what?... why walletSession.params?.."
1936
+ method: request.method
1937
+ };
1938
+ }
1939
+ } else if (request.method === "eth_accounts") {
1940
+ const ethAccounts = yield this.kvstore.get(ACCOUNTS_STORE_KEY);
1941
+ if (ethAccounts) {
1942
+ return {
1943
+ id: request.id,
1944
+ jsonrpc: "2.0",
1945
+ result: JSON.parse(ethAccounts),
1946
+ method: request.method
1947
+ };
1948
+ }
1949
+ } else if (request.method === "eth_chainId") {
1950
+ const ethChainId = yield this.kvstore.get(CHAIN_STORE_KEY);
1951
+ if (ethChainId) {
1952
+ return {
1953
+ id: request.id,
1954
+ jsonrpc: "2.0",
1955
+ result: JSON.parse(ethChainId),
1581
1956
  method: request.method
1582
1957
  };
1583
1958
  }
@@ -1588,8 +1963,17 @@ var MWPTransport = class {
1588
1963
  return __async(this, null, function* () {
1589
1964
  if (CACHED_METHOD_LIST.includes(request.method)) {
1590
1965
  yield this.kvstore.set(SESSION_STORE_KEY, JSON.stringify(response));
1966
+ } else if (request.method === "eth_accounts") {
1967
+ yield this.kvstore.set(
1968
+ ACCOUNTS_STORE_KEY,
1969
+ JSON.stringify(response.result)
1970
+ );
1971
+ } else if (request.method === "eth_chainId") {
1972
+ yield this.kvstore.set(CHAIN_STORE_KEY, JSON.stringify(response.result));
1591
1973
  } else if (CACHED_RESET_METHOD_LIST.includes(request.method)) {
1592
1974
  yield this.kvstore.delete(SESSION_STORE_KEY);
1975
+ yield this.kvstore.delete(ACCOUNTS_STORE_KEY);
1976
+ yield this.kvstore.delete(CHAIN_STORE_KEY);
1593
1977
  }
1594
1978
  });
1595
1979
  }
@@ -1599,11 +1983,14 @@ var MWPTransport = class {
1599
1983
  jsonrpc: "2.0",
1600
1984
  id: `${this.__reqId++}`
1601
1985
  }, payload);
1602
- const cachedWalletSession = yield this.fetchCachedWalletSession(request);
1986
+ const cachedWalletSession = yield this.getCachedResponse(request);
1603
1987
  if (cachedWalletSession) {
1604
1988
  this.notifyCallbacks(cachedWalletSession);
1605
1989
  return cachedWalletSession;
1606
1990
  }
1991
+ if (!this.isConnected()) {
1992
+ yield this.attemptResumeSession();
1993
+ }
1607
1994
  return new Promise((resolve, reject) => {
1608
1995
  var _a;
1609
1996
  const timeout = setTimeout(() => {
@@ -1613,15 +2000,16 @@ var MWPTransport = class {
1613
2000
  request,
1614
2001
  method: request.method,
1615
2002
  resolve: (response) => __async(this, null, function* () {
1616
- if (CACHED_METHOD_LIST.includes(request.method)) {
1617
- yield this.storeWalletSession(request, response);
1618
- }
2003
+ yield this.storeWalletSession(request, response);
1619
2004
  return resolve(response);
1620
2005
  }),
1621
2006
  reject,
1622
2007
  timeout
1623
2008
  });
1624
- this.dappClient.sendRequest(request).catch(reject);
2009
+ this.dappClient.sendRequest({
2010
+ name: MULTICHAIN_PROVIDER_STREAM_NAME,
2011
+ data: request
2012
+ }).catch(reject);
1625
2013
  });
1626
2014
  });
1627
2015
  }
@@ -1661,21 +2049,22 @@ var KeyManager = class {
1661
2049
  var keymanager = new KeyManager();
1662
2050
 
1663
2051
  // src/multichain/index.ts
2052
+ init_utils();
1664
2053
  var logger2 = createLogger("metamask-sdk:core");
1665
2054
  var MultichainSDK = class _MultichainSDK extends MultichainCore {
1666
2055
  constructor(options) {
1667
- var _a, _b, _c, _d, _e, _f;
1668
- const withInfuraRPCMethods = setupInfuraProvider(options);
1669
- const withDappMetadata = setupDappMetadata(withInfuraRPCMethods);
2056
+ var _a, _b, _c, _d, _e, _f, _g;
2057
+ const withDappMetadata = setupDappMetadata(options);
2058
+ const integrationType = ((_a = options.analytics) == null ? void 0 : _a.enabled) ? options.analytics.integrationType : "direct";
1670
2059
  const allOptions = __spreadProps(__spreadValues({}, withDappMetadata), {
1671
2060
  ui: __spreadProps(__spreadValues({}, withDappMetadata.ui), {
1672
- preferExtension: (_a = withDappMetadata.ui.preferExtension) != null ? _a : true,
1673
- preferDesktop: (_b = withDappMetadata.ui.preferDesktop) != null ? _b : false,
1674
- headless: (_c = withDappMetadata.ui.headless) != null ? _c : false
2061
+ preferExtension: (_b = withDappMetadata.ui.preferExtension) != null ? _b : true,
2062
+ showInstallModal: (_c = withDappMetadata.ui.showInstallModal) != null ? _c : false,
2063
+ headless: (_d = withDappMetadata.ui.headless) != null ? _d : false
1675
2064
  }),
1676
- analytics: __spreadProps(__spreadValues({}, (_d = options.analytics) != null ? _d : {}), {
1677
- enabled: (_f = (_e = options.analytics) == null ? void 0 : _e.enabled) != null ? _f : true,
1678
- integrationType: "unknown"
2065
+ analytics: __spreadProps(__spreadValues({}, (_e = options.analytics) != null ? _e : {}), {
2066
+ enabled: (_g = (_f = options.analytics) == null ? void 0 : _f.enabled) != null ? _g : true,
2067
+ integrationType
1679
2068
  })
1680
2069
  });
1681
2070
  super(allOptions);
@@ -1696,6 +2085,10 @@ var MultichainSDK = class _MultichainSDK extends MultichainCore {
1696
2085
  });
1697
2086
  }
1698
2087
  get provider() {
2088
+ if (!this.__provider && this.__transport) {
2089
+ this.__provider = getMultichainClient({ transport: this.__transport });
2090
+ return this.__provider;
2091
+ }
1699
2092
  if (!this.__provider) {
1700
2093
  throw new Error("Provider not initialized, establish connection first");
1701
2094
  }
@@ -1716,6 +2109,9 @@ var MultichainSDK = class _MultichainSDK extends MultichainCore {
1716
2109
  get storage() {
1717
2110
  return this.options.storage;
1718
2111
  }
2112
+ get transportType() {
2113
+ return this.__transport instanceof MWPTransport ? "mwp" /* MWP */ : "browser" /* Browser */;
2114
+ }
1719
2115
  get sdkInfo() {
1720
2116
  var _a;
1721
2117
  return `Sdk/Javascript SdkVersion/${getVersion()} Platform/${getPlatformType()} dApp/${(_a = this.options.dapp.url) != null ? _a : this.options.dapp.name} dAppTitle/${this.options.dapp.name}`;
@@ -1752,12 +2148,12 @@ var MultichainSDK = class _MultichainSDK extends MultichainCore {
1752
2148
  const { integrationType } = (_b = this.options.analytics) != null ? _b : {
1753
2149
  integrationType: ""
1754
2150
  };
1755
- analytics.setGlobalProperty("sdk_version", version);
1756
- analytics.setGlobalProperty("dapp_id", dappId);
1757
- analytics.setGlobalProperty("anon_id", anonId);
1758
- analytics.setGlobalProperty("platform", platform);
1759
- analytics.setGlobalProperty("integration_type", integrationType);
1760
- analytics.enable();
2151
+ analytics2.setGlobalProperty("mmconnect_version", version);
2152
+ analytics2.setGlobalProperty("dapp_id", dappId);
2153
+ analytics2.setGlobalProperty("anon_id", anonId);
2154
+ analytics2.setGlobalProperty("platform", platform);
2155
+ analytics2.setGlobalProperty("integration_type", integrationType);
2156
+ analytics2.enable();
1761
2157
  });
1762
2158
  }
1763
2159
  onTransportNotification(payload) {
@@ -1770,13 +2166,11 @@ var MultichainSDK = class _MultichainSDK extends MultichainCore {
1770
2166
  }
1771
2167
  getStoredTransport() {
1772
2168
  return __async(this, null, function* () {
1773
- const { ui } = this.options;
1774
- const { preferExtension = true } = ui;
1775
2169
  const transportType = yield this.storage.getTransport();
1776
2170
  const hasExtensionInstalled = yield hasExtension();
1777
2171
  if (transportType) {
1778
2172
  if (transportType === "browser" /* Browser */) {
1779
- if (hasExtensionInstalled && preferExtension) {
2173
+ if (hasExtensionInstalled) {
1780
2174
  const apiTransport = new DefaultTransport();
1781
2175
  this.__transport = apiTransport;
1782
2176
  this.listener = apiTransport.onNotification(
@@ -1784,7 +2178,7 @@ var MultichainSDK = class _MultichainSDK extends MultichainCore {
1784
2178
  );
1785
2179
  return apiTransport;
1786
2180
  }
1787
- } else if (transportType === "mwp" /* MPW */) {
2181
+ } else if (transportType === "mwp" /* MWP */) {
1788
2182
  const { adapter: kvstore } = this.options.storage;
1789
2183
  const dappClient = yield this.createDappClient();
1790
2184
  const apiTransport = new MWPTransport(dappClient, kvstore);
@@ -1810,7 +2204,7 @@ var MultichainSDK = class _MultichainSDK extends MultichainCore {
1810
2204
  }
1811
2205
  this.state = "connected";
1812
2206
  if (this.transport instanceof MWPTransport) {
1813
- yield this.storage.setTransport("mwp" /* MPW */);
2207
+ yield this.storage.setTransport("mwp" /* MWP */);
1814
2208
  } else {
1815
2209
  yield this.storage.setTransport("browser" /* Browser */);
1816
2210
  }
@@ -1821,14 +2215,24 @@ var MultichainSDK = class _MultichainSDK extends MultichainCore {
1821
2215
  }
1822
2216
  init() {
1823
2217
  return __async(this, null, function* () {
1824
- var _a;
2218
+ var _a, _b;
1825
2219
  try {
1826
2220
  if (typeof window !== "undefined" && ((_a = window.mmsdk) == null ? void 0 : _a.isInitialized)) {
1827
2221
  logger2("MetaMaskSDK: init already initialized");
1828
2222
  } else {
1829
2223
  yield this.setupAnalytics();
1830
2224
  yield this.setupTransport();
1831
- analytics.track("sdk_initialized", {});
2225
+ if ((_b = this.options.analytics) == null ? void 0 : _b.enabled) {
2226
+ try {
2227
+ const baseProps = yield getBaseAnalyticsProperties(
2228
+ this.options,
2229
+ this.storage
2230
+ );
2231
+ analytics2.track("mmconnect_initialized", baseProps);
2232
+ } catch (error) {
2233
+ logger2("Error tracking initialized event", error);
2234
+ }
2235
+ }
1832
2236
  if (typeof window !== "undefined") {
1833
2237
  window.mmsdk = this;
1834
2238
  }
@@ -1870,7 +2274,7 @@ var MultichainSDK = class _MultichainSDK extends MultichainCore {
1870
2274
  this.listener = this.transport.onNotification(
1871
2275
  this.onTransportNotification.bind(this)
1872
2276
  );
1873
- yield this.storage.setTransport("mwp" /* MPW */);
2277
+ yield this.storage.setTransport("mwp" /* MWP */);
1874
2278
  });
1875
2279
  }
1876
2280
  onBeforeUnload() {
@@ -1926,7 +2330,7 @@ var MultichainSDK = class _MultichainSDK extends MultichainCore {
1926
2330
  this.options.ui.factory.unload();
1927
2331
  (_a2 = this.options.ui.factory.modal) == null ? void 0 : _a2.unmount();
1928
2332
  this.state = "connected";
1929
- return this.storage.setTransport("mwp" /* MPW */);
2333
+ return this.storage.setTransport("mwp" /* MWP */);
1930
2334
  }).catch((error) => {
1931
2335
  if (error instanceof ProtocolError) {
1932
2336
  if (error.code !== ErrorCode.REQUEST_EXPIRED) {
@@ -1942,7 +2346,7 @@ var MultichainSDK = class _MultichainSDK extends MultichainCore {
1942
2346
  }),
1943
2347
  (error) => __async(this, null, function* () {
1944
2348
  if (!error) {
1945
- yield this.storage.setTransport("mwp" /* MPW */);
2349
+ yield this.storage.setTransport("mwp" /* MWP */);
1946
2350
  resolve();
1947
2351
  } else {
1948
2352
  yield this.storage.removeTransport();
@@ -2030,52 +2434,128 @@ var MultichainSDK = class _MultichainSDK extends MultichainCore {
2030
2434
  }));
2031
2435
  });
2032
2436
  }
2033
- handleConnection(promise) {
2437
+ handleConnection(promise, scopes, transportType) {
2034
2438
  return __async(this, null, function* () {
2035
2439
  this.state = "connecting";
2036
- return promise.then(() => {
2440
+ return promise.then(() => __async(this, null, function* () {
2441
+ var _a;
2037
2442
  this.state = "connected";
2038
- }).catch((error) => {
2443
+ if ((_a = this.options.analytics) == null ? void 0 : _a.enabled) {
2444
+ try {
2445
+ const baseProps = yield getBaseAnalyticsProperties(
2446
+ this.options,
2447
+ this.storage
2448
+ );
2449
+ analytics2.track("mmconnect_connection_established", __spreadProps(__spreadValues({}, baseProps), {
2450
+ transport_type: transportType,
2451
+ user_permissioned_chains: scopes
2452
+ }));
2453
+ } catch (error) {
2454
+ logger2("Error tracking connection_established event", error);
2455
+ }
2456
+ }
2457
+ })).catch((error) => __async(this, null, function* () {
2458
+ var _a;
2039
2459
  this.state = "disconnected";
2460
+ if ((_a = this.options.analytics) == null ? void 0 : _a.enabled) {
2461
+ try {
2462
+ const baseProps = yield getBaseAnalyticsProperties(
2463
+ this.options,
2464
+ this.storage
2465
+ );
2466
+ const isRejection = isRejectionError(error);
2467
+ if (isRejection) {
2468
+ analytics2.track("mmconnect_connection_rejected", __spreadProps(__spreadValues({}, baseProps), {
2469
+ transport_type: transportType
2470
+ }));
2471
+ } else {
2472
+ analytics2.track("mmconnect_connection_failed", __spreadProps(__spreadValues({}, baseProps), {
2473
+ transport_type: transportType
2474
+ }));
2475
+ }
2476
+ } catch (e) {
2477
+ logger2("Error tracking connection failed/rejected event", error);
2478
+ }
2479
+ }
2040
2480
  return Promise.reject(error);
2041
- });
2481
+ }));
2042
2482
  });
2043
2483
  }
2044
- connect(scopes, caipAccountIds) {
2484
+ connect(scopes, caipAccountIds, forceRequest) {
2045
2485
  return __async(this, null, function* () {
2046
- var _a;
2486
+ var _a, _b;
2047
2487
  const { ui } = this.options;
2048
2488
  const platformType = getPlatformType();
2049
2489
  const isWeb = platformType === "in-app-browser" /* MetaMaskMobileWebview */ || platformType === "web-desktop" /* DesktopWeb */;
2050
- const { preferExtension = true, preferDesktop = false } = ui;
2490
+ const { preferExtension = true, showInstallModal = false } = ui;
2051
2491
  const secure = isSecure();
2052
2492
  const hasExtensionInstalled = yield hasExtension();
2053
- if (((_a = this.__transport) == null ? void 0 : _a.isConnected()) && !secure) {
2493
+ let transportType;
2494
+ if (platformType === "in-app-browser" /* MetaMaskMobileWebview */ || isWeb && hasExtensionInstalled && preferExtension) {
2495
+ transportType = "browser" /* Browser */;
2496
+ } else {
2497
+ transportType = "mwp" /* MWP */;
2498
+ }
2499
+ if ((_a = this.options.analytics) == null ? void 0 : _a.enabled) {
2500
+ try {
2501
+ const baseProps = yield getBaseAnalyticsProperties(
2502
+ this.options,
2503
+ this.storage
2504
+ );
2505
+ const dappConfiguredChains = Object.keys(
2506
+ this.options.api.supportedNetworks
2507
+ );
2508
+ analytics2.track("mmconnect_connection_initiated", __spreadProps(__spreadValues({}, baseProps), {
2509
+ transport_type: transportType,
2510
+ dapp_configured_chains: dappConfiguredChains,
2511
+ dapp_requested_chains: scopes
2512
+ }));
2513
+ } catch (error) {
2514
+ logger2("Error tracking connection_initiated event", error);
2515
+ }
2516
+ }
2517
+ if (((_b = this.__transport) == null ? void 0 : _b.isConnected()) && !secure) {
2054
2518
  return this.handleConnection(
2055
- this.__transport.connect({ scopes, caipAccountIds }).then(() => {
2519
+ this.__transport.connect({ scopes, caipAccountIds, forceRequest }).then(() => {
2056
2520
  if (this.__transport instanceof MWPTransport) {
2057
- return this.storage.setTransport("mwp" /* MPW */);
2521
+ return this.storage.setTransport("mwp" /* MWP */);
2058
2522
  } else {
2059
2523
  return this.storage.setTransport("browser" /* Browser */);
2060
2524
  }
2061
- })
2525
+ }),
2526
+ scopes,
2527
+ transportType
2528
+ );
2529
+ }
2530
+ if (platformType === "in-app-browser" /* MetaMaskMobileWebview */) {
2531
+ const defaultTransport = yield this.setupDefaultTransport();
2532
+ return this.handleConnection(
2533
+ defaultTransport.connect({ scopes, caipAccountIds, forceRequest }),
2534
+ scopes,
2535
+ transportType
2062
2536
  );
2063
2537
  }
2064
2538
  if (isWeb && hasExtensionInstalled && preferExtension) {
2065
2539
  const defaultTransport = yield this.setupDefaultTransport();
2066
2540
  return this.handleConnection(
2067
- defaultTransport.connect({ scopes, caipAccountIds })
2541
+ defaultTransport.connect({ scopes, caipAccountIds, forceRequest }),
2542
+ scopes,
2543
+ transportType
2068
2544
  );
2069
2545
  }
2070
2546
  yield this.setupMWP();
2071
- const isDesktopPreferred = hasExtensionInstalled ? preferDesktop : !preferExtension || preferDesktop;
2072
- if (secure && !isDesktopPreferred) {
2547
+ const shouldShowInstallModal = hasExtensionInstalled ? showInstallModal : !preferExtension || showInstallModal;
2548
+ if (secure && !shouldShowInstallModal) {
2073
2549
  return this.handleConnection(
2074
- this.deeplinkConnect(scopes, caipAccountIds)
2550
+ this.deeplinkConnect(scopes, caipAccountIds),
2551
+ scopes,
2552
+ transportType
2075
2553
  );
2076
2554
  }
2077
2555
  return this.handleConnection(
2078
- this.showInstallModal(isDesktopPreferred, scopes, caipAccountIds)
2556
+ this.showInstallModal(shouldShowInstallModal, scopes, caipAccountIds),
2557
+ scopes,
2558
+ transportType
2079
2559
  );
2080
2560
  });
2081
2561
  }
@@ -2110,6 +2590,26 @@ var MultichainSDK = class _MultichainSDK extends MultichainCore {
2110
2590
  return requestRouter.invokeMethod(request);
2111
2591
  });
2112
2592
  }
2593
+ // DRY THIS WITH REQUEST ROUTER
2594
+ openDeeplinkIfNeeded() {
2595
+ const { ui, mobile } = this.options;
2596
+ const { showInstallModal = false } = ui != null ? ui : {};
2597
+ const secure = isSecure();
2598
+ const shouldOpenDeeplink = secure && !showInstallModal;
2599
+ if (shouldOpenDeeplink) {
2600
+ setTimeout(() => {
2601
+ if (mobile == null ? void 0 : mobile.preferredOpenLink) {
2602
+ mobile.preferredOpenLink(METAMASK_DEEPLINK_BASE, "_self");
2603
+ } else {
2604
+ openDeeplink(
2605
+ this.options,
2606
+ METAMASK_DEEPLINK_BASE,
2607
+ METAMASK_CONNECT_BASE_URL
2608
+ );
2609
+ }
2610
+ }, 10);
2611
+ }
2612
+ }
2113
2613
  };
2114
2614
 
2115
2615
  // src/store/index.ts
@@ -2308,25 +2808,34 @@ function preloadQR() {
2308
2808
  }
2309
2809
 
2310
2810
  // src/ui/index.ts
2811
+ init_utils();
2311
2812
  var __instance;
2312
2813
  function preload() {
2313
2814
  return __async(this, null, function* () {
2314
- __instance != null ? __instance : __instance = yield import(
2315
- // Use a non-literal specifier to avoid Vite static analysis of deep imports
2316
- // and gracefully handle absence of the Stencil loader in this package build.
2317
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2318
- // @ts-ignore
2319
- "@metamask/multichain-ui".concat("/dist/loader/index.js")
2320
- // Prefer ESM loader in browsers
2321
- ).then((loader) => __async(null, null, function* () {
2322
- if (typeof (loader == null ? void 0 : loader.defineCustomElements) === "function") {
2323
- loader.defineCustomElements();
2324
- }
2325
- return Promise.resolve(loader);
2326
- })).catch((error) => __async(null, null, function* () {
2327
- console.error(`Gracefully Failed to load modal customElements:`, error);
2328
- return Promise.resolve(void 0);
2329
- }));
2815
+ if (false) {
2816
+ __instance != null ? __instance : __instance = yield null.then((loader) => __async(null, null, function* () {
2817
+ if (typeof (loader == null ? void 0 : loader.defineCustomElements) === "function") {
2818
+ loader.defineCustomElements();
2819
+ }
2820
+ return Promise.resolve(loader);
2821
+ })).catch((error) => __async(null, null, function* () {
2822
+ console.error(`Gracefully Failed to load modal customElements:`, error);
2823
+ return Promise.resolve(void 0);
2824
+ }));
2825
+ } else {
2826
+ const dynamicImport = (0, eval)("import");
2827
+ __instance != null ? __instance : __instance = yield dynamicImport(
2828
+ "@metamask/multichain-ui/dist/loader/index.js"
2829
+ ).then((loader) => __async(null, null, function* () {
2830
+ if (typeof (loader == null ? void 0 : loader.defineCustomElements) === "function") {
2831
+ loader.defineCustomElements();
2832
+ }
2833
+ return Promise.resolve(loader);
2834
+ })).catch((error) => __async(null, null, function* () {
2835
+ console.error(`Gracefully Failed to load modal customElements:`, error);
2836
+ return Promise.resolve(void 0);
2837
+ }));
2838
+ }
2330
2839
  });
2331
2840
  }
2332
2841
  var ModalFactory = class {
@@ -2418,7 +2927,7 @@ var ModalFactory = class {
2418
2927
  onStartDesktopOnboarding() {
2419
2928
  new MetaMaskOnboarding().startOnboarding();
2420
2929
  }
2421
- renderInstallModal(preferDesktop, createConnectionRequest, successCallback) {
2930
+ renderInstallModal(showInstallModal, createConnectionRequest, successCallback) {
2422
2931
  return __async(this, null, function* () {
2423
2932
  var _a;
2424
2933
  (_a = this.modal) == null ? void 0 : _a.unmount();
@@ -2431,7 +2940,7 @@ var ModalFactory = class {
2431
2940
  expiresIn: (connectionRequest.sessionRequest.expiresAt - Date.now()) / 1e3,
2432
2941
  connectionRequest,
2433
2942
  parentElement,
2434
- preferDesktop,
2943
+ showInstallModal,
2435
2944
  link: qrCodeLink,
2436
2945
  sdkVersion: getVersion(),
2437
2946
  generateQRCode: (request) => __async(this, null, function* () {
@@ -2508,10 +3017,12 @@ export {
2508
3017
  getPlatformType,
2509
3018
  getTransportType,
2510
3019
  getVersion,
3020
+ getWalletActionAnalyticsProperties,
2511
3021
  hasExtension,
2512
3022
  infuraRpcUrls,
2513
3023
  isEnabled,
2514
3024
  isMetamaskExtensionInstalled,
3025
+ isRejectionError,
2515
3026
  isSecure
2516
3027
  };
2517
3028
  //# sourceMappingURL=connect-multichain.mjs.map