@metamask-previews/bridge-status-controller 12.0.1-preview-c67b57f2 → 12.0.1-preview-5867b015

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 (51) hide show
  1. package/dist/bridge-status-controller.cjs +119 -5
  2. package/dist/bridge-status-controller.cjs.map +1 -1
  3. package/dist/bridge-status-controller.d.cts +21 -2
  4. package/dist/bridge-status-controller.d.cts.map +1 -1
  5. package/dist/bridge-status-controller.d.mts +21 -2
  6. package/dist/bridge-status-controller.d.mts.map +1 -1
  7. package/dist/bridge-status-controller.mjs +121 -7
  8. package/dist/bridge-status-controller.mjs.map +1 -1
  9. package/dist/constants.cjs +2 -1
  10. package/dist/constants.cjs.map +1 -1
  11. package/dist/constants.d.cts +1 -0
  12. package/dist/constants.d.cts.map +1 -1
  13. package/dist/constants.d.mts +1 -0
  14. package/dist/constants.d.mts.map +1 -1
  15. package/dist/constants.mjs +1 -0
  16. package/dist/constants.mjs.map +1 -1
  17. package/dist/index.cjs +4 -1
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +2 -1
  20. package/dist/index.d.cts.map +1 -1
  21. package/dist/index.d.mts +2 -1
  22. package/dist/index.d.mts.map +1 -1
  23. package/dist/index.mjs +2 -1
  24. package/dist/index.mjs.map +1 -1
  25. package/dist/types.cjs +10 -1
  26. package/dist/types.cjs.map +1 -1
  27. package/dist/types.d.cts +14 -6
  28. package/dist/types.d.cts.map +1 -1
  29. package/dist/types.d.mts +14 -6
  30. package/dist/types.d.mts.map +1 -1
  31. package/dist/types.mjs +9 -0
  32. package/dist/types.mjs.map +1 -1
  33. package/dist/utils/bridge-status.cjs +6 -5
  34. package/dist/utils/bridge-status.cjs.map +1 -1
  35. package/dist/utils/bridge-status.d.cts.map +1 -1
  36. package/dist/utils/bridge-status.d.mts.map +1 -1
  37. package/dist/utils/bridge-status.mjs +6 -5
  38. package/dist/utils/bridge-status.mjs.map +1 -1
  39. package/dist/utils/transaction.cjs +75 -0
  40. package/dist/utils/transaction.cjs.map +1 -0
  41. package/dist/utils/transaction.d.cts +29 -0
  42. package/dist/utils/transaction.d.cts.map +1 -0
  43. package/dist/utils/transaction.d.mts +29 -0
  44. package/dist/utils/transaction.d.mts.map +1 -0
  45. package/dist/utils/transaction.mjs +69 -0
  46. package/dist/utils/transaction.mjs.map +1 -0
  47. package/dist/utils/validators.cjs +1 -1
  48. package/dist/utils/validators.cjs.map +1 -1
  49. package/dist/utils/validators.mjs +2 -2
  50. package/dist/utils/validators.mjs.map +1 -1
  51. package/package.json +5 -2
@@ -10,15 +10,17 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
11
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
12
  };
13
- var _BridgeStatusController_instances, _BridgeStatusController_pollingTokensByTxMetaId, _BridgeStatusController_clientId, _BridgeStatusController_fetchFn, _BridgeStatusController_config, _BridgeStatusController_restartPollingForIncompleteHistoryItems, _BridgeStatusController_getMultichainSelectedAccountAddress, _BridgeStatusController_fetchBridgeTxStatus, _BridgeStatusController_getSrcTxHash, _BridgeStatusController_updateSrcTxHash, _BridgeStatusController_wipeBridgeStatusByChainId;
13
+ var _BridgeStatusController_instances, _BridgeStatusController_pollingTokensByTxMetaId, _BridgeStatusController_clientId, _BridgeStatusController_fetchFn, _BridgeStatusController_config, _BridgeStatusController_restartPollingForIncompleteHistoryItems, _BridgeStatusController_getMultichainSelectedAccount, _BridgeStatusController_getMultichainSelectedAccountAddress, _BridgeStatusController_fetchBridgeTxStatus, _BridgeStatusController_getSrcTxHash, _BridgeStatusController_updateSrcTxHash, _BridgeStatusController_wipeBridgeStatusByChainId, _BridgeStatusController_handleSolanaTx;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.BridgeStatusController = void 0;
16
16
  const bridge_controller_1 = require("@metamask/bridge-controller");
17
17
  const polling_controller_1 = require("@metamask/polling-controller");
18
18
  const utils_1 = require("@metamask/utils");
19
+ const uuid_1 = require("uuid");
19
20
  const constants_1 = require("./constants.cjs");
20
21
  const types_1 = require("./types.cjs");
21
22
  const bridge_status_1 = require("./utils/bridge-status.cjs");
23
+ const transaction_1 = require("./utils/transaction.cjs");
22
24
  const metadata = {
23
25
  // We want to persist the bridge status state so that we can show the proper data for the Activity list
24
26
  // basically match the behavior of TransactionController
@@ -44,6 +46,49 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
44
46
  _BridgeStatusController_clientId.set(this, void 0);
45
47
  _BridgeStatusController_fetchFn.set(this, void 0);
46
48
  _BridgeStatusController_config.set(this, void 0);
49
+ /**
50
+ * Submits a cross-chain swap transaction
51
+ *
52
+ * @param quoteResponse - The quote response
53
+ * @param quoteResponse.quote - The quote
54
+ * @param quoteResponse.trade - The trade
55
+ * @param quoteResponse.approval - The approval
56
+ * @returns The transaction meta
57
+ */
58
+ this.submitTx = async (quoteResponse) => {
59
+ this.stopAllPolling();
60
+ if (!(0, bridge_controller_1.isSolanaChainId)(quoteResponse.quote.srcChainId)) {
61
+ throw new Error('Failed to submit bridge tx: only Solana is supported');
62
+ }
63
+ let txMeta;
64
+ // Submit SOLANA tx
65
+ if ((0, bridge_controller_1.isSolanaChainId)(quoteResponse.quote.srcChainId) &&
66
+ typeof quoteResponse.trade === 'string') {
67
+ const { approval, trade, ...partialQuoteResponse } = quoteResponse;
68
+ txMeta = await __classPrivateFieldGet(this, _BridgeStatusController_handleSolanaTx, "f").call(this, trade, partialQuoteResponse);
69
+ }
70
+ if (!txMeta) {
71
+ throw new Error('Failed to submit bridge tx: txMeta is undefined');
72
+ }
73
+ // Start polling for bridge tx status
74
+ try {
75
+ const statusRequestCommon = (0, transaction_1.getStatusRequestParams)(quoteResponse);
76
+ this.startPollingForBridgeTxStatus({
77
+ bridgeTxMeta: txMeta,
78
+ statusRequest: {
79
+ ...statusRequestCommon,
80
+ srcTxHash: txMeta.hash,
81
+ },
82
+ quoteResponse,
83
+ slippagePercentage: 0,
84
+ startTime: Date.now(),
85
+ });
86
+ }
87
+ catch {
88
+ // Ignore errors here, we don't want to crash the app if this fails and tx submission succeeds
89
+ }
90
+ return txMeta;
91
+ };
47
92
  this.resetState = () => {
48
93
  this.update((state) => {
49
94
  state.txHistory = constants_1.DEFAULT_BRIDGE_STATUS_CONTROLLER_STATE.txHistory;
@@ -85,6 +130,12 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
85
130
  });
86
131
  });
87
132
  });
133
+ /**
134
+ * Starts polling for the bridge tx status
135
+ *
136
+ * @param startPollingForBridgeTxStatusArgs - The args to start polling for the bridge tx status
137
+ * @deprecated Use {@link submitTx} to submit tx and start polling for bridge tx status instead
138
+ */
88
139
  this.startPollingForBridgeTxStatus = (startPollingForBridgeTxStatusArgs) => {
89
140
  const { bridgeTxMeta, statusRequest, quoteResponse, startTime, slippagePercentage, initialDestAssetBalance, targetContractAddress, } = startPollingForBridgeTxStatusArgs;
90
141
  const accountAddress = __classPrivateFieldGet(this, _BridgeStatusController_instances, "m", _BridgeStatusController_getMultichainSelectedAccountAddress).call(this);
@@ -142,7 +193,7 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
142
193
  }
143
194
  __classPrivateFieldGet(this, _BridgeStatusController_updateSrcTxHash, "f").call(this, bridgeTxMetaId, srcTxHash);
144
195
  const statusRequest = (0, bridge_status_1.getStatusRequestWithSrcTxHash)(historyItem.quote, srcTxHash);
145
- const status = await (0, bridge_status_1.fetchBridgeTxStatus)(statusRequest, __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f"), __classPrivateFieldGet(this, _BridgeStatusController_fetchFn, "f"), __classPrivateFieldGet(this, _BridgeStatusController_config, "f").customBridgeApiBaseUrl ?? bridge_controller_1.BRIDGE_PROD_API_BASE_URL);
196
+ const status = await (0, bridge_status_1.fetchBridgeTxStatus)(statusRequest, __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f"), __classPrivateFieldGet(this, _BridgeStatusController_fetchFn, "f"), __classPrivateFieldGet(this, _BridgeStatusController_config, "f").customBridgeApiBaseUrl);
146
197
  const newBridgeHistoryItem = {
147
198
  ...historyItem,
148
199
  status,
@@ -219,13 +270,74 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
219
270
  }, state.txHistory);
220
271
  });
