@metamask/bridge-status-controller 71.2.1 → 72.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/CHANGELOG.md +40 -1
  2. package/dist/bridge-status-controller-method-action-types.cjs.map +1 -1
  3. package/dist/bridge-status-controller-method-action-types.d.cts +5 -1
  4. package/dist/bridge-status-controller-method-action-types.d.cts.map +1 -1
  5. package/dist/bridge-status-controller-method-action-types.d.mts +5 -1
  6. package/dist/bridge-status-controller-method-action-types.d.mts.map +1 -1
  7. package/dist/bridge-status-controller-method-action-types.mjs.map +1 -1
  8. package/dist/bridge-status-controller.cjs +161 -366
  9. package/dist/bridge-status-controller.cjs.map +1 -1
  10. package/dist/bridge-status-controller.d.cts +27 -7
  11. package/dist/bridge-status-controller.d.cts.map +1 -1
  12. package/dist/bridge-status-controller.d.mts +27 -7
  13. package/dist/bridge-status-controller.d.mts.map +1 -1
  14. package/dist/bridge-status-controller.mjs +162 -370
  15. package/dist/bridge-status-controller.mjs.map +1 -1
  16. package/dist/index.cjs +4 -1
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +1 -0
  19. package/dist/index.d.cts.map +1 -1
  20. package/dist/index.d.mts +1 -0
  21. package/dist/index.d.mts.map +1 -1
  22. package/dist/index.mjs +1 -0
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/strategy/batch-sell-strategy.cjs +103 -0
  25. package/dist/strategy/batch-sell-strategy.cjs.map +1 -0
  26. package/dist/strategy/batch-sell-strategy.d.cts +10 -0
  27. package/dist/strategy/batch-sell-strategy.d.cts.map +1 -0
  28. package/dist/strategy/batch-sell-strategy.d.mts +10 -0
  29. package/dist/strategy/batch-sell-strategy.d.mts.map +1 -0
  30. package/dist/strategy/batch-sell-strategy.mjs +99 -0
  31. package/dist/strategy/batch-sell-strategy.mjs.map +1 -0
  32. package/dist/strategy/batch-strategy.cjs +74 -0
  33. package/dist/strategy/batch-strategy.cjs.map +1 -0
  34. package/dist/strategy/batch-strategy.d.cts +10 -0
  35. package/dist/strategy/batch-strategy.d.cts.map +1 -0
  36. package/dist/strategy/batch-strategy.d.mts +10 -0
  37. package/dist/strategy/batch-strategy.d.mts.map +1 -0
  38. package/dist/strategy/batch-strategy.mjs +70 -0
  39. package/dist/strategy/batch-strategy.mjs.map +1 -0
  40. package/dist/strategy/evm-strategy.cjs +149 -0
  41. package/dist/strategy/evm-strategy.cjs.map +1 -0
  42. package/dist/strategy/evm-strategy.d.cts +38 -0
  43. package/dist/strategy/evm-strategy.d.cts.map +1 -0
  44. package/dist/strategy/evm-strategy.d.mts +38 -0
  45. package/dist/strategy/evm-strategy.d.mts.map +1 -0
  46. package/dist/strategy/evm-strategy.mjs +143 -0
  47. package/dist/strategy/evm-strategy.mjs.map +1 -0
  48. package/dist/strategy/index.cjs +70 -0
  49. package/dist/strategy/index.cjs.map +1 -0
  50. package/dist/strategy/index.d.cts +12 -0
  51. package/dist/strategy/index.d.cts.map +1 -0
  52. package/dist/strategy/index.d.mts +12 -0
  53. package/dist/strategy/index.d.mts.map +1 -0
  54. package/dist/strategy/index.mjs +68 -0
  55. package/dist/strategy/index.mjs.map +1 -0
  56. package/dist/strategy/intent-strategy.cjs +160 -0
  57. package/dist/strategy/intent-strategy.cjs.map +1 -0
  58. package/dist/strategy/intent-strategy.d.cts +17 -0
  59. package/dist/strategy/intent-strategy.d.cts.map +1 -0
  60. package/dist/strategy/intent-strategy.d.mts +17 -0
  61. package/dist/strategy/intent-strategy.d.mts.map +1 -0
  62. package/dist/strategy/intent-strategy.mjs +156 -0
  63. package/dist/strategy/intent-strategy.mjs.map +1 -0
  64. package/dist/strategy/non-evm-strategy.cjs +80 -0
  65. package/dist/strategy/non-evm-strategy.cjs.map +1 -0
  66. package/dist/strategy/non-evm-strategy.d.cts +15 -0
  67. package/dist/strategy/non-evm-strategy.d.cts.map +1 -0
  68. package/dist/strategy/non-evm-strategy.d.mts +15 -0
  69. package/dist/strategy/non-evm-strategy.d.mts.map +1 -0
  70. package/dist/strategy/non-evm-strategy.mjs +76 -0
  71. package/dist/strategy/non-evm-strategy.mjs.map +1 -0
  72. package/dist/strategy/types.cjs +13 -0
  73. package/dist/strategy/types.cjs.map +1 -0
  74. package/dist/strategy/types.d.cts +77 -0
  75. package/dist/strategy/types.d.cts.map +1 -0
  76. package/dist/strategy/types.d.mts +77 -0
  77. package/dist/strategy/types.d.mts.map +1 -0
  78. package/dist/strategy/types.mjs +10 -0
  79. package/dist/strategy/types.mjs.map +1 -0
  80. package/dist/types.cjs.map +1 -1
  81. package/dist/types.d.cts +41 -6
  82. package/dist/types.d.cts.map +1 -1
  83. package/dist/types.d.mts +41 -6
  84. package/dist/types.d.mts.map +1 -1
  85. package/dist/types.mjs.map +1 -1
  86. package/dist/utils/bridge.cjs +5 -1
  87. package/dist/utils/bridge.cjs.map +1 -1
  88. package/dist/utils/bridge.d.cts +2 -2
  89. package/dist/utils/bridge.d.cts.map +1 -1
  90. package/dist/utils/bridge.d.mts +2 -2
  91. package/dist/utils/bridge.d.mts.map +1 -1
  92. package/dist/utils/bridge.mjs +3 -0
  93. package/dist/utils/bridge.mjs.map +1 -1
  94. package/dist/utils/history.cjs +72 -20
  95. package/dist/utils/history.cjs.map +1 -1
  96. package/dist/utils/history.d.cts +19 -5
  97. package/dist/utils/history.d.cts.map +1 -1
  98. package/dist/utils/history.d.mts +19 -5
  99. package/dist/utils/history.d.mts.map +1 -1
  100. package/dist/utils/history.mjs +69 -19
  101. package/dist/utils/history.mjs.map +1 -1
  102. package/dist/utils/metrics.cjs +10 -7
  103. package/dist/utils/metrics.cjs.map +1 -1
  104. package/dist/utils/metrics.d.cts +7 -6
  105. package/dist/utils/metrics.d.cts.map +1 -1
  106. package/dist/utils/metrics.d.mts +7 -6
  107. package/dist/utils/metrics.d.mts.map +1 -1
  108. package/dist/utils/metrics.mjs +10 -7
  109. package/dist/utils/metrics.mjs.map +1 -1
  110. package/dist/utils/trace.cjs +4 -4
  111. package/dist/utils/trace.cjs.map +1 -1
  112. package/dist/utils/trace.d.cts +2 -2
  113. package/dist/utils/trace.d.cts.map +1 -1
  114. package/dist/utils/trace.d.mts +2 -2
  115. package/dist/utils/trace.d.mts.map +1 -1
  116. package/dist/utils/trace.mjs +4 -4
  117. package/dist/utils/trace.mjs.map +1 -1
  118. package/dist/utils/transaction.cjs +222 -253
  119. package/dist/utils/transaction.cjs.map +1 -1
  120. package/dist/utils/transaction.d.cts +68 -147
  121. package/dist/utils/transaction.d.cts.map +1 -1
  122. package/dist/utils/transaction.d.mts +68 -147
  123. package/dist/utils/transaction.d.mts.map +1 -1
  124. package/dist/utils/transaction.mjs +213 -248
  125. package/dist/utils/transaction.mjs.map +1 -1
  126. package/package.json +2 -2
