@aztec/ethereum 0.0.1-commit.6d3c34e → 0.0.1-commit.6ebe706df

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 (160) hide show
  1. package/dest/client.d.ts +10 -2
  2. package/dest/client.d.ts.map +1 -1
  3. package/dest/client.js +13 -7
  4. package/dest/config.d.ts +17 -28
  5. package/dest/config.d.ts.map +1 -1
  6. package/dest/config.js +56 -57
  7. package/dest/contracts/empire_base.d.ts +3 -1
  8. package/dest/contracts/empire_base.d.ts.map +1 -1
  9. package/dest/contracts/empire_slashing_proposer.d.ts +3 -1
  10. package/dest/contracts/empire_slashing_proposer.d.ts.map +1 -1
  11. package/dest/contracts/empire_slashing_proposer.js +22 -15
  12. package/dest/contracts/fee_asset_handler.d.ts +1 -1
  13. package/dest/contracts/fee_asset_handler.d.ts.map +1 -1
  14. package/dest/contracts/fee_asset_handler.js +2 -0
  15. package/dest/contracts/fee_asset_price_oracle.d.ts +101 -0
  16. package/dest/contracts/fee_asset_price_oracle.d.ts.map +1 -0
  17. package/dest/contracts/fee_asset_price_oracle.js +651 -0
  18. package/dest/contracts/governance.d.ts +3 -1
  19. package/dest/contracts/governance.d.ts.map +1 -1
  20. package/dest/contracts/governance.js +14 -4
  21. package/dest/contracts/governance_proposer.d.ts +3 -1
  22. package/dest/contracts/governance_proposer.d.ts.map +1 -1
  23. package/dest/contracts/governance_proposer.js +13 -1
  24. package/dest/contracts/inbox.d.ts +18 -1
  25. package/dest/contracts/inbox.d.ts.map +1 -1
  26. package/dest/contracts/inbox.js +32 -1
  27. package/dest/contracts/index.d.ts +3 -1
  28. package/dest/contracts/index.d.ts.map +1 -1
  29. package/dest/contracts/index.js +2 -0
  30. package/dest/contracts/log.d.ts +13 -0
  31. package/dest/contracts/log.d.ts.map +1 -0
  32. package/dest/contracts/log.js +1 -0
  33. package/dest/contracts/multicall.d.ts +51 -2
  34. package/dest/contracts/multicall.d.ts.map +1 -1
  35. package/dest/contracts/multicall.js +87 -1
  36. package/dest/contracts/registry.d.ts +3 -1
  37. package/dest/contracts/registry.d.ts.map +1 -1
  38. package/dest/contracts/registry.js +30 -1
  39. package/dest/contracts/rollup.d.ts +51 -6
  40. package/dest/contracts/rollup.d.ts.map +1 -1
  41. package/dest/contracts/rollup.js +133 -13
  42. package/dest/contracts/tally_slashing_proposer.d.ts +1 -1
  43. package/dest/contracts/tally_slashing_proposer.d.ts.map +1 -1
  44. package/dest/contracts/tally_slashing_proposer.js +8 -1
  45. package/dest/deploy_aztec_l1_contracts.d.ts +7 -3
  46. package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -1
  47. package/dest/deploy_aztec_l1_contracts.js +56 -28
  48. package/dest/deploy_l1_contract.js +3 -3
  49. package/dest/generated/l1-contracts-defaults.d.ts +30 -0
  50. package/dest/generated/l1-contracts-defaults.d.ts.map +1 -0
  51. package/dest/generated/l1-contracts-defaults.js +30 -0
  52. package/dest/l1_artifacts.d.ts +2405 -473
  53. package/dest/l1_artifacts.d.ts.map +1 -1
  54. package/dest/l1_reader.d.ts +3 -1
  55. package/dest/l1_reader.d.ts.map +1 -1
  56. package/dest/l1_reader.js +6 -1
  57. package/dest/l1_tx_utils/config.d.ts +7 -1
  58. package/dest/l1_tx_utils/config.d.ts.map +1 -1
  59. package/dest/l1_tx_utils/config.js +14 -1
  60. package/dest/l1_tx_utils/constants.d.ts +1 -1
  61. package/dest/l1_tx_utils/constants.js +2 -2
  62. package/dest/l1_tx_utils/factory.d.ts +18 -10
  63. package/dest/l1_tx_utils/factory.d.ts.map +1 -1
  64. package/dest/l1_tx_utils/factory.js +17 -7
  65. package/dest/l1_tx_utils/fee-strategies/p75_competitive.js +1 -1
  66. package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.js +1 -1
  67. package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts +15 -15
  68. package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts.map +1 -1
  69. package/dest/l1_tx_utils/forwarder_l1_tx_utils.js +9 -15
  70. package/dest/l1_tx_utils/index-blobs.d.ts +3 -3
  71. package/dest/l1_tx_utils/index-blobs.d.ts.map +1 -1
  72. package/dest/l1_tx_utils/index-blobs.js +2 -2
  73. package/dest/l1_tx_utils/index.d.ts +2 -1
  74. package/dest/l1_tx_utils/index.d.ts.map +1 -1
  75. package/dest/l1_tx_utils/index.js +1 -0
  76. package/dest/l1_tx_utils/l1_tx_utils.d.ts +18 -7
  77. package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
  78. package/dest/l1_tx_utils/l1_tx_utils.js +58 -42
  79. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +1 -1
  80. package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -1
  81. package/dest/l1_tx_utils/readonly_l1_tx_utils.js +11 -7
  82. package/dest/l1_tx_utils/tx_delayer.d.ts +56 -0
  83. package/dest/l1_tx_utils/tx_delayer.d.ts.map +1 -0
  84. package/dest/{test → l1_tx_utils}/tx_delayer.js +62 -34
  85. package/dest/publisher_manager.d.ts +21 -6
  86. package/dest/publisher_manager.d.ts.map +1 -1
  87. package/dest/publisher_manager.js +81 -7
  88. package/dest/queries.d.ts +2 -2
  89. package/dest/queries.d.ts.map +1 -1
  90. package/dest/queries.js +4 -1
  91. package/dest/test/chain_monitor.d.ts +22 -3
  92. package/dest/test/chain_monitor.d.ts.map +1 -1
  93. package/dest/test/chain_monitor.js +33 -2
  94. package/dest/test/eth_cheat_codes.d.ts +18 -4
  95. package/dest/test/eth_cheat_codes.d.ts.map +1 -1
  96. package/dest/test/eth_cheat_codes.js +6 -4
  97. package/dest/test/index.d.ts +1 -3
  98. package/dest/test/index.d.ts.map +1 -1
  99. package/dest/test/index.js +0 -2
  100. package/dest/test/rollup_cheat_codes.d.ts +4 -2
  101. package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
  102. package/dest/test/rollup_cheat_codes.js +10 -1
  103. package/dest/test/start_anvil.d.ts +23 -3
  104. package/dest/test/start_anvil.d.ts.map +1 -1
  105. package/dest/test/start_anvil.js +143 -29
  106. package/dest/test/upgrade_utils.js +2 -2
  107. package/dest/utils.d.ts +2 -1
  108. package/dest/utils.d.ts.map +1 -1
  109. package/dest/utils.js +62 -12
  110. package/package.json +8 -9
  111. package/src/client.ts +10 -2
  112. package/src/config.ts +70 -56
  113. package/src/contracts/README.md +157 -0
  114. package/src/contracts/empire_base.ts +2 -0
  115. package/src/contracts/empire_slashing_proposer.ts +22 -27
  116. package/src/contracts/fee_asset_handler.ts +2 -0
  117. package/src/contracts/fee_asset_price_oracle.ts +280 -0
  118. package/src/contracts/governance.ts +13 -4
  119. package/src/contracts/governance_proposer.ts +10 -1
  120. package/src/contracts/inbox.ts +48 -1
  121. package/src/contracts/index.ts +2 -0
  122. package/src/contracts/log.ts +13 -0
  123. package/src/contracts/multicall.ts +70 -3
  124. package/src/contracts/registry.ts +31 -1
  125. package/src/contracts/rollup.ts +169 -14
  126. package/src/contracts/tally_slashing_proposer.ts +5 -1
  127. package/src/deploy_aztec_l1_contracts.ts +80 -35
  128. package/src/deploy_l1_contract.ts +3 -3
  129. package/src/generated/l1-contracts-defaults.ts +32 -0
  130. package/src/l1_reader.ts +13 -1
  131. package/src/l1_tx_utils/config.ts +20 -0
  132. package/src/l1_tx_utils/constants.ts +2 -2
  133. package/src/l1_tx_utils/factory.ts +31 -31
  134. package/src/l1_tx_utils/fee-strategies/p75_competitive.ts +1 -1
  135. package/src/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.ts +1 -1
  136. package/src/l1_tx_utils/forwarder_l1_tx_utils.ts +43 -54
  137. package/src/l1_tx_utils/index-blobs.ts +2 -2
  138. package/src/l1_tx_utils/index.ts +1 -0
  139. package/src/l1_tx_utils/l1_tx_utils.ts +60 -32
  140. package/src/l1_tx_utils/readonly_l1_tx_utils.ts +11 -7
  141. package/src/{test → l1_tx_utils}/tx_delayer.ts +78 -50
  142. package/src/publisher_manager.ts +107 -10
  143. package/src/queries.ts +3 -1
  144. package/src/test/chain_monitor.ts +60 -3
  145. package/src/test/eth_cheat_codes.ts +6 -4
  146. package/src/test/index.ts +0 -2
  147. package/src/test/rollup_cheat_codes.ts +11 -2
  148. package/src/test/start_anvil.ts +177 -29
  149. package/src/test/upgrade_utils.ts +2 -2
  150. package/src/utils.ts +70 -14
  151. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts +0 -26
  152. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +0 -1
  153. package/dest/l1_tx_utils/l1_tx_utils_with_blobs.js +0 -26
  154. package/dest/test/delayed_tx_utils.d.ts +0 -13
  155. package/dest/test/delayed_tx_utils.d.ts.map +0 -1
  156. package/dest/test/delayed_tx_utils.js +0 -28
  157. package/dest/test/tx_delayer.d.ts +0 -36
  158. package/dest/test/tx_delayer.d.ts.map +0 -1
  159. package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +0 -77
  160. package/src/test/delayed_tx_utils.ts +0 -52