221
272
  });
273
+ /**
274
+ * Submits a solana swap or bridge transaction using the snap controller
275
+ *
276
+ * @param trade - The trade data to confirm
277
+ * @param quoteResponse - The quote response
278
+ * @param quoteResponse.quote - The quote
279
+ * @returns The transaction meta
280
+ */
281
+ _BridgeStatusController_handleSolanaTx.set(this, async (trade, quoteResponse) => {
282
+ const selectedAccount = __classPrivateFieldGet(this, _BridgeStatusController_instances, "m", _BridgeStatusController_getMultichainSelectedAccount).call(this);
283
+ if (!selectedAccount) {
284
+ throw new Error('Failed to submit cross-chain swap transaction: undefined multichain account');
285
+ }
286
+ if (!selectedAccount.metadata?.snap?.id ||
287
+ !selectedAccount.options?.scope) {
288
+ throw new Error('Failed to submit cross-chain swap transaction: undefined snap id or scope');
289
+ }
290
+ /**
291
+ * Submit the transaction to the snap using the keyring rpc method
292
+ * This adds an approval tx to the ApprovalsController in the background
293
+ * The client needs to handle the approval tx by redirecting to the confirmation page with the approvalTxId in the URL
294
+ */
295
+ const keyringReqId = (0, uuid_1.v4)();
296
+ const snapRequestId = (0, uuid_1.v4)();
297
+ const keyringResponse = await this.messagingSystem.call('SnapController:handleRequest', {
298
+ origin: 'metamask',
299
+ snapId: selectedAccount.metadata.snap.id,
300
+ handler: 'onKeyringRequest',
301
+ request: {
302
+ id: keyringReqId,
303
+ jsonrpc: '2.0',
304
+ method: 'keyring_submitRequest',
305
+ params: {
306
+ request: {
307
+ params: {
308
+ account: { address: selectedAccount.address },
309
+ transaction: trade,
310
+ scope: selectedAccount.options.scope,
311
+ },
312
+ method: 'signAndSendTransaction',
313
+ },
314
+ id: snapRequestId,
315
+ account: selectedAccount.id,
316
+ scope: selectedAccount.options.scope,
317
+ },
318
+ },
319
+ });
320
+ // The extension client actually redirects before it can do anytyhing with this meta
321
+ const txMeta = (0, transaction_1.handleSolanaTxResponse)(keyringResponse, // This is ok bc the snap response can be different types
322
+ quoteResponse, selectedAccount.metadata.snap.id, selectedAccount.address);
323
+ // TODO remove this eventually, just returning it now to match extension behavior
324
+ // OR if the snap can propagate the snapRequestId or keyringReqId to the ApprovalsControlle, this can return the approvalTxId instead and clients won't need to subscribe to the ApprovalsController state to redirect
325
+ return {
326
+ ...txMeta,
327
+ keyringReqId,
328
+ snapRequestId,
329
+ };
330
+ });
222
331
  __classPrivateFieldSet(this, _BridgeStatusController_clientId, clientId, "f");
223
332
  __classPrivateFieldSet(this, _BridgeStatusController_fetchFn, fetchFn, "f");
224
- __classPrivateFieldSet(this, _BridgeStatusController_config, config ?? {}, "f");
333
+ __classPrivateFieldSet(this, _BridgeStatusController_config, {
334
+ customBridgeApiBaseUrl: config?.customBridgeApiBaseUrl ?? constants_1.BRIDGE_PROD_API_BASE_URL,
335
+ }, "f");
225
336
  // Register action handlers
226
337
  this.messagingSystem.registerActionHandler(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:startPollingForBridgeTxStatus`, this.startPollingForBridgeTxStatus.bind(this));
227
338
  this.messagingSystem.registerActionHandler(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:wipeBridgeStatus`, this.wipeBridgeStatus.bind(this));
228
339
  this.messagingSystem.registerActionHandler(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:resetState`, this.resetState.bind(this));
340
+ this.messagingSystem.registerActionHandler(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:submitTx`, this.submitTx.bind(this));
229
341
  // Set interval
230
342
  this.setIntervalLength(constants_1.REFRESH_INTERVAL_MS);
231
343
  // If you close the extension, but keep the browser open, the polling continues
@@ -235,7 +347,9 @@ class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPoll
235
347
  }
236
348
  }
237
349
  exports.BridgeStatusController = BridgeStatusController;
