@lifi/sdk 3.6.0-beta.3 → 3.6.0-beta.4

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 (96) hide show
  1. package/package.json +4 -4
  2. package/src/_cjs/core/EVM/EVMStepExecutor.js +250 -220
  3. package/src/_cjs/core/EVM/EVMStepExecutor.js.map +1 -1
  4. package/src/_cjs/core/EVM/parseEVMErrors.js +2 -1
  5. package/src/_cjs/core/EVM/parseEVMErrors.js.map +1 -1
  6. package/src/_cjs/core/EVM/typeguards.js +2 -2
  7. package/src/_cjs/core/EVM/typeguards.js.map +1 -1
  8. package/src/_cjs/core/Solana/SolanaStepExecutor.js +1 -13
  9. package/src/_cjs/core/Solana/SolanaStepExecutor.js.map +1 -1
  10. package/src/_cjs/core/Solana/parseSolanaErrors.js.map +1 -1
  11. package/src/_cjs/core/StatusManager.js +13 -9
  12. package/src/_cjs/core/StatusManager.js.map +1 -1
  13. package/src/_cjs/core/UTXO/UTXOStepExecutor.js +1 -13
  14. package/src/_cjs/core/UTXO/UTXOStepExecutor.js.map +1 -1
  15. package/src/_cjs/core/UTXO/parseUTXOErrors.js.map +1 -1
  16. package/src/_cjs/core/processMessages.js +22 -15
  17. package/src/_cjs/core/processMessages.js.map +1 -1
  18. package/src/_cjs/core/waitForDestinationChainTransaction.js +16 -1
  19. package/src/_cjs/core/waitForDestinationChainTransaction.js.map +1 -1
  20. package/src/_cjs/core/waitForTransactionStatus.js.map +1 -1
  21. package/src/_cjs/errors/SDKError.js.map +1 -1
  22. package/src/_cjs/index.js +2 -2
  23. package/src/_cjs/index.js.map +1 -1
  24. package/src/_cjs/utils/getTransactionMessage.js.map +1 -1
  25. package/src/_cjs/version.js +1 -1
  26. package/src/_esm/core/EVM/EVMStepExecutor.js +273 -242
  27. package/src/_esm/core/EVM/EVMStepExecutor.js.map +1 -1
  28. package/src/_esm/core/EVM/parseEVMErrors.js +2 -1
  29. package/src/_esm/core/EVM/parseEVMErrors.js.map +1 -1
  30. package/src/_esm/core/EVM/typeguards.js +1 -1
  31. package/src/_esm/core/EVM/typeguards.js.map +1 -1
  32. package/src/_esm/core/Solana/SolanaStepExecutor.js +1 -14
  33. package/src/_esm/core/Solana/SolanaStepExecutor.js.map +1 -1
  34. package/src/_esm/core/Solana/parseSolanaErrors.js.map +1 -1
  35. package/src/_esm/core/StatusManager.js +24 -18
  36. package/src/_esm/core/StatusManager.js.map +1 -1
  37. package/src/_esm/core/UTXO/UTXOStepExecutor.js +1 -14
  38. package/src/_esm/core/UTXO/UTXOStepExecutor.js.map +1 -1
  39. package/src/_esm/core/UTXO/parseUTXOErrors.js.map +1 -1
  40. package/src/_esm/core/processMessages.js +22 -15
  41. package/src/_esm/core/processMessages.js.map +1 -1
  42. package/src/_esm/core/waitForDestinationChainTransaction.js +17 -1
  43. package/src/_esm/core/waitForDestinationChainTransaction.js.map +1 -1
  44. package/src/_esm/core/waitForTransactionStatus.js.map +1 -1
  45. package/src/_esm/errors/SDKError.js.map +1 -1
  46. package/src/_esm/index.js +1 -1
  47. package/src/_esm/index.js.map +1 -1
  48. package/src/_esm/utils/getTransactionMessage.js.map +1 -1
  49. package/src/_esm/version.js +1 -1
  50. package/src/_types/core/EVM/EVMStepExecutor.d.ts +13 -3
  51. package/src/_types/core/EVM/EVMStepExecutor.d.ts.map +1 -1
  52. package/src/_types/core/EVM/checkAllowance.d.ts.map +1 -1
  53. package/src/_types/core/EVM/parseEVMErrors.d.ts +2 -1
  54. package/src/_types/core/EVM/parseEVMErrors.d.ts.map +1 -1
  55. package/src/_types/core/EVM/typeguards.d.ts +1 -1
  56. package/src/_types/core/EVM/typeguards.d.ts.map +1 -1
  57. package/src/_types/core/Solana/SolanaStepExecutor.d.ts.map +1 -1
  58. package/src/_types/core/Solana/parseSolanaErrors.d.ts +2 -1
  59. package/src/_types/core/Solana/parseSolanaErrors.d.ts.map +1 -1
  60. package/src/_types/core/StatusManager.d.ts +14 -11
  61. package/src/_types/core/StatusManager.d.ts.map +1 -1
  62. package/src/_types/core/UTXO/UTXOStepExecutor.d.ts.map +1 -1
  63. package/src/_types/core/UTXO/parseUTXOErrors.d.ts +2 -1
  64. package/src/_types/core/UTXO/parseUTXOErrors.d.ts.map +1 -1
  65. package/src/_types/core/processMessages.d.ts +3 -1
  66. package/src/_types/core/processMessages.d.ts.map +1 -1
  67. package/src/_types/core/types.d.ts +32 -1
  68. package/src/_types/core/types.d.ts.map +1 -1
  69. package/src/_types/core/waitForDestinationChainTransaction.d.ts +3 -3
  70. package/src/_types/core/waitForDestinationChainTransaction.d.ts.map +1 -1
  71. package/src/_types/core/waitForTransactionStatus.d.ts +2 -1
  72. package/src/_types/core/waitForTransactionStatus.d.ts.map +1 -1
  73. package/src/_types/errors/SDKError.d.ts +2 -1
  74. package/src/_types/errors/SDKError.d.ts.map +1 -1
  75. package/src/_types/index.d.ts +2 -2
  76. package/src/_types/index.d.ts.map +1 -1
  77. package/src/_types/utils/getTransactionMessage.d.ts +2 -1
  78. package/src/_types/utils/getTransactionMessage.d.ts.map +1 -1
  79. package/src/_types/version.d.ts +1 -1
  80. package/src/core/EVM/EVMStepExecutor.ts +352 -301
  81. package/src/core/EVM/checkAllowance.ts +2 -2
  82. package/src/core/EVM/parseEVMErrors.ts +6 -2
  83. package/src/core/EVM/typeguards.ts +1 -1
  84. package/src/core/Solana/SolanaStepExecutor.ts +2 -16
  85. package/src/core/Solana/parseSolanaErrors.ts +2 -1
  86. package/src/core/StatusManager.ts +38 -26
  87. package/src/core/UTXO/UTXOStepExecutor.ts +2 -16
  88. package/src/core/UTXO/parseUTXOErrors.ts +2 -1
  89. package/src/core/processMessages.ts +25 -21
  90. package/src/core/types.ts +54 -1
  91. package/src/core/waitForDestinationChainTransaction.ts +21 -4
  92. package/src/core/waitForTransactionStatus.ts +2 -6
  93. package/src/errors/SDKError.ts +2 -1
  94. package/src/index.ts +6 -1
  95. package/src/utils/getTransactionMessage.ts +2 -1
  96. package/src/version.ts +1 -1
