@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,80 @@
1
+ import { EthAddress } from '@aztec/foundation/eth-address';
2
+ import { type Logger } from '@aztec/foundation/log';
3
+ import { DateProvider } from '@aztec/foundation/timer';
4
+ import { type Abi, type BlockOverrides, type Hex, type PrepareTransactionRequestRequest, type StateOverride, type TransactionReceipt } from 'viem';
5
+ import type { ViemClient } from '../types.js';
6
+ import { type L1TxUtilsConfig } from './config.js';
7
+ import { ReadOnlyL1TxUtils } from './readonly_l1_tx_utils.js';
8
+ import { type GasPrice, type L1BlobInputs, type L1GasConfig, type L1TxRequest, type SigningCallback, TxUtilsState } from './types.js';
9
+ export declare class L1TxUtils extends ReadOnlyL1TxUtils {
10
+ client: ViemClient;
11
+ address: EthAddress;
12
+ protected signer: SigningCallback;
13
+ protected logger: Logger;
14
+ private txUtilsState;
15
+ private lastMinedBlockNumber;
16
+ private nonceManager;
17
+ constructor(client: ViemClient, address: EthAddress, signer: SigningCallback, logger?: Logger, dateProvider?: DateProvider, config?: Partial<L1TxUtilsConfig>, debugMaxGasLimit?: boolean);
18
+ get state(): TxUtilsState;
19
+ get lastMinedAtBlockNumber(): bigint | undefined;
20
+ private set lastMinedAtBlockNumber(value);
21
+ private set state(value);
22
+ getSenderAddress(): EthAddress;
23
+ getSenderBalance(): Promise<bigint>;
24
+ private signTransaction;
25
+ protected prepareSignedTransaction(txData: PrepareTransactionRequestRequest): Promise<`0x${string}`>;
26
+ /**
27
+ * Sends a transaction with gas estimation and pricing
28
+ * @param request - The transaction request (to, data, value)
29
+ * @param gasConfig - Optional gas configuration
30
+ * @returns The transaction hash and parameters used
31
+ */
32
+ sendTransaction(request: L1TxRequest, _gasConfig?: L1GasConfig, blobInputs?: L1BlobInputs, stateChange?: TxUtilsState): Promise<{
33
+ txHash: Hex;
34
+ gasLimit: bigint;
35
+ gasPrice: GasPrice;
36
+ }>;
37
+ /**
38
+ * Monitors a transaction until completion, handling speed-ups if needed
39
+ * @param request - Original transaction request (needed for speed-ups)
40
+ * @param initialTxHash - Hash of the initial transaction
41
+ * @param allVersions - Hashes of all transactions submitted under the same nonce (any of them could mine)
42
+ * @param params - Parameters used in the initial transaction
43
+ * @param gasConfig - Optional gas configuration
44
+ */
45
+ monitorTransaction(request: L1TxRequest, initialTxHash: Hex, allVersions: Set<Hex>, params: {
46
+ gasLimit: bigint;
47
+ }, _gasConfig?: Partial<L1TxUtilsConfig> & {
48
+ txTimeoutAt?: Date;
49
+ }, _blobInputs?: L1BlobInputs, isCancelTx?: boolean): Promise<TransactionReceipt>;
50
+ /**
51
+ * Sends a transaction and monitors it until completion
52
+ * @param request - The transaction request (to, data, value)
53
+ * @param gasConfig - Optional gas configuration
54
+ * @returns The receipt of the successful transaction
55
+ */
56
+ sendAndMonitorTransaction(request: L1TxRequest, gasConfig?: L1GasConfig, blobInputs?: L1BlobInputs): Promise<{
57
+ receipt: TransactionReceipt;
58
+ gasPrice: GasPrice;
59
+ }>;
60
+ simulate(request: L1TxRequest & {
61
+ gas?: bigint;
62
+ from?: Hex;
63
+ }, _blockOverrides?: BlockOverrides<bigint, number>, stateOverrides?: StateOverride, abi?: Abi, _gasConfig?: L1TxUtilsConfig & {
64
+ fallbackGasEstimate?: bigint;
65
+ ignoreBlockGasLimit?: boolean;
66
+ }): Promise<{
67
+ gasUsed: bigint;
68
+ result: `0x${string}`;
69
+ }>;
70
+ /**
71
+ * Attempts to cancel a transaction by sending a 0-value tx to self with same nonce but higher gas prices
72
+ * @param nonce - The nonce of the transaction to cancel
73
+ * @param allVersions - Hashes of all transactions submitted under the same nonce (any of them could mine)
74
+ * @param previousGasPrice - The gas price of the previous transaction
75
+ * @param attempts - The number of attempts to cancel the transaction
76
+ * @returns The hash of the cancellation transaction
77
+ */
78
+ protected attemptTxCancellation(currentTxHash: Hex, nonce: number, allVersions: Set<Hex>, isBlobTx?: boolean, previousGasPrice?: GasPrice, attempts?: number): Promise<`0x${string}`>;
79
+ }
80
+ //# sourceMappingURL=l1_tx_utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"l1_tx_utils.d.ts","sourceRoot":"","sources":["../../src/l1_tx_utils/l1_tx_utils.ts"],"names":[],"mappings":"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"}
@@ -1,400 +1,18 @@
1
- import { compactArray, times } from '@aztec/foundation/collection';
2
- import { bigintConfigHelper, booleanConfigHelper, getConfigFromMappings, getDefaultConfig, numberConfigHelper } from '@aztec/foundation/config';
1
+ import { times } from '@aztec/foundation/collection';
3
2
  import { TimeoutError } from '@aztec/foundation/error';