238
- _BridgeStatusController_pollingTokensByTxMetaId = new WeakMap(), _BridgeStatusController_clientId = new WeakMap(), _BridgeStatusController_fetchFn = new WeakMap(), _BridgeStatusController_config = new WeakMap(), _BridgeStatusController_restartPollingForIncompleteHistoryItems = new WeakMap(), _BridgeStatusController_fetchBridgeTxStatus = new WeakMap(), _BridgeStatusController_getSrcTxHash = new WeakMap(), _BridgeStatusController_updateSrcTxHash = new WeakMap(), _BridgeStatusController_wipeBridgeStatusByChainId = new WeakMap(), _BridgeStatusController_instances = new WeakSet(), _BridgeStatusController_getMultichainSelectedAccountAddress = function _BridgeStatusController_getMultichainSelectedAccountAddress() {
239
- return (this.messagingSystem.call('AccountsController:getSelectedMultichainAccount')?.address ?? '');
350
+ _BridgeStatusController_pollingTokensByTxMetaId = new WeakMap(), _BridgeStatusController_clientId = new WeakMap(), _BridgeStatusController_fetchFn = new WeakMap(), _BridgeStatusController_config = new WeakMap(), _BridgeStatusController_restartPollingForIncompleteHistoryItems = new WeakMap(), _BridgeStatusController_fetchBridgeTxStatus = new WeakMap(), _BridgeStatusController_getSrcTxHash = new WeakMap(), _BridgeStatusController_updateSrcTxHash = new WeakMap(), _BridgeStatusController_wipeBridgeStatusByChainId = new WeakMap(), _BridgeStatusController_handleSolanaTx = new WeakMap(), _BridgeStatusController_instances = new WeakSet(), _BridgeStatusController_getMultichainSelectedAccount = function _BridgeStatusController_getMultichainSelectedAccount() {
351
+ return this.messagingSystem.call('AccountsController:getSelectedMultichainAccount');
352
+ }, _BridgeStatusController_getMultichainSelectedAccountAddress = function _BridgeStatusController_getMultichainSelectedAccountAddress() {
353
+ return __classPrivateFieldGet(this, _BridgeStatusController_instances, "m", _BridgeStatusController_getMultichainSelectedAccount).call(this)?.address ?? '';
240
354
  };
241
355
  //# sourceMappingURL=bridge-status-controller.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"bridge-status-controller.cjs","sourceRoot":"","sources":["../src/bridge-status-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { StateMetadata } from '@metamask/base-controller';\nimport type { BridgeClientId } from '@metamask/bridge-controller';\nimport { BRIDGE_PROD_API_BASE_URL } from '@metamask/bridge-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport { numberToHex, type Hex } from '@metamask/utils';\n\nimport {\n BRIDGE_STATUS_CONTROLLER_NAME,\n DEFAULT_BRIDGE_STATUS_CONTROLLER_STATE,\n REFRESH_INTERVAL_MS,\n} from './constants';\nimport { StatusTypes, type BridgeStatusControllerMessenger } from './types';\nimport type {\n BridgeStatusControllerState,\n StartPollingForBridgeTxStatusArgsSerialized,\n FetchFunction,\n} from './types';\nimport {\n fetchBridgeTxStatus,\n getStatusRequestWithSrcTxHash,\n} from './utils/bridge-status';\n\nconst metadata: StateMetadata<BridgeStatusControllerState> = {\n // We want to persist the bridge status state so that we can show the proper data for the Activity list\n // basically match the behavior of TransactionController\n txHistory: {\n persist: true,\n anonymous: false,\n },\n};\n\n/** The input to start polling for the {@link BridgeStatusController} */\ntype BridgeStatusPollingInput = FetchBridgeTxStatusArgs;\n\ntype SrcTxMetaId = string;\nexport type FetchBridgeTxStatusArgs = {\n bridgeTxMetaId: string;\n};\nexport class BridgeStatusController extends StaticIntervalPollingController<BridgeStatusPollingInput>()<\n typeof BRIDGE_STATUS_CONTROLLER_NAME,\n BridgeStatusControllerState,\n BridgeStatusControllerMessenger\n> {\n #pollingTokensByTxMetaId: Record<SrcTxMetaId, string> = {};\n\n readonly #clientId: BridgeClientId;\n\n readonly #fetchFn: FetchFunction;\n\n readonly #config: {\n customBridgeApiBaseUrl?: string;\n };\n\n constructor({\n messenger,\n state,\n clientId,\n fetchFn,\n config,\n }: {\n messenger: BridgeStatusControllerMessenger;\n state?: Partial<BridgeStatusControllerState>;\n clientId: BridgeClientId;\n fetchFn: FetchFunction;\n config?: {\n customBridgeApiBaseUrl?: string;\n };\n }) {\n super({\n name: BRIDGE_STATUS_CONTROLLER_NAME,\n metadata,\n messenger,\n // Restore the persisted state\n state: {\n ...DEFAULT_BRIDGE_STATUS_CONTROLLER_STATE,\n ...state,\n },\n });\n\n this.#clientId = clientId;\n this.#fetchFn = fetchFn;\n this.#config = config ?? {};\n\n // Register action handlers\n this.messagingSystem.registerActionHandler(\n `${BRIDGE_STATUS_CONTROLLER_NAME}:startPollingForBridgeTxStatus`,\n this.startPollingForBridgeTxStatus.bind(this),\n );\n this.messagingSystem.registerActionHandler(\n `${BRIDGE_STATUS_CONTROLLER_NAME}:wipeBridgeStatus`,\n this.wipeBridgeStatus.bind(this),\n );\n this.messagingSystem.registerActionHandler(\n `${BRIDGE_STATUS_CONTROLLER_NAME}:resetState`,\n this.resetState.bind(this),\n );\n\n // Set interval\n this.setIntervalLength(REFRESH_INTERVAL_MS);\n\n // If you close the extension, but keep the browser open, the polling continues\n // If you close the browser, the polling stops\n // Check for historyItems that do not have a status of complete and restart polling\n this.#restartPollingForIncompleteHistoryItems();\n }\n\n resetState = () => {\n this.update((state) => {\n state.txHistory = DEFAULT_BRIDGE_STATUS_CONTROLLER_STATE.txHistory;\n });\n };\n\n wipeBridgeStatus = ({\n address,\n ignoreNetwork,\n }: {\n address: string;\n ignoreNetwork: boolean;\n }) => {\n // Wipe all networks for this address\n if (ignoreNetwork) {\n this.update((state) => {\n state.txHistory = DEFAULT_BRIDGE_STATUS_CONTROLLER_STATE.txHistory;\n });\n } else {\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n const selectedNetworkClient = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n const selectedChainId = selectedNetworkClient.configuration.chainId;\n\n this.#wipeBridgeStatusByChainId(address, selectedChainId);\n }\n };\n\n readonly #restartPollingForIncompleteHistoryItems = () => {\n // Check for historyItems that do not have a status of complete and restart polling\n const { txHistory } = this.state;\n const historyItems = Object.values(txHistory);\n const incompleteHistoryItems = historyItems\n .filter(\n (historyItem) =>\n historyItem.status.status === StatusTypes.PENDING ||\n historyItem.status.status === StatusTypes.UNKNOWN,\n )\n .filter((historyItem) => {\n // Check if we are already polling this tx, if so, skip restarting polling for that\n const srcTxMetaId = historyItem.txMetaId;\n const pollingToken = this.#pollingTokensByTxMetaId[srcTxMetaId];\n return !pollingToken;\n });\n\n incompleteHistoryItems.forEach((historyItem) => {\n const bridgeTxMetaId = historyItem.txMetaId;\n\n // We manually call startPolling() here rather than go through startPollingForBridgeTxStatus()\n // because we don't want to overwrite the existing historyItem in state\n this.#pollingTokensByTxMetaId[bridgeTxMetaId] = this.startPolling({\n bridgeTxMetaId,\n });\n });\n };\n\n startPollingForBridgeTxStatus = (\n startPollingForBridgeTxStatusArgs: StartPollingForBridgeTxStatusArgsSerialized,\n ) => {\n const {\n bridgeTxMeta,\n statusRequest,\n quoteResponse,\n startTime,\n slippagePercentage,\n initialDestAssetBalance,\n targetContractAddress,\n } = startPollingForBridgeTxStatusArgs;\n const accountAddress = this.#getMultichainSelectedAccountAddress();\n // Write all non-status fields to state so we can reference the quote in Activity list without the Bridge API\n // We know it's in progress but not the exact status yet\n const txHistoryItem = {\n txMetaId: bridgeTxMeta.id,\n quote: quoteResponse.quote,\n startTime,\n estimatedProcessingTimeInSeconds:\n quoteResponse.estimatedProcessingTimeInSeconds,\n slippagePercentage,\n pricingData: {\n amountSent: quoteResponse.sentAmount.amount,\n amountSentInUsd: quoteResponse.sentAmount.usd ?? undefined,\n quotedGasInUsd: quoteResponse.gasFee.usd ?? undefined,\n quotedReturnInUsd: quoteResponse.toTokenAmount.usd ?? undefined,\n },\n initialDestAssetBalance,\n targetContractAddress,\n account: accountAddress,\n status: {\n // We always have a PENDING status when we start polling for a tx, don't need the Bridge API for that\n // Also we know the bare minimum fields for status at this point in time\n status: StatusTypes.PENDING,\n srcChain: {\n chainId: statusRequest.srcChainId,\n txHash: statusRequest.srcTxHash,\n },\n },\n hasApprovalTx: Boolean(quoteResponse.approval),\n };\n this.update((state) => {\n // Use the txMeta.id as the key so we can reference the txMeta in TransactionController\n state.txHistory[bridgeTxMeta.id] = txHistoryItem;\n });\n\n this.#pollingTokensByTxMetaId[bridgeTxMeta.id] = this.startPolling({\n bridgeTxMetaId: bridgeTxMeta.id,\n });\n };\n\n // This will be called after you call this.startPolling()\n // The args passed in are the args you passed in to startPolling()\n _executePoll = async (pollingInput: BridgeStatusPollingInput) => {\n await this.#fetchBridgeTxStatus(pollingInput);\n };\n\n #getMultichainSelectedAccountAddress() {\n return (\n this.messagingSystem.call(\n 'AccountsController:getSelectedMultichainAccount',\n )?.address ?? ''\n );\n }\n\n readonly #fetchBridgeTxStatus = async ({\n bridgeTxMetaId,\n }: FetchBridgeTxStatusArgs) => {\n const { txHistory } = this.state;\n\n try {\n // We try here because we receive 500 errors from Bridge API if we try to fetch immediately after submitting the source tx\n // Oddly mostly happens on Optimism, never on Arbitrum. By the 2nd fetch, the Bridge API responds properly.\n // Also srcTxHash may not be available immediately for STX, so we don't want to fetch in those cases\n const historyItem = txHistory[bridgeTxMetaId];\n const srcTxHash = this.#getSrcTxHash(bridgeTxMetaId);\n if (!srcTxHash) {\n return;\n }\n\n this.#updateSrcTxHash(bridgeTxMetaId, srcTxHash);\n\n const statusRequest = getStatusRequestWithSrcTxHash(\n historyItem.quote,\n srcTxHash,\n );\n const status = await fetchBridgeTxStatus(\n statusRequest,\n this.#clientId,\n this.#fetchFn,\n this.#config.customBridgeApiBaseUrl ?? BRIDGE_PROD_API_BASE_URL,\n );\n const newBridgeHistoryItem = {\n ...historyItem,\n status,\n completionTime:\n status.status === StatusTypes.COMPLETE ||\n status.status === StatusTypes.FAILED\n ? Date.now()\n : undefined, // TODO make this more accurate by looking up dest txHash block time\n };\n\n // No need to purge these on network change or account change, TransactionController does not purge either.\n // TODO In theory we can skip checking status if it's not the current account/network\n // we need to keep track of the account that this is associated with as well so that we don't show it in Activity list for other accounts\n // First stab at this will not stop polling when you are on a different account\n this.update((state) => {\n state.txHistory[bridgeTxMetaId] = newBridgeHistoryItem;\n });\n\n const pollingToken = this.#pollingTokensByTxMetaId[bridgeTxMetaId];\n\n if (\n (status.status === StatusTypes.COMPLETE ||\n status.status === StatusTypes.FAILED) &&\n pollingToken\n ) {\n this.stopPollingByPollingToken(pollingToken);\n\n if (status.status === StatusTypes.COMPLETE) {\n this.messagingSystem.publish(\n `${BRIDGE_STATUS_CONTROLLER_NAME}:bridgeTransactionComplete`,\n { bridgeHistoryItem: newBridgeHistoryItem },\n );\n }\n if (status.status === StatusTypes.FAILED) {\n this.messagingSystem.publish(\n `${BRIDGE_STATUS_CONTROLLER_NAME}:bridgeTransactionFailed`,\n { bridgeHistoryItem: newBridgeHistoryItem },\n );\n }\n }\n } catch (e) {\n console.log('Failed to fetch bridge tx status', e);\n }\n };\n\n readonly #getSrcTxHash = (bridgeTxMetaId: string): string | undefined => {\n const { txHistory } = this.state;\n // Prefer the srcTxHash from bridgeStatusState so we don't have to l ook up in TransactionController\n // But it is possible to have bridgeHistoryItem in state without the srcTxHash yet when it is an STX\n const srcTxHash = txHistory[bridgeTxMetaId].status.srcChain.txHash;\n\n if (srcTxHash) {\n return srcTxHash;\n }\n\n // Look up in TransactionController if txMeta has been updated with the srcTxHash\n const txControllerState = this.messagingSystem.call(\n 'TransactionController:getState',\n );\n const txMeta = txControllerState.transactions.find(\n (tx) => tx.id === bridgeTxMetaId,\n );\n return txMeta?.hash;\n };\n\n readonly #updateSrcTxHash = (bridgeTxMetaId: string, srcTxHash: string) => {\n const { txHistory } = this.state;\n if (txHistory[bridgeTxMetaId].status.srcChain.txHash) {\n return;\n }\n\n this.update((state) => {\n state.txHistory[bridgeTxMetaId].status.srcChain.txHash = srcTxHash;\n });\n };\n\n // Wipes the bridge status for the given address and chainId\n // Will match only source chainId to the selectedChainId\n readonly #wipeBridgeStatusByChainId = (\n address: string,\n selectedChainId: Hex,\n ) => {\n const sourceTxMetaIdsToDelete = Object.keys(this.state.txHistory).filter(\n (txMetaId) => {\n const bridgeHistoryItem = this.state.txHistory[txMetaId];\n\n const hexSourceChainId = numberToHex(\n bridgeHistoryItem.quote.srcChainId,\n );\n\n return (\n bridgeHistoryItem.account === address &&\n hexSourceChainId === selectedChainId\n );\n },\n );\n\n sourceTxMetaIdsToDelete.forEach((sourceTxMetaId) => {\n const pollingToken = this.#pollingTokensByTxMetaId[sourceTxMetaId];\n\n if (pollingToken) {\n this.stopPollingByPollingToken(\n this.#pollingTokensByTxMetaId[sourceTxMetaId],\n );\n }\n });\n\n this.update((state) => {\n state.txHistory = sourceTxMetaIdsToDelete.reduce(\n (acc, sourceTxMetaId) => {\n delete acc[sourceTxMetaId];\n return acc;\n },\n state.txHistory,\n );\n });\n };\n}\n"]}
1
+ {"version":3,"file":"bridge-status-controller.cjs","sourceRoot":"","sources":["../src/bridge-status-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { StateMetadata } from '@metamask/base-controller';\nimport {\n isSolanaChainId,\n type QuoteResponse,\n} from '@metamask/bridge-controller';\nimport type { QuoteMetadata, TxData } from '@metamask/bridge-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type { TransactionMeta } from '@metamask/transaction-controller';\nimport { numberToHex, type Hex } from '@metamask/utils';\nimport { v4 as uuid } from 'uuid';\n\nimport {\n BRIDGE_PROD_API_BASE_URL,\n BRIDGE_STATUS_CONTROLLER_NAME,\n DEFAULT_BRIDGE_STATUS_CONTROLLER_STATE,\n REFRESH_INTERVAL_MS,\n} from './constants';\nimport { StatusTypes, type BridgeStatusControllerMessenger } from './types';\nimport type {\n BridgeStatusControllerState,\n StartPollingForBridgeTxStatusArgsSerialized,\n FetchFunction,\n BridgeClientId,\n} from './types';\nimport {\n fetchBridgeTxStatus,\n getStatusRequestWithSrcTxHash,\n} from './utils/bridge-status';\nimport {\n getStatusRequestParams,\n handleSolanaTxResponse,\n} from './utils/transaction';\n\nconst metadata: StateMetadata<BridgeStatusControllerState> = {\n // We want to persist the bridge status state so that we can show the proper data for the Activity list\n // basically match the behavior of TransactionController\n txHistory: {\n persist: true,\n anonymous: false,\n },\n};\n\n/** The input to start polling for the {@link BridgeStatusController} */\ntype BridgeStatusPollingInput = FetchBridgeTxStatusArgs;\n\ntype SrcTxMetaId = string;\nexport type FetchBridgeTxStatusArgs = {\n bridgeTxMetaId: string;\n};\nexport class BridgeStatusController extends StaticIntervalPollingController<BridgeStatusPollingInput>()<\n typeof BRIDGE_STATUS_CONTROLLER_NAME,\n BridgeStatusControllerState,\n BridgeStatusControllerMessenger\n> {\n #pollingTokensByTxMetaId: Record<SrcTxMetaId, string> = {};\n\n readonly #clientId: BridgeClientId;\n\n readonly #fetchFn: FetchFunction;\n\n readonly #config: {\n customBridgeApiBaseUrl: string;\n };\n\n constructor({\n messenger,\n state,\n clientId,\n fetchFn,\n config,\n }: {\n messenger: BridgeStatusControllerMessenger;\n state?: Partial<BridgeStatusControllerState>;\n clientId: BridgeClientId;\n fetchFn: FetchFunction;\n config?: {\n customBridgeApiBaseUrl?: string;\n };\n }) {\n super({\n name: BRIDGE_STATUS_CONTROLLER_NAME,\n metadata,\n messenger,\n // Restore the persisted state\n state: {\n ...DEFAULT_BRIDGE_STATUS_CONTROLLER_STATE,\n ...state,\n },\n });\n\n this.#clientId = clientId;\n this.#fetchFn = fetchFn;\n this.#config = {\n customBridgeApiBaseUrl:\n config?.customBridgeApiBaseUrl ?? BRIDGE_PROD_API_BASE_URL,\n };\n\n // Register action handlers\n this.messagingSystem.registerActionHandler(\n `${BRIDGE_STATUS_CONTROLLER_NAME}:startPollingForBridgeTxStatus`,\n this.startPollingForBridgeTxStatus.bind(this),\n );\n this.messagingSystem.registerActionHandler(\n `${BRIDGE_STATUS_CONTROLLER_NAME}:wipeBridgeStatus`,\n this.wipeBridgeStatus.bind(this),\n );\n this.messagingSystem.registerActionHandler(\n `${BRIDGE_STATUS_CONTROLLER_NAME}:resetState`,\n this.resetState.bind(this),\n );\n this.messagingSystem.registerActionHandler(\n `${BRIDGE_STATUS_CONTROLLER_NAME}:submitTx`,\n this.submitTx.bind(this),\n );\n\n // Set interval\n this.setIntervalLength(REFRESH_INTERVAL_MS);\n\n // If you close the extension, but keep the browser open, the polling continues\n // If you close the browser, the polling stops\n // Check for historyItems that do not have a status of complete and restart polling\n this.#restartPollingForIncompleteHistoryItems();\n }\n\n /**\n * Submits a cross-chain swap transaction\n *\n * @param quoteResponse - The quote response\n * @param quoteResponse.quote - The quote\n * @param quoteResponse.trade - The trade\n * @param quoteResponse.approval - The approval\n * @returns The transaction meta\n */\n submitTx = async (\n quoteResponse: QuoteResponse<TxData | string> & QuoteMetadata,\n ) => {\n this.stopAllPolling();\n\n if (!isSolanaChainId(quoteResponse.quote.srcChainId)) {\n throw new Error('Failed to submit bridge tx: only Solana is supported');\n }\n\n let txMeta: TransactionMeta | undefined;\n // Submit SOLANA tx\n if (\n isSolanaChainId(quoteResponse.quote.srcChainId) &&\n typeof quoteResponse.trade === 'string'\n ) {\n const { approval, trade, ...partialQuoteResponse } = quoteResponse;\n txMeta = await this.#handleSolanaTx(trade, partialQuoteResponse);\n }\n\n if (!txMeta) {\n throw new Error('Failed to submit bridge tx: txMeta is undefined');\n }\n\n // Start polling for bridge tx status\n try {\n const statusRequestCommon = getStatusRequestParams(quoteResponse);\n this.startPollingForBridgeTxStatus({\n bridgeTxMeta: txMeta, // Only the id field is used by the BridgeStatusController\n statusRequest: {\n ...statusRequestCommon,\n srcTxHash: txMeta.hash,\n },\n quoteResponse,\n slippagePercentage: 0, // TODO include slippage provided by quote if using dynamic slippage, or slippage from quote request\n startTime: Date.now(),\n });\n } catch {\n // Ignore errors here, we don't want to crash the app if this fails and tx submission succeeds\n }\n return txMeta;\n };\n\n resetState = () => {\n this.update((state) => {\n state.txHistory = DEFAULT_BRIDGE_STATUS_CONTROLLER_STATE.txHistory;\n });\n };\n\n wipeBridgeStatus = ({\n address,\n ignoreNetwork,\n }: {\n address: string;\n ignoreNetwork: boolean;\n }) => {\n // Wipe all networks for this address\n if (ignoreNetwork) {\n this.update((state) => {\n state.txHistory = DEFAULT_BRIDGE_STATUS_CONTROLLER_STATE.txHistory;\n });\n } else {\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n const selectedNetworkClient = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n const selectedChainId = selectedNetworkClient.configuration.chainId;\n\n this.#wipeBridgeStatusByChainId(address, selectedChainId);\n }\n };\n\n readonly #restartPollingForIncompleteHistoryItems = () => {\n // Check for historyItems that do not have a status of complete and restart polling\n const { txHistory } = this.state;\n const historyItems = Object.values(txHistory);\n const incompleteHistoryItems = historyItems\n .filter(\n (historyItem) =>\n historyItem.status.status === StatusTypes.PENDING ||\n historyItem.status.status === StatusTypes.UNKNOWN,\n )\n .filter((historyItem) => {\n // Check if we are already polling this tx, if so, skip restarting polling for that\n const srcTxMetaId = historyItem.txMetaId;\n const pollingToken = this.#pollingTokensByTxMetaId[srcTxMetaId];\n return !pollingToken;\n });\n\n incompleteHistoryItems.forEach((historyItem) => {\n const bridgeTxMetaId = historyItem.txMetaId;\n\n // We manually call startPolling() here rather than go through startPollingForBridgeTxStatus()\n // because we don't want to overwrite the existing historyItem in state\n this.#pollingTokensByTxMetaId[bridgeTxMetaId] = this.startPolling({\n bridgeTxMetaId,\n });\n });\n };\n\n /**\n * Starts polling for the bridge tx status\n *\n * @param startPollingForBridgeTxStatusArgs - The args to start polling for the bridge tx status\n * @deprecated Use {@link submitTx} to submit tx and start polling for bridge tx status instead\n */\n startPollingForBridgeTxStatus = (\n startPollingForBridgeTxStatusArgs: StartPollingForBridgeTxStatusArgsSerialized,\n ) => {\n const {\n bridgeTxMeta,\n statusRequest,\n quoteResponse,\n startTime,\n slippagePercentage,\n initialDestAssetBalance,\n targetContractAddress,\n } = startPollingForBridgeTxStatusArgs;\n const accountAddress = this.#getMultichainSelectedAccountAddress();\n // Write all non-status fields to state so we can reference the quote in Activity list without the Bridge API\n // We know it's in progress but not the exact status yet\n const txHistoryItem = {\n txMetaId: bridgeTxMeta.id,\n quote: quoteResponse.quote,\n startTime,\n estimatedProcessingTimeInSeconds:\n quoteResponse.estimatedProcessingTimeInSeconds,\n slippagePercentage,\n pricingData: {\n amountSent: quoteResponse.sentAmount.amount,\n amountSentInUsd: quoteResponse.sentAmount.usd ?? undefined,\n quotedGasInUsd: quoteResponse.gasFee.usd ?? undefined,\n quotedReturnInUsd: quoteResponse.toTokenAmount.usd ?? undefined,\n },\n initialDestAssetBalance,\n targetContractAddress,\n account: accountAddress,\n status: {\n // We always have a PENDING status when we start polling for a tx, don't need the Bridge API for that\n // Also we know the bare minimum fields for status at this point in time\n status: StatusTypes.PENDING,\n srcChain: {\n chainId: statusRequest.srcChainId,\n txHash: statusRequest.srcTxHash,\n },\n },\n hasApprovalTx: Boolean(quoteResponse.approval),\n };\n this.update((state) => {\n // Use the txMeta.id as the key so we can reference the txMeta in TransactionController\n state.txHistory[bridgeTxMeta.id] = txHistoryItem;\n });\n\n this.#pollingTokensByTxMetaId[bridgeTxMeta.id] = this.startPolling({\n bridgeTxMetaId: bridgeTxMeta.id,\n });\n };\n\n // This will be called after you call this.startPolling()\n // The args passed in are the args you passed in to startPolling()\n _executePoll = async (pollingInput: BridgeStatusPollingInput) => {\n await this.#fetchBridgeTxStatus(pollingInput);\n };\n\n #getMultichainSelectedAccount() {\n return this.messagingSystem.call(\n 'AccountsController:getSelectedMultichainAccount',\n );\n }\n\n #getMultichainSelectedAccountAddress() {\n return this.#getMultichainSelectedAccount()?.address ?? '';\n }\n\n readonly #fetchBridgeTxStatus = async ({\n bridgeTxMetaId,\n }: FetchBridgeTxStatusArgs) => {\n const { txHistory } = this.state;\n\n try {\n // We try here because we receive 500 errors from Bridge API if we try to fetch immediately after submitting the source tx\n // Oddly mostly happens on Optimism, never on Arbitrum. By the 2nd fetch, the Bridge API responds properly.\n // Also srcTxHash may not be available immediately for STX, so we don't want to fetch in those cases\n const historyItem = txHistory[bridgeTxMetaId];\n const srcTxHash = this.#getSrcTxHash(bridgeTxMetaId);\n if (!srcTxHash) {\n return;\n }\n\n this.#updateSrcTxHash(bridgeTxMetaId, srcTxHash);\n\n const statusRequest = getStatusRequestWithSrcTxHash(\n historyItem.quote,\n srcTxHash,\n );\n const status = await fetchBridgeTxStatus(\n statusRequest,\n this.#clientId,\n this.#fetchFn,\n this.#config.customBridgeApiBaseUrl,\n );\n const newBridgeHistoryItem = {\n ...historyItem,\n status,\n completionTime:\n status.status === StatusTypes.COMPLETE ||\n status.status === StatusTypes.FAILED\n ? Date.now()\n : undefined, // TODO make this more accurate by looking up dest txHash block time\n };\n\n // No need to purge these on network change or account change, TransactionController does not purge either.\n // TODO In theory we can skip checking status if it's not the current account/network\n // we need to keep track of the account that this is associated with as well so that we don't show it in Activity list for other accounts\n // First stab at this will not stop polling when you are on a different account\n this.update((state) => {\n state.txHistory[bridgeTxMetaId] = newBridgeHistoryItem;\n });\n\n const pollingToken = this.#pollingTokensByTxMetaId[bridgeTxMetaId];\n\n if (\n (status.status === StatusTypes.COMPLETE ||\n status.status === StatusTypes.FAILED) &&\n pollingToken\n ) {\n this.stopPollingByPollingToken(pollingToken);\n\n if (status.status === StatusTypes.COMPLETE) {\n this.messagingSystem.publish(\n `${BRIDGE_STATUS_CONTROLLER_NAME}:bridgeTransactionComplete`,\n { bridgeHistoryItem: newBridgeHistoryItem },\n );\n }\n if (status.status === StatusTypes.FAILED) {\n this.messagingSystem.publish(\n `${BRIDGE_STATUS_CONTROLLER_NAME}:bridgeTransactionFailed`,\n { bridgeHistoryItem: newBridgeHistoryItem },\n );\n }\n }\n } catch (e) {\n console.log('Failed to fetch bridge tx status', e);\n }\n };\n\n readonly #getSrcTxHash = (bridgeTxMetaId: string): string | undefined => {\n const { txHistory } = this.state;\n // Prefer the srcTxHash from bridgeStatusState so we don't have to l ook up in TransactionController\n // But it is possible to have bridgeHistoryItem in state without the srcTxHash yet when it is an STX\n const srcTxHash = txHistory[bridgeTxMetaId].status.srcChain.txHash;\n\n if (srcTxHash) {\n return srcTxHash;\n }\n\n // Look up in TransactionController if txMeta has been updated with the srcTxHash\n const txControllerState = this.messagingSystem.call(\n 'TransactionController:getState',\n );\n const txMeta = txControllerState.transactions.find(\n (tx) => tx.id === bridgeTxMetaId,\n );\n return txMeta?.hash;\n };\n\n readonly #updateSrcTxHash = (bridgeTxMetaId: string, srcTxHash: string) => {\n const { txHistory } = this.state;\n if (txHistory[bridgeTxMetaId].status.srcChain.txHash) {\n return;\n }\n\n this.update((state) => {\n state.txHistory[bridgeTxMetaId].status.srcChain.txHash = srcTxHash;\n });\n };\n\n // Wipes the bridge status for the given address and chainId\n // Will match only source chainId to the selectedChainId\n readonly #wipeBridgeStatusByChainId = (\n address: string,\n selectedChainId: Hex,\n ) => {\n const sourceTxMetaIdsToDelete = Object.keys(this.state.txHistory).filter(\n (txMetaId) => {\n const bridgeHistoryItem = this.state.txHistory[txMetaId];\n\n const hexSourceChainId = numberToHex(\n bridgeHistoryItem.quote.srcChainId,\n );\n\n return (\n bridgeHistoryItem.account === address &&\n hexSourceChainId === selectedChainId\n );\n },\n );\n\n sourceTxMetaIdsToDelete.forEach((sourceTxMetaId) => {\n const pollingToken = this.#pollingTokensByTxMetaId[sourceTxMetaId];\n\n if (pollingToken) {\n this.stopPollingByPollingToken(\n this.#pollingTokensByTxMetaId[sourceTxMetaId],\n );\n }\n });\n\n this.update((state) => {\n state.txHistory = sourceTxMetaIdsToDelete.reduce(\n (acc, sourceTxMetaId) => {\n delete acc[sourceTxMetaId];\n return acc;\n },\n state.txHistory,\n );\n });\n };\n\n /**\n * Submits a solana swap or bridge transaction using the snap controller\n *\n * @param trade - The trade data to confirm\n * @param quoteResponse - The quote response\n * @param quoteResponse.quote - The quote\n * @returns The transaction meta\n */\n readonly #handleSolanaTx = async (\n trade: string,\n quoteResponse: Omit<QuoteResponse<string>, 'approval' | 'trade'> &\n QuoteMetadata,\n ) => {\n const selectedAccount = this.#getMultichainSelectedAccount();\n if (!selectedAccount) {\n throw new Error(\n 'Failed to submit cross-chain swap transaction: undefined multichain account',\n );\n }\n if (\n !selectedAccount.metadata?.snap?.id ||\n !selectedAccount.options?.scope\n ) {\n throw new Error(\n 'Failed to submit cross-chain swap transaction: undefined snap id or scope',\n );\n }\n /**\n * Submit the transaction to the snap using the keyring rpc method\n * This adds an approval tx to the ApprovalsController in the background\n * The client needs to handle the approval tx by redirecting to the confirmation page with the approvalTxId in the URL\n */\n const keyringReqId = uuid();\n const snapRequestId = uuid();\n const keyringResponse = await this.messagingSystem.call(\n 'SnapController:handleRequest',\n {\n origin: 'metamask',\n snapId: selectedAccount.metadata.snap.id as never,\n handler: 'onKeyringRequest' as never,\n request: {\n id: keyringReqId,\n jsonrpc: '2.0',\n method: 'keyring_submitRequest',\n params: {\n request: {\n params: {\n account: { address: selectedAccount.address },\n transaction: trade,\n scope: selectedAccount.options.scope,\n },\n method: 'signAndSendTransaction',\n },\n id: snapRequestId,\n account: selectedAccount.id,\n scope: selectedAccount.options.scope,\n },\n },\n },\n );\n\n // The extension client actually redirects before it can do anytyhing with this meta\n const txMeta = handleSolanaTxResponse(\n keyringResponse as never, // This is ok bc the snap response can be different types\n quoteResponse,\n selectedAccount.metadata.snap.id,\n selectedAccount.address,\n );\n\n // TODO remove this eventually, just returning it now to match extension behavior\n // OR if the snap can propagate the snapRequestId or keyringReqId to the ApprovalsControlle, this can return the approvalTxId instead and clients won't need to subscribe to the ApprovalsController state to redirect\n return {\n ...txMeta,\n keyringReqId,\n snapRequestId,\n };\n };\n}\n"]}
@@ -1,7 +1,9 @@
1
- import type { BridgeClientId } from "@metamask/bridge-controller";
1
+ import { type QuoteResponse } from "@metamask/bridge-controller";
2
+ import type { QuoteMetadata, TxData } from "@metamask/bridge-controller";
3
+ import type { TransactionMeta } from "@metamask/transaction-controller";
2
4
  import { BRIDGE_STATUS_CONTROLLER_NAME } from "./constants.cjs";
3
5
  import { type BridgeStatusControllerMessenger } from "./types.cjs";
4
- import type { BridgeStatusControllerState, StartPollingForBridgeTxStatusArgsSerialized, FetchFunction } from "./types.cjs";
6
+ import type { BridgeStatusControllerState, StartPollingForBridgeTxStatusArgsSerialized, FetchFunction, BridgeClientId } from "./types.cjs";
5
7
  /** The input to start polling for the {@link BridgeStatusController} */
6
8
  type BridgeStatusPollingInput = FetchBridgeTxStatusArgs;
7
9
  export type FetchBridgeTxStatusArgs = {
@@ -10,6 +12,7 @@ export type FetchBridgeTxStatusArgs = {
10
12
  declare const BridgeStatusController_base: (abstract new (...args: any[]) => {
11
13
  readonly "__#14@#intervalIds": Record<string, NodeJS.Timeout>;
12
14
  "__#14@#intervalLength": number | undefined;
15
+ /** The input to start polling for the {@link BridgeStatusController} */
13
16
  setIntervalLength(intervalLength: number): void;
14
17
  getIntervalLength(): number | undefined;
15
18
  _startPolling(input: FetchBridgeTxStatusArgs): void;
@@ -33,11 +36,27 @@ export declare class BridgeStatusController extends BridgeStatusController_base<
33
36
  customBridgeApiBaseUrl?: string;
34
37
  };
35
38
  });
39
+ /**
40
+ * Submits a cross-chain swap transaction
41
+ *
42
+ * @param quoteResponse - The quote response
43
+ * @param quoteResponse.quote - The quote
44
+ * @param quoteResponse.trade - The trade
45
+ * @param quoteResponse.approval - The approval
46
+ * @returns The transaction meta
47
+ */
48
+ submitTx: (quoteResponse: QuoteResponse<TxData | string> & QuoteMetadata) => Promise<TransactionMeta>;
36
49
  resetState: () => void;
37
50
  wipeBridgeStatus: ({ address, ignoreNetwork, }: {
38
51
  address: string;
39
52
  ignoreNetwork: boolean;
40
53
  }) => void;
54
+ /**
55
+ * Starts polling for the bridge tx status
56
+ *
57
+ * @param startPollingForBridgeTxStatusArgs - The args to start polling for the bridge tx status
58
+ * @deprecated Use {@link submitTx} to submit tx and start polling for bridge tx status instead
59
+ */
41
60
  startPollingForBridgeTxStatus: (startPollingForBridgeTxStatusArgs: StartPollingForBridgeTxStatusArgsSerialized) => void;
42
61
  _executePoll: (pollingInput: BridgeStatusPollingInput) => Promise<void>;
43
62
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bridge-status-controller.d.cts","sourceRoot":"","sources":["../src/bridge-status-controller.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,oCAAoC;AAKlE,OAAO,EACL,6BAA6B,EAG9B,wBAAoB;AACrB,OAAO,EAAe,KAAK,+BAA+B,EAAE,oBAAgB;AAC5E,OAAO,KAAK,EACV,2BAA2B,EAC3B,2CAA2C,EAC3C,aAAa,EACd,oBAAgB;AAejB,wEAAwE;AACxE,KAAK,wBAAwB,GAAG,uBAAuB,CAAC;AAGxD,MAAM,MAAM,uBAAuB,GAAG;IACpC,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;;;;;;;;;;;;;;;;AACF,qBAAa,sBAAuB,SAAQ,4BAC1C,OAAO,6BAA6B,EACpC,2BAA2B,EAC3B,+BAA+B,CAChC;;gBAWa,EACV,SAAS,EACT,KAAK,EACL,QAAQ,EACR,OAAO,EACP,MAAM,GACP,EAAE;QACD,SAAS,EAAE,+BAA+B,CAAC;QAC3C,KAAK,CAAC,EAAE,OAAO,CAAC,2BAA2B,CAAC,CAAC;QAC7C,QAAQ,EAAE,cAAc,CAAC;QACzB,OAAO,EAAE,aAAa,CAAC;QACvB,MAAM,CAAC,EAAE;YACP,sBAAsB,CAAC,EAAE,MAAM,CAAC;SACjC,CAAC;KACH;IAuCD,UAAU,aAIR;IAEF,gBAAgB;iBAIL,MAAM;uBACA,OAAO;eAmBtB;IA8BF,6BAA6B,sCACQ,2CAA2C,UAiD9E;IAIF,YAAY,iBAAwB,wBAAwB,mBAE1D;CA0JH"}
1
+ {"version":3,"file":"bridge-status-controller.d.cts","sourceRoot":"","sources":["../src/bridge-status-controller.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,aAAa,EACnB,oCAAoC;AACrC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,oCAAoC;AAEzE,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AAIxE,OAAO,EAEL,6BAA6B,EAG9B,wBAAoB;AACrB,OAAO,EAAe,KAAK,+BAA+B,EAAE,oBAAgB;AAC5E,OAAO,KAAK,EACV,2BAA2B,EAC3B,2CAA2C,EAC3C,aAAa,EACb,cAAc,EACf,oBAAgB;AAmBjB,wEAAwE;AACxE,KAAK,wBAAwB,GAAG,uBAAuB,CAAC;AAGxD,MAAM,MAAM,uBAAuB,GAAG;IACpC,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;;;;IANF,wEAAwE;;;;;;;;;;;;;AAOxE,qBAAa,sBAAuB,SAAQ,4BAC1C,OAAO,6BAA6B,EACpC,2BAA2B,EAC3B,+BAA+B,CAChC;;gBAWa,EACV,SAAS,EACT,KAAK,EACL,QAAQ,EACR,OAAO,EACP,MAAM,GACP,EAAE;QACD,SAAS,EAAE,+BAA+B,CAAC;QAC3C,KAAK,CAAC,EAAE,OAAO,CAAC,2BAA2B,CAAC,CAAC;QAC7C,QAAQ,EAAE,cAAc,CAAC;QACzB,OAAO,EAAE,aAAa,CAAC;QACvB,MAAM,CAAC,EAAE;YACP,sBAAsB,CAAC,EAAE,MAAM,CAAC;SACjC,CAAC;KACH;IA8CD;;;;;;;;OAQG;IACH,QAAQ,kBACS,cAAc,MAAM,GAAG,MAAM,CAAC,GAAG,aAAa,8BAuC7D;IAEF,UAAU,aAIR;IAEF,gBAAgB;iBAIL,MAAM;uBACA,OAAO;eAmBtB;IA8BF;;;;;OAKG;IACH,6BAA6B,sCACQ,2CAA2C,UAiD9E;IAIF,YAAY,iBAAwB,wBAAwB,mBAE1D;CA0OH"}
@@ -1,7 +1,9 @@
1
- import type { BridgeClientId } from "@metamask/bridge-controller";
1
+ import { type QuoteResponse } from "@metamask/bridge-controller";
2
+ import type { QuoteMetadata, TxData } from "@metamask/bridge-controller";
3
+ import type { TransactionMeta } from "@metamask/transaction-controller";
2
4
  import { BRIDGE_STATUS_CONTROLLER_NAME } from "./constants.mjs";
3
5
  import { type BridgeStatusControllerMessenger } from "./types.mjs";
4
- import type { BridgeStatusControllerState, StartPollingForBridgeTxStatusArgsSerialized, FetchFunction } from "./types.mjs";
6
+ import type { BridgeStatusControllerState, StartPollingForBridgeTxStatusArgsSerialized, FetchFunction, BridgeClientId } from "./types.mjs";
5
7
  /** The input to start polling for the {@link BridgeStatusController} */
6
8
  type BridgeStatusPollingInput = FetchBridgeTxStatusArgs;
7
9
  export type FetchBridgeTxStatusArgs = {
@@ -10,6 +12,7 @@ export type FetchBridgeTxStatusArgs = {
10
12
  declare const BridgeStatusController_base: (abstract new (...args: any[]) => {
11
13
  readonly "__#14@#intervalIds": Record<string, NodeJS.Timeout>;
12
14
  "__#14@#intervalLength": number | undefined;
15
+ /** The input to start polling for the {@link BridgeStatusController} */
13
16
  setIntervalLength(intervalLength: number): void;
14
17
  getIntervalLength(): number | undefined;
15
18
  _startPolling(input: FetchBridgeTxStatusArgs): void;
@@ -33,11 +36,27 @@ export declare class BridgeStatusController extends BridgeStatusController_base<
33
36
  customBridgeApiBaseUrl?: string;
34
37
  };
35
38
  });
39
+ /**
40
+ * Submits a cross-chain swap transaction
41
+ *
42
+ * @param quoteResponse - The quote response
43
+ * @param quoteResponse.quote - The quote
44
+ * @param quoteResponse.trade - The trade
45
+ * @param quoteResponse.approval - The approval
46
+ * @returns The transaction meta
47
+ */
48
+ submitTx: (quoteResponse: QuoteResponse<TxData | string> & QuoteMetadata) => Promise<TransactionMeta>;
36
49
  resetState: () => void;
37
50
  wipeBridgeStatus: ({ address, ignoreNetwork, }: {
38
51
  address: string;
39
52
  ignoreNetwork: boolean;
40
53
  }) => void;
54
+ /**
55
+ * Starts polling for the bridge tx status
56
+ *
57
+ * @param startPollingForBridgeTxStatusArgs - The args to start polling for the bridge tx status
58
+ * @deprecated Use {@link submitTx} to submit tx and start polling for bridge tx status instead
59
+ */
41
60
  startPollingForBridgeTxStatus: (startPollingForBridgeTxStatusArgs: StartPollingForBridgeTxStatusArgsSerialized) => void;
42
61
  _executePoll: (pollingInput: BridgeStatusPollingInput) => Promise<void>;
43
62
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bridge-status-controller.d.mts","sourceRoot":"","sources":["../src/bridge-status-controller.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,oCAAoC;AAKlE,OAAO,EACL,6BAA6B,EAG9B,wBAAoB;AACrB,OAAO,EAAe,KAAK,+BAA+B,EAAE,oBAAgB;AAC5E,OAAO,KAAK,EACV,2BAA2B,EAC3B,2CAA2C,EAC3C,aAAa,EACd,oBAAgB;AAejB,wEAAwE;AACxE,KAAK,wBAAwB,GAAG,uBAAuB,CAAC;AAGxD,MAAM,MAAM,uBAAuB,GAAG;IACpC,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;;;;;;;;;;;;;;;;AACF,qBAAa,sBAAuB,SAAQ,4BAC1C,OAAO,6BAA6B,EACpC,2BAA2B,EAC3B,+BAA+B,CAChC;;gBAWa,EACV,SAAS,EACT,KAAK,EACL,QAAQ,EACR,OAAO,EACP,MAAM,GACP,EAAE;QACD,SAAS,EAAE,+BAA+B,CAAC;QAC3C,KAAK,CAAC,EAAE,OAAO,CAAC,2BAA2B,CAAC,CAAC;QAC7C,QAAQ,EAAE,cAAc,CAAC;QACzB,OAAO,EAAE,aAAa,CAAC;QACvB,MAAM,CAAC,EAAE;YACP,sBAAsB,CAAC,EAAE,MAAM,CAAC;SACjC,CAAC;KACH;IAuCD,UAAU,aAIR;IAEF,gBAAgB;iBAIL,MAAM;uBACA,OAAO;eAmBtB;IA8BF,6BAA6B,sCACQ,2CAA2C,UAiD9E;IAIF,YAAY,iBAAwB,wBAAwB,mBAE1D;CA0JH"}
1
+ {"version":3,"file":"bridge-status-controller.d.mts","sourceRoot":"","sources":["../src/bridge-status-controller.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,aAAa,EACnB,oCAAoC;AACrC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,oCAAoC;AAEzE,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AAIxE,OAAO,EAEL,6BAA6B,EAG9B,wBAAoB;AACrB,OAAO,EAAe,KAAK,+BAA+B,EAAE,oBAAgB;AAC5E,OAAO,KAAK,EACV,2BAA2B,EAC3B,2CAA2C,EAC3C,aAAa,EACb,cAAc,EACf,oBAAgB;AAmBjB,wEAAwE;AACxE,KAAK,wBAAwB,GAAG,uBAAuB,CAAC;AAGxD,MAAM,MAAM,uBAAuB,GAAG;IACpC,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;;;;IANF,wEAAwE;;;;;;;;;;;;;AAOxE,qBAAa,sBAAuB,SAAQ,4BAC1C,OAAO,6BAA6B,EACpC,2BAA2B,EAC3B,+BAA+B,CAChC;;gBAWa,EACV,SAAS,EACT,KAAK,EACL,QAAQ,EACR,OAAO,EACP,MAAM,GACP,EAAE;QACD,SAAS,EAAE,+BAA+B,CAAC;QAC3C,KAAK,CAAC,EAAE,OAAO,CAAC,2BAA2B,CAAC,CAAC;QAC7C,QAAQ,EAAE,cAAc,CAAC;QACzB,OAAO,EAAE,aAAa,CAAC;QACvB,MAAM,CAAC,EAAE;YACP,sBAAsB,CAAC,EAAE,MAAM,CAAC;SACjC,CAAC;KACH;IA8CD;;;;;;;;OAQG;IACH,QAAQ,kBACS,cAAc,MAAM,GAAG,MAAM,CAAC,GAAG,aAAa,8BAuC7D;IAEF,UAAU,aAIR;IAEF,gBAAgB;iBAIL,MAAM;uBACA,OAAO;eAmBtB;IA8BF;;;;;OAKG;IACH,6BAA6B,sCACQ,2CAA2C,UAiD9E;IAIF,YAAY,iBAAwB,wBAAwB,mBAE1D;CA0OH"}
@@ -9,13 +9,15 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _BridgeStatusController_instances, _BridgeStatusController_pollingTokensByTxMetaId, _BridgeStatusController_clientId, _BridgeStatusController_fetchFn, _BridgeStatusController_config, _BridgeStatusController_restartPollingForIncompleteHistoryItems, _BridgeStatusController_getMultichainSelectedAccountAddress, _BridgeStatusController_fetchBridgeTxStatus, _BridgeStatusController_getSrcTxHash, _BridgeStatusController_updateSrcTxHash, _BridgeStatusController_wipeBridgeStatusByChainId;
13
- import { BRIDGE_PROD_API_BASE_URL } from "@metamask/bridge-controller";
12
+ var _BridgeStatusController_instances, _BridgeStatusController_pollingTokensByTxMetaId, _BridgeStatusController_clientId, _BridgeStatusController_fetchFn, _BridgeStatusController_config, _BridgeStatusController_restartPollingForIncompleteHistoryItems, _BridgeStatusController_getMultichainSelectedAccount, _BridgeStatusController_getMultichainSelectedAccountAddress, _BridgeStatusController_fetchBridgeTxStatus, _BridgeStatusController_getSrcTxHash, _BridgeStatusController_updateSrcTxHash, _BridgeStatusController_wipeBridgeStatusByChainId, _BridgeStatusController_handleSolanaTx;
13
+ import { isSolanaChainId } from "@metamask/bridge-controller";
14
14
  import { StaticIntervalPollingController } from "@metamask/polling-controller";
15
15
  import { numberToHex } from "@metamask/utils";
16
- import { BRIDGE_STATUS_CONTROLLER_NAME, DEFAULT_BRIDGE_STATUS_CONTROLLER_STATE, REFRESH_INTERVAL_MS } from "./constants.mjs";
16
+ import { v4 as uuid } from "uuid";
17
+ import { BRIDGE_PROD_API_BASE_URL, BRIDGE_STATUS_CONTROLLER_NAME, DEFAULT_BRIDGE_STATUS_CONTROLLER_STATE, REFRESH_INTERVAL_MS } from "./constants.mjs";
17
18
  import { StatusTypes } from "./types.mjs";
18
19
  import { fetchBridgeTxStatus, getStatusRequestWithSrcTxHash } from "./utils/bridge-status.mjs";
20
+ import { getStatusRequestParams, handleSolanaTxResponse } from "./utils/transaction.mjs";
19
21
  const metadata = {
20
22
  // We want to persist the bridge status state so that we can show the proper data for the Activity list
21
23
  // basically match the behavior of TransactionController
@@ -41,6 +43,49 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
41
43
  _BridgeStatusController_clientId.set(this, void 0);
42
44
  _BridgeStatusController_fetchFn.set(this, void 0);
43
45
  _BridgeStatusController_config.set(this, void 0);
46
+ /**
47
+ * Submits a cross-chain swap transaction
48
+ *
49
+ * @param quoteResponse - The quote response
50
+ * @param quoteResponse.quote - The quote
51
+ * @param quoteResponse.trade - The trade
52
+ * @param quoteResponse.approval - The approval
53
+ * @returns The transaction meta
54
+ */
55
+ this.submitTx = async (quoteResponse) => {
56
+ this.stopAllPolling();
57
+ if (!isSolanaChainId(quoteResponse.quote.srcChainId)) {
58
+ throw new Error('Failed to submit bridge tx: only Solana is supported');
59
+ }
60
+ let txMeta;
61
+ // Submit SOLANA tx
62
+ if (isSolanaChainId(quoteResponse.quote.srcChainId) &&
63
+ typeof quoteResponse.trade === 'string') {
64
+ const { approval, trade, ...partialQuoteResponse } = quoteResponse;
65
+ txMeta = await __classPrivateFieldGet(this, _BridgeStatusController_handleSolanaTx, "f").call(this, trade, partialQuoteResponse);
66
+ }
67
+ if (!txMeta) {
68
+ throw new Error('Failed to submit bridge tx: txMeta is undefined');
69
+ }
70
+ // Start polling for bridge tx status
71
+ try {
72
+ const statusRequestCommon = getStatusRequestParams(quoteResponse);
73
+ this.startPollingForBridgeTxStatus({
74
+ bridgeTxMeta: txMeta,
75
+ statusRequest: {
76
+ ...statusRequestCommon,
77
+ srcTxHash: txMeta.hash,
78
+ },
79
+ quoteResponse,
80
+ slippagePercentage: 0,
81
+ startTime: Date.now(),
82
+ });
83
+ }
84
+ catch {
85
+ // Ignore errors here, we don't want to crash the app if this fails and tx submission succeeds
86
+ }
87
+ return txMeta;
88
+ };
44
89
  this.resetState = () => {
45
90
  this.update((state) => {
46
91
  state.txHistory = DEFAULT_BRIDGE_STATUS_CONTROLLER_STATE.txHistory;
@@ -82,6 +127,12 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
82
127
  });
83
128
  });
84
129
  });
130
+ /**
131
+ * Starts polling for the bridge tx status
132
+ *
133
+ * @param startPollingForBridgeTxStatusArgs - The args to start polling for the bridge tx status
134
+ * @deprecated Use {@link submitTx} to submit tx and start polling for bridge tx status instead
135
+ */
85
136
  this.startPollingForBridgeTxStatus = (startPollingForBridgeTxStatusArgs) => {
86
137
  const { bridgeTxMeta, statusRequest, quoteResponse, startTime, slippagePercentage, initialDestAssetBalance, targetContractAddress, } = startPollingForBridgeTxStatusArgs;
87
138
  const accountAddress = __classPrivateFieldGet(this, _BridgeStatusController_instances, "m", _BridgeStatusController_getMultichainSelectedAccountAddress).call(this);
@@ -139,7 +190,7 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
139
190
  }
140
191
  __classPrivateFieldGet(this, _BridgeStatusController_updateSrcTxHash, "f").call(this, bridgeTxMetaId, srcTxHash);
141
192
  const statusRequest = getStatusRequestWithSrcTxHash(historyItem.quote, srcTxHash);
142
- const status = await fetchBridgeTxStatus(statusRequest, __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f"), __classPrivateFieldGet(this, _BridgeStatusController_fetchFn, "f"), __classPrivateFieldGet(this, _BridgeStatusController_config, "f").customBridgeApiBaseUrl ?? BRIDGE_PROD_API_BASE_URL);
193
+ const status = await fetchBridgeTxStatus(statusRequest, __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f"), __classPrivateFieldGet(this, _BridgeStatusController_fetchFn, "f"), __classPrivateFieldGet(this, _BridgeStatusController_config, "f").customBridgeApiBaseUrl);
143
194
  const newBridgeHistoryItem = {
144
195
  ...historyItem,
145
196
  status,
@@ -216,13 +267,74 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
216
267
  }, state.txHistory);
217
268
  });
218
269
  });
