@aztec/end-to-end 0.0.1-commit.96dac018d → 0.0.1-commit.9badcec54

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 (133) hide show
  1. package/README.md +27 -0
  2. package/dest/bench/client_flows/client_flows_benchmark.d.ts +1 -1
  3. package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -1
  4. package/dest/bench/client_flows/client_flows_benchmark.js +19 -26
  5. package/dest/bench/utils.d.ts +1 -1
  6. package/dest/bench/utils.d.ts.map +1 -1
  7. package/dest/bench/utils.js +6 -3
  8. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +3 -2
  9. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts.map +1 -1
  10. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.js +15 -15
  11. package/dest/e2e_epochs/epochs_test.d.ts +3 -1
  12. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  13. package/dest/e2e_epochs/epochs_test.js +8 -5
  14. package/dest/e2e_fees/fees_test.d.ts +1 -1
  15. package/dest/e2e_fees/fees_test.d.ts.map +1 -1
  16. package/dest/e2e_fees/fees_test.js +14 -7
  17. package/dest/e2e_nested_contract/nested_contract_test.d.ts +1 -1
  18. package/dest/e2e_nested_contract/nested_contract_test.d.ts.map +1 -1
  19. package/dest/e2e_nested_contract/nested_contract_test.js +4 -6
  20. package/dest/e2e_p2p/inactivity_slash_test.js +3 -3
  21. package/dest/e2e_p2p/p2p_network.d.ts +8 -9
  22. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  23. package/dest/e2e_p2p/p2p_network.js +33 -29
  24. package/dest/e2e_p2p/reqresp/utils.d.ts +1 -1
  25. package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -1
  26. package/dest/e2e_p2p/reqresp/utils.js +16 -3
  27. package/dest/e2e_p2p/shared.d.ts +25 -7
  28. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  29. package/dest/e2e_p2p/shared.js +49 -44
  30. package/dest/e2e_token_contract/token_contract_test.d.ts +1 -1
  31. package/dest/e2e_token_contract/token_contract_test.d.ts.map +1 -1
  32. package/dest/e2e_token_contract/token_contract_test.js +11 -11
  33. package/dest/fixtures/authwit_proxy.d.ts +3 -3
  34. package/dest/fixtures/authwit_proxy.d.ts.map +1 -1
  35. package/dest/fixtures/authwit_proxy.js +4 -0
  36. package/dest/fixtures/e2e_prover_test.d.ts +4 -3
  37. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
  38. package/dest/fixtures/e2e_prover_test.js +11 -16
  39. package/dest/fixtures/get_bb_config.d.ts +1 -1
  40. package/dest/fixtures/get_bb_config.d.ts.map +1 -1
  41. package/dest/fixtures/get_bb_config.js +5 -5
  42. package/dest/fixtures/setup.d.ts +18 -11
  43. package/dest/fixtures/setup.d.ts.map +1 -1
  44. package/dest/fixtures/setup.js +27 -21
  45. package/dest/fixtures/setup_p2p_test.d.ts +6 -6
  46. package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
  47. package/dest/fixtures/setup_p2p_test.js +8 -8
  48. package/dest/fixtures/token_utils.d.ts +1 -1
  49. package/dest/fixtures/token_utils.d.ts.map +1 -1
  50. package/dest/fixtures/token_utils.js +2 -5
  51. package/dest/forward-compatibility/wallet_rpc_client.d.ts +7 -0
  52. package/dest/forward-compatibility/wallet_rpc_client.d.ts.map +1 -0
  53. package/dest/forward-compatibility/wallet_rpc_client.js +15 -0
  54. package/dest/forward-compatibility/wallet_service.d.ts +3 -0
  55. package/dest/forward-compatibility/wallet_service.d.ts.map +1 -0
  56. package/dest/forward-compatibility/wallet_service.js +109 -0
  57. package/dest/legacy-jest-resolver.d.cts +3 -0
  58. package/dest/legacy-jest-resolver.d.cts.map +1 -0
  59. package/dest/shared/cross_chain_test_harness.d.ts +1 -1
  60. package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
  61. package/dest/shared/cross_chain_test_harness.js +13 -13
  62. package/dest/shared/gas_portal_test_harness.js +3 -3
  63. package/dest/shared/jest_setup.js +32 -1
  64. package/dest/shared/submit-transactions.d.ts +1 -1
  65. package/dest/shared/submit-transactions.d.ts.map +1 -1
  66. package/dest/shared/submit-transactions.js +1 -1
  67. package/dest/shared/uniswap_l1_l2.d.ts +1 -1
  68. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  69. package/dest/shared/uniswap_l1_l2.js +14 -21
  70. package/dest/simulators/lending_simulator.d.ts +1 -1
  71. package/dest/simulators/lending_simulator.d.ts.map +1 -1
  72. package/dest/simulators/lending_simulator.js +4 -4
  73. package/dest/simulators/token_simulator.d.ts +1 -1
  74. package/dest/simulators/token_simulator.d.ts.map +1 -1
  75. package/dest/simulators/token_simulator.js +2 -2
  76. package/dest/spartan/setup_test_wallets.d.ts +4 -2
  77. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  78. package/dest/spartan/setup_test_wallets.js +69 -38
  79. package/dest/spartan/tx_metrics.js +1 -1
  80. package/dest/spartan/utils/config.d.ts +7 -1
  81. package/dest/spartan/utils/config.d.ts.map +1 -1
  82. package/dest/spartan/utils/config.js +3 -1
  83. package/dest/spartan/utils/index.d.ts +3 -1
  84. package/dest/spartan/utils/index.d.ts.map +1 -1
  85. package/dest/spartan/utils/index.js +4 -0
  86. package/dest/spartan/utils/nodes.js +1 -1
  87. package/dest/spartan/utils/pod_logs.d.ts +25 -0
  88. package/dest/spartan/utils/pod_logs.d.ts.map +1 -0
  89. package/dest/spartan/utils/pod_logs.js +74 -0
  90. package/dest/test-wallet/test_wallet.d.ts +24 -23
  91. package/dest/test-wallet/test_wallet.d.ts.map +1 -1
  92. package/dest/test-wallet/test_wallet.js +115 -80
  93. package/dest/test-wallet/worker_wallet.d.ts +4 -4
  94. package/dest/test-wallet/worker_wallet.d.ts.map +1 -1
  95. package/dest/test-wallet/worker_wallet_schema.d.ts +10 -5
  96. package/dest/test-wallet/worker_wallet_schema.d.ts.map +1 -1
  97. package/package.json +43 -44
  98. package/src/bench/client_flows/client_flows_benchmark.ts +27 -10
  99. package/src/bench/utils.ts +7 -2
  100. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +21 -20
  101. package/src/e2e_epochs/epochs_test.ts +17 -5
  102. package/src/e2e_fees/fees_test.ts +14 -7
  103. package/src/e2e_nested_contract/nested_contract_test.ts +6 -4
  104. package/src/e2e_p2p/inactivity_slash_test.ts +3 -3
  105. package/src/e2e_p2p/p2p_network.ts +47 -48
  106. package/src/e2e_p2p/reqresp/utils.ts +24 -3
  107. package/src/e2e_p2p/shared.ts +71 -59
  108. package/src/e2e_token_contract/token_contract_test.ts +16 -8
  109. package/src/fixtures/authwit_proxy.ts +4 -0
  110. package/src/fixtures/e2e_prover_test.ts +19 -18
  111. package/src/fixtures/get_bb_config.ts +7 -6
  112. package/src/fixtures/setup.ts +46 -32
  113. package/src/fixtures/setup_p2p_test.ts +9 -9
  114. package/src/fixtures/token_utils.ts +1 -2
  115. package/src/forward-compatibility/wallet_rpc_client.ts +14 -0
  116. package/src/forward-compatibility/wallet_service.ts +104 -0
  117. package/src/guides/up_quick_start.sh +0 -2
  118. package/src/legacy-jest-resolver.cjs +135 -0
  119. package/src/shared/cross_chain_test_harness.ts +13 -9
  120. package/src/shared/gas_portal_test_harness.ts +1 -2
  121. package/src/shared/jest_setup.ts +36 -1
  122. package/src/shared/submit-transactions.ts +1 -4
  123. package/src/shared/uniswap_l1_l2.ts +35 -32
  124. package/src/simulators/lending_simulator.ts +8 -4
  125. package/src/simulators/token_simulator.ts +6 -2
  126. package/src/spartan/setup_test_wallets.ts +90 -35
  127. package/src/spartan/tx_metrics.ts +1 -1
  128. package/src/spartan/utils/config.ts +2 -0
  129. package/src/spartan/utils/index.ts +6 -0
  130. package/src/spartan/utils/nodes.ts +1 -1
  131. package/src/spartan/utils/pod_logs.ts +99 -0
  132. package/src/test-wallet/test_wallet.ts +144 -99
  133. package/src/test-wallet/worker_wallet.ts +3 -2
