@aztec/end-to-end 0.0.1-commit.e3c1de76 → 0.0.1-commit.e57c76e

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 (230) hide show
  1. package/README.md +27 -0
  2. package/dest/bench/client_flows/benchmark.d.ts +15 -1
  3. package/dest/bench/client_flows/benchmark.d.ts.map +1 -1
  4. package/dest/bench/client_flows/benchmark.js +17 -0
  5. package/dest/bench/client_flows/client_flows_benchmark.d.ts +3 -3
  6. package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -1
  7. package/dest/bench/client_flows/client_flows_benchmark.js +36 -39
  8. package/dest/bench/client_flows/config.d.ts +2 -2
  9. package/dest/bench/client_flows/config.d.ts.map +1 -1
  10. package/dest/bench/client_flows/config.js +18 -0
  11. package/dest/bench/utils.d.ts +1 -1
  12. package/dest/bench/utils.d.ts.map +1 -1
  13. package/dest/bench/utils.js +8 -3
  14. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +8 -5
  15. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts.map +1 -1
  16. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.js +36 -17
  17. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts +16 -5
  18. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts.map +1 -1
  19. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.js +42 -9
  20. package/dest/e2e_deploy_contract/deploy_test.d.ts +4 -4
  21. package/dest/e2e_deploy_contract/deploy_test.d.ts.map +1 -1
  22. package/dest/e2e_deploy_contract/deploy_test.js +2 -1
  23. package/dest/e2e_epochs/epochs_test.d.ts +33 -8
  24. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  25. package/dest/e2e_epochs/epochs_test.js +143 -44
  26. package/dest/e2e_fees/fees_test.d.ts +6 -3
  27. package/dest/e2e_fees/fees_test.d.ts.map +1 -1
  28. package/dest/e2e_fees/fees_test.js +50 -17
  29. package/dest/e2e_nested_contract/nested_contract_test.d.ts +3 -3
  30. package/dest/e2e_nested_contract/nested_contract_test.d.ts.map +1 -1
  31. package/dest/e2e_nested_contract/nested_contract_test.js +6 -7
  32. package/dest/e2e_p2p/inactivity_slash_test.d.ts +1 -1
  33. package/dest/e2e_p2p/inactivity_slash_test.d.ts.map +1 -1
  34. package/dest/e2e_p2p/inactivity_slash_test.js +4 -3
  35. package/dest/e2e_p2p/p2p_network.d.ts +14 -12
  36. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  37. package/dest/e2e_p2p/p2p_network.js +70 -34
  38. package/dest/e2e_p2p/reqresp/utils.d.ts +3 -3
  39. package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -1
  40. package/dest/e2e_p2p/reqresp/utils.js +67 -14
  41. package/dest/e2e_p2p/shared.d.ts +37 -8
  42. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  43. package/dest/e2e_p2p/shared.js +91 -51
  44. package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.d.ts +2 -0
  45. package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.d.ts.map +1 -0
  46. package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.js +184 -0
  47. package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.d.ts +18 -0
  48. package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.d.ts.map +1 -0
  49. package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.js +120 -0
  50. package/dest/e2e_token_contract/token_contract_test.d.ts +6 -4
  51. package/dest/e2e_token_contract/token_contract_test.d.ts.map +1 -1
  52. package/dest/e2e_token_contract/token_contract_test.js +23 -11
  53. package/dest/fixtures/authwit_proxy.d.ts +15 -0
  54. package/dest/fixtures/authwit_proxy.d.ts.map +1 -0
  55. package/dest/fixtures/authwit_proxy.js +34 -0
  56. package/dest/fixtures/e2e_prover_test.d.ts +9 -8
  57. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
  58. package/dest/fixtures/e2e_prover_test.js +39 -50
  59. package/dest/fixtures/elu_monitor.d.ts +21 -0
  60. package/dest/fixtures/elu_monitor.d.ts.map +1 -0
  61. package/dest/fixtures/elu_monitor.js +102 -0
  62. package/dest/fixtures/fixtures.d.ts +74 -1
  63. package/dest/fixtures/fixtures.d.ts.map +1 -1
  64. package/dest/fixtures/fixtures.js +71 -0
  65. package/dest/fixtures/get_bb_config.d.ts +1 -1
  66. package/dest/fixtures/get_bb_config.d.ts.map +1 -1
  67. package/dest/fixtures/get_bb_config.js +5 -5
  68. package/dest/fixtures/ha_setup.d.ts +71 -0
  69. package/dest/fixtures/ha_setup.d.ts.map +1 -0
  70. package/dest/fixtures/ha_setup.js +116 -0
  71. package/dest/fixtures/index.d.ts +2 -1
  72. package/dest/fixtures/index.d.ts.map +1 -1
  73. package/dest/fixtures/index.js +1 -0
  74. package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts +25 -0
  75. package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts.map +1 -0
  76. package/dest/fixtures/schnorr_hardcoded_account_contract.js +37 -0
  77. package/dest/fixtures/setup.d.ts +86 -32
  78. package/dest/fixtures/setup.d.ts.map +1 -1
  79. package/dest/fixtures/setup.js +209 -169
  80. package/dest/fixtures/setup_p2p_test.d.ts +22 -10
  81. package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
  82. package/dest/fixtures/setup_p2p_test.js +23 -17
  83. package/dest/fixtures/token_utils.d.ts +2 -2
  84. package/dest/fixtures/token_utils.d.ts.map +1 -1
  85. package/dest/fixtures/token_utils.js +5 -7
  86. package/dest/fixtures/utils.d.ts +2 -2
  87. package/dest/fixtures/utils.d.ts.map +1 -1
  88. package/dest/fixtures/utils.js +1 -1
  89. package/dest/forward-compatibility/wallet_rpc_client.d.ts +7 -0
  90. package/dest/forward-compatibility/wallet_rpc_client.d.ts.map +1 -0
  91. package/dest/forward-compatibility/wallet_rpc_client.js +15 -0
  92. package/dest/forward-compatibility/wallet_service.d.ts +3 -0
  93. package/dest/forward-compatibility/wallet_service.d.ts.map +1 -0
  94. package/dest/forward-compatibility/wallet_service.js +109 -0
  95. package/dest/install_legacy_contracts.d.cts +10 -0
  96. package/dest/install_legacy_contracts.d.cts.map +1 -0
  97. package/dest/legacy-jest-resolver.d.cts +3 -0
  98. package/dest/legacy-jest-resolver.d.cts.map +1 -0
  99. package/dest/shared/cross_chain_test_harness.d.ts +4 -2
  100. package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
  101. package/dest/shared/cross_chain_test_harness.js +22 -18
  102. package/dest/shared/gas_portal_test_harness.d.ts +8 -5
  103. package/dest/shared/gas_portal_test_harness.d.ts.map +1 -1
  104. package/dest/shared/gas_portal_test_harness.js +19 -10
  105. package/dest/shared/index.d.ts +2 -1
  106. package/dest/shared/index.d.ts.map +1 -1
  107. package/dest/shared/index.js +1 -0
  108. package/dest/shared/jest_setup.js +41 -1
  109. package/dest/shared/mock_state_view.d.ts +86 -0
  110. package/dest/shared/mock_state_view.d.ts.map +1 -0
  111. package/dest/shared/mock_state_view.js +186 -0
  112. package/dest/shared/submit-transactions.d.ts +2 -2
  113. package/dest/shared/submit-transactions.d.ts.map +1 -1
  114. package/dest/shared/submit-transactions.js +1 -1
  115. package/dest/shared/uniswap_l1_l2.d.ts +1 -1
  116. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  117. package/dest/shared/uniswap_l1_l2.js +57 -40
  118. package/dest/shared/wait_for_l1_to_l2_message.d.ts +13 -0
  119. package/dest/shared/wait_for_l1_to_l2_message.d.ts.map +1 -0
  120. package/dest/shared/wait_for_l1_to_l2_message.js +10 -0
  121. package/dest/simulators/lending_simulator.d.ts +10 -3
  122. package/dest/simulators/lending_simulator.d.ts.map +1 -1
  123. package/dest/simulators/lending_simulator.js +26 -14
  124. package/dest/simulators/token_simulator.d.ts +1 -1
  125. package/dest/simulators/token_simulator.d.ts.map +1 -1
  126. package/dest/simulators/token_simulator.js +3 -24
  127. package/dest/spartan/setup_test_wallets.d.ts +12 -3
  128. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  129. package/dest/spartan/setup_test_wallets.js +108 -41
  130. package/dest/spartan/tx_metrics.d.ts +18 -4
  131. package/dest/spartan/tx_metrics.d.ts.map +1 -1
  132. package/dest/spartan/tx_metrics.js +74 -21
  133. package/dest/spartan/utils/bot.d.ts +3 -2
  134. package/dest/spartan/utils/bot.d.ts.map +1 -1
  135. package/dest/spartan/utils/bot.js +2 -1
  136. package/dest/spartan/utils/config.d.ts +11 -28
  137. package/dest/spartan/utils/config.d.ts.map +1 -1
  138. package/dest/spartan/utils/config.js +4 -1
  139. package/dest/spartan/utils/index.d.ts +5 -3
  140. package/dest/spartan/utils/index.d.ts.map +1 -1
  141. package/dest/spartan/utils/index.js +5 -1
  142. package/dest/spartan/utils/k8s.d.ts +3 -1
  143. package/dest/spartan/utils/k8s.d.ts.map +1 -1
  144. package/dest/spartan/utils/k8s.js +6 -0
  145. package/dest/spartan/utils/nodes.d.ts +4 -5
  146. package/dest/spartan/utils/nodes.d.ts.map +1 -1
  147. package/dest/spartan/utils/nodes.js +11 -11
  148. package/dest/spartan/utils/pod_logs.d.ts +25 -0
  149. package/dest/spartan/utils/pod_logs.d.ts.map +1 -0
  150. package/dest/spartan/utils/pod_logs.js +74 -0
  151. package/dest/spartan/utils/scripts.d.ts +18 -4
  152. package/dest/spartan/utils/scripts.d.ts.map +1 -1
  153. package/dest/spartan/utils/scripts.js +19 -4
  154. package/dest/test-wallet/test_wallet.d.ts +85 -0
  155. package/dest/test-wallet/test_wallet.d.ts.map +1 -0
  156. package/dest/test-wallet/test_wallet.js +273 -0
  157. package/dest/test-wallet/utils.d.ts +41 -0
  158. package/dest/test-wallet/utils.d.ts.map +1 -0
  159. package/dest/test-wallet/utils.js +66 -0
  160. package/dest/test-wallet/wallet_worker_script.d.ts +2 -0
  161. package/dest/test-wallet/wallet_worker_script.d.ts.map +1 -0
  162. package/dest/test-wallet/wallet_worker_script.js +53 -0
  163. package/dest/test-wallet/worker_wallet.d.ts +53 -0
  164. package/dest/test-wallet/worker_wallet.d.ts.map +1 -0
  165. package/dest/test-wallet/worker_wallet.js +155 -0
  166. package/dest/test-wallet/worker_wallet_schema.d.ts +160 -0
  167. package/dest/test-wallet/worker_wallet_schema.d.ts.map +1 -0
  168. package/dest/test-wallet/worker_wallet_schema.js +22 -0
  169. package/package.json +52 -45
  170. package/src/bench/client_flows/benchmark.ts +19 -0
  171. package/src/bench/client_flows/client_flows_benchmark.ts +64 -49
  172. package/src/bench/client_flows/config.ts +9 -1
  173. package/src/bench/utils.ts +10 -4
  174. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +52 -25
  175. package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +56 -19
  176. package/src/e2e_deploy_contract/deploy_test.ts +6 -5
  177. package/src/e2e_epochs/epochs_test.ts +166 -68
  178. package/src/e2e_fees/bridging_race.notest.ts +1 -1
  179. package/src/e2e_fees/fees_test.ts +57 -32
  180. package/src/e2e_nested_contract/nested_contract_test.ts +10 -6
  181. package/src/e2e_p2p/inactivity_slash_test.ts +8 -7
  182. package/src/e2e_p2p/p2p_network.ts +93 -49
  183. package/src/e2e_p2p/reqresp/utils.ts +84 -17
  184. package/src/e2e_p2p/shared.ts +109 -65
  185. package/src/e2e_storage_proof/fixtures/storage_proof.json +915 -0
  186. package/src/e2e_storage_proof/fixtures/storage_proof_fetcher.ts +190 -0
  187. package/src/e2e_storage_proof/fixtures/storage_proof_fixture.ts +173 -0
  188. package/src/e2e_token_contract/token_contract_test.ts +38 -11
  189. package/src/fixtures/authwit_proxy.ts +54 -0
  190. package/src/fixtures/dumps/epoch_proof_result.json +1 -1
  191. package/src/fixtures/e2e_prover_test.ts +49 -56
  192. package/src/fixtures/elu_monitor.ts +126 -0
  193. package/src/fixtures/fixtures.ts +93 -0
  194. package/src/fixtures/get_bb_config.ts +7 -6
  195. package/src/fixtures/ha_setup.ts +188 -0
  196. package/src/fixtures/index.ts +1 -0
  197. package/src/fixtures/schnorr_hardcoded_account_contract.ts +49 -0
  198. package/src/fixtures/setup.ts +272 -233
  199. package/src/fixtures/setup_p2p_test.ts +37 -32
  200. package/src/fixtures/token_utils.ts +3 -3
  201. package/src/fixtures/utils.ts +2 -0
  202. package/src/forward-compatibility/wallet_rpc_client.ts +14 -0
  203. package/src/forward-compatibility/wallet_service.ts +104 -0
  204. package/src/guides/up_quick_start.sh +3 -5
  205. package/src/install_legacy_contracts.cjs +75 -0
  206. package/src/legacy-jest-resolver.cjs +112 -0
  207. package/src/shared/cross_chain_test_harness.ts +27 -13
  208. package/src/shared/gas_portal_test_harness.ts +21 -11
  209. package/src/shared/index.ts +1 -0
  210. package/src/shared/jest_setup.ts +51 -1
  211. package/src/shared/mock_state_view.ts +188 -0
  212. package/src/shared/submit-transactions.ts +3 -2
  213. package/src/shared/uniswap_l1_l2.ts +103 -54
  214. package/src/shared/wait_for_l1_to_l2_message.ts +23 -0
  215. package/src/simulators/lending_simulator.ts +32 -14
  216. package/src/simulators/token_simulator.ts +6 -30
  217. package/src/spartan/setup_test_wallets.ts +146 -35
  218. package/src/spartan/tx_metrics.ts +82 -24
  219. package/src/spartan/utils/bot.ts +4 -1
  220. package/src/spartan/utils/config.ts +3 -0
  221. package/src/spartan/utils/index.ts +8 -1
  222. package/src/spartan/utils/k8s.ts +8 -0
  223. package/src/spartan/utils/nodes.ts +17 -12
  224. package/src/spartan/utils/pod_logs.ts +99 -0
  225. package/src/spartan/utils/scripts.ts +43 -7
  226. package/src/test-wallet/test_wallet.ts +376 -0
  227. package/src/test-wallet/utils.ts +108 -0
  228. package/src/test-wallet/wallet_worker_script.ts +63 -0
  229. package/src/test-wallet/worker_wallet.ts +218 -0
  230. package/src/test-wallet/worker_wallet_schema.ts +13 -0