270
+ /**
271
+ * Submits a solana swap or bridge transaction using the snap controller
272
+ *
273
+ * @param trade - The trade data to confirm
274
+ * @param quoteResponse - The quote response
275
+ * @param quoteResponse.quote - The quote
276
+ * @returns The transaction meta
277
+ */
278
+ _BridgeStatusController_handleSolanaTx.set(this, async (trade, quoteResponse) => {
279
+ const selectedAccount = __classPrivateFieldGet(this, _BridgeStatusController_instances, "m", _BridgeStatusController_getMultichainSelectedAccount).call(this);
280
+ if (!selectedAccount) {
281
+ throw new Error('Failed to submit cross-chain swap transaction: undefined multichain account');
282
+ }
283
+ if (!selectedAccount.metadata?.snap?.id ||
284
+ !selectedAccount.options?.scope) {
285
+ throw new Error('Failed to submit cross-chain swap transaction: undefined snap id or scope');
286
+ }
287
+ /**
288
+ * Submit the transaction to the snap using the keyring rpc method
289
+ * This adds an approval tx to the ApprovalsController in the background
290
+ * The client needs to handle the approval tx by redirecting to the confirmation page with the approvalTxId in the URL
291
+ */
292
+ const keyringReqId = uuid();
293
+ const snapRequestId = uuid();
294
+ const keyringResponse = await this.messagingSystem.call('SnapController:handleRequest', {
295
+ origin: 'metamask',
296
+ snapId: selectedAccount.metadata.snap.id,
297
+ handler: 'onKeyringRequest',
298
+ request: {
299
+ id: keyringReqId,
300
+ jsonrpc: '2.0',
301
+ method: 'keyring_submitRequest',
302
+ params: {
303
+ request: {
304
+ params: {
305
+ account: { address: selectedAccount.address },
306
+ transaction: trade,
307
+ scope: selectedAccount.options.scope,
308
+ },
309
+ method: 'signAndSendTransaction',
310
+ },
311
+ id: snapRequestId,
312
+ account: selectedAccount.id,
313
+ scope: selectedAccount.options.scope,
314
+ },
315
+ },
316
+ });
317
+ // The extension client actually redirects before it can do anytyhing with this meta
318
+ const txMeta = handleSolanaTxResponse(keyringResponse, // This is ok bc the snap response can be different types
319
+ quoteResponse, selectedAccount.metadata.snap.id, selectedAccount.address);
320
+ // TODO remove this eventually, just returning it now to match extension behavior
321
+ // OR if the snap can propagate the snapRequestId or keyringReqId to the ApprovalsControlle, this can return the approvalTxId instead and clients won't need to subscribe to the ApprovalsController state to redirect
322
+ return {
323
+ ...txMeta,
324
+ keyringReqId,
325
+ snapRequestId,
326
+ };
327
+ });
219
328
  __classPrivateFieldSet(this, _BridgeStatusController_clientId, clientId, "f");