@@ -1,80 +1,51 @@
1
1
  /* eslint-disable @typescript-eslint/explicit-function-return-type */
2
- import { ChainId, formatChainIdToHex, BRIDGE_PREFERRED_GAS_ESTIMATE } from "@metamask/bridge-controller";
2
+ import { ChainId, formatChainIdToHex, BRIDGE_PREFERRED_GAS_ESTIMATE, isEvmTxData, FeeType, BatchSellTransactionType } from "@metamask/bridge-controller";
3
3
  import { toHex } from "@metamask/controller-utils";
4
- import { TransactionStatus, TransactionType } from "@metamask/transaction-controller";
5
- import { createProjectLogger } from "@metamask/utils";
6
- import { BigNumber } from "bignumber.js";
4
+ import { GasFeeEstimateType, TransactionStatus, TransactionType } from "@metamask/transaction-controller";
5
+ import { createProjectLogger, isStrictHexString } from "@metamask/utils";
7
6
  import { APPROVAL_DELAY_MS } from "../constants.mjs";
8
7
  import { getAccountByAddress } from "./accounts.mjs";
9
8
  import { getNetworkClientIdByChainId } from "./network.mjs";
10
- const isApprovalTx = (type) => type === TransactionType.bridgeApproval ||
9
+ export const isApprovalTx = (type) => type === TransactionType.bridgeApproval ||
11
10
  type === TransactionType.swapApproval;
