@aztec/ethereum 3.0.0-nightly.20250925 → 3.0.0-nightly.20250927

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 (89) hide show
  1. package/dest/config.d.ts +1 -1
  2. package/dest/config.d.ts.map +1 -1
  3. package/dest/config.js +1 -1
  4. package/dest/contracts/empire_base.d.ts +1 -1
  5. package/dest/contracts/empire_base.d.ts.map +1 -1
  6. package/dest/contracts/empire_slashing_proposer.d.ts +1 -1
  7. package/dest/contracts/empire_slashing_proposer.d.ts.map +1 -1
  8. package/dest/contracts/fee_asset_handler.d.ts +3 -3
  9. package/dest/contracts/fee_asset_handler.d.ts.map +1 -1
  10. package/dest/contracts/governance.js +1 -1
  11. package/dest/contracts/governance_proposer.d.ts +1 -1
  12. package/dest/contracts/governance_proposer.d.ts.map +1 -1
  13. package/dest/contracts/multicall.d.ts +4 -4
  14. package/dest/contracts/multicall.d.ts.map +1 -1
  15. package/dest/contracts/rollup.d.ts +3 -3
  16. package/dest/contracts/rollup.d.ts.map +1 -1
  17. package/dest/deploy_l1_contracts.d.ts +1 -1
  18. package/dest/deploy_l1_contracts.d.ts.map +1 -1
  19. package/dest/deploy_l1_contracts.js +1 -1
  20. package/dest/index.d.ts +1 -1
  21. package/dest/index.d.ts.map +1 -1
  22. package/dest/index.js +1 -1
  23. package/dest/l1_artifacts.d.ts +978 -2218
  24. package/dest/l1_artifacts.d.ts.map +1 -1
  25. package/dest/l1_tx_utils/config.d.ts +56 -0
  26. package/dest/l1_tx_utils/config.d.ts.map +1 -0
  27. package/dest/l1_tx_utils/config.js +67 -0
  28. package/dest/l1_tx_utils/constants.d.ts +6 -0
  29. package/dest/l1_tx_utils/constants.d.ts.map +1 -0
  30. package/dest/l1_tx_utils/constants.js +14 -0
  31. package/dest/l1_tx_utils/factory.d.ts +9 -0
  32. package/dest/l1_tx_utils/factory.d.ts.map +1 -0
  33. package/dest/l1_tx_utils/factory.js +14 -0
  34. package/dest/l1_tx_utils/index.d.ts +9 -0
  35. package/dest/l1_tx_utils/index.d.ts.map +1 -0
  36. package/dest/l1_tx_utils/index.js +9 -0
  37. package/dest/l1_tx_utils/l1_tx_utils.d.ts +80 -0
  38. package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -0
  39. package/dest/{l1_tx_utils.js → l1_tx_utils/l1_tx_utils.js} +14 -433
  40. package/dest/{l1_tx_utils_with_blobs.d.ts → l1_tx_utils/l1_tx_utils_with_blobs.d.ts} +6 -4
  41. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +1 -0
  42. package/dest/{l1_tx_utils_with_blobs.js → l1_tx_utils/l1_tx_utils_with_blobs.js} +2 -1
  43. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +81 -0
  44. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -0
  45. package/dest/l1_tx_utils/readonly_l1_tx_utils.js +304 -0
  46. package/dest/l1_tx_utils/signer.d.ts +4 -0
  47. package/dest/l1_tx_utils/signer.d.ts.map +1 -0
  48. package/dest/l1_tx_utils/signer.js +16 -0
  49. package/dest/l1_tx_utils/types.d.ts +44 -0
  50. package/dest/l1_tx_utils/types.d.ts.map +1 -0
  51. package/dest/l1_tx_utils/types.js +9 -0
  52. package/dest/l1_tx_utils/utils.d.ts +4 -0
  53. package/dest/l1_tx_utils/utils.d.ts.map +1 -0
  54. package/dest/l1_tx_utils/utils.js +14 -0
  55. package/dest/publisher_manager.d.ts +1 -1
  56. package/dest/publisher_manager.d.ts.map +1 -1
  57. package/dest/publisher_manager.js +1 -1
  58. package/dest/test/delayed_tx_utils.d.ts +2 -2
  59. package/dest/test/delayed_tx_utils.d.ts.map +1 -1
  60. package/dest/test/delayed_tx_utils.js +2 -2
  61. package/dest/test/upgrade_utils.js +1 -1
  62. package/package.json +6 -6
  63. package/src/config.ts +1 -1
  64. package/src/contracts/empire_base.ts +1 -1
  65. package/src/contracts/empire_slashing_proposer.ts +1 -1
  66. package/src/contracts/fee_asset_handler.ts +1 -1
  67. package/src/contracts/governance.ts +1 -1
  68. package/src/contracts/governance_proposer.ts +1 -1
  69. package/src/contracts/multicall.ts +1 -1
  70. package/src/contracts/rollup.ts +1 -1
  71. package/src/deploy_l1_contracts.ts +1 -1
  72. package/src/index.ts +1 -1
  73. package/src/l1_tx_utils/config.ts +129 -0
  74. package/src/l1_tx_utils/constants.ts +18 -0
  75. package/src/l1_tx_utils/factory.ts +44 -0
  76. package/src/l1_tx_utils/index.ts +11 -0
  77. package/src/l1_tx_utils/l1_tx_utils.ts +527 -0
  78. package/src/{l1_tx_utils_with_blobs.ts → l1_tx_utils/l1_tx_utils_with_blobs.ts} +7 -10
  79. package/src/l1_tx_utils/readonly_l1_tx_utils.ts +368 -0
  80. package/src/l1_tx_utils/signer.ts +28 -0
  81. package/src/l1_tx_utils/types.ts +52 -0
  82. package/src/l1_tx_utils/utils.ts +16 -0
  83. package/src/publisher_manager.ts +1 -1
  84. package/src/test/delayed_tx_utils.ts +2 -2
  85. package/src/test/upgrade_utils.ts +1 -1
  86. package/dest/l1_tx_utils.d.ts +0 -252
  87. package/dest/l1_tx_utils.d.ts.map +0 -1
  88. package/dest/l1_tx_utils_with_blobs.d.ts.map +0 -1
  89. package/src/l1_tx_utils.ts +0 -1125
