@metamask/connect-multichain 0.12.1 → 0.14.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.
Files changed (55) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/dist/browser/es/connect-multichain.d.mts +46 -2
  3. package/dist/browser/es/connect-multichain.mjs +1733 -1566
  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 +46 -2
  7. package/dist/browser/iife/connect-multichain.js +6279 -5413
  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 +46 -2
  11. package/dist/browser/umd/connect-multichain.js +1761 -1589
  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 +46 -2
  15. package/dist/node/cjs/connect-multichain.js +892 -719
  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 +46 -2
  19. package/dist/node/es/connect-multichain.mjs +890 -723
  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 +46 -2
  23. package/dist/react-native/es/connect-multichain.mjs +890 -723
  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/multichain/index.d.ts +1 -1
  27. package/dist/src/domain/multichain/index.d.ts.map +1 -1
  28. package/dist/src/domain/utils/index.d.ts +2 -1
  29. package/dist/src/domain/utils/index.d.ts.map +1 -1
  30. package/dist/src/domain/utils/index.js +1 -1
  31. package/dist/src/domain/utils/index.js.map +1 -1
  32. package/dist/src/multichain/index.d.ts +2 -2
  33. package/dist/src/multichain/index.d.ts.map +1 -1
  34. package/dist/src/multichain/index.js +39 -25
  35. package/dist/src/multichain/index.js.map +1 -1
  36. package/dist/src/multichain/rpc/requestRouter.d.ts.map +1 -1
  37. package/dist/src/multichain/rpc/requestRouter.js +4 -4
  38. package/dist/src/multichain/rpc/requestRouter.js.map +1 -1
  39. package/dist/src/multichain/transports/multichainApiClientWrapper/index.d.ts +1 -0
  40. package/dist/src/multichain/transports/multichainApiClientWrapper/index.d.ts.map +1 -1
  41. package/dist/src/multichain/transports/multichainApiClientWrapper/index.js +10 -10
  42. package/dist/src/multichain/transports/multichainApiClientWrapper/index.js.map +1 -1
  43. package/dist/src/multichain/transports/mwp/KeyManager.d.ts +12 -9
  44. package/dist/src/multichain/transports/mwp/KeyManager.d.ts.map +1 -1
  45. package/dist/src/multichain/transports/mwp/KeyManager.js +38 -25
  46. package/dist/src/multichain/transports/mwp/KeyManager.js.map +1 -1
  47. package/dist/src/multichain/transports/mwp/index.d.ts.map +1 -1
  48. package/dist/src/multichain/transports/mwp/index.js +18 -6
  49. package/dist/src/multichain/transports/mwp/index.js.map +1 -1
  50. package/dist/src/multichain/utils/analytics.d.ts +82 -1
  51. package/dist/src/multichain/utils/analytics.d.ts.map +1 -1
  52. package/dist/src/multichain/utils/analytics.js +252 -17
  53. package/dist/src/multichain/utils/analytics.js.map +1 -1
  54. package/dist/types/connect-multichain.d.ts +46 -2
  55. package/package.json +2 -2
@@ -679,17 +679,94 @@ var init_ui = __esm({
679
679
  });
680
680
 
681
681
  // src/multichain/utils/analytics.ts
682
+ function sanitiseErrorMessage(message) {
683
+ if (!message) {
684
+ return void 0;
685
+ }
686
+ let sanitised = message;
687
+ for (const { pattern, replacement } of SANITISE_PATTERNS) {
688
+ sanitised = sanitised.replace(pattern, replacement);
689
+ }
690
+ if (sanitised.length > ERROR_MESSAGE_SAMPLE_MAX_LENGTH) {
691
+ sanitised = `${sanitised.slice(0, ERROR_MESSAGE_SAMPLE_MAX_LENGTH - 1)}\u2026`;
692
+ }
693
+ return sanitised;
694
+ }
695
+ function getUnwrappedErrorDetails(error) {
696
+ var _a3, _b, _c, _d;
697
+ if (typeof error !== "object" || error === null) {
698
+ return { code: void 0, message: "" };
699
+ }
700
+ if (error instanceof RPCInvokeMethodErr) {
701
+ return {
702
+ code: (_a3 = error.rpcCode) != null ? _a3 : error.code,
703
+ message: (_c = (_b = error.rpcMessage) != null ? _b : error.message) != null ? _c : ""
704
+ };
705
+ }
706
+ const errorObj = error;
707
+ return {
708
+ code: errorObj.code,
709
+ message: (_d = errorObj.message) != null ? _d : ""
710
+ };
711
+ }
682
712
  function isRejectionError(error) {
683
- var _a3, _b;
684
713
  if (typeof error !== "object" || error === null) {
685
714
  return false;
686
715
  }
716
+ const { code, message } = getUnwrappedErrorDetails(error);
717
+ const errorMessage = message.toLowerCase();
718
+ return code === 4001 || errorMessage.includes("reject") || errorMessage.includes("denied") || errorMessage.includes("cancel") || // Narrow "user …" matches — bare "user" is too greedy (catches Account
719
+ // Abstraction errors like "user operation reverted").
720
+ errorMessage.includes("user rejected") || errorMessage.includes("user denied") || errorMessage.includes("user cancelled") || errorMessage.includes("user canceled");
721
+ }
722
+ function classifyFailureReason(error) {
723
+ var _a3, _b;
724
+ if (typeof error !== "object" || error === null) {
725
+ return "unknown";
726
+ }
687
727
  const errorObj = error;
688
- const errorCode = errorObj.code;
689
- const errorMessage = (_b = (_a3 = errorObj.message) == null ? void 0 : _a3.toLowerCase()) != null ? _b : "";
690
- return errorCode === 4001 || // User rejected request (common EIP-1193 code)
691
- errorCode === 4100 || // Unauthorized (common rejection code)
692
- errorMessage.includes("reject") || errorMessage.includes("denied") || errorMessage.includes("cancel") || errorMessage.includes("user");
728
+ const errorName = (_a3 = errorObj.name) != null ? _a3 : "";
729
+ const errorMessageRaw = (_b = errorObj.message) != null ? _b : "";
730
+ const errorMessage = errorMessageRaw.toLowerCase();
731
+ const { code } = getUnwrappedErrorDetails(error);
732
+ if (typeof code === "number") {
733
+ if (code === -32601) {
734
+ return "wallet_method_unsupported";
735
+ }
736
+ if (code === -32602) {
737
+ return "wallet_invalid_params";
738
+ }
739
+ if (code === -32603) {
740
+ return "wallet_internal_error";
741
+ }
742
+ if (code <= -32e3 && code >= -32099) {
743
+ return "wallet_internal_error";
744
+ }
745
+ if (code === 4100) {
746
+ return "wallet_unauthorized";
747
+ }
748
+ if (code === 4200) {
749
+ return "wallet_method_unsupported";
750
+ }
751
+ if (code === 4902) {
752
+ return "unrecognized_chain";
753
+ }
754
+ }
755
+ if (errorName === "TransportTimeoutError" || errorMessageRaw === "Request timeout" || errorMessage.includes("timed out") || errorMessage.includes("timeout")) {
756
+ return "transport_timeout";
757
+ }
758
+ if (errorName === "TransportError" || errorMessage.includes("not connected") || errorMessage.includes("transport disconnect") || errorMessage.includes("connection lost") || errorMessage.includes("socket closed")) {
759
+ return "transport_disconnect";
760
+ }
761
+ return "unknown";
762
+ }
763
+ function extractErrorDiagnostics(error) {
764
+ const failureReason = classifyFailureReason(error);
765
+ const { code, message } = getUnwrappedErrorDetails(error);
766
+ const messageSample = sanitiseErrorMessage(message);
767
+ return __spreadValues(__spreadValues({
768
+ failure_reason: failureReason
769
+ }, typeof code === "number" ? { error_code: code } : {}), messageSample ? { error_message_sample: messageSample } : {});
693
770
  }
694
771
  function getBaseAnalyticsProperties(options, storage) {
695
772
  return __async(this, null, function* () {
@@ -705,26 +782,61 @@ function getBaseAnalyticsProperties(options, storage) {
705
782
  };
706
783
  });
707
784
  }
