@aztec/end-to-end 0.0.1-commit.2448fdb → 0.0.1-commit.2606882

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 (172) hide show
  1. package/dest/bench/client_flows/benchmark.d.ts +15 -1
  2. package/dest/bench/client_flows/benchmark.d.ts.map +1 -1
  3. package/dest/bench/client_flows/benchmark.js +17 -0
  4. package/dest/bench/client_flows/client_flows_benchmark.d.ts +2 -2
  5. package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -1
  6. package/dest/bench/client_flows/client_flows_benchmark.js +25 -35
  7. package/dest/bench/utils.d.ts +1 -1
  8. package/dest/bench/utils.d.ts.map +1 -1
  9. package/dest/bench/utils.js +2 -0
  10. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +3 -3
  11. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts.map +1 -1
  12. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.js +13 -4
  13. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts +15 -4
  14. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts.map +1 -1
  15. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.js +39 -7
  16. package/dest/e2e_deploy_contract/deploy_test.d.ts +3 -3
  17. package/dest/e2e_deploy_contract/deploy_test.d.ts.map +1 -1
  18. package/dest/e2e_deploy_contract/deploy_test.js +2 -1
  19. package/dest/e2e_epochs/epochs_test.d.ts +23 -2
  20. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  21. package/dest/e2e_epochs/epochs_test.js +83 -12
  22. package/dest/e2e_fees/fees_test.d.ts +5 -2
  23. package/dest/e2e_fees/fees_test.d.ts.map +1 -1
  24. package/dest/e2e_fees/fees_test.js +31 -5
  25. package/dest/e2e_nested_contract/nested_contract_test.d.ts +3 -3
  26. package/dest/e2e_nested_contract/nested_contract_test.d.ts.map +1 -1
  27. package/dest/e2e_nested_contract/nested_contract_test.js +2 -1
  28. package/dest/e2e_p2p/inactivity_slash_test.js +3 -3
  29. package/dest/e2e_p2p/p2p_network.d.ts +11 -10
  30. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  31. package/dest/e2e_p2p/p2p_network.js +47 -28
  32. package/dest/e2e_p2p/reqresp/utils.d.ts +1 -1
  33. package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -1
  34. package/dest/e2e_p2p/reqresp/utils.js +42 -13
  35. package/dest/e2e_p2p/shared.d.ts +23 -26
  36. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  37. package/dest/e2e_p2p/shared.js +62 -80
  38. package/dest/e2e_token_contract/token_contract_test.d.ts +3 -3
  39. package/dest/e2e_token_contract/token_contract_test.d.ts.map +1 -1
  40. package/dest/e2e_token_contract/token_contract_test.js +4 -2
  41. package/dest/fixtures/e2e_prover_test.d.ts +6 -5
  42. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
  43. package/dest/fixtures/e2e_prover_test.js +9 -13
  44. package/dest/fixtures/elu_monitor.d.ts +21 -0
  45. package/dest/fixtures/elu_monitor.d.ts.map +1 -0
  46. package/dest/fixtures/elu_monitor.js +102 -0
  47. package/dest/fixtures/fixtures.d.ts +70 -1
  48. package/dest/fixtures/fixtures.d.ts.map +1 -1
  49. package/dest/fixtures/fixtures.js +65 -0
  50. package/dest/fixtures/get_bb_config.d.ts +1 -1
  51. package/dest/fixtures/get_bb_config.d.ts.map +1 -1
  52. package/dest/fixtures/get_bb_config.js +5 -5
  53. package/dest/fixtures/ha_setup.d.ts +2 -2
  54. package/dest/fixtures/ha_setup.d.ts.map +1 -1
  55. package/dest/fixtures/ha_setup.js +1 -1
  56. package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts +25 -0
  57. package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts.map +1 -0
  58. package/dest/fixtures/schnorr_hardcoded_account_contract.js +37 -0
  59. package/dest/fixtures/setup.d.ts +44 -10
  60. package/dest/fixtures/setup.d.ts.map +1 -1
  61. package/dest/fixtures/setup.js +145 -19
  62. package/dest/fixtures/setup_p2p_test.d.ts +10 -6
  63. package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
  64. package/dest/fixtures/setup_p2p_test.js +8 -8
  65. package/dest/fixtures/token_utils.d.ts +1 -1
  66. package/dest/fixtures/token_utils.d.ts.map +1 -1
  67. package/dest/fixtures/token_utils.js +2 -5
  68. package/dest/fixtures/utils.d.ts +2 -2
  69. package/dest/fixtures/utils.d.ts.map +1 -1
  70. package/dest/fixtures/utils.js +1 -1
  71. package/dest/install_legacy_contracts.d.cts +1 -1
  72. package/dest/install_legacy_contracts.d.cts.map +1 -1
  73. package/dest/legacy-jest-resolver.d.cts +1 -1
  74. package/dest/legacy-jest-resolver.d.cts.map +1 -1
  75. package/dest/shared/cross_chain_test_harness.d.ts +4 -2
  76. package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
  77. package/dest/shared/cross_chain_test_harness.js +9 -5
  78. package/dest/shared/gas_portal_test_harness.d.ts +8 -5
  79. package/dest/shared/gas_portal_test_harness.d.ts.map +1 -1
  80. package/dest/shared/gas_portal_test_harness.js +17 -8
  81. package/dest/shared/jest_setup.js +41 -1
  82. package/dest/shared/submit-transactions.d.ts +1 -1
  83. package/dest/shared/submit-transactions.d.ts.map +1 -1
  84. package/dest/shared/uniswap_l1_l2.d.ts +1 -1
  85. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  86. package/dest/shared/uniswap_l1_l2.js +50 -32
  87. package/dest/shared/wait_for_l1_to_l2_message.d.ts +13 -0
  88. package/dest/shared/wait_for_l1_to_l2_message.d.ts.map +1 -0
  89. package/dest/shared/wait_for_l1_to_l2_message.js +10 -0
  90. package/dest/simulators/lending_simulator.d.ts +10 -3
  91. package/dest/simulators/lending_simulator.d.ts.map +1 -1
  92. package/dest/simulators/lending_simulator.js +23 -11
  93. package/dest/simulators/token_simulator.js +1 -1
  94. package/dest/spartan/setup_test_wallets.d.ts +1 -1
  95. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  96. package/dest/spartan/setup_test_wallets.js +67 -43
  97. package/dest/spartan/tx_metrics.d.ts +18 -4
  98. package/dest/spartan/tx_metrics.d.ts.map +1 -1
  99. package/dest/spartan/tx_metrics.js +74 -21
  100. package/dest/spartan/utils/config.d.ts +10 -30
  101. package/dest/spartan/utils/config.d.ts.map +1 -1
  102. package/dest/spartan/utils/config.js +3 -1
  103. package/dest/spartan/utils/index.d.ts +2 -1
  104. package/dest/spartan/utils/index.d.ts.map +1 -1
  105. package/dest/spartan/utils/index.js +2 -0
  106. package/dest/spartan/utils/nodes.d.ts +4 -5
  107. package/dest/spartan/utils/nodes.d.ts.map +1 -1
  108. package/dest/spartan/utils/nodes.js +11 -11
  109. package/dest/spartan/utils/pod_logs.d.ts +25 -0
  110. package/dest/spartan/utils/pod_logs.d.ts.map +1 -0
  111. package/dest/spartan/utils/pod_logs.js +74 -0
  112. package/dest/test-wallet/test_wallet.d.ts +3 -2
  113. package/dest/test-wallet/test_wallet.d.ts.map +1 -1
  114. package/dest/test-wallet/test_wallet.js +52 -28
  115. package/dest/test-wallet/utils.d.ts +3 -3
  116. package/dest/test-wallet/utils.d.ts.map +1 -1
  117. package/dest/test-wallet/utils.js +2 -7
  118. package/dest/test-wallet/wallet_worker_script.js +7 -2
  119. package/dest/test-wallet/worker_wallet.d.ts +2 -1
  120. package/dest/test-wallet/worker_wallet.d.ts.map +1 -1
  121. package/dest/test-wallet/worker_wallet.js +6 -2
  122. package/dest/test-wallet/worker_wallet_schema.d.ts +110 -224
  123. package/dest/test-wallet/worker_wallet_schema.d.ts.map +1 -1
  124. package/dest/test-wallet/worker_wallet_schema.js +14 -2
  125. package/package.json +48 -46
  126. package/src/bench/client_flows/benchmark.ts +19 -0
  127. package/src/bench/client_flows/client_flows_benchmark.ts +62 -51
  128. package/src/bench/utils.ts +2 -1
  129. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +21 -4
  130. package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +49 -11
  131. package/src/e2e_deploy_contract/deploy_test.ts +3 -2
  132. package/src/e2e_epochs/epochs_test.ts +85 -9
  133. package/src/e2e_fees/fees_test.ts +37 -4
  134. package/src/e2e_nested_contract/nested_contract_test.ts +3 -1
  135. package/src/e2e_p2p/inactivity_slash_test.ts +3 -3
  136. package/src/e2e_p2p/p2p_network.ts +58 -40
  137. package/src/e2e_p2p/reqresp/utils.ts +51 -12
  138. package/src/e2e_p2p/shared.ts +60 -113
  139. package/src/e2e_token_contract/token_contract_test.ts +12 -2
  140. package/src/fixtures/dumps/epoch_proof_result.json +1 -1
  141. package/src/fixtures/e2e_prover_test.ts +15 -18
  142. package/src/fixtures/elu_monitor.ts +126 -0
  143. package/src/fixtures/fixtures.ts +83 -0
  144. package/src/fixtures/get_bb_config.ts +7 -6
  145. package/src/fixtures/ha_setup.ts +4 -2
  146. package/src/fixtures/schnorr_hardcoded_account_contract.ts +49 -0
  147. package/src/fixtures/setup.ts +175 -24
  148. package/src/fixtures/setup_p2p_test.ts +13 -9
  149. package/src/fixtures/token_utils.ts +1 -4
  150. package/src/fixtures/utils.ts +2 -0
  151. package/src/guides/up_quick_start.sh +0 -2
  152. package/src/install_legacy_contracts.cjs +9 -5
  153. package/src/legacy-jest-resolver.cjs +15 -4
  154. package/src/shared/cross_chain_test_harness.ts +14 -4
  155. package/src/shared/gas_portal_test_harness.ts +20 -10
  156. package/src/shared/jest_setup.ts +51 -1
  157. package/src/shared/submit-transactions.ts +1 -4
  158. package/src/shared/uniswap_l1_l2.ts +84 -40
  159. package/src/shared/wait_for_l1_to_l2_message.ts +23 -0
  160. package/src/simulators/lending_simulator.ts +27 -13
  161. package/src/simulators/token_simulator.ts +1 -1
  162. package/src/spartan/setup_test_wallets.ts +65 -40
  163. package/src/spartan/tx_metrics.ts +82 -24
  164. package/src/spartan/utils/config.ts +2 -0
  165. package/src/spartan/utils/index.ts +3 -0
  166. package/src/spartan/utils/nodes.ts +17 -12
  167. package/src/spartan/utils/pod_logs.ts +99 -0
  168. package/src/test-wallet/test_wallet.ts +49 -24
  169. package/src/test-wallet/utils.ts +3 -7
  170. package/src/test-wallet/wallet_worker_script.ts +5 -2
  171. package/src/test-wallet/worker_wallet.ts +7 -3
  172. package/src/test-wallet/worker_wallet_schema.ts +2 -2
