@aztec/ethereum 0.0.0-test.1 → 0.0.1-commit.21caa21

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