@@ -5,6 +5,7 @@ import { memoize } from '@aztec/foundation/decorators';
5
5
  import { EthAddress } from '@aztec/foundation/eth-address';
6
6
  import type { ViemSignature } from '@aztec/foundation/eth-signature';
7
7
  import { makeBackoff, retry } from '@aztec/foundation/retry';
8
+ import { EscapeHatchAbi } from '@aztec/l1-artifacts/EscapeHatchAbi';
8
9
  import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
9
10
  import { RollupStorage } from '@aztec/l1-artifacts/RollupStorage';
10
11
 
@@ -30,6 +31,7 @@ import type { ViemClient } from '../types.js';
30
31
  import { formatViemError } from '../utils.js';
31
32
  import { EmpireSlashingProposerContract } from './empire_slashing_proposer.js';
32
33
  import { GSEContract } from './gse.js';
34
+ import type { L1EventLog } from './log.js';
33
35
  import { SlasherContract } from './slasher_contract.js';
34
36
  import { TallySlashingProposerContract } from './tally_slashing_proposer.js';
35
37
  import { checkBlockTag } from './utils.js';
@@ -69,6 +71,7 @@ export type ViemHeader = {
69
71
  blockHeadersHash: `0x${string}`;
70
72
  blobsHash: `0x${string}`;
71
73
  inHash: `0x${string}`;
74
+ outHash: `0x${string}`;
72
75
  slotNumber: bigint;
73
76
  timestamp: bigint;
74
77
  coinbase: `0x${string}`;
@@ -105,7 +108,7 @@ export enum AttesterStatus {
105
108
  export type FeeHeader = {
106
109
  excessMana: bigint;
107
110
  manaUsed: bigint;
108
- feeAssetPriceNumerator: bigint;
111
+ ethPerFeeAsset: bigint;
109
112
  congestionCost: bigint;
110
113
  proverCost: bigint;
111
114
  };
@@ -131,6 +134,14 @@ export type L1FeeData = {
131
134
  blobFee: bigint;
132
135
  };
133
136
 
137
+ /** Components of the minimum fee per mana, as returned by the L1 rollup contract. */
138
+ export type ManaMinFeeComponents = {
139
+ sequencerCost: bigint;
140
+ proverCost: bigint;
141
+ congestionCost: bigint;
142
+ congestionMultiplier: bigint;
143
+ };
144
+
134
145
  /**
135
146
  * Reward configuration for the rollup
136
147
  */
@@ -185,10 +196,28 @@ export type RollupStatusResponse = {
185
196
  archiveOfMyCheckpoint: Fr;
186
197
  };
187
198
 
199
+ /** Arguments for the CheckpointProposed event. */
200
+ export type CheckpointProposedArgs = {
201
+ checkpointNumber: CheckpointNumber;
202
+ archive: Fr;
203
+ versionedBlobHashes: Buffer[];
204
+ /** Hash of attestations emitted in the CheckpointProposed event. */
205
+ attestationsHash: Buffer32;
206
+ /** Digest of the payload emitted in the CheckpointProposed event. */
207
+ payloadDigest: Buffer32;
208
+ };
209
+
210
+ /** Log type for CheckpointProposed events. */
211
+ export type CheckpointProposedLog = L1EventLog<CheckpointProposedArgs>;
212
+
188
213
  export class RollupContract {
189
214
  private readonly rollup: GetContractReturnType<typeof RollupAbi, ViemClient>;
190
215
 
191
216
  private static cachedStfStorageSlot: Hex | undefined;
217
+ private cachedEscapeHatch?: {
218
+ address: EthAddress;
219
+ contract: GetContractReturnType<typeof EscapeHatchAbi, ViemClient>;
220
+ };
192
221
 
193
222
  static get checkBlobStorageSlot(): bigint {
194
223
  const asString = RollupStorage.find(storage => storage.label === 'checkBlob')?.slot;
@@ -358,6 +387,20 @@ export class RollupContract {
358
387
  return Fr.fromString(await this.rollup.read.archiveAt([0n]));
359
388
  }
360
389
 
390
+ @memoize
391
+ async getVkTreeRoot(): Promise<Fr> {
392
+ const slot = BigInt(RollupContract.stfStorageSlot) + 3n;
393
+ const value = await this.client.getStorageAt({ address: this.address, slot: `0x${slot.toString(16)}` });
394
+ return Fr.fromString(value ?? '0x0');
395
+ }
396
+
397
+ @memoize
398
+ async getProtocolContractsHash(): Promise<Fr> {
399
+ const slot = BigInt(RollupContract.stfStorageSlot) + 4n;
400
+ const value = await this.client.getStorageAt({ address: this.address, slot: `0x${slot.toString(16)}` });
401
+ return Fr.fromString(value ?? '0x0');
402
+ }
403
+
361
404
  /**
362
405
  * Returns rollup constants used for epoch queries.
363
406
  * Return type is `L1RollupConstants` which is defined in stdlib,
@@ -370,13 +413,25 @@ export class RollupContract {
370
413
  slotDuration: number;
371
414
  epochDuration: number;
372
415
  proofSubmissionEpochs: number;
416
+ targetCommitteeSize: number;
417
+ rollupManaLimit: number;
373
418
  }> {
374
- const [l1StartBlock, l1GenesisTime, slotDuration, epochDuration, proofSubmissionEpochs] = await Promise.all([
419
+ const [
420
+ l1StartBlock,
421
+ l1GenesisTime,
422
+ slotDuration,
423
+ epochDuration,
424
+ proofSubmissionEpochs,
425
+ targetCommitteeSize,
426
+ rollupManaLimit,
427
+ ] = await Promise.all([
375
428
  this.getL1StartBlock(),
376
429
  this.getL1GenesisTime(),
377
430
  this.getSlotDuration(),
378
431
  this.getEpochDuration(),
379
432
  this.getProofSubmissionEpochs(),
433
+ this.getTargetCommitteeSize(),
434
+ this.getManaLimit(),
380
435
  ]);
381
436
  return {
382
437
  l1StartBlock,
@@ -384,6 +439,8 @@ export class RollupContract {
384
439
  slotDuration,
385
440
  epochDuration: Number(epochDuration),
386
441
  proofSubmissionEpochs: Number(proofSubmissionEpochs),
442
+ targetCommitteeSize,
443
+ rollupManaLimit: Number(rollupManaLimit),
387
444
  };
388
445
  }
389
446
 
@@ -391,6 +448,58 @@ export class RollupContract {
391
448
  return EthAddress.fromString(await this.rollup.read.getSlasher());
392
449
  }
393
450
 
451
+ /**
452
+ * Returns the configured escape hatch contract address, or zero if disabled.
453
+ */
454
+ async getEscapeHatchAddress(): Promise<EthAddress> {
455
+ return EthAddress.fromString(await this.rollup.read.getEscapeHatch());
456
+ }
457
+
458
+ private async getEscapeHatchContract(): Promise<
459
+ GetContractReturnType<typeof EscapeHatchAbi, ViemClient> | undefined
460
+ > {
461
+ const escapeHatchAddress = await this.getEscapeHatchAddress();
462
+ if (escapeHatchAddress.isZero()) {
463
+ return undefined;
464
+ }
465
+
466
+ // Cache the viem contract wrapper since it will be used frequently.
467
+ if (!this.cachedEscapeHatch || !this.cachedEscapeHatch.address.equals(escapeHatchAddress)) {
468
+ this.cachedEscapeHatch = {
469
+ address: escapeHatchAddress,
470
+ contract: getContract({
471
+ address: escapeHatchAddress.toString(),
472
+ abi: EscapeHatchAbi,
473
+ client: this.client,
474
+ }),
475
+ };
476
+ }
477
+
478
+ return this.cachedEscapeHatch.contract;
479
+ }
480
+
481
+ /**
482
+ * Returns whether the escape hatch is open for the given epoch.
483
+ * If escape hatch is not configured, returns false.
484
+ *
485
+ * This function is intentionally defensive: any failure to query the escape hatch
486
+ * (RPC issues, transient errors, etc.) is treated as "closed" to avoid callers
487
+ * needing to sprinkle try/catch everywhere.
488
+ */
489
+ async isEscapeHatchOpen(epoch: EpochNumber): Promise<boolean> {
490
+ try {
491
+ const escapeHatch = await this.getEscapeHatchContract();
492
+ if (!escapeHatch) {
493
+ return false;
494
+ }
495
+
496
+ const [isOpen] = await escapeHatch.read.isHatchOpen([BigInt(epoch)]);
497
+ return isOpen;
498
+ } catch {
499
+ return false;
500
+ }
501
+ }
502
+
394
503
  /**
395
504
  * Returns a SlasherContract instance for interacting with the slasher contract.
396
505
  */
@@ -426,8 +535,9 @@ export class RollupContract {
426
535
  return CheckpointNumber.fromBigInt(await this.rollup.read.getPendingCheckpointNumber());
427
536
  }
428
537
 
429
- async getProvenCheckpointNumber(): Promise<CheckpointNumber> {
430
- return CheckpointNumber.fromBigInt(await this.rollup.read.getProvenCheckpointNumber());
538
+ async getProvenCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
539
+ await checkBlockTag(options?.blockNumber, this.client);
540
+ return CheckpointNumber.fromBigInt(await this.rollup.read.getProvenCheckpointNumber(options));
431
541
  }
432
542
 
433
543
  async getSlotNumber(): Promise<SlotNumber> {
@@ -442,8 +552,8 @@ export class RollupContract {
442
552
  };
443
553
  }
444
554
 
445
- getFeeAssetPerEth(): Promise<bigint> {
446
- return this.rollup.read.getFeeAssetPerEth();
555
+ getEthPerFeeAsset(): Promise<bigint> {
556
+ return this.rollup.read.getEthPerFeeAsset();
447
557
  }
448
558
 
449
559
  async getCommitteeAt(timestamp: bigint): Promise<EthAddress[] | undefined> {
@@ -528,7 +638,7 @@ export class RollupContract {
528
638
  feeHeader: {
529
639
  excessMana: result.feeHeader.excessMana,
530
640
  manaUsed: result.feeHeader.manaUsed,
531
- feeAssetPriceNumerator: result.feeHeader.feeAssetPriceNumerator,
641
+ ethPerFeeAsset: result.feeHeader.ethPerFeeAsset,
532
642
  congestionCost: result.feeHeader.congestionCost,
533
643
  proverCost: result.feeHeader.proverCost,
534
644
  },
@@ -668,14 +778,13 @@ export class RollupContract {
668
778
  * timestamp of the next L1 block
669
779
  * @throws otherwise
670
780
  */
671
- public async canProposeAtNextEthBlock(
781
+ public async canProposeAt(
672
782
  archive: Buffer,
673
783
  account: `0x${string}` | Account,
674
- slotDuration: number,
784
+ timestamp: bigint,
675
785
  opts: { forcePendingCheckpointNumber?: CheckpointNumber } = {},
676
786
  ): Promise<{ slot: SlotNumber; checkpointNumber: CheckpointNumber; timeOfNextL1Slot: bigint }> {
677
- const latestBlock = await this.client.getBlock();
678
- const timeOfNextL1Slot = latestBlock.timestamp + BigInt(slotDuration);
787
+ const timeOfNextL1Slot = timestamp;
679
788
  const who = typeof account === 'string' ? account : account.address;
680
789
 
681
790
  try {
@@ -732,6 +841,7 @@ export class RollupContract {
732
841
  ): L1TxRequest {
733
842
  return {
734
843
  to: this.address,
844
+ abi: RollupAbi,
735
845
  data: encodeFunctionData({
736
846
  abi: RollupAbi,
737
847
  functionName: 'invalidateBadAttestation',
@@ -753,6 +863,7 @@ export class RollupContract {
753
863
  ): L1TxRequest {
754
864
  return {
755
865
  to: this.address,
866
+ abi: RollupAbi,
756
867
  data: encodeFunctionData({
757
868
  abi: RollupAbi,
758
869
  functionName: 'invalidateInsufficientAttestations',
@@ -773,6 +884,16 @@ export class RollupContract {
773
884
  return this.rollup.read.getManaMinFeeAt([timestamp, inFeeAsset]);
774
885
  }
775
886
 
887
+ async getManaMinFeeComponentsAt(timestamp: bigint, inFeeAsset: boolean): Promise<ManaMinFeeComponents> {
888
+ const result = await this.rollup.read.getManaMinFeeComponentsAt([timestamp, inFeeAsset]);
889
+ return {
890
+ sequencerCost: result.sequencerCost,
891
+ proverCost: result.proverCost,
892
+ congestionCost: result.congestionCost,
893
+ congestionMultiplier: result.congestionMultiplier,
894
+ };
895
+ }
896
+
776
897
  async getSlotAt(timestamp: bigint): Promise<SlotNumber> {
777
898
  return SlotNumber.fromBigInt(await this.rollup.read.getSlotAt([timestamp]));
778
899
  }
@@ -816,11 +937,10 @@ export class RollupContract {
816
937
  return this.rollup.read.getSpecificProverRewardsForEpoch([epoch, prover]);
817
938
  }
818
939
 
819
- async getAttesters(): Promise<EthAddress[]> {
940
+ async getAttesters(timestamp?: bigint): Promise<EthAddress[]> {
820
941
  const attesterSize = await this.getActiveAttesterCount();
821
942
  const gse = new GSEContract(this.client, await this.getGSE());
822
- const ts = (await this.client.getBlock()).timestamp;
823
-
943
+ const ts = timestamp ?? (await this.client.getBlock()).timestamp;
824
944
  const indices = Array.from({ length: attesterSize }, (_, i) => BigInt(i));
825
945
  const chunks = chunk(indices, 1000);
826
946
 
@@ -886,6 +1006,7 @@ export class RollupContract {
886
1006
  setupEpoch(l1TxUtils: L1TxUtils) {
887
1007
  return l1TxUtils.sendAndMonitorTransaction({
888
1008
  to: this.address,
1009
+ abi: RollupAbi,
889
1010
  data: encodeFunctionData({
890
1011
  abi: RollupAbi,
891
1012
  functionName: 'setupEpoch',
@@ -897,6 +1018,7 @@ export class RollupContract {
897
1018
  vote(l1TxUtils: L1TxUtils, proposalId: bigint) {
898
1019
  return l1TxUtils.sendAndMonitorTransaction({
899
1020
  to: this.address,
1021
+ abi: RollupAbi,
900
1022
  data: encodeFunctionData({
901
1023
  abi: RollupAbi,
902
1024
  functionName: 'vote',
@@ -965,4 +1087,37 @@ export class RollupContract {
965
1087
  },
966
1088
  );
967
1089
  }
1090
+
1091
+ /** Fetches CheckpointProposed events within the given block range. */
1092
+ async getCheckpointProposedEvents(fromBlock: bigint, toBlock: bigint): Promise<CheckpointProposedLog[]> {
1093
+ const logs = await this.rollup.getEvents.CheckpointProposed({}, { fromBlock, toBlock });
1094
+ return logs
1095
+ .filter(log => log.blockNumber! >= fromBlock && log.blockNumber! <= toBlock)
1096
+ .map(log => ({
1097
+ l1BlockNumber: log.blockNumber!,
1098
+ l1BlockHash: Buffer32.fromString(log.blockHash!),
1099
+ l1TransactionHash: log.transactionHash!,
1100
+ args: {
1101
+ checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber!),
1102
+ archive: Fr.fromString(log.args.archive!),
1103
+ versionedBlobHashes: log.args.versionedBlobHashes!.map(h => Buffer.from(h.slice(2), 'hex')),
1104
+ attestationsHash: (() => {
1105
+ if (!log.args.attestationsHash) {
1106
+ throw new Error(
1107
+ `CheckpointProposed event missing attestationsHash for checkpoint ${log.args.checkpointNumber}`,
1108
+ );
1109
+ }
1110
+ return Buffer32.fromString(log.args.attestationsHash);
1111
+ })(),
1112
+ payloadDigest: (() => {
1113
+ if (!log.args.payloadDigest) {
1114
+ throw new Error(
1115
+ `CheckpointProposed event missing payloadDigest for checkpoint ${log.args.checkpointNumber}`,
1116
+ );
1117
+ }
1118
+ return Buffer32.fromString(log.args.payloadDigest);
1119
+ })(),
1120
+ },
1121
+ }));
1122
+ }
968
1123
  }
@@ -1,11 +1,12 @@
1
1
  import type { L1TxRequest } from '@aztec/ethereum/l1-tx-utils';
2
2
  import type { ViemClient } from '@aztec/ethereum/types';
3
- import { tryExtractEvent } from '@aztec/ethereum/utils';
3
+ import { mergeAbis, tryExtractEvent } from '@aztec/ethereum/utils';
4
4
  import { SlotNumber } from '@aztec/foundation/branded-types';
5
5
  import { Buffer32 } from '@aztec/foundation/buffer';
6
6
  import { EthAddress } from '@aztec/foundation/eth-address';
7
7
  import { Signature } from '@aztec/foundation/eth-signature';
8
8
  import { hexToBuffer } from '@aztec/foundation/string';
9
+ import { SlasherAbi } from '@aztec/l1-artifacts/SlasherAbi';
9
10
  import { TallySlashingProposerAbi } from '@aztec/l1-artifacts/TallySlashingProposerAbi';
10
11
 
11
12
  import {
@@ -160,6 +161,7 @@ export class TallySlashingProposerContract {
160
161
 
161
162
  return {
162
163
  to: this.contract.address,
164
+ abi: TallySlashingProposerAbi,
163
165
  data: encodeFunctionData({
164
166
  abi: TallySlashingProposerAbi,
165
167
  functionName: 'vote',
@@ -207,6 +209,7 @@ export class TallySlashingProposerContract {
207
209
  public buildVoteRequestWithSignature(votes: Hex, signature: { v: number; r: Hex; s: Hex }): L1TxRequest {
208
210
  return {
209
211
  to: this.contract.address,
212
+ abi: TallySlashingProposerAbi,
210
213
  data: encodeFunctionData({
211
214
  abi: TallySlashingProposerAbi,
212
215
  functionName: 'vote',
@@ -224,6 +227,7 @@ export class TallySlashingProposerContract {
224
227
  public buildExecuteRoundRequest(round: bigint, committees: EthAddress[][]): L1TxRequest {
225
228
  return {
226
229
  to: this.contract.address,
230
+ abi: mergeAbis([TallySlashingProposerAbi, SlasherAbi]),
227
231
  data: encodeFunctionData({
228
232
  abi: TallySlashingProposerAbi,
229
233
  functionName: 'executeRound',
@@ -10,12 +10,12 @@ import { fileURLToPath } from '@aztec/foundation/url';
10
10
  import { bn254 } from '@noble/curves/bn254';
11
11
  import type { Abi, Narrow } from 'abitype';
12
12
  import { spawn } from 'child_process';
13
- import { cpSync, existsSync, mkdirSync, mkdtempSync, readdirSync, rmSync } from 'fs';
13
+ import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'fs';
14
14
  import { tmpdir } from 'os';
15
15
  import { dirname, join, resolve } from 'path';
16
16
  import readline from 'readline';
17
17
  import type { Hex } from 'viem';
18
- import { foundry, mainnet, sepolia } from 'viem/chains';
18
+ import { mainnet, sepolia } from 'viem/chains';
19
19
 
20
20
  import { createEthereumChain, isAnvilTestChain } from './chain.js';
21
21
  import { createExtendedL1Client } from './client.js';
@@ -23,7 +23,6 @@ import type { L1ContractsConfig } from './config.js';
23
23
  import { deployMulticall3 } from './contracts/multicall.js';
24
24
  import { RollupContract } from './contracts/rollup.js';
25
25
  import type { L1ContractAddresses } from './l1_contract_addresses.js';
26
- import type { L1TxUtilsConfig } from './l1_tx_utils/config.js';
27
26
  import type { ExtendedViemWalletClient } from './types.js';
28
27
 
29
28
  const logger = createLogger('ethereum:deploy_aztec_l1_contracts');
@@ -31,9 +30,9 @@ const logger = createLogger('ethereum:deploy_aztec_l1_contracts');
31
30
  const JSON_DEPLOY_RESULT_PREFIX = 'JSON DEPLOY RESULT:';
32
31
 
33
32
  /**
34
- * Runs a process with the given command, arguments, and environment.
35
- * If the process outputs a line starting with JSON_DEPLOY_RESULT_PREFIX,
36
- * the JSON is parsed and returned.
33
+ * Runs a process and parses JSON deploy results from stdout.
34
+ * Lines starting with JSON_DEPLOY_RESULT_PREFIX are parsed and returned.
35
+ * All other stdout goes to logger.info, stderr goes to logger.warn.
37
36
  */
38
37
  function runProcess<T>(
39
38
  command: string,
@@ -49,26 +48,41 @@ function runProcess<T>(
49
48
  });
50
49
 
51
50
  let result: T | undefined;
51
+ let parseError: Error | undefined;
52
+ let settled = false;
52
53
 
53
54
  readline.createInterface({ input: proc.stdout }).on('line', line => {
54
55
  const trimmedLine = line.trim();
55
56
  if (trimmedLine.startsWith(JSON_DEPLOY_RESULT_PREFIX)) {
56
57
  const jsonStr = trimmedLine.slice(JSON_DEPLOY_RESULT_PREFIX.length).trim();
57
- // TODO(AD): should this be a zod parse?
58
- result = JSON.parse(jsonStr);
58
+ try {
59
+ result = JSON.parse(jsonStr);
60
+ } catch {
61
+ parseError = new Error(`Failed to parse deploy result JSON: ${jsonStr.slice(0, 200)}`);
62
+ }
59
63
  } else {
60
64
  logger.info(line);
61
65
  }
62
66
  });
63
- readline.createInterface({ input: proc.stderr }).on('line', logger.error.bind(logger));
67
+ readline.createInterface({ input: proc.stderr }).on('line', logger.warn.bind(logger));
64
68
 
65
69
  proc.on('error', error => {
70
+ if (settled) {
71
+ return;
72
+ }
73
+ settled = true;
66
74
  reject(new Error(`Failed to spawn ${command}: ${error.message}`));
67
75
  });
68
76
 
69
77
  proc.on('close', code => {
78
+ if (settled) {
79
+ return;
80
+ }
81
+ settled = true;
70
82
  if (code !== 0) {
71
- reject(new Error(`${command} exited with code ${code}. See logs for details.\n`));
83
+ reject(new Error(`${command} exited with code ${code}`));
84
+ } else if (parseError) {
85
+ reject(parseError);
72
86
  } else {
73
87
  resolve(result);
74
88
  }
@@ -141,11 +155,14 @@ function cleanupDeployDir() {
141
155
  */
142
156
  export function prepareL1ContractsForDeployment(): string {
143
157
  if (preparedDeployDir && existsSync(preparedDeployDir)) {
158
+ logger.verbose(`Using cached deployment directory: ${preparedDeployDir}`);
144
159
  return preparedDeployDir;
145
160
  }
146
161
 
147
162
  const basePath = getL1ContractsPath();
163
+ logger.verbose(`Preparing L1 contracts from: ${basePath}`);
148
164
  const tempDir = mkdtempSync(join(tmpdir(), '.foundry-deploy-'));
165
+ logger.verbose(`Created temp directory for deployment: ${tempDir}`);
149
166
  preparedDeployDir = tempDir;
150
167
  process.on('exit', cleanupDeployDir);
151
168
 
@@ -157,13 +174,24 @@ export function prepareL1ContractsForDeployment(): string {
157
174
  cpSync(join(basePath, 'src'), join(tempDir, 'src'), copyOpts);
158
175
  cpSync(join(basePath, 'script'), join(tempDir, 'script'), copyOpts);
159
176
  cpSync(join(basePath, 'generated'), join(tempDir, 'generated'), copyOpts);
160
- cpSync(join(basePath, 'foundry.toml'), join(tempDir, 'foundry.toml'));
177
+ // Kludge: copy test/ to appease forge cache which references test/shouting.t.sol
178
+ cpSync(join(basePath, 'test'), join(tempDir, 'test'), copyOpts);
161
179
  cpSync(join(basePath, 'foundry.lock'), join(tempDir, 'foundry.lock'));
162
- for (const file of readdirSync(basePath)) {
163
- if (file.startsWith('solc-')) {
164
- cpSync(join(basePath, file), join(tempDir, file));
165
- }
180
+
181
+ // Update foundry.toml to use absolute path to solc binary (avoids copying to noexec tmpfs)
182
+ const foundryTomlPath = join(basePath, 'foundry.toml');
183
+ let foundryToml = readFileSync(foundryTomlPath, 'utf-8');
184
+ const solcPathMatch = foundryToml.match(/solc\s*=\s*"\.\/solc-([^"]+)"/);
185
+ // Did we find a hardcoded solc path that we need to make absolute?
186
+ // This code path happens in CI currently as we bundle solc there to avoid race conditions when
187
+ // downloading solc.
188
+ if (solcPathMatch) {
189
+ const solcVersion = solcPathMatch[1];
190
+ const absoluteSolcPath = join(basePath, `solc-${solcVersion}`);
191
+ foundryToml = foundryToml.replace(/solc\s*=\s*"\.\/solc-[^"]+"/, `solc = "${absoluteSolcPath}"`);
192
+ logger.verbose(`Updated solc path in foundry.toml to: ${absoluteSolcPath}`);
166
193
  }
194
+ writeFileSync(join(tempDir, 'foundry.toml'), foundryToml);
167
195
 
168
196
  mkdirSync(join(tempDir, 'broadcast'));
169
197
  return tempDir;
@@ -307,11 +335,8 @@ export async function deployAztecL1Contracts(
307
335
  );
308
336
  }
309
337
 
310
- // From heuristic testing. More caused issues with anvil.
311
- const MAGIC_ANVIL_BATCH_SIZE = 12;
312
- // Anvil seems to stall with unbounded batch size. Otherwise no max batch size is desirable.
338
+ const scriptPath = join(getL1ContractsPath(), 'scripts', 'forge_broadcast.js');
313
339
  const forgeArgs = [
314
- 'script',
315
340
  FORGE_SCRIPT,
316
341
  '--sig',
317
342
  'run()',
@@ -319,8 +344,6 @@ export async function deployAztecL1Contracts(
319
344
  privateKey,
320
345
  '--rpc-url',
321
346
  rpcUrl,
322
- '--broadcast',
323
- ...(chainId === foundry.id ? ['--batch-size', MAGIC_ANVIL_BATCH_SIZE.toString()] : []),
324
347
  ...(shouldVerify ? ['--verify'] : []),
325
348
  ];
326
349
  const forgeEnv = {
@@ -329,7 +352,12 @@ export async function deployAztecL1Contracts(
329
352
  FOUNDRY_PROFILE: chainId === mainnet.id ? 'production' : undefined,
330
353
  ...getDeployAztecL1ContractsEnvVars(args),
331
354
  };
332
- const result = await runProcess<ForgeL1ContractsDeployResult>('forge', forgeArgs, forgeEnv, l1ContractsPath);
355
+ const result = await runProcess<ForgeL1ContractsDeployResult>(
356
+ process.execPath,
357
+ [scriptPath, ...forgeArgs],
358
+ forgeEnv,
359
+ l1ContractsPath,
360
+ );
333
361
  if (!result) {
334
362
  throw new Error('Forge script did not output deployment result');
335
363
  }
@@ -462,7 +490,25 @@ export type VerificationRecord = {
462
490
  libraries: VerificationLibraryEntry[];
463
491
  };
464
492
 
465
- export interface DeployAztecL1ContractsArgs extends Omit<L1ContractsConfig, keyof L1TxUtilsConfig> {
493
+ export interface DeployAztecL1ContractsArgs
494
+ extends Omit<
495
+ L1ContractsConfig,
496
+ | 'gasLimitBufferPercentage'
497
+ | 'maxGwei'
498
+ | 'maxBlobGwei'
499
+ | 'priorityFeeBumpPercentage'
500
+ | 'priorityFeeRetryBumpPercentage'
501
+ | 'minimumPriorityFeePerGas'
502
+ | 'maxSpeedUpAttempts'
503
+ | 'checkIntervalMs'
504
+ | 'stallTimeMs'
505
+ | 'txTimeoutMs'
506
+ | 'cancelTxOnTimeout'
507
+ | 'txCancellationFinalTimeoutMs'
508
+ | 'txUnseenConsideredDroppedMs'
509
+ | 'enableDelayer'
510
+ | 'txDelayerMaxInclusionTimeIntoSlot'
511
+ > {
466
512
  /** The vk tree root. */
467
513
  vkTreeRoot: Fr;
468
514
  /** The hash of the protocol contracts. */
@@ -497,6 +543,7 @@ export function getDeployAztecL1ContractsEnvVars(args: DeployAztecL1ContractsArg
497
543
  AZTEC_EJECTION_THRESHOLD: args.ejectionThreshold?.toString(),
498
544
  AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE: args.governanceProposerRoundSize?.toString(),
499
545
  AZTEC_GOVERNANCE_PROPOSER_QUORUM: args.governanceProposerQuorum?.toString(),
546
+ AZTEC_GOVERNANCE_VOTING_DURATION: args.governanceVotingDuration?.toString(),
500
547
  ZKPASSPORT_DOMAIN: args.zkPassportArgs?.zkPassportDomain,
501
548
  ZKPASSPORT_SCOPE: args.zkPassportArgs?.zkPassportScope,
502
549
  } as const;
@@ -531,11 +578,13 @@ export function getDeployRollupForUpgradeEnvVars(
531
578
  AZTEC_PROOF_SUBMISSION_EPOCHS: args.aztecProofSubmissionEpochs.toString(),
532
579
  AZTEC_LOCAL_EJECTION_THRESHOLD: args.localEjectionThreshold.toString(),
533
580
  AZTEC_SLASHING_LIFETIME_IN_ROUNDS: args.slashingLifetimeInRounds.toString(),
581
+ AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS: args.slashingExecutionDelayInRounds.toString(),
534
582
  AZTEC_SLASHING_VETOER: args.slashingVetoer.toString(),
535
583
  AZTEC_SLASHING_DISABLE_DURATION: args.slashingDisableDuration.toString(),
536
584
  AZTEC_MANA_TARGET: args.manaTarget.toString(),
537
585
  AZTEC_EXIT_DELAY_SECONDS: args.exitDelaySeconds.toString(),
538
586
  AZTEC_PROVING_COST_PER_MANA: args.provingCostPerMana.toString(),
587
+ AZTEC_INITIAL_ETH_PER_FEE_ASSET: args.initialEthPerFeeAsset.toString(),
539
588
  AZTEC_SLASHER_FLAVOR: args.slasherFlavor,
540
589
  AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS: args.slashingRoundSizeInEpochs.toString(),
541
590
  AZTEC_SLASHING_QUORUM: args.slashingQuorum?.toString(),
@@ -569,17 +618,8 @@ export const deployRollupForUpgrade = async (
569
618
  const FORGE_SCRIPT = 'script/deploy/DeployRollupForUpgrade.s.sol';
570
619
  await maybeForgeForceProductionBuild(l1ContractsPath, FORGE_SCRIPT, chainId);
571
620
 
572
- const forgeArgs = [
573
- 'script',
574
- FORGE_SCRIPT,
575
- '--sig',
576
- 'run()',
577
- '--private-key',
578
- privateKey,
579
- '--rpc-url',
580
- rpcUrl,
581
- '--broadcast',
582
- ];
621
+ const scriptPath = join(getL1ContractsPath(), 'scripts', 'forge_broadcast.js');
622
+ const forgeArgs = [FORGE_SCRIPT, '--sig', 'run()', '--private-key', privateKey, '--rpc-url', rpcUrl];
583
623
  const forgeEnv = {
584
624
  FOUNDRY_PROFILE: chainId === mainnet.id ? 'production' : undefined,
585
625
  // Env vars required by l1-contracts/script/deploy/RollupConfiguration.sol.
@@ -588,7 +628,12 @@ export const deployRollupForUpgrade = async (
588
628
  ...getDeployRollupForUpgradeEnvVars(args),
589
629
  };
590
630
 
591
- const result = await runProcess<ForgeRollupUpgradeResult>('forge', forgeArgs, forgeEnv, l1ContractsPath);
631
+ const result = await runProcess<ForgeRollupUpgradeResult>(
632
+ process.execPath,
633
+ [scriptPath, ...forgeArgs],
634
+ forgeEnv,
635
+ l1ContractsPath,
636
+ );
592
637
  if (!result) {
593
638
  throw new Error('Forge script did not output deployment result');
594
639
  }
@@ -24,7 +24,7 @@ import {
24
24
  } from './deploy_aztec_l1_contracts.js';
25
25
  import { RegisterNewRollupVersionPayloadArtifact } from './l1_artifacts.js';
26
26
  import { type L1TxUtilsConfig, getL1TxUtilsConfigEnvVars } from './l1_tx_utils/config.js';
27
- import { createL1TxUtilsFromViemWallet } from './l1_tx_utils/factory.js';
27
+ import { createL1TxUtils } from './l1_tx_utils/factory.js';
28
28
  import type { L1TxUtils } from './l1_tx_utils/l1_tx_utils.js';
29
29
  import type { GasPrice, L1TxConfig, L1TxRequest } from './l1_tx_utils/types.js';
30
30
  import type { ExtendedViemWalletClient } from './types.js';
@@ -46,7 +46,7 @@ export class L1Deployer {
46
46
  private createVerificationJson: boolean = false,
47
47
  ) {
48
48
  this.salt = maybeSalt ? padHex(numberToHex(maybeSalt), { size: 32 }) : undefined;
49
- this.l1TxUtils = createL1TxUtilsFromViemWallet(
49
+ this.l1TxUtils = createL1TxUtils(
50
50
  this.client,
51
51
  { logger: this.logger, dateProvider },
52
52
  { ...this.txUtilsConfig, debugMaxGasLimit: acceleratedTestDeployments },
@@ -179,7 +179,7 @@ export async function deployL1Contract(
179
179
 
180
180
  if (!l1TxUtils) {
181
181
  const config = getL1TxUtilsConfigEnvVars();
182
- l1TxUtils = createL1TxUtilsFromViemWallet(
182
+ l1TxUtils = createL1TxUtils(
183
183
  extendedClient,
184
184
  { logger },
185
185
  { ...config, debugMaxGasLimit: acceleratedTestDeployments },
@@ -0,0 +1,32 @@
1
+ // Auto-generated from spartan/environments/network-defaults.yml
2
+ // Do not edit manually - run yarn generate to regenerate
3
+
4
+ /** Default L1 contracts configuration values from network-defaults.yml */
5
+ export const l1ContractsDefaultEnv = {
6
+ ETHEREUM_SLOT_DURATION: 12,
7
+ AZTEC_SLOT_DURATION: 72,
8
+ AZTEC_EPOCH_DURATION: 32,
9
+ AZTEC_TARGET_COMMITTEE_SIZE: 48,
10
+ AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET: 2,
11
+ AZTEC_LAG_IN_EPOCHS_FOR_RANDAO: 2,
12
+ AZTEC_ACTIVATION_THRESHOLD: 100000000000000000000,
13
+ AZTEC_EJECTION_THRESHOLD: 50000000000000000000,
14
+ AZTEC_LOCAL_EJECTION_THRESHOLD: 98000000000000000000,
15
+ AZTEC_EXIT_DELAY_SECONDS: 172800,
16
+ AZTEC_INBOX_LAG: 1,
17
+ AZTEC_PROOF_SUBMISSION_EPOCHS: 1,
18
+ AZTEC_MANA_TARGET: 100000000,
19
+ AZTEC_PROVING_COST_PER_MANA: 100,
20
+ AZTEC_INITIAL_ETH_PER_FEE_ASSET: 10000000,
21
+ AZTEC_SLASHER_FLAVOR: 'tally',
22
+ AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS: 4,
23
+ AZTEC_SLASHING_LIFETIME_IN_ROUNDS: 5,
24
+ AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS: 0,
25
+ AZTEC_SLASHING_OFFSET_IN_ROUNDS: 2,
26
+ AZTEC_SLASHING_VETOER: '0x0000000000000000000000000000000000000000',
27
+ AZTEC_SLASHING_DISABLE_DURATION: 432000,
28
+ AZTEC_SLASH_AMOUNT_SMALL: 10000000000000000000,
29
+ AZTEC_SLASH_AMOUNT_MEDIUM: 20000000000000000000,
30
+ AZTEC_SLASH_AMOUNT_LARGE: 50000000000000000000,
31
+ AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE: 300,
32
+ } as const;