@aztec/ethereum 0.0.1-commit.96bb3f7 → 0.0.1-commit.a072138

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 (83) hide show
  1. package/dest/config.d.ts +15 -28
  2. package/dest/config.d.ts.map +1 -1
  3. package/dest/config.js +46 -55
  4. package/dest/contracts/empire_slashing_proposer.d.ts +1 -1
  5. package/dest/contracts/empire_slashing_proposer.d.ts.map +1 -1
  6. package/dest/contracts/empire_slashing_proposer.js +13 -15
  7. package/dest/contracts/fee_asset_handler.d.ts +1 -1
  8. package/dest/contracts/fee_asset_handler.d.ts.map +1 -1
  9. package/dest/contracts/fee_asset_handler.js +2 -0
  10. package/dest/contracts/governance.d.ts +3 -1
  11. package/dest/contracts/governance.d.ts.map +1 -1
  12. package/dest/contracts/governance.js +11 -1
  13. package/dest/contracts/governance_proposer.d.ts +1 -1
  14. package/dest/contracts/governance_proposer.d.ts.map +1 -1
  15. package/dest/contracts/governance_proposer.js +4 -1
  16. package/dest/contracts/inbox.d.ts +18 -1
  17. package/dest/contracts/inbox.d.ts.map +1 -1
  18. package/dest/contracts/inbox.js +32 -1
  19. package/dest/contracts/index.d.ts +2 -1
  20. package/dest/contracts/index.d.ts.map +1 -1
  21. package/dest/contracts/index.js +1 -0
  22. package/dest/contracts/log.d.ts +13 -0
  23. package/dest/contracts/log.d.ts.map +1 -0
  24. package/dest/contracts/log.js +1 -0
  25. package/dest/contracts/multicall.d.ts +1 -1
  26. package/dest/contracts/multicall.d.ts.map +1 -1
  27. package/dest/contracts/multicall.js +2 -1
  28. package/dest/contracts/rollup.d.ts +34 -3
  29. package/dest/contracts/rollup.d.ts.map +1 -1
  30. package/dest/contracts/rollup.js +71 -3
  31. package/dest/contracts/tally_slashing_proposer.d.ts +1 -1
  32. package/dest/contracts/tally_slashing_proposer.d.ts.map +1 -1
  33. package/dest/contracts/tally_slashing_proposer.js +8 -1
  34. package/dest/deploy_aztec_l1_contracts.d.ts +6 -1
  35. package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -1
  36. package/dest/deploy_aztec_l1_contracts.js +20 -7
  37. package/dest/generated/l1-contracts-defaults.d.ts +30 -0
  38. package/dest/generated/l1-contracts-defaults.d.ts.map +1 -0
  39. package/dest/generated/l1-contracts-defaults.js +30 -0
  40. package/dest/l1_artifacts.d.ts +1394 -471
  41. package/dest/l1_artifacts.d.ts.map +1 -1
  42. package/dest/l1_tx_utils/constants.d.ts +1 -1
  43. package/dest/l1_tx_utils/constants.js +2 -2
  44. package/dest/l1_tx_utils/l1_tx_utils.js +6 -6
  45. package/dest/l1_tx_utils/readonly_l1_tx_utils.js +3 -3
  46. package/dest/publisher_manager.d.ts +3 -2
  47. package/dest/publisher_manager.d.ts.map +1 -1
  48. package/dest/publisher_manager.js +2 -2
  49. package/dest/queries.d.ts +2 -2
  50. package/dest/queries.d.ts.map +1 -1
  51. package/dest/queries.js +4 -1
  52. package/dest/test/eth_cheat_codes.d.ts +13 -1
  53. package/dest/test/eth_cheat_codes.d.ts.map +1 -1
  54. package/dest/test/rollup_cheat_codes.d.ts +4 -2
  55. package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
  56. package/dest/test/rollup_cheat_codes.js +10 -1
  57. package/dest/test/start_anvil.js +1 -1
  58. package/dest/utils.d.ts +2 -1
  59. package/dest/utils.d.ts.map +1 -1
  60. package/dest/utils.js +46 -0
  61. package/package.json +8 -7
  62. package/src/config.ts +55 -54
  63. package/src/contracts/README.md +157 -0
  64. package/src/contracts/empire_slashing_proposer.ts +16 -27
  65. package/src/contracts/fee_asset_handler.ts +2 -0
  66. package/src/contracts/governance.ts +10 -1
  67. package/src/contracts/governance_proposer.ts +4 -1
  68. package/src/contracts/inbox.ts +48 -1
  69. package/src/contracts/index.ts +1 -0
  70. package/src/contracts/log.ts +13 -0
  71. package/src/contracts/multicall.ts +5 -2
  72. package/src/contracts/rollup.ts +100 -4
  73. package/src/contracts/tally_slashing_proposer.ts +5 -1
  74. package/src/deploy_aztec_l1_contracts.ts +21 -7
  75. package/src/generated/l1-contracts-defaults.ts +32 -0
  76. package/src/l1_tx_utils/constants.ts +2 -2
  77. package/src/l1_tx_utils/l1_tx_utils.ts +6 -6
  78. package/src/l1_tx_utils/readonly_l1_tx_utils.ts +3 -3
  79. package/src/publisher_manager.ts +4 -2
  80. package/src/queries.ts +3 -1
  81. package/src/test/rollup_cheat_codes.ts +11 -2
  82. package/src/test/start_anvil.ts +1 -1
  83. package/src/utils.ts +53 -0
