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