@metamask/transaction-pay-controller 16.3.0 → 16.4.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 (148) hide show
  1. package/CHANGELOG.md +20 -1
  2. package/dist/TransactionPayController.cjs +9 -0
  3. package/dist/TransactionPayController.cjs.map +1 -1
  4. package/dist/TransactionPayController.d.cts +2 -1
  5. package/dist/TransactionPayController.d.cts.map +1 -1
  6. package/dist/TransactionPayController.d.mts +2 -1
  7. package/dist/TransactionPayController.d.mts.map +1 -1
  8. package/dist/TransactionPayController.mjs +9 -0
  9. package/dist/TransactionPayController.mjs.map +1 -1
  10. package/dist/actions/update-fiat-payment.cjs +29 -0
  11. package/dist/actions/update-fiat-payment.cjs.map +1 -0
  12. package/dist/actions/update-fiat-payment.d.cts +14 -0
  13. package/dist/actions/update-fiat-payment.d.cts.map +1 -0
  14. package/dist/actions/update-fiat-payment.d.mts +14 -0
  15. package/dist/actions/update-fiat-payment.d.mts.map +1 -0
  16. package/dist/actions/update-fiat-payment.mjs +25 -0
  17. package/dist/actions/update-fiat-payment.mjs.map +1 -0
  18. package/dist/actions/update-payment-token.cjs +1 -0
  19. package/dist/actions/update-payment-token.cjs.map +1 -1
  20. package/dist/actions/update-payment-token.d.cts.map +1 -1
  21. package/dist/actions/update-payment-token.d.mts.map +1 -1
  22. package/dist/actions/update-payment-token.mjs +1 -0
  23. package/dist/actions/update-payment-token.mjs.map +1 -1
  24. package/dist/constants.cjs +1 -0
  25. package/dist/constants.cjs.map +1 -1
  26. package/dist/constants.d.cts +1 -0
  27. package/dist/constants.d.cts.map +1 -1
  28. package/dist/constants.d.mts +1 -0
  29. package/dist/constants.d.mts.map +1 -1
  30. package/dist/constants.mjs +1 -0
  31. package/dist/constants.mjs.map +1 -1
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.d.cts +1 -1
  34. package/dist/index.d.cts.map +1 -1
  35. package/dist/index.d.mts +1 -1
  36. package/dist/index.d.mts.map +1 -1
  37. package/dist/index.mjs.map +1 -1
  38. package/dist/strategy/across/AcrossStrategy.cjs +28 -0
  39. package/dist/strategy/across/AcrossStrategy.cjs.map +1 -0
  40. package/dist/strategy/across/AcrossStrategy.d.cts +8 -0
  41. package/dist/strategy/across/AcrossStrategy.d.cts.map +1 -0
  42. package/dist/strategy/across/AcrossStrategy.d.mts +8 -0
  43. package/dist/strategy/across/AcrossStrategy.d.mts.map +1 -0
  44. package/dist/strategy/across/AcrossStrategy.mjs +24 -0
  45. package/dist/strategy/across/AcrossStrategy.mjs.map +1 -0
  46. package/dist/strategy/across/across-quotes.cjs +356 -0
  47. package/dist/strategy/across/across-quotes.cjs.map +1 -0
  48. package/dist/strategy/across/across-quotes.d.cts +10 -0
  49. package/dist/strategy/across/across-quotes.d.cts.map +1 -0
  50. package/dist/strategy/across/across-quotes.d.mts +10 -0
  51. package/dist/strategy/across/across-quotes.d.mts.map +1 -0
  52. package/dist/strategy/across/across-quotes.mjs +352 -0
  53. package/dist/strategy/across/across-quotes.mjs.map +1 -0
  54. package/dist/strategy/across/across-submit.cjs +241 -0
  55. package/dist/strategy/across/across-submit.cjs.map +1 -0
  56. package/dist/strategy/across/across-submit.d.cts +13 -0
  57. package/dist/strategy/across/across-submit.d.cts.map +1 -0
  58. package/dist/strategy/across/across-submit.d.mts +13 -0
  59. package/dist/strategy/across/across-submit.d.mts.map +1 -0
  60. package/dist/strategy/across/across-submit.mjs +237 -0
  61. package/dist/strategy/across/across-submit.mjs.map +1 -0
  62. package/dist/strategy/across/types.cjs +3 -0
  63. package/dist/strategy/across/types.cjs.map +1 -0
  64. package/dist/strategy/across/types.d.cts +89 -0
  65. package/dist/strategy/across/types.d.cts.map +1 -0
  66. package/dist/strategy/across/types.d.mts +89 -0
  67. package/dist/strategy/across/types.d.mts.map +1 -0
  68. package/dist/strategy/across/types.mjs +2 -0
  69. package/dist/strategy/across/types.mjs.map +1 -0
  70. package/dist/strategy/relay/RelayStrategy.cjs +5 -0
  71. package/dist/strategy/relay/RelayStrategy.cjs.map +1 -1
  72. package/dist/strategy/relay/RelayStrategy.d.cts +1 -0
  73. package/dist/strategy/relay/RelayStrategy.d.cts.map +1 -1
  74. package/dist/strategy/relay/RelayStrategy.d.mts +1 -0
  75. package/dist/strategy/relay/RelayStrategy.d.mts.map +1 -1
  76. package/dist/strategy/relay/RelayStrategy.mjs +5 -0
  77. package/dist/strategy/relay/RelayStrategy.mjs.map +1 -1
  78. package/dist/strategy/relay/gas-station.cjs +92 -0
  79. package/dist/strategy/relay/gas-station.cjs.map +1 -0
  80. package/dist/strategy/relay/gas-station.d.cts +22 -0
  81. package/dist/strategy/relay/gas-station.d.cts.map +1 -0
  82. package/dist/strategy/relay/gas-station.d.mts +22 -0
  83. package/dist/strategy/relay/gas-station.d.mts.map +1 -0
  84. package/dist/strategy/relay/gas-station.mjs +87 -0
  85. package/dist/strategy/relay/gas-station.mjs.map +1 -0
  86. package/dist/strategy/relay/relay-max-gas-station.cjs +242 -0
  87. package/dist/strategy/relay/relay-max-gas-station.cjs.map +1 -0
  88. package/dist/strategy/relay/relay-max-gas-station.d.cts +22 -0
  89. package/dist/strategy/relay/relay-max-gas-station.d.cts.map +1 -0
  90. package/dist/strategy/relay/relay-max-gas-station.d.mts +22 -0
  91. package/dist/strategy/relay/relay-max-gas-station.d.mts.map +1 -0
  92. package/dist/strategy/relay/relay-max-gas-station.mjs +238 -0
  93. package/dist/strategy/relay/relay-max-gas-station.mjs.map +1 -0
  94. package/dist/strategy/relay/relay-quotes.cjs +32 -59
  95. package/dist/strategy/relay/relay-quotes.cjs.map +1 -1
  96. package/dist/strategy/relay/relay-quotes.d.cts.map +1 -1
  97. package/dist/strategy/relay/relay-quotes.d.mts.map +1 -1
  98. package/dist/strategy/relay/relay-quotes.mjs +29 -56
  99. package/dist/strategy/relay/relay-quotes.mjs.map +1 -1
  100. package/dist/strategy/relay/types.cjs.map +1 -1
  101. package/dist/strategy/relay/types.d.cts +1 -0
  102. package/dist/strategy/relay/types.d.cts.map +1 -1
  103. package/dist/strategy/relay/types.d.mts +1 -0
  104. package/dist/strategy/relay/types.d.mts.map +1 -1
  105. package/dist/strategy/relay/types.mjs.map +1 -1
  106. package/dist/types.cjs.map +1 -1
  107. package/dist/types.d.cts +24 -1
  108. package/dist/types.d.cts.map +1 -1
  109. package/dist/types.d.mts +24 -1
  110. package/dist/types.d.mts.map +1 -1
  111. package/dist/types.mjs.map +1 -1
  112. package/dist/utils/amounts.cjs +40 -0
  113. package/dist/utils/amounts.cjs.map +1 -0
  114. package/dist/utils/amounts.d.cts +18 -0
  115. package/dist/utils/amounts.d.cts.map +1 -0
  116. package/dist/utils/amounts.d.mts +18 -0
  117. package/dist/utils/amounts.d.mts.map +1 -0
  118. package/dist/utils/amounts.mjs +35 -0
  119. package/dist/utils/amounts.mjs.map +1 -0
  120. package/dist/utils/feature-flags.cjs +45 -6
  121. package/dist/utils/feature-flags.cjs.map +1 -1
  122. package/dist/utils/feature-flags.d.cts +45 -2
  123. package/dist/utils/feature-flags.d.cts.map +1 -1
  124. package/dist/utils/feature-flags.d.mts +45 -2
  125. package/dist/utils/feature-flags.d.mts.map +1 -1
  126. package/dist/utils/feature-flags.mjs +42 -5
  127. package/dist/utils/feature-flags.mjs.map +1 -1
  128. package/dist/utils/gas.cjs +46 -1
  129. package/dist/utils/gas.cjs.map +1 -1
  130. package/dist/utils/gas.d.cts +18 -0
  131. package/dist/utils/gas.d.cts.map +1 -1
  132. package/dist/utils/gas.d.mts +18 -0
  133. package/dist/utils/gas.d.mts.map +1 -1
  134. package/dist/utils/gas.mjs +44 -0
  135. package/dist/utils/gas.mjs.map +1 -1
  136. package/dist/utils/strategy.cjs +3 -0
  137. package/dist/utils/strategy.cjs.map +1 -1
  138. package/dist/utils/strategy.d.cts.map +1 -1
  139. package/dist/utils/strategy.d.mts.map +1 -1
  140. package/dist/utils/strategy.mjs +3 -0
  141. package/dist/utils/strategy.mjs.map +1 -1
  142. package/dist/utils/totals.cjs +4 -19
  143. package/dist/utils/totals.cjs.map +1 -1
  144. package/dist/utils/totals.d.cts.map +1 -1
  145. package/dist/utils/totals.d.mts.map +1 -1
  146. package/dist/utils/totals.mjs +1 -16
  147. package/dist/utils/totals.mjs.map +1 -1
  148. package/package.json +5 -5
