@aztec/end-to-end 0.0.1-commit.b1c78909e → 0.0.1-commit.b2a5d0dd1

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 (103) 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 +15 -30
  5. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +3 -2
  6. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts.map +1 -1
  7. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.js +1 -1
  8. package/dest/e2e_epochs/epochs_test.d.ts +18 -1
  9. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  10. package/dest/e2e_epochs/epochs_test.js +59 -9
  11. package/dest/e2e_fees/fees_test.d.ts +1 -1
  12. package/dest/e2e_fees/fees_test.d.ts.map +1 -1
  13. package/dest/e2e_fees/fees_test.js +3 -3
  14. package/dest/e2e_p2p/inactivity_slash_test.js +3 -3
  15. package/dest/e2e_p2p/p2p_network.d.ts +10 -9
  16. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  17. package/dest/e2e_p2p/p2p_network.js +46 -27
  18. package/dest/e2e_p2p/reqresp/utils.js +1 -1
  19. package/dest/e2e_p2p/shared.d.ts +5 -7
  20. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  21. package/dest/e2e_p2p/shared.js +29 -44
  22. package/dest/fixtures/authwit_proxy.d.ts +1 -1
  23. package/dest/fixtures/authwit_proxy.d.ts.map +1 -1
  24. package/dest/fixtures/authwit_proxy.js +4 -0
  25. package/dest/fixtures/e2e_prover_test.d.ts +4 -3
  26. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
  27. package/dest/fixtures/e2e_prover_test.js +7 -12
  28. package/dest/fixtures/fixtures.d.ts +12 -1
  29. package/dest/fixtures/fixtures.d.ts.map +1 -1
  30. package/dest/fixtures/fixtures.js +10 -0
  31. package/dest/fixtures/get_bb_config.d.ts +1 -1
  32. package/dest/fixtures/get_bb_config.d.ts.map +1 -1
  33. package/dest/fixtures/get_bb_config.js +5 -5
  34. package/dest/fixtures/ha_setup.d.ts +2 -2
  35. package/dest/fixtures/ha_setup.d.ts.map +1 -1
  36. package/dest/fixtures/ha_setup.js +1 -1
  37. package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts +25 -0
  38. package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts.map +1 -0
  39. package/dest/fixtures/schnorr_hardcoded_account_contract.js +39 -0
  40. package/dest/fixtures/setup.d.ts +17 -10
  41. package/dest/fixtures/setup.d.ts.map +1 -1
  42. package/dest/fixtures/setup.js +40 -21
  43. package/dest/fixtures/setup_p2p_test.d.ts +6 -6
  44. package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
  45. package/dest/fixtures/setup_p2p_test.js +8 -8
  46. package/dest/fixtures/token_utils.d.ts +1 -1
  47. package/dest/fixtures/token_utils.d.ts.map +1 -1
  48. package/dest/fixtures/token_utils.js +2 -5
  49. package/dest/forward-compatibility/wallet_rpc_client.d.ts +7 -0
  50. package/dest/forward-compatibility/wallet_rpc_client.d.ts.map +1 -0
  51. package/dest/forward-compatibility/wallet_rpc_client.js +15 -0
  52. package/dest/forward-compatibility/wallet_service.d.ts +3 -0
  53. package/dest/forward-compatibility/wallet_service.d.ts.map +1 -0
  54. package/dest/forward-compatibility/wallet_service.js +109 -0
  55. package/dest/legacy-jest-resolver.d.cts +3 -0
  56. package/dest/legacy-jest-resolver.d.cts.map +1 -0
  57. package/dest/shared/gas_portal_test_harness.js +1 -1
  58. package/dest/shared/uniswap_l1_l2.d.ts +1 -1
  59. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  60. package/dest/shared/uniswap_l1_l2.js +9 -16
  61. package/dest/simulators/lending_simulator.d.ts +1 -1
  62. package/dest/simulators/lending_simulator.d.ts.map +1 -1
  63. package/dest/simulators/lending_simulator.js +2 -2
  64. package/dest/simulators/token_simulator.js +1 -1
  65. package/dest/spartan/setup_test_wallets.d.ts +1 -1
  66. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  67. package/dest/spartan/setup_test_wallets.js +63 -45
  68. package/dest/test-wallet/test_wallet.d.ts +24 -23
  69. package/dest/test-wallet/test_wallet.d.ts.map +1 -1
  70. package/dest/test-wallet/test_wallet.js +118 -81
  71. package/dest/test-wallet/worker_wallet.d.ts +4 -4
  72. package/dest/test-wallet/worker_wallet.d.ts.map +1 -1
  73. package/dest/test-wallet/worker_wallet_schema.d.ts +9 -4
  74. package/dest/test-wallet/worker_wallet_schema.d.ts.map +1 -1
  75. package/package.json +40 -40
  76. package/src/bench/client_flows/client_flows_benchmark.ts +33 -24
  77. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +3 -6
  78. package/src/e2e_epochs/epochs_test.ts +69 -9
  79. package/src/e2e_fees/fees_test.ts +4 -2
  80. package/src/e2e_p2p/inactivity_slash_test.ts +3 -3
  81. package/src/e2e_p2p/p2p_network.ts +57 -39
  82. package/src/e2e_p2p/reqresp/utils.ts +1 -1
  83. package/src/e2e_p2p/shared.ts +29 -59
  84. package/src/fixtures/authwit_proxy.ts +4 -0
  85. package/src/fixtures/e2e_prover_test.ts +12 -17
  86. package/src/fixtures/fixtures.ts +22 -0
  87. package/src/fixtures/get_bb_config.ts +7 -6
  88. package/src/fixtures/ha_setup.ts +4 -2
  89. package/src/fixtures/schnorr_hardcoded_account_contract.ts +49 -0
  90. package/src/fixtures/setup.ts +54 -25
  91. package/src/fixtures/setup_p2p_test.ts +9 -9
  92. package/src/fixtures/token_utils.ts +1 -4
  93. package/src/forward-compatibility/wallet_rpc_client.ts +14 -0
  94. package/src/forward-compatibility/wallet_service.ts +104 -0
  95. package/src/guides/up_quick_start.sh +0 -2
  96. package/src/legacy-jest-resolver.cjs +135 -0
  97. package/src/shared/gas_portal_test_harness.ts +0 -1
  98. package/src/shared/uniswap_l1_l2.ts +29 -28
  99. package/src/simulators/lending_simulator.ts +4 -2
  100. package/src/simulators/token_simulator.ts +1 -1
  101. package/src/spartan/setup_test_wallets.ts +63 -39
  102. package/src/test-wallet/test_wallet.ts +147 -100
  103. package/src/test-wallet/worker_wallet.ts +3 -2