@@ -1,11 +1,14 @@
1
1
  import { SchnorrAccountContractArtifact } from '@aztec/accounts/schnorr';
2
2
  import { type InitialAccountData, generateSchnorrAccounts } from '@aztec/accounts/testing';
3
3
  import { type AztecNodeConfig, AztecNodeService, getConfigEnvVars } from '@aztec/aztec-node';
4
+ import { NO_FROM } from '@aztec/aztec.js/account';
4
5
  import { AztecAddress, EthAddress } from '@aztec/aztec.js/addresses';
5
6
  import {
6
7
  BatchCall,
7
8
  type ContractFunctionInteraction,
8
9
  type ContractMethod,
10
+ type DeployInteractionWaitOptions,
11
+ type DeployOptions,
9
12
  getContractClassFromArtifact,
10
13
  waitForProven,
11
14
  } from '@aztec/aztec.js/contracts';
@@ -30,6 +33,7 @@ import {
30
33
  } from '@aztec/ethereum/deploy-aztec-l1-contracts';
31
34
  import type { Delayer } from '@aztec/ethereum/l1-tx-utils';
32
35
  import { EthCheatCodes, EthCheatCodesWithState, startAnvil } from '@aztec/ethereum/test';
36
+ import type { Anvil } from '@aztec/ethereum/test';
33
37
  import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
34
38
  import { SecretValue } from '@aztec/foundation/config';
35
39
  import { randomBytes } from '@aztec/foundation/crypto/random';
@@ -47,10 +51,10 @@ import type { ProverNodeConfig } from '@aztec/prover-node';
47
51
  import { type PXEConfig, getPXEConfig } from '@aztec/pxe/server';