@@ -0,0 +1,368 @@
1
+ import { times } from '@aztec/foundation/collection';
2
+ import { type Logger, createLogger } from '@aztec/foundation/log';
3
+ import { makeBackoff, retry } from '@aztec/foundation/retry';
4
+ import { DateProvider } from '@aztec/foundation/timer';
5
+ import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
6
+
7
+ import pickBy from 'lodash.pickby';
8
+ import {
9
+ type Abi,
10
+ type Account,
11
+ type BaseError,
12
+ type BlockOverrides,
13
+ type ContractFunctionExecutionError,
14
+ type Hex,
15
+ MethodNotFoundRpcError,
16
+ MethodNotSupportedRpcError,
17
+ type StateOverride,
18
+ decodeErrorResult,
19
+ formatGwei,
20
+ getContractError,
21
+ hexToBytes,
22
+ } from 'viem';
23
+
24
+ import type { ViemClient } from '../types.js';
25
+ import { type L1TxUtilsConfig, defaultL1TxUtilsConfig, l1TxUtilsConfigMappings } from './config.js';
26
+ import {
27
+ BLOCK_TIME_MS,
28
+ LARGE_GAS_LIMIT,
29
+ MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE,
30
+ MIN_REPLACEMENT_BUMP_PERCENTAGE,
31
+ WEI_CONST,
32
+ } from './constants.js';
33
+ import type { GasPrice, L1BlobInputs, L1TxRequest, TransactionStats } from './types.js';
34
+ import { getCalldataGasUsage, tryGetCustomErrorNameContractFunction } from './utils.js';
35
+
36
+ export class ReadOnlyL1TxUtils {
37
+ public readonly config: L1TxUtilsConfig;
38
+ protected interrupted = false;
39
+
40
+ constructor(
41
+ public client: ViemClient,
42
+ protected logger: Logger = createLogger('ReadOnlyL1TxUtils'),
43
+ public readonly dateProvider: DateProvider,
44
+ config?: Partial<L1TxUtilsConfig>,
45
+ protected debugMaxGasLimit: boolean = false,
46
+ ) {
47
+ this.config = {
48
+ ...defaultL1TxUtilsConfig,
49
+ ...(config || {}),
50
+ };
51
+ }
52
+
53
+ public interrupt() {
54
+ this.interrupted = true;
55
+ }
56
+
57
+ public restart() {
58
+ this.interrupted = false;
59
+ }
60
+
61
+ public getBlock() {
62
+ return this.client.getBlock();
63
+ }
64
+
65
+ public getBlockNumber() {
66
+ return this.client.getBlockNumber();
67
+ }
68
+
69
+ /**
70
+ * Gets the current gas price with bounds checking
71
+ */
72
+ public async getGasPrice(
73
+ _gasConfig?: L1TxUtilsConfig,
74
+ isBlobTx: boolean = false,
75
+ attempt: number = 0,
76
+ previousGasPrice?: typeof attempt extends 0 ? never : GasPrice,
77
+ ): Promise<GasPrice> {
78
+ const gasConfig = { ...this.config, ..._gasConfig };
79
+ const block = await this.client.getBlock({ blockTag: 'latest' });
80
+ const baseFee = block.baseFeePerGas ?? 0n;
81
+
82
+ // Get blob base fee if available
83
+ let blobBaseFee = 0n;
84
+ if (isBlobTx) {
85
+ try {
86
+ blobBaseFee = await retry<bigint>(
87
+ () => this.client.getBlobBaseFee(),
88
+ 'Getting L1 blob base fee',
89
+ makeBackoff(times(2, () => 1)),
90
+ this.logger,
91
+ true,
92
+ );
93
+ this.logger?.debug('L1 Blob base fee:', { blobBaseFee: formatGwei(blobBaseFee) });
94
+ } catch {
95
+ this.logger?.warn('Failed to get L1 blob base fee', attempt);
96
+ }
97
+ }
98
+
99
+ let priorityFee: bigint;
100
+ if (gasConfig.fixedPriorityFeePerGas) {
101
+ this.logger?.debug('Using fixed priority fee per L1 gas', {
102
+ fixedPriorityFeePerGas: gasConfig.fixedPriorityFeePerGas,
103
+ });
104
+ // try to maintain precision up to 1000000 wei
105
+ priorityFee = BigInt(gasConfig.fixedPriorityFeePerGas * 1_000_000) * (WEI_CONST / 1_000_000n);
106
+ } else {
107
+ // Get initial priority fee from the network
108
+ priorityFee = await this.client.estimateMaxPriorityFeePerGas();
109
+ }
110
+ let maxFeePerGas = baseFee;
111
+
112
+ let maxFeePerBlobGas = blobBaseFee;
113
+
114
+ // Bump base fee so it's valid for next blocks if it stalls
115
+ const numBlocks = Math.ceil(gasConfig.stallTimeMs! / BLOCK_TIME_MS);
116
+ for (let i = 0; i < numBlocks; i++) {
117
+ // each block can go up 12.5% from previous baseFee
118
+ maxFeePerGas = (maxFeePerGas * (1_000n + 125n)) / 1_000n;
119
+ // same for blob gas fee
120
+ maxFeePerBlobGas = (maxFeePerBlobGas * (1_000n + 125n)) / 1_000n;
121
+ }
122
+ if (attempt > 0) {
123
+ const configBump =
124
+ gasConfig.priorityFeeRetryBumpPercentage ?? defaultL1TxUtilsConfig.priorityFeeRetryBumpPercentage!;
125
+
126
+ // if this is a blob tx, we have to use the blob bump percentage
127
+ const minBumpPercentage = isBlobTx ? MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE : MIN_REPLACEMENT_BUMP_PERCENTAGE;
128
+
129
+ const bumpPercentage = configBump > minBumpPercentage ? configBump : minBumpPercentage;
130
+ // Calculate minimum required fees based on previous attempt
131
+ // multiply by 100 & divide by 100 to maintain some precision
132
+ const minPriorityFee =
133
+ (previousGasPrice!.maxPriorityFeePerGas * (100_00n + BigInt(bumpPercentage * 1_00))) / 100_00n;
134
+ const minMaxFee = (previousGasPrice!.maxFeePerGas * (100_00n + BigInt(bumpPercentage * 1_00))) / 100_00n;
135
+
136
+ // Add priority fee to maxFeePerGas
137
+ maxFeePerGas += priorityFee;
138
+
139
+ // Use maximum between current network values and minimum required values
140
+ priorityFee = priorityFee > minPriorityFee ? priorityFee : minPriorityFee;
141
+ maxFeePerGas = maxFeePerGas > minMaxFee ? maxFeePerGas : minMaxFee;
142
+ } else {
143
+ // first attempt, just bump priority fee, unless it's a fixed config
144
+ // multiply by 100 & divide by 100 to maintain some precision
145
+ if (!gasConfig.fixedPriorityFeePerGas) {
146
+ priorityFee = (priorityFee * (100_00n + BigInt((gasConfig.priorityFeeBumpPercentage || 0) * 1_00))) / 100_00n;
147
+ }
148
+ maxFeePerGas += priorityFee;
149
+ }
150
+
151
+ // Ensure we don't exceed maxGwei
152
+ const maxGweiInWei = gasConfig.maxGwei! * WEI_CONST;
153
+ maxFeePerGas = maxFeePerGas > maxGweiInWei ? maxGweiInWei : maxFeePerGas;
154
+
155
+ // Ensure we don't exceed maxBlobGwei
156
+ if (maxFeePerBlobGas) {
157
+ const maxBlobGweiInWei = gasConfig.maxBlobGwei! * WEI_CONST;
158
+ maxFeePerBlobGas = maxFeePerBlobGas > maxBlobGweiInWei ? maxBlobGweiInWei : maxFeePerBlobGas;
159
+ }
160
+
161
+ // Ensure priority fee doesn't exceed max fee
162
+ const maxPriorityFeePerGas = priorityFee > maxFeePerGas ? maxFeePerGas : priorityFee;
163
+
164
+ if (attempt > 0 && previousGasPrice?.maxFeePerBlobGas) {
165
+ const bumpPercentage =
166
+ gasConfig.priorityFeeRetryBumpPercentage! > MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE
167
+ ? gasConfig.priorityFeeRetryBumpPercentage!
168
+ : MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE;
169
+
170
+ // calculate min blob fee based on previous attempt
171
+ const minBlobFee = (previousGasPrice.maxFeePerBlobGas * (100_00n + BigInt(bumpPercentage * 1_00))) / 100_00n;
172
+
173
+ // use max between current network values and min required values
174
+ maxFeePerBlobGas = maxFeePerBlobGas > minBlobFee ? maxFeePerBlobGas : minBlobFee;
175
+ }
176
+
177
+ this.logger?.debug(`Computed L1 gas price`, {
178
+ attempt,
179
+ baseFee: formatGwei(baseFee),
180
+ maxFeePerGas: formatGwei(maxFeePerGas),
181
+ maxPriorityFeePerGas: formatGwei(maxPriorityFeePerGas),
182
+ ...(maxFeePerBlobGas && { maxFeePerBlobGas: formatGwei(maxFeePerBlobGas) }),
183
+ });
184
+
185
+ return {
186
+ maxFeePerGas,
187
+ maxPriorityFeePerGas,
188
+ ...(maxFeePerBlobGas && { maxFeePerBlobGas: maxFeePerBlobGas }),
189
+ };
190
+ }
191
+
192
+ /**
193
+ * Estimates gas and adds buffer
194
+ */
195
+ public async estimateGas(
196
+ account: Account | Hex,
197
+ request: L1TxRequest,
198
+ _gasConfig?: L1TxUtilsConfig,
199
+ _blobInputs?: L1BlobInputs,
200
+ ): Promise<bigint> {
201
+ const gasConfig = { ...this.config, ..._gasConfig };
202
+ let initialEstimate = 0n;
203
+ if (_blobInputs) {
204
+ // @note requests with blobs also require maxFeePerBlobGas to be set
205
+ const gasPrice = await this.getGasPrice(gasConfig, true, 0);
206
+ initialEstimate = await this.client.estimateGas({
207
+ account,
208
+ ...request,
209
+ ..._blobInputs,
210
+ maxFeePerBlobGas: gasPrice.maxFeePerBlobGas!,
211
+ gas: LARGE_GAS_LIMIT,
212
+ });
213
+
214
+ this.logger?.debug(`L1 gas used in estimateGas by blob tx: ${initialEstimate}`);
215
+ } else {
216
+ initialEstimate = await this.client.estimateGas({ account, ...request, gas: LARGE_GAS_LIMIT });
217
+ this.logger?.debug(`L1 gas used in estimateGas by non-blob tx: ${initialEstimate}`);
218
+ }
219
+
220
+ // Add buffer based on either fixed amount or percentage
221
+ const withBuffer = this.bumpGasLimit(initialEstimate, gasConfig);
222
+
223
+ return withBuffer;
224
+ }
225
+
226
+ async getTransactionStats(txHash: string): Promise<TransactionStats | undefined> {
227
+ const tx = await this.client.getTransaction({ hash: txHash as Hex });
228
+ if (!tx) {
229
+ return undefined;
230
+ }
231
+ const calldata = hexToBytes(tx.input);
232
+ return {
233
+ sender: tx.from.toString(),
234
+ transactionHash: tx.hash,
235
+ calldataSize: calldata.length,
236
+ calldataGas: getCalldataGasUsage(calldata),
237
+ };
238
+ }
239
+
240
+ public async tryGetErrorFromRevertedTx(
241
+ data: Hex,
242
+ args: {
243
+ args: readonly any[];
244
+ functionName: string;
245
+ abi: Abi;
246
+ address: Hex;
247
+ },
248
+ blobInputs: (L1BlobInputs & { maxFeePerBlobGas: bigint }) | undefined,
249
+ stateOverride: StateOverride = [],
250
+ ) {
251
+ try {
252
+ await this.client.simulateContract({
253
+ ...args,
254
+ account: this.client.account,
255
+ stateOverride,
256
+ });
257
+ this.logger?.trace('Simulated blob tx', { blobInputs });
258
+ // If the above passes, we have a blob error. We cannot simulate blob txs, and failed txs no longer throw errors.
259
+ // Strangely, the only way to throw the revert reason as an error and provide blobs is prepareTransactionRequest.
260
+ // See: https://github.com/wevm/viem/issues/2075
261
+ // This throws a EstimateGasExecutionError with the custom error information:
262
+ const request = blobInputs
263
+ ? {
264
+ account: this.client.account,
265
+ to: args.address,
266
+ data,
267
+ blobs: blobInputs.blobs,
268
+ kzg: blobInputs.kzg,
269
+ maxFeePerBlobGas: blobInputs.maxFeePerBlobGas,
270
+ }
271
+ : {
272
+ account: this.client.account,
273
+ to: args.address,
274
+ data,
275
+ };
276
+ this.logger?.trace('Preparing tx', { request });
277
+ await this.client.prepareTransactionRequest(request);
278
+ this.logger?.trace('Prepared tx');
279
+ return undefined;
280
+ } catch (simulationErr: any) {
281
+ // If we don't have a ContractFunctionExecutionError, we have a blob related error => use getContractError to get the error msg.
282
+ const contractErr =
283
+ simulationErr.name === 'ContractFunctionExecutionError'
284
+ ? simulationErr
285
+ : getContractError(simulationErr as BaseError, {
286
+ args: [],
287
+ abi: args.abi,
288
+ functionName: args.functionName,
289
+ address: args.address,
290
+ });
291
+ if (contractErr.name === 'ContractFunctionExecutionError') {
292
+ const execErr = contractErr as ContractFunctionExecutionError;
293
+ return tryGetCustomErrorNameContractFunction(execErr);
294
+ }
295
+ this.logger?.error(`Error getting error from simulation`, simulationErr);
296
+ }
297
+ }
298
+
299
+ public async simulate(
300
+ request: L1TxRequest & { gas?: bigint; from?: Hex },
301
+ blockOverrides: BlockOverrides<bigint, number> = {},
302
+ stateOverrides: StateOverride = [],
303
+ abi: Abi = RollupAbi,
304
+ _gasConfig?: L1TxUtilsConfig & { fallbackGasEstimate?: bigint },
305
+ ): Promise<{ gasUsed: bigint; result: `0x${string}` }> {
306
+ const gasConfig = { ...this.config, ..._gasConfig };
307
+
308
+ const call: any = {
309
+ to: request.to!,
310
+ data: request.data,
311
+ ...(request.from && { from: request.from }),
312
+ };
313
+
314
+ return await this._simulate(call, blockOverrides, stateOverrides, gasConfig, abi);
315
+ }
316
+
317
+ protected async _simulate(
318
+ call: any,
319
+ blockOverrides: BlockOverrides<bigint, number> = {},
320
+ stateOverrides: StateOverride = [],
321
+ gasConfig: L1TxUtilsConfig & { fallbackGasEstimate?: bigint },
322
+ abi: Abi,
323
+ ) {
324
+ try {
325
+ const result = await this.client.simulateBlocks({
326
+ validation: false,
327
+ blocks: [
328
+ {
329
+ blockOverrides,
330
+ stateOverrides,
331
+ calls: [call],
332
+ },
333
+ ],
334
+ });
335
+
336
+ if (result[0].calls[0].status === 'failure') {
337
+ this.logger?.error('L1 transaction simulation failed', result[0].calls[0].error);
338
+ const decodedError = decodeErrorResult({ abi, data: result[0].calls[0].data });
339
+
340
+ throw new Error(
341
+ `L1 transaction simulation failed with error ${decodedError.errorName}(${decodedError.args?.join(',')})`,
342
+ );
343
+ }
344
+ this.logger?.debug(`L1 transaction simulation succeeded`, { ...result[0].calls[0] });
345
+ return { gasUsed: result[0].gasUsed, result: result[0].calls[0].data as `0x${string}` };
346
+ } catch (err) {
347
+ if (err instanceof MethodNotFoundRpcError || err instanceof MethodNotSupportedRpcError) {
348
+ if (gasConfig.fallbackGasEstimate) {
349
+ this.logger?.warn(
350
+ `Node does not support eth_simulateV1 API. Using fallback gas estimate: ${gasConfig.fallbackGasEstimate}`,
351
+ );
352
+ return { gasUsed: gasConfig.fallbackGasEstimate, result: '0x' as `0x${string}` };
353
+ }
354
+ this.logger?.error('Node does not support eth_simulateV1 API');
355
+ }
356
+ throw err;
357
+ }
358
+ }
359
+
360
+ public bumpGasLimit(gasLimit: bigint, _gasConfig?: L1TxUtilsConfig): bigint {
361
+ const gasConfig = { ...this.config, ..._gasConfig };
362
+ const bumpedGasLimit = gasLimit + (gasLimit * BigInt((gasConfig?.gasLimitBufferPercentage || 0) * 1_00)) / 100_00n;
363
+
364
+ const cleanGasConfig = pickBy(gasConfig, (_, key) => key in l1TxUtilsConfigMappings);
365
+ this.logger?.debug('Bumping gas limit', { gasLimit, gasConfig: cleanGasConfig, bumpedGasLimit });
366
+ return bumpedGasLimit;
367
+ }
368
+ }
@@ -0,0 +1,28 @@
1
+ import { EthAddress } from '@aztec/foundation/eth-address';
2
+ import type { ViemTransactionSignature } from '@aztec/foundation/eth-signature';
3
+
4
+ import { type TransactionSerializable, type WalletClient, parseTransaction } from 'viem';
5
+
6
+ import type { SigningCallback } from './types.js';
7
+
8
+ export function createViemSigner(client: WalletClient) {
9
+ const signer: SigningCallback = async (
10
+ tx: TransactionSerializable,
11
+ _address: EthAddress,
12
+ ): Promise<ViemTransactionSignature> => {
13
+ const signedTx = await client.signTransaction(tx as any);
14
+
15
+ const parsed = parseTransaction(signedTx);
16
+
17
+ if (!parsed.r || !parsed.s || (parsed.yParity !== 0 && parsed.yParity !== 1)) {
18
+ throw new Error('Failed to extract signature from viem signed transaction');
19
+ }
20
+
21
+ return {
22
+ r: parsed.r,
23
+ s: parsed.s,
24
+ yParity: parsed.yParity,
25
+ };
26
+ };
27
+ return signer;
28
+ }
@@ -0,0 +1,52 @@
1
+ import { EthAddress } from '@aztec/foundation/eth-address';
2
+ import type { ViemTransactionSignature } from '@aztec/foundation/eth-signature';
3
+
4
+ import type { Abi, Address, Hex, TransactionSerializable } from 'viem';
5
+
6
+ import type { L1TxUtilsConfig } from './config.js';
7
+
8
+ export interface L1TxRequest {
9
+ to: Address | null;
10
+ data?: Hex;
11
+ value?: bigint;
12
+ abi?: Abi;
13
+ }
14
+
15
+ export type L1GasConfig = Partial<L1TxUtilsConfig> & { gasLimit?: bigint; txTimeoutAt?: Date };
16
+
17
+ export interface L1BlobInputs {
18
+ blobs: Uint8Array[];
19
+ kzg: any;
20
+ maxFeePerBlobGas?: bigint;
21
+ }
22
+
23
+ export interface GasPrice {
24
+ maxFeePerGas: bigint;
25
+ maxPriorityFeePerGas: bigint;
26
+ maxFeePerBlobGas?: bigint;
27
+ }
28
+
29
+ export type TransactionStats = {
30
+ /** Address of the sender. */
31
+ sender: string;
32
+ /** Hash of the transaction. */
33
+ transactionHash: string;
34
+ /** Size in bytes of the tx calldata */
35
+ calldataSize: number;
36
+ /** Gas required to pay for the calldata inclusion (depends on size and number of zeros) */
37
+ calldataGas: number;
38
+ };
39
+
40
+ export enum TxUtilsState {
41
+ IDLE,
42
+ SENT,
43
+ SPEED_UP,
44
+ CANCELLED,
45
+ NOT_MINED,
46
+ MINED,
47
+ }
48
+
49
+ export type SigningCallback = (
50
+ transaction: TransactionSerializable,
51
+ signingAddress: EthAddress,
52
+ ) => Promise<ViemTransactionSignature>;
@@ -0,0 +1,16 @@
1
+ import { compactArray } from '@aztec/foundation/collection';
2
+
3
+ import type { ContractFunctionExecutionError } from 'viem';
4
+
5
+ export function tryGetCustomErrorNameContractFunction(err: ContractFunctionExecutionError) {
6
+ return compactArray([err.shortMessage, ...(err.metaMessages ?? []).slice(0, 2).map(s => s.trim())]).join(' ');
7
+ }
8
+
9
+ /*
10
+ * Returns cost of calldata usage in Ethereum.
11
+ * @param data - Calldata.
12
+ * @returns 4 for each zero byte, 16 for each nonzero.
13
+ */
14
+ export function getCalldataGasUsage(data: Uint8Array) {
15
+ return data.filter(byte => byte === 0).length * 4 + data.filter(byte => byte !== 0).length * 16;
16
+ }
@@ -1,7 +1,7 @@
1
1
  import { pick } from '@aztec/foundation/collection';
