@aztec/end-to-end 0.0.1-commit.04852196a → 0.0.1-commit.04d373f

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 (175) 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 +2 -2
  6. package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -1
  7. package/dest/bench/client_flows/client_flows_benchmark.js +27 -38
  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 +2 -0
  11. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +5 -4
  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 +14 -5
  14. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts +15 -4
  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 +39 -7
  17. package/dest/e2e_deploy_contract/deploy_test.d.ts +3 -3
  18. package/dest/e2e_deploy_contract/deploy_test.d.ts.map +1 -1
  19. package/dest/e2e_deploy_contract/deploy_test.js +2 -1
  20. package/dest/e2e_epochs/epochs_test.d.ts +25 -2
  21. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  22. package/dest/e2e_epochs/epochs_test.js +88 -14
  23. package/dest/e2e_fees/fees_test.d.ts +5 -2
  24. package/dest/e2e_fees/fees_test.d.ts.map +1 -1
  25. package/dest/e2e_fees/fees_test.js +32 -6
  26. package/dest/e2e_nested_contract/nested_contract_test.d.ts +3 -3
  27. package/dest/e2e_nested_contract/nested_contract_test.d.ts.map +1 -1
  28. package/dest/e2e_nested_contract/nested_contract_test.js +2 -1
  29. package/dest/e2e_p2p/inactivity_slash_test.d.ts +1 -1
  30. package/dest/e2e_p2p/inactivity_slash_test.d.ts.map +1 -1
  31. package/dest/e2e_p2p/inactivity_slash_test.js +5 -3
  32. package/dest/e2e_p2p/p2p_network.d.ts +10 -9
  33. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  34. package/dest/e2e_p2p/p2p_network.js +46 -27
  35. package/dest/e2e_p2p/reqresp/utils.d.ts +1 -1
  36. package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -1
  37. package/dest/e2e_p2p/reqresp/utils.js +42 -13
  38. package/dest/e2e_p2p/shared.d.ts +16 -12
  39. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  40. package/dest/e2e_p2p/shared.js +57 -57
  41. package/dest/e2e_token_contract/token_contract_test.d.ts +3 -3
  42. package/dest/e2e_token_contract/token_contract_test.d.ts.map +1 -1
  43. package/dest/e2e_token_contract/token_contract_test.js +4 -2
  44. package/dest/fixtures/authwit_proxy.d.ts +1 -1
  45. package/dest/fixtures/authwit_proxy.d.ts.map +1 -1
  46. package/dest/fixtures/authwit_proxy.js +4 -0
  47. package/dest/fixtures/e2e_prover_test.d.ts +6 -5
  48. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
  49. package/dest/fixtures/e2e_prover_test.js +9 -13
  50. package/dest/fixtures/fixtures.d.ts +73 -1
  51. package/dest/fixtures/fixtures.d.ts.map +1 -1
  52. package/dest/fixtures/fixtures.js +68 -0
  53. package/dest/fixtures/get_bb_config.d.ts +1 -1
  54. package/dest/fixtures/get_bb_config.d.ts.map +1 -1
  55. package/dest/fixtures/get_bb_config.js +5 -5
  56. package/dest/fixtures/ha_setup.d.ts +2 -2
  57. package/dest/fixtures/ha_setup.d.ts.map +1 -1
  58. package/dest/fixtures/ha_setup.js +1 -1
  59. package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts +25 -0
  60. package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts.map +1 -0
  61. package/dest/fixtures/schnorr_hardcoded_account_contract.js +37 -0
  62. package/dest/fixtures/setup.d.ts +43 -11
  63. package/dest/fixtures/setup.d.ts.map +1 -1
  64. package/dest/fixtures/setup.js +135 -26
  65. package/dest/fixtures/setup_p2p_test.d.ts +10 -6
  66. package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
  67. package/dest/fixtures/setup_p2p_test.js +8 -8
  68. package/dest/fixtures/token_utils.d.ts +1 -1
  69. package/dest/fixtures/token_utils.d.ts.map +1 -1
  70. package/dest/fixtures/token_utils.js +2 -5
  71. package/dest/fixtures/utils.d.ts +2 -2
  72. package/dest/fixtures/utils.d.ts.map +1 -1
  73. package/dest/fixtures/utils.js +1 -1
  74. package/dest/forward-compatibility/wallet_rpc_client.d.ts +7 -0
  75. package/dest/forward-compatibility/wallet_rpc_client.d.ts.map +1 -0
  76. package/dest/forward-compatibility/wallet_rpc_client.js +15 -0
  77. package/dest/forward-compatibility/wallet_service.d.ts +3 -0
  78. package/dest/forward-compatibility/wallet_service.d.ts.map +1 -0
  79. package/dest/forward-compatibility/wallet_service.js +109 -0
  80. package/dest/install_legacy_contracts.d.cts +10 -0
  81. package/dest/install_legacy_contracts.d.cts.map +1 -0
  82. package/dest/legacy-jest-resolver.d.cts +3 -0
  83. package/dest/legacy-jest-resolver.d.cts.map +1 -0
  84. package/dest/shared/cross_chain_test_harness.d.ts +4 -2
  85. package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
  86. package/dest/shared/cross_chain_test_harness.js +9 -5
  87. package/dest/shared/gas_portal_test_harness.d.ts +8 -5
  88. package/dest/shared/gas_portal_test_harness.d.ts.map +1 -1
  89. package/dest/shared/gas_portal_test_harness.js +17 -8
  90. package/dest/shared/uniswap_l1_l2.d.ts +1 -1
  91. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  92. package/dest/shared/uniswap_l1_l2.js +55 -34
  93. package/dest/shared/wait_for_l1_to_l2_message.d.ts +13 -0
  94. package/dest/shared/wait_for_l1_to_l2_message.d.ts.map +1 -0
  95. package/dest/shared/wait_for_l1_to_l2_message.js +10 -0
  96. package/dest/simulators/lending_simulator.d.ts +10 -3
  97. package/dest/simulators/lending_simulator.d.ts.map +1 -1
  98. package/dest/simulators/lending_simulator.js +24 -12
  99. package/dest/simulators/token_simulator.js +1 -1
  100. package/dest/spartan/setup_test_wallets.d.ts +4 -2
  101. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  102. package/dest/spartan/setup_test_wallets.js +73 -41
  103. package/dest/spartan/tx_metrics.d.ts +18 -4
  104. package/dest/spartan/tx_metrics.d.ts.map +1 -1
  105. package/dest/spartan/tx_metrics.js +73 -20
  106. package/dest/spartan/utils/config.d.ts +9 -32
  107. package/dest/spartan/utils/config.d.ts.map +1 -1
  108. package/dest/spartan/utils/config.js +1 -0
  109. package/dest/spartan/utils/index.d.ts +2 -1
  110. package/dest/spartan/utils/index.d.ts.map +1 -1
  111. package/dest/spartan/utils/index.js +2 -0
  112. package/dest/spartan/utils/nodes.js +2 -2
  113. package/dest/spartan/utils/pod_logs.d.ts +25 -0
  114. package/dest/spartan/utils/pod_logs.d.ts.map +1 -0
  115. package/dest/spartan/utils/pod_logs.js +74 -0
  116. package/dest/test-wallet/test_wallet.d.ts +25 -23
  117. package/dest/test-wallet/test_wallet.d.ts.map +1 -1
  118. package/dest/test-wallet/test_wallet.js +146 -87
  119. package/dest/test-wallet/utils.d.ts +3 -3
  120. package/dest/test-wallet/utils.d.ts.map +1 -1
  121. package/dest/test-wallet/utils.js +2 -7
  122. package/dest/test-wallet/wallet_worker_script.js +2 -2
  123. package/dest/test-wallet/worker_wallet.d.ts +5 -4
  124. package/dest/test-wallet/worker_wallet.d.ts.map +1 -1
  125. package/dest/test-wallet/worker_wallet.js +5 -1
  126. package/dest/test-wallet/worker_wallet_schema.d.ts +110 -224
  127. package/dest/test-wallet/worker_wallet_schema.d.ts.map +1 -1
  128. package/dest/test-wallet/worker_wallet_schema.js +14 -2
  129. package/package.json +46 -42
  130. package/src/bench/client_flows/benchmark.ts +19 -0
  131. package/src/bench/client_flows/client_flows_benchmark.ts +64 -53
  132. package/src/bench/utils.ts +2 -1
  133. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +24 -10
  134. package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +49 -11
  135. package/src/e2e_deploy_contract/deploy_test.ts +3 -2
  136. package/src/e2e_epochs/epochs_test.ts +99 -11
  137. package/src/e2e_fees/fees_test.ts +37 -4
  138. package/src/e2e_nested_contract/nested_contract_test.ts +3 -1
  139. package/src/e2e_p2p/inactivity_slash_test.ts +5 -3
  140. package/src/e2e_p2p/p2p_network.ts +57 -39
  141. package/src/e2e_p2p/reqresp/utils.ts +51 -12
  142. package/src/e2e_p2p/shared.ts +57 -72
  143. package/src/e2e_token_contract/token_contract_test.ts +12 -2
  144. package/src/fixtures/authwit_proxy.ts +4 -0
  145. package/src/fixtures/e2e_prover_test.ts +15 -18
  146. package/src/fixtures/fixtures.ts +86 -0
  147. package/src/fixtures/get_bb_config.ts +7 -6
  148. package/src/fixtures/ha_setup.ts +4 -2
  149. package/src/fixtures/schnorr_hardcoded_account_contract.ts +49 -0
  150. package/src/fixtures/setup.ts +171 -31
  151. package/src/fixtures/setup_p2p_test.ts +13 -9
  152. package/src/fixtures/token_utils.ts +1 -4
  153. package/src/fixtures/utils.ts +2 -0
  154. package/src/forward-compatibility/wallet_rpc_client.ts +14 -0
  155. package/src/forward-compatibility/wallet_service.ts +104 -0
  156. package/src/guides/up_quick_start.sh +0 -2
  157. package/src/install_legacy_contracts.cjs +75 -0
  158. package/src/legacy-jest-resolver.cjs +112 -0
  159. package/src/shared/cross_chain_test_harness.ts +14 -4
  160. package/src/shared/gas_portal_test_harness.ts +20 -10
  161. package/src/shared/uniswap_l1_l2.ts +71 -46
  162. package/src/shared/wait_for_l1_to_l2_message.ts +23 -0
  163. package/src/simulators/lending_simulator.ts +28 -12
  164. package/src/simulators/token_simulator.ts +1 -1
  165. package/src/spartan/setup_test_wallets.ts +98 -37
  166. package/src/spartan/tx_metrics.ts +81 -23
  167. package/src/spartan/utils/config.ts +1 -0
  168. package/src/spartan/utils/index.ts +3 -0
  169. package/src/spartan/utils/nodes.ts +2 -2
  170. package/src/spartan/utils/pod_logs.ts +99 -0
  171. package/src/test-wallet/test_wallet.ts +174 -104
  172. package/src/test-wallet/utils.ts +3 -7
  173. package/src/test-wallet/wallet_worker_script.ts +2 -2
  174. package/src/test-wallet/worker_wallet.ts +9 -4
  175. package/src/test-wallet/worker_wallet_schema.ts +2 -2
