@aztec/ethereum 0.74.0 → 0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2

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 (81) hide show
  1. package/dest/chain.js +17 -18
  2. package/dest/client.js +5 -9
  3. package/dest/config.js +13 -14
  4. package/dest/constants.js +0 -1
  5. package/dest/contracts/empire_base.js +3 -2
  6. package/dest/contracts/forwarder.js +46 -26
  7. package/dest/contracts/governance.js +11 -6
  8. package/dest/contracts/governance_proposer.js +78 -67
  9. package/dest/contracts/index.js +0 -1
  10. package/dest/contracts/rollup.js +270 -243
  11. package/dest/contracts/slashing_proposer.js +18 -8
  12. package/dest/deploy_l1_contracts.js +201 -126
  13. package/dest/eth_cheat_codes.js +144 -127
  14. package/dest/index.js +0 -1
  15. package/dest/l1_contract_addresses.js +17 -19
  16. package/dest/l1_reader.js +6 -7
  17. package/dest/l1_tx_utils.js +227 -186
  18. package/dest/l1_tx_utils_with_blobs.js +25 -22
  19. package/dest/queries.js +6 -9
  20. package/dest/test/delayed_tx_utils.js +3 -3
  21. package/dest/test/eth_cheat_codes_with_state.js +10 -12
  22. package/dest/test/index.js +0 -1
  23. package/dest/test/start_anvil.js +17 -9
  24. package/dest/test/tx_delayer.js +77 -74
  25. package/dest/types.js +1 -2
  26. package/dest/utils.js +35 -36
  27. package/package.json +5 -4
  28. package/src/contracts/rollup.ts +1 -1
  29. package/src/l1_tx_utils_with_blobs.ts +1 -1
  30. package/dest/chain.d.ts +0 -25
  31. package/dest/chain.d.ts.map +0 -1
  32. package/dest/client.d.ts +0 -16
  33. package/dest/client.d.ts.map +0 -1
  34. package/dest/config.d.ts +0 -38
  35. package/dest/config.d.ts.map +0 -1
  36. package/dest/constants.d.ts +0 -4
  37. package/dest/constants.d.ts.map +0 -1
  38. package/dest/contracts/empire_base.d.ts +0 -13
  39. package/dest/contracts/empire_base.d.ts.map +0 -1
  40. package/dest/contracts/forwarder.d.ts +0 -24
  41. package/dest/contracts/forwarder.d.ts.map +0 -1
  42. package/dest/contracts/governance.d.ts +0 -14
  43. package/dest/contracts/governance.d.ts.map +0 -1
  44. package/dest/contracts/governance_proposer.d.ts +0 -28
  45. package/dest/contracts/governance_proposer.d.ts.map +0 -1
  46. package/dest/contracts/index.d.ts +0 -7
  47. package/dest/contracts/index.d.ts.map +0 -1
  48. package/dest/contracts/rollup.d.ts +0 -115
  49. package/dest/contracts/rollup.d.ts.map +0 -1
  50. package/dest/contracts/slashing_proposer.d.ts +0 -21
  51. package/dest/contracts/slashing_proposer.d.ts.map +0 -1
  52. package/dest/deploy_l1_contracts.d.ts +0 -21118
  53. package/dest/deploy_l1_contracts.d.ts.map +0 -1
  54. package/dest/eth_cheat_codes.d.ts +0 -146
  55. package/dest/eth_cheat_codes.d.ts.map +0 -1
  56. package/dest/index.d.ts +0 -15
  57. package/dest/index.d.ts.map +0 -1
  58. package/dest/l1_contract_addresses.d.ts +0 -55
  59. package/dest/l1_contract_addresses.d.ts.map +0 -1
  60. package/dest/l1_reader.d.ts +0 -16
  61. package/dest/l1_reader.d.ts.map +0 -1
  62. package/dest/l1_tx_utils.d.ts +0 -194
  63. package/dest/l1_tx_utils.d.ts.map +0 -1
  64. package/dest/l1_tx_utils_with_blobs.d.ts +0 -12
  65. package/dest/l1_tx_utils_with_blobs.d.ts.map +0 -1
  66. package/dest/queries.d.ts +0 -15
  67. package/dest/queries.d.ts.map +0 -1
  68. package/dest/test/delayed_tx_utils.d.ts +0 -8
  69. package/dest/test/delayed_tx_utils.d.ts.map +0 -1
  70. package/dest/test/eth_cheat_codes_with_state.d.ts +0 -18
  71. package/dest/test/eth_cheat_codes_with_state.d.ts.map +0 -1
  72. package/dest/test/index.d.ts +0 -5
  73. package/dest/test/index.d.ts.map +0 -1
  74. package/dest/test/start_anvil.d.ts +0 -9
  75. package/dest/test/start_anvil.d.ts.map +0 -1
  76. package/dest/test/tx_delayer.d.ts +0 -24
  77. package/dest/test/tx_delayer.d.ts.map +0 -1
  78. package/dest/types.d.ts +0 -12
  79. package/dest/types.d.ts.map +0 -1
  80. package/dest/utils.d.ts +0 -24
  81. package/dest/utils.d.ts.map +0 -1
@@ -1,15 +1,15 @@
1
1
  import { compactArray, times } from '@aztec/foundation/collection';
2
- import { bigintConfigHelper, getDefaultConfig, numberConfigHelper, } from '@aztec/foundation/config';
2
+ import { bigintConfigHelper, getDefaultConfig, numberConfigHelper } from '@aztec/foundation/config';
3
3
  import { makeBackoff, retry } from '@aztec/foundation/retry';
4
4
  import { sleep } from '@aztec/foundation/sleep';
5
- import { MethodNotFoundRpcError, MethodNotSupportedRpcError, formatGwei, getContractError, hexToBytes, } from 'viem';
5
+ import { MethodNotFoundRpcError, MethodNotSupportedRpcError, formatGwei, getContractError, hexToBytes } from 'viem';
6
6
  import { formatViemError } from './utils.js';
7
7
  // 1_000_000_000 Gwei = 1 ETH
8
8
  // 1_000_000_000 Wei = 1 Gwei
9
9
  // 1_000_000_000_000_000_000 Wei = 1 ETH
