@aztec/bot 0.0.1-fake-ceab37513c → 0.0.2-commit.217f559981

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 (54) hide show
  1. package/dest/amm_bot.d.ts +9 -10
  2. package/dest/amm_bot.d.ts.map +1 -1
  3. package/dest/amm_bot.js +27 -20
  4. package/dest/base_bot.d.ts +12 -9
  5. package/dest/base_bot.d.ts.map +1 -1
  6. package/dest/base_bot.js +28 -29
  7. package/dest/bot.d.ts +9 -10
  8. package/dest/bot.d.ts.map +1 -1
  9. package/dest/bot.js +12 -10
  10. package/dest/config.d.ts +82 -63
  11. package/dest/config.d.ts.map +1 -1
  12. package/dest/config.js +61 -31
  13. package/dest/cross_chain_bot.d.ts +54 -0
  14. package/dest/cross_chain_bot.d.ts.map +1 -0
  15. package/dest/cross_chain_bot.js +140 -0
  16. package/dest/factory.d.ts +27 -34
  17. package/dest/factory.d.ts.map +1 -1
  18. package/dest/factory.js +271 -151
  19. package/dest/index.d.ts +3 -1
  20. package/dest/index.d.ts.map +1 -1
  21. package/dest/index.js +2 -0
  22. package/dest/interface.d.ts +2 -2
  23. package/dest/interface.d.ts.map +1 -1
  24. package/dest/interface.js +1 -1
  25. package/dest/l1_to_l2_seeding.d.ts +8 -0
  26. package/dest/l1_to_l2_seeding.d.ts.map +1 -0
  27. package/dest/l1_to_l2_seeding.js +63 -0
  28. package/dest/rpc.d.ts +1 -1
  29. package/dest/runner.d.ts +12 -13
  30. package/dest/runner.d.ts.map +1 -1
  31. package/dest/runner.js +445 -61
  32. package/dest/store/bot_store.d.ts +69 -0
  33. package/dest/store/bot_store.d.ts.map +1 -0
  34. package/dest/store/bot_store.js +138 -0
  35. package/dest/store/index.d.ts +2 -0
  36. package/dest/store/index.d.ts.map +1 -0
  37. package/dest/store/index.js +1 -0
  38. package/dest/utils.d.ts +4 -4
  39. package/dest/utils.d.ts.map +1 -1
  40. package/dest/utils.js +5 -5
  41. package/package.json +19 -13
  42. package/src/amm_bot.ts +40 -32
  43. package/src/base_bot.ts +27 -39
  44. package/src/bot.ts +25 -13
  45. package/src/config.ts +101 -72
  46. package/src/cross_chain_bot.ts +209 -0
  47. package/src/factory.ts +313 -177
  48. package/src/index.ts +2 -0
  49. package/src/interface.ts +1 -1
  50. package/src/l1_to_l2_seeding.ts +79 -0
  51. package/src/runner.ts +33 -24
  52. package/src/store/bot_store.ts +196 -0
  53. package/src/store/index.ts +1 -0
  54. package/src/utils.ts +10 -5
package/dest/factory.js CHANGED
@@ -1,216 +1,293 @@
1
- import { getSchnorrAccount } from '@aztec/accounts/schnorr';
2
- import { getDeployedTestAccountsWallets, getInitialTestAccounts } from '@aztec/accounts/testing';
3
- import { BatchCall, FeeJuicePaymentMethodWithClaim, L1FeeJuicePortalManager, createLogger, createPXEClient, waitForL1ToL2MessageReady } from '@aztec/aztec.js';
4
- import { createEthereumChain, createExtendedL1Client } from '@aztec/ethereum';
5
- import { Fr } from '@aztec/foundation/fields';
1
+ import { getInitialTestAccountsData } from '@aztec/accounts/testing';
2
+ import { AztecAddress } from '@aztec/aztec.js/addresses';
3
+ import { BatchCall, NO_WAIT } from '@aztec/aztec.js/contracts';
4
+ import { L1FeeJuicePortalManager } from '@aztec/aztec.js/ethereum';
5
+ import { FeeJuicePaymentMethodWithClaim } from '@aztec/aztec.js/fee';
6
+ import { deriveKeys } from '@aztec/aztec.js/keys';
7
+ import { createLogger } from '@aztec/aztec.js/log';
8
+ import { waitForL1ToL2MessageReady } from '@aztec/aztec.js/messaging';
9
+ import { waitForTx } from '@aztec/aztec.js/node';
10
+ import { createEthereumChain } from '@aztec/ethereum/chain';
11
+ import { createExtendedL1Client } from '@aztec/ethereum/client';
12
+ import { RollupContract } from '@aztec/ethereum/contracts';
13
+ import { Fr } from '@aztec/foundation/curves/bn254';
14
+ import { EthAddress } from '@aztec/foundation/eth-address';
6
15
  import { Timer } from '@aztec/foundation/timer';
7
16
  import { AMMContract } from '@aztec/noir-contracts.js/AMM';
8
17
  import { PrivateTokenContract } from '@aztec/noir-contracts.js/PrivateToken';
9
18
  import { TokenContract } from '@aztec/noir-contracts.js/Token';