@@ -5,7 +5,6 @@ import { config } from '../../config.js';
5
5
  import { LiFiErrorCode } from '../../errors/constants.js';
6
6
  import { TransactionError } from '../../errors/errors.js';
7
7
  import { getRelayerQuote, getStepTransaction, relayTransaction, } from '../../services/api.js';
8
- import { isZeroAddress } from '../../utils/isZeroAddress.js';
9
8
  import { BaseStepExecutor } from '../BaseStepExecutor.js';
10
9
  import { checkBalance } from '../checkBalance.js';
11
10
  import { stepComparison } from '../stepComparison.js';
@@ -15,7 +14,7 @@ import { getNativePermit } from './getNativePermit.js';
15
14
  import { parseEVMErrors } from './parseEVMErrors.js';
16
15
  import { signPermitMessage } from './signPermitMessage.js';
17
16
  import { switchChain } from './switchChain.js';
18
- import { isEVMPermitStep } from './typeguards.js';
17
+ import { isRelayerStep } from './typeguards.js';
19
18
  import { getMaxPriorityFeePerGas } from './utils.js';
20
19
  import { waitForBatchTransactionReceipt, } from './waitForBatchTransactionReceipt.js';
21
20
  import { waitForRelayedTransactionReceipt } from './waitForRelayedTransactionReceipt.js';