@@ -21,7 +21,11 @@ import { computeL2ToL1MembershipWitness } from '@aztec/stdlib/messaging';
21
21
  import { jest } from '@jest/globals';
22
22
  import { type GetContractReturnType, getContract, parseEther, toFunctionSelector } from 'viem';
23
23
 
24
- import { type EndToEndContext, ensureAccountContractsPublished } from '../fixtures/utils.js';
24
+ import {
25
+ type EndToEndContext,
26
+ ensureAccountContractsPublished,
27
+ ensureAuthRegistryPublished,
28
+ } from '../fixtures/utils.js';
25
29
  import type { TestWallet } from '../test-wallet/test_wallet.js';
26
30
  import { CrossChainTestHarness } from './cross_chain_test_harness.js';
27
31
 
@@ -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>,
@@ -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(
@@ -154,7 +159,6 @@ export const uniswapL1L2TestSuite = (
154
159
  await cleanup();
155
160
  });
156
161
 
157
- // docs:start:uniswap_private
158
162
  it('should uniswap trade on L1 from L2 funds privately (swaps WETH -> DAI)', async () => {
159
163
  const wethL1BeforeBalance = await wethCrossChainHarness.getL1BalanceOf(ownerEthAddress);
160
164
 
@@ -251,10 +255,13 @@ export const uniswapL1L2TestSuite = (
251
255
  // ensure that uniswap contract didn't eat the funds.
252
256
  await wethCrossChainHarness.expectPublicBalanceOnL2(uniswapL2Contract.address, 0n);
253
257
 
254
- // 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);
257
- 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));
258
265
  await waitForProven(aztecNode, l2UniswapInteractionReceipt, { provenTimeout: 300 });
259
266
 
260
267
  // 5. Consume L2 to L1 message by calling uniswapPortal.swap_private()
@@ -262,17 +269,21 @@ export const uniswapL1L2TestSuite = (
262
269
  const daiL1BalanceOfPortalBeforeSwap = await daiCrossChainHarness.getL1BalanceOf(
263
270
  daiCrossChainHarness.tokenPortalAddress,
264
271
  );
265
- const swapResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, swapPrivateLeaf);
266
- const withdrawResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, withdrawLeaf);
272
+ // Fetch the outbox roots once and share them between the two witnesses in this epoch.
273
+ const epochRoots = await wethCrossChainHarness.outboxContract.getRoots(minedReceipt.epochNumber);
274
+ const swapResult = (await computeL2ToL1MembershipWitness(aztecNode, epochRoots, swapPrivateLeaf, minedReceipt))!;
275
+ const { epochNumber: epoch, numCheckpointsInEpoch } = swapResult;
276
+ const withdrawResult = (await computeL2ToL1MembershipWitness(aztecNode, epochRoots, withdrawLeaf, minedReceipt))!;
267
277
 
