@aztec/bot 0.0.1-commit.03f7ef2 → 0.0.1-commit.08c5969dc

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/bot.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import type { AztecAddress } from '@aztec/aztec.js/addresses';
2
- import { BatchCall, SentTx } from '@aztec/aztec.js/contracts';
2
+ import { BatchCall, NO_WAIT } from '@aztec/aztec.js/contracts';
3
+ import { TxHash } from '@aztec/aztec.js/tx';
3
4
  import { times } from '@aztec/foundation/collection';
4
5
  import type { PrivateTokenContract } from '@aztec/noir-contracts.js/PrivateToken';
5
6
  import type { TokenContract } from '@aztec/noir-contracts.js/Token';
6
7
  import type { AztecNode, AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
7
- import type { TestWallet } from '@aztec/test-wallet/server';
8
+ import type { EmbeddedWallet } from '@aztec/wallets/embedded';
8
9
 
9
10
  import { BaseBot } from './base_bot.js';
10
11
  import type { BotConfig } from './config.js';
@@ -17,7 +18,7 @@ const TRANSFER_AMOUNT = 1;
17
18
  export class Bot extends BaseBot {
18
19
  protected constructor(
19
20
  node: AztecNode,
20
- wallet: TestWallet,
21
+ wallet: EmbeddedWallet,
21
22
  defaultAccountAddress: AztecAddress,
22
23
  public readonly token: TokenContract | PrivateTokenContract,
23
24
  public readonly recipient: AztecAddress,
@@ -28,7 +29,7 @@ export class Bot extends BaseBot {
28
29
 
29
30
  static async create(
30
31
  config: BotConfig,
31
- wallet: TestWallet,
32
+ wallet: EmbeddedWallet,
32
33
  aztecNode: AztecNode,
33
34
  aztecNodeAdmin: AztecNodeAdmin | undefined,
34
35
  store: BotStore,
@@ -48,7 +49,7 @@ export class Bot extends BaseBot {
48
49
  this.config = { ...this.config, ...config };
49
50
  }
50
51
 
51
- protected async createAndSendTx(logCtx: object): Promise<SentTx> {
52
+ protected async createAndSendTx(logCtx: object): Promise<TxHash> {
52
53
  const { privateTransfersPerTx, publicTransfersPerTx, feePaymentMethod } = this.config;
53
54
  const { token, recipient, wallet } = this;
54
55
 
@@ -75,14 +76,14 @@ export class Bot extends BaseBot {
75
76
  await batch.simulate({ from: this.defaultAccountAddress });
76
77
 
77
78
  this.log.verbose(`Sending transaction`, logCtx);
78
- return batch.send(opts);
79
+ return batch.send({ ...opts, wait: NO_WAIT });
79
80
  }
80
81
 
81
82
  public async getBalances() {
82
83
  if (isStandardTokenContract(this.token)) {
83
84
  return {
84
85
  sender: await getBalances(this.token, this.defaultAccountAddress),
85
- recipient: await getBalances(this.token, this.recipient, this.defaultAccountAddress),
86
+ recipient: await getBalances(this.token, this.recipient),
86
87
  };
87
88
  } else {
88
89
  return {
@@ -91,7 +92,7 @@ export class Bot extends BaseBot {
91
92
  publicBalance: 0n,
92
93
  },
93
94
  recipient: {
94
- privateBalance: await getPrivateBalance(this.token, this.recipient, this.defaultAccountAddress),
95
+ privateBalance: await getPrivateBalance(this.token, this.recipient),
95
96
  publicBalance: 0n,
96
97
  },
97
98
  };
package/src/config.ts CHANGED
@@ -19,7 +19,7 @@ import type { ComponentsVersions } from '@aztec/stdlib/versioning';
19
19
 
20
20
  import { z } from 'zod';
21
21
 
22
- const BotFollowChain = ['NONE', 'PENDING', 'PROVEN'] as const;
22
+ const BotFollowChain = ['NONE', 'PROPOSED', 'CHECKPOINTED', 'PROVEN'] as const;
23
23
  type BotFollowChain = (typeof BotFollowChain)[number];
24
24
 
25
25
  export enum SupportedTokenContracts {
@@ -54,8 +54,8 @@ export type BotConfig = {
54
54
  publicTransfersPerTx: number;
55
55
  /** How to handle fee payments. */
56
56
  feePaymentMethod: 'fee_juice';
57
- /** 'How much is the bot willing to overpay vs. the current base fee' */
58
- baseFeePadding: number;
57
+ /** 'How much is the bot willing to overpay vs. the current min fee' */
58
+ minFeePadding: number;
59
59
  /** True to not automatically setup or start the bot on initialization. */
60
60
  noStart: boolean;
61
61
  /** How long to wait for a tx to be mined before reporting an error. */
@@ -96,7 +96,7 @@ export const BotConfigSchema = zodFor<BotConfig>()(
96
96
  privateTransfersPerTx: z.number().int().nonnegative(),
97
97
  publicTransfersPerTx: z.number().int().nonnegative(),
98
98
  feePaymentMethod: z.literal('fee_juice'),
99
- baseFeePadding: z.number().int().nonnegative(),
99
+ minFeePadding: z.number().int().nonnegative(),
100
100
  noStart: z.boolean(),
101
101
  txMinedWaitSeconds: z.number(),
102
102
  followChain: z.enum(BotFollowChain),
@@ -193,8 +193,8 @@ export const botConfigMappings: ConfigMappingsType<BotConfig> = {
193
193
  parseEnv: val => (val as 'fee_juice') || undefined,
194
194
  defaultValue: 'fee_juice',
195
195
  },
196
- baseFeePadding: {
197
- env: 'BOT_BASE_FEE_PADDING',
196
+ minFeePadding: {
197
+ env: 'BOT_MIN_FEE_PADDING',
198
198
  description: 'How much is the bot willing to overpay vs. the current base fee',
199
199
  ...numberConfigHelper(3),
200
200
  },
@@ -213,10 +213,14 @@ export const botConfigMappings: ConfigMappingsType<BotConfig> = {
213
213
  description: 'Which chain the bot follows',
214
214
  defaultValue: 'NONE',
215
215
  parseEnv(val) {
216
- if (!(BotFollowChain as readonly string[]).includes(val.toUpperCase())) {
216
+ const upper = val.toUpperCase();
217
+ if (upper === 'PENDING') {
218
+ return 'CHECKPOINTED';
219
+ }
220
+ if (!(BotFollowChain as readonly string[]).includes(upper)) {
217
221
  throw new Error(`Invalid value for BOT_FOLLOW_CHAIN: ${val}`);
218
222
  }
219
- return val as BotFollowChain;
223
+ return upper as BotFollowChain;
220
224
  },
221
225
  },
222
226
  maxPendingTxs: {
package/src/factory.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { SchnorrAccountContract } from '@aztec/accounts/schnorr';
2
1
  import { getInitialTestAccountsData } from '@aztec/accounts/testing';
3
2
  import { AztecAddress } from '@aztec/aztec.js/addresses';
4
3
  import {
@@ -7,6 +6,7 @@ import {
7
6
  ContractFunctionInteraction,
8
7
  type DeployMethod,
9
8
  type DeployOptions,
9
+ NO_WAIT,
10
10
  } from '@aztec/aztec.js/contracts';
11
11
  import { L1FeeJuicePortalManager } from '@aztec/aztec.js/ethereum';
12
12
  import type { L2AmountClaim } from '@aztec/aztec.js/ethereum';
@@ -14,6 +14,7 @@ import { FeeJuicePaymentMethodWithClaim } from '@aztec/aztec.js/fee';
14
14
  import { deriveKeys } from '@aztec/aztec.js/keys';
15
15
  import { createLogger } from '@aztec/aztec.js/log';
16
16
  import { waitForL1ToL2MessageReady } from '@aztec/aztec.js/messaging';
17
+ import { waitForTx } from '@aztec/aztec.js/node';
17
18
  import { createEthereumChain } from '@aztec/ethereum/chain';
18
19
  import { createExtendedL1Client } from '@aztec/ethereum/client';
19
20
  import { Fr } from '@aztec/foundation/curves/bn254';
@@ -25,7 +26,7 @@ import type { ContractInstanceWithAddress } from '@aztec/stdlib/contract';
25
26
  import { GasSettings } from '@aztec/stdlib/gas';
26
27
  import type { AztecNode, AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
27
28
  import { deriveSigningKey } from '@aztec/stdlib/keys';
28
- import { TestWallet } from '@aztec/test-wallet/server';
29
+ import { EmbeddedWallet } from '@aztec/wallets/embedded';
29
30
 
30
31
  import { type BotConfig, SupportedTokenContracts } from './config.js';
31
32
  import type { BotStore } from './store/index.js';
@@ -39,7 +40,7 @@ export class BotFactory {
39
40
 
40
41
  constructor(
41
42
  private readonly config: BotConfig,
42
- private readonly wallet: TestWallet,
43
+ private readonly wallet: EmbeddedWallet,
43
44
  private readonly store: BotStore,
44
45
  private readonly aztecNode: AztecNode,
45
46
  private readonly aztecNodeAdmin?: AztecNodeAdmin,
@@ -50,21 +51,21 @@ export class BotFactory {
50
51
  * deploying the token contract, and minting tokens if necessary.
51
52
  */
52
53
  public async setup(): Promise<{
53
- wallet: TestWallet;
54
+ wallet: EmbeddedWallet;
54
55
  defaultAccountAddress: AztecAddress;
55
56
  token: TokenContract | PrivateTokenContract;
56
57
  node: AztecNode;
57
58
  recipient: AztecAddress;
58
59
  }> {
59
- const recipient = (await this.wallet.createAccount()).address;
60
60
  const defaultAccountAddress = await this.setupAccount();
61
+ const recipient = (await this.wallet.createSchnorrAccount(Fr.random(), Fr.random())).address;
61
62
  const token = await this.setupToken(defaultAccountAddress);
62
63
  await this.mintTokens(token, defaultAccountAddress);
63
64
  return { wallet: this.wallet, defaultAccountAddress, token, node: this.aztecNode, recipient };
64
65
  }
65
66
 
66
67
  public async setupAmm(): Promise<{
67
- wallet: TestWallet;
68
+ wallet: EmbeddedWallet;
68
69
  defaultAccountAddress: AztecAddress;
69
70
  amm: AMMContract;
70
71
  token0: TokenContract;
@@ -112,14 +113,9 @@ export class BotFactory {
112
113
  private async setupAccountWithPrivateKey(secret: Fr) {
113
114
  const salt = this.config.senderSalt ?? Fr.ONE;
114
115
  const signingKey = deriveSigningKey(secret);
115
- const accountData = {
116
- secret,
117
- salt,
118
- contract: new SchnorrAccountContract(signingKey!),
119
- };
120
- const accountManager = await this.wallet.createAccount(accountData);
121
- const isInit = (await this.wallet.getContractMetadata(accountManager.address)).isContractInitialized;
122
- if (isInit) {
116
+ const accountManager = await this.wallet.createSchnorrAccount(secret, salt, signingKey);
117
+ const metadata = await this.wallet.getContractMetadata(accountManager.address);
118
+ if (metadata.isContractInitialized) {
123
119
  this.log.info(`Account at ${accountManager.address.toString()} already initialized`);
124
120
  const timer = new Timer();
125
121
  const address = accountManager.address;
@@ -134,12 +130,18 @@ export class BotFactory {
134
130
 
135
131
  const paymentMethod = new FeeJuicePaymentMethodWithClaim(accountManager.address, claim);
136
132
  const deployMethod = await accountManager.getDeployMethod();
137
- const maxFeesPerGas = (await this.aztecNode.getCurrentBaseFees()).mul(1 + this.config.baseFeePadding);
133
+ const maxFeesPerGas = (await this.aztecNode.getCurrentMinFees()).mul(1 + this.config.minFeePadding);
138
134
  const gasSettings = GasSettings.default({ maxFeesPerGas });
139
- const sentTx = deployMethod.send({ from: AztecAddress.ZERO, fee: { gasSettings, paymentMethod } });
140
- const txHash = await sentTx.getTxHash();
141
- this.log.info(`Sent tx for account deployment with hash ${txHash.toString()}`);
142
- await this.withNoMinTxsPerBlock(() => sentTx.wait({ timeout: this.config.txMinedWaitSeconds }));
135
+
136
+ await this.withNoMinTxsPerBlock(async () => {
137
+ const txHash = await deployMethod.send({
138
+ from: AztecAddress.ZERO,
139
+ fee: { gasSettings, paymentMethod },
140
+ wait: NO_WAIT,
141
+ });
142
+ this.log.info(`Sent tx for account deployment with hash ${txHash.toString()}`);
143
+ return waitForTx(this.aztecNode, txHash, { timeout: this.config.txMinedWaitSeconds });
144
+ });
143
145
  this.log.info(`Account deployed at ${address}`);
144
146
 
145
147
  // Clean up the consumed bridge claim
@@ -151,12 +153,11 @@ export class BotFactory {
151
153
 
152
154
  private async setupTestAccount() {
153
155
  const [initialAccountData] = await getInitialTestAccountsData();
154
- const accountData = {
155
- secret: initialAccountData.secret,
156
- salt: initialAccountData.salt,
157
- contract: new SchnorrAccountContract(initialAccountData.signingKey),
158
- };
159
- const accountManager = await this.wallet.createAccount(accountData);
156
+ const accountManager = await this.wallet.createSchnorrAccount(
157
+ initialAccountData.secret,
158
+ initialAccountData.salt,
159
+ initialAccountData.signingKey,
160
+ );
160
161
  return accountManager.address;
161
162
  }
162
163
 
@@ -173,8 +174,11 @@ export class BotFactory {
173
174
  contractAddressSalt: this.config.tokenSalt,
174
175
  universalDeploy: true,
175
176
  };
177
+ let token: TokenContract | PrivateTokenContract;
176
178
  if (this.config.contract === SupportedTokenContracts.TokenContract) {
177
179
  deploy = TokenContract.deploy(this.wallet, sender, 'BotToken', 'BOT', 18);
180
+ tokenInstance = await deploy.getInstance(deployOpts);
181
+ token = TokenContract.at(tokenInstance.address, this.wallet);
178
182
  } else if (this.config.contract === SupportedTokenContracts.PrivateTokenContract) {
179
183
  // Generate keys for the contract since PrivateToken uses SinglePrivateMutable which requires keys
180
184
  const tokenSecretKey = Fr.random();
@@ -186,22 +190,27 @@ export class BotFactory {
186
190
 
187
191
  // Register the contract with the secret key before deployment
188
192
  tokenInstance = await deploy.getInstance(deployOpts);
193
+ token = PrivateTokenContract.at(tokenInstance.address, this.wallet);
189
194
  await this.wallet.registerContract(tokenInstance, PrivateTokenContract.artifact, tokenSecretKey);
190
195
  } else {
191
196
  throw new Error(`Unsupported token contract type: ${this.config.contract}`);
192
197
  }
193
198
 
194
199
  const address = tokenInstance?.address ?? (await deploy.getInstance(deployOpts)).address;
195
- if ((await this.wallet.getContractMetadata(address)).isContractPublished) {
200
+ const metadata = await this.wallet.getContractMetadata(address);
201
+ if (metadata.isContractPublished) {
196
202
  this.log.info(`Token at ${address.toString()} already deployed`);
197
- return deploy.register();
203
+ await deploy.register();
198
204
  } else {
199
205
  this.log.info(`Deploying token contract at ${address.toString()}`);
200
- const sentTx = deploy.send(deployOpts);
201
- const txHash = await sentTx.getTxHash();
206
+ const txHash = await deploy.send({ ...deployOpts, wait: NO_WAIT });
202
207
  this.log.info(`Sent tx for token setup with hash ${txHash.toString()}`);
203
- return this.withNoMinTxsPerBlock(() => sentTx.deployed({ timeout: this.config.txMinedWaitSeconds }));
208
+ await this.withNoMinTxsPerBlock(async () => {
209
+ await waitForTx(this.aztecNode, txHash, { timeout: this.config.txMinedWaitSeconds });
210
+ return token;
211
+ });
204
212
  }
213
+ return token;
205
214
  }
206
215
 
207
216
  /**
@@ -209,7 +218,7 @@ export class BotFactory {
209
218
  * @param wallet - Wallet to deploy the token contract from.
210
219
  * @returns The TokenContract instance.
211
220
  */
212
- private setupTokenContract(
221
+ private async setupTokenContract(
213
222
  deployer: AztecAddress,
214
223
  contractAddressSalt: Fr,
215
224
  name: string,
@@ -218,7 +227,8 @@ export class BotFactory {
218
227
  ): Promise<TokenContract> {
219
228
  const deployOpts: DeployOptions = { from: deployer, contractAddressSalt, universalDeploy: true };
220
229
  const deploy = TokenContract.deploy(this.wallet, deployer, name, ticker, decimals);
221
- return this.registerOrDeployContract('Token - ' + name, deploy, deployOpts);
230
+ const instance = await this.registerOrDeployContract('Token - ' + name, deploy, deployOpts);
231
+ return TokenContract.at(instance.address, this.wallet);
222
232
  }
223
233
 
224
234
  private async setupAmmContract(
@@ -230,12 +240,14 @@ export class BotFactory {
230
240
  ): Promise<AMMContract> {
231
241
  const deployOpts: DeployOptions = { from: deployer, contractAddressSalt, universalDeploy: true };
232
242
  const deploy = AMMContract.deploy(this.wallet, token0.address, token1.address, lpToken.address);
233
- const amm = await this.registerOrDeployContract('AMM', deploy, deployOpts);
243
+ const instance = await this.registerOrDeployContract('AMM', deploy, deployOpts);
244
+ const amm = AMMContract.at(instance.address, this.wallet);
234
245
 
235
246
  this.log.info(`AMM deployed at ${amm.address}`);
236
- const minterTx = lpToken.methods.set_minter(amm.address, true).send({ from: deployer });
237
- this.log.info(`Set LP token minter to AMM txHash=${(await minterTx.getTxHash()).toString()}`);
238
- await minterTx.wait({ timeout: this.config.txMinedWaitSeconds });
247
+ const minterReceipt = await lpToken.methods
248
+ .set_minter(amm.address, true)
249
+ .send({ from: deployer, wait: { timeout: this.config.txMinedWaitSeconds } });
250
+ this.log.info(`Set LP token minter to AMM txHash=${minterReceipt.txHash.toString()}`);
239
251
  this.log.info(`Liquidity token initialized`);
240
252
 
241
253
  return amm;
@@ -294,23 +306,22 @@ export class BotFactory {
294
306
  .getFunctionCall(),
295
307
  });
296
308
 
297
- const mintTx = new BatchCall(this.wallet, [
309
+ const mintReceipt = await new BatchCall(this.wallet, [
298
310
  token0.methods.mint_to_private(liquidityProvider, MINT_BALANCE),
299
311
  token1.methods.mint_to_private(liquidityProvider, MINT_BALANCE),
300
- ]).send({ from: liquidityProvider });
312
+ ]).send({ from: liquidityProvider, wait: { timeout: this.config.txMinedWaitSeconds } });
301
313
 
302
- this.log.info(`Sent mint tx: ${(await mintTx.getTxHash()).toString()}`);
303
- await mintTx.wait({ timeout: this.config.txMinedWaitSeconds });
314
+ this.log.info(`Sent mint tx: ${mintReceipt.txHash.toString()}`);
304
315
 
305
- const addLiquidityTx = amm.methods
316
+ const addLiquidityReceipt = await amm.methods
306
317
  .add_liquidity(amount0Max, amount1Max, amount0Min, amount1Min, authwitNonce)
307
318
  .send({
308
319
  from: liquidityProvider,
309
320
  authWitnesses: [token0Authwit, token1Authwit],
321
+ wait: { timeout: this.config.txMinedWaitSeconds },
310
322
  });
311
323
 
312
- this.log.info(`Sent tx to add liquidity to the AMM: ${(await addLiquidityTx.getTxHash()).toString()}`);
313
- await addLiquidityTx.wait({ timeout: this.config.txMinedWaitSeconds });
324
+ this.log.info(`Sent tx to add liquidity to the AMM: ${addLiquidityReceipt.txHash.toString()}`);
314
325
  this.log.info(`Liquidity added`);
315
326
 
316
327
  const [newT0Bal, newT1Bal, newLPBal] = await getPrivateBalances();
@@ -323,18 +334,22 @@ export class BotFactory {
323
334
  name: string,
324
335
  deploy: DeployMethod<T>,
325
336
  deployOpts: DeployOptions,
326
- ): Promise<T> {
327
- const address = (await deploy.getInstance(deployOpts)).address;
328
- if ((await this.wallet.getContractMetadata(address)).isContractPublished) {
337
+ ): Promise<ContractInstanceWithAddress> {
338
+ const instance = await deploy.getInstance(deployOpts);
339
+ const address = instance.address;
340
+ const metadata = await this.wallet.getContractMetadata(address);
341
+ if (metadata.isContractPublished) {
329
342
  this.log.info(`Contract ${name} at ${address.toString()} already deployed`);
330
- return deploy.register();
343
+ await deploy.register();
331
344
  } else {
332
345
  this.log.info(`Deploying contract ${name} at ${address.toString()}`);
333
- const sentTx = deploy.send(deployOpts);
334
- const txHash = await sentTx.getTxHash();
335
- this.log.info(`Sent contract ${name} setup tx with hash ${txHash.toString()}`);
336
- return this.withNoMinTxsPerBlock(() => sentTx.deployed({ timeout: this.config.txMinedWaitSeconds }));
346
+ await this.withNoMinTxsPerBlock(async () => {
347
+ const txHash = await deploy.send({ ...deployOpts, wait: NO_WAIT });
348
+ this.log.info(`Sent contract ${name} setup tx with hash ${txHash.toString()}`);
349
+ return waitForTx(this.aztecNode, txHash, { timeout: this.config.txMinedWaitSeconds });
350
+ });
337
351
  }
352
+ return instance;
338
353
  }
339
354
 
340
355
  /**
@@ -370,10 +385,12 @@ export class BotFactory {
370
385
  this.log.info(`Skipping minting as ${minter.toString()} has enough tokens`);
371
386
  return;
372
387
  }
373
- const sentTx = new BatchCall(token.wallet, calls).send({ from: minter });
374
- const txHash = await sentTx.getTxHash();
375
- this.log.info(`Sent token mint tx with hash ${txHash.toString()}`);
376
- await this.withNoMinTxsPerBlock(() => sentTx.wait({ timeout: this.config.txMinedWaitSeconds }));
388
+
389
+ await this.withNoMinTxsPerBlock(async () => {
390
+ const txHash = await new BatchCall(token.wallet, calls).send({ from: minter, wait: NO_WAIT });
391
+ this.log.info(`Sent token mint tx with hash ${txHash.toString()}`);
392
+ return waitForTx(this.aztecNode, txHash, { timeout: this.config.txMinedWaitSeconds });
393
+ });
377
394
  }
378
395
 
379
396
  /**
package/src/runner.ts CHANGED
@@ -4,7 +4,7 @@ import { omit } from '@aztec/foundation/collection';
4
4
  import { RunningPromise } from '@aztec/foundation/running-promise';
5
5
  import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
6
6
  import { type TelemetryClient, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client';
7
- import type { TestWallet } from '@aztec/test-wallet/server';
7
+ import type { EmbeddedWallet } from '@aztec/wallets/embedded';
8
8
 
9
9
  import { AmmBot } from './amm_bot.js';
10
10
  import type { BaseBot } from './base_bot.js';
@@ -24,7 +24,7 @@ export class BotRunner implements BotRunnerApi, Traceable {
24
24
 
25
25
  public constructor(
26
26
  private config: BotConfig,
27
- private readonly wallet: TestWallet,
27
+ private readonly wallet: EmbeddedWallet,
28
28
  private readonly aztecNode: AztecNode,
29
29
  private readonly telemetry: TelemetryClient,
30
30
  private readonly aztecNodeAdmin: AztecNodeAdmin | undefined,