@aztec/ethereum 0.78.1 → 0.80.0

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 (48) hide show
  1. package/dest/contracts/fee_juice.js +1 -1
  2. package/dest/contracts/forwarder.d.ts.map +1 -1
  3. package/dest/contracts/forwarder.js +2 -1
  4. package/dest/contracts/governance.d.ts +17 -5
  5. package/dest/contracts/governance.d.ts.map +1 -1
  6. package/dest/contracts/governance.js +18 -20
  7. package/dest/contracts/governance_proposer.d.ts +1 -0
  8. package/dest/contracts/governance_proposer.d.ts.map +1 -1
  9. package/dest/contracts/governance_proposer.js +10 -3
  10. package/dest/contracts/registry.d.ts +1 -0
  11. package/dest/contracts/registry.d.ts.map +1 -1
  12. package/dest/contracts/registry.js +6 -2
  13. package/dest/contracts/rollup.d.ts.map +1 -1
  14. package/dest/contracts/rollup.js +3 -1
  15. package/dest/contracts/slashing_proposer.js +1 -1
  16. package/dest/deploy_l1_contracts.d.ts +181 -325
  17. package/dest/deploy_l1_contracts.d.ts.map +1 -1
  18. package/dest/deploy_l1_contracts.js +48 -26
  19. package/dest/l1_tx_utils.d.ts +1 -0
  20. package/dest/l1_tx_utils.d.ts.map +1 -1
  21. package/dest/l1_tx_utils.js +4 -1
  22. package/dest/queries.d.ts +7 -0
  23. package/dest/queries.d.ts.map +1 -1
  24. package/dest/queries.js +14 -2
  25. package/dest/test/chain_monitor.d.ts +25 -0
  26. package/dest/test/chain_monitor.d.ts.map +1 -0
  27. package/dest/test/chain_monitor.js +74 -0
  28. package/dest/test/index.d.ts +1 -0
  29. package/dest/test/index.d.ts.map +1 -1
  30. package/dest/test/index.js +1 -0
  31. package/dest/test/upgrade_utils.d.ts.map +1 -1
  32. package/dest/test/upgrade_utils.js +1 -1
  33. package/dest/utils.js +1 -1
  34. package/package.json +5 -5
  35. package/src/contracts/fee_juice.ts +1 -1
  36. package/src/contracts/forwarder.ts +2 -1
  37. package/src/contracts/governance.ts +22 -21
  38. package/src/contracts/governance_proposer.ts +7 -3
  39. package/src/contracts/registry.ts +7 -2
  40. package/src/contracts/rollup.ts +3 -1
  41. package/src/contracts/slashing_proposer.ts +1 -1
  42. package/src/deploy_l1_contracts.ts +66 -28
  43. package/src/l1_tx_utils.ts +5 -0
  44. package/src/queries.ts +29 -2
  45. package/src/test/chain_monitor.ts +88 -0
  46. package/src/test/index.ts +1 -0
  47. package/src/test/upgrade_utils.ts +1 -1
  48. package/src/utils.ts +1 -1
@@ -1,20 +1,21 @@
1
1
  import { EthAddress } from '@aztec/foundation/eth-address';
2
2
  import type { Logger } from '@aztec/foundation/log';
3
3
  import { sleep } from '@aztec/foundation/sleep';
4
- import { GovernanceAbi } from '@aztec/l1-artifacts';
4
+ import { GovernanceAbi } from '@aztec/l1-artifacts/GovernanceAbi';
5
5
 
6
6
  import {
7
7
  type EncodeFunctionDataParameters,
8
8
  type GetContractReturnType,
9
9
  type Hex,
10
+ type Log,
10
11
  encodeFunctionData,
11
12
  getContract,
13
+ parseEventLogs,
12
14
  } from 'viem';
13
15
 
14
16
  import type { L1ContractAddresses } from '../l1_contract_addresses.js';
15
17
  import { L1TxUtils } from '../l1_tx_utils.js';
16
18
  import type { ViemPublicClient, ViemWalletClient } from '../types.js';
17
- import { GovernanceProposerContract } from './governance_proposer.js';
18
19
 
19
20
  export type L1GovernanceContractAddresses = Pick<
