@aztec/ethereum 0.0.0-test.1 → 0.0.1-commit.03f7ef2

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 (272) hide show
  1. package/dest/account.d.ts +2 -0
  2. package/dest/account.d.ts.map +1 -0
  3. package/dest/account.js +4 -0
  4. package/dest/chain.d.ts +1 -1
  5. package/dest/client.d.ts +6 -4
  6. package/dest/client.d.ts.map +1 -1
  7. package/dest/client.js +21 -3
  8. package/dest/config.d.ts +71 -16
  9. package/dest/config.d.ts.map +1 -1
  10. package/dest/config.js +138 -22
  11. package/dest/constants.d.ts +1 -1
  12. package/dest/contracts/empire_base.d.ts +25 -8
  13. package/dest/contracts/empire_base.d.ts.map +1 -1
  14. package/dest/contracts/empire_base.js +75 -2
  15. package/dest/contracts/empire_slashing_proposer.d.ts +67 -0
  16. package/dest/contracts/empire_slashing_proposer.d.ts.map +1 -0
  17. package/dest/contracts/empire_slashing_proposer.js +209 -0
  18. package/dest/contracts/errors.d.ts +7 -0
  19. package/dest/contracts/errors.d.ts.map +1 -0
  20. package/dest/contracts/errors.js +12 -0
  21. package/dest/contracts/fee_asset_handler.d.ts +19 -0
  22. package/dest/contracts/fee_asset_handler.d.ts.map +1 -0
  23. package/dest/contracts/fee_asset_handler.js +57 -0
  24. package/dest/contracts/fee_juice.d.ts +6 -7
  25. package/dest/contracts/fee_juice.d.ts.map +1 -1
  26. package/dest/contracts/fee_juice.js +27 -20
  27. package/dest/contracts/governance.d.ts +43 -32
  28. package/dest/contracts/governance.d.ts.map +1 -1
  29. package/dest/contracts/governance.js +87 -84
  30. package/dest/contracts/governance_proposer.d.ts +17 -13
  31. package/dest/contracts/governance_proposer.d.ts.map +1 -1
  32. package/dest/contracts/governance_proposer.js +46 -17
  33. package/dest/contracts/gse.d.ts +32 -0
  34. package/dest/contracts/gse.d.ts.map +1 -0
  35. package/dest/contracts/gse.js +72 -0
  36. package/dest/contracts/inbox.d.ts +26 -0
  37. package/dest/contracts/inbox.d.ts.map +1 -0
  38. package/dest/contracts/inbox.js +45 -0
  39. package/dest/contracts/index.d.ts +9 -3
  40. package/dest/contracts/index.d.ts.map +1 -1
  41. package/dest/contracts/index.js +8 -2
  42. package/dest/contracts/multicall.d.ts +21 -0
  43. package/dest/contracts/multicall.d.ts.map +1 -0
  44. package/dest/contracts/multicall.js +156 -0
  45. package/dest/contracts/registry.d.ts +10 -5
  46. package/dest/contracts/registry.d.ts.map +1 -1
  47. package/dest/contracts/registry.js +44 -16
  48. package/dest/contracts/rollup.d.ts +221 -41
  49. package/dest/contracts/rollup.d.ts.map +1 -1
  50. package/dest/contracts/rollup.js +549 -81
  51. package/dest/contracts/slasher_contract.d.ts +44 -0
  52. package/dest/contracts/slasher_contract.d.ts.map +1 -0
  53. package/dest/contracts/slasher_contract.js +75 -0
  54. package/dest/contracts/tally_slashing_proposer.d.ts +140 -0
  55. package/dest/contracts/tally_slashing_proposer.d.ts.map +1 -0
  56. package/dest/contracts/tally_slashing_proposer.js +313 -0
  57. package/dest/contracts/utils.d.ts +3 -0
  58. package/dest/contracts/utils.d.ts.map +1 -0
  59. package/dest/contracts/utils.js +11 -0
  60. package/dest/deploy_aztec_l1_contracts.d.ts +245 -0
  61. package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -0
  62. package/dest/deploy_aztec_l1_contracts.js +335 -0
  63. package/dest/deploy_l1_contract.d.ts +68 -0
  64. package/dest/deploy_l1_contract.d.ts.map +1 -0
  65. package/dest/deploy_l1_contract.js +312 -0
  66. package/dest/eth-signer/eth-signer.d.ts +21 -0
  67. package/dest/eth-signer/eth-signer.d.ts.map +1 -0
  68. package/dest/eth-signer/eth-signer.js +5 -0
  69. package/dest/eth-signer/index.d.ts +2 -0
  70. package/dest/eth-signer/index.d.ts.map +1 -0
  71. package/dest/eth-signer/index.js +1 -0
  72. package/dest/forwarder_proxy.d.ts +32 -0
  73. package/dest/forwarder_proxy.d.ts.map +1 -0
  74. package/dest/forwarder_proxy.js +93 -0
  75. package/dest/l1_artifacts.d.ts +77364 -0
  76. package/dest/l1_artifacts.d.ts.map +1 -0
  77. package/dest/l1_artifacts.js +166 -0
  78. package/dest/l1_contract_addresses.d.ts +24 -4
  79. package/dest/l1_contract_addresses.d.ts.map +1 -1
  80. package/dest/l1_contract_addresses.js +25 -21
  81. package/dest/l1_reader.d.ts +4 -2
  82. package/dest/l1_reader.d.ts.map +1 -1
  83. package/dest/l1_reader.js +14 -8
  84. package/dest/l1_tx_utils/config.d.ts +59 -0
  85. package/dest/l1_tx_utils/config.d.ts.map +1 -0
  86. package/dest/l1_tx_utils/config.js +96 -0
  87. package/dest/l1_tx_utils/constants.d.ts +12 -0
  88. package/dest/l1_tx_utils/constants.d.ts.map +1 -0
  89. package/dest/l1_tx_utils/constants.js +39 -0
  90. package/dest/l1_tx_utils/factory.d.ts +24 -0
  91. package/dest/l1_tx_utils/factory.d.ts.map +1 -0
  92. package/dest/l1_tx_utils/factory.js +12 -0
  93. package/dest/l1_tx_utils/fee-strategies/index.d.ts +9 -0
  94. package/dest/l1_tx_utils/fee-strategies/index.d.ts.map +1 -0
  95. package/dest/l1_tx_utils/fee-strategies/index.js +11 -0
  96. package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts +18 -0
  97. package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts.map +1 -0
  98. package/dest/l1_tx_utils/fee-strategies/p75_competitive.js +111 -0
  99. package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts +32 -0
  100. package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts.map +1 -0
  101. package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.js +173 -0
  102. package/dest/l1_tx_utils/fee-strategies/types.d.ts +64 -0
  103. package/dest/l1_tx_utils/fee-strategies/types.d.ts.map +1 -0
  104. package/dest/l1_tx_utils/fee-strategies/types.js +24 -0
  105. package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts +41 -0
  106. package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts.map +1 -0
  107. package/dest/l1_tx_utils/forwarder_l1_tx_utils.js +48 -0
  108. package/dest/l1_tx_utils/index-blobs.d.ts +3 -0
  109. package/dest/l1_tx_utils/index-blobs.d.ts.map +1 -0
  110. package/dest/l1_tx_utils/index-blobs.js +2 -0
  111. package/dest/l1_tx_utils/index.d.ts +12 -0
  112. package/dest/l1_tx_utils/index.d.ts.map +1 -0
  113. package/dest/l1_tx_utils/index.js +12 -0
  114. package/dest/l1_tx_utils/interfaces.d.ts +76 -0
  115. package/dest/l1_tx_utils/interfaces.d.ts.map +1 -0
  116. package/dest/l1_tx_utils/interfaces.js +4 -0
  117. package/dest/l1_tx_utils/l1_fee_analyzer.d.ts +233 -0
  118. package/dest/l1_tx_utils/l1_fee_analyzer.d.ts.map +1 -0
  119. package/dest/l1_tx_utils/l1_fee_analyzer.js +506 -0
  120. package/dest/l1_tx_utils/l1_tx_utils.d.ts +94 -0
  121. package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -0
  122. package/dest/l1_tx_utils/l1_tx_utils.js +623 -0
  123. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts +26 -0
  124. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +1 -0
  125. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.js +26 -0
  126. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +87 -0
  127. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -0
  128. package/dest/l1_tx_utils/readonly_l1_tx_utils.js +360 -0
  129. package/dest/l1_tx_utils/signer.d.ts +4 -0
  130. package/dest/l1_tx_utils/signer.d.ts.map +1 -0
  131. package/dest/l1_tx_utils/signer.js +16 -0
  132. package/dest/l1_tx_utils/types.d.ts +67 -0
  133. package/dest/l1_tx_utils/types.d.ts.map +1 -0
  134. package/dest/l1_tx_utils/types.js +26 -0
  135. package/dest/l1_tx_utils/utils.d.ts +4 -0
  136. package/dest/l1_tx_utils/utils.d.ts.map +1 -0
  137. package/dest/l1_tx_utils/utils.js +14 -0
  138. package/dest/l1_types.d.ts +6 -0
  139. package/dest/l1_types.d.ts.map +1 -0
  140. package/dest/l1_types.js +1 -0
  141. package/dest/publisher_manager.d.ts +15 -0
  142. package/dest/publisher_manager.d.ts.map +1 -0
  143. package/dest/publisher_manager.js +88 -0
  144. package/dest/queries.d.ts +4 -2
  145. package/dest/queries.d.ts.map +1 -1
  146. package/dest/queries.js +53 -12
  147. package/dest/test/chain_monitor.d.ts +75 -0
  148. package/dest/test/chain_monitor.d.ts.map +1 -0
  149. package/dest/test/chain_monitor.js +214 -0
  150. package/dest/test/delayed_tx_utils.d.ts +8 -3
  151. package/dest/test/delayed_tx_utils.d.ts.map +1 -1
  152. package/dest/test/delayed_tx_utils.js +13 -6
  153. package/dest/test/eth_cheat_codes.d.ts +217 -0
  154. package/dest/test/eth_cheat_codes.d.ts.map +1 -0
  155. package/dest/test/eth_cheat_codes.js +560 -0
  156. package/dest/test/eth_cheat_codes_with_state.d.ts +2 -2
  157. package/dest/test/eth_cheat_codes_with_state.d.ts.map +1 -1
  158. package/dest/test/eth_cheat_codes_with_state.js +1 -1
  159. package/dest/test/index.d.ts +4 -1
  160. package/dest/test/index.d.ts.map +1 -1
  161. package/dest/test/index.js +3 -0
  162. package/dest/test/rollup_cheat_codes.d.ts +87 -0
  163. package/dest/test/rollup_cheat_codes.d.ts.map +1 -0
  164. package/dest/test/rollup_cheat_codes.js +275 -0
  165. package/dest/test/start_anvil.d.ts +9 -1
  166. package/dest/test/start_anvil.d.ts.map +1 -1
  167. package/dest/test/start_anvil.js +16 -7
  168. package/dest/test/tx_delayer.d.ts +18 -7
  169. package/dest/test/tx_delayer.d.ts.map +1 -1
  170. package/dest/test/tx_delayer.js +97 -20
  171. package/dest/test/upgrade_utils.d.ts +6 -5
  172. package/dest/test/upgrade_utils.d.ts.map +1 -1
  173. package/dest/test/upgrade_utils.js +23 -16
  174. package/dest/types.d.ts +62 -8
  175. package/dest/types.d.ts.map +1 -1
  176. package/dest/types.js +3 -1
  177. package/dest/utils.d.ts +16 -3
  178. package/dest/utils.d.ts.map +1 -1
  179. package/dest/utils.js +61 -88
  180. package/dest/zkPassportVerifierAddress.d.ts +15 -0
  181. package/dest/zkPassportVerifierAddress.d.ts.map +1 -0
  182. package/dest/zkPassportVerifierAddress.js +11 -0
  183. package/package.json +50 -23
  184. package/src/account.ts +5 -0
  185. package/src/client.ts +43 -5
  186. package/src/config.ts +188 -31
  187. package/src/contracts/empire_base.ts +77 -7
  188. package/src/contracts/empire_slashing_proposer.ts +270 -0
  189. package/src/contracts/errors.ts +13 -0
  190. package/src/contracts/fee_asset_handler.ts +63 -0
  191. package/src/contracts/fee_juice.ts +29 -15
  192. package/src/contracts/governance.ts +80 -77
  193. package/src/contracts/governance_proposer.ts +71 -24
  194. package/src/contracts/gse.ts +88 -0
  195. package/src/contracts/inbox.ts +63 -0
  196. package/src/contracts/index.ts +8 -2
  197. package/src/contracts/multicall.ts +155 -0
  198. package/src/contracts/registry.ts +51 -26
  199. package/src/contracts/rollup.ts +624 -78
  200. package/src/contracts/slasher_contract.ts +89 -0
  201. package/src/contracts/tally_slashing_proposer.ts +318 -0
  202. package/src/contracts/utils.ts +14 -0
  203. package/src/deploy_aztec_l1_contracts.ts +556 -0
  204. package/src/deploy_l1_contract.ts +362 -0
  205. package/src/eth-signer/eth-signer.ts +25 -0
  206. package/src/eth-signer/index.ts +1 -0
  207. package/src/forwarder_proxy.ts +108 -0
  208. package/src/l1_artifacts.ts +254 -0
  209. package/src/l1_contract_addresses.ts +49 -34
  210. package/src/l1_reader.ts +17 -9
  211. package/src/l1_tx_utils/README.md +177 -0
  212. package/src/l1_tx_utils/config.ts +161 -0
  213. package/src/l1_tx_utils/constants.ts +29 -0
  214. package/src/l1_tx_utils/factory.ts +64 -0
  215. package/src/l1_tx_utils/fee-strategies/index.ts +22 -0
  216. package/src/l1_tx_utils/fee-strategies/p75_competitive.ts +159 -0
  217. package/src/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.ts +241 -0
  218. package/src/l1_tx_utils/fee-strategies/types.ts +88 -0
  219. package/src/l1_tx_utils/forwarder_l1_tx_utils.ts +119 -0
  220. package/src/l1_tx_utils/index-blobs.ts +2 -0
  221. package/src/l1_tx_utils/index.ts +14 -0
  222. package/src/l1_tx_utils/interfaces.ts +86 -0
  223. package/src/l1_tx_utils/l1_fee_analyzer.ts +804 -0
  224. package/src/l1_tx_utils/l1_tx_utils.ts +738 -0
  225. package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +77 -0
  226. package/src/l1_tx_utils/readonly_l1_tx_utils.ts +458 -0
  227. package/src/l1_tx_utils/signer.ts +28 -0
  228. package/src/l1_tx_utils/types.ts +85 -0
  229. package/src/l1_tx_utils/utils.ts +16 -0
  230. package/src/l1_types.ts +6 -0
  231. package/src/publisher_manager.ts +106 -0
  232. package/src/queries.ts +73 -15
  233. package/src/test/chain_monitor.ts +245 -0
  234. package/src/test/delayed_tx_utils.ts +34 -6
  235. package/src/test/eth_cheat_codes.ts +588 -0
  236. package/src/test/eth_cheat_codes_with_state.ts +1 -1
  237. package/src/test/index.ts +3 -0
  238. package/src/test/rollup_cheat_codes.ts +312 -0
  239. package/src/test/start_anvil.ts +24 -5
  240. package/src/test/tx_delayer.ts +130 -27
  241. package/src/test/upgrade_utils.ts +30 -21
  242. package/src/types.ts +71 -7
  243. package/src/utils.ts +79 -91
  244. package/src/zkPassportVerifierAddress.ts +15 -0
  245. package/dest/contracts/forwarder.d.ts +0 -24
  246. package/dest/contracts/forwarder.d.ts.map +0 -1
  247. package/dest/contracts/forwarder.js +0 -101
  248. package/dest/contracts/slashing_proposer.d.ts +0 -21
  249. package/dest/contracts/slashing_proposer.d.ts.map +0 -1
  250. package/dest/contracts/slashing_proposer.js +0 -47
  251. package/dest/deploy_l1_contracts.d.ts +0 -21210
  252. package/dest/deploy_l1_contracts.d.ts.map +0 -1
  253. package/dest/deploy_l1_contracts.js +0 -687
  254. package/dest/eth_cheat_codes.d.ts +0 -147
  255. package/dest/eth_cheat_codes.d.ts.map +0 -1
  256. package/dest/eth_cheat_codes.js +0 -303
  257. package/dest/index.d.ts +0 -14
  258. package/dest/index.d.ts.map +0 -1
  259. package/dest/index.js +0 -13
  260. package/dest/l1_tx_utils.d.ts +0 -192
  261. package/dest/l1_tx_utils.d.ts.map +0 -1
  262. package/dest/l1_tx_utils.js +0 -641
  263. package/dest/l1_tx_utils_with_blobs.d.ts +0 -12
  264. package/dest/l1_tx_utils_with_blobs.d.ts.map +0 -1
  265. package/dest/l1_tx_utils_with_blobs.js +0 -64
  266. package/src/contracts/forwarder.ts +0 -132
  267. package/src/contracts/slashing_proposer.ts +0 -51
  268. package/src/deploy_l1_contracts.ts +0 -948
  269. package/src/eth_cheat_codes.ts +0 -314
  270. package/src/index.ts +0 -13
  271. package/src/l1_tx_utils.ts +0 -847
  272. package/src/l1_tx_utils_with_blobs.ts +0 -86