19
+ import { TestContract } from '@aztec/noir-test-contracts.js/Test';
20
+ import { GasSettings } from '@aztec/stdlib/gas';
10
21
  import { deriveSigningKey } from '@aztec/stdlib/keys';
11
- import { makeTracedFetch } from '@aztec/telemetry-client';
12
- import { SupportedTokenContracts, getVersions } from './config.js';
22
+ import { SupportedTokenContracts } from './config.js';
23
+ import { seedL1ToL2Message } from './l1_to_l2_seeding.js';
13
24
  import { getBalances, getPrivateBalance, isStandardTokenContract } from './utils.js';
14
25
  const MINT_BALANCE = 1e12;
15
26
  const MIN_BALANCE = 1e3;
16
27
  export class BotFactory {
17
28
  config;
18
- pxe;
19
- node;
20
- nodeAdmin;
29
+ wallet;
30
+ store;
31
+ aztecNode;
32
+ aztecNodeAdmin;
21
33
  log;
22
- constructor(config, dependencies){
34
+ constructor(config, wallet, store, aztecNode, aztecNodeAdmin){
23
35
  this.config = config;
36
+ this.wallet = wallet;
37
+ this.store = store;
38
+ this.aztecNode = aztecNode;
39
+ this.aztecNodeAdmin = aztecNodeAdmin;
24
40
  this.log = createLogger('bot');
25
- if (config.flushSetupTransactions && !dependencies.nodeAdmin) {
26
- throw new Error(`Either a node admin client or node admin url must be provided if transaction flushing is requested`);
27
- }
28
- if (config.senderPrivateKey && config.senderPrivateKey.getValue() && !dependencies.node) {
29
- throw new Error(`Either a node client or node url must be provided for bridging L1 fee juice to deploy an account with private key`);
30
- }
31
- if (!dependencies.pxe && !config.pxeUrl) {
32
- throw new Error(`Either a PXE client or a PXE URL must be provided`);
33
- }
34
- this.node = dependencies.node;
35
- this.nodeAdmin = dependencies.nodeAdmin;
36
- if (dependencies.pxe) {
37
- this.log.info(`Using local PXE`);
38
- this.pxe = dependencies.pxe;
39
- return;
40
- }
41
- this.log.info(`Using remote PXE at ${config.pxeUrl}`);
42
- this.pxe = createPXEClient(config.pxeUrl, getVersions(), makeTracedFetch([
43
- 1,
44
- 2,
45
- 3
46
- ], false));
47
41
  }
48
42
  /**
49
43
  * Initializes a new bot by setting up the sender account, registering the recipient,
50
44
  * deploying the token contract, and minting tokens if necessary.
51
45
  */ async setup() {
52
- const recipient = await this.registerRecipient();
53
- const wallet = await this.setupAccount();
54
- const defaultAccountAddress = wallet.getAddress();
55
- const token = await this.setupToken(wallet, defaultAccountAddress);
46
+ const defaultAccountAddress = await this.setupAccount();
47
+ const recipient = (await this.wallet.createSchnorrAccount(Fr.random(), Fr.random())).address;
48
+ const token = await this.setupToken(defaultAccountAddress);
56
49
  await this.mintTokens(token, defaultAccountAddress);
57
50
  return {
58
- wallet,
51
+ wallet: this.wallet,
59
52
  defaultAccountAddress,
60
53
  token,
61
- pxe: this.pxe,
54
+ node: this.aztecNode,
62
55
  recipient
63
56
  };
64
57
  }
65
58
  async setupAmm() {
66
- const wallet = await this.setupAccount();
67
- const defaultAccountAddress = wallet.getAddress();
68
- const token0 = await this.setupTokenContract(wallet, wallet.getAddress(), this.config.tokenSalt, 'BotToken0', 'BOT0');
69
- const token1 = await this.setupTokenContract(wallet, wallet.getAddress(), this.config.tokenSalt, 'BotToken1', 'BOT1');
70
- const liquidityToken = await this.setupTokenContract(wallet, wallet.getAddress(), this.config.tokenSalt, 'BotLPToken', 'BOTLP');
71
- const amm = await this.setupAmmContract(wallet, wallet.getAddress(), this.config.tokenSalt, token0, token1, liquidityToken);
72
- await this.fundAmm(wallet, wallet.getAddress(), amm, token0, token1, liquidityToken);
59
+ const defaultAccountAddress = await this.setupAccount();
60
+ const token0 = await this.setupTokenContract(defaultAccountAddress, this.config.tokenSalt, 'BotToken0', 'BOT0');
61
+ const token1 = await this.setupTokenContract(defaultAccountAddress, this.config.tokenSalt, 'BotToken1', 'BOT1');
62
+ const liquidityToken = await this.setupTokenContract(defaultAccountAddress, this.config.tokenSalt, 'BotLPToken', 'BOTLP');
63
+ const amm = await this.setupAmmContract(defaultAccountAddress, this.config.tokenSalt, token0, token1, liquidityToken);
64
+ await this.fundAmm(defaultAccountAddress, defaultAccountAddress, amm, token0, token1, liquidityToken);
73
65
  this.log.info(`AMM initialized and funded`);
74
66
  return {
75
- wallet,
67
+ wallet: this.wallet,
76
68
  defaultAccountAddress,
77
69
  amm,
78
70
  token0,
79
71
  token1,
80
- pxe: this.pxe
72
+ node: this.aztecNode
81
73
  };
82
74
  }
83
75
  /**
76
+ * Initializes the cross-chain bot by deploying TestContract, creating an L1 client,
77
+ * seeding initial L1→L2 messages, and waiting for the first to be ready.
78
+ */ async setupCrossChain() {
79
+ const defaultAccountAddress = await this.setupAccount();
80
+ // Create L1 client (same pattern as bridgeL1FeeJuice)
81
+ const l1RpcUrls = this.config.l1RpcUrls;
82
+ if (!l1RpcUrls?.length) {
83
+ throw new Error('L1 RPC URLs required for cross-chain bot');
84
+ }
85
+ const mnemonicOrPrivateKey = this.config.l1PrivateKey?.getValue() ?? this.config.l1Mnemonic?.getValue();
86
+ if (!mnemonicOrPrivateKey) {
87
+ throw new Error('L1 mnemonic or private key required for cross-chain bot');
88
+ }
89
+ const { l1ChainId, l1ContractAddresses } = await this.aztecNode.getNodeInfo();
90
+ const chain = createEthereumChain(l1RpcUrls, l1ChainId);
91
+ const l1Client = createExtendedL1Client(chain.rpcUrls, mnemonicOrPrivateKey, chain.chainInfo);
92
+ // Fetch Rollup version (needed for Inbox L2Actor struct)
93
+ const rollupContract = new RollupContract(l1Client, l1ContractAddresses.rollupAddress.toString());
94
+ const rollupVersion = await rollupContract.getVersion();
95
+ // Deploy TestContract
96
+ const contract = await this.setupTestContract(defaultAccountAddress);
97
+ // Recover any pending messages from store (clean up stale ones first)
98
+ await this.store.cleanupOldPendingMessages();
99
+ const pendingMessages = await this.store.getUnconsumedL1ToL2Messages();
100
+ // Seed initial L1→L2 messages if pipeline is empty
101
+ const seedCount = Math.max(0, this.config.l1ToL2SeedCount - pendingMessages.length);
102
+ for(let i = 0; i < seedCount; i++){
103
+ await seedL1ToL2Message(l1Client, EthAddress.fromString(l1ContractAddresses.inboxAddress.toString()), contract.address, rollupVersion, this.store, this.log);
104
+ }
105
+ // Block until at least one message is ready
106
+ const allMessages = await this.store.getUnconsumedL1ToL2Messages();
107
+ if (allMessages.length > 0) {
108
+ this.log.info(`Waiting for first L1→L2 message to be ready...`);
109
+ const firstMsg = allMessages[0];
110
+ await waitForL1ToL2MessageReady(this.aztecNode, Fr.fromHexString(firstMsg.msgHash), {
111
+ timeoutSeconds: this.config.l1ToL2MessageTimeoutSeconds,
112
+ // Use forPublicConsumption: false so we wait until the message is in the current world
113
+ // state. With true, it returns one block early which causes gas estimation simulation to
114
+ // fail since it runs against the current state.
115
+ // See https://linear.app/aztec-labs/issue/A-548 for details.
116
+ forPublicConsumption: false
117
+ });
118
+ this.log.info(`First L1→L2 message is ready`);
119
+ }
120
+ return {
121
+ wallet: this.wallet,
122
+ defaultAccountAddress,
123
+ contract,
124
+ node: this.aztecNode,
125
+ l1Client,
126
+ rollupVersion
127
+ };
128
+ }
129
+ async setupTestContract(deployer) {
130
+ const deployOpts = {
131
+ from: deployer,
132
+ contractAddressSalt: this.config.tokenSalt,
133
+ universalDeploy: true
134
+ };
135
+ const deploy = TestContract.deploy(this.wallet);
136
+ const instance = await this.registerOrDeployContract('TestContract', deploy, deployOpts);
137
+ return TestContract.at(instance.address, this.wallet);
138
+ }
139
+ /**
84
140
  * Checks if the sender account contract is initialized, and initializes it if necessary.
85
141
  * @returns The sender wallet.
86
142
  */ async setupAccount() {
87
143
  const privateKey = this.config.senderPrivateKey?.getValue();
88
144
  if (privateKey) {
145
+ this.log.info(`Setting up account with provided private key`);
89
146
  return await this.setupAccountWithPrivateKey(privateKey);
90
147
  } else {
148
+ this.log.info(`Setting up test account`);
91
149
  return await this.setupTestAccount();
92
150
  }
93
151
  }
94
- async setupAccountWithPrivateKey(privateKey) {
152
+ async setupAccountWithPrivateKey(secret) {
95
153
  const salt = this.config.senderSalt ?? Fr.ONE;
96
- const signingKey = deriveSigningKey(privateKey);
97
- const account = await getSchnorrAccount(this.pxe, privateKey, signingKey, salt);
98
- const isInit = (await this.pxe.getContractMetadata(account.getAddress())).isContractInitialized;
99
- if (isInit) {
100
- this.log.info(`Account at ${account.getAddress().toString()} already initialized`);
154
+ const signingKey = deriveSigningKey(secret);
155
+ const accountManager = await this.wallet.createSchnorrAccount(secret, salt, signingKey);
156
+ const metadata = await this.wallet.getContractMetadata(accountManager.address);
157
+ if (metadata.isContractInitialized) {
158
+ this.log.info(`Account at ${accountManager.address.toString()} already initialized`);
101
159
  const timer = new Timer();
102
- const wallet = await account.register();
103
- this.log.info(`Account at ${account.getAddress()} registered. duration=${timer.ms()}`);
104
- return wallet;
160
+ const address = accountManager.address;
161
+ this.log.info(`Account at ${address} registered. duration=${timer.ms()}`);
162
+ await this.store.deleteBridgeClaim(address);
163
+ return address;
105
164
  } else {
106
- const address = account.getAddress();
165
+ const address = accountManager.address;
107
166
  this.log.info(`Deploying account at ${address}`);
108
- const claim = await this.bridgeL1FeeJuice(address);
109
- // docs:start:claim_and_deploy
110
- const wallet = await account.getWallet();
111
- const paymentMethod = new FeeJuicePaymentMethodWithClaim(wallet, claim);
112
- const sentTx = account.deploy({
113
- fee: {
114
- paymentMethod
115
- }
167
+ const claim = await this.getOrCreateBridgeClaim(address);
168
+ const paymentMethod = new FeeJuicePaymentMethodWithClaim(accountManager.address, claim);
169
+ const deployMethod = await accountManager.getDeployMethod();
170
+ const maxFeesPerGas = (await this.aztecNode.getCurrentMinFees()).mul(1 + this.config.minFeePadding);
171
+ const gasSettings = GasSettings.default({
172
+ maxFeesPerGas
116
173
  });
117
- const txHash = await sentTx.getTxHash();
118
- // docs:end:claim_and_deploy
119
- this.log.info(`Sent tx for account deployment with hash ${txHash.toString()}`);
120
- await this.withNoMinTxsPerBlock(()=>sentTx.wait({
174
+ await this.withNoMinTxsPerBlock(async ()=>{
175
+ const txHash = await deployMethod.send({
176
+ from: AztecAddress.ZERO,
177
+ fee: {
178
+ gasSettings,
179
+ paymentMethod
180
+ },
181
+ wait: NO_WAIT
182
+ });
183
+ this.log.info(`Sent tx for account deployment with hash ${txHash.toString()}`);
184
+ return waitForTx(this.aztecNode, txHash, {
121
185
  timeout: this.config.txMinedWaitSeconds
122
- }));
186
+ });
187
+ });
123
188
  this.log.info(`Account deployed at ${address}`);
124
- return wallet;
189
+ // Clean up the consumed bridge claim
190
+ await this.store.deleteBridgeClaim(address);
191
+ return accountManager.address;
125
192
  }
126
193
  }
127
194
  async setupTestAccount() {
128
- let [wallet] = await getDeployedTestAccountsWallets(this.pxe);
129
- if (wallet) {
130
- this.log.info(`Using funded test account: ${wallet.getAddress()}`);
131
- } else {
132
- this.log.info('Registering funded test account');
133
- const [account] = await getInitialTestAccounts();
134
- const manager = await getSchnorrAccount(this.pxe, account.secret, account.signingKey, account.salt);
135
- wallet = await manager.register();
136
- this.log.info(`Funded test account registered: ${wallet.getAddress()}`);
137
- }
138
- return wallet;
139
- }
140
- /**
141
- * Registers the recipient for txs in the pxe.
142
- */ async registerRecipient() {
143
- const recipient = await this.pxe.registerAccount(this.config.recipientEncryptionSecret.getValue(), Fr.ONE);
144
- return recipient.address;
195
+ const [initialAccountData] = await getInitialTestAccountsData();
196
+ const accountManager = await this.wallet.createSchnorrAccount(initialAccountData.secret, initialAccountData.salt, initialAccountData.signingKey);
197
+ return accountManager.address;
145
198
  }
146
199
  /**
147
200
  * Checks if the token contract is deployed and deploys it if necessary.
148
201
  * @param wallet - Wallet to deploy the token contract from.
149
202
  * @returns The TokenContract instance.
150
- */ async setupToken(wallet, sender) {
203
+ */ async setupToken(sender) {
151
204
  let deploy;
205
+ let tokenInstance;
152
206
  const deployOpts = {
153
207
  from: sender,
154
208
  contractAddressSalt: this.config.tokenSalt,
155
209
  universalDeploy: true
156
210
  };
211
+ let token;
157
212
  if (this.config.contract === SupportedTokenContracts.TokenContract) {
158
- deploy = TokenContract.deploy(wallet, sender, 'BotToken', 'BOT', 18);
213
+ deploy = TokenContract.deploy(this.wallet, sender, 'BotToken', 'BOT', 18);
214
+ tokenInstance = await deploy.getInstance(deployOpts);
215
+ token = TokenContract.at(tokenInstance.address, this.wallet);
159
216
  } else if (this.config.contract === SupportedTokenContracts.PrivateTokenContract) {
160
- deploy = PrivateTokenContract.deploy(wallet, MINT_BALANCE, sender);
217
+ // Generate keys for the contract since PrivateToken uses SinglePrivateMutable which requires keys
218
+ const tokenSecretKey = Fr.random();
219
+ const tokenPublicKeys = (await deriveKeys(tokenSecretKey)).publicKeys;
220
+ deploy = PrivateTokenContract.deployWithPublicKeys(tokenPublicKeys, this.wallet, MINT_BALANCE, sender);
161
221
  deployOpts.skipInstancePublication = true;
162
222
  deployOpts.skipClassPublication = true;
163
223
  deployOpts.skipInitialization = false;
224
+ // Register the contract with the secret key before deployment
225
+ tokenInstance = await deploy.getInstance(deployOpts);
226
+ token = PrivateTokenContract.at(tokenInstance.address, this.wallet);
227
+ await this.wallet.registerContract(tokenInstance, PrivateTokenContract.artifact, tokenSecretKey);
228
+ // The contract constructor initializes private storage vars that need the contract's own nullifier key.
229
+ deployOpts.additionalScopes = [
230
+ tokenInstance.address
231
+ ];
164
232
  } else {
165
233
  throw new Error(`Unsupported token contract type: ${this.config.contract}`);
166
234
  }
167
- const address = (await deploy.getInstance(deployOpts)).address;
168
- if ((await this.pxe.getContractMetadata(address)).isContractPublished) {
235
+ const address = tokenInstance?.address ?? (await deploy.getInstance(deployOpts)).address;
236
+ const metadata = await this.wallet.getContractMetadata(address);
237
+ if (metadata.isContractPublished) {
169
238
  this.log.info(`Token at ${address.toString()} already deployed`);
170
- return deploy.register();
239
+ await deploy.register();
171
240
  } else {
172
241
  this.log.info(`Deploying token contract at ${address.toString()}`);
173
- const sentTx = deploy.send(deployOpts);
174
- const txHash = await sentTx.getTxHash();
242
+ const txHash = await deploy.send({
243
+ ...deployOpts,
244
+ wait: NO_WAIT
245
+ });
175
246
  this.log.info(`Sent tx for token setup with hash ${txHash.toString()}`);
176
- return this.withNoMinTxsPerBlock(()=>sentTx.deployed({
247
+ await this.withNoMinTxsPerBlock(async ()=>{
248
+ await waitForTx(this.aztecNode, txHash, {
177
249
  timeout: this.config.txMinedWaitSeconds
178
- }));
250
+ });
251
+ return token;
252
+ });
179
253
  }
254
+ return token;
180
255
  }
181
256
  /**
182
257
  * Checks if the token contract is deployed and deploys it if necessary.
183
258
  * @param wallet - Wallet to deploy the token contract from.
184
259
  * @returns The TokenContract instance.
185
- */ setupTokenContract(wallet, deployer, contractAddressSalt, name, ticker, decimals = 18) {
260
+ */ async setupTokenContract(deployer, contractAddressSalt, name, ticker, decimals = 18) {
186
261
  const deployOpts = {
187
262
  from: deployer,
188
263
  contractAddressSalt,
189
264
  universalDeploy: true
190
265
  };
191
- const deploy = TokenContract.deploy(wallet, deployer, name, ticker, decimals);
192
- return this.registerOrDeployContract('Token - ' + name, deploy, deployOpts);
266
+ const deploy = TokenContract.deploy(this.wallet, deployer, name, ticker, decimals);
267
+ const instance = await this.registerOrDeployContract('Token - ' + name, deploy, deployOpts);
268
+ return TokenContract.at(instance.address, this.wallet);
193
269
  }
194
- async setupAmmContract(wallet, deployer, contractAddressSalt, token0, token1, lpToken) {
270
+ async setupAmmContract(deployer, contractAddressSalt, token0, token1, lpToken) {
195
271
  const deployOpts = {
196
272
  from: deployer,
197
273
  contractAddressSalt,
198
274
  universalDeploy: true
199
275
  };
200
- const deploy = AMMContract.deploy(wallet, token0.address, token1.address, lpToken.address);
201
- const amm = await this.registerOrDeployContract('AMM', deploy, deployOpts);
276
+ const deploy = AMMContract.deploy(this.wallet, token0.address, token1.address, lpToken.address);
277
+ const instance = await this.registerOrDeployContract('AMM', deploy, deployOpts);
278
+ const amm = AMMContract.at(instance.address, this.wallet);
202
279
  this.log.info(`AMM deployed at ${amm.address}`);
203
- const minterTx = lpToken.methods.set_minter(amm.address, true).send({
204
- from: deployer
205
- });
206
- this.log.info(`Set LP token minter to AMM txHash=${(await minterTx.getTxHash()).toString()}`);
207
- await minterTx.wait({
208
- timeout: this.config.txMinedWaitSeconds
280
+ const minterReceipt = await lpToken.methods.set_minter(amm.address, true).send({
281
+ from: deployer,
282
+ wait: {
283
+ timeout: this.config.txMinedWaitSeconds
284
+ }
209
285
  });
286
+ this.log.info(`Set LP token minter to AMM txHash=${minterReceipt.txHash.toString()}`);
210
287
  this.log.info(`Liquidity token initialized`);
211
288
  return amm;
212
289
  }
213
- async fundAmm(wallet, liquidityProvider, amm, token0, token1, lpToken) {
290
+ async fundAmm(defaultAccountAddress, liquidityProvider, amm, token0, token1, lpToken) {
214
291
  const getPrivateBalances = ()=>Promise.all([
215
292
  token0.methods.balance_of_private(liquidityProvider).simulate({
216
293
  from: liquidityProvider
@@ -231,53 +308,60 @@ export class BotFactory {
231
308
  const [t0Bal, t1Bal, lpBal] = await getPrivateBalances();
232
309
  this.log.info(`Minting ${MINT_BALANCE} tokens of each BotToken0 and BotToken1. Current private balances of ${liquidityProvider}: token0=${t0Bal}, token1=${t1Bal}, lp=${lpBal}`);
233
310
  // Add authwitnesses for the transfers in AMM::add_liquidity function
234
- const token0Authwit = await wallet.createAuthWit({
311
+ const token0Authwit = await this.wallet.createAuthWit(defaultAccountAddress, {
235
312
  caller: amm.address,
236
- action: token0.methods.transfer_to_public_and_prepare_private_balance_increase(liquidityProvider, amm.address, amount0Max, authwitNonce)
313
+ call: await token0.methods.transfer_to_public_and_prepare_private_balance_increase(liquidityProvider, amm.address, amount0Max, authwitNonce).getFunctionCall()
237
314
  });
238
- const token1Authwit = await wallet.createAuthWit({
315
+ const token1Authwit = await this.wallet.createAuthWit(defaultAccountAddress, {
239
316
  caller: amm.address,
240
- action: token1.methods.transfer_to_public_and_prepare_private_balance_increase(liquidityProvider, amm.address, amount1Max, authwitNonce)
317
+ call: await token1.methods.transfer_to_public_and_prepare_private_balance_increase(liquidityProvider, amm.address, amount1Max, authwitNonce).getFunctionCall()
241
318
  });
242
- const mintTx = new BatchCall(wallet, [
319
+ const mintReceipt = await new BatchCall(this.wallet, [
243
320
  token0.methods.mint_to_private(liquidityProvider, MINT_BALANCE),
244
321
  token1.methods.mint_to_private(liquidityProvider, MINT_BALANCE)
245
322
  ]).send({
246
- from: liquidityProvider
247
- });
248
- this.log.info(`Sent mint tx: ${(await mintTx.getTxHash()).toString()}`);
249
- await mintTx.wait({
250
- timeout: this.config.txMinedWaitSeconds
323
+ from: liquidityProvider,
324
+ wait: {
325
+ timeout: this.config.txMinedWaitSeconds
326
+ }
251
327
  });
252
- const addLiquidityTx = amm.methods.add_liquidity(amount0Max, amount1Max, amount0Min, amount1Min, authwitNonce).send({
328
+ this.log.info(`Sent mint tx: ${mintReceipt.txHash.toString()}`);
329
+ const addLiquidityReceipt = await amm.methods.add_liquidity(amount0Max, amount1Max, amount0Min, amount1Min, authwitNonce).send({
253
330
  from: liquidityProvider,
254
331
  authWitnesses: [
255
332
  token0Authwit,
256
333
  token1Authwit
257
- ]
258
- });
259
- this.log.info(`Sent tx to add liquidity to the AMM: ${(await addLiquidityTx.getTxHash()).toString()}`);
260
- await addLiquidityTx.wait({
261
- timeout: this.config.txMinedWaitSeconds
334
+ ],
335
+ wait: {
336
+ timeout: this.config.txMinedWaitSeconds
337
+ }
262
338
  });
339
+ this.log.info(`Sent tx to add liquidity to the AMM: ${addLiquidityReceipt.txHash.toString()}`);
263
340
  this.log.info(`Liquidity added`);
264
341
  const [newT0Bal, newT1Bal, newLPBal] = await getPrivateBalances();
265
- this.log.info(`Updated private balances of ${wallet.getAddress()} after minting and funding AMM: token0=${newT0Bal}, token1=${newT1Bal}, lp=${newLPBal}`);
342
+ this.log.info(`Updated private balances of ${defaultAccountAddress} after minting and funding AMM: token0=${newT0Bal}, token1=${newT1Bal}, lp=${newLPBal}`);
266
343
  }
267
344
  async registerOrDeployContract(name, deploy, deployOpts) {
268
- const address = (await deploy.getInstance(deployOpts)).address;
269
- if ((await this.pxe.getContractMetadata(address)).isContractPublished) {
345
+ const instance = await deploy.getInstance(deployOpts);
346
+ const address = instance.address;
347
+ const metadata = await this.wallet.getContractMetadata(address);
348
+ if (metadata.isContractPublished) {
270
349
  this.log.info(`Contract ${name} at ${address.toString()} already deployed`);
271
- return deploy.register();
350
+ await deploy.register();
272
351
  } else {
273
352
  this.log.info(`Deploying contract ${name} at ${address.toString()}`);
274
- const sentTx = deploy.send(deployOpts);
275
- const txHash = await sentTx.getTxHash();
276
- this.log.info(`Sent contract ${name} setup tx with hash ${txHash.toString()}`);
277
- return this.withNoMinTxsPerBlock(()=>sentTx.deployed({
353
+ await this.withNoMinTxsPerBlock(async ()=>{
354
+ const txHash = await deploy.send({
355
+ ...deployOpts,
356
+ wait: NO_WAIT
357
+ });
358
+ this.log.info(`Sent contract ${name} setup tx with hash ${txHash.toString()}`);
359
+ return waitForTx(this.aztecNode, txHash, {
278
360
  timeout: this.config.txMinedWaitSeconds
279
- }));
361
+ });
362
+ });
280
363
  }
364
+ return instance;
281
365
  }
282
366
  /**
283
367
  * Mints private and public tokens for the sender if their balance is below the minimum.
@@ -304,14 +388,47 @@ export class BotFactory {
304
388
  this.log.info(`Skipping minting as ${minter.toString()} has enough tokens`);
305
389
  return;
306
390
  }
307
- const sentTx = new BatchCall(token.wallet, calls).send({
308
- from: minter
309
- });
310
- const txHash = await sentTx.getTxHash();
311
- this.log.info(`Sent token mint tx with hash ${txHash.toString()}`);
312
- await this.withNoMinTxsPerBlock(()=>sentTx.wait({
391
+ // PrivateToken's mint accesses contract-level private storage vars (admin, total_supply).
392
+ const additionalScopes = isStandardToken ? undefined : [
393
+ token.address
394
+ ];
395
+ await this.withNoMinTxsPerBlock(async ()=>{
396
+ const txHash = await new BatchCall(token.wallet, calls).send({
397
+ from: minter,
398
+ additionalScopes,
399
+ wait: NO_WAIT
400
+ });
401
+ this.log.info(`Sent token mint tx with hash ${txHash.toString()}`);
402
+ return waitForTx(this.aztecNode, txHash, {
313
403
  timeout: this.config.txMinedWaitSeconds
314
- }));
404
+ });
405
+ });
406
+ }
407
+ /**
408
+ * Gets or creates a bridge claim for the recipient.
409
+ * Checks if a claim already exists in the store and reuses it if valid.
410
+ * Only creates a new bridge if fee juice balance is below threshold.
411
+ */ async getOrCreateBridgeClaim(recipient) {
412
+ // Check if we have an existing claim in the store
413
+ const existingClaim = await this.store.getBridgeClaim(recipient);
414
+ if (existingClaim) {
415
+ this.log.info(`Found existing bridge claim for ${recipient.toString()}, checking validity...`);
416
+ // Check if the message is ready on L2
417
+ try {
418
+ const messageHash = Fr.fromHexString(existingClaim.claim.messageHash);
419
+ await this.withNoMinTxsPerBlock(()=>waitForL1ToL2MessageReady(this.aztecNode, messageHash, {
420
+ timeoutSeconds: this.config.l1ToL2MessageTimeoutSeconds,
421
+ forPublicConsumption: false
422
+ }));
423
+ return existingClaim.claim;
424
+ } catch (err) {
425
+ this.log.warn(`Failed to verify existing claim, creating new one: ${err}`);
426
+ await this.store.deleteBridgeClaim(recipient);
427
+ }
428
+ }
429
+ const claim = await this.bridgeL1FeeJuice(recipient);
430
+ await this.store.saveBridgeClaim(recipient, claim);
431
+ return claim;
315
432
  }
316
433
  async bridgeL1FeeJuice(recipient) {
317
434
  const l1RpcUrls = this.config.l1RpcUrls;
@@ -322,13 +439,13 @@ export class BotFactory {
322
439
  if (!mnemonicOrPrivateKey) {
323
440
  throw new Error('Either a mnemonic or private key of an L1 account is required to bridge the fee juice to fund the deployment of the account.');
324
441
  }
325
- const { l1ChainId } = await this.pxe.getNodeInfo();
442
+ const { l1ChainId } = await this.aztecNode.getNodeInfo();
326
443
  const chain = createEthereumChain(l1RpcUrls, l1ChainId);
327
444
  const extendedClient = createExtendedL1Client(chain.rpcUrls, mnemonicOrPrivateKey, chain.chainInfo);
328
- const portal = await L1FeeJuicePortalManager.new(this.pxe, extendedClient, this.log);
445
+ const portal = await L1FeeJuicePortalManager.new(this.aztecNode, extendedClient, this.log);
329
446
  const mintAmount = await portal.getTokenManager().getMintAmount();
330
447
  const claim = await portal.bridgeTokensPublic(recipient, mintAmount, true);
331
- await this.withNoMinTxsPerBlock(()=>waitForL1ToL2MessageReady(this.pxe, Fr.fromHexString(claim.messageHash), {
448
+ await this.withNoMinTxsPerBlock(()=>waitForL1ToL2MessageReady(this.aztecNode, Fr.fromHexString(claim.messageHash), {
332
449
  timeoutSeconds: this.config.l1ToL2MessageTimeoutSeconds,
333
450
  forPublicConsumption: false
334
451
  }));
@@ -336,17 +453,20 @@ export class BotFactory {
336
453
  return claim;
337
454
  }
338
455
  async withNoMinTxsPerBlock(fn) {
339
- if (!this.nodeAdmin || !this.config.flushSetupTransactions) {
456
+ if (!this.aztecNodeAdmin || !this.config.flushSetupTransactions) {
457
+ this.log.verbose(`No node admin client or flushing not requested (not setting minTxsPerBlock to 0)`);
340
458
  return fn();
341
459
  }
342
- const { minTxsPerBlock } = await this.nodeAdmin.getConfig();
343
- await this.nodeAdmin.setConfig({
460
+ const { minTxsPerBlock } = await this.aztecNodeAdmin.getConfig();
461
+ this.log.warn(`Setting sequencer minTxsPerBlock to 0 from ${minTxsPerBlock} to flush setup transactions`);
462
+ await this.aztecNodeAdmin.setConfig({
344
463
  minTxsPerBlock: 0
345
464
  });
346
465
  try {
347
466
  return await fn();
348
467
  } finally{
349
- await this.nodeAdmin.setConfig({
468
+ this.log.warn(`Restoring sequencer minTxsPerBlock to ${minTxsPerBlock}`);
469
+ await this.aztecNodeAdmin.setConfig({
350
470
  minTxsPerBlock
351
471
  });
352
472
  }
package/dest/index.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  export { Bot } from './bot.js';
2
2
  export { AmmBot } from './amm_bot.js';
3
+ export { CrossChainBot } from './cross_chain_bot.js';
3
4
  export { BotRunner } from './runner.js';
5
+ export { BotStore } from './store/bot_store.js';
4
6
  export { type BotConfig, getBotConfigFromEnv, getBotDefaultConfig, botConfigMappings, SupportedTokenContracts, } from './config.js';
5
7
  export { getBotRunnerApiHandler } from './rpc.js';
6
8
  export * from './interface.js';
7
- //# sourceMappingURL=index.d.ts.map
9
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQy9CLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDdEMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDeEMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2hELE9BQU8sRUFDTCxLQUFLLFNBQVMsRUFDZCxtQkFBbUIsRUFDbkIsbUJBQW1CLEVBQ25CLGlCQUFpQixFQUNqQix1QkFBdUIsR0FDeEIsTUFBTSxhQUFhLENBQUM7QUFDckIsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQ2xELGNBQWMsZ0JBQWdCLENBQUMifQ==
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EACL,KAAK,SAAS,EACd,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAClD,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EACL,KAAK,SAAS,EACd,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAClD,cAAc,gBAAgB,CAAC"}
package/dest/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  export { Bot } from './bot.js';
2
2
  export { AmmBot } from './amm_bot.js';
3
+ export { CrossChainBot } from './cross_chain_bot.js';
3
4
  export { BotRunner } from './runner.js';
5
+ export { BotStore } from './store/bot_store.js';
4
6
  export { getBotConfigFromEnv, getBotDefaultConfig, botConfigMappings, SupportedTokenContracts } from './config.js';
5
7
  export { getBotRunnerApiHandler } from './rpc.js';
6
8
  export * from './interface.js';
@@ -1,4 +1,4 @@
1
- import { AztecAddress } from '@aztec/aztec.js';
1
+ import { AztecAddress } from '@aztec/aztec.js/addresses';
2
2
  import type { ApiSchemaFor } from '@aztec/stdlib/schemas';
3
3
  import { z } from 'zod';
4
4
  import { type BotConfig } from './config.js';
@@ -20,4 +20,4 @@ export interface BotRunnerApi {
20
20
  update(config: BotConfig): Promise<void>;
21
21
  }
22
22
  export declare const BotRunnerApiSchema: ApiSchemaFor<BotRunnerApi>;
23
- //# sourceMappingURL=interface.d.ts.map
23
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJmYWNlLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW50ZXJmYWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUN6RCxPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUUxRCxPQUFPLEVBQUUsQ0FBQyxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBRXhCLE9BQU8sRUFBRSxLQUFLLFNBQVMsRUFBbUIsTUFBTSxhQUFhLENBQUM7QUFFOUQsZUFBTyxNQUFNLGFBQWE7Ozs7OztFQUV4QixDQUFDO0FBRUgsTUFBTSxNQUFNLE9BQU8sR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sYUFBYSxDQUFDLENBQUM7QUFFcEQsTUFBTSxXQUFXLFlBQVk7SUFDM0IsS0FBSyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN2QixJQUFJLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3RCLEdBQUcsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDckIsS0FBSyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN2QixTQUFTLElBQUksT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ2hDLE9BQU8sSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDNUIsTUFBTSxDQUFDLE1BQU0sRUFBRSxTQUFTLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO0NBQzFDO0FBRUQsZUFBTyxNQUFNLGtCQUFrQixFQUFFLFlBQVksQ0FBQyxZQUFZLENBUXpELENBQUMifQ==
@@ -1 +1 @@
1
- {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../src/interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,aAAa,CAAC;AAE9D,eAAO,MAAM,aAAa;;;;;;EAExB,CAAC;AAEH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,MAAM,WAAW,YAAY;IAC3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,SAAS,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5B,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED,eAAO,MAAM,kBAAkB,EAAE,YAAY,CAAC,YAAY,CAQzD,CAAC"}
1
+ {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../src/interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,aAAa,CAAC;AAE9D,eAAO,MAAM,aAAa;;;;;;EAExB,CAAC;AAEH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,MAAM,WAAW,YAAY;IAC3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,SAAS,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5B,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED,eAAO,MAAM,kBAAkB,EAAE,YAAY,CAAC,YAAY,CAQzD,CAAC"}