@@ -8,7 +8,12 @@ import type { ExtendedViemWalletClient } from '@aztec/ethereum/types';
8
8
  import { retryUntil } from '@aztec/foundation/retry';
9
9
  import { FeeJuiceContract } from '@aztec/noir-contracts.js/FeeJuice';
10
10
  import { ProtocolContractAddress } from '@aztec/protocol-contracts';
11
- import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
11
+ import type { AztecNodeAdmin, AztecNodeDebug } from '@aztec/stdlib/interfaces/client';
12
+
13
+ import { waitForL1ToL2MessageSeen } from './wait_for_l1_to_l2_message.js';
14
+
15
+ /** Aztec node that may expose the debug mining API in local e2e setups. */
16
+ type MiningAztecNode = AztecNode & Partial<AztecNodeDebug>;
12
17
 
13
18
  export interface IGasBridgingTestHarness {
14
19
  getL1FeeJuiceBalance(address: EthAddress): Promise<bigint>;
@@ -19,7 +24,7 @@ export interface IGasBridgingTestHarness {
19
24
  }
20
25
 
21
26
  export interface FeeJuicePortalTestingHarnessFactoryConfig {
22
- aztecNode: AztecNode;
27
+ aztecNode: MiningAztecNode;
23
28
  aztecNodeAdmin?: AztecNodeAdmin;
24
29
  l1Client: ExtendedViemWalletClient;
25
30
  wallet: Wallet;
@@ -75,7 +80,7 @@ export class GasBridgingTestHarness implements IGasBridgingTestHarness {
75
80
 
76
81
  constructor(
77
82
  /** Aztec node */
78
- public aztecNode: AztecNode,
83
+ public aztecNode: MiningAztecNode,
79
84
  /** Aztec node admin interface */
80
85
  public aztecNodeAdmin: AztecNodeAdmin | undefined,
81
86
  /** Wallet. */
@@ -131,7 +136,7 @@ export class GasBridgingTestHarness implements IGasBridgingTestHarness {
131
136
  }
132
137
 
133
138
  async getL2PublicBalanceOf(owner: AztecAddress) {
134
- return await this.feeJuice.methods.balance_of_public(owner).simulate({ from: owner });
139
+ return (await this.feeJuice.methods.balance_of_public(owner).simulate({ from: owner })).result;
135
140
  }
136
141
 
137
142
  async expectPublicBalanceOnL2(owner: AztecAddress, expectedBalance: bigint) {
@@ -144,8 +149,7 @@ export class GasBridgingTestHarness implements IGasBridgingTestHarness {
144
149
  await this.mintTokensOnL1();
145
150
  const claim = await this.sendTokensToPortalPublic(bridgeAmount, owner);
146
151
 
147
- const isSynced = async () => await this.aztecNode.isL1ToL2MessageSynced(Fr.fromHexString(claim.messageHash));
148
- await retryUntil(isSynced, `message ${claim.messageHash} sync`, 24, 1);
152
+ await waitForL1ToL2MessageSeen(this.aztecNode, Fr.fromHexString(claim.messageHash), { timeoutSeconds: 24 });
149
153
 
150
154
  // Progress by 2 L2 blocks so that the l1ToL2Message added above will be available to use on L2.
151
155
  await this.advanceL2Block();
@@ -163,6 +167,11 @@ export class GasBridgingTestHarness implements IGasBridgingTestHarness {
163
167
  }
164
168
 
165
169
  private async advanceL2Block() {
170
+ if (this.aztecNode.mineBlock) {
171
+ await this.aztecNode.mineBlock();
172
+ return;
173
+ }
174
+
166
175
  const initialBlockNumber = await this.aztecNode.getBlockNumber();
167
176
 
168
177
  let minTxsPerBlock = undefined;
@@ -171,11 +180,12 @@ export class GasBridgingTestHarness implements IGasBridgingTestHarness {
171
180
  await this.aztecNodeAdmin.setConfig({ minTxsPerBlock: 0 }); // Set to 0 to ensure we can advance the block
172
181
  }
173
182
 
174
- await retryUntil(async () => (await this.aztecNode.getBlockNumber()) >= initialBlockNumber + 1);
175
-
176
- if (this.aztecNodeAdmin && minTxsPerBlock !== undefined) {
177
- await this.aztecNodeAdmin.setConfig({ minTxsPerBlock });
183
+ try {
184
+ await retryUntil(async () => (await this.aztecNode.getBlockNumber()) >= initialBlockNumber + 1);
185
+ } finally {
186
+ if (this.aztecNodeAdmin && minTxsPerBlock !== undefined) {
187
+ await this.aztecNodeAdmin.setConfig({ minTxsPerBlock });
188
+ }
178
189
  }
179
190
  }
180
191
  }
181
- // docs:end:cross_chain_test_harness
@@ -1 +1,2 @@
1
1
  export { uniswapL1L2TestSuite } from './uniswap_l1_l2.js';
2
+ export { MockStateView, diffInBps } from './mock_state_view.js';
@@ -1,8 +1,19 @@
1
1
  import { createLogger } from '@aztec/aztec.js/log';
2
2
 
3
- import { beforeEach, expect } from '@jest/globals';
3
+ import { afterAll, afterEach, beforeEach, expect } from '@jest/globals';
4
+ import { readlinkSync } from 'fs';
4
5
  import { basename } from 'path';
5
6
 
7
+ import { EluMonitor } from '../fixtures/elu_monitor.js';
8
+
9
+ const eluMonitor = process.env.ELU_MONITOR_FILE
10
+ ? new EluMonitor(process.env.ELU_MONITOR_FILE, Number(process.env.ELU_MONITOR_INTERVAL_MS) || undefined)
11
+ : undefined;
12
+
13
+ if (eluMonitor) {
14
+ process.on('exit', () => eluMonitor.stop());
15
+ }
16
+
6
17
  beforeEach(() => {
7
18
  const { testPath, currentTestName } = expect.getState();
8
19
  if (!testPath || !currentTestName) {
@@ -10,4 +21,43 @@ beforeEach(() => {
10
21
  }
11
22
  const logger = createLogger(`e2e:${basename(testPath).replace('.test.ts', '')}`);
12
23
  logger.info(`Running test: ${currentTestName}`);
24
+ eluMonitor?.startTest(currentTestName);
25
+ });
26
+
27
+ afterEach(() => {
28
+ eluMonitor?.stopTest();
29
+ });
30
+
31
+ // Log leaked handles after all tests complete. This runs after test-level afterAll hooks,
32
+ // so any handles still alive at this point were not properly cleaned up during teardown.
33
+ // This diagnostic helps identify the source of exit hangs without masking them.
34
+ afterAll(() => {
35
+ const handles = (process as any)._getActiveHandles();
36
+ if (handles.length > 0) {
37
+ const details = handles.map((h: any) => {
38
+ const type = h?.constructor?.name ?? typeof h;
39
+ const fd = h?.fd ?? h?._handle?.fd ?? '?';
40
+ const destroyed = h?.destroyed ?? '?';
41
+ const hasRef = typeof h?.hasRef === 'function' ? h.hasRef() : '?';
42
+ const localAddr = h?.localAddress ?? '';
43
+ const remoteAddr = h?.remoteAddress ?? '';
44
+ const localPort = h?.localPort ?? '';
45
+ const remotePort = h?.remotePort ?? '';
46
+ const proto = Object.getPrototypeOf(h)?.constructor?.name ?? '?';
47
+ const keys = Object.keys(h).slice(0, 10).join(',');
48
+ let fdTarget = '';
49
+ if (typeof fd === 'number') {
50
+ try {
51
+ fdTarget = ` -> ${readlinkSync(`/proc/self/fd/${fd}`)}`;
52
+ } catch {
53
+ // ignore
54
+ }
55
+ }
56
+ return ` ${type}(fd=${fd}, destroyed=${destroyed}, hasRef=${hasRef}${fdTarget}) proto=${proto} addr=${localAddr}:${localPort}->${remoteAddr}:${remotePort} keys=[${keys}]`;
57
+ });
58
+ process.stderr.write(
59
+ `\n[jest_setup] WARNING: ${handles.length} handle(s) still active after teardown:\n${details.join('\n')}\n` +
60
+ `These may prevent Jest from exiting. Investigate and fix the leak.\n\n`,
61
+ );
62
+ }
13
63
  });
@@ -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,7 @@ 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({ from: submitter, wait: NO_WAIT });
22
23
 
23
24
  logger.info(`Tx sent with hash ${txHash}`);
24
25
  const receipt: TxReceipt = await wallet.getTxReceipt(txHash);
@@ -11,18 +11,22 @@ import type { DeployAztecL1ContractsReturnType } from '@aztec/ethereum/deploy-az
11
11
  import { deployL1Contract } from '@aztec/ethereum/deploy-l1-contract';
12
12
  import type { ExtendedViemWalletClient } from '@aztec/ethereum/types';
13
13
  import { extractEvent } from '@aztec/ethereum/utils';
14
- import { CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
14
+ import { EpochNumber } from '@aztec/foundation/branded-types';
15
15
  import { sha256ToField } from '@aztec/foundation/crypto/sha256';
16
+ import { retryUntil } from '@aztec/foundation/retry';
16
17
  import { InboxAbi, UniswapPortalAbi, UniswapPortalBytecode } from '@aztec/l1-artifacts';
17
18
  import { UniswapContract } from '@aztec/noir-contracts.js/Uniswap';
18
19
  import { computeL2ToL1MessageHash } from '@aztec/stdlib/hash';
19
- import { computeL2ToL1MembershipWitness } from '@aztec/stdlib/messaging';
20
- import type { TestWallet } from '@aztec/test-wallet/server';
21
20
 
22
21
  import { jest } from '@jest/globals';
23
22
  import { type GetContractReturnType, getContract, parseEther, toFunctionSelector } from 'viem';
24
23
 
25
- import { type EndToEndContext, ensureAccountContractsPublished } from '../fixtures/utils.js';
24
+ import {
25
+ type EndToEndContext,
26
+ ensureAccountContractsPublished,
27
+ ensureAuthRegistryPublished,
28
+ } from '../fixtures/utils.js';
29
+ import type { TestWallet } from '../test-wallet/test_wallet.js';
26
30
  import { CrossChainTestHarness } from './cross_chain_test_harness.js';
27
31
 
28
32
  // PSA: This tests works on forked mainnet. There is a dump of the data in `dumpedState` such that we
@@ -32,7 +36,7 @@ import { CrossChainTestHarness } from './cross_chain_test_harness.js';
32
36
  // anvil --fork-url https://mainnet.infura.io/v3/9928b52099854248b3a096be07a6b23c --fork-block-number 17514288 --chain-id 31337
33
37
  // For CI, this is configured in `run_tests.sh` and `docker-compose-images.yml`
34
38
 
35
- const TIMEOUT = 360_000;
39
+ const TIMEOUT = 15 * 60 * 1000;
36
40
 
37
41
  export const uniswapL1L2TestSuite = (
38
42
  setup: () => Promise<EndToEndContext>,
@@ -84,7 +88,7 @@ export const uniswapL1L2TestSuite = (
84
88
 
85
89
  l1Client = deployL1ContractsValues.l1Client;
86
90
 
87
- t.watcher?.setIsMarkingAsProven(false);
91
+ t.watcher.setIsMarkingAsProven(false);
88
92
 
89
93
  if (Number(await l1Client.getBlockNumber()) < expectedForkBlockNumber) {
90
94
  throw new Error('This test must be run on a fork of mainnet with the expected fork block');
@@ -98,6 +102,7 @@ export const uniswapL1L2TestSuite = (
98
102
  ownerEthAddress = EthAddress.fromString((await l1Client.getAddresses())[0]);
99
103
 
100
104
  await ensureAccountContractsPublished(wallet, [ownerAddress, sponsorAddress]);
105
+ await ensureAuthRegistryPublished(wallet, ownerAddress);
101
106
 
102
107
  logger.info('Deploying DAI Portal, initializing and deploying l2 contract...');
103
108
  daiCrossChainHarness = await CrossChainTestHarness.new(
@@ -130,7 +135,9 @@ export const uniswapL1L2TestSuite = (
130
135
  client: l1Client,
131
136
  });
132
137
  // deploy l2 uniswap contract and attach to portal
133
- uniswapL2Contract = await UniswapContract.deploy(wallet, uniswapPortalAddress).send({ from: ownerAddress });
138
+ ({ contract: uniswapL2Contract } = await UniswapContract.deploy(wallet, uniswapPortalAddress).send({
139
+ from: ownerAddress,
140
+ }));
134
141
 
135
142
  const registryAddress = (await aztecNode.getNodeInfo()).l1ContractAddresses.registryAddress;
136
143
 
@@ -152,7 +159,6 @@ export const uniswapL1L2TestSuite = (
152
159
  await cleanup();
153
160
  });
154
161
 
155
- // docs:start:uniswap_private
156
162
  it('should uniswap trade on L1 from L2 funds privately (swaps WETH -> DAI)', async () => {
157
163
  const wethL1BeforeBalance = await wethCrossChainHarness.getL1BalanceOf(ownerEthAddress);
158
164
 
@@ -195,7 +201,7 @@ export const uniswapL1L2TestSuite = (
195
201
  logger.info('Withdrawing weth to L1 and sending message to swap to dai');
196
202
  const [secretForDepositingSwappedDai, secretHashForDepositingSwappedDai] = await generateClaimSecret();
197
203
 
198
- const l2UniswapInteractionReceipt = await uniswapL2Contract.methods
204
+ const { receipt: l2UniswapInteractionReceipt } = await uniswapL2Contract.methods
199
205
  .swap_private(
200
206
  wethCrossChainHarness.l2Token.address,
201
207
  wethCrossChainHarness.l2Bridge.address,
@@ -249,10 +255,13 @@ export const uniswapL1L2TestSuite = (
249
255
  // ensure that uniswap contract didn't eat the funds.
250
256
  await wethCrossChainHarness.expectPublicBalanceOnL2(uniswapL2Contract.address, 0n);
251
257
 
252
- // Since the outbox is only consumable when the epoch is proven, we need to advance to the next epoch.
253
- const checkpointNumber = CheckpointNumber.fromBlockNumber(l2UniswapInteractionReceipt.blockNumber!);
254
- const epoch = await rollup.getEpochNumberForCheckpoint(checkpointNumber);
255
- await cheatCodes.rollup.advanceToEpoch(EpochNumber(epoch + 1));
258
+ // Since the outbox is only consumable when the epoch is proven, we need to advance to the next epoch
259
+ // before we can ask the witness helper for a covering root.
260
+ const minedReceipt = await aztecNode.getTxReceipt(l2UniswapInteractionReceipt.txHash);
261
+ if (minedReceipt.epochNumber === undefined) {
262
+ throw new Error('L2 Uniswap interaction tx is not yet in an epoch');
263
+ }
264
+ await cheatCodes.rollup.advanceToEpoch(EpochNumber(minedReceipt.epochNumber + 1));
256
265
  await waitForProven(aztecNode, l2UniswapInteractionReceipt, { provenTimeout: 300 });
257
266
 
258
267
  // 5. Consume L2 to L1 message by calling uniswapPortal.swap_private()
@@ -260,17 +269,29 @@ export const uniswapL1L2TestSuite = (
260
269
  const daiL1BalanceOfPortalBeforeSwap = await daiCrossChainHarness.getL1BalanceOf(
261
270
  daiCrossChainHarness.tokenPortalAddress,
262
271
  );
263
- const swapResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, swapPrivateLeaf);
264
- const withdrawResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, withdrawLeaf);
272
+ const swapResult = await retryUntil(
273
+ () => aztecNode.getL2ToL1MembershipWitness(minedReceipt.txHash, swapPrivateLeaf),
274
+ 'swap private l2 to l1 witness',
275
+ 60,
276
+ 1,
277
+ );
278
+ const { epochNumber: epoch, numCheckpointsInEpoch } = swapResult;
279
+ const withdrawResult = await retryUntil(
280
+ () => aztecNode.getL2ToL1MembershipWitness(minedReceipt.txHash, withdrawLeaf),
281
+ 'withdraw l2 to l1 witness',
282
+ 60,
283
+ 1,
284
+ );
265
285
 
266
- const swapPrivateL2MessageIndex = swapResult!.leafIndex;
267
- const swapPrivateSiblingPath = swapResult!.siblingPath;
286
+ const swapPrivateL2MessageIndex = swapResult.leafIndex;
287
+ const swapPrivateSiblingPath = swapResult.siblingPath;
268
288
 
269
- const withdrawL2MessageIndex = withdrawResult!.leafIndex;
270
- const withdrawSiblingPath = withdrawResult!.siblingPath;
289
+ const withdrawL2MessageIndex = withdrawResult.leafIndex;
290
+ const withdrawSiblingPath = withdrawResult.siblingPath;
271
291
 
272
292
  const withdrawMessageMetadata = {
273
293
  _epoch: BigInt(epoch),
294
+ _numCheckpointsInEpoch: BigInt(withdrawResult.numCheckpointsInEpoch),
274
295
  _leafIndex: BigInt(withdrawL2MessageIndex),
275
296
  _path: withdrawSiblingPath
276
297
  .toBufferArray()
@@ -279,6 +300,7 @@ export const uniswapL1L2TestSuite = (
279
300
 
280
301
  const swapPrivateMessageMetadata = {
281
302
  _epoch: BigInt(epoch),
303
+ _numCheckpointsInEpoch: BigInt(numCheckpointsInEpoch),
282
304
  _leafIndex: BigInt(swapPrivateL2MessageIndex),
283
305
  _path: swapPrivateSiblingPath
284
306
  .toBufferArray()
@@ -336,10 +358,8 @@ export const uniswapL1L2TestSuite = (
336
358
  logger.info('WETH balance after swap : ', wethL2BalanceAfterSwap.toString());
337
359
  logger.info('DAI balance after swap : ', daiL2BalanceAfterSwap.toString());
338
360
  });
339
- // docs:end:uniswap_private
340
361
 
341
362
  // TODO(#7463): reenable look into this failure https://github.com/AztecProtocol/aztec-packages/actions/runs/9912612912/job/27388320150?pr=7462
342
- // // docs:start:uniswap_public
343
363
  // it('should uniswap trade on L1 from L2 funds publicly (swaps WETH -> DAI)', async () => {
344
364
  // const wethL1BeforeBalance = await wethCrossChainHarness.getL1BalanceOf(ownerEthAddress);
345
365
 
@@ -572,7 +592,6 @@ export const uniswapL1L2TestSuite = (
572
592
  // logger.info('WETH balance after swap : ', wethL2BalanceAfterSwap.toString());
573
593
  // logger.info('DAI balance after swap : ', daiL2BalanceAfterSwap.toString());
574
594
  // });
575
- // // docs:end:uniswap_public
576
595
 
577
596
  // Edge cases for the private flow:
578
597
  // note - tests for uniswapPortal.sol and minting asset on L2 are covered in other tests.
@@ -787,7 +806,7 @@ export const uniswapL1L2TestSuite = (
787
806
  logger.info('Withdrawing weth to L1 and sending message to swap to dai');
788
807
 
789
808
  const [, secretHashForDepositingSwappedDai] = await generateClaimSecret();
790
- const withdrawReceipt = await uniswapL2Contract.methods
809
+ const { receipt: withdrawReceipt } = await uniswapL2Contract.methods
791
810
  .swap_private(
792
811
  wethCrossChainHarness.l2Token.address,
793
812
  wethCrossChainHarness.l2Bridge.address,
@@ -838,20 +857,41 @@ export const uniswapL1L2TestSuite = (
838
857
  chainId: new Fr(l1Client.chain.id),
839
858
  });
840
859
 
841
- const epoch = await rollup.getEpochNumberForCheckpoint(
842
- CheckpointNumber.fromBlockNumber(withdrawReceipt.blockNumber!),
860
+ // ensure that user's funds were burnt
861
+ await wethCrossChainHarness.expectPrivateBalanceOnL2(ownerAddress, wethL2BalanceBeforeSwap - wethAmountToBridge);
862
+
863
+ // Since the outbox is only consumable when the epoch is proven, we need to advance to the next epoch
864
+ // before we can ask the witness helper for a covering root.
865
+ const minedReceipt = await aztecNode.getTxReceipt(withdrawReceipt.txHash);
866
+ if (minedReceipt.epochNumber === undefined) {
867
+ throw new Error('Withdraw tx is not yet in an epoch');
868
+ }
869
+ await cheatCodes.rollup.advanceToEpoch(EpochNumber(minedReceipt.epochNumber + 1));
870
+ await waitForProven(aztecNode, withdrawReceipt, { provenTimeout: 300 });
871
+
872
+ const swapResult = await retryUntil(
873
+ () => aztecNode.getL2ToL1MembershipWitness(minedReceipt.txHash, swapPrivateLeaf),
874
+ 'swap private l2 to l1 witness',
875
+ 60,
876
+ 1,
877
+ );
878
+ const { epochNumber: epoch, numCheckpointsInEpoch } = swapResult;
879
+ const withdrawResult = await retryUntil(
880
+ () => aztecNode.getL2ToL1MembershipWitness(minedReceipt.txHash, withdrawLeaf),
881
+ 'withdraw l2 to l1 witness',
882
+ 60,
883
+ 1,
843
884
  );
844
- const swapResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, swapPrivateLeaf);
845
- const withdrawResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, withdrawLeaf);
846
885
 
847
- const swapPrivateL2MessageIndex = swapResult!.leafIndex;
848
- const swapPrivateSiblingPath = swapResult!.siblingPath;
886
+ const swapPrivateL2MessageIndex = swapResult.leafIndex;
887
+ const swapPrivateSiblingPath = swapResult.siblingPath;
849
888
 
850
- const withdrawL2MessageIndex = withdrawResult!.leafIndex;
851
- const withdrawSiblingPath = withdrawResult!.siblingPath;
889
+ const withdrawL2MessageIndex = withdrawResult.leafIndex;
890
+ const withdrawSiblingPath = withdrawResult.siblingPath;
852
891
 
853
892
  const withdrawMessageMetadata = {
854
893
  _epoch: BigInt(epoch),
894
+ _numCheckpointsInEpoch: BigInt(withdrawResult.numCheckpointsInEpoch),
855
895
  _leafIndex: BigInt(withdrawL2MessageIndex),
856
896
  _path: withdrawSiblingPath
857
897
  .toBufferArray()
@@ -860,19 +900,13 @@ export const uniswapL1L2TestSuite = (
860
900
 
861
901
  const swapPrivateMessageMetadata = {
862
902
  _epoch: BigInt(epoch),
903
+ _numCheckpointsInEpoch: BigInt(numCheckpointsInEpoch),
863
904
  _leafIndex: BigInt(swapPrivateL2MessageIndex),
864
905
  _path: swapPrivateSiblingPath
865
906
  .toBufferArray()
866
907
  .map((buf: Buffer) => `0x${buf.toString('hex')}`) as readonly `0x${string}`[],
867
908
  };
868
909
 
869
- // ensure that user's funds were burnt
870
- await wethCrossChainHarness.expectPrivateBalanceOnL2(ownerAddress, wethL2BalanceBeforeSwap - wethAmountToBridge);
871
-
872
- // Since the outbox is only consumable when the epoch is proven, we need to advance to the next epoch.
873
- await cheatCodes.rollup.advanceToEpoch(EpochNumber(epoch + 1));
874
- await waitForProven(aztecNode, withdrawReceipt, { provenTimeout: 300 });
875
-
876
910
  // On L1 call swap_public!
877
911
  logger.info('call swap_public on L1');
878
912
  const swapArgs = [
@@ -916,7 +950,7 @@ export const uniswapL1L2TestSuite = (
916
950
 
917
951
  // Call swap_public on L2
918
952
  const secretHashForDepositingSwappedDai = Fr.random();
919
- const withdrawReceipt = await uniswapL2Contract.methods
953
+ const { receipt: withdrawReceipt } = await uniswapL2Contract.methods
920
954
  .swap_public(
921
955
  ownerAddress,
922
956
  wethCrossChainHarness.l2Bridge.address,
@@ -972,20 +1006,41 @@ export const uniswapL1L2TestSuite = (
972
1006
  chainId: new Fr(l1Client.chain.id),
973
1007
  });
974
1008
 
975
- const epoch = await rollup.getEpochNumberForCheckpoint(
976
- CheckpointNumber.fromBlockNumber(withdrawReceipt.blockNumber!),
1009
+ // check weth balance of owner on L2 (we first bridged `wethAmountToBridge` into L2 and now withdrew it!)
1010
+ await wethCrossChainHarness.expectPublicBalanceOnL2(ownerAddress, 0n);
1011
+
1012
+ // Since the outbox is only consumable when the epoch is proven, we need to advance to the next epoch
1013
+ // before we can ask the witness helper for a covering root.
1014
+ const minedReceipt = await aztecNode.getTxReceipt(withdrawReceipt.txHash);
1015
+ if (minedReceipt.epochNumber === undefined) {
1016
+ throw new Error('Withdraw tx is not yet in an epoch');
1017
+ }
1018
+ await cheatCodes.rollup.advanceToEpoch(EpochNumber(minedReceipt.epochNumber + 1));
1019
+ await waitForProven(aztecNode, withdrawReceipt, { provenTimeout: 300 });
1020
+
1021
+ const swapResult = await retryUntil(
1022
+ () => aztecNode.getL2ToL1MembershipWitness(minedReceipt.txHash, swapPublicLeaf),
1023
+ 'swap public l2 to l1 witness',
1024
+ 60,
1025
+ 1,
1026
+ );
1027
+ const { epochNumber: epoch, numCheckpointsInEpoch } = swapResult;
1028
+ const withdrawResult = await retryUntil(
1029
+ () => aztecNode.getL2ToL1MembershipWitness(minedReceipt.txHash, withdrawLeaf),
1030
+ 'withdraw l2 to l1 witness',
1031
+ 60,
1032
+ 1,
977
1033
  );
978
- const swapResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, swapPublicLeaf);
979
- const withdrawResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, withdrawLeaf);
980
1034
 
981
- const swapPublicL2MessageIndex = swapResult!.leafIndex;
982
- const swapPublicSiblingPath = swapResult!.siblingPath;
1035
+ const swapPublicL2MessageIndex = swapResult.leafIndex;
1036
+ const swapPublicSiblingPath = swapResult.siblingPath;
983
1037
 
984
- const withdrawL2MessageIndex = withdrawResult!.leafIndex;
985
- const withdrawSiblingPath = withdrawResult!.siblingPath;
1038
+ const withdrawL2MessageIndex = withdrawResult.leafIndex;
1039
+ const withdrawSiblingPath = withdrawResult.siblingPath;
986
1040
 
987
1041
  const withdrawMessageMetadata = {
988
1042
  _epoch: BigInt(epoch),
1043
+ _numCheckpointsInEpoch: BigInt(withdrawResult.numCheckpointsInEpoch),
989
1044
  _leafIndex: BigInt(withdrawL2MessageIndex),
990
1045
  _path: withdrawSiblingPath
991
1046
  .toBufferArray()
@@ -994,19 +1049,13 @@ export const uniswapL1L2TestSuite = (
994
1049
 
995
1050
  const swapPublicMessageMetadata = {
996
1051
  _epoch: BigInt(epoch),
1052
+ _numCheckpointsInEpoch: BigInt(numCheckpointsInEpoch),
997
1053
  _leafIndex: BigInt(swapPublicL2MessageIndex),
998
1054
  _path: swapPublicSiblingPath
999
1055
  .toBufferArray()
1000
1056
  .map((buf: Buffer) => `0x${buf.toString('hex')}`) as readonly `0x${string}`[],
1001
1057
  };
1002
1058
 
1003
- // check weth balance of owner on L2 (we first bridged `wethAmountToBridge` into L2 and now withdrew it!)
1004
- await wethCrossChainHarness.expectPublicBalanceOnL2(ownerAddress, 0n);
1005
-
1006
- // Since the outbox is only consumable when the epoch is proven, we need to advance to the next epoch.
1007
- await cheatCodes.rollup.advanceToEpoch(EpochNumber(epoch + 1));
1008
- await waitForProven(aztecNode, withdrawReceipt, { provenTimeout: 300 });
1009
-
1010
1059
  // Call swap_private on L1
1011
1060
  logger.info('Execute withdraw and swap on the uniswapPortal!');
1012
1061