@aztec/ethereum 3.0.0-canary.a9708bd → 3.0.0-devnet.20251212

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