708
- function getWalletActionAnalyticsProperties(options, storage, invokeOptions, transportType) {
785
+ function getWalletActionAnalyticsProperties(options, storage, invokeOptions, transportType, extra) {
709
786
  return __async(this, null, function* () {
710
787
  var _a3;
711
788
  const dappId = getDappId(options.dapp);
712
789
  const anonId = yield storage.getAnonId();
713
- return {
790
+ return __spreadValues(__spreadValues(__spreadValues({
714
791
  mmconnect_versions: (_a3 = options.versions) != null ? _a3 : {},
715
792
  dapp_id: dappId,
716
793
  method: invokeOptions.request.method,
717
794
  caip_chain_id: invokeOptions.scope,
718
795
  anon_id: anonId,
719
796
  transport_type: transportType
720
- };
797
+ }, (extra == null ? void 0 : extra.failure_reason) ? { failure_reason: extra.failure_reason } : {}), typeof (extra == null ? void 0 : extra.error_code) === "number" ? { error_code: extra.error_code } : {}), (extra == null ? void 0 : extra.error_message_sample) ? { error_message_sample: extra.error_message_sample } : {});
721
798
  });
722
799
  }
800
+ var ERROR_MESSAGE_SAMPLE_MAX_LENGTH, SANITISE_PATTERNS;
723
801
  var init_analytics = __esm({
724
802
  "src/multichain/utils/analytics.ts"() {
725
803
  "use strict";
726
804
  init_utils2();
727
805
  init_domain();
806
+ ERROR_MESSAGE_SAMPLE_MAX_LENGTH = 200;
807
+ SANITISE_PATTERNS = [
808
+ // EVM-style 20-byte hex addresses (e.g. `0x` + 40 hex chars).
809
+ { pattern: /0x[a-fA-F0-9]{40}/gu, replacement: "<addr>" },
810
+ // Other long hex blobs: tx hashes, signatures, raw byte strings, large
811
+ // hex amounts. 16+ hex chars catches 32-byte hashes/signatures without
812
+ // snagging EVM method selectors (8 chars) or short hex codes.
813
+ { pattern: /(?:0x)?[a-fA-F0-9]{16,}/gu, replacement: "<hex>" },
814
+ // URLs of any scheme up to the first whitespace / quote / closing paren.
815
+ // Catches RPC endpoints, dapp deeplinks, query strings with secrets.
816
+ { pattern: /https?:\/\/[^\s"')]+/gu, replacement: "<url>" },
817
+ // Bech32 addresses: short HRP (1-10 lowercase chars) + `1` separator +
818
+ // ≥38 chars of Bech32 data alphabet `[ac-hj-np-z02-9]` (excludes the
819
+ // look-alike chars `b`, `i`, `o`, `1`). Covers Bitcoin SegWit
820
+ // (`bc1…`/`tb1…`) and Cosmos-SDK chains (`cosmos1…`, `osmo1…`,
821
+ // `juno1…`, `inj1…`, etc.) without enumerating every HRP. Runs before
822
+ // the Base58 pattern below — see header comment for why.
823
+ {
824
+ pattern: /\b[a-z]{1,10}1[ac-hj-np-z02-9]{38,}\b/gu,
825
+ replacement: "<addr>"
826
+ },
827
+ // Base58 tokens (32+ chars, Base58 alphabet `[1-9A-HJ-NP-Za-km-z]`).
828
+ // Covers Solana pubkeys (32-44 chars), Solana tx signatures (~88 chars),
829
+ // and Bitcoin Base58 addresses ≥32 chars. The 32-char floor and `\b`
830
+ // word boundary keep English words and shorter alphanumerics safe.
831
+ {
832
+ pattern: /\b[1-9A-HJ-NP-Za-km-z]{32,}\b/gu,
833
+ replacement: "<addr>"
834
+ },
835
+ // Long decimal numbers — token amounts, gas units, timestamps, lamports.
836
+ // 10+ digits catches typical chain quantities without affecting JSON-RPC
837
+ // codes (-32601, 4001, etc.) or short numeric IDs.
838
+ { pattern: /\d{10,}/gu, replacement: "<num>" }
839
+ ];
728
840
  }
729
841
  });
730
842
 
@@ -1024,1723 +1136,1754 @@ var init_utils2 = __esm({
1024
1136
  }
1025
1137
  });
1026
1138
 
1027
- // src/ui/modals/base/utils.ts
1028
- function formatRemainingTime(milliseconds) {
1029
- if (milliseconds <= 0) {
1030
- return "EXPIRED";
1031
- }
1032
- const seconds = Math.floor(milliseconds / 1e3);
1033
- return `${seconds}s`;
1034
- }
1035
- function shouldLogCountdown(remainingSeconds) {
1036
- if (remainingSeconds <= 10) {
1037
- return true;
1038
- } else if (remainingSeconds <= 30) {
1039
- return remainingSeconds % 5 === 0;
1040
- } else if (remainingSeconds <= 60) {
1041
- return remainingSeconds % 10 === 0;
1042
- } else if (remainingSeconds <= 300) {
1043
- return remainingSeconds % 30 === 0;
1044
- }
1045
- return remainingSeconds % 60 === 0;
1046
- }
1047
- var init_utils3 = __esm({
1048
- "src/ui/modals/base/utils.ts"() {
1139
+ // src/multichain/transports/constants.ts
1140
+ var MULTICHAIN_PROVIDER_STREAM_NAME;
1141
+ var init_constants2 = __esm({
1142
+ "src/multichain/transports/constants.ts"() {
1049
1143
  "use strict";
1144
+ MULTICHAIN_PROVIDER_STREAM_NAME = "metamask-multichain-provider";
1050
1145
  }
1051
1146
  });
1052
1147
 
1053
- // src/ui/modals/base/AbstractInstallModal.ts
1054
- var logger3, _expirationInterval, _lastLoggedCountdown, AbstractInstallModal;
1055
- var init_AbstractInstallModal = __esm({
1056
- "src/ui/modals/base/AbstractInstallModal.ts"() {
1148
+ // src/multichain/transports/mwp/index.ts
1149
+ var mwp_exports = {};
1150
+ __export(mwp_exports, {
1151
+ MWPTransport: () => MWPTransport
1152
+ });
1153
+ import {
1154
+ TransportTimeoutError
1155
+ } from "@metamask/multichain-api-client";
1156
+ import { JsonRpcError, providerErrors as providerErrors2, rpcErrors } from "@metamask/rpc-errors";
1157
+ var DEFAULT_REQUEST_TIMEOUT2, CONNECTION_GRACE_PERIOD, DEFAULT_CONNECTION_TIMEOUT, DEFAULT_RESUME_TIMEOUT, SESSION_STORE_KEY, ACCOUNTS_STORE_KEY, CHAIN_STORE_KEY, PENDING_SESSION_REQUEST_KEY, CACHED_METHOD_LIST, CACHED_RESET_METHOD_LIST, logger, MWPTransport;
1158
+ var init_mwp = __esm({
1159
+ "src/multichain/transports/mwp/index.ts"() {
1057
1160
  "use strict";
1058
- init_utils3();
1059
1161
  init_domain();
1060
- logger3 = createLogger("metamask-sdk:ui");
1061
- AbstractInstallModal = class extends Modal {
1062
- constructor() {
1063
- super(...arguments);
1064
- __privateAdd(this, _expirationInterval, null);
1065
- __privateAdd(this, _lastLoggedCountdown, -1);
1162
+ init_utils2();
1163
+ init_constants2();
1164
+ DEFAULT_REQUEST_TIMEOUT2 = 60 * 1e3;
1165
+ CONNECTION_GRACE_PERIOD = 60 * 1e3;
1166
+ DEFAULT_CONNECTION_TIMEOUT = DEFAULT_REQUEST_TIMEOUT2 + CONNECTION_GRACE_PERIOD;
1167
+ DEFAULT_RESUME_TIMEOUT = 10 * 1e3;
1168
+ SESSION_STORE_KEY = "cache_wallet_getSession";
1169
+ ACCOUNTS_STORE_KEY = "cache_eth_accounts";
1170
+ CHAIN_STORE_KEY = "cache_eth_chainId";
1171
+ PENDING_SESSION_REQUEST_KEY = "pending_session_request";
1172
+ CACHED_METHOD_LIST = [
1173
+ "wallet_getSession",
1174
+ "wallet_createSession",
1175
+ "wallet_sessionChanged"
1176
+ ];
1177
+ CACHED_RESET_METHOD_LIST = [
1178
+ "wallet_revokeSession",
1179
+ "wallet_revokePermissions"
1180
+ ];
1181
+ logger = createLogger("metamask-sdk:transport");
1182
+ MWPTransport = class {
1183
+ constructor(dappClient, kvstore, options = {
1184
+ requestTimeout: DEFAULT_REQUEST_TIMEOUT2,
1185
+ connectionTimeout: DEFAULT_CONNECTION_TIMEOUT,
1186
+ resumeTimeout: DEFAULT_RESUME_TIMEOUT
1187
+ }) {
1188
+ this.dappClient = dappClient;
1189
+ this.kvstore = kvstore;
1190
+ this.options = options;
1191
+ this.__pendingRequests = /* @__PURE__ */ new Map();
1192
+ this.notificationCallbacks = /* @__PURE__ */ new Set();
1193
+ this.dappClient.on("message", this.handleMessage.bind(this));
1194
+ this.dappClient.on("session_request", (sessionRequest) => {
1195
+ this.currentSessionRequest = sessionRequest;
1196
+ this.kvstore.set(PENDING_SESSION_REQUEST_KEY, JSON.stringify(sessionRequest)).catch((err) => {
1197
+ logger("Failed to store pending session request", err);
1198
+ });
1199
+ });
1200
+ if (typeof window !== "undefined" && typeof window.addEventListener !== "undefined") {
1201
+ this.windowFocusHandler = this.onWindowFocus.bind(this);
1202
+ window.addEventListener("focus", this.windowFocusHandler);
1203
+ }
1066
1204
  }
1067
- get link() {
1068
- return this.data;
1205
+ get pendingRequests() {
1206
+ return this.__pendingRequests;
1069
1207
  }
1070
- set link(link) {
1071
- this.data = link;
1208
+ set pendingRequests(pendingRequests) {
1209
+ this.__pendingRequests = pendingRequests;
1072
1210
  }
1073
- get connectionRequest() {
1074
- return this.options.connectionRequest;
1211
+ get sessionRequest() {
1212
+ return this.currentSessionRequest;
1075
1213
  }
1076
- set connectionRequest(connectionRequest) {
1077
- this.options.connectionRequest = connectionRequest;
1214
+ /**
1215
+ * Returns the stored pending session request from the dappClient session_request event, if any.
1216
+ *
1217
+ * @returns The stored SessionRequest, or null if none or invalid.
1218
+ */
1219
+ getStoredPendingSessionRequest() {
1220
+ return __async(this, null, function* () {
1221
+ try {
1222
+ const raw = yield this.kvstore.get(PENDING_SESSION_REQUEST_KEY);
1223
+ if (!raw) {
1224
+ return null;
1225
+ }
1226
+ return JSON.parse(raw);
1227
+ } catch (e) {
1228
+ return null;
1229
+ }
1230
+ });
1078
1231
  }
1079
- updateLink(link) {
1080
- this.link = link;
1081
- if (this.instance) {
1082
- this.instance.link = link;
1232
+ /**
1233
+ * Removes the stored pending session request from the KVStore.
1234
+ * This is necessary to ensure that ConnectMultichain is able to correctly
1235
+ * infer the MWP Transport connection attempt status.
1236
+ */
1237
+ removeStoredPendingSessionRequest() {
1238
+ return __async(this, null, function* () {
1239
+ yield this.kvstore.delete(PENDING_SESSION_REQUEST_KEY);
1240
+ });
1241
+ }
1242
+ onWindowFocus() {
1243
+ if (!this.isConnected()) {
1244
+ this.dappClient.reconnect();
1083
1245
  }
1084
1246
  }
1085
- updateExpiresIn(expiresIn) {
1086
- if (expiresIn >= 0 && this.instance) {
1087
- this.instance.expiresIn = expiresIn;
1247
+ notifyCallbacks(data) {
1248
+ this.notificationCallbacks.forEach((callback) => callback(data));
1249
+ }
1250
+ rejectRequest(id, error = new Error("Request rejected")) {
1251
+ const request = this.pendingRequests.get(id);
1252
+ if (request) {
1253
+ this.pendingRequests.delete(id);
1254
+ clearTimeout(request.timeout);
1255
+ request.reject(error);
1088
1256
  }
1089
1257
  }
1090
- startExpirationCheck(connectionRequest) {
1091
- this.stopExpirationCheck();
1092
- let currentConnectionRequest = connectionRequest;
1093
- __privateSet(this, _expirationInterval, setInterval(() => __async(this, null, function* () {
1094
- const { sessionRequest } = currentConnectionRequest;
1095
- const now = Date.now();
1096
- const remainingMs = sessionRequest.expiresAt - now;
1097
- const remainingSeconds = Math.floor(remainingMs / 1e3);
1098
- if (remainingMs > 0 && shouldLogCountdown(remainingSeconds) && __privateGet(this, _lastLoggedCountdown) !== remainingSeconds) {
1099
- const formattedTime = formatRemainingTime(remainingMs);
1100
- logger3(
1101
- `[UI: InstallModal-nodejs()] QR code expires in: ${formattedTime} (${remainingSeconds}s)`
1102
- );
1103
- __privateSet(this, _lastLoggedCountdown, remainingSeconds);
1258
+ parseWalletError(errorPayload) {
1259
+ const errorData = errorPayload;
1260
+ if (typeof errorData.code === "number" && typeof errorData.message === "string") {
1261
+ const { code, message: message2 } = errorData;
1262
+ if (code >= 1e3 && code <= 4999) {
1263
+ return providerErrors2.custom({ code, message: message2 });
1104
1264
  }
1105
- if (now >= sessionRequest.expiresAt) {
1106
- this.stopExpirationCheck();
1107
- logger3(
1108
- "[UI: InstallModal-nodejs()] \u23F0 QR code EXPIRED! Generating new one..."
1109
- );
1110
- try {
1111
- currentConnectionRequest = yield this.options.createConnectionRequest();
1112
- const generateQRCode = yield this.options.generateQRCode(
1113
- currentConnectionRequest
1265
+ return new JsonRpcError(code, message2);
1266
+ }
1267
+ const message = errorPayload instanceof Error ? errorPayload.message : JSON.stringify(errorPayload);
1268
+ return rpcErrors.internal({ message });
1269
+ }
1270
+ handleMessage(message) {
1271
+ if (typeof message === "object" && message !== null) {
1272
+ if ("data" in message) {
1273
+ const messagePayload = message.data;
1274
+ if ("id" in messagePayload && typeof messagePayload.id === "string") {
1275
+ const request = this.pendingRequests.get(messagePayload.id);
1276
+ if (request) {
1277
+ clearTimeout(request.timeout);
1278
+ if ("error" in messagePayload && messagePayload.error) {
1279
+ this.pendingRequests.delete(messagePayload.id);
1280
+ request.reject(this.parseWalletError(messagePayload.error));
1281
+ return;
1282
+ }
1283
+ const requestWithName = __spreadProps(__spreadValues({}, messagePayload), {
1284
+ method: request.method === "wallet_getSession" || request.method === "wallet_createSession" ? "wallet_sessionChanged" : request.method
1285
+ });
1286
+ const notification = __spreadProps(__spreadValues({}, messagePayload), {
1287
+ method: request.method === "wallet_getSession" || request.method === "wallet_createSession" ? "wallet_sessionChanged" : request.method,
1288
+ params: requestWithName.result
1289
+ });
1290
+ this.notifyCallbacks(notification);
1291
+ request.resolve(requestWithName);
1292
+ this.pendingRequests.delete(messagePayload.id);
1293
+ }
1294
+ } else {
1295
+ if (message.data.method === "metamask_chainChanged") {
1296
+ this.kvstore.set(
1297
+ CHAIN_STORE_KEY,
1298
+ JSON.stringify(
1299
+ message.data.params.chainId
1300
+ )
1301
+ );
1302
+ }
1303
+ if (message.data.method === "metamask_accountsChanged") {
1304
+ this.kvstore.set(
1305
+ ACCOUNTS_STORE_KEY,
1306
+ JSON.stringify(
1307
+ message.data.params
1308
+ )
1309
+ );
1310
+ }
1311
+ if (message.data.method === "wallet_sessionChanged") {
1312
+ const notification = message.data;
1313
+ const response = {
1314
+ result: notification.params
1315
+ };
1316
+ this.kvstore.set(SESSION_STORE_KEY, JSON.stringify(response));
1317
+ }
1318
+ this.notifyCallbacks(message.data);
1319
+ }
1320
+ }
1321
+ }
1322
+ }
1323
+ onResumeSuccess(resumeResolve, resumeReject, options) {
1324
+ return __async(this, null, function* () {
1325
+ var _a3, _b, _c, _d, _e, _f, _g;
1326
+ try {
1327
+ yield this.waitForWalletSessionIfNotCached();
1328
+ const sessionRequest = yield this.request({
1329
+ method: "wallet_getSession"
1330
+ });
1331
+ if (sessionRequest.error) {
1332
+ return resumeReject(new Error(sessionRequest.error.message));
1333
+ }
1334
+ let walletSession = sessionRequest.result;
1335
+ if (walletSession && options) {
1336
+ const currentScopes = Object.keys(
1337
+ (_a3 = walletSession == null ? void 0 : walletSession.sessionScopes) != null ? _a3 : {}
1114
1338
  );
1115
- __privateSet(this, _lastLoggedCountdown, -1);
1116
- this.updateLink(generateQRCode);
1117
- this.updateExpiresIn(remainingSeconds);
1118
- this.renderQRCode(generateQRCode, currentConnectionRequest);
1119
- } catch (error) {
1120
- logger3(
1121
- `[UI: InstallModal-nodejs()] \u274C Error generating new QR code: ${error}`
1339
+ const proposedScopes = (_b = options == null ? void 0 : options.scopes) != null ? _b : [];
1340
+ const proposedCaipAccountIds = (_c = options == null ? void 0 : options.caipAccountIds) != null ? _c : [];
1341
+ const hasSameScopesAndAccounts = isSameScopesAndAccounts(
1342
+ currentScopes,
1343
+ proposedScopes,
1344
+ walletSession,
1345
+ proposedCaipAccountIds
1346
+ );
1347
+ if (options.forceRequest || !hasSameScopesAndAccounts) {
1348
+ const optionalScopes = addValidAccounts(
1349
+ getOptionalScopes((_d = options == null ? void 0 : options.scopes) != null ? _d : []),
1350
+ getValidAccounts((_e = options == null ? void 0 : options.caipAccountIds) != null ? _e : [])
1351
+ );
1352
+ const sessionRequest2 = {
1353
+ optionalScopes
1354
+ };
1355
+ const response = yield this.request({
1356
+ method: "wallet_createSession",
1357
+ params: sessionRequest2
1358
+ });
1359
+ if (response.error) {
1360
+ return resumeReject(new Error(response.error.message));
1361
+ }
1362
+ walletSession = response.result;
1363
+ }
1364
+ } else if (!walletSession) {
1365
+ const optionalScopes = addValidAccounts(
1366
+ getOptionalScopes((_f = options == null ? void 0 : options.scopes) != null ? _f : []),
1367
+ getValidAccounts((_g = options == null ? void 0 : options.caipAccountIds) != null ? _g : [])
1122
1368
  );
1369
+ const sessionRequest2 = { optionalScopes };
1370
+ const response = yield this.request({
1371
+ method: "wallet_createSession",
1372
+ params: sessionRequest2
1373
+ });
1374
+ if (response.error) {
1375
+ return resumeReject(new Error(response.error.message));
1376
+ }
1377
+ walletSession = response.result;
1123
1378
  }
1379
+ yield this.removeStoredPendingSessionRequest();
1380
+ this.notifyCallbacks({
1381
+ method: "wallet_sessionChanged",
1382
+ params: walletSession
1383
+ });
1384
+ return resumeResolve();
1385
+ } catch (err) {
1386
+ return resumeReject(err);
1124
1387
  }
1125
- }), 1e3));
1126
- }
1127
- stopExpirationCheck() {
1128
- if (__privateGet(this, _expirationInterval)) {
1129
- clearInterval(__privateGet(this, _expirationInterval));
1130
- __privateSet(this, _expirationInterval, null);
1131
- logger3(
1132
- "[UI: InstallModal-nodejs()] \u{1F6D1} Stopped QR code expiration checking"
1133
- );
1134
- }
1388
+ });
1135
1389
  }
1136
- };
1137
- _expirationInterval = new WeakMap();
1138
- _lastLoggedCountdown = new WeakMap();
1139
- }
1140
- });
1141
-
1142
- // src/ui/modals/web/install.ts
1143
- var InstallModal;
1144
- var init_install = __esm({
1145
- "src/ui/modals/web/install.ts"() {
1146
- "use strict";
1147
- init_AbstractInstallModal();
1148
- InstallModal = class extends AbstractInstallModal {
1149
- renderQRCode() {
1390
+ init() {
1391
+ return __async(this, null, function* () {
1392
+ });
1150
1393
  }
1151
- mount() {
1152
- var _a3;
1153
- const { options } = this;
1154
- const modal = document.createElement(
1155
- "mm-install-modal"
1156
- );
1157
- modal.showInstallModal = options.showInstallModal;
1158
- modal.addEventListener("close", (ev) => {
1159
- const { detail } = ev;
1160
- options.onClose(detail == null ? void 0 : detail.shouldTerminate);
1394
+ // TODO: Rename this
1395
+ sendEip1193Message(payload, options) {
1396
+ return __async(this, null, function* () {
1397
+ const request = __spreadValues({
1398
+ jsonrpc: "2.0",
1399
+ id: String(getUniqueRequestId())
1400
+ }, payload);
1401
+ const cachedWalletSession = yield this.getCachedResponse(request);
1402
+ if (cachedWalletSession) {
1403
+ this.notifyCallbacks(cachedWalletSession);
1404
+ return cachedWalletSession;
1405
+ }
1406
+ return new Promise((resolve, reject) => {
1407
+ var _a3;
1408
+ const timeout = setTimeout(() => {
1409
+ this.rejectRequest(request.id, new TransportTimeoutError());
1410
+ }, (_a3 = options == null ? void 0 : options.timeout) != null ? _a3 : this.options.requestTimeout);
1411
+ this.pendingRequests.set(request.id, {
1412
+ request,
1413
+ method: request.method,
1414
+ resolve: (response) => __async(this, null, function* () {
1415
+ yield this.storeWalletSession(request, response);
1416
+ return resolve(response);
1417
+ }),
1418
+ reject,
1419
+ timeout
1420
+ });
1421
+ this.dappClient.sendRequest({
1422
+ name: "metamask-provider",
1423
+ data: request
1424
+ }).catch(reject);
1425
+ });
1161
1426
  });
1162
- modal.addEventListener(
1163
- "startDesktopOnboarding",
1164
- options.startDesktopOnboarding
1165
- );
1166
- modal.link = options.link;
1167
- this.instance = modal;
1168
- (_a3 = options.parentElement) == null ? void 0 : _a3.appendChild(modal);
1169
- this.startExpirationCheck(options.connectionRequest);
1170
1427
  }
1171
- unmount() {
1172
- var _a3;
1173
- const { options, instance: modal } = this;
1174
- this.stopExpirationCheck();
1175
- if (modal && ((_a3 = options.parentElement) == null ? void 0 : _a3.contains(modal))) {
1176
- options.parentElement.removeChild(modal);
1177
- this.instance = void 0;
1178
- }
1428
+ connect(options) {
1429
+ return __async(this, null, function* () {
1430
+ const { dappClient } = this;
1431
+ const session = yield this.getActiveSession();
1432
+ if (session) {
1433
+ logger("active session found", {
1434
+ id: session.id,
1435
+ channel: session.channel,
1436
+ expiresAt: session.expiresAt
1437
+ });
1438
+ }
1439
+ const storedSessionRequestBeforeConnectionAttempt = yield this.getStoredPendingSessionRequest();
1440
+ let timeout;
1441
+ let initialConnectionMessageHandler;
1442
+ const connectionPromise = new Promise((resolve, reject) => __async(this, null, function* () {
1443
+ let connection;
1444
+ if (session) {
1445
+ connection = new Promise((resumeResolve, resumeReject) => {
1446
+ var _a3;
1447
+ if (this.dappClient.state === "CONNECTED") {
1448
+ this.onResumeSuccess(resumeResolve, resumeReject, options);
1449
+ } else {
1450
+ this.dappClient.once("connected", () => __async(this, null, function* () {
1451
+ this.onResumeSuccess(resumeResolve, resumeReject, options);
1452
+ }));
1453
+ dappClient.resume((_a3 = session == null ? void 0 : session.id) != null ? _a3 : "");
1454
+ }
1455
+ });
1456
+ } else {
1457
+ connection = new Promise(
1458
+ (resolveConnection, rejectConnection) => {
1459
+ var _a3, _b;
1460
+ const optionalScopes = addValidAccounts(
1461
+ getOptionalScopes((_a3 = options == null ? void 0 : options.scopes) != null ? _a3 : []),
1462
+ getValidAccounts((_b = options == null ? void 0 : options.caipAccountIds) != null ? _b : [])
1463
+ );
1464
+ const sessionRequest = {
1465
+ optionalScopes,
1466
+ sessionProperties: options == null ? void 0 : options.sessionProperties
1467
+ };
1468
+ const request = {
1469
+ jsonrpc: "2.0",
1470
+ id: String(getUniqueRequestId()),
1471
+ method: "wallet_createSession",
1472
+ params: sessionRequest
1473
+ };
1474
+ initialConnectionMessageHandler = (message) => __async(this, null, function* () {
1475
+ if (typeof message !== "object" || message === null) {
1476
+ return;
1477
+ }
1478
+ if (!("data" in message)) {
1479
+ return;
1480
+ }
1481
+ const messagePayload = message.data;
1482
+ const isMatchingId = messagePayload.id === request.id;
1483
+ const isMatchingMethod = messagePayload.method === "wallet_createSession" || messagePayload.method === "wallet_sessionChanged";
1484
+ if (!isMatchingId && !isMatchingMethod) {
1485
+ return;
1486
+ }
1487
+ if (messagePayload.error) {
1488
+ return rejectConnection(
1489
+ this.parseWalletError(messagePayload.error)
1490
+ );
1491
+ }
1492
+ yield this.storeWalletSession(
1493
+ request,
1494
+ messagePayload
1495
+ );
1496
+ yield this.removeStoredPendingSessionRequest();
1497
+ this.notifyCallbacks(messagePayload);
1498
+ return resolveConnection();
1499
+ });
1500
+ this.dappClient.on("message", initialConnectionMessageHandler);
1501
+ const platformType = getPlatformType();
1502
+ const isQRCodeFlow = [
1503
+ "web-desktop" /* DesktopWeb */,
1504
+ "nodejs" /* NonBrowser */
1505
+ ].includes(platformType);
1506
+ const initialPayload = {
1507
+ name: MULTICHAIN_PROVIDER_STREAM_NAME,
1508
+ data: request
1509
+ };
1510
+ dappClient.connect({
1511
+ mode: "trusted",
1512
+ initialPayload: isQRCodeFlow ? void 0 : initialPayload
1513
+ }).then(() => __async(this, null, function* () {
1514
+ if (isQRCodeFlow) {
1515
+ return dappClient.sendRequest(initialPayload);
1516
+ }
1517
+ return void 0;
1518
+ })).catch((error) => {
1519
+ if (initialConnectionMessageHandler) {
1520
+ this.dappClient.off(
1521
+ "message",
1522
+ initialConnectionMessageHandler
1523
+ );
1524
+ }
1525
+ rejectConnection(error);
1526
+ });
1527
+ }
1528
+ );
1529
+ }
1530
+ timeout = setTimeout(
1531
+ () => {
1532
+ reject(new TransportTimeoutError());
1533
+ },
1534
+ storedSessionRequestBeforeConnectionAttempt ? this.options.resumeTimeout : this.options.connectionTimeout
1535
+ );
1536
+ connection.then(resolve).catch(reject);
1537
+ }));
1538
+ return connectionPromise.catch((error) => __async(this, null, function* () {
1539
+ yield this.dappClient.disconnect();
1540
+ throw error;
1541
+ })).finally(() => {
1542
+ if (timeout) {
1543
+ clearTimeout(timeout);
1544
+ }
1545
+ if (initialConnectionMessageHandler) {
1546
+ this.dappClient.off("message", initialConnectionMessageHandler);
1547
+ initialConnectionMessageHandler = void 0;
1548
+ }
1549
+ this.removeStoredPendingSessionRequest();
1550
+ });
1551
+ });
1179
1552
  }
1180
- };
1181
- }
1182
- });
1183
-
1184
- // src/ui/modals/base/AbstractOTPModal.ts
1185
- var AbstractOTPCodeModal;
1186
- var init_AbstractOTPModal = __esm({
1187
- "src/ui/modals/base/AbstractOTPModal.ts"() {
1188
- "use strict";
1189
- init_domain();
1190
- AbstractOTPCodeModal = class extends Modal {
1191
- get otpCode() {
1192
- return this.data;
1193
- }
1194
- set otpCode(code) {
1195
- this.data = code;
1196
- }
1197
- updateOTPCode(code) {
1198
- this.otpCode = code;
1199
- if (this.instance) {
1200
- this.instance.otpCode = code;
1201
- }
1202
- }
1203
- };
1204
- }
1205
- });
1206
-
1207
- // src/ui/modals/web/otp.ts
1208
- var OTPCodeModal;
1209
- var init_otp = __esm({
1210
- "src/ui/modals/web/otp.ts"() {
1211
- "use strict";
1212
- init_AbstractOTPModal();
1213
- OTPCodeModal = class extends AbstractOTPCodeModal {
1214
- mount() {
1553
+ /**
1554
+ * Disconnects from the Mobile Wallet Protocol
1555
+ *
1556
+ * @param [scopes] - The scopes to revoke. If not provided or empty, all scopes will be revoked.
1557
+ * @returns Nothing
1558
+ */
1559
+ disconnect() {
1560
+ return __async(this, arguments, function* (scopes = []) {
1561
+ var _a3, _b;
1562
+ const cachedSession = yield this.getCachedResponse({
1563
+ jsonrpc: "2.0",
1564
+ id: "0",
1565
+ method: "wallet_getSession"
1566
+ });
1567
+ const cachedSessionScopes = (_b = (_a3 = cachedSession == null ? void 0 : cachedSession.result) == null ? void 0 : _a3.sessionScopes) != null ? _b : {};
1568
+ const remainingScopes = scopes.length === 0 ? [] : Object.keys(cachedSessionScopes).filter(
1569
+ (scope) => !scopes.includes(scope)
1570
+ );
1571
+ const newSessionScopes = Object.fromEntries(
1572
+ Object.entries(cachedSessionScopes).filter(
1573
+ ([key]) => remainingScopes.includes(key)
1574
+ )
1575
+ );
1576
+ this.request({ method: "wallet_revokeSession", params: { scopes } }).catch(
1577
+ (err) => {
1578
+ console.error("error revoking session", err);
1579
+ }
1580
+ );
1581
+ const remainingScopesIncludeEip155 = remainingScopes.some(
1582
+ (scope) => scope.includes("eip155")
1583
+ );
1584
+ if (!remainingScopesIncludeEip155) {
1585
+ this.kvstore.delete(ACCOUNTS_STORE_KEY);
1586
+ this.kvstore.delete(CHAIN_STORE_KEY);
1587
+ }
1588
+ if (remainingScopes.length > 0) {
1589
+ this.kvstore.set(
1590
+ SESSION_STORE_KEY,
1591
+ JSON.stringify({
1592
+ result: {
1593
+ sessionScopes: newSessionScopes
1594
+ }
1595
+ })
1596
+ );
1597
+ } else {
1598
+ this.kvstore.delete(SESSION_STORE_KEY);
1599
+ if (typeof window !== "undefined" && typeof window.removeEventListener !== "undefined" && this.windowFocusHandler) {
1600
+ window.removeEventListener("focus", this.windowFocusHandler);
1601
+ this.windowFocusHandler = void 0;
1602
+ }
1603
+ yield this.dappClient.disconnect();
1604
+ }
1605
+ this.notifyCallbacks({
1606
+ method: "wallet_sessionChanged",
1607
+ params: {
1608
+ sessionScopes: newSessionScopes
1609
+ }
1610
+ });
1611
+ });
1215
1612
  }
1216
- unmount() {
1613
+ /**
1614
+ * Checks if the transport is connected
1615
+ *
1616
+ * @returns True if transport is connected, false otherwise
1617
+ */
1618
+ isConnected() {
1619
+ return this.dappClient.state === "CONNECTED";
1217
1620
  }
1218
- };
1219
- }
1220
- });
1221
-
1222
- // src/ui/modals/web/index.ts
1223
- var web_exports = {};
1224
- __export(web_exports, {
1225
- InstallModal: () => InstallModal,
1226
- OTPCodeModal: () => OTPCodeModal
1227
- });
1228
- var init_web = __esm({
1229
- "src/ui/modals/web/index.ts"() {
1230
- "use strict";
1231
- init_install();
1232
- init_otp();
1233
- }
1234
- });
1235
-
1236
- // src/store/adapters/web.ts
1237
- var web_exports2 = {};
1238
- __export(web_exports2, {
1239
- StoreAdapterWeb: () => StoreAdapterWeb
1240
- });
1241
- var _StoreAdapterWeb, StoreAdapterWeb;
1242
- var init_web2 = __esm({
1243
- "src/store/adapters/web.ts"() {
1244
- "use strict";
1245
- init_domain();
1246
- _StoreAdapterWeb = class _StoreAdapterWeb extends StoreAdapter {
1247
- constructor(dbNameSuffix = "-kv-store", storeName = _StoreAdapterWeb.stores[0]) {
1248
- super();
1249
- this.storeName = storeName;
1250
- this.platform = "web";
1251
- const dbName = `${_StoreAdapterWeb.DB_NAME}${dbNameSuffix}`;
1252
- this.dbPromise = new Promise((resolve, reject) => {
1621
+ /**
1622
+ * Attempts to re-establish a connection via DappClient
1623
+ *
1624
+ * @returns Nothing
1625
+ */
1626
+ // TODO: We should re-evaluate adding this to the WebSocketTransport layer from `@metamask/mobile-wallet-protocol-core`
1627
+ // ticket: https://consensyssoftware.atlassian.net/browse/WAPI-862
1628
+ attemptResumeSession() {
1629
+ return __async(this, null, function* () {
1253
1630
  try {
1254
- const request = this.internal.open(dbName, 1);
1255
- request.onerror = () => reject(new Error("Failed to open IndexedDB."));
1256
- request.onsuccess = () => resolve(request.result);
1257
- request.onupgradeneeded = () => {
1258
- const db = request.result;
1259
- for (const name of _StoreAdapterWeb.stores) {
1260
- if (!db.objectStoreNames.contains(name)) {
1261
- db.createObjectStore(name);
1262
- }
1631
+ yield this.dappClient.reconnect();
1632
+ yield new Promise((resolve, reject) => {
1633
+ const timeout = setTimeout(() => {
1634
+ reject(new Error("Resume timeout"));
1635
+ }, 2e3);
1636
+ if (this.isConnected()) {
1637
+ clearTimeout(timeout);
1638
+ resolve();
1639
+ } else {
1640
+ this.dappClient.once("connected", () => {
1641
+ clearTimeout(timeout);
1642
+ resolve();
1643
+ });
1263
1644
  }
1264
- };
1645
+ });
1265
1646
  } catch (error) {
1266
- reject(error);
1647
+ return Promise.reject(
1648
+ new Error(`Failed to resume session: ${error.message}`)
1649
+ );
1267
1650
  }
1268
1651
  });
1269
1652
  }
1270
- get internal() {
1271
- if (typeof window === "undefined" || !window.indexedDB) {
1272
- throw new Error("indexedDB is not available in this environment");
1273
- }
1274
- return window.indexedDB;
1275
- }
1276
- get(key) {
1653
+ getCachedResponse(request) {
1277
1654
  return __async(this, null, function* () {
1278
- const { storeName } = this;
1279
- const db = yield this.dbPromise;
1280
- return new Promise((resolve, reject) => {
1281
- try {
1282
- const tx = db.transaction(storeName, "readonly");
1283
- const store = tx.objectStore(storeName);
1284
- const request = store.get(key);
1285
- request.onerror = () => reject(new Error("Failed to get value from IndexedDB."));
1286
- request.onsuccess = () => {
1287
- var _a3;
1288
- return resolve((_a3 = request.result) != null ? _a3 : null);
1655
+ var _a3;
1656
+ if (request.method === "wallet_getSession") {
1657
+ const walletGetSession = yield this.kvstore.get(SESSION_STORE_KEY);
1658
+ if (walletGetSession) {
1659
+ const walletSession = JSON.parse(walletGetSession);
1660
+ return {
1661
+ id: request.id,
1662
+ jsonrpc: "2.0",
1663
+ result: (_a3 = walletSession.params) != null ? _a3 : walletSession.result,
1664
+ // "what?... why walletSession.params?.."
1665
+ method: request.method
1289
1666
  };
1290
- } catch (error) {
1291
- reject(error);
1292
1667
  }
1293
- });
1668
+ } else if (request.method === "eth_accounts") {
1669
+ const ethAccounts = yield this.kvstore.get(ACCOUNTS_STORE_KEY);
1670
+ if (ethAccounts) {
1671
+ return {
1672
+ id: request.id,
1673
+ jsonrpc: "2.0",
1674
+ result: JSON.parse(ethAccounts),
1675
+ method: request.method
1676
+ };
1677
+ }
1678
+ } else if (request.method === "eth_chainId") {
1679
+ const ethChainId = yield this.kvstore.get(CHAIN_STORE_KEY);
1680
+ if (ethChainId) {
1681
+ return {
1682
+ id: request.id,
1683
+ jsonrpc: "2.0",
1684
+ result: JSON.parse(ethChainId),
1685
+ method: request.method
1686
+ };
1687
+ }
1688
+ }
1294
1689
  });
1295
1690
  }
1296
- set(key, value) {
1691
+ storeWalletSession(request, response) {
1297
1692
  return __async(this, null, function* () {
1298
- const { storeName } = this;
1299
- const db = yield this.dbPromise;
1693
+ if (response.error) {
1694
+ return;
1695
+ }
1696
+ if (CACHED_METHOD_LIST.includes(request.method)) {
1697
+ yield this.kvstore.set(SESSION_STORE_KEY, JSON.stringify(response));
1698
+ } else if (request.method === "eth_accounts") {
1699
+ yield this.kvstore.set(
1700
+ ACCOUNTS_STORE_KEY,
1701
+ JSON.stringify(response.result)
1702
+ );
1703
+ } else if (request.method === "eth_chainId") {
1704
+ yield this.kvstore.set(CHAIN_STORE_KEY, JSON.stringify(response.result));
1705
+ } else if (CACHED_RESET_METHOD_LIST.includes(request.method)) {
1706
+ yield this.kvstore.delete(SESSION_STORE_KEY);
1707
+ yield this.kvstore.delete(ACCOUNTS_STORE_KEY);
1708
+ yield this.kvstore.delete(CHAIN_STORE_KEY);
1709
+ }
1710
+ });
1711
+ }
1712
+ request(payload, options) {
1713
+ return __async(this, null, function* () {
1714
+ const request = __spreadValues({
1715
+ jsonrpc: "2.0",
1716
+ id: String(getUniqueRequestId())
1717
+ }, payload);
1718
+ const cachedWalletSession = yield this.getCachedResponse(request);
1719
+ if (cachedWalletSession) {
1720
+ this.notifyCallbacks(cachedWalletSession);
1721
+ return cachedWalletSession;
1722
+ }
1723
+ if (!this.isConnected()) {
1724
+ yield this.attemptResumeSession();
1725
+ }
1300
1726
  return new Promise((resolve, reject) => {
1301
- try {
1302
- const tx = db.transaction(storeName, "readwrite");
1303
- const store = tx.objectStore(storeName);
1304
- const request = store.put(value, key);
1305
- request.onerror = () => reject(new Error("Failed to set value in IndexedDB."));
1306
- request.onsuccess = () => resolve();
1307
- } catch (error) {
1308
- reject(error);
1309
- }
1727
+ var _a3;
1728
+ const timeout = setTimeout(() => {
1729
+ this.rejectRequest(request.id, new TransportTimeoutError());
1730
+ }, (_a3 = options == null ? void 0 : options.timeout) != null ? _a3 : this.options.requestTimeout);
1731
+ this.pendingRequests.set(request.id, {
1732
+ request,
1733
+ method: request.method,
1734
+ resolve: (response) => __async(this, null, function* () {
1735
+ yield this.storeWalletSession(request, response);
1736
+ return resolve(response);
1737
+ }),
1738
+ reject,
1739
+ timeout
1740
+ });
1741
+ this.dappClient.sendRequest({
1742
+ name: MULTICHAIN_PROVIDER_STREAM_NAME,
1743
+ data: request
1744
+ }).catch(reject);
1310
1745
  });
1311
1746
  });
1312
1747
  }
1313
- delete(key) {
1748
+ onNotification(callback) {
1749
+ this.notificationCallbacks.add(callback);
1750
+ return () => {
1751
+ this.notificationCallbacks.delete(callback);
1752
+ };
1753
+ }
1754
+ getActiveSession() {
1314
1755
  return __async(this, null, function* () {
1315
- const { storeName } = this;
1316
- const db = yield this.dbPromise;
1317
- return new Promise((resolve, reject) => {
1318
- try {
1319
- const tx = db.transaction(storeName, "readwrite");
1320
- const store = tx.objectStore(storeName);
1321
- const request = store.delete(key);
1322
- request.onerror = () => reject(new Error("Failed to delete value from IndexedDB."));
1323
- request.onsuccess = () => resolve();
1324
- } catch (error) {
1325
- reject(error);
1326
- }
1756
+ const { kvstore } = this;
1757
+ const { SessionStore } = yield import("@metamask/mobile-wallet-protocol-core");
1758
+ const sessionStore = yield SessionStore.create(kvstore);
1759
+ try {
1760
+ const [activeSession] = yield sessionStore.list();
1761
+ return activeSession;
1762
+ } catch (error) {
1763
+ logger("error getting active session", error);
1764
+ return void 0;
1765
+ }
1766
+ });
1767
+ }
1768
+ // This method checks if an existing CAIP session response is cached or waits for one
1769
+ // to be received from the wallet if not cached. This is necessary because there is an edge
1770
+ // case during the initial connection flow where after the user has accepted the permission approval
1771
+ // and returned back to the dapp from the wallet, the dapp page may have gotten unloaded and refreshed.
1772
+ // When it is unloaded and refreshed, it will try to resume the session by making a request for wallet_getSession
1773
+ // which should resolve from cache, but because a race condition makes it possible for the response from the wallet
1774
+ // for the initial wallet_createSession connection request to not have been handled and cached yet. This results
1775
+ // in the wallet_getSession request never resolving unless we wait for it explicitly as done in this method.
1776
+ waitForWalletSessionIfNotCached() {
1777
+ return __async(this, null, function* () {
1778
+ const cachedWalletGetSessionResponse = yield this.kvstore.get(SESSION_STORE_KEY);
1779
+ if (cachedWalletGetSessionResponse) {
1780
+ return;
1781
+ }
1782
+ let unsubscribe;
1783
+ const responsePromise = new Promise((resolve) => {
1784
+ unsubscribe = this.onNotification((message) => {
1785
+ if (typeof message === "object" && message !== null) {
1786
+ if ("data" in message) {
1787
+ const messagePayload = message.data;
1788
+ if (messagePayload.method === "wallet_getSession" || messagePayload.method === "wallet_sessionChanged") {
1789
+ unsubscribe();
1790
+ resolve();
1791
+ }
1792
+ }
1793
+ }
1794
+ });
1327
1795
  });
1796
+ const timeoutPromise = new Promise((_resolve, reject) => {
1797
+ setTimeout(() => {
1798
+ unsubscribe();
1799
+ this.removeStoredPendingSessionRequest();
1800
+ reject(new TransportTimeoutError());
1801
+ }, this.options.resumeTimeout);
1802
+ });
1803
+ return Promise.race([responsePromise, timeoutPromise]);
1328
1804
  });
1329
1805
  }
1330
1806
  };
1331
- _StoreAdapterWeb.stores = ["sdk-kv-store", "key-value-pairs"];
1332
- _StoreAdapterWeb.DB_NAME = "mmconnect";
1333
- StoreAdapterWeb = _StoreAdapterWeb;
1334
1807
  }
1335
1808
  });
1336
1809
 
1337
- // src/polyfills/buffer-shim.ts
1338
- init_utils2();
1339
- import { Buffer as Buffer2 } from "buffer";
1340
- var globalObj = getGlobalObject();
1341
- var _a;
1342
- (_a = globalObj.Buffer) != null ? _a : globalObj.Buffer = Buffer2;
1343
-
1344
- // src/index.browser.ts
1345
- init_domain();
1346
-
1347
- // src/multichain/index.ts
1348
- import { analytics as analytics2 } from "@metamask/analytics";
1349
- import {
1350
- ErrorCode,
1351
- ProtocolError,
1352
- SessionStore as SessionStore2,
1353
- WebSocketTransport
1354
- } from "@metamask/mobile-wallet-protocol-core";
1355
- import { DappClient } from "@metamask/mobile-wallet-protocol-dapp-client";
1356
- import {
1357
- getMultichainClient
1358
- } from "@metamask/multichain-api-client";
1359
-
1360
- // src/config/index.ts
1361
- var MWP_RELAY_URL = "wss://mm-sdk-relay.api.cx.metamask.io/connection/websocket";
1362
- var METAMASK_CONNECT_BASE_URL = "https://metamask.app.link/connect";
1363
- var METAMASK_DEEPLINK_BASE = "metamask://connect";
1364
-
1365
- // src/multichain/index.ts
1366
- init_domain();
1367
- init_analytics();
1368
- init_logger();
1369
- init_multichain();
1370
- init_platform();
1371
-
1372
- // src/multichain/rpc/handlers/rpcClient.ts
1373
- init_domain();
1374
- import fetch from "cross-fetch";
1375
- var rpcId = 1;
1376
- function getNextRpcId() {
1377
- rpcId += 1;
1378
- return rpcId;
1810
+ // src/multichain/transports/mwp/KeyManager.ts
1811
+ var KeyManager_exports = {};
1812
+ __export(KeyManager_exports, {
1813
+ createKeyManager: () => createKeyManager
1814
+ });
1815
+ function createKeyManager() {
1816
+ return __async(this, null, function* () {
1817
+ const { decrypt, encrypt, PrivateKey, PublicKey } = yield import("eciesjs");
1818
+ return {
1819
+ generateKeyPair() {
1820
+ const privateKey = new PrivateKey();
1821
+ return {
1822
+ privateKey: new Uint8Array(privateKey.secret),
1823
+ publicKey: privateKey.publicKey.toBytes(true)
1824
+ };
1825
+ },
1826
+ encrypt(plaintext, theirPublicKey) {
1827
+ return __async(this, null, function* () {
1828
+ const plaintextBuffer = Buffer.from(plaintext, "utf8");
1829
+ const encryptedBuffer = encrypt(theirPublicKey, plaintextBuffer);
1830
+ return encryptedBuffer.toString("base64");
1831
+ });
1832
+ },
1833
+ decrypt(encryptedB64, myPrivateKey) {
1834
+ return __async(this, null, function* () {
1835
+ const encryptedBuffer = Buffer.from(encryptedB64, "base64");
1836
+ const decryptedBuffer = yield decrypt(myPrivateKey, encryptedBuffer);
1837
+ return Buffer.from(decryptedBuffer).toString("utf8");
1838
+ });
1839
+ },
1840
+ validatePeerKey(key) {
1841
+ PublicKey.fromHex(Buffer.from(key).toString("hex"));
1842
+ }
1843
+ };
1844
+ });
1379
1845
  }
1380
- var MissingRpcEndpointErr = class extends Error {
1381
- };
1382
- var RpcClient = class {
1383
- constructor(config, sdkInfo) {
1384
- this.config = config;
1385
- this.sdkInfo = sdkInfo;
1846
+ var init_KeyManager = __esm({
1847
+ "src/multichain/transports/mwp/KeyManager.ts"() {
1848
+ "use strict";
1386
1849
  }
1387
- /**
1388
- * Routes the request to a configured RPC node.
1389
- *
1390
- * @param options - The invoke method options.
1391
- * @returns The JSON response from the RPC node.
1392
- */
1393
- request(options) {
1394
- return __async(this, null, function* () {
1395
- const { request } = options;
1396
- const body = JSON.stringify({
1397
- jsonrpc: "2.0",
1398
- method: request.method,
1399
- params: request.params,
1400
- id: getNextRpcId()
1401
- });
1402
- const rpcEndpoint = this.getRpcEndpoint(options.scope);
1403
- const rpcRequest = yield this.fetchWithTimeout(
1404
- rpcEndpoint,
1405
- body,
1406
- "POST",
1407
- this.getHeaders(rpcEndpoint),
1408
- 3e4
1409
- );
1410
- const response = yield this.parseResponse(rpcRequest);
1411
- return response;
1412
- });
1850
+ });
1851
+
1852
+ // src/ui/modals/base/utils.ts
1853
+ function formatRemainingTime(milliseconds) {
1854
+ if (milliseconds <= 0) {
1855
+ return "EXPIRED";
1413
1856
  }
1414
- getRpcEndpoint(scope) {
1415
- var _a3, _b, _c;
1416
- const supportedNetworks = (_c = (_b = (_a3 = this.config) == null ? void 0 : _a3.api) == null ? void 0 : _b.supportedNetworks) != null ? _c : {};
1417
- const rpcEndpoint = supportedNetworks[scope];
1418
- if (!rpcEndpoint) {
1419
- throw new MissingRpcEndpointErr(
1420
- `No RPC endpoint found for scope ${scope}`
1421
- );
1422
- }
1423
- return rpcEndpoint;
1857
+ const seconds = Math.floor(milliseconds / 1e3);
1858
+ return `${seconds}s`;
1859
+ }
1860
+ function shouldLogCountdown(remainingSeconds) {
1861
+ if (remainingSeconds <= 10) {
1862
+ return true;
1863
+ } else if (remainingSeconds <= 30) {
1864
+ return remainingSeconds % 5 === 0;
1865
+ } else if (remainingSeconds <= 60) {
1866
+ return remainingSeconds % 10 === 0;
1867
+ } else if (remainingSeconds <= 300) {
1868
+ return remainingSeconds % 30 === 0;
1424
1869
  }
1425
- fetchWithTimeout(endpoint, body, method, headers, timeout) {
1426
- return __async(this, null, function* () {
1427
- const controller = new AbortController();
1428
- const timeoutId = setTimeout(() => controller.abort(), timeout);
1429
- try {
1430
- const response = yield fetch(endpoint, {
1431
- method,
1432
- headers,
1433
- body,
1434
- signal: controller.signal
1435
- });
1436
- clearTimeout(timeoutId);
1437
- if (!response.ok) {
1438
- throw new RPCHttpErr(endpoint, method, response.status);
1439
- }
1440
- return response;
1441
- } catch (error) {
1442
- clearTimeout(timeoutId);
1443
- if (error instanceof RPCHttpErr) {
1444
- throw error;
1870
+ return remainingSeconds % 60 === 0;
1871
+ }
1872
+ var init_utils3 = __esm({
1873
+ "src/ui/modals/base/utils.ts"() {
1874
+ "use strict";
1875
+ }
1876
+ });
1877
+
1878
+ // src/ui/modals/base/AbstractInstallModal.ts
1879
+ var logger3, _expirationInterval, _lastLoggedCountdown, AbstractInstallModal;
1880
+ var init_AbstractInstallModal = __esm({
1881
+ "src/ui/modals/base/AbstractInstallModal.ts"() {
1882
+ "use strict";
1883
+ init_utils3();
1884
+ init_domain();
1885
+ logger3 = createLogger("metamask-sdk:ui");
1886
+ AbstractInstallModal = class extends Modal {
1887
+ constructor() {
1888
+ super(...arguments);
1889
+ __privateAdd(this, _expirationInterval, null);
1890
+ __privateAdd(this, _lastLoggedCountdown, -1);
1891
+ }
1892
+ get link() {
1893
+ return this.data;
1894
+ }
1895
+ set link(link) {
1896
+ this.data = link;
1897
+ }
1898
+ get connectionRequest() {
1899
+ return this.options.connectionRequest;
1900
+ }
1901
+ set connectionRequest(connectionRequest) {
1902
+ this.options.connectionRequest = connectionRequest;
1903
+ }
1904
+ updateLink(link) {
1905
+ this.link = link;
1906
+ if (this.instance) {
1907
+ this.instance.link = link;
1445
1908
  }
1446
- if (error instanceof Error && error.name === "AbortError") {
1447
- throw new RPCReadonlyRequestErr(`Request timeout after ${timeout}ms`);
1909
+ }
1910
+ updateExpiresIn(expiresIn) {
1911
+ if (expiresIn >= 0 && this.instance) {
1912
+ this.instance.expiresIn = expiresIn;
1448
1913
  }
1449
- throw new RPCReadonlyRequestErr(error.message);
1450
1914
  }
1451
- });
1452
- }
1453
- parseResponse(response) {
1454
- return __async(this, null, function* () {
1455
- try {
1456
- const rpcResponse = yield response.json();
1457
- return rpcResponse.result;
1458
- } catch (error) {
1459
- throw new RPCReadonlyResponseErr(error.message);
1915
+ startExpirationCheck(connectionRequest) {
1916
+ this.stopExpirationCheck();
1917
+ let currentConnectionRequest = connectionRequest;
1918
+ __privateSet(this, _expirationInterval, setInterval(() => __async(this, null, function* () {
1919
+ const { sessionRequest } = currentConnectionRequest;
1920
+ const now = Date.now();
1921
+ const remainingMs = sessionRequest.expiresAt - now;
1922
+ const remainingSeconds = Math.floor(remainingMs / 1e3);
1923
+ if (remainingMs > 0 && shouldLogCountdown(remainingSeconds) && __privateGet(this, _lastLoggedCountdown) !== remainingSeconds) {
1924
+ const formattedTime = formatRemainingTime(remainingMs);
1925
+ logger3(
1926
+ `[UI: InstallModal-nodejs()] QR code expires in: ${formattedTime} (${remainingSeconds}s)`
1927
+ );
1928
+ __privateSet(this, _lastLoggedCountdown, remainingSeconds);
1929
+ }
1930
+ if (now >= sessionRequest.expiresAt) {
1931
+ this.stopExpirationCheck();
1932
+ logger3(
1933
+ "[UI: InstallModal-nodejs()] \u23F0 QR code EXPIRED! Generating new one..."
1934
+ );
1935
+ try {
1936
+ currentConnectionRequest = yield this.options.createConnectionRequest();
1937
+ const generateQRCode = yield this.options.generateQRCode(
1938
+ currentConnectionRequest
1939
+ );
1940
+ __privateSet(this, _lastLoggedCountdown, -1);
1941
+ this.updateLink(generateQRCode);
1942
+ this.updateExpiresIn(remainingSeconds);
1943
+ this.renderQRCode(generateQRCode, currentConnectionRequest);
1944
+ } catch (error) {
1945
+ logger3(
1946
+ `[UI: InstallModal-nodejs()] \u274C Error generating new QR code: ${error}`
1947
+ );
1948
+ }
1949
+ }
1950
+ }), 1e3));
1951
+ }
1952
+ stopExpirationCheck() {
1953
+ if (__privateGet(this, _expirationInterval)) {
1954
+ clearInterval(__privateGet(this, _expirationInterval));
1955
+ __privateSet(this, _expirationInterval, null);
1956
+ logger3(
1957
+ "[UI: InstallModal-nodejs()] \u{1F6D1} Stopped QR code expiration checking"
1958
+ );
1959
+ }
1460
1960
  }
1461
- });
1462
- }
1463
- getHeaders(rpcEndpoint) {
1464
- const defaultHeaders = {
1465
- Accept: "application/json",
1466
- "Content-Type": "application/json"
1467
1961
  };
1468
- if (rpcEndpoint.includes("infura")) {
1469
- return __spreadProps(__spreadValues({}, defaultHeaders), {
1470
- "Metamask-Sdk-Info": this.sdkInfo
1471
- });
1472
- }
1473
- return defaultHeaders;
1962
+ _expirationInterval = new WeakMap();
1963
+ _lastLoggedCountdown = new WeakMap();
1474
1964
  }
1475
- };
1965
+ });
1476
1966
 
1477
- // src/multichain/rpc/requestRouter.ts
1478
- import { analytics } from "@metamask/analytics";
1479
- init_domain();
1480
- init_utils2();
1481
- init_analytics();
1482
- var _RequestRouter_instances, withAnalyticsTracking_fn, trackWalletActionRequested_fn, trackWalletActionSucceeded_fn, trackWalletActionFailed_fn, trackWalletActionRejected_fn;
1483
- var RequestRouter = class {
1484
- constructor(transport, rpcClient, config, transportType) {
1485
- this.transport = transport;
1486
- this.rpcClient = rpcClient;
1487
- this.config = config;
1488
- this.transportType = transportType;
1489
- __privateAdd(this, _RequestRouter_instances);
1490
- }
1491
- /**
1492
- * The main entry point for invoking an RPC method.
1493
- * This method acts as a router, determining the correct handling strategy
1494
- * for the request and delegating to the appropriate private handler.
1495
- *
1496
- * @param options
1497
- */
1498
- invokeMethod(options) {
1499
- return __async(this, null, function* () {
1500
- const { method } = options.request;
1501
- if (RPC_HANDLED_METHODS.has(method)) {
1502
- return this.handleWithRpcNode(options);
1967
+ // src/ui/modals/web/install.ts
1968
+ var InstallModal;
1969
+ var init_install = __esm({
1970
+ "src/ui/modals/web/install.ts"() {
1971
+ "use strict";
1972
+ init_AbstractInstallModal();
1973
+ InstallModal = class extends AbstractInstallModal {
1974
+ renderQRCode() {
1503
1975
  }
1504
- if (SDK_HANDLED_METHODS.has(method)) {
1505
- return this.handleWithSdkState(options);
1976
+ mount() {
1977
+ var _a3;
1978
+ const { options } = this;
1979
+ const modal = document.createElement(
1980
+ "mm-install-modal"
1981
+ );
1982
+ modal.showInstallModal = options.showInstallModal;
1983
+ modal.addEventListener("close", (ev) => {
1984
+ const { detail } = ev;
1985
+ options.onClose(detail == null ? void 0 : detail.shouldTerminate);
1986
+ });
1987
+ modal.addEventListener(
1988
+ "startDesktopOnboarding",
1989
+ options.startDesktopOnboarding
1990
+ );
1991
+ modal.link = options.link;
1992
+ this.instance = modal;
1993
+ (_a3 = options.parentElement) == null ? void 0 : _a3.appendChild(modal);
1994
+ this.startExpirationCheck(options.connectionRequest);
1506
1995
  }
1507
- return this.handleWithWallet(options);
1508
- });
1996
+ unmount() {
1997
+ var _a3;
1998
+ const { options, instance: modal } = this;
1999
+ this.stopExpirationCheck();
2000
+ if (modal && ((_a3 = options.parentElement) == null ? void 0 : _a3.contains(modal))) {
2001
+ options.parentElement.removeChild(modal);
2002
+ this.instance = void 0;
2003
+ }
2004
+ }
2005
+ };
1509
2006
  }
1510
- /**
1511
- * Forwards the request directly to the wallet via the transport.
1512
- *
1513
- * @param options
1514
- */
1515
- handleWithWallet(options) {
1516
- return __async(this, null, function* () {
1517
- return __privateMethod(this, _RequestRouter_instances, withAnalyticsTracking_fn).call(this, options, () => __async(this, null, function* () {
1518
- const request = this.transport.request({
1519
- method: "wallet_invokeMethod",
1520
- params: options
1521
- });
1522
- const { ui, mobile } = this.config;
1523
- const { showInstallModal = false } = ui != null ? ui : {};
1524
- const secure = isSecure();
1525
- const shouldOpenDeeplink = secure && !showInstallModal;
1526
- if (shouldOpenDeeplink) {
1527
- setTimeout(() => __async(this, null, function* () {
1528
- const session = yield this.transport.getActiveSession();
1529
- if (!session) {
1530
- throw new Error("No active session found");
1531
- }
1532
- const url = `${METAMASK_DEEPLINK_BASE}/mwp?id=${encodeURIComponent(session.id)}`;
1533
- if (mobile == null ? void 0 : mobile.preferredOpenLink) {
1534
- mobile.preferredOpenLink(url, "_self");
1535
- } else {
1536
- openDeeplink(this.config, url, METAMASK_CONNECT_BASE_URL);
1537
- }
1538
- }), 10);
1539
- }
1540
- const response = yield request;
1541
- if (response.error) {
1542
- const { error } = response;
1543
- throw new RPCInvokeMethodErr(
1544
- `RPC Request failed with code ${error.code}: ${error.message}`,
1545
- error.code,
1546
- error.message
1547
- );
1548
- }
1549
- return response.result;
1550
- }));
1551
- });
1552
- }
1553
- /**
1554
- * Routes the request to a configured RPC node.
1555
- *
1556
- * @param options
1557
- */
1558
- handleWithRpcNode(options) {
1559
- return __async(this, null, function* () {
1560
- try {
1561
- return yield this.rpcClient.request(options);
1562
- } catch (error) {
1563
- if (error instanceof MissingRpcEndpointErr) {
1564
- return this.handleWithWallet(options);
2007
+ });
2008
+
2009
+ // src/ui/modals/base/AbstractOTPModal.ts
2010
+ var AbstractOTPCodeModal;
2011
+ var init_AbstractOTPModal = __esm({
2012
+ "src/ui/modals/base/AbstractOTPModal.ts"() {
2013
+ "use strict";
2014
+ init_domain();
2015
+ AbstractOTPCodeModal = class extends Modal {
2016
+ get otpCode() {
2017
+ return this.data;
2018
+ }
2019
+ set otpCode(code) {
2020
+ this.data = code;
2021
+ }
2022
+ updateOTPCode(code) {
2023
+ this.otpCode = code;
2024
+ if (this.instance) {
2025
+ this.instance.otpCode = code;
1565
2026
  }
1566
- throw error;
1567
2027
  }
1568
- });
1569
- }
1570
- /**
1571
- * Responds directly from the SDK's session state.
1572
- *
1573
- * @param options
1574
- */
1575
- handleWithSdkState(options) {
1576
- return __async(this, null, function* () {
1577
- console.warn(
1578
- `Method "${options.request.method}" is configured for SDK state handling, but this is not yet implemented. Falling back to wallet passthrough.`
1579
- );
1580
- return this.handleWithWallet(options);
1581
- });
2028
+ };
1582
2029
  }
1583
- };
1584
- _RequestRouter_instances = new WeakSet();
1585
- withAnalyticsTracking_fn = function(options, execute) {
1586
- return __async(this, null, function* () {
1587
- var _a3;
1588
- yield __privateMethod(this, _RequestRouter_instances, trackWalletActionRequested_fn).call(this, options);
1589
- try {
1590
- const result = yield execute();
1591
- yield __privateMethod(this, _RequestRouter_instances, trackWalletActionSucceeded_fn).call(this, options);
1592
- return result;
1593
- } catch (error) {
1594
- const isRejection = isRejectionError(error);
1595
- if (isRejection) {
1596
- yield __privateMethod(this, _RequestRouter_instances, trackWalletActionRejected_fn).call(this, options);
1597
- } else {
1598
- yield __privateMethod(this, _RequestRouter_instances, trackWalletActionFailed_fn).call(this, options);
2030
+ });
2031
+
2032
+ // src/ui/modals/web/otp.ts
2033
+ var OTPCodeModal;
2034
+ var init_otp = __esm({
2035
+ "src/ui/modals/web/otp.ts"() {
2036
+ "use strict";
2037
+ init_AbstractOTPModal();
2038
+ OTPCodeModal = class extends AbstractOTPCodeModal {
2039
+ mount() {
1599
2040
  }
1600
- if (error instanceof RPCInvokeMethodErr) {
1601
- throw error;
2041
+ unmount() {
1602
2042
  }
1603
- const castError = error;
1604
- throw new RPCInvokeMethodErr(
1605
- (_a3 = castError.message) != null ? _a3 : "Unknown error",
1606
- castError.code
1607
- );
1608
- }
1609
- });
1610
- };
1611
- trackWalletActionRequested_fn = function(options) {
1612
- return __async(this, null, function* () {
1613
- const props = yield getWalletActionAnalyticsProperties(
1614
- this.config,
1615
- this.config.storage,
1616
- options,
1617
- this.transportType
1618
- );
1619
- analytics.track("mmconnect_wallet_action_requested", props);
1620
- });
1621
- };
1622
- trackWalletActionSucceeded_fn = function(options) {
1623
- return __async(this, null, function* () {
1624
- const props = yield getWalletActionAnalyticsProperties(
1625
- this.config,
1626
- this.config.storage,
1627
- options,
1628
- this.transportType
1629
- );
1630
- analytics.track("mmconnect_wallet_action_succeeded", props);
1631
- });
1632
- };
1633
- trackWalletActionFailed_fn = function(options) {
1634
- return __async(this, null, function* () {
1635
- const props = yield getWalletActionAnalyticsProperties(
1636
- this.config,
1637
- this.config.storage,
1638
- options,
1639
- this.transportType
1640
- );
1641
- analytics.track("mmconnect_wallet_action_failed", props);
1642
- });
1643
- };
1644
- trackWalletActionRejected_fn = function(options) {
1645
- return __async(this, null, function* () {
1646
- const props = yield getWalletActionAnalyticsProperties(
1647
- this.config,
1648
- this.config.storage,
1649
- options,
1650
- this.transportType
1651
- );
1652
- analytics.track("mmconnect_wallet_action_rejected", props);
1653
- });
1654
- };
2043
+ };
2044
+ }
2045
+ });
1655
2046
 
1656
- // src/multichain/transports/default/index.ts
1657
- init_utils2();
1658
- import {
1659
- getDefaultTransport
1660
- } from "@metamask/multichain-api-client";
1661
- var DEFAULT_REQUEST_TIMEOUT = 60 * 1e3;
1662
- var _notificationCallbacks, _transport, _defaultRequestOptions, _pendingRequests, _handleResponseListener, _handleNotificationListener, _DefaultTransport_instances, notifyCallbacks_fn, isMetamaskProviderEvent_fn, handleResponse_fn, handleNotification_fn, setupMessageListener_fn, init_fn;
1663
- var DefaultTransport = class {
1664
- constructor() {
1665
- __privateAdd(this, _DefaultTransport_instances);
1666
- __privateAdd(this, _notificationCallbacks, /* @__PURE__ */ new Set());
1667
- __privateAdd(this, _transport, getDefaultTransport());
1668
- __privateAdd(this, _defaultRequestOptions, {
1669
- timeout: DEFAULT_REQUEST_TIMEOUT
1670
- });
1671
- __privateAdd(this, _pendingRequests, /* @__PURE__ */ new Map());
1672
- __privateAdd(this, _handleResponseListener);
1673
- __privateAdd(this, _handleNotificationListener);
2047
+ // src/ui/modals/web/index.ts
2048
+ var web_exports = {};
2049
+ __export(web_exports, {
2050
+ InstallModal: () => InstallModal,
2051
+ OTPCodeModal: () => OTPCodeModal
2052
+ });
2053
+ var init_web = __esm({
2054
+ "src/ui/modals/web/index.ts"() {
2055
+ "use strict";
2056
+ init_install();
2057
+ init_otp();
1674
2058
  }
1675
- sendEip1193Message(payload, options) {
1676
- return __async(this, null, function* () {
1677
- __privateMethod(this, _DefaultTransport_instances, setupMessageListener_fn).call(this);
1678
- const requestId = String(getUniqueRequestId());
1679
- const request = __spreadValues({
1680
- jsonrpc: "2.0",
1681
- id: requestId
1682
- }, payload);
1683
- return new Promise((resolve, reject) => {
1684
- var _a3;
1685
- const timeout = setTimeout(() => {
1686
- __privateGet(this, _pendingRequests).delete(requestId);
1687
- reject(new Error("Request timeout"));
1688
- }, (_a3 = options == null ? void 0 : options.timeout) != null ? _a3 : __privateGet(this, _defaultRequestOptions).timeout);
1689
- __privateGet(this, _pendingRequests).set(requestId, {
1690
- resolve: (response) => {
1691
- resolve(response);
1692
- },
1693
- reject,
1694
- timeout
2059
+ });
2060
+
2061
+ // src/store/adapters/web.ts
2062
+ var web_exports2 = {};
2063
+ __export(web_exports2, {
2064
+ StoreAdapterWeb: () => StoreAdapterWeb
2065
+ });
2066
+ var _StoreAdapterWeb, StoreAdapterWeb;
2067
+ var init_web2 = __esm({
2068
+ "src/store/adapters/web.ts"() {
2069
+ "use strict";
2070
+ init_domain();
2071
+ _StoreAdapterWeb = class _StoreAdapterWeb extends StoreAdapter {
2072
+ constructor(dbNameSuffix = "-kv-store", storeName = _StoreAdapterWeb.stores[0]) {
2073
+ super();
2074
+ this.storeName = storeName;
2075
+ this.platform = "web";
2076
+ const dbName = `${_StoreAdapterWeb.DB_NAME}${dbNameSuffix}`;
2077
+ this.dbPromise = new Promise((resolve, reject) => {
2078
+ try {
2079
+ const request = this.internal.open(dbName, 1);
2080
+ request.onerror = () => reject(new Error("Failed to open IndexedDB."));
2081
+ request.onsuccess = () => resolve(request.result);
2082
+ request.onupgradeneeded = () => {
2083
+ const db = request.result;
2084
+ for (const name of _StoreAdapterWeb.stores) {
2085
+ if (!db.objectStoreNames.contains(name)) {
2086
+ db.createObjectStore(name);
2087
+ }
2088
+ }
2089
+ };
2090
+ } catch (error) {
2091
+ reject(error);
2092
+ }
1695
2093
  });
1696
- window.postMessage(
1697
- {
1698
- target: "metamask-contentscript",
1699
- data: {
1700
- name: "metamask-provider",
1701
- data: request
1702
- }
1703
- },
1704
- // eslint-disable-next-line no-restricted-globals
1705
- location.origin
1706
- );
1707
- });
1708
- });
1709
- }
1710
- init() {
1711
- return __async(this, null, function* () {
1712
- yield __privateMethod(this, _DefaultTransport_instances, init_fn).call(this);
1713
- let walletSession = { sessionScopes: {} };
1714
- try {
1715
- const sessionRequest = yield this.request(
1716
- { method: "wallet_getSession" },
1717
- __privateGet(this, _defaultRequestOptions)
1718
- );
1719
- walletSession = sessionRequest.result;
1720
- } catch (e) {
1721
- console.error(
1722
- "Failed to get wallet session during DefaultTransport init"
1723
- );
1724
2094
  }
1725
- __privateMethod(this, _DefaultTransport_instances, notifyCallbacks_fn).call(this, {
1726
- method: "wallet_sessionChanged",
1727
- params: walletSession
1728
- });
1729
- });
1730
- }
1731
- connect(options) {
1732
- return __async(this, null, function* () {
1733
- var _a3, _b, _c, _d, _e;
1734
- yield __privateMethod(this, _DefaultTransport_instances, init_fn).call(this);
1735
- const sessionRequest = yield this.request(
1736
- { method: "wallet_getSession" },
1737
- __privateGet(this, _defaultRequestOptions)
1738
- );
1739
- if (sessionRequest.error) {
1740
- throw new Error(sessionRequest.error.message);
1741
- }
1742
- let walletSession = sessionRequest.result;
1743
- const createSessionParams = {
1744
- optionalScopes: addValidAccounts(
1745
- getOptionalScopes((_a3 = options == null ? void 0 : options.scopes) != null ? _a3 : []),
1746
- getValidAccounts((_b = options == null ? void 0 : options.caipAccountIds) != null ? _b : [])
1747
- ),
1748
- sessionProperties: options == null ? void 0 : options.sessionProperties
1749
- };
1750
- if (walletSession && options && !options.forceRequest) {
1751
- const currentScopes = Object.keys(
1752
- (_c = walletSession == null ? void 0 : walletSession.sessionScopes) != null ? _c : {}
1753
- );
1754
- const proposedScopes = (_d = options == null ? void 0 : options.scopes) != null ? _d : [];
1755
- const proposedCaipAccountIds = (_e = options == null ? void 0 : options.caipAccountIds) != null ? _e : [];
1756
- const hasSameScopesAndAccounts = isSameScopesAndAccounts(
1757
- currentScopes,
1758
- proposedScopes,
1759
- walletSession,
1760
- proposedCaipAccountIds
1761
- );
1762
- if (!hasSameScopesAndAccounts) {
1763
- const response = yield this.request(
1764
- { method: "wallet_createSession", params: createSessionParams },
1765
- __privateGet(this, _defaultRequestOptions)
1766
- );
1767
- if (response.error) {
1768
- throw new Error(response.error.message);
1769
- }
1770
- walletSession = response.result;
1771
- }
1772
- } else if (!walletSession || (options == null ? void 0 : options.forceRequest)) {
1773
- const response = yield this.request(
1774
- { method: "wallet_createSession", params: createSessionParams },
1775
- __privateGet(this, _defaultRequestOptions)
1776
- );
1777
- if (response.error) {
1778
- throw new Error(response.error.message);
2095
+ get internal() {
2096
+ if (typeof window === "undefined" || !window.indexedDB) {
2097
+ throw new Error("indexedDB is not available in this environment");
1779
2098
  }
1780
- walletSession = response.result;
2099
+ return window.indexedDB;
1781
2100
  }
1782
- __privateMethod(this, _DefaultTransport_instances, notifyCallbacks_fn).call(this, {
1783
- method: "wallet_sessionChanged",
1784
- params: walletSession
1785
- });
1786
- });
1787
- }
1788
- disconnect() {
1789
- return __async(this, arguments, function* (scopes = []) {
1790
- yield this.request({ method: "wallet_revokeSession", params: { scopes } });
1791
- });
1792
- }
1793
- isConnected() {
1794
- return __privateGet(this, _transport).isConnected();
1795
- }
1796
- request(_0) {
1797
- return __async(this, arguments, function* (request, options = __privateGet(this, _defaultRequestOptions)) {
1798
- return __privateGet(this, _transport).request(request, options);
1799
- });
1800
- }
1801
- onNotification(callback) {
1802
- __privateGet(this, _transport).onNotification(callback);
1803
- __privateGet(this, _notificationCallbacks).add(callback);
1804
- return () => {
1805
- __privateGet(this, _notificationCallbacks).delete(callback);
1806
- };
1807
- }
1808
- getActiveSession() {
1809
- return __async(this, null, function* () {
1810
- throw new Error(
1811
- "getActiveSession is purposely not implemented for the DefaultTransport"
1812
- );
1813
- });
1814
- }
1815
- getStoredPendingSessionRequest() {
1816
- return __async(this, null, function* () {
1817
- throw new Error(
1818
- "getStoredPendingSessionRequest is purposely not implemented for the DefaultTransport"
1819
- );
1820
- });
1821
- }
1822
- };
1823
- _notificationCallbacks = new WeakMap();
1824
- _transport = new WeakMap();
1825
- _defaultRequestOptions = new WeakMap();
1826
- _pendingRequests = new WeakMap();
1827
- _handleResponseListener = new WeakMap();
1828
- _handleNotificationListener = new WeakMap();
1829
- _DefaultTransport_instances = new WeakSet();
1830
- notifyCallbacks_fn = function(data) {
1831
- for (const callback of __privateGet(this, _notificationCallbacks)) {
1832
- try {
1833
- callback(data);
1834
- } catch (error) {
1835
- console.log(
1836
- "[WindowPostMessageTransport] notifyCallbacks error:",
1837
- error
1838
- );
1839
- }
1840
- }
1841
- };
1842
- isMetamaskProviderEvent_fn = function(event) {
1843
- var _a3, _b;
1844
- return ((_b = (_a3 = event == null ? void 0 : event.data) == null ? void 0 : _a3.data) == null ? void 0 : _b.name) === "metamask-provider" && // eslint-disable-next-line no-restricted-globals
1845
- event.origin === location.origin;
1846
- };
1847
- handleResponse_fn = function(event) {
1848
- var _a3, _b;
1849
- if (!__privateMethod(this, _DefaultTransport_instances, isMetamaskProviderEvent_fn).call(this, event)) {
1850
- return;
1851
- }
1852
- const responseData = (_b = (_a3 = event == null ? void 0 : event.data) == null ? void 0 : _a3.data) == null ? void 0 : _b.data;
1853
- if (typeof responseData === "object" && responseData !== null && "method" in responseData) {
1854
- return;
1855
- }
1856
- if (typeof responseData === "object" && responseData !== null && "id" in responseData && ("result" in responseData || "error" in responseData)) {
1857
- const responseId = String(responseData.id);
1858
- const pendingRequest = __privateGet(this, _pendingRequests).get(responseId);
1859
- if (pendingRequest) {
1860
- clearTimeout(pendingRequest.timeout);
1861
- __privateGet(this, _pendingRequests).delete(responseId);
1862
- const response = responseData;
1863
- if ("error" in response && response.error) {
1864
- const error = new Error(
1865
- response.error.message || "Request failed"
1866
- );
1867
- if (typeof response.error.code === "number") {
1868
- error.code = response.error.code;
1869
- }
1870
- pendingRequest.reject(error);
1871
- } else {
1872
- pendingRequest.resolve(response);
2101
+ get(key) {
2102
+ return __async(this, null, function* () {
2103
+ const { storeName } = this;
2104
+ const db = yield this.dbPromise;
2105
+ return new Promise((resolve, reject) => {
2106
+ try {
2107
+ const tx = db.transaction(storeName, "readonly");
2108
+ const store = tx.objectStore(storeName);
2109
+ const request = store.get(key);
2110
+ request.onerror = () => reject(new Error("Failed to get value from IndexedDB."));
2111
+ request.onsuccess = () => {
2112
+ var _a3;
2113
+ return resolve((_a3 = request.result) != null ? _a3 : null);
2114
+ };
2115
+ } catch (error) {
2116
+ reject(error);
2117
+ }
2118
+ });
2119
+ });
1873
2120
  }
1874
- }
1875
- }
1876
- };
1877
- handleNotification_fn = function(event) {
1878
- var _a3, _b;
1879
- if (!__privateMethod(this, _DefaultTransport_instances, isMetamaskProviderEvent_fn).call(this, event)) {
1880
- return;
1881
- }
1882
- const responseData = (_b = (_a3 = event == null ? void 0 : event.data) == null ? void 0 : _a3.data) == null ? void 0 : _b.data;
1883
- if (typeof responseData === "object" && responseData !== null && "method" in responseData) {
1884
- __privateMethod(this, _DefaultTransport_instances, notifyCallbacks_fn).call(this, responseData);
1885
- }
1886
- };
1887
- setupMessageListener_fn = function() {
1888
- if (__privateGet(this, _handleResponseListener)) {
1889
- return;
2121
+ set(key, value) {
2122
+ return __async(this, null, function* () {
2123
+ const { storeName } = this;
2124
+ const db = yield this.dbPromise;
2125
+ return new Promise((resolve, reject) => {
2126
+ try {
2127
+ const tx = db.transaction(storeName, "readwrite");
2128
+ const store = tx.objectStore(storeName);
2129
+ const request = store.put(value, key);
2130
+ request.onerror = () => reject(new Error("Failed to set value in IndexedDB."));
2131
+ request.onsuccess = () => resolve();
2132
+ } catch (error) {
2133
+ reject(error);
2134
+ }
2135
+ });
2136
+ });
2137
+ }
2138
+ delete(key) {
2139
+ return __async(this, null, function* () {
2140
+ const { storeName } = this;
2141
+ const db = yield this.dbPromise;
2142
+ return new Promise((resolve, reject) => {
2143
+ try {
2144
+ const tx = db.transaction(storeName, "readwrite");
2145
+ const store = tx.objectStore(storeName);
2146
+ const request = store.delete(key);
2147
+ request.onerror = () => reject(new Error("Failed to delete value from IndexedDB."));
2148
+ request.onsuccess = () => resolve();
2149
+ } catch (error) {
2150
+ reject(error);
2151
+ }
2152
+ });
2153
+ });
2154
+ }
2155
+ };
2156
+ _StoreAdapterWeb.stores = ["sdk-kv-store", "key-value-pairs"];
2157
+ _StoreAdapterWeb.DB_NAME = "mmconnect";
2158
+ StoreAdapterWeb = _StoreAdapterWeb;
1890
2159
  }
1891
- __privateSet(this, _handleResponseListener, __privateMethod(this, _DefaultTransport_instances, handleResponse_fn).bind(this));
1892
- __privateSet(this, _handleNotificationListener, __privateMethod(this, _DefaultTransport_instances, handleNotification_fn).bind(this));
1893
- window.addEventListener("message", __privateGet(this, _handleResponseListener));
1894
- window.addEventListener("message", __privateGet(this, _handleNotificationListener));
1895
- };
1896
- init_fn = function() {
1897
- return __async(this, null, function* () {
1898
- __privateMethod(this, _DefaultTransport_instances, setupMessageListener_fn).call(this);
1899
- if (!__privateGet(this, _transport).isConnected()) {
1900
- yield __privateGet(this, _transport).connect();
1901
- }
1902
- });
1903
- };
2160
+ });
1904
2161
 
1905
- // src/multichain/transports/multichainApiClientWrapper/index.ts
2162
+ // src/polyfills/buffer-shim.ts
1906
2163
  init_utils2();
1907
- import { providerErrors } from "@metamask/rpc-errors";
1908
- var _notificationCallbacks2, _MultichainApiClientWrapperTransport_instances, walletCreateSession_fn, walletGetSession_fn, walletRevokeSession_fn, walletInvokeMethod_fn;
1909
- var MultichainApiClientWrapperTransport = class {
1910
- constructor(metamaskConnectMultichain) {
1911
- this.metamaskConnectMultichain = metamaskConnectMultichain;
1912
- __privateAdd(this, _MultichainApiClientWrapperTransport_instances);
1913
- __privateAdd(this, _notificationCallbacks2, /* @__PURE__ */ new Set());
1914
- }
1915
- isTransportDefined() {
1916
- try {
1917
- return Boolean(this.metamaskConnectMultichain.transport);
1918
- } catch (_error) {
1919
- return false;
1920
- }
1921
- }
1922
- clearNotificationCallbacks() {
1923
- __privateGet(this, _notificationCallbacks2).clear();
2164
+ import { Buffer as Buffer2 } from "buffer";
2165
+ var globalObj = getGlobalObject();
2166
+ var _a;
2167
+ (_a = globalObj.Buffer) != null ? _a : globalObj.Buffer = Buffer2;
2168
+
2169
+ // src/index.browser.ts
2170
+ init_domain();
2171
+
2172
+ // src/multichain/index.ts
2173
+ import { analytics as analytics2 } from "@metamask/analytics";
2174
+ import {
2175
+ getMultichainClient
2176
+ } from "@metamask/multichain-api-client";
2177
+
2178
+ // src/config/index.ts
2179
+ var MWP_RELAY_URL = "wss://mm-sdk-relay.api.cx.metamask.io/connection/websocket";
2180
+ var METAMASK_CONNECT_BASE_URL = "https://metamask.app.link/connect";
2181
+ var METAMASK_DEEPLINK_BASE = "metamask://connect";
2182
+
2183
+ // src/multichain/index.ts
2184
+ init_domain();
2185
+ init_analytics();
2186
+ init_logger();
2187
+ init_multichain();
2188
+ init_platform();
2189
+
2190
+ // src/multichain/rpc/handlers/rpcClient.ts
2191
+ init_domain();
2192
+ import fetch from "cross-fetch";
2193
+ var rpcId = 1;
2194
+ function getNextRpcId() {
2195
+ rpcId += 1;
2196
+ return rpcId;
2197
+ }
2198
+ var MissingRpcEndpointErr = class extends Error {
2199
+ };
2200
+ var RpcClient = class {
2201
+ constructor(config, sdkInfo) {
2202
+ this.config = config;
2203
+ this.sdkInfo = sdkInfo;
1924
2204
  }
1925
- notifyCallbacks(data) {
1926
- __privateGet(this, _notificationCallbacks2).forEach((callback) => {
1927
- callback(data);
2205
+ /**
2206
+ * Routes the request to a configured RPC node.
2207
+ *
2208
+ * @param options - The invoke method options.
2209
+ * @returns The JSON response from the RPC node.
2210
+ */
2211
+ request(options) {
2212
+ return __async(this, null, function* () {
2213
+ const { request } = options;
2214
+ const body = JSON.stringify({
2215
+ jsonrpc: "2.0",
2216
+ method: request.method,
2217
+ params: request.params,
2218
+ id: getNextRpcId()
2219
+ });
2220
+ const rpcEndpoint = this.getRpcEndpoint(options.scope);
2221
+ const rpcRequest = yield this.fetchWithTimeout(
2222
+ rpcEndpoint,
2223
+ body,
2224
+ "POST",
2225
+ this.getHeaders(rpcEndpoint),
2226
+ 3e4
2227
+ );
2228
+ const response = yield this.parseResponse(rpcRequest);
2229
+ return response;
1928
2230
  });
1929
2231
  }
1930
- clearTransportNotificationListener() {
1931
- var _a3;
1932
- (_a3 = this.notificationListener) == null ? void 0 : _a3.call(this);
1933
- this.notificationListener = void 0;
1934
- }
1935
- setupTransportNotificationListener() {
1936
- if (!this.isTransportDefined() || this.notificationListener) {
1937
- return;
2232
+ getRpcEndpoint(scope) {
2233
+ var _a3, _b, _c;
2234
+ const supportedNetworks = (_c = (_b = (_a3 = this.config) == null ? void 0 : _a3.api) == null ? void 0 : _b.supportedNetworks) != null ? _c : {};
2235
+ const rpcEndpoint = supportedNetworks[scope];
2236
+ if (!rpcEndpoint) {
2237
+ throw new MissingRpcEndpointErr(
2238
+ `No RPC endpoint found for scope ${scope}`
2239
+ );
1938
2240
  }
1939
- this.notificationListener = this.metamaskConnectMultichain.transport.onNotification(
1940
- this.notifyCallbacks.bind(this)
1941
- );
1942
- }
1943
- connect() {
1944
- return __async(this, null, function* () {
1945
- console.log("\u{1F4DA} connect");
1946
- yield this.metamaskConnectMultichain.emitSessionChanged();
1947
- });
2241
+ return rpcEndpoint;
1948
2242
  }
1949
- disconnect() {
2243
+ fetchWithTimeout(endpoint, body, method, headers, timeout) {
1950
2244
  return __async(this, null, function* () {
1951
- return Promise.resolve();
1952
- });
1953
- }
1954
- isConnected() {
1955
- return true;
1956
- }
1957
- request(_0) {
1958
- return __async(this, arguments, function* (params, _options = {}) {
1959
- const id = getUniqueRequestId();
1960
- const requestPayload = __spreadValues({
1961
- id,
1962
- jsonrpc: "2.0"
1963
- }, params);
1964
- switch (requestPayload.method) {
1965
- case "wallet_createSession":
1966
- return __privateMethod(this, _MultichainApiClientWrapperTransport_instances, walletCreateSession_fn).call(this, requestPayload);
1967
- case "wallet_getSession":
1968
- return __privateMethod(this, _MultichainApiClientWrapperTransport_instances, walletGetSession_fn).call(this, requestPayload);
1969
- case "wallet_revokeSession":
1970
- return __privateMethod(this, _MultichainApiClientWrapperTransport_instances, walletRevokeSession_fn).call(this, requestPayload);
1971
- case "wallet_invokeMethod":
1972
- return __privateMethod(this, _MultichainApiClientWrapperTransport_instances, walletInvokeMethod_fn).call(this, requestPayload);
1973
- default:
1974
- throw new Error(`Unsupported method: ${requestPayload.method}`);
1975
- }
1976
- throw new Error(`Unknown method: ${requestPayload.method}`);
1977
- });
1978
- }
1979
- onNotification(callback) {
1980
- this.setupTransportNotificationListener();
1981
- __privateGet(this, _notificationCallbacks2).add(callback);
1982
- return () => {
1983
- __privateGet(this, _notificationCallbacks2).delete(callback);
1984
- };
1985
- }
1986
- };
1987
- _notificationCallbacks2 = new WeakMap();
1988
- _MultichainApiClientWrapperTransport_instances = new WeakSet();
1989
- walletCreateSession_fn = function(request) {
1990
- return __async(this, null, function* () {
1991
- const createSessionParams = request.params;
1992
- const scopes = Object.keys(__spreadValues(__spreadValues({}, createSessionParams.optionalScopes), createSessionParams.requiredScopes));
1993
- const scopeAccounts = [];
1994
- scopes.forEach((scope) => {
1995
- var _a3, _b, _c, _d;
1996
- const requiredScope = (_a3 = createSessionParams.requiredScopes) == null ? void 0 : _a3[scope];
1997
- const optionalScope = (_b = createSessionParams.optionalScopes) == null ? void 0 : _b[scope];
1998
- if (requiredScope) {
1999
- scopeAccounts.push(...(_c = requiredScope.accounts) != null ? _c : []);
2000
- }
2001
- if (optionalScope) {
2002
- scopeAccounts.push(...(_d = optionalScope.accounts) != null ? _d : []);
2245
+ const controller = new AbortController();
2246
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
2247
+ try {
2248
+ const response = yield fetch(endpoint, {
2249
+ method,
2250
+ headers,
2251
+ body,
2252
+ signal: controller.signal
2253
+ });
2254
+ clearTimeout(timeoutId);
2255
+ if (!response.ok) {
2256
+ throw new RPCHttpErr(endpoint, method, response.status);
2257
+ }
2258
+ return response;
2259
+ } catch (error) {
2260
+ clearTimeout(timeoutId);
2261
+ if (error instanceof RPCHttpErr) {
2262
+ throw error;
2263
+ }
2264
+ if (error instanceof Error && error.name === "AbortError") {
2265
+ throw new RPCReadonlyRequestErr(`Request timeout after ${timeout}ms`);
2266
+ }
2267
+ throw new RPCReadonlyRequestErr(error.message);
2003
2268
  }
2004
2269
  });
2005
- const accounts = [...new Set(scopeAccounts)];
2006
- console.log("\u{1F4DA} SDK connect");
2007
- yield this.metamaskConnectMultichain.connect(
2008
- scopes,
2009
- accounts,
2010
- createSessionParams.sessionProperties
2011
- );
2012
- console.log("\u{1F4DA} SDK connected");
2013
- return this.metamaskConnectMultichain.transport.request({
2014
- method: "wallet_getSession"
2015
- });
2016
- });
2017
- };
2018
- walletGetSession_fn = function(request) {
2019
- return __async(this, null, function* () {
2020
- if (!this.isTransportDefined()) {
2021
- return {
2022
- jsonrpc: "2.0",
2023
- id: request.id,
2024
- result: {
2025
- sessionScopes: {}
2026
- }
2027
- };
2028
- }
2029
- return this.metamaskConnectMultichain.transport.request({
2030
- method: "wallet_getSession"
2270
+ }
2271
+ parseResponse(response) {
2272
+ return __async(this, null, function* () {
2273
+ try {
2274
+ const rpcResponse = yield response.json();
2275
+ return rpcResponse.result;
2276
+ } catch (error) {
2277
+ throw new RPCReadonlyResponseErr(error.message);
2278
+ }
2031
2279
  });
2032
- });
2033
- };
2034
- walletRevokeSession_fn = function(request) {
2035
- return __async(this, null, function* () {
2036
- var _a3;
2037
- if (!this.isTransportDefined()) {
2038
- return { jsonrpc: "2.0", id: request.id, result: true };
2039
- }
2040
- const revokeSessionParams = request.params;
2041
- const scopes = (_a3 = revokeSessionParams == null ? void 0 : revokeSessionParams.scopes) != null ? _a3 : [];
2042
- try {
2043
- yield this.metamaskConnectMultichain.disconnect(scopes);
2044
- return { jsonrpc: "2.0", id: request.id, result: true };
2045
- } catch (_error) {
2046
- return { jsonrpc: "2.0", id: request.id, result: false };
2047
- }
2048
- });
2049
- };
2050
- walletInvokeMethod_fn = function(request) {
2051
- return __async(this, null, function* () {
2052
- if (!this.isTransportDefined()) {
2053
- return { error: providerErrors.unauthorized() };
2054
- }
2055
- const result = this.metamaskConnectMultichain.invokeMethod(
2056
- request.params
2057
- );
2058
- return {
2059
- result
2280
+ }
2281
+ getHeaders(rpcEndpoint) {
2282
+ const defaultHeaders = {
2283
+ Accept: "application/json",
2284
+ "Content-Type": "application/json"
2060
2285
  };
2061
- });
2286
+ if (rpcEndpoint.includes("infura")) {
2287
+ return __spreadProps(__spreadValues({}, defaultHeaders), {
2288
+ "Metamask-Sdk-Info": this.sdkInfo
2289
+ });
2290
+ }
2291
+ return defaultHeaders;
2292
+ }
2062
2293
  };
2063
2294
 
2064
- // src/multichain/transports/mwp/index.ts
2295
+ // src/multichain/rpc/requestRouter.ts
2296
+ import { analytics } from "@metamask/analytics";
2065
2297
  init_domain();
2066
2298
  init_utils2();
2067
- import { SessionStore } from "@metamask/mobile-wallet-protocol-core";
2068
- import {
2069
- TransportTimeoutError
2070
- } from "@metamask/multichain-api-client";
2071
- import { JsonRpcError, providerErrors as providerErrors2, rpcErrors } from "@metamask/rpc-errors";
2072
-
2073
- // src/multichain/transports/constants.ts
2074
- var MULTICHAIN_PROVIDER_STREAM_NAME = "metamask-multichain-provider";
2075
-
2076
- // src/multichain/transports/mwp/index.ts
2077
- var DEFAULT_REQUEST_TIMEOUT2 = 60 * 1e3;
2078
- var CONNECTION_GRACE_PERIOD = 60 * 1e3;
2079
- var DEFAULT_CONNECTION_TIMEOUT = DEFAULT_REQUEST_TIMEOUT2 + CONNECTION_GRACE_PERIOD;
2080
- var DEFAULT_RESUME_TIMEOUT = 10 * 1e3;
2081
- var SESSION_STORE_KEY = "cache_wallet_getSession";
2082
- var ACCOUNTS_STORE_KEY = "cache_eth_accounts";
2083
- var CHAIN_STORE_KEY = "cache_eth_chainId";
2084
- var PENDING_SESSION_REQUEST_KEY = "pending_session_request";
2085
- var CACHED_METHOD_LIST = [
2086
- "wallet_getSession",
2087
- "wallet_createSession",
2088
- "wallet_sessionChanged"
2089
- ];
2090
- var CACHED_RESET_METHOD_LIST = [
2091
- "wallet_revokeSession",
2092
- "wallet_revokePermissions"
2093
- ];
2094
- var logger = createLogger("metamask-sdk:transport");
2095
- var MWPTransport = class {
2096
- constructor(dappClient, kvstore, options = {
2097
- requestTimeout: DEFAULT_REQUEST_TIMEOUT2,
2098
- connectionTimeout: DEFAULT_CONNECTION_TIMEOUT,
2099
- resumeTimeout: DEFAULT_RESUME_TIMEOUT
2100
- }) {
2101
- this.dappClient = dappClient;
2102
- this.kvstore = kvstore;
2103
- this.options = options;
2104
- this.__pendingRequests = /* @__PURE__ */ new Map();
2105
- this.notificationCallbacks = /* @__PURE__ */ new Set();
2106
- this.dappClient.on("message", this.handleMessage.bind(this));
2107
- this.dappClient.on("session_request", (sessionRequest) => {
2108
- this.currentSessionRequest = sessionRequest;
2109
- this.kvstore.set(PENDING_SESSION_REQUEST_KEY, JSON.stringify(sessionRequest)).catch((err) => {
2110
- logger("Failed to store pending session request", err);
2111
- });
2112
- });
2113
- if (typeof window !== "undefined" && typeof window.addEventListener !== "undefined") {
2114
- this.windowFocusHandler = this.onWindowFocus.bind(this);
2115
- window.addEventListener("focus", this.windowFocusHandler);
2116
- }
2117
- }
2118
- get pendingRequests() {
2119
- return this.__pendingRequests;
2120
- }
2121
- set pendingRequests(pendingRequests) {
2122
- this.__pendingRequests = pendingRequests;
2123
- }
2124
- get sessionRequest() {
2125
- return this.currentSessionRequest;
2299
+ init_analytics();
2300
+ var _RequestRouter_instances, withAnalyticsTracking_fn, trackWalletActionRequested_fn, trackWalletActionSucceeded_fn, trackWalletActionFailed_fn, trackWalletActionRejected_fn;
2301
+ var RequestRouter = class {
2302
+ constructor(transport, rpcClient, config, transportType) {
2303
+ this.transport = transport;
2304
+ this.rpcClient = rpcClient;
2305
+ this.config = config;
2306
+ this.transportType = transportType;
2307
+ __privateAdd(this, _RequestRouter_instances);
2126
2308
  }
2127
2309
  /**
2128
- * Returns the stored pending session request from the dappClient session_request event, if any.
2310
+ * The main entry point for invoking an RPC method.
2311
+ * This method acts as a router, determining the correct handling strategy
2312
+ * for the request and delegating to the appropriate private handler.
2129
2313
  *
2130
- * @returns The stored SessionRequest, or null if none or invalid.
2314
+ * @param options
2131
2315
  */
2132
- getStoredPendingSessionRequest() {
2316
+ invokeMethod(options) {
2133
2317
  return __async(this, null, function* () {
2134
- try {
2135
- const raw = yield this.kvstore.get(PENDING_SESSION_REQUEST_KEY);
2136
- if (!raw) {
2137
- return null;
2138
- }
2139
- return JSON.parse(raw);
2140
- } catch (e) {
2141
- return null;
2318
+ const { method } = options.request;
2319
+ if (RPC_HANDLED_METHODS.has(method)) {
2320
+ return this.handleWithRpcNode(options);
2321
+ }
2322
+ if (SDK_HANDLED_METHODS.has(method)) {
2323
+ return this.handleWithSdkState(options);
2142
2324
  }
2325
+ return this.handleWithWallet(options);
2143
2326
  });
2144
2327
  }
2145
2328
  /**
2146
- * Removes the stored pending session request from the KVStore.
2147
- * This is necessary to ensure that ConnectMultichain is able to correctly
2148
- * infer the MWP Transport connection attempt status.
2329
+ * Forwards the request directly to the wallet via the transport.
2330
+ *
2331
+ * @param options
2149
2332
  */
2150
- removeStoredPendingSessionRequest() {
2333
+ handleWithWallet(options) {
2151
2334
  return __async(this, null, function* () {
2152
- yield this.kvstore.delete(PENDING_SESSION_REQUEST_KEY);
2153
- });
2154
- }
2155
- onWindowFocus() {
2156
- if (!this.isConnected()) {
2157
- this.dappClient.reconnect();
2158
- }
2159
- }
2160
- notifyCallbacks(data) {
2161
- this.notificationCallbacks.forEach((callback) => callback(data));
2162
- }
2163
- rejectRequest(id, error = new Error("Request rejected")) {
2164
- const request = this.pendingRequests.get(id);
2165
- if (request) {
2166
- this.pendingRequests.delete(id);
2167
- clearTimeout(request.timeout);
2168
- request.reject(error);
2169
- }
2170
- }
2171
- parseWalletError(errorPayload) {
2172
- const errorData = errorPayload;
2173
- if (typeof errorData.code === "number" && typeof errorData.message === "string") {
2174
- const { code, message: message2 } = errorData;
2175
- if (code >= 1e3 && code <= 4999) {
2176
- return providerErrors2.custom({ code, message: message2 });
2177
- }
2178
- return new JsonRpcError(code, message2);
2179
- }
2180
- const message = errorPayload instanceof Error ? errorPayload.message : JSON.stringify(errorPayload);
2181
- return rpcErrors.internal({ message });
2182
- }
2183
- handleMessage(message) {
2184
- if (typeof message === "object" && message !== null) {
2185
- if ("data" in message) {
2186
- const messagePayload = message.data;
2187
- if ("id" in messagePayload && typeof messagePayload.id === "string") {
2188
- const request = this.pendingRequests.get(messagePayload.id);
2189
- if (request) {
2190
- clearTimeout(request.timeout);
2191
- if ("error" in messagePayload && messagePayload.error) {
2192
- this.pendingRequests.delete(messagePayload.id);
2193
- request.reject(this.parseWalletError(messagePayload.error));
2194
- return;
2335
+ return __privateMethod(this, _RequestRouter_instances, withAnalyticsTracking_fn).call(this, options, () => __async(this, null, function* () {
2336
+ const request = this.transport.request({
2337
+ method: "wallet_invokeMethod",
2338
+ params: options
2339
+ });
2340
+ const { ui, mobile } = this.config;
2341
+ const { showInstallModal = false } = ui != null ? ui : {};
2342
+ const secure = isSecure();
2343
+ const shouldOpenDeeplink = secure && !showInstallModal;
2344
+ if (shouldOpenDeeplink) {
2345
+ setTimeout(() => __async(this, null, function* () {
2346
+ const session = yield this.transport.getActiveSession();
2347
+ if (!session) {
2348
+ throw new Error("No active session found");
2195
2349
  }
2196
- const requestWithName = __spreadProps(__spreadValues({}, messagePayload), {
2197
- method: request.method === "wallet_getSession" || request.method === "wallet_createSession" ? "wallet_sessionChanged" : request.method
2198
- });
2199
- const notification = __spreadProps(__spreadValues({}, messagePayload), {
2200
- method: request.method === "wallet_getSession" || request.method === "wallet_createSession" ? "wallet_sessionChanged" : request.method,
2201
- params: requestWithName.result
2202
- });
2203
- this.notifyCallbacks(notification);
2204
- request.resolve(requestWithName);
2205
- this.pendingRequests.delete(messagePayload.id);
2206
- }
2207
- } else {
2208
- if (message.data.method === "metamask_chainChanged") {
2209
- this.kvstore.set(
2210
- CHAIN_STORE_KEY,
2211
- JSON.stringify(
2212
- message.data.params.chainId
2213
- )
2214
- );
2215
- }
2216
- if (message.data.method === "metamask_accountsChanged") {
2217
- this.kvstore.set(
2218
- ACCOUNTS_STORE_KEY,
2219
- JSON.stringify(
2220
- message.data.params
2221
- )
2222
- );
2223
- }
2224
- if (message.data.method === "wallet_sessionChanged") {
2225
- const notification = message.data;
2226
- const response = {
2227
- result: notification.params
2228
- };
2229
- this.kvstore.set(SESSION_STORE_KEY, JSON.stringify(response));
2230
- }
2231
- this.notifyCallbacks(message.data);
2350
+ const url = `${METAMASK_DEEPLINK_BASE}/mwp?id=${encodeURIComponent(session.id)}`;
2351
+ if (mobile == null ? void 0 : mobile.preferredOpenLink) {
2352
+ mobile.preferredOpenLink(url, "_self");
2353
+ } else {
2354
+ openDeeplink(this.config, url, METAMASK_CONNECT_BASE_URL);
2355
+ }
2356
+ }), 10);
2232
2357
  }
2233
- }
2234
- }
2358
+ const response = yield request;
2359
+ if (response.error) {
2360
+ const { error } = response;
2361
+ throw new RPCInvokeMethodErr(
2362
+ `RPC Request failed with code ${error.code}: ${error.message}`,
2363
+ error.code,
2364
+ error.message
2365
+ );
2366
+ }
2367
+ return response.result;
2368
+ }));
2369
+ });
2235
2370
  }
2236
- onResumeSuccess(resumeResolve, resumeReject, options) {
2371
+ /**
2372
+ * Routes the request to a configured RPC node.
2373
+ *
2374
+ * @param options
2375
+ */
2376
+ handleWithRpcNode(options) {
2237
2377
  return __async(this, null, function* () {
2238
- var _a3, _b, _c, _d, _e, _f, _g;
2239
2378
  try {
2240
- yield this.waitForWalletSessionIfNotCached();
2241
- const sessionRequest = yield this.request({
2242
- method: "wallet_getSession"
2243
- });
2244
- if (sessionRequest.error) {
2245
- return resumeReject(new Error(sessionRequest.error.message));
2246
- }
2247
- let walletSession = sessionRequest.result;
2248
- if (walletSession && options) {
2249
- const currentScopes = Object.keys(
2250
- (_a3 = walletSession == null ? void 0 : walletSession.sessionScopes) != null ? _a3 : {}
2251
- );
2252
- const proposedScopes = (_b = options == null ? void 0 : options.scopes) != null ? _b : [];
2253
- const proposedCaipAccountIds = (_c = options == null ? void 0 : options.caipAccountIds) != null ? _c : [];
2254
- const hasSameScopesAndAccounts = isSameScopesAndAccounts(
2255
- currentScopes,
2256
- proposedScopes,
2257
- walletSession,
2258
- proposedCaipAccountIds
2259
- );
2260
- if (options.forceRequest || !hasSameScopesAndAccounts) {
2261
- const optionalScopes = addValidAccounts(
2262
- getOptionalScopes((_d = options == null ? void 0 : options.scopes) != null ? _d : []),
2263
- getValidAccounts((_e = options == null ? void 0 : options.caipAccountIds) != null ? _e : [])
2264
- );
2265
- const sessionRequest2 = {
2266
- optionalScopes
2267
- };
2268
- const response = yield this.request({
2269
- method: "wallet_createSession",
2270
- params: sessionRequest2
2271
- });
2272
- if (response.error) {
2273
- return resumeReject(new Error(response.error.message));
2274
- }
2275
- walletSession = response.result;
2276
- }
2277
- } else if (!walletSession) {
2278
- const optionalScopes = addValidAccounts(
2279
- getOptionalScopes((_f = options == null ? void 0 : options.scopes) != null ? _f : []),
2280
- getValidAccounts((_g = options == null ? void 0 : options.caipAccountIds) != null ? _g : [])
2281
- );
2282
- const sessionRequest2 = { optionalScopes };
2283
- const response = yield this.request({
2284
- method: "wallet_createSession",
2285
- params: sessionRequest2
2286
- });
2287
- if (response.error) {
2288
- return resumeReject(new Error(response.error.message));
2289
- }
2290
- walletSession = response.result;
2379
+ return yield this.rpcClient.request(options);
2380
+ } catch (error) {
2381
+ if (error instanceof MissingRpcEndpointErr) {
2382
+ return this.handleWithWallet(options);
2291
2383
  }
2292
- yield this.removeStoredPendingSessionRequest();
2293
- this.notifyCallbacks({
2294
- method: "wallet_sessionChanged",
2295
- params: walletSession
2296
- });
2297
- return resumeResolve();
2298
- } catch (err) {
2299
- return resumeReject(err);
2384
+ throw error;
2300
2385
  }
2301
2386
  });
2302
2387
  }
2303
- init() {
2388
+ /**
2389
+ * Responds directly from the SDK's session state.
2390
+ *
2391
+ * @param options
2392
+ */
2393
+ handleWithSdkState(options) {
2304
2394
  return __async(this, null, function* () {
2395
+ console.warn(
2396
+ `Method "${options.request.method}" is configured for SDK state handling, but this is not yet implemented. Falling back to wallet passthrough.`
2397
+ );
2398
+ return this.handleWithWallet(options);
2399
+ });
2400
+ }
2401
+ };
2402
+ _RequestRouter_instances = new WeakSet();
2403
+ withAnalyticsTracking_fn = function(options, execute) {
2404
+ return __async(this, null, function* () {
2405
+ var _a3;
2406
+ yield __privateMethod(this, _RequestRouter_instances, trackWalletActionRequested_fn).call(this, options);
2407
+ try {
2408
+ const result = yield execute();
2409
+ yield __privateMethod(this, _RequestRouter_instances, trackWalletActionSucceeded_fn).call(this, options);
2410
+ return result;
2411
+ } catch (error) {
2412
+ const isRejection = isRejectionError(error);
2413
+ if (isRejection) {
2414
+ yield __privateMethod(this, _RequestRouter_instances, trackWalletActionRejected_fn).call(this, options);
2415
+ } else {
2416
+ yield __privateMethod(this, _RequestRouter_instances, trackWalletActionFailed_fn).call(this, options, error);
2417
+ }
2418
+ if (error instanceof RPCInvokeMethodErr) {
2419
+ throw error;
2420
+ }
2421
+ const castError = error;
2422
+ throw new RPCInvokeMethodErr(
2423
+ (_a3 = castError.message) != null ? _a3 : "Unknown error",
2424
+ castError.code
2425
+ );
2426
+ }
2427
+ });
2428
+ };
2429
+ trackWalletActionRequested_fn = function(options) {
2430
+ return __async(this, null, function* () {
2431
+ const props = yield getWalletActionAnalyticsProperties(
2432
+ this.config,
2433
+ this.config.storage,
2434
+ options,
2435
+ this.transportType
2436
+ );
2437
+ analytics.track("mmconnect_wallet_action_requested", props);
2438
+ });
2439
+ };
2440
+ trackWalletActionSucceeded_fn = function(options) {
2441
+ return __async(this, null, function* () {
2442
+ const props = yield getWalletActionAnalyticsProperties(
2443
+ this.config,
2444
+ this.config.storage,
2445
+ options,
2446
+ this.transportType
2447
+ );
2448
+ analytics.track("mmconnect_wallet_action_succeeded", props);
2449
+ });
2450
+ };
2451
+ trackWalletActionFailed_fn = function(options, error) {
2452
+ return __async(this, null, function* () {
2453
+ const props = yield getWalletActionAnalyticsProperties(
2454
+ this.config,
2455
+ this.config.storage,
2456
+ options,
2457
+ this.transportType,
2458
+ extractErrorDiagnostics(error)
2459
+ );
2460
+ analytics.track("mmconnect_wallet_action_failed", props);
2461
+ });
2462
+ };
2463
+ trackWalletActionRejected_fn = function(options) {
2464
+ return __async(this, null, function* () {
2465
+ const props = yield getWalletActionAnalyticsProperties(
2466
+ this.config,
2467
+ this.config.storage,
2468
+ options,
2469
+ this.transportType
2470
+ );
2471
+ analytics.track("mmconnect_wallet_action_rejected", props);
2472
+ });
2473
+ };
2474
+
2475
+ // src/multichain/transports/default/index.ts
2476
+ init_utils2();
2477
+ import {
2478
+ getDefaultTransport
2479
+ } from "@metamask/multichain-api-client";
2480
+ var DEFAULT_REQUEST_TIMEOUT = 60 * 1e3;
2481
+ var _notificationCallbacks, _transport, _defaultRequestOptions, _pendingRequests, _handleResponseListener, _handleNotificationListener, _DefaultTransport_instances, notifyCallbacks_fn, isMetamaskProviderEvent_fn, handleResponse_fn, handleNotification_fn, setupMessageListener_fn, init_fn;
2482
+ var DefaultTransport = class {
2483
+ constructor() {
2484
+ __privateAdd(this, _DefaultTransport_instances);
2485
+ __privateAdd(this, _notificationCallbacks, /* @__PURE__ */ new Set());
2486
+ __privateAdd(this, _transport, getDefaultTransport());
2487
+ __privateAdd(this, _defaultRequestOptions, {
2488
+ timeout: DEFAULT_REQUEST_TIMEOUT
2305
2489
  });
2490
+ __privateAdd(this, _pendingRequests, /* @__PURE__ */ new Map());
2491
+ __privateAdd(this, _handleResponseListener);
2492
+ __privateAdd(this, _handleNotificationListener);
2306
2493
  }
2307
- // TODO: Rename this
2308
2494
  sendEip1193Message(payload, options) {
2309
2495
  return __async(this, null, function* () {
2496
+ __privateMethod(this, _DefaultTransport_instances, setupMessageListener_fn).call(this);
2497
+ const requestId = String(getUniqueRequestId());
2310
2498
  const request = __spreadValues({
2311
2499
  jsonrpc: "2.0",
2312
- id: String(getUniqueRequestId())
2500
+ id: requestId
2313
2501
  }, payload);
2314
- const cachedWalletSession = yield this.getCachedResponse(request);
2315
- if (cachedWalletSession) {
2316
- this.notifyCallbacks(cachedWalletSession);
2317
- return cachedWalletSession;
2318
- }
2319
2502
  return new Promise((resolve, reject) => {
2320
2503
  var _a3;
2321
2504
  const timeout = setTimeout(() => {
2322
- this.rejectRequest(request.id, new TransportTimeoutError());
2323
- }, (_a3 = options == null ? void 0 : options.timeout) != null ? _a3 : this.options.requestTimeout);
2324
- this.pendingRequests.set(request.id, {
2325
- request,
2326
- method: request.method,
2327
- resolve: (response) => __async(this, null, function* () {
2328
- yield this.storeWalletSession(request, response);
2329
- return resolve(response);
2330
- }),
2505
+ __privateGet(this, _pendingRequests).delete(requestId);
2506
+ reject(new Error("Request timeout"));
2507
+ }, (_a3 = options == null ? void 0 : options.timeout) != null ? _a3 : __privateGet(this, _defaultRequestOptions).timeout);
2508
+ __privateGet(this, _pendingRequests).set(requestId, {
2509
+ resolve: (response) => {
2510
+ resolve(response);
2511
+ },
2331
2512
  reject,
2332
2513
  timeout
2333
2514
  });
2334
- this.dappClient.sendRequest({
2335
- name: "metamask-provider",
2336
- data: request
2337
- }).catch(reject);
2515
+ window.postMessage(
2516
+ {
2517
+ target: "metamask-contentscript",
2518
+ data: {
2519
+ name: "metamask-provider",
2520
+ data: request
2521
+ }
2522
+ },
2523
+ // eslint-disable-next-line no-restricted-globals
2524
+ location.origin
2525
+ );
2526
+ });
2527
+ });
2528
+ }
2529
+ init() {
2530
+ return __async(this, null, function* () {
2531
+ yield __privateMethod(this, _DefaultTransport_instances, init_fn).call(this);
2532
+ let walletSession = { sessionScopes: {} };
2533
+ try {
2534
+ const sessionRequest = yield this.request(
2535
+ { method: "wallet_getSession" },
2536
+ __privateGet(this, _defaultRequestOptions)
2537
+ );
2538
+ walletSession = sessionRequest.result;
2539
+ } catch (e) {
2540
+ console.error(
2541
+ "Failed to get wallet session during DefaultTransport init"
2542
+ );
2543
+ }
2544
+ __privateMethod(this, _DefaultTransport_instances, notifyCallbacks_fn).call(this, {
2545
+ method: "wallet_sessionChanged",
2546
+ params: walletSession
2338
2547
  });
2339
2548
  });
2340
2549
  }
2341
2550
  connect(options) {
2342
2551
  return __async(this, null, function* () {
2343
- const { dappClient } = this;
2344
- const session = yield this.getActiveSession();
2345
- if (session) {
2346
- logger("active session found", {
2347
- id: session.id,
2348
- channel: session.channel,
2349
- expiresAt: session.expiresAt
2350
- });
2552
+ var _a3, _b, _c, _d, _e;
2553
+ yield __privateMethod(this, _DefaultTransport_instances, init_fn).call(this);
2554
+ const sessionRequest = yield this.request(
2555
+ { method: "wallet_getSession" },
2556
+ __privateGet(this, _defaultRequestOptions)
2557
+ );
2558
+ if (sessionRequest.error) {
2559
+ throw new Error(sessionRequest.error.message);
2351
2560
  }
2352
- const storedSessionRequestBeforeConnectionAttempt = yield this.getStoredPendingSessionRequest();
2353
- let timeout;
2354
- let initialConnectionMessageHandler;
2355
- const connectionPromise = new Promise((resolve, reject) => __async(this, null, function* () {
2356
- let connection;
2357
- if (session) {
2358
- connection = new Promise((resumeResolve, resumeReject) => {
2359
- var _a3;
2360
- if (this.dappClient.state === "CONNECTED") {
2361
- this.onResumeSuccess(resumeResolve, resumeReject, options);
2362
- } else {
2363
- this.dappClient.once("connected", () => __async(this, null, function* () {
2364
- this.onResumeSuccess(resumeResolve, resumeReject, options);
2365
- }));
2366
- dappClient.resume((_a3 = session == null ? void 0 : session.id) != null ? _a3 : "");
2367
- }
2368
- });
2369
- } else {
2370
- connection = new Promise(
2371
- (resolveConnection, rejectConnection) => {
2372
- var _a3, _b;
2373
- const optionalScopes = addValidAccounts(
2374
- getOptionalScopes((_a3 = options == null ? void 0 : options.scopes) != null ? _a3 : []),
2375
- getValidAccounts((_b = options == null ? void 0 : options.caipAccountIds) != null ? _b : [])
2376
- );
2377
- const sessionRequest = {
2378
- optionalScopes,
2379
- sessionProperties: options == null ? void 0 : options.sessionProperties
2380
- };
2381
- const request = {
2382
- jsonrpc: "2.0",
2383
- id: String(getUniqueRequestId()),
2384
- method: "wallet_createSession",
2385
- params: sessionRequest
2386
- };
2387
- initialConnectionMessageHandler = (message) => __async(this, null, function* () {
2388
- if (typeof message !== "object" || message === null) {
2389
- return;
2390
- }
2391
- if (!("data" in message)) {
2392
- return;
2393
- }
2394
- const messagePayload = message.data;
2395
- const isMatchingId = messagePayload.id === request.id;
2396
- const isMatchingMethod = messagePayload.method === "wallet_createSession" || messagePayload.method === "wallet_sessionChanged";
2397
- if (!isMatchingId && !isMatchingMethod) {
2398
- return;
2399
- }
2400
- if (messagePayload.error) {
2401
- return rejectConnection(
2402
- this.parseWalletError(messagePayload.error)
2403
- );
2404
- }
2405
- yield this.storeWalletSession(
2406
- request,
2407
- messagePayload
2408
- );
2409
- yield this.removeStoredPendingSessionRequest();
2410
- this.notifyCallbacks(messagePayload);
2411
- return resolveConnection();
2412
- });
2413
- this.dappClient.on("message", initialConnectionMessageHandler);
2414
- dappClient.connect({
2415
- mode: "trusted",
2416
- initialPayload: {
2417
- name: MULTICHAIN_PROVIDER_STREAM_NAME,
2418
- data: request
2419
- }
2420
- }).catch((error) => {
2421
- if (initialConnectionMessageHandler) {
2422
- this.dappClient.off(
2423
- "message",
2424
- initialConnectionMessageHandler
2425
- );
2426
- }
2427
- rejectConnection(error);
2428
- });
2429
- }
2561
+ let walletSession = sessionRequest.result;
2562
+ const createSessionParams = {
2563
+ optionalScopes: addValidAccounts(
2564
+ getOptionalScopes((_a3 = options == null ? void 0 : options.scopes) != null ? _a3 : []),
2565
+ getValidAccounts((_b = options == null ? void 0 : options.caipAccountIds) != null ? _b : [])
2566
+ ),
2567
+ sessionProperties: options == null ? void 0 : options.sessionProperties
2568
+ };
2569
+ if (walletSession && options && !options.forceRequest) {
2570
+ const currentScopes = Object.keys(
2571
+ (_c = walletSession == null ? void 0 : walletSession.sessionScopes) != null ? _c : {}
2572
+ );
2573
+ const proposedScopes = (_d = options == null ? void 0 : options.scopes) != null ? _d : [];
2574
+ const proposedCaipAccountIds = (_e = options == null ? void 0 : options.caipAccountIds) != null ? _e : [];
2575
+ const hasSameScopesAndAccounts = isSameScopesAndAccounts(
2576
+ currentScopes,
2577
+ proposedScopes,
2578
+ walletSession,
2579
+ proposedCaipAccountIds
2580
+ );
2581
+ if (!hasSameScopesAndAccounts) {
2582
+ const response = yield this.request(
2583
+ { method: "wallet_createSession", params: createSessionParams },
2584
+ __privateGet(this, _defaultRequestOptions)
2430
2585
  );
2586
+ if (response.error) {
2587
+ throw new Error(response.error.message);
2588
+ }
2589
+ walletSession = response.result;
2431
2590
  }
2432
- timeout = setTimeout(
2433
- () => {
2434
- reject(new TransportTimeoutError());
2435
- },
2436
- storedSessionRequestBeforeConnectionAttempt ? this.options.resumeTimeout : this.options.connectionTimeout
2591
+ } else if (!walletSession || (options == null ? void 0 : options.forceRequest)) {
2592
+ const response = yield this.request(
2593
+ { method: "wallet_createSession", params: createSessionParams },
2594
+ __privateGet(this, _defaultRequestOptions)
2437
2595
  );
2438
- connection.then(resolve).catch(reject);
2439
- }));
2440
- return connectionPromise.catch((error) => __async(this, null, function* () {
2441
- yield this.dappClient.disconnect();
2442
- throw error;
2443
- })).finally(() => {
2444
- if (timeout) {
2445
- clearTimeout(timeout);
2446
- }
2447
- if (initialConnectionMessageHandler) {
2448
- this.dappClient.off("message", initialConnectionMessageHandler);
2449
- initialConnectionMessageHandler = void 0;
2596
+ if (response.error) {
2597
+ throw new Error(response.error.message);
2450
2598
  }
2451
- this.removeStoredPendingSessionRequest();
2599
+ walletSession = response.result;
2600
+ }
2601
+ __privateMethod(this, _DefaultTransport_instances, notifyCallbacks_fn).call(this, {
2602
+ method: "wallet_sessionChanged",
2603
+ params: walletSession
2452
2604
  });
2453
2605
  });
2454
2606
  }
2455
- /**
2456
- * Disconnects from the Mobile Wallet Protocol
2457
- *
2458
- * @param [scopes] - The scopes to revoke. If not provided or empty, all scopes will be revoked.
2459
- * @returns Nothing
2460
- */
2461
2607
  disconnect() {
2462
2608
  return __async(this, arguments, function* (scopes = []) {
2463
- var _a3, _b;
2464
- const cachedSession = yield this.getCachedResponse({
2465
- jsonrpc: "2.0",
2466
- id: "0",
2467
- method: "wallet_getSession"
2468
- });
2469
- const cachedSessionScopes = (_b = (_a3 = cachedSession == null ? void 0 : cachedSession.result) == null ? void 0 : _a3.sessionScopes) != null ? _b : {};
2470
- const remainingScopes = scopes.length === 0 ? [] : Object.keys(cachedSessionScopes).filter(
2471
- (scope) => !scopes.includes(scope)
2472
- );
2473
- const newSessionScopes = Object.fromEntries(
2474
- Object.entries(cachedSessionScopes).filter(
2475
- ([key]) => remainingScopes.includes(key)
2476
- )
2609
+ yield this.request({ method: "wallet_revokeSession", params: { scopes } });
2610
+ });
2611
+ }
2612
+ isConnected() {
2613
+ return __privateGet(this, _transport).isConnected();
2614
+ }
2615
+ request(_0) {
2616
+ return __async(this, arguments, function* (request, options = __privateGet(this, _defaultRequestOptions)) {
2617
+ return __privateGet(this, _transport).request(request, options);
2618
+ });
2619
+ }
2620
+ onNotification(callback) {
2621
+ __privateGet(this, _transport).onNotification(callback);
2622
+ __privateGet(this, _notificationCallbacks).add(callback);
2623
+ return () => {
2624
+ __privateGet(this, _notificationCallbacks).delete(callback);
2625
+ };
2626
+ }
2627
+ getActiveSession() {
2628
+ return __async(this, null, function* () {
2629
+ throw new Error(
2630
+ "getActiveSession is purposely not implemented for the DefaultTransport"
2477
2631
  );
2478
- this.request({ method: "wallet_revokeSession", params: { scopes } }).catch(
2479
- (err) => {
2480
- console.error("error revoking session", err);
2481
- }
2632
+ });
2633
+ }
2634
+ getStoredPendingSessionRequest() {
2635
+ return __async(this, null, function* () {
2636
+ throw new Error(
2637
+ "getStoredPendingSessionRequest is purposely not implemented for the DefaultTransport"
2482
2638
  );
2483
- const remainingScopesIncludeEip155 = remainingScopes.some(
2484
- (scope) => scope.includes("eip155")
2639
+ });
2640
+ }
2641
+ };
2642
+ _notificationCallbacks = new WeakMap();
2643
+ _transport = new WeakMap();
2644
+ _defaultRequestOptions = new WeakMap();
2645
+ _pendingRequests = new WeakMap();
2646
+ _handleResponseListener = new WeakMap();
2647
+ _handleNotificationListener = new WeakMap();
2648
+ _DefaultTransport_instances = new WeakSet();
2649
+ notifyCallbacks_fn = function(data) {
2650
+ for (const callback of __privateGet(this, _notificationCallbacks)) {
2651
+ try {
2652
+ callback(data);
2653
+ } catch (error) {
2654
+ console.log(
2655
+ "[WindowPostMessageTransport] notifyCallbacks error:",
2656
+ error
2485
2657
  );
2486
- if (!remainingScopesIncludeEip155) {
2487
- this.kvstore.delete(ACCOUNTS_STORE_KEY);
2488
- this.kvstore.delete(CHAIN_STORE_KEY);
2489
- }
2490
- if (remainingScopes.length > 0) {
2491
- this.kvstore.set(
2492
- SESSION_STORE_KEY,
2493
- JSON.stringify({
2494
- result: {
2495
- sessionScopes: newSessionScopes
2496
- }
2497
- })
2658
+ }
2659
+ }
2660
+ };
2661
+ isMetamaskProviderEvent_fn = function(event) {
2662
+ var _a3, _b;
2663
+ return ((_b = (_a3 = event == null ? void 0 : event.data) == null ? void 0 : _a3.data) == null ? void 0 : _b.name) === "metamask-provider" && // eslint-disable-next-line no-restricted-globals
2664
+ event.origin === location.origin;
2665
+ };
2666
+ handleResponse_fn = function(event) {
2667
+ var _a3, _b;
2668
+ if (!__privateMethod(this, _DefaultTransport_instances, isMetamaskProviderEvent_fn).call(this, event)) {
2669
+ return;
2670
+ }
2671
+ const responseData = (_b = (_a3 = event == null ? void 0 : event.data) == null ? void 0 : _a3.data) == null ? void 0 : _b.data;
2672
+ if (typeof responseData === "object" && responseData !== null && "method" in responseData) {
2673
+ return;
2674
+ }
2675
+ if (typeof responseData === "object" && responseData !== null && "id" in responseData && ("result" in responseData || "error" in responseData)) {
2676
+ const responseId = String(responseData.id);
2677
+ const pendingRequest = __privateGet(this, _pendingRequests).get(responseId);
2678
+ if (pendingRequest) {
2679
+ clearTimeout(pendingRequest.timeout);
2680
+ __privateGet(this, _pendingRequests).delete(responseId);
2681
+ const response = responseData;
2682
+ if ("error" in response && response.error) {
2683
+ const error = new Error(
2684
+ response.error.message || "Request failed"
2498
2685
  );
2499
- } else {
2500
- this.kvstore.delete(SESSION_STORE_KEY);
2501
- if (typeof window !== "undefined" && typeof window.removeEventListener !== "undefined" && this.windowFocusHandler) {
2502
- window.removeEventListener("focus", this.windowFocusHandler);
2503
- this.windowFocusHandler = void 0;
2686
+ if (typeof response.error.code === "number") {
2687
+ error.code = response.error.code;
2504
2688
  }
2505
- yield this.dappClient.disconnect();
2689
+ pendingRequest.reject(error);
2690
+ } else {
2691
+ pendingRequest.resolve(response);
2506
2692
  }
2507
- this.notifyCallbacks({
2508
- method: "wallet_sessionChanged",
2509
- params: {
2510
- sessionScopes: newSessionScopes
2511
- }
2512
- });
2513
- });
2693
+ }
2514
2694
  }
2515
- /**
2516
- * Checks if the transport is connected
2517
- *
2518
- * @returns True if transport is connected, false otherwise
2519
- */
2520
- isConnected() {
2521
- return this.dappClient.state === "CONNECTED";
2695
+ };
2696
+ handleNotification_fn = function(event) {
2697
+ var _a3, _b;
2698
+ if (!__privateMethod(this, _DefaultTransport_instances, isMetamaskProviderEvent_fn).call(this, event)) {
2699
+ return;
2522
2700
  }
2523
- /**
2524
- * Attempts to re-establish a connection via DappClient
2525
- *
2526
- * @returns Nothing
2527
- */
2528
- // TODO: We should re-evaluate adding this to the WebSocketTransport layer from `@metamask/mobile-wallet-protocol-core`
2529
- // ticket: https://consensyssoftware.atlassian.net/browse/WAPI-862
2530
- attemptResumeSession() {
2531
- return __async(this, null, function* () {
2532
- try {
2533
- yield this.dappClient.reconnect();
2534
- yield new Promise((resolve, reject) => {
2535
- const timeout = setTimeout(() => {
2536
- reject(new Error("Resume timeout"));
2537
- }, 2e3);
2538
- if (this.isConnected()) {
2539
- clearTimeout(timeout);
2540
- resolve();
2541
- } else {
2542
- this.dappClient.once("connected", () => {
2543
- clearTimeout(timeout);
2544
- resolve();
2545
- });
2546
- }
2547
- });
2548
- } catch (error) {
2549
- return Promise.reject(
2550
- new Error(`Failed to resume session: ${error.message}`)
2551
- );
2552
- }
2701
+ const responseData = (_b = (_a3 = event == null ? void 0 : event.data) == null ? void 0 : _a3.data) == null ? void 0 : _b.data;
2702
+ if (typeof responseData === "object" && responseData !== null && "method" in responseData) {
2703
+ __privateMethod(this, _DefaultTransport_instances, notifyCallbacks_fn).call(this, responseData);
2704
+ }
2705
+ };
2706
+ setupMessageListener_fn = function() {
2707
+ if (__privateGet(this, _handleResponseListener)) {
2708
+ return;
2709
+ }
2710
+ __privateSet(this, _handleResponseListener, __privateMethod(this, _DefaultTransport_instances, handleResponse_fn).bind(this));
2711
+ __privateSet(this, _handleNotificationListener, __privateMethod(this, _DefaultTransport_instances, handleNotification_fn).bind(this));
2712
+ window.addEventListener("message", __privateGet(this, _handleResponseListener));
2713
+ window.addEventListener("message", __privateGet(this, _handleNotificationListener));
2714
+ };
2715
+ init_fn = function() {
2716
+ return __async(this, null, function* () {
2717
+ __privateMethod(this, _DefaultTransport_instances, setupMessageListener_fn).call(this);
2718
+ if (!__privateGet(this, _transport).isConnected()) {
2719
+ yield __privateGet(this, _transport).connect();
2720
+ }
2721
+ });
2722
+ };
2723
+
2724
+ // src/multichain/transports/multichainApiClientWrapper/index.ts
2725
+ init_utils2();
2726
+ import { providerErrors } from "@metamask/rpc-errors";
2727
+ var _notificationCallbacks2, _MultichainApiClientWrapperTransport_instances, walletCreateSession_fn, walletGetSession_fn, walletRevokeSession_fn, walletInvokeMethod_fn;
2728
+ var MultichainApiClientWrapperTransport = class {
2729
+ constructor(metamaskConnectMultichain) {
2730
+ this.metamaskConnectMultichain = metamaskConnectMultichain;
2731
+ __privateAdd(this, _MultichainApiClientWrapperTransport_instances);
2732
+ __privateAdd(this, _notificationCallbacks2, /* @__PURE__ */ new Set());
2733
+ }
2734
+ isTransportDefined() {
2735
+ try {
2736
+ return Boolean(this.metamaskConnectMultichain.transport);
2737
+ } catch (_error) {
2738
+ return false;
2739
+ }
2740
+ }
2741
+ isTransportConnected() {
2742
+ return this.isTransportDefined() && this.metamaskConnectMultichain.transport.isConnected();
2743
+ }
2744
+ clearNotificationCallbacks() {
2745
+ __privateGet(this, _notificationCallbacks2).clear();
2746
+ }
2747
+ notifyCallbacks(data) {
2748
+ __privateGet(this, _notificationCallbacks2).forEach((callback) => {
2749
+ callback(data);
2553
2750
  });
2554
2751
  }
2555
- getCachedResponse(request) {
2752
+ clearTransportNotificationListener() {
2753
+ var _a3;
2754
+ (_a3 = this.notificationListener) == null ? void 0 : _a3.call(this);
2755
+ this.notificationListener = void 0;
2756
+ }
2757
+ setupTransportNotificationListener() {
2758
+ if (!this.isTransportDefined() || this.notificationListener) {
2759
+ return;
2760
+ }
2761
+ this.notificationListener = this.metamaskConnectMultichain.transport.onNotification(
2762
+ this.notifyCallbacks.bind(this)
2763
+ );
2764
+ }
2765
+ // Purposely noop, resolves successfully. Actual connection is handled by the underlying client/transport.
2766
+ connect() {
2556
2767
  return __async(this, null, function* () {
2557
- var _a3;
2558
- if (request.method === "wallet_getSession") {
2559
- const walletGetSession = yield this.kvstore.get(SESSION_STORE_KEY);
2560
- if (walletGetSession) {
2561
- const walletSession = JSON.parse(walletGetSession);
2562
- return {
2563
- id: request.id,
2564
- jsonrpc: "2.0",
2565
- result: (_a3 = walletSession.params) != null ? _a3 : walletSession.result,
2566
- // "what?... why walletSession.params?.."
2567
- method: request.method
2568
- };
2569
- }
2570
- } else if (request.method === "eth_accounts") {
2571
- const ethAccounts = yield this.kvstore.get(ACCOUNTS_STORE_KEY);
2572
- if (ethAccounts) {
2573
- return {
2574
- id: request.id,
2575
- jsonrpc: "2.0",
2576
- result: JSON.parse(ethAccounts),
2577
- method: request.method
2578
- };
2579
- }
2580
- } else if (request.method === "eth_chainId") {
2581
- const ethChainId = yield this.kvstore.get(CHAIN_STORE_KEY);
2582
- if (ethChainId) {
2583
- return {
2584
- id: request.id,
2585
- jsonrpc: "2.0",
2586
- result: JSON.parse(ethChainId),
2587
- method: request.method
2588
- };
2589
- }
2590
- }
2768
+ return Promise.resolve();
2591
2769
  });
2592
2770
  }
2593
- storeWalletSession(request, response) {
2771
+ // Purposely noop, resolves successfully. Actual connection is handled by the underlying client/transport.
2772
+ disconnect() {
2594
2773
  return __async(this, null, function* () {
2595
- if (response.error) {
2596
- return;
2597
- }
2598
- if (CACHED_METHOD_LIST.includes(request.method)) {
2599
- yield this.kvstore.set(SESSION_STORE_KEY, JSON.stringify(response));
2600
- } else if (request.method === "eth_accounts") {
2601
- yield this.kvstore.set(
2602
- ACCOUNTS_STORE_KEY,
2603
- JSON.stringify(response.result)
2604
- );
2605
- } else if (request.method === "eth_chainId") {
2606
- yield this.kvstore.set(CHAIN_STORE_KEY, JSON.stringify(response.result));
2607
- } else if (CACHED_RESET_METHOD_LIST.includes(request.method)) {
2608
- yield this.kvstore.delete(SESSION_STORE_KEY);
2609
- yield this.kvstore.delete(ACCOUNTS_STORE_KEY);
2610
- yield this.kvstore.delete(CHAIN_STORE_KEY);
2611
- }
2774
+ return Promise.resolve();
2612
2775
  });
2613
2776
  }
2614
- request(payload, options) {
2615
- return __async(this, null, function* () {
2616
- const request = __spreadValues({
2617
- jsonrpc: "2.0",
2618
- id: String(getUniqueRequestId())
2619
- }, payload);
2620
- const cachedWalletSession = yield this.getCachedResponse(request);
2621
- if (cachedWalletSession) {
2622
- this.notifyCallbacks(cachedWalletSession);
2623
- return cachedWalletSession;
2624
- }
2625
- if (!this.isConnected()) {
2626
- yield this.attemptResumeSession();
2777
+ // Purposely hardcoded to true. Actual connection is handled by the underlying client/transport.
2778
+ isConnected() {
2779
+ return true;
2780
+ }
2781
+ request(_0) {
2782
+ return __async(this, arguments, function* (params, _options = {}) {
2783
+ const id = getUniqueRequestId();
2784
+ const requestPayload = __spreadValues({
2785
+ id,
2786
+ jsonrpc: "2.0"
2787
+ }, params);
2788
+ switch (requestPayload.method) {
2789
+ case "wallet_createSession":
2790
+ return __privateMethod(this, _MultichainApiClientWrapperTransport_instances, walletCreateSession_fn).call(this, requestPayload);
2791
+ case "wallet_getSession":
2792
+ return __privateMethod(this, _MultichainApiClientWrapperTransport_instances, walletGetSession_fn).call(this, requestPayload);
2793
+ case "wallet_revokeSession":
2794
+ return __privateMethod(this, _MultichainApiClientWrapperTransport_instances, walletRevokeSession_fn).call(this, requestPayload);
2795
+ case "wallet_invokeMethod":
2796
+ return __privateMethod(this, _MultichainApiClientWrapperTransport_instances, walletInvokeMethod_fn).call(this, requestPayload);
2797
+ default:
2798
+ throw new Error(`Unsupported method: ${requestPayload.method}`);
2627
2799
  }
2628
- return new Promise((resolve, reject) => {
2629
- var _a3;
2630
- const timeout = setTimeout(() => {
2631
- this.rejectRequest(request.id, new TransportTimeoutError());
2632
- }, (_a3 = options == null ? void 0 : options.timeout) != null ? _a3 : this.options.requestTimeout);
2633
- this.pendingRequests.set(request.id, {
2634
- request,
2635
- method: request.method,
2636
- resolve: (response) => __async(this, null, function* () {
2637
- yield this.storeWalletSession(request, response);
2638
- return resolve(response);
2639
- }),
2640
- reject,
2641
- timeout
2642
- });
2643
- this.dappClient.sendRequest({
2644
- name: MULTICHAIN_PROVIDER_STREAM_NAME,
2645
- data: request
2646
- }).catch(reject);
2647
- });
2648
2800
  });
2649
2801
  }
2650
2802
  onNotification(callback) {
2651
- this.notificationCallbacks.add(callback);
2803
+ this.setupTransportNotificationListener();
2804
+ __privateGet(this, _notificationCallbacks2).add(callback);
2652
2805
  return () => {
2653
- this.notificationCallbacks.delete(callback);
2806
+ __privateGet(this, _notificationCallbacks2).delete(callback);
2654
2807
  };
2655
2808
  }
2656
- getActiveSession() {
2657
- return __async(this, null, function* () {
2658
- const { kvstore } = this;
2659
- const sessionStore = yield SessionStore.create(kvstore);
2660
- try {
2661
- const [activeSession] = yield sessionStore.list();
2662
- return activeSession;
2663
- } catch (error) {
2664
- logger("error getting active session", error);
2665
- return void 0;
2809
+ };
2810
+ _notificationCallbacks2 = new WeakMap();
2811
+ _MultichainApiClientWrapperTransport_instances = new WeakSet();
2812
+ walletCreateSession_fn = function(request) {
2813
+ return __async(this, null, function* () {
2814
+ const createSessionParams = request.params;
2815
+ const scopes = Object.keys(__spreadValues(__spreadValues({}, createSessionParams.optionalScopes), createSessionParams.requiredScopes));
2816
+ const scopeAccounts = [];
2817
+ scopes.forEach((scope) => {
2818
+ var _a3, _b, _c, _d;
2819
+ const requiredScope = (_a3 = createSessionParams.requiredScopes) == null ? void 0 : _a3[scope];
2820
+ const optionalScope = (_b = createSessionParams.optionalScopes) == null ? void 0 : _b[scope];
2821
+ if (requiredScope) {
2822
+ scopeAccounts.push(...(_c = requiredScope.accounts) != null ? _c : []);
2666
2823
  }
2667
- });
2668
- }
2669
- // This method checks if an existing CAIP session response is cached or waits for one
2670
- // to be received from the wallet if not cached. This is necessary because there is an edge
2671
- // case during the initial connection flow where after the user has accepted the permission approval
2672
- // and returned back to the dapp from the wallet, the dapp page may have gotten unloaded and refreshed.
2673
- // When it is unloaded and refreshed, it will try to resume the session by making a request for wallet_getSession
2674
- // which should resolve from cache, but because a race condition makes it possible for the response from the wallet
2675
- // for the initial wallet_createSession connection request to not have been handled and cached yet. This results
2676
- // in the wallet_getSession request never resolving unless we wait for it explicitly as done in this method.
2677
- waitForWalletSessionIfNotCached() {
2678
- return __async(this, null, function* () {
2679
- const cachedWalletGetSessionResponse = yield this.kvstore.get(SESSION_STORE_KEY);
2680
- if (cachedWalletGetSessionResponse) {
2681
- return;
2824
+ if (optionalScope) {
2825
+ scopeAccounts.push(...(_d = optionalScope.accounts) != null ? _d : []);
2682
2826
  }
2683
- let unsubscribe;
2684
- const responsePromise = new Promise((resolve) => {
2685
- unsubscribe = this.onNotification((message) => {
2686
- if (typeof message === "object" && message !== null) {
2687
- if ("data" in message) {
2688
- const messagePayload = message.data;
2689
- if (messagePayload.method === "wallet_getSession" || messagePayload.method === "wallet_sessionChanged") {
2690
- unsubscribe();
2691
- resolve();
2692
- }
2693
- }
2694
- }
2695
- });
2696
- });
2697
- const timeoutPromise = new Promise((_resolve, reject) => {
2698
- setTimeout(() => {
2699
- unsubscribe();
2700
- this.removeStoredPendingSessionRequest();
2701
- reject(new TransportTimeoutError());
2702
- }, this.options.resumeTimeout);
2703
- });
2704
- return Promise.race([responsePromise, timeoutPromise]);
2705
2827
  });
2706
- }
2828
+ const accounts = [...new Set(scopeAccounts)];
2829
+ yield this.metamaskConnectMultichain.connect(
2830
+ scopes,
2831
+ accounts,
2832
+ createSessionParams.sessionProperties
2833
+ );
2834
+ return this.metamaskConnectMultichain.transport.request({
2835
+ method: "wallet_getSession"
2836
+ });
2837
+ });
2707
2838
  };
2708
-
2709
- // src/multichain/transports/mwp/KeyManager.ts
2710
- import { decrypt, encrypt, PrivateKey, PublicKey } from "eciesjs";
2711
- var KeyManager = class {
2712
- generateKeyPair() {
2713
- const privateKey = new PrivateKey();
2839
+ walletGetSession_fn = function(request) {
2840
+ return __async(this, null, function* () {
2841
+ if (!this.isTransportConnected()) {
2842
+ return {
2843
+ jsonrpc: "2.0",
2844
+ id: request.id,
2845
+ result: {
2846
+ sessionScopes: {}
2847
+ }
2848
+ };
2849
+ }
2850
+ return this.metamaskConnectMultichain.transport.request({
2851
+ method: "wallet_getSession"
2852
+ });
2853
+ });
2854
+ };
2855
+ walletRevokeSession_fn = function(request) {
2856
+ return __async(this, null, function* () {
2857
+ var _a3;
2858
+ const revokeSessionParams = request.params;
2859
+ const scopes = (_a3 = revokeSessionParams == null ? void 0 : revokeSessionParams.scopes) != null ? _a3 : [];
2860
+ try {
2861
+ yield this.metamaskConnectMultichain.disconnect(scopes);
2862
+ return { jsonrpc: "2.0", id: request.id, result: true };
2863
+ } catch (_error) {
2864
+ return { jsonrpc: "2.0", id: request.id, result: false };
2865
+ }
2866
+ });
2867
+ };
2868
+ walletInvokeMethod_fn = function(request) {
2869
+ return __async(this, null, function* () {
2870
+ if (!this.isTransportConnected()) {
2871
+ return { error: providerErrors.unauthorized() };
2872
+ }
2873
+ const result = this.metamaskConnectMultichain.invokeMethod(
2874
+ request.params
2875
+ );
2714
2876
  return {
2715
- privateKey: new Uint8Array(privateKey.secret),
2716
- publicKey: privateKey.publicKey.toBytes(true)
2877
+ result
2717
2878
  };
2718
- }
2719
- encrypt(plaintext, theirPublicKey) {
2720
- return __async(this, null, function* () {
2721
- const plaintextBuffer = Buffer.from(plaintext, "utf8");
2722
- const encryptedBuffer = encrypt(theirPublicKey, plaintextBuffer);
2723
- return encryptedBuffer.toString("base64");
2724
- });
2725
- }
2726
- decrypt(encryptedB64, myPrivateKey) {
2727
- return __async(this, null, function* () {
2728
- const encryptedBuffer = Buffer.from(encryptedB64, "base64");
2729
- const decryptedBuffer = yield decrypt(myPrivateKey, encryptedBuffer);
2730
- return Buffer.from(decryptedBuffer).toString("utf8");
2731
- });
2732
- }
2733
- validatePeerKey(key) {
2734
- PublicKey.fromHex(Buffer.from(key).toString("hex"));
2735
- }
2879
+ });
2736
2880
  };
2737
- var keymanager = new KeyManager();
2738
2881
 
2739
2882
  // src/multichain/index.ts
2740
2883
  init_utils2();
2741
2884
  var logger2 = createLogger("metamask-sdk:core");
2742
2885
  var SINGLETON_KEY = "__METAMASK_CONNECT_MULTICHAIN_SINGLETON__";
2743
- var _a2, _provider, _providerTransportWrapper, _transport2, _dappClient, _beforeUnloadListener, _listener, _anonId, _sdkInfo, _MetaMaskConnectMultichain_instances, setupAnalytics_fn, onTransportNotification_fn, getStoredTransport_fn, setupTransport_fn, buildConnectionMetadata_fn, init_fn2, createDappClient_fn, setupMWP_fn, onBeforeUnload_fn, createBeforeUnloadListener_fn, renderInstallModalAsync_fn, showInstallModal_fn, headlessConnect_fn, setupDefaultTransport_fn, deeplinkConnect_fn, handleConnection_fn, getCaipSession_fn, openConnectDeeplinkIfNeeded_fn;
2886
+ var _a2, _provider, _providerTransportWrapper, _transport2, _dappClient, _beforeUnloadListener, _transportType, _listener, _anonId, _sdkInfo, _MetaMaskConnectMultichain_instances, setupAnalytics_fn, onTransportNotification_fn, getStoredTransport_fn, setupTransport_fn, buildConnectionMetadata_fn, init_fn2, createDappClient_fn, setupMWP_fn, onBeforeUnload_fn, createBeforeUnloadListener_fn, renderInstallModalAsync_fn, showInstallModal_fn, headlessConnect_fn, setupDefaultTransport_fn, deeplinkConnect_fn, handleConnection_fn, getCaipSession_fn, openConnectDeeplinkIfNeeded_fn;
2744
2887
  var _MetaMaskConnectMultichain = class _MetaMaskConnectMultichain extends MultichainCore {
2745
2888
  constructor(options) {
2746
2889
  var _a3, _b, _c, _d, _e, _f;
@@ -2758,7 +2901,7 @@ var _MetaMaskConnectMultichain = class _MetaMaskConnectMultichain extends Multic
2758
2901
  versions: __spreadValues({
2759
2902
  // typeof guard needed: Metro (React Native) bundles TS source directly,
2760
2903
  // bypassing the tsup build that substitutes __PACKAGE_VERSION__.
2761
- "connect-multichain": false ? "unknown" : "0.12.1"
2904
+ "connect-multichain": false ? "unknown" : "0.14.0"
2762
2905
  }, (_f = options.versions) != null ? _f : {})
2763
2906
  });
2764
2907
  super(allOptions);
@@ -2768,6 +2911,7 @@ var _MetaMaskConnectMultichain = class _MetaMaskConnectMultichain extends Multic
2768
2911
  __privateAdd(this, _transport2);
2769
2912
  __privateAdd(this, _dappClient);
2770
2913
  __privateAdd(this, _beforeUnloadListener);
2914
+ __privateAdd(this, _transportType);
2771
2915
  this._status = "pending";
2772
2916
  __privateAdd(this, _listener);
2773
2917
  __privateAdd(this, _anonId);
@@ -2804,12 +2948,13 @@ var _MetaMaskConnectMultichain = class _MetaMaskConnectMultichain extends Multic
2804
2948
  }
2805
2949
  return __privateGet(this, _dappClient);
2806
2950
  }
2951
+ get transportType() {
2952
+ var _a3;
2953
+ return (_a3 = __privateGet(this, _transportType)) != null ? _a3 : "unknown" /* UNKNOWN */;
2954
+ }
2807
2955
  get storage() {
2808
2956
  return this.options.storage;
2809
2957
  }
2810
- get transportType() {
2811
- return __privateGet(this, _transport2) instanceof MWPTransport ? "mwp" /* MWP */ : "browser" /* Browser */;
2812
- }
2813
2958
  // Creates a singleton instance of MetaMaskConnectMultichain.
2814
2959
  // If the singleton already exists, it merges the incoming options with the
2815
2960
  // existing singleton options for the following keys: `api.supportedNetworks`,
@@ -2863,7 +3008,7 @@ var _MetaMaskConnectMultichain = class _MetaMaskConnectMultichain extends Multic
2863
3008
  connect(scopes, caipAccountIds, sessionProperties, forceRequest) {
2864
3009
  return __async(this, null, function* () {
2865
3010
  var _a3;
2866
- if (this.status === "connecting" && this.transportType === "mwp" /* MWP */) {
3011
+ if (this.status === "connecting" && __privateGet(this, _transportType) === "mwp" /* MWP */) {
2867
3012
  yield __privateMethod(this, _MetaMaskConnectMultichain_instances, openConnectDeeplinkIfNeeded_fn).call(this);
2868
3013
  throw new Error(
2869
3014
  "Existing connection is pending. Please check your MetaMask Mobile app to continue."
@@ -2912,7 +3057,7 @@ var _MetaMaskConnectMultichain = class _MetaMaskConnectMultichain extends Multic
2912
3057
  sessionProperties: nonEmptySessionProperties,
2913
3058
  forceRequest
2914
3059
  }).then(() => __async(this, null, function* () {
2915
- if (__privateGet(this, _transport2) instanceof MWPTransport) {
3060
+ if (__privateGet(this, _transportType) === "mwp" /* MWP */) {
2916
3061
  return this.storage.setTransport("mwp" /* MWP */);
2917
3062
  }
2918
3063
  return this.storage.setTransport("browser" /* Browser */);
@@ -2959,12 +3104,13 @@ var _MetaMaskConnectMultichain = class _MetaMaskConnectMultichain extends Multic
2959
3104
  yield (_a3 = __privateGet(this, _transport2)) == null ? void 0 : _a3.disconnect(scopes);
2960
3105
  if (remainingScopes.length === 0) {
2961
3106
  yield this.storage.removeTransport();
2962
- if (this.transportType !== "browser" /* Browser */) {
3107
+ if (__privateGet(this, _transportType) !== "browser" /* Browser */) {
2963
3108
  yield (_b = __privateGet(this, _listener)) == null ? void 0 : _b.call(this);
2964
3109
  (_c = __privateGet(this, _beforeUnloadListener)) == null ? void 0 : _c.call(this);
2965
3110
  __privateSet(this, _listener, void 0);
2966
3111
  __privateSet(this, _beforeUnloadListener, void 0);
2967
3112
  __privateSet(this, _transport2, void 0);
3113
+ __privateSet(this, _transportType, void 0);
2968
3114
  __privateGet(this, _providerTransportWrapper).clearTransportNotificationListener();
2969
3115
  __privateSet(this, _dappClient, void 0);
2970
3116
  }
@@ -2974,13 +3120,14 @@ var _MetaMaskConnectMultichain = class _MetaMaskConnectMultichain extends Multic
2974
3120
  }
2975
3121
  invokeMethod(request) {
2976
3122
  return __async(this, null, function* () {
3123
+ var _a3;
2977
3124
  const { transport, options } = this;
2978
3125
  const rpcClient = new RpcClient(options, __privateGet(this, _sdkInfo));
2979
3126
  const requestRouter = new RequestRouter(
2980
3127
  transport,
2981
3128
  rpcClient,
2982
3129
  options,
2983
- this.transportType
3130
+ (_a3 = __privateGet(this, _transportType)) != null ? _a3 : "unknown" /* UNKNOWN */
2984
3131
  );
2985
3132
  return requestRouter.invokeMethod(request);
2986
3133
  });
@@ -3029,6 +3176,7 @@ _providerTransportWrapper = new WeakMap();
3029
3176
  _transport2 = new WeakMap();
3030
3177
  _dappClient = new WeakMap();
3031
3178
  _beforeUnloadListener = new WeakMap();
3179
+ _transportType = new WeakMap();
3032
3180
  _listener = new WeakMap();
3033
3181
  _anonId = new WeakMap();
3034
3182
  _sdkInfo = new WeakMap();
@@ -3086,6 +3234,7 @@ getStoredTransport_fn = function() {
3086
3234
  if (hasExtensionInstalled) {
3087
3235
  const apiTransport = new DefaultTransport();
3088
3236
  __privateSet(this, _transport2, apiTransport);
3237
+ __privateSet(this, _transportType, "browser" /* Browser */);
3089
3238
  __privateGet(this, _providerTransportWrapper).setupTransportNotificationListener();
3090
3239
  __privateSet(this, _listener, apiTransport.onNotification(
3091
3240
  __privateMethod(this, _MetaMaskConnectMultichain_instances, onTransportNotification_fn).bind(this)
@@ -3095,9 +3244,11 @@ getStoredTransport_fn = function() {
3095
3244
  } else if (transportType === "mwp" /* MWP */) {
3096
3245
  const { adapter: kvstore } = this.options.storage;
3097
3246
  const dappClient = yield __privateMethod(this, _MetaMaskConnectMultichain_instances, createDappClient_fn).call(this);
3098
- const apiTransport = new MWPTransport(dappClient, kvstore);
3247
+ const { MWPTransport: MWPTransport2 } = yield Promise.resolve().then(() => (init_mwp(), mwp_exports));
3248
+ const apiTransport = new MWPTransport2(dappClient, kvstore);
3099
3249
  __privateSet(this, _dappClient, dappClient);
3100
3250
  __privateSet(this, _transport2, apiTransport);
3251
+ __privateSet(this, _transportType, "mwp" /* MWP */);
3101
3252
  __privateGet(this, _providerTransportWrapper).setupTransportNotificationListener();
3102
3253
  __privateSet(this, _listener, apiTransport.onNotification(
3103
3254
  __privateMethod(this, _MetaMaskConnectMultichain_instances, onTransportNotification_fn).bind(this)
@@ -3119,7 +3270,7 @@ setupTransport_fn = function() {
3119
3270
  yield this.transport.connect();
3120
3271
  }
3121
3272
  this.status = "connected";
3122
- if (this.transport instanceof MWPTransport) {
3273
+ if (__privateGet(this, _transportType) === "mwp" /* MWP */) {
3123
3274
  yield this.storage.setTransport("mwp" /* MWP */);
3124
3275
  } else {
3125
3276
  yield this.storage.setTransport("browser" /* Browser */);
@@ -3163,31 +3314,43 @@ init_fn2 = function() {
3163
3314
  };
3164
3315
  createDappClient_fn = function() {
3165
3316
  return __async(this, null, function* () {
3317
+ const [mwpCore, { DappClient: DappClientClass }, { createKeyManager: createKeyManager2 }] = yield Promise.all([
3318
+ import("@metamask/mobile-wallet-protocol-core"),
3319
+ import("@metamask/mobile-wallet-protocol-dapp-client"),
3320
+ Promise.resolve().then(() => (init_KeyManager(), KeyManager_exports))
3321
+ ]);
3322
+ const keymanager = yield createKeyManager2();
3166
3323
  const { adapter: kvstore } = this.options.storage;
3167
- const sessionstore = yield SessionStore2.create(kvstore);
3324
+ const sessionstore = yield mwpCore.SessionStore.create(kvstore);
3168
3325
  const websocket = (
3169
3326
  // eslint-disable-next-line no-negated-condition
3170
3327
  typeof window !== "undefined" ? WebSocket : (yield import("ws")).WebSocket
3171
3328
  );
3172
- const transport = yield WebSocketTransport.create({
3329
+ const transport = yield mwpCore.WebSocketTransport.create({
3173
3330
  url: MWP_RELAY_URL,
3174
3331
  kvstore,
3175
3332
  websocket
3176
3333
  });
3177
- const dappClient = new DappClient({ transport, sessionstore, keymanager });
3334
+ const dappClient = new DappClientClass({
3335
+ transport,
3336
+ sessionstore,
3337
+ keymanager
3338
+ });
3178
3339
  return dappClient;
3179
3340
  });
3180
3341
  };
3181
3342
  setupMWP_fn = function() {
3182
3343
  return __async(this, null, function* () {
3183
- if (__privateGet(this, _transport2) instanceof MWPTransport) {
3344
+ if (__privateGet(this, _transportType) === "mwp" /* MWP */) {
3184
3345
  return;
3185
3346
  }
3186
3347
  const { adapter: kvstore } = this.options.storage;
3187
3348
  const dappClient = yield __privateMethod(this, _MetaMaskConnectMultichain_instances, createDappClient_fn).call(this);
3188
3349
  __privateSet(this, _dappClient, dappClient);
3189
- const apiTransport = new MWPTransport(dappClient, kvstore);
3350
+ const { MWPTransport: MWPTransport2 } = yield Promise.resolve().then(() => (init_mwp(), mwp_exports));
3351
+ const apiTransport = new MWPTransport2(dappClient, kvstore);
3190
3352
  __privateSet(this, _transport2, apiTransport);
3353
+ __privateSet(this, _transportType, "mwp" /* MWP */);
3191
3354
  __privateGet(this, _providerTransportWrapper).setupTransportNotificationListener();
3192
3355
  __privateSet(this, _listener, this.transport.onNotification(
3193
3356
  __privateMethod(this, _MetaMaskConnectMultichain_instances, onTransportNotification_fn).bind(this)
@@ -3246,6 +3409,7 @@ renderInstallModalAsync_fn = function(desktopPreferred, scopes, caipAccountIds,
3246
3409
  this.status = "connected";
3247
3410
  yield this.storage.setTransport("mwp" /* MWP */);
3248
3411
  } catch (error) {
3412
+ const { ProtocolError, ErrorCode } = yield import("@metamask/mobile-wallet-protocol-core");
3249
3413
  if (error instanceof ProtocolError) {
3250
3414
  if (error.code !== ErrorCode.REQUEST_EXPIRED) {
3251
3415
  this.status = "disconnected";
@@ -3315,6 +3479,7 @@ headlessConnect_fn = function(scopes, caipAccountIds, sessionProperties) {
3315
3479
  yield this.storage.setTransport("mwp" /* MWP */);
3316
3480
  resolve();
3317
3481
  })).catch((error) => __async(this, null, function* () {
3482
+ const { ProtocolError } = yield import("@metamask/mobile-wallet-protocol-core");
3318
3483
  if (error instanceof ProtocolError) {
3319
3484
  this.status = "disconnected";
3320
3485
  yield this.storage.removeTransport();
@@ -3330,7 +3495,7 @@ headlessConnect_fn = function(scopes, caipAccountIds, sessionProperties) {
3330
3495
  };
3331
3496
  setupDefaultTransport_fn = function() {
3332
3497
  return __async(this, arguments, function* (options = { persist: true }) {
3333
- if (__privateGet(this, _transport2) instanceof DefaultTransport) {
3498
+ if (__privateGet(this, _transportType) === "browser" /* Browser */) {
3334
3499
  return __privateGet(this, _transport2);
3335
3500
  }
3336
3501
  if (options == null ? void 0 : options.persist) {
@@ -3341,6 +3506,7 @@ setupDefaultTransport_fn = function() {
3341
3506
  __privateMethod(this, _MetaMaskConnectMultichain_instances, onTransportNotification_fn).bind(this)
3342
3507
  ));
3343
3508
  __privateSet(this, _transport2, transport);
3509
+ __privateSet(this, _transportType, "browser" /* Browser */);
3344
3510
  __privateGet(this, _providerTransportWrapper).setupTransportNotificationListener();
3345
3511
  return transport;
3346
3512
  });
@@ -3437,9 +3603,9 @@ handleConnection_fn = function(promise, scopes, transportType) {
3437
3603
  transport_type: transportType
3438
3604
  }));
3439
3605
  } else {
3440
- analytics2.track("mmconnect_connection_failed", __spreadProps(__spreadValues({}, baseProps), {
3606
+ analytics2.track("mmconnect_connection_failed", __spreadValues(__spreadProps(__spreadValues({}, baseProps), {
3441
3607
  transport_type: transportType
3442
- }));
3608
+ }), extractErrorDiagnostics(error)));
3443
3609
  }
3444
3610
  } catch (e) {
3445
3611
  logger2("Error tracking connection failed/rejected event", error);
@@ -3884,6 +4050,7 @@ export {
3884
4050
  StoreAdapter,
3885
4051
  StoreClient,
3886
4052
  TransportType,
4053
+ classifyFailureReason,
3887
4054
  createLogger,
3888
4055
  createMultichainClient,
3889
4056
  enableDebug,