@@ -67,6 +66,46 @@ export class EVMStepExecutor extends BaseStepExecutor {
67
66
  return updatedClient;
68
67
  }
69
68
  });
69
+ Object.defineProperty(this, "waitForTransaction", {
70
+ enumerable: true,
71
+ configurable: true,
72
+ writable: true,
73
+ value: async ({ step, process, fromChain, toChain, atomicBatchSupported, isRelayerTransaction, txHash, isBridgeExecution, }) => {
74
+ let transactionReceipt;
75
+ if (atomicBatchSupported) {
76
+ transactionReceipt = await waitForBatchTransactionReceipt(this.client, txHash);
77
+ }
78
+ else if (isRelayerTransaction) {
79
+ transactionReceipt = await waitForRelayedTransactionReceipt(txHash);
80
+ }
81
+ else {
82
+ transactionReceipt = await waitForTransactionReceipt({
83
+ client: this.client,
84
+ chainId: fromChain.id,
85
+ txHash,
86
+ onReplaced: (response) => {
87
+ this.statusManager.updateProcess(step, process.type, 'PENDING', {
88
+ txHash: response.transaction.hash,
89
+ txLink: `${fromChain.metamask.blockExplorerUrls[0]}tx/${response.transaction.hash}`,
90
+ });
91
+ },
92
+ });
93
+ }
94
+ // Update pending process if the transaction hash from the receipt is different.
95
+ // This might happen if the transaction was replaced.
96
+ if (transactionReceipt?.transactionHash &&
97
+ transactionReceipt.transactionHash !== txHash) {
98
+ process = this.statusManager.updateProcess(step, process.type, 'PENDING', {
99
+ txHash: transactionReceipt.transactionHash,
100
+ txLink: `${fromChain.metamask.blockExplorerUrls[0]}tx/${transactionReceipt.transactionHash}`,
101
+ });
102
+ }
103
+ if (isBridgeExecution) {
104
+ process = this.statusManager.updateProcess(step, process.type, 'DONE');
105
+ }
106
+ await waitForDestinationChainTransaction(step, process, fromChain, toChain, this.statusManager);
107
+ }
108
+ });
70
109
  Object.defineProperty(this, "executeStep", {
71
110
  enumerable: true,
72
111
  configurable: true,
@@ -87,21 +126,24 @@ export class EVMStepExecutor extends BaseStepExecutor {
87
126
  }
88
127
  const fromChain = await config.getChainById(step.action.fromChainId);
89
128
  const toChain = await config.getChainById(step.action.toChainId);
129
+ // Check if the wallet supports atomic batch transactions (EIP-5792)
130
+ const calls = [];
90
131
  let atomicBatchSupported = false;
91
132
  try {
92
133
  const capabilities = (await getAction(this.client, getCapabilities, 'getCapabilities')(undefined));
93
134
  atomicBatchSupported = capabilities[fromChain.id]?.atomicBatch?.supported;
94
135
  }
95
136
  catch {
96
- // If the wallet does not support getCapabilities, we assume that atomic batch is not supported
137
+ // If the wallet does not support getCapabilities or the call fails,
138
+ // we assume that atomic batch is not supported
97
139
  }
98
- const calls = [];
99
140
  const isBridgeExecution = fromChain.id !== toChain.id;
100
141
  const currentProcessType = isBridgeExecution ? 'CROSS_CHAIN' : 'SWAP';
101
142
  // Find existing swap/bridge process
102
143
  const existingProcess = step.execution.process.find((p) => p.type === currentProcessType);
144
+ const isFromNativeToken = fromChain.nativeToken.address === step.action.fromToken.address;
103
145
  // Check if step requires permit signature and will be used with relayer service
104
- const isPermitStep = isEVMPermitStep(step);
146
+ const isRelayerTransaction = isRelayerStep(step);
105
147
  // Check if token requires approval
106
148
  // Native tokens (like ETH) don't need approval since they're not ERC20 tokens
107
149
  // We should support different permit types:
@@ -110,19 +152,23 @@ export class EVMStepExecutor extends BaseStepExecutor {
110
152
  // 3. Standard ERC20 approval
111
153
  const nativePermit = await getNativePermit(this.client, fromChain, step.action.fromToken.address);
112
154
  // Check if proxy contract is available and token supports native permits, not available for atomic batch
113
- const nativePermitSupported = !!fromChain.permit2Proxy &&
114
- nativePermit.supported &&
155
+ const nativePermitSupported = nativePermit.supported &&
156
+ !!fromChain.permit2Proxy &&
115
157
  !atomicBatchSupported &&
116
- !isPermitStep;
158
+ !isRelayerTransaction && // TODO: remove once we support ERC-2771
159
+ !isFromNativeToken;
117
160
  // Check if chain has Permit2 contract deployed. Permit2 should not be available for atomic batch.
118
- const permit2Supported = !!fromChain.permit2 && !!fromChain.permit2Proxy && !atomicBatchSupported;
161
+ const permit2Supported = !!fromChain.permit2 &&
162
+ !!fromChain.permit2Proxy &&
163
+ !atomicBatchSupported &&
164
+ !isFromNativeToken;
119
165
  // Token supports either native permits or Permit2
120
166
  const permitSupported = permit2Supported || nativePermitSupported;
121
167
  const checkForAllowance =
122
168
  // No existing swap/bridgetransaction is pending
123
169
  !existingProcess?.txHash &&
124
170
  // Token is not native (address is not zero)
125
- !isZeroAddress(step.action.fromToken.address) &&
171
+ !isFromNativeToken &&
126
172
  // Token doesn't support native permits
127
173
  !nativePermitSupported;
128
174
  if (checkForAllowance) {
@@ -149,252 +195,237 @@ export class EVMStepExecutor extends BaseStepExecutor {
149
195
  }
150
196
  }
151
197
  }
152
- let process = this.statusManager.findOrCreateProcess({
153
- step,
154
- type: currentProcessType,
155
- chainId: fromChain.id,
156
- });
157
- if (process.status !== 'DONE') {
158
- try {
159
- let txHash;
160
- if (process.txHash) {
161
- // Make sure that the chain is still correct
162
- const updatedClient = await this.checkClient(step, process);
163
- if (!updatedClient) {
164
- return step;
165
- }
166
- // Wait for exiting transaction
167
- txHash = process.txHash;
198
+ let process = this.statusManager.findProcess(step, currentProcessType);
199
+ if (process?.status === 'DONE') {
200
+ await waitForDestinationChainTransaction(step, process, fromChain, toChain, this.statusManager);
201
+ return step;
202
+ }
203
+ try {
204
+ if (process?.txHash) {
205
+ // Make sure that the chain is still correct
206
+ const updatedClient = await this.checkClient(step, process);
207
+ if (!updatedClient) {
208
+ return step;
168
209
  }
169
- else {
170
- process = this.statusManager.updateProcess(step, process.type, 'STARTED');
171
- // Check balance
172
- await checkBalance(this.client.account.address, step);
173
- // Create new transaction request
174
- if (!step.transactionRequest) {
175
- const { execution, ...stepBase } = step;
176
- let updatedStep;
177
- if (isPermitStep) {
178
- const updatedRelayedStep = await getRelayerQuote({
179
- fromChain: stepBase.action.fromChainId,
180
- fromToken: stepBase.action.fromToken.address,
181
- fromAddress: stepBase.action.fromAddress,
182
- fromAmount: stepBase.action.fromAmount,
183
- toChain: stepBase.action.toChainId,
184
- toToken: stepBase.action.toToken.address,
185
- slippage: stepBase.action.slippage,
186
- toAddress: stepBase.action.toAddress,
187
- allowBridges: [stepBase.tool],
188
- });
189
- updatedStep = {
190
- ...updatedRelayedStep.data.quote.step,
191
- ...updatedRelayedStep.data.quote,
192
- id: stepBase.id,
193
- };
194
- }
195
- else {
196
- updatedStep = await getStepTransaction(stepBase);
197
- }
198
- const comparedStep = await stepComparison(this.statusManager, step, updatedStep, this.allowUserInteraction, this.executionOptions);
199
- Object.assign(step, {
200
- ...comparedStep,
201
- execution: step.execution,
202
- });
203
- }
204
- if (!step.transactionRequest) {
205
- throw new TransactionError(LiFiErrorCode.TransactionUnprepared, 'Unable to prepare transaction.');
206
- }
207
- let transactionRequest = {
208
- to: step.transactionRequest.to,
209
- from: step.transactionRequest.from,
210
- data: step.transactionRequest.data,
211
- value: step.transactionRequest.value
212
- ? BigInt(step.transactionRequest.value)
213
- : undefined,
214
- gas: step.transactionRequest.gasLimit
215
- ? BigInt(step.transactionRequest.gasLimit)
216
- : undefined,
217
- // gasPrice: step.transactionRequest.gasPrice
218
- // ? BigInt(step.transactionRequest.gasPrice as string)
219
- // : undefined,
220
- // maxFeePerGas: step.transactionRequest.maxFeePerGas
221
- // ? BigInt(step.transactionRequest.maxFeePerGas as string)
222
- // : undefined,
223
- maxPriorityFeePerGas: this.client.account?.type === 'local'
224
- ? await getMaxPriorityFeePerGas(this.client)
225
- : step.transactionRequest.maxPriorityFeePerGas
226
- ? BigInt(step.transactionRequest.maxPriorityFeePerGas)
227
- : undefined,
210
+ // Wait for exiting transaction
211
+ const txHash = process.txHash;
212
+ await this.waitForTransaction({
213
+ step,
214
+ process,
215
+ fromChain,
216
+ toChain,
217
+ atomicBatchSupported,
218
+ isRelayerTransaction,
219
+ txHash,
220
+ isBridgeExecution,
221
+ });
222
+ return step;
223
+ }
224
+ process = this.statusManager.findOrCreateProcess({
225
+ step,
226
+ type: permitSupported ? 'PERMIT' : currentProcessType,
227
+ status: 'STARTED',
228
+ });
229
+ // Check balance
230
+ await checkBalance(this.client.account.address, step);
231
+ // Create new transaction request
232
+ if (!step.transactionRequest) {
233
+ const { execution, ...stepBase } = step;
234
+ let updatedStep;
235
+ if (isRelayerTransaction) {
236
+ const updatedRelayedStep = await getRelayerQuote({
237
+ fromChain: stepBase.action.fromChainId,
238
+ fromToken: stepBase.action.fromToken.address,
239
+ fromAddress: stepBase.action.fromAddress,
240
+ fromAmount: stepBase.action.fromAmount,
241
+ toChain: stepBase.action.toChainId,
242
+ toToken: stepBase.action.toToken.address,
243
+ slippage: stepBase.action.slippage,
244
+ toAddress: stepBase.action.toAddress,
245
+ allowBridges: [stepBase.tool],
246
+ });
247
+ updatedStep = {
248
+ ...updatedRelayedStep.data.quote.step,
249
+ ...updatedRelayedStep.data.quote,
250
+ id: stepBase.id,
228
251
  };
229
- if (this.executionOptions?.updateTransactionRequestHook) {
230
- const customizedTransactionRequest = await this.executionOptions.updateTransactionRequestHook({
231
- requestType: 'transaction',
232
- ...transactionRequest,
233
- });
234
- transactionRequest = {
235
- ...transactionRequest,
236
- ...customizedTransactionRequest,
237
- };
238
- }
239
- // Make sure that the chain is still correct
240
- const updatedClient = await this.checkClient(step, process);
241
- if (!updatedClient) {
242
- return step;
243
- }
244
- process = this.statusManager.updateProcess(step, process.type, permitSupported ? 'PERMIT_REQUIRED' : 'ACTION_REQUIRED');
245
- if (!this.allowUserInteraction) {
246
- return step;
247
- }
248
- let isTransactionRelayed = false;
249
- if (atomicBatchSupported) {
250
- const transferCall = {
251
- chainId: fromChain.id,
252
- data: transactionRequest.data,
253
- to: transactionRequest.to,
254
- value: transactionRequest.value,
255
- };
256
- calls.push(transferCall);
257
- txHash = (await getAction(this.client, sendCalls, 'sendCalls')({
258
- account: this.client.account,
259
- calls,
260
- }));
261
- }
262
- else {
263
- let permitSignature;
264
- if (permitSupported) {
265
- permitSignature = await signPermitMessage(this.client, {
266
- transactionRequest,
267
- chain: fromChain,
268
- tokenAddress: step.action.fromToken.address,
269
- amount: BigInt(step.action.fromAmount),
270
- nativePermit,
271
- permitData: isPermitStep ? step.permitData : undefined,
272
- useWitness: isPermitStep,
273
- });
274
- transactionRequest.to = fromChain.permit2Proxy;
275
- }
276
- if (isPermitStep && permitSignature) {
277
- const relayedTransaction = await relayTransaction({
278
- tokenOwner: this.client.account.address,
279
- chainId: fromChain.id,
280
- permit: step.permit,
281
- witness: step.witness,
282
- signedPermitData: permitSignature.signature,
283
- callData: transactionRequest.data,
284
- });
285
- txHash = relayedTransaction.data.taskId;
286
- isTransactionRelayed = true;
287
- }
288
- else {
289
- if (permitSignature) {
290
- // If we have a permit signature, we need to use updated data
291
- transactionRequest.data = permitSignature.data;
292
- try {
293
- // Try to re-estimate the gas due to additional Permit data
294
- const estimatedGas = await estimateGas(this.client, {
295
- account: this.client.account,
296
- to: transactionRequest.to,
297
- data: transactionRequest.data,
298
- value: transactionRequest.value,
299
- });
300
- transactionRequest.gas =
301
- transactionRequest.gas &&
302
- transactionRequest.gas > estimatedGas
303
- ? transactionRequest.gas
304
- : estimatedGas;
305
- }
306
- catch {
307
- // Let the wallet estimate the gas in case of failure
308
- transactionRequest.gas = undefined;
309
- }
310
- }
311
- process = this.statusManager.updateProcess(step, process.type, 'ACTION_REQUIRED');
312
- txHash = await getAction(this.client, sendTransaction, 'sendTransaction')({
313
- to: transactionRequest.to,
314
- account: this.client.account,
315
- data: transactionRequest.data,
316
- value: transactionRequest.value,
317
- gas: transactionRequest.gas,
318
- gasPrice: transactionRequest.gasPrice,
319
- maxFeePerGas: transactionRequest.maxFeePerGas,
320
- maxPriorityFeePerGas: transactionRequest.maxPriorityFeePerGas,
321
- });
322
- }
323
- }
324
- process = this.statusManager.updateProcess(step, process.type, 'PENDING',
325
- // When atomic batch is supported, txHash represents the batch hash rather than an individual transaction hash at this point
326
- atomicBatchSupported
327
- ? {
328
- atomicBatchSupported,
329
- }
330
- : isTransactionRelayed
331
- ? undefined
332
- : {
333
- txHash: txHash,
334
- txLink: `${fromChain.metamask.blockExplorerUrls[0]}tx/${txHash}`,
335
- });
336
252
  }
337
- let transactionReceipt;
338
- if (atomicBatchSupported) {
339
- transactionReceipt = await waitForBatchTransactionReceipt(this.client, txHash);
253
+ else {
254
+ updatedStep = await getStepTransaction(stepBase);
340
255
  }
341
- else if (isPermitStep) {
342
- transactionReceipt = await waitForRelayedTransactionReceipt(txHash);
256
+ const comparedStep = await stepComparison(this.statusManager, step, updatedStep, this.allowUserInteraction, this.executionOptions);
257
+ Object.assign(step, {
258
+ ...comparedStep,
259
+ execution: step.execution,
260
+ });
261
+ }
262
+ if (!step.transactionRequest) {
263
+ throw new TransactionError(LiFiErrorCode.TransactionUnprepared, 'Unable to prepare transaction.');
264
+ }
265
+ let transactionRequest = {
266
+ to: step.transactionRequest.to,
267
+ from: step.transactionRequest.from,
268
+ data: step.transactionRequest.data,
269
+ value: step.transactionRequest.value
270
+ ? BigInt(step.transactionRequest.value)
271
+ : undefined,
272
+ gas: step.transactionRequest.gasLimit
273
+ ? BigInt(step.transactionRequest.gasLimit)
274
+ : undefined,
275
+ // gasPrice: step.transactionRequest.gasPrice
276
+ // ? BigInt(step.transactionRequest.gasPrice as string)
277
+ // : undefined,
278
+ // maxFeePerGas: step.transactionRequest.maxFeePerGas
279
+ // ? BigInt(step.transactionRequest.maxFeePerGas as string)
280
+ // : undefined,
281
+ maxPriorityFeePerGas: this.client.account?.type === 'local'
282
+ ? await getMaxPriorityFeePerGas(this.client)
283
+ : step.transactionRequest.maxPriorityFeePerGas
284
+ ? BigInt(step.transactionRequest.maxPriorityFeePerGas)
285
+ : undefined,
286
+ };
287
+ if (this.executionOptions?.updateTransactionRequestHook) {
288
+ const customizedTransactionRequest = await this.executionOptions.updateTransactionRequestHook({
289
+ requestType: 'transaction',
290
+ ...transactionRequest,
291
+ });
292
+ transactionRequest = {
293
+ ...transactionRequest,
294
+ ...customizedTransactionRequest,
295
+ };
296
+ }
297
+ // Make sure that the chain is still correct
298
+ const updatedClient = await this.checkClient(step, process);
299
+ if (!updatedClient) {
300
+ return step;
301
+ }
302
+ process = this.statusManager.updateProcess(step, process.type, 'ACTION_REQUIRED');
303
+ if (!this.allowUserInteraction) {
304
+ return step;
305
+ }
306
+ let txHash;
307
+ let isTransactionRelayed = false;
308
+ if (atomicBatchSupported) {
309
+ const transferCall = {
310
+ chainId: fromChain.id,
311
+ data: transactionRequest.data,
312
+ to: transactionRequest.to,
313
+ value: transactionRequest.value,
314
+ };
315
+ calls.push(transferCall);
316
+ txHash = (await getAction(this.client, sendCalls, 'sendCalls')({
317
+ account: this.client.account,
318
+ calls,
319
+ }));
320
+ }
321
+ else {
322
+ let permitSignature;
323
+ if (permitSupported) {
324
+ permitSignature = await signPermitMessage(this.client, {
325
+ transactionRequest,
326
+ chain: fromChain,
327
+ tokenAddress: step.action.fromToken.address,
328
+ amount: BigInt(step.action.fromAmount),
329
+ nativePermit,
330
+ permitData: isRelayerTransaction ? step.permitData : undefined,
331
+ useWitness: isRelayerTransaction,
332
+ });
333
+ transactionRequest.to = fromChain.permit2Proxy;
334
+ this.statusManager.updateProcess(step, process.type, 'DONE');
343
335
  }
344
- else {
345
- transactionReceipt = await waitForTransactionReceipt({
346
- client: this.client,
336
+ if (isRelayerTransaction && permitSignature) {
337
+ process = this.statusManager.findOrCreateProcess({
338
+ step,
339
+ type: currentProcessType,
340
+ status: 'PENDING',
341
+ });
342
+ const relayedTransaction = await relayTransaction({
343
+ tokenOwner: this.client.account.address,
347
344
  chainId: fromChain.id,
348
- txHash,
349
- onReplaced: (response) => {
350
- this.statusManager.updateProcess(step, process.type, 'PENDING', {
351
- txHash: response.transaction.hash,
352
- txLink: `${fromChain.metamask.blockExplorerUrls[0]}tx/${response.transaction.hash}`,
353
- });
354
- },
345
+ permit: step.permit,
346
+ witness: step.witness,
347
+ signedPermitData: permitSignature.signature,
348
+ callData: transactionRequest.data,
355
349
  });
350
+ txHash = relayedTransaction.data.taskId;
351
+ isTransactionRelayed = true;
356
352
  }
357
- // Update pending process if the transaction hash from the receipt is different.
358
- // This might happen if the transaction was replaced.
359
- if (transactionReceipt?.transactionHash &&
360
- transactionReceipt.transactionHash !== txHash) {
361
- process = this.statusManager.updateProcess(step, process.type, 'PENDING', {
362
- txHash: transactionReceipt.transactionHash,
363
- txLink: `${fromChain.metamask.blockExplorerUrls[0]}tx/${transactionReceipt.transactionHash}`,
353
+ else {
354
+ process = this.statusManager.findOrCreateProcess({
355
+ step,
356
+ type: currentProcessType,
357
+ status: 'STARTED',
358
+ });
359
+ if (permitSignature) {
360
+ // If we have a permit signature, we need to use updated data
361
+ transactionRequest.data = permitSignature.data;
362
+ try {
363
+ // Try to re-estimate the gas due to additional Permit data
364
+ const estimatedGas = await estimateGas(this.client, {
365
+ account: this.client.account,
366
+ to: transactionRequest.to,
367
+ data: transactionRequest.data,
368
+ value: transactionRequest.value,
369
+ });
370
+ transactionRequest.gas =
371
+ transactionRequest.gas && transactionRequest.gas > estimatedGas
372
+ ? transactionRequest.gas
373
+ : estimatedGas;
374
+ }
375
+ catch {
376
+ // Let the wallet estimate the gas in case of failure
377
+ transactionRequest.gas = undefined;
378
+ }
379
+ }
380
+ process = this.statusManager.updateProcess(step, process.type, 'ACTION_REQUIRED');
381
+ txHash = await getAction(this.client, sendTransaction, 'sendTransaction')({
382
+ to: transactionRequest.to,
383
+ account: this.client.account,
384
+ data: transactionRequest.data,
385
+ value: transactionRequest.value,
386
+ gas: transactionRequest.gas,
387
+ gasPrice: transactionRequest.gasPrice,
388
+ maxFeePerGas: transactionRequest.maxFeePerGas,
389
+ maxPriorityFeePerGas: transactionRequest.maxPriorityFeePerGas,
364
390
  });
365
- }
366
- if (isBridgeExecution) {
367
- process = this.statusManager.updateProcess(step, process.type, 'DONE');
368
391
  }
369
392
  }
370
- catch (e) {
371
- const error = await parseEVMErrors(e, step, process);
372
- process = this.statusManager.updateProcess(step, process.type, 'FAILED', {
373
- error: {
374
- message: error.cause.message,
375
- code: error.code,
376
- },
377
- });
378
- this.statusManager.updateExecution(step, 'FAILED');
379
- throw error;
380
- }
381
- }
382
- // Wait for the transaction status on the destination chain
383
- const transactionHash = process.txHash;
384
- if (!transactionHash) {
385
- throw new Error('Transaction hash is undefined.');
386
- }
387
- if (isBridgeExecution) {
388
- process = this.statusManager.findOrCreateProcess({
393
+ process = this.statusManager.updateProcess(step, process.type, 'PENDING',
394
+ // When atomic batch is supported, txHash represents the batch hash rather than an individual transaction hash at this point
395
+ atomicBatchSupported
396
+ ? {
397
+ atomicBatchSupported,
398
+ }
399
+ : isTransactionRelayed
400
+ ? undefined
401
+ : {
402
+ txHash: txHash,
403
+ txLink: `${fromChain.metamask.blockExplorerUrls[0]}tx/${txHash}`,
404
+ });
405
+ await this.waitForTransaction({
389
406
  step,
390
- type: 'RECEIVING_CHAIN',
391
- status: 'PENDING',
392
- chainId: toChain.id,
407
+ process,
408
+ fromChain,
409
+ toChain,
410
+ atomicBatchSupported,
411
+ isRelayerTransaction,
412
+ txHash,
413
+ isBridgeExecution,
393
414
  });
415
+ // DONE
416
+ return step;
417
+ }
418
+ catch (e) {
419
+ const error = await parseEVMErrors(e, step, process);
420
+ process = this.statusManager.updateProcess(step, process?.type || currentProcessType, 'FAILED', {
421
+ error: {
422
+ message: error.cause.message,
423
+ code: error.code,
424
+ },
425
+ });
426
+ this.statusManager.updateExecution(step, 'FAILED');
427
+ throw error;
394
428
  }
395
- await waitForDestinationChainTransaction(step, process.type, transactionHash, toChain, this.statusManager);
396
- // DONE
397
- return step;
398
429
  }
399
430
  });
400
431
  this.client = options.client;