20
21
  L1ContractAddresses,
@@ -33,6 +34,19 @@ export enum ProposalState {
33
34
  Expired,
34
35
  }
35
36
 
37
+ export function extractProposalIdFromLogs(logs: Log[]): bigint {
38
+ const parsedLogs = parseEventLogs({
39
+ abi: GovernanceAbi,
40
+ logs: logs,
41
+ eventName: 'Proposed',
42
+ });
43
+
44
+ if (parsedLogs.length === 0) {
45
+ throw new Error('Proposal log not found');
46
+ }
47
+ return parsedLogs[0].args.proposalId;
48
+ }
49
+
36
50
  export class GovernanceContract {
37
51
  private readonly publicGovernance: GetContractReturnType<typeof GovernanceAbi, ViemPublicClient>;
38
52
  private readonly walletGovernance: GetContractReturnType<typeof GovernanceAbi, ViemWalletClient> | undefined;
@@ -52,23 +66,12 @@ export class GovernanceContract {
52
66
  return EthAddress.fromString(this.publicGovernance.address);
53
67
  }
54
68
 
55
- public async getProposer() {
56
- const governanceProposerAddress = EthAddress.fromString(await this.publicGovernance.read.governanceProposer());
57
- return new GovernanceProposerContract(this.publicClient, governanceProposerAddress.toString());
69
+ public async getGovernanceProposerAddress() {
70
+ return EthAddress.fromString(await this.publicGovernance.read.governanceProposer());
58
71
  }
59
72
 
60
- public async getGovernanceAddresses(): Promise<L1GovernanceContractAddresses> {
61
- const governanceProposer = await this.getProposer();
62
- const [rollupAddress, registryAddress] = await Promise.all([
63
- governanceProposer.getRollupAddress(),
64
- governanceProposer.getRegistryAddress(),
65
- ]);
66
- return {
67
- governanceAddress: this.address,
68
- rollupAddress,
69
- registryAddress,
70
- governanceProposerAddress: governanceProposer.address,
71
- };
73
+ public getConfiguration() {
74
+ return this.publicGovernance.read.getConfiguration();
72
75
  }
73
76
 
74
77
  public getProposal(proposalId: bigint) {
@@ -102,16 +105,14 @@ export class GovernanceContract {
102
105
  }: {
103
106
  payloadAddress: Hex;
104
107
  withdrawAddress: Hex;
105
- }): Promise<number> {
108
+ }): Promise<bigint> {
106
109
  const walletGovernance = this.assertWalletGovernance();
107
110
  const proposeTx = await walletGovernance.write.proposeWithLock([payloadAddress, withdrawAddress]);
108
111
  const receipt = await this.publicClient.waitForTransactionReceipt({ hash: proposeTx });
109
112
  if (receipt.status !== 'success') {
110
113
  throw new Error(`Proposal failed: ${receipt.status}`);
111
114
  }
112
-
113
- const proposalId = Number(receipt.logs[1].topics[1]);
114
- return proposalId;
115
+ return extractProposalIdFromLogs(receipt.logs);
115
116
  }
116
117
 
117
118
  public async awaitProposalActive({ proposalId, logger }: { proposalId: bigint; logger: Logger }) {
@@ -1,12 +1,13 @@
1
1
  import { memoize } from '@aztec/foundation/decorators';
2
2
  import { EthAddress } from '@aztec/foundation/eth-address';
3
- import { GovernanceProposerAbi } from '@aztec/l1-artifacts';
3
+ import { GovernanceProposerAbi } from '@aztec/l1-artifacts/GovernanceProposerAbi';
4
4
 
5
5
  import { type GetContractReturnType, type Hex, type TransactionReceipt, encodeFunctionData, getContract } from 'viem';
6
6
 
7
7
  import type { GasPrice, L1TxRequest, L1TxUtils } from '../l1_tx_utils.js';
8
8
  import type { ViemPublicClient } from '../types.js';
9
9
  import { type IEmpireBase, encodeVote } from './empire_base.js';
10
+ import { extractProposalIdFromLogs } from './governance.js';
10
11
 
11
12
  export class GovernanceProposerContract implements IEmpireBase {
12
13
  private readonly proposer: GetContractReturnType<typeof GovernanceProposerAbi, ViemPublicClient>;
@@ -63,14 +64,15 @@ export class GovernanceProposerContract implements IEmpireBase {
63
64
  };
64
65
  }
65
66
 
66
- public executeProposal(
67
+ public async executeProposal(
67
68
  round: bigint,
68
69
  l1TxUtils: L1TxUtils,
69
70
  ): Promise<{
70
71
  receipt: TransactionReceipt;
71
72
  gasPrice: GasPrice;
73
+ proposalId: bigint;
72
74
  }> {
73
- return l1TxUtils.sendAndMonitorTransaction({
75
+ const { receipt, gasPrice } = await l1TxUtils.sendAndMonitorTransaction({
74
76
  to: this.address.toString(),
75
77
  data: encodeFunctionData({
76
78
  abi: this.proposer.abi,
@@ -78,5 +80,7 @@ export class GovernanceProposerContract implements IEmpireBase {
78
80
  args: [round],
79
81
  }),
80
82
  });
83
+ const proposalId = extractProposalIdFromLogs(receipt.logs);
84
+ return { receipt, gasPrice, proposalId };
81
85
  }
82
86
  }
@@ -68,10 +68,10 @@ export class RegistryContract {
68
68
  > {
69
69
  const governanceAddress = await this.registry.read.getGovernance();
70
70
  const governance = new GovernanceContract(governanceAddress, this.client, undefined);
71
- const governanceProposer = await governance.getProposer();
71
+ const governanceProposerAddress = await governance.getGovernanceProposerAddress();
72
72
  return {
73
73
  governanceAddress: governance.address,
74
- governanceProposerAddress: governanceProposer.address,
74
+ governanceProposerAddress: governanceProposerAddress,
75
75
  };
76
76
  }
77
77
 
@@ -103,4 +103,9 @@ export class RegistryContract {
103
103
  coinIssuerAddress: EthAddress.fromString(coinIssuer),
104
104
  };
105
105
  }
106
+
107
+ public async getNumberOfVersions(): Promise<number> {
108
+ const version = await this.registry.read.numberOfVersions();
109
+ return Number(version);
110
+ }
106
111
  }
@@ -1,7 +1,9 @@
1
1
  import { memoize } from '@aztec/foundation/decorators';
2
2
  import { EthAddress } from '@aztec/foundation/eth-address';
3
3
  import type { ViemSignature } from '@aztec/foundation/eth-signature';
4
- import { RollupAbi, RollupStorage, SlasherAbi } from '@aztec/l1-artifacts';
4
+ import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
5
+ import { RollupStorage } from '@aztec/l1-artifacts/RollupStorage';
6
+ import { SlasherAbi } from '@aztec/l1-artifacts/SlasherAbi';
5
7
 
6
8
  import { type Account, type GetContractReturnType, type Hex, getAddress, getContract } from 'viem';
7
9
 
@@ -1,5 +1,5 @@
1
1
  import { EthAddress } from '@aztec/foundation/eth-address';
2
- import { SlashingProposerAbi } from '@aztec/l1-artifacts';
2
+ import { SlashingProposerAbi } from '@aztec/l1-artifacts/SlashingProposerAbi';
3
3
 
4
4
  import { type GetContractReturnType, type Hex, getContract } from 'viem';
5
5
 
@@ -66,7 +66,7 @@ import {
66
66
  type L1TxRequest,
67
67
  L1TxUtils,
68
68
  type L1TxUtilsConfig,
69
- defaultL1TxUtilsConfig,
69
+ getL1TxUtilsConfigEnvVars,
70
70
  } from './l1_tx_utils.js';
71
71
  import type { L1Clients, ViemPublicClient, ViemWalletClient } from './types.js';
72
72
 
@@ -257,7 +257,15 @@ export function createL1Clients(
257
257
  return { walletClient, publicClient } as L1Clients;
258
258
  }
259
259
 
260
- export const deployRollupAndPeriphery = async (
260
+ /**
261
+ * Deploys the rollup, slash factory, and the payload which can be used to make the rollup the canonical version.
262
+ * @param clients - The L1 clients.
263
+ * @param args - The deployment arguments.
264
+ * @param registryAddress - The address of the registry.
265
+ * @param logger - The logger.
266
+ * @param txUtilsConfig - The L1 tx utils config.
267
+ */
268
+ export const deployRollupForUpgrade = async (
261
269
  clients: L1Clients,
262
270
  args: DeployL1ContractsArgs,
263
271
  registryAddress: EthAddress,
@@ -343,22 +351,56 @@ export const deployRollup = async (
343
351
  await deployer.waitForDeployments();
344
352
  logger.verbose(`All core contracts have been deployed`);
345
353
 
354
+ if (args.initialValidators) {
355
+ await cheat_initializeValidatorSet(
356
+ clients,
357
+ deployer,
358
+ rollupAddress.toString(),
359
+ addresses.stakingAssetAddress.toString(),
360
+ args.initialValidators.map(v => v.toString()),
361
+ args.acceleratedTestDeployments,
362
+ logger,
363
+ );
364
+ }
365
+
366
+ return new RollupContract(clients.publicClient, rollupAddress);
367
+ };
368
+
369
+ /**
370
+ * Initialize the validator set for the rollup using a cheat function.
371
+ * @note This function will only be used when the chain is local anvil node soon (#12050)
372
+ *
373
+ * @param clients - The L1 clients.
374
+ * @param deployer - The L1 deployer.
375
+ * @param rollupAddress - The address of the rollup.
376
+ * @param stakingAssetAddress - The address of the staking asset.
377
+ * @param validators - The validators to initialize.
378
+ * @param acceleratedTestDeployments - Whether to use accelerated test deployments.
379
+ * @param logger - The logger.
380
+ */
381
+ // eslint-disable-next-line camelcase
382
+ export const cheat_initializeValidatorSet = async (
383
+ clients: L1Clients,
384
+ deployer: L1Deployer,
385
+ rollupAddress: Hex,
386
+ stakingAssetAddress: Hex,
387
+ validators: Hex[],
388
+ acceleratedTestDeployments: boolean | undefined,
389
+ logger: Logger,
390
+ ) => {
346
391
  const rollup = getContract({
347
392
  address: getAddress(rollupAddress.toString()),
348
393
  abi: l1Artifacts.rollup.contractAbi,
349
394
  client: clients.walletClient,
350
395
  });
351
-
352
- const txHashes: Hex[] = [];
353
-
354
- if (args.initialValidators && args.initialValidators.length > 0) {
396
+ const minimumStake = await rollup.read.getMinimumStake();
397
+ if (validators && validators.length > 0) {
355
398
  // Check if some of the initial validators are already registered, so we support idempotent deployments
356
- let newValidatorsAddresses = args.initialValidators.map(v => v.toString());
357
- if (!args.acceleratedTestDeployments) {
399
+ if (!acceleratedTestDeployments) {
358
400
  const validatorsInfo = await Promise.all(
359
- args.initialValidators.map(async address => ({
401
+ validators.map(async address => ({
360
402
  address,
361
- ...(await rollup.read.getInfo([address.toString()])),
403
+ ...(await rollup.read.getInfo([address])),
362
404
  })),
363
405
  );
364
406
  const existingValidators = validatorsInfo.filter(v => v.status !== 0);
@@ -370,16 +412,16 @@ export const deployRollup = async (
370
412
  );
371
413
  }
372
414
 
373
- newValidatorsAddresses = validatorsInfo.filter(v => v.status === 0).map(v => v.address.toString());
415
+ validators = validatorsInfo.filter(v => v.status === 0).map(v => v.address);
374
416
  }
375
417
 
376
- if (newValidatorsAddresses.length > 0) {
418
+ if (validators.length > 0) {
377
419
  // Mint tokens, approve them, use cheat code to initialise validator set without setting up the epoch.
378
- const stakeNeeded = args.minimumStake * BigInt(newValidatorsAddresses.length);
420
+ const stakeNeeded = minimumStake * BigInt(validators.length);
379
421
  await Promise.all(
380
422
  [
381
423
  await deployer.sendTransaction({
382
- to: addresses.stakingAssetAddress.toString(),
424
+ to: stakingAssetAddress,
383
425
  data: encodeFunctionData({
384
426
  abi: l1Artifacts.stakingAsset.contractAbi,
385
427
  functionName: 'mint',
@@ -387,40 +429,35 @@ export const deployRollup = async (
387
429
  }),
388
430
  }),
389
431
  await deployer.sendTransaction({
390
- to: addresses.stakingAssetAddress.toString(),
432
+ to: stakingAssetAddress,
391
433
  data: encodeFunctionData({
392
434
  abi: l1Artifacts.stakingAsset.contractAbi,
393
435
  functionName: 'approve',
394
- args: [rollupAddress.toString(), stakeNeeded],
436
+ args: [rollupAddress, stakeNeeded],
395
437
  }),
396
438
  }),
397
439
  ].map(tx => clients.publicClient.waitForTransactionReceipt({ hash: tx.txHash })),
398
440
  );
399
441
 
400
- const validators = newValidatorsAddresses.map(v => ({
442
+ const validatorsTuples = validators.map(v => ({
401
443
  attester: v,
402
444
  proposer: getExpectedAddress(ForwarderAbi, ForwarderBytecode, [v], v).address,
403
445
  withdrawer: v,
404
- amount: args.minimumStake,
446
+ amount: minimumStake,
405
447
  }));
406
- // const initiateValidatorSetTxHash = await rollup.write.cheat__InitialiseValidatorSet([validators]);
407
448
  const initiateValidatorSetTxHash = await deployer.walletClient.writeContract({
408
- address: rollupAddress.toString(),
449
+ address: rollupAddress,
409
450
  abi: l1Artifacts.rollup.contractAbi,
410
451
  functionName: 'cheat__InitialiseValidatorSet',
411
- args: [validators],
452
+ args: [validatorsTuples],
412
453
  });
413
- txHashes.push(initiateValidatorSetTxHash);
454
+ await clients.publicClient.waitForTransactionReceipt({ hash: initiateValidatorSetTxHash });
414
455
  logger.info(`Initialized validator set`, {
415
456
  validators,
416
457
  txHash: initiateValidatorSetTxHash,
417
458
  });
418
459
  }
419
460
  }
420
-
421
- await Promise.all(txHashes.map(txHash => clients.publicClient.waitForTransactionReceipt({ hash: txHash })));
422
-
423
- return new RollupContract(clients.publicClient, rollupAddress);
424
461
  };
425
462
 
426
463
  /**
@@ -438,7 +475,7 @@ export const deployL1Contracts = async (
438
475
  chain: Chain,
439
476
  logger: Logger,
440
477
  args: DeployL1ContractsArgs,
441
- txUtilsConfig: L1TxUtilsConfig = defaultL1TxUtilsConfig,
478
+ txUtilsConfig: L1TxUtilsConfig = getL1TxUtilsConfigEnvVars(),
442
479
  ): Promise<DeployL1ContractsReturnType> => {
443
480
  const clients = createL1Clients(rpcUrls, account, chain);
444
481
  const { walletClient, publicClient } = clients;
@@ -809,7 +846,8 @@ export async function deployL1Contract(
809
846
  let resultingAddress: Hex | null | undefined = undefined;
810
847
 
811
848
  if (!l1TxUtils) {
812
- l1TxUtils = new L1TxUtils(publicClient, walletClient, logger, undefined, acceleratedTestDeployments);
849
+ const config = getL1TxUtilsConfigEnvVars();
850
+ l1TxUtils = new L1TxUtils(publicClient, walletClient, logger, config, acceleratedTestDeployments);
813
851
  }
814
852
 
815
853
  if (libraries) {
@@ -2,6 +2,7 @@ import { compactArray, times } from '@aztec/foundation/collection';
2
2
  import {
3
3
  type ConfigMappingsType,
4
4
  bigintConfigHelper,
5
+ getConfigFromMappings,
5
6
  getDefaultConfig,
6
7
  numberConfigHelper,
7
8
  } from '@aztec/foundation/config';
@@ -158,6 +159,10 @@ export const l1TxUtilsConfigMappings: ConfigMappingsType<L1TxUtilsConfig> = {
158
159
 
159
160
  export const defaultL1TxUtilsConfig = getDefaultConfig<L1TxUtilsConfig>(l1TxUtilsConfigMappings);
160
161
 
162
+ export function getL1TxUtilsConfigEnvVars(): L1TxUtilsConfig {
163
+ return getConfigFromMappings(l1TxUtilsConfigMappings);
164
+ }
165
+
161
166
  export interface L1TxRequest {
162
167
  to: Address | null;
163
168
  data?: Hex;
package/src/queries.ts CHANGED
@@ -1,7 +1,11 @@
1
1
  import type { EthAddress } from '@aztec/foundation/eth-address';
2
+ import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
3
+
4
+ import type { Hex } from 'viem';
2
5
 
3
6
  import type { L1ContractsConfig } from './config.js';
4
7
  import { GovernanceContract } from './contracts/governance.js';
8
+ import { GovernanceProposerContract } from './contracts/governance_proposer.js';
5
9
  import { RollupContract } from './contracts/rollup.js';
6
10
  import type { ViemPublicClient } from './types.js';
7
11
 
@@ -11,8 +15,9 @@ export async function getL1ContractsConfig(
11
15
  addresses: { governanceAddress: EthAddress; rollupAddress?: EthAddress },
12
16
  ): Promise<Omit<L1ContractsConfig, 'ethereumSlotDuration'> & { l1StartBlock: bigint; l1GenesisTime: bigint }> {
13
17
  const governance = new GovernanceContract(addresses.governanceAddress.toString(), publicClient, undefined);
14
- const governanceProposer = await governance.getProposer();
15
- const rollupAddress = addresses.rollupAddress ?? (await governance.getGovernanceAddresses()).rollupAddress;
18
+ const governanceProposerAddress = await governance.getGovernanceProposerAddress();
19
+ const governanceProposer = new GovernanceProposerContract(publicClient, governanceProposerAddress.toString());
20
+ const rollupAddress = addresses.rollupAddress ?? (await governanceProposer.getRollupAddress());
16
21
  const rollup = new RollupContract(publicClient, rollupAddress.toString());
17
22
  const slasherProposer = await rollup.getSlashingProposer();
18
23
 
@@ -56,3 +61,25 @@ export async function getL1ContractsConfig(
56
61
  slashingRoundSize: Number(slashingRoundSize),
57
62
  };
58
63
  }
64
+
65
+ export type L2BlockProposedEvent = {
66
+ versionedBlobHashes: readonly Hex[];
67
+ archive: Hex;
68
+ blockNumber: bigint;
69
+ };
70
+
71
+ export async function getL2BlockProposalEvents(
72
+ client: ViemPublicClient,
73
+ blockId: Hex,
74
+ rollupAddress?: EthAddress,
75
+ ): Promise<L2BlockProposedEvent[]> {
76
+ return (
77
+ await client.getContractEvents({
78
+ abi: RollupAbi,
79
+ address: rollupAddress?.toString(),
80
+ blockHash: blockId,
81
+ eventName: 'L2BlockProposed',
82
+ strict: true,
83
+ })
84
+ ).map(log => log.args);
85
+ }
@@ -0,0 +1,88 @@
1
+ import type { RollupContract } from '@aztec/ethereum/contracts';
2
+ import { createLogger } from '@aztec/foundation/log';
3
+
4
+ import type { PublicClient } from 'viem';
5
+
6
+ /** Utility class that polls the chain on quick intervals and logs new L1 blocks, L2 blocks, and L2 proofs. */
7
+ export class ChainMonitor {
8
+ private readonly l1Client: PublicClient;
9
+ private handle: NodeJS.Timeout | undefined;
10
+
11
+ /** Current L1 block number */
12
+ public l1BlockNumber!: number;
13
+ /** Current L2 block number */
14
+ public l2BlockNumber!: number;
15
+ /** Current L2 proven block number */
16
+ public l2ProvenBlockNumber!: number;
17
+ /** L1 timestamp for the current L2 block */
18
+ public l2BlockTimestamp!: bigint;
19
+ /** L1 timestamp for the proven L2 block */
20
+ public l2ProvenBlockTimestamp!: bigint;
21
+
22
+ constructor(
23
+ private readonly rollup: RollupContract,
24
+ private logger = createLogger('aztecjs:utils:chain_monitor'),
25
+ private readonly intervalMs = 200,
26
+ ) {
27
+ this.l1Client = rollup.client;
28
+ }
29
+
30
+ start() {
31
+ if (this.handle) {
32
+ throw new Error('Chain monitor already started');
33
+ }
34
+ this.handle = setInterval(this.safeRun.bind(this), this.intervalMs);
35
+ return this;
36
+ }
37
+
38
+ stop() {
39
+ if (this.handle) {
40
+ clearInterval(this.handle!);
41
+ this.handle = undefined;
42
+ }
43
+ }
44
+
45
+ private safeRun() {
46
+ void this.run().catch(error => {
47
+ this.logger.error('Error in chain monitor loop', error);
48
+ });
49
+ }
50
+
51
+ async run() {
52
+ const newL1BlockNumber = Number(await this.l1Client.getBlockNumber({ cacheTime: 0 }));
53
+ if (this.l1BlockNumber === newL1BlockNumber) {
54
+ return;
55
+ }
56
+ this.l1BlockNumber = newL1BlockNumber;
57
+
58
+ const block = await this.l1Client.getBlock({ blockNumber: BigInt(newL1BlockNumber), includeTransactions: false });
59
+ const timestamp = block.timestamp;
60
+ const timestampString = new Date(Number(timestamp) * 1000).toTimeString().split(' ')[0];
61
+
62
+ let msg = `L1 block ${newL1BlockNumber} mined at ${timestampString}`;
63
+
64
+ const newL2BlockNumber = Number(await this.rollup.getBlockNumber());
65
+ if (this.l2BlockNumber !== newL2BlockNumber) {
66
+ const epochNumber = await this.rollup.getEpochNumber(BigInt(newL2BlockNumber));
67
+ msg += ` with new L2 block ${newL2BlockNumber} for epoch ${epochNumber}`;
68
+ this.l2BlockNumber = newL2BlockNumber;
69
+ this.l2BlockTimestamp = timestamp;
70
+ }
71
+
72
+ const newL2ProvenBlockNumber = Number(await this.rollup.getProvenBlockNumber());
73
+ if (this.l2ProvenBlockNumber !== newL2ProvenBlockNumber) {
74
+ const epochNumber = await this.rollup.getEpochNumber(BigInt(newL2ProvenBlockNumber));
75
+ msg += ` with proof up to L2 block ${newL2ProvenBlockNumber} for epoch ${epochNumber}`;
76
+ this.l2ProvenBlockNumber = newL2ProvenBlockNumber;
77
+ this.l2ProvenBlockTimestamp = timestamp;
78
+ }
79
+
80
+ this.logger.info(msg, {
81
+ l1Timestamp: timestamp,
82
+ l1BlockNumber: this.l1BlockNumber,
83
+ l2SlotNumber: await this.rollup.getSlotNumber(),
84
+ l2BlockNumber: this.l2BlockNumber,
85
+ l2ProvenBlockNumber: this.l2ProvenBlockNumber,
86
+ });
87
+ }
88
+ }
package/src/test/index.ts CHANGED
@@ -3,3 +3,4 @@ export * from './eth_cheat_codes_with_state.js';
3
3
  export * from './start_anvil.js';
4
4
  export * from './tx_delayer.js';
5
5
  export * from './upgrade_utils.js';
6
+ export * from './chain_monitor.js';
@@ -1,6 +1,6 @@
1
1
  import type { Logger } from '@aztec/foundation/log';
2
- import { TestERC20Abi as FeeJuiceAbi } from '@aztec/l1-artifacts';
3
2
  import { GovernanceAbi } from '@aztec/l1-artifacts/GovernanceAbi';
3
+ import { TestERC20Abi as FeeJuiceAbi } from '@aztec/l1-artifacts/TestERC20Abi';
4
4
 
5
5
  import { type GetContractReturnType, type PrivateKeyAccount, getContract } from 'viem';
6
6
 
package/src/utils.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { Fr } from '@aztec/foundation/fields';
2
2
  import type { Logger } from '@aztec/foundation/log';
3
- import { ErrorsAbi } from '@aztec/l1-artifacts';
3
+ import { ErrorsAbi } from '@aztec/l1-artifacts/ErrorsAbi';
4
4
 
5
5
  import {
6
6
  type Abi,