@@ -6,7 +6,6 @@ import { EmpireSlashingProposerAbi } from '@aztec/l1-artifacts/EmpireSlashingPro
6
6
 
7
7
  import EventEmitter from 'events';
8
8
  import {
9
- type EncodeFunctionDataParameters,
10
9
  type GetContractReturnType,
11
10
  type Hex,
12
11
  type Log,
@@ -100,6 +99,7 @@ export class EmpireSlashingProposerContract extends EventEmitter implements IEmp
100
99
  public createSignalRequest(payload: Hex): L1TxRequest {
101
100
  return {
102
101
  to: this.address.toString(),
102
+ abi: EmpireSlashingProposerAbi,
103
103
  data: encodeSignal(payload),
104
104
  };
105
105
  }
@@ -121,6 +121,7 @@ export class EmpireSlashingProposerContract extends EventEmitter implements IEmp
121
121
  );
122
122
  return {
123
123
  to: this.address.toString(),
124
+ abi: EmpireSlashingProposerAbi,
124
125
  data: encodeSignalWithSignature(payload, signature),
125
126
  };
126
127
  }
@@ -180,6 +181,7 @@ export class EmpireSlashingProposerContract extends EventEmitter implements IEmp
180
181
  public buildExecuteRoundRequest(round: bigint): L1TxRequest {
181
182
  return {
182
183
  to: this.address.toString(),
184
+ abi: EmpireSlashingProposerAbi,
183
185
  data: encodeFunctionData({
184
186
  abi: EmpireSlashingProposerAbi,
185
187
  functionName: 'submitRoundWinner',
@@ -222,24 +224,13 @@ export class EmpireSlashingProposerContract extends EventEmitter implements IEmp
222
224
  if (typeof round === 'number') {
223
225
  round = BigInt(round);
224
226
  }
225
- const args: EncodeFunctionDataParameters<typeof EmpireSlashingProposerAbi, 'submitRoundWinner'> = {
226
- abi: EmpireSlashingProposerAbi,
227
- functionName: 'submitRoundWinner',
228
- args: [round],
229
- };
230
- const data = encodeFunctionData(args);
227
+ const request = this.buildExecuteRoundRequest(round);
231
228
  const response = await txUtils
232
- .sendAndMonitorTransaction(
233
- {
234
- to: this.address.toString(),
235
- data,
236
- },
237
- {
238
- // Gas estimation is way off for this, likely because we are creating the contract/selector to call
239
- // for the actual slashing dynamically.
240
- gasLimitBufferPercentage: 50, // +50% gas
241
- },
242
- )
229
+ .sendAndMonitorTransaction(request, {
230
+ // Gas estimation is way off for this, likely because we are creating the contract/selector to call
231
+ // for the actual slashing dynamically.
232
+ gasLimitBufferPercentage: 50, // +50% gas
233
+ })
243
234
  .catch(err => {
244
235
  if (err instanceof FormattedViemError && err.message.includes('ProposalAlreadyExecuted')) {
245
236
  throw new ProposalAlreadyExecutedError(round);
@@ -248,15 +239,13 @@ export class EmpireSlashingProposerContract extends EventEmitter implements IEmp
248
239
  });
249
240
 
250
241
  if (response.receipt.status === 'reverted') {
251
- const error = await txUtils.tryGetErrorFromRevertedTx(
252
- data,
253
- {
254
- ...args,
255
- address: this.address.toString(),
256
- },
257
- undefined,
258
- [],
259
- );
242
+ const args = {
243
+ abi: EmpireSlashingProposerAbi,
244
+ functionName: 'submitRoundWinner' as const,
245
+ args: [round] as const,
246
+ address: this.address.toString(),
247
+ };
248
+ const error = await txUtils.tryGetErrorFromRevertedTx(request.data!, args, undefined, []);
260
249
  if (error?.includes('ProposalAlreadyExecuted')) {
261
250
  throw new ProposalAlreadyExecutedError(round);
262
251
  }
@@ -43,6 +43,7 @@ export class FeeAssetHandlerContract {
43
43
  }
44
44
  return txUtils.sendAndMonitorTransaction({
45
45
  to: this.address.toString(),
46
+ abi: FeeAssetHandlerAbi,
46
47
  data: encodeFunctionData({
47
48
  abi: FeeAssetHandlerAbi,
48
49
  functionName: 'mint',
@@ -54,6 +55,7 @@ export class FeeAssetHandlerContract {
54
55
  public setMintAmount(txUtils: L1TxUtils, amount: bigint) {
55
56
  return txUtils.sendAndMonitorTransaction({
56
57
  to: this.address.toString(),
58
+ abi: FeeAssetHandlerAbi,
57
59
  data: encodeFunctionData({
58
60
  abi: FeeAssetHandlerAbi,
59
61
  functionName: 'setMintAmount',
@@ -174,6 +174,13 @@ export class GovernanceContract extends ReadOnlyGovernanceContract {
174
174
  return this.governanceContract.read.powerAt([this.client.account.address, now.timestamp]);
175
175
  }
176
176
 
177
+ /** Returns the user's voting power for a specific proposal, checked at pendingThrough timestamp. */
178
+ public async getPowerForProposal(proposalId: bigint): Promise<bigint> {
179
+ const proposal = await this.getProposal(proposalId);
180
+ const pendingThrough = proposal.creation + proposal.config.votingDelay;
181
+ return this.governanceContract.read.powerAt([this.client.account.address, pendingThrough]);
182
+ }
183
+
177
184
  public async vote({
178
185
  proposalId,
179
186
  voteAmount,
@@ -190,7 +197,7 @@ export class GovernanceContract extends ReadOnlyGovernanceContract {
190
197
  const l1TxUtils = createL1TxUtilsFromViemWallet(this.client, { logger });
191
198
  const retryDelaySeconds = 12;
192
199
 
193
- voteAmount = voteAmount ?? (await this.getPower());
200
+ voteAmount = voteAmount ?? (await this.getPowerForProposal(proposalId));
194
201
 
195
202
  let success = false;
196
203
  for (let i = 0; i < retries; i++) {
@@ -204,6 +211,7 @@ export class GovernanceContract extends ReadOnlyGovernanceContract {
204
211
 
205
212
  const { receipt } = await l1TxUtils.sendAndMonitorTransaction({
206
213
  to: this.governanceContract.address,
214
+ abi: GovernanceAbi,
207
215
  data: encodedVoteData,
208
216
  });
209
217
 
@@ -258,6 +266,7 @@ export class GovernanceContract extends ReadOnlyGovernanceContract {
258
266
 
259
267
  const { receipt } = await l1TxUtils.sendAndMonitorTransaction({
260
268
  to: this.governanceContract.address,
269
+ abi: GovernanceAbi,
261
270
  data: encodedExecuteData,
262
271
  });
263
272
 
@@ -83,6 +83,7 @@ export class GovernanceProposerContract implements IEmpireBase {
83
83
  public createSignalRequest(payload: Hex): L1TxRequest {
84
84
  return {
85
85
  to: this.address.toString(),
86
+ abi: GovernanceProposerAbi,
86
87
  data: encodeSignal(payload),
87
88
  };
88
89
  }
@@ -104,6 +105,7 @@ export class GovernanceProposerContract implements IEmpireBase {
104
105
  );
105
106
  return {
106
107
  to: this.address.toString(),
108
+ abi: GovernanceProposerAbi,
107
109
  data: encodeSignalWithSignature(payload, signature),
108
110
  };
109
111
  }
@@ -117,8 +119,9 @@ export class GovernanceProposerContract implements IEmpireBase {
117
119
  }> {
118
120
  const { receipt } = await l1TxUtils.sendAndMonitorTransaction({
119
121
  to: this.address.toString(),
122
+ abi: GovernanceProposerAbi,
120
123
  data: encodeFunctionData({
121
- abi: this.proposer.abi,
124
+ abi: GovernanceProposerAbi,
122
125
  functionName: 'submitRoundWinner',
123
126
  args: [round],
124
127
  }),
@@ -1,4 +1,6 @@
1
- import { Buffer16 } from '@aztec/foundation/buffer';
1
+ import { CheckpointNumber } from '@aztec/foundation/branded-types';
2
+ import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
3
+ import { Fr } from '@aztec/foundation/curves/bn254';
2
4
  import { EthAddress } from '@aztec/foundation/eth-address';
3
5
  import { InboxAbi } from '@aztec/l1-artifacts/InboxAbi';
4
6
 
@@ -8,8 +10,20 @@ import { getPublicClient } from '../client.js';
8
10
  import type { DeployAztecL1ContractsReturnType } from '../deploy_aztec_l1_contracts.js';
9
11
  import type { L1ReaderConfig } from '../l1_reader.js';
10
12
  import type { ViemClient } from '../types.js';
13
+ import type { L1EventLog } from './log.js';
11
14
  import { checkBlockTag } from './utils.js';
12
15
 
16
+ /** Arguments for the MessageSent event. */
17
+ export type MessageSentArgs = {
18
+ index: bigint;
19
+ leaf: Fr;
20
+ checkpointNumber: CheckpointNumber;
21
+ rollingHash: Buffer16;
22
+ };
23
+
24
+ /** Log type for MessageSent events. */
25
+ export type MessageSentLog = L1EventLog<MessageSentArgs>;
26
+
13
27
  export class InboxContract {
14
28
  private readonly inbox: GetContractReturnType<typeof InboxAbi, ViemClient>;
15
29
 
@@ -59,6 +73,39 @@ export class InboxContract {
59
73
  treeInProgress: state.inProgress,
60
74
  };
61
75
  }
76
+
77
+ /** Fetches MessageSent events within the given block range. */
78
+ async getMessageSentEvents(fromBlock: bigint, toBlock: bigint): Promise<MessageSentLog[]> {
79
+ const logs = await this.inbox.getEvents.MessageSent({}, { fromBlock, toBlock });
80
+ return logs
81
+ .filter(log => log.blockNumber! >= fromBlock && log.blockNumber! <= toBlock)
82
+ .map(log => this.mapMessageSentLog(log));
83
+ }
84
+
85
+ /** Fetches MessageSent events for a specific message hash within the given block range. */
86
+ async getMessageSentEventByHash(hash: Hex, fromBlock: bigint, toBlock: bigint): Promise<MessageSentLog[]> {
87
+ const logs = await this.inbox.getEvents.MessageSent({ hash }, { fromBlock, toBlock });
88
+ return logs.map(log => this.mapMessageSentLog(log));
89
+ }
90
+
91
+ private mapMessageSentLog(log: {
92
+ blockNumber: bigint | null;
93
+ blockHash: `0x${string}` | null;
94
+ transactionHash: `0x${string}` | null;
95
+ args: { index?: bigint; hash?: `0x${string}`; checkpointNumber?: bigint; rollingHash?: `0x${string}` };
96
+ }): MessageSentLog {
97
+ return {
98
+ l1BlockNumber: log.blockNumber!,
99
+ l1BlockHash: Buffer32.fromString(log.blockHash!),
100
+ l1TransactionHash: log.transactionHash!,
101
+ args: {
102
+ index: log.args.index!,
103
+ leaf: Fr.fromString(log.args.hash!),
104
+ checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber!),
105
+ rollingHash: Buffer16.fromString(log.args.rollingHash!),
106
+ },
107
+ };
108
+ }
62
109
  }
63
110
 
64
111
  export type InboxContractState = {
@@ -6,6 +6,7 @@ export * from './governance.js';
6
6
  export * from './governance_proposer.js';
7
7
  export * from './gse.js';
8
8
  export * from './inbox.js';
9
+ export * from './log.js';
9
10
  export * from './multicall.js';
10
11
  export * from './outbox.js';
11
12
  export * from './registry.js';
@@ -0,0 +1,13 @@
1
+ import type { Buffer32 } from '@aztec/foundation/buffer';
2
+
3
+ /** Base L1 event log with common fields. */
4
+ export type L1EventLog<T> = {
5
+ /** L1 block number where the event was emitted. */
6
+ l1BlockNumber: bigint;
7
+ /** L1 block hash. */
8
+ l1BlockHash: Buffer32;
9
+ /** L1 transaction hash that emitted the event. */
10
+ l1TransactionHash: `0x${string}`;
11
+ /** Event-specific arguments. */
12
+ args: T;
13
+ };
@@ -34,10 +34,13 @@ export class Multicall3 {
34
34
  };
35
35
 
36
36
  const encodedForwarderData = encodeFunctionData(forwarderFunctionData);
37
-
38
37
  try {
39
38
  const { receipt, state } = await l1TxUtils.sendAndMonitorTransaction(
40
- { to: MULTI_CALL_3_ADDRESS, data: encodedForwarderData },
39
+ {
40
+ to: MULTI_CALL_3_ADDRESS,
41
+ data: encodedForwarderData,
42
+ abi: multicall3Abi,
43
+ },
41
44
  gasConfig,
42
45
  blobConfig,
43
46
  );
@@ -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
  };
@@ -185,10 +188,28 @@ export type RollupStatusResponse = {
185
188
  archiveOfMyCheckpoint: Fr;
186
189
  };
187
190
 
191
+ /** Arguments for the CheckpointProposed event. */
192
+ export type CheckpointProposedArgs = {
193
+ checkpointNumber: CheckpointNumber;
194
+ archive: Fr;
195
+ versionedBlobHashes: Buffer[];
196
+ /** Hash of attestations. Undefined for older events (backwards compatibility). */
197
+ attestationsHash?: Buffer32;
198
+ /** Digest of the payload. Undefined for older events (backwards compatibility). */
199
+ payloadDigest?: Buffer32;
200
+ };
201
+
202
+ /** Log type for CheckpointProposed events. */
203
+ export type CheckpointProposedLog = L1EventLog<CheckpointProposedArgs>;
204
+
188
205
  export class RollupContract {
189
206
  private readonly rollup: GetContractReturnType<typeof RollupAbi, ViemClient>;
190
207
 
191
208
  private static cachedStfStorageSlot: Hex | undefined;
209
+ private cachedEscapeHatch?: {
210
+ address: EthAddress;
211
+ contract: GetContractReturnType<typeof EscapeHatchAbi, ViemClient>;
212
+ };
192
213
 
193
214
  static get checkBlobStorageSlot(): bigint {
194
215
  const asString = RollupStorage.find(storage => storage.label === 'checkBlob')?.slot;
@@ -391,6 +412,58 @@ export class RollupContract {
391
412
  return EthAddress.fromString(await this.rollup.read.getSlasher());
392
413
  }
393
414
 
415
+ /**
416
+ * Returns the configured escape hatch contract address, or zero if disabled.
417
+ */
418
+ async getEscapeHatchAddress(): Promise<EthAddress> {
419
+ return EthAddress.fromString(await this.rollup.read.getEscapeHatch());
420
+ }
421
+
422
+ private async getEscapeHatchContract(): Promise<
423
+ GetContractReturnType<typeof EscapeHatchAbi, ViemClient> | undefined
424
+ > {
425
+ const escapeHatchAddress = await this.getEscapeHatchAddress();
426
+ if (escapeHatchAddress.isZero()) {
427
+ return undefined;
428
+ }
429
+
430
+ // Cache the viem contract wrapper since it will be used frequently.
431
+ if (!this.cachedEscapeHatch || !this.cachedEscapeHatch.address.equals(escapeHatchAddress)) {
432
+ this.cachedEscapeHatch = {
433
+ address: escapeHatchAddress,
434
+ contract: getContract({
435
+ address: escapeHatchAddress.toString(),
436
+ abi: EscapeHatchAbi,
437
+ client: this.client,
438
+ }),
439
+ };
440
+ }
441
+
442
+ return this.cachedEscapeHatch.contract;
443
+ }
444
+
445
+ /**
446
+ * Returns whether the escape hatch is open for the given epoch.
447
+ * If escape hatch is not configured, returns false.
448
+ *
449
+ * This function is intentionally defensive: any failure to query the escape hatch
450
+ * (RPC issues, transient errors, etc.) is treated as "closed" to avoid callers
451
+ * needing to sprinkle try/catch everywhere.
452
+ */
453
+ async isEscapeHatchOpen(epoch: EpochNumber): Promise<boolean> {
454
+ try {
455
+ const escapeHatch = await this.getEscapeHatchContract();
456
+ if (!escapeHatch) {
457
+ return false;
458
+ }
459
+
460
+ const [isOpen] = await escapeHatch.read.isHatchOpen([BigInt(epoch)]);
461
+ return isOpen;
462
+ } catch {
463
+ return false;
464
+ }
465
+ }
466
+
394
467
  /**
395
468
  * Returns a SlasherContract instance for interacting with the slasher contract.
396
469
  */
@@ -442,8 +515,8 @@ export class RollupContract {
442
515
  };
443
516
  }
444
517
 
445
- getFeeAssetPerEth(): Promise<bigint> {
446
- return this.rollup.read.getFeeAssetPerEth();
518
+ getEthPerFeeAsset(): Promise<bigint> {
519
+ return this.rollup.read.getEthPerFeeAsset();
447
520
  }
448
521
 
449
522
  async getCommitteeAt(timestamp: bigint): Promise<EthAddress[] | undefined> {
@@ -528,7 +601,7 @@ export class RollupContract {
528
601
  feeHeader: {
529
602
  excessMana: result.feeHeader.excessMana,
530
603
  manaUsed: result.feeHeader.manaUsed,
531
- feeAssetPriceNumerator: result.feeHeader.feeAssetPriceNumerator,
604
+ ethPerFeeAsset: result.feeHeader.ethPerFeeAsset,
532
605
  congestionCost: result.feeHeader.congestionCost,
533
606
  proverCost: result.feeHeader.proverCost,
534
607
  },
@@ -732,6 +805,7 @@ export class RollupContract {
732
805
  ): L1TxRequest {
733
806
  return {
734
807
  to: this.address,
808
+ abi: RollupAbi,
735
809
  data: encodeFunctionData({
736
810
  abi: RollupAbi,
737
811
  functionName: 'invalidateBadAttestation',
@@ -753,6 +827,7 @@ export class RollupContract {
753
827
  ): L1TxRequest {
754
828
  return {
755
829
  to: this.address,
830
+ abi: RollupAbi,
756
831
  data: encodeFunctionData({
757
832
  abi: RollupAbi,
758
833
  functionName: 'invalidateInsufficientAttestations',
@@ -886,6 +961,7 @@ export class RollupContract {
886
961
  setupEpoch(l1TxUtils: L1TxUtils) {
887
962
  return l1TxUtils.sendAndMonitorTransaction({
888
963
  to: this.address,
964
+ abi: RollupAbi,
889
965
  data: encodeFunctionData({
890
966
  abi: RollupAbi,
891
967
  functionName: 'setupEpoch',
@@ -897,6 +973,7 @@ export class RollupContract {
897
973
  vote(l1TxUtils: L1TxUtils, proposalId: bigint) {
898
974
  return l1TxUtils.sendAndMonitorTransaction({
899
975
  to: this.address,
976
+ abi: RollupAbi,
900
977
  data: encodeFunctionData({
901
978
  abi: RollupAbi,
902
979
  functionName: 'vote',
@@ -965,4 +1042,23 @@ export class RollupContract {
965
1042
  },
966
1043
  );
967
1044
  }
1045
+
1046
+ /** Fetches CheckpointProposed events within the given block range. */
1047
+ async getCheckpointProposedEvents(fromBlock: bigint, toBlock: bigint): Promise<CheckpointProposedLog[]> {
1048
+ const logs = await this.rollup.getEvents.CheckpointProposed({}, { fromBlock, toBlock });
1049
+ return logs
1050
+ .filter(log => log.blockNumber! >= fromBlock && log.blockNumber! <= toBlock)
1051
+ .map(log => ({
1052
+ l1BlockNumber: log.blockNumber!,
1053
+ l1BlockHash: Buffer32.fromString(log.blockHash!),
1054
+ l1TransactionHash: log.transactionHash!,
1055
+ args: {
1056
+ checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber!),
1057
+ archive: Fr.fromString(log.args.archive!),
1058
+ versionedBlobHashes: log.args.versionedBlobHashes!.map(h => Buffer.from(h.slice(2), 'hex')),
1059
+ attestationsHash: log.args.attestationsHash ? Buffer32.fromString(log.args.attestationsHash) : undefined,
1060
+ payloadDigest: log.args.payloadDigest ? Buffer32.fromString(log.args.payloadDigest) : undefined,
1061
+ },
1062
+ }));
1063
+ }
968
1064
  }
@@ -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,7 +10,7 @@ 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';
@@ -141,11 +141,14 @@ function cleanupDeployDir() {
141
141
  */
142
142
  export function prepareL1ContractsForDeployment(): string {
143
143
  if (preparedDeployDir && existsSync(preparedDeployDir)) {
144
+ logger.verbose(`Using cached deployment directory: ${preparedDeployDir}`);
144
145
  return preparedDeployDir;
145
146
  }
146
147
 
147
148
  const basePath = getL1ContractsPath();
149
+ logger.verbose(`Preparing L1 contracts from: ${basePath}`);
148
150
  const tempDir = mkdtempSync(join(tmpdir(), '.foundry-deploy-'));
151
+ logger.verbose(`Created temp directory for deployment: ${tempDir}`);
149
152
  preparedDeployDir = tempDir;
150
153
  process.on('exit', cleanupDeployDir);
151
154
 
@@ -157,13 +160,21 @@ export function prepareL1ContractsForDeployment(): string {
157
160
  cpSync(join(basePath, 'src'), join(tempDir, 'src'), copyOpts);
158
161
  cpSync(join(basePath, 'script'), join(tempDir, 'script'), copyOpts);
159
162
  cpSync(join(basePath, 'generated'), join(tempDir, 'generated'), copyOpts);
160
- cpSync(join(basePath, 'foundry.toml'), join(tempDir, 'foundry.toml'));
163
+ // Kludge: copy test/ to appease forge cache which references test/shouting.t.sol
164
+ cpSync(join(basePath, 'test'), join(tempDir, 'test'), copyOpts);
161
165
  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
- }
166
+
167
+ // Update foundry.toml to use absolute path to solc binary (avoids copying to noexec tmpfs)
168
+ const foundryTomlPath = join(basePath, 'foundry.toml');
169
+ let foundryToml = readFileSync(foundryTomlPath, 'utf-8');
170
+ const solcPathMatch = foundryToml.match(/solc\s*=\s*"\.\/solc-([^"]+)"/);
171
+ if (solcPathMatch) {
172
+ const solcVersion = solcPathMatch[1];
173
+ const absoluteSolcPath = join(basePath, `solc-${solcVersion}`);
174
+ foundryToml = foundryToml.replace(/solc\s*=\s*"\.\/solc-[^"]+"/, `solc = "${absoluteSolcPath}"`);
175
+ logger.verbose(`Updated solc path in foundry.toml to: ${absoluteSolcPath}`);
166
176
  }
177
+ writeFileSync(join(tempDir, 'foundry.toml'), foundryToml);
167
178
 
168
179
  mkdirSync(join(tempDir, 'broadcast'));
169
180
  return tempDir;
@@ -308,7 +319,7 @@ export async function deployAztecL1Contracts(
308
319
  }
309
320
 
310
321
  // From heuristic testing. More caused issues with anvil.
311
- const MAGIC_ANVIL_BATCH_SIZE = 12;
322
+ const MAGIC_ANVIL_BATCH_SIZE = 8;
312
323
  // Anvil seems to stall with unbounded batch size. Otherwise no max batch size is desirable.
313
324
  const forgeArgs = [
314
325
  'script',
@@ -497,6 +508,7 @@ export function getDeployAztecL1ContractsEnvVars(args: DeployAztecL1ContractsArg
497
508
  AZTEC_EJECTION_THRESHOLD: args.ejectionThreshold?.toString(),
498
509
  AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE: args.governanceProposerRoundSize?.toString(),
499
510
  AZTEC_GOVERNANCE_PROPOSER_QUORUM: args.governanceProposerQuorum?.toString(),
511
+ AZTEC_GOVERNANCE_VOTING_DURATION: args.governanceVotingDuration?.toString(),
500
512
  ZKPASSPORT_DOMAIN: args.zkPassportArgs?.zkPassportDomain,
501
513
  ZKPASSPORT_SCOPE: args.zkPassportArgs?.zkPassportScope,
502
514
  } as const;
@@ -531,11 +543,13 @@ export function getDeployRollupForUpgradeEnvVars(
531
543
  AZTEC_PROOF_SUBMISSION_EPOCHS: args.aztecProofSubmissionEpochs.toString(),
532
544
  AZTEC_LOCAL_EJECTION_THRESHOLD: args.localEjectionThreshold.toString(),
533
545
  AZTEC_SLASHING_LIFETIME_IN_ROUNDS: args.slashingLifetimeInRounds.toString(),
546
+ AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS: args.slashingExecutionDelayInRounds.toString(),
534
547
  AZTEC_SLASHING_VETOER: args.slashingVetoer.toString(),
535
548
  AZTEC_SLASHING_DISABLE_DURATION: args.slashingDisableDuration.toString(),
536
549
  AZTEC_MANA_TARGET: args.manaTarget.toString(),
537
550
  AZTEC_EXIT_DELAY_SECONDS: args.exitDelaySeconds.toString(),
538
551
  AZTEC_PROVING_COST_PER_MANA: args.provingCostPerMana.toString(),
552
+ AZTEC_INITIAL_ETH_PER_FEE_ASSET: args.initialEthPerFeeAsset.toString(),
539
553
  AZTEC_SLASHER_FLAVOR: args.slasherFlavor,
540
554
  AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS: args.slashingRoundSizeInEpochs.toString(),
541
555
  AZTEC_SLASHING_QUORUM: args.slashingQuorum?.toString(),
@@ -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: 36,
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;
@@ -3,8 +3,8 @@
3
3
  // 1_000_000_000_000_000_000 Wei = 1 ETH
4
4
  export const WEI_CONST = 1_000_000_000n;
5
5
 
6
- // @note using this large gas limit to avoid the issue of `gas limit too low` when estimating gas in reth
7
- export const LARGE_GAS_LIMIT = 12_000_000n;
6
+ // EIP-7825: protocol-level cap on tx gas limit (2^24). Clients reject above this.
7
+ export const MAX_L1_TX_LIMIT = 16_777_216n;
8
8
 
9
9
  // setting a minimum bump percentage to 10% due to geth's implementation
10
10
  // https://github.com/ethereum/go-ethereum/blob/e3d61e6db028c412f74bc4d4c7e117a9e29d0de0/core/txpool/legacypool/list.go#L298