@@ -0,0 +1,352 @@
1
+ import { Interface } from "@ethersproject/abi";
2
+ import { successfulFetch, toHex } from "@metamask/controller-utils";
3
+ import { createModuleLogger } from "@metamask/utils";
4
+ import { BigNumber } from "bignumber.js";
5
+ import { TransactionPayStrategy } from "../../constants.mjs";
6
+ import { projectLogger } from "../../logger.mjs";
7
+ import { getFiatValueFromUsd, sumAmounts } from "../../utils/amounts.mjs";
8
+ import { getPayStrategiesConfig, getSlippage } from "../../utils/feature-flags.mjs";
9
+ import { calculateGasCost, estimateGasLimit } from "../../utils/gas.mjs";
10
+ import { getTokenFiatRate } from "../../utils/token.mjs";
11
+ import { TOKEN_TRANSFER_FOUR_BYTE } from "../relay/constants.mjs";
12
+ const log = createModuleLogger(projectLogger, 'across-strategy');
13
+ const TOKEN_TRANSFER_INTERFACE = new Interface([
14
+ 'function transfer(address to, uint256 amount)',
15
+ ]);
16
+ const UNSUPPORTED_AUTHORIZATION_LIST_ERROR = 'Across does not support type-4/EIP-7702 authorization lists yet';
17
+ const UNSUPPORTED_DESTINATION_ERROR = 'Across only supports transfer-style destination flows at the moment';
18
+ /**
19
+ * Fetch Across quotes.
20
+ *
21
+ * @param request - Request object.
22
+ * @returns Array of quotes.
23
+ */
24
+ export async function getAcrossQuotes(request) {
25
+ const { requests } = request;
26
+ log('Fetching quotes', requests);
27
+ try {
28
+ const normalizedRequests = requests.filter((singleRequest) => singleRequest.isMaxAmount === true ||
29
+ (singleRequest.targetAmountMinimum !== undefined &&
30
+ singleRequest.targetAmountMinimum !== '0'));
31
+ if (normalizedRequests.length === 0) {
32
+ return [];
33
+ }
34
+ if (request.transaction.txParams?.authorizationList?.length) {
35
+ throw new Error(UNSUPPORTED_AUTHORIZATION_LIST_ERROR);
36
+ }
37
+ return await Promise.all(normalizedRequests.map((singleRequest) => getSingleQuote(singleRequest, request)));
38
+ }
39
+ catch (error) {
40
+ log('Error fetching quotes', { error });
41
+ throw new Error(`Failed to fetch Across quotes: ${String(error)}`);
42
+ }
43
+ }
44
+ async function getSingleQuote(request, fullRequest) {
45
+ const { messenger, transaction } = fullRequest;
46
+ const { from, isMaxAmount, sourceChainId, sourceTokenAddress, sourceTokenAmount, targetAmountMinimum, targetChainId, targetTokenAddress, } = request;
47
+ const config = getPayStrategiesConfig(messenger);
48
+ const slippageDecimal = getSlippage(messenger, sourceChainId, sourceTokenAddress);
49
+ const amount = isMaxAmount ? sourceTokenAmount : targetAmountMinimum;
50
+ const tradeType = isMaxAmount ? 'exactInput' : 'exactOutput';
51
+ const recipient = getAcrossRecipient(transaction, request);
52
+ const quote = await requestAcrossApproval({
53
+ amount,
54
+ apiBase: config.across.apiBase,
55
+ depositor: from,
56
+ destinationChainId: targetChainId,
57
+ inputToken: sourceTokenAddress,
58
+ originChainId: sourceChainId,
59
+ outputToken: targetTokenAddress,
60
+ recipient,
61
+ slippage: slippageDecimal,
62
+ tradeType,
63
+ });
64
+ const originalQuote = {
65
+ quote,
66
+ request: {
67
+ amount,
68
+ tradeType,
69
+ },
70
+ };
71
+ return await normalizeQuote(originalQuote, request, fullRequest);
72
+ }
73
+ async function requestAcrossApproval(request) {
74
+ const { amount, apiBase, depositor, destinationChainId, inputToken, originChainId, outputToken, recipient, slippage, tradeType, } = request;
75
+ const params = new URLSearchParams();
76
+ params.set('tradeType', tradeType);
77
+ params.set('amount', amount);
78
+ params.set('inputToken', inputToken);
79
+ params.set('outputToken', outputToken);
80
+ params.set('originChainId', String(parseInt(originChainId, 16)));
81
+ params.set('destinationChainId', String(parseInt(destinationChainId, 16)));
82
+ params.set('depositor', depositor);
83
+ params.set('recipient', recipient);
84
+ if (slippage !== undefined) {
85
+ params.set('slippage', String(slippage));
86
+ }
87
+ const body = { actions: [] };
88
+ const url = `${apiBase}/swap/approval?${params.toString()}`;
89
+ const options = {
90
+ body: JSON.stringify(body),
91
+ headers: {
92
+ Accept: 'application/json',
93
+ 'Content-Type': 'application/json',
94
+ },
95
+ method: 'POST',
96
+ };
97
+ const response = await successfulFetch(url, options);
98
+ return (await response.json());
99
+ }
100
+ function getAcrossRecipient(transaction, request) {
101
+ const { txParams } = transaction;
102
+ const { from } = request;
103
+ const transferData = getTransferData(transaction);
104
+ if (transferData) {
105
+ return getTransferRecipient(transferData);
106
+ }
107
+ const data = txParams?.data;
108
+ const hasNoData = data === undefined || data === '0x';
109
+ const nestedCalldata = getNestedCalldata(transaction);
110
+ if (hasNoData && nestedCalldata.length === 0) {
111
+ return from;
112
+ }
113
+ throw new Error(UNSUPPORTED_DESTINATION_ERROR);
114
+ }
115
+ function getTransferData(transaction) {
116
+ const { nestedTransactions, txParams } = transaction;
117
+ const nestedTransferData = nestedTransactions?.find((nestedTx) => nestedTx.data?.startsWith(TOKEN_TRANSFER_FOUR_BYTE))?.data;
118
+ const data = txParams?.data;
119
+ const tokenTransferData = data?.startsWith(TOKEN_TRANSFER_FOUR_BYTE)
120
+ ? data
121
+ : undefined;
122
+ return nestedTransferData ?? tokenTransferData;
123
+ }
124
+ function getNestedCalldata(transaction) {
125
+ return (transaction.nestedTransactions ?? [])
126
+ .map((nestedTx) => nestedTx.data)
127
+ .filter((data) => data !== undefined && data !== '0x');
128
+ }
129
+ function getTransferRecipient(data) {
130
+ return TOKEN_TRANSFER_INTERFACE.decodeFunctionData('transfer', data).to.toLowerCase();
131
+ }
132
+ async function normalizeQuote(original, request, fullRequest) {
133
+ const { messenger } = fullRequest;
134
+ const { quote } = original;
135
+ const { usdToFiatRate, sourceFiatRate, targetFiatRate } = getFiatRates(messenger, quote);
136
+ const dustUsd = calculateDustUsd(quote, request, targetFiatRate);
137
+ const dust = getFiatValueFromUsd(dustUsd, usdToFiatRate);
138
+ const { sourceNetwork, gasLimits } = await calculateSourceNetworkCost(quote, messenger, request);
139
+ const targetNetwork = getFiatValueFromUsd(new BigNumber(0), usdToFiatRate);
140
+ const inputAmountRaw = quote.inputAmount ?? '0';
141
+ const outputAmountRaw = new BigNumber(quote.expectedOutputAmount ??
142
+ quote.minOutputAmount ??
143
+ request.targetAmountMinimum ??
144
+ '0').toString(10);
145
+ const sourceAmount = getAmountFromTokenAmount({
146
+ amountRaw: inputAmountRaw,
147
+ decimals: quote.inputToken.decimals,
148
+ fiatRate: sourceFiatRate,
149
+ });
150
+ const providerUsd = calculateProviderUsd(quote, inputAmountRaw, sourceFiatRate, targetFiatRate, quote.expectedOutputAmount);
151
+ const provider = getFiatValueFromUsd(providerUsd, usdToFiatRate);
152
+ const metaMaskFee = getFiatValueFromUsd(new BigNumber(quote.fees?.app?.amountUsd ?? '0').abs(), usdToFiatRate);
153
+ const targetAmount = getAmountFromTokenAmount({
154
+ amountRaw: outputAmountRaw,
155
+ decimals: quote.outputToken.decimals,
156
+ fiatRate: targetFiatRate,
157
+ });
158
+ const metamask = {
159
+ gasLimits,
160
+ };
161
+ return {
162
+ dust,
163
+ estimatedDuration: quote.expectedFillTime ?? 0,
164
+ fees: {
165
+ metaMask: metaMaskFee,
166
+ provider,
167
+ sourceNetwork,
168
+ targetNetwork,
169
+ },
170
+ original: {
171
+ ...original,
172
+ metamask,
173
+ },
174
+ request,
175
+ sourceAmount,
176
+ targetAmount,
177
+ strategy: TransactionPayStrategy.Across,
178
+ };
179
+ }
180
+ function getFiatRates(messenger, quote) {
181
+ const sourceFiatRate = getTokenFiatRate(messenger, quote.inputToken.address, toHex(quote.inputToken.chainId));
182
+ if (!sourceFiatRate) {
183
+ throw new Error('Source token fiat rate not found');
184
+ }
185
+ const targetFiatRate = getTokenFiatRate(messenger, quote.outputToken.address, toHex(quote.outputToken.chainId)) ?? sourceFiatRate;
186
+ const usdToFiatRate = new BigNumber(sourceFiatRate.fiatRate).dividedBy(sourceFiatRate.usdRate);
187
+ return { sourceFiatRate, targetFiatRate, usdToFiatRate };
188
+ }
189
+ function calculateDustUsd(quote, request, targetFiatRate) {
190
+ const expectedOutputRaw = quote.expectedOutputAmount;
191
+ if (expectedOutputRaw === undefined) {
192
+ return new BigNumber(0);
193
+ }
194
+ const expectedOutput = new BigNumber(expectedOutputRaw);
195
+ const minimumOutput = new BigNumber(quote.minOutputAmount ?? request.targetAmountMinimum ?? '0');
196
+ const dustRaw = expectedOutput.minus(minimumOutput).isNegative()
197
+ ? new BigNumber(0)
198
+ : expectedOutput.minus(minimumOutput);
199
+ const dustHuman = dustRaw.shiftedBy(-quote.outputToken.decimals);
200
+ return dustHuman.multipliedBy(targetFiatRate.usdRate);
201
+ }
202
+ function calculateProviderUsd(quote, inputAmountRaw, sourceFiatRate, targetFiatRate, expectedOutputRaw) {
203
+ const totalFeeUsd = quote.fees?.total?.amountUsd;
204
+ if (totalFeeUsd !== undefined) {
205
+ return new BigNumber(totalFeeUsd).abs();
206
+ }
207
+ if (expectedOutputRaw === undefined) {
208
+ return new BigNumber(0);
209
+ }
210
+ const expectedOutput = new BigNumber(expectedOutputRaw);
211
+ if (expectedOutput.lte(0)) {
212
+ return new BigNumber(0);
213
+ }
214
+ const inputAmountUsd = new BigNumber(inputAmountRaw)
215
+ .shiftedBy(-quote.inputToken.decimals)
216
+ .multipliedBy(sourceFiatRate.usdRate);
217
+ const expectedOutputUsd = expectedOutput
218
+ .shiftedBy(-quote.outputToken.decimals)
219
+ .multipliedBy(targetFiatRate.usdRate);
220
+ const providerFeeUsd = inputAmountUsd.minus(expectedOutputUsd);
221
+ return providerFeeUsd.isNegative() ? new BigNumber(0) : providerFeeUsd;
222
+ }
223
+ function getAmountFromTokenAmount({ amountRaw, decimals, fiatRate, }) {
224
+ const rawValue = new BigNumber(amountRaw);
225
+ const raw = rawValue.toString(10);
226
+ const humanValue = rawValue.shiftedBy(-decimals);
227
+ const human = humanValue.toString(10);
228
+ const usd = humanValue.multipliedBy(fiatRate.usdRate).toString(10);
229
+ const fiat = humanValue.multipliedBy(fiatRate.fiatRate).toString(10);
230
+ return {
231
+ fiat,
232
+ human,
233
+ raw,
234
+ usd,
235
+ };
236
+ }
237
+ async function calculateSourceNetworkCost(quote, messenger, request) {
238
+ const acrossFallbackGas = getPayStrategiesConfig(messenger).across.fallbackGas;
239
+ const { from } = request;
240
+ const approvalTxns = quote.approvalTxns ?? [];
241
+ const { swapTx } = quote;
242
+ const swapChainId = toHex(swapTx.chainId);
243
+ const approvalGasResults = await Promise.all(approvalTxns.map(async (approval) => {
244
+ const chainId = toHex(approval.chainId);
245
+ const gas = await estimateGasLimit({
246
+ chainId,
247
+ data: approval.data,
248
+ fallbackGas: acrossFallbackGas,
249
+ from,
250
+ messenger,
251
+ to: approval.to,
252
+ value: approval.value ?? '0x0',
253
+ });
254
+ if (gas.usedFallback) {
255
+ log('Gas estimate failed, using fallback', {
256
+ error: gas.error,
257
+ transactionType: 'approval',
258
+ });
259
+ }
260
+ return { chainId, gas };
261
+ }));
262
+ const swapGasFromQuote = parseAcrossSwapGasLimit(swapTx.gas);
263
+ const swapGas = swapGasFromQuote === undefined
264
+ ? await estimateGasLimit({
265
+ chainId: swapChainId,
266
+ data: swapTx.data,
267
+ fallbackGas: acrossFallbackGas,
268
+ from,
269
+ messenger,
270
+ to: swapTx.to,
271
+ value: swapTx.value ?? '0x0',
272
+ })
273
+ : {
274
+ estimate: swapGasFromQuote,
275
+ max: swapGasFromQuote,
276
+ usedFallback: false,
277
+ };
278
+ if (swapGasFromQuote !== undefined) {
279
+ log('Using Across-provided swap gas limit', {
280
+ gas: swapGasFromQuote,
281
+ transactionType: 'swap',
282
+ });
283
+ }
284
+ else if (swapGas.usedFallback) {
285
+ log('Gas estimate failed, using fallback', {
286
+ error: swapGas.error,
287
+ transactionType: 'swap',
288
+ });
289
+ }
290
+ const estimate = sumAmounts([
291
+ ...approvalGasResults.map(({ chainId, gas }) => calculateGasCost({
292
+ chainId,
293
+ gas: gas.estimate,
294
+ messenger,
295
+ })),
296
+ calculateGasCost({
297
+ chainId: swapChainId,
298
+ gas: swapGas.estimate,
299
+ maxFeePerGas: swapTx.maxFeePerGas,
300
+ maxPriorityFeePerGas: swapTx.maxPriorityFeePerGas,
301
+ messenger,
302
+ }),
303
+ ]);
304
+ const max = sumAmounts([
305
+ ...approvalGasResults.map(({ chainId, gas }) => calculateGasCost({
306
+ chainId,
307
+ gas: gas.max,
308
+ isMax: true,
309
+ messenger,
310
+ })),
311
+ calculateGasCost({
312
+ chainId: swapChainId,
313
+ gas: swapGas.max,
314
+ isMax: true,
315
+ maxFeePerGas: swapTx.maxFeePerGas,
316
+ maxPriorityFeePerGas: swapTx.maxPriorityFeePerGas,
317
+ messenger,
318
+ }),
319
+ ]);
320
+ return {
321
+ sourceNetwork: {
322
+ estimate,
323
+ max,
324
+ },
325
+ gasLimits: {
326
+ approval: approvalGasResults.map(({ gas }) => ({
327
+ estimate: gas.estimate,
328
+ max: gas.max,
329
+ })),
330
+ swap: {
331
+ estimate: swapGas.estimate,
332
+ max: swapGas.max,
333
+ },
334
+ },
335
+ };
336
+ }
337
+ function parseAcrossSwapGasLimit(gas) {
338
+ if (!gas) {
339
+ return undefined;
340
+ }
341
+ const parsedGas = gas.startsWith('0x')
342
+ ? new BigNumber(gas.slice(2), 16)
343
+ : new BigNumber(gas);
344
+ if (!parsedGas.isFinite() ||
345
+ parsedGas.isNaN() ||
346
+ !parsedGas.isInteger() ||
347
+ parsedGas.lte(0)) {
348
+ return undefined;
349
+ }
350
+ return parsedGas.toNumber();
351
+ }
352
+ //# sourceMappingURL=across-quotes.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"across-quotes.mjs","sourceRoot":"","sources":["../../../src/strategy/across/across-quotes.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { successfulFetch, toHex } from '@metamask/controller-utils';\nimport type { TransactionMeta } from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport type {\n AcrossActionRequestBody,\n AcrossGasLimits,\n AcrossQuote,\n AcrossSwapApprovalResponse,\n} from './types';\nimport { TransactionPayStrategy } from '../../constants';\nimport { projectLogger } from '../../logger';\nimport type {\n Amount,\n FiatRates,\n PayStrategyGetQuotesRequest,\n QuoteRequest,\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types';\nimport { getFiatValueFromUsd, sumAmounts } from '../../utils/amounts';\nimport { getPayStrategiesConfig, getSlippage } from '../../utils/feature-flags';\nimport { calculateGasCost, estimateGasLimit } from '../../utils/gas';\nimport { getTokenFiatRate } from '../../utils/token';\nimport { TOKEN_TRANSFER_FOUR_BYTE } from '../relay/constants';\n\nconst log = createModuleLogger(projectLogger, 'across-strategy');\n\nconst TOKEN_TRANSFER_INTERFACE = new Interface([\n 'function transfer(address to, uint256 amount)',\n]);\n\nconst UNSUPPORTED_AUTHORIZATION_LIST_ERROR =\n 'Across does not support type-4/EIP-7702 authorization lists yet';\nconst UNSUPPORTED_DESTINATION_ERROR =\n 'Across only supports transfer-style destination flows at the moment';\n\ntype AcrossQuoteWithoutMetaMask = Omit<AcrossQuote, 'metamask'>;\n\n/**\n * Fetch Across quotes.\n *\n * @param request - Request object.\n * @returns Array of quotes.\n */\nexport async function getAcrossQuotes(\n request: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<AcrossQuote>[]> {\n const { requests } = request;\n\n log('Fetching quotes', requests);\n\n try {\n const normalizedRequests = requests.filter(\n (singleRequest) =>\n singleRequest.isMaxAmount === true ||\n (singleRequest.targetAmountMinimum !== undefined &&\n singleRequest.targetAmountMinimum !== '0'),\n );\n\n if (normalizedRequests.length === 0) {\n return [];\n }\n\n if (request.transaction.txParams?.authorizationList?.length) {\n throw new Error(UNSUPPORTED_AUTHORIZATION_LIST_ERROR);\n }\n\n return await Promise.all(\n normalizedRequests.map((singleRequest) =>\n getSingleQuote(singleRequest, request),\n ),\n );\n } catch (error) {\n log('Error fetching quotes', { error });\n throw new Error(`Failed to fetch Across quotes: ${String(error)}`);\n }\n}\n\nasync function getSingleQuote(\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<AcrossQuote>> {\n const { messenger, transaction } = fullRequest;\n const {\n from,\n isMaxAmount,\n sourceChainId,\n sourceTokenAddress,\n sourceTokenAmount,\n targetAmountMinimum,\n targetChainId,\n targetTokenAddress,\n } = request;\n\n const config = getPayStrategiesConfig(messenger);\n const slippageDecimal = getSlippage(\n messenger,\n sourceChainId,\n sourceTokenAddress,\n );\n\n const amount = isMaxAmount ? sourceTokenAmount : targetAmountMinimum;\n const tradeType = isMaxAmount ? 'exactInput' : 'exactOutput';\n const recipient = getAcrossRecipient(transaction, request);\n const quote = await requestAcrossApproval({\n amount,\n apiBase: config.across.apiBase,\n depositor: from,\n destinationChainId: targetChainId,\n inputToken: sourceTokenAddress,\n originChainId: sourceChainId,\n outputToken: targetTokenAddress,\n recipient,\n slippage: slippageDecimal,\n tradeType,\n });\n\n const originalQuote: AcrossQuoteWithoutMetaMask = {\n quote,\n request: {\n amount,\n tradeType,\n },\n };\n\n return await normalizeQuote(originalQuote, request, fullRequest);\n}\n\ntype AcrossApprovalRequest = {\n amount: string;\n apiBase: string;\n depositor: Hex;\n destinationChainId: Hex;\n inputToken: Hex;\n originChainId: Hex;\n outputToken: Hex;\n recipient: Hex;\n slippage?: number;\n tradeType: 'exactInput' | 'exactOutput';\n};\n\nasync function requestAcrossApproval(\n request: AcrossApprovalRequest,\n): Promise<AcrossSwapApprovalResponse> {\n const {\n amount,\n apiBase,\n depositor,\n destinationChainId,\n inputToken,\n originChainId,\n outputToken,\n recipient,\n slippage,\n tradeType,\n } = request;\n\n const params = new URLSearchParams();\n params.set('tradeType', tradeType);\n params.set('amount', amount);\n params.set('inputToken', inputToken);\n params.set('outputToken', outputToken);\n params.set('originChainId', String(parseInt(originChainId, 16)));\n params.set('destinationChainId', String(parseInt(destinationChainId, 16)));\n params.set('depositor', depositor);\n params.set('recipient', recipient);\n\n if (slippage !== undefined) {\n params.set('slippage', String(slippage));\n }\n\n const body: AcrossActionRequestBody = { actions: [] };\n const url = `${apiBase}/swap/approval?${params.toString()}`;\n const options: RequestInit = {\n body: JSON.stringify(body),\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n };\n const response = await successfulFetch(url, options);\n\n return (await response.json()) as AcrossSwapApprovalResponse;\n}\n\nfunction getAcrossRecipient(\n transaction: TransactionMeta,\n request: QuoteRequest,\n): Hex {\n const { txParams } = transaction;\n const { from } = request;\n const transferData = getTransferData(transaction);\n\n if (transferData) {\n return getTransferRecipient(transferData);\n }\n\n const data = txParams?.data as Hex | undefined;\n const hasNoData = data === undefined || data === '0x';\n const nestedCalldata = getNestedCalldata(transaction);\n\n if (hasNoData && nestedCalldata.length === 0) {\n return from;\n }\n\n throw new Error(UNSUPPORTED_DESTINATION_ERROR);\n}\n\nfunction getTransferData(transaction: TransactionMeta): Hex | undefined {\n const { nestedTransactions, txParams } = transaction;\n\n const nestedTransferData = nestedTransactions?.find(\n (nestedTx: { data?: Hex }) =>\n nestedTx.data?.startsWith(TOKEN_TRANSFER_FOUR_BYTE),\n )?.data;\n\n const data = txParams?.data as Hex | undefined;\n const tokenTransferData = data?.startsWith(TOKEN_TRANSFER_FOUR_BYTE)\n ? data\n : undefined;\n\n return nestedTransferData ?? tokenTransferData;\n}\n\nfunction getNestedCalldata(transaction: TransactionMeta): Hex[] {\n return (transaction.nestedTransactions ?? [])\n .map((nestedTx: { data?: Hex }) => nestedTx.data)\n .filter(\n (data: Hex | undefined): data is Hex =>\n data !== undefined && data !== '0x',\n );\n}\n\nfunction getTransferRecipient(data: Hex): Hex {\n return TOKEN_TRANSFER_INTERFACE.decodeFunctionData(\n 'transfer',\n data,\n ).to.toLowerCase() as Hex;\n}\n\nasync function normalizeQuote(\n original: AcrossQuoteWithoutMetaMask,\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<AcrossQuote>> {\n const { messenger } = fullRequest;\n const { quote } = original;\n\n const { usdToFiatRate, sourceFiatRate, targetFiatRate } = getFiatRates(\n messenger,\n quote,\n );\n\n const dustUsd = calculateDustUsd(quote, request, targetFiatRate);\n const dust = getFiatValueFromUsd(dustUsd, usdToFiatRate);\n\n const { sourceNetwork, gasLimits } = await calculateSourceNetworkCost(\n quote,\n messenger,\n request,\n );\n\n const targetNetwork = getFiatValueFromUsd(new BigNumber(0), usdToFiatRate);\n\n const inputAmountRaw = quote.inputAmount ?? '0';\n const outputAmountRaw = new BigNumber(\n quote.expectedOutputAmount ??\n quote.minOutputAmount ??\n request.targetAmountMinimum ??\n '0',\n ).toString(10);\n\n const sourceAmount = getAmountFromTokenAmount({\n amountRaw: inputAmountRaw,\n decimals: quote.inputToken.decimals,\n fiatRate: sourceFiatRate,\n });\n\n const providerUsd = calculateProviderUsd(\n quote,\n inputAmountRaw,\n sourceFiatRate,\n targetFiatRate,\n quote.expectedOutputAmount,\n );\n const provider = getFiatValueFromUsd(providerUsd, usdToFiatRate);\n const metaMaskFee = getFiatValueFromUsd(\n new BigNumber(quote.fees?.app?.amountUsd ?? '0').abs(),\n usdToFiatRate,\n );\n\n const targetAmount = getAmountFromTokenAmount({\n amountRaw: outputAmountRaw,\n decimals: quote.outputToken.decimals,\n fiatRate: targetFiatRate,\n });\n\n const metamask = {\n gasLimits,\n };\n\n return {\n dust,\n estimatedDuration: quote.expectedFillTime ?? 0,\n fees: {\n metaMask: metaMaskFee,\n provider,\n sourceNetwork,\n targetNetwork,\n },\n original: {\n ...original,\n metamask,\n },\n request,\n sourceAmount,\n targetAmount,\n strategy: TransactionPayStrategy.Across,\n } as TransactionPayQuote<AcrossQuote>;\n}\n\nfunction getFiatRates(\n messenger: TransactionPayControllerMessenger,\n quote: AcrossSwapApprovalResponse,\n): {\n sourceFiatRate: FiatRates;\n targetFiatRate: FiatRates;\n usdToFiatRate: BigNumber;\n} {\n const sourceFiatRate = getTokenFiatRate(\n messenger,\n quote.inputToken.address,\n toHex(quote.inputToken.chainId),\n );\n\n if (!sourceFiatRate) {\n throw new Error('Source token fiat rate not found');\n }\n\n const targetFiatRate =\n getTokenFiatRate(\n messenger,\n quote.outputToken.address,\n toHex(quote.outputToken.chainId),\n ) ?? sourceFiatRate;\n\n const usdToFiatRate = new BigNumber(sourceFiatRate.fiatRate).dividedBy(\n sourceFiatRate.usdRate,\n );\n\n return { sourceFiatRate, targetFiatRate, usdToFiatRate };\n}\n\nfunction calculateDustUsd(\n quote: AcrossSwapApprovalResponse,\n request: QuoteRequest,\n targetFiatRate: FiatRates,\n): BigNumber {\n const expectedOutputRaw = quote.expectedOutputAmount;\n\n if (expectedOutputRaw === undefined) {\n return new BigNumber(0);\n }\n\n const expectedOutput = new BigNumber(expectedOutputRaw);\n const minimumOutput = new BigNumber(\n quote.minOutputAmount ?? request.targetAmountMinimum ?? '0',\n );\n\n const dustRaw = expectedOutput.minus(minimumOutput).isNegative()\n ? new BigNumber(0)\n : expectedOutput.minus(minimumOutput);\n const dustHuman = dustRaw.shiftedBy(-quote.outputToken.decimals);\n\n return dustHuman.multipliedBy(targetFiatRate.usdRate);\n}\n\nfunction calculateProviderUsd(\n quote: AcrossSwapApprovalResponse,\n inputAmountRaw: string,\n sourceFiatRate: FiatRates,\n targetFiatRate: FiatRates,\n expectedOutputRaw?: string,\n): BigNumber {\n const totalFeeUsd = quote.fees?.total?.amountUsd;\n\n if (totalFeeUsd !== undefined) {\n return new BigNumber(totalFeeUsd).abs();\n }\n\n if (expectedOutputRaw === undefined) {\n return new BigNumber(0);\n }\n\n const expectedOutput = new BigNumber(expectedOutputRaw);\n\n if (expectedOutput.lte(0)) {\n return new BigNumber(0);\n }\n\n const inputAmountUsd = new BigNumber(inputAmountRaw)\n .shiftedBy(-quote.inputToken.decimals)\n .multipliedBy(sourceFiatRate.usdRate);\n const expectedOutputUsd = expectedOutput\n .shiftedBy(-quote.outputToken.decimals)\n .multipliedBy(targetFiatRate.usdRate);\n const providerFeeUsd = inputAmountUsd.minus(expectedOutputUsd);\n\n return providerFeeUsd.isNegative() ? new BigNumber(0) : providerFeeUsd;\n}\n\nfunction getAmountFromTokenAmount({\n amountRaw,\n decimals,\n fiatRate,\n}: {\n amountRaw: string;\n decimals: number;\n fiatRate: FiatRates;\n}): Amount {\n const rawValue = new BigNumber(amountRaw);\n const raw = rawValue.toString(10);\n\n const humanValue = rawValue.shiftedBy(-decimals);\n const human = humanValue.toString(10);\n\n const usd = humanValue.multipliedBy(fiatRate.usdRate).toString(10);\n const fiat = humanValue.multipliedBy(fiatRate.fiatRate).toString(10);\n\n return {\n fiat,\n human,\n raw,\n usd,\n };\n}\n\nasync function calculateSourceNetworkCost(\n quote: AcrossSwapApprovalResponse,\n messenger: TransactionPayControllerMessenger,\n request: QuoteRequest,\n): Promise<{\n sourceNetwork: TransactionPayQuote<AcrossQuote>['fees']['sourceNetwork'];\n gasLimits: AcrossGasLimits;\n}> {\n const acrossFallbackGas =\n getPayStrategiesConfig(messenger).across.fallbackGas;\n const { from } = request;\n const approvalTxns = quote.approvalTxns ?? [];\n const { swapTx } = quote;\n const swapChainId = toHex(swapTx.chainId);\n\n const approvalGasResults = await Promise.all(\n approvalTxns.map(async (approval) => {\n const chainId = toHex(approval.chainId);\n const gas = await estimateGasLimit({\n chainId,\n data: approval.data,\n fallbackGas: acrossFallbackGas,\n from,\n messenger,\n to: approval.to,\n value: approval.value ?? '0x0',\n });\n\n if (gas.usedFallback) {\n log('Gas estimate failed, using fallback', {\n error: gas.error,\n transactionType: 'approval',\n });\n }\n\n return { chainId, gas };\n }),\n );\n\n const swapGasFromQuote = parseAcrossSwapGasLimit(swapTx.gas);\n const swapGas =\n swapGasFromQuote === undefined\n ? await estimateGasLimit({\n chainId: swapChainId,\n data: swapTx.data,\n fallbackGas: acrossFallbackGas,\n from,\n messenger,\n to: swapTx.to,\n value: swapTx.value ?? '0x0',\n })\n : {\n estimate: swapGasFromQuote,\n max: swapGasFromQuote,\n usedFallback: false,\n };\n\n if (swapGasFromQuote !== undefined) {\n log('Using Across-provided swap gas limit', {\n gas: swapGasFromQuote,\n transactionType: 'swap',\n });\n } else if (swapGas.usedFallback) {\n log('Gas estimate failed, using fallback', {\n error: swapGas.error,\n transactionType: 'swap',\n });\n }\n\n const estimate = sumAmounts([\n ...approvalGasResults.map(({ chainId, gas }) =>\n calculateGasCost({\n chainId,\n gas: gas.estimate,\n messenger,\n }),\n ),\n calculateGasCost({\n chainId: swapChainId,\n gas: swapGas.estimate,\n maxFeePerGas: swapTx.maxFeePerGas,\n maxPriorityFeePerGas: swapTx.maxPriorityFeePerGas,\n messenger,\n }),\n ]);\n\n const max = sumAmounts([\n ...approvalGasResults.map(({ chainId, gas }) =>\n calculateGasCost({\n chainId,\n gas: gas.max,\n isMax: true,\n messenger,\n }),\n ),\n calculateGasCost({\n chainId: swapChainId,\n gas: swapGas.max,\n isMax: true,\n maxFeePerGas: swapTx.maxFeePerGas,\n maxPriorityFeePerGas: swapTx.maxPriorityFeePerGas,\n messenger,\n }),\n ]);\n\n return {\n sourceNetwork: {\n estimate,\n max,\n },\n gasLimits: {\n approval: approvalGasResults.map(({ gas }) => ({\n estimate: gas.estimate,\n max: gas.max,\n })),\n swap: {\n estimate: swapGas.estimate,\n max: swapGas.max,\n },\n },\n };\n}\n\nfunction parseAcrossSwapGasLimit(gas?: string): number | undefined {\n if (!gas) {\n return undefined;\n }\n\n const parsedGas = gas.startsWith('0x')\n ? new BigNumber(gas.slice(2), 16)\n : new BigNumber(gas);\n\n if (\n !parsedGas.isFinite() ||\n parsedGas.isNaN() ||\n !parsedGas.isInteger() ||\n parsedGas.lte(0)\n ) {\n return undefined;\n }\n\n return parsedGas.toNumber();\n}\n"]}
@@ -0,0 +1,241 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.submitAcrossQuotes = void 0;
4
+ const controller_utils_1 = require("@metamask/controller-utils");
5
+ const transaction_controller_1 = require("@metamask/transaction-controller");
6
+ const utils_1 = require("@metamask/utils");
7
+ const logger_1 = require("../../logger.cjs");
8
+ const feature_flags_1 = require("../../utils/feature-flags.cjs");
9
+ const transaction_1 = require("../../utils/transaction.cjs");
10
+ const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'across-strategy');
11
+ const ACROSS_STATUS_POLL_INTERVAL = 1000;
12
+ /**
13
+ * Submit Across quotes.
14
+ *
15
+ * @param request - Request object.
16
+ * @returns An object containing the transaction hash if available.
17
+ */
18
+ async function submitAcrossQuotes(request) {
19
+ log('Executing quotes', request);
20
+ const { quotes, messenger, transaction } = request;
21
+ let transactionHash;
22
+ for (const quote of quotes) {
23
+ ({ transactionHash } = await executeSingleQuote(quote, messenger, transaction));
24
+ }
25
+ return { transactionHash };
26
+ }
27
+ exports.submitAcrossQuotes = submitAcrossQuotes;
28
+ async function executeSingleQuote(quote, messenger, transaction) {
29
+ log('Executing single quote', quote);
30
+ (0, transaction_1.updateTransaction)({
31
+ transactionId: transaction.id,
32
+ messenger,
33
+ note: 'Remove nonce from skipped transaction',
34
+ }, (tx) => {
35
+ tx.txParams.nonce = undefined;
36
+ });
37
+ const acrossDepositType = getAcrossDepositType(transaction.type);
38
+ const transactionHash = await submitTransactions(quote, transaction.id, acrossDepositType, messenger);
39
+ (0, transaction_1.updateTransaction)({
40
+ transactionId: transaction.id,
41
+ messenger,
42
+ note: 'Intent complete after Across submission',
43
+ }, (tx) => {
44
+ tx.isIntentComplete = true;
45
+ });
46
+ return { transactionHash };
47
+ }
48
+ /**
49
+ * Submit transactions for an Across quote.
50
+ *
51
+ * @param quote - Across quote.
52
+ * @param parentTransactionId - ID of the parent transaction.
53
+ * @param acrossDepositType - Transaction type used for the swap/deposit step.
54
+ * @param messenger - Controller messenger.
55
+ * @returns Hash of the last submitted transaction, if available.
56
+ */
57
+ async function submitTransactions(quote, parentTransactionId, acrossDepositType, messenger) {
58
+ const { approvalTxns, swapTx } = quote.original.quote;
59
+ const { gasLimits: quoteGasLimits } = quote.original.metamask;
60
+ const { from } = quote.request;
61
+ const chainId = (0, controller_utils_1.toHex)(swapTx.chainId);
62
+ const networkClientId = messenger.call('NetworkController:findNetworkClientIdByChainId', chainId);
63
+ const transactions = [];
64
+ if (approvalTxns?.length) {
65
+ for (const [index, approval] of approvalTxns.entries()) {
66
+ const approvalGasLimit = quoteGasLimits?.approval[index]?.max;
67
+ if (approvalGasLimit === undefined) {
68
+ throw new Error(`Missing quote gas limit for Across approval transaction at index ${index}`);
69
+ }
70
+ transactions.push({
71
+ params: buildTransactionParams(from, {
72
+ chainId: approval.chainId,
73
+ data: approval.data,
74
+ gasLimit: approvalGasLimit,
75
+ to: approval.to,
76
+ value: approval.value,
77
+ }),
78
+ type: transaction_controller_1.TransactionType.tokenMethodApprove,
79
+ });
80
+ }
81
+ }
82
+ const swapGasLimit = quoteGasLimits?.swap?.max;
83
+ if (swapGasLimit === undefined) {
84
+ throw new Error('Missing quote gas limit for Across swap transaction');
85
+ }
86
+ transactions.push({
87
+ params: buildTransactionParams(from, {
88
+ chainId: swapTx.chainId,
89
+ data: swapTx.data,
90
+ gasLimit: swapGasLimit,
91
+ to: swapTx.to,
92
+ value: swapTx.value,
93
+ maxFeePerGas: swapTx.maxFeePerGas,
94
+ maxPriorityFeePerGas: swapTx.maxPriorityFeePerGas,
95
+ }),
96
+ type: acrossDepositType,
97
+ });
98
+ const transactionIds = [];
99
+ const { end } = (0, transaction_1.collectTransactionIds)(chainId, from, messenger, (transactionId) => {
100
+ transactionIds.push(transactionId);
101
+ (0, transaction_1.updateTransaction)({
102
+ transactionId: parentTransactionId,
103
+ messenger,
104
+ note: 'Add required transaction ID from Across submission',
105
+ }, (tx) => {
106
+ tx.requiredTransactionIds ?? (tx.requiredTransactionIds = []);
107
+ tx.requiredTransactionIds.push(transactionId);
108
+ });
109
+ });
110
+ let result;
111
+ try {
112
+ if (transactions.length === 1) {
113
+ result = await messenger.call('TransactionController:addTransaction', transactions[0].params, {
114
+ networkClientId,
115
+ origin: controller_utils_1.ORIGIN_METAMASK,
116
+ requireApproval: false,
117
+ type: transactions[0].type,
118
+ });
119
+ }
120
+ else {
121
+ const batchTransactions = transactions.map(({ params, type }) => ({
122
+ params: toBatchTransactionParams(params),
123
+ type,
124
+ }));
125
+ await messenger.call('TransactionController:addTransactionBatch', {
126
+ from,
127
+ networkClientId,
128
+ origin: controller_utils_1.ORIGIN_METAMASK,
129
+ requireApproval: false,
130
+ transactions: batchTransactions,
131
+ });
132
+ }
133
+ }
134
+ finally {
135
+ end();
136
+ }
137
+ if (result) {
138
+ const txHash = await result.result;
139
+ log('Submitted transaction', txHash);
140
+ }
141
+ await Promise.all(transactionIds.map((txId) => (0, transaction_1.waitForTransactionConfirmed)(txId, messenger)));
142
+ const hash = transactionIds.length
143
+ ? (0, transaction_1.getTransaction)(transactionIds.slice(-1)[0], messenger)?.hash
144
+ : undefined;
145
+ return await waitForAcrossCompletion(quote.original, hash, messenger);
146
+ }
147
+ async function waitForAcrossCompletion(quote, transactionHash, messenger) {
148
+ if (!transactionHash || !quote.quote.id) {
149
+ return transactionHash;
150
+ }
151
+ const config = (0, feature_flags_1.getPayStrategiesConfig)(messenger);
152
+ const params = new URLSearchParams({
153
+ depositId: quote.quote.id,
154
+ originChainId: String(quote.quote.swapTx.chainId),
155
+ txHash: transactionHash,
156
+ });
157
+ const url = `${config.across.apiBase}/deposit/status?${params.toString()}`;
158
+ let attempt = 0;
159
+ while (true) {
160
+ attempt += 1;
161
+ let status;
162
+ try {
163
+ const response = await (0, controller_utils_1.successfulFetch)(url, {
164
+ method: 'GET',
165
+ headers: {
166
+ Accept: 'application/json',
167
+ },
168
+ });
169
+ status = (await response.json());
170
+ }
171
+ catch (error) {
172
+ log('Across status polling request failed', {
173
+ attempt,
174
+ error: String(error),
175
+ transactionHash,
176
+ });
177
+ await new Promise((resolve) => setTimeout(resolve, ACROSS_STATUS_POLL_INTERVAL));
178
+ continue;
179
+ }
180
+ const normalizedStatus = status.status?.toLowerCase();
181
+ log('Polled Across status', {
182
+ attempt,
183
+ status: normalizedStatus,
184
+ transactionHash,
185
+ });
186
+ if (normalizedStatus &&
187
+ ['completed', 'filled', 'success'].includes(normalizedStatus)) {
188
+ return (status.destinationTxHash ??
189
+ status.fillTxHash ??
190
+ status.txHash ??
191
+ transactionHash);
192
+ }
193
+ if (normalizedStatus &&
194
+ ['error', 'failed', 'refund', 'refunded'].includes(normalizedStatus)) {
195
+ throw new Error(`Across request failed with status: ${normalizedStatus}`);
196
+ }
197
+ await new Promise((resolve) => setTimeout(resolve, ACROSS_STATUS_POLL_INTERVAL));
198
+ }
199
+ }
200
+ function getAcrossDepositType(transactionType) {
201
+ switch (transactionType) {
202
+ case transaction_controller_1.TransactionType.perpsDeposit:
203
+ return transaction_controller_1.TransactionType.perpsAcrossDeposit;
204
+ case transaction_controller_1.TransactionType.predictDeposit:
205
+ return transaction_controller_1.TransactionType.predictAcrossDeposit;
206
+ case undefined:
207
+ return transaction_controller_1.TransactionType.perpsAcrossDeposit;
208
+ default:
209
+ return transactionType;
210
+ }
211
+ }
212
+ function buildTransactionParams(from, params) {
213
+ const value = (0, controller_utils_1.toHex)(params.value ?? '0x0');
214
+ const gas = params.gasLimit;
215
+ return {
216
+ data: params.data,
217
+ from,
218
+ gas: (0, controller_utils_1.toHex)(gas),
219
+ maxFeePerGas: normalizeOptionalHex(params.maxFeePerGas),
220
+ maxPriorityFeePerGas: normalizeOptionalHex(params.maxPriorityFeePerGas),
221
+ to: params.to,
222
+ value,
223
+ };
224
+ }
225
+ function normalizeOptionalHex(value) {
226
+ if (value === undefined) {
227
+ return undefined;
228
+ }
229
+ return (0, controller_utils_1.toHex)(value);
230
+ }
231
+ function toBatchTransactionParams(params) {
232
+ return {
233
+ data: params.data,
234
+ gas: params.gas,
235
+ maxFeePerGas: params.maxFeePerGas,
236
+ maxPriorityFeePerGas: params.maxPriorityFeePerGas,
237
+ to: params.to,
238
+ value: params.value,
239
+ };
240
+ }
241
+ //# sourceMappingURL=across-submit.cjs.map