@aztec/ethereum 0.0.1-commit.b655e406 → 0.0.1-commit.c7c42ec

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 (184) hide show
  1. package/dest/account.d.ts +1 -1
  2. package/dest/chain.d.ts +1 -1
  3. package/dest/client.d.ts +1 -1
  4. package/dest/client.js +6 -2
  5. package/dest/config.d.ts +11 -44
  6. package/dest/config.d.ts.map +1 -1
  7. package/dest/config.js +20 -332
  8. package/dest/constants.d.ts +1 -1
  9. package/dest/contracts/empire_base.d.ts +7 -5
  10. package/dest/contracts/empire_base.d.ts.map +1 -1
  11. package/dest/contracts/empire_base.js +1 -1
  12. package/dest/contracts/empire_slashing_proposer.d.ts +6 -4
  13. package/dest/contracts/empire_slashing_proposer.d.ts.map +1 -1
  14. package/dest/contracts/empire_slashing_proposer.js +17 -2
  15. package/dest/contracts/errors.d.ts +1 -1
  16. package/dest/contracts/errors.d.ts.map +1 -1
  17. package/dest/contracts/fee_asset_handler.d.ts +1 -1
  18. package/dest/contracts/fee_asset_handler.d.ts.map +1 -1
  19. package/dest/contracts/fee_juice.d.ts +1 -1
  20. package/dest/contracts/fee_juice.d.ts.map +1 -1
  21. package/dest/contracts/governance.d.ts +16 -16
  22. package/dest/contracts/governance.d.ts.map +1 -1
  23. package/dest/contracts/governance_proposer.d.ts +6 -4
  24. package/dest/contracts/governance_proposer.d.ts.map +1 -1
  25. package/dest/contracts/governance_proposer.js +17 -2
  26. package/dest/contracts/gse.d.ts +1 -1
  27. package/dest/contracts/gse.d.ts.map +1 -1
  28. package/dest/contracts/inbox.d.ts +7 -3
  29. package/dest/contracts/inbox.d.ts.map +1 -1
  30. package/dest/contracts/inbox.js +4 -0
  31. package/dest/contracts/index.d.ts +1 -1
  32. package/dest/contracts/multicall.d.ts +2 -2
  33. package/dest/contracts/multicall.d.ts.map +1 -1
  34. package/dest/contracts/registry.d.ts +1 -1
  35. package/dest/contracts/registry.d.ts.map +1 -1
  36. package/dest/contracts/rollup.d.ts +71 -64
  37. package/dest/contracts/rollup.d.ts.map +1 -1
  38. package/dest/contracts/rollup.js +90 -67
  39. package/dest/contracts/slasher_contract.d.ts +1 -1
  40. package/dest/contracts/slasher_contract.d.ts.map +1 -1
  41. package/dest/contracts/tally_slashing_proposer.d.ts +9 -7
  42. package/dest/contracts/tally_slashing_proposer.d.ts.map +1 -1
  43. package/dest/contracts/tally_slashing_proposer.js +4 -4
  44. package/dest/contracts/utils.d.ts +1 -1
  45. package/dest/deploy_aztec_l1_contracts.d.ts +247 -0
  46. package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -0
  47. package/dest/deploy_aztec_l1_contracts.js +336 -0
  48. package/dest/deploy_l1_contract.d.ts +68 -0
  49. package/dest/deploy_l1_contract.d.ts.map +1 -0
  50. package/dest/deploy_l1_contract.js +312 -0
  51. package/dest/eth-signer/eth-signer.d.ts +1 -1
  52. package/dest/eth-signer/index.d.ts +1 -1
  53. package/dest/forwarder_proxy.d.ts +32 -0
  54. package/dest/forwarder_proxy.d.ts.map +1 -0
  55. package/dest/forwarder_proxy.js +93 -0
  56. package/dest/l1_artifacts.d.ts +2078 -880
  57. package/dest/l1_artifacts.d.ts.map +1 -1
  58. package/dest/l1_contract_addresses.d.ts +3 -3
  59. package/dest/l1_contract_addresses.d.ts.map +1 -1
  60. package/dest/l1_contract_addresses.js +3 -3
  61. package/dest/l1_reader.d.ts +3 -1
  62. package/dest/l1_reader.d.ts.map +1 -1
  63. package/dest/l1_reader.js +6 -0
  64. package/dest/l1_tx_utils/config.d.ts +5 -5
  65. package/dest/l1_tx_utils/config.d.ts.map +1 -1
  66. package/dest/l1_tx_utils/config.js +30 -7
  67. package/dest/l1_tx_utils/constants.d.ts +7 -1
  68. package/dest/l1_tx_utils/constants.d.ts.map +1 -1
  69. package/dest/l1_tx_utils/constants.js +25 -0
  70. package/dest/l1_tx_utils/factory.d.ts +1 -1
  71. package/dest/l1_tx_utils/fee-strategies/index.d.ts +9 -0
  72. package/dest/l1_tx_utils/fee-strategies/index.d.ts.map +1 -0
  73. package/dest/l1_tx_utils/fee-strategies/index.js +11 -0
  74. package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts +18 -0
  75. package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts.map +1 -0
  76. package/dest/l1_tx_utils/fee-strategies/p75_competitive.js +111 -0
  77. package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts +32 -0
  78. package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts.map +1 -0
  79. package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.js +173 -0
  80. package/dest/l1_tx_utils/fee-strategies/types.d.ts +64 -0
  81. package/dest/l1_tx_utils/fee-strategies/types.d.ts.map +1 -0
  82. package/dest/l1_tx_utils/fee-strategies/types.js +24 -0
  83. package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts +41 -0
  84. package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts.map +1 -0
  85. package/dest/l1_tx_utils/forwarder_l1_tx_utils.js +48 -0
  86. package/dest/l1_tx_utils/index-blobs.d.ts +3 -0
  87. package/dest/l1_tx_utils/index-blobs.d.ts.map +1 -0
  88. package/dest/l1_tx_utils/index-blobs.js +2 -0
  89. package/dest/l1_tx_utils/index.d.ts +3 -1
  90. package/dest/l1_tx_utils/index.d.ts.map +1 -1
  91. package/dest/l1_tx_utils/index.js +2 -0
  92. package/dest/l1_tx_utils/interfaces.d.ts +2 -2
  93. package/dest/l1_tx_utils/interfaces.d.ts.map +1 -1
  94. package/dest/l1_tx_utils/l1_fee_analyzer.d.ts +233 -0
  95. package/dest/l1_tx_utils/l1_fee_analyzer.d.ts.map +1 -0
  96. package/dest/l1_tx_utils/l1_fee_analyzer.js +506 -0
  97. package/dest/l1_tx_utils/l1_tx_utils.d.ts +1 -2
  98. package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
  99. package/dest/l1_tx_utils/l1_tx_utils.js +17 -4
  100. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts +1 -1
  101. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +1 -1
  102. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +19 -26
  103. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -1
  104. package/dest/l1_tx_utils/readonly_l1_tx_utils.js +70 -141
  105. package/dest/l1_tx_utils/signer.d.ts +1 -1
  106. package/dest/l1_tx_utils/types.d.ts +1 -1
  107. package/dest/l1_tx_utils/types.d.ts.map +1 -1
  108. package/dest/l1_tx_utils/utils.d.ts +1 -1
  109. package/dest/l1_types.d.ts +1 -1
  110. package/dest/publisher_manager.d.ts +1 -1
  111. package/dest/publisher_manager.d.ts.map +1 -1
  112. package/dest/queries.d.ts +1 -1
  113. package/dest/queries.d.ts.map +1 -1
  114. package/dest/queries.js +10 -3
  115. package/dest/test/chain_monitor.d.ts +27 -24
  116. package/dest/test/chain_monitor.d.ts.map +1 -1
  117. package/dest/test/chain_monitor.js +32 -34
  118. package/dest/test/delayed_tx_utils.d.ts +1 -1
  119. package/dest/test/delayed_tx_utils.d.ts.map +1 -1
  120. package/dest/test/eth_cheat_codes.d.ts +8 -12
  121. package/dest/test/eth_cheat_codes.d.ts.map +1 -1
  122. package/dest/test/eth_cheat_codes.js +11 -3
  123. package/dest/test/eth_cheat_codes_with_state.d.ts +1 -1
  124. package/dest/test/eth_cheat_codes_with_state.d.ts.map +1 -1
  125. package/dest/test/index.d.ts +1 -1
  126. package/dest/test/rollup_cheat_codes.d.ts +14 -13
  127. package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
  128. package/dest/test/rollup_cheat_codes.js +46 -39
  129. package/dest/test/start_anvil.d.ts +4 -1
  130. package/dest/test/start_anvil.d.ts.map +1 -1
  131. package/dest/test/start_anvil.js +2 -1
  132. package/dest/test/tx_delayer.d.ts +1 -1
  133. package/dest/test/tx_delayer.d.ts.map +1 -1
  134. package/dest/test/tx_delayer.js +4 -3
  135. package/dest/test/upgrade_utils.d.ts +1 -1
  136. package/dest/types.d.ts +57 -2
  137. package/dest/types.d.ts.map +1 -1
  138. package/dest/utils.d.ts +15 -3
  139. package/dest/utils.d.ts.map +1 -1
  140. package/dest/utils.js +18 -0
  141. package/dest/zkPassportVerifierAddress.d.ts +1 -1
  142. package/package.json +33 -14
  143. package/src/client.ts +2 -2
  144. package/src/config.ts +24 -412
  145. package/src/contracts/empire_base.ts +6 -5
  146. package/src/contracts/empire_slashing_proposer.ts +16 -5
  147. package/src/contracts/governance_proposer.ts +16 -5
  148. package/src/contracts/inbox.ts +7 -2
  149. package/src/contracts/rollup.ts +99 -82
  150. package/src/contracts/tally_slashing_proposer.ts +11 -8
  151. package/src/deploy_aztec_l1_contracts.ts +557 -0
  152. package/src/deploy_l1_contract.ts +362 -0
  153. package/src/forwarder_proxy.ts +108 -0
  154. package/src/l1_contract_addresses.ts +22 -20
  155. package/src/l1_reader.ts +8 -0
  156. package/src/l1_tx_utils/config.ts +32 -11
  157. package/src/l1_tx_utils/constants.ts +11 -0
  158. package/src/l1_tx_utils/fee-strategies/index.ts +22 -0
  159. package/src/l1_tx_utils/fee-strategies/p75_competitive.ts +159 -0
  160. package/src/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.ts +241 -0
  161. package/src/l1_tx_utils/fee-strategies/types.ts +88 -0
  162. package/src/l1_tx_utils/forwarder_l1_tx_utils.ts +119 -0
  163. package/src/l1_tx_utils/index-blobs.ts +2 -0
  164. package/src/l1_tx_utils/index.ts +2 -0
  165. package/src/l1_tx_utils/interfaces.ts +1 -1
  166. package/src/l1_tx_utils/l1_fee_analyzer.ts +804 -0
  167. package/src/l1_tx_utils/l1_tx_utils.ts +24 -4
  168. package/src/l1_tx_utils/readonly_l1_tx_utils.ts +78 -179
  169. package/src/queries.ts +12 -3
  170. package/src/test/chain_monitor.ts +50 -48
  171. package/src/test/eth_cheat_codes.ts +9 -3
  172. package/src/test/rollup_cheat_codes.ts +45 -43
  173. package/src/test/start_anvil.ts +4 -0
  174. package/src/test/tx_delayer.ts +5 -3
  175. package/src/types.ts +62 -0
  176. package/src/utils.ts +30 -1
  177. package/dest/deploy_l1_contracts.d.ts +0 -226
  178. package/dest/deploy_l1_contracts.d.ts.map +0 -1
  179. package/dest/deploy_l1_contracts.js +0 -1473
  180. package/dest/index.d.ts +0 -18
  181. package/dest/index.d.ts.map +0 -1
  182. package/dest/index.js +0 -17
  183. package/src/deploy_l1_contracts.ts +0 -1849
  184. package/src/index.ts +0 -17