4
- import { EthAddress } from '@aztec/foundation/eth-address';
5
3
  import { createLogger } from '@aztec/foundation/log';
6
4
  import { makeBackoff, retry } from '@aztec/foundation/retry';
7
5
  import { sleep } from '@aztec/foundation/sleep';
8
6
  import { DateProvider } from '@aztec/foundation/timer';
9
7
  import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
10
8
  import pickBy from 'lodash.pickby';
11
- import { MethodNotFoundRpcError, MethodNotSupportedRpcError, createNonceManager, decodeErrorResult, formatGwei, getContractError, hexToBytes, parseTransaction, serializeTransaction } from 'viem';
9
+ import { createNonceManager, formatGwei, serializeTransaction } from 'viem';
12
10
  import { jsonRpc } from 'viem/nonce';
13
- import { formatViemError } from './utils.js';
14
- // 1_000_000_000 Gwei = 1 ETH
15
- // 1_000_000_000 Wei = 1 Gwei
16
- // 1_000_000_000_000_000_000 Wei = 1 ETH
17
- const WEI_CONST = 1_000_000_000n;
18
- // @note using this large gas limit to avoid the issue of `gas limit too low` when estimating gas in reth
19
- const LARGE_GAS_LIMIT = 12_000_000n;
20
- // setting a minimum bump percentage to 10% due to geth's implementation
21
- // https://github.com/ethereum/go-ethereum/blob/e3d61e6db028c412f74bc4d4c7e117a9e29d0de0/core/txpool/legacypool/list.go#L298
22
- const MIN_REPLACEMENT_BUMP_PERCENTAGE = 10;
23
- // setting a minimum bump percentage to 100% due to geth's implementation
24
- // https://github.com/ethereum/go-ethereum/blob/e3d61e6db028c412f74bc4d4c7e117a9e29d0de0/core/txpool/blobpool/config.go#L34
25
- const MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE = 100;
26
- // Avg ethereum block time is ~12s
27
- const BLOCK_TIME_MS = 12_000;
28
- export const l1TxUtilsConfigMappings = {
29
- gasLimitBufferPercentage: {
30
- description: 'How much to increase calculated gas limit by (percentage)',
31
- env: 'L1_GAS_LIMIT_BUFFER_PERCENTAGE',
32
- ...numberConfigHelper(20)
33
- },
34
- maxGwei: {
35
- description: 'Maximum gas price in gwei',
36
- env: 'L1_GAS_PRICE_MAX',
37
- ...bigintConfigHelper(500n)
38
- },
39
- maxBlobGwei: {
40
- description: 'Maximum blob fee per gas in gwei',
41
- env: 'L1_BLOB_FEE_PER_GAS_MAX',
42
- ...bigintConfigHelper(1_500n)
43
- },
44
- priorityFeeBumpPercentage: {
45
- description: 'How much to increase priority fee by each attempt (percentage)',
46
- env: 'L1_PRIORITY_FEE_BUMP_PERCENTAGE',
47
- ...numberConfigHelper(20)
48
- },
49
- priorityFeeRetryBumpPercentage: {
50
- description: 'How much to increase priority fee by each retry attempt (percentage)',
51
- env: 'L1_PRIORITY_FEE_RETRY_BUMP_PERCENTAGE',
52
- ...numberConfigHelper(50)
53
- },
54
- fixedPriorityFeePerGas: {
55
- description: 'Fixed priority fee per gas in Gwei. Overrides any priority fee bump percentage',
56
- env: 'L1_FIXED_PRIORITY_FEE_PER_GAS',
57
- ...numberConfigHelper(0)
58
- },
59
- maxAttempts: {
60
- description: 'Maximum number of speed-up attempts',
61
- env: 'L1_TX_MONITOR_MAX_ATTEMPTS',
62
- ...numberConfigHelper(3)
63
- },
64
- checkIntervalMs: {
65
- description: 'How often to check tx status',
66
- env: 'L1_TX_MONITOR_CHECK_INTERVAL_MS',
67
- ...numberConfigHelper(1_000)
68
- },
69
- stallTimeMs: {
70
- description: 'How long before considering tx stalled',
71
- env: 'L1_TX_MONITOR_STALL_TIME_MS',
72
- ...numberConfigHelper(24_000)
73
- },
74
- txTimeoutMs: {
75
- description: 'How long to wait for a tx to be mined before giving up. Set to 0 to disable.',
76
- env: 'L1_TX_MONITOR_TX_TIMEOUT_MS',
77
- ...numberConfigHelper(120_000)
78
- },
79
- txPropagationMaxQueryAttempts: {
80
- description: 'How many attempts will be done to get a tx after it was sent',
81
- env: 'L1_TX_PROPAGATION_MAX_QUERY_ATTEMPTS',
82
- ...numberConfigHelper(3)
83
- },
84
- cancelTxOnTimeout: {
85
- description: "Whether to attempt to cancel a tx if it's not mined after txTimeoutMs",
86
- env: 'L1_TX_MONITOR_CANCEL_TX_ON_TIMEOUT',
87
- ...booleanConfigHelper(true)
88
- }
89
- };
90
- export const defaultL1TxUtilsConfig = getDefaultConfig(l1TxUtilsConfigMappings);
91
- export function getL1TxUtilsConfigEnvVars() {
92
- return getConfigFromMappings(l1TxUtilsConfigMappings);
93
- }
94
- export var TxUtilsState = /*#__PURE__*/ function(TxUtilsState) {
95
- TxUtilsState[TxUtilsState["IDLE"] = 0] = "IDLE";
96
- TxUtilsState[TxUtilsState["SENT"] = 1] = "SENT";
97
- TxUtilsState[TxUtilsState["SPEED_UP"] = 2] = "SPEED_UP";
98
- TxUtilsState[TxUtilsState["CANCELLED"] = 3] = "CANCELLED";
99
- TxUtilsState[TxUtilsState["NOT_MINED"] = 4] = "NOT_MINED";
100
- TxUtilsState[TxUtilsState["MINED"] = 5] = "MINED";
101
- return TxUtilsState;
102
- }({});
103
- export class ReadOnlyL1TxUtils {
104
- client;
105
- logger;
106
- dateProvider;
107
- debugMaxGasLimit;
108
- config;
109
- interrupted;
110
- constructor(client, logger = createLogger('ReadOnlyL1TxUtils'), dateProvider, config, debugMaxGasLimit = false){
111
- this.client = client;
112
- this.logger = logger;
113
- this.dateProvider = dateProvider;
114
- this.debugMaxGasLimit = debugMaxGasLimit;
115
- this.interrupted = false;
116
- this.config = {
117
- ...defaultL1TxUtilsConfig,
118
- ...config || {}
119
- };
120
- }
121
- interrupt() {
122
- this.interrupted = true;
123
- }
124
- restart() {
125
- this.interrupted = false;
126
- }
127
- getBlock() {
128
- return this.client.getBlock();
129
- }
130
- getBlockNumber() {
131
- return this.client.getBlockNumber();
132
- }
133
- /**
134
- * Gets the current gas price with bounds checking
135
- */ async getGasPrice(_gasConfig, isBlobTx = false, attempt = 0, previousGasPrice) {
136
- const gasConfig = {
137
- ...this.config,
138
- ..._gasConfig
139
- };
140
- const block = await this.client.getBlock({
141
- blockTag: 'latest'
142
- });
143
- const baseFee = block.baseFeePerGas ?? 0n;
144
- // Get blob base fee if available
145
- let blobBaseFee = 0n;
146
- if (isBlobTx) {
147
- try {
148
- blobBaseFee = await retry(()=>this.client.getBlobBaseFee(), 'Getting L1 blob base fee', makeBackoff(times(2, ()=>1)), this.logger, true);
149
- this.logger?.debug('L1 Blob base fee:', {
150
- blobBaseFee: formatGwei(blobBaseFee)
151
- });
152
- } catch {
153
- this.logger?.warn('Failed to get L1 blob base fee', attempt);
154
- }
155
- }
156
- let priorityFee;
157
- if (gasConfig.fixedPriorityFeePerGas) {
158
- this.logger?.debug('Using fixed priority fee per L1 gas', {
159
- fixedPriorityFeePerGas: gasConfig.fixedPriorityFeePerGas
160
- });
161
- // try to maintain precision up to 1000000 wei
162
- priorityFee = BigInt(gasConfig.fixedPriorityFeePerGas * 1_000_000) * (WEI_CONST / 1_000_000n);
163
- } else {
164
- // Get initial priority fee from the network
165
- priorityFee = await this.client.estimateMaxPriorityFeePerGas();
166
- }
167
- let maxFeePerGas = baseFee;
168
- let maxFeePerBlobGas = blobBaseFee;
169
- // Bump base fee so it's valid for next blocks if it stalls
170
- const numBlocks = Math.ceil(gasConfig.stallTimeMs / BLOCK_TIME_MS);
171
- for(let i = 0; i < numBlocks; i++){
172
- // each block can go up 12.5% from previous baseFee
173
- maxFeePerGas = maxFeePerGas * (1_000n + 125n) / 1_000n;
174
- // same for blob gas fee
175
- maxFeePerBlobGas = maxFeePerBlobGas * (1_000n + 125n) / 1_000n;
176
- }
177
- if (attempt > 0) {
178
- const configBump = gasConfig.priorityFeeRetryBumpPercentage ?? defaultL1TxUtilsConfig.priorityFeeRetryBumpPercentage;
179
- // if this is a blob tx, we have to use the blob bump percentage
180
- const minBumpPercentage = isBlobTx ? MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE : MIN_REPLACEMENT_BUMP_PERCENTAGE;
181
- const bumpPercentage = configBump > minBumpPercentage ? configBump : minBumpPercentage;
182
- // Calculate minimum required fees based on previous attempt
183
- // multiply by 100 & divide by 100 to maintain some precision
184
- const minPriorityFee = previousGasPrice.maxPriorityFeePerGas * (100_00n + BigInt(bumpPercentage * 1_00)) / 100_00n;
185
- const minMaxFee = previousGasPrice.maxFeePerGas * (100_00n + BigInt(bumpPercentage * 1_00)) / 100_00n;
186
- // Add priority fee to maxFeePerGas
187
- maxFeePerGas += priorityFee;
188
- // Use maximum between current network values and minimum required values
189
- priorityFee = priorityFee > minPriorityFee ? priorityFee : minPriorityFee;
190
- maxFeePerGas = maxFeePerGas > minMaxFee ? maxFeePerGas : minMaxFee;
191
- } else {
192
- // first attempt, just bump priority fee, unless it's a fixed config
193
- // multiply by 100 & divide by 100 to maintain some precision
194
- if (!gasConfig.fixedPriorityFeePerGas) {
195
- priorityFee = priorityFee * (100_00n + BigInt((gasConfig.priorityFeeBumpPercentage || 0) * 1_00)) / 100_00n;
196
- }
197
- maxFeePerGas += priorityFee;
198
- }
199
- // Ensure we don't exceed maxGwei
200
- const maxGweiInWei = gasConfig.maxGwei * WEI_CONST;
201
- maxFeePerGas = maxFeePerGas > maxGweiInWei ? maxGweiInWei : maxFeePerGas;
202
- // Ensure we don't exceed maxBlobGwei
203
- if (maxFeePerBlobGas) {
204
- const maxBlobGweiInWei = gasConfig.maxBlobGwei * WEI_CONST;
205
- maxFeePerBlobGas = maxFeePerBlobGas > maxBlobGweiInWei ? maxBlobGweiInWei : maxFeePerBlobGas;
206
- }
207
- // Ensure priority fee doesn't exceed max fee
208
- const maxPriorityFeePerGas = priorityFee > maxFeePerGas ? maxFeePerGas : priorityFee;
209
- if (attempt > 0 && previousGasPrice?.maxFeePerBlobGas) {
210
- const bumpPercentage = gasConfig.priorityFeeRetryBumpPercentage > MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE ? gasConfig.priorityFeeRetryBumpPercentage : MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE;
211
- // calculate min blob fee based on previous attempt
212
- const minBlobFee = previousGasPrice.maxFeePerBlobGas * (100_00n + BigInt(bumpPercentage * 1_00)) / 100_00n;
213
- // use max between current network values and min required values
214
- maxFeePerBlobGas = maxFeePerBlobGas > minBlobFee ? maxFeePerBlobGas : minBlobFee;
215
- }
216
- this.logger?.debug(`Computed L1 gas price`, {
217
- attempt,
218
- baseFee: formatGwei(baseFee),
219
- maxFeePerGas: formatGwei(maxFeePerGas),
220
- maxPriorityFeePerGas: formatGwei(maxPriorityFeePerGas),
221
- ...maxFeePerBlobGas && {
222
- maxFeePerBlobGas: formatGwei(maxFeePerBlobGas)
223
- }
224
- });
225
- return {
226
- maxFeePerGas,
227
- maxPriorityFeePerGas,
228
- ...maxFeePerBlobGas && {
229
- maxFeePerBlobGas: maxFeePerBlobGas
230
- }
231
- };
232
- }
233
- /**
234
- * Estimates gas and adds buffer
235
- */ async estimateGas(account, request, _gasConfig, _blobInputs) {
236
- const gasConfig = {
237
- ...this.config,
238
- ..._gasConfig
239
- };
240
- let initialEstimate = 0n;
241
- if (_blobInputs) {
242
- // @note requests with blobs also require maxFeePerBlobGas to be set
243
- const gasPrice = await this.getGasPrice(gasConfig, true, 0);
244
- initialEstimate = await this.client.estimateGas({
245
- account,
246
- ...request,
247
- ..._blobInputs,
248
- maxFeePerBlobGas: gasPrice.maxFeePerBlobGas,
249
- gas: LARGE_GAS_LIMIT
250
- });
251
- this.logger?.debug(`L1 gas used in estimateGas by blob tx: ${initialEstimate}`);
252
- } else {
253
- initialEstimate = await this.client.estimateGas({
254
- account,
255
- ...request,
256
- gas: LARGE_GAS_LIMIT
257
- });
258
- this.logger?.debug(`L1 gas used in estimateGas by non-blob tx: ${initialEstimate}`);
259
- }
260
- // Add buffer based on either fixed amount or percentage
261
- const withBuffer = this.bumpGasLimit(initialEstimate, gasConfig);
262
- return withBuffer;
263
- }
264
- async getTransactionStats(txHash) {
265
- const tx = await this.client.getTransaction({
266
- hash: txHash
267
- });
268
- if (!tx) {
269
- return undefined;
270
- }
271
- const calldata = hexToBytes(tx.input);
272
- return {
273
- sender: tx.from.toString(),
274
- transactionHash: tx.hash,
275
- calldataSize: calldata.length,
276
- calldataGas: getCalldataGasUsage(calldata)
277
- };
278
- }
279
- async tryGetErrorFromRevertedTx(data, args, blobInputs, stateOverride = []) {
280
- try {
281
- await this.client.simulateContract({
282
- ...args,
283
- account: this.client.account,
284
- stateOverride
285
- });
286
- this.logger?.trace('Simulated blob tx', {
287
- blobInputs
288
- });
289
- // If the above passes, we have a blob error. We cannot simulate blob txs, and failed txs no longer throw errors.
290
- // Strangely, the only way to throw the revert reason as an error and provide blobs is prepareTransactionRequest.
291
- // See: https://github.com/wevm/viem/issues/2075
292
- // This throws a EstimateGasExecutionError with the custom error information:
293
- const request = blobInputs ? {
294
- account: this.client.account,
295
- to: args.address,
296
- data,
297
- blobs: blobInputs.blobs,
298
- kzg: blobInputs.kzg,
299
- maxFeePerBlobGas: blobInputs.maxFeePerBlobGas
300
- } : {
301
- account: this.client.account,
302
- to: args.address,
303
- data
304
- };
305
- this.logger?.trace('Preparing tx', {
306
- request
307
- });
308
- await this.client.prepareTransactionRequest(request);
309
- this.logger?.trace('Prepared tx');
310
- return undefined;
311
- } catch (simulationErr) {
312
- // If we don't have a ContractFunctionExecutionError, we have a blob related error => use getContractError to get the error msg.
313
- const contractErr = simulationErr.name === 'ContractFunctionExecutionError' ? simulationErr : getContractError(simulationErr, {
314
- args: [],
315
- abi: args.abi,
316
- functionName: args.functionName,
317
- address: args.address
318
- });
319
- if (contractErr.name === 'ContractFunctionExecutionError') {
320
- const execErr = contractErr;
321
- return tryGetCustomErrorNameContractFunction(execErr);
322
- }
323
- this.logger?.error(`Error getting error from simulation`, simulationErr);
324
- }
325
- }
326
- async simulate(request, blockOverrides = {}, stateOverrides = [], abi = RollupAbi, _gasConfig) {
327
- const gasConfig = {
328
- ...this.config,
329
- ..._gasConfig
330
- };
331
- const call = {
332
- to: request.to,
333
- data: request.data,
334
- ...request.from && {
335
- from: request.from
336
- }
337
- };
338
- return await this._simulate(call, blockOverrides, stateOverrides, gasConfig, abi);
339
- }
340
- async _simulate(call, blockOverrides = {}, stateOverrides = [], gasConfig, abi) {
341
- try {
342
- const result = await this.client.simulateBlocks({
343
- validation: false,
344
- blocks: [
345
- {
346
- blockOverrides,
347
- stateOverrides,
348
- calls: [
349
- call
350
- ]
351
- }
352
- ]
353
- });
354
- if (result[0].calls[0].status === 'failure') {
355
- this.logger?.error('L1 transaction simulation failed', result[0].calls[0].error);
356
- const decodedError = decodeErrorResult({
357
- abi,
358
- data: result[0].calls[0].data
359
- });
360
- throw new Error(`L1 transaction simulation failed with error ${decodedError.errorName}(${decodedError.args?.join(',')})`);
361
- }
362
- this.logger?.debug(`L1 transaction simulation succeeded`, {
363
- ...result[0].calls[0]
364
- });
365
- return {
366
- gasUsed: result[0].gasUsed,
367
- result: result[0].calls[0].data
368
- };
369
- } catch (err) {
370
- if (err instanceof MethodNotFoundRpcError || err instanceof MethodNotSupportedRpcError) {
371
- if (gasConfig.fallbackGasEstimate) {
372
- this.logger?.warn(`Node does not support eth_simulateV1 API. Using fallback gas estimate: ${gasConfig.fallbackGasEstimate}`);
373
- return {
374
- gasUsed: gasConfig.fallbackGasEstimate,
375
- result: '0x'
376
- };
377
- }
378
- this.logger?.error('Node does not support eth_simulateV1 API');
379
- }
380
- throw err;
381
- }
382
- }
383
- bumpGasLimit(gasLimit, _gasConfig) {
384
- const gasConfig = {
385
- ...this.config,
386
- ..._gasConfig
387
- };
388
- const bumpedGasLimit = gasLimit + gasLimit * BigInt((gasConfig?.gasLimitBufferPercentage || 0) * 1_00) / 100_00n;
389
- const cleanGasConfig = pickBy(gasConfig, (_, key)=>key in l1TxUtilsConfigMappings);
390
- this.logger?.debug('Bumping gas limit', {
391
- gasLimit,
392
- gasConfig: cleanGasConfig,
393
- bumpedGasLimit
394
- });
395
- return bumpedGasLimit;
396
- }
397
- }
11
+ import { formatViemError } from '../utils.js';
12
+ import { l1TxUtilsConfigMappings } from './config.js';
13
+ import { LARGE_GAS_LIMIT } from './constants.js';
14
+ import { ReadOnlyL1TxUtils } from './readonly_l1_tx_utils.js';
15
+ import { TxUtilsState } from './types.js';
398
16
  export class L1TxUtils extends ReadOnlyL1TxUtils {
399
17
  client;
400
18
  address;
@@ -404,7 +22,7 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
404
22
  lastMinedBlockNumber;
405
23
  nonceManager;
406
24
  constructor(client, address, signer, logger = createLogger('L1TxUtils'), dateProvider = new DateProvider(), config, debugMaxGasLimit = false){
407
- super(client, logger, dateProvider, config, debugMaxGasLimit), this.client = client, this.address = address, this.signer = signer, this.logger = logger, this.txUtilsState = 0, this.lastMinedBlockNumber = undefined;
25
+ super(client, logger, dateProvider, config, debugMaxGasLimit), this.client = client, this.address = address, this.signer = signer, this.logger = logger, this.txUtilsState = TxUtilsState.IDLE, this.lastMinedBlockNumber = undefined;
408
26
  this.nonceManager = createNonceManager({
409
27
  source: jsonRpc()
410
28
  });
@@ -443,7 +61,7 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
443
61
  * @param request - The transaction request (to, data, value)
444
62
  * @param gasConfig - Optional gas configuration
445
63
  * @returns The transaction hash and parameters used
446
- */ async sendTransaction(request, _gasConfig, blobInputs, stateChange = 1) {
64
+ */ async sendTransaction(request, _gasConfig, blobInputs, stateChange = TxUtilsState.SENT) {
447
65
  try {
448
66
  const gasConfig = {
449
67
  ...this.config,
@@ -588,7 +206,7 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
588
206
  } else {
589
207
  this.logger?.debug(`L1 transaction ${hash} mined`);
590
208
  }
591
- this.state = 5;
209
+ this.state = TxUtilsState.MINED;
592
210
  this.lastMinedAtBlockNumber = receipt.blockNumber;
593
211
  return receipt;
594
212
  }
@@ -600,7 +218,7 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
600
218
  }
601
219
  // If we get here then we have checked all of our tx versions and not found anything.
602
220
  // We should consider the nonce as MINED
603
- this.state = 5;
221
+ this.state = TxUtilsState.MINED;
604
222
  throw new Error(`Nonce ${nonce} is MINED but not by one of our expected transactions`);
605
223
  }
606
224
  this.logger?.trace(`Tx timeout check for ${currentTxHash}: ${isTimedOut()}`, {
@@ -658,7 +276,7 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
658
276
  serializedTransaction: signedRequest
659
277
  });
660
278
  if (!isCancelTx) {
661
- this.state = 2;
279
+ this.state = TxUtilsState.SPEED_UP;
662
280
  }
663
281
  const cleanGasConfig = pickBy(gasConfig, (_, key)=>key in l1TxUtilsConfigMappings);
664
282
  this.logger?.verbose(`Sent L1 speed-up tx ${newHash}, replacing ${currentTxHash}`, {
@@ -689,7 +307,7 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
689
307
  // The transaction has timed out. If it's a cancellation then we are giving up on it.
690
308
  // Otherwise we may attempt to cancel it if configured to do so.
691
309
  if (isCancelTx) {
692
- this.state = 4;
310
+ this.state = TxUtilsState.NOT_MINED;
693
311
  } else if (gasConfig.cancelTxOnTimeout) {
694
312
  // Fire cancellation without awaiting to avoid blocking the main thread
695
313
  this.attemptTxCancellation(currentTxHash, nonce, allVersions, isBlobTx, lastGasPrice, attempts).catch((err)=>{
@@ -786,7 +404,7 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
786
404
  const cancelTxHash = await this.client.sendRawTransaction({
787
405
  serializedTransaction: signedRequest
788
406
  });
789
- this.state = 3;
407
+ this.state = TxUtilsState.CANCELLED;
790
408
  this.logger?.info(`Sent cancellation tx ${cancelTxHash} for timed out tx ${currentTxHash}`, {
791
409
  nonce
792
410
  });
@@ -796,40 +414,3 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
796
414
  return receipt.transactionHash;
797
415
  }
798
416
  }
799
- export function createViemSigner(client) {
800
- const signer = async (tx, _address)=>{
801
- const signedTx = await client.signTransaction(tx);
802
- const parsed = parseTransaction(signedTx);
803
- if (!parsed.r || !parsed.s || parsed.yParity !== 0 && parsed.yParity !== 1) {
804
- throw new Error('Failed to extract signature from viem signed transaction');
805
- }
806
- return {
807
- r: parsed.r,
808
- s: parsed.s,
809
- yParity: parsed.yParity
810
- };
811
- };
812
- return signer;
813
- }
814
- export function createL1TxUtilsFromViemWallet(client, logger = createLogger('L1TxUtils'), dateProvider = new DateProvider(), config, debugMaxGasLimit = false) {
815
- return new L1TxUtils(client, EthAddress.fromString(client.account.address), createViemSigner(client), logger, dateProvider, config, debugMaxGasLimit);
816
- }
817
- export function createL1TxUtilsFromEthSigner(client, signer, logger = createLogger('L1TxUtils'), dateProvider = new DateProvider(), config, debugMaxGasLimit = false) {
818
- const callback = async (transaction, _signingAddress)=>{
819
- return (await signer.signTransaction(transaction)).toViemTransactionSignature();
820
- };
821
- return new L1TxUtils(client, signer.address, callback, logger, dateProvider, config, debugMaxGasLimit);
822
- }
823
- export function tryGetCustomErrorNameContractFunction(err) {
824
- return compactArray([
825
- err.shortMessage,
826
- ...(err.metaMessages ?? []).slice(0, 2).map((s)=>s.trim())
827
- ]).join(' ');
828
- }
829
- /*
830
- * Returns cost of calldata usage in Ethereum.
831
- * @param data - Calldata.
832
- * @returns 4 for each zero byte, 16 for each nonzero.
833
- */ export function getCalldataGasUsage(data) {
834
- return data.filter((byte)=>byte === 0).length * 4 + data.filter((byte)=>byte !== 0).length * 16;
835
- }
@@ -1,9 +1,11 @@
1
1
  import { type Logger } from '@aztec/foundation/log';
2
2
  import { DateProvider } from '@aztec/foundation/timer';
3
3
  import { type Hex } from 'viem';
4
- import type { EthSigner } from './eth-signer/eth-signer.js';
5
- import { type GasPrice, L1TxUtils, type L1TxUtilsConfig } from './l1_tx_utils.js';
6
- import type { ExtendedViemWalletClient, ViemClient } from './types.js';
4
+ import type { EthSigner } from '../eth-signer/eth-signer.js';
5
+ import type { ExtendedViemWalletClient, ViemClient } from '../types.js';
6
+ import type { L1TxUtilsConfig } from './config.js';
7
+ import { L1TxUtils } from './l1_tx_utils.js';
8
+ import type { GasPrice } from './types.js';
7
9
  export declare class L1TxUtilsWithBlobs extends L1TxUtils {
8
10
  /**
9
11
  * Attempts to cancel a transaction by sending a 0-value tx to self with same nonce but higher gas prices
@@ -13,7 +15,7 @@ export declare class L1TxUtilsWithBlobs extends L1TxUtils {
13
15
  * @param attempts - The number of attempts to cancel the transaction
14
16
  * @returns The hash of the cancellation transaction
15
17
  */
16
- attemptTxCancellation(currentTxHash: Hex, nonce: number, allVersions: Set<Hex>, isBlobTx?: boolean, previousGasPrice?: GasPrice, attempts?: number): Promise<`0x${string}`>;
18
+ protected attemptTxCancellation(currentTxHash: Hex, nonce: number, allVersions: Set<Hex>, isBlobTx?: boolean, previousGasPrice?: GasPrice, attempts?: number): Promise<`0x${string}`>;
17
19
  }
18
20
  export declare function createL1TxUtilsWithBlobsFromViemWallet(client: ExtendedViemWalletClient, logger?: Logger, dateProvider?: DateProvider, config?: Partial<L1TxUtilsConfig>, debugMaxGasLimit?: boolean): L1TxUtilsWithBlobs;
19
21
  export declare function createL1TxUtilsWithBlobsFromEthSigner(client: ViemClient, signer: EthSigner, logger?: Logger, dateProvider?: DateProvider, config?: Partial<L1TxUtilsConfig>, debugMaxGasLimit?: boolean): L1TxUtilsWithBlobs;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"l1_tx_utils_with_blobs.d.ts","sourceRoot":"","sources":["../../src/l1_tx_utils/l1_tx_utils_with_blobs.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,KAAK,GAAG,EAA4C,MAAM,MAAM,CAAC;AAE1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,wBAAwB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,EAAE,QAAQ,EAAmB,MAAM,YAAY,CAAC;AAE5D,qBAAa,kBAAmB,SAAQ,SAAS;IAC/C;;;;;;;OAOG;cACsB,qBAAqB,CAC5C,aAAa,EAAE,GAAG,EAClB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,GAAG,CAAC,GAAG,CAAC,EACrB,QAAQ,UAAQ,EAChB,gBAAgB,CAAC,EAAE,QAAQ,EAC3B,QAAQ,SAAI;CAoFf;AAED,wBAAgB,sCAAsC,CACpD,MAAM,EAAE,wBAAwB,EAChC,MAAM,GAAE,MAAkC,EAC1C,YAAY,GAAE,YAAiC,EAC/C,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,EACjC,gBAAgB,GAAE,OAAe,sBAWlC;AAED,wBAAgB,qCAAqC,CACnD,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,SAAS,EACjB,MAAM,GAAE,MAAkC,EAC1C,YAAY,GAAE,YAAiC,EAC/C,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,EACjC,gBAAgB,GAAE,OAAe,sBAOlC"}
@@ -3,7 +3,8 @@ import { EthAddress } from '@aztec/foundation/eth-address';
3
3
  import { createLogger } from '@aztec/foundation/log';
4
4
  import { DateProvider } from '@aztec/foundation/timer';
5
5
  import { formatGwei } from 'viem';
6
- import { L1TxUtils, createViemSigner } from './l1_tx_utils.js';
6
+ import { L1TxUtils } from './l1_tx_utils.js';
7
+ import { createViemSigner } from './signer.js';
7
8
  export class L1TxUtilsWithBlobs extends L1TxUtils {
8
9
  /**
9
10
  * Attempts to cancel a transaction by sending a 0-value tx to self with same nonce but higher gas prices