10
- const WEI_CONST = 1000000000n;
10
+ const WEI_CONST = 1_000_000_000n;
11
11
  // @note using this large gas limit to avoid the issue of `gas limit too low` when estimating gas in reth
12
- const LARGE_GAS_LIMIT = 10000000n;
12
+ const LARGE_GAS_LIMIT = 10_000_000n;
13
13
  // setting a minimum bump percentage to 10% due to geth's implementation
14
14
  // https://github.com/ethereum/go-ethereum/blob/e3d61e6db028c412f74bc4d4c7e117a9e29d0de0/core/txpool/legacypool/list.go#L298
15
15
  const MIN_REPLACEMENT_BUMP_PERCENTAGE = 10;
@@ -17,79 +17,84 @@ const MIN_REPLACEMENT_BUMP_PERCENTAGE = 10;
17
17
  // https://github.com/ethereum/go-ethereum/blob/e3d61e6db028c412f74bc4d4c7e117a9e29d0de0/core/txpool/blobpool/config.go#L34
18
18
  const MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE = 100;
19
19
  // Avg ethereum block time is ~12s
20
- const BLOCK_TIME_MS = 12000;
20
+ const BLOCK_TIME_MS = 12_000;
21
21
  export const l1TxUtilsConfigMappings = {
22
22
  gasLimitBufferPercentage: {
23
23
  description: 'How much to increase calculated gas limit by (percentage)',
24
24
  env: 'L1_GAS_LIMIT_BUFFER_PERCENTAGE',
25
- ...numberConfigHelper(20),
25
+ ...numberConfigHelper(20)
26
26
  },
27
27
  minGwei: {
28
28
  description: 'Minimum gas price in gwei',
29
29
  env: 'L1_GAS_PRICE_MIN',
30
- ...bigintConfigHelper(1n),
30
+ ...bigintConfigHelper(1n)
31
31
  },
32
32
  maxGwei: {
33
33
  description: 'Maximum gas price in gwei',
34
34
  env: 'L1_GAS_PRICE_MAX',
35
- ...bigintConfigHelper(100n),
35
+ ...bigintConfigHelper(100n)
36
36
  },
37
37
  maxBlobGwei: {
38
38
  description: 'Maximum blob fee per gas in gwei',
39
39
  env: 'L1_BLOB_FEE_PER_GAS_MAX',
40
- ...bigintConfigHelper(1500n),
40
+ ...bigintConfigHelper(1_500n)
41
41
  },
42
42
  priorityFeeBumpPercentage: {
43
43
  description: 'How much to increase priority fee by each attempt (percentage)',
44
44
  env: 'L1_PRIORITY_FEE_BUMP_PERCENTAGE',
45
- ...numberConfigHelper(20),
45
+ ...numberConfigHelper(20)
46
46
  },
47
47
  priorityFeeRetryBumpPercentage: {
48
48
  description: 'How much to increase priority fee by each retry attempt (percentage)',
49
49
  env: 'L1_PRIORITY_FEE_RETRY_BUMP_PERCENTAGE',
50
- ...numberConfigHelper(50),
50
+ ...numberConfigHelper(50)
51
51
  },
52
52
  fixedPriorityFeePerGas: {
53
53
  description: 'Fixed priority fee per gas in Gwei. Overrides any priority fee bump percentage',
54
54
  env: 'L1_FIXED_PRIORITY_FEE_PER_GAS',
55
- ...numberConfigHelper(0),
55
+ ...numberConfigHelper(0)
56
56
  },
57
57
  maxAttempts: {
58
58
  description: 'Maximum number of speed-up attempts',
59
59
  env: 'L1_TX_MONITOR_MAX_ATTEMPTS',
60
- ...numberConfigHelper(3),
60
+ ...numberConfigHelper(3)
61
61
  },
62
62
  checkIntervalMs: {
63
63
  description: 'How often to check tx status',
64
64
  env: 'L1_TX_MONITOR_CHECK_INTERVAL_MS',
65
- ...numberConfigHelper(10000),
65
+ ...numberConfigHelper(10_000)
66
66
  },
67
67
  stallTimeMs: {
68
68
  description: 'How long before considering tx stalled',
69
69
  env: 'L1_TX_MONITOR_STALL_TIME_MS',
70
- ...numberConfigHelper(45000),
70
+ ...numberConfigHelper(45_000)
71
71
  },
72
72
  txTimeoutMs: {
73
73
  description: 'How long to wait for a tx to be mined before giving up. Set to 0 to disable.',
74
74
  env: 'L1_TX_MONITOR_TX_TIMEOUT_MS',
75
- ...numberConfigHelper(300000), // 5 mins
75
+ ...numberConfigHelper(300_000)
76
76
  },
77
77
  txPropagationMaxQueryAttempts: {
78
78
  description: 'How many attempts will be done to get a tx after it was sent',
79
79
  env: 'L1_TX_PROPAGATION_MAX_QUERY_ATTEMPTS',
80
- ...numberConfigHelper(3),
81
- },
80
+ ...numberConfigHelper(3)
81
+ }
82
82
  };
83
83
  export const defaultL1TxUtilsConfig = getDefaultConfig(l1TxUtilsConfigMappings);