12
- const isTradeTx = (type) => type === TransactionType.bridge || type === TransactionType.swap;
11
+ export const isTradeTx = (type) => type === TransactionType.bridge || type === TransactionType.swap;
13
12
  export const isCrossChainTx = (type) => isTradeTx(type) || isApprovalTx(type);
14
- export const getGasFeeEstimates = async (messenger, args) => {
15
- const { estimates } = await messenger.call('TransactionController:estimateGasFee', args);
16
- if (BRIDGE_PREFERRED_GAS_ESTIMATE in estimates &&
17
- typeof estimates[BRIDGE_PREFERRED_GAS_ESTIMATE] === 'object' &&
18
- 'maxFeePerGas' in estimates[BRIDGE_PREFERRED_GAS_ESTIMATE] &&
19
- 'maxPriorityFeePerGas' in estimates[BRIDGE_PREFERRED_GAS_ESTIMATE]) {
20
- return estimates[BRIDGE_PREFERRED_GAS_ESTIMATE];
21
- }
22
- return {};
23
- };
24
13
  /**
25
- * Get the gas fee estimates for a transaction
14
+ * For 7702 delegated transactions, check for delegation-specific fields
15
+ * These transactions might have authorizationList or delegationAddress
26
16
  *
27
- * @param messenger - The messenger for the gas fee estimates
28
- * @param estimateGasFeeParams - The parameters for the {@link TransactionController.estimateGasFee} method
29
-
30
- * @returns The gas fee estimates for the transaction
17
+ * @param tx - The transaction meta
18
+ * @returns Whether the transaction is a 7702 transaction
31
19
  */