@@ -7,6 +7,8 @@ import {
7
7
  BatchCall,
8
8
  type ContractFunctionInteraction,
9
9
  type ContractMethod,
10
+ type DeployOptions,
11
+ type InteractionWaitOptions,
10
12
  getContractClassFromArtifact,
11
13
  waitForProven,
12
14
  } from '@aztec/aztec.js/contracts';
@@ -15,7 +17,7 @@ import { Fr } from '@aztec/aztec.js/fields';
15
17
  import { type Logger, createLogger } from '@aztec/aztec.js/log';
16
18
  import type { AztecNode } from '@aztec/aztec.js/node';
17
19
  import type { Wallet } from '@aztec/aztec.js/wallet';
18
- import { AnvilTestWatcher, CheatCodes } from '@aztec/aztec/testing';
20
+ import { AnvilTestWatcher, type AnvilTestWatcherOpts, CheatCodes } from '@aztec/aztec/testing';
19
21
  import { SPONSORED_FPC_SALT } from '@aztec/constants';
20
22
  import { isAnvilTestChain } from '@aztec/ethereum/chain';
21
23
  import { createExtendedL1Client } from '@aztec/ethereum/client';
@@ -30,7 +32,8 @@ import {
30
32
  deployAztecL1Contracts,
31
33
  } from '@aztec/ethereum/deploy-aztec-l1-contracts';
