@aztec-labs/ethereum 6.0.0-nightly.20260829
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/README.md +3 -0
- package/dest/account.d.ts +2 -0
- package/dest/account.d.ts.map +1 -0
- package/dest/account.js +4 -0
- package/dest/chain.d.ts +25 -0
- package/dest/chain.d.ts.map +1 -0
- package/dest/chain.js +53 -0
- package/dest/client.d.ts +42 -0
- package/dest/client.d.ts.map +1 -0
- package/dest/client.js +104 -0
- package/dest/config.d.ts +103 -0
- package/dest/config.d.ts.map +1 -0
- package/dest/config.js +233 -0
- package/dest/constants.d.ts +4 -0
- package/dest/constants.d.ts.map +1 -0
- package/dest/constants.js +2 -0
- package/dest/contracts/chain_state_override.d.ts +81 -0
- package/dest/contracts/chain_state_override.d.ts.map +1 -0
- package/dest/contracts/chain_state_override.js +139 -0
- package/dest/contracts/empire_base.d.ts +30 -0
- package/dest/contracts/empire_base.d.ts.map +1 -0
- package/dest/contracts/empire_base.js +84 -0
- package/dest/contracts/errors.d.ts +7 -0
- package/dest/contracts/errors.d.ts.map +1 -0
- package/dest/contracts/errors.js +12 -0
- package/dest/contracts/fee_asset_handler.d.ts +20 -0
- package/dest/contracts/fee_asset_handler.d.ts.map +1 -0
- package/dest/contracts/fee_asset_handler.js +59 -0
- package/dest/contracts/fee_asset_price_oracle.d.ts +105 -0
- package/dest/contracts/fee_asset_price_oracle.d.ts.map +1 -0
- package/dest/contracts/fee_asset_price_oracle.js +656 -0
- package/dest/contracts/fee_juice.d.ts +14 -0
- package/dest/contracts/fee_juice.d.ts.map +1 -0
- package/dest/contracts/fee_juice.js +59 -0
- package/dest/contracts/governance.d.ts +192 -0
- package/dest/contracts/governance.d.ts.map +1 -0
- package/dest/contracts/governance.js +471 -0
- package/dest/contracts/governance_proposer.d.ts +63 -0
- package/dest/contracts/governance_proposer.d.ts.map +1 -0
- package/dest/contracts/governance_proposer.js +536 -0
- package/dest/contracts/gse.d.ts +38 -0
- package/dest/contracts/gse.d.ts.map +1 -0
- package/dest/contracts/gse.js +81 -0
- package/dest/contracts/inbox.d.ts +94 -0
- package/dest/contracts/inbox.d.ts.map +1 -0
- package/dest/contracts/inbox.js +141 -0
- package/dest/contracts/index.d.ts +18 -0
- package/dest/contracts/index.d.ts.map +1 -0
- package/dest/contracts/index.js +17 -0
- package/dest/contracts/log.d.ts +13 -0
- package/dest/contracts/log.d.ts.map +1 -0
- package/dest/contracts/log.js +1 -0
- package/dest/contracts/multicall.d.ts +138 -0
- package/dest/contracts/multicall.d.ts.map +1 -0
- package/dest/contracts/multicall.js +266 -0
- package/dest/contracts/outbox.d.ts +64 -0
- package/dest/contracts/outbox.d.ts.map +1 -0
- package/dest/contracts/outbox.js +113 -0
- package/dest/contracts/registry.d.ts +31 -0
- package/dest/contracts/registry.d.ts.map +1 -0
- package/dest/contracts/registry.js +142 -0
- package/dest/contracts/rollup.d.ts +5836 -0
- package/dest/contracts/rollup.d.ts.map +1 -0
- package/dest/contracts/rollup.js +1612 -0
- package/dest/contracts/slasher_contract.d.ts +44 -0
- package/dest/contracts/slasher_contract.d.ts.map +1 -0
- package/dest/contracts/slasher_contract.js +75 -0
- package/dest/contracts/slashing_proposer.d.ts +174 -0
- package/dest/contracts/slashing_proposer.d.ts.map +1 -0
- package/dest/contracts/slashing_proposer.js +755 -0
- package/dest/contracts/utils.d.ts +3 -0
- package/dest/contracts/utils.d.ts.map +1 -0
- package/dest/contracts/utils.js +11 -0
- package/dest/contracts/watch_event.d.ts +36 -0
- package/dest/contracts/watch_event.d.ts.map +1 -0
- package/dest/contracts/watch_event.js +66 -0
- package/dest/deploy_aztec_l1_contracts.d.ts +267 -0
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -0
- package/dest/deploy_aztec_l1_contracts.js +424 -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/eth-signer/eth-signer.d.ts +21 -0
- package/dest/eth-signer/eth-signer.d.ts.map +1 -0
- package/dest/eth-signer/eth-signer.js +5 -0
- package/dest/eth-signer/index.d.ts +2 -0
- package/dest/eth-signer/index.d.ts.map +1 -0
- package/dest/eth-signer/index.js +1 -0
- package/dest/forwarder_proxy.d.ts +32 -0
- package/dest/forwarder_proxy.d.ts.map +1 -0
- package/dest/forwarder_proxy.js +93 -0
- package/dest/foundry_binary.d.ts +13 -0
- package/dest/foundry_binary.d.ts.map +1 -0
- package/dest/foundry_binary.js +52 -0
- package/dest/l1_artifacts.d.ts +81896 -0
- package/dest/l1_artifacts.d.ts.map +1 -0
- package/dest/l1_artifacts.js +151 -0
- package/dest/l1_contract_addresses.d.ts +73 -0
- package/dest/l1_contract_addresses.d.ts.map +1 -0
- package/dest/l1_contract_addresses.js +120 -0
- package/dest/l1_reader.d.ts +18 -0
- package/dest/l1_reader.d.ts.map +1 -0
- package/dest/l1_reader.js +35 -0
- package/dest/l1_tx_utils/config.d.ts +65 -0
- package/dest/l1_tx_utils/config.d.ts.map +1 -0
- package/dest/l1_tx_utils/config.js +109 -0
- package/dest/l1_tx_utils/constants.d.ts +12 -0
- package/dest/l1_tx_utils/constants.d.ts.map +1 -0
- package/dest/l1_tx_utils/constants.js +39 -0
- package/dest/l1_tx_utils/factory.d.ts +32 -0
- package/dest/l1_tx_utils/factory.d.ts.map +1 -0
- package/dest/l1_tx_utils/factory.js +22 -0
- package/dest/l1_tx_utils/fee-strategies/index.d.ts +10 -0
- package/dest/l1_tx_utils/fee-strategies/index.d.ts.map +1 -0
- package/dest/l1_tx_utils/fee-strategies/index.js +12 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts +8 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive.d.ts.map +1 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive.js +129 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts +23 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.d.ts.map +1 -0
- package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.js +191 -0
- package/dest/l1_tx_utils/fee-strategies/types.d.ts +51 -0
- package/dest/l1_tx_utils/fee-strategies/types.d.ts.map +1 -0
- package/dest/l1_tx_utils/fee-strategies/types.js +3 -0
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts +41 -0
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts.map +1 -0
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.js +42 -0
- package/dest/l1_tx_utils/index-blobs.d.ts +3 -0
- package/dest/l1_tx_utils/index-blobs.d.ts.map +1 -0
- package/dest/l1_tx_utils/index-blobs.js +2 -0
- package/dest/l1_tx_utils/index.d.ts +13 -0
- package/dest/l1_tx_utils/index.d.ts.map +1 -0
- package/dest/l1_tx_utils/index.js +13 -0
- package/dest/l1_tx_utils/interfaces.d.ts +76 -0
- package/dest/l1_tx_utils/interfaces.d.ts.map +1 -0
- package/dest/l1_tx_utils/interfaces.js +4 -0
- package/dest/l1_tx_utils/l1_fee_analyzer.d.ts +252 -0
- package/dest/l1_tx_utils/l1_fee_analyzer.d.ts.map +1 -0
- package/dest/l1_tx_utils/l1_fee_analyzer.js +568 -0
- package/dest/l1_tx_utils/l1_tx_utils.d.ts +113 -0
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -0
- package/dest/l1_tx_utils/l1_tx_utils.js +720 -0
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +83 -0
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -0
- package/dest/l1_tx_utils/readonly_l1_tx_utils.js +357 -0
- package/dest/l1_tx_utils/signer.d.ts +4 -0
- package/dest/l1_tx_utils/signer.d.ts.map +1 -0
- package/dest/l1_tx_utils/signer.js +16 -0
- package/dest/l1_tx_utils/tx_delayer.d.ts +58 -0
- package/dest/l1_tx_utils/tx_delayer.d.ts.map +1 -0
- package/dest/l1_tx_utils/tx_delayer.js +223 -0
- package/dest/l1_tx_utils/types.d.ts +93 -0
- package/dest/l1_tx_utils/types.d.ts.map +1 -0
- package/dest/l1_tx_utils/types.js +36 -0
- package/dest/l1_tx_utils/utils.d.ts +4 -0
- package/dest/l1_tx_utils/utils.d.ts.map +1 -0
- package/dest/l1_tx_utils/utils.js +14 -0
- package/dest/l1_types.d.ts +6 -0
- package/dest/l1_types.d.ts.map +1 -0
- package/dest/l1_types.js +1 -0
- package/dest/publisher_manager.d.ts +42 -0
- package/dest/publisher_manager.d.ts.map +1 -0
- package/dest/publisher_manager.js +199 -0
- package/dest/queries.d.ts +25 -0
- package/dest/queries.d.ts.map +1 -0
- package/dest/queries.js +144 -0
- package/dest/test/blob_kzg_warmup.d.ts +19 -0
- package/dest/test/blob_kzg_warmup.d.ts.map +1 -0
- package/dest/test/blob_kzg_warmup.js +64 -0
- package/dest/test/chain_monitor.d.ts +126 -0
- package/dest/test/chain_monitor.d.ts.map +1 -0
- package/dest/test/chain_monitor.js +314 -0
- package/dest/test/eth_cheat_codes.d.ts +260 -0
- package/dest/test/eth_cheat_codes.d.ts.map +1 -0
- package/dest/test/eth_cheat_codes.js +608 -0
- package/dest/test/eth_cheat_codes_with_state.d.ts +18 -0
- package/dest/test/eth_cheat_codes_with_state.d.ts.map +1 -0
- package/dest/test/eth_cheat_codes_with_state.js +34 -0
- package/dest/test/index.d.ts +8 -0
- package/dest/test/index.d.ts.map +1 -0
- package/dest/test/index.js +7 -0
- package/dest/test/recording_rpc_server.d.ts +18 -0
- package/dest/test/recording_rpc_server.d.ts.map +1 -0
- package/dest/test/recording_rpc_server.js +68 -0
- package/dest/test/rollup_cheat_codes.d.ts +142 -0
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -0
- package/dest/test/rollup_cheat_codes.js +338 -0
- package/dest/test/start_anvil.d.ts +40 -0
- package/dest/test/start_anvil.d.ts.map +1 -0
- package/dest/test/start_anvil.js +210 -0
- package/dest/test/upgrade_utils.d.ts +12 -0
- package/dest/test/upgrade_utils.d.ts.map +1 -0
- package/dest/test/upgrade_utils.js +111 -0
- package/dest/types.d.ts +68 -0
- package/dest/types.d.ts.map +1 -0
- package/dest/types.js +3 -0
- package/dest/utils.d.ts +45 -0
- package/dest/utils.d.ts.map +1 -0
- package/dest/utils.js +260 -0
- package/dest/zkPassportVerifierAddress.d.ts +15 -0
- package/dest/zkPassportVerifierAddress.d.ts.map +1 -0
- package/dest/zkPassportVerifierAddress.js +11 -0
- package/package.json +122 -0
- package/src/account.ts +5 -0
- package/src/chain.ts +71 -0
- package/src/client.ts +165 -0
- package/src/config.ts +342 -0
- package/src/constants.ts +4 -0
- package/src/contracts/README.md +157 -0
- package/src/contracts/chain_state_override.ts +203 -0
- package/src/contracts/empire_base.ts +89 -0
- package/src/contracts/errors.ts +13 -0
- package/src/contracts/fee_asset_handler.ts +66 -0
- package/src/contracts/fee_asset_price_oracle.ts +284 -0
- package/src/contracts/fee_juice.ts +57 -0
- package/src/contracts/governance.ts +597 -0
- package/src/contracts/governance_proposer.ts +181 -0
- package/src/contracts/gse.ts +105 -0
- package/src/contracts/inbox.ts +223 -0
- package/src/contracts/index.ts +17 -0
- package/src/contracts/log.ts +13 -0
- package/src/contracts/multicall.ts +298 -0
- package/src/contracts/outbox.ts +132 -0
- package/src/contracts/registry.ts +161 -0
- package/src/contracts/rollup.ts +1502 -0
- package/src/contracts/slasher_contract.ts +89 -0
- package/src/contracts/slashing_proposer.ts +397 -0
- package/src/contracts/utils.ts +14 -0
- package/src/contracts/watch_event.ts +109 -0
- package/src/deploy_aztec_l1_contracts.ts +663 -0
- package/src/deploy_l1_contract.ts +361 -0
- package/src/eth-signer/eth-signer.ts +24 -0
- package/src/eth-signer/index.ts +1 -0
- package/src/forwarder_proxy.ts +107 -0
- package/src/foundry_binary.ts +57 -0
- package/src/l1_artifacts.ts +231 -0
- package/src/l1_contract_addresses.ts +149 -0
- package/src/l1_reader.ts +57 -0
- package/src/l1_tx_utils/README.md +177 -0
- package/src/l1_tx_utils/config.ts +181 -0
- package/src/l1_tx_utils/constants.ts +29 -0
- package/src/l1_tx_utils/factory.ts +64 -0
- package/src/l1_tx_utils/fee-strategies/index.ts +22 -0
- package/src/l1_tx_utils/fee-strategies/p75_competitive.ts +162 -0
- package/src/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.ts +244 -0
- package/src/l1_tx_utils/fee-strategies/types.ts +55 -0
- package/src/l1_tx_utils/forwarder_l1_tx_utils.ts +107 -0
- package/src/l1_tx_utils/index-blobs.ts +2 -0
- package/src/l1_tx_utils/index.ts +15 -0
- package/src/l1_tx_utils/interfaces.ts +86 -0
- package/src/l1_tx_utils/l1_fee_analyzer.ts +874 -0
- package/src/l1_tx_utils/l1_tx_utils.ts +840 -0
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +459 -0
- package/src/l1_tx_utils/signer.ts +27 -0
- package/src/l1_tx_utils/tx_delayer.ts +302 -0
- package/src/l1_tx_utils/types.ts +116 -0
- package/src/l1_tx_utils/utils.ts +15 -0
- package/src/l1_types.ts +6 -0
- package/src/publisher_manager.ts +239 -0
- package/src/queries.ts +189 -0
- package/src/test/blob_kzg_warmup.ts +65 -0
- package/src/test/chain_monitor.ts +389 -0
- package/src/test/eth_cheat_codes.ts +624 -0
- package/src/test/eth_cheat_codes_with_state.ts +38 -0
- package/src/test/index.ts +7 -0
- package/src/test/recording_rpc_server.ts +69 -0
- package/src/test/rollup_cheat_codes.ts +398 -0
- package/src/test/start_anvil.ts +255 -0
- package/src/test/upgrade_utils.ts +109 -0
- package/src/types.ts +97 -0
- package/src/utils.ts +344 -0
- package/src/zkPassportVerifierAddress.ts +15 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { createLogger } from '@aztec-labs/foundation/log';
|
|
2
|
+
import { makeBackoff, retry } from '@aztec-labs/foundation/retry';
|
|
3
|
+
import type { TestDateProvider } from '@aztec-labs/foundation/timer';
|
|
4
|
+
import { type ChildProcess, spawn } from 'child_process';
|
|
5
|
+
|
|
6
|
+
import { resolveFoundryBinary } from '../foundry_binary.js';
|
|
7
|
+
|
|
8
|
+
/** Minimal interface matching the @viem/anvil Anvil shape used by callers. */
|
|
9
|
+
export interface Anvil {
|
|
10
|
+
readonly port: number;
|
|
11
|
+
readonly host: string;
|
|
12
|
+
readonly status: 'listening' | 'idle';
|
|
13
|
+
stop(): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Watchdog wrapper: instead of spawning anvil directly, we spawn a small bash supervisor that runs
|
|
17
|
+
// anvil as a background child and polls its own parent (this node process). If the parent dies for
|
|
18
|
+
// ANY reason — including SIGKILL / crash / OOM, where node's own exit handlers never run — the poll
|
|
19
|
+
// loop ends and the EXIT trap reaps anvil. The script is inlined (rather than shipped as a `.sh`) so
|
|
20
|
+
// it works from the published npm tarball too, and the resolved anvil binary is passed via
|
|
21
|
+
// `$ANVIL_BIN` so it works without `anvil` on PATH.
|
|
22
|
+
//
|
|
23
|
+
// `$@` is the anvil argv; `bash -c <script> bash <...args>` puts the args in `$@` and `$0` = 'bash'.
|
|
24
|
+
//
|
|
25
|
+
// The EXIT trap reaps anvil; INT/TERM just `exit` (which fires the EXIT trap) so a signal terminates
|
|
26
|
+
// the supervisor promptly instead of being swallowed — a trapped TERM does NOT terminate the shell,
|
|
27
|
+
// so trapping the kill directly on TERM would leave the poll loop running and the caller's teardown
|
|
28
|
+
// hanging until its SIGKILL escalation. `sleep & wait` makes the poll interruptible, so INT/TERM are
|
|
29
|
+
// handled immediately rather than after the current `sleep` returns.
|
|
30
|
+
//
|
|
31
|
+
// The poll loop also exits when ANVIL itself dies: startAnvil detects a failed start via the
|
|
32
|
+
// supervisor's 'close' event, so a supervisor that outlived a dead anvil (e.g. port already in use,
|
|
33
|
+
// unsupported flag) would turn a loud startup error into an unresolvable await — the caller would
|
|
34
|
+
// hang until an outer timeout with no output at all.
|
|
35
|
+
const ANVIL_WATCHDOG = `
|
|
36
|
+
set -u
|
|
37
|
+
parent=$PPID
|
|
38
|
+
"$ANVIL_BIN" "$@" &
|
|
39
|
+
anvil_pid=$!
|
|
40
|
+
trap 'kill "$anvil_pid" 2>/dev/null' EXIT
|
|
41
|
+
trap 'exit 0' INT TERM
|
|
42
|
+
while kill -0 "$parent" 2>/dev/null && kill -0 "$anvil_pid" 2>/dev/null; do sleep 1 & wait $!; done
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Ensures there's a running Anvil instance and returns the RPC URL.
|
|
47
|
+
*/
|
|
48
|
+
export async function startAnvil(
|
|
49
|
+
opts: {
|
|
50
|
+
port?: number;
|
|
51
|
+
l1BlockTime?: number;
|
|
52
|
+
log?: boolean;
|
|
53
|
+
captureMethodCalls?: boolean;
|
|
54
|
+
accounts?: number;
|
|
55
|
+
chainId?: number;
|
|
56
|
+
/** The hardfork to use (e.g. 'cancun', 'latest'). */
|
|
57
|
+
hardfork?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Number of slots per epoch used by anvil to compute the 'finalized' and 'safe' block tags.
|
|
60
|
+
* Anvil reports `finalized = latest - slotsInAnEpoch * 2`.
|
|
61
|
+
* Defaults to 1 so the finalized block advances immediately, making tests that check
|
|
62
|
+
* L1-finality-based logic work without needing hundreds of mined blocks.
|
|
63
|
+
*/
|
|
64
|
+
slotsInAnEpoch?: number;
|
|
65
|
+
/**
|
|
66
|
+
* If provided, the date provider will be synced to anvil's block time on every mined block.
|
|
67
|
+
* This keeps the dateProvider in lockstep with anvil's chain time, avoiding drift between
|
|
68
|
+
* the wall clock and the L1 chain when computing L1 slot timestamps.
|
|
69
|
+
*/
|
|
70
|
+
dateProvider?: TestDateProvider;
|
|
71
|
+
} = {},
|
|
72
|
+
): Promise<{ anvil: Anvil; methodCalls?: string[]; rpcUrl: string; stop: () => Promise<void> }> {
|
|
73
|
+
const anvilBinary = resolveFoundryBinary('anvil');
|
|
74
|
+
const logger = opts.log ? createLogger('ethereum:anvil') : undefined;
|
|
75
|
+
const methodCalls = opts.captureMethodCalls ? ([] as string[]) : undefined;
|
|
76
|
+
|
|
77
|
+
let detectedPort: number | undefined;
|
|
78
|
+
|
|
79
|
+
const anvil = await retry(
|
|
80
|
+
async () => {
|
|
81
|
+
// `--port 0` lets anvil bind an OS-assigned ephemeral port; the actual port is read back from
|
|
82
|
+
// its "Listening on host:port" stdout below, so independent suites can spawn their own anvil
|
|
83
|
+
// in parallel without fighting over a fixed port.
|
|
84
|
+
const port = opts.port ?? (process.env.ANVIL_PORT ? parseInt(process.env.ANVIL_PORT) : 8545);
|
|
85
|
+
const args: string[] = [
|
|
86
|
+
'--host',
|
|
87
|
+
'127.0.0.1',
|
|
88
|
+
'--port',
|
|
89
|
+
String(port),
|
|
90
|
+
'--accounts',
|
|
91
|
+
String(opts.accounts ?? 20),
|
|
92
|
+
'--gas-limit',
|
|
93
|
+
String(45_000_000),
|
|
94
|
+
'--chain-id',
|
|
95
|
+
String(opts.chainId ?? 31337),
|
|
96
|
+
];
|
|
97
|
+
if (opts.l1BlockTime !== undefined) {
|
|
98
|
+
args.push('--block-time', String(opts.l1BlockTime));
|
|
99
|
+
}
|
|
100
|
+
if (opts.hardfork !== undefined) {
|
|
101
|
+
args.push('--hardfork', opts.hardfork);
|
|
102
|
+
}
|
|
103
|
+
args.push('--slots-in-an-epoch', String(opts.slotsInAnEpoch ?? 1));
|
|
104
|
+
|
|
105
|
+
// Spawn the watchdog (see ANVIL_WATCHDOG). It launches anvil with these args and reaps it if we
|
|
106
|
+
// die; `$0` is 'bash' and `$@` is the anvil argv.
|
|
107
|
+
const child = spawn('bash', ['-c', ANVIL_WATCHDOG, 'bash', ...args], {
|
|
108
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
109
|
+
env: { ...process.env, ANVIL_BIN: anvilBinary, RAYON_NUM_THREADS: '1' },
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Wait for "Listening on" or an early exit.
|
|
113
|
+
await new Promise<void>((resolve, reject) => {
|
|
114
|
+
let stderr = '';
|
|
115
|
+
|
|
116
|
+
const onStdout = (data: Buffer) => {
|
|
117
|
+
const text = data.toString();
|
|
118
|
+
logger?.debug(text.trim());
|
|
119
|
+
methodCalls?.push(...(text.match(/eth_[^\s]+/g) || []));
|
|
120
|
+
|
|
121
|
+
if (detectedPort === undefined && text.includes('Listening on')) {
|
|
122
|
+
const match = text.match(/Listening on ([^:]+):(\d+)/);
|
|
123
|
+
if (match) {
|
|
124
|
+
detectedPort = parseInt(match[2]);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (detectedPort !== undefined) {
|
|
128
|
+
child.stdout?.removeListener('data', onStdout);
|
|
129
|
+
child.stderr?.removeListener('data', onStderr);
|
|
130
|
+
child.removeListener('close', onClose);
|
|
131
|
+
resolve();
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const onStderr = (data: Buffer) => {
|
|
136
|
+
stderr += data.toString();
|
|
137
|
+
logger?.debug(data.toString().trim());
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const onClose = (code: number | null) => {
|
|
141
|
+
child.stdout?.removeListener('data', onStdout);
|
|
142
|
+
child.stderr?.removeListener('data', onStderr);
|
|
143
|
+
reject(new Error(`Anvil exited with code ${code} before listening. stderr: ${stderr}`));
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
child.stdout?.on('data', onStdout);
|
|
147
|
+
child.stderr?.on('data', onStderr);
|
|
148
|
+
child.once('close', onClose);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Continue piping for logging, method-call capture, and/or dateProvider sync after startup.
|
|
152
|
+
if (logger || opts.captureMethodCalls || opts.dateProvider) {
|
|
153
|
+
child.stdout?.on('data', (data: Buffer) => {
|
|
154
|
+
const text = data.toString();
|
|
155
|
+
logger?.debug(text.trim());
|
|
156
|
+
methodCalls?.push(...(text.match(/eth_[^\s]+/g) || []));
|
|
157
|
+
if (opts.dateProvider) {
|
|
158
|
+
syncDateProviderFromAnvilOutput(text, opts.dateProvider);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
child.stderr?.on('data', (data: Buffer) => {
|
|
162
|
+
logger?.debug(data.toString().trim());
|
|
163
|
+
});
|
|
164
|
+
} else {
|
|
165
|
+
// Consume streams so the child process doesn't block on full pipe buffers.
|
|
166
|
+
child.stdout?.resume();
|
|
167
|
+
child.stderr?.resume();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return child;
|
|
171
|
+
},
|
|
172
|
+
'Start anvil',
|
|
173
|
+
makeBackoff([5, 5, 5]),
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
if (!detectedPort) {
|
|
177
|
+
throw new Error('Failed to start anvil');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const port = detectedPort;
|
|
181
|
+
let status: 'listening' | 'idle' = 'listening';
|
|
182
|
+
|
|
183
|
+
anvil.once('close', () => {
|
|
184
|
+
status = 'idle';
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const stop = async () => {
|
|
188
|
+
if (status === 'idle') {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
await killChild(anvil);
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const anvilObj: Anvil = {
|
|
195
|
+
port,
|
|
196
|
+
host: '127.0.0.1',
|
|
197
|
+
get status() {
|
|
198
|
+
return status;
|
|
199
|
+
},
|
|
200
|
+
stop,
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
return { anvil: anvilObj, methodCalls, stop, rpcUrl: `http://127.0.0.1:${port}` };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** Extracts block time from anvil stdout and syncs the dateProvider. */
|
|
207
|
+
function syncDateProviderFromAnvilOutput(text: string, dateProvider: TestDateProvider): void {
|
|
208
|
+
// Anvil logs mined blocks as:
|
|
209
|
+
// Block Time: "Fri, 20 Mar 2026 02:10:46 +0000"
|
|
210
|
+
const match = text.match(/Block Time:\s*"([^"]+)"/);
|
|
211
|
+
if (match) {
|
|
212
|
+
const blockTimeMs = new Date(match[1]).getTime();
|
|
213
|
+
if (!isNaN(blockTimeMs)) {
|
|
214
|
+
dateProvider.setTime(blockTimeMs);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Send SIGTERM to the watchdog, wait up to 5 s, then SIGKILL. The watchdog's trap forwards the
|
|
221
|
+
* signal to anvil, so terminating it tears down anvil too. All timers are always cleared.
|
|
222
|
+
*/
|
|
223
|
+
function killChild(child: ChildProcess): Promise<void> {
|
|
224
|
+
return new Promise<void>(resolve => {
|
|
225
|
+
if (child.exitCode !== null || child.killed) {
|
|
226
|
+
child.stdout?.destroy();
|
|
227
|
+
child.stderr?.destroy();
|
|
228
|
+
resolve();
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
let killTimer: NodeJS.Timeout | undefined;
|
|
233
|
+
|
|
234
|
+
const onClose = () => {
|
|
235
|
+
if (killTimer !== undefined) {
|
|
236
|
+
clearTimeout(killTimer);
|
|
237
|
+
}
|
|
238
|
+
// Destroy stdio streams so their PipeWrap handles don't keep the event loop alive.
|
|
239
|
+
child.stdout?.destroy();
|
|
240
|
+
child.stderr?.destroy();
|
|
241
|
+
resolve();
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
child.once('close', onClose);
|
|
245
|
+
child.kill('SIGTERM');
|
|
246
|
+
|
|
247
|
+
killTimer = setTimeout(() => {
|
|
248
|
+
killTimer = undefined;
|
|
249
|
+
child.kill('SIGKILL');
|
|
250
|
+
}, 5000);
|
|
251
|
+
|
|
252
|
+
// Ensure the timer does not prevent Node from exiting.
|
|
253
|
+
killTimer.unref();
|
|
254
|
+
});
|
|
255
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { GovernanceAbi } from '@aztec/l1-artifacts/GovernanceAbi';
|
|
2
|
+
import { TestERC20Abi as StakingAssetAbi } from '@aztec/l1-artifacts/TestERC20Abi';
|
|
3
|
+
|
|
4
|
+
import type { Logger } from '@aztec-labs/foundation/log';
|
|
5
|
+
import { DateProvider } from '@aztec-labs/foundation/timer';
|
|
6
|
+
import { type GetContractReturnType, type PrivateKeyAccount, getContract } from 'viem';
|
|
7
|
+
|
|
8
|
+
import { extractProposalIdFromLogs } from '../contracts/governance.js';
|
|
9
|
+
import type { L1ContractAddresses } from '../l1_contract_addresses.js';
|
|
10
|
+
import { createL1TxUtils } from '../l1_tx_utils/index.js';
|
|
11
|
+
import type { ExtendedViemWalletClient, ViemPublicClient } from '../types.js';
|
|
12
|
+
import { EthCheatCodes } from './eth_cheat_codes.js';
|
|
13
|
+
|
|
14
|
+
export async function executeGovernanceProposal(
|
|
15
|
+
proposalId: bigint,
|
|
16
|
+
governance: GetContractReturnType<typeof GovernanceAbi, ViemPublicClient>,
|
|
17
|
+
voteAmount: bigint,
|
|
18
|
+
privateKey: PrivateKeyAccount,
|
|
19
|
+
l1Client: ExtendedViemWalletClient,
|
|
20
|
+
rpcUrls: string[],
|
|
21
|
+
logger: Logger,
|
|
22
|
+
) {
|
|
23
|
+
const proposal = await governance.read.getProposal([proposalId]);
|
|
24
|
+
|
|
25
|
+
const l1TxUtils = createL1TxUtils(l1Client);
|
|
26
|
+
|
|
27
|
+
const waitL1Block = async () => {
|
|
28
|
+
await l1TxUtils.sendAndMonitorTransaction({
|
|
29
|
+
to: l1Client.account.address,
|
|
30
|
+
value: 1n,
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const cheatCodes = new EthCheatCodes(rpcUrls, new DateProvider(), logger);
|
|
35
|
+
|
|
36
|
+
const timeToActive = proposal.creation + proposal.config.votingDelay;
|
|
37
|
+
logger.info(`Warping to ${timeToActive + 1n}`);
|
|
38
|
+
await cheatCodes.warp(Number(timeToActive + 1n));
|
|
39
|
+
logger.info(`Warped to ${timeToActive + 1n}`);
|
|
40
|
+
await waitL1Block();
|
|
41
|
+
|
|
42
|
+
logger.info(`Voting`);
|
|
43
|
+
const voteTx = await governance.write.vote([proposalId, voteAmount, true], { account: privateKey });
|
|
44
|
+
await l1Client.waitForTransactionReceipt({ hash: voteTx });
|
|
45
|
+
logger.info(`Voted`);
|
|
46
|
+
|
|
47
|
+
const timeToExecutable = timeToActive + proposal.config.votingDuration + proposal.config.executionDelay + 1n;
|
|
48
|
+
logger.info(`Warping to ${timeToExecutable}`);
|
|
49
|
+
await cheatCodes.warp(Number(timeToExecutable));
|
|
50
|
+
logger.info(`Warped to ${timeToExecutable}`);
|
|
51
|
+
await waitL1Block();
|
|
52
|
+
|
|
53
|
+
const executeTx = await governance.write.execute([proposalId], { account: privateKey });
|
|
54
|
+
await l1Client.waitForTransactionReceipt({ hash: executeTx });
|
|
55
|
+
logger.info(`Executed proposal`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function createGovernanceProposal(
|
|
59
|
+
payloadAddress: `0x${string}`,
|
|
60
|
+
addresses: L1ContractAddresses,
|
|
61
|
+
privateKey: PrivateKeyAccount,
|
|
62
|
+
publicClient: ViemPublicClient,
|
|
63
|
+
logger: Logger,
|
|
64
|
+
): Promise<{
|
|
65
|
+
governance: GetContractReturnType<typeof GovernanceAbi, ViemPublicClient>;
|
|
66
|
+
voteAmount: bigint;
|
|
67
|
+
proposalId: bigint;
|
|
68
|
+
}> {
|
|
69
|
+
const token = getContract({
|
|
70
|
+
address: addresses.stakingAssetAddress.toString(),
|
|
71
|
+
abi: StakingAssetAbi,
|
|
72
|
+
client: publicClient,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const governance = getContract({
|
|
76
|
+
address: addresses.governanceAddress.toString(),
|
|
77
|
+
abi: GovernanceAbi,
|
|
78
|
+
client: publicClient,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const lockAmount = 10000n * 10n ** 18n;
|
|
82
|
+
const voteAmount = 10000n * 10n ** 18n;
|
|
83
|
+
|
|
84
|
+
const mintTx = await token.write.mint([privateKey.address, lockAmount + voteAmount], { account: privateKey });
|
|
85
|
+
await publicClient.waitForTransactionReceipt({ hash: mintTx });
|
|
86
|
+
logger.info(`Minted tokens`);
|
|
87
|
+
|
|
88
|
+
const approveTx = await token.write.approve([addresses.governanceAddress.toString(), lockAmount + voteAmount], {
|
|
89
|
+
account: privateKey,
|
|
90
|
+
});
|
|
91
|
+
await publicClient.waitForTransactionReceipt({ hash: approveTx });
|
|
92
|
+
logger.info(`Approved tokens`);
|
|
93
|
+
|
|
94
|
+
const depositTx = await governance.write.deposit([privateKey.address, lockAmount + voteAmount], {
|
|
95
|
+
account: privateKey,
|
|
96
|
+
});
|
|
97
|
+
await publicClient.waitForTransactionReceipt({ hash: depositTx });
|
|
98
|
+
logger.info(`Deposited tokens`);
|
|
99
|
+
|
|
100
|
+
const proposeTx = await governance.write.proposeWithLock([payloadAddress, privateKey.address], {
|
|
101
|
+
account: privateKey,
|
|
102
|
+
});
|
|
103
|
+
const receipt = await publicClient.waitForTransactionReceipt({ hash: proposeTx });
|
|
104
|
+
logger.info(`Proposed upgrade`);
|
|
105
|
+
|
|
106
|
+
const proposalId = extractProposalIdFromLogs(receipt.logs);
|
|
107
|
+
|
|
108
|
+
return { governance, voteAmount, proposalId };
|
|
109
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Abi,
|
|
3
|
+
Account,
|
|
4
|
+
Chain,
|
|
5
|
+
Client,
|
|
6
|
+
FallbackTransport,
|
|
7
|
+
GetContractReturnType,
|
|
8
|
+
Hex,
|
|
9
|
+
HttpTransport,
|
|
10
|
+
PublicActions,
|
|
11
|
+
PublicClient,
|
|
12
|
+
PublicRpcSchema,
|
|
13
|
+
WalletActions,
|
|
14
|
+
WalletRpcSchema,
|
|
15
|
+
} from 'viem';
|
|
16
|
+
|
|
17
|
+
/** Type for a viem public client */
|
|
18
|
+
export type ViemPublicClient = PublicClient<FallbackTransport<HttpTransport[]>, Chain>;
|
|
19
|
+
|
|
20
|
+
export type PublicRpcDebugSchema = [
|
|
21
|
+
{
|
|
22
|
+
Method: 'debug_traceTransaction';
|
|
23
|
+
Parameters: [txHash: `0x${string}`, options: { tracer: 'callTracer' }];
|
|
24
|
+
ReturnType: DebugCallTrace;
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
Method: 'trace_transaction';
|
|
28
|
+
Parameters: [txHash: `0x${string}`];
|
|
29
|
+
ReturnType: TraceTransactionResponse[];
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
/** Return type for a debug_traceTransaction call */
|
|
34
|
+
export type DebugCallTrace = {
|
|
35
|
+
from: Hex;
|
|
36
|
+
to?: Hex;
|
|
37
|
+
type: string;
|
|
38
|
+
input?: Hex;
|
|
39
|
+
output?: Hex;
|
|
40
|
+
gas?: Hex;
|
|
41
|
+
gasUsed?: Hex;
|
|
42
|
+
value?: Hex;
|
|
43
|
+
error?: string;
|
|
44
|
+
calls?: DebugCallTrace[];
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/** Action object for a trace_transaction call */
|
|
48
|
+
export type TraceAction = {
|
|
49
|
+
from: Hex;
|
|
50
|
+
to?: Hex;
|
|
51
|
+
callType: string;
|
|
52
|
+
gas?: Hex;
|
|
53
|
+
input?: Hex;
|
|
54
|
+
value?: Hex;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/** Result object for a trace_transaction call */
|
|
58
|
+
export type TraceResult = {
|
|
59
|
+
gasUsed?: Hex;
|
|
60
|
+
output?: Hex;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/** Return type for a single trace in trace_transaction response */
|
|
64
|
+
export type TraceTransactionResponse = {
|
|
65
|
+
action: TraceAction;
|
|
66
|
+
result?: TraceResult;
|
|
67
|
+
error?: string;
|
|
68
|
+
subtraces: number;
|
|
69
|
+
traceAddress: number[];
|
|
70
|
+
type: string;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/** Type for a viem public client with support for debug methods */
|
|
74
|
+
export type ViemPublicDebugClient = PublicClient<
|
|
75
|
+
FallbackTransport<HttpTransport[]>,
|
|
76
|
+
Chain,
|
|
77
|
+
undefined,
|
|
78
|
+
[...PublicRpcSchema, ...PublicRpcDebugSchema]
|
|
79
|
+
>;
|
|
80
|
+
|
|
81
|
+
export type ExtendedViemWalletClient = Client<
|
|
82
|
+
FallbackTransport<readonly HttpTransport[]>,
|
|
83
|
+
Chain,
|
|
84
|
+
Account,
|
|
85
|
+
[...PublicRpcSchema, ...WalletRpcSchema],
|
|
86
|
+
PublicActions<FallbackTransport<readonly HttpTransport[]>, Chain> & WalletActions<Chain, Account>
|
|
87
|
+
>;
|
|
88
|
+
|
|
89
|
+
/** Type for a viem client that can be either public or extended with wallet capabilities */
|
|
90
|
+
export type ViemClient = ViemPublicClient | ExtendedViemWalletClient;
|
|
91
|
+
|
|
92
|
+
/** Type for a viem contract that can be used with an extended viem client */
|
|
93
|
+
export type ViemContract<TAbi extends Abi> = GetContractReturnType<TAbi, ExtendedViemWalletClient>;
|
|
94
|
+
|
|
95
|
+
export function isExtendedClient(client: ViemClient): client is ExtendedViemWalletClient {
|
|
96
|
+
return 'account' in client && client.account !== undefined;
|
|
97
|
+
}
|