@hyperlane-xyz/rebalancer 2.0.0 → 3.0.0

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 (209) hide show
  1. package/dist/bridges/LiFiBridge.d.ts +67 -0
  2. package/dist/bridges/LiFiBridge.d.ts.map +1 -0
  3. package/dist/bridges/LiFiBridge.js +386 -0
  4. package/dist/bridges/LiFiBridge.js.map +1 -0
  5. package/dist/config/RebalancerConfig.d.ts +7 -2
  6. package/dist/config/RebalancerConfig.d.ts.map +1 -1
  7. package/dist/config/RebalancerConfig.js +7 -4
  8. package/dist/config/RebalancerConfig.js.map +1 -1
  9. package/dist/config/RebalancerConfig.test.js +134 -1
  10. package/dist/config/RebalancerConfig.test.js.map +1 -1
  11. package/dist/config/types.d.ts +1016 -304
  12. package/dist/config/types.d.ts.map +1 -1
  13. package/dist/config/types.js +105 -10
  14. package/dist/config/types.js.map +1 -1
  15. package/dist/core/InventoryRebalancer.d.ts +190 -0
  16. package/dist/core/InventoryRebalancer.d.ts.map +1 -0
  17. package/dist/core/InventoryRebalancer.js +885 -0
  18. package/dist/core/InventoryRebalancer.js.map +1 -0
  19. package/dist/core/InventoryRebalancer.test.d.ts +2 -0
  20. package/dist/core/InventoryRebalancer.test.d.ts.map +1 -0
  21. package/dist/core/InventoryRebalancer.test.js +1351 -0
  22. package/dist/core/InventoryRebalancer.test.js.map +1 -0
  23. package/dist/core/Rebalancer.d.ts +11 -4
  24. package/dist/core/Rebalancer.d.ts.map +1 -1
  25. package/dist/core/Rebalancer.js +92 -9
  26. package/dist/core/Rebalancer.js.map +1 -1
  27. package/dist/core/Rebalancer.test.js +82 -49
  28. package/dist/core/Rebalancer.test.js.map +1 -1
  29. package/dist/core/RebalancerOrchestrator.d.ts +30 -9
  30. package/dist/core/RebalancerOrchestrator.d.ts.map +1 -1
  31. package/dist/core/RebalancerOrchestrator.js +79 -71
  32. package/dist/core/RebalancerOrchestrator.js.map +1 -1
  33. package/dist/core/RebalancerOrchestrator.test.d.ts +2 -0
  34. package/dist/core/RebalancerOrchestrator.test.d.ts.map +1 -0
  35. package/dist/core/RebalancerOrchestrator.test.js +714 -0
  36. package/dist/core/RebalancerOrchestrator.test.js.map +1 -0
  37. package/dist/core/RebalancerService.d.ts +7 -3
  38. package/dist/core/RebalancerService.d.ts.map +1 -1
  39. package/dist/core/RebalancerService.js +44 -24
  40. package/dist/core/RebalancerService.js.map +1 -1
  41. package/dist/core/RebalancerService.test.js +71 -109
  42. package/dist/core/RebalancerService.test.js.map +1 -1
  43. package/dist/e2e/collateral-deficit.e2e-test.js +1 -3
  44. package/dist/e2e/collateral-deficit.e2e-test.js.map +1 -1
  45. package/dist/e2e/composite.e2e-test.js.map +1 -1
  46. package/dist/e2e/harness/BridgeSetup.d.ts +6 -0
  47. package/dist/e2e/harness/BridgeSetup.d.ts.map +1 -1
  48. package/dist/e2e/harness/BridgeSetup.js +10 -1
  49. package/dist/e2e/harness/BridgeSetup.js.map +1 -1
  50. package/dist/e2e/harness/TestHelpers.d.ts.map +1 -1
  51. package/dist/e2e/harness/TestHelpers.js +1 -4
  52. package/dist/e2e/harness/TestHelpers.js.map +1 -1
  53. package/dist/e2e/harness/TestRebalancer.d.ts +1 -1
  54. package/dist/e2e/harness/TestRebalancer.d.ts.map +1 -1
  55. package/dist/e2e/harness/TestRebalancer.js +6 -7
  56. package/dist/e2e/harness/TestRebalancer.js.map +1 -1
  57. package/dist/e2e/minAmount.e2e-test.js +0 -1
  58. package/dist/e2e/minAmount.e2e-test.js.map +1 -1
  59. package/dist/e2e/weighted.e2e-test.js +0 -1
  60. package/dist/e2e/weighted.e2e-test.js.map +1 -1
  61. package/dist/factories/RebalancerContextFactory.d.ts +48 -6
  62. package/dist/factories/RebalancerContextFactory.d.ts.map +1 -1
  63. package/dist/factories/RebalancerContextFactory.js +170 -17
  64. package/dist/factories/RebalancerContextFactory.js.map +1 -1
  65. package/dist/index.d.ts +5 -5
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +1 -1
  68. package/dist/index.js.map +1 -1
  69. package/dist/interfaces/IExternalBridge.d.ts +101 -0
  70. package/dist/interfaces/IExternalBridge.d.ts.map +1 -0
  71. package/dist/interfaces/IExternalBridge.js +2 -0
  72. package/dist/interfaces/IExternalBridge.js.map +1 -0
  73. package/dist/interfaces/IMonitor.d.ts +1 -0
  74. package/dist/interfaces/IMonitor.d.ts.map +1 -1
  75. package/dist/interfaces/IRebalancer.d.ts +25 -25
  76. package/dist/interfaces/IRebalancer.d.ts.map +1 -1
  77. package/dist/interfaces/IStrategy.d.ts +36 -3
  78. package/dist/interfaces/IStrategy.d.ts.map +1 -1
  79. package/dist/interfaces/IStrategy.js +12 -1
  80. package/dist/interfaces/IStrategy.js.map +1 -1
  81. package/dist/metrics/PriceGetter.js +1 -1
  82. package/dist/metrics/PriceGetter.js.map +1 -1
  83. package/dist/metrics/scripts/metrics.d.ts +3 -3
  84. package/dist/monitor/Monitor.d.ts +12 -2
  85. package/dist/monitor/Monitor.d.ts.map +1 -1
  86. package/dist/monitor/Monitor.js +46 -1
  87. package/dist/monitor/Monitor.js.map +1 -1
  88. package/dist/service.js +40 -17
  89. package/dist/service.js.map +1 -1
  90. package/dist/strategy/BaseStrategy.d.ts +12 -6
  91. package/dist/strategy/BaseStrategy.d.ts.map +1 -1
  92. package/dist/strategy/BaseStrategy.js +56 -21
  93. package/dist/strategy/BaseStrategy.js.map +1 -1
  94. package/dist/strategy/CollateralDeficitStrategy.d.ts +1 -1
  95. package/dist/strategy/CollateralDeficitStrategy.d.ts.map +1 -1
  96. package/dist/strategy/CollateralDeficitStrategy.js +19 -11
  97. package/dist/strategy/CollateralDeficitStrategy.js.map +1 -1
  98. package/dist/strategy/CollateralDeficitStrategy.test.js +135 -2
  99. package/dist/strategy/CollateralDeficitStrategy.test.js.map +1 -1
  100. package/dist/strategy/CompositeStrategy.test.js +13 -0
  101. package/dist/strategy/CompositeStrategy.test.js.map +1 -1
  102. package/dist/strategy/MinAmountStrategy.test.js +4 -0
  103. package/dist/strategy/MinAmountStrategy.test.js.map +1 -1
  104. package/dist/strategy/StrategyFactory.d.ts +2 -1
  105. package/dist/strategy/StrategyFactory.d.ts.map +1 -1
  106. package/dist/strategy/StrategyFactory.js +24 -8
  107. package/dist/strategy/StrategyFactory.js.map +1 -1
  108. package/dist/strategy/WeightedStrategy.test.js +6 -0
  109. package/dist/strategy/WeightedStrategy.test.js.map +1 -1
  110. package/dist/test/helpers.d.ts +8 -7
  111. package/dist/test/helpers.d.ts.map +1 -1
  112. package/dist/test/helpers.js +23 -5
  113. package/dist/test/helpers.js.map +1 -1
  114. package/dist/test/lifiMocks.d.ts +51 -0
  115. package/dist/test/lifiMocks.d.ts.map +1 -0
  116. package/dist/test/lifiMocks.js +130 -0
  117. package/dist/test/lifiMocks.js.map +1 -0
  118. package/dist/tracking/ActionTracker.d.ts +33 -1
  119. package/dist/tracking/ActionTracker.d.ts.map +1 -1
  120. package/dist/tracking/ActionTracker.js +193 -22
  121. package/dist/tracking/ActionTracker.js.map +1 -1
  122. package/dist/tracking/ActionTracker.test.js +107 -19
  123. package/dist/tracking/ActionTracker.test.js.map +1 -1
  124. package/dist/tracking/IActionTracker.d.ts +47 -3
  125. package/dist/tracking/IActionTracker.d.ts.map +1 -1
  126. package/dist/tracking/InflightContextAdapter.d.ts.map +1 -1
  127. package/dist/tracking/InflightContextAdapter.js +24 -7
  128. package/dist/tracking/InflightContextAdapter.js.map +1 -1
  129. package/dist/tracking/InflightContextAdapter.test.js +7 -4
  130. package/dist/tracking/InflightContextAdapter.test.js.map +1 -1
  131. package/dist/tracking/types.d.ts +31 -2
  132. package/dist/tracking/types.d.ts.map +1 -1
  133. package/dist/utils/ExplorerClient.d.ts +2 -1
  134. package/dist/utils/ExplorerClient.d.ts.map +1 -1
  135. package/dist/utils/ExplorerClient.js +13 -8
  136. package/dist/utils/ExplorerClient.js.map +1 -1
  137. package/dist/utils/bridgeUtils.d.ts +27 -4
  138. package/dist/utils/bridgeUtils.d.ts.map +1 -1
  139. package/dist/utils/bridgeUtils.js +38 -0
  140. package/dist/utils/bridgeUtils.js.map +1 -1
  141. package/dist/utils/bridgeUtils.test.js +9 -0
  142. package/dist/utils/bridgeUtils.test.js.map +1 -1
  143. package/dist/utils/gasEstimation.d.ts +65 -0
  144. package/dist/utils/gasEstimation.d.ts.map +1 -0
  145. package/dist/utils/gasEstimation.js +176 -0
  146. package/dist/utils/gasEstimation.js.map +1 -0
  147. package/dist/utils/tokenUtils.d.ts +9 -1
  148. package/dist/utils/tokenUtils.d.ts.map +1 -1
  149. package/dist/utils/tokenUtils.js +11 -0
  150. package/dist/utils/tokenUtils.js.map +1 -1
  151. package/package.json +9 -7
  152. package/src/bridges/LiFiBridge.ts +538 -0
  153. package/src/config/RebalancerConfig.test.ts +160 -0
  154. package/src/config/RebalancerConfig.ts +14 -3
  155. package/src/config/types.ts +136 -10
  156. package/src/core/InventoryRebalancer.test.ts +1684 -0
  157. package/src/core/InventoryRebalancer.ts +1255 -0
  158. package/src/core/Rebalancer.test.ts +84 -30
  159. package/src/core/Rebalancer.ts +144 -23
  160. package/src/core/RebalancerOrchestrator.test.ts +860 -0
  161. package/src/core/RebalancerOrchestrator.ts +146 -95
  162. package/src/core/RebalancerService.test.ts +80 -123
  163. package/src/core/RebalancerService.ts +67 -33
  164. package/src/e2e/collateral-deficit.e2e-test.ts +2 -4
  165. package/src/e2e/composite.e2e-test.ts +5 -5
  166. package/src/e2e/harness/BridgeSetup.ts +28 -1
  167. package/src/e2e/harness/TestHelpers.ts +1 -4
  168. package/src/e2e/harness/TestRebalancer.ts +7 -7
  169. package/src/e2e/minAmount.e2e-test.ts +1 -2
  170. package/src/e2e/weighted.e2e-test.ts +1 -2
  171. package/src/factories/RebalancerContextFactory.ts +293 -24
  172. package/src/index.ts +20 -5
  173. package/src/interfaces/IExternalBridge.ts +115 -0
  174. package/src/interfaces/IMonitor.ts +1 -0
  175. package/src/interfaces/IRebalancer.ts +45 -29
  176. package/src/interfaces/IStrategy.ts +50 -3
  177. package/src/metrics/PriceGetter.ts +1 -1
  178. package/src/monitor/Monitor.ts +81 -2
  179. package/src/service.ts +59 -18
  180. package/src/strategy/BaseStrategy.ts +77 -24
  181. package/src/strategy/CollateralDeficitStrategy.test.ts +181 -4
  182. package/src/strategy/CollateralDeficitStrategy.ts +42 -15
  183. package/src/strategy/CompositeStrategy.test.ts +13 -0
  184. package/src/strategy/MinAmountStrategy.test.ts +4 -0
  185. package/src/strategy/StrategyFactory.ts +33 -6
  186. package/src/strategy/WeightedStrategy.test.ts +6 -0
  187. package/src/test/helpers.ts +39 -14
  188. package/src/test/lifiMocks.ts +174 -0
  189. package/src/tracking/ActionTracker.test.ts +122 -19
  190. package/src/tracking/ActionTracker.ts +284 -24
  191. package/src/tracking/IActionTracker.ts +58 -3
  192. package/src/tracking/InflightContextAdapter.test.ts +7 -4
  193. package/src/tracking/InflightContextAdapter.ts +42 -9
  194. package/src/tracking/types.ts +43 -2
  195. package/src/utils/ExplorerClient.ts +23 -10
  196. package/src/utils/bridgeUtils.test.ts +9 -0
  197. package/src/utils/bridgeUtils.ts +75 -6
  198. package/src/utils/gasEstimation.ts +272 -0
  199. package/src/utils/tokenUtils.ts +12 -0
  200. package/dist/tracking/index.d.ts +0 -7
  201. package/dist/tracking/index.d.ts.map +0 -1
  202. package/dist/tracking/index.js +0 -6
  203. package/dist/tracking/index.js.map +0 -1
  204. package/dist/utils/index.d.ts +0 -5
  205. package/dist/utils/index.d.ts.map +0 -1
  206. package/dist/utils/index.js +0 -5
  207. package/dist/utils/index.js.map +0 -1
  208. package/src/tracking/index.ts +0 -36
  209. package/src/utils/index.ts +0 -4