32
34
  import type { Delayer } from '@aztec/ethereum/l1-tx-utils';
33
- import { type Anvil, EthCheatCodes, EthCheatCodesWithState, startAnvil } from '@aztec/ethereum/test';
35
+ import { EthCheatCodes, EthCheatCodesWithState, startAnvil } from '@aztec/ethereum/test';
36
+ import type { Anvil } from '@aztec/ethereum/test';
34
37
  import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
35
38
  import { SecretValue } from '@aztec/foundation/config';
36
39
  import { randomBytes } from '@aztec/foundation/crypto/random';
@@ -45,12 +48,17 @@ import type { P2PClientDeps } from '@aztec/p2p';
45
48
  import { MockGossipSubNetwork, getMockPubSubP2PServiceFactory } from '@aztec/p2p/test-helpers';
46
49
  import { protocolContractsHash } from '@aztec/protocol-contracts';
47
50
  import type { ProverNodeConfig } from '@aztec/prover-node';
48
- import { type PXEConfig, getPXEConfig } from '@aztec/pxe/server';
51
+ import { type PXEConfig, type PXECreationOptions, getPXEConfig } from '@aztec/pxe/server';
49
52
  import type { SequencerClient } from '@aztec/sequencer-client';
53
+ import { AuthRegistryArtifact, getStandardAuthRegistry } from '@aztec/standard-contracts/auth-registry';
54
+ import { HandshakeRegistryArtifact, getStandardHandshakeRegistry } from '@aztec/standard-contracts/handshake-registry';
55
+ import { PublicChecksArtifact, getStandardPublicChecks } from '@aztec/standard-contracts/public-checks';
56
+ import { ARTIFACT_VERSION_BEFORE_INJECTION } from '@aztec/stdlib/abi';
50
57
  import { type ContractInstanceWithAddress, getContractInstanceFromInstantiationParams } from '@aztec/stdlib/contract';
51
58
  import type { AztecNodeAdmin, AztecNodeDebug } from '@aztec/stdlib/interfaces/client';
52
59
  import { tryStop } from '@aztec/stdlib/interfaces/server';
53
60
  import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