@@ -0,0 +1,77 @@
1
+ import { Blob } from '@aztec/blob-lib';
2
+ import { EthAddress } from '@aztec/foundation/eth-address';
3
+ import type { Logger } from '@aztec/foundation/log';
4
+ import { DateProvider } from '@aztec/foundation/timer';
5
+
6
+ import type { TransactionSerializable } from 'viem';
7
+
8
+ import type { EthSigner } from '../eth-signer/eth-signer.js';
9
+ import type { ExtendedViemWalletClient, ViemClient } from '../types.js';
10
+ import type { L1TxUtilsConfig } from './config.js';
11
+ import type { IL1TxMetrics, IL1TxStore } from './interfaces.js';
12
+ import { L1TxUtils } from './l1_tx_utils.js';
13
+ import { createViemSigner } from './signer.js';
14
+ import type { L1BlobInputs, SigningCallback } from './types.js';
15
+
16
+ /** Extends L1TxUtils with the capability to cancel blobs. This needs to be a separate class so we don't require a dependency on blob-lib unnecessarily. */
17
+ export class L1TxUtilsWithBlobs extends L1TxUtils {
18
+ /** Makes empty blob inputs for the cancellation tx. */
19
+ protected override makeEmptyBlobInputs(maxFeePerBlobGas: bigint): Required<L1BlobInputs> {
20
+ const blobData = new Uint8Array(131072).fill(0);
21
+ const kzg = Blob.getViemKzgInstance();
22
+ return { blobs: [blobData], kzg, maxFeePerBlobGas };
23
+ }
24
+ }
25
+
26
+ export function createL1TxUtilsWithBlobsFromViemWallet(
27
+ client: ExtendedViemWalletClient,
28
+ deps: {
29
+ logger?: Logger;
30
+ dateProvider?: DateProvider;
31
+ store?: IL1TxStore;
32
+ metrics?: IL1TxMetrics;
33
+ } = {},
34
+ config: Partial<L1TxUtilsConfig> = {},
35
+ debugMaxGasLimit: boolean = false,
36
+ ) {
37
+ return new L1TxUtilsWithBlobs(
38
+ client,
39
+ EthAddress.fromString(client.account.address),
40
+ createViemSigner(client),
41
+ deps.logger,
42
+ deps.dateProvider,
43
+ config,
44
+ debugMaxGasLimit,
45
+ deps.store,
46
+ deps.metrics,
47
+ );
48
+ }
49
+
50
+ export function createL1TxUtilsWithBlobsFromEthSigner(
51
+ client: ViemClient,
52
+ signer: EthSigner,
53
+ deps: {
54
+ logger?: Logger;
55
+ dateProvider?: DateProvider;
56
+ store?: IL1TxStore;
57
+ metrics?: IL1TxMetrics;
58
+ } = {},
59
+ config: Partial<L1TxUtilsConfig> = {},
60
+ debugMaxGasLimit: boolean = false,
61
+ ) {
62
+ const callback: SigningCallback = async (transaction: TransactionSerializable, _signingAddress) => {
63
+ return (await signer.signTransaction(transaction)).toViemTransactionSignature();
64
+ };
65
+
66
+ return new L1TxUtilsWithBlobs(
67
+ client,
68
+ signer.address,
69
+ callback,
70
+ deps.logger,
71
+ deps.dateProvider,
72
+ config,
73
+ debugMaxGasLimit,
74
+ deps.store,
75
+ deps.metrics,
76
+ );
77
+ }
@@ -0,0 +1,458 @@
1
+ import { getKeys, merge, pick, times } from '@aztec/foundation/collection';
2
+ import type { EthAddress } from '@aztec/foundation/eth-address';
3
+ import { type Logger, createLogger } from '@aztec/foundation/log';
4
+ import { makeBackoff, retry } from '@aztec/foundation/retry';
5
+ import { DateProvider } from '@aztec/foundation/timer';
6
+ import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
7
+
8
+ import pickBy from 'lodash.pickby';
9
+ import {
10
+ type Abi,
11
+ type Account,
12
+ type BaseError,
13
+ type BlockOverrides,
14
+ type ContractFunctionExecutionError,
15
+ type GetCodeReturnType,
16
+ type Hex,
17
+ MethodNotFoundRpcError,
18
+ MethodNotSupportedRpcError,
19
+ type StateOverride,
20
+ decodeErrorResult,
21
+ formatGwei,
22
+ getContractError,
23
+ hexToBytes,
24
+ } from 'viem';
25
+
26
+ import type { ViemClient } from '../types.js';
27
+ import { type L1TxUtilsConfig, defaultL1TxUtilsConfig, l1TxUtilsConfigMappings } from './config.js';
28
+ import {
29
+ BLOCK_TIME_MS,
30
+ LARGE_GAS_LIMIT,
31
+ MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE,
32
+ MIN_REPLACEMENT_BUMP_PERCENTAGE,
33
+ WEI_CONST,
34
+ } from './constants.js';
35
+ import { P75AllTxsPriorityFeeStrategy, type PriorityFeeStrategy } from './fee-strategies/index.js';
36
+ import type { GasPrice, L1BlobInputs, L1TxRequest, TransactionStats } from './types.js';
37
+ import { getCalldataGasUsage, tryGetCustomErrorNameContractFunction } from './utils.js';
38
+
39
+ // Change this to the current strategy we want to use
40
+ const CurrentStrategy: PriorityFeeStrategy = P75AllTxsPriorityFeeStrategy;
41
+
42
+ export class ReadOnlyL1TxUtils {
43
+ public config: Required<L1TxUtilsConfig>;
44
+ protected interrupted = false;
45
+
46
+ constructor(
47
+ public client: ViemClient,
48
+ protected logger: Logger = createLogger('ethereum:readonly-l1-utils'),
49
+ public readonly dateProvider: DateProvider,
50
+ config?: Partial<L1TxUtilsConfig>,
51
+ protected debugMaxGasLimit: boolean = false,
52
+ ) {
53
+ this.config = merge(defaultL1TxUtilsConfig, pick(config || {}, ...getKeys(l1TxUtilsConfigMappings)));
54
+ }
55
+
56
+ public interrupt() {
57
+ this.interrupted = true;
58
+ }
59
+
60
+ public restart() {
61
+ this.interrupted = false;
62
+ }
63
+
64
+ public getBlock() {
65
+ return this.client.getBlock();
66
+ }
67
+
68
+ public getBlockNumber() {
69
+ return this.client.getBlockNumber();
70
+ }
71
+
72
+ public getCode(address: EthAddress): Promise<GetCodeReturnType> {
73
+ return this.client.getCode({ address: address.toString() });
74
+ }
75
+
76
+ /**
77
+ * Gets the current gas price with bounds checking
78
+ */
79
+ public async getGasPrice(
80
+ gasConfigOverrides?: L1TxUtilsConfig,
81
+ isBlobTx: boolean = false,
82
+ attempt: number = 0,
83
+ previousGasPrice?: typeof attempt extends 0 ? never : GasPrice,
84
+ ): Promise<GasPrice> {
85
+ const gasConfig = merge(this.config, gasConfigOverrides);
86
+
87
+ // Make all RPC calls in parallel upfront with retry logic
88
+ // First 2 calls are necessary to complete
89
+ const latestBlockPromise = this.tryTwice(
90
+ () => this.client.getBlock({ blockTag: 'latest' }),
91
+ 'Getting latest block',
92
+ );
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
+ ]);
113
+
114
+ // Extract results
115
+ const baseFee =
116
+ latestBlockResult.status === 'fulfilled' &&
117
+ typeof latestBlockResult.value === 'object' &&
118
+ latestBlockResult.value.baseFeePerGas
119
+ ? latestBlockResult.value.baseFeePerGas
120
+ : 0n;
121
+
122
+ // Get blob base fee if available
123
+ let blobBaseFee = 0n;
124
+ if (isBlobTx && blobBaseFeeResult.status === 'fulfilled' && typeof blobBaseFeeResult.value === 'bigint') {
125
+ blobBaseFee = blobBaseFeeResult.value;
126
+ } else if (isBlobTx) {
127
+ this.logger?.warn('Failed to get L1 blob base fee', attempt);
128
+ }
129
+
130
+ let priorityFee: bigint;
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
+ }
156
+ }
157
+ let maxFeePerGas = baseFee;
158
+
159
+ let maxFeePerBlobGas = blobBaseFee;
160
+
161
+ // Bump base fee so it's valid for next blocks if it stalls
162
+ const numBlocks = Math.ceil(gasConfig.stallTimeMs! / BLOCK_TIME_MS);
163
+ for (let i = 0; i < numBlocks; i++) {
164
+ // each block can go up 12.5% from previous baseFee
165
+ maxFeePerGas = (maxFeePerGas * (1_000n + 125n)) / 1_000n;
166
+ // same for blob gas fee
167
+ maxFeePerBlobGas = (maxFeePerBlobGas * (1_000n + 125n)) / 1_000n;
168
+ }
169
+
170
+ if (attempt > 0) {
171
+ const configBump =
172
+ gasConfig.priorityFeeRetryBumpPercentage ?? defaultL1TxUtilsConfig.priorityFeeRetryBumpPercentage!;
173
+
174
+ // if this is a blob tx, we have to use the blob bump percentage
175
+ const minBumpPercentage = isBlobTx ? MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE : MIN_REPLACEMENT_BUMP_PERCENTAGE;
176
+
177
+ const bumpPercentage = configBump > minBumpPercentage ? configBump : minBumpPercentage;
178
+ // Calculate minimum required fees based on previous attempt
179
+ // multiply by 100 & divide by 100 to maintain some precision
180
+ const minPriorityFee =
181
+ (previousGasPrice!.maxPriorityFeePerGas * (100_00n + BigInt(bumpPercentage * 1_00))) / 100_00n;
182
+ const minMaxFee = (previousGasPrice!.maxFeePerGas * (100_00n + BigInt(bumpPercentage * 1_00))) / 100_00n;
183
+
184
+ // Apply bump percentage to competitive fee
185
+ const competitivePriorityFee = (priorityFee * (100_00n + BigInt(configBump * 1_00))) / 100_00n;
186
+
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
+ });
193
+
194
+ // Use maximum between competitive fee and minimum required bump
195
+ const finalPriorityFee = competitivePriorityFee > minPriorityFee ? competitivePriorityFee : minPriorityFee;
196
+ const feeSource = finalPriorityFee === competitivePriorityFee ? 'competitive' : 'minimum-bump';
197
+
198
+ priorityFee = finalPriorityFee;
199
+ // Add the final priority fee to maxFeePerGas
200
+ maxFeePerGas += finalPriorityFee;
201
+ maxFeePerGas = maxFeePerGas > minMaxFee ? maxFeePerGas : minMaxFee;
202
+
203
+ this.logger?.debug(`Speed-up fee decision: using ${feeSource} fee`, {
204
+ finalPriorityFee: formatGwei(finalPriorityFee),
205
+ });
206
+ } else {
207
+ // First attempt: apply configured bump percentage to competitive fee
208
+ // multiply by 100 & divide by 100 to maintain some precision
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
+ });
213
+ maxFeePerGas += priorityFee;
214
+ }
215
+
216
+ // maxGwei and maxBlobGwei are hard limits
217
+ const effectiveMaxGwei = BigInt(Math.trunc(gasConfig.maxGwei! * Number(WEI_CONST)));
218
+ const effectiveMaxBlobGwei = BigInt(Math.trunc(gasConfig.maxBlobGwei! * Number(WEI_CONST)));
219
+
220
+ // Ensure we don't exceed maxGwei
221
+ if (effectiveMaxGwei > 0n) {
222
+ maxFeePerGas = maxFeePerGas > effectiveMaxGwei ? effectiveMaxGwei : maxFeePerGas;
223
+ }
224
+
225
+ // Ensure we don't exceed maxBlobGwei
226
+ if (maxFeePerBlobGas && effectiveMaxBlobGwei > 0n) {
227
+ maxFeePerBlobGas = maxFeePerBlobGas > effectiveMaxBlobGwei ? effectiveMaxBlobGwei : maxFeePerBlobGas;
228
+ }
229
+
230
+ // Ensure priority fee doesn't exceed max fee
231
+ const maxPriorityFeePerGas = priorityFee > maxFeePerGas ? maxFeePerGas : priorityFee;
232
+
233
+ if (attempt > 0 && previousGasPrice?.maxFeePerBlobGas) {
234
+ const bumpPercentage =
235
+ gasConfig.priorityFeeRetryBumpPercentage! > MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE
236
+ ? gasConfig.priorityFeeRetryBumpPercentage!
237
+ : MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE;
238
+
239
+ // calculate min blob fee based on previous attempt
240
+ const minBlobFee = (previousGasPrice.maxFeePerBlobGas * (100_00n + BigInt(bumpPercentage * 1_00))) / 100_00n;
241
+
242
+ // use max between current network values and min required values
243
+ maxFeePerBlobGas = maxFeePerBlobGas > minBlobFee ? maxFeePerBlobGas : minBlobFee;
244
+ }
245
+
246
+ this.logger?.trace(
247
+ `Computed L1 gas price max fee ${formatGwei(maxFeePerGas)} and max priority fee ${formatGwei(maxPriorityFeePerGas)}`,
248
+ {
249
+ attempt,
250
+ baseFee: formatGwei(baseFee),
251
+ maxFeePerGas: formatGwei(maxFeePerGas),
252
+ maxPriorityFeePerGas: formatGwei(maxPriorityFeePerGas),
253
+ blobBaseFee: formatGwei(blobBaseFee),
254
+ maxFeePerBlobGas: formatGwei(maxFeePerBlobGas),
255
+ },
256
+ );
257
+
258
+ return {
259
+ maxFeePerGas,
260
+ maxPriorityFeePerGas,
261
+ ...(maxFeePerBlobGas && { maxFeePerBlobGas: maxFeePerBlobGas }),
262
+ };
263
+ }
264
+
265
+ /**
266
+ * Estimates gas and adds buffer
267
+ */
268
+ public async estimateGas(
269
+ account: Account | Hex,
270
+ request: L1TxRequest,
271
+ _gasConfig?: L1TxUtilsConfig,
272
+ _blobInputs?: L1BlobInputs,
273
+ ): Promise<bigint> {
274
+ const gasConfig = { ...this.config, ..._gasConfig };
275
+ let initialEstimate = 0n;
276
+ if (_blobInputs) {
277
+ // @note requests with blobs also require maxFeePerBlobGas to be set
278
+ const gasPrice = await this.getGasPrice(gasConfig, true, 0);
279
+ initialEstimate = await this.client.estimateGas({
280
+ account,
281
+ ...request,
282
+ ..._blobInputs,
283
+ maxFeePerBlobGas: gasPrice.maxFeePerBlobGas!,
284
+ gas: LARGE_GAS_LIMIT,
285
+ blockTag: 'latest',
286
+ });
287
+
288
+ this.logger?.trace(`Estimated gas for blob tx: ${initialEstimate}`);
289
+ } else {
290
+ initialEstimate = await this.client.estimateGas({
291
+ account,
292
+ ...request,
293
+ gas: LARGE_GAS_LIMIT,
294
+ blockTag: 'latest',
295
+ });
296
+ this.logger?.trace(`Estimated gas for non-blob tx: ${initialEstimate}`);
297
+ }
298
+
299
+ // Add buffer based on either fixed amount or percentage
300
+ const withBuffer = this.bumpGasLimit(initialEstimate, gasConfig);
301
+
302
+ return withBuffer;
303
+ }
304
+
305
+ async getTransactionStats(txHash: string): Promise<TransactionStats | undefined> {
306
+ const tx = await this.client.getTransaction({ hash: txHash as Hex });
307
+ if (!tx) {
308
+ return undefined;
309
+ }
310
+ const calldata = hexToBytes(tx.input);
311
+ return {
312
+ sender: tx.from.toString(),
313
+ transactionHash: tx.hash,
314
+ calldataSize: calldata.length,
315
+ calldataGas: getCalldataGasUsage(calldata),
316
+ };
317
+ }
318
+
319
+ public async tryGetErrorFromRevertedTx(
320
+ data: Hex,
321
+ args: {
322
+ args: readonly any[];
323
+ functionName: string;
324
+ abi: Abi;
325
+ address: Hex;
326
+ },
327
+ blobInputs: (L1BlobInputs & { maxFeePerBlobGas: bigint }) | undefined,
328
+ stateOverride: StateOverride = [],
329
+ ) {
330
+ try {
331
+ await this.client.simulateContract({
332
+ ...args,
333
+ account: this.client.account,
334
+ stateOverride,
335
+ });
336
+ this.logger?.trace('Simulated blob tx', { blobInputs });
337
+ // If the above passes, we have a blob error. We cannot simulate blob txs, and failed txs no longer throw errors.
338
+ // Strangely, the only way to throw the revert reason as an error and provide blobs is prepareTransactionRequest.
339
+ // See: https://github.com/wevm/viem/issues/2075
340
+ // This throws a EstimateGasExecutionError with the custom error information:
341
+ const request = blobInputs
342
+ ? {
343
+ account: this.client.account,
344
+ to: args.address,
345
+ data,
346
+ blobs: blobInputs.blobs,
347
+ kzg: blobInputs.kzg,
348
+ maxFeePerBlobGas: blobInputs.maxFeePerBlobGas,
349
+ }
350
+ : {
351
+ account: this.client.account,
352
+ to: args.address,
353
+ data,
354
+ };
355
+ this.logger?.trace('Preparing tx', { request });
356
+ await this.client.prepareTransactionRequest(request);
357
+ this.logger?.trace('Prepared tx');
358
+ return undefined;
359
+ } catch (simulationErr: any) {
360
+ // If we don't have a ContractFunctionExecutionError, we have a blob related error => use getContractError to get the error msg.
361
+ const contractErr =
362
+ simulationErr.name === 'ContractFunctionExecutionError'
363
+ ? simulationErr
364
+ : getContractError(simulationErr as BaseError, {
365
+ args: [],
366
+ abi: args.abi,
367
+ functionName: args.functionName,
368
+ address: args.address,
369
+ });
370
+ if (contractErr.name === 'ContractFunctionExecutionError') {
371
+ const execErr = contractErr as ContractFunctionExecutionError;
372
+ return tryGetCustomErrorNameContractFunction(execErr);
373
+ }
374
+ this.logger?.error(`Error getting error from simulation`, simulationErr);
375
+ }
376
+ }
377
+
378
+ public async simulate(
379
+ request: L1TxRequest & { gas?: bigint; from?: Hex },
380
+ blockOverrides: BlockOverrides<bigint, number> = {},
381
+ stateOverrides: StateOverride = [],
382
+ abi: Abi = RollupAbi,
383
+ _gasConfig?: L1TxUtilsConfig & { fallbackGasEstimate?: bigint },
384
+ ): Promise<{ gasUsed: bigint; result: `0x${string}` }> {
385
+ const gasConfig = { ...this.config, ..._gasConfig };
386
+
387
+ const call: any = {
388
+ to: request.to!,
389
+ data: request.data,
390
+ ...(request.from && { from: request.from }),
391
+ };
392
+
393
+ return await this._simulate(call, blockOverrides, stateOverrides, gasConfig, abi);
394
+ }
395
+
396
+ protected async _simulate(
397
+ call: any,
398
+ blockOverrides: BlockOverrides<bigint, number> = {},
399
+ stateOverrides: StateOverride = [],
400
+ gasConfig: L1TxUtilsConfig & { fallbackGasEstimate?: bigint },
401
+ abi: Abi,
402
+ ) {
403
+ try {
404
+ const result = await this.client.simulateBlocks({
405
+ validation: false,
406
+ blocks: [
407
+ {
408
+ blockOverrides,
409
+ stateOverrides,
410
+ calls: [call],
411
+ },
412
+ ],
413
+ });
414
+
415
+ if (result[0].calls[0].status === 'failure') {
416
+ this.logger?.error('L1 transaction simulation failed', result[0].calls[0].error);
417
+ const decodedError = decodeErrorResult({ abi, data: result[0].calls[0].data });
418
+
419
+ throw new Error(
420
+ `L1 transaction simulation failed with error ${decodedError.errorName}(${decodedError.args?.join(',')})`,
421
+ );
422
+ }
423
+ this.logger?.debug(`L1 transaction simulation succeeded`, { ...result[0].calls[0] });
424
+ return { gasUsed: result[0].gasUsed, result: result[0].calls[0].data as `0x${string}` };
425
+ } catch (err) {
426
+ if (err instanceof MethodNotFoundRpcError || err instanceof MethodNotSupportedRpcError) {
427
+ if (gasConfig.fallbackGasEstimate) {
428
+ this.logger?.warn(
429
+ `Node does not support eth_simulateV1 API. Using fallback gas estimate: ${gasConfig.fallbackGasEstimate}`,
430
+ );
431
+ return { gasUsed: gasConfig.fallbackGasEstimate, result: '0x' as `0x${string}` };
432
+ }
433
+ this.logger?.error('Node does not support eth_simulateV1 API');
434
+ }
435
+ throw err;
436
+ }
437
+ }
438
+
439
+ public bumpGasLimit(gasLimit: bigint, _gasConfig?: L1TxUtilsConfig): bigint {
440
+ const gasConfig = { ...this.config, ..._gasConfig };
441
+ const bumpedGasLimit = gasLimit + (gasLimit * BigInt((gasConfig?.gasLimitBufferPercentage || 0) * 1_00)) / 100_00n;
442
+
443
+ const cleanGasConfig = pickBy(gasConfig, (_, key) => key in l1TxUtilsConfigMappings);
444
+ this.logger?.trace(`Bumping gas limit from ${gasLimit} to ${bumpedGasLimit}`, {
445
+ gasLimit,
446
+ gasConfig: cleanGasConfig,
447
+ bumpedGasLimit,
448
+ });
449
+ return bumpedGasLimit;
450
+ }
451
+
452
+ /**
453
+ * Helper function to retry RPC calls twice
454
+ */
455
+ private tryTwice<T>(fn: () => Promise<T>, description: string): Promise<T> {
456
+ return retry<T>(fn, description, makeBackoff(times(2, () => 0)), this.logger, true);
457
+ }
458
+ }
@@ -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,85 @@
1
+ import type { BlobKzgInstance } from '@aztec/blob-lib/types';
2
+ import { EthAddress } from '@aztec/foundation/eth-address';
3
+ import type { ViemTransactionSignature } from '@aztec/foundation/eth-signature';
4
+
5
+ import type { Abi, Address, Hex, TransactionReceipt, TransactionSerializable } from 'viem';
6
+
7
+ import type { L1TxUtilsConfig } from './config.js';
8
+
9
+ export interface L1TxRequest {
10
+ to: Address | null;
11
+ data?: Hex;
12
+ value?: bigint;
13
+ abi?: Abi;
14
+ }
15
+
16
+ export type L1TxConfig = Partial<L1TxUtilsConfig> & { gasLimit?: bigint; txTimeoutAt?: Date };
17
+
18
+ export interface L1BlobInputs {
19
+ blobs: Uint8Array[];
20
+ kzg: BlobKzgInstance;
21
+ maxFeePerBlobGas?: bigint;
22
+ }
23
+
24
+ export interface GasPrice {
25
+ maxFeePerGas: bigint;
26
+ maxPriorityFeePerGas: bigint;
27
+ maxFeePerBlobGas?: bigint;
28
+ }
29
+
30
+ export type TransactionStats = {
31
+ /** Address of the sender. */
32
+ sender: string;
33
+ /** Hash of the transaction. */
34
+ transactionHash: string;
35
+ /** Size in bytes of the tx calldata */
36
+ calldataSize: number;
37
+ /** Gas required to pay for the calldata inclusion (depends on size and number of zeros) */
38
+ calldataGas: number;
39
+ };
40
+
41
+ export enum TxUtilsState {
42
+ IDLE,
43
+ SENT,
44
+ SPEED_UP,
45
+ CANCELLED,
46
+ NOT_MINED,
47
+ MINED,
48
+ }
49
+
50
+ export const TerminalTxUtilsState = [TxUtilsState.IDLE, TxUtilsState.MINED, TxUtilsState.NOT_MINED];
51
+
52
+ export type L1TxState = {
53
+ id: number;
54
+ txHashes: Hex[];
55
+ cancelTxHashes: Hex[];
56
+ gasLimit: bigint;
57
+ gasPrice: GasPrice;
58
+ txConfigOverrides: L1TxConfig;
59
+ request: L1TxRequest;
60
+ status: TxUtilsState;
61
+ nonce: number;
62
+ sentAtL1Ts: Date;
63
+ lastSentAtL1Ts: Date;
64
+ receipt?: TransactionReceipt;
65
+ blobInputs: L1BlobInputs | undefined;
66
+ };
67
+
68
+ export type SigningCallback = (
69
+ transaction: TransactionSerializable,
70
+ signingAddress: EthAddress,
71
+ ) => Promise<ViemTransactionSignature>;
72
+
73
+ export class UnknownMinedTxError extends Error {
74
+ constructor(nonce: number, account: string) {
75
+ super(`Nonce ${nonce} from account ${account} is MINED but not by one of our expected transactions`);
76
+ this.name = 'UnknownMinedTxError';
77
+ }
78
+ }
79
+
80
+ export class DroppedTransactionError extends Error {
81
+ constructor(nonce: number, account: string) {
82
+ super(`Transaction with nonce ${nonce} from account ${account} was dropped from the mempool`);
83
+ this.name = 'DroppedTransactionError';
84
+ }
85
+ }
@@ -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
+ }
@@ -0,0 +1,6 @@
1
+ import type { Buffer32 } from '@aztec/foundation/buffer';
2
+
3
+ export type L1BlockId = {
4
+ l1BlockNumber: bigint;
5
+ l1BlockHash: Buffer32;
6
+ };