@aztec/bot 0.0.1-commit.fce3e4f → 0.0.1-commit.ff7989d6c

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 (44) hide show
  1. package/dest/amm_bot.d.ts +6 -7
  2. package/dest/amm_bot.d.ts.map +1 -1
  3. package/dest/amm_bot.js +5 -1
  4. package/dest/base_bot.d.ts +6 -6
  5. package/dest/base_bot.d.ts.map +1 -1
  6. package/dest/base_bot.js +14 -15
  7. package/dest/bot.d.ts +6 -6
  8. package/dest/bot.d.ts.map +1 -1
  9. package/dest/bot.js +7 -4
  10. package/dest/config.d.ts +40 -25
  11. package/dest/config.d.ts.map +1 -1
  12. package/dest/config.js +43 -15
  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 +20 -10
  17. package/dest/factory.d.ts.map +1 -1
  18. package/dest/factory.js +175 -75
  19. package/dest/index.d.ts +2 -1
  20. package/dest/index.d.ts.map +1 -1
  21. package/dest/index.js +1 -0
  22. package/dest/l1_to_l2_seeding.d.ts +8 -0
  23. package/dest/l1_to_l2_seeding.d.ts.map +1 -0
  24. package/dest/l1_to_l2_seeding.js +63 -0
  25. package/dest/runner.d.ts +3 -3
  26. package/dest/runner.d.ts.map +1 -1
  27. package/dest/runner.js +429 -31
  28. package/dest/store/bot_store.d.ts +31 -6
  29. package/dest/store/bot_store.d.ts.map +1 -1
  30. package/dest/store/bot_store.js +38 -7
  31. package/dest/store/index.d.ts +2 -2
  32. package/dest/store/index.d.ts.map +1 -1
  33. package/package.json +19 -16
  34. package/src/amm_bot.ts +7 -7
  35. package/src/base_bot.ts +13 -27
  36. package/src/bot.ts +9 -8
  37. package/src/config.ts +90 -59
  38. package/src/cross_chain_bot.ts +209 -0
  39. package/src/factory.ts +185 -60
  40. package/src/index.ts +1 -0
  41. package/src/l1_to_l2_seeding.ts +79 -0
  42. package/src/runner.ts +18 -5
  43. package/src/store/bot_store.ts +61 -6
  44. package/src/store/index.ts +1 -1
@@ -1,21 +1,40 @@
1
1
  import { AztecAddress } from '@aztec/aztec.js/addresses';
2
2
  import type { L2AmountClaim } from '@aztec/aztec.js/ethereum';
3
3
  import { type Logger } from '@aztec/foundation/log';
4
+ import { DateProvider } from '@aztec/foundation/timer';
4
5
  import type { AztecAsyncKVStore } from '@aztec/kv-store';
5
6
  export interface BridgeClaimData {
6
7
  claim: L2AmountClaim;
7
8
  timestamp: number;
8
9
  recipient: string;
9
10
  }
11
+ export interface PendingL1ToL2Message {
12
+ /** Random content field sent in the message. */
13
+ content: string;
14
+ /** Secret for consuming the message. */
15
+ secret: string;
16
+ /** Hash of the secret. */
17
+ secretHash: string;
18
+ /** Hash of the L1→L2 message. */
19
+ msgHash: string;
20
+ /** L1 sender address (hex). */
21
+ sender: string;
22
+ /** Global leaf index in the L1→L2 message tree. */
23
+ globalLeafIndex: string;
24
+ /** Timestamp when the message was seeded. */
25
+ timestamp: number;
26
+ }
10
27
  /**
11
28
  * Simple data store for the bot to persist L1 bridge claims.
12
29
  */
13
30
  export declare class BotStore {
14
31
  private readonly store;
15
32
  private readonly log;
16
- static readonly SCHEMA_VERSION: number;
33
+ private readonly dateProvider;
34
+ static readonly SCHEMA_VERSION = 1;
17
35
  private readonly bridgeClaims;
18
- constructor(store: AztecAsyncKVStore, log?: Logger);
36
+ private readonly pendingL1ToL2;
37
+ constructor(store: AztecAsyncKVStore, log?: Logger, dateProvider?: DateProvider);
19
38
  /**
20
39
  * Saves a bridge claim for a recipient.
21
40
  */
@@ -36,9 +55,15 @@ export declare class BotStore {
36
55
  * Cleans up old bridge claims (older than 24 hours).
37
56
  */
38
57
  cleanupOldClaims(maxAgeMs?: number): Promise<number>;
39
- /**
40
- * Closes the store.
41
- */
58
+ /** Saves a pending L1→L2 message keyed by msgHash. */
59
+ savePendingL1ToL2Message(msg: PendingL1ToL2Message): Promise<void>;
60
+ /** Returns all unconsumed pending L1→L2 messages. */
61
+ getUnconsumedL1ToL2Messages(): Promise<PendingL1ToL2Message[]>;
62
+ /** Deletes a consumed L1→L2 message from the store. */
63
+ deleteL1ToL2Message(msgHash: string): Promise<void>;
64
+ /** Cleans up pending L1→L2 messages older than maxAgeMs. */
65
+ cleanupOldPendingMessages(maxAgeMs?: number): Promise<number>;
66
+ /** Closes the store. */
42
67
  close(): Promise<void>;
43
68
  }
44
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm90X3N0b3JlLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3RvcmUvYm90X3N0b3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUN6RCxPQUFPLEtBQUssRUFBRSxhQUFhLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUU5RCxPQUFPLEVBQUUsS0FBSyxNQUFNLEVBQWdCLE1BQU0sdUJBQXVCLENBQUM7QUFDbEUsT0FBTyxLQUFLLEVBQUUsaUJBQWlCLEVBQWlCLE1BQU0saUJBQWlCLENBQUM7QUFFeEUsTUFBTSxXQUFXLGVBQWU7SUFDOUIsS0FBSyxFQUFFLGFBQWEsQ0FBQztJQUNyQixTQUFTLEVBQUUsTUFBTSxDQUFDO0lBQ2xCLFNBQVMsRUFBRSxNQUFNLENBQUM7Q0FDbkI7QUFFRDs7R0FFRztBQUNILHFCQUFhLFFBQVE7SUFLakIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxLQUFLO0lBQ3RCLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRztJQUx0QixnQkFBdUIsY0FBYyxTQUFLO0lBQzFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFnQztJQUU3RCxZQUNtQixLQUFLLEVBQUUsaUJBQWlCLEVBQ3hCLEdBQUcsR0FBRSxNQUFrQyxFQUd6RDtJQUVEOztPQUVHO0lBQ1UsZUFBZSxDQUFDLFNBQVMsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLGFBQWEsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBa0J6RjtJQUVEOztPQUVHO0lBQ1UsY0FBYyxDQUFDLFNBQVMsRUFBRSxZQUFZLEdBQUcsT0FBTyxDQUFDLGVBQWUsR0FBRyxTQUFTLENBQUMsQ0FzQnpGO0lBRUQ7O09BRUc7SUFDVSxpQkFBaUIsQ0FBQyxTQUFTLEVBQUUsWUFBWSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FHckU7SUFFRDs7T0FFRztJQUNVLGtCQUFrQixJQUFJLE9BQU8sQ0FBQyxlQUFlLEVBQUUsQ0FBQyxDQXdCNUQ7SUFFRDs7T0FFRztJQUNVLGdCQUFnQixDQUFDLFFBQVEsR0FBRSxNQUE0QixHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FlckY7SUFFRDs7T0FFRztJQUNVLEtBQUssSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLENBR2xDO0NBQ0YifQ==
69
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm90X3N0b3JlLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3RvcmUvYm90X3N0b3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUN6RCxPQUFPLEtBQUssRUFBRSxhQUFhLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUU5RCxPQUFPLEVBQUUsS0FBSyxNQUFNLEVBQWdCLE1BQU0sdUJBQXVCLENBQUM7QUFDbEUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3ZELE9BQU8sS0FBSyxFQUFFLGlCQUFpQixFQUFpQixNQUFNLGlCQUFpQixDQUFDO0FBRXhFLE1BQU0sV0FBVyxlQUFlO0lBQzlCLEtBQUssRUFBRSxhQUFhLENBQUM7SUFDckIsU0FBUyxFQUFFLE1BQU0sQ0FBQztJQUNsQixTQUFTLEVBQUUsTUFBTSxDQUFDO0NBQ25CO0FBRUQsTUFBTSxXQUFXLG9CQUFvQjtJQUNuQyxnREFBZ0Q7SUFDaEQsT0FBTyxFQUFFLE1BQU0sQ0FBQztJQUNoQix3Q0FBd0M7SUFDeEMsTUFBTSxFQUFFLE1BQU0sQ0FBQztJQUNmLDBCQUEwQjtJQUMxQixVQUFVLEVBQUUsTUFBTSxDQUFDO0lBQ25CLG1DQUFpQztJQUNqQyxPQUFPLEVBQUUsTUFBTSxDQUFDO0lBQ2hCLCtCQUErQjtJQUMvQixNQUFNLEVBQUUsTUFBTSxDQUFDO0lBQ2YscURBQW1EO0lBQ25ELGVBQWUsRUFBRSxNQUFNLENBQUM7SUFDeEIsNkNBQTZDO0lBQzdDLFNBQVMsRUFBRSxNQUFNLENBQUM7Q0FDbkI7QUFFRDs7R0FFRztBQUNILHFCQUFhLFFBQVE7SUFNakIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxLQUFLO0lBQ3RCLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRztJQUNwQixPQUFPLENBQUMsUUFBUSxDQUFDLFlBQVk7SUFQL0IsZ0JBQXVCLGNBQWMsS0FBSztJQUMxQyxPQUFPLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBZ0M7SUFDN0QsT0FBTyxDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQWdDO0lBRTlELFlBQ21CLEtBQUssRUFBRSxpQkFBaUIsRUFDeEIsR0FBRyxHQUFFLE1BQWtDLEVBQ3ZDLFlBQVksR0FBRSxZQUFpQyxFQUlqRTtJQUVEOztPQUVHO0lBQ1UsZUFBZSxDQUFDLFNBQVMsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLGFBQWEsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBa0J6RjtJQUVEOztPQUVHO0lBQ1UsY0FBYyxDQUFDLFNBQVMsRUFBRSxZQUFZLEdBQUcsT0FBTyxDQUFDLGVBQWUsR0FBRyxTQUFTLENBQUMsQ0FzQnpGO0lBRUQ7O09BRUc7SUFDVSxpQkFBaUIsQ0FBQyxTQUFTLEVBQUUsWUFBWSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FHckU7SUFFRDs7T0FFRztJQUNVLGtCQUFrQixJQUFJLE9BQU8sQ0FBQyxlQUFlLEVBQUUsQ0FBQyxDQXdCNUQ7SUFFRDs7T0FFRztJQUNVLGdCQUFnQixDQUFDLFFBQVEsR0FBRSxNQUE0QixHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FlckY7SUFFRCx3REFBc0Q7SUFDekMsd0JBQXdCLENBQUMsR0FBRyxFQUFFLG9CQUFvQixHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FHOUU7SUFFRCx1REFBcUQ7SUFDeEMsMkJBQTJCLElBQUksT0FBTyxDQUFDLG9CQUFvQixFQUFFLENBQUMsQ0FNMUU7SUFFRCx5REFBdUQ7SUFDMUMsbUJBQW1CLENBQUMsT0FBTyxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBRy9EO0lBRUQsOERBQTREO0lBQy9DLHlCQUF5QixDQUFDLFFBQVEsR0FBRSxNQUE0QixHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FZOUY7SUFFRCx3QkFBd0I7SUFDWCxLQUFLLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQUdsQztDQUNGIn0=
@@ -1 +1 @@
1
- {"version":3,"file":"bot_store.d.ts","sourceRoot":"","sources":["../../src/store/bot_store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAiB,MAAM,iBAAiB,CAAC;AAExE,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,QAAQ;IAKjB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,GAAG;IALtB,gBAAuB,cAAc,SAAK;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgC;IAE7D,YACmB,KAAK,EAAE,iBAAiB,EACxB,GAAG,GAAE,MAAkC,EAGzD;IAED;;OAEG;IACU,eAAe,CAAC,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBzF;IAED;;OAEG;IACU,cAAc,CAAC,SAAS,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAsBzF;IAED;;OAEG;IACU,iBAAiB,CAAC,SAAS,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAGrE;IAED;;OAEG;IACU,kBAAkB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAwB5D;IAED;;OAEG;IACU,gBAAgB,CAAC,QAAQ,GAAE,MAA4B,GAAG,OAAO,CAAC,MAAM,CAAC,CAerF;IAED;;OAEG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAGlC;CACF"}
1
+ {"version":3,"file":"bot_store.d.ts","sourceRoot":"","sources":["../../src/store/bot_store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,KAAK,EAAE,iBAAiB,EAAiB,MAAM,iBAAiB,CAAC;AAExE,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,mCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,qDAAmD;IACnD,eAAe,EAAE,MAAM,CAAC;IACxB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,QAAQ;IAMjB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAP/B,gBAAuB,cAAc,KAAK;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgC;IAC7D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgC;IAE9D,YACmB,KAAK,EAAE,iBAAiB,EACxB,GAAG,GAAE,MAAkC,EACvC,YAAY,GAAE,YAAiC,EAIjE;IAED;;OAEG;IACU,eAAe,CAAC,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBzF;IAED;;OAEG;IACU,cAAc,CAAC,SAAS,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAsBzF;IAED;;OAEG;IACU,iBAAiB,CAAC,SAAS,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAGrE;IAED;;OAEG;IACU,kBAAkB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAwB5D;IAED;;OAEG;IACU,gBAAgB,CAAC,QAAQ,GAAE,MAA4B,GAAG,OAAO,CAAC,MAAM,CAAC,CAerF;IAED,wDAAsD;IACzC,wBAAwB,CAAC,GAAG,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAG9E;IAED,uDAAqD;IACxC,2BAA2B,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAM1E;IAED,yDAAuD;IAC1C,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG/D;IAED,8DAA4D;IAC/C,yBAAyB,CAAC,QAAQ,GAAE,MAA4B,GAAG,OAAO,CAAC,MAAM,CAAC,CAY9F;IAED,wBAAwB;IACX,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAGlC;CACF"}
@@ -1,16 +1,21 @@
1
- import { Fr } from '@aztec/foundation/fields';
1
+ import { Fr } from '@aztec/foundation/curves/bn254';
2
2
  import { createLogger } from '@aztec/foundation/log';
3
+ import { DateProvider } from '@aztec/foundation/timer';
3
4
  /**
4
5
  * Simple data store for the bot to persist L1 bridge claims.
5
6
  */ export class BotStore {
6
7
  store;
7
8
  log;
9
+ dateProvider;
8
10
  static SCHEMA_VERSION = 1;
9
11
  bridgeClaims;
10
- constructor(store, log = createLogger('bot:store')){
12
+ pendingL1ToL2;
13
+ constructor(store, log = createLogger('bot:store'), dateProvider = new DateProvider()){
11
14
  this.store = store;
12
15
  this.log = log;
16
+ this.dateProvider = dateProvider;
13
17
  this.bridgeClaims = store.openMap('bridge_claims');
18
+ this.pendingL1ToL2 = store.openMap('pending_l1_to_l2');
14
19
  }
15
20
  /**
16
21
  * Saves a bridge claim for a recipient.
@@ -25,7 +30,7 @@ import { createLogger } from '@aztec/foundation/log';
25
30
  };
26
31
  const data = {
27
32
  claim: serializableClaim,
28
- timestamp: Date.now(),
33
+ timestamp: this.dateProvider.now(),
29
34
  recipient: recipient.toString()
30
35
  };
31
36
  await this.bridgeClaims.set(recipient.toString(), JSON.stringify(data));
@@ -85,7 +90,7 @@ import { createLogger } from '@aztec/foundation/log';
85
90
  /**
86
91
  * Cleans up old bridge claims (older than 24 hours).
87
92
  */ async cleanupOldClaims(maxAgeMs = 24 * 60 * 60 * 1000) {
88
- const now = Date.now();
93
+ const now = this.dateProvider.now();
89
94
  let cleanedCount = 0;
90
95
  const entries = this.bridgeClaims.entriesAsync();
91
96
  for await (const [key, data] of entries){
@@ -98,9 +103,35 @@ import { createLogger } from '@aztec/foundation/log';
98
103
  }
99
104
  return cleanedCount;
100
105
  }
101
- /**
102
- * Closes the store.
103
- */ async close() {
106
+ /** Saves a pending L1→L2 message keyed by msgHash. */ async savePendingL1ToL2Message(msg) {
107
+ await this.pendingL1ToL2.set(msg.msgHash, JSON.stringify(msg));
108
+ this.log.info(`Saved pending L1→L2 message ${msg.msgHash}`);
109
+ }
110
+ /** Returns all unconsumed pending L1→L2 messages. */ async getUnconsumedL1ToL2Messages() {
111
+ const messages = [];
112
+ for await (const [_, data] of this.pendingL1ToL2.entriesAsync()){
113
+ messages.push(JSON.parse(data));
114
+ }
115
+ return messages;
116
+ }
117
+ /** Deletes a consumed L1→L2 message from the store. */ async deleteL1ToL2Message(msgHash) {
118
+ await this.pendingL1ToL2.delete(msgHash);
119
+ this.log.info(`Deleted consumed L1→L2 message ${msgHash}`);
120
+ }
121
+ /** Cleans up pending L1→L2 messages older than maxAgeMs. */ async cleanupOldPendingMessages(maxAgeMs = 24 * 60 * 60 * 1000) {
122
+ const now = this.dateProvider.now();
123
+ let cleanedCount = 0;
124
+ for await (const [key, data] of this.pendingL1ToL2.entriesAsync()){
125
+ const parsed = JSON.parse(data);
126
+ if (now - parsed.timestamp > maxAgeMs) {
127
+ await this.pendingL1ToL2.delete(key);
128
+ cleanedCount++;
129
+ this.log.info(`Cleaned up old pending L1→L2 message ${key}`);
130
+ }
131
+ }
132
+ return cleanedCount;
133
+ }
134
+ /** Closes the store. */ async close() {
104
135
  await this.store.close();
105
136
  this.log.info('Closed bot data store');
106
137
  }
@@ -1,2 +1,2 @@
1
- export { BotStore, type BridgeClaimData } from './bot_store.js';
2
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zdG9yZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLEtBQUssZUFBZSxFQUFFLE1BQU0sZ0JBQWdCLENBQUMifQ==
1
+ export { BotStore, type BridgeClaimData, type PendingL1ToL2Message } from './bot_store.js';
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zdG9yZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLEtBQUssZUFBZSxFQUFFLEtBQUssb0JBQW9CLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQyJ9
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/bot",
3
- "version": "0.0.1-commit.fce3e4f",
3
+ "version": "0.0.1-commit.ff7989d6c",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -10,8 +10,8 @@
10
10
  "../package.common.json"
11
11
  ],
12
12
  "scripts": {
13
- "build": "yarn clean && tsgo -b",
14
- "build:dev": "tsgo -b --watch",
13
+ "build": "yarn clean && ../scripts/tsc.sh",
14
+ "build:dev": "../scripts/tsc.sh --watch",
15
15
  "clean": "rm -rf ./dest .tsbuildinfo",
16
16
  "bb": "node --no-warnings ./dest/bb/index.js",
17
17
  "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --passWithNoTests --maxWorkers=${JEST_MAX_WORKERS:-8}"
@@ -54,20 +54,23 @@
54
54
  ]
55
55
  },
56
56
  "dependencies": {
57
- "@aztec/accounts": "0.0.1-commit.fce3e4f",
58
- "@aztec/aztec.js": "0.0.1-commit.fce3e4f",
59
- "@aztec/entrypoints": "0.0.1-commit.fce3e4f",
60
- "@aztec/ethereum": "0.0.1-commit.fce3e4f",
61
- "@aztec/foundation": "0.0.1-commit.fce3e4f",
62
- "@aztec/kv-store": "0.0.1-commit.fce3e4f",
63
- "@aztec/noir-contracts.js": "0.0.1-commit.fce3e4f",
64
- "@aztec/noir-protocol-circuits-types": "0.0.1-commit.fce3e4f",
65
- "@aztec/protocol-contracts": "0.0.1-commit.fce3e4f",
66
- "@aztec/stdlib": "0.0.1-commit.fce3e4f",
67
- "@aztec/telemetry-client": "0.0.1-commit.fce3e4f",
68
- "@aztec/test-wallet": "0.0.1-commit.fce3e4f",
57
+ "@aztec/accounts": "0.0.1-commit.ff7989d6c",
58
+ "@aztec/aztec.js": "0.0.1-commit.ff7989d6c",
59
+ "@aztec/entrypoints": "0.0.1-commit.ff7989d6c",
60
+ "@aztec/ethereum": "0.0.1-commit.ff7989d6c",
61
+ "@aztec/foundation": "0.0.1-commit.ff7989d6c",
62
+ "@aztec/kv-store": "0.0.1-commit.ff7989d6c",
63
+ "@aztec/l1-artifacts": "0.0.1-commit.ff7989d6c",
64
+ "@aztec/noir-contracts.js": "0.0.1-commit.ff7989d6c",
65
+ "@aztec/noir-protocol-circuits-types": "0.0.1-commit.ff7989d6c",
66
+ "@aztec/noir-test-contracts.js": "0.0.1-commit.ff7989d6c",
67
+ "@aztec/protocol-contracts": "0.0.1-commit.ff7989d6c",
68
+ "@aztec/stdlib": "0.0.1-commit.ff7989d6c",
69
+ "@aztec/telemetry-client": "0.0.1-commit.ff7989d6c",
70
+ "@aztec/wallets": "0.0.1-commit.ff7989d6c",
69
71
  "source-map-support": "^0.5.21",
70
72
  "tslib": "^2.4.0",
73
+ "viem": "npm:@aztec/viem@2.38.2",
71
74
  "zod": "^3.23.8"
72
75
  },
73
76
  "devDependencies": {
@@ -75,7 +78,7 @@
75
78
  "@types/jest": "^30.0.0",
76
79
  "@types/node": "^22.15.17",
77
80
  "@types/source-map-support": "^0.5.10",
78
- "@typescript/native-preview": "7.0.0-dev.20251126.1",
81
+ "@typescript/native-preview": "7.0.0-dev.20260113.1",
79
82
  "jest": "^30.0.0",
80
83
  "jest-mock-extended": "^4.0.0",
81
84
  "ts-node": "^10.9.1",
package/src/amm_bot.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import { AztecAddress } from '@aztec/aztec.js/addresses';
2
- import { SentTx } from '@aztec/aztec.js/contracts';
2
+ import { NO_WAIT } from '@aztec/aztec.js/contracts';
3
3
  import { Fr } from '@aztec/aztec.js/fields';
4
- import { TxReceipt } from '@aztec/aztec.js/tx';
4
+ import { TxHash, TxReceipt } from '@aztec/aztec.js/tx';
5
5
  import { jsonStringify } from '@aztec/foundation/json-rpc';
6
6
  import type { AMMContract } from '@aztec/noir-contracts.js/AMM';
7
7
  import type { TokenContract } from '@aztec/noir-contracts.js/Token';
8
8
  import type { AztecNode, AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
9
- import type { TestWallet } from '@aztec/test-wallet/server';
9
+ import type { EmbeddedWallet } from '@aztec/wallets/embedded';
10
10
 
11
11
  import { BaseBot } from './base_bot.js';
12
12
  import type { BotConfig } from './config.js';
@@ -21,7 +21,7 @@ type Balances = { token0: bigint; token1: bigint };
21
21
  export class AmmBot extends BaseBot {
22
22
  protected constructor(
23
23
  node: AztecNode,
24
- wallet: TestWallet,
24
+ wallet: EmbeddedWallet,
25
25
  defaultAccountAddress: AztecAddress,
26
26
  public readonly amm: AMMContract,
27
27
  public readonly token0: TokenContract,
@@ -33,7 +33,7 @@ export class AmmBot extends BaseBot {
33
33
 
34
34
  static async create(
35
35
  config: BotConfig,
36
- wallet: TestWallet,
36
+ wallet: EmbeddedWallet,
37
37
  aztecNode: AztecNode,
38
38
  aztecNodeAdmin: AztecNodeAdmin | undefined,
39
39
  store: BotStore,
@@ -48,7 +48,7 @@ export class AmmBot extends BaseBot {
48
48
  return new AmmBot(aztecNode, wallet, defaultAccountAddress, amm, token0, token1, config);
49
49
  }
50
50
 
51
- protected async createAndSendTx(logCtx: object): Promise<SentTx> {
51
+ protected async createAndSendTx(logCtx: object): Promise<TxHash> {
52
52
  const { feePaymentMethod } = this.config;
53
53
  const { wallet, amm, token0, token1 } = this;
54
54
 
@@ -89,7 +89,7 @@ export class AmmBot extends BaseBot {
89
89
 
90
90
  this.log.verbose(`Sending transaction`, logCtx);
91
91
  this.log.info(`Tx. Balances: ${jsonStringify(balances)}`, { ...logCtx, balances });
92
- return swapExactTokensInteraction.send(opts);
92
+ return swapExactTokensInteraction.send({ ...opts, wait: NO_WAIT });
93
93
  }
94
94
 
95
95
  protected override async onTxMined(receipt: TxReceipt, logCtx: object): Promise<void> {
package/src/base_bot.ts CHANGED
@@ -1,16 +1,11 @@
1
1
  import { AztecAddress } from '@aztec/aztec.js/addresses';
2
- import {
3
- BatchCall,
4
- ContractFunctionInteraction,
5
- type SendInteractionOptions,
6
- SentTx,
7
- waitForProven,
8
- } from '@aztec/aztec.js/contracts';
2
+ import { BatchCall, ContractFunctionInteraction, type SendInteractionOptions } from '@aztec/aztec.js/contracts';
9
3
  import { createLogger } from '@aztec/aztec.js/log';
10
- import { TxHash, TxReceipt } from '@aztec/aztec.js/tx';
4
+ import { waitForTx } from '@aztec/aztec.js/node';
5
+ import { TxHash, TxReceipt, TxStatus } from '@aztec/aztec.js/tx';
11
6
  import { Gas } from '@aztec/stdlib/gas';
12
7
  import type { AztecNode } from '@aztec/stdlib/interfaces/client';
13
- import type { TestWallet } from '@aztec/test-wallet/server';
8
+ import type { EmbeddedWallet } from '@aztec/wallets/embedded';
14
9
 
15
10
  import type { BotConfig } from './config.js';
16
11
 
@@ -22,36 +17,27 @@ export abstract class BaseBot {
22
17
 
23
18
  protected constructor(
24
19
  public readonly node: AztecNode,
25
- public readonly wallet: TestWallet,
20
+ public readonly wallet: EmbeddedWallet,
26
21
  public readonly defaultAccountAddress: AztecAddress,
27
22
  public config: BotConfig,
28
23
  ) {}
29
24
 
30
25
  public async run(): Promise<TxReceipt | TxHash> {
31
26
  this.attempts++;
32
- const logCtx = { runId: Date.now() * 1000 + Math.floor(Math.random() * 1000) };
33
27
  const { followChain, txMinedWaitSeconds } = this.config;
28
+ const logCtx = { runId: Date.now() * 1000 + Math.floor(Math.random() * 1000), followChain, txMinedWaitSeconds };
34
29
 
35
30
  this.log.verbose(`Creating tx`, logCtx);
36
- const tx = await this.createAndSendTx(logCtx);
37
-
38
- const txHash = await tx.getTxHash();
31
+ const txHash = await this.createAndSendTx(logCtx);
39
32
 
40
33
  if (followChain === 'NONE') {
41
34
  this.log.info(`Transaction ${txHash.toString()} sent, not waiting for it to be mined`);
42
35
  return txHash;
43
36
  }
44
37
 
45
- this.log.verbose(
46
- `Awaiting tx ${txHash.toString()} to be on the ${followChain} chain (timeout ${txMinedWaitSeconds}s)`,
47
- logCtx,
48
- );
49
- const receipt = await tx.wait({
50
- timeout: txMinedWaitSeconds,
51
- });
52
- if (followChain === 'PROVEN') {
53
- await waitForProven(this.node, receipt, { provenTimeout: txMinedWaitSeconds });
54
- }
38
+ const waitForStatus = TxStatus[followChain];
39
+ this.log.verbose(`Awaiting tx ${txHash.toString()} to be on the ${followChain} chain`, logCtx);
40
+ const receipt = await waitForTx(this.node, txHash, { timeout: txMinedWaitSeconds, waitForStatus });
55
41
  this.successes++;
56
42
  this.log.info(
57
43
  `Tx #${this.attempts} ${receipt.txHash} successfully mined in block ${receipt.blockNumber} (stats: ${this.successes}/${this.attempts} success)`,
@@ -63,7 +49,7 @@ export abstract class BaseBot {
63
49
  return receipt;
64
50
  }
65
51
 
66
- protected abstract createAndSendTx(logCtx: object): Promise<SentTx>;
52
+ protected abstract createAndSendTx(logCtx: object): Promise<TxHash>;
67
53
 
68
54
  protected onTxMined(_receipt: TxReceipt, _logCtx: object): Promise<void> {
69
55
  // no-op
@@ -73,9 +59,9 @@ export abstract class BaseBot {
73
59
  protected async getSendMethodOpts(
74
60
  interaction: ContractFunctionInteraction | BatchCall,
75
61
  ): Promise<SendInteractionOptions> {
76
- const { l2GasLimit, daGasLimit, baseFeePadding } = this.config;
62
+ const { l2GasLimit, daGasLimit, minFeePadding } = this.config;
77
63
 
78
- this.wallet.setBaseFeePadding(baseFeePadding);
64
+ this.wallet.setMinFeePadding(minFeePadding);
79
65
 
80
66
  let gasSettings;
81
67
  if (l2GasLimit !== undefined && l2GasLimit > 0 && daGasLimit !== undefined && daGasLimit > 0) {
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
@@ -10,18 +10,21 @@ import {
10
10
  secretFrConfigHelper,
11
11
  secretStringConfigHelper,
12
12
  } from '@aztec/foundation/config';
13
- import { Fr } from '@aztec/foundation/fields';
13
+ import { Fr } from '@aztec/foundation/curves/bn254';
14
14
  import { type DataStoreConfig, dataConfigMappings } from '@aztec/kv-store/config';
15
15
  import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
16
16
  import { protocolContractsHash } from '@aztec/protocol-contracts';
17
- import { type ZodFor, schemas } from '@aztec/stdlib/schemas';
17
+ import { schemas, zodFor } from '@aztec/stdlib/schemas';
18
18
  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
+ const BotMode = ['transfer', 'amm', 'crosschain'] as const;
26
+ type BotMode = (typeof BotMode)[number];
27
+
25
28
  export enum SupportedTokenContracts {
26
29
  TokenContract = 'TokenContract',
27
30
  PrivateTokenContract = 'PrivateTokenContract',
@@ -54,8 +57,8 @@ export type BotConfig = {
54
57
  publicTransfersPerTx: number;
55
58
  /** How to handle fee payments. */
56
59
  feePaymentMethod: 'fee_juice';
57
- /** 'How much is the bot willing to overpay vs. the current base fee' */
58
- baseFeePadding: number;
60
+ /** 'How much is the bot willing to overpay vs. the current min fee' */
61
+ minFeePadding: number;
59
62
  /** True to not automatically setup or start the bot on initialization. */
60
63
  noStart: boolean;
61
64
  /** How long to wait for a tx to be mined before reporting an error. */
@@ -76,54 +79,62 @@ export type BotConfig = {
76
79
  maxConsecutiveErrors: number;
77
80
  /** Stops the bot if service becomes unhealthy */
78
81
  stopWhenUnhealthy: boolean;
79
- /** Deploy an AMM contract and do swaps instead of transfers */
80
- ammTxs: boolean;
82
+ /** Bot mode: transfer, amm, or crosschain. */
83
+ botMode: BotMode;
84
+ /** Number of L2→L1 messages per tx (crosschain mode). */
85
+ l2ToL1MessagesPerTx: number;
86
+ /** Max L1→L2 messages to keep in-flight (crosschain mode). */
87
+ l1ToL2SeedCount: number;
81
88
  } & Pick<DataStoreConfig, 'dataDirectory' | 'dataStoreMapSizeKb'>;
82
89
 
83
- export const BotConfigSchema = z
84
- .object({
85
- nodeUrl: z.string().optional(),
86
- nodeAdminUrl: z.string().optional(),
87
- l1RpcUrls: z.array(z.string()).optional(),
88
- l1Mnemonic: schemas.SecretValue(z.string()).optional(),
89
- l1PrivateKey: schemas.SecretValue(z.string()).optional(),
90
- l1ToL2MessageTimeoutSeconds: z.number(),
91
- senderPrivateKey: schemas.SecretValue(schemas.Fr).optional(),
92
- senderSalt: schemas.Fr.optional(),
93
- tokenSalt: schemas.Fr,
94
- txIntervalSeconds: z.number(),
95
- privateTransfersPerTx: z.number().int().nonnegative(),
96
- publicTransfersPerTx: z.number().int().nonnegative(),
97
- feePaymentMethod: z.literal('fee_juice'),
98
- baseFeePadding: z.number().int().nonnegative(),
99
- noStart: z.boolean(),
100
- txMinedWaitSeconds: z.number(),
101
- followChain: z.enum(BotFollowChain),
102
- maxPendingTxs: z.number().int().nonnegative(),
103
- flushSetupTransactions: z.boolean(),
104
- l2GasLimit: z.number().int().nonnegative().optional(),
105
- daGasLimit: z.number().int().nonnegative().optional(),
106
- contract: z.nativeEnum(SupportedTokenContracts),
107
- maxConsecutiveErrors: z.number().int().nonnegative(),
108
- stopWhenUnhealthy: z.boolean(),
109
- ammTxs: z.boolean().default(false),
110
- dataDirectory: z.string().optional(),
111
- dataStoreMapSizeKb: z.number().optional(),
112
- })
113
- .transform(config => ({
114
- nodeUrl: undefined,
115
- nodeAdminUrl: undefined,
116
- l1RpcUrls: undefined,
117
- senderSalt: undefined,
118
- l2GasLimit: undefined,
119
- daGasLimit: undefined,
120
- l1Mnemonic: undefined,
121
- l1PrivateKey: undefined,
122
- senderPrivateKey: undefined,
123
- dataDirectory: undefined,
124
- dataStoreMapSizeKb: 1_024 * 1_024,
125
- ...config,
126
- })) satisfies ZodFor<BotConfig>;
90
+ export const BotConfigSchema = zodFor<BotConfig>()(
91
+ z
92
+ .object({
93
+ nodeUrl: z.string().optional(),
94
+ nodeAdminUrl: z.string().optional(),
95
+ l1RpcUrls: z.array(z.string()).optional(),
96
+ l1Mnemonic: schemas.SecretValue(z.string()).optional(),
97
+ l1PrivateKey: schemas.SecretValue(z.string()).optional(),
98
+ l1ToL2MessageTimeoutSeconds: z.number(),
99
+ senderPrivateKey: schemas.SecretValue(schemas.Fr).optional(),
100
+ senderSalt: schemas.Fr.optional(),
101
+ tokenSalt: schemas.Fr,
102
+ txIntervalSeconds: z.number(),
103
+ privateTransfersPerTx: z.number().int().nonnegative(),
104
+ publicTransfersPerTx: z.number().int().nonnegative(),
105
+ feePaymentMethod: z.literal('fee_juice'),
106
+ minFeePadding: z.number().int().nonnegative(),
107
+ noStart: z.boolean(),
108
+ txMinedWaitSeconds: z.number(),
109
+ followChain: z.enum(BotFollowChain),
110
+ maxPendingTxs: z.number().int().nonnegative(),
111
+ flushSetupTransactions: z.boolean(),
112
+ l2GasLimit: z.number().int().nonnegative().optional(),
113
+ daGasLimit: z.number().int().nonnegative().optional(),
114
+ contract: z.nativeEnum(SupportedTokenContracts),
115
+ maxConsecutiveErrors: z.number().int().nonnegative(),
116
+ stopWhenUnhealthy: z.boolean(),
117
+ botMode: z.enum(BotMode).default('transfer'),
118
+ l2ToL1MessagesPerTx: z.number().int().nonnegative().default(1),
119
+ l1ToL2SeedCount: z.number().int().nonnegative().default(1),
120
+ dataDirectory: z.string().optional(),
121
+ dataStoreMapSizeKb: z.number().optional(),
122
+ })
123
+ .transform(config => ({
124
+ nodeUrl: undefined,
125
+ nodeAdminUrl: undefined,
126
+ l1RpcUrls: undefined,
127
+ senderSalt: undefined,
128
+ l2GasLimit: undefined,
129
+ daGasLimit: undefined,
130
+ l1Mnemonic: undefined,
131
+ l1PrivateKey: undefined,
132
+ senderPrivateKey: undefined,
133
+ dataDirectory: undefined,
134
+ dataStoreMapSizeKb: 1_024 * 1_024,
135
+ ...config,
136
+ })),
137
+ );
127
138
 
128
139
  export const botConfigMappings: ConfigMappingsType<BotConfig> = {
129
140
  nodeUrl: {
@@ -191,8 +202,8 @@ export const botConfigMappings: ConfigMappingsType<BotConfig> = {
191
202
  parseEnv: val => (val as 'fee_juice') || undefined,
192
203
  defaultValue: 'fee_juice',
193
204
  },
194
- baseFeePadding: {
195
- env: 'BOT_BASE_FEE_PADDING',
205
+ minFeePadding: {
206
+ env: 'BOT_MIN_FEE_PADDING',
196
207
  description: 'How much is the bot willing to overpay vs. the current base fee',
197
208
  ...numberConfigHelper(3),
198
209
  },
@@ -211,10 +222,14 @@ export const botConfigMappings: ConfigMappingsType<BotConfig> = {
211
222
  description: 'Which chain the bot follows',
212
223
  defaultValue: 'NONE',
213
224
  parseEnv(val) {
214
- if (!(BotFollowChain as readonly string[]).includes(val.toUpperCase())) {
225
+ const upper = val.toUpperCase();
226
+ if (upper === 'PENDING') {
227
+ return 'CHECKPOINTED';
228
+ }
229
+ if (!(BotFollowChain as readonly string[]).includes(upper)) {
215
230
  throw new Error(`Invalid value for BOT_FOLLOW_CHAIN: ${val}`);
216
231
  }
217
- return val as BotFollowChain;
232
+ return upper as BotFollowChain;
218
233
  },
219
234
  },
220
235
  maxPendingTxs: {
@@ -262,10 +277,26 @@ export const botConfigMappings: ConfigMappingsType<BotConfig> = {
262
277
  description: 'Stops the bot if service becomes unhealthy',
263
278
  ...booleanConfigHelper(false),
264
279
  },
265
- ammTxs: {
266
- env: 'BOT_AMM_TXS',
267
- description: 'Deploy an AMM and send swaps to it',
268
- ...booleanConfigHelper(false),
280
+ botMode: {
281
+ env: 'BOT_MODE',
282
+ description: 'Bot mode: transfer, amm, or crosschain',
283
+ defaultValue: 'transfer' as BotMode,
284
+ parseEnv(val: string) {
285
+ if (!(BotMode as readonly string[]).includes(val)) {
286
+ throw new Error(`Invalid value for BOT_MODE: ${val}`);
287
+ }
288
+ return val as BotMode;
289
+ },
290
+ },
291
+ l2ToL1MessagesPerTx: {
292
+ env: 'BOT_L2_TO_L1_MESSAGES_PER_TX',
293
+ description: 'Number of L2→L1 messages per tx (crosschain mode)',
294
+ ...numberConfigHelper(1),
295
+ },
296
+ l1ToL2SeedCount: {
297
+ env: 'BOT_L1_TO_L2_SEED_COUNT',
298
+ description: 'Max L1→L2 messages to keep in-flight (crosschain mode)',
299
+ ...numberConfigHelper(1),
269
300
  },
270
301
  ...pickConfigMappings(dataConfigMappings, ['dataStoreMapSizeKb', 'dataDirectory']),
271
302
  };