84
84
  export class L1TxUtils {
85
- constructor(publicClient, walletClient, logger, config) {
85
+ publicClient;
86
+ walletClient;
87
+ logger;
88
+ config;
89
+ interrupted;
90
+ constructor(publicClient, walletClient, logger, config){
86
91
  this.publicClient = publicClient;
87
92
  this.walletClient = walletClient;
88
93
  this.logger = logger;
89
94
  this.interrupted = false;
90
95
  this.config = {
91
96
  ...defaultL1TxUtilsConfig,
92
- ...(config || {}),
97
+ ...config || {}
93
98
  };
94
99
  }
95
100
  interrupt() {
@@ -108,20 +113,21 @@ export class L1TxUtils {
108
113
  return this.publicClient.getBlockNumber();
109
114
  }
110
115
  /**
111
- * Sends a transaction with gas estimation and pricing
112
- * @param request - The transaction request (to, data, value)
113
- * @param gasConfig - Optional gas configuration
114
- * @returns The transaction hash and parameters used
115
- */
116
- async sendTransaction(request, _gasConfig, blobInputs) {
116
+ * Sends a transaction with gas estimation and pricing
117
+ * @param request - The transaction request (to, data, value)
118
+ * @param gasConfig - Optional gas configuration
119
+ * @returns The transaction hash and parameters used
120
+ */ async sendTransaction(request, _gasConfig, blobInputs) {
117
121
  try {
118
- const gasConfig = { ...this.config, ..._gasConfig };
122
+ const gasConfig = {
123
+ ...this.config,
124
+ ..._gasConfig
125
+ };
119
126
  const account = this.walletClient.account;
120
127
  let gasLimit;
121
128
  if (gasConfig.gasLimit) {
122
129
  gasLimit = gasConfig.gasLimit;
123
- }
124
- else {
130
+ } else {
125
131
  gasLimit = await this.estimateGas(account, request);
126
132
  }
127
133
  const gasPrice = await this.getGasPrice(gasConfig, !!blobInputs);
@@ -136,46 +142,56 @@ export class L1TxUtils {
136
142
  gas: gasLimit,
137
143
  maxFeePerGas: gasPrice.maxFeePerGas,
138
144
  maxPriorityFeePerGas: gasPrice.maxPriorityFeePerGas,
139
- maxFeePerBlobGas: gasPrice.maxFeePerBlobGas,
145
+ maxFeePerBlobGas: gasPrice.maxFeePerBlobGas
140
146
  });
141
- }
142
- else {
147
+ } else {
143
148
  txHash = await this.walletClient.sendTransaction({
144
149
  ...request,
145
150
  gas: gasLimit,
146
151
  maxFeePerGas: gasPrice.maxFeePerGas,
147
- maxPriorityFeePerGas: gasPrice.maxPriorityFeePerGas,
152
+ maxPriorityFeePerGas: gasPrice.maxPriorityFeePerGas
148
153
  });
149
154
  }
150
155
  this.logger?.verbose(`Sent L1 transaction ${txHash}`, {
151
156
  gasLimit,
152
157
  maxFeePerGas: formatGwei(gasPrice.maxFeePerGas),
153
158
  maxPriorityFeePerGas: formatGwei(gasPrice.maxPriorityFeePerGas),
154
- ...(gasPrice.maxFeePerBlobGas && { maxFeePerBlobGas: formatGwei(gasPrice.maxFeePerBlobGas) }),
159
+ ...gasPrice.maxFeePerBlobGas && {
160
+ maxFeePerBlobGas: formatGwei(gasPrice.maxFeePerBlobGas)
161
+ }
155
162
  });
156
- return { txHash, gasLimit, gasPrice };
157
- }
158
- catch (err) {
163
+ return {
164
+ txHash,
165
+ gasLimit,
166
+ gasPrice
167
+ };
168
+ } catch (err) {
159
169
  const viemError = formatViemError(err);
160
- this.logger?.error(`Failed to send L1 transaction`, viemError.message, { metaMessages: viemError.metaMessages });
170
+ this.logger?.error(`Failed to send L1 transaction`, viemError.message, {
171
+ metaMessages: viemError.metaMessages
172
+ });
161
173
  throw viemError;
162
174
  }
163
175
  }
164
176
  /**
165
- * Monitors a transaction until completion, handling speed-ups if needed
166
- * @param request - Original transaction request (needed for speed-ups)
167
- * @param initialTxHash - Hash of the initial transaction
168
- * @param params - Parameters used in the initial transaction
169
- * @param gasConfig - Optional gas configuration
170
- */
171
- async monitorTransaction(request, initialTxHash, params, _gasConfig, _blobInputs, isCancelTx = false) {
177
+ * Monitors a transaction until completion, handling speed-ups if needed
178
+ * @param request - Original transaction request (needed for speed-ups)
179
+ * @param initialTxHash - Hash of the initial transaction
180
+ * @param params - Parameters used in the initial transaction
181
+ * @param gasConfig - Optional gas configuration
182
+ */ async monitorTransaction(request, initialTxHash, params, _gasConfig, _blobInputs, isCancelTx = false) {
172
183
  const isBlobTx = !!_blobInputs;
173
- const gasConfig = { ...this.config, ..._gasConfig };
184
+ const gasConfig = {
185
+ ...this.config,
186
+ ..._gasConfig
187
+ };
174
188
  const account = this.walletClient.account;
175
189
  const blobInputs = _blobInputs || {};
176
- const makeGetTransactionBackoff = () => makeBackoff(times(gasConfig.txPropagationMaxQueryAttempts ?? 3, i => i + 1));
190
+ const makeGetTransactionBackoff = ()=>makeBackoff(times(gasConfig.txPropagationMaxQueryAttempts ?? 3, (i)=>i + 1));
177
191
  // Retry a few times, in case the tx is not yet propagated.
178
- const tx = await retry(() => this.publicClient.getTransaction({ hash: initialTxHash }), `Getting L1 transaction ${initialTxHash}`, makeGetTransactionBackoff(), this.logger, true);
192
+ const tx = await retry(()=>this.publicClient.getTransaction({
193
+ hash: initialTxHash
194
+ }), `Getting L1 transaction ${initialTxHash}`, makeGetTransactionBackoff(), this.logger, true);
179
195
  if (!tx) {
180
196
  throw new Error(`Failed to get L1 transaction ${initialTxHash} to monitor`);
181
197
  }
@@ -183,39 +199,40 @@ export class L1TxUtils {
183
199
  throw new Error(`Failed to get L1 transaction ${initialTxHash} nonce`);
184
200
  }
185
201
  const nonce = tx.nonce;
186
- const txHashes = new Set([initialTxHash]);
202
+ const txHashes = new Set([
203
+ initialTxHash
204
+ ]);
187
205
  let currentTxHash = initialTxHash;
188
206
  let attempts = 0;
189
207
  let lastAttemptSent = Date.now();
190
208
  let lastGasPrice = {
191
209
  maxFeePerGas: tx.maxFeePerGas,
192
210
  maxPriorityFeePerGas: tx.maxPriorityFeePerGas,
193
- maxFeePerBlobGas: tx.maxFeePerBlobGas,
211
+ maxFeePerBlobGas: tx.maxFeePerBlobGas
194
212
  };
195
213
  const initialTxTime = lastAttemptSent;
196
214
  let txTimedOut = false;
197
- const isTimedOut = () => (gasConfig.txTimeoutAt && Date.now() > gasConfig.txTimeoutAt.getTime()) ||
198
- (gasConfig.txTimeoutMs !== undefined && Date.now() - initialTxTime > gasConfig.txTimeoutMs) ||
199
- this.interrupted ||
200
- false;
201
- while (!txTimedOut) {
215
+ const isTimedOut = ()=>gasConfig.txTimeoutAt && Date.now() > gasConfig.txTimeoutAt.getTime() || gasConfig.txTimeoutMs !== undefined && Date.now() - initialTxTime > gasConfig.txTimeoutMs || this.interrupted || false;
216
+ while(!txTimedOut){
202
217
  try {
203
- const currentNonce = await this.publicClient.getTransactionCount({ address: account.address });
218
+ const currentNonce = await this.publicClient.getTransactionCount({
219
+ address: account.address
220
+ });
204
221
  if (currentNonce > nonce) {
205
- for (const hash of txHashes) {
222
+ for (const hash of txHashes){
206
223
  try {
207
- const receipt = await this.publicClient.getTransactionReceipt({ hash });
224
+ const receipt = await this.publicClient.getTransactionReceipt({
225
+ hash
226
+ });
208
227
  if (receipt) {
209
228
  if (receipt.status === 'reverted') {
210
229
  this.logger?.error(`L1 transaction ${hash} reverted`, receipt);
211
- }
212
- else {
230
+ } else {
213
231
  this.logger?.debug(`L1 transaction ${hash} mined`);
214
232
  }
215
233
  return receipt;
216
234
  }
217
- }
218
- catch (err) {
235
+ } catch (err) {
219
236
  if (err instanceof Error && err.message.includes('reverted')) {
220
237
  throw formatViemError(err);
221
238
  }
@@ -223,7 +240,9 @@ export class L1TxUtils {
223
240
  }
224
241
  }
225
242
  // Retry a few times, in case the tx is not yet propagated.
226
- const tx = await retry(() => this.publicClient.getTransaction({ hash: currentTxHash }), `Getting L1 transaction ${currentTxHash}`, makeGetTransactionBackoff(), this.logger, true);
243
+ const tx = await retry(()=>this.publicClient.getTransaction({
244
+ hash: currentTxHash
245
+ }), `Getting L1 transaction ${currentTxHash}`, makeGetTransactionBackoff(), this.logger, true);
227
246
  const timePassed = Date.now() - lastAttemptSent;
228
247
  if (tx && timePassed < gasConfig.stallTimeMs) {
229
248
  this.logger?.debug(`L1 transaction ${currentTxHash} pending. Time passed: ${timePassed}ms.`);
@@ -237,19 +256,18 @@ export class L1TxUtils {
237
256
  }
238
257
  if (timePassed > gasConfig.stallTimeMs && attempts < gasConfig.maxAttempts) {
239
258
  attempts++;
240
- const newGasPrice = await this.getGasPrice(gasConfig, isBlobTx, attempts, tx.maxFeePerGas && tx.maxPriorityFeePerGas
241
- ? {
242
- maxFeePerGas: tx.maxFeePerGas,
243
- maxPriorityFeePerGas: tx.maxPriorityFeePerGas,
244
- maxFeePerBlobGas: tx.maxFeePerBlobGas,
245
- }
246
- : undefined);
259
+ const newGasPrice = await this.getGasPrice(gasConfig, isBlobTx, attempts, tx.maxFeePerGas && tx.maxPriorityFeePerGas ? {
260
+ maxFeePerGas: tx.maxFeePerGas,
261
+ maxPriorityFeePerGas: tx.maxPriorityFeePerGas,
262
+ maxFeePerBlobGas: tx.maxFeePerBlobGas
263
+ } : undefined);
247
264
  lastGasPrice = newGasPrice;
248
- this.logger?.debug(`L1 transaction ${currentTxHash} appears stuck. Attempting speed-up ${attempts}/${gasConfig.maxAttempts} ` +
249
- `with new priority fee ${formatGwei(newGasPrice.maxPriorityFeePerGas)} gwei`, {
265
+ this.logger?.debug(`L1 transaction ${currentTxHash} appears stuck. Attempting speed-up ${attempts}/${gasConfig.maxAttempts} ` + `with new priority fee ${formatGwei(newGasPrice.maxPriorityFeePerGas)} gwei`, {
250
266
  maxFeePerGas: formatGwei(newGasPrice.maxFeePerGas),
251
267
  maxPriorityFeePerGas: formatGwei(newGasPrice.maxPriorityFeePerGas),
252
- ...(newGasPrice.maxFeePerBlobGas && { maxFeePerBlobGas: formatGwei(newGasPrice.maxFeePerBlobGas) }),
268
+ ...newGasPrice.maxFeePerBlobGas && {
269
+ maxFeePerBlobGas: formatGwei(newGasPrice.maxFeePerBlobGas)
270
+ }
253
271
  });
254
272
  currentTxHash = await this.walletClient.sendTransaction({
255
273
  ...request,
@@ -257,14 +275,13 @@ export class L1TxUtils {
257
275
  nonce,
258
276
  gas: params.gasLimit,
259
277
  maxFeePerGas: newGasPrice.maxFeePerGas,
260
- maxPriorityFeePerGas: newGasPrice.maxPriorityFeePerGas,
278
+ maxPriorityFeePerGas: newGasPrice.maxPriorityFeePerGas
261
279
  });
262
280
  txHashes.add(currentTxHash);
263
281
  lastAttemptSent = Date.now();
264
282
  }
265
283
  await sleep(gasConfig.checkIntervalMs);
266
- }
267
- catch (err) {
284
+ } catch (err) {
268
285
  const viemError = formatViemError(err);
269
286
  this.logger?.warn(`Error monitoring L1 transaction ${currentTxHash}:`, viemError.message);
270
287
  if (viemError.message?.includes('reverted')) {
@@ -277,60 +294,68 @@ export class L1TxUtils {
277
294
  }
278
295
  if (!isCancelTx) {
279
296
  // Fire cancellation without awaiting to avoid blocking the main thread
280
- this.attemptTxCancellation(nonce, isBlobTx, lastGasPrice, attempts)
281
- .then(cancelTxHash => {
297
+ this.attemptTxCancellation(nonce, isBlobTx, lastGasPrice, attempts).then((cancelTxHash)=>{
282
298
  this.logger?.debug(`Sent cancellation tx ${cancelTxHash} for timed out tx ${currentTxHash}`);
283
- })
284
- .catch(err => {
299
+ }).catch((err)=>{
285
300
  const viemError = formatViemError(err);
286
301
  this.logger?.error(`Failed to send cancellation for timed out tx ${currentTxHash}:`, viemError.message, {
287
- metaMessages: viemError.metaMessages,
302
+ metaMessages: viemError.metaMessages
288
303
  });
289
304
  });
290
305
  this.logger?.error(`L1 transaction ${currentTxHash} timed out`, {
291
306
  txHash: currentTxHash,
292
- ...tx,
307
+ ...tx
293
308
  });
294
309
  }
295
310
  throw new Error(`L1 transaction ${currentTxHash} timed out`);
296
311
  }
297
312
  /**
298
- * Sends a transaction and monitors it until completion
299
- * @param request - The transaction request (to, data, value)
300
- * @param gasConfig - Optional gas configuration
301
- * @returns The receipt of the successful transaction
302
- */
303
- async sendAndMonitorTransaction(request, gasConfig, blobInputs) {
313
+ * Sends a transaction and monitors it until completion
314
+ * @param request - The transaction request (to, data, value)
315
+ * @param gasConfig - Optional gas configuration
316
+ * @returns The receipt of the successful transaction
317
+ */ async sendAndMonitorTransaction(request, gasConfig, blobInputs) {
304
318
  const { txHash, gasLimit, gasPrice } = await this.sendTransaction(request, gasConfig, blobInputs);
305
- const receipt = await this.monitorTransaction(request, txHash, { gasLimit }, gasConfig, blobInputs);
306
- return { receipt, gasPrice };
319
+ const receipt = await this.monitorTransaction(request, txHash, {
320
+ gasLimit
321
+ }, gasConfig, blobInputs);
322
+ return {
323
+ receipt,
324
+ gasPrice
325
+ };
307
326
  }
308
327
  /**
309
- * Gets the current gas price with bounds checking
310
- */
311
- async getGasPrice(_gasConfig, isBlobTx = false, attempt = 0, previousGasPrice) {
312
- const gasConfig = { ...this.config, ..._gasConfig };
313
- const block = await this.publicClient.getBlock({ blockTag: 'latest' });
328
+ * Gets the current gas price with bounds checking
329
+ */ async getGasPrice(_gasConfig, isBlobTx = false, attempt = 0, previousGasPrice) {
330
+ const gasConfig = {
331
+ ...this.config,
332
+ ..._gasConfig
333
+ };
334
+ const block = await this.publicClient.getBlock({
335
+ blockTag: 'latest'
336
+ });
314
337
  const baseFee = block.baseFeePerGas ?? 0n;
315
338
  // Get blob base fee if available
316
339
  let blobBaseFee = 0n;
317
340
  try {
318
- const blobBaseFeeHex = await this.publicClient.request({ method: 'eth_blobBaseFee' });
341
+ const blobBaseFeeHex = await this.publicClient.request({
342
+ method: 'eth_blobBaseFee'
343
+ });
319
344
  blobBaseFee = BigInt(blobBaseFeeHex);
320
- this.logger?.debug('L1 Blob base fee:', { blobBaseFee: formatGwei(blobBaseFee) });
321
- }
322
- catch {
345
+ this.logger?.debug('L1 Blob base fee:', {
346
+ blobBaseFee: formatGwei(blobBaseFee)
347
+ });
348
+ } catch {
323
349
  this.logger?.warn('Failed to get L1 blob base fee', attempt);
324
350
  }
325
351
  let priorityFee;
326
352
  if (gasConfig.fixedPriorityFeePerGas) {
327
353
  this.logger?.debug('Using fixed priority fee per L1 gas', {
328
- fixedPriorityFeePerGas: gasConfig.fixedPriorityFeePerGas,
354
+ fixedPriorityFeePerGas: gasConfig.fixedPriorityFeePerGas
329
355
  });
330
356
  // try to maintain precision up to 1000000 wei
331
- priorityFee = BigInt(gasConfig.fixedPriorityFeePerGas * 1000000) * (WEI_CONST / 1000000n);
332
- }
333
- else {
357
+ priorityFee = BigInt(gasConfig.fixedPriorityFeePerGas * 1_000_000) * (WEI_CONST / 1_000_000n);
358
+ } else {
334
359
  // Get initial priority fee from the network
335
360
  priorityFee = await this.publicClient.estimateMaxPriorityFeePerGas();
336
361
  }
@@ -338,11 +363,11 @@ export class L1TxUtils {
338
363
  let maxFeePerBlobGas = blobBaseFee;
339
364
  // Bump base fee so it's valid for next blocks if it stalls
340
365
  const numBlocks = Math.ceil(gasConfig.stallTimeMs / BLOCK_TIME_MS);
341
- for (let i = 0; i < numBlocks; i++) {
366
+ for(let i = 0; i < numBlocks; i++){
342
367
  // each block can go up 12.5% from previous baseFee
343
- maxFeePerGas = (maxFeePerGas * (1000n + 125n)) / 1000n;
368
+ maxFeePerGas = maxFeePerGas * (1_000n + 125n) / 1_000n;
344
369
  // same for blob gas fee
345
- maxFeePerBlobGas = (maxFeePerBlobGas * (1000n + 125n)) / 1000n;
370
+ maxFeePerBlobGas = maxFeePerBlobGas * (1_000n + 125n) / 1_000n;
346
371
  }
347
372
  if (attempt > 0) {
348
373
  const configBump = gasConfig.priorityFeeRetryBumpPercentage ?? defaultL1TxUtilsConfig.priorityFeeRetryBumpPercentage;
@@ -351,19 +376,18 @@ export class L1TxUtils {
351
376
  const bumpPercentage = configBump > minBumpPercentage ? configBump : minBumpPercentage;
352
377
  // Calculate minimum required fees based on previous attempt
353
378
  // multiply by 100 & divide by 100 to maintain some precision
354
- const minPriorityFee = (previousGasPrice.maxPriorityFeePerGas * (10000n + BigInt(bumpPercentage * 100))) / 10000n;
355
- const minMaxFee = (previousGasPrice.maxFeePerGas * (10000n + BigInt(bumpPercentage * 100))) / 10000n;
379
+ const minPriorityFee = previousGasPrice.maxPriorityFeePerGas * (100_00n + BigInt(bumpPercentage * 1_00)) / 100_00n;
380
+ const minMaxFee = previousGasPrice.maxFeePerGas * (100_00n + BigInt(bumpPercentage * 1_00)) / 100_00n;
356
381
  // Add priority fee to maxFeePerGas
357
382
  maxFeePerGas += priorityFee;
358
383
  // Use maximum between current network values and minimum required values
359
384
  priorityFee = priorityFee > minPriorityFee ? priorityFee : minPriorityFee;
360
385
  maxFeePerGas = maxFeePerGas > minMaxFee ? maxFeePerGas : minMaxFee;
361
- }
362
- else {
386
+ } else {
363
387
  // first attempt, just bump priority fee, unless it's a fixed config
364
388
  // multiply by 100 & divide by 100 to maintain some precision
365
389
  if (!gasConfig.fixedPriorityFeePerGas) {
366
- priorityFee = (priorityFee * (10000n + BigInt((gasConfig.priorityFeeBumpPercentage || 0) * 100))) / 10000n;
390
+ priorityFee = priorityFee * (100_00n + BigInt((gasConfig.priorityFeeBumpPercentage || 0) * 1_00)) / 100_00n;
367
391
  }
368
392
  maxFeePerGas += priorityFee;
369
393
  }
@@ -378,11 +402,9 @@ export class L1TxUtils {
378
402
  // Ensure priority fee doesn't exceed max fee
379
403
  const maxPriorityFeePerGas = priorityFee > maxFeePerGas ? maxFeePerGas : priorityFee;
380
404
  if (attempt > 0 && previousGasPrice?.maxFeePerBlobGas) {
381
- const bumpPercentage = gasConfig.priorityFeeRetryBumpPercentage > MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE
382
- ? gasConfig.priorityFeeRetryBumpPercentage
383
- : MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE;
405
+ const bumpPercentage = gasConfig.priorityFeeRetryBumpPercentage > MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE ? gasConfig.priorityFeeRetryBumpPercentage : MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE;
384
406
  // calculate min blob fee based on previous attempt
385
- const minBlobFee = (previousGasPrice.maxFeePerBlobGas * (10000n + BigInt(bumpPercentage * 100))) / 10000n;
407
+ const minBlobFee = previousGasPrice.maxFeePerBlobGas * (100_00n + BigInt(bumpPercentage * 1_00)) / 100_00n;
386
408
  // use max between current network values and min required values
387
409
  maxFeePerBlobGas = maxFeePerBlobGas > minBlobFee ? maxFeePerBlobGas : minBlobFee;
388
410
  }
@@ -391,19 +413,25 @@ export class L1TxUtils {
391
413
  baseFee: formatGwei(baseFee),
392
414
  maxFeePerGas: formatGwei(maxFeePerGas),
393
415
  maxPriorityFeePerGas: formatGwei(maxPriorityFeePerGas),
394
- ...(maxFeePerBlobGas && { maxFeePerBlobGas: formatGwei(maxFeePerBlobGas) }),
416
+ ...maxFeePerBlobGas && {
417
+ maxFeePerBlobGas: formatGwei(maxFeePerBlobGas)
418
+ }
395
419
  });
396
420
  return {
397
421
  maxFeePerGas,
398
422
  maxPriorityFeePerGas,
399
- ...(maxFeePerBlobGas && { maxFeePerBlobGas: maxFeePerBlobGas }),
423
+ ...maxFeePerBlobGas && {
424
+ maxFeePerBlobGas: maxFeePerBlobGas
425
+ }
400
426
  };
401
427
  }
402
428
  /**
403
- * Estimates gas and adds buffer
404
- */
405
- async estimateGas(account, request, _gasConfig, _blobInputs) {
406
- const gasConfig = { ...this.config, ..._gasConfig };
429
+ * Estimates gas and adds buffer
430
+ */ async estimateGas(account, request, _gasConfig, _blobInputs) {
431
+ const gasConfig = {
432
+ ...this.config,
433
+ ..._gasConfig
434
+ };
407
435
  let initialEstimate = 0n;
408
436
  if (_blobInputs) {
409
437
  // @note requests with blobs also require maxFeePerBlobGas to be set
@@ -413,12 +441,15 @@ export class L1TxUtils {
413
441
  ...request,
414
442
  ..._blobInputs,
415
443
  maxFeePerBlobGas: gasPrice.maxFeePerBlobGas,
416
- gas: LARGE_GAS_LIMIT,
444
+ gas: LARGE_GAS_LIMIT
417
445
  });
418
446
  this.logger?.debug(`L1 gas used in estimateGas by blob tx: ${initialEstimate}`);
419
- }
420
- else {
421
- initialEstimate = await this.publicClient.estimateGas({ account, ...request, gas: LARGE_GAS_LIMIT });
447
+ } else {
448
+ initialEstimate = await this.publicClient.estimateGas({
449
+ account,
450
+ ...request,
451
+ gas: LARGE_GAS_LIMIT
452
+ });
422
453
  this.logger?.debug(`L1 gas used in estimateGas by non-blob tx: ${initialEstimate}`);
423
454
  }
424
455
  // Add buffer based on either fixed amount or percentage
@@ -426,7 +457,9 @@ export class L1TxUtils {
426
457
  return withBuffer;
427
458
  }
428
459
  async getTransactionStats(txHash) {
429
- const tx = await this.publicClient.getTransaction({ hash: txHash });
460
+ const tx = await this.publicClient.getTransaction({
461
+ hash: txHash
462
+ });
430
463
  if (!tx) {
431
464
  return undefined;
432
465
  }
@@ -435,7 +468,7 @@ export class L1TxUtils {
435
468
  sender: tx.from.toString(),
436
469
  transactionHash: tx.hash,
437
470
  calldataSize: calldata.length,
438
- calldataGas: getCalldataGasUsage(calldata),
471
+ calldataGas: getCalldataGasUsage(calldata)
439
472
  };
440
473
  }
441
474
  async tryGetErrorFromRevertedTx(data, args, blobInputs, stateOverride = []) {
@@ -443,43 +476,42 @@ export class L1TxUtils {
443
476
  await this.publicClient.simulateContract({
444
477
  ...args,
445
478
  account: this.walletClient.account,
446
- stateOverride,
479
+ stateOverride
480
+ });
481
+ this.logger?.trace('Simulated blob tx', {
482
+ blobInputs
447
483
  });
448
- this.logger?.trace('Simulated blob tx', { blobInputs });
449
484
  // If the above passes, we have a blob error. We cannot simulate blob txs, and failed txs no longer throw errors.
450
485
  // Strangely, the only way to throw the revert reason as an error and provide blobs is prepareTransactionRequest.
451
486
  // See: https://github.com/wevm/viem/issues/2075
452
487
  // This throws a EstimateGasExecutionError with the custom error information:
453
- const request = blobInputs
454
- ? {
455
- account: this.walletClient.account,
456
- to: args.address,
457
- data,
458
- blobs: blobInputs.blobs,
459
- kzg: blobInputs.kzg,
460
- maxFeePerBlobGas: blobInputs.maxFeePerBlobGas,
461
- }
462
- : {
463
- account: this.walletClient.account,
464
- to: args.address,
465
- data,
466
- };
467
- this.logger?.trace('Preparing tx', { request });
488
+ const request = blobInputs ? {
489
+ account: this.walletClient.account,
490
+ to: args.address,
491
+ data,
492
+ blobs: blobInputs.blobs,
493
+ kzg: blobInputs.kzg,
494
+ maxFeePerBlobGas: blobInputs.maxFeePerBlobGas
495
+ } : {
496
+ account: this.walletClient.account,
497
+ to: args.address,
498
+ data
499
+ };
500
+ this.logger?.trace('Preparing tx', {
501
+ request
502
+ });
468
503
  await this.walletClient.prepareTransactionRequest(request);
469
504
  this.logger?.trace('Prepared tx');
470
505
  return undefined;
471
- }
472
- catch (simulationErr) {
506
+ } catch (simulationErr) {
473
507
  // If we don't have a ContractFunctionExecutionError, we have a blob related error => use getContractError to get the error msg.
474
- const contractErr = simulationErr.name === 'ContractFunctionExecutionError'
475
- ? simulationErr
476
- : getContractError(simulationErr, {
477
- args: [],
478
- abi: args.abi,
479
- functionName: args.functionName,
480
- address: args.address,
481
- sender: this.walletClient.account.address,
482
- });
508
+ const contractErr = simulationErr.name === 'ContractFunctionExecutionError' ? simulationErr : getContractError(simulationErr, {
509
+ args: [],
510
+ abi: args.abi,
511
+ functionName: args.functionName,
512
+ address: args.address,
513
+ sender: this.walletClient.account.address
514
+ });
483
515
  if (contractErr.name === 'ContractFunctionExecutionError') {
484
516
  const execErr = contractErr;
485
517
  return tryGetCustomErrorNameContractFunction(execErr);
@@ -488,9 +520,14 @@ export class L1TxUtils {
488
520
  }
489
521
  }
490
522
  async simulateGasUsed(request, blockOverrides = {}, stateOverrides = [], _gasConfig) {
491
- const gasConfig = { ...this.config, ..._gasConfig };
523
+ const gasConfig = {
524
+ ...this.config,
525
+ ..._gasConfig
526
+ };
492
527
  const gasPrice = await this.getGasPrice(gasConfig, false);
493
- const nonce = await this.publicClient.getTransactionCount({ address: this.walletClient.account.address });
528
+ const nonce = await this.publicClient.getTransactionCount({
529
+ address: this.walletClient.account.address
530
+ });
494
531
  try {
495
532
  const result = await this.publicClient.simulate({
496
533
  validation: true,
@@ -506,24 +543,23 @@ export class L1TxUtils {
506
543
  maxFeePerGas: gasPrice.maxFeePerGas,
507
544
  maxPriorityFeePerGas: gasPrice.maxPriorityFeePerGas,
508
545
  gas: request.gas ?? LARGE_GAS_LIMIT,
509
- nonce,
510
- },
511
- ],
512
- },
513
- ],
546
+ nonce
547
+ }
548
+ ]
549
+ }
550
+ ]
514
551
  });
515
552
  this.logger?.debug(`L1 gas used in simulation: ${result[0].calls[0].gasUsed}`, {
516
- result,
553
+ result
517
554
  });
518
555
  if (result[0].calls[0].status === 'failure') {
519
556
  this.logger?.error('L1 transaction Simulation failed', {
520
- error: result[0].calls[0].error,
557
+ error: result[0].calls[0].error
521
558
  });
522
559
  throw new Error(`L1 transaction simulation failed with error: ${result[0].calls[0].error.message}`);
523
560
  }
524
561
  return result[0].gasUsed;
525
- }
526
- catch (err) {
562
+ } catch (err) {
527
563
  if (err instanceof MethodNotFoundRpcError || err instanceof MethodNotSupportedRpcError) {
528
564
  if (gasConfig.fallbackGasEstimate) {
529
565
  this.logger?.warn(`Node does not support eth_simulateV1 API. Using fallback gas estimate: ${gasConfig.fallbackGasEstimate}`);
@@ -535,17 +571,19 @@ export class L1TxUtils {
535
571
  }
536
572
  }
537
573
  bumpGasLimit(gasLimit, _gasConfig) {
538
- const gasConfig = { ...this.config, ..._gasConfig };
539
- return gasLimit + (gasLimit * BigInt((gasConfig?.gasLimitBufferPercentage || 0) * 100)) / 10000n;
574
+ const gasConfig = {
575
+ ...this.config,
576
+ ..._gasConfig
577
+ };
578
+ return gasLimit + gasLimit * BigInt((gasConfig?.gasLimitBufferPercentage || 0) * 1_00) / 100_00n;
540
579
  }
541
580
  /**
542
- * Attempts to cancel a transaction by sending a 0-value tx to self with same nonce but higher gas prices
543
- * @param nonce - The nonce of the transaction to cancel
544
- * @param previousGasPrice - The gas price of the previous transaction
545
- * @param attempts - The number of attempts to cancel the transaction
546
- * @returns The hash of the cancellation transaction
547
- */
548
- async attemptTxCancellation(nonce, isBlobTx = false, previousGasPrice, attempts = 0) {
581
+ * Attempts to cancel a transaction by sending a 0-value tx to self with same nonce but higher gas prices
582
+ * @param nonce - The nonce of the transaction to cancel
583
+ * @param previousGasPrice - The gas price of the previous transaction
584
+ * @param attempts - The number of attempts to cancel the transaction
585
+ * @returns The hash of the cancellation transaction
586
+ */ async attemptTxCancellation(nonce, isBlobTx = false, previousGasPrice, attempts = 0) {
549
587
  if (isBlobTx) {
550
588
  throw new Error('Cannot cancel blob transactions, please use L1TxUtilsWithBlobsClass');
551
589
  }
@@ -554,37 +592,40 @@ export class L1TxUtils {
554
592
  const cancelGasPrice = await this.getGasPrice({
555
593
  ...this.config,
556
594
  // Use high bump for cancellation to ensure it replaces the original tx
557
- priorityFeeRetryBumpPercentage: 150, // 150% bump should be enough to replace any tx
595
+ priorityFeeRetryBumpPercentage: 150
558
596
  }, isBlobTx, attempts + 1, previousGasPrice);
559
597
  this.logger?.debug(`Attempting to cancel transaction with nonce ${nonce}`, {
560
598
  maxFeePerGas: formatGwei(cancelGasPrice.maxFeePerGas),
561
- maxPriorityFeePerGas: formatGwei(cancelGasPrice.maxPriorityFeePerGas),
599
+ maxPriorityFeePerGas: formatGwei(cancelGasPrice.maxPriorityFeePerGas)
562
600
  });
563
601
  const request = {
564
602
  to: account.address,
565
- value: 0n,
603
+ value: 0n
566
604
  };
567
605
  // Send 0-value tx to self with higher gas price
568
606
  const cancelTxHash = await this.walletClient.sendTransaction({
569
607
  ...request,
570
608
  nonce,
571
- gas: 21000n, // Standard ETH transfer gas
609
+ gas: 21_000n,
572
610
  maxFeePerGas: cancelGasPrice.maxFeePerGas,
573
- maxPriorityFeePerGas: cancelGasPrice.maxPriorityFeePerGas,
611
+ maxPriorityFeePerGas: cancelGasPrice.maxPriorityFeePerGas
574
612
  });
575
- const receipt = await this.monitorTransaction(request, cancelTxHash, { gasLimit: 21000n }, undefined, undefined, true);
613
+ const receipt = await this.monitorTransaction(request, cancelTxHash, {
614
+ gasLimit: 21_000n
615
+ }, undefined, undefined, true);
576
616
  return receipt.transactionHash;
577
617
  }
578
618
  }
579
619
  export function tryGetCustomErrorNameContractFunction(err) {
580
- return compactArray([err.shortMessage, ...(err.metaMessages ?? []).slice(0, 2).map(s => s.trim())]).join(' ');
620
+ return compactArray([
621
+ err.shortMessage,
622
+ ...(err.metaMessages ?? []).slice(0, 2).map((s)=>s.trim())
623
+ ]).join(' ');
581
624
  }
582
625
  /*
583
626
  * Returns cost of calldata usage in Ethereum.
584
627
  * @param data - Calldata.
585
628
  * @returns 4 for each zero byte, 16 for each nonzero.
586
- */
587
- export function getCalldataGasUsage(data) {
588
- return data.filter(byte => byte === 0).length * 4 + data.filter(byte => byte !== 0).length * 16;
629
+ */ export function getCalldataGasUsage(data) {
630
+ return data.filter((byte)=>byte === 0).length * 4 + data.filter((byte)=>byte !== 0).length * 16;
589
631
  }
590
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibDFfdHhfdXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvbDFfdHhfdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUNuRSxPQUFPLEVBRUwsa0JBQWtCLEVBQ2xCLGdCQUFnQixFQUNoQixrQkFBa0IsR0FDbkIsTUFBTSwwQkFBMEIsQ0FBQztBQUVsQyxPQUFPLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzdELE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUVoRCxPQUFPLEVBV0wsc0JBQXNCLEVBQ3RCLDBCQUEwQixFQUkxQixVQUFVLEVBQ1YsZ0JBQWdCLEVBQ2hCLFVBQVUsR0FDWCxNQUFNLE1BQU0sQ0FBQztBQUdkLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFN0MsNkJBQTZCO0FBQzdCLDZCQUE2QjtBQUM3Qix3Q0FBd0M7QUFFeEMsTUFBTSxTQUFTLEdBQUcsV0FBYyxDQUFDO0FBRWpDLHlHQUF5RztBQUN6RyxNQUFNLGVBQWUsR0FBRyxTQUFXLENBQUM7QUFFcEMsd0VBQXdFO0FBQ3hFLDRIQUE0SDtBQUM1SCxNQUFNLCtCQUErQixHQUFHLEVBQUUsQ0FBQztBQUUzQyx5RUFBeUU7QUFDekUsMkhBQTJIO0FBQzNILE1BQU0sb0NBQW9DLEdBQUcsR0FBRyxDQUFDO0FBRWpELGtDQUFrQztBQUNsQyxNQUFNLGFBQWEsR0FBRyxLQUFNLENBQUM7QUFzRDdCLE1BQU0sQ0FBQyxNQUFNLHVCQUF1QixHQUF3QztJQUMxRSx3QkFBd0IsRUFBRTtRQUN4QixXQUFXLEVBQUUsMkRBQTJEO1FBQ3hFLEdBQUcsRUFBRSxnQ0FBZ0M7UUFDckMsR0FBRyxrQkFBa0IsQ0FBQyxFQUFFLENBQUM7S0FDMUI7SUFDRCxPQUFPLEVBQUU7UUFDUCxXQUFX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