@@ -130,12 +130,32 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
130
130
  return;
131
131
  }
132
132
 
133
- // Convert loaded states (which have id) to the txs format
134
- this.txs = loadedStates;
135
- this.logger.info(`Rehydrated ${loadedStates.length} tx states for account ${account}`);
133
+ // Clean up excess states if we have more than MAX_L1_TX_STATES
134
+ if (loadedStates.length > MAX_L1_TX_STATES) {
135
+ this.logger.warn(
136
+ `Found ${loadedStates.length} tx states for account ${account}, pruning to most recent ${MAX_L1_TX_STATES}`,
137
+ );
138
+
139
+ // Keep only the most recent MAX_L1_TX_STATES
140
+ const statesToKeep = loadedStates.slice(-MAX_L1_TX_STATES);
141
+ const statesToDelete = loadedStates.slice(0, -MAX_L1_TX_STATES);
142
+
143
+ // Batch delete old states in a transaction for efficiency
144
+ const idsToDelete = statesToDelete.map(s => s.id);
145
+ await this.store.deleteState(account, ...idsToDelete);
146
+
147
+ this.txs = statesToKeep;
148
+ this.logger.info(
149
+ `Cleaned up ${statesToDelete.length} old tx states, kept ${statesToKeep.length} for account ${account}`,
150
+ );
151
+ } else {
152
+ // Convert loaded states (which have id) to the txs format
153
+ this.txs = loadedStates;
154
+ this.logger.info(`Rehydrated ${loadedStates.length} tx states for account ${account}`);
155
+ }
136
156
 