2
2
  import { createLogger } from '@aztec/foundation/log';
3
3
 
4
- import { L1TxUtils, TxUtilsState } from './l1_tx_utils.js';
4
+ import { L1TxUtils, TxUtilsState } from './l1_tx_utils/index.js';
5
5
 
6
6
  const sortOrder = [TxUtilsState.IDLE, TxUtilsState.MINED];
7
7
  const invalidStates = [TxUtilsState.SENT, TxUtilsState.SPEED_UP, TxUtilsState.CANCELLED, TxUtilsState.NOT_MINED]; // Cancelled and not mined are states that can be handled by a later iteration
@@ -2,8 +2,8 @@ import { EthAddress } from '@aztec/foundation/eth-address';
2
2
  import { type Logger, createLogger } from '@aztec/foundation/log';
3
3
  import { DateProvider } from '@aztec/foundation/timer';
4
4
 
5
- import { type L1TxUtilsConfig, createViemSigner } from '../l1_tx_utils.js';
6
- import { L1TxUtilsWithBlobs } from '../l1_tx_utils_with_blobs.js';
5
+ import { type L1TxUtilsConfig, createViemSigner } from '../l1_tx_utils/index.js';
6
+ import { L1TxUtilsWithBlobs } from '../l1_tx_utils/l1_tx_utils_with_blobs.js';
7
7
  import type { ExtendedViemWalletClient } from '../types.js';
8
8
  import { type Delayer, withDelayer } from './tx_delayer.js';
9
9
 
@@ -7,7 +7,7 @@ import { type GetContractReturnType, type PrivateKeyAccount, getContract } from
7
7
 
8
8
  import { extractProposalIdFromLogs } from '../contracts/governance.js';
9
9
  import type { L1ContractAddresses } from '../l1_contract_addresses.js';
10
- import { createL1TxUtilsFromViemWallet } from '../l1_tx_utils.js';
10
+ import { createL1TxUtilsFromViemWallet } from '../l1_tx_utils/index.js';
11
11
  import type { ExtendedViemWalletClient, ViemPublicClient } from '../types.js';
12
12
  import { EthCheatCodes } from './eth_cheat_codes.js';
13
13