48
52
  import type { SequencerClient } from '@aztec/sequencer-client';
49
53
  import { type ContractInstanceWithAddress, getContractInstanceFromInstantiationParams } from '@aztec/stdlib/contract';
50
- import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
54
+ import type { AztecNodeAdmin, AztecNodeDebug } from '@aztec/stdlib/interfaces/client';
51
55
  import { tryStop } from '@aztec/stdlib/interfaces/server';
52
- import type { P2PClientType } from '@aztec/stdlib/p2p';
53
56
  import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
57
+ import type { GenesisData } from '@aztec/stdlib/world-state';
54
58
  import {
55
59
  type TelemetryClient,
56
60
  type TelemetryClientConfig,
@@ -61,7 +65,6 @@ import { BenchmarkTelemetryClient } from '@aztec/telemetry-client/bench';
61
65
  import { deployFundedSchnorrAccounts } from '@aztec/wallets/testing';
62
66
  import { getGenesisValues } from '@aztec/world-state/testing';
63
67
 
64
- import type { Anvil } from '@viem/anvil';
65
68
  import fs from 'fs/promises';
66
69
  import { tmpdir } from 'os';
67
70
  import path from 'path';
@@ -178,6 +181,8 @@ export type SetupOptions = {
178
181
  proverNodeConfig?: Partial<ProverNodeConfig>;
179
182
  /** Whether to use a mock gossip sub network for p2p clients. */
180
183
  mockGossipSubNetwork?: boolean;
184
+ /** Whether to add simulated latency to the mock gossipsub network (in ms) */
185
+ mockGossipSubNetworkLatency?: number;
181
186
  /** Whether to disable the anvil test watcher (can still be manually started) */
182
187
  disableAnvilTestWatcher?: boolean;
183
188
  /** Whether to enable anvil automine during deployment of L1 contracts (consider defaulting this to true). */
@@ -186,6 +191,11 @@ export type SetupOptions = {
186
191
  anvilAccounts?: number;
187
192
  /** Port to start anvil (defaults to 8545) */
188
193
  anvilPort?: number;
194
+ /**
195
+ * Number of slots per epoch for Anvil's finality simulation.
196
+ * Anvil reports `finalized = latest - slotsInAnEpoch * 2`.
197
+ */
198
+ anvilSlotsInAnEpoch?: number;
189
199
  /** Key to use for publishing L1 contracts */
190
200
  l1PublisherKey?: SecretValue<`0x${string}`>;
191
201
  /** ZkPassport configuration (domain, scope, mock verifier) */
@@ -205,7 +215,7 @@ export type EndToEndContext = {
205
215
  /** The Anvil instance (only set if anvil was started locally). */
206
216
  anvil: Anvil | undefined;
207
217
  /** The Aztec Node service or client a connected to it. */
208
- aztecNode: AztecNode;
218
+ aztecNode: AztecNode & AztecNodeDebug;
209
219
  /** The Aztec Node as a service. */
210
220
  aztecNodeService: AztecNodeService;
211
221
  /** Client to the Aztec Node admin interface. */
@@ -244,8 +254,8 @@ export type EndToEndContext = {
244
254
  sequencerDelayer: Delayer | undefined;
245
255
  /** Delayer for prover node L1 txs (only when enableDelayer and startProverNode are true). */
246
256
  proverDelayer: Delayer | undefined;
247
- /** Prefilled public data used for setting up nodes. */
248
- prefilledPublicData: PublicDataTreeLeaf[] | undefined;
257
+ /** Genesis data used for setting up nodes. */
258
+ genesis: GenesisData | undefined;
249
259
  /** ACVM config (only set if running locally). */
250
260
  acvmConfig: Awaited<ReturnType<typeof getACVMConfig>>;
251
261
  /** BB config (only set if running locally). */
@@ -271,7 +281,7 @@ export async function setup(
271
281
  let anvil: Anvil | undefined;
272
282
  try {
273
283
  opts.aztecTargetCommitteeSize ??= 0;
274
- opts.slasherFlavor ??= 'none';
284
+ opts.slasherEnabled ??= false;
275
285
 
276
286
  const config: AztecNodeConfig & SetupOptions = { ...getConfigEnvVars(), ...opts };
277
287
  // use initialValidators for the node config
@@ -298,6 +308,8 @@ export async function setup(
298
308
  config.dataDirectory = directoryToCleanup;
299
309
  }
300
310
 
311
+ const dateProvider = new TestDateProvider();
312
+
301
313
  if (!config.l1RpcUrls?.length) {
302
314
  if (!isAnvilTestChain(chain.id)) {
303
315
  throw new Error(`No ETHEREUM_HOSTS set but non anvil chain requested`);
@@ -306,6 +318,8 @@ export async function setup(
306
318
  l1BlockTime: opts.ethereumSlotDuration,
307
319
  accounts: opts.anvilAccounts,
308
320
  port: opts.anvilPort ?? (process.env.ANVIL_PORT ? parseInt(process.env.ANVIL_PORT) : undefined),
321
+ slotsInAnEpoch: opts.anvilSlotsInAnEpoch,
322
+ dateProvider,
309
323
  });
310
324
  anvil = res.anvil;
311
325
  config.l1RpcUrls = [res.rpcUrl];
@@ -317,8 +331,6 @@ export async function setup(
317
331
  logger.info(`Logging metrics to ${filename}`);
318
332
  setupMetricsLogger(filename);
319
333
  }
320
-
321
- const dateProvider = new TestDateProvider();
322
334
  const ethCheatCodes = new EthCheatCodesWithState(config.l1RpcUrls, dateProvider);
323
335
 
324
336
  if (opts.stateLoad) {
@@ -368,10 +380,12 @@ export async function setup(
368
380
  addressesToFund.push(sponsoredFPCAddress);
369
381
  }
370
382
 
371
- const { genesisArchiveRoot, prefilledPublicData, fundingNeeded } = await getGenesisValues(
383
+ const genesisTimestamp = BigInt(Math.floor(Date.now() / 1000));
384
+ const { genesisArchiveRoot, genesis, fundingNeeded } = await getGenesisValues(
372
385
  addressesToFund,
373
386
  opts.initialAccountFeeJuice,
374
387
  opts.genesisPublicData,
388
+ genesisTimestamp,
375
389
  );
376
390
 
377
391
  const wasAutomining = await ethCheatCodes.isAutoMining();
@@ -414,11 +428,12 @@ export async function setup(
414
428
  await ethCheatCodes.setIntervalMining(config.ethereumSlotDuration);
415
429
  }
416
430
 
417
- // Always sync dateProvider to L1 time after deploying L1 contracts, regardless of mining mode.
418
- // In compose mode, L1 time may have drifted ahead of system time due to the local-network watcher
419
- // warping time forward on each filled slot. Without this sync, the sequencer computes the wrong
420
- // slot from its dateProvider and cannot propose blocks.
421
- dateProvider.setTime((await ethCheatCodes.timestamp()) * 1000);
431
+ // In compose mode (no local anvil), sync dateProvider to L1 time since it may have drifted
432
+ // ahead of system time due to the local-network watcher warping time forward on each filled slot.
433
+ // When running with a local anvil, the dateProvider is kept in sync via the stdout listener.
434
+ if (!anvil) {
435
+ dateProvider.setTime((await ethCheatCodes.lastBlockTimestamp()) * 1000);
436
+ }
422
437
 
423
438
  if (opts.l2StartTime) {
424
439
  await ethCheatCodes.warp(opts.l2StartTime, { resetBlockInterval: true });
@@ -456,10 +471,10 @@ export async function setup(
456
471
  }
457
472
 
458
473
  let mockGossipSubNetwork: MockGossipSubNetwork | undefined;
459
- let p2pClientDeps: P2PClientDeps<P2PClientType.Full> | undefined = undefined;
474
+ let p2pClientDeps: P2PClientDeps | undefined = undefined;
460
475
 
461
476
  if (opts.mockGossipSubNetwork) {
462
- mockGossipSubNetwork = new MockGossipSubNetwork();
477
+ mockGossipSubNetwork = new MockGossipSubNetwork(opts.mockGossipSubNetworkLatency);
463
478
  p2pClientDeps = { p2pServiceFactory: getMockPubSubP2PServiceFactory(mockGossipSubNetwork) };
464
479
  }
465
480
 
@@ -488,11 +503,7 @@ export async function setup(
488
503
  }
489
504
 
490
505
  const aztecNodeService = await withLoggerBindings({ actor: 'node-0' }, () =>
491
- AztecNodeService.createAndSync(
492
- config,
493
- { dateProvider, telemetry: telemetryClient, p2pClientDeps },
494
- { prefilledPublicData },
495
- ),
506
+ AztecNodeService.createAndSync(config, { dateProvider, telemetry: telemetryClient, p2pClientDeps }, { genesis }),
496
507
  );
497
508
  const sequencerClient = aztecNodeService.getSequencer();
498
509
 
@@ -503,7 +514,7 @@ export async function setup(
503
514
  const proverNodePrivateKeyHex: Hex = `0x${proverNodePrivateKey!.toString('hex')}`;
504
515
  const proverNodeDataDirectory = path.join(directoryToCleanup, randomBytes(8).toString('hex'));
505
516
 
506
- const p2pClientDeps: Partial<P2PClientDeps<P2PClientType.Full>> = {
517
+ const p2pClientDeps: Partial<P2PClientDeps> = {
507
518
  p2pServiceFactory: mockGossipSubNetwork && getMockPubSubP2PServiceFactory(mockGossipSubNetwork!),
508
519
  rpcTxProviders: [aztecNodeService],
509
520
  };
@@ -516,7 +527,7 @@ export async function setup(
516
527
  dataDirectory: proverNodeDataDirectory,
517
528
  },
518
529
  { dateProvider, p2pClientDeps, telemetry: telemetryClient },
519
- { prefilledPublicData },
530
+ { genesis },
520
531
  ));
521
532
  }
522
533
 
@@ -621,7 +632,7 @@ export async function setup(
621
632
  initialFundedAccounts,
622
633
  logger,
623
634
  mockGossipSubNetwork,
624
- prefilledPublicData,
635
+ genesis,
625
636
  proverNode,
626
637
  sequencerDelayer,
627
638
  proverDelayer,
@@ -719,9 +730,9 @@ export function createAndSyncProverNode(
719
730
  deps: {
720
731
  telemetry?: TelemetryClient;
721
732
  dateProvider: DateProvider;
722
- p2pClientDeps?: P2PClientDeps<P2PClientType.Full>;
733
+ p2pClientDeps?: P2PClientDeps;
723
734
  },
724
- options: { prefilledPublicData: PublicDataTreeLeaf[]; dontStart?: boolean },
735
+ options: { genesis?: GenesisData; dontStart?: boolean },
725
736
  ): Promise<{ proverNode: AztecNodeService }> {
726
737
  return withLoggerBindings({ actor: 'prover-0' }, async () => {
727
738
  const proverNode = await AztecNodeService.createAndSync(
@@ -734,7 +745,7 @@ export function createAndSyncProverNode(
734
745
  proverPublisherPrivateKeys: [new SecretValue(proverNodePrivateKey)],
735
746
  },
736
747
  deps,
737
- { ...options, dontStartProverNode: options.dontStart },
748
+ { genesis: options.genesis, dontStartProverNode: options.dontStart },
738
749
  );
739
750
 
740
751
  if (!proverNode.getProverNode()) {
@@ -754,7 +765,9 @@ export function getBalancesFn(
754
765
  ): (...addresses: (AztecAddress | { address: AztecAddress })[]) => Promise<bigint[]> {
755
766
  const balances = async (...addressLikes: (AztecAddress | { address: AztecAddress })[]) => {
756
767
  const addresses = addressLikes.map(addressLike => ('address' in addressLike ? addressLike.address : addressLike));
757
- const b = await Promise.all(addresses.map(address => method(address).simulate({ from: address })));
768
+ const b = await Promise.all(
769
+ addresses.map(async address => (await method(address).simulate({ from: address })).result),
770
+ );
758
771
  const debugString = `${symbol} balances: ${addresses.map((address, i) => `${address}: ${b[i]}`).join(', ')}`;
759
772
  logger.verbose(debugString);
760
773
  return b;
@@ -823,7 +836,7 @@ export async function ensureAccountContractsPublished(wallet: Wallet, accountsTo
823
836
  * Returns deployed account data that can be used by tests.
824
837
  */
825
838
  export const deployAccounts =
826
- (numberOfAccounts: number, logger: Logger) =>
839
+ (numberOfAccounts: number, logger: Logger, deployOptions?: Partial<DeployOptions<DeployInteractionWaitOptions>>) =>
827
840
  async ({ wallet, initialFundedAccounts }: { wallet: TestWallet; initialFundedAccounts: InitialAccountData[] }) => {
828
841
  if (initialFundedAccounts.length < numberOfAccounts) {
829
842
  throw new Error(`Cannot deploy more than ${initialFundedAccounts.length} initial accounts.`);
@@ -840,8 +853,9 @@ export const deployAccounts =
840
853
  );
841
854
  const deployMethod = await accountManager.getDeployMethod();
842
855
  await deployMethod.send({
843
- from: AztecAddress.ZERO,
856
+ from: NO_FROM,
844
857
  skipClassPublication: i !== 0, // Publish the contract class at most once.
858
+ ...deployOptions,
845
859
  });
846
860
  }
847
861
 
@@ -872,7 +886,7 @@ export async function publicDeployAccounts(
872
886
 
873
887
  const batch = new BatchCall(wallet, calls);
874
888
 
875
- const txReceipt = await batch.send({ from: accountsToDeploy[0] });
889
+ const { receipt: txReceipt } = await batch.send({ from: accountsToDeploy[0] });
876
890
  if (waitUntilProven) {
877
891
  if (!node) {
878
892
  throw new Error('Need to provide an AztecNode to wait for proven.');
@@ -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
  );
@@ -97,7 +97,7 @@ export async function createNode(
97
97
  tcpPort: number,
98
98
  bootstrapNode: string | undefined,
99
99
  addressIndex: number | number[],
100
- prefilledPublicData?: PublicDataTreeLeaf[],
100
+ genesis?: GenesisData,
101
101
  dataDirectory?: string,
102
102
  metricsPort?: number,
103
103
  ) {
@@ -108,7 +108,7 @@ export async function createNode(
108
108
  return await AztecNodeService.createAndSync(
109
109
  validatorConfig,
110
110
  { telemetry, dateProvider },
111
- { prefilledPublicData, dontStartSequencer: config.dontStartSequencer },
111
+ { genesis, dontStartSequencer: config.dontStartSequencer },
112
112
  );
113
113
  });
114
114
  }
@@ -119,7 +119,7 @@ export async function createNonValidatorNode(
119
119
  dateProvider: DateProvider,
120
120
  tcpPort: number,
121
121
  bootstrapNode: string | undefined,
122
- prefilledPublicData?: PublicDataTreeLeaf[],
122
+ genesis?: GenesisData,
123
123
  dataDirectory?: string,
124
124
  metricsPort?: number,
125
125
  ) {
@@ -133,7 +133,7 @@ export async function createNonValidatorNode(
133
133
  sequencerPublisherPrivateKeys: [],
134
134
  };
135
135
  const telemetry = await getEndToEndTestTelemetryClient(metricsPort);
136
- return await AztecNodeService.createAndSync(config, { telemetry, dateProvider }, { prefilledPublicData });
136
+ return await AztecNodeService.createAndSync(config, { telemetry, dateProvider }, { genesis });
137
137
  });
138
138
  }
139
139
 
@@ -143,7 +143,7 @@ export async function createProverNode(
143
143
  bootstrapNode: string | undefined,
144
144
  addressIndex: number,
145
145
  deps: { dateProvider: DateProvider },
146
- prefilledPublicData?: PublicDataTreeLeaf[],
146
+ genesis?: GenesisData,
147
147
  dataDirectory?: string,
148
148
  metricsPort?: number,
149
149
  ): Promise<{ proverNode: AztecNodeService }> {
@@ -159,7 +159,7 @@ export async function createProverNode(
159
159
  { ...config, ...p2pConfig },
160
160
  { dataDirectory },
161
161
  { ...deps, telemetry },
162
- { prefilledPublicData: prefilledPublicData ?? [] },
162
+ { genesis },
163
163
  );
164
164
  });
165
165
  }
@@ -8,7 +8,6 @@ export async function deployToken(wallet: Wallet, admin: AztecAddress, initialAd
8
8
  logger.info(`Deploying Token contract...`);
9
9
  const { contract, instance } = await TokenContract.deploy(wallet, admin, 'TokenName', 'TokenSymbol', 18).send({
10
10
  from: admin,
11
- wait: { returnReceipt: true },
12
11
  });
13
12
 
14
13
  if (initialAdminBalance > 0n) {
@@ -39,7 +38,7 @@ export async function expectTokenBalance(
39
38
  ) {
40
39
  // Then check the balance
41
40
  const contractWithWallet = TokenContract.at(token.address, wallet);
42
- const balance = await contractWithWallet.methods.balance_of_private(owner).simulate({ from: owner });
41
+ const { result: balance } = await contractWithWallet.methods.balance_of_private(owner).simulate({ from: owner });
43
42
  logger.info(`Account ${owner} balance: ${balance}`);
44
43
  expect(balance).toBe(expectedBalance);
45
44
  }
@@ -0,0 +1,14 @@
1
+ import type { Wallet } from '@aztec/aztec.js/wallet';
2
+ import { WalletSchema } from '@aztec/aztec.js/wallet';
3
+ import { createSafeJsonRpcClient, makeFetch } from '@aztec/foundation/json-rpc/client';
4
+
5
+ /**
6
+ * Creates a JSON-RPC client that connects to a remote wallet service.
7
+ * The returned object implements the {@link Wallet} interface, proxying all calls over HTTP to the specified URL.
8
+ */
9
+ export function createWalletClient(url: string): Wallet {
10
+ return createSafeJsonRpcClient<Wallet>(url, WalletSchema, {
11
+ namespaceMethods: 'wallet',
12
+ fetch: makeFetch([1, 2, 3], false),
13
+ });
14
+ }
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env -S node --no-warnings
2
+ /**
3
+ * Standalone entrypoint that spins up a local Aztec network (L1 + node) and exposes a {@link NodeEmbeddedWallet} over
4
+ * JSON-RPC.
5
+ *
6
+ * Intended for forward-compatibility testing: an **old** release image runs this script so that **new** tests can send
7
+ * new artifacts to old runtime code (loadContractArtifact, ACIR simulator, class-ID computation, entrypoint encoding,
8
+ * etc.).
9
+ */
10
+ import { getSchnorrAccountContractAddress } from '@aztec/accounts/schnorr';
11
+ import { getInitialTestAccountsData } from '@aztec/accounts/testing';
12
+ import { createLocalNetwork } from '@aztec/aztec';
13
+ import { Fr } from '@aztec/aztec.js/fields';
14
+ import { WalletSchema } from '@aztec/aztec.js/wallet';
15
+ import { GrumpkinScalar } from '@aztec/foundation/curves/grumpkin';
16
+ import { createNamespacedSafeJsonRpcServer, startHttpRpcServer } from '@aztec/foundation/json-rpc/server';
17
+ import { createLogger } from '@aztec/foundation/log';
18
+ import { AztecNodeApiSchema } from '@aztec/stdlib/interfaces/client';
19
+ import { EmbeddedWallet } from '@aztec/wallets/embedded';
20
+
21
+ const logger = createLogger('wallet-service');
22
+
23
+ const { ETHEREUM_HOSTS = 'http://localhost:8545', NODE_PORT = '8080', WALLET_PORT = '8081' } = process.env;
24
+
25
+ async function main() {
26
+ const l1RpcUrls = ETHEREUM_HOSTS.split(',').map(url => url.trim());
27
+
28
+ // Some tests (e.g. AMM) need 4 accounts but only 3 are funded via genesis. Generate deterministic keys for a 4th
29
+ // account so we can compute its address before network startup and include it in genesis funding. We cannot do this
30
+ // in the test because Wallet interface does not expose account creation functionality (only TestWallet exposes that
31
+ // but that's not used in forward compatibility testing).
32
+ const extraAccountSecret = Fr.fromHexString('0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef');
33
+ const extraAccountSalt = Fr.ZERO;
34
+ const extraAccountSigningKey = GrumpkinScalar.random();
35
+ const extraAccountAddress = await getSchnorrAccountContractAddress(
36
+ extraAccountSecret,
37
+ extraAccountSalt,
38
+ extraAccountSigningKey,
39
+ );
40
+
41
+ logger.info('Starting wallet service...', { l1RpcUrls });
42
+
43
+ // createLocalNetwork deploys L1 contracts, starts the node, and optionally deploys funded test accounts (when
44
+ // TEST_ACCOUNTS=true via env). We are not proving anything just like is done when local network is started by
45
+ // the `aztecStart` function. The extra account address is passed via prefundAddresses so it gets fee juice at genesis.
46
+ const { node, stop: stopNetwork } = await createLocalNetwork(
47
+ { l1RpcUrls, realProofs: false, prefundAddresses: [extraAccountAddress.toString()] },
48
+ logger.info,
49
+ );
50
+
51
+ // Create an ephemeral embedded wallet backed by the local node.
52
+ const wallet = await EmbeddedWallet.create(node, { ephemeral: true });
53
+
54
+ // Re-register the initial test accounts so they are available via wallet.getAccounts(). createLocalNetwork deploys
55
+ // them onchain but uses a temporary wallet that is then stopped.
56
+ //
57
+ // We use the non-lazy import path (@aztec/accounts/testing, not /lazy) to avoid the dynamic JSON import that is
58
+ // incompatible with Node.js import attribute enforcement.
59
+ const testAccountsData = await getInitialTestAccountsData();
60
+ const accounts = await Promise.all(
61
+ testAccountsData.map(({ secret, salt, signingKey }) => wallet.createSchnorrAccount(secret, salt, signingKey)),
62
+ );
63
+
64
+ // Register and deploy the 4th account.
65
+ const extraAccount = await wallet.createSchnorrAccount(extraAccountSecret, extraAccountSalt, extraAccountSigningKey);
66
+ const deployMethod = await extraAccount.getDeployMethod();
67
+ await deployMethod.send({ from: accounts[0].address });
68
+
69
+ logger.info('Embedded wallet created', {
70
+ accounts: [...accounts, extraAccount].map(a => a.address.toString()),
71
+ });
72
+
73
+ // Contract artifacts are large, so allow generous body sizes for RPC requests.
74
+ const rpcOptions = { maxBodySizeBytes: '50mb' };
75
+
76
+ // Serve node RPC
77
+ const nodeRpcServer = createNamespacedSafeJsonRpcServer({ node: [node, AztecNodeApiSchema] }, rpcOptions);
78
+ const nodeHttpServer = await startHttpRpcServer(nodeRpcServer, { port: NODE_PORT });
79
+ logger.info(`Node JSON-RPC server listening on port ${nodeHttpServer.port}`);
80
+
81
+ // Serve wallet RPC
82
+ const walletRpcServer = createNamespacedSafeJsonRpcServer({ wallet: [wallet, WalletSchema] }, rpcOptions);
83
+ const walletHttpServer = await startHttpRpcServer(walletRpcServer, { port: WALLET_PORT });
84
+ logger.info(`Wallet JSON-RPC server listening on port ${walletHttpServer.port}`);
85
+
86
+ const shutdown = async () => {
87
+ logger.info('Shutting down...');
88
+ nodeHttpServer.close();
89
+ walletHttpServer.close();
90
+ await wallet.stop();
91
+ await stopNetwork();
92
+ process.exit(0);
93
+ };
94
+
95
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
96
+ process.once('SIGINT', shutdown);
97
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
98
+ process.once('SIGTERM', shutdown);
99
+ }
100
+
101
+ main().catch(err => {
102
+ logger.error('Wallet service failed to start', err);
103
+ process.exit(1);
104
+ });
@@ -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
 
@@ -0,0 +1,135 @@
1
+ // Custom Jest resolver. When CONTRACT_ARTIFACTS_VERSION is set, redirects *only* JSON artifact files under
2
+ // @aztec/noir-contracts.js/artifacts/, @aztec/noir-test-contracts.js/artifacts/, and @aztec/accounts/artifacts/ to a local cache of the pinned
3
+ // legacy versions. TypeScript wrapper classes (e.g. Token.ts) continue to load from the current workspace and use the
4
+ // current @aztec/aztec.js — only the artifact JSON (the deployed-contract ABI / bytecode / notes surface) is swapped.
5
+ //
6
+ // Why JSON-only: the JSON artifact is the actual interchange surface a "deployed contract" exposes. The TS wrapper is
7
+ // generated client-side ergonomics that's tightly coupled to the current @aztec/aztec.js API. Redirecting the wrapper
8
+ // would couple this test to a moving aztec.js surface and break at import time on unrelated breaking changes; we want
9
+ // to fail only on actual artifact-compat regressions.
10
+ //
11
+ // The cache is populated on demand by running `npm install` into .legacy-contracts/<version>/.
12
+ //
13
+ // Activated by env var; passthrough otherwise.
14
+ /* eslint-disable @typescript-eslint/no-require-imports */
15
+
16
+ const path = require('path');
17
+ const fs = require('fs');
18
+ const { execSync } = require('child_process');
19
+
20
+ const version = process.env.CONTRACT_ARTIFACTS_VERSION;
21
+ const REDIRECTED = ['@aztec/noir-contracts.js', '@aztec/noir-test-contracts.js', '@aztec/accounts'];
22
+
23
+ // Jest sets rootDir to <e2e>/src; this file lives there too.
24
+ const e2eRoot = path.resolve(__dirname, '..');
25
+ const cacheRoot = version ? path.join(e2eRoot, '.legacy-contracts', version) : null;
26
+
27
+ function pkgJsonPath(name) {
28
+ return path.join(cacheRoot, 'node_modules', name, 'package.json');
29
+ }
30
+
31
+ function ensureCache() {
32
+ const missing = REDIRECTED.some(p => !fs.existsSync(pkgJsonPath(p)));
33
+ if (!missing) {
34
+ return;
35
+ }
36
+ fs.mkdirSync(cacheRoot, { recursive: true });
37
+ // Seed a standalone package.json so `npm install --prefix` treats cacheRoot as its own project. Without this, npm
38
+ // walks up and finds the yarn-project workspace root, which breaks on `workspace:` protocol deps and risks
39
+ // clobbering the monorepo's node_modules.
40
+ const seed = path.join(cacheRoot, 'package.json');
41
+ if (!fs.existsSync(seed)) {
42
+ fs.writeFileSync(seed, JSON.stringify({ name: 'legacy-contracts-cache', private: true }));
43
+ }
44
+
45
+ const specs = REDIRECTED.map(p => `${p}@${version}`).join(' ');
46
+ process.stderr.write(`[legacy-contracts] installing ${specs} into ${cacheRoot}\n`);
47
+ // --prefix: install into cacheRoot instead of cwd, so the cache is isolated from the monorepo.
48
+ // --no-save: don't write the installed packages back to the seeded package.json.
49
+ // --ignore-scripts: skip lifecycle scripts (preinstall/postinstall) of the legacy packages and their transitive
50
+ // deps; we only want the files on disk, not to run any build steps.
51
+ // --legacy-peer-deps: tolerate peer-dependency mismatches between the pinned legacy @aztec/* graph and whatever
52
+ // current versions npm would otherwise try to reconcile.
53
+ execSync(`npm install --prefix "${cacheRoot}" --no-save --ignore-scripts --legacy-peer-deps ${specs}`, {
54
+ stdio: 'inherit',
55
+ });
56
+
57
+ // Verify versions on disk match the requested version.
58
+ for (const p of REDIRECTED) {
59
+ const onDisk = JSON.parse(fs.readFileSync(pkgJsonPath(p), 'utf8')).version;
60
+ if (onDisk !== version) {
61
+ throw new Error(`[legacy-contracts] ${p} on disk is ${onDisk}, expected ${version}`);
62
+ }
63
+ }
64
+ }
65
+
66
+ if (version) {
67
+ ensureCache();
68
+ }
69
+
70
+ let bannerPrinted = false;
71
+ const seen = new Set();
72
+
73
+ function printBannerOnce() {
74
+ if (bannerPrinted || !version) {
75
+ return;
76
+ }
77
+ bannerPrinted = true;
78
+ const lines = ['='.repeat(60), `[legacy-contracts][jest] CONTRACT_ARTIFACTS_VERSION=${version}`];
79
+ for (const p of REDIRECTED) {
80
+ const v = JSON.parse(fs.readFileSync(pkgJsonPath(p), 'utf8')).version;
81
+ if (v !== version) {
82
+ throw new Error(`[legacy-contracts] ${p} on disk is ${v}, expected ${version}`);
83
+ }
84
+ lines.push(`[legacy-contracts][jest] redirecting ${p}/artifacts/*.json -> .legacy-contracts/${version}/...`);
85
+ }
86
+ lines.push('='.repeat(60));
87
+ process.stderr.write(lines.join('\n') + '\n');
88
+ }
89
+
90
+ // Match a resolved absolute path against the workspace artifacts dirs and return the legacy cache equivalent, or null
91
+ // if it's not an artifact path we should redirect.
92
+ function legacyArtifactPath(resolved) {
93
+ if (!resolved.endsWith('.json')) {
94
+ return null;
95
+ }
96
+ for (const pkg of REDIRECTED) {
97
+ // pkg = '@aztec/noir-contracts.js' -> match '/noir-contracts.js/artifacts/'
98
+ const dirName = pkg.split('/')[1];
99
+ const marker = `/${dirName}/artifacts/`;
100
+ const idx = resolved.indexOf(marker);
101
+ if (idx === -1) {
102
+ continue;
103
+ }
104
+ const basename = resolved.slice(idx + marker.length);
105
+ return path.join(cacheRoot, 'node_modules', pkg, 'artifacts', basename);
106
+ }
107
+ return null;
108
+ }
109
+
110
+ module.exports = function legacyResolver(request, options) {
111
+ // Always run the default resolver first. We only inspect (and possibly rewrite) the *result*; this catches both
112
+ // bare-specifier imports of `@aztec/noir-contracts.js/artifacts/foo.json` and the relative `../artifacts/foo.json`
113
+ // imports inside the workspace TS wrapper classes — both resolve to the same workspace artifact path that we then
114
+ // redirect.
115
+ const resolved = options.defaultResolver(request, options);
116
+ if (!version) {
117
+ return resolved;
118
+ }
119
+ printBannerOnce();
120
+ const legacy = legacyArtifactPath(resolved);
121
+ if (!legacy) {
122
+ return resolved;
123
+ }
124
+ if (!fs.existsSync(legacy)) {
125
+ throw new Error(
126
+ `[legacy-contracts] artifact ${path.basename(legacy)} not present in legacy cache @${version}; ` +
127
+ `the contract may have been added after that release. Pin a newer CONTRACT_ARTIFACTS_VERSION or skip this test.`,
128
+ );
129
+ }
130
+ if (!seen.has(resolved)) {
131
+ seen.add(resolved);
132
+ process.stderr.write(`[legacy-contracts][jest] redirected ${path.basename(legacy)} -> ${legacy}\n`);
133
+ }
134
+ return legacy;
135
+ };