@aztec/ethereum 2.1.0-rc.1 → 2.1.0-rc.11

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 (168) hide show
  1. package/dest/account.js +1 -1
  2. package/dest/chain.d.ts +1 -1
  3. package/dest/chain.d.ts.map +1 -1
  4. package/dest/chain.js +1 -1
  5. package/dest/client.d.ts +1 -1
  6. package/dest/client.d.ts.map +1 -1
  7. package/dest/client.js +3 -3
  8. package/dest/config.d.ts +1 -1
  9. package/dest/config.d.ts.map +1 -1
  10. package/dest/config.js +1 -1
  11. package/dest/constants.d.ts +1 -1
  12. package/dest/constants.d.ts.map +1 -1
  13. package/dest/contracts/empire_base.d.ts +2 -2
  14. package/dest/contracts/empire_base.d.ts.map +1 -1
  15. package/dest/contracts/empire_base.js +1 -1
  16. package/dest/contracts/empire_slashing_proposer.d.ts +5 -5
  17. package/dest/contracts/empire_slashing_proposer.d.ts.map +1 -1
  18. package/dest/contracts/empire_slashing_proposer.js +1 -1
  19. package/dest/contracts/fee_asset_handler.d.ts +6 -6
  20. package/dest/contracts/fee_asset_handler.d.ts.map +1 -1
  21. package/dest/contracts/fee_asset_handler.js +1 -1
  22. package/dest/contracts/fee_juice.d.ts +1 -1
  23. package/dest/contracts/fee_juice.d.ts.map +1 -1
  24. package/dest/contracts/fee_juice.js +1 -1
  25. package/dest/contracts/governance.d.ts +1 -1
  26. package/dest/contracts/governance.d.ts.map +1 -1
  27. package/dest/contracts/governance.js +8 -4
  28. package/dest/contracts/governance_proposer.d.ts +2 -3
  29. package/dest/contracts/governance_proposer.d.ts.map +1 -1
  30. package/dest/contracts/governance_proposer.js +2 -3
  31. package/dest/contracts/gse.d.ts +1 -1
  32. package/dest/contracts/gse.d.ts.map +1 -1
  33. package/dest/contracts/gse.js +1 -1
  34. package/dest/contracts/inbox.d.ts +1 -1
  35. package/dest/contracts/inbox.d.ts.map +1 -1
  36. package/dest/contracts/inbox.js +1 -1
  37. package/dest/contracts/multicall.d.ts +6 -8
  38. package/dest/contracts/multicall.d.ts.map +1 -1
  39. package/dest/contracts/multicall.js +3 -5
  40. package/dest/contracts/registry.d.ts +1 -1
  41. package/dest/contracts/registry.d.ts.map +1 -1
  42. package/dest/contracts/registry.js +1 -1
  43. package/dest/contracts/rollup.d.ts +9 -9
  44. package/dest/contracts/rollup.d.ts.map +1 -1
  45. package/dest/contracts/rollup.js +6 -7
  46. package/dest/contracts/slasher_contract.js +1 -1
  47. package/dest/contracts/tally_slashing_proposer.d.ts +1 -1
  48. package/dest/contracts/tally_slashing_proposer.d.ts.map +1 -1
  49. package/dest/contracts/tally_slashing_proposer.js +1 -1
  50. package/dest/deploy_l1_contracts.d.ts +3 -3
  51. package/dest/deploy_l1_contracts.d.ts.map +1 -1
  52. package/dest/deploy_l1_contracts.js +21 -6
  53. package/dest/eth-signer/eth-signer.d.ts +1 -1
  54. package/dest/eth-signer/eth-signer.d.ts.map +1 -1
  55. package/dest/index.d.ts +1 -1
  56. package/dest/index.d.ts.map +1 -1
  57. package/dest/index.js +1 -1
  58. package/dest/l1_artifacts.d.ts +1 -1
  59. package/dest/l1_artifacts.d.ts.map +1 -1
  60. package/dest/l1_tx_utils/config.d.ts +59 -0
  61. package/dest/l1_tx_utils/config.d.ts.map +1 -0
  62. package/dest/l1_tx_utils/config.js +73 -0
  63. package/dest/l1_tx_utils/constants.d.ts +6 -0
  64. package/dest/l1_tx_utils/constants.d.ts.map +1 -0
  65. package/dest/l1_tx_utils/constants.js +14 -0
  66. package/dest/l1_tx_utils/factory.d.ts +24 -0
  67. package/dest/l1_tx_utils/factory.d.ts.map +1 -0
  68. package/dest/l1_tx_utils/factory.js +12 -0
  69. package/dest/l1_tx_utils/index.d.ts +10 -0
  70. package/dest/l1_tx_utils/index.d.ts.map +1 -0
  71. package/dest/l1_tx_utils/index.js +10 -0
  72. package/dest/l1_tx_utils/interfaces.d.ts +76 -0
  73. package/dest/l1_tx_utils/interfaces.d.ts.map +1 -0
  74. package/dest/l1_tx_utils/interfaces.js +4 -0
  75. package/dest/l1_tx_utils/l1_tx_utils.d.ts +95 -0
  76. package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -0
  77. package/dest/l1_tx_utils/l1_tx_utils.js +610 -0
  78. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts +26 -0
  79. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +1 -0
  80. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.js +26 -0
  81. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +81 -0
  82. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -0
  83. package/dest/l1_tx_utils/readonly_l1_tx_utils.js +294 -0
  84. package/dest/l1_tx_utils/signer.d.ts +4 -0
  85. package/dest/l1_tx_utils/signer.d.ts.map +1 -0
  86. package/dest/l1_tx_utils/signer.js +16 -0
  87. package/dest/l1_tx_utils/types.d.ts +67 -0
  88. package/dest/l1_tx_utils/types.d.ts.map +1 -0
  89. package/dest/l1_tx_utils/types.js +26 -0
  90. package/dest/l1_tx_utils/utils.d.ts +4 -0
  91. package/dest/l1_tx_utils/utils.d.ts.map +1 -0
  92. package/dest/l1_tx_utils/utils.js +14 -0
  93. package/dest/publisher_manager.d.ts +3 -1
  94. package/dest/publisher_manager.d.ts.map +1 -1
  95. package/dest/publisher_manager.js +28 -8
  96. package/dest/test/chain_monitor.js +2 -2
  97. package/dest/test/delayed_tx_utils.d.ts +2 -2
  98. package/dest/test/delayed_tx_utils.d.ts.map +1 -1
  99. package/dest/test/delayed_tx_utils.js +2 -2
  100. package/dest/test/eth_cheat_codes.d.ts +18 -1
  101. package/dest/test/eth_cheat_codes.d.ts.map +1 -1
  102. package/dest/test/eth_cheat_codes.js +101 -22
  103. package/dest/test/rollup_cheat_codes.d.ts +1 -1
  104. package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
  105. package/dest/test/rollup_cheat_codes.js +2 -2
  106. package/dest/test/tx_delayer.d.ts +1 -1
  107. package/dest/test/tx_delayer.d.ts.map +1 -1
  108. package/dest/test/tx_delayer.js +1 -1
  109. package/dest/test/upgrade_utils.d.ts +1 -1
  110. package/dest/test/upgrade_utils.d.ts.map +1 -1
  111. package/dest/test/upgrade_utils.js +2 -2
  112. package/dest/types.d.ts +1 -1
  113. package/dest/types.d.ts.map +1 -1
  114. package/dest/utils.d.ts +1 -1
  115. package/dest/utils.d.ts.map +1 -1
  116. package/dest/utils.js +1 -1
  117. package/package.json +7 -7
  118. package/src/account.ts +1 -1
  119. package/src/chain.ts +2 -2
  120. package/src/client.ts +3 -3
  121. package/src/config.ts +1 -1
  122. package/src/constants.ts +1 -1
  123. package/src/contracts/empire_base.ts +2 -2
  124. package/src/contracts/empire_slashing_proposer.ts +3 -3
  125. package/src/contracts/fee_asset_handler.ts +2 -2
  126. package/src/contracts/fee_juice.ts +1 -1
  127. package/src/contracts/governance.ts +4 -4
  128. package/src/contracts/governance_proposer.ts +4 -5
  129. package/src/contracts/gse.ts +1 -1
  130. package/src/contracts/inbox.ts +1 -1
  131. package/src/contracts/multicall.ts +8 -11
  132. package/src/contracts/registry.ts +1 -1
  133. package/src/contracts/rollup.ts +11 -11
  134. package/src/contracts/slasher_contract.ts +1 -1
  135. package/src/contracts/tally_slashing_proposer.ts +1 -1
  136. package/src/deploy_l1_contracts.ts +20 -14
  137. package/src/eth-signer/eth-signer.ts +1 -1
  138. package/src/index.ts +1 -1
  139. package/src/l1_artifacts.ts +1 -1
  140. package/src/l1_tx_utils/README.md +177 -0
  141. package/src/l1_tx_utils/config.ts +140 -0
  142. package/src/l1_tx_utils/constants.ts +18 -0
  143. package/src/l1_tx_utils/factory.ts +64 -0
  144. package/src/l1_tx_utils/index.ts +12 -0
  145. package/src/l1_tx_utils/interfaces.ts +86 -0
  146. package/src/l1_tx_utils/l1_tx_utils.ts +718 -0
  147. package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +77 -0
  148. package/src/l1_tx_utils/readonly_l1_tx_utils.ts +372 -0
  149. package/src/l1_tx_utils/signer.ts +28 -0
  150. package/src/l1_tx_utils/types.ts +85 -0
  151. package/src/l1_tx_utils/utils.ts +16 -0
  152. package/src/publisher_manager.ts +39 -7
  153. package/src/test/chain_monitor.ts +2 -2
  154. package/src/test/delayed_tx_utils.ts +2 -2
  155. package/src/test/eth_cheat_codes.ts +120 -20
  156. package/src/test/rollup_cheat_codes.ts +2 -2
  157. package/src/test/tx_delayer.ts +2 -2
  158. package/src/test/upgrade_utils.ts +2 -2
  159. package/src/types.ts +1 -1
  160. package/src/utils.ts +1 -1
  161. package/dest/l1_tx_utils.d.ts +0 -252
  162. package/dest/l1_tx_utils.d.ts.map +0 -1
  163. package/dest/l1_tx_utils.js +0 -835
  164. package/dest/l1_tx_utils_with_blobs.d.ts +0 -20
  165. package/dest/l1_tx_utils_with_blobs.d.ts.map +0 -1
  166. package/dest/l1_tx_utils_with_blobs.js +0 -87
  167. package/src/l1_tx_utils.ts +0 -1125
  168. package/src/l1_tx_utils_with_blobs.ts +0 -150
