@lifi/sdk 3.6.1 → 3.6.2

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