@@ -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
  }
@@ -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) {
@@ -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
+ };
@@ -178,4 +178,3 @@ export class GasBridgingTestHarness implements IGasBridgingTestHarness {
178
178
  }
179
179
  }
180
180
  }
181
- // docs:end:cross_chain_test_harness
@@ -154,7 +154,6 @@ export const uniswapL1L2TestSuite = (
154
154
  await cleanup();
155
155
  });
156
156
 
157
- // docs:start:uniswap_private
158
157
  it('should uniswap trade on L1 from L2 funds privately (swaps WETH -> DAI)', async () => {
159
158
  const wethL1BeforeBalance = await wethCrossChainHarness.getL1BalanceOf(ownerEthAddress);
160
159
 
@@ -252,8 +251,12 @@ export const uniswapL1L2TestSuite = (
252
251
  await wethCrossChainHarness.expectPublicBalanceOnL2(uniswapL2Contract.address, 0n);
253
252
 
254
253
  // Since the outbox is only consumable when the epoch is proven, we need to advance to the next epoch.
255
- const block = await aztecNode.getBlock(l2UniswapInteractionReceipt.blockNumber!);
256
- const epoch = await rollup.getEpochNumberForCheckpoint(block!.checkpointNumber);
254
+ const swapResult = (await computeL2ToL1MembershipWitness(
255
+ aztecNode,
256
+ swapPrivateLeaf,
257
+ l2UniswapInteractionReceipt.txHash,
258
+ ))!;
259
+ const { epochNumber: epoch } = swapResult;
257
260
  await cheatCodes.rollup.advanceToEpoch(EpochNumber(epoch + 1));
258
261
  await waitForProven(aztecNode, l2UniswapInteractionReceipt, { provenTimeout: 300 });
259
262
 
@@ -262,14 +265,17 @@ export const uniswapL1L2TestSuite = (
262
265
  const daiL1BalanceOfPortalBeforeSwap = await daiCrossChainHarness.getL1BalanceOf(
263
266
  daiCrossChainHarness.tokenPortalAddress,
264
267
  );
265
- const swapResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, swapPrivateLeaf);
266
- const withdrawResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, withdrawLeaf);
268
+ const withdrawResult = (await computeL2ToL1MembershipWitness(
269
+ aztecNode,
270
+ withdrawLeaf,
271
+ l2UniswapInteractionReceipt.txHash,
272
+ ))!;
267
273
 
268
- const swapPrivateL2MessageIndex = swapResult!.leafIndex;
269
- const swapPrivateSiblingPath = swapResult!.siblingPath;
274
+ const swapPrivateL2MessageIndex = swapResult.leafIndex;
275
+ const swapPrivateSiblingPath = swapResult.siblingPath;
270
276
 
271
- const withdrawL2MessageIndex = withdrawResult!.leafIndex;
272
- const withdrawSiblingPath = withdrawResult!.siblingPath;
277
+ const withdrawL2MessageIndex = withdrawResult.leafIndex;
278
+ const withdrawSiblingPath = withdrawResult.siblingPath;
273
279
 
274
280
  const withdrawMessageMetadata = {
275
281
  _epoch: BigInt(epoch),
@@ -338,10 +344,8 @@ export const uniswapL1L2TestSuite = (
338
344
  logger.info('WETH balance after swap : ', wethL2BalanceAfterSwap.toString());
339
345
  logger.info('DAI balance after swap : ', daiL2BalanceAfterSwap.toString());
340
346
  });
341
- // docs:end:uniswap_private
342
347
 
343
348
  // TODO(#7463): reenable look into this failure https://github.com/AztecProtocol/aztec-packages/actions/runs/9912612912/job/27388320150?pr=7462
344
- // // docs:start:uniswap_public
345
349
  // it('should uniswap trade on L1 from L2 funds publicly (swaps WETH -> DAI)', async () => {
346
350
  // const wethL1BeforeBalance = await wethCrossChainHarness.getL1BalanceOf(ownerEthAddress);
347
351
 
@@ -574,7 +578,6 @@ export const uniswapL1L2TestSuite = (
574
578
  // logger.info('WETH balance after swap : ', wethL2BalanceAfterSwap.toString());
575
579
  // logger.info('DAI balance after swap : ', daiL2BalanceAfterSwap.toString());
576
580
  // });
577
- // // docs:end:uniswap_public
578
581
 
579
582
  // Edge cases for the private flow:
580
583
  // note - tests for uniswapPortal.sol and minting asset on L2 are covered in other tests.
@@ -840,16 +843,15 @@ export const uniswapL1L2TestSuite = (
840
843
  chainId: new Fr(l1Client.chain.id),
841
844
  });
842
845
 
843
- const block = await aztecNode.getBlock(withdrawReceipt.blockNumber!);
844
- const epoch = await rollup.getEpochNumberForCheckpoint(block!.checkpointNumber);
845
- const swapResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, swapPrivateLeaf);
846
- const withdrawResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, withdrawLeaf);
846
+ const swapResult = (await computeL2ToL1MembershipWitness(aztecNode, swapPrivateLeaf, withdrawReceipt.txHash))!;
847
+ const { epochNumber: epoch } = swapResult;
848
+ const withdrawResult = (await computeL2ToL1MembershipWitness(aztecNode, withdrawLeaf, withdrawReceipt.txHash))!;
847
849
 