@@ -1,835 +0,0 @@
1
- import { compactArray, times } from '@aztec/foundation/collection';
2
- import { bigintConfigHelper, booleanConfigHelper, getConfigFromMappings, getDefaultConfig, numberConfigHelper } from '@aztec/foundation/config';
3
- import { TimeoutError } from '@aztec/foundation/error';
4
- import { EthAddress } from '@aztec/foundation/eth-address';
5
- import { createLogger } from '@aztec/foundation/log';
6
- import { makeBackoff, retry } from '@aztec/foundation/retry';
7
- import { sleep } from '@aztec/foundation/sleep';
8
- import { DateProvider } from '@aztec/foundation/timer';
9
- import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
10
- import pickBy from 'lodash.pickby';
11
- import { MethodNotFoundRpcError, MethodNotSupportedRpcError, createNonceManager, decodeErrorResult, formatGwei, getContractError, hexToBytes, parseTransaction, serializeTransaction } from 'viem';
12
- import { jsonRpc } from 'viem/nonce';
13
- import { formatViemError } from './utils.js';
14
- // 1_000_000_000 Gwei = 1 ETH
15
- // 1_000_000_000 Wei = 1 Gwei
16
- // 1_000_000_000_000_000_000 Wei = 1 ETH
17
- const WEI_CONST = 1_000_000_000n;
18
- // @note using this large gas limit to avoid the issue of `gas limit too low` when estimating gas in reth
19
- const LARGE_GAS_LIMIT = 12_000_000n;
20
- // setting a minimum bump percentage to 10% due to geth's implementation
21
- // https://github.com/ethereum/go-ethereum/blob/e3d61e6db028c412f74bc4d4c7e117a9e29d0de0/core/txpool/legacypool/list.go#L298
22
- const MIN_REPLACEMENT_BUMP_PERCENTAGE = 10;
23
- // setting a minimum bump percentage to 100% due to geth's implementation
24
- // https://github.com/ethereum/go-ethereum/blob/e3d61e6db028c412f74bc4d4c7e117a9e29d0de0/core/txpool/blobpool/config.go#L34
25
- const MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE = 100;
26
- // Avg ethereum block time is ~12s
27
- const BLOCK_TIME_MS = 12_000;
28
- export const l1TxUtilsConfigMappings = {
29
- gasLimitBufferPercentage: {
30
- description: 'How much to increase calculated gas limit by (percentage)',
31
- env: 'L1_GAS_LIMIT_BUFFER_PERCENTAGE',
32
- ...numberConfigHelper(20)
33
- },
34
- maxGwei: {
35
- description: 'Maximum gas price in gwei',
36
- env: 'L1_GAS_PRICE_MAX',
37
- ...bigintConfigHelper(500n)
38
- },
39
- maxBlobGwei: {
40
- description: 'Maximum blob fee per gas in gwei',
41
- env: 'L1_BLOB_FEE_PER_GAS_MAX',
42
- ...bigintConfigHelper(1_500n)
43
- },
44
- priorityFeeBumpPercentage: {
45
- description: 'How much to increase priority fee by each attempt (percentage)',
46
- env: 'L1_PRIORITY_FEE_BUMP_PERCENTAGE',
47
- ...numberConfigHelper(20)
48
- },
49
- priorityFeeRetryBumpPercentage: {
50
- description: 'How much to increase priority fee by each retry attempt (percentage)',
51
- env: 'L1_PRIORITY_FEE_RETRY_BUMP_PERCENTAGE',
52
- ...numberConfigHelper(50)
53
- },
54
- fixedPriorityFeePerGas: {
55
- description: 'Fixed priority fee per gas in Gwei. Overrides any priority fee bump percentage',
56
- env: 'L1_FIXED_PRIORITY_FEE_PER_GAS',
57
- ...numberConfigHelper(0)
58
- },
59
- maxAttempts: {
60
- description: 'Maximum number of speed-up attempts',
61
- env: 'L1_TX_MONITOR_MAX_ATTEMPTS',
62
- ...numberConfigHelper(3)
63
- },
64
- checkIntervalMs: {
65
- description: 'How often to check tx status',
66
- env: 'L1_TX_MONITOR_CHECK_INTERVAL_MS',
67
- ...numberConfigHelper(1_000)
68
- },
69
- stallTimeMs: {
70
- description: 'How long before considering tx stalled',
71
- env: 'L1_TX_MONITOR_STALL_TIME_MS',
72
- ...numberConfigHelper(24_000)
73
- },
74
- txTimeoutMs: {
75
- description: 'How long to wait for a tx to be mined before giving up. Set to 0 to disable.',
76
- env: 'L1_TX_MONITOR_TX_TIMEOUT_MS',
77
- ...numberConfigHelper(120_000)
78
- },
79
- txPropagationMaxQueryAttempts: {
80
- description: 'How many attempts will be done to get a tx after it was sent',
81
- env: 'L1_TX_PROPAGATION_MAX_QUERY_ATTEMPTS',
82
- ...numberConfigHelper(3)
83
- },
84
- cancelTxOnTimeout: {
85
- description: "Whether to attempt to cancel a tx if it's not mined after txTimeoutMs",
86
- env: 'L1_TX_MONITOR_CANCEL_TX_ON_TIMEOUT',
87
- ...booleanConfigHelper(true)
88
- }
89
- };
90
- export const defaultL1TxUtilsConfig = getDefaultConfig(l1TxUtilsConfigMappings);
91
- export function getL1TxUtilsConfigEnvVars() {
92
- return getConfigFromMappings(l1TxUtilsConfigMappings);
93
- }
94
- export var TxUtilsState = /*#__PURE__*/ function(TxUtilsState) {
95
- TxUtilsState[TxUtilsState["IDLE"] = 0] = "IDLE";
96
- TxUtilsState[TxUtilsState["SENT"] = 1] = "SENT";
97
- TxUtilsState[TxUtilsState["SPEED_UP"] = 2] = "SPEED_UP";
98
- TxUtilsState[TxUtilsState["CANCELLED"] = 3] = "CANCELLED";
99
- TxUtilsState[TxUtilsState["NOT_MINED"] = 4] = "NOT_MINED";
100
- TxUtilsState[TxUtilsState["MINED"] = 5] = "MINED";
101
- return TxUtilsState;
102
- }({});
103
- export class ReadOnlyL1TxUtils {
104
- client;
105
- logger;
106
- dateProvider;
107
- debugMaxGasLimit;
108
- config;
109
- interrupted;
110
- constructor(client, logger = createLogger('ReadOnlyL1TxUtils'), dateProvider, config, debugMaxGasLimit = false){
111
- this.client = client;
112
- this.logger = logger;
113
- this.dateProvider = dateProvider;
114
- this.debugMaxGasLimit = debugMaxGasLimit;
115
- this.interrupted = false;
116
- this.config = {
117
- ...defaultL1TxUtilsConfig,
118
- ...config || {}
119
- };
120
- }
121
- interrupt() {
122
- this.interrupted = true;
123
- }
124
- restart() {
125
- this.interrupted = false;
126
- }
127
- getBlock() {
128
- return this.client.getBlock();
129
- }
130
- getBlockNumber() {
131
- return this.client.getBlockNumber();
132
- }
133
- /**
134
- * Gets the current gas price with bounds checking
135
- */ async getGasPrice(_gasConfig, isBlobTx = false, attempt = 0, previousGasPrice) {
136
- const gasConfig = {
137
- ...this.config,
138
- ..._gasConfig
139
- };
140
- const block = await this.client.getBlock({
141
- blockTag: 'latest'
142
- });
143
- const baseFee = block.baseFeePerGas ?? 0n;
144
- // Get blob base fee if available
145
- let blobBaseFee = 0n;
146
- if (isBlobTx) {
147
- try {
148
- blobBaseFee = await retry(()=>this.client.getBlobBaseFee(), 'Getting L1 blob base fee', makeBackoff(times(2, ()=>1)), this.logger, true);
149
- this.logger?.debug('L1 Blob base fee:', {
150
- blobBaseFee: formatGwei(blobBaseFee)
151
- });
152
- } catch {
153
- this.logger?.warn('Failed to get L1 blob base fee', attempt);
154
- }
155
- }
156
- let priorityFee;
157
- if (gasConfig.fixedPriorityFeePerGas) {
158
- this.logger?.debug('Using fixed priority fee per L1 gas', {
159
- fixedPriorityFeePerGas: gasConfig.fixedPriorityFeePerGas
160
- });
161
- // try to maintain precision up to 1000000 wei
162
- priorityFee = BigInt(gasConfig.fixedPriorityFeePerGas * 1_000_000) * (WEI_CONST / 1_000_000n);
163
- } else {
164
- // Get initial priority fee from the network
165
- priorityFee = await this.client.estimateMaxPriorityFeePerGas();
166
- }
167
- let maxFeePerGas = baseFee;
168
- let maxFeePerBlobGas = blobBaseFee;
169
- // Bump base fee so it's valid for next blocks if it stalls
170
- const numBlocks = Math.ceil(gasConfig.stallTimeMs / BLOCK_TIME_MS);
171
- for(let i = 0; i < numBlocks; i++){
172
- // each block can go up 12.5% from previous baseFee
173
- maxFeePerGas = maxFeePerGas * (1_000n + 125n) / 1_000n;
174
- // same for blob gas fee
175
- maxFeePerBlobGas = maxFeePerBlobGas * (1_000n + 125n) / 1_000n;
176
- }
177
- if (attempt > 0) {
178
- const configBump = gasConfig.priorityFeeRetryBumpPercentage ?? defaultL1TxUtilsConfig.priorityFeeRetryBumpPercentage;
179
- // if this is a blob tx, we have to use the blob bump percentage
180
- const minBumpPercentage = isBlobTx ? MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE : MIN_REPLACEMENT_BUMP_PERCENTAGE;
181
- const bumpPercentage = configBump > minBumpPercentage ? configBump : minBumpPercentage;
182
- // Calculate minimum required fees based on previous attempt
183
- // multiply by 100 & divide by 100 to maintain some precision
184
- const minPriorityFee = previousGasPrice.maxPriorityFeePerGas * (100_00n + BigInt(bumpPercentage * 1_00)) / 100_00n;
185
- const minMaxFee = previousGasPrice.maxFeePerGas * (100_00n + BigInt(bumpPercentage * 1_00)) / 100_00n;
186
- // Add priority fee to maxFeePerGas
187
- maxFeePerGas += priorityFee;
188
- // Use maximum between current network values and minimum required values
189
- priorityFee = priorityFee > minPriorityFee ? priorityFee : minPriorityFee;
190
- maxFeePerGas = maxFeePerGas > minMaxFee ? maxFeePerGas : minMaxFee;
191
- } else {
192
- // first attempt, just bump priority fee, unless it's a fixed config
193
- // multiply by 100 & divide by 100 to maintain some precision
194
- if (!gasConfig.fixedPriorityFeePerGas) {
195
- priorityFee = priorityFee * (100_00n + BigInt((gasConfig.priorityFeeBumpPercentage || 0) * 1_00)) / 100_00n;
196
- }
197
- maxFeePerGas += priorityFee;
198
- }
199
- // Ensure we don't exceed maxGwei
200
- const maxGweiInWei = gasConfig.maxGwei * WEI_CONST;
201
- maxFeePerGas = maxFeePerGas > maxGweiInWei ? maxGweiInWei : maxFeePerGas;
202
- // Ensure we don't exceed maxBlobGwei
203
- if (maxFeePerBlobGas) {
204
- const maxBlobGweiInWei = gasConfig.maxBlobGwei * WEI_CONST;
205
- maxFeePerBlobGas = maxFeePerBlobGas > maxBlobGweiInWei ? maxBlobGweiInWei : maxFeePerBlobGas;
206
- }
207
- // Ensure priority fee doesn't exceed max fee
208
- const maxPriorityFeePerGas = priorityFee > maxFeePerGas ? maxFeePerGas : priorityFee;
209
- if (attempt > 0 && previousGasPrice?.maxFeePerBlobGas) {
210
- const bumpPercentage = gasConfig.priorityFeeRetryBumpPercentage > MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE ? gasConfig.priorityFeeRetryBumpPercentage : MIN_BLOB_REPLACEMENT_BUMP_PERCENTAGE;
211
- // calculate min blob fee based on previous attempt
212
- const minBlobFee = previousGasPrice.maxFeePerBlobGas * (100_00n + BigInt(bumpPercentage * 1_00)) / 100_00n;
213
- // use max between current network values and min required values
214
- maxFeePerBlobGas = maxFeePerBlobGas > minBlobFee ? maxFeePerBlobGas : minBlobFee;
215
- }
216
- this.logger?.debug(`Computed L1 gas price`, {
217
- attempt,
218
- baseFee: formatGwei(baseFee),
219
- maxFeePerGas: formatGwei(maxFeePerGas),
220
- maxPriorityFeePerGas: formatGwei(maxPriorityFeePerGas),
221
- ...maxFeePerBlobGas && {
222
- maxFeePerBlobGas: formatGwei(maxFeePerBlobGas)
223
- }
224
- });
225
- return {
226
- maxFeePerGas,
227
- maxPriorityFeePerGas,
228
- ...maxFeePerBlobGas && {
229
- maxFeePerBlobGas: maxFeePerBlobGas
230
- }
231
- };
232
- }
233
- /**
234
- * Estimates gas and adds buffer
235
- */ async estimateGas(account, request, _gasConfig, _blobInputs) {
236
- const gasConfig = {
237
- ...this.config,
238
- ..._gasConfig
239
- };
240
- let initialEstimate = 0n;
241
- if (_blobInputs) {
242
- // @note requests with blobs also require maxFeePerBlobGas to be set
243
- const gasPrice = await this.getGasPrice(gasConfig, true, 0);
244
- initialEstimate = await this.client.estimateGas({
245
- account,
246
- ...request,
247
- ..._blobInputs,
248
- maxFeePerBlobGas: gasPrice.maxFeePerBlobGas,
249
- gas: LARGE_GAS_LIMIT
250
- });
251
- this.logger?.debug(`L1 gas used in estimateGas by blob tx: ${initialEstimate}`);
252
- } else {
253
- initialEstimate = await this.client.estimateGas({
254
- account,
255
- ...request,
256
- gas: LARGE_GAS_LIMIT
257
- });
258
- this.logger?.debug(`L1 gas used in estimateGas by non-blob tx: ${initialEstimate}`);
259
- }
260
- // Add buffer based on either fixed amount or percentage
261
- const withBuffer = this.bumpGasLimit(initialEstimate, gasConfig);
262
- return withBuffer;
263
- }
264
- async getTransactionStats(txHash) {
265
- const tx = await this.client.getTransaction({
266
- hash: txHash
267
- });
268
- if (!tx) {
269
- return undefined;
270
- }
271
- const calldata = hexToBytes(tx.input);
272
- return {
273
- sender: tx.from.toString(),
274
- transactionHash: tx.hash,
275
- calldataSize: calldata.length,
276
- calldataGas: getCalldataGasUsage(calldata)
277
- };
278
- }
279
- async tryGetErrorFromRevertedTx(data, args, blobInputs, stateOverride = []) {
280
- try {
281
- await this.client.simulateContract({
282
- ...args,
283
- account: this.client.account,
284
- stateOverride
285
- });
286
- this.logger?.trace('Simulated blob tx', {
287
- blobInputs
288
- });
289
- // If the above passes, we have a blob error. We cannot simulate blob txs, and failed txs no longer throw errors.
290
- // Strangely, the only way to throw the revert reason as an error and provide blobs is prepareTransactionRequest.
291
- // See: https://github.com/wevm/viem/issues/2075
292
- // This throws a EstimateGasExecutionError with the custom error information:
293
- const request = blobInputs ? {
294
- account: this.client.account,
295
- to: args.address,
296
- data,
297
- blobs: blobInputs.blobs,
298
- kzg: blobInputs.kzg,
299
- maxFeePerBlobGas: blobInputs.maxFeePerBlobGas
300
- } : {
301
- account: this.client.account,
302
- to: args.address,
303
- data
304
- };
305
- this.logger?.trace('Preparing tx', {
306
- request
307
- });
308
- await this.client.prepareTransactionRequest(request);
309
- this.logger?.trace('Prepared tx');
310
- return undefined;
311
- } catch (simulationErr) {
312
- // If we don't have a ContractFunctionExecutionError, we have a blob related error => use getContractError to get the error msg.
313
- const contractErr = simulationErr.name === 'ContractFunctionExecutionError' ? simulationErr : getContractError(simulationErr, {
314
- args: [],
315
- abi: args.abi,
316
- functionName: args.functionName,
317
- address: args.address
318
- });
319
- if (contractErr.name === 'ContractFunctionExecutionError') {
320
- const execErr = contractErr;
321
- return tryGetCustomErrorNameContractFunction(execErr);
322
- }
323
- this.logger?.error(`Error getting error from simulation`, simulationErr);
324
- }
325
- }
326
- async simulate(request, blockOverrides = {}, stateOverrides = [], abi = RollupAbi, _gasConfig) {
327
- const gasConfig = {
328
- ...this.config,
329
- ..._gasConfig
330
- };
331
- const call = {
332
- to: request.to,
333
- data: request.data,
334
- ...request.from && {
335
- from: request.from
336
- }
337
- };
338
- return await this._simulate(call, blockOverrides, stateOverrides, gasConfig, abi);
339
- }
340
- async _simulate(call, blockOverrides = {}, stateOverrides = [], gasConfig, abi) {
341
- try {
342
- const result = await this.client.simulateBlocks({
343
- validation: false,
344
- blocks: [
345
- {
346
- blockOverrides,
347
- stateOverrides,
348
- calls: [
349
- call
350
- ]
351
- }
352
- ]
353
- });
354
- if (result[0].calls[0].status === 'failure') {
355
- this.logger?.error('L1 transaction simulation failed', result[0].calls[0].error);
356
- const decodedError = decodeErrorResult({
357
- abi,
358
- data: result[0].calls[0].data
359
- });
360
- throw new Error(`L1 transaction simulation failed with error ${decodedError.errorName}(${decodedError.args?.join(',')})`);
361
- }
362
- this.logger?.debug(`L1 transaction simulation succeeded`, {
363
- ...result[0].calls[0]
364
- });
365
- return {
366
- gasUsed: result[0].gasUsed,
367
- result: result[0].calls[0].data
368
- };
369
- } catch (err) {
370
- if (err instanceof MethodNotFoundRpcError || err instanceof MethodNotSupportedRpcError) {
371
- if (gasConfig.fallbackGasEstimate) {
372
- this.logger?.warn(`Node does not support eth_simulateV1 API. Using fallback gas estimate: ${gasConfig.fallbackGasEstimate}`);
373
- return {
374
- gasUsed: gasConfig.fallbackGasEstimate,
375
- result: '0x'
376
- };
377
- }
378
- this.logger?.error('Node does not support eth_simulateV1 API');
379
- }
380
- throw err;
381
- }
382
- }
383
- bumpGasLimit(gasLimit, _gasConfig) {
384
- const gasConfig = {
385
- ...this.config,
386
- ..._gasConfig
387
- };
388
- const bumpedGasLimit = gasLimit + gasLimit * BigInt((gasConfig?.gasLimitBufferPercentage || 0) * 1_00) / 100_00n;
389
- const cleanGasConfig = pickBy(gasConfig, (_, key)=>key in l1TxUtilsConfigMappings);
390
- this.logger?.debug('Bumping gas limit', {
391
- gasLimit,
392
- gasConfig: cleanGasConfig,
393
- bumpedGasLimit
394
- });
395
- return bumpedGasLimit;
396
- }
397
- }
398
- export class L1TxUtils extends ReadOnlyL1TxUtils {
399
- client;
400
- address;
401
- signer;
402
- logger;
403
- txUtilsState;
404
- lastMinedBlockNumber;
405
- nonceManager;
406
- constructor(client, address, signer, logger = createLogger('L1TxUtils'), dateProvider = new DateProvider(), config, debugMaxGasLimit = false){
407
- super(client, logger, dateProvider, config, debugMaxGasLimit), this.client = client, this.address = address, this.signer = signer, this.logger = logger, this.txUtilsState = 0, this.lastMinedBlockNumber = undefined;
408
- this.nonceManager = createNonceManager({
409
- source: jsonRpc()
410
- });
411
- }
412
- get state() {
413
- return this.txUtilsState;
414
- }
415
- get lastMinedAtBlockNumber() {
416
- return this.lastMinedBlockNumber;
417
- }
418
- set lastMinedAtBlockNumber(blockNumber) {
419
- this.lastMinedBlockNumber = blockNumber;
420
- }
421
- set state(state) {
422
- this.txUtilsState = state;
423
- this.logger?.debug(`L1TxUtils state changed to ${TxUtilsState[state]} for sender: ${this.getSenderAddress().toString()}`);
424
- }
425
- getSenderAddress() {
426
- return this.address;
427
- }
428
- getSenderBalance() {
429
- return this.client.getBalance({
430
- address: this.getSenderAddress().toString()
431
- });
432
- }
433
- async signTransaction(txRequest) {
434
- const signature = await this.signer(txRequest, this.getSenderAddress());
435
- return serializeTransaction(txRequest, signature);
436
- }
437
- async prepareSignedTransaction(txData) {
438
- const txRequest = await this.client.prepareTransactionRequest(txData);
439
- return await this.signTransaction(txRequest);
440
- }
441
- /**
442
- * Sends a transaction with gas estimation and pricing
443
- * @param request - The transaction request (to, data, value)
444
- * @param gasConfig - Optional gas configuration
445
- * @returns The transaction hash and parameters used
446
- */ async sendTransaction(request, _gasConfig, blobInputs, stateChange = 1) {
447
- try {
448
- const gasConfig = {
449
- ...this.config,
450
- ..._gasConfig
451
- };
452
- const account = this.getSenderAddress().toString();
453
- let gasLimit;
454
- if (this.debugMaxGasLimit) {
455
- gasLimit = LARGE_GAS_LIMIT;
456
- } else if (gasConfig.gasLimit) {
457
- gasLimit = gasConfig.gasLimit;
458
- } else {
459
- gasLimit = await this.estimateGas(account, request, gasConfig);
460
- }
461
- this.logger?.debug(`Gas limit for request is ${gasLimit}`, {
462
- gasLimit,
463
- ...request
464
- });
465
- const gasPrice = await this.getGasPrice(gasConfig, !!blobInputs);
466
- if (gasConfig.txTimeoutAt && this.dateProvider.now() > gasConfig.txTimeoutAt.getTime()) {
467
- throw new Error('Transaction timed out before sending');
468
- }
469
- const nonce = await this.nonceManager.consume({
470
- client: this.client,
471
- address: account,
472
- chainId: this.client.chain.id
473
- });
474
- let txHash;
475
- if (blobInputs) {
476
- const txData = {
477
- ...request,
478
- ...blobInputs,
479
- gas: gasLimit,
480
- maxFeePerGas: gasPrice.maxFeePerGas,
481
- maxPriorityFeePerGas: gasPrice.maxPriorityFeePerGas,
482
- maxFeePerBlobGas: gasPrice.maxFeePerBlobGas,
483
- nonce
484
- };
485
- const signedRequest = await this.prepareSignedTransaction(txData);
486
- txHash = await this.client.sendRawTransaction({
487
- serializedTransaction: signedRequest
488
- });
489
- } else {
490
- const txData = {
491
- ...request,
492
- gas: gasLimit,
493
- maxFeePerGas: gasPrice.maxFeePerGas,
494
- maxPriorityFeePerGas: gasPrice.maxPriorityFeePerGas,
495
- nonce
496
- };
497
- const signedRequest = await this.prepareSignedTransaction(txData);
498
- txHash = await this.client.sendRawTransaction({
499
- serializedTransaction: signedRequest
500
- });
501
- }
502
- this.state = stateChange;
503
- const cleanGasConfig = pickBy(gasConfig, (_, key)=>key in l1TxUtilsConfigMappings);
504
- this.logger?.info(`Sent L1 transaction ${txHash}`, {
505
- gasLimit,
506
- maxFeePerGas: formatGwei(gasPrice.maxFeePerGas),
507
- maxPriorityFeePerGas: formatGwei(gasPrice.maxPriorityFeePerGas),
508
- gasConfig: cleanGasConfig,
509
- ...gasPrice.maxFeePerBlobGas && {
510
- maxFeePerBlobGas: formatGwei(gasPrice.maxFeePerBlobGas)
511
- }
512
- });
513
- return {
514
- txHash,
515
- gasLimit,
516
- gasPrice
517
- };
518
- } catch (err) {
519
- const viemError = formatViemError(err, request.abi);
520
- this.logger?.error(`Failed to send L1 transaction`, viemError.message, {
521
- metaMessages: viemError.metaMessages
522
- });
523
- throw viemError;
524
- }
525
- }
526
- /**
527
- * Monitors a transaction until completion, handling speed-ups if needed
528
- * @param request - Original transaction request (needed for speed-ups)
529
- * @param initialTxHash - Hash of the initial transaction
530
- * @param allVersions - Hashes of all transactions submitted under the same nonce (any of them could mine)
531
- * @param params - Parameters used in the initial transaction
532
- * @param gasConfig - Optional gas configuration
533
- */ async monitorTransaction(request, initialTxHash, allVersions, params, _gasConfig, _blobInputs, isCancelTx = false) {
534
- const isBlobTx = !!_blobInputs;
535
- const gasConfig = {
536
- ...this.config,
537
- ..._gasConfig
538
- };
539
- const account = this.getSenderAddress().toString();
540
- const blobInputs = _blobInputs || {};
541
- const makeGetTransactionBackoff = ()=>makeBackoff(times(gasConfig.txPropagationMaxQueryAttempts ?? 3, (i)=>i + 1));
542
- // Retry a few times, in case the tx is not yet propagated.
543
- const tx = await retry(()=>this.client.getTransaction({
544
- hash: initialTxHash
545
- }), `Getting L1 transaction ${initialTxHash}`, makeGetTransactionBackoff(), this.logger, true);
546
- if (!tx) {
547
- throw new Error(`Failed to get L1 transaction ${initialTxHash} to monitor`);
548
- }
549
- if (tx?.nonce === undefined || tx?.nonce === null) {
550
- throw new Error(`Failed to get L1 transaction ${initialTxHash} nonce`);
551
- }
552
- const nonce = tx.nonce;
553
- allVersions.add(initialTxHash);
554
- let currentTxHash = initialTxHash;
555
- let attempts = 0;
556
- let lastAttemptSent = this.dateProvider.now();
557
- let lastGasPrice = {
558
- maxFeePerGas: tx.maxFeePerGas,
559
- maxPriorityFeePerGas: tx.maxPriorityFeePerGas,
560
- maxFeePerBlobGas: tx.maxFeePerBlobGas
561
- };
562
- const initialTxTime = lastAttemptSent;
563
- let txTimedOut = false;
564
- let latestBlockTimestamp;
565
- // We check against the latestBlockTimestamp as opposed to the current time to avoid a race condition where
566
- // the tx is mined in a block with the same timestamp as txTimeoutAt, but our execution node has not yet processed it,
567
- // or the loop here has not yet checked the tx before that timeout.
568
- const isTimedOut = ()=>gasConfig.txTimeoutAt && latestBlockTimestamp !== undefined && Number(latestBlockTimestamp) * 1000 >= gasConfig.txTimeoutAt.getTime() || gasConfig.txTimeoutMs !== undefined && this.dateProvider.now() - initialTxTime > gasConfig.txTimeoutMs || this.interrupted || false;
569
- while(!txTimedOut){
570
- try {
571
- ({ timestamp: latestBlockTimestamp } = await this.client.getBlock({
572
- blockTag: 'latest',
573
- includeTransactions: false
574
- }));
575
- const currentNonce = await this.client.getTransactionCount({
576
- address: account
577
- });
578
- // If the current nonce on our account is greater than our transaction's nonce then a tx with the same nonce has been mined.
579
- if (currentNonce > nonce) {
580
- for (const hash of allVersions){
581
- try {
582
- const receipt = await this.client.getTransactionReceipt({
583
- hash
584
- });
585
- if (receipt) {
586
- if (receipt.status === 'reverted') {
587
- this.logger?.error(`L1 transaction ${hash} reverted`, receipt);
588
- } else {
589
- this.logger?.debug(`L1 transaction ${hash} mined`);
590
- }
591
- this.state = 5;
592
- this.lastMinedAtBlockNumber = receipt.blockNumber;
593
- return receipt;
594
- }
595
- } catch (err) {
596
- if (err instanceof Error && err.message.includes('reverted')) {
597
- throw formatViemError(err);
598
- }
599
- }
600
- }
601
- // If we get here then we have checked all of our tx versions and not found anything.
602
- // We should consider the nonce as MINED
603
- this.state = 5;
604
- throw new Error(`Nonce ${nonce} is MINED but not by one of our expected transactions`);
605
- }
606
- this.logger?.trace(`Tx timeout check for ${currentTxHash}: ${isTimedOut()}`, {
607
- latestBlockTimestamp: Number(latestBlockTimestamp) * 1000,
608
- lastAttemptSent,
609
- initialTxTime,
610
- now: this.dateProvider.now(),
611
- txTimeoutAt: gasConfig.txTimeoutAt?.getTime(),
612
- txTimeoutMs: gasConfig.txTimeoutMs,
613
- txStallTime: gasConfig.stallTimeMs
614
- });
615
- // Retry a few times, in case the tx is not yet propagated.
616
- const tx = await retry(()=>this.client.getTransaction({
617
- hash: currentTxHash
618
- }), `Getting L1 transaction ${currentTxHash}`, makeGetTransactionBackoff(), this.logger, true);
619
- const timePassed = this.dateProvider.now() - lastAttemptSent;
620
- if (tx && timePassed < gasConfig.stallTimeMs) {
621
- this.logger?.debug(`L1 transaction ${currentTxHash} pending. Time passed: ${timePassed}ms.`);
622
- // Check timeout before continuing
623
- txTimedOut = isTimedOut();
624
- if (txTimedOut) {
625
- break;
626
- }
627
- await sleep(gasConfig.checkIntervalMs);
628
- continue;
629
- }
630
- if (timePassed > gasConfig.stallTimeMs && attempts < gasConfig.maxAttempts) {
631
- attempts++;
632
- const newGasPrice = await this.getGasPrice(gasConfig, isBlobTx, attempts, tx.maxFeePerGas && tx.maxPriorityFeePerGas ? {
633
- maxFeePerGas: tx.maxFeePerGas,
634
- maxPriorityFeePerGas: tx.maxPriorityFeePerGas,
635
- maxFeePerBlobGas: tx.maxFeePerBlobGas
636
- } : undefined);
637
- lastGasPrice = newGasPrice;
638
- this.logger?.debug(`L1 transaction ${currentTxHash} appears stuck. Attempting speed-up ${attempts}/${gasConfig.maxAttempts} ` + `with new priority fee ${formatGwei(newGasPrice.maxPriorityFeePerGas)} gwei`, {
639
- maxFeePerGas: formatGwei(newGasPrice.maxFeePerGas),
640
- maxPriorityFeePerGas: formatGwei(newGasPrice.maxPriorityFeePerGas),
641
- ...newGasPrice.maxFeePerBlobGas && {
642
- maxFeePerBlobGas: formatGwei(newGasPrice.maxFeePerBlobGas)
643
- }
644
- });
645
- const txData = {
646
- ...request,
647
- ...blobInputs,
648
- nonce,
649
- gas: params.gasLimit,
650
- maxFeePerGas: newGasPrice.maxFeePerGas,
651
- maxPriorityFeePerGas: newGasPrice.maxPriorityFeePerGas
652
- };
653
- if (isBlobTx && newGasPrice.maxFeePerBlobGas) {
654
- txData.maxFeePerBlobGas = newGasPrice.maxFeePerBlobGas;
655
- }
656
- const signedRequest = await this.prepareSignedTransaction(txData);
657
- const newHash = await this.client.sendRawTransaction({
658
- serializedTransaction: signedRequest
659
- });
660
- if (!isCancelTx) {
661
- this.state = 2;
662
- }
663
- const cleanGasConfig = pickBy(gasConfig, (_, key)=>key in l1TxUtilsConfigMappings);
664
- this.logger?.verbose(`Sent L1 speed-up tx ${newHash}, replacing ${currentTxHash}`, {
665
- gasLimit: params.gasLimit,
666
- maxFeePerGas: formatGwei(newGasPrice.maxFeePerGas),
667
- maxPriorityFeePerGas: formatGwei(newGasPrice.maxPriorityFeePerGas),
668
- gasConfig: cleanGasConfig,
669
- ...newGasPrice.maxFeePerBlobGas && {
670
- maxFeePerBlobGas: formatGwei(newGasPrice.maxFeePerBlobGas)
671
- }
672
- });
673
- currentTxHash = newHash;
674
- allVersions.add(currentTxHash);
675
- lastAttemptSent = this.dateProvider.now();
676
- }
677
- await sleep(gasConfig.checkIntervalMs);
678
- } catch (err) {
679
- const viemError = formatViemError(err);
680
- this.logger?.warn(`Error monitoring L1 transaction ${currentTxHash}:`, viemError.message);
681
- if (viemError.message?.includes('reverted')) {
682
- throw viemError;
683
- }
684
- await sleep(gasConfig.checkIntervalMs);
685
- }
686
- // Check if tx has timed out.
687
- txTimedOut = isTimedOut();
688
- }
689
- // The transaction has timed out. If it's a cancellation then we are giving up on it.
690
- // Otherwise we may attempt to cancel it if configured to do so.
691
- if (isCancelTx) {
692
- this.state = 4;
693
- } else if (gasConfig.cancelTxOnTimeout) {
694
- // Fire cancellation without awaiting to avoid blocking the main thread
695
- this.attemptTxCancellation(currentTxHash, nonce, allVersions, isBlobTx, lastGasPrice, attempts).catch((err)=>{
696
- const viemError = formatViemError(err);
697
- this.logger?.error(`Failed to send cancellation for timed out tx ${currentTxHash}:`, viemError.message, {
698
- metaMessages: viemError.metaMessages
699
- });
700
- });
701
- }
702
- this.logger?.error(`L1 transaction ${currentTxHash} timed out`, undefined, {
703
- txHash: currentTxHash,
704
- txTimeoutAt: gasConfig.txTimeoutAt,
705
- txTimeoutMs: gasConfig.txTimeoutMs,
706
- txInitialTime: initialTxTime,
707
- now: this.dateProvider.now(),
708
- attempts,
709
- isInterrupted: this.interrupted,
710
- ...tx
711
- });
712
- throw new TimeoutError(`L1 transaction ${currentTxHash} timed out`);
713
- }
714
- /**
715
- * Sends a transaction and monitors it until completion
716
- * @param request - The transaction request (to, data, value)
717
- * @param gasConfig - Optional gas configuration
718
- * @returns The receipt of the successful transaction
719
- */ async sendAndMonitorTransaction(request, gasConfig, blobInputs) {
720
- const { txHash, gasLimit, gasPrice } = await this.sendTransaction(request, gasConfig, blobInputs);
721
- const receipt = await this.monitorTransaction(request, txHash, new Set(), {
722
- gasLimit
723
- }, gasConfig, blobInputs);
724
- return {
725
- receipt,
726
- gasPrice
727
- };
728
- }
729
- async simulate(request, _blockOverrides = {}, stateOverrides = [], abi = RollupAbi, _gasConfig) {
730
- const blockOverrides = {
731
- ..._blockOverrides
732
- };
733
- const gasConfig = {
734
- ...this.config,
735
- ..._gasConfig
736
- };
737
- const gasPrice = await this.getGasPrice(gasConfig, false);
738
- const call = {
739
- to: request.to,
740
- data: request.data,
741
- from: request.from ?? this.getSenderAddress().toString(),
742
- maxFeePerGas: gasPrice.maxFeePerGas,
743
- maxPriorityFeePerGas: gasPrice.maxPriorityFeePerGas,
744
- gas: request.gas ?? LARGE_GAS_LIMIT
745
- };
746
- if (!request.gas && !gasConfig.ignoreBlockGasLimit) {
747
- // LARGE_GAS_LIMIT is set as call.gas, increase block gasLimit
748
- blockOverrides.gasLimit = LARGE_GAS_LIMIT * 2n;
749
- }
750
- return this._simulate(call, blockOverrides, stateOverrides, gasConfig, abi);
751
- }
752
- /**
753
- * Attempts to cancel a transaction by sending a 0-value tx to self with same nonce but higher gas prices
754
- * @param nonce - The nonce of the transaction to cancel
755
- * @param allVersions - Hashes of all transactions submitted under the same nonce (any of them could mine)
756
- * @param previousGasPrice - The gas price of the previous transaction
757
- * @param attempts - The number of attempts to cancel the transaction
758
- * @returns The hash of the cancellation transaction
759
- */ async attemptTxCancellation(currentTxHash, nonce, allVersions, isBlobTx = false, previousGasPrice, attempts = 0) {
760
- if (isBlobTx) {
761
- throw new Error('Cannot cancel blob transactions, please use L1TxUtilsWithBlobsClass');
762
- }
763
- // Get gas price with higher priority fee for cancellation
764
- const cancelGasPrice = await this.getGasPrice({
765
- ...this.config,
766
- // Use high bump for cancellation to ensure it replaces the original tx
767
- priorityFeeRetryBumpPercentage: 150
768
- }, isBlobTx, attempts + 1, previousGasPrice);
769
- this.logger?.info(`Attempting to cancel L1 transaction ${currentTxHash} with nonce ${nonce}`, {
770
- maxFeePerGas: formatGwei(cancelGasPrice.maxFeePerGas),
771
- maxPriorityFeePerGas: formatGwei(cancelGasPrice.maxPriorityFeePerGas)
772
- });
773
- const request = {
774
- to: this.getSenderAddress().toString(),
775
- value: 0n
776
- };
777
- // Send 0-value tx to self with higher gas price
778
- const txData = {
779
- ...request,
780
- nonce,
781
- gas: 21_000n,
782
- maxFeePerGas: cancelGasPrice.maxFeePerGas,
783
- maxPriorityFeePerGas: cancelGasPrice.maxPriorityFeePerGas
784
- };
785
- const signedRequest = await this.prepareSignedTransaction(txData);
786
- const cancelTxHash = await this.client.sendRawTransaction({
787
- serializedTransaction: signedRequest
788
- });
789
- this.state = 3;
790
- this.logger?.info(`Sent cancellation tx ${cancelTxHash} for timed out tx ${currentTxHash}`, {
791
- nonce
792
- });
793
- const receipt = await this.monitorTransaction(request, cancelTxHash, allVersions, {
794
- gasLimit: 21_000n
795
- }, undefined, undefined, true);
796
- return receipt.transactionHash;
797
- }
798
- }
799
- export function createViemSigner(client) {
800
- const signer = async (tx, _address)=>{
801
- const signedTx = await client.signTransaction(tx);
802
- const parsed = parseTransaction(signedTx);
803
- if (!parsed.r || !parsed.s || parsed.yParity !== 0 && parsed.yParity !== 1) {
804
- throw new Error('Failed to extract signature from viem signed transaction');
805
- }
806
- return {
807
- r: parsed.r,
808
- s: parsed.s,
809
- yParity: parsed.yParity
810
- };
811
- };
812
- return signer;
813
- }
814
- export function createL1TxUtilsFromViemWallet(client, logger = createLogger('L1TxUtils'), dateProvider = new DateProvider(), config, debugMaxGasLimit = false) {
815
- return new L1TxUtils(client, EthAddress.fromString(client.account.address), createViemSigner(client), logger, dateProvider, config, debugMaxGasLimit);
816
- }
817
- export function createL1TxUtilsFromEthSigner(client, signer, logger = createLogger('L1TxUtils'), dateProvider = new DateProvider(), config, debugMaxGasLimit = false) {
818
- const callback = async (transaction, _signingAddress)=>{
819
- return (await signer.signTransaction(transaction)).toViemTransactionSignature();
820
- };
821
- return new L1TxUtils(client, signer.address, callback, logger, dateProvider, config, debugMaxGasLimit);
822
- }
823
- export function tryGetCustomErrorNameContractFunction(err) {
824
- return compactArray([
825
- err.shortMessage,
826
- ...(err.metaMessages ?? []).slice(0, 2).map((s)=>s.trim())
827
- ]).join(' ');
828
- }
829
- /*
830
- * Returns cost of calldata usage in Ethereum.
831
- * @param data - Calldata.
832
- * @returns 4 for each zero byte, 16 for each nonzero.
833
- */ export function getCalldataGasUsage(data) {
834
- return data.filter((byte)=>byte === 0).length * 4 + data.filter((byte)=>byte !== 0).length * 16;
835
- }