@@ -1,18 +1,24 @@
1
+ import type { z } from 'zod';
1
2
  import { fromZodError } from 'zod-validation-error';
2
3
 
3
4
  import { readYamlOrJson } from '@hyperlane-xyz/utils/fs';
4
5
 
5
6
  import {
7
+ type ExternalBridgesConfigSchema,
6
8
  type RebalancerConfigFileInput,
7
9
  RebalancerConfigSchema,
8
10
  type StrategyConfig,
9
11
  getStrategyChainNames,
10
12
  } from './types.js';
11
13
 
14
+ type ExternalBridgesConfig = z.infer<typeof ExternalBridgesConfigSchema>;
15
+
12
16
  export class RebalancerConfig {
13
17
  constructor(
14
18
  public readonly warpRouteId: string,
15
19
  public readonly strategyConfig: StrategyConfig[],
20
+ public readonly inventorySigner?: string,
21
+ public readonly externalBridges?: ExternalBridgesConfig,
16
22
  ) {}
17
23
 
18
24
  /**
@@ -28,14 +34,19 @@ export class RebalancerConfig {
28
34
  throw new Error(fromZodError(validationResult.error).message);
29
35
  }
30
36
 
31
- const { warpRouteId, strategy } = validationResult.data;
37
+ const { warpRouteId, strategy, inventorySigner, externalBridges } =
38
+ validationResult.data;
32
39
 
33
- // Check that at least one chain is configured across all strategies
34
40
  const chainNames = getStrategyChainNames(strategy);
35
41
  if (chainNames.length === 0) {
36
42
  throw new Error('No chains configured');
37
43
  }
38
44
 
39
- return new RebalancerConfig(warpRouteId, strategy);
45
+ return new RebalancerConfig(
46
+ warpRouteId,
47
+ strategy,
48
+ inventorySigner,
49
+ externalBridges,
50
+ );
40
51
  }
41
52
  }
@@ -23,22 +23,39 @@ export enum RebalancerMinAmountType {
23
23
  Relative = 'relative',
24
24
  }
25
25
 
26
+ /**
27
+ * Execution type for rebalancing on a chain:
28
+ * - `movableCollateral`: Uses MovableCollateralRouter.rebalance() on-chain (requires bridge address)
29
+ * - `inventory`: Uses external bridges (LiFi) + transferRemote (no bridge address needed)
30
+ */
31
+ export enum ExecutionType {
32
+ MovableCollateral = 'movableCollateral',
33
+ Inventory = 'inventory',
34
+ }
35
+
36
+ export enum ExternalBridgeType {
37
+ LiFi = 'lifi',
38
+ }
39
+
26
40
  export const RebalancerMinAmountConfigSchema = z.object({
27
41
  min: z.string().or(z.number()),
28
42
  target: z.string().or(z.number()),
29
43
  type: z.nativeEnum(RebalancerMinAmountType),
30
44
  });
31
45
 
32
- // Base chain config with common properties
33
46
  const RebalancerBridgeConfigSchema = z.object({
34
- bridge: z.string().regex(/0x[a-fA-F0-9]{40}/),
47
+ bridge: z
48
+ .string()
49
+ .regex(/0x[a-fA-F0-9]{40}/)
50
+ .optional(),
51
+ executionType: z.nativeEnum(ExecutionType).optional(),
52
+ externalBridge: z.nativeEnum(ExternalBridgeType).optional(),
35
53
  bridgeMinAcceptedAmount: z.string().or(z.number()).optional(),
36
54
  bridgeLockTime: z
37
55
  .number()
38
56
  .positive()
39
57
  .transform((val) => val * 1_000)
40
- .optional()
41
- .describe('Expected time in seconds for bridge to process a transfer'),
58
+ .optional(),
42
59
  });
43
60
 
44
61
  export const RebalancerBaseChainConfigSchema =
@@ -94,19 +111,28 @@ export const StrategyConfigSchema = z.discriminatedUnion('rebalanceStrategy', [
94
111
  CollateralDeficitStrategySchema,
95
112
  ]);
96
113
 
97
- // Accept either a single strategy (backwards compatible) or an array of strategies
98
- // Normalizes to array internally so the rest of the code doesn't need to change
99
114
  export const RebalancerStrategySchema = z
100
- .union([
101
- StrategyConfigSchema, // Old format: single object
102
- z.array(StrategyConfigSchema).min(1), // New format: array
103
- ])
115
+ .union([StrategyConfigSchema, z.array(StrategyConfigSchema).min(1)])
104
116
  .transform((val) => (Array.isArray(val) ? val : [val]));
105
117
 
118
+ export const LiFiBridgeConfigSchema = z.object({
119
+ integrator: z.string(),
120
+ defaultSlippage: z.number().optional(),
121
+ });
122
+
123
+ export const ExternalBridgesConfigSchema = z.object({
124
+ lifi: LiFiBridgeConfigSchema.optional(),
125
+ });
126
+
106
127
  export const RebalancerConfigSchema = z
107
128
  .object({
108
129
  warpRouteId: z.string(),
109
130
  strategy: RebalancerStrategySchema,
131
+ inventorySigner: z
132
+ .string()
133
+ .regex(/0x[a-fA-F0-9]{40}/)
134
+ .optional(),
135
+ externalBridges: ExternalBridgesConfigSchema.optional(),
110
136
  })
111
137
  .superRefine((config, ctx) => {
112
138
  // CollateralDeficitStrategy must be first in composite if it is used
@@ -189,6 +215,83 @@ export const RebalancerConfigSchema = z
189
215
  });
190
216
  }
