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

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 (177) hide show
  1. package/README.md +27 -0
  2. package/dest/bench/client_flows/client_flows_benchmark.d.ts +2 -2
  3. package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -1
  4. package/dest/bench/client_flows/client_flows_benchmark.js +21 -14
  5. package/dest/bench/client_flows/config.d.ts +2 -2
  6. package/dest/bench/client_flows/config.d.ts.map +1 -1
  7. package/dest/bench/client_flows/config.js +18 -0
  8. package/dest/bench/utils.d.ts +1 -1
  9. package/dest/bench/utils.d.ts.map +1 -1
  10. package/dest/bench/utils.js +6 -3
  11. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +6 -3
  12. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts.map +1 -1
  13. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.js +23 -13
  14. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts +2 -2
  15. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts.map +1 -1
  16. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.js +3 -2
  17. package/dest/e2e_deploy_contract/deploy_test.d.ts +2 -2
  18. package/dest/e2e_deploy_contract/deploy_test.d.ts.map +1 -1
  19. package/dest/e2e_epochs/epochs_test.d.ts +11 -7
  20. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  21. package/dest/e2e_epochs/epochs_test.js +62 -34
  22. package/dest/e2e_fees/fees_test.d.ts +2 -2
  23. package/dest/e2e_fees/fees_test.d.ts.map +1 -1
  24. package/dest/e2e_fees/fees_test.js +19 -12
  25. package/dest/e2e_nested_contract/nested_contract_test.d.ts +1 -1
  26. package/dest/e2e_nested_contract/nested_contract_test.d.ts.map +1 -1
  27. package/dest/e2e_nested_contract/nested_contract_test.js +4 -6
  28. package/dest/e2e_p2p/inactivity_slash_test.d.ts +1 -1
  29. package/dest/e2e_p2p/inactivity_slash_test.d.ts.map +1 -1
  30. package/dest/e2e_p2p/inactivity_slash_test.js +1 -0
  31. package/dest/e2e_p2p/p2p_network.d.ts +4 -3
  32. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  33. package/dest/e2e_p2p/p2p_network.js +23 -6
  34. package/dest/e2e_p2p/reqresp/utils.d.ts +3 -3
  35. package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -1
  36. package/dest/e2e_p2p/reqresp/utils.js +32 -8
  37. package/dest/e2e_p2p/shared.d.ts +34 -2
  38. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  39. package/dest/e2e_p2p/shared.js +61 -3
  40. package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.d.ts +2 -0
  41. package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.d.ts.map +1 -0
  42. package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.js +184 -0
  43. package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.d.ts +18 -0
  44. package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.d.ts.map +1 -0
  45. package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.js +120 -0
  46. package/dest/e2e_token_contract/token_contract_test.d.ts +4 -2
  47. package/dest/e2e_token_contract/token_contract_test.d.ts.map +1 -1
  48. package/dest/e2e_token_contract/token_contract_test.js +19 -9
  49. package/dest/fixtures/authwit_proxy.d.ts +15 -0
  50. package/dest/fixtures/authwit_proxy.d.ts.map +1 -0
  51. package/dest/fixtures/authwit_proxy.js +34 -0
  52. package/dest/fixtures/e2e_prover_test.d.ts +4 -4
  53. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
  54. package/dest/fixtures/e2e_prover_test.js +33 -40
  55. package/dest/fixtures/fixtures.d.ts +5 -1
  56. package/dest/fixtures/fixtures.d.ts.map +1 -1
  57. package/dest/fixtures/fixtures.js +6 -0
  58. package/dest/fixtures/ha_setup.d.ts +1 -1
  59. package/dest/fixtures/ha_setup.d.ts.map +1 -1
  60. package/dest/fixtures/ha_setup.js +3 -1
  61. package/dest/fixtures/setup.d.ts +46 -26
  62. package/dest/fixtures/setup.d.ts.map +1 -1
  63. package/dest/fixtures/setup.js +70 -156
  64. package/dest/fixtures/setup_p2p_test.d.ts +15 -7
  65. package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
  66. package/dest/fixtures/setup_p2p_test.js +18 -12
  67. package/dest/fixtures/token_utils.d.ts +2 -2
  68. package/dest/fixtures/token_utils.d.ts.map +1 -1
  69. package/dest/fixtures/token_utils.js +5 -4
  70. package/dest/forward-compatibility/wallet_rpc_client.d.ts +7 -0
  71. package/dest/forward-compatibility/wallet_rpc_client.d.ts.map +1 -0
  72. package/dest/forward-compatibility/wallet_rpc_client.js +15 -0
  73. package/dest/forward-compatibility/wallet_service.d.ts +3 -0
  74. package/dest/forward-compatibility/wallet_service.d.ts.map +1 -0
  75. package/dest/forward-compatibility/wallet_service.js +109 -0
  76. package/dest/install_legacy_contracts.d.cts +10 -0
  77. package/dest/install_legacy_contracts.d.cts.map +1 -0
  78. package/dest/legacy-jest-resolver.d.cts +3 -0
  79. package/dest/legacy-jest-resolver.d.cts.map +1 -0
  80. package/dest/shared/cross_chain_test_harness.d.ts +1 -1
  81. package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
  82. package/dest/shared/cross_chain_test_harness.js +13 -13
  83. package/dest/shared/gas_portal_test_harness.js +2 -2
  84. package/dest/shared/index.d.ts +2 -1
  85. package/dest/shared/index.d.ts.map +1 -1
  86. package/dest/shared/index.js +1 -0
  87. package/dest/shared/mock_state_view.d.ts +86 -0
  88. package/dest/shared/mock_state_view.d.ts.map +1 -0
  89. package/dest/shared/mock_state_view.js +186 -0
  90. package/dest/shared/submit-transactions.d.ts +2 -2
  91. package/dest/shared/submit-transactions.d.ts.map +1 -1
  92. package/dest/shared/submit-transactions.js +1 -1
  93. package/dest/shared/uniswap_l1_l2.d.ts +1 -1
  94. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  95. package/dest/shared/uniswap_l1_l2.js +16 -17
  96. package/dest/simulators/lending_simulator.d.ts +1 -1
  97. package/dest/simulators/lending_simulator.d.ts.map +1 -1
  98. package/dest/simulators/lending_simulator.js +4 -4
  99. package/dest/simulators/token_simulator.d.ts +1 -1
  100. package/dest/simulators/token_simulator.d.ts.map +1 -1
  101. package/dest/simulators/token_simulator.js +3 -24
  102. package/dest/spartan/setup_test_wallets.d.ts +12 -3
  103. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  104. package/dest/spartan/setup_test_wallets.js +59 -16
  105. package/dest/spartan/utils/bot.d.ts +3 -2
  106. package/dest/spartan/utils/bot.d.ts.map +1 -1
  107. package/dest/spartan/utils/bot.js +2 -1
  108. package/dest/spartan/utils/index.d.ts +3 -2
  109. package/dest/spartan/utils/index.d.ts.map +1 -1
  110. package/dest/spartan/utils/index.js +3 -1
  111. package/dest/spartan/utils/k8s.d.ts +3 -1
  112. package/dest/spartan/utils/k8s.d.ts.map +1 -1
  113. package/dest/spartan/utils/k8s.js +6 -0
  114. package/dest/test-wallet/test_wallet.d.ts +84 -0
  115. package/dest/test-wallet/test_wallet.d.ts.map +1 -0
  116. package/dest/test-wallet/test_wallet.js +249 -0
  117. package/dest/test-wallet/utils.d.ts +41 -0
  118. package/dest/test-wallet/utils.d.ts.map +1 -0
  119. package/dest/test-wallet/utils.js +71 -0
  120. package/dest/test-wallet/wallet_worker_script.d.ts +2 -0
  121. package/dest/test-wallet/wallet_worker_script.d.ts.map +1 -0
  122. package/dest/test-wallet/wallet_worker_script.js +48 -0
  123. package/dest/test-wallet/worker_wallet.d.ts +52 -0
  124. package/dest/test-wallet/worker_wallet.d.ts.map +1 -0
  125. package/dest/test-wallet/worker_wallet.js +151 -0
  126. package/dest/test-wallet/worker_wallet_schema.d.ts +274 -0
  127. package/dest/test-wallet/worker_wallet_schema.d.ts.map +1 -0
  128. package/dest/test-wallet/worker_wallet_schema.js +10 -0
  129. package/package.json +41 -39
  130. package/src/bench/client_flows/client_flows_benchmark.ts +44 -40
  131. package/src/bench/client_flows/config.ts +9 -1
  132. package/src/bench/utils.ts +8 -3
  133. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +31 -21
  134. package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +7 -8
  135. package/src/e2e_deploy_contract/deploy_test.ts +3 -3
  136. package/src/e2e_epochs/epochs_test.ts +83 -61
  137. package/src/e2e_fees/bridging_race.notest.ts +1 -1
  138. package/src/e2e_fees/fees_test.ts +21 -29
  139. package/src/e2e_nested_contract/nested_contract_test.ts +7 -5
  140. package/src/e2e_p2p/inactivity_slash_test.ts +5 -4
  141. package/src/e2e_p2p/p2p_network.ts +35 -9
  142. package/src/e2e_p2p/reqresp/utils.ts +40 -12
  143. package/src/e2e_p2p/shared.ts +100 -3
  144. package/src/e2e_storage_proof/fixtures/storage_proof.json +915 -0
  145. package/src/e2e_storage_proof/fixtures/storage_proof_fetcher.ts +190 -0
  146. package/src/e2e_storage_proof/fixtures/storage_proof_fixture.ts +173 -0
  147. package/src/e2e_token_contract/token_contract_test.ts +26 -9
  148. package/src/fixtures/authwit_proxy.ts +54 -0
  149. package/src/fixtures/dumps/epoch_proof_result.json +1 -1
  150. package/src/fixtures/e2e_prover_test.ts +39 -43
  151. package/src/fixtures/fixtures.ts +10 -0
  152. package/src/fixtures/ha_setup.ts +3 -1
  153. package/src/fixtures/setup.ts +107 -219
  154. package/src/fixtures/setup_p2p_test.ts +25 -24
  155. package/src/fixtures/token_utils.ts +6 -3
  156. package/src/forward-compatibility/wallet_rpc_client.ts +14 -0
  157. package/src/forward-compatibility/wallet_service.ts +104 -0
  158. package/src/guides/up_quick_start.sh +3 -3
  159. package/src/install_legacy_contracts.cjs +71 -0
  160. package/src/legacy-jest-resolver.cjs +101 -0
  161. package/src/shared/cross_chain_test_harness.ts +13 -9
  162. package/src/shared/gas_portal_test_harness.ts +1 -1
  163. package/src/shared/index.ts +1 -0
  164. package/src/shared/mock_state_view.ts +188 -0
  165. package/src/shared/submit-transactions.ts +6 -2
  166. package/src/shared/uniswap_l1_l2.ts +38 -33
  167. package/src/simulators/lending_simulator.ts +8 -4
  168. package/src/simulators/token_simulator.ts +6 -30
  169. package/src/spartan/setup_test_wallets.ts +104 -18
  170. package/src/spartan/utils/bot.ts +4 -1
  171. package/src/spartan/utils/index.ts +4 -0
  172. package/src/spartan/utils/k8s.ts +8 -0
  173. package/src/test-wallet/test_wallet.ts +351 -0
  174. package/src/test-wallet/utils.ts +112 -0
  175. package/src/test-wallet/wallet_worker_script.ts +60 -0
  176. package/src/test-wallet/worker_wallet.ts +214 -0
  177. package/src/test-wallet/worker_wallet_schema.ts +13 -0
