@aztec/bot 0.0.0-test.1 → 0.0.1-commit.5476d83

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 (49) hide show
  1. package/dest/amm_bot.d.ts +33 -0
  2. package/dest/amm_bot.d.ts.map +1 -0
  3. package/dest/amm_bot.js +97 -0
  4. package/dest/base_bot.d.ts +21 -0
  5. package/dest/base_bot.d.ts.map +1 -0
  6. package/dest/base_bot.js +80 -0
  7. package/dest/bot.d.ts +13 -18
  8. package/dest/bot.d.ts.map +1 -1
  9. package/dest/bot.js +24 -86
  10. package/dest/config.d.ts +82 -57
  11. package/dest/config.d.ts.map +1 -1
  12. package/dest/config.js +55 -32
  13. package/dest/factory.d.ts +31 -27
  14. package/dest/factory.d.ts.map +1 -1
  15. package/dest/factory.js +277 -132
  16. package/dest/index.d.ts +4 -2
  17. package/dest/index.d.ts.map +1 -1
  18. package/dest/index.js +3 -1
  19. package/dest/interface.d.ts +12 -1
  20. package/dest/interface.d.ts.map +1 -1
  21. package/dest/interface.js +5 -0
  22. package/dest/rpc.d.ts +1 -7
  23. package/dest/rpc.d.ts.map +1 -1
  24. package/dest/rpc.js +0 -11
  25. package/dest/runner.d.ts +15 -11
  26. package/dest/runner.d.ts.map +1 -1
  27. package/dest/runner.js +33 -25
  28. package/dest/store/bot_store.d.ts +44 -0
  29. package/dest/store/bot_store.d.ts.map +1 -0
  30. package/dest/store/bot_store.js +107 -0
  31. package/dest/store/index.d.ts +2 -0
  32. package/dest/store/index.d.ts.map +1 -0
  33. package/dest/store/index.js +1 -0
  34. package/dest/utils.d.ts +8 -5
  35. package/dest/utils.d.ts.map +1 -1
  36. package/dest/utils.js +14 -5
  37. package/package.json +27 -23
  38. package/src/amm_bot.ts +124 -0
  39. package/src/base_bot.ts +96 -0
  40. package/src/bot.ts +52 -103
  41. package/src/config.ts +66 -38
  42. package/src/factory.ts +335 -146
  43. package/src/index.ts +3 -1
  44. package/src/interface.ts +9 -0
  45. package/src/rpc.ts +0 -13
  46. package/src/runner.ts +38 -21
  47. package/src/store/bot_store.ts +141 -0
  48. package/src/store/index.ts +1 -0
  49. package/src/utils.ts +17 -6
package/src/runner.ts CHANGED
@@ -1,16 +1,21 @@
1
- import { type AztecNode, type PXE, createAztecNodeClient, createLogger } from '@aztec/aztec.js';
1
+ import { createLogger } from '@aztec/aztec.js/log';
2
+ import type { AztecNode } from '@aztec/aztec.js/node';
3
+ import { omit } from '@aztec/foundation/collection';
2
4
  import { RunningPromise } from '@aztec/foundation/running-promise';