220
329
  __classPrivateFieldSet(this, _BridgeStatusController_fetchFn, fetchFn, "f");
221
- __classPrivateFieldSet(this, _BridgeStatusController_config, config ?? {}, "f");
330
+ __classPrivateFieldSet(this, _BridgeStatusController_config, {
331
+ customBridgeApiBaseUrl: config?.customBridgeApiBaseUrl ?? BRIDGE_PROD_API_BASE_URL,
332
+ }, "f");
222
333
  // Register action handlers
223
334
  this.messagingSystem.registerActionHandler(`${BRIDGE_STATUS_CONTROLLER_NAME}:startPollingForBridgeTxStatus`, this.startPollingForBridgeTxStatus.bind(this));
224
335
  this.messagingSystem.registerActionHandler(`${BRIDGE_STATUS_CONTROLLER_NAME}:wipeBridgeStatus`, this.wipeBridgeStatus.bind(this));
225
336
  this.messagingSystem.registerActionHandler(`${BRIDGE_STATUS_CONTROLLER_NAME}:resetState`, this.resetState.bind(this));
337
+ this.messagingSystem.registerActionHandler(`${BRIDGE_STATUS_CONTROLLER_NAME}:submitTx`, this.submitTx.bind(this));
226
338
  // Set interval
227
339
  this.setIntervalLength(REFRESH_INTERVAL_MS);
