{"version":3,"file":"bridge-submit.mjs","sourceRoot":"","sources":["../../../src/strategy/bridge/bridge-submit.ts"],"names":[],"mappings":"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","sourcesContent":["import { StatusTypes } from '@metamask/bridge-controller';\nimport type { QuoteMetadata } from '@metamask/bridge-controller';\nimport type { QuoteResponse } from '@metamask/bridge-controller';\nimport type { BridgeHistoryItem } from '@metamask/bridge-status-controller';\nimport { toHex } from '@metamask/controller-utils';\nimport type { TransactionMeta } from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { cloneDeep } from 'lodash';\n\nimport { refreshQuote } from './bridge-quotes';\nimport type { TransactionPayBridgeQuote } from './types';\nimport { projectLogger } from '../../logger';\nimport type {\n  TransactionPayControllerMessenger,\n  TransactionPayQuote,\n} from '../../types';\nimport {\n  updateTransaction,\n  waitForTransactionConfirmed,\n} from '../../utils/transaction';\n\nconst log = createModuleLogger(projectLogger, 'bridge-strategy');\n\nexport type SubmitBridgeQuotesRequest = {\n  from: Hex;\n  isSmartTransaction: (chainId: Hex) => boolean;\n  messenger: TransactionPayControllerMessenger;\n  quotes: TransactionPayQuote<TransactionPayBridgeQuote>[];\n  transaction: TransactionMeta;\n};\n\n/**\n * Submit multiple bridge quotes sequentially and wait for their completion.\n *\n * @param request - The request object containing necessary data.\n * @returns An object containing the transaction hash if available.\n */\nexport async function submitBridgeQuotes(\n  request: SubmitBridgeQuotesRequest,\n): Promise<void> {\n  const { quotes, messenger, transaction } = request;\n\n  if (!quotes?.length) {\n    log('No quotes found');\n    return;\n  }\n\n  // Currently we only support a single source meaning we only check the first quote.\n  const isSameChain =\n    quotes[0].original.quote.srcChainId ===\n    quotes[0].original.quote.destChainId;\n\n  if (isSameChain) {\n    log(\n      'Ignoring quotes as source is same chain',\n      quotes[0].original.quote.srcChainId,\n    );\n    return;\n  }\n\n  let index = 0;\n\n  for (const quote of quotes) {\n    log('Submitting bridge', index, quote);\n\n    const finalQuote =\n      index > 0\n        ? await refreshQuote(quote, messenger as never, transaction)\n        : quote.original;\n\n    await submitBridgeTransaction(request, finalQuote);\n\n    index += 1;\n  }\n}\n\n/**\n * Submit a bridge transaction and wait for it to complete.\n *\n * @param request - The request object containing necessary data.\n * @param originalQuote - The original quote to submit.\n */\nasync function submitBridgeTransaction(\n  request: SubmitBridgeQuotesRequest,\n  originalQuote: QuoteResponse,\n): Promise<void> {\n  const { isSmartTransaction, messenger, from, transaction } = request;\n  const quote = cloneDeep(originalQuote);\n  const sourceChainId = toHex(quote.quote.srcChainId);\n  const isSTX = isSmartTransaction(sourceChainId);\n  const requiredTransactionIds: string[] = [];\n\n  const bridgeTransactionIdCollector = collectTransactionIds(\n    sourceChainId,\n    from,\n    messenger,\n    (id) =>\n      updateTransaction(\n        {\n          transactionId: transaction.id,\n          messenger,\n          note: 'Add required transaction ID',\n        },\n        (transactionMeta) => {\n          if (!transactionMeta.requiredTransactionIds) {\n            transactionMeta.requiredTransactionIds = [];\n          }\n\n          transactionMeta?.requiredTransactionIds.push(id);\n          requiredTransactionIds.push(id);\n        },\n      ),\n  );\n\n  const tokenAmountValues = {\n    amount: '0',\n    valueInCurrency: null,\n    usd: null,\n  };\n\n  const metadata: QuoteMetadata = {\n    gasFee: {\n      effective: tokenAmountValues,\n      max: tokenAmountValues,\n      total: tokenAmountValues,\n    },\n    totalNetworkFee: tokenAmountValues,\n    totalMaxNetworkFee: tokenAmountValues,\n    toTokenAmount: tokenAmountValues,\n    minToTokenAmount: tokenAmountValues,\n    adjustedReturn: tokenAmountValues,\n    sentAmount: tokenAmountValues,\n    swapRate: '0',\n    cost: tokenAmountValues,\n  };\n\n  const result = await messenger.call(\n    'BridgeStatusController:submitTx',\n    from,\n    { ...quote, ...metadata },\n    isSTX,\n  );\n\n  bridgeTransactionIdCollector.end();\n\n  log('Bridge transaction submitted', {\n    requiredTransactionIds,\n    result,\n  });\n\n  await Promise.all(\n    requiredTransactionIds.map((id) =>\n      waitForTransactionConfirmed(id, messenger),\n    ),\n  );\n\n  log('All required transactions confirmed', requiredTransactionIds);\n\n  const { id: bridgeTransactionId } = result;\n\n  log('Waiting for bridge completion', bridgeTransactionId);\n\n  await waitForBridgeCompletion(bridgeTransactionId, messenger);\n}\n\n/**\n * Wait for a bridge transaction to complete.\n *\n * @param bridgeTransactionId - The bridge transaction ID.\n * @param messenger - The controller messenger.\n */\nasync function waitForBridgeCompletion(\n  bridgeTransactionId: string,\n  messenger: TransactionPayControllerMessenger,\n): Promise<void> {\n  return new Promise((resolve, reject) => {\n    const isComplete = (item?: BridgeHistoryItem, fn?: () => void) => {\n      const status = item?.status?.status;\n\n      log('Checking bridge status', status ?? 'missing');\n\n      if (status === StatusTypes.COMPLETE) {\n        fn?.();\n        resolve();\n        return true;\n      }\n\n      if (status === StatusTypes.FAILED) {\n        fn?.();\n        reject(new Error('Bridge failed'));\n        return true;\n      }\n\n      return false;\n    };\n\n    const initialState = messenger.call('BridgeStatusController:getState');\n\n    const initialTx = initialState.txHistory[bridgeTransactionId];\n\n    if (isComplete(initialTx)) {\n      return;\n    }\n\n    const handler = (bridgeHistory?: BridgeHistoryItem) => {\n      const unsubscribe = () =>\n        messenger.unsubscribe('BridgeStatusController:stateChange', handler);\n\n      isComplete(bridgeHistory, unsubscribe);\n    };\n\n    messenger.subscribe(\n      'BridgeStatusController:stateChange',\n      handler,\n      (state) => state.txHistory[bridgeTransactionId],\n    );\n  });\n}\n\n/**\n * Collect all new transactions until `end` is called.\n *\n * @param chainId - The chain ID to filter transactions by.\n * @param from - The address to filter transactions by.\n * @param messenger - The controller messenger.\n * @param onTransaction - Callback called with each matching transaction ID.\n * @returns An object with an `end` method to stop collecting transactions.\n */\nfunction collectTransactionIds(\n  chainId: Hex,\n  from: Hex,\n  messenger: TransactionPayControllerMessenger,\n  onTransaction: (transactionId: string) => void,\n): { end: () => void } {\n  const listener = (tx: TransactionMeta) => {\n    if (\n      tx.chainId !== chainId ||\n      tx.txParams.from.toLowerCase() !== from.toLowerCase()\n    ) {\n      return;\n    }\n\n    onTransaction(tx.id);\n  };\n\n  messenger.subscribe(\n    'TransactionController:unapprovedTransactionAdded',\n    listener,\n  );\n\n  const end = () => {\n    messenger.unsubscribe(\n      'TransactionController:unapprovedTransactionAdded',\n      listener,\n    );\n  };\n\n  return { end };\n}\n"]}