@@ -6,7 +6,9 @@ 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 { contract, instance } = await TokenContract.deploy(wallet, admin, 'TokenName', 'TokenSymbol', 18).send({
9
+ const {
10
+ receipt: { contract, instance },
11
+ } = await TokenContract.deploy(wallet, admin, 'TokenName', 'TokenSymbol', 18).send({
10
12
  from: admin,
11
13
  wait: { returnReceipt: true },
12
14
  });
@@ -25,8 +27,9 @@ export async function mintTokensToPrivate(
25
27
  minter: AztecAddress,
26
28
  recipient: AztecAddress,
27
29
  amount: bigint,
30
+ additionalScopes?: AztecAddress[],
28
31
  ) {
29
- await token.methods.mint_to_private(recipient, amount).send({ from: minter });
32
+ await token.methods.mint_to_private(recipient, amount).send({ from: minter, additionalScopes });
30
33
  }
31
34
 
32
35
  export async function expectTokenBalance(
@@ -38,7 +41,7 @@ export async function expectTokenBalance(
38
41
  ) {
39
42
  // Then check the balance
40
43
  const contractWithWallet = TokenContract.at(token.address, wallet);
41
- const balance = await contractWithWallet.methods.balance_of_private(owner).simulate({ from: owner });
44
+ const { result: balance } = await contractWithWallet.methods.balance_of_private(owner).simulate({ from: owner });
42
45
  logger.info(`Account ${owner} balance: ${balance}`);
43
46
  expect(balance).toBe(expectedBalance);
44
47
  }
@@ -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
+ });
@@ -23,6 +23,8 @@ aztec-wallet create-account -a alice -f test0
23
23
  aztec-wallet create-account -a bob -f test0
24
24
  # docs:end:declare-accounts
25
25
 
26
+ aztec-wallet bridge-fee-juice 1000000000000000000000 accounts:alice --mint --no-wait
27
+
26
28
  DEPLOY_OUTPUT=$(aztec-wallet deploy ../noir-contracts.js/artifacts/token_contract-Token.json --args accounts:test0 Test TST 18 -f test0)
27
29
  TOKEN_ADDRESS=$(echo "$DEPLOY_OUTPUT" | grep -oE 'Contract deployed at 0x[0-9a-fA-F]+' | cut -d ' ' -f4)
28
30
  echo "Deployed contract at $TOKEN_ADDRESS"
@@ -38,9 +40,7 @@ fi
38
40
 
39
41
  TRANSFER_AMOUNT=42
40
42
 
41
- aztec-wallet create-authwit transfer_in_private accounts:test0 -ca last --args accounts:alice accounts:bob $TRANSFER_AMOUNT 1 -f alice
42
-
43
- aztec-wallet send transfer_in_private -ca last --args accounts:alice accounts:bob $TRANSFER_AMOUNT 1 -aw authwits:last -f test0
43
+ aztec-wallet send transfer_in_private -ca last --args accounts:alice accounts:bob $TRANSFER_AMOUNT 0 -f alice --payment method=fee_juice,claim
44
44
 
45
45
  # Test end result
46
46
  ALICE_BALANCE=$(aztec-wallet simulate balance_of_private -ca last --args accounts:alice -f alice)
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+ // Installs pinned legacy @aztec/* contract-artifact packages into .legacy-contracts/<version>/.
3
+ //
4
+ // Called from two places:
5
+ // - bootstrap.sh ci-compat-e2e: pre-populates the cache on the host before hermetic test
6
+ // containers launch. The containers run with --net=none (see ci3/docker_isolate), so on-demand
7
+ // installs from inside them fail with EAI_AGAIN.
8
+ // - legacy-jest-resolver.cjs: on-demand install for local dev, where jest runs with network.
9
+ //
10
+ // Idempotent: no-op when all packages are already present.
11
+ /* eslint-disable @typescript-eslint/no-require-imports */
12
+
13
+ const path = require('path');
14
+ const fs = require('fs');
15
+ const { execFileSync } = require('child_process');
16
+
17
+ const REDIRECTED = ['@aztec/noir-contracts.js', '@aztec/noir-test-contracts.js', '@aztec/accounts'];
18
+
19
+ const e2eRoot = path.resolve(__dirname, '..');
20
+
21
+ function cacheRoot(version) {
22
+ return path.join(e2eRoot, '.legacy-contracts', version);
23
+ }
24
+
25
+ function pkgJsonPath(version, pkg) {
26
+ return path.join(cacheRoot(version), 'node_modules', pkg, 'package.json');
27
+ }
28
+
29
+ function installLegacyContracts(version) {
30
+ if (!version) {
31
+ throw new Error('installLegacyContracts: version is required');
32
+ }
33
+ if (REDIRECTED.every(pkg => fs.existsSync(pkgJsonPath(version, pkg)))) {
34
+ return;
35
+ }
36
+
37
+ const cacheDir = cacheRoot(version);
38
+ fs.mkdirSync(cacheDir, { recursive: true });
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.
43
+ const seed = path.join(cacheDir, 'package.json');
44
+ if (!fs.existsSync(seed)) {
45
+ fs.writeFileSync(seed, JSON.stringify({ name: 'legacy-contracts-cache', private: true }));
46
+ }
47
+
48
+ const specs = REDIRECTED.map(pkg => `${pkg}@${version}`);
49
+ process.stderr.write(`[legacy-contracts] installing ${specs.join(' ')} into ${cacheDir}\n`);
50
+ // --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.
53
+ execFileSync(
54
+ 'npm',
55
+ ['install', '--prefix', cacheDir, '--no-save', '--ignore-scripts', '--legacy-peer-deps', ...specs],
56
+ { stdio: 'inherit' },
57
+ );
58
+
59
+ for (const pkg of REDIRECTED) {
60
+ const onDisk = JSON.parse(fs.readFileSync(pkgJsonPath(version, pkg), 'utf8')).version;
61
+ if (onDisk !== version) {
62
+ throw new Error(`[legacy-contracts] ${pkg} on disk is ${onDisk}, expected ${version}`);
63
+ }
64
+ }
65
+ }
66
+
67
+ module.exports = { installLegacyContracts, REDIRECTED, cacheRoot };
68
+
69
+ if (require.main === module) {
70
+ installLegacyContracts(process.argv[2]);
71
+ }
@@ -0,0 +1,101 @@
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
+ // Cache population lives in install_legacy_contracts.cjs — invoked lazily here for local dev, and eagerly
12
+ // by bootstrap.sh ci-compat-e2e before hermetic test containers (which run with --net=none) launch.
13
+ //
14
+ // Activated by env var; passthrough otherwise.
15
+ /* eslint-disable @typescript-eslint/no-require-imports */
16
+
17
+ const path = require('path');
18
+ const fs = require('fs');
19
+ const { installLegacyContracts, REDIRECTED, cacheRoot } = require('./install_legacy_contracts.cjs');
20
+
21
+ const version = process.env.CONTRACT_ARTIFACTS_VERSION;
22
+ const cacheDir = version ? cacheRoot(version) : null;
23
+
24
+ function pkgJsonPath(name) {
25
+ return path.join(cacheDir, 'node_modules', name, 'package.json');
26
+ }
27
+
28
+ // Kept in a separate module (not inlined) because bootstrap.sh ci-compat-e2e also calls it directly
29
+ // via `node .../install_legacy_contracts.cjs <version>` to pre-populate the cache on the host before
30
+ // hermetic --net=none test containers launch. Inlining here would force us to duplicate the logic
31
+ // in bash or re-run jest just to trigger the install.
32
+ if (version) {
33
+ installLegacyContracts(version);
34
+ }
35
+
36
+ let bannerPrinted = false;
37
+ const seen = new Set();
38
+
39
+ function printBannerOnce() {
40
+ if (bannerPrinted || !version) {
41
+ return;
42
+ }
43
+ bannerPrinted = true;
44
+ const lines = ['='.repeat(60), `[legacy-contracts][jest] CONTRACT_ARTIFACTS_VERSION=${version}`];
45
+ for (const p of REDIRECTED) {
46
+ const v = JSON.parse(fs.readFileSync(pkgJsonPath(p), 'utf8')).version;
47
+ if (v !== version) {
48
+ throw new Error(`[legacy-contracts] ${p} on disk is ${v}, expected ${version}`);
49
+ }
50
+ lines.push(`[legacy-contracts][jest] redirecting ${p}/artifacts/*.json -> .legacy-contracts/${version}/...`);
51
+ }
52
+ lines.push('='.repeat(60));
53
+ process.stderr.write(lines.join('\n') + '\n');
54
+ }
55
+
56
+ // Match a resolved absolute path against the workspace artifacts dirs and return the legacy cache equivalent, or null
57
+ // if it's not an artifact path we should redirect.
58
+ function legacyArtifactPath(resolved) {
59
+ if (!resolved.endsWith('.json')) {
60
+ return null;
61
+ }
62
+ for (const pkg of REDIRECTED) {
63
+ // pkg = '@aztec/noir-contracts.js' -> match '/noir-contracts.js/artifacts/'
64
+ const dirName = pkg.split('/')[1];
65
+ const marker = `/${dirName}/artifacts/`;
66
+ const idx = resolved.indexOf(marker);
67
+ if (idx === -1) {
68
+ continue;
69
+ }
70
+ const basename = resolved.slice(idx + marker.length);
71
+ return path.join(cacheRoot, 'node_modules', pkg, 'artifacts', basename);
72
+ }
73
+ return null;
74
+ }
75
+
76
+ module.exports = function legacyResolver(request, options) {
77
+ // Always run the default resolver first. We only inspect (and possibly rewrite) the *result*; this catches both
78
+ // bare-specifier imports of `@aztec/noir-contracts.js/artifacts/foo.json` and the relative `../artifacts/foo.json`
79
+ // imports inside the workspace TS wrapper classes — both resolve to the same workspace artifact path that we then
80
+ // redirect.
81
+ const resolved = options.defaultResolver(request, options);
82
+ if (!version) {
83
+ return resolved;
84
+ }
85
+ printBannerOnce();
86
+ const legacy = legacyArtifactPath(resolved);
87
+ if (!legacy) {
88
+ return resolved;
89
+ }
90
+ 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.`,
94
+ );
95
+ }
96
+ if (!seen.has(resolved)) {
97
+ seen.add(resolved);
98
+ process.stderr.write(`[legacy-contracts][jest] redirected ${path.basename(legacy)} -> ${legacy}\n`);
99
+ }
100
+ return legacy;
101
+ };
@@ -73,22 +73,26 @@ export async function deployAndInitializeTokenAndBridgeContracts(
73
73
  });
74
74
 
75
75
  // deploy l2 token
76
- const token = await TokenContract.deploy(wallet, owner, 'TokenName', 'TokenSymbol', 18).send({ from: owner });
76
+ const { contract: token } = await TokenContract.deploy(wallet, owner, 'TokenName', 'TokenSymbol', 18).send({
77
+ from: owner,
78
+ });
77
79
 
78
80
  // deploy l2 token bridge and attach to the portal
79
- const bridge = await TokenBridgeContract.deploy(wallet, token.address, tokenPortalAddress).send({ from: owner });
81
+ const { contract: bridge } = await TokenBridgeContract.deploy(wallet, token.address, tokenPortalAddress).send({
82
+ from: owner,
83
+ });
80
84
 
81
- if ((await token.methods.get_admin().simulate({ from: owner })) !== owner.toBigInt()) {
85
+ if ((await token.methods.get_admin().simulate({ from: owner })).result !== owner.toBigInt()) {
82
86
  throw new Error(`Token admin is not ${owner}`);
83
87
  }
84
88
 
85
- if (!(await bridge.methods.get_config().simulate({ from: owner })).token.equals(token.address)) {
89
+ if (!(await bridge.methods.get_config().simulate({ from: owner })).result.token.equals(token.address)) {
86
90
  throw new Error(`Bridge token is not ${token.address}`);
87
91
  }
88
92
 
89
93
  // make the bridge a minter on the token:
90
94
  await token.methods.set_minter(bridge.address, true).send({ from: owner });
91
- if ((await token.methods.is_minter(bridge.address).simulate({ from: owner })) === 1n) {
95
+ if ((await token.methods.is_minter(bridge.address).simulate({ from: owner })).result === 1n) {
92
96
  throw new Error(`Bridge is not a minter`);
93
97
  }
94
98
 
@@ -269,7 +273,7 @@ export class CrossChainTestHarness {
269
273
  authwitNonce: Fr = Fr.ZERO,
270
274
  authWitness: AuthWitness,
271
275
  ): Promise<TxReceipt> {
272
- const withdrawReceipt = await this.l2Bridge.methods
276
+ const { receipt: withdrawReceipt } = await this.l2Bridge.methods
273
277
  .exit_to_l1_private(this.l2Token.address, this.ethAccount, withdrawAmount, EthAddress.ZERO, authwitNonce)
274
278
  .send({ authWitnesses: [authWitness], from: this.ownerAddress });
275
279
 
@@ -277,7 +281,7 @@ export class CrossChainTestHarness {
277
281
  }
278
282
 
279
283
  async withdrawPublicFromAztecToL1(withdrawAmount: bigint, authwitNonce: Fr = Fr.ZERO): Promise<TxReceipt> {
280
- const withdrawReceipt = await this.l2Bridge.methods
284
+ const { receipt: withdrawReceipt } = await this.l2Bridge.methods
281
285
  .exit_to_l1_public(this.ethAccount, withdrawAmount, EthAddress.ZERO, authwitNonce)
282
286
  .send({ from: this.ownerAddress });
283
287
 
@@ -285,7 +289,7 @@ export class CrossChainTestHarness {
285
289
  }
286
290
 
287
291
  async getL2PrivateBalanceOf(owner: AztecAddress) {
288
- return await this.l2Token.methods.balance_of_private(owner).simulate({ from: owner });
292
+ return (await this.l2Token.methods.balance_of_private(owner).simulate({ from: owner })).result;
289
293
  }
290
294
 
291
295
  async expectPrivateBalanceOnL2(owner: AztecAddress, expectedBalance: bigint) {
@@ -295,7 +299,7 @@ export class CrossChainTestHarness {
295
299
  }
296
300
 
297
301
  async getL2PublicBalanceOf(owner: AztecAddress) {
298
- return await this.l2Token.methods.balance_of_public(owner).simulate({ from: this.ownerAddress });
302
+ return (await this.l2Token.methods.balance_of_public(owner).simulate({ from: this.ownerAddress })).result;
299
303
  }
300
304
 
301
305
  async expectPublicBalanceOnL2(owner: AztecAddress, expectedBalance: bigint) {
@@ -131,7 +131,7 @@ export class GasBridgingTestHarness implements IGasBridgingTestHarness {
131
131
  }
132
132
 
133
133
  async getL2PublicBalanceOf(owner: AztecAddress) {
134
- return await this.feeJuice.methods.balance_of_public(owner).simulate({ from: owner });
134
+ return (await this.feeJuice.methods.balance_of_public(owner).simulate({ from: owner })).result;
135
135
  }
136
136
 
137
137
  async expectPublicBalanceOnL2(owner: AztecAddress, expectedBalance: bigint) {
@@ -1 +1,2 @@
1
1
  export { uniswapL1L2TestSuite } from './uniswap_l1_l2.js';
2
+ export { MockStateView, diffInBps } from './mock_state_view.js';
@@ -0,0 +1,188 @@
1
+ import { EthAddress } from '@aztec/aztec.js/addresses';
2
+ import { type Logger, createLogger } from '@aztec/aztec.js/log';
3
+ import type { EthCheatCodes } from '@aztec/aztec/testing';
4
+ import type { ExtendedViemWalletClient } from '@aztec/ethereum/types';
5
+
6
+ import { getContract } from 'viem';
7
+
8
+ /**
9
+ * Mock StateView contract for testing the Uniswap price oracle.
10
+ *
11
+ * Wraps a compiled Solidity contract that mimics the Uniswap V4 StateView's getSlot0 function.
12
+ * The mock allows setting return values dynamically for testing different price scenarios.
13
+ *
14
+ * Solidity source:
15
+ * ```solidity
16
+ * // SPDX-License-Identifier: Apache-2.0
17
+ * pragma solidity >=0.8.27;
18
+ *
19
+ * contract MockStateView {
20
+ * uint160 public sqrtPriceX96;
21
+ * int24 public tick;
22
+ * uint24 public protocolFee;
23
+ * uint24 public lpFee;
24
+ *
25
+ * function setReturnValues(
26
+ * uint160 _sqrtPriceX96,
27
+ * int24 _tick,
28
+ * uint24 _protocolFee,
29
+ * uint24 _lpFee
30
+ * ) external {
31
+ * sqrtPriceX96 = _sqrtPriceX96;
32
+ * tick = _tick;
33
+ * protocolFee = _protocolFee;
34
+ * lpFee = _lpFee;
35
+ * }
36
+ *
37
+ * function getSlot0(bytes32 poolId) external view returns (uint160, int24, uint24, uint24) {
38
+ * return (sqrtPriceX96, tick, protocolFee, lpFee);
39
+ * }
40
+ * }
41
+ * ```
42
+ */
43
+ export class MockStateView {
44
+ private static readonly BYTECODE: `0x${string}` =
45
+ '0x608060405234801561000f575f5ffd5b5060043610610060575f3560e01c80633eaf5d9f14610064578063704ce43e146100825780638db791d2146100a0578063b0e21e8a146100be578063b52e4bdd146100dc578063c815641c146100f8575b5f5ffd5b61006c61012b565b60405161007991906102ab565b60405180910390f35b61008a61013d565b60405161009791906102e1565b60405180910390f35b6100a8610151565b6040516100b59190610328565b60405180910390f35b6100c6610175565b6040516100d391906102e1565b60405180910390f35b6100f660048036038101906100f191906103c3565b610189565b005b610112600480360381019061010d919061045a565b61022b565b6040516101229493929190610485565b60405180910390f35b5f60149054906101000a900460020b81565b5f601a9054906101000a900462ffffff1681565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f60179054906101000a900462ffffff1681565b835f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550825f60146101000a81548162ffffff021916908360020b62ffffff160217905550815f60176101000a81548162ffffff021916908362ffffff160217905550805f601a6101000a81548162ffffff021916908362ffffff16021790555050505050565b5f5f5f5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff165f60149054906101000a900460020b5f60179054906101000a900462ffffff165f601a9054906101000a900462ffffff1693509350935093509193509193565b5f8160020b9050919050565b6102a581610290565b82525050565b5f6020820190506102be5f83018461029c565b92915050565b5f62ffffff82169050919050565b6102db816102c4565b82525050565b5f6020820190506102f45f8301846102d2565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b610322816102fa565b82525050565b5f60208201905061033b5f830184610319565b92915050565b5f5ffd5b61034e816102fa565b8114610358575f5ffd5b50565b5f8135905061036981610345565b92915050565b61037881610290565b8114610382575f5ffd5b50565b5f813590506103938161036f565b92915050565b6103a2816102c4565b81146103ac575f5ffd5b50565b5f813590506103bd81610399565b92915050565b5f5f5f5f608085870312156103db576103da610341565b5b5f6103e88782880161035b565b94505060206103f987828801610385565b935050604061040a878288016103af565b925050606061041b878288016103af565b91505092959194509250565b5f819050919050565b61043981610427565b8114610443575f5ffd5b50565b5f8135905061045481610430565b92915050565b5f6020828403121561046f5761046e610341565b5b5f61047c84828501610446565b91505092915050565b5f6080820190506104985f830187610319565b6104a5602083018661029c565b6104b260408301856102d2565b6104bf60608301846102d2565b9594505050505056fea2646970667358221220f8b1bfff284535bc078368ed34bd5e78981644845f3c9c1f5a4b8448c976805464736f6c634300081f0033';
46
+ private static readonly ABI = [
47
+ {
48
+ type: 'function',
49
+ name: 'setReturnValues',
50
+ inputs: [
51
+ { name: '_sqrtPriceX96', type: 'uint160' },
52
+ { name: '_tick', type: 'int24' },
53
+ { name: '_protocolFee', type: 'uint24' },
54
+ { name: '_lpFee', type: 'uint24' },
55
+ ],
56
+ outputs: [],
57
+ stateMutability: 'nonpayable',
58
+ },
59
+ {
60
+ inputs: [
61
+ {
62
+ internalType: 'bytes32',
63
+ name: 'poolId',
64
+ type: 'bytes32',
65
+ },
66
+ ],
67
+ name: 'getSlot0',
68
+ outputs: [
69
+ {
70
+ internalType: 'uint160',
71
+ name: '',
72
+ type: 'uint160',
73
+ },
74
+ {
75
+ internalType: 'int24',
76
+ name: '',
77
+ type: 'int24',
78
+ },
79
+ {
80
+ internalType: 'uint24',
81
+ name: '',
82
+ type: 'uint24',
83
+ },
84
+ {
85
+ internalType: 'uint24',
86
+ name: '',
87
+ type: 'uint24',
88
+ },
89
+ ],
90
+ stateMutability: 'view',
91
+ type: 'function',
92
+ },
93
+ ] as const;
94
+
95
+ private constructor(
96
+ private readonly address: EthAddress,
97
+ private readonly walletClient: ExtendedViemWalletClient,
98
+ private readonly log: Logger = createLogger('mock-state-view'),
99
+ ) {}
100
+
101
+ /**
102
+ * Deploys the mock StateView contract at the specified address using etch.
103
+ * @param ethCheatCodes - Cheat codes for etching bytecode
104
+ * @param walletClient - Wallet client for sending transactions
105
+ * @param address - Address to deploy the mock at (typically the real StateView address)
106
+ */
107
+ static async deploy(
108
+ ethCheatCodes: EthCheatCodes,
109
+ walletClient: ExtendedViemWalletClient,
110
+ address: EthAddress,
111
+ ): Promise<MockStateView> {
112
+ await ethCheatCodes.etch(address, MockStateView.BYTECODE);
113
+ return new MockStateView(address, walletClient);
114
+ }
115
+
116
+ /**
117
+ * Sets the price using the ethPerFeeAssetE12 format (same as rollup contract).
118
+ * Computes the corresponding sqrtPriceX96 internally.
119
+ *
120
+ * Math (from fee_asset_price_oracle.ts):
121
+ * ethPerFeeAssetE12 = 1e12 * 2^192 / sqrtPriceX96^2
122
+ *
123
+ * Inverted:
124
+ * sqrtPriceX96^2 = 1e12 * 2^192 / ethPerFeeAssetE12
125
+ * sqrtPriceX96 = sqrt(1e12 * 2^192 / ethPerFeeAssetE12)
126
+ *
127
+ * @param ethPerFeeAssetE12 - The price in ETH per fee asset, scaled by 1e12
128
+ */
129
+ async setEthPerFeeAsset(ethPerFeeAssetE12: bigint) {
130
+ const sqrtPriceX96 = this.ethPerFeeAssetE12ToSqrtPriceX96(ethPerFeeAssetE12);
131
+ return await this.setSqrtPriceX96(sqrtPriceX96);
132
+ }
133
+
134
+ /**
135
+ * Sets the sqrtPriceX96 value directly (Uniswap's price encoding).
136
+ * @param sqrtPriceX96 - The sqrtPriceX96 value
137
+ * @param tick - The tick value (default 10)
138
+ * @param protocolFee - The protocol fee (default 0)
139
+ * @param lpFee - The LP fee (default 500)
140
+ */
141
+ async setSqrtPriceX96(sqrtPriceX96: bigint, tick: number = 10, protocolFee: number = 0, lpFee: number = 500) {
142
+ const contract = getContract({
143
+ address: this.address.toString() as `0x${string}`,
144
+ abi: MockStateView.ABI,
145
+ client: this.walletClient,
146
+ });
147
+
148
+ const hash = await contract.write.setReturnValues([sqrtPriceX96, tick, protocolFee, lpFee]);
149
+ this.log.info(`Set sqrtPriceX96 to ${sqrtPriceX96}`);
150
+ return await this.walletClient.waitForTransactionReceipt({ hash });
151
+ }
152
+
153
+ /**
154
+ * Converts ethPerFeeAssetE12 to sqrtPriceX96 (inverse of sqrtPriceX96ToEthPerFeeAssetE12).
155
+ *
156
+ * Math:
157
+ * sqrtPriceX96 = sqrt(1e12 * 2^192 / ethPerFeeAssetE12)
158
+ */
159
+ ethPerFeeAssetE12ToSqrtPriceX96(ethPerFeeAssetE12: bigint): bigint {
160
+ if (ethPerFeeAssetE12 === 0n) {
161
+ throw new Error('Cannot convert zero ethPerFeeAssetE12');
162
+ }
163
+ const Q192 = 2n ** 192n;
164
+ const sqrtPriceSquared = (10n ** 12n * Q192) / ethPerFeeAssetE12;
165
+ return this.bigintSqrt(sqrtPriceSquared);
166
+ }
167
+
168
+ /** Integer square root using Newton's method */
169
+ bigintSqrt(n: bigint): bigint {
170
+ if (n < 0n) {
171
+ throw new Error('Cannot compute sqrt of negative number');
172
+ }
173
+ if (n === 0n) {
174
+ return 0n;
175
+ }
176
+ let x = n;
177
+ let y = (x + 1n) / 2n;
178
+ while (y < x) {
179
+ x = y;
180
+ y = (x + n / x) / 2n;
181
+ }
182
+ return x;
183
+ }
184
+ }
185
+
186
+ export function diffInBps(a: bigint, b: bigint): bigint {
187
+ return ((a - b) * 10000n) / b;
188
+ }
@@ -4,7 +4,8 @@ import { Fr, GrumpkinScalar } from '@aztec/aztec.js/fields';
4
4
  import type { Logger } from '@aztec/aztec.js/log';
5
5
  import { TxHash, type TxReceipt, TxStatus } from '@aztec/aztec.js/tx';
6
6
  import { times } from '@aztec/foundation/collection';
7
- import type { TestWallet } from '@aztec/test-wallet/server';
7
+
8
+ import type { TestWallet } from '../test-wallet/test_wallet.js';
8
9
 
9
10
  // submits a set of transactions to the provided Wallet
10
11
  export const submitTxsTo = async (
@@ -18,7 +19,10 @@ export const submitTxsTo = async (
18
19
  times(numTxs, async () => {
19
20
  const accountManager = await wallet.createSchnorrAccount(Fr.random(), Fr.random(), GrumpkinScalar.random());
20
21
  const deployMethod = await accountManager.getDeployMethod();
21
- const txHash = await deployMethod.send({ from: submitter, wait: NO_WAIT });
22
+ const { txHash } = await deployMethod.send({
23
+ from: submitter,
24
+ wait: NO_WAIT,
25
+ });
22
26
 
23
27
  logger.info(`Tx sent with hash ${txHash}`);
24
28
  const receipt: TxReceipt = await wallet.getTxReceipt(txHash);