268
- const swapPrivateL2MessageIndex = swapResult!.leafIndex;
269
- const swapPrivateSiblingPath = swapResult!.siblingPath;
278
+ const swapPrivateL2MessageIndex = swapResult.leafIndex;
279
+ const swapPrivateSiblingPath = swapResult.siblingPath;
270
280
 
271
- const withdrawL2MessageIndex = withdrawResult!.leafIndex;
272
- const withdrawSiblingPath = withdrawResult!.siblingPath;
281
+ const withdrawL2MessageIndex = withdrawResult.leafIndex;
282
+ const withdrawSiblingPath = withdrawResult.siblingPath;
273
283
 
274
284
  const withdrawMessageMetadata = {
275
285
  _epoch: BigInt(epoch),
286
+ _numCheckpointsInEpoch: BigInt(withdrawResult.numCheckpointsInEpoch),
276
287
  _leafIndex: BigInt(withdrawL2MessageIndex),
277
288
  _path: withdrawSiblingPath
278
289
  .toBufferArray()
@@ -281,6 +292,7 @@ export const uniswapL1L2TestSuite = (
281
292
 
282
293
  const swapPrivateMessageMetadata = {
283
294
  _epoch: BigInt(epoch),
295
+ _numCheckpointsInEpoch: BigInt(numCheckpointsInEpoch),
284
296
  _leafIndex: BigInt(swapPrivateL2MessageIndex),
285
297
  _path: swapPrivateSiblingPath
286
298
  .toBufferArray()
@@ -338,10 +350,8 @@ export const uniswapL1L2TestSuite = (
338
350
  logger.info('WETH balance after swap : ', wethL2BalanceAfterSwap.toString());
339
351
  logger.info('DAI balance after swap : ', daiL2BalanceAfterSwap.toString());
340
352
  });
341
- // docs:end:uniswap_private
342
353
 
343
354
  // 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
355
  // it('should uniswap trade on L1 from L2 funds publicly (swaps WETH -> DAI)', async () => {
346
356
  // const wethL1BeforeBalance = await wethCrossChainHarness.getL1BalanceOf(ownerEthAddress);
347
357
 
@@ -574,7 +584,6 @@ export const uniswapL1L2TestSuite = (
574
584
  // logger.info('WETH balance after swap : ', wethL2BalanceAfterSwap.toString());
575
585
  // logger.info('DAI balance after swap : ', daiL2BalanceAfterSwap.toString());
576
586
  // });
577
- // // docs:end:uniswap_public
578
587
 
579
588
  // Edge cases for the private flow:
580
589
  // note - tests for uniswapPortal.sol and minting asset on L2 are covered in other tests.
@@ -840,19 +849,33 @@ export const uniswapL1L2TestSuite = (
840
849
  chainId: new Fr(l1Client.chain.id),
841
850
  });
842
851
 
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);
852
+ // ensure that user's funds were burnt
853
+ await wethCrossChainHarness.expectPrivateBalanceOnL2(ownerAddress, wethL2BalanceBeforeSwap - wethAmountToBridge);
854
+
855
+ // Since the outbox is only consumable when the epoch is proven, we need to advance to the next epoch
856
+ // before we can ask the witness helper for a covering root.
857
+ const minedReceipt = await aztecNode.getTxReceipt(withdrawReceipt.txHash);
858
+ if (minedReceipt.epochNumber === undefined) {
859
+ throw new Error('Withdraw tx is not yet in an epoch');
860
+ }
861
+ await cheatCodes.rollup.advanceToEpoch(EpochNumber(minedReceipt.epochNumber + 1));
862
+ await waitForProven(aztecNode, withdrawReceipt, { provenTimeout: 300 });
863
+
864
+ // Fetch the outbox roots once and share them between the two witnesses in this epoch.
865
+ const epochRoots = await wethCrossChainHarness.outboxContract.getRoots(minedReceipt.epochNumber);
866
+ const swapResult = (await computeL2ToL1MembershipWitness(aztecNode, epochRoots, swapPrivateLeaf, minedReceipt))!;
867
+ const { epochNumber: epoch, numCheckpointsInEpoch } = swapResult;
868
+ const withdrawResult = (await computeL2ToL1MembershipWitness(aztecNode, epochRoots, withdrawLeaf, minedReceipt))!;
847
869
 
848
- const swapPrivateL2MessageIndex = swapResult!.leafIndex;
849
- const swapPrivateSiblingPath = swapResult!.siblingPath;
870
+ const swapPrivateL2MessageIndex = swapResult.leafIndex;
871
+ const swapPrivateSiblingPath = swapResult.siblingPath;
850
872
 
851
- const withdrawL2MessageIndex = withdrawResult!.leafIndex;
852
- const withdrawSiblingPath = withdrawResult!.siblingPath;
873
+ const withdrawL2MessageIndex = withdrawResult.leafIndex;
874
+ const withdrawSiblingPath = withdrawResult.siblingPath;
853
875
 
854
876
  const withdrawMessageMetadata = {
855
877
  _epoch: BigInt(epoch),
878
+ _numCheckpointsInEpoch: BigInt(withdrawResult.numCheckpointsInEpoch),
856
879
  _leafIndex: BigInt(withdrawL2MessageIndex),
857
880
  _path: withdrawSiblingPath
858
881
  .toBufferArray()
@@ -861,19 +884,13 @@ export const uniswapL1L2TestSuite = (
861
884
 
862
885
  const swapPrivateMessageMetadata = {
863
886
  _epoch: BigInt(epoch),
887
+ _numCheckpointsInEpoch: BigInt(numCheckpointsInEpoch),
864
888
  _leafIndex: BigInt(swapPrivateL2MessageIndex),
865
889
  _path: swapPrivateSiblingPath
866
890
  .toBufferArray()
867
891
  .map((buf: Buffer) => `0x${buf.toString('hex')}`) as readonly `0x${string}`[],
868
892
  };
869
893
 
870
- // ensure that user's funds were burnt
871
- await wethCrossChainHarness.expectPrivateBalanceOnL2(ownerAddress, wethL2BalanceBeforeSwap - wethAmountToBridge);
872
-
873
- // Since the outbox is only consumable when the epoch is proven, we need to advance to the next epoch.
874
- await cheatCodes.rollup.advanceToEpoch(EpochNumber(epoch + 1));
875
- await waitForProven(aztecNode, withdrawReceipt, { provenTimeout: 300 });
876
-
877
894
  // On L1 call swap_public!
878
895
  logger.info('call swap_public on L1');
879
896
  const swapArgs = [
@@ -973,19 +990,33 @@ export const uniswapL1L2TestSuite = (
973
990
  chainId: new Fr(l1Client.chain.id),
974
991
  });
975
992
 
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);
993
+ // check weth balance of owner on L2 (we first bridged `wethAmountToBridge` into L2 and now withdrew it!)
994
+ await wethCrossChainHarness.expectPublicBalanceOnL2(ownerAddress, 0n);
995
+
996
+ // Since the outbox is only consumable when the epoch is proven, we need to advance to the next epoch
997
+ // before we can ask the witness helper for a covering root.
998
+ const minedReceipt = await aztecNode.getTxReceipt(withdrawReceipt.txHash);
999
+ if (minedReceipt.epochNumber === undefined) {
1000
+ throw new Error('Withdraw tx is not yet in an epoch');
1001
+ }
1002
+ await cheatCodes.rollup.advanceToEpoch(EpochNumber(minedReceipt.epochNumber + 1));
1003
+ await waitForProven(aztecNode, withdrawReceipt, { provenTimeout: 300 });
1004
+
1005
+ // Fetch the outbox roots once and share them between the two witnesses in this epoch.
1006
+ const epochRoots = await wethCrossChainHarness.outboxContract.getRoots(minedReceipt.epochNumber);
1007
+ const swapResult = (await computeL2ToL1MembershipWitness(aztecNode, epochRoots, swapPublicLeaf, minedReceipt))!;
1008
+ const { epochNumber: epoch, numCheckpointsInEpoch } = swapResult;
1009
+ const withdrawResult = (await computeL2ToL1MembershipWitness(aztecNode, epochRoots, withdrawLeaf, minedReceipt))!;
980
1010
 
981
- const swapPublicL2MessageIndex = swapResult!.leafIndex;
982
- const swapPublicSiblingPath = swapResult!.siblingPath;
1011
+ const swapPublicL2MessageIndex = swapResult.leafIndex;
1012
+ const swapPublicSiblingPath = swapResult.siblingPath;
983
1013
 
984
- const withdrawL2MessageIndex = withdrawResult!.leafIndex;
985
- const withdrawSiblingPath = withdrawResult!.siblingPath;
1014
+ const withdrawL2MessageIndex = withdrawResult.leafIndex;
1015
+ const withdrawSiblingPath = withdrawResult.siblingPath;
986
1016
 
987
1017
  const withdrawMessageMetadata = {
988
1018
  _epoch: BigInt(epoch),
1019
+ _numCheckpointsInEpoch: BigInt(withdrawResult.numCheckpointsInEpoch),
989
1020
  _leafIndex: BigInt(withdrawL2MessageIndex),
990
1021
  _path: withdrawSiblingPath
991
1022
  .toBufferArray()
@@ -994,19 +1025,13 @@ export const uniswapL1L2TestSuite = (
994
1025
 
995
1026
  const swapPublicMessageMetadata = {
996
1027
  _epoch: BigInt(epoch),
1028
+ _numCheckpointsInEpoch: BigInt(numCheckpointsInEpoch),
997
1029
  _leafIndex: BigInt(swapPublicL2MessageIndex),
998
1030
  _path: swapPublicSiblingPath
999
1031
  .toBufferArray()
1000
1032
  .map((buf: Buffer) => `0x${buf.toString('hex')}`) as readonly `0x${string}`[],
1001
1033
  };
1002
1034
 
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
1035
  // Call swap_private on L1
1011
1036
  logger.info('Execute withdraw and swap on the uniswapPortal!');
1012
1037
 
@@ -0,0 +1,23 @@
1
+ import type { Fr } from '@aztec/aztec.js/fields';
2
+ import type { AztecNode } from '@aztec/aztec.js/node';
3
+ import { retryUntil } from '@aztec/foundation/retry';
4
+
5
+ /**
6
+ * Waits until the archiver has seen the L1 to L2 message and indexed it. Unlike
7
+ * {@link waitForL1ToL2MessageReady} from `@aztec/aztec.js/messaging`, this does not
8
+ * require the L2 chain to have advanced to the message's checkpoint — it only confirms
9
+ * the message has been picked up from L1. Use this in tests that explicitly produce L2
10
+ * blocks afterwards to make the message consumable.
11
+ */
12
+ export function waitForL1ToL2MessageSeen(
13
+ node: Pick<AztecNode, 'getL1ToL2MessageCheckpoint'>,
14
+ l1ToL2MessageHash: Fr,
15
+ opts: { timeoutSeconds: number },
16
+ ) {
17
+ return retryUntil(
18
+ async () => (await node.getL1ToL2MessageCheckpoint(l1ToL2MessageHash)) !== undefined,
19
+ `L1 to L2 message ${l1ToL2MessageHash.toString()} seen`,
20
+ opts.timeoutSeconds,
21
+ 1,
22
+ );
23
+ }
@@ -7,6 +7,7 @@ import { SlotNumber } from '@aztec/foundation/branded-types';
7
7
  import { poseidon2Hash } from '@aztec/foundation/crypto/poseidon';
8
8
  import type { TestDateProvider } from '@aztec/foundation/timer';
9
9
  import type { LendingContract } from '@aztec/noir-contracts.js/Lending';
10
+ import type { AztecNode, AztecNodeDebug } from '@aztec/stdlib/interfaces/client';
10
11
 
11
12
  import type { TokenSimulator } from './token_simulator.js';
12
13
 
@@ -92,30 +93,45 @@ export class LendingSimulator {
92
93
  public stableCoin: TokenSimulator,
93
94
  ) {}
94
95
 
95
- async prepare() {
96
+ prepare() {
96
97
  this.accumulator = BASE;
97
- const slot = await this.rollup.getSlotAt(BigInt(await this.cc.eth.timestamp()) + BigInt(this.ethereumSlotDuration));
98
- this.time = Number(await this.rollup.getTimestampForSlot(slot));
98
+ this.time = 0;
99
99
  }
100
100
 
101
- async progressSlots(diff: number, dateProvider?: TestDateProvider) {
101
+ /**
102
+ * Advances the simulator's accumulator and clock to match a block timestamp observed on chain.
103
+ * Call this BEFORE applying any accumulator-sensitive mutation (borrow/repay) so the mutation
104
+ * sees the same accumulator as the contract did during execution.
105
+ */
106
+ observeBlockTimestamp(ts: number) {
107
+ const diff = ts - this.time;
108
+ if (diff > 0) {
109
+ this.accumulator = muldivDown(this.accumulator, computeMultiplier(this.rate, BigInt(diff)), BASE);
110
+ }
111
+ this.time = ts;
112
+ }
113
+
114
+ async progressSlots(diff: number, _dateProvider?: TestDateProvider, node?: AztecNode & AztecNodeDebug) {
102
115
  if (diff <= 1) {
103
116
  return;
104
117
  }
105
118
 
106
- const slot = await this.rollup.getSlotAt(BigInt(await this.cc.eth.timestamp()));
119
+ const slot = await this.rollup.getSlotAt(BigInt(await this.cc.eth.lastBlockTimestamp()));
107
120
  const targetSlot = SlotNumber(slot + diff);
108
121
  const ts = Number(await this.rollup.getTimestampForSlot(targetSlot));
109
- const timeDiff = ts - this.time;
110
- this.time = ts;
111
122
 
112
- // Mine ethereum blocks such that the next block will be in a new slot
113
- await this.cc.eth.warp(this.time - this.ethereumSlotDuration);
114
- if (dateProvider) {
115
- dateProvider.setTime(this.time * 1000);
123
+ // Queue-aware warp under AutomineSequencer: atomic warp + mineBlock that advances L2 time to the
124
+ // target slot. The cheat code routes through the AutomineSequencer queue when one is installed,
125
+ // and otherwise falls back to a manual warp + mineBlock loop.
126
+ if (node) {
127
+ await this.cc.warpL2TimeAtLeastTo(node, ts);
128
+ } else {
129
+ await this.cc.eth.warp(ts - this.ethereumSlotDuration);
116
130
  }
131
+
132
+ // Mark the latest checkpoint as proven so the rollup does not reorg pending checkpoints when
133
+ // time jumps far enough forward to cross an unproven epoch boundary.
117
134
  await this.cc.rollup.markAsProven(await this.rollup.getCheckpointNumber());
118
- this.accumulator = muldivDown(this.accumulator, computeMultiplier(this.rate, BigInt(timeDiff)), BASE);
119
135
  }
120
136
 
121
137
  depositPrivate(from: AztecAddress, onBehalfOf: Fr, amount: bigint) {
@@ -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,16 +1,18 @@
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';
5
6
  import { FeeJuicePaymentMethodWithClaim } from '@aztec/aztec.js/fee';
6
7
  import { type FeePaymentMethod, SponsoredFeePaymentMethod } from '@aztec/aztec.js/fee';
7
8
  import { Fr } from '@aztec/aztec.js/fields';
9
+ import { waitForL1ToL2MessageReady } from '@aztec/aztec.js/messaging';
8
10
  import { type AztecNode, createAztecNodeClient, waitForTx } from '@aztec/aztec.js/node';
9
11
  import type { Wallet } from '@aztec/aztec.js/wallet';
10
12
  import { createEthereumChain } from '@aztec/ethereum/chain';
11
13
  import { createExtendedL1Client } from '@aztec/ethereum/client';
12
14
  import type { Logger } from '@aztec/foundation/log';
13
- import { retryUntil } from '@aztec/foundation/retry';
15
+ import { makeBackoff, retry, retryUntil } from '@aztec/foundation/retry';
14
16
  import { TokenContract } from '@aztec/noir-contracts.js/Token';
15
17
  import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
16
18
  import { registerInitialLocalNetworkAccountsInWallet } from '@aztec/wallets/testing';
@@ -89,7 +91,7 @@ export async function deploySponsoredTestAccountsWithTokens(
89
91
  const paymentMethod = new SponsoredFeePaymentMethod(await getSponsoredFPCAddress());
90
92
  const recipientDeployMethod = await recipientAccount.getDeployMethod();
91
93
  await recipientDeployMethod.send({
92
- from: AztecAddress.ZERO,
94
+ from: NO_FROM,
93
95
  fee: { paymentMethod },
94
96
  wait: { timeout: 2400 },
95
97
  });
@@ -97,7 +99,7 @@ export async function deploySponsoredTestAccountsWithTokens(
97
99
  fundedAccounts.map(async a => {
98
100
  const deployMethod = await a.getDeployMethod();
99
101
  await deployMethod.send({
100
- from: AztecAddress.ZERO,
102
+ from: NO_FROM,
101
103
  fee: { paymentMethod },
102
104
  wait: { timeout: 2400 },
103
105
  }); // increase timeout on purpose in order to account for two empty epochs
@@ -129,50 +131,91 @@ export async function deploySponsoredTestAccountsWithTokens(
129
131
  }
130
132
 
131
133
  async function deployAccountWithDiagnostics(
132
- account: { getDeployMethod: () => Promise<{ send: (opts: any) => any }>; address: any },
134
+ account: { getDeployMethod: () => Promise<{ simulate: (opts: any) => any; send: (opts: any) => any }>; address: any },
133
135
  paymentMethod: SponsoredFeePaymentMethod,
134
136
  aztecNode: AztecNode,
135
137
  logger: Logger,
136
138
  accountLabel: string,
139
+ estimateGas?: boolean,
137
140
  ): Promise<void> {
138
141
  const deployMethod = await account.getDeployMethod();
139
- let txHash;
140
- try {
141
- const deployResult = await deployMethod.send({ from: AztecAddress.ZERO, fee: { paymentMethod }, wait: NO_WAIT });
142
- txHash = deployResult.txHash;
143
- await waitForTx(aztecNode, txHash, { timeout: 2400 });
144
- logger.info(`${accountLabel} deployed at ${account.address}`);
145
- } catch (error) {
146
- const blockNumber = await aztecNode.getBlockNumber();
147
- let receipt;
148
- try {
149
- receipt = await aztecNode.getTxReceipt(txHash);
150
- } catch {
151
- receipt = 'unavailable';
152
- }
153
- logger.error(`${accountLabel} deployment failed`, {
154
- txHash: txHash.toString(),
155
- receipt: JSON.stringify(receipt),
156
- currentBlockNumber: blockNumber,
157
- error: String(error),
158
- });
159
- throw error;
142
+ let gasSettings: any;
143
+ if (estimateGas) {
144
+ const sim = await deployMethod.simulate({ from: NO_FROM, fee: { paymentMethod } });
145
+ gasSettings = sim.estimatedGas;
146
+ logger.info(`${accountLabel} estimated gas: DA=${gasSettings.gasLimits.daGas} L2=${gasSettings.gasLimits.l2Gas}`);
160
147
  }
148
+
149
+ // Track the tx hash across retries so we don't re-send when the previous tx is still pending.
150
+ let sentTxHash: { txHash: any } | undefined;
151
+
152
+ await retry(
153
+ async () => {
154
+ // Check if already deployed (handles case where previous attempt succeeded but waitForTx timed out)
155
+ const existing = await aztecNode.getContract(account.address);
156
+ if (existing) {
157
+ logger.info(`${accountLabel} already deployed at ${account.address}, skipping`);
158
+ return;
159
+ }
160
+
161
+ // If we already sent a tx, check if it was dropped before deciding to re-send.
162
+ if (sentTxHash) {
163
+ const prevReceipt = await aztecNode.getTxReceipt(sentTxHash.txHash);
164
+ if (prevReceipt.isDropped()) {
165
+ logger.info(`${accountLabel} previous tx ${sentTxHash.txHash} was dropped, re-sending`);
166
+ sentTxHash = undefined;
167
+ } else {
168
+ logger.info(`${accountLabel} previous tx ${sentTxHash.txHash} still pending, waiting again...`);
169
+ }
170
+ }
171
+
172
+ if (!sentTxHash) {
173
+ const deployResult = await deployMethod.send({
174
+ from: NO_FROM,
175
+ fee: { paymentMethod, gasSettings },
176
+ wait: NO_WAIT,
177
+ });
178
+ sentTxHash = { txHash: deployResult.txHash };
179
+ logger.info(`${accountLabel} tx sent`, { txHash: sentTxHash.txHash.toString() });
180
+ }
181
+
182
+ const receipt = await waitForTx(aztecNode, sentTxHash.txHash, { timeout: 600 });
183
+ if (receipt.isDropped()) {
184
+ sentTxHash = undefined;
185
+ throw new Error(`${accountLabel} tx was dropped, retrying...`);
186
+ }
187
+ logger.info(`${accountLabel} deployed at ${account.address}`);
188
+ },
189
+ `deploy ${accountLabel}`,
190
+ makeBackoff([1, 2, 4, 8, 16]),
191
+ logger,
192
+ );
161
193
  }
162
194
 
163
195
  async function deployAccountsInBatches(
164
- accounts: { getDeployMethod: () => Promise<{ send: (opts: any) => any }>; address: any }[],
196
+ accounts: {
197
+ getDeployMethod: () => Promise<{ simulate: (opts: any) => any; send: (opts: any) => any }>;
198
+ address: any;
199
+ }[],
165
200
  paymentMethod: SponsoredFeePaymentMethod,
166
201
  aztecNode: AztecNode,
167
202
  logger: Logger,
168
203
  labelPrefix: string,
169
204
  batchSize = 2,
205
+ estimateGas?: boolean,
170
206
  ): Promise<void> {
171
207
  for (let i = 0; i < accounts.length; i += batchSize) {
172
208
  const batch = accounts.slice(i, i + batchSize);
173
209
  await Promise.all(
174
210
  batch.map((account, idx) =>
175
- deployAccountWithDiagnostics(account, paymentMethod, aztecNode, logger, `${labelPrefix}${i + idx + 1}`),
211
+ deployAccountWithDiagnostics(
212
+ account,
213
+ paymentMethod,
214
+ aztecNode,
215
+ logger,
216
+ `${labelPrefix}${i + idx + 1}`,
217
+ estimateGas,
218
+ ),
176
219
  ),
177
220
  );
178
221
  }
@@ -183,6 +226,7 @@ export async function deploySponsoredTestAccounts(
183
226
  aztecNode: AztecNode,
184
227
  logger: Logger,
185
228
  numberOfFundedWallets = 1,
229
+ opts?: { estimateGas?: boolean },
186
230
  ): Promise<TestAccountsWithoutTokens> {
187
231
  const [recipient, ...funded] = await generateSchnorrAccounts(numberOfFundedWallets + 1);
188
232
  const recipientAccount = await wallet.createSchnorrAccount(recipient.secret, recipient.salt);
@@ -192,8 +236,23 @@ export async function deploySponsoredTestAccounts(
192
236
 
193
237
  const paymentMethod = new SponsoredFeePaymentMethod(await getSponsoredFPCAddress());
194
238
 
195
- await deployAccountWithDiagnostics(recipientAccount, paymentMethod, aztecNode, logger, 'Recipient account');
196
- await deployAccountsInBatches(fundedAccounts, paymentMethod, aztecNode, logger, 'Funded account ', 2);
239
+ await deployAccountWithDiagnostics(
240
+ recipientAccount,
241
+ paymentMethod,
242
+ aztecNode,
243
+ logger,
244
+ 'Recipient account',
245
+ opts?.estimateGas,
246
+ );
247
+ await deployAccountsInBatches(
248
+ fundedAccounts,
249
+ paymentMethod,
250
+ aztecNode,
251
+ logger,
252
+ 'Funded account ',
253
+ 2,
254
+ opts?.estimateGas,
255
+ );
197
256
 
198
257
  return {
199
258
  aztecNode,
@@ -231,7 +290,7 @@ export async function deployTestAccountsWithTokens(
231
290
  fundedAccounts.map(async (a, i) => {
232
291
  const paymentMethod = new FeeJuicePaymentMethodWithClaim(a.address, claims[i]);
233
292
  const deployMethod = await a.getDeployMethod();
234
- await deployMethod.send({ from: AztecAddress.ZERO, fee: { paymentMethod } });
293
+ await deployMethod.send({ from: NO_FROM, fee: { paymentMethod } });
235
294
  logger.info(`Account deployed at ${a.address}`);
236
295
  }),
237
296
  );
@@ -274,9 +333,7 @@ async function bridgeL1FeeJuice(
274
333
  const portal = await L1FeeJuicePortalManager.new(aztecNode, l1Client, log);
275
334
  const claim = await portal.bridgeTokensPublic(recipient, amount, true /* mint */);
276
335
 
277
- const isSynced = async () =>
278
- (await aztecNode.getL1ToL2MessageCheckpoint(Fr.fromHexString(claim.messageHash))) !== undefined;
279
- await retryUntil(isSynced, `message ${claim.messageHash} sync`, 24, 0.5);
336
+ await waitForL1ToL2MessageReady(aztecNode, Fr.fromHexString(claim.messageHash), { timeoutSeconds: 24 });
280
337
 
281
338
  log.info(`Created a claim for ${amount} L1 fee juice to ${recipient}.`, claim);
282
339
  return claim;
@@ -307,14 +364,18 @@ async function deployTokenAndMint(
307
364
  logger: Logger,
308
365
  ) {
309
366
  logger.verbose(`Deploying TokenContract...`);
310
- const {
311
- receipt: { contract: tokenContract },
312
- } = await TokenContract.deploy(wallet, admin, TOKEN_NAME, TOKEN_SYMBOL, TOKEN_DECIMALS).send({
367
+ const { contract: tokenContract } = await TokenContract.deploy(
368
+ wallet,
369
+ admin,
370
+ TOKEN_NAME,
371
+ TOKEN_SYMBOL,
372
+ TOKEN_DECIMALS,
373
+ ).send({
313
374
  from: admin,
314
375
  fee: {
315
376
  paymentMethod,
316
377
  },
317
- wait: { timeout: 600, returnReceipt: true },
378
+ wait: { timeout: 600 },
318
379
  });
319
380
 
320
381
  const tokenAddress = tokenContract.address;