@aztec/ethereum 3.0.0-nightly.20251211 → 3.0.0-nightly.20251213
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/config.d.ts +3 -42
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +3 -327
- package/dest/contracts/inbox.d.ts +3 -3
- package/dest/contracts/inbox.d.ts.map +1 -1
- package/dest/contracts/rollup.d.ts +3 -3
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/deploy_aztec_l1_contracts.d.ts +245 -0
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -0
- package/dest/deploy_aztec_l1_contracts.js +329 -0
- package/dest/deploy_l1_contract.d.ts +68 -0
- package/dest/deploy_l1_contract.d.ts.map +1 -0
- package/dest/deploy_l1_contract.js +312 -0
- package/dest/forwarder_proxy.js +1 -1
- package/dest/l1_artifacts.d.ts +37 -37
- package/dest/test/rollup_cheat_codes.js +4 -1
- package/dest/test/start_anvil.d.ts +3 -1
- package/dest/test/start_anvil.d.ts.map +1 -1
- package/package.json +10 -6
- package/src/config.ts +2 -406
- package/src/contracts/inbox.ts +2 -2
- package/src/contracts/rollup.ts +2 -2
- package/src/deploy_aztec_l1_contracts.ts +545 -0
- package/src/deploy_l1_contract.ts +362 -0
- package/src/forwarder_proxy.ts +1 -1
- package/src/test/rollup_cheat_codes.ts +1 -1
- package/src/test/start_anvil.ts +2 -0
- package/dest/deploy_l1_contracts.d.ts +0 -673
- package/dest/deploy_l1_contracts.d.ts.map +0 -1
- package/dest/deploy_l1_contracts.js +0 -1491
- package/src/deploy_l1_contracts.ts +0 -1869
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
2
|
+
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
3
|
+
import { DateProvider } from '@aztec/foundation/timer';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
type Abi,
|
|
7
|
+
type ContractConstructorArgs,
|
|
8
|
+
type Hex,
|
|
9
|
+
type Narrow,
|
|
10
|
+
concatHex,
|
|
11
|
+
encodeAbiParameters,
|
|
12
|
+
encodeDeployData,
|
|
13
|
+
getContractAddress,
|
|
14
|
+
numberToHex,
|
|
15
|
+
padHex,
|
|
16
|
+
} from 'viem';
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
type ContractArtifacts,
|
|
20
|
+
DEPLOYER_ADDRESS,
|
|
21
|
+
type Libraries,
|
|
22
|
+
type VerificationLibraryEntry,
|
|
23
|
+
type VerificationRecord,
|
|
24
|
+
} from './deploy_aztec_l1_contracts.js';
|
|
25
|
+
import { RegisterNewRollupVersionPayloadArtifact } from './l1_artifacts.js';
|
|
26
|
+
import { type L1TxUtilsConfig, getL1TxUtilsConfigEnvVars } from './l1_tx_utils/config.js';
|
|
27
|
+
import { createL1TxUtilsFromViemWallet } from './l1_tx_utils/factory.js';
|
|
28
|
+
import type { L1TxUtils } from './l1_tx_utils/l1_tx_utils.js';
|
|
29
|
+
import type { GasPrice, L1TxConfig, L1TxRequest } from './l1_tx_utils/types.js';
|
|
30
|
+
import type { ExtendedViemWalletClient } from './types.js';
|
|
31
|
+
import { formatViemError } from './utils.js';
|
|
32
|
+
|
|
33
|
+
export class L1Deployer {
|
|
34
|
+
private salt: Hex | undefined;
|
|
35
|
+
private txHashes: Hex[] = [];
|
|
36
|
+
public readonly l1TxUtils: L1TxUtils;
|
|
37
|
+
public readonly verificationRecords: VerificationRecord[] = [];
|
|
38
|
+
|
|
39
|
+
constructor(
|
|
40
|
+
public readonly client: ExtendedViemWalletClient,
|
|
41
|
+
maybeSalt: number | undefined,
|
|
42
|
+
dateProvider: DateProvider = new DateProvider(),
|
|
43
|
+
private acceleratedTestDeployments: boolean = false,
|
|
44
|
+
private logger: Logger = createLogger('L1Deployer'),
|
|
45
|
+
private txUtilsConfig?: L1TxUtilsConfig,
|
|
46
|
+
private createVerificationJson: boolean = false,
|
|
47
|
+
) {
|
|
48
|
+
this.salt = maybeSalt ? padHex(numberToHex(maybeSalt), { size: 32 }) : undefined;
|
|
49
|
+
this.l1TxUtils = createL1TxUtilsFromViemWallet(
|
|
50
|
+
this.client,
|
|
51
|
+
{ logger: this.logger, dateProvider },
|
|
52
|
+
{ ...this.txUtilsConfig, debugMaxGasLimit: acceleratedTestDeployments },
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async deploy<const TAbi extends Abi>(
|
|
57
|
+
params: ContractArtifacts<TAbi>,
|
|
58
|
+
args?: ContractConstructorArgs<TAbi>,
|
|
59
|
+
opts: { gasLimit?: bigint; noSimulation?: boolean } = {},
|
|
60
|
+
): Promise<{ address: EthAddress; existed: boolean }> {
|
|
61
|
+
this.logger.debug(`Deploying ${params.name} contract`, { args });
|
|
62
|
+
try {
|
|
63
|
+
const { txHash, address, deployedLibraries, existed } = await deployL1Contract(
|
|
64
|
+
this.client,
|
|
65
|
+
params.contractAbi,
|
|
66
|
+
params.contractBytecode,
|
|
67
|
+
(args ?? []) as readonly unknown[],
|
|
68
|
+
{
|
|
69
|
+
salt: this.salt,
|
|
70
|
+
libraries: params.libraries,
|
|
71
|
+
logger: this.logger,
|
|
72
|
+
l1TxUtils: this.l1TxUtils,
|
|
73
|
+
acceleratedTestDeployments: this.acceleratedTestDeployments,
|
|
74
|
+
gasLimit: opts.gasLimit,
|
|
75
|
+
noSimulation: opts.noSimulation,
|
|
76
|
+
},
|
|
77
|
+
);
|
|
78
|
+
if (txHash) {
|
|
79
|
+
this.txHashes.push(txHash);
|
|
80
|
+
}
|
|
81
|
+
this.logger.debug(`Deployed ${params.name} at ${address}`, { args });
|
|
82
|
+
|
|
83
|
+
if (this.createVerificationJson) {
|
|
84
|
+
// Encode constructor args for verification
|
|
85
|
+
let constructorArgsHex: Hex = '0x';
|
|
86
|
+
try {
|
|
87
|
+
const abiItem: any = (params.contractAbi as any[]).find((x: any) => x && x.type === 'constructor');
|
|
88
|
+
const inputDefs: any[] = abiItem && Array.isArray(abiItem.inputs) ? abiItem.inputs : [];
|
|
89
|
+
constructorArgsHex =
|
|
90
|
+
inputDefs.length > 0 ? (encodeAbiParameters(inputDefs as any, (args ?? []) as any) as Hex) : ('0x' as Hex);
|
|
91
|
+
} catch {
|
|
92
|
+
constructorArgsHex = '0x' as Hex;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
this.verificationRecords.push({
|
|
96
|
+
name: params.name,
|
|
97
|
+
address: address.toString(),
|
|
98
|
+
constructorArgsHex,
|
|
99
|
+
libraries: deployedLibraries ?? [],
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
address,
|
|
104
|
+
existed,
|
|
105
|
+
};
|
|
106
|
+
} catch (error) {
|
|
107
|
+
throw new Error(`Failed to deploy ${params.name}`, { cause: formatViemError(error) });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async waitForDeployments(): Promise<void> {
|
|
112
|
+
if (this.acceleratedTestDeployments) {
|
|
113
|
+
this.logger.info('Accelerated test deployments - skipping waiting for deployments');
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (this.txHashes.length === 0) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
this.logger.verbose(`Waiting for ${this.txHashes.length} transactions to be mined`, { txHashes: this.txHashes });
|
|
121
|
+
const receipts = await Promise.all(
|
|
122
|
+
this.txHashes.map(txHash => this.client.waitForTransactionReceipt({ hash: txHash })),
|
|
123
|
+
);
|
|
124
|
+
const failed = receipts.filter(r => r.status !== 'success');
|
|
125
|
+
if (failed.length > 0) {
|
|
126
|
+
throw new Error(`Some deployment txs have failed: ${failed.map(f => f.transactionHash).join(', ')}`);
|
|
127
|
+
}
|
|
128
|
+
this.logger.info('All transactions mined successfully', { txHashes: this.txHashes });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
sendTransaction(
|
|
132
|
+
tx: L1TxRequest,
|
|
133
|
+
options?: L1TxConfig,
|
|
134
|
+
): Promise<{ txHash: Hex; gasLimit: bigint; gasPrice: GasPrice }> {
|
|
135
|
+
return this.l1TxUtils.sendTransaction(tx, options).then(({ txHash, state }) => ({
|
|
136
|
+
txHash,
|
|
137
|
+
gasLimit: state.gasLimit,
|
|
138
|
+
gasPrice: state.gasPrice,
|
|
139
|
+
}));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Helper function to deploy ETH contracts.
|
|
145
|
+
* @param walletClient - A viem WalletClient.
|
|
146
|
+
* @param publicClient - A viem PublicClient.
|
|
147
|
+
* @param abi - The ETH contract's ABI (as abitype's Abi).
|
|
148
|
+
* @param bytecode - The ETH contract's bytecode.
|
|
149
|
+
* @param args - Constructor arguments for the contract.
|
|
150
|
+
* @param salt - Optional salt for CREATE2 deployment (does not wait for deployment tx to be mined if set, does not send tx if contract already exists).
|
|
151
|
+
* @returns The ETH address the contract was deployed to.
|
|
152
|
+
*/
|
|
153
|
+
export async function deployL1Contract(
|
|
154
|
+
extendedClient: ExtendedViemWalletClient,
|
|
155
|
+
abi: Narrow<Abi | readonly unknown[]>,
|
|
156
|
+
bytecode: Hex,
|
|
157
|
+
args: readonly unknown[] = [],
|
|
158
|
+
opts: {
|
|
159
|
+
salt?: Hex;
|
|
160
|
+
libraries?: Libraries;
|
|
161
|
+
logger?: Logger;
|
|
162
|
+
l1TxUtils?: L1TxUtils;
|
|
163
|
+
gasLimit?: bigint;
|
|
164
|
+
acceleratedTestDeployments?: boolean;
|
|
165
|
+
noSimulation?: boolean;
|
|
166
|
+
} = {},
|
|
167
|
+
): Promise<{
|
|
168
|
+
address: EthAddress;
|
|
169
|
+
txHash: Hex | undefined;
|
|
170
|
+
deployedLibraries?: VerificationLibraryEntry[];
|
|
171
|
+
existed: boolean;
|
|
172
|
+
}> {
|
|
173
|
+
let txHash: Hex | undefined = undefined;
|
|
174
|
+
let resultingAddress: Hex | null | undefined = undefined;
|
|
175
|
+
const deployedLibraries: VerificationLibraryEntry[] = [];
|
|
176
|
+
|
|
177
|
+
const { salt: saltFromOpts, libraries, logger, gasLimit, acceleratedTestDeployments, noSimulation } = opts;
|
|
178
|
+
let { l1TxUtils } = opts;
|
|
179
|
+
|
|
180
|
+
if (!l1TxUtils) {
|
|
181
|
+
const config = getL1TxUtilsConfigEnvVars();
|
|
182
|
+
l1TxUtils = createL1TxUtilsFromViemWallet(
|
|
183
|
+
extendedClient,
|
|
184
|
+
{ logger },
|
|
185
|
+
{ ...config, debugMaxGasLimit: acceleratedTestDeployments },
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (libraries) {
|
|
190
|
+
// Note that this does NOT work well for linked libraries having linked libraries.
|
|
191
|
+
|
|
192
|
+
// Verify that all link references have corresponding code
|
|
193
|
+
for (const linkRef in libraries.linkReferences) {
|
|
194
|
+
for (const contractName in libraries.linkReferences[linkRef]) {
|
|
195
|
+
if (!libraries.libraryCode[contractName]) {
|
|
196
|
+
throw new Error(`Missing library code for ${contractName}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const replacements: Record<string, EthAddress> = {};
|
|
202
|
+
const libraryTxs: Hex[] = [];
|
|
203
|
+
for (const libraryName in libraries?.libraryCode) {
|
|
204
|
+
const lib = libraries.libraryCode[libraryName];
|
|
205
|
+
const { libraries: _libraries, ...optsWithoutLibraries } = opts;
|
|
206
|
+
const { address, txHash } = await deployL1Contract(
|
|
207
|
+
extendedClient,
|
|
208
|
+
lib.contractAbi,
|
|
209
|
+
lib.contractBytecode,
|
|
210
|
+
[],
|
|
211
|
+
optsWithoutLibraries,
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
// Log deployed library name and address for easier verification/triage
|
|
215
|
+
logger?.verbose(`Linked library deployed`, { library: libraryName, address: address.toString(), txHash });
|
|
216
|
+
|
|
217
|
+
if (txHash) {
|
|
218
|
+
libraryTxs.push(txHash);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Try to find the source file for this library from linkReferences
|
|
222
|
+
let fileNameForLibrary: string | undefined = undefined;
|
|
223
|
+
for (const fileName in libraries.linkReferences) {
|
|
224
|
+
if (libraries.linkReferences[fileName] && libraries.linkReferences[fileName][libraryName]) {
|
|
225
|
+
fileNameForLibrary = fileName;
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (fileNameForLibrary) {
|
|
230
|
+
deployedLibraries.push({
|
|
231
|
+
file: fileNameForLibrary,
|
|
232
|
+
contract: libraryName,
|
|
233
|
+
address: address.toString(),
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
for (const linkRef in libraries.linkReferences) {
|
|
238
|
+
for (const contractName in libraries.linkReferences[linkRef]) {
|
|
239
|
+
// If the library name matches the one we just deployed, we replace it.
|
|
240
|
+
if (contractName !== libraryName) {
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// We read the first instance to figure out what we are to replace.
|
|
245
|
+
const start = 2 + 2 * libraries.linkReferences[linkRef][contractName][0].start;
|
|
246
|
+
const length = 2 * libraries.linkReferences[linkRef][contractName][0].length;
|
|
247
|
+
|
|
248
|
+
const toReplace = bytecode.slice(start, start + length);
|
|
249
|
+
replacements[toReplace] = address;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const escapeRegExp = (s: string) => {
|
|
255
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // Escape special characters
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
for (const toReplace in replacements) {
|
|
259
|
+
const replacement = replacements[toReplace].toString().slice(2);
|
|
260
|
+
bytecode = bytecode.replace(new RegExp(escapeRegExp(toReplace), 'g'), replacement) as Hex;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Reth fails gas estimation if the deployed contract attempts to call a library that is not yet deployed,
|
|
264
|
+
// so we wait for all library deployments to be mined before deploying the contract.
|
|
265
|
+
// However, if we are in fast mode or using debugMaxGasLimit, we will skip simulation, so we can skip waiting.
|
|
266
|
+
if (libraryTxs.length > 0 && !acceleratedTestDeployments) {
|
|
267
|
+
logger?.verbose(`Awaiting for linked libraries to be deployed`);
|
|
268
|
+
await Promise.all(libraryTxs.map(txHash => extendedClient.waitForTransactionReceipt({ hash: txHash })));
|
|
269
|
+
} else {
|
|
270
|
+
logger?.verbose(
|
|
271
|
+
`Skipping waiting for linked libraries to be deployed ${
|
|
272
|
+
acceleratedTestDeployments ? '(accelerated test deployments)' : ''
|
|
273
|
+
}`,
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
let existed = false;
|
|
279
|
+
|
|
280
|
+
if (saltFromOpts) {
|
|
281
|
+
logger?.info(`Deploying contract with salt ${saltFromOpts}`);
|
|
282
|
+
const { address, paddedSalt: salt, calldata } = getExpectedAddress(abi, bytecode, args, saltFromOpts);
|
|
283
|
+
resultingAddress = address;
|
|
284
|
+
const existing = await extendedClient.getCode({ address: resultingAddress });
|
|
285
|
+
if (existing === undefined || existing === '0x') {
|
|
286
|
+
if (!noSimulation) {
|
|
287
|
+
try {
|
|
288
|
+
await l1TxUtils.simulate({ to: DEPLOYER_ADDRESS, data: concatHex([salt, calldata]), gas: gasLimit });
|
|
289
|
+
} catch (err) {
|
|
290
|
+
logger?.error(`Failed to simulate deployment tx using universal deployer`, err);
|
|
291
|
+
await l1TxUtils.simulate({ to: null, data: encodeDeployData({ abi, bytecode, args }), gas: gasLimit });
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
const res = await l1TxUtils.sendTransaction(
|
|
295
|
+
{ to: DEPLOYER_ADDRESS, data: concatHex([salt, calldata]) },
|
|
296
|
+
{ gasLimit },
|
|
297
|
+
);
|
|
298
|
+
txHash = res.txHash;
|
|
299
|
+
|
|
300
|
+
logger?.verbose(`Deployed contract with salt ${salt} to address ${resultingAddress} in tx ${txHash}.`);
|
|
301
|
+
} else {
|
|
302
|
+
logger?.verbose(`Skipping existing deployment of contract with salt ${salt} to address ${resultingAddress}`);
|
|
303
|
+
existed = true;
|
|
304
|
+
}
|
|
305
|
+
} else {
|
|
306
|
+
const deployData = encodeDeployData({ abi, bytecode, args });
|
|
307
|
+
const { receipt } = await l1TxUtils.sendAndMonitorTransaction(
|
|
308
|
+
{
|
|
309
|
+
to: null,
|
|
310
|
+
data: deployData,
|
|
311
|
+
},
|
|
312
|
+
{ gasLimit },
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
txHash = receipt.transactionHash;
|
|
316
|
+
resultingAddress = receipt.contractAddress;
|
|
317
|
+
if (!resultingAddress) {
|
|
318
|
+
throw new Error(
|
|
319
|
+
`No contract address found in receipt: ${JSON.stringify(receipt, (_, val) =>
|
|
320
|
+
typeof val === 'bigint' ? String(val) : val,
|
|
321
|
+
)}`,
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return { address: EthAddress.fromString(resultingAddress!), txHash, deployedLibraries, existed };
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export function getExpectedAddress(
|
|
330
|
+
abi: Narrow<Abi | readonly unknown[]>,
|
|
331
|
+
bytecode: Hex,
|
|
332
|
+
args: readonly unknown[],
|
|
333
|
+
salt: Hex,
|
|
334
|
+
) {
|
|
335
|
+
const paddedSalt = padHex(salt, { size: 32 });
|
|
336
|
+
const calldata = encodeDeployData({ abi, bytecode, args });
|
|
337
|
+
const address = getContractAddress({
|
|
338
|
+
from: DEPLOYER_ADDRESS,
|
|
339
|
+
salt: paddedSalt,
|
|
340
|
+
bytecode: calldata,
|
|
341
|
+
opcode: 'CREATE2',
|
|
342
|
+
});
|
|
343
|
+
return {
|
|
344
|
+
address,
|
|
345
|
+
paddedSalt,
|
|
346
|
+
calldata,
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
export const deployUpgradePayload = async (
|
|
351
|
+
deployer: L1Deployer,
|
|
352
|
+
addresses: { registryAddress: EthAddress; rollupAddress: EthAddress },
|
|
353
|
+
) => {
|
|
354
|
+
const payloadAddress = (
|
|
355
|
+
await deployer.deploy(RegisterNewRollupVersionPayloadArtifact, [
|
|
356
|
+
addresses.registryAddress.toString(),
|
|
357
|
+
addresses.rollupAddress.toString(),
|
|
358
|
+
])
|
|
359
|
+
).address;
|
|
360
|
+
|
|
361
|
+
return payloadAddress;
|
|
362
|
+
};
|
package/src/forwarder_proxy.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { DateProvider } from '@aztec/foundation/timer';
|
|
|
7
7
|
import { type Hex, extractChain } from 'viem';
|
|
8
8
|
import { anvil, mainnet, sepolia } from 'viem/chains';
|
|
9
9
|
|
|
10
|
-
import { L1Deployer } from './
|
|
10
|
+
import { L1Deployer } from './deploy_l1_contract.js';
|
|
11
11
|
import type { ExtendedViemWalletClient } from './types.js';
|
|
12
12
|
|
|
13
13
|
export const FORWARDER_SOLIDITY_SOURCE = `
|
|
@@ -128,7 +128,7 @@ export class RollupCheatCodes {
|
|
|
128
128
|
const timestamp = (await this.rollup.read.getTimestampForSlot([BigInt(slotNumber)])) + BigInt(opts.offset ?? 0);
|
|
129
129
|
try {
|
|
130
130
|
await this.ethCheatCodes.warp(Number(timestamp), { ...opts, silent: true, resetBlockInterval: true });
|
|
131
|
-
this.logger.warn(`Warped to epoch ${epoch}
|
|
131
|
+
this.logger.warn(`Warped to epoch ${epoch}`, { offset: opts.offset, timestamp });
|
|
132
132
|
} catch (err) {
|
|
133
133
|
this.logger.warn(`Warp to epoch ${epoch} failed: ${err}`);
|
|
134
134
|
}
|
package/src/test/start_anvil.ts
CHANGED
|
@@ -16,6 +16,8 @@ export async function startAnvil(
|
|
|
16
16
|
captureMethodCalls?: boolean;
|
|
17
17
|
accounts?: number;
|
|
18
18
|
chainId?: number;
|
|
19
|
+
/** The hardfork to use - note: @viem/anvil types are out of date but 'cancun' and 'latest' work */
|
|
20
|
+
hardfork?: string;
|
|
19
21
|
} = {},
|
|
20
22
|
): Promise<{ anvil: Anvil; methodCalls?: string[]; rpcUrl: string; stop: () => Promise<void> }> {
|
|
21
23
|
const anvilBinary = resolve(dirname(fileURLToPath(import.meta.url)), '../../', 'scripts/anvil_kill_wrapper.sh');
|