32
- export const getTxGasEstimates = async (messenger, estimateGasFeeParams) => {
33
- const { gasFeeEstimates } = messenger.call('GasFeeController:getState');
34
- const estimatedBaseFee = 'estimatedBaseFee' in gasFeeEstimates
35
- ? gasFeeEstimates.estimatedBaseFee
36
- : '0';
37
- // Get transaction's 1559 gas fee estimates
38
- const { maxFeePerGas, maxPriorityFeePerGas } = await getGasFeeEstimates(messenger, estimateGasFeeParams);
20
+ export const is7702Tx = (tx) => {
21
+ return ((Array.isArray(tx.txParams.authorizationList) &&
22
+ tx.txParams.authorizationList.length > 0) ||
23
+ Boolean(tx.delegationAddress));
24
+ };
25
+ export const shouldDisable7702 = (gasIncluded7702 = false, gasIncluded = false, isDelegatedAccount = false) => {
26
+ // Enable 7702 batching when the quote includes gasless 7702 support
27
+ if (gasIncluded7702) {
28
+ return false;
29
+ }
30
+ // Enable batching when the account is already delegated (to avoid the in-flight transaction limit for delegated accounts)
31
+ // For gasless transactions with STX/sendBundle we keep disabling 7702
32
+ if (isDelegatedAccount && !gasIncluded) {
33
+ return false;
34
+ }
39
35
  /**
40
- * @deprecated this is unused
36
+ * Explicitly return default instead of falsy value (see TransactionBatchRequest.disable7702)
41
37
  */
42
- const baseAndPriorityFeePerGas = maxPriorityFeePerGas
43
- ? new BigNumber(estimatedBaseFee, 10)
44
- .times(10 ** 9)
45
- .plus(maxPriorityFeePerGas, 16)
46
- : undefined;
47
- return {
48
- baseAndPriorityFeePerGas,
49
- maxFeePerGas,
50
- maxPriorityFeePerGas,
51
- };
38
+ return true;
52
39
  };
53
- export const calculateGasFees = async (skipGasFields, messenger, { chainId: _, gasLimit, ...trade }, networkClientId, chainId, txFee) => {
54
- if (skipGasFields) {
55
- return {};
56
- }
57
- if (txFee) {
58
- return { ...txFee, gas: gasLimit?.toString() };
40
+ export const hasNestedSwapTransactions = (txMeta) => {
41
+ return Boolean(txMeta?.nestedTransactions?.some((tx) => tx.type === TransactionType.swap));
42
+ };
43
+ export const getGasFeeEstimates = async (messenger, args) => {
44
+ const { estimates } = await messenger.call('TransactionController:estimateGasFee', args);
45
+ if (estimates?.type === GasFeeEstimateType.FeeMarket) {
46
+ return estimates[BRIDGE_PREFERRED_GAS_ESTIMATE];
59
47
  }
60
- const transactionParams = {
61
- ...trade,
62
- gas: gasLimit?.toString(),
63
- data: trade.data,
64
- to: trade.to,
65
- value: trade.value,
66
- };
67
- const { maxFeePerGas, maxPriorityFeePerGas } = await getTxGasEstimates(messenger, {
68
- transactionParams,
69
- networkClientId,
70
- chainId,
71
- });
72
- const maxGasLimit = toHex(transactionParams.gas ?? 0);
73
- return {
74
- maxFeePerGas,
75
- maxPriorityFeePerGas,
76
- gas: maxGasLimit,
77
- };
48
+ return undefined;
78
49
  };
79
50
  export const getTransactions = (messenger) => {
80
51
  return messenger.call('TransactionController:getState').transactions ?? [];
@@ -182,222 +153,216 @@ export const waitForTxConfirmation = async (messenger, txId, { timeoutMs = 5 * 6
182
153
  await new Promise((resolve) => setTimeout(resolve, pollMs));
183
154
  }
184
155
  };
185
- export const toBatchTxParams = (skipGasFields, { chainId, gasLimit, ...trade }, { maxFeePerGas, maxPriorityFeePerGas, gas, }) => {
186
- const params = {
187
- ...trade,
188
- data: trade.data,
189
- to: trade.to,
190
- value: trade.value,
191
- };
192
- if (skipGasFields) {
193
- return params;
194
- }
195
- return {
196
- ...params,
197
- gas: toHex(gas ?? 0),
198
- maxFeePerGas: toHex(maxFeePerGas ?? 0),
199
- maxPriorityFeePerGas: toHex(maxPriorityFeePerGas ?? 0),
200
- };
201
- };
202
- export const getAddTransactionBatchParams = async ({ messenger, isBridgeTx, approval, resetApproval, trade, quoteResponse: { quote: { feeData: { txFee }, gasIncluded, gasIncluded7702, gasSponsored, }, sentAmount, toTokenAmount, }, requireApproval = false, isDelegatedAccount = false, }) => {
203
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
204
- const isGasless = gasIncluded || gasIncluded7702;
205
- const selectedAccount = getAccountByAddress(messenger, trade.from);
206
- if (!selectedAccount) {
207
- throw new Error('Failed to submit cross-chain swap batch transaction: unknown account in trade data');
208
- }
209
- const hexChainId = formatChainIdToHex(trade.chainId);
210
- const networkClientId = getNetworkClientIdByChainId(messenger, hexChainId);
211
- // Gas fields should be omitted only when gas is sponsored via 7702
212
- const skipGasFields = gasIncluded7702 === true;
213
- // Enable 7702 batching when the quote includes gasless 7702 support,
214
- // or when the account is already delegated (to avoid the in-flight
215
- // transaction limit for delegated accounts)
216
- let disable7702 = !skipGasFields && !isDelegatedAccount;
217
- // For gasless transactions with STX/sendBundle we keep disabling 7702.
218
- if (gasIncluded && !gasIncluded7702) {
219
- disable7702 = true;
220
- }
221
- const transactions = [];
222
- if (resetApproval) {
223
- const gasFees = await calculateGasFees(skipGasFields, messenger, resetApproval, networkClientId, hexChainId, isGasless ? txFee : undefined);
224
- transactions.push({
225
- type: isBridgeTx
226
- ? TransactionType.bridgeApproval
227
- : TransactionType.swapApproval,
228
- params: toBatchTxParams(skipGasFields, resetApproval, gasFees),
156
+ export const toQuoteAndTxMetadata = ({ quoteResponse, isBridgeTx, }) => {
157
+ const tradeData = [];
158
+ const approvalTxType = isBridgeTx
159
+ ? TransactionType.bridgeApproval
160
+ : TransactionType.swapApproval;
161
+ if (quoteResponse.resetApproval) {
162
+ tradeData.push({
163
+ quoteResponse,
164
+ tx: quoteResponse.resetApproval,
165
+ type: approvalTxType,
166
+ txFee: quoteResponse.quote.feeData[FeeType.TX_FEE],
229
167
  });
230
168
  }
231
- if (approval) {
232
- const gasFees = await calculateGasFees(skipGasFields, messenger, approval, networkClientId, hexChainId, isGasless ? txFee : undefined);
233
- transactions.push({
234
- type: isBridgeTx
235
- ? TransactionType.bridgeApproval
236
- : TransactionType.swapApproval,
237
- params: toBatchTxParams(skipGasFields, approval, gasFees),
169
+ if (quoteResponse.approval && isEvmTxData(quoteResponse.approval)) {
170
+ tradeData.push({
171
+ quoteResponse,
172
+ tx: quoteResponse.approval,
173
+ type: approvalTxType,
174
+ txFee: quoteResponse.quote.feeData[FeeType.TX_FEE],
238
175
  });
239
176
  }
240
- const gasFees = await calculateGasFees(skipGasFields, messenger, trade, networkClientId, hexChainId, isGasless ? txFee : undefined);
241
- transactions.push({
177
+ tradeData.push({
178
+ quoteResponse,
179
+ tx: quoteResponse.trade,
242
180
  type: isBridgeTx ? TransactionType.bridge : TransactionType.swap,
243
- params: toBatchTxParams(skipGasFields, trade, gasFees),
244
181
  assetsFiatValues: {
245
- sending: sentAmount?.valueInCurrency?.toString(),
246
- receiving: toTokenAmount?.valueInCurrency?.toString(),
182
+ sending: quoteResponse.sentAmount?.valueInCurrency?.toString(),
183
+ receiving: quoteResponse.toTokenAmount?.valueInCurrency?.toString(),
247
184
  },
185
+ txFee: quoteResponse.quote.feeData[FeeType.TX_FEE],
248
186
  });
249
- const transactionParams = {
250
- disable7702,
251
- isGasFeeIncluded: Boolean(gasIncluded7702),
252
- isGasFeeSponsored: Boolean(gasSponsored),
253
- networkClientId,
254
- requireApproval,
255
- origin: 'metamask',
256
- from: trade.from,
257
- isInternal: true,
258
- transactions,
259
- };
260
- return transactionParams;
187
+ return tradeData;
261
188
  };
262
- export const findAndUpdateTransactionsInBatch = ({ messenger, batchId, txDataByType, }) => {
263
- const txs = getTransactions(messenger);
264
- const txBatch = {
265
- approvalMeta: undefined,
266
- tradeMeta: undefined,
267
- };
268
- // This is a workaround to update the tx type after the tx is signed
269
- // TODO: remove this once the tx type for batch txs is preserved in the tx controller
270
- const txEntries = Object.entries(txDataByType);
271
- txEntries.forEach(([txType, txData]) => {
272
- // Skip types not present in the batch (e.g. swap entry is undefined for bridge txs)
273
- if (txData === undefined) {
274
- return;
189
+ /**
190
+ * Build the trade+quote metadata array for the batch sell transaction
191
+ * This ties together the quote, the tx params and the txMeta after submission
192
+ *
193
+ * @param options - The options for the batch sell transaction
194
+ * @param options.quoteResponses - The quote responses for the batch sell transaction
195
+ * @param options.batchSellTrades - The batch sell trades for the batch sell transaction
196
+ * @returns The trade+quote metadata array for the batch sell transaction
197
+ */
198
+ export const toQuoteAndTxMetadataBatch = ({ quoteResponses, batchSellTrades, }) => {
199
+ const tradeData = [];
200
+ const { transactions, gasIncluded7702, gasIncluded, gasSponsored = false, } = batchSellTrades;
201
+ for (const transaction of transactions) {
202
+ const { type, maxFeePerGas, maxPriorityFeePerGas, ...tx } = transaction;
203
+ // Match the trade or approval tx data with the quote response
204
+ const matchingQuoteResponse = quoteResponses.find(({ approval, trade }) => trade?.data.toLowerCase() === tx.data.toLowerCase() ||
205
+ approval?.data.toLowerCase() === tx.data.toLowerCase()) ?? quoteResponses[0];
206
+ // Include gasIncluded and gasIncluded7702 from the gasless batch
207
+ const normalizedQuote = {
208
+ ...matchingQuoteResponse,
209
+ quote: {
210
+ ...matchingQuoteResponse.quote,
211
+ gasIncluded,
212
+ gasIncluded7702,
213
+ gasSponsored,
214
+ },
215
+ };
216
+ const commonTradeData = {
217
+ tx,
218
+ quoteResponse: normalizedQuote,
219
+ txFee: { maxFeePerGas, maxPriorityFeePerGas },
220
+ };
221
+ if (type === BatchSellTransactionType.TRADE) {
222
+ tradeData.push({
223
+ ...commonTradeData,
224
+ type: TransactionType.swap,
225
+ assetsFiatValues: {
226
+ sending: matchingQuoteResponse.sentAmount?.valueInCurrency?.toString(),
227
+ receiving: matchingQuoteResponse.toTokenAmount?.valueInCurrency?.toString(),
228
+ },
229
+ });
275
230
  }
276
- // Find transaction by batchId and either matching data or delegation characteristics
277
- const txMeta = txs.find((tx) => {
278
- if (tx.batchId !== batchId) {
279
- return false;
280
- }
281
- // For 7702 delegated transactions, check for delegation-specific fields
282
- // These transactions might have authorizationList or delegationAddress
283
- const is7702Transaction = (Array.isArray(tx.txParams.authorizationList) &&
284
- tx.txParams.authorizationList.length > 0) ||
285
- Boolean(tx.delegationAddress);
286
- if (is7702Transaction) {
287
- // For 7702 transactions, we need to match based on transaction type
288
- // since the data field might be different (batch execute call)
289
- if (isTradeTx(txType) && tx.type === TransactionType.batch) {
290
- return true;
291
- }
292
- // Also check if it's an approval transaction for 7702
293
- if (isApprovalTx(txType) && tx.txParams.data === txData) {
294
- return true;
295
- }
296
- }
297
- // Default matching logic for non-7702 transactions
298
- return tx.txParams.data === txData;
299
- });
300
- if (txMeta) {
301
- const updatedTx = { ...txMeta, type: txType };
302
- updateTransaction(messenger, txMeta, { type: txType }, `Update tx type to ${txType}`);
303
- const txTypes = [
304
- TransactionType.bridgeApproval,
305
- TransactionType.swapApproval,
306
- ];
307
- txBatch[txTypes.includes(txType) ? 'approvalMeta' : 'tradeMeta'] =
308
- updatedTx;
231
+ else {
232
+ tradeData.push({
233
+ ...commonTradeData,
234
+ type: type === BatchSellTransactionType.APPROVAL
235
+ ? TransactionType.swapApproval
236
+ : TransactionType.tokenMethodTransfer,
237
+ });
309
238
  }
310
- });
311
- return txBatch;
312
- };
313
- export const addTransactionBatch = async (messenger, addTransactionBatchFn, ...args) => {
314
- const txDataByType = {
315
- [TransactionType.bridgeApproval]: args[0].transactions.find(({ type }) => type === TransactionType.bridgeApproval)?.params.data,
316
- [TransactionType.swapApproval]: args[0].transactions.find(({ type }) => type === TransactionType.swapApproval)?.params.data,
317
- [TransactionType.bridge]: args[0].transactions.find(({ type }) => type === TransactionType.bridge)?.params.data,
318
- [TransactionType.swap]: args[0].transactions.find(({ type }) => type === TransactionType.swap)?.params.data,
319
- };
320
- const { batchId } = await addTransactionBatchFn(...args);
321
- const { approvalMeta, tradeMeta } = findAndUpdateTransactionsInBatch({
322
- messenger,
323
- batchId,
324
- txDataByType,
325
- });
326
- if (!tradeMeta) {
327
- throw new Error('Failed to update cross-chain swap transaction batch: tradeMeta not found');
328
239
  }
329
- return { approvalMeta, tradeMeta };
240
+ return tradeData;
330
241
  };
331
- // TODO rename
332
- const getGasFeesForSubmission = async (messenger, transactionParams, networkClientId, chainId, txFee) => {
333
- const { gas } = transactionParams;
334
- // If txFee is provided (gasIncluded case), use the quote's gas fees
335
- // Convert to hex since txFee values from the quote are decimal strings
336
- if (txFee) {
242
+ /**
243
+ * Appends the gas fee estimates for a transaction and normalizes the trade data
244
+ *
245
+ * @param messenger - The messenger for the gas fee estimates
246
+ * @param trade - the trade data to append gas fees to
247
+ * @param trade.chainId - ignored, use chainId instead
248
+ * @param trade.gasLimit - the gas limit to use for the gas fee estimates
249
+ * @param networkClientId - the network client ID to use for the gas fee estimates
250
+ * @param chainId - the chain ID to use for the gas fee estimates
251
+ * @param simulatedGasFeeLimits - either the txFee from the quote or the simulated gas fee limits for the batch sell
252
+ * @returns The gas fee estimates for the transaction
253
+ */
254
+ export const toTransactionParams = async (messenger, { chainId: tradeChainId, gasLimit, ...trade }, networkClientId, chainId, simulatedGasFeeLimits) => {
255
+ const transactionParams = {
256
+ data: trade.data,
257
+ to: trade.to,
258
+ from: trade.from,
259
+ value: trade.value,
260
+ // Only add gas if it's truthy
261
+ gas: gasLimit ? toHex(gasLimit) : undefined,
262
+ };
263
+ // Use bridge-api's provided gas fee estimates
264
+ if (simulatedGasFeeLimits) {
337
265
  return {
338
- maxFeePerGas: toHex(txFee.maxFeePerGas),
339
- maxPriorityFeePerGas: toHex(txFee.maxPriorityFeePerGas),
340
- gas: gas ? toHex(gas) : undefined,
266
+ ...transactionParams,
267
+ // Sometimes estimates are hex, somethings numeric strings
268
+ maxFeePerGas: isStrictHexString(simulatedGasFeeLimits.maxFeePerGas)
269
+ ? simulatedGasFeeLimits.maxFeePerGas
270
+ : toHex(simulatedGasFeeLimits.maxFeePerGas),
271
+ maxPriorityFeePerGas: isStrictHexString(simulatedGasFeeLimits.maxPriorityFeePerGas)
272
+ ? simulatedGasFeeLimits.maxPriorityFeePerGas
273
+ : toHex(simulatedGasFeeLimits.maxPriorityFeePerGas),
341
274
  };
342
275
  }
343
- const { maxFeePerGas, maxPriorityFeePerGas } = await getTxGasEstimates(messenger, {
276
+ // Get transaction's 1559 gas fee estimates
277
+ const gasFeeEstimates = await getGasFeeEstimates(messenger, {
344
278
  transactionParams,
345
- chainId,
346
279
  networkClientId,
280
+ chainId,
347
281
  });
348
282
  return {
349
- maxFeePerGas,
350
- maxPriorityFeePerGas,
351
- gas: gas ? toHex(gas) : undefined,
283
+ ...transactionParams,
284
+ maxFeePerGas: gasFeeEstimates?.maxFeePerGas,
285
+ maxPriorityFeePerGas: gasFeeEstimates?.maxPriorityFeePerGas,
352
286
  };
353
287
  };
354
- /**
355
- * Submits an EVM transaction to the TransactionController
356
- *
357
- * @param params - The parameters for the transaction
358
- * @param params.transactionType - The type of transaction to submit
359
- * @param params.trade - The trade data to confirm
360
- * @param params.requireApproval - Whether to require approval for the transaction
361
- * @param params.txFee - Optional gas fee parameters from the quote (used when gasIncluded is true)
362
- * @param params.txFee.maxFeePerGas - The maximum fee per gas from the quote
363
- * @param params.txFee.maxPriorityFeePerGas - The maximum priority fee per gas from the quote
364
- * @param params.actionId - Optional actionId for pre-submission history (if not provided, one is generated)
365
- * @param params.messenger - The messenger to use for the transaction
366
- * @returns The transaction meta
367
- */
368
- export const submitEvmTransaction = async ({ messenger, trade, transactionType, requireApproval = false, txFee,
369
- // Use provided actionId (for pre-submission history) or generate one
370
- actionId = generateActionId(), }) => {
288
+ export const getAddTransactionBatchParams = async ({ messenger, tradeData, requireApproval = false, isDelegatedAccount, ...addTransactionBatchParams }) => {
289
+ const trade = tradeData[0].tx;
371
290
  const selectedAccount = getAccountByAddress(messenger, trade.from);
372
291
  if (!selectedAccount) {
373
- throw new Error('Failed to submit cross-chain swap transaction: unknown account in trade data');
292
+ throw new Error('Failed to submit cross-chain swap batch transaction: unknown account in trade data');
374
293
  }
375
294
  const hexChainId = formatChainIdToHex(trade.chainId);
376
295
  const networkClientId = getNetworkClientIdByChainId(messenger, hexChainId);
377
- const requestOptions = {
378
- actionId,
296
+ const transactions = await Promise.all(tradeData.map(async ({ tx, txFee, assetsFiatValues, type }) => ({
297
+ params: await toTransactionParams(messenger, tx, networkClientId, hexChainId, txFee),
298
+ assetsFiatValues,
299
+ type,
300
+ })));
301
+ return {
379
302
  networkClientId,
380
303
  requireApproval,
381
- type: transactionType,
382
304
  origin: 'metamask',
305
+ from: selectedAccount.address,
383
306
  isInternal: true,
307
+ transactions,
308
+ ...addTransactionBatchParams,
384
309
  };
385
- // Exclude gasLimit from trade to avoid type issues (it can be null)
386
- const { gasLimit: tradeGasLimit, ...tradeWithoutGasLimit } = trade;
387
- const transactionParams = {
388
- ...tradeWithoutGasLimit,
389
- chainId: hexChainId,
390
- // Only add gasLimit and gas if they're valid (not undefined/null/zero)
391
- ...(tradeGasLimit &&
392
- tradeGasLimit !== 0 && {
393
- gasLimit: tradeGasLimit.toString(),
394
- gas: tradeGasLimit.toString(),
395
- }),
396
- };
397
- const transactionParamsWithMaxGas = {
398
- ...transactionParams,
399
- ...(await getGasFeesForSubmission(messenger, transactionParams, networkClientId, hexChainId, txFee)),
400
- };
401
- return await addTransaction(messenger, transactionParamsWithMaxGas, requestOptions);
310
+ };
311
+ export const findAllTransactionsInBatch = ({ messenger, batchId, tradeData, }) => {
312
+ // Filter for transactions with batchId
313
+ const txs = getTransactions(messenger).filter((tx) => tx.batchId === batchId);
314
+ return tradeData.map((tradeWithMetadata) => {
315
+ const { tx, type } = tradeWithMetadata;
316
+ return {
317
+ ...tradeWithMetadata,
318
+ txMeta: txs.find((txMeta) => {
319
+ if (is7702Tx(txMeta)) {
320
+ // For 7702 transactions, we need to match based on transaction type
321
+ // since the data field might be different (batch execute call)
322
+ if (isTradeTx(type) && txMeta.type === TransactionType.batch) {
323
+ return true;
324
+ }
325
+ // Also check if it's an approval transaction for 7702
326
+ if (isApprovalTx(type) && txMeta.txParams.data === tx.data) {
327
+ return true;
328
+ }
329
+ }
330
+ // Default matching logic for non-7702 transactions
331
+ if (txMeta.txParams.data === tx.data) {
332
+ return true;
333
+ }
334
+ return false;
335
+ }),
336
+ };
337
+ });
338
+ };
339
+ /**
340
+ * This is a workaround to update the tx type after submission. Batch txs are submitted with
341
+ * the "batch" type, but we need to update to swap/bridge for display purposes.
342
+ *
343
+ * @param params - The parameters for the transaction search
344
+ * @param params.messenger - The messenger to use for the transaction
345
+ * @param params.allTradesWithMetadata - The quote, tx data and type for each transaction in the batch
346
+ * @returns A list of transaction metas for each trade in the batch]
347
+ *
348
+ * @example
349
+ * [
350
+ * {...tradeData[0], tradeMeta: TransactionMeta}
351
+ * {...tradeData[1], tradeMeta: TransactionMeta}
352
+ * {...tradeData[2], tradeMeta: TransactionMeta}
353
+ * {...tradeData[3], tradeMeta: TransactionMeta}
354
+ * ]
355
+ */
356
+ export const updateTransactionsInBatch = ({ messenger, allTradesWithMetadata, }) => {
357
+ return allTradesWithMetadata.map((tradeWithMetadata) => {
358
+ const { txMeta, type } = tradeWithMetadata;
359
+ if (txMeta) {
360
+ // Update the tx type from batch to swap/bridge
361
+ updateTransaction(messenger, txMeta, { type }, `Update tx type to ${type}`);
362
+ const updatedTx = { ...txMeta, type };
363
+ return { ...tradeWithMetadata, txMeta: updatedTx, type };
364
+ }
365
+ return tradeWithMetadata;
366
+ });
402
367
  };
403
368
  //# sourceMappingURL=transaction.mjs.map