3
- import { type TelemetryClient, type Traceable, type Tracer, makeTracedFetch, trackSpan } from '@aztec/telemetry-client';
5
+ import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
6
+ import { type TelemetryClient, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client';
7
+ import type { TestWallet } from '@aztec/test-wallet/server';
4
8
 
9
+ import { AmmBot } from './amm_bot.js';
10
+ import type { BaseBot } from './base_bot.js';
5
11
  import { Bot } from './bot.js';
6
- import { type BotConfig, getVersions } from './config.js';
7
- import type { BotRunnerApi } from './interface.js';
12
+ import type { BotConfig } from './config.js';
13
+ import type { BotInfo, BotRunnerApi } from './interface.js';
14
+ import { BotStore } from './store/index.js';
8
15
 
9
16
  export class BotRunner implements BotRunnerApi, Traceable {
10
17
  private log = createLogger('bot');
11
- private bot?: Promise<Bot>;
12
- private pxe?: PXE;
13
- private node: AztecNode;
18
+ private bot?: Promise<BaseBot>;
14
19
  private runningPromise: RunningPromise;
15
20
  private consecutiveErrors = 0;
16
21
  private healthy = true;
@@ -19,15 +24,14 @@ export class BotRunner implements BotRunnerApi, Traceable {
19
24
 
20
25
  public constructor(
21
26
  private config: BotConfig,
22
- dependencies: { pxe?: PXE; node?: AztecNode; telemetry: TelemetryClient },
27
+ private readonly wallet: TestWallet,
28
+ private readonly aztecNode: AztecNode,
29
+ private readonly telemetry: TelemetryClient,
30
+ private readonly aztecNodeAdmin: AztecNodeAdmin | undefined,
31
+ private readonly store: BotStore,
23
32
  ) {
24
- this.tracer = dependencies.telemetry.getTracer('Bot');
25
- this.pxe = dependencies.pxe;
26
- if (!dependencies.node && !config.nodeUrl) {
27
- throw new Error(`Missing node URL in config or dependencies`);
28
- }
29
- this.node =
30
- dependencies.node ?? createAztecNodeClient(config.nodeUrl!, getVersions(), makeTracedFetch([1, 2, 3], true));
33
+ this.tracer = telemetry.getTracer('Bot');
34
+
31
35
  this.runningPromise = new RunningPromise(() => this.#work(), this.log, config.txIntervalSeconds * 1000);
32
36
  }
33
37
 
@@ -65,6 +69,7 @@ export class BotRunner implements BotRunnerApi, Traceable {
65
69
  this.log.verbose(`Stopping bot`);
66
70
  await this.runningPromise.stop();
67
71
  }
72
+ await this.store.close();
68
73
  this.log.info(`Stopped bot`);
69
74
  }
70
75
 
@@ -126,12 +131,24 @@ export class BotRunner implements BotRunnerApi, Traceable {
126
131
 
127
132
  /** Returns the current configuration for the bot. */
128
133
  public getConfig() {
129
- return Promise.resolve(this.config);
134
+ const redacted = omit(this.config, 'l1Mnemonic', 'l1PrivateKey', 'senderPrivateKey');
135
+ return Promise.resolve(redacted as BotConfig);
136
+ }
137
+
138
+ /** Returns the bot sender address. */
139
+ public async getInfo(): Promise<BotInfo> {
140
+ if (!this.bot) {
141
+ throw new Error(`Bot is not initialized`);
142
+ }
143
+ const botAddress = await this.bot.then(b => b.defaultAccountAddress);
144
+ return { botAddress };
130
145
  }
131
146
 
132
147
  async #createBot() {
133
148
  try {
134
- this.bot = Bot.create(this.config, { pxe: this.pxe, node: this.node });
149
+ this.bot = this.config.ammTxs
150
+ ? AmmBot.create(this.config, this.wallet, this.aztecNode, this.aztecNodeAdmin, this.store)
151
+ : Bot.create(this.config, this.wallet, this.aztecNode, this.aztecNodeAdmin, this.store);
135
152
  await this.bot;
136
153
  } catch (err) {
137
154
  this.log.error(`Error setting up bot: ${err}`);
@@ -142,16 +159,16 @@ export class BotRunner implements BotRunnerApi, Traceable {
142
159
  @trackSpan('Bot.work')
143
160
  async #work() {
144
161
  if (this.config.maxPendingTxs > 0) {
145
- const pendingTxs = await this.node.getPendingTxs();
146
- if (pendingTxs.length >= this.config.maxPendingTxs) {
147
- this.log.verbose(`Not sending bot tx since node has ${pendingTxs.length} pending txs`);
162
+ const pendingTxCount = await this.aztecNode.getPendingTxCount();
163
+ if (pendingTxCount >= this.config.maxPendingTxs) {
164
+ this.log.verbose(`Not sending bot tx since node has ${pendingTxCount} pending txs`);
148
165
  return;
149
166
  }
150
167
  }
151
168
 
152
169
  try {
153
170
  await this.run();
154
- } catch (err) {
171
+ } catch {
155
172
  // Already logged in run()
156
173
  if (this.config.maxConsecutiveErrors > 0 && this.consecutiveErrors >= this.config.maxConsecutiveErrors) {
157
174
  this.log.error(`Too many errors bot is unhealthy`);
@@ -0,0 +1,141 @@
1
+ import { AztecAddress } from '@aztec/aztec.js/addresses';
2
+ import type { L2AmountClaim } from '@aztec/aztec.js/ethereum';
3
+ import { Fr } from '@aztec/foundation/fields';
4
+ import { type Logger, createLogger } from '@aztec/foundation/log';
5
+ import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
6
+
7
+ export interface BridgeClaimData {
8
+ claim: L2AmountClaim;
9
+ timestamp: number;
10
+ recipient: string;
11
+ }
12
+
13
+ /**
14
+ * Simple data store for the bot to persist L1 bridge claims.
15
+ */
16
+ export class BotStore {
17
+ public static readonly SCHEMA_VERSION = 1;
18
+ private readonly bridgeClaims: AztecAsyncMap<string, string>;
19
+
20
+ constructor(
21
+ private readonly store: AztecAsyncKVStore,
22
+ private readonly log: Logger = createLogger('bot:store'),
23
+ ) {
24
+ this.bridgeClaims = store.openMap<string, string>('bridge_claims');
25
+ }
26
+
27
+ /**
28
+ * Saves a bridge claim for a recipient.
29
+ */
30
+ public async saveBridgeClaim(recipient: AztecAddress, claim: L2AmountClaim): Promise<void> {
31
+ // Convert Fr fields and BigInts to strings for JSON serialization
32
+ const serializableClaim = {
33
+ claimAmount: claim.claimAmount.toString(),
34
+ claimSecret: claim.claimSecret.toString(),
35
+ claimSecretHash: claim.claimSecretHash.toString(),
36
+ messageHash: claim.messageHash,
37
+ messageLeafIndex: claim.messageLeafIndex.toString(),
38
+ };
39
+
40
+ const data = {
41
+ claim: serializableClaim,
42
+ timestamp: Date.now(),
43
+ recipient: recipient.toString(),
44
+ };
45
+
46
+ await this.bridgeClaims.set(recipient.toString(), JSON.stringify(data));
47
+ this.log.info(`Saved bridge claim for ${recipient.toString()}`);
48
+ }
49
+
50
+ /**
51
+ * Gets a bridge claim for a recipient if it exists.
52
+ */
53
+ public async getBridgeClaim(recipient: AztecAddress): Promise<BridgeClaimData | undefined> {
54
+ const data = await this.bridgeClaims.getAsync(recipient.toString());
55
+ if (!data) {
56
+ return undefined;
57
+ }
58
+
59
+ const parsed = JSON.parse(data);
60
+
61
+ // Reconstruct L2AmountClaim from serialized data
62
+ const claim: L2AmountClaim = {
63
+ claimAmount: BigInt(parsed.claim.claimAmount),
64
+ claimSecret: Fr.fromString(parsed.claim.claimSecret),
65
+ claimSecretHash: Fr.fromString(parsed.claim.claimSecretHash),
66
+ messageHash: parsed.claim.messageHash,
67
+ messageLeafIndex: BigInt(parsed.claim.messageLeafIndex),
68
+ };
69
+
70
+ return {
71
+ claim,
72
+ timestamp: parsed.timestamp,
73
+ recipient: parsed.recipient,
74
+ };
75
+ }
76
+
77
+ /**
78
+ * Deletes a bridge claim for a recipient.
79
+ */
80
+ public async deleteBridgeClaim(recipient: AztecAddress): Promise<void> {
81
+ await this.bridgeClaims.delete(recipient.toString());
82
+ this.log.info(`Deleted bridge claim for ${recipient.toString()}`);
83
+ }
84
+
85
+ /**
86
+ * Gets all stored bridge claims.
87
+ */
88
+ public async getAllBridgeClaims(): Promise<BridgeClaimData[]> {
89
+ const claims: BridgeClaimData[] = [];
90
+ const entries = this.bridgeClaims.entriesAsync();
91
+
92
+ for await (const [_, data] of entries) {
93
+ const parsed = JSON.parse(data);
94
+
95
+ // Reconstruct L2AmountClaim from serialized data
96
+ const claim: L2AmountClaim = {
97
+ claimAmount: BigInt(parsed.claim.claimAmount),
98
+ claimSecret: Fr.fromString(parsed.claim.claimSecret),
99
+ claimSecretHash: Fr.fromString(parsed.claim.claimSecretHash),
100
+ messageHash: parsed.claim.messageHash,
101
+ messageLeafIndex: BigInt(parsed.claim.messageLeafIndex),
102
+ };
103
+
104
+ claims.push({
105
+ claim,
106
+ timestamp: parsed.timestamp,
107
+ recipient: parsed.recipient,
108
+ });
109
+ }
110
+
111
+ return claims;
112
+ }
113
+
114
+ /**
115
+ * Cleans up old bridge claims (older than 24 hours).
116
+ */
117
+ public async cleanupOldClaims(maxAgeMs: number = 24 * 60 * 60 * 1000): Promise<number> {
118
+ const now = Date.now();
119
+ let cleanedCount = 0;
120
+ const entries = this.bridgeClaims.entriesAsync();
121
+
122
+ for await (const [key, data] of entries) {
123
+ const parsed = JSON.parse(data);
124
+ if (now - parsed.timestamp > maxAgeMs) {
125
+ await this.bridgeClaims.delete(key);
126
+ cleanedCount++;
127
+ this.log.info(`Cleaned up old bridge claim for ${parsed.recipient}`);
128
+ }
129
+ }
130
+
131
+ return cleanedCount;
132
+ }
133
+
134
+ /**
135
+ * Closes the store.
136
+ */
137
+ public async close(): Promise<void> {
138
+ await this.store.close();
139
+ this.log.info('Closed bot data store');
140
+ }
141
+ }
@@ -0,0 +1 @@
1
+ export { BotStore, type BridgeClaimData } from './bot_store.js';
package/src/utils.ts CHANGED
@@ -1,4 +1,6 @@
1
- import type { EasyPrivateTokenContract } from '@aztec/noir-contracts.js/EasyPrivateToken';
1
+ import { ContractBase } from '@aztec/aztec.js/contracts';
2
+ import type { AMMContract } from '@aztec/noir-contracts.js/AMM';
3
+ import type { PrivateTokenContract } from '@aztec/noir-contracts.js/PrivateToken';
2
4
  import type { TokenContract } from '@aztec/noir-contracts.js/Token';
3
5
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
4
6
 
@@ -11,17 +13,26 @@ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
11
13
  export async function getBalances(
12
14
  token: TokenContract,
13
15
  who: AztecAddress,
16
+ from?: AztecAddress,
14
17
  ): Promise<{ privateBalance: bigint; publicBalance: bigint }> {
15
- const privateBalance = await token.methods.balance_of_private(who).simulate();
16
- const publicBalance = await token.methods.balance_of_public(who).simulate();
18
+ const privateBalance = await token.methods.balance_of_private(who).simulate({ from: from ?? who });
19
+ const publicBalance = await token.methods.balance_of_public(who).simulate({ from: from ?? who });
17
20
  return { privateBalance, publicBalance };
18
21
  }
19
22
 
20
- export async function getPrivateBalance(token: EasyPrivateTokenContract, who: AztecAddress): Promise<bigint> {
21
- const privateBalance = await token.methods.get_balance(who).simulate();
23
+ export async function getPrivateBalance(
24
+ token: PrivateTokenContract,
25
+ who: AztecAddress,
26
+ from?: AztecAddress,
27
+ ): Promise<bigint> {
28
+ const privateBalance = await token.methods.get_balance(who).simulate({ from: from ?? who });
22
29
  return privateBalance;
23
30
  }
24
31
 
25
- export function isStandardTokenContract(token: TokenContract | EasyPrivateTokenContract): token is TokenContract {
32
+ export function isStandardTokenContract(token: ContractBase): token is TokenContract {
26
33
  return 'mint_to_public' in token.methods;
27
34
  }
35
+
36
+ export function isAMMContract(contract: ContractBase): contract is AMMContract {
37
+ return 'add_liquidity' in contract.methods;
38
+ }