848
- const swapPrivateL2MessageIndex = swapResult!.leafIndex;
849
- const swapPrivateSiblingPath = swapResult!.siblingPath;
850
+ const swapPrivateL2MessageIndex = swapResult.leafIndex;
851
+ const swapPrivateSiblingPath = swapResult.siblingPath;
850
852
 
851
- const withdrawL2MessageIndex = withdrawResult!.leafIndex;
852
- const withdrawSiblingPath = withdrawResult!.siblingPath;
853
+ const withdrawL2MessageIndex = withdrawResult.leafIndex;
854
+ const withdrawSiblingPath = withdrawResult.siblingPath;
853
855
 
854
856
  const withdrawMessageMetadata = {
855
857
  _epoch: BigInt(epoch),
@@ -973,16 +975,15 @@ export const uniswapL1L2TestSuite = (
973
975
  chainId: new Fr(l1Client.chain.id),
974
976
  });
975
977
 
976
- const block = await aztecNode.getBlock(withdrawReceipt.blockNumber!);
977
- const epoch = await rollup.getEpochNumberForCheckpoint(block!.checkpointNumber);
978
- const swapResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, swapPublicLeaf);
979
- const withdrawResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, withdrawLeaf);
978
+ const swapResult = (await computeL2ToL1MembershipWitness(aztecNode, swapPublicLeaf, withdrawReceipt.txHash))!;
979
+ const { epochNumber: epoch } = swapResult;
980
+ const withdrawResult = (await computeL2ToL1MembershipWitness(aztecNode, withdrawLeaf, withdrawReceipt.txHash))!;
980
981
 