137
157
  // Find all pending states and resume monitoring
138
- const pendingStates = loadedStates.filter(state => !TerminalTxUtilsState.includes(state.status));
158
+ const pendingStates = this.txs.filter(state => !TerminalTxUtilsState.includes(state.status));
139
159
  if (pendingStates.length === 0) {
140
160
  return;
141
161
  }
@@ -1,4 +1,5 @@
1
- import { getKeys, median, merge, pick, times } from '@aztec/foundation/collection';
1
+ import { getKeys, merge, pick, times } from '@aztec/foundation/collection';
2
+ import type { EthAddress } from '@aztec/foundation/eth-address';
2
3
  import { type Logger, createLogger } from '@aztec/foundation/log';
3
4
  import { makeBackoff, retry } from '@aztec/foundation/retry';
4
5
  import { DateProvider } from '@aztec/foundation/timer';
@@ -11,6 +12,7 @@ import {
11
12
  type BaseError,
12
13
  type BlockOverrides,
13
14
  type ContractFunctionExecutionError,
15
+ type GetCodeReturnType,
14
16
  type Hex,
15
17
  MethodNotFoundRpcError,
16
18
  MethodNotSupportedRpcError,
@@ -30,10 +32,12 @@ import {
30
32
  MIN_REPLACEMENT_BUMP_PERCENTAGE,
31
33
  WEI_CONST,
32
34
  } from './constants.js';
35
+ import { P75AllTxsPriorityFeeStrategy, type PriorityFeeStrategy } from './fee-strategies/index.js';
33
36
  import type { GasPrice, L1BlobInputs, L1TxRequest, TransactionStats } from './types.js';
34
37
  import { getCalldataGasUsage, tryGetCustomErrorNameContractFunction } from './utils.js';
35
38
 
36
- const HISTORICAL_BLOCK_COUNT = 5;
39
+ // Change this to the current strategy we want to use
40
+ const CurrentStrategy: PriorityFeeStrategy = P75AllTxsPriorityFeeStrategy;
37
41
 
38
42
  export class ReadOnlyL1TxUtils {
39
43
  public config: Required<L1TxUtilsConfig>;
@@ -65,122 +69,8 @@ export class ReadOnlyL1TxUtils {
65
69
  return this.client.getBlockNumber();
66
70
  }
67
71
 
68
- /**
69
- * Analyzes pending transactions and recent fee history to determine a competitive priority fee.
70
- * Falls back to network estimate if data is unavailable or fails.
71
- * @param networkEstimateResult - Result from estimateMaxPriorityFeePerGas RPC call
72
- * @param pendingBlockResult - Result from getBlock with pending tag RPC call
73
- * @param feeHistoryResult - Result from getFeeHistory RPC call
74
- * @returns A competitive priority fee based on pending txs and recent block history
75
- */
76
- protected getCompetitivePriorityFee(
77
- networkEstimateResult: PromiseSettledResult<bigint | null>,
78
- pendingBlockResult: PromiseSettledResult<Awaited<ReturnType<ViemClient['getBlock']>> | null>,
79
- feeHistoryResult: PromiseSettledResult<Awaited<ReturnType<ViemClient['getFeeHistory']>> | null>,
80
- ): bigint {
81
- const networkEstimate =
82
- networkEstimateResult.status === 'fulfilled' && typeof networkEstimateResult.value === 'bigint'
83
- ? networkEstimateResult.value
84
- : 0n;
85
- let competitiveFee = networkEstimate;
86
-
87
- if (
88
- pendingBlockResult.status === 'fulfilled' &&
89
- pendingBlockResult.value !== null &&
90
- pendingBlockResult.value.transactions &&
91
- pendingBlockResult.value.transactions.length > 0
92
- ) {
93
- const pendingBlock = pendingBlockResult.value;
94
- // Extract priority fees from pending transactions
95
- const pendingFees = pendingBlock.transactions
96
- .map(tx => {
97
- // Transaction can be just a hash string, so we need to check if it's an object
98
- if (typeof tx === 'string') {
99
- return 0n;
100
- }
101
- const fee = tx.maxPriorityFeePerGas || 0n;
102
- // Debug: Log suspicious fees
103
- if (fee > 100n * WEI_CONST) {
104
- this.logger?.warn('Suspicious high priority fee in pending tx', {
105
- txHash: tx.hash,
106
- maxPriorityFeePerGas: formatGwei(fee),
107
- maxFeePerGas: formatGwei(tx.maxFeePerGas || 0n),
108
- maxFeePerBlobGas: tx.maxFeePerBlobGas ? formatGwei(tx.maxFeePerBlobGas) : 'N/A',
109
- });
110
- }
111
- return fee;
112
- })
113
- .filter((fee: bigint) => fee > 0n);
114
-
115
- if (pendingFees.length > 0) {
116
- // Use 75th percentile of pending fees to be competitive
117
- const sortedPendingFees = [...pendingFees].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
118
- const percentile75Index = Math.floor((sortedPendingFees.length - 1) * 0.75);
119
- const pendingCompetitiveFee = sortedPendingFees[percentile75Index];
120
-
121
- if (pendingCompetitiveFee > competitiveFee) {
122
- competitiveFee = pendingCompetitiveFee;
123
- }
124
-
125
- this.logger?.debug('Analyzed pending transactions for competitive pricing', {
126
- pendingTxCount: pendingFees.length,
127
- pendingP75: formatGwei(pendingCompetitiveFee),
128
- });
129
- }
130
- }
131
- if (
132
- feeHistoryResult.status === 'fulfilled' &&
133
- feeHistoryResult.value !== null &&
134
- feeHistoryResult.value.reward &&
135
- feeHistoryResult.value.reward.length > 0
136
- ) {
137
- const feeHistory = feeHistoryResult.value;
138
- // Extract 75th percentile fees from each block
139
- const percentile75Fees = feeHistory.reward!.map(rewards => rewards[0] || 0n).filter(fee => fee > 0n);
140
-
141
- if (percentile75Fees.length > 0) {
142
- // Calculate median of the 75th percentile fees across blocks
143
- const medianHistoricalFee = median(percentile75Fees) ?? 0n;
144
-
145
- // Debug: Log suspicious fees from history
146
- if (medianHistoricalFee > 100n * WEI_CONST) {
147
- this.logger?.warn('Suspicious high fee in history', {
148
- historicalMedian: formatGwei(medianHistoricalFee),
149
- allP75Fees: percentile75Fees.map(f => formatGwei(f)),
150
- });
151
- }
152
-
153
- if (medianHistoricalFee > competitiveFee) {
154
- competitiveFee = medianHistoricalFee;
155
- }
156
-
157
- this.logger?.debug('Analyzed fee history for competitive pricing', {
158
- historicalMedian: formatGwei(medianHistoricalFee),
159
- });
160
- }
161
- }
162
-
163
- // Sanity check: cap competitive fee at 100x network estimate to avoid using unrealistic fees
164
- // (e.g., Anvil returns inflated historical fees that don't reflect actual network conditions)
165
- const maxReasonableFee = networkEstimate * 100n;
166
- if (competitiveFee > maxReasonableFee) {
167
- this.logger?.warn('Competitive fee exceeds sanity cap, using capped value', {
168
- competitiveFee: formatGwei(competitiveFee),
169
- networkEstimate: formatGwei(networkEstimate),
170
- cappedTo: formatGwei(maxReasonableFee),
171
- });
172
- competitiveFee = maxReasonableFee;
173
- }
174
-
175
- // Log final decision
176
- if (competitiveFee > networkEstimate) {
177
- this.logger?.debug('Using competitive fee from market analysis', {
178
- networkEstimate: formatGwei(networkEstimate),
179
- competitive: formatGwei(competitiveFee),
180
- });
181
- }
182
-
183
- return competitiveFee;
72
+ public getCode(address: EthAddress): Promise<GetCodeReturnType> {
73
+ return this.client.getCode({ address: address.toString() });
184
74
  }
185
75
 
186
76
  /**
@@ -195,37 +85,31 @@ export class ReadOnlyL1TxUtils {
195
85
  const gasConfig = merge(this.config, gasConfigOverrides);
196
86
 
197
87
  // Make all RPC calls in parallel upfront with retry logic
88
+ // First 2 calls are necessary to complete
198
89
  const latestBlockPromise = this.tryTwice(
199
90
  () => this.client.getBlock({ blockTag: 'latest' }),
200
91
  'Getting latest block',
201
92
  );
202
- const networkEstimatePromise = gasConfig.fixedPriorityFeePerGas
203
- ? null
204
- : this.tryTwice(() => this.client.estimateMaxPriorityFeePerGas(), 'Estimating max priority fee per gas');
205
- const pendingBlockPromise = gasConfig.fixedPriorityFeePerGas
206
- ? null
207
- : this.tryTwice(
208
- () => this.client.getBlock({ blockTag: 'pending', includeTransactions: true }),
209
- 'Getting pending block',
210
- );
211
- const feeHistoryPromise = gasConfig.fixedPriorityFeePerGas
212
- ? null
213
- : this.tryTwice(
214
- () => this.client.getFeeHistory({ blockCount: HISTORICAL_BLOCK_COUNT, rewardPercentiles: [75] }),
215
- 'Getting fee history',
216
- );
217
- const blobBaseFeePromise = isBlobTx
218
- ? this.tryTwice(() => this.client.getBlobBaseFee(), 'Getting blob base fee')
219
- : null;
220
-
221
- const [latestBlockResult, networkEstimateResult, pendingBlockResult, feeHistoryResult, blobBaseFeeResult] =
222
- await Promise.allSettled([
223
- latestBlockPromise,
224
- networkEstimatePromise ?? Promise.resolve(0n),
225
- pendingBlockPromise ?? Promise.resolve(null),
226
- feeHistoryPromise ?? Promise.resolve(null),
227
- blobBaseFeePromise ?? Promise.resolve(0n),
228
- ]);
93
+
94
+ let blobBaseFeePromise = null;
95
+ if (isBlobTx) {
96
+ blobBaseFeePromise = this.tryTwice(() => this.client.getBlobBaseFee(), 'Getting blob base fee');
97
+ }
98
+
99
+ // Get strategy promises for priority fee calculation
100
+ const strategyPromises = CurrentStrategy.getRequiredPromises(this.client, { isBlobTx });
101
+ const strategyPromiseKeys = [];
102
+ const strategyPromisesArr = [];
103
+ for (const [key, promise] of Object.entries(strategyPromises)) {
104
+ strategyPromiseKeys.push(key);
105
+ strategyPromisesArr.push(this.tryTwice(() => promise, `Getting strategy data for ${key}`));
106
+ }
107
+
108
+ const [latestBlockResult, blobBaseFeeResult, ...strategyResults] = await Promise.allSettled([
109
+ latestBlockPromise,
110
+ blobBaseFeePromise ?? Promise.resolve(0n),
111
+ ...strategyPromisesArr,
112
+ ]);
229
113
 
230
114
  // Extract results
231
115
  const baseFee =
@@ -244,15 +128,31 @@ export class ReadOnlyL1TxUtils {
244
128
  }
245
129
 
246
130
  let priorityFee: bigint;
247
- if (gasConfig.fixedPriorityFeePerGas) {
248
- this.logger?.debug('Using fixed priority fee per L1 gas', {
249
- fixedPriorityFeePerGas: gasConfig.fixedPriorityFeePerGas,
250
- });
251
- // try to maintain precision up to 1000000 wei
252
- priorityFee = BigInt(gasConfig.fixedPriorityFeePerGas * 1_000_000) * (WEI_CONST / 1_000_000n);
253
- } else {
254
- // Get competitive priority fee (includes network estimate + analysis)
255
- priorityFee = this.getCompetitivePriorityFee(networkEstimateResult, pendingBlockResult, feeHistoryResult);
131
+ // Get competitive priority fee using strategy
132
+ // Reconstruct the results object with the same keys as the promises
133
+ const resultsObject: Record<string, PromiseSettledResult<unknown>> = {};
134
+ strategyPromiseKeys.forEach((key, index) => {
135
+ resultsObject[key] = strategyResults[index];
136
+ });
137
+
138
+ const result = CurrentStrategy.calculate(resultsObject as any, {
139
+ gasConfig,
140
+ isBlobTx,
141
+ logger: this.logger,
142
+ });
143
+ priorityFee = result.priorityFee;
144
+
145
+ // Apply minimum priority fee floor if configured
146
+ if (gasConfig.minimumPriorityFeePerGas) {
147
+ const minimumPriorityFee = BigInt(Math.trunc(gasConfig.minimumPriorityFeePerGas * Number(WEI_CONST)));
148
+ if (priorityFee < minimumPriorityFee) {
149
+ this.logger?.debug('Applying minimum priority fee floor', {
150
+ calculatedPriorityFee: formatGwei(priorityFee),
151
+ minimumPriorityFeePerGas: gasConfig.minimumPriorityFeePerGas,
152
+ appliedFee: formatGwei(minimumPriorityFee),
153
+ });
154
+ priorityFee = minimumPriorityFee;
155
+ }
256
156
  }
257
157
  let maxFeePerGas = baseFee;
258
158
 
@@ -281,18 +181,15 @@ export class ReadOnlyL1TxUtils {
281
181
  (previousGasPrice!.maxPriorityFeePerGas * (100_00n + BigInt(bumpPercentage * 1_00))) / 100_00n;
282
182
  const minMaxFee = (previousGasPrice!.maxFeePerGas * (100_00n + BigInt(bumpPercentage * 1_00))) / 100_00n;
283
183
 
284
- let competitivePriorityFee = priorityFee;
285
- if (!gasConfig.fixedPriorityFeePerGas) {
286
- // Apply bump percentage to competitive fee
287
- competitivePriorityFee = (priorityFee * (100_00n + BigInt(configBump * 1_00))) / 100_00n;
184
+ // Apply bump percentage to competitive fee
185
+ const competitivePriorityFee = (priorityFee * (100_00n + BigInt(configBump * 1_00))) / 100_00n;
288
186
 
289
- this.logger?.debug(`Speed-up attempt ${attempt}: using competitive fee strategy`, {
290
- networkEstimate: formatGwei(priorityFee),
291
- competitiveFee: formatGwei(competitivePriorityFee),
292
- minRequired: formatGwei(minPriorityFee),
293
- bumpPercentage: configBump,
294
- });
295
- }
187
+ this.logger?.debug(`Speed-up attempt ${attempt}: using competitive fee strategy`, {
188
+ networkEstimate: formatGwei(priorityFee),
189
+ competitiveFee: formatGwei(competitivePriorityFee),
190
+ minRequired: formatGwei(minPriorityFee),
191
+ bumpPercentage: configBump,
192
+ });
296
193
 
297
194
  // Use maximum between competitive fee and minimum required bump
298
195
  const finalPriorityFee = competitivePriorityFee > minPriorityFee ? competitivePriorityFee : minPriorityFee;
@@ -303,26 +200,22 @@ export class ReadOnlyL1TxUtils {
303
200
  maxFeePerGas += finalPriorityFee;
304
201
  maxFeePerGas = maxFeePerGas > minMaxFee ? maxFeePerGas : minMaxFee;
305
202
 
306
- if (!gasConfig.fixedPriorityFeePerGas) {
307
- this.logger?.debug(`Speed-up fee decision: using ${feeSource} fee`, {
308
- finalPriorityFee: formatGwei(finalPriorityFee),
309
- });
310
- }
203
+ this.logger?.debug(`Speed-up fee decision: using ${feeSource} fee`, {
204
+ finalPriorityFee: formatGwei(finalPriorityFee),
205
+ });
311
206
  } else {
312
207
  // First attempt: apply configured bump percentage to competitive fee
313
208
  // multiply by 100 & divide by 100 to maintain some precision
314
- if (!gasConfig.fixedPriorityFeePerGas) {
315
- priorityFee = (priorityFee * (100_00n + BigInt((gasConfig.priorityFeeBumpPercentage || 0) * 1_00))) / 100_00n;
316
- this.logger?.debug('Initial transaction: using competitive fee from market analysis', {
317
- networkEstimate: formatGwei(priorityFee),
318
- });
319
- }
209
+ priorityFee = (priorityFee * (100_00n + BigInt((gasConfig.priorityFeeBumpPercentage || 0) * 1_00))) / 100_00n;
210
+ this.logger?.debug('Initial transaction: using competitive fee from market analysis', {
211
+ networkEstimate: formatGwei(priorityFee),
212
+ });
320
213
  maxFeePerGas += priorityFee;
321
214
  }
322
215
 
323
216
  // maxGwei and maxBlobGwei are hard limits
324
- const effectiveMaxGwei = gasConfig.maxGwei! * WEI_CONST;
325
- const effectiveMaxBlobGwei = gasConfig.maxBlobGwei! * WEI_CONST;
217
+ const effectiveMaxGwei = BigInt(Math.trunc(gasConfig.maxGwei! * Number(WEI_CONST)));
218
+ const effectiveMaxBlobGwei = BigInt(Math.trunc(gasConfig.maxBlobGwei! * Number(WEI_CONST)));
326
219
 
327
220
  // Ensure we don't exceed maxGwei
328
221
  if (effectiveMaxGwei > 0n) {
@@ -389,11 +282,17 @@ export class ReadOnlyL1TxUtils {
389
282
  ..._blobInputs,
390
283
  maxFeePerBlobGas: gasPrice.maxFeePerBlobGas!,
391
284
  gas: LARGE_GAS_LIMIT,
285
+ blockTag: 'latest',
392
286
  });
393
287
 
394
288
  this.logger?.trace(`Estimated gas for blob tx: ${initialEstimate}`);
395
289
  } else {
396
- initialEstimate = await this.client.estimateGas({ account, ...request, gas: LARGE_GAS_LIMIT });
290
+ initialEstimate = await this.client.estimateGas({
291
+ account,
292
+ ...request,
293
+ gas: LARGE_GAS_LIMIT,
294
+ blockTag: 'latest',
295
+ });
397
296
  this.logger?.trace(`Estimated gas for non-blob tx: ${initialEstimate}`);
398
297
  }
399
298
 
package/src/queries.ts CHANGED
@@ -3,6 +3,7 @@ import { EthAddress } from '@aztec/foundation/eth-address';
3
3
  import type { L1ContractsConfig } from './config.js';
4
4
  import { ReadOnlyGovernanceContract } from './contracts/governance.js';
5
5
  import { GovernanceProposerContract } from './contracts/governance_proposer.js';
6
+ import { InboxContract } from './contracts/inbox.js';
6
7
  import { RollupContract } from './contracts/rollup.js';
7
8
  import type { ViemPublicClient } from './types.js';
8
9
 
@@ -25,6 +26,8 @@ export async function getL1ContractsConfig(
25
26
  const rollup = new RollupContract(publicClient, rollupAddress.toString());
26
27
  const slasherProposer = await rollup.getSlashingProposer();
27
28
  const slasher = await rollup.getSlasherContract();
29
+ const rollupAddresses = await rollup.getRollupAddresses();
30
+ const inboxContract = new InboxContract(publicClient, rollupAddresses.inboxAddress.toString());
28
31
 
29
32
  const [
30
33
  l1StartBlock,
@@ -33,7 +36,9 @@ export async function getL1ContractsConfig(
33
36
  aztecSlotDuration,
34
37
  aztecProofSubmissionEpochs,
35
38
  aztecTargetCommitteeSize,
36
- lagInEpochs,
39
+ lagInEpochsForValidatorSet,
40
+ lagInEpochsForRandao,
41
+ inboxLag,
37
42
  activationThreshold,
38
43
  ejectionThreshold,
39
44
  localEjectionThreshold,
@@ -59,7 +64,9 @@ export async function getL1ContractsConfig(
59
64
  rollup.getSlotDuration(),
60
65
  rollup.getProofSubmissionEpochs(),
61
66
  rollup.getTargetCommitteeSize(),
62
- rollup.getLagInEpochs(),
67
+ rollup.getLagInEpochsForValidatorSet(),
68
+ rollup.getLagInEpochsForRandao(),
69
+ inboxContract.getLag(),
63
70
  rollup.getActivationThreshold(),
64
71
  rollup.getEjectionThreshold(),
65
72
  rollup.getLocalEjectionThreshold(),
@@ -87,7 +94,9 @@ export async function getL1ContractsConfig(
87
94
  aztecSlotDuration: Number(aztecSlotDuration),
88
95
  aztecProofSubmissionEpochs: Number(aztecProofSubmissionEpochs),
89
96
  aztecTargetCommitteeSize: Number(aztecTargetCommitteeSize),
90
- lagInEpochs: Number(lagInEpochs),
97
+ lagInEpochsForValidatorSet: Number(lagInEpochsForValidatorSet),
98
+ lagInEpochsForRandao: Number(lagInEpochsForRandao),
99
+ inboxLag: Number(inboxLag),
91
100
  governanceProposerQuorum: Number(governanceProposerQuorum),
92
101
  governanceProposerRoundSize: Number(governanceProposerRoundSize),
93
102
  activationThreshold,
@@ -1,4 +1,6 @@
1
- import { InboxContract, type RollupContract } from '@aztec/ethereum/contracts';
1
+ import type { RollupContract } from '@aztec/ethereum/contracts';
2
+ import { InboxContract } from '@aztec/ethereum/contracts';
3
+ import { CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
2
4
  import { EthAddress } from '@aztec/foundation/eth-address';
3
5
  import { createLogger } from '@aztec/foundation/log';
4
6
  import { promiseWithResolvers } from '@aztec/foundation/promise';
@@ -10,11 +12,13 @@ import type { ViemClient } from '../types.js';
10
12
 
11
13
  export type ChainMonitorEventMap = {
12
14
  'l1-block': [{ l1BlockNumber: number; timestamp: bigint }];
13
- 'l2-block': [{ l2BlockNumber: number; l1BlockNumber: number; l2SlotNumber: number; timestamp: bigint }];
14
- 'l2-block-proven': [{ l2ProvenBlockNumber: number; l1BlockNumber: number; timestamp: bigint }];
15
+ checkpoint: [
16
+ { checkpointNumber: CheckpointNumber; l1BlockNumber: number; l2SlotNumber: SlotNumber; timestamp: bigint },
17
+ ];
18
+ 'checkpoint-proven': [{ provenCheckpointNumber: CheckpointNumber; l1BlockNumber: number; timestamp: bigint }];
15
19
  'l2-messages': [{ totalL2Messages: number; l1BlockNumber: number }];
16
- 'l2-epoch': [{ l2EpochNumber: number; timestamp: bigint; committee: EthAddress[] | undefined }];
17
- 'l2-slot': [{ l2SlotNumber: number; timestamp: bigint }];
20
+ 'l2-epoch': [{ l2EpochNumber: EpochNumber; timestamp: bigint; committee: EthAddress[] | undefined }];
21
+ 'l2-slot': [{ l2SlotNumber: SlotNumber; timestamp: bigint }];
18
22
  };
19
23
 
20
24
  /** Utility class that polls the chain on quick intervals and logs new L1 blocks, L2 blocks, and L2 proofs. */
@@ -27,20 +31,20 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
27
31
 
28
32
  /** Current L1 block number */
29
33
  public l1BlockNumber!: number;
30
- /** Current L2 block number */
31
- public l2BlockNumber!: number;
32
- /** Current L2 proven block number */
33
- public l2ProvenBlockNumber!: number;
34
- /** L1 timestamp for the current L2 block */
35
- public l2BlockTimestamp!: bigint;
36
- /** L1 timestamp for the proven L2 block */
37
- public l2ProvenBlockTimestamp!: bigint;
34
+ /** Current checkpoint number */
35
+ public checkpointNumber!: CheckpointNumber;
36
+ /** Current proven checkpoint number */
37
+ public provenCheckpointNumber!: CheckpointNumber;
38
+ /** L1 timestamp for the current checkpoint */
39
+ public checkpointTimestamp!: bigint;
40
+ /** L1 timestamp for the proven checkpoint */
41
+ public provenCheckpointTimestamp!: bigint;
38
42
  /** Total number of L2 messages pushed into the Inbox */
39
43
  public totalL2Messages: number = 0;
40
44
  /** Current L2 epoch number */
41
- public l2EpochNumber!: bigint;
45
+ public l2EpochNumber!: EpochNumber;
42
46
  /** Current L2 slot number */
43
- public l2SlotNumber!: bigint;
47
+ public l2SlotNumber!: SlotNumber;
44
48
 
45
49
  constructor(
46
50
  private readonly rollup: RollupContract,
@@ -114,28 +118,28 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
114
118
  this.emit('l1-block', { l1BlockNumber: newL1BlockNumber, timestamp });
115
119
  let msg = `L1 block ${newL1BlockNumber} mined at ${timestampString}`;
116
120
 
117
- const newL2BlockNumber = Number(await this.rollup.getBlockNumber());
118
- if (this.l2BlockNumber !== newL2BlockNumber) {
119
- const epochNumber = await this.rollup.getEpochNumberForBlock(BigInt(newL2BlockNumber));
120
- msg += ` with new L2 block ${newL2BlockNumber} for epoch ${epochNumber}`;
121
- this.l2BlockNumber = newL2BlockNumber;
122
- this.l2BlockTimestamp = timestamp;
123
- this.emit('l2-block', {
124
- l2BlockNumber: newL2BlockNumber,
121
+ const newCheckpointNumber = await this.rollup.getCheckpointNumber();
122
+ if (this.checkpointNumber !== newCheckpointNumber) {
123
+ const epochNumber = await this.rollup.getEpochNumberForCheckpoint(newCheckpointNumber);
124
+ msg += ` with new checkpoint ${newCheckpointNumber} for epoch ${epochNumber}`;
125
+ this.checkpointNumber = newCheckpointNumber;
126
+ this.checkpointTimestamp = timestamp;
127
+ this.emit('checkpoint', {
128
+ checkpointNumber: newCheckpointNumber,
125
129
  l1BlockNumber: newL1BlockNumber,
126
- l2SlotNumber: Number(l2SlotNumber),
130
+ l2SlotNumber,
127
131
  timestamp,
128
132
  });
129
133
  }
130
134
 
131
- const newL2ProvenBlockNumber = Number(await this.rollup.getProvenBlockNumber());
132
- if (this.l2ProvenBlockNumber !== newL2ProvenBlockNumber) {
133
- const epochNumber = await this.rollup.getEpochNumberForBlock(BigInt(newL2ProvenBlockNumber));
134
- msg += ` with proof up to L2 block ${newL2ProvenBlockNumber} for epoch ${epochNumber}`;
135
- this.l2ProvenBlockNumber = newL2ProvenBlockNumber;
136
- this.l2ProvenBlockTimestamp = timestamp;
137
- this.emit('l2-block-proven', {
138
- l2ProvenBlockNumber: newL2ProvenBlockNumber,
135
+ const newProvenCheckpointNumber = await this.rollup.getProvenCheckpointNumber();
136
+ if (this.provenCheckpointNumber !== newProvenCheckpointNumber) {
137
+ const epochNumber = await this.rollup.getEpochNumberForCheckpoint(newProvenCheckpointNumber);
138
+ msg += ` with proof up to checkpoint ${newProvenCheckpointNumber} for epoch ${epochNumber}`;
139
+ this.provenCheckpointNumber = newProvenCheckpointNumber;
140
+ this.provenCheckpointTimestamp = timestamp;
141
+ this.emit('checkpoint-proven', {
142
+ provenCheckpointNumber: newProvenCheckpointNumber,
139
143
  l1BlockNumber: newL1BlockNumber,
140
144
  timestamp,
141
145
  });
@@ -153,13 +157,13 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
153
157
  if (l2Epoch !== this.l2EpochNumber) {
154
158
  this.l2EpochNumber = l2Epoch;
155
159
  committee = (await this.rollup.getCurrentEpochCommittee())?.map(addr => EthAddress.fromString(addr));
156
- this.emit('l2-epoch', { l2EpochNumber: Number(l2Epoch), timestamp, committee });
160
+ this.emit('l2-epoch', { l2EpochNumber: l2Epoch, timestamp, committee });
157
161
  msg += ` starting new epoch ${this.l2EpochNumber} `;
158
162
  }
159
163
 
160
164
  if (l2SlotNumber !== this.l2SlotNumber) {
161
165
  this.l2SlotNumber = l2SlotNumber;
162
- this.emit('l2-slot', { l2SlotNumber: Number(l2SlotNumber), timestamp });
166
+ this.emit('l2-slot', { l2SlotNumber, timestamp });
163
167
  }
164
168
 
165
169
  this.logger.info(msg, {
@@ -168,8 +172,8 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
168
172
  l1BlockNumber: this.l1BlockNumber,
169
173
  l2SlotNumber,
170
174
  l2Epoch,
171
- l2BlockNumber: this.l2BlockNumber,
172
- l2ProvenBlockNumber: this.l2ProvenBlockNumber,
175
+ checkpointNumber: this.checkpointNumber,
176
+ provenCheckpointNumber: this.provenCheckpointNumber,
173
177
  totalL2Messages: this.totalL2Messages,
174
178
  committee,
175
179
  });
@@ -177,14 +181,13 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
177
181
  return this;
178
182
  }
179
183
 
180
- public waitUntilL2Slot(slot: number | bigint): Promise<void> {
181
- const targetSlot = typeof slot === 'bigint' ? slot.valueOf() : slot;
182
- if (this.l2SlotNumber >= targetSlot) {
184
+ public waitUntilL2Slot(slot: SlotNumber): Promise<void> {
185
+ if (this.l2SlotNumber >= slot) {
183
186
  return Promise.resolve();
184
187
  }
185
188
  return new Promise(resolve => {
186
- const listener = (data: { l2SlotNumber: number; timestamp: bigint }) => {
187
- if (data.l2SlotNumber >= targetSlot) {
189
+ const listener = (data: { l2SlotNumber: SlotNumber; timestamp: bigint }) => {
190
+ if (data.l2SlotNumber >= slot) {
188
191
  this.off('l2-slot', listener);
189
192
  resolve();
190
193
  }
@@ -225,19 +228,18 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
225
228
  });
226
229
  }
227
230
 
228
- public waitUntilL2Block(l2BlockNumber: number | bigint): Promise<void> {
229
- const targetBlock = typeof l2BlockNumber === 'bigint' ? l2BlockNumber.valueOf() : l2BlockNumber;
230
- if (this.l2BlockNumber >= targetBlock) {
231
+ public waitUntilCheckpoint(checkpointNumber: CheckpointNumber): Promise<void> {
232
+ if (this.checkpointNumber >= checkpointNumber) {
231
233
  return Promise.resolve();
232
234
  }
233
235
  return new Promise(resolve => {
234
- const listener = (data: { l2BlockNumber: number; timestamp: bigint }) => {
235
- if (data.l2BlockNumber >= targetBlock) {
236
- this.off('l2-block', listener);
236
+ const listener = (data: { checkpointNumber: CheckpointNumber; timestamp: bigint }) => {
237
+ if (data.checkpointNumber >= checkpointNumber) {
238
+ this.off('checkpoint', listener);
237
239
  resolve();
238
240
  }
239
241
  };
240
- this.on('l2-block', listener);
242
+ this.on('checkpoint', listener);
241
243
  });
242
244
  }
243
245
  }
@@ -1,12 +1,13 @@
1
1
  import { toBigIntBE, toHex } from '@aztec/foundation/bigint-buffer';
2
- import { keccak256 } from '@aztec/foundation/crypto';
2
+ import { keccak256 } from '@aztec/foundation/crypto/keccak';
3
3
  import { EthAddress } from '@aztec/foundation/eth-address';
4
4
  import { jsonStringify } from '@aztec/foundation/json-rpc';
5
5
  import { createLogger } from '@aztec/foundation/log';
6
6
  import { pluralize } from '@aztec/foundation/string';
7
7
  import type { DateProvider, TestDateProvider } from '@aztec/foundation/timer';
8
8
 
9
- import { type Hex, type Transaction, createPublicClient, fallback, hexToNumber, http } from 'viem';
9
+ import { type Chain, type Hex, type Transaction, createPublicClient, fallback, hexToNumber, http } from 'viem';
10
+ import { foundry } from 'viem/chains';
10
11
 
11
12
  import type { ViemPublicClient } from '../types.js';
12
13
 
@@ -28,9 +29,14 @@ export class EthCheatCodes {
28
29
  * The logger to use for the eth cheatcodes
29
30
  */
30
31
  public logger = createLogger('ethereum:cheat_codes'),
32
+ /**
33
+ * The chain configuration provided to Anvil
34
+ */
35
+ public chain: Chain = foundry,
31
36
  ) {
32
37
  this.publicClient = createPublicClient({
33
- transport: fallback(this.rpcUrls.map(url => http(url))),
38
+ transport: fallback(this.rpcUrls.map(url => http(url, { batch: false }))),
39
+ chain: chain,
34
40
  });
35
41
  }
36
42