@aztec/bot 0.0.1-commit.5de5ca79e → 0.0.1-commit.6201a7b05

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.
package/src/factory.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { getInitialTestAccountsData } 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 {
4
5
  BatchCall,
@@ -15,6 +16,8 @@ import { deriveKeys } from '@aztec/aztec.js/keys';
15
16
  import { createLogger } from '@aztec/aztec.js/log';
16
17
  import { waitForL1ToL2MessageReady } from '@aztec/aztec.js/messaging';
17
18
  import { waitForTx } from '@aztec/aztec.js/node';
19
+ import { getFeeJuiceBalance } from '@aztec/aztec.js/utils';
20
+ import { ContractInitializationStatus } from '@aztec/aztec.js/wallet';
18
21
  import { createEthereumChain } from '@aztec/ethereum/chain';
19
22
  import { createExtendedL1Client } from '@aztec/ethereum/client';
20
23
  import { RollupContract } from '@aztec/ethereum/contracts';
@@ -27,7 +30,7 @@ import { PrivateTokenContract } from '@aztec/noir-contracts.js/PrivateToken';
27
30
  import { TokenContract } from '@aztec/noir-contracts.js/Token';
28
31
  import { TestContract } from '@aztec/noir-test-contracts.js/Test';
29
32
  import type { ContractInstanceWithAddress } from '@aztec/stdlib/contract';
30
- import { GasFees, GasSettings } from '@aztec/stdlib/gas';
33
+ import { GasFees, GasSettings, ManaUsageEstimate } from '@aztec/stdlib/gas';
31
34
  import type { AztecNode, AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
32
35
  import { deriveSigningKey } from '@aztec/stdlib/keys';
33
36
  import { EmbeddedWallet } from '@aztec/wallets/embedded';
@@ -39,6 +42,8 @@ import { getBalances, getPrivateBalance, isStandardTokenContract } from './utils
39
42
 
40
43
  const MINT_BALANCE = 1e12;
41
44
  const MIN_BALANCE = 1e3;
45
+ const FEE_JUICE_TOP_UP_THRESHOLD = 100n * 10n ** 18n;
46
+ const FEE_JUICE_TOP_UP_TARGET = 10_000n * 10n ** 18n;
42
47
 
43
48
  export class BotFactory {
44
49
  private log = createLogger('bot');
@@ -68,7 +73,8 @@ export class BotFactory {
68
73
  }> {
69
74
  const defaultAccountAddress = await this.setupAccount();
70
75
  const recipient = (await this.wallet.createSchnorrAccount(Fr.random(), Fr.random())).address;
71
- const token = await this.setupToken(defaultAccountAddress);
76
+ const token = await this.setupTokenWithOptionalEarlyRefuel(defaultAccountAddress);
77
+ await this.ensureFeeJuiceBalance(defaultAccountAddress, token);
72
78
  await this.mintTokens(token, defaultAccountAddress);
73
79
  return { wallet: this.wallet, defaultAccountAddress, token, node: this.aztecNode, recipient };
74
80
  }
@@ -82,7 +88,13 @@ export class BotFactory {
82
88
  node: AztecNode;
83
89
  }> {
84
90
  const defaultAccountAddress = await this.setupAccount();
85
- const token0 = await this.setupTokenContract(defaultAccountAddress, this.config.tokenSalt, 'BotToken0', 'BOT0');
91
+ const token0 = await this.setupTokenContractWithOptionalEarlyRefuel(
92
+ defaultAccountAddress,
93
+ this.config.tokenSalt,
94
+ 'BotToken0',
95
+ 'BOT0',
96
+ );
97
+ await this.ensureFeeJuiceBalance(defaultAccountAddress, token0);
86
98
  const token1 = await this.setupTokenContract(defaultAccountAddress, this.config.tokenSalt, 'BotToken1', 'BOT1');
87
99
  const liquidityToken = await this.setupTokenContract(
88
100
  defaultAccountAddress,
@@ -207,7 +219,7 @@ export class BotFactory {
207
219
  const signingKey = deriveSigningKey(secret);
208
220
  const accountManager = await this.wallet.createSchnorrAccount(secret, salt, signingKey);
209
221
  const metadata = await this.wallet.getContractMetadata(accountManager.address);
210
- if (metadata.isContractInitialized) {
222
+ if (metadata.initializationStatus === ContractInitializationStatus.INITIALIZED) {
211
223
  this.log.info(`Account at ${accountManager.address.toString()} already initialized`);
212
224
  const timer = new Timer();
213
225
  const address = accountManager.address;
@@ -222,21 +234,14 @@ export class BotFactory {
222
234
 
223
235
  const paymentMethod = new FeeJuicePaymentMethodWithClaim(accountManager.address, claim);
224
236
  const deployMethod = await accountManager.getDeployMethod();
225
- const maxFeesPerGas = (await this.aztecNode.getCurrentMinFees()).mul(1 + this.config.minFeePadding);
226
-
227
- const { estimatedGas } = await deployMethod.simulate({
228
- from: AztecAddress.ZERO,
229
- fee: { estimateGas: true, paymentMethod },
230
- });
231
- const gasSettings = GasSettings.from({ ...estimatedGas!, maxFeesPerGas, maxPriorityFeesPerGas: GasFees.empty() });
232
237
 
233
238
  await this.withNoMinTxsPerBlock(async () => {
234
239
  const { txHash } = await deployMethod.send({
235
- from: AztecAddress.ZERO,
236
- fee: { gasSettings, paymentMethod },
240
+ from: NO_FROM,
241
+ fee: { paymentMethod },
237
242
  wait: NO_WAIT,
238
243
  });
239
- this.log.info(`Sent tx for account deployment with hash ${txHash.toString()}`, { gasSettings });
244
+ this.log.info(`Sent tx for account deployment with hash ${txHash.toString()}`);
240
245
  return waitForTx(this.aztecNode, txHash, { timeout: this.config.txMinedWaitSeconds });
241
246
  });
242
247
  this.log.info(`Account deployed at ${address}`);
@@ -258,14 +263,79 @@ export class BotFactory {
258
263
  return accountManager.address;
259
264
  }
260
265
 
266
+ /**
267
+ * Setup token and refuel first: if the token already exists (restart scenario),
268
+ * run ensureFeeJuiceBalance before any step that might need fee juice. When deploying,
269
+ * use a bridge claim if balance is below threshold.
270
+ */
271
+ private async setupTokenWithOptionalEarlyRefuel(sender: AztecAddress): Promise<TokenContract | PrivateTokenContract> {
272
+ const token = await this.getTokenInstance(sender);
273
+ const address = token.address;
274
+ const metadata = await this.wallet.getContractMetadata(address);
275
+ if (metadata.isContractPublished) {
276
+ this.log.info(`Token at ${address.toString()} already deployed, refueling before setup`);
277
+ await this.ensureFeeJuiceBalance(sender, token);
278
+ }
279
+ return this.setupToken(sender);
280
+ }
281
+
282
+ /**
283
+ * Setup token0 for AMM with refuel-first behaviour when token already exists.
284
+ */
285
+ private async setupTokenContractWithOptionalEarlyRefuel(
286
+ deployer: AztecAddress,
287
+ contractAddressSalt: Fr,
288
+ name: string,
289
+ ticker: string,
290
+ decimals = 18,
291
+ ): Promise<TokenContract> {
292
+ const deployOpts: DeployOptions = { from: deployer, contractAddressSalt, universalDeploy: true };
293
+ const deploy = TokenContract.deploy(this.wallet, deployer, name, ticker, decimals);
294
+ const instance = await deploy.getInstance(deployOpts);
295
+ const metadata = await this.wallet.getContractMetadata(instance.address);
296
+ if (metadata.isContractPublished) {
297
+ this.log.info(`Token ${name} at ${instance.address.toString()} already deployed, refueling before setup`);
298
+ const token = TokenContract.at(instance.address, this.wallet);
299
+ await this.ensureFeeJuiceBalance(deployer, token);
300
+ }
301
+ return this.setupTokenContract(deployer, contractAddressSalt, name, ticker, decimals);
302
+ }
303
+
304
+ private async getTokenInstance(sender: AztecAddress): Promise<TokenContract | PrivateTokenContract> {
305
+ const deployOpts: DeployOptions = {
306
+ from: sender,
307
+ contractAddressSalt: this.config.tokenSalt,
308
+ universalDeploy: true,
309
+ };
310
+ if (this.config.contract === SupportedTokenContracts.TokenContract) {
311
+ const deploy = TokenContract.deploy(this.wallet, sender, 'BotToken', 'BOT', 18);
312
+ const instance = await deploy.getInstance(deployOpts);
313
+ return TokenContract.at(instance.address, this.wallet);
314
+ }
315
+ if (this.config.contract === SupportedTokenContracts.PrivateTokenContract) {
316
+ const tokenSecretKey = Fr.random();
317
+ const tokenPublicKeys = (await deriveKeys(tokenSecretKey)).publicKeys;
318
+ const deploy = PrivateTokenContract.deployWithPublicKeys(tokenPublicKeys, this.wallet, MINT_BALANCE, sender);
319
+ const instance = await deploy.getInstance({
320
+ ...deployOpts,
321
+ skipInstancePublication: true,
322
+ skipClassPublication: true,
323
+ skipInitialization: false,
324
+ });
325
+ return PrivateTokenContract.at(instance.address, this.wallet);
326
+ }
327
+ throw new Error(`Unsupported token contract type: ${this.config.contract}`);
328
+ }
329
+
261
330
  /**
262
331
  * Checks if the token contract is deployed and deploys it if necessary.
263
- * @param wallet - Wallet to deploy the token contract from.
264
- * @returns The TokenContract instance.
332
+ * Uses a bridge claim for deploy when balance is below threshold to avoid failing before refuel.
333
+ * @param sender - Aztec address to deploy the token contract from.
334
+ * @param existingToken - Optional token instance when called from setupTokenWithOptionalEarlyRefuel.
335
+ * @returns The TokenContract or PrivateTokenContract instance.
265
336
  */
266
337
  private async setupToken(sender: AztecAddress): Promise<TokenContract | PrivateTokenContract> {
267
338
  let deploy: DeployMethod<TokenContract | PrivateTokenContract>;
268
- let tokenInstance: ContractInstanceWithAddress | undefined;
269
339
  const deployOpts: DeployOptions = {
270
340
  from: sender,
271
341
  contractAddressSalt: this.config.tokenSalt,
@@ -274,8 +344,8 @@ export class BotFactory {
274
344
  let token: TokenContract | PrivateTokenContract;
275
345
  if (this.config.contract === SupportedTokenContracts.TokenContract) {
276
346
  deploy = TokenContract.deploy(this.wallet, sender, 'BotToken', 'BOT', 18);
277
- tokenInstance = await deploy.getInstance(deployOpts);
278
- token = TokenContract.at(tokenInstance.address, this.wallet);
347
+ const instance = await deploy.getInstance(deployOpts);
348
+ token = TokenContract.at(instance.address, this.wallet);
279
349
  } else if (this.config.contract === SupportedTokenContracts.PrivateTokenContract) {
280
350
  // Generate keys for the contract since PrivateToken uses SinglePrivateMutable which requires keys
281
351
  const tokenSecretKey = Fr.random();
@@ -286,7 +356,7 @@ export class BotFactory {
286
356
  deployOpts.skipInitialization = false;
287
357
 
288
358
  // Register the contract with the secret key before deployment
289
- tokenInstance = await deploy.getInstance(deployOpts);
359
+ const tokenInstance = await deploy.getInstance(deployOpts);
290
360
  token = PrivateTokenContract.at(tokenInstance.address, this.wallet);
291
361
  await this.wallet.registerContract(tokenInstance, PrivateTokenContract.artifact, tokenSecretKey);
292
362
  // The contract constructor initializes private storage vars that need the contract's own nullifier key.
@@ -295,21 +365,7 @@ export class BotFactory {
295
365
  throw new Error(`Unsupported token contract type: ${this.config.contract}`);
296
366
  }
297
367
 
298
- const address = tokenInstance?.address ?? (await deploy.getInstance(deployOpts)).address;
299
- const metadata = await this.wallet.getContractMetadata(address);
300
- if (metadata.isContractPublished) {
301
- this.log.info(`Token at ${address.toString()} already deployed`);
302
- await deploy.register();
303
- } else {
304
- this.log.info(`Deploying token contract at ${address.toString()}`);
305
- const { estimatedGas } = await deploy.simulate({ ...deployOpts, fee: { estimateGas: true } });
306
- const { txHash } = await deploy.send({ ...deployOpts, fee: { gasSettings: estimatedGas }, wait: NO_WAIT });
307
- this.log.info(`Sent tx for token setup with hash ${txHash.toString()}`, { estimatedGas });
308
- await this.withNoMinTxsPerBlock(async () => {
309
- await waitForTx(this.aztecNode, txHash, { timeout: this.config.txMinedWaitSeconds });
310
- return token;
311
- });
312
- }
368
+ await this.registerOrDeployContract('token', deploy, deployOpts);
313
369
  return token;
314
370
  }
315
371
 
@@ -345,18 +401,11 @@ export class BotFactory {
345
401
 
346
402
  this.log.info(`AMM deployed at ${amm.address}`);
347
403
  const setMinterInteraction = lpToken.methods.set_minter(amm.address, true);
348
- const { estimatedGas: setMinterGas } = await setMinterInteraction.simulate({
349
- from: deployer,
350
- fee: { estimateGas: true },
351
- });
352
404
  const { receipt: minterReceipt } = await setMinterInteraction.send({
353
405
  from: deployer,
354
- fee: { gasSettings: setMinterGas },
355
406
  wait: { timeout: this.config.txMinedWaitSeconds },
356
407
  });
357
- this.log.info(`Set LP token minter to AMM txHash=${minterReceipt.txHash.toString()}`, {
358
- estimatedGas: setMinterGas,
359
- });
408
+ this.log.info(`Set LP token minter to AMM txHash=${minterReceipt.txHash.toString()}`);
360
409
  this.log.info(`Liquidity token initialized`);
361
410
 
362
411
  return amm;
@@ -428,17 +477,12 @@ export class BotFactory {
428
477
  token0.methods.mint_to_private(liquidityProvider, MINT_BALANCE),
429
478
  token1.methods.mint_to_private(liquidityProvider, MINT_BALANCE),
430
479
  ]);
431
- const { estimatedGas: mintGas } = await mintBatch.simulate({
432
- from: liquidityProvider,
433
- fee: { estimateGas: true },
434
- });
435
480
  const { receipt: mintReceipt } = await mintBatch.send({
436
481
  from: liquidityProvider,
437
- fee: { gasSettings: mintGas },
438
482
  wait: { timeout: this.config.txMinedWaitSeconds },
439
483
  });
440
484
 
441
- this.log.info(`Sent mint tx: ${mintReceipt.txHash.toString()}`, { estimatedGas: mintGas });
485
+ this.log.info(`Sent mint tx: ${mintReceipt.txHash.toString()}`);
442
486
 
443
487
  const addLiquidityInteraction = amm.methods.add_liquidity(
444
488
  amount0Max,
@@ -447,21 +491,13 @@ export class BotFactory {
447
491
  amount1Min,
448
492
  authwitNonce,
449
493
  );
450
- const { estimatedGas: addLiquidityGas } = await addLiquidityInteraction.simulate({
451
- from: liquidityProvider,
452
- fee: { estimateGas: true },
453
- authWitnesses: [token0Authwit, token1Authwit],
454
- });
455
494
  const { receipt: addLiquidityReceipt } = await addLiquidityInteraction.send({
456
495
  from: liquidityProvider,
457
- fee: { gasSettings: addLiquidityGas },
458
496
  authWitnesses: [token0Authwit, token1Authwit],
459
497
  wait: { timeout: this.config.txMinedWaitSeconds },
460
498
  });
461
499
 
462
- this.log.info(`Sent tx to add liquidity to the AMM: ${addLiquidityReceipt.txHash.toString()}`, {
463
- estimatedGas: addLiquidityGas,
464
- });
500
+ this.log.info(`Sent tx to add liquidity to the AMM: ${addLiquidityReceipt.txHash.toString()}`);
465
501
  this.log.info(`Liquidity added`);
466
502
 
467
503
  const [newT0Bal, newT1Bal, newLPBal] = await getPrivateBalances();
@@ -482,13 +518,42 @@ export class BotFactory {
482
518
  this.log.info(`Contract ${name} at ${address.toString()} already deployed`);
483
519
  await deploy.register();
484
520
  } else {
485
- const { estimatedGas } = await deploy.simulate({ ...deployOpts, fee: { estimateGas: true } });
486
- this.log.info(`Deploying contract ${name} at ${address.toString()}`, { estimatedGas });
487
- await this.withNoMinTxsPerBlock(async () => {
488
- const { txHash } = await deploy.send({ ...deployOpts, fee: { gasSettings: estimatedGas }, wait: NO_WAIT });
489
- this.log.info(`Sent contract ${name} setup tx with hash ${txHash.toString()}`);
490
- return waitForTx(this.aztecNode, txHash, { timeout: this.config.txMinedWaitSeconds });
491
- });
521
+ const sender = deployOpts.from === NO_FROM ? undefined : deployOpts.from;
522
+ const balance = sender ? await getFeeJuiceBalance(sender, this.aztecNode) : 0n;
523
+ const useClaim =
524
+ sender &&
525
+ balance < FEE_JUICE_TOP_UP_THRESHOLD &&
526
+ this.config.feePaymentMethod === 'fee_juice' &&
527
+ !!this.config.l1RpcUrls?.length;
528
+ const mnemonicOrPrivateKey = this.config.l1PrivateKey?.getValue() ?? this.config.l1Mnemonic?.getValue();
529
+
530
+ if (useClaim && mnemonicOrPrivateKey) {
531
+ const claim = await this.getOrCreateBridgeClaim(sender!);
532
+ const paymentMethod = new FeeJuicePaymentMethodWithClaim(sender!, claim);
533
+ const { estimatedGas } = await deploy.simulate({ ...deployOpts, fee: { estimateGas: true, paymentMethod } });
534
+ const maxFeesPerGas = (await this.getMinFees()).mul(1 + this.config.minFeePadding);
535
+ const gasSettings = GasSettings.from({
536
+ ...estimatedGas!,
537
+ maxFeesPerGas,
538
+ maxPriorityFeesPerGas: GasFees.empty(),
539
+ });
540
+ await this.withNoMinTxsPerBlock(async () => {
541
+ const { txHash } = await deploy.send({ ...deployOpts, fee: { gasSettings, paymentMethod }, wait: NO_WAIT });
542
+ this.log.info(
543
+ `Sent contract ${name} deploy tx ${txHash.toString()} (using bridge claim, balance was ${balance})`,
544
+ );
545
+ return waitForTx(this.aztecNode, txHash, { timeout: this.config.txMinedWaitSeconds });
546
+ });
547
+ await this.store.deleteBridgeClaim(sender!);
548
+ } else {
549
+ const { estimatedGas } = await deploy.simulate({ ...deployOpts, fee: { estimateGas: true } });
550
+ this.log.info(`Deploying contract ${name} at ${address.toString()}`, { estimatedGas });
551
+ await this.withNoMinTxsPerBlock(async () => {
552
+ const { txHash } = await deploy.send({ ...deployOpts, fee: { gasSettings: estimatedGas }, wait: NO_WAIT });
553
+ this.log.info(`Sent contract ${name} setup tx with hash ${txHash.toString()}`);
554
+ return waitForTx(this.aztecNode, txHash, { timeout: this.config.txMinedWaitSeconds });
555
+ });
556
+ }
492
557
  }
493
558
  return instance;
494
559
  }
@@ -497,6 +562,66 @@ export class BotFactory {
497
562
  * Mints private and public tokens for the sender if their balance is below the minimum.
498
563
  * @param token - Token contract.
499
564
  */
565
+ /**
566
+ * Ensures the account has sufficient fee juice by bridging from L1 if balance is below threshold.
567
+ * Bridges repeatedly until balance reaches the target (10k FJ).
568
+ * Used on startup/restart to top up when the account has run out after previous runs.
569
+ */
570
+ private async ensureFeeJuiceBalance(
571
+ account: AztecAddress,
572
+ token: TokenContract | PrivateTokenContract,
573
+ ): Promise<void> {
574
+ const { feePaymentMethod, l1RpcUrls } = this.config;
575
+ if (feePaymentMethod !== 'fee_juice' || !l1RpcUrls?.length) {
576
+ return;
577
+ }
578
+ const mnemonicOrPrivateKey = this.config.l1PrivateKey?.getValue() ?? this.config.l1Mnemonic?.getValue();
579
+ if (!mnemonicOrPrivateKey) {
580
+ return;
581
+ }
582
+
583
+ let balance = await getFeeJuiceBalance(account, this.aztecNode);
584
+ if (balance >= FEE_JUICE_TOP_UP_THRESHOLD) {
585
+ this.log.info(`Fee juice balance ${balance} above threshold ${FEE_JUICE_TOP_UP_THRESHOLD}, skipping top-up`);
586
+ return;
587
+ }
588
+
589
+ this.log.info(
590
+ `Fee juice balance ${balance} below threshold ${FEE_JUICE_TOP_UP_THRESHOLD}, bridging from L1 until ${FEE_JUICE_TOP_UP_TARGET}`,
591
+ );
592
+ const maxFeesPerGas = (await this.getMinFees()).mul(1 + this.config.minFeePadding);
593
+ const minimalInteraction = isStandardTokenContract(token)
594
+ ? token.methods.transfer_in_public(account, account, 0n, 0)
595
+ : token.methods.transfer(0n, account, account);
596
+
597
+ while (balance < FEE_JUICE_TOP_UP_TARGET) {
598
+ const claim = await this.bridgeL1FeeJuice(account);
599
+ const paymentMethod = new FeeJuicePaymentMethodWithClaim(account, claim);
600
+ const { estimatedGas } = await minimalInteraction.simulate({
601
+ from: account,
602
+ fee: { estimateGas: true, paymentMethod },
603
+ });
604
+ const gasSettings = GasSettings.from({
605
+ ...estimatedGas!,
606
+ maxFeesPerGas,
607
+ maxPriorityFeesPerGas: GasFees.empty(),
608
+ });
609
+
610
+ await this.withNoMinTxsPerBlock(async () => {
611
+ const { txHash } = await minimalInteraction.send({
612
+ from: account,
613
+ fee: { gasSettings, paymentMethod },
614
+ wait: NO_WAIT,
615
+ });
616
+ this.log.info(`Sent fee juice top-up tx ${txHash.toString()}`);
617
+ return waitForTx(this.aztecNode, txHash, { timeout: this.config.txMinedWaitSeconds });
618
+ });
619
+ balance = await getFeeJuiceBalance(account, this.aztecNode);
620
+ this.log.info(`Fee juice balance after top-up: ${balance}`);
621
+ }
622
+ this.log.info(`Fee juice top-up complete for ${account.toString()}`);
623
+ }
624
+
500
625
  private async mintTokens(token: TokenContract | PrivateTokenContract, minter: AztecAddress) {
501
626
  const isStandardToken = isStandardTokenContract(token);
502
627
  let privateBalance = 0n;
@@ -530,15 +655,13 @@ export class BotFactory {
530
655
  // PrivateToken's mint accesses contract-level private storage vars (admin, total_supply).
531
656
  const additionalScopes = isStandardToken ? undefined : [token.address];
532
657
  const mintBatch = new BatchCall(token.wallet, calls);
533
- const { estimatedGas } = await mintBatch.simulate({ from: minter, fee: { estimateGas: true }, additionalScopes });
534
658
  await this.withNoMinTxsPerBlock(async () => {
535
659
  const { txHash } = await mintBatch.send({
536
660
  from: minter,
537
661
  additionalScopes,
538
- fee: { gasSettings: estimatedGas },
539
662
  wait: NO_WAIT,
540
663
  });
541
- this.log.info(`Sent token mint tx with hash ${txHash.toString()}`, { estimatedGas });
664
+ this.log.info(`Sent token mint tx with hash ${txHash.toString()}`);
542
665
  return waitForTx(this.aztecNode, txHash, { timeout: this.config.txMinedWaitSeconds });
543
666
  });
544
667
  }
@@ -606,6 +729,19 @@ export class BotFactory {
606
729
  return claim as L2AmountClaim;
607
730
  }
608
731
 
732
+ /** Returns worst-case min fees across predicted slots, with fallback to current min fees. */
733
+ private async getMinFees(): Promise<GasFees> {
734
+ try {
735
+ const predicted = await this.aztecNode.getPredictedMinFees(ManaUsageEstimate.Limit);
736
+ if (predicted.length === 0) {
737
+ return this.aztecNode.getCurrentMinFees();
738
+ }
739
+ return predicted.reduce((worst, fees) => (fees.feePerL2Gas > worst.feePerL2Gas ? fees : worst));
740
+ } catch {
741
+ return this.aztecNode.getCurrentMinFees();
742
+ }
743
+ }
744
+
609
745
  private async withNoMinTxsPerBlock<T>(fn: () => Promise<T>): Promise<T> {
610
746
  if (!this.aztecNodeAdmin || !this.config.flushSetupTransactions) {
611
747
  this.log.verbose(`No node admin client or flushing not requested (not setting minTxsPerBlock to 0)`);