981
- const swapPublicL2MessageIndex = swapResult!.leafIndex;
982
- const swapPublicSiblingPath = swapResult!.siblingPath;
982
+ const swapPublicL2MessageIndex = swapResult.leafIndex;
983
+ const swapPublicSiblingPath = swapResult.siblingPath;
983
984
 
984
- const withdrawL2MessageIndex = withdrawResult!.leafIndex;
985
- const withdrawSiblingPath = withdrawResult!.siblingPath;
985
+ const withdrawL2MessageIndex = withdrawResult.leafIndex;
986
+ const withdrawSiblingPath = withdrawResult.siblingPath;
986
987
 
987
988
  const withdrawMessageMetadata = {
988
989
  _epoch: BigInt(epoch),
@@ -94,7 +94,9 @@ export class LendingSimulator {
94
94
 
95
95
  async prepare() {
96
96
  this.accumulator = BASE;
97
- const slot = await this.rollup.getSlotAt(BigInt(await this.cc.eth.timestamp()) + BigInt(this.ethereumSlotDuration));
97
+ const slot = await this.rollup.getSlotAt(
98
+ BigInt(await this.cc.eth.lastBlockTimestamp()) + BigInt(this.ethereumSlotDuration),
99
+ );
98
100
  this.time = Number(await this.rollup.getTimestampForSlot(slot));
99
101
  }
100
102
 
@@ -103,7 +105,7 @@ export class LendingSimulator {
103
105
  return;
104
106
  }
105
107
 
106
- const slot = await this.rollup.getSlotAt(BigInt(await this.cc.eth.timestamp()));
108
+ const slot = await this.rollup.getSlotAt(BigInt(await this.cc.eth.lastBlockTimestamp()));
107
109
  const targetSlot = SlotNumber(slot + diff);
108
110
  const ts = Number(await this.rollup.getTimestampForSlot(targetSlot));
109
111
  const timeDiff = ts - this.time;
@@ -110,7 +110,7 @@ export class TokenSimulator {
110
110
  chunk(calls, 5).map(batch => new BatchCall(this.defaultWallet, batch).simulate({ from: this.defaultAddress })),
111
111
  )
112
112
  )
113
- .flat()
113
+ .flatMap(r => r.result)
114
114
  .map(r => r.result);
115
115
  expect(results[0]).toEqual(this.totalSupply);
116
116
 
@@ -1,4 +1,5 @@
1
1
  import { generateSchnorrAccounts } from '@aztec/accounts/testing';
2
+ import { NO_FROM } from '@aztec/aztec.js/account';
2
3
  import { AztecAddress } from '@aztec/aztec.js/addresses';
3
4
  import { NO_WAIT } from '@aztec/aztec.js/contracts';
4
5
  import { L1FeeJuicePortalManager } from '@aztec/aztec.js/ethereum';
@@ -10,7 +11,7 @@ import type { Wallet } from '@aztec/aztec.js/wallet';
10
11
  import { createEthereumChain } from '@aztec/ethereum/chain';
11
12
  import { createExtendedL1Client } from '@aztec/ethereum/client';
12
13
  import type { Logger } from '@aztec/foundation/log';
13
- import { retryUntil } from '@aztec/foundation/retry';
14
+ import { makeBackoff, retry, retryUntil } from '@aztec/foundation/retry';
14
15
  import { TokenContract } from '@aztec/noir-contracts.js/Token';
15
16
  import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
16
17
  import { registerInitialLocalNetworkAccountsInWallet } from '@aztec/wallets/testing';
@@ -89,7 +90,7 @@ export async function deploySponsoredTestAccountsWithTokens(
89
90
  const paymentMethod = new SponsoredFeePaymentMethod(await getSponsoredFPCAddress());
90
91
  const recipientDeployMethod = await recipientAccount.getDeployMethod();
91
92
  await recipientDeployMethod.send({
92
- from: AztecAddress.ZERO,
93
+ from: NO_FROM,
93
94
  fee: { paymentMethod },
94
95
  wait: { timeout: 2400 },
95
96
  });
@@ -97,7 +98,7 @@ export async function deploySponsoredTestAccountsWithTokens(
97
98
  fundedAccounts.map(async a => {
98
99
  const deployMethod = await a.getDeployMethod();
99
100
  await deployMethod.send({
100
- from: AztecAddress.ZERO,
101
+ from: NO_FROM,
101
102
  fee: { paymentMethod },
102
103
  wait: { timeout: 2400 },
103
104
  }); // increase timeout on purpose in order to account for two empty epochs
@@ -137,38 +138,57 @@ async function deployAccountWithDiagnostics(
137
138
  estimateGas?: boolean,
138
139
  ): Promise<void> {
139
140
  const deployMethod = await account.getDeployMethod();
140
- let txHash;
141
- try {
142
- let gasSettings;
143
- if (estimateGas) {
144
- const sim = await deployMethod.simulate({ from: AztecAddress.ZERO, fee: { paymentMethod } });
145
- gasSettings = sim.estimatedGas;
146
- logger.info(`${accountLabel} estimated gas: DA=${gasSettings.gasLimits.daGas} L2=${gasSettings.gasLimits.l2Gas}`);
147
- }
148
- const deployResult = await deployMethod.send({
149
- from: AztecAddress.ZERO,
150
- fee: { paymentMethod, gasSettings },
151
- wait: NO_WAIT,
152
- });
153
- txHash = deployResult.txHash;
154
- await waitForTx(aztecNode, txHash, { timeout: 2400 });
155
- logger.info(`${accountLabel} deployed at ${account.address}`);
156
- } catch (error) {
157
- const blockNumber = await aztecNode.getBlockNumber();
158
- let receipt;
159
- try {
160
- receipt = await aztecNode.getTxReceipt(txHash);
161
- } catch {
162
- receipt = 'unavailable';
163
- }
164
- logger.error(`${accountLabel} deployment failed`, {
165
- txHash: txHash.toString(),
166
- receipt: JSON.stringify(receipt),
167
- currentBlockNumber: blockNumber,
168
- error: String(error),
169
- });
170
- throw error;
141
+ let gasSettings: any;
142
+ if (estimateGas) {
143
+ const sim = await deployMethod.simulate({ from: NO_FROM, fee: { paymentMethod } });
144
+ gasSettings = sim.estimatedGas;
145
+ logger.info(`${accountLabel} estimated gas: DA=${gasSettings.gasLimits.daGas} L2=${gasSettings.gasLimits.l2Gas}`);
171
146
  }
147
+
148
+ // Track the tx hash across retries so we don't re-send when the previous tx is still pending.
149
+ let sentTxHash: { txHash: any } | undefined;
150
+
151
+ await retry(
152
+ async () => {
153
+ // Check if already deployed (handles case where previous attempt succeeded but waitForTx timed out)
154
+ const existing = await aztecNode.getContract(account.address);
155
+ if (existing) {
156
+ logger.info(`${accountLabel} already deployed at ${account.address}, skipping`);
157
+ return;
158
+ }
159
+
160
+ // If we already sent a tx, check if it was dropped before deciding to re-send.
161
+ if (sentTxHash) {
162
+ const prevReceipt = await aztecNode.getTxReceipt(sentTxHash.txHash);
163
+ if (prevReceipt.isDropped()) {
164
+ logger.info(`${accountLabel} previous tx ${sentTxHash.txHash} was dropped, re-sending`);
165
+ sentTxHash = undefined;
166
+ } else {
167
+ logger.info(`${accountLabel} previous tx ${sentTxHash.txHash} still pending, waiting again...`);
168
+ }
169
+ }
170
+
171
+ if (!sentTxHash) {
172
+ const deployResult = await deployMethod.send({
173
+ from: NO_FROM,
174
+ fee: { paymentMethod, gasSettings },
175
+ wait: NO_WAIT,
176
+ });
177
+ sentTxHash = { txHash: deployResult.txHash };
178
+ logger.info(`${accountLabel} tx sent`, { txHash: sentTxHash.txHash.toString() });
179
+ }
180
+
181
+ const receipt = await waitForTx(aztecNode, sentTxHash.txHash, { timeout: 600 });
182
+ if (receipt.isDropped()) {
183
+ sentTxHash = undefined;
184
+ throw new Error(`${accountLabel} tx was dropped, retrying...`);
185
+ }
186
+ logger.info(`${accountLabel} deployed at ${account.address}`);
187
+ },
188
+ `deploy ${accountLabel}`,
189
+ makeBackoff([1, 2, 4, 8, 16]),
190
+ logger,
191
+ );
172
192
  }
173
193
 
174
194
  async function deployAccountsInBatches(
@@ -269,7 +289,7 @@ export async function deployTestAccountsWithTokens(
269
289
  fundedAccounts.map(async (a, i) => {
270
290
  const paymentMethod = new FeeJuicePaymentMethodWithClaim(a.address, claims[i]);
271
291
  const deployMethod = await a.getDeployMethod();
272
- await deployMethod.send({ from: AztecAddress.ZERO, fee: { paymentMethod } });
292
+ await deployMethod.send({ from: NO_FROM, fee: { paymentMethod } });
273
293
  logger.info(`Account deployed at ${a.address}`);
274
294
  }),
275
295
  );
@@ -345,14 +365,18 @@ async function deployTokenAndMint(
345
365
  logger: Logger,
346
366
  ) {
347
367
  logger.verbose(`Deploying TokenContract...`);
348
- const {
349
- receipt: { contract: tokenContract },
350
- } = await TokenContract.deploy(wallet, admin, TOKEN_NAME, TOKEN_SYMBOL, TOKEN_DECIMALS).send({
368
+ const { contract: tokenContract } = await TokenContract.deploy(
369
+ wallet,
370
+ admin,
371
+ TOKEN_NAME,
372
+ TOKEN_SYMBOL,
373
+ TOKEN_DECIMALS,
374
+ ).send({
351
375
  from: admin,
352
376
  fee: {
353
377
  paymentMethod,
354
378
  },
355
- wait: { timeout: 600, returnReceipt: true },
379
+ wait: { timeout: 600 },
356
380
  });
357
381
 
358
382
  const tokenAddress = tokenContract.address;