228
340
  // If you close the extension, but keep the browser open, the polling continues
@@ -231,7 +343,9 @@ export class BridgeStatusController extends StaticIntervalPollingController() {
231
343
  __classPrivateFieldGet(this, _BridgeStatusController_restartPollingForIncompleteHistoryItems, "f").call(this);
232
344
  }
233
345
  }
234
- _BridgeStatusController_pollingTokensByTxMetaId = new WeakMap(), _BridgeStatusController_clientId = new WeakMap(), _BridgeStatusController_fetchFn = new WeakMap(), _BridgeStatusController_config = new WeakMap(), _BridgeStatusController_restartPollingForIncompleteHistoryItems = new WeakMap(), _BridgeStatusController_fetchBridgeTxStatus = new WeakMap(), _BridgeStatusController_getSrcTxHash = new WeakMap(), _BridgeStatusController_updateSrcTxHash = new WeakMap(), _BridgeStatusController_wipeBridgeStatusByChainId = new WeakMap(), _BridgeStatusController_instances = new WeakSet(), _BridgeStatusController_getMultichainSelectedAccountAddress = function _BridgeStatusController_getMultichainSelectedAccountAddress() {
235
- return (this.messagingSystem.call('AccountsController:getSelectedMultichainAccount')?.address ?? '');
346
+ _BridgeStatusController_pollingTokensByTxMetaId = new WeakMap(), _BridgeStatusController_clientId = new WeakMap(), _BridgeStatusController_fetchFn = new WeakMap(), _BridgeStatusController_config = new WeakMap(), _BridgeStatusController_restartPollingForIncompleteHistoryItems = new WeakMap(), _BridgeStatusController_fetchBridgeTxStatus = new WeakMap(), _BridgeStatusController_getSrcTxHash = new WeakMap(), _BridgeStatusController_updateSrcTxHash = new WeakMap(), _BridgeStatusController_wipeBridgeStatusByChainId = new WeakMap(), _BridgeStatusController_handleSolanaTx = new WeakMap(), _BridgeStatusController_instances = new WeakSet(), _BridgeStatusController_getMultichainSelectedAccount = function _BridgeStatusController_getMultichainSelectedAccount() {
347
+ return this.messagingSystem.call('AccountsController:getSelectedMultichainAccount');
348
+ }, _BridgeStatusController_getMultichainSelectedAccountAddress = function _BridgeStatusController_getMultichainSelectedAccountAddress() {
349
+ return __classPrivateFieldGet(this, _BridgeStatusController_instances, "m", _BridgeStatusController_getMultichainSelectedAccount).call(this)?.address ?? '';
236
350
  };
237
351
  //# sourceMappingURL=bridge-status-controller.mjs.map