61
+ import type { GenesisData } from '@aztec/stdlib/world-state';
54
62
  import {
55
63
  type TelemetryClient,
56
64
  type TelemetryClientConfig,
@@ -177,8 +185,11 @@ export type SetupOptions = {
177
185
  proverNodeConfig?: Partial<ProverNodeConfig>;
178
186
  /** Whether to use a mock gossip sub network for p2p clients. */
179
187
  mockGossipSubNetwork?: boolean;
188
+ /** Whether to add simulated latency to the mock gossipsub network (in ms) */
189
+ mockGossipSubNetworkLatency?: number;
180
190
  /** Whether to disable the anvil test watcher (can still be manually started) */
181
191
  disableAnvilTestWatcher?: boolean;
192
+ anvilTestWatcherOpts?: AnvilTestWatcherOpts;
182
193
  /** Whether to enable anvil automine during deployment of L1 contracts (consider defaulting this to true). */
183
194
  automineL1Setup?: boolean;
184
195
  /** How many accounts to seed and unlock in anvil. */
@@ -200,8 +211,16 @@ export type SetupOptions = {
200
211
  skipAccountDeployment?: boolean;
201
212
  /** L1 contracts deployment arguments. */
202
213
  l1ContractsArgs?: Partial<DeployAztecL1ContractsArgs>;
203
- /** Wallet minimum fee padding multiplier (defaults to 0.5, which is 50% padding). */
214
+ /** Wallet minimum fee padding multiplier */
204
215
  walletMinFeePadding?: number;
216
+ /** Whether the initial node should be a lightweight RPC-only node (no sequencer, no validator).
217
+ * Use for tests that create their own validator nodes and don't need the initial sequencer. */
218
+ skipInitialSequencer?: boolean;
219
+ /** Whether to swap the production Sequencer for the minimal AutomineSequencer.
220
+ * Use only for single-sequencer non-block-building tests. See AUTOMINE_E2E_OPTS in `fixtures.ts`. */
221
+ useAutomineSequencer?: boolean;
222
+ /** Options forwarded to PXE creation (e.g. execution hooks). */
223
+ pxeCreationOptions?: PXECreationOptions;
205
224
  } & Partial<AztecNodeConfig>;
206
225
 
207
226
  /** Context for an end-to-end test as returned by the `setup` function */
@@ -248,8 +267,8 @@ export type EndToEndContext = {
248
267
  sequencerDelayer: Delayer | undefined;
249
268
  /** Delayer for prover node L1 txs (only when enableDelayer and startProverNode are true). */
250
269
  proverDelayer: Delayer | undefined;
251
- /** Prefilled public data used for setting up nodes. */
252
- prefilledPublicData: PublicDataTreeLeaf[] | undefined;
270
+ /** Genesis data used for setting up nodes. */
271
+ genesis: GenesisData | undefined;
253
272
  /** ACVM config (only set if running locally). */
254
273
  acvmConfig: Awaited<ReturnType<typeof getACVMConfig>>;
255
274
  /** BB config (only set if running locally). */
@@ -260,6 +279,32 @@ export type EndToEndContext = {
260
279
  teardown: () => Promise<void>;
261
280
  };
262
281
 
282
+ /**
283
+ * When CONTRACT_ARTIFACTS_VERSION is set (backwards compatibility testing), asserts that the loaded artifact's
284
+ * aztecVersion matches the expected version. This is a sanity check verifying that the legacy artifact resolver
285
+ * actually swapped in the correct version.
286
+ */
287
+ function assertContractArtifactsVersion() {
288
+ const expected = process.env.CONTRACT_ARTIFACTS_VERSION;
289
+ if (!expected) {
290
+ return;
291
+ }
292
+ const { aztecVersion } = SponsoredFPCContract.artifact;
293
+ // TODO(F-557): Remove this bypass once pre-version artifacts are no longer tested.
294
+ if (aztecVersion === ARTIFACT_VERSION_BEFORE_INJECTION) {
295
+ createLogger('e2e:setup').info(
296
+ `Skipping artifact version check: artifact predates version injection (CONTRACT_ARTIFACTS_VERSION=${expected})`,
297
+ );
298
+ return;
299
+ }
300
+ if (aztecVersion !== expected) {
301
+ throw new Error(
302
+ `Artifact version mismatch: expected ${expected} but got ${aztecVersion}. ` +
303
+ `The legacy artifact resolver may not have swapped in the correct version.`,
304
+ );
305
+ }
306
+ }
307
+
263
308
  /**
264
309
  * Sets up the environment for the end-to-end tests.
265
310
  * @param numberOfAccounts - The number of new accounts to be created once the PXE is initiated.
@@ -272,10 +317,11 @@ export async function setup(
272
317
  pxeOpts: Partial<PXEConfig> = {},
273
318
  chain: Chain = foundry,
274
319
  ): Promise<EndToEndContext> {
320
+ assertContractArtifactsVersion();
275
321
  let anvil: Anvil | undefined;
276
322
  try {
277
323
  opts.aztecTargetCommitteeSize ??= 0;
278
- opts.slasherFlavor ??= 'none';
324
+ opts.slasherEnabled ??= false;
279
325
 
280
326
  const config: AztecNodeConfig & SetupOptions = { ...getConfigEnvVars(), ...opts };
281
327
  // use initialValidators for the node config
@@ -374,10 +420,12 @@ export async function setup(
374
420
  addressesToFund.push(sponsoredFPCAddress);
375
421
  }
376
422
 
377
- const { genesisArchiveRoot, prefilledPublicData, fundingNeeded } = await getGenesisValues(
423
+ const genesisTimestamp = BigInt(Math.floor(Date.now() / 1000));
424
+ const { genesisArchiveRoot, genesis, fundingNeeded } = await getGenesisValues(
378
425
  addressesToFund,
379
426
  opts.initialAccountFeeJuice,
380
427
  opts.genesisPublicData,
428
+ genesisTimestamp,
381
429
  );
382
430
 
383
431
  const wasAutomining = await ethCheatCodes.isAutoMining();
@@ -412,9 +460,27 @@ export async function setup(
412
460
  },
413
461
  );
414
462
 
415
- config.l1Contracts = deployL1ContractsValues.l1ContractAddresses;
463
+ Object.assign(config, deployL1ContractsValues.l1ContractAddresses);
416
464
  config.rollupVersion = deployL1ContractsValues.rollupVersion;
417
465
 
466
+ // Propagate L1-contracts-config overrides back to the node config so the archiver's
467
+ // `l1Constants` (and any other node-side consumer) agrees with what was actually deployed.
468
+ // Without this, a per-test override like `aztecEpochDuration: 4` lands on the rollup contract
469
+ // but the node config keeps the default (32), so `archiver.isEpochComplete(0)` computes
470
+ // `endSlot=31` and `EpochTestSettler`/`EpochMonitor` never fires — letting the
471
+ // `aztecProofSubmissionEpochs` window expire mid-test and prune the pending chain.
472
+ // Skip undefined values: callers (e.g. `P2PNetworkTest`) sometimes build `l1ContractsArgs`
473
+ // by spreading a partial `AztecNodeConfig`, which leaves unset fields (notably `dataDirectory`)
474
+ // as `undefined`. A blind Object.assign would then clobber the temp `dataDirectory` set earlier
475
+ // in this function and crash `setupSharedBlobStorage`.
476
+ if (opts.l1ContractsArgs) {
477
+ for (const [key, value] of Object.entries(opts.l1ContractsArgs)) {
478
+ if (value !== undefined) {
479
+ (config as unknown as Record<string, unknown>)[key] = value;
480
+ }
481
+ }
482
+ }
483
+
418
484
  if (enableAutomine) {
419
485
  await ethCheatCodes.setAutomine(false);
420
486
  await ethCheatCodes.setIntervalMining(config.ethereumSlotDuration);
@@ -436,6 +502,7 @@ export async function setup(
436
502
  deployL1ContractsValues.l1ContractAddresses.rollupAddress,
437
503
  deployL1ContractsValues.l1Client,
438
504
  dateProvider,
505
+ opts.anvilTestWatcherOpts,
439
506
  );
440
507
  if (!opts.disableAnvilTestWatcher) {
441
508
  await watcher.start();
@@ -466,7 +533,7 @@ export async function setup(
466
533
  let p2pClientDeps: P2PClientDeps | undefined = undefined;
467
534
 
468
535
  if (opts.mockGossipSubNetwork) {
469
- mockGossipSubNetwork = new MockGossipSubNetwork();
536
+ mockGossipSubNetwork = new MockGossipSubNetwork(opts.mockGossipSubNetworkLatency);
470
537
  p2pClientDeps = { p2pServiceFactory: getMockPubSubP2PServiceFactory(mockGossipSubNetwork) };
471
538
  }
472
539
 
@@ -479,11 +546,17 @@ export async function setup(
479
546
  throw new Error('minTxsPerBlock is undefined in e2e test setup');
480
547
  }
481
548
 
482
- // Only set minTxsPerBlock=1 if we're going to deploy accounts and need reliable block inclusion
549
+ // Whether we're deploying accounts (and therefore need reliable block inclusion past genesis)
483
550
  const shouldDeployAccounts = numberOfAccounts > 0 && !opts.skipAccountDeployment;
484
551
  // Only set minTxsPerBlock=0 if we need an empty block (no accounts at all, not skipped deployment)
485
552
  const needsEmptyBlock = numberOfAccounts === 0 && !opts.skipAccountDeployment;
486
- config.minTxsPerBlock = shouldDeployAccounts ? 1 : needsEmptyBlock ? 0 : originalMinTxsPerBlock;
553
+ // Pipelining is always on: the proposer builds during slot N-1 for slot N. A tx submitted at
554
+ // slot N start arrives after that build, so forcing minTxsPerBlock=1 would stall the chain on
555
+ // alternating slots -- hence empty checkpoints are allowed (minTxsPerBlock=0) for account
556
+ // deployment. Automine is unaffected: its runBuild clamps mempool builds to
557
+ // Math.max(minTxsPerBlock ?? 1, 1) and still requires minValidTxs: 1.
558
+ const accountsDeployMinTxs = 0;
559
+ config.minTxsPerBlock = shouldDeployAccounts ? accountsDeployMinTxs : needsEmptyBlock ? 0 : originalMinTxsPerBlock;
487
560
 
488
561
  config.p2pEnabled = opts.mockGossipSubNetwork || config.p2pEnabled;
489
562
  config.p2pIp = opts.p2pIp ?? config.p2pIp ?? '127.0.0.1';
@@ -494,11 +567,22 @@ export async function setup(
494
567
  }
495
568
  }
496
569
 
570
+ // When skipInitialSequencer is set, the initial node is a lightweight RPC-only node.
571
+ // We apply these overrides to a copy so they don't leak into the returned config.
572
+ // Keep P2P enabled if mockGossipSubNetwork is used (needed for tx propagation to validators).
573
+ const initialNodeConfig = opts.skipInitialSequencer
574
+ ? {
575
+ ...config,
576
+ disableValidator: true,
577
+ ...(opts.mockGossipSubNetwork ? {} : { p2pEnabled: false, bootstrapNodes: [] as string[] }),
578
+ }
579
+ : config;
580
+
497
581
  const aztecNodeService = await withLoggerBindings({ actor: 'node-0' }, () =>
498
582
  AztecNodeService.createAndSync(
499
- config,
583
+ initialNodeConfig,
500
584
  { dateProvider, telemetry: telemetryClient, p2pClientDeps },
501
- { prefilledPublicData },
585
+ { genesis, dontStartSequencer: opts.skipInitialSequencer },
502
586
  ),
503
587
  );
504
588
  const sequencerClient = aztecNodeService.getSequencer();
@@ -523,7 +607,7 @@ export async function setup(
523
607
  dataDirectory: proverNodeDataDirectory,
524
608
  },
525
609
  { dateProvider, p2pClientDeps, telemetry: telemetryClient },
526
- { prefilledPublicData },
610
+ { genesis },
527
611
  ));
528
612
  }
529
613
 
@@ -535,13 +619,21 @@ export async function setup(
535
619
  pxeConfig.dataDirectory = path.join(directoryToCleanup, randomBytes(8).toString('hex'));
536
620
  // For tests we only want proving enabled if specifically requested
537
621
  pxeConfig.proverEnabled = !!pxeOpts.proverEnabled;
538
- const wallet = await TestWallet.create(aztecNodeService, pxeConfig, { loggerActorLabel: 'pxe-0' });
622
+ const wallet = await TestWallet.create(aztecNodeService, pxeConfig, {
623
+ loggerActorLabel: 'pxe-0',
624
+ ...opts.pxeCreationOptions,
625
+ });
539
626
 
540
627
  if (opts.walletMinFeePadding !== undefined) {
541
628
  wallet.setMinFeePadding(opts.walletMinFeePadding);
542
629
  }
543
630
 
544
- const cheatCodes = await CheatCodes.create(config.l1RpcUrls, aztecNodeService, dateProvider);
631
+ const cheatCodes = await CheatCodes.create(
632
+ config.l1RpcUrls,
633
+ aztecNodeService,
634
+ dateProvider,
635
+ aztecNodeService.getAutomineSequencer(),
636
+ );
545
637
 
546
638
  if (
547
639
  (opts.aztecTargetCommitteeSize && opts.aztecTargetCommitteeSize > 0) ||
@@ -559,15 +651,22 @@ export async function setup(
559
651
 
560
652
  let accounts: AztecAddress[] = [];
561
653
 
562
- if (shouldDeployAccounts) {
654
+ if (opts.skipInitialSequencer) {
655
+ logger.info('Sequencer not started on initial node, skipping block progression');
656
+ } else if (shouldDeployAccounts) {
563
657
  logger.info(
564
- `${numberOfAccounts} accounts are being deployed. Reliably progressing past genesis by setting minTxsPerBlock to 1 and waiting for the accounts to be deployed`,
658
+ `${numberOfAccounts} accounts are being deployed. Reliably progressing past genesis by waiting for the accounts to be deployed`,
565
659
  );
566
660
  const accountsData = initialFundedAccounts.slice(0, numberOfAccounts);
567
661
  const accountManagers = await deployFundedSchnorrAccounts(wallet, accountsData);
568
662
  accounts = accountManagers.map(accountManager => accountManager.address);
569
663
  } else if (needsEmptyBlock) {
570
664
  logger.info('No accounts are being deployed, waiting for an empty block 1 to be mined');
665
+ // AutomineSequencer only builds on tx arrival; explicitly request an empty block.
666
+ const automine = aztecNodeService.getAutomineSequencer();
667
+ if (automine) {
668
+ await automine.buildEmptyBlock();
669
+ }
571
670
  while ((await aztecNodeService.getBlockNumber()) === 0) {
572
671
  await sleep(2000);
573
672
  }
@@ -628,7 +727,7 @@ export async function setup(
628
727
  initialFundedAccounts,
629
728
  logger,
630
729
  mockGossipSubNetwork,
631
- prefilledPublicData,
730
+ genesis,
632
731
  proverNode,
633
732
  sequencerDelayer,
634
733
  proverDelayer,
@@ -708,7 +807,7 @@ export async function waitForProvenChain(node: AztecNode, targetBlock?: BlockNum
708
807
  targetBlock ??= await node.getBlockNumber();
709
808
 
710
809
  await retryUntil(
711
- async () => (await node.getProvenBlockNumber()) >= targetBlock,
810
+ async () => (await node.getBlockNumber('proven')) >= targetBlock,
712
811
  'proven chain status',
713
812
  timeoutSec,
714
813
  intervalSec,
@@ -728,7 +827,7 @@ export function createAndSyncProverNode(
728
827
  dateProvider: DateProvider;
729
828
  p2pClientDeps?: P2PClientDeps;
730
829
  },
731
- options: { prefilledPublicData: PublicDataTreeLeaf[]; dontStart?: boolean },
830
+ options: { genesis?: GenesisData; dontStart?: boolean },
732
831
  ): Promise<{ proverNode: AztecNodeService }> {
733
832
  return withLoggerBindings({ actor: 'prover-0' }, async () => {
734
833
  const proverNode = await AztecNodeService.createAndSync(
@@ -741,7 +840,7 @@ export function createAndSyncProverNode(
741
840
  proverPublisherPrivateKeys: [new SecretValue(proverNodePrivateKey)],
742
841
  },
743
842
  deps,
744
- { ...options, dontStartProverNode: options.dontStart },
843
+ { genesis: options.genesis, dontStartProverNode: options.dontStart },
745
844
  );
746
845
 
747
846
  if (!proverNode.getProverNode()) {
@@ -798,6 +897,57 @@ export async function expectMappingDelta<K, V extends number | bigint>(
798
897
  expect(diffs).toEqual(expectedDiffs);
799
898
  }
800
899
 
900
+ /**
901
+ * Registers the auth_registry contract class and publishes its standard instance if not already
902
+ * present, and registers the artifact with PXE. Publishing is required before exercising the public
903
+ * authwit path (which relies on the AVM's deployment-nullifier check); the PXE-side registration is
904
+ * required so revert messages from AuthRegistry calls can be enriched (otherwise assertion strings
905
+ * surface as generic "Assertion failed:" and tests that match on the real message fail).
906
+ */
907
+ export async function ensureAuthRegistryPublished(wallet: Wallet, from: AztecAddress) {
908
+ const { instance, contractClass } = await getStandardAuthRegistry();
909
+ if (!(await wallet.getContractClassMetadata(contractClass.id)).isContractClassPubliclyRegistered) {
910
+ await (await publishContractClass(wallet, AuthRegistryArtifact)).send({ from });
911
+ }
912
+ if (!(await wallet.getContractMetadata(instance.address)).isContractPublished) {
913
+ await publishInstance(wallet, instance).send({ from });
914
+ }
915
+ await wallet.registerContract(instance, AuthRegistryArtifact);
916
+ }
917
+
918
+ /**
919
+ * Registers the public_checks contract class and publishes its standard instance if not already
920
+ * present, and registers the artifact with PXE. Required for any contract that calls
921
+ * `privately_check_timestamp` / `privately_check_block_number` (which dispatch into the
922
+ * deployed PublicChecks contract via an enqueued public call).
923
+ */
924
+ export async function ensurePublicChecksPublished(wallet: Wallet, from: AztecAddress) {
925
+ const { instance, contractClass } = await getStandardPublicChecks();
926
+ if (!(await wallet.getContractClassMetadata(contractClass.id)).isContractClassPubliclyRegistered) {
927
+ await (await publishContractClass(wallet, PublicChecksArtifact)).send({ from });
928
+ }
929
+ if (!(await wallet.getContractMetadata(instance.address)).isContractPublished) {
930
+ await publishInstance(wallet, instance).send({ from });
931
+ }
932
+ await wallet.registerContract(instance, PublicChecksArtifact);
933
+ }
934
+
935
+ /**
936
+ * Registers the handshake_registry contract class and publishes its standard instance if not
937
+ * already present, and registers the artifact with PXE. Required for constrained-delivery flows
938
+ * that call into the HandshakeRegistry at its well-known address.
939
+ */
940
+ export async function ensureHandshakeRegistryPublished(wallet: Wallet, from: AztecAddress) {
941
+ const { instance, contractClass } = await getStandardHandshakeRegistry();
942
+ if (!(await wallet.getContractClassMetadata(contractClass.id)).isContractClassPubliclyRegistered) {
943
+ await (await publishContractClass(wallet, HandshakeRegistryArtifact)).send({ from });
944
+ }
945
+ if (!(await wallet.getContractMetadata(instance.address)).isContractPublished) {
946
+ await publishInstance(wallet, instance).send({ from });
947
+ }
948
+ await wallet.registerContract(instance, HandshakeRegistryArtifact);
949
+ }
950
+
801
951
  /**
802
952
  * Registers the contract class used for test accounts and publicly deploys the instances requested.
803
953
  * Use this when you need to make a public call to an account contract, such as for requesting a public authwit.
@@ -832,7 +982,7 @@ export async function ensureAccountContractsPublished(wallet: Wallet, accountsTo
832
982
  * Returns deployed account data that can be used by tests.
833
983
  */
834
984
  export const deployAccounts =
835
- (numberOfAccounts: number, logger: Logger) =>
985
+ (numberOfAccounts: number, logger: Logger, deployOptions?: Partial<DeployOptions<InteractionWaitOptions>>) =>
836
986
  async ({ wallet, initialFundedAccounts }: { wallet: TestWallet; initialFundedAccounts: InitialAccountData[] }) => {
837
987
  if (initialFundedAccounts.length < numberOfAccounts) {
838
988
  throw new Error(`Cannot deploy more than ${initialFundedAccounts.length} initial accounts.`);
@@ -851,6 +1001,7 @@ export const deployAccounts =
851
1001
  await deployMethod.send({
852
1002
  from: NO_FROM,
853
1003
  skipClassPublication: i !== 0, // Publish the contract class at most once.
1004
+ ...deployOptions,
854
1005
  });
855
1006
  }
856
1007
 
@@ -7,7 +7,7 @@ import { SecretValue } from '@aztec/foundation/config';
7
7
  import { withLoggerBindings } from '@aztec/foundation/log/server';
8
8
  import { bufferToHex } from '@aztec/foundation/string';
9
9
  import type { DateProvider } from '@aztec/foundation/timer';
10
- import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
10
+ import type { GenesisData } from '@aztec/stdlib/world-state';
11
11
 
12
12
  import getPort from 'get-port';
13
13
 
@@ -40,7 +40,7 @@ export async function createNodes(
40
40
  bootstrapNodeEnr: string,
41
41
  numNodes: number,
42
42
  bootNodePort: number,
43
- prefilledPublicData?: PublicDataTreeLeaf[],
43
+ genesis?: GenesisData,
44
44
  dataDirectory?: string,
45
45
  metricsPort?: number,
46
46
  indexOffset = 0,
@@ -65,7 +65,7 @@ export async function createNodes(
65
65
  port,
66
66
  bootstrapNodeEnr,
67
67
  validatorIndices,
68
- prefilledPublicData,
68
+ genesis,
69
69
  dataDir,
70
70
  metricsPort,
71
71
  );
@@ -88,6 +88,10 @@ export type CreateNodeConfig = AztecNodeConfig & {
88
88
  dontStartSequencer?: boolean;
89
89
  /** Override the private key (instead of deriving from addressIndex). */
90
90
  validatorPrivateKey?: `0x${string}`;
91
+ /** Corrupt only the block proposal at this indexWithinCheckpoint (testing only). */
92
+ invalidBlockProposalIndexWithinCheckpoint?: number;
93
+ /** Accept proposal gossip regardless of slot timing (testing only). */
94
+ skipProposalSlotValidation?: boolean;
91
95
  };
92
96
 
93
97
  /** Creates a P2P enabled instance of Aztec Node Service with a validator. */
@@ -97,7 +101,7 @@ export async function createNode(
97
101
  tcpPort: number,
98
102
  bootstrapNode: string | undefined,
99
103
  addressIndex: number | number[],
100
- prefilledPublicData?: PublicDataTreeLeaf[],
104
+ genesis?: GenesisData,
101
105
  dataDirectory?: string,
102
106
  metricsPort?: number,
103
107
  ) {
@@ -108,7 +112,7 @@ export async function createNode(
108
112
  return await AztecNodeService.createAndSync(
109
113
  validatorConfig,
110
114
  { telemetry, dateProvider },
111
- { prefilledPublicData, dontStartSequencer: config.dontStartSequencer },
115
+ { genesis, dontStartSequencer: config.dontStartSequencer },
112
116
  );
113
117
  });
114
118
  }
@@ -119,7 +123,7 @@ export async function createNonValidatorNode(
119
123
  dateProvider: DateProvider,
120
124
  tcpPort: number,
121
125
  bootstrapNode: string | undefined,
122
- prefilledPublicData?: PublicDataTreeLeaf[],
126
+ genesis?: GenesisData,
123
127
  dataDirectory?: string,
124
128
  metricsPort?: number,
125
129
  ) {
@@ -133,7 +137,7 @@ export async function createNonValidatorNode(
133
137
  sequencerPublisherPrivateKeys: [],
134
138
  };
135
139
  const telemetry = await getEndToEndTestTelemetryClient(metricsPort);
136
- return await AztecNodeService.createAndSync(config, { telemetry, dateProvider }, { prefilledPublicData });
140
+ return await AztecNodeService.createAndSync(config, { telemetry, dateProvider }, { genesis });
137
141
  });
138
142
  }
139
143
 
@@ -143,7 +147,7 @@ export async function createProverNode(
143
147
  bootstrapNode: string | undefined,
144
148
  addressIndex: number,
145
149
  deps: { dateProvider: DateProvider },
146
- prefilledPublicData?: PublicDataTreeLeaf[],
150
+ genesis?: GenesisData,
147
151
  dataDirectory?: string,
148
152
  metricsPort?: number,
149
153
  ): Promise<{ proverNode: AztecNodeService }> {
@@ -159,7 +163,7 @@ export async function createProverNode(
159
163
  { ...config, ...p2pConfig },
160
164
  { dataDirectory },
161
165
  { ...deps, telemetry },
162
- { prefilledPublicData: prefilledPublicData ?? [] },
166
+ { genesis },
163
167
  );
164
168
  });
165
169
  }
@@ -6,11 +6,8 @@ import { TokenContract } from '@aztec/noir-contracts.js/Token';
6
6
 
7
7
  export async function deployToken(wallet: Wallet, admin: AztecAddress, initialAdminBalance: bigint, logger: Logger) {
8
8
  logger.info(`Deploying Token contract...`);
9
- const {
10
- receipt: { contract, instance },
11
- } = await TokenContract.deploy(wallet, admin, 'TokenName', 'TokenSymbol', 18).send({
9
+ const { contract, instance } = await TokenContract.deploy(wallet, admin, 'TokenName', 'TokenSymbol', 18).send({
12
10
  from: admin,
13
- wait: { returnReceipt: true },
14
11
  });
15
12
 
16
13
  if (initialAdminBalance > 0n) {
@@ -9,6 +9,8 @@ export {
9
9
  createAndSyncProverNode,
10
10
  deployAccounts,
11
11
  ensureAccountContractsPublished,
12
+ ensureAuthRegistryPublished,
13
+ ensurePublicChecksPublished,
12
14
  expectMapping,
13
15
  expectMappingDelta,
14
16
  getBalancesFn,
@@ -18,10 +18,8 @@ aztec-wallet() {
18
18
 
19
19
  aztec-wallet import-test-accounts
20
20
 
21
- # docs:start:declare-accounts
22
21
  aztec-wallet create-account -a alice -f test0
23
22
  aztec-wallet create-account -a bob -f test0
24
- # docs:end:declare-accounts
25
23
 
26
24
  aztec-wallet bridge-fee-juice 1000000000000000000000 accounts:alice --mint --no-wait
27
25
 
@@ -37,9 +37,9 @@ function installLegacyContracts(version) {
37
37
  const cacheDir = cacheRoot(version);
38
38
  fs.mkdirSync(cacheDir, { recursive: true });
39
39
 
40
- // Seed a standalone package.json so `npm install --prefix` treats cacheDir as its own project.
41
- // Without this, npm walks up and finds the yarn-project workspace root, which breaks on
42
- // `workspace:` protocol deps and risks clobbering the monorepo's node_modules.
40
+ // Seed a standalone package.json so `npm install --prefix` treats cacheRoot as its own project. Without this, npm
41
+ // walks up and finds the yarn-project workspace root, which breaks on `workspace:` protocol deps and risks
42
+ // clobbering the monorepo's node_modules.
43
43
  const seed = path.join(cacheDir, 'package.json');
44
44
  if (!fs.existsSync(seed)) {
45
45
  fs.writeFileSync(seed, JSON.stringify({ name: 'legacy-contracts-cache', private: true }));
@@ -47,15 +47,19 @@ function installLegacyContracts(version) {
47
47
 
48
48
  const specs = REDIRECTED.map(pkg => `${pkg}@${version}`);
49
49
  process.stderr.write(`[legacy-contracts] installing ${specs.join(' ')} into ${cacheDir}\n`);
50
+ // --prefix: install into cacheRoot instead of cwd, so the cache is isolated from the monorepo.
50
51
  // --no-save: don't write the installed packages back to the seeded package.json.
51
- // --ignore-scripts: skip lifecycle scripts of the legacy packages and their transitive deps.
52
- // --legacy-peer-deps: tolerate peer-dependency mismatches between pinned legacy graph and current.
52
+ // --ignore-scripts: skip lifecycle scripts (preinstall/postinstall) of the legacy packages and their transitive
53
+ // deps; we only want the files on disk, not to run any build steps.
54
+ // --legacy-peer-deps: tolerate peer-dependency mismatches between the pinned legacy @aztec/* graph and whatever
55
+ // current versions npm would otherwise try to reconcile.
53
56
  execFileSync(
54
57
  'npm',
55
58
  ['install', '--prefix', cacheDir, '--no-save', '--ignore-scripts', '--legacy-peer-deps', ...specs],
56
59
  { stdio: 'inherit' },
57
60
  );
58
61
 
62
+ // Verify versions on disk match the requested version.
59
63
  for (const pkg of REDIRECTED) {
60
64
  const onDisk = JSON.parse(fs.readFileSync(pkgJsonPath(version, pkg), 'utf8')).version;
61
65
  if (onDisk !== version) {
@@ -11,6 +11,13 @@
11
11
  // Cache population lives in install_legacy_contracts.cjs — invoked lazily here for local dev, and eagerly
12
12
  // by bootstrap.sh ci-compat-e2e before hermetic test containers (which run with --net=none) launch.
13
13
  //
14
+ // Missing artifacts: legacy version directories are immutable, so an artifact missing from the cache means the
15
+ // contract was added after the pinned release — there's nothing to compat-test. Rather than failing or silently
16
+ // falling back to the workspace artifact (which would turn the compat run into a regular e2e run that always
17
+ // passes), we log the miss and exit the process cleanly with code 0. The test never runs, but the per-test CI
18
+ // log captures the explanatory line so the reason is auditable. This keeps the change scoped to this resolver,
19
+ // avoiding a new exit-code contract in the shared ci3 test runner.
20
+ //
14
21
  // Activated by env var; passthrough otherwise.
15
22
  /* eslint-disable @typescript-eslint/no-require-imports */
16
23
 
@@ -68,7 +75,7 @@ function legacyArtifactPath(resolved) {
68
75
  continue;
69
76
  }
70
77
  const basename = resolved.slice(idx + marker.length);
71
- return path.join(cacheRoot, 'node_modules', pkg, 'artifacts', basename);
78
+ return path.join(cacheDir, 'node_modules', pkg, 'artifacts', basename);
72
79
  }
73
80
  return null;
74
81
  }
@@ -88,10 +95,14 @@ module.exports = function legacyResolver(request, options) {
88
95
  return resolved;
89
96
  }
90
97
  if (!fs.existsSync(legacy)) {
91
- throw new Error(
92
- `[legacy-contracts] artifact ${path.basename(legacy)} not present in legacy cache @${version}; ` +
93
- `the contract may have been added after that release. Pin a newer CONTRACT_ARTIFACTS_VERSION or skip this test.`,
98
+ // Contract was added after this historical release, there is nothing to compat-test for it. Exit the process
99
+ // cleanly with code 0 so the test runner reports the run as passed.
100
+ fs.writeSync(
101
+ 2,
102
+ `[legacy-contracts][jest] artifact ${path.basename(legacy)} not in legacy cache @${version}; ` +
103
+ `assumed added after this release. No compat coverage applicable for this version, treating as passed.\n`,
94
104
  );
105
+ process.exit(0);
95
106
  }
96
107
  if (!seen.has(resolved)) {
97
108
  seen.add(resolved);
@@ -13,11 +13,11 @@ import type { AztecNode } from '@aztec/aztec.js/node';
13
13
  import type { SiblingPath } from '@aztec/aztec.js/trees';
14
14
  import type { TxReceipt } from '@aztec/aztec.js/tx';
15
15
  import type { Wallet } from '@aztec/aztec.js/wallet';
16
+ import { OutboxContract } from '@aztec/ethereum/contracts';
16
17
  import { deployL1Contract } from '@aztec/ethereum/deploy-l1-contract';
17
18
  import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
18
19
  import type { ExtendedViemWalletClient } from '@aztec/ethereum/types';
19
20
  import { EpochNumber } from '@aztec/foundation/branded-types';
20
- import { retryUntil } from '@aztec/foundation/retry';
21
21
  import { TestERC20Abi, TokenPortalAbi, TokenPortalBytecode } from '@aztec/l1-artifacts';
22
22
  import { TokenContract } from '@aztec/noir-contracts.js/Token';
23
23
  import { TokenBridgeContract } from '@aztec/noir-contracts.js/TokenBridge';
@@ -25,6 +25,7 @@ import { TokenBridgeContract } from '@aztec/noir-contracts.js/TokenBridge';
25
25
  import { type Hex, getContract } from 'viem';
26
26
 
27
27
  import { mintTokensToPrivate } from '../fixtures/token_utils.js';
28
+ import { waitForL1ToL2MessageSeen } from './wait_for_l1_to_l2_message.js';
28
29
 
29
30
  /**
30
31
  * Deploy L1 token and portal, initialize portal, deploy a non native l2 token contract, its L2 bridge contract and attach is to the portal.
@@ -166,6 +167,7 @@ export class CrossChainTestHarness {
166
167
 
167
168
  private readonly l1TokenManager: L1TokenManager;
168
169
  private readonly l1TokenPortalManager: L1TokenPortalManager;
170
+ public readonly outboxContract: OutboxContract;
169
171
 
170
172
  constructor(
171
173
  /** Aztec node instance. */
@@ -206,6 +208,7 @@ export class CrossChainTestHarness {
206
208
  this.logger,
207
209
  );
208
210
  this.l1TokenManager = this.l1TokenPortalManager.getTokenManager();
211
+ this.outboxContract = new OutboxContract(this.l1Client, this.l1ContractAddresses.outboxAddress);
209
212
  }
210
213
 
211
214
  async mintTokensOnL1(amount: bigint) {
@@ -319,10 +322,18 @@ export class CrossChainTestHarness {
319
322
  withdrawFundsFromBridgeOnL1(
320
323
  amount: bigint,
321
324
  epochNumber: EpochNumber,
325
+ numCheckpointsInEpoch: number,
322
326
  messageIndex: bigint,
323
327
  siblingPath: SiblingPath<number>,
324
328
  ) {
325
- return this.l1TokenPortalManager.withdrawFunds(amount, this.ethAccount, epochNumber, messageIndex, siblingPath);
329
+ return this.l1TokenPortalManager.withdrawFunds(
330
+ amount,
331
+ this.ethAccount,
332
+ epochNumber,
333
+ numCheckpointsInEpoch,
334
+ messageIndex,
335
+ siblingPath,
336
+ );
326
337
  }
327
338
 
328
339
  async transferToPrivateOnL2(shieldAmount: bigint) {
@@ -346,8 +357,7 @@ export class CrossChainTestHarness {
346
357
  */
347
358
  async makeMessageConsumable(msgHash: Fr | Hex) {
348
359
  const frMsgHash = typeof msgHash === 'string' ? Fr.fromHexString(msgHash) : msgHash;
349
- // We poll isL1ToL2MessageSynced endpoint until the message is available
350
- await retryUntil(async () => await this.aztecNode.isL1ToL2MessageSynced(frMsgHash), 'message sync', 10);
360
+ await waitForL1ToL2MessageSeen(this.aztecNode, frMsgHash, { timeoutSeconds: 10 });
351
361
 
352
362
  await this.mintTokensPublicOnL2(0n);
353
363
  await this.mintTokensPublicOnL2(0n);