191
217
  }
218
+
219
+ // Validate bridge requirement based on executionType
220
+ for (const [chainName, chainConfig] of Object.entries(strategy.chains)) {
221
+ const executionType =
222
+ chainConfig.executionType ?? ExecutionType.MovableCollateral;
223
+
224
+ // bridge is required for movableCollateral execution type
225
+ if (
226
+ executionType === ExecutionType.MovableCollateral &&
227
+ !chainConfig.bridge
228
+ ) {
229
+ ctx.addIssue({
230
+ code: z.ZodIssueCode.custom,
231
+ message: `Chain '${chainName}' uses movableCollateral execution but has no 'bridge' address`,
232
+ path: ['strategy', strategyIndex, 'chains', chainName, 'bridge'],
233
+ });
234
+ }
235
+
236
+ // externalBridge is required for inventory execution type
237
+ if (
238
+ executionType === ExecutionType.Inventory &&
239
+ !chainConfig.externalBridge
240
+ ) {
241
+ ctx.addIssue({
242
+ code: z.ZodIssueCode.custom,
243
+ message: `Chain '${chainName}' uses inventory execution but has no 'externalBridge' configured`,
244
+ path: [
245
+ 'strategy',
246
+ strategyIndex,
247
+ 'chains',
248
+ chainName,
249
+ 'externalBridge',
250
+ ],
251
+ });
252
+ }
253
+ }
254
+ }
255
+
256
+ const hasInventoryChains = config.strategy.some((strategy) =>
257
+ Object.values(strategy.chains).some(
258
+ (chainConfig) => chainConfig.executionType === ExecutionType.Inventory,
259
+ ),
260
+ );
261
+
262
+ if (hasInventoryChains) {
263
+ if (!config.inventorySigner) {
264
+ ctx.addIssue({
265
+ code: z.ZodIssueCode.custom,
266
+ message:
267
+ 'inventorySigner is required when any chain uses inventory execution type',
268
+ path: ['inventorySigner'],
269
+ });
270
+ }
271
+
272
+ if (!config.externalBridges?.lifi?.integrator) {
273
+ ctx.addIssue({
274
+ code: z.ZodIssueCode.custom,
275
+ message:
276
+ 'externalBridges.lifi is required when using inventory execution',
277
+ path: ['externalBridges', 'lifi'],
278
+ });
279
+ }
280
+ }
281
+
282
+ for (const strategy of config.strategy) {
283
+ for (const [chainName, chainConfig] of Object.entries(strategy.chains)) {
284
+ if (
285
+ chainConfig.externalBridge === ExternalBridgeType.LiFi &&
286
+ !config.externalBridges?.lifi?.integrator
287
+ ) {
288
+ ctx.addIssue({
289
+ code: z.ZodIssueCode.custom,
290
+ message: `Chain '${chainName}' uses externalBridge: 'lifi' but externalBridges.lifi is not configured`,
291
+ path: ['externalBridges', 'lifi'],
292
+ });
293
+ }
294
+ }
192
295
  }
193
296
  });
194
297
 
@@ -261,3 +364,26 @@ export function getAllBridges(strategies: StrategyConfig[]): string[] {
261
364
 
262
365
  return Array.from(bridges);
263
366
  }
367
+
368
+ /**
369
+ * Get the execution type for a chain.
370
+ * Returns the executionType from chain config, or MovableCollateral as default.
371
+ */
372
+ export function getChainExecutionType(
373
+ strategies: StrategyConfig[],
374
+ chainName: string,
375
+ ): ExecutionType {
376
+ const chainConfig = getStrategyChainConfig(strategies, chainName);
377
+ return chainConfig?.executionType ?? ExecutionType.MovableCollateral;
378
+ }
379
+
380
+ /**
381
+ * Check if any chain in the strategies uses inventory execution type.
382
+ */
383
+ export function hasInventoryChains(strategies: StrategyConfig[]): boolean {
384
+ return strategies.some((strategy) =>
385
+ Object.values(strategy.chains).some(
386
+ (chainConfig) => chainConfig.executionType === ExecutionType.Inventory,
387
+ ),
388
+ );
389
+ }