@humanode-hyperlane/rebalancer 0.0.0-stage → 27.2.2-humanode.1

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 (439) hide show
  1. package/LICENSE.md +193 -0
  2. package/README.md +297 -2
  3. package/dist/bridges/LiFiBridge.d.ts +93 -0
  4. package/dist/bridges/LiFiBridge.d.ts.map +1 -0
  5. package/dist/bridges/LiFiBridge.js +527 -0
  6. package/dist/bridges/LiFiBridge.js.map +1 -0
  7. package/dist/bridges/LiFiBridge.test.d.ts +2 -0
  8. package/dist/bridges/LiFiBridge.test.d.ts.map +1 -0
  9. package/dist/bridges/LiFiBridge.test.js +504 -0
  10. package/dist/bridges/LiFiBridge.test.js.map +1 -0
  11. package/dist/config/RebalancerConfig.d.ts +20 -0
  12. package/dist/config/RebalancerConfig.d.ts.map +1 -0
  13. package/dist/config/RebalancerConfig.js +35 -0
  14. package/dist/config/RebalancerConfig.js.map +1 -0
  15. package/dist/config/RebalancerConfig.test.d.ts +2 -0
  16. package/dist/config/RebalancerConfig.test.d.ts.map +1 -0
  17. package/dist/config/RebalancerConfig.test.js +798 -0
  18. package/dist/config/RebalancerConfig.test.js.map +1 -0
  19. package/dist/config/types.d.ts +3008 -0
  20. package/dist/config/types.d.ts.map +1 -0
  21. package/dist/config/types.js +451 -0
  22. package/dist/config/types.js.map +1 -0
  23. package/dist/core/InventoryRebalancer.d.ts +201 -0
  24. package/dist/core/InventoryRebalancer.d.ts.map +1 -0
  25. package/dist/core/InventoryRebalancer.js +994 -0
  26. package/dist/core/InventoryRebalancer.js.map +1 -0
  27. package/dist/core/InventoryRebalancer.test.d.ts +2 -0
  28. package/dist/core/InventoryRebalancer.test.d.ts.map +1 -0
  29. package/dist/core/InventoryRebalancer.test.js +1511 -0
  30. package/dist/core/InventoryRebalancer.test.js.map +1 -0
  31. package/dist/core/Rebalancer.d.ts +37 -0
  32. package/dist/core/Rebalancer.d.ts.map +1 -0
  33. package/dist/core/Rebalancer.js +433 -0
  34. package/dist/core/Rebalancer.js.map +1 -0
  35. package/dist/core/Rebalancer.test.d.ts +2 -0
  36. package/dist/core/Rebalancer.test.d.ts.map +1 -0
  37. package/dist/core/Rebalancer.test.js +424 -0
  38. package/dist/core/Rebalancer.test.js.map +1 -0
  39. package/dist/core/RebalancerOrchestrator.d.ts +56 -0
  40. package/dist/core/RebalancerOrchestrator.d.ts.map +1 -0
  41. package/dist/core/RebalancerOrchestrator.js +154 -0
  42. package/dist/core/RebalancerOrchestrator.js.map +1 -0
  43. package/dist/core/RebalancerOrchestrator.test.d.ts +2 -0
  44. package/dist/core/RebalancerOrchestrator.test.d.ts.map +1 -0
  45. package/dist/core/RebalancerOrchestrator.test.js +721 -0
  46. package/dist/core/RebalancerOrchestrator.test.js.map +1 -0
  47. package/dist/core/RebalancerService.d.ts +127 -0
  48. package/dist/core/RebalancerService.d.ts.map +1 -0
  49. package/dist/core/RebalancerService.js +270 -0
  50. package/dist/core/RebalancerService.js.map +1 -0
  51. package/dist/core/RebalancerService.test.d.ts +2 -0
  52. package/dist/core/RebalancerService.test.d.ts.map +1 -0
  53. package/dist/core/RebalancerService.test.js +777 -0
  54. package/dist/core/RebalancerService.test.js.map +1 -0
  55. package/dist/e2e/collateral-deficit.e2e-test.d.ts +2 -0
  56. package/dist/e2e/collateral-deficit.e2e-test.d.ts.map +1 -0
  57. package/dist/e2e/collateral-deficit.e2e-test.js +227 -0
  58. package/dist/e2e/collateral-deficit.e2e-test.js.map +1 -0
  59. package/dist/e2e/composite.e2e-test.d.ts +2 -0
  60. package/dist/e2e/composite.e2e-test.d.ts.map +1 -0
  61. package/dist/e2e/composite.e2e-test.js +666 -0
  62. package/dist/e2e/composite.e2e-test.js.map +1 -0
  63. package/dist/e2e/fixtures/routes.d.ts +89 -0
  64. package/dist/e2e/fixtures/routes.d.ts.map +1 -0
  65. package/dist/e2e/fixtures/routes.js +420 -0
  66. package/dist/e2e/fixtures/routes.js.map +1 -0
  67. package/dist/e2e/harness/BaseLocalDeploymentManager.d.ts +38 -0
  68. package/dist/e2e/harness/BaseLocalDeploymentManager.d.ts.map +1 -0
  69. package/dist/e2e/harness/BaseLocalDeploymentManager.js +144 -0
  70. package/dist/e2e/harness/BaseLocalDeploymentManager.js.map +1 -0
  71. package/dist/e2e/harness/BridgeSetup.d.ts +11 -0
  72. package/dist/e2e/harness/BridgeSetup.d.ts.map +1 -0
  73. package/dist/e2e/harness/BridgeSetup.js +50 -0
  74. package/dist/e2e/harness/BridgeSetup.js.map +1 -0
  75. package/dist/e2e/harness/Erc20InventoryLocalDeploymentManager.d.ts +13 -0
  76. package/dist/e2e/harness/Erc20InventoryLocalDeploymentManager.d.ts.map +1 -0
  77. package/dist/e2e/harness/Erc20InventoryLocalDeploymentManager.js +105 -0
  78. package/dist/e2e/harness/Erc20InventoryLocalDeploymentManager.js.map +1 -0
  79. package/dist/e2e/harness/Erc20LocalDeploymentManager.d.ts +11 -0
  80. package/dist/e2e/harness/Erc20LocalDeploymentManager.d.ts.map +1 -0
  81. package/dist/e2e/harness/Erc20LocalDeploymentManager.js +105 -0
  82. package/dist/e2e/harness/Erc20LocalDeploymentManager.js.map +1 -0
  83. package/dist/e2e/harness/ForkIndexer.d.ts +23 -0
  84. package/dist/e2e/harness/ForkIndexer.d.ts.map +1 -0
  85. package/dist/e2e/harness/ForkIndexer.js +127 -0
  86. package/dist/e2e/harness/ForkIndexer.js.map +1 -0
  87. package/dist/e2e/harness/ForkIndexer.test.d.ts +2 -0
  88. package/dist/e2e/harness/ForkIndexer.test.d.ts.map +1 -0
  89. package/dist/e2e/harness/ForkIndexer.test.js +257 -0
  90. package/dist/e2e/harness/ForkIndexer.test.js.map +1 -0
  91. package/dist/e2e/harness/MixedLocalDeploymentManager.d.ts +21 -0
  92. package/dist/e2e/harness/MixedLocalDeploymentManager.d.ts.map +1 -0
  93. package/dist/e2e/harness/MixedLocalDeploymentManager.js +115 -0
  94. package/dist/e2e/harness/MixedLocalDeploymentManager.js.map +1 -0
  95. package/dist/e2e/harness/MockExplorerClient.d.ts +23 -0
  96. package/dist/e2e/harness/MockExplorerClient.d.ts.map +1 -0
  97. package/dist/e2e/harness/MockExplorerClient.js +57 -0
  98. package/dist/e2e/harness/MockExplorerClient.js.map +1 -0
  99. package/dist/e2e/harness/MockExternalBridge.d.ts +32 -0
  100. package/dist/e2e/harness/MockExternalBridge.d.ts.map +1 -0
  101. package/dist/e2e/harness/MockExternalBridge.js +247 -0
  102. package/dist/e2e/harness/MockExternalBridge.js.map +1 -0
  103. package/dist/e2e/harness/NativeLocalDeploymentManager.d.ts +13 -0
  104. package/dist/e2e/harness/NativeLocalDeploymentManager.d.ts.map +1 -0
  105. package/dist/e2e/harness/NativeLocalDeploymentManager.js +91 -0
  106. package/dist/e2e/harness/NativeLocalDeploymentManager.js.map +1 -0
  107. package/dist/e2e/harness/SnapshotHelper.d.ts +13 -0
  108. package/dist/e2e/harness/SnapshotHelper.d.ts.map +1 -0
  109. package/dist/e2e/harness/SnapshotHelper.js +36 -0
  110. package/dist/e2e/harness/SnapshotHelper.js.map +1 -0
  111. package/dist/e2e/harness/TestHelpers.d.ts +25 -0
  112. package/dist/e2e/harness/TestHelpers.d.ts.map +1 -0
  113. package/dist/e2e/harness/TestHelpers.js +103 -0
  114. package/dist/e2e/harness/TestHelpers.js.map +1 -0
  115. package/dist/e2e/harness/TestRebalancer.d.ts +85 -0
  116. package/dist/e2e/harness/TestRebalancer.d.ts.map +1 -0
  117. package/dist/e2e/harness/TestRebalancer.js +427 -0
  118. package/dist/e2e/harness/TestRebalancer.js.map +1 -0
  119. package/dist/e2e/harness/TransferHelper.d.ts +34 -0
  120. package/dist/e2e/harness/TransferHelper.d.ts.map +1 -0
  121. package/dist/e2e/harness/TransferHelper.js +93 -0
  122. package/dist/e2e/harness/TransferHelper.js.map +1 -0
  123. package/dist/e2e/inventory-erc20-minAmount.e2e-test.d.ts +2 -0
  124. package/dist/e2e/inventory-erc20-minAmount.e2e-test.d.ts.map +1 -0
  125. package/dist/e2e/inventory-erc20-minAmount.e2e-test.js +411 -0
  126. package/dist/e2e/inventory-erc20-minAmount.e2e-test.js.map +1 -0
  127. package/dist/e2e/inventory-erc20-weighted.e2e-test.d.ts +2 -0
  128. package/dist/e2e/inventory-erc20-weighted.e2e-test.d.ts.map +1 -0
  129. package/dist/e2e/inventory-erc20-weighted.e2e-test.js +408 -0
  130. package/dist/e2e/inventory-erc20-weighted.e2e-test.js.map +1 -0
  131. package/dist/e2e/inventory-minAmount.e2e-test.d.ts +2 -0
  132. package/dist/e2e/inventory-minAmount.e2e-test.d.ts.map +1 -0
  133. package/dist/e2e/inventory-minAmount.e2e-test.js +411 -0
  134. package/dist/e2e/inventory-minAmount.e2e-test.js.map +1 -0
  135. package/dist/e2e/inventory-weighted.e2e-test.d.ts +2 -0
  136. package/dist/e2e/inventory-weighted.e2e-test.d.ts.map +1 -0
  137. package/dist/e2e/inventory-weighted.e2e-test.js +409 -0
  138. package/dist/e2e/inventory-weighted.e2e-test.js.map +1 -0
  139. package/dist/e2e/minAmount.e2e-test.d.ts +2 -0
  140. package/dist/e2e/minAmount.e2e-test.d.ts.map +1 -0
  141. package/dist/e2e/minAmount.e2e-test.js +203 -0
  142. package/dist/e2e/minAmount.e2e-test.js.map +1 -0
  143. package/dist/e2e/mixed-weighted.e2e-test.d.ts +2 -0
  144. package/dist/e2e/mixed-weighted.e2e-test.d.ts.map +1 -0
  145. package/dist/e2e/mixed-weighted.e2e-test.js +189 -0
  146. package/dist/e2e/mixed-weighted.e2e-test.js.map +1 -0
  147. package/dist/e2e/weighted.e2e-test.d.ts +2 -0
  148. package/dist/e2e/weighted.e2e-test.d.ts.map +1 -0
  149. package/dist/e2e/weighted.e2e-test.js +198 -0
  150. package/dist/e2e/weighted.e2e-test.js.map +1 -0
  151. package/dist/factories/RebalancerContextFactory.d.ts +89 -0
  152. package/dist/factories/RebalancerContextFactory.d.ts.map +1 -0
  153. package/dist/factories/RebalancerContextFactory.js +420 -0
  154. package/dist/factories/RebalancerContextFactory.js.map +1 -0
  155. package/dist/factories/RebalancerContextFactory.test.d.ts +2 -0
  156. package/dist/factories/RebalancerContextFactory.test.d.ts.map +1 -0
  157. package/dist/factories/RebalancerContextFactory.test.js +270 -0
  158. package/dist/factories/RebalancerContextFactory.test.js.map +1 -0
  159. package/dist/index.d.ts +37 -0
  160. package/dist/index.d.ts.map +1 -0
  161. package/dist/index.js +37 -0
  162. package/dist/index.js.map +1 -0
  163. package/dist/interfaces/IExternalBridge.d.ts +103 -0
  164. package/dist/interfaces/IExternalBridge.d.ts.map +1 -0
  165. package/dist/interfaces/IExternalBridge.js +2 -0
  166. package/dist/interfaces/IExternalBridge.js.map +1 -0
  167. package/dist/interfaces/IMetrics.d.ts +5 -0
  168. package/dist/interfaces/IMetrics.d.ts.map +1 -0
  169. package/dist/interfaces/IMetrics.js +2 -0
  170. package/dist/interfaces/IMetrics.js.map +1 -0
  171. package/dist/interfaces/IMonitor.d.ts +50 -0
  172. package/dist/interfaces/IMonitor.d.ts.map +1 -0
  173. package/dist/interfaces/IMonitor.js +14 -0
  174. package/dist/interfaces/IMonitor.js.map +1 -0
  175. package/dist/interfaces/IRebalancer.d.ts +31 -0
  176. package/dist/interfaces/IRebalancer.d.ts.map +1 -0
  177. package/dist/interfaces/IRebalancer.js +2 -0
  178. package/dist/interfaces/IRebalancer.js.map +1 -0
  179. package/dist/interfaces/IStrategy.d.ts +60 -0
  180. package/dist/interfaces/IStrategy.d.ts.map +1 -0
  181. package/dist/interfaces/IStrategy.js +13 -0
  182. package/dist/interfaces/IStrategy.js.map +1 -0
  183. package/dist/metrics/Metrics.d.ts +25 -0
  184. package/dist/metrics/Metrics.d.ts.map +1 -0
  185. package/dist/metrics/Metrics.js +164 -0
  186. package/dist/metrics/Metrics.js.map +1 -0
  187. package/dist/metrics/PriceGetter.d.ts +10 -0
  188. package/dist/metrics/PriceGetter.d.ts.map +1 -0
  189. package/dist/metrics/PriceGetter.js +41 -0
  190. package/dist/metrics/PriceGetter.js.map +1 -0
  191. package/dist/metrics/scripts/metrics.d.ts +28 -0
  192. package/dist/metrics/scripts/metrics.d.ts.map +1 -0
  193. package/dist/metrics/scripts/metrics.js +61 -0
  194. package/dist/metrics/scripts/metrics.js.map +1 -0
  195. package/dist/monitor/Monitor.d.ts +40 -0
  196. package/dist/monitor/Monitor.d.ts.map +1 -0
  197. package/dist/monitor/Monitor.js +211 -0
  198. package/dist/monitor/Monitor.js.map +1 -0
  199. package/dist/service.d.ts +3 -0
  200. package/dist/service.d.ts.map +1 -0
  201. package/dist/service.js +205 -0
  202. package/dist/service.js.map +1 -0
  203. package/dist/strategy/BaseStrategy.d.ts +86 -0
  204. package/dist/strategy/BaseStrategy.d.ts.map +1 -0
  205. package/dist/strategy/BaseStrategy.js +342 -0
  206. package/dist/strategy/BaseStrategy.js.map +1 -0
  207. package/dist/strategy/CollateralDeficitStrategy.d.ts +65 -0
  208. package/dist/strategy/CollateralDeficitStrategy.d.ts.map +1 -0
  209. package/dist/strategy/CollateralDeficitStrategy.js +253 -0
  210. package/dist/strategy/CollateralDeficitStrategy.js.map +1 -0
  211. package/dist/strategy/CollateralDeficitStrategy.test.d.ts +2 -0
  212. package/dist/strategy/CollateralDeficitStrategy.test.d.ts.map +1 -0
  213. package/dist/strategy/CollateralDeficitStrategy.test.js +497 -0
  214. package/dist/strategy/CollateralDeficitStrategy.test.js.map +1 -0
  215. package/dist/strategy/CompositeStrategy.d.ts +18 -0
  216. package/dist/strategy/CompositeStrategy.d.ts.map +1 -0
  217. package/dist/strategy/CompositeStrategy.js +63 -0
  218. package/dist/strategy/CompositeStrategy.js.map +1 -0
  219. package/dist/strategy/CompositeStrategy.test.d.ts +2 -0
  220. package/dist/strategy/CompositeStrategy.test.d.ts.map +1 -0
  221. package/dist/strategy/CompositeStrategy.test.js +278 -0
  222. package/dist/strategy/CompositeStrategy.test.js.map +1 -0
  223. package/dist/strategy/MinAmountStrategy.d.ts +35 -0
  224. package/dist/strategy/MinAmountStrategy.d.ts.map +1 -0
  225. package/dist/strategy/MinAmountStrategy.js +112 -0
  226. package/dist/strategy/MinAmountStrategy.js.map +1 -0
  227. package/dist/strategy/MinAmountStrategy.test.d.ts +2 -0
  228. package/dist/strategy/MinAmountStrategy.test.d.ts.map +1 -0
  229. package/dist/strategy/MinAmountStrategy.test.js +547 -0
  230. package/dist/strategy/MinAmountStrategy.test.js.map +1 -0
  231. package/dist/strategy/StrategyFactory.d.ts +27 -0
  232. package/dist/strategy/StrategyFactory.d.ts.map +1 -0
  233. package/dist/strategy/StrategyFactory.js +79 -0
  234. package/dist/strategy/StrategyFactory.js.map +1 -0
  235. package/dist/strategy/StrategyFactory.test.d.ts +2 -0
  236. package/dist/strategy/StrategyFactory.test.d.ts.map +1 -0
  237. package/dist/strategy/StrategyFactory.test.js +81 -0
  238. package/dist/strategy/StrategyFactory.test.js.map +1 -0
  239. package/dist/strategy/WeightedStrategy.d.ts +32 -0
  240. package/dist/strategy/WeightedStrategy.d.ts.map +1 -0
  241. package/dist/strategy/WeightedStrategy.js +73 -0
  242. package/dist/strategy/WeightedStrategy.js.map +1 -0
  243. package/dist/strategy/WeightedStrategy.test.d.ts +2 -0
  244. package/dist/strategy/WeightedStrategy.test.d.ts.map +1 -0
  245. package/dist/strategy/WeightedStrategy.test.js +403 -0
  246. package/dist/strategy/WeightedStrategy.test.js.map +1 -0
  247. package/dist/strategy/index.d.ts +7 -0
  248. package/dist/strategy/index.d.ts.map +1 -0
  249. package/dist/strategy/index.js +7 -0
  250. package/dist/strategy/index.js.map +1 -0
  251. package/dist/test/helpers.d.ts +99 -0
  252. package/dist/test/helpers.d.ts.map +1 -0
  253. package/dist/test/helpers.js +311 -0
  254. package/dist/test/helpers.js.map +1 -0
  255. package/dist/test/lifiMocks.d.ts +52 -0
  256. package/dist/test/lifiMocks.d.ts.map +1 -0
  257. package/dist/test/lifiMocks.js +160 -0
  258. package/dist/test/lifiMocks.js.map +1 -0
  259. package/dist/tracking/ActionTracker.d.ts +90 -0
  260. package/dist/tracking/ActionTracker.d.ts.map +1 -0
  261. package/dist/tracking/ActionTracker.js +678 -0
  262. package/dist/tracking/ActionTracker.js.map +1 -0
  263. package/dist/tracking/ActionTracker.test.d.ts +2 -0
  264. package/dist/tracking/ActionTracker.test.d.ts.map +1 -0
  265. package/dist/tracking/ActionTracker.test.js +1351 -0
  266. package/dist/tracking/ActionTracker.test.js.map +1 -0
  267. package/dist/tracking/IActionTracker.d.ts +157 -0
  268. package/dist/tracking/IActionTracker.d.ts.map +1 -0
  269. package/dist/tracking/IActionTracker.js +2 -0
  270. package/dist/tracking/IActionTracker.js.map +1 -0
  271. package/dist/tracking/InflightContextAdapter.d.ts +18 -0
  272. package/dist/tracking/InflightContextAdapter.d.ts.map +1 -0
  273. package/dist/tracking/InflightContextAdapter.js +52 -0
  274. package/dist/tracking/InflightContextAdapter.js.map +1 -0
  275. package/dist/tracking/InflightContextAdapter.test.d.ts +2 -0
  276. package/dist/tracking/InflightContextAdapter.test.d.ts.map +1 -0
  277. package/dist/tracking/InflightContextAdapter.test.js +175 -0
  278. package/dist/tracking/InflightContextAdapter.test.js.map +1 -0
  279. package/dist/tracking/store/IStore.d.ts +41 -0
  280. package/dist/tracking/store/IStore.d.ts.map +1 -0
  281. package/dist/tracking/store/IStore.js +2 -0
  282. package/dist/tracking/store/IStore.js.map +1 -0
  283. package/dist/tracking/store/InMemoryStore.d.ts +21 -0
  284. package/dist/tracking/store/InMemoryStore.d.ts.map +1 -0
  285. package/dist/tracking/store/InMemoryStore.js +40 -0
  286. package/dist/tracking/store/InMemoryStore.js.map +1 -0
  287. package/dist/tracking/store/InMemoryStore.test.d.ts +2 -0
  288. package/dist/tracking/store/InMemoryStore.test.d.ts.map +1 -0
  289. package/dist/tracking/store/InMemoryStore.test.js +290 -0
  290. package/dist/tracking/store/InMemoryStore.test.js.map +1 -0
  291. package/dist/tracking/store/index.d.ts +3 -0
  292. package/dist/tracking/store/index.d.ts.map +1 -0
  293. package/dist/tracking/store/index.js +2 -0
  294. package/dist/tracking/store/index.js.map +1 -0
  295. package/dist/tracking/types.d.ts +77 -0
  296. package/dist/tracking/types.d.ts.map +1 -0
  297. package/dist/tracking/types.js +2 -0
  298. package/dist/tracking/types.js.map +1 -0
  299. package/dist/utils/ExplorerClient.d.ts +68 -0
  300. package/dist/utils/ExplorerClient.d.ts.map +1 -0
  301. package/dist/utils/ExplorerClient.js +324 -0
  302. package/dist/utils/ExplorerClient.js.map +1 -0
  303. package/dist/utils/ExplorerClient.test.d.ts +2 -0
  304. package/dist/utils/ExplorerClient.test.d.ts.map +1 -0
  305. package/dist/utils/ExplorerClient.test.js +261 -0
  306. package/dist/utils/ExplorerClient.test.js.map +1 -0
  307. package/dist/utils/balanceUtils.d.ts +12 -0
  308. package/dist/utils/balanceUtils.d.ts.map +1 -0
  309. package/dist/utils/balanceUtils.js +40 -0
  310. package/dist/utils/balanceUtils.js.map +1 -0
  311. package/dist/utils/balanceUtils.test.d.ts +2 -0
  312. package/dist/utils/balanceUtils.test.d.ts.map +1 -0
  313. package/dist/utils/balanceUtils.test.js +55 -0
  314. package/dist/utils/balanceUtils.test.js.map +1 -0
  315. package/dist/utils/blockTag.d.ts +14 -0
  316. package/dist/utils/blockTag.d.ts.map +1 -0
  317. package/dist/utils/blockTag.js +46 -0
  318. package/dist/utils/blockTag.js.map +1 -0
  319. package/dist/utils/bridgeUtils.d.ts +40 -0
  320. package/dist/utils/bridgeUtils.d.ts.map +1 -0
  321. package/dist/utils/bridgeUtils.js +54 -0
  322. package/dist/utils/bridgeUtils.js.map +1 -0
  323. package/dist/utils/bridgeUtils.test.d.ts +2 -0
  324. package/dist/utils/bridgeUtils.test.d.ts.map +1 -0
  325. package/dist/utils/bridgeUtils.test.js +163 -0
  326. package/dist/utils/bridgeUtils.test.js.map +1 -0
  327. package/dist/utils/errors.d.ts +4 -0
  328. package/dist/utils/errors.d.ts.map +1 -0
  329. package/dist/utils/errors.js +6 -0
  330. package/dist/utils/errors.js.map +1 -0
  331. package/dist/utils/gasEstimation.d.ts +65 -0
  332. package/dist/utils/gasEstimation.d.ts.map +1 -0
  333. package/dist/utils/gasEstimation.js +206 -0
  334. package/dist/utils/gasEstimation.js.map +1 -0
  335. package/dist/utils/solanaKeyParser.d.ts +10 -0
  336. package/dist/utils/solanaKeyParser.d.ts.map +1 -0
  337. package/dist/utils/solanaKeyParser.js +87 -0
  338. package/dist/utils/solanaKeyParser.js.map +1 -0
  339. package/dist/utils/solanaKeyParser.test.d.ts +2 -0
  340. package/dist/utils/solanaKeyParser.test.d.ts.map +1 -0
  341. package/dist/utils/solanaKeyParser.test.js +71 -0
  342. package/dist/utils/solanaKeyParser.test.js.map +1 -0
  343. package/dist/utils/tokenUtils.d.ts +38 -0
  344. package/dist/utils/tokenUtils.d.ts.map +1 -0
  345. package/dist/utils/tokenUtils.js +65 -0
  346. package/dist/utils/tokenUtils.js.map +1 -0
  347. package/dist/utils/transactionUtils.d.ts +22 -0
  348. package/dist/utils/transactionUtils.d.ts.map +1 -0
  349. package/dist/utils/transactionUtils.js +26 -0
  350. package/dist/utils/transactionUtils.js.map +1 -0
  351. package/package.json +87 -3
  352. package/src/bridges/LiFiBridge.test.ts +615 -0
  353. package/src/bridges/LiFiBridge.ts +731 -0
  354. package/src/config/RebalancerConfig.test.ts +921 -0
  355. package/src/config/RebalancerConfig.ts +63 -0
  356. package/src/config/types.ts +613 -0
  357. package/src/core/InventoryRebalancer.test.ts +1858 -0
  358. package/src/core/InventoryRebalancer.ts +1455 -0
  359. package/src/core/Rebalancer.test.ts +686 -0
  360. package/src/core/Rebalancer.ts +686 -0
  361. package/src/core/RebalancerOrchestrator.test.ts +871 -0
  362. package/src/core/RebalancerOrchestrator.ts +273 -0
  363. package/src/core/RebalancerService.test.ts +1094 -0
  364. package/src/core/RebalancerService.ts +412 -0
  365. package/src/e2e/E2E_TEST_CONVENTIONS.md +222 -0
  366. package/src/e2e/collateral-deficit.e2e-test.ts +403 -0
  367. package/src/e2e/composite.e2e-test.ts +1008 -0
  368. package/src/e2e/fixtures/routes.ts +532 -0
  369. package/src/e2e/harness/BaseLocalDeploymentManager.ts +246 -0
  370. package/src/e2e/harness/BridgeSetup.ts +95 -0
  371. package/src/e2e/harness/Erc20InventoryLocalDeploymentManager.ts +183 -0
  372. package/src/e2e/harness/Erc20LocalDeploymentManager.ts +190 -0
  373. package/src/e2e/harness/ForkIndexer.test.ts +448 -0
  374. package/src/e2e/harness/ForkIndexer.ts +183 -0
  375. package/src/e2e/harness/MixedLocalDeploymentManager.ts +196 -0
  376. package/src/e2e/harness/MockExplorerClient.ts +94 -0
  377. package/src/e2e/harness/MockExternalBridge.ts +411 -0
  378. package/src/e2e/harness/NativeLocalDeploymentManager.ts +138 -0
  379. package/src/e2e/harness/SnapshotHelper.ts +56 -0
  380. package/src/e2e/harness/TestHelpers.ts +169 -0
  381. package/src/e2e/harness/TestRebalancer.ts +758 -0
  382. package/src/e2e/harness/TransferHelper.ts +188 -0
  383. package/src/e2e/inventory-erc20-minAmount.e2e-test.ts +735 -0
  384. package/src/e2e/inventory-erc20-weighted.e2e-test.ts +733 -0
  385. package/src/e2e/inventory-minAmount.e2e-test.ts +734 -0
  386. package/src/e2e/inventory-weighted.e2e-test.ts +734 -0
  387. package/src/e2e/minAmount.e2e-test.ts +313 -0
  388. package/src/e2e/mixed-weighted.e2e-test.ts +267 -0
  389. package/src/e2e/weighted.e2e-test.ts +304 -0
  390. package/src/factories/RebalancerContextFactory.test.ts +394 -0
  391. package/src/factories/RebalancerContextFactory.ts +771 -0
  392. package/src/index.ts +125 -0
  393. package/src/interfaces/IExternalBridge.ts +117 -0
  394. package/src/interfaces/IMetrics.ts +5 -0
  395. package/src/interfaces/IMonitor.ts +71 -0
  396. package/src/interfaces/IRebalancer.ts +57 -0
  397. package/src/interfaces/IStrategy.ts +81 -0
  398. package/src/metrics/Metrics.ts +335 -0
  399. package/src/metrics/PriceGetter.ts +74 -0
  400. package/src/metrics/scripts/metrics.ts +139 -0
  401. package/src/monitor/Monitor.ts +324 -0
  402. package/src/service.ts +285 -0
  403. package/src/strategy/BaseStrategy.ts +553 -0
  404. package/src/strategy/CollateralDeficitStrategy.test.ts +728 -0
  405. package/src/strategy/CollateralDeficitStrategy.ts +421 -0
  406. package/src/strategy/CompositeStrategy.test.ts +418 -0
  407. package/src/strategy/CompositeStrategy.ts +102 -0
  408. package/src/strategy/MinAmountStrategy.test.ts +732 -0
  409. package/src/strategy/MinAmountStrategy.ts +200 -0
  410. package/src/strategy/StrategyFactory.test.ts +108 -0
  411. package/src/strategy/StrategyFactory.ts +157 -0
  412. package/src/strategy/WeightedStrategy.test.ts +529 -0
  413. package/src/strategy/WeightedStrategy.ts +126 -0
  414. package/src/strategy/index.ts +6 -0
  415. package/src/test/helpers.ts +477 -0
  416. package/src/test/lifiMocks.ts +211 -0
  417. package/src/tracking/ActionTracker.test.ts +1625 -0
  418. package/src/tracking/ActionTracker.ts +1019 -0
  419. package/src/tracking/IActionTracker.ts +213 -0
  420. package/src/tracking/InflightContextAdapter.test.ts +206 -0
  421. package/src/tracking/InflightContextAdapter.ts +75 -0
  422. package/src/tracking/store/IStore.ts +48 -0
  423. package/src/tracking/store/InMemoryStore.test.ts +338 -0
  424. package/src/tracking/store/InMemoryStore.ts +59 -0
  425. package/src/tracking/store/index.ts +2 -0
  426. package/src/tracking/types.ts +118 -0
  427. package/src/utils/ExplorerClient.test.ts +386 -0
  428. package/src/utils/ExplorerClient.ts +439 -0
  429. package/src/utils/balanceUtils.test.ts +79 -0
  430. package/src/utils/balanceUtils.ts +65 -0
  431. package/src/utils/blockTag.ts +68 -0
  432. package/src/utils/bridgeUtils.test.ts +193 -0
  433. package/src/utils/bridgeUtils.ts +101 -0
  434. package/src/utils/errors.ts +5 -0
  435. package/src/utils/gasEstimation.ts +306 -0
  436. package/src/utils/solanaKeyParser.test.ts +103 -0
  437. package/src/utils/solanaKeyParser.ts +117 -0
  438. package/src/utils/tokenUtils.ts +89 -0
  439. package/src/utils/transactionUtils.ts +41 -0
@@ -0,0 +1,412 @@
1
+ import { Logger } from 'pino';
2
+
3
+ import { IRegistry } from '@humanode-hyperlane/registry';
4
+ import {
5
+ type MultiProtocolProvider,
6
+ type MultiProvider,
7
+ Token,
8
+ } from '@humanode-hyperlane/sdk';
9
+ import { ProtocolType, assert, toWei } from '@humanode-hyperlane/utils';
10
+
11
+ import { RebalancerConfig } from '../config/RebalancerConfig.js';
12
+ import {
13
+ getStrategyChainConfig,
14
+ getStrategyChainNames,
15
+ } from '../config/types.js';
16
+ import { RebalancerContextFactory } from '../factories/RebalancerContextFactory.js';
17
+ import type { ExternalBridgeRegistry } from '../interfaces/IExternalBridge.js';
18
+ import {
19
+ MonitorEvent,
20
+ MonitorEventType,
21
+ MonitorPollingError,
22
+ MonitorStartError,
23
+ } from '../interfaces/IMonitor.js';
24
+ import type { IRebalancer } from '../interfaces/IRebalancer.js';
25
+ import type {
26
+ IStrategy,
27
+ MovableCollateralRoute,
28
+ } from '../interfaces/IStrategy.js';
29
+ import { Metrics } from '../metrics/Metrics.js';
30
+ import { type InventoryMonitorConfig, Monitor } from '../monitor/Monitor.js';
31
+ import type { IActionTracker } from '../tracking/IActionTracker.js';
32
+ import { InflightContextAdapter } from '../tracking/InflightContextAdapter.js';
33
+
34
+ import type { RebalancerOrchestrator } from './RebalancerOrchestrator.js';
35
+
36
+ export interface RebalancerServiceConfig {
37
+ /** Execution mode: 'manual' for one-off execution, 'daemon' for continuous monitoring */
38
+ mode: 'manual' | 'daemon';
39
+
40
+ /** Frequency to check balances in milliseconds (daemon mode only) */
41
+ checkFrequency?: number;
42
+
43
+ /** Enable monitor-only mode (no transactions executed) */
44
+ monitorOnly?: boolean;
45
+
46
+ /** Enable Prometheus metrics collection */
47
+ withMetrics?: boolean;
48
+
49
+ /** CoinGecko API key for token price fetching (required for metrics) */
50
+ coingeckoApiKey?: string;
51
+
52
+ /** Logger instance */
53
+ logger: Logger;
54
+
55
+ /** Service version for logging */
56
+ version?: string;
57
+
58
+ /**
59
+ * Optional pre-configured ActionTracker.
60
+ * If provided, skips ActionTracker creation and uses this directly.
61
+ * Useful for simulation/testing where tracking is mocked externally.
62
+ */
63
+ actionTracker?: IActionTracker;
64
+ }
65
+
66
+ export interface ManualRebalanceRequest {
67
+ origin: string;
68
+ destination: string;
69
+ amount: string;
70
+ }
71
+
72
+ /**
73
+ * RebalancerService is the main orchestrator for the Hyperlane Warp Route Rebalancer.
74
+ * It supports both manual one-off rebalances and continuous daemon mode.
75
+ *
76
+ * @example Manual execution
77
+ * ```typescript
78
+ * const service = new RebalancerService(
79
+ * multiProvider,
80
+ * multiProtocolProvider,
81
+ * registry,
82
+ * rebalancerConfig,
83
+ * {
84
+ * mode: 'manual',
85
+ * logger: console,
86
+ * }
87
+ * );
88
+ * await service.executeManual({
89
+ * origin: 'ethereum',
90
+ * destination: 'arbitrum',
91
+ * amount: '1000',
92
+ * });
93
+ * ```
94
+ *
95
+ * @example Daemon mode
96
+ * ```typescript
97
+ * const service = new RebalancerService(
98
+ * multiProvider,
99
+ * multiProtocolProvider,
100
+ * registry,
101
+ * rebalancerConfig,
102
+ * {
103
+ * mode: 'daemon',
104
+ * checkFrequency: 60_000,
105
+ * withMetrics: true,
106
+ * coingeckoApiKey: process.env.COINGECKO_API_KEY,
107
+ * logger: console,
108
+ * }
109
+ * );
110
+ * await service.start();
111
+ * ```
112
+ */
113
+ export class RebalancerService {
114
+ private isExiting = false;
115
+ private logger: Logger;
116
+ private contextFactory?: RebalancerContextFactory;
117
+ private monitor?: Monitor;
118
+ private strategy?: IStrategy;
119
+ private rebalancer?: IRebalancer;
120
+ private metrics?: Metrics;
121
+ private mode: 'manual' | 'daemon';
122
+ private actionTracker?: IActionTracker;
123
+ private inflightContextAdapter?: InflightContextAdapter;
124
+ private orchestrator?: RebalancerOrchestrator;
125
+ constructor(
126
+ private readonly multiProvider: MultiProvider,
127
+ private readonly multiProtocolProvider: MultiProtocolProvider | undefined,
128
+ private readonly registry: IRegistry,
129
+ private readonly rebalancerConfig: RebalancerConfig,
130
+ private readonly config: RebalancerServiceConfig,
131
+ private readonly inventorySignerKeysByProtocol?: Partial<
132
+ Record<ProtocolType, string>
133
+ >,
134
+ ) {
135
+ this.logger = config.logger;
136
+ this.mode = config.mode;
137
+ }
138
+
139
+ /**
140
+ * Initialize the service components
141
+ */
142
+ private async initialize(): Promise<void> {
143
+ if (this.contextFactory) {
144
+ // Already initialized
145
+ return;
146
+ }
147
+
148
+ this.logger.info('Initializing RebalancerService...');
149
+
150
+ // Create context factory
151
+ this.contextFactory = await RebalancerContextFactory.create(
152
+ this.rebalancerConfig,
153
+ this.multiProvider,
154
+ this.multiProtocolProvider,
155
+ this.registry,
156
+ this.logger,
157
+ this.inventorySignerKeysByProtocol,
158
+ );
159
+
160
+ // Create metrics if enabled
161
+ if (this.config.withMetrics) {
162
+ this.metrics = await this.contextFactory.createMetrics(
163
+ this.config.coingeckoApiKey,
164
+ );
165
+ this.logger.info('Metrics collection enabled');
166
+ }
167
+
168
+ // Create strategy
169
+ this.strategy = await this.contextFactory.createStrategy(this.metrics);
170
+
171
+ // Create or use provided ActionTracker for tracking inflight actions
172
+ // Must be created BEFORE rebalancer since rebalancer needs it
173
+ if (this.config.actionTracker) {
174
+ // Use externally provided ActionTracker (e.g., for simulation/testing)
175
+ this.actionTracker = this.config.actionTracker;
176
+ this.inflightContextAdapter = new InflightContextAdapter(
177
+ this.actionTracker,
178
+ this.multiProvider,
179
+ );
180
+ await this.actionTracker.initialize();
181
+ this.logger.info('Using externally provided ActionTracker');
182
+ } else {
183
+ const { tracker, adapter } =
184
+ await this.contextFactory.createActionTracker();
185
+ this.actionTracker = tracker;
186
+ this.inflightContextAdapter = adapter;
187
+ await this.actionTracker.initialize();
188
+ this.logger.info('ActionTracker initialized');
189
+ }
190
+
191
+ // Create rebalancers (both movableCollateral and inventory if configured)
192
+ let rebalancers: IRebalancer[] = [];
193
+ let externalBridgeRegistry: Partial<ExternalBridgeRegistry> = {};
194
+ let inventoryConfig: InventoryMonitorConfig | undefined;
195
+
196
+ if (!this.config.monitorOnly) {
197
+ const result = await this.contextFactory.createRebalancers(
198
+ this.actionTracker,
199
+ this.metrics,
200
+ );
201
+ rebalancers = result.rebalancers;
202
+ externalBridgeRegistry = result.externalBridgeRegistry;
203
+ inventoryConfig = result.inventoryConfig;
204
+
205
+ if (rebalancers.length > 0) {
206
+ this.logger.info(`${rebalancers.length} rebalancer(s) created`);
207
+ }
208
+ } else {
209
+ this.logger.warn(
210
+ 'Running in monitorOnly mode: no transactions will be executed.',
211
+ );
212
+ }
213
+
214
+ // Set instance variable for backward compatibility with executeManual
215
+ // (Task 5 will remove this when refactoring executeManual)
216
+ if (rebalancers.length > 0) {
217
+ this.rebalancer = rebalancers[0];
218
+ }
219
+
220
+ if (this.mode === 'daemon') {
221
+ const checkFrequency = this.config.checkFrequency ?? 60_000;
222
+ this.monitor = this.contextFactory.createMonitor(
223
+ checkFrequency,
224
+ inventoryConfig,
225
+ );
226
+ }
227
+
228
+ this.orchestrator = this.contextFactory.createOrchestrator({
229
+ strategy: this.strategy,
230
+ actionTracker: this.actionTracker,
231
+ inflightContextAdapter: this.inflightContextAdapter,
232
+ rebalancers,
233
+ externalBridgeRegistry: externalBridgeRegistry,
234
+ metrics: this.metrics,
235
+ });
236
+
237
+ this.logger.info(
238
+ {
239
+ warpRouteId: this.rebalancerConfig.warpRouteId,
240
+ strategyTypes: this.rebalancerConfig.strategyConfig.map(
241
+ (s) => s.rebalanceStrategy,
242
+ ),
243
+ chains: getStrategyChainNames(this.rebalancerConfig.strategyConfig),
244
+ },
245
+ 'RebalancerService initialized',
246
+ );
247
+ }
248
+
249
+ /**
250
+ * Execute a manual one-off rebalance
251
+ */
252
+ async executeManual(request: ManualRebalanceRequest): Promise<void> {
253
+ await this.initialize();
254
+
255
+ assert(
256
+ this.rebalancer,
257
+ 'Rebalancer not available. MonitorOnly mode cannot execute manual rebalances.',
258
+ );
259
+
260
+ const { origin, destination, amount } = request;
261
+
262
+ this.logger.info(
263
+ `Manual rebalance strategy selected. Origin: ${origin}, Destination: ${destination}, Amount: ${amount}`,
264
+ );
265
+
266
+ const warpCore = this.contextFactory!.getWarpCore();
267
+ const originToken = warpCore.tokens.find(
268
+ (t: Token) => t.chainName === origin,
269
+ );
270
+
271
+ if (!originToken) {
272
+ const error = `Origin token not found for chain ${origin}`;
273
+ this.logger.error(error);
274
+ throw new Error(error);
275
+ }
276
+
277
+ // Validate amount
278
+ const amountNum = Number(amount);
279
+ assert(!isNaN(amountNum), 'Amount must be a valid number');
280
+ assert(amountNum > 0, 'Amount must be greater than 0');
281
+
282
+ const originConfig = getStrategyChainConfig(
283
+ this.rebalancerConfig.strategyConfig,
284
+ origin,
285
+ );
286
+ assert(
287
+ originConfig?.bridge,
288
+ `No bridge configured for origin chain ${origin}`,
289
+ );
290
+
291
+ // Use destination-specific bridge override if configured, otherwise use default
292
+ const bridge =
293
+ originConfig.override?.[destination]?.bridge ?? originConfig.bridge;
294
+
295
+ try {
296
+ const manualRoute: MovableCollateralRoute & { intentId: string } = {
297
+ origin,
298
+ destination,
299
+ amount: BigInt(toWei(amount, originToken.decimals)),
300
+ executionType: 'movableCollateral',
301
+ bridge,
302
+ intentId: `manual-${Date.now()}`,
303
+ };
304
+ await this.rebalancer.rebalance([manualRoute]);
305
+ this.logger.info(
306
+ `✅ Manual rebalance from ${origin} to ${destination} for amount ${amount} submitted successfully.`,
307
+ );
308
+ } catch (error) {
309
+ this.logger.error(
310
+ { error },
311
+ `❌ Manual rebalance from ${origin} to ${destination} failed`,
312
+ );
313
+ throw error;
314
+ }
315
+ }
316
+
317
+ /**
318
+ * Start the rebalancer in daemon mode (continuous monitoring)
319
+ */
320
+ async start(): Promise<void> {
321
+ if (this.mode !== 'daemon') {
322
+ throw new Error('start() can only be called in daemon mode');
323
+ }
324
+
325
+ await this.initialize();
326
+
327
+ assert(this.monitor, 'Monitor must be initialized for daemon mode');
328
+
329
+ // Setup monitor event listeners
330
+ this.monitor
331
+ .on(MonitorEventType.TokenInfo, this.onTokenInfo.bind(this))
332
+ .on(MonitorEventType.Error, this.onMonitorError.bind(this))
333
+ .on(MonitorEventType.Start, this.onMonitorStart.bind(this));
334
+
335
+ // Set up signal handlers for graceful shutdown
336
+ process.on('SIGINT', () => this.gracefulShutdown());
337
+ process.on('SIGTERM', () => this.gracefulShutdown());
338
+
339
+ try {
340
+ await this.monitor.start();
341
+ } catch (error) {
342
+ this.logger.error({ error }, 'Rebalancer startup error');
343
+ throw error;
344
+ }
345
+ }
346
+
347
+ /**
348
+ * Stop the rebalancer daemon
349
+ */
350
+ async stop(): Promise<void> {
351
+ if (this.monitor) {
352
+ await this.monitor.stop();
353
+ }
354
+ }
355
+
356
+ /**
357
+ * Gracefully shutdown the service
358
+ */
359
+ async gracefulShutdown(): Promise<void> {
360
+ if (this.isExiting) {
361
+ return;
362
+ }
363
+ this.isExiting = true;
364
+
365
+ this.logger.info('Gracefully shutting down rebalancer...');
366
+ await this.stop();
367
+
368
+ // Unregister listeners to prevent them from being called again during shutdown
369
+ process.removeAllListeners('SIGINT');
370
+ process.removeAllListeners('SIGTERM');
371
+
372
+ this.logger.info('Rebalancer shutdown complete');
373
+ process.exit(0);
374
+ }
375
+
376
+ /**
377
+ * Handle token info events from monitor by delegating to orchestrator
378
+ */
379
+ private async onTokenInfo(event: MonitorEvent): Promise<void> {
380
+ if (!this.orchestrator) {
381
+ this.logger.error('Orchestrator not initialized');
382
+ return;
383
+ }
384
+
385
+ await this.orchestrator.executeCycle(event);
386
+ }
387
+
388
+ /**
389
+ * Event handler for monitor errors
390
+ */
391
+ private onMonitorError(error: Error): void {
392
+ if (error instanceof MonitorPollingError) {
393
+ this.logger.error(error.message);
394
+ this.metrics?.recordPollingError();
395
+ } else if (error instanceof MonitorStartError) {
396
+ this.logger.error(error.message);
397
+ throw error;
398
+ } else {
399
+ this.logger.error(
400
+ { error },
401
+ 'An unexpected error occurred in the monitor',
402
+ );
403
+ }
404
+ }
405
+
406
+ /**
407
+ * Event handler for monitor start
408
+ */
409
+ private onMonitorStart(): void {
410
+ this.logger.info('Rebalancer started successfully 🚀');
411
+ }
412
+ }
@@ -0,0 +1,222 @@
1
+ # E2E Test Conventions
2
+
3
+ Guidelines for writing and updating rebalancer e2e tests.
4
+
5
+ ## 1. Assert total action counts at each stage
6
+
7
+ Don't just filter for the action type you care about. Assert the total count first, then find/filter within it. This catches unexpected extra actions.
8
+
9
+ ```ts
10
+ // Good
11
+ const actionsAfterBridge = await context.tracker.getActionsForIntent(intent.id);
12
+ expect(actionsAfterBridge.length).to.equal(2); // 1 deposit + 1 movement
13
+ const movementAction = actionsAfterBridge.find(
14
+ (a) => a.type === 'inventory_movement',
15
+ );
16
+
17
+ // Bad — doesn't catch unexpected extra actions
18
+ const movementActions = actionsAfterBridge.filter(
19
+ (a) => a.type === 'inventory_movement' && a.status === 'complete',
20
+ );
21
+ expect(movementActions.length).to.equal(1);
22
+ ```
23
+
24
+ ## 2. Use `find` + `expect(x).to.exist` for single items
25
+
26
+ When you expect exactly one action of a type, use `find` instead of `filter` + length check. It reads as "there should be one of these" and gives you a non-null reference.
27
+
28
+ ```ts
29
+ // Good
30
+ const movementAction = actionsAfterBridge.find(
31
+ (a) => a.type === 'inventory_movement',
32
+ );
33
+ expect(movementAction).to.exist;
34
+ expect(movementAction!.origin).to.equal(DOMAIN_IDS.anvil1);
35
+
36
+ // Bad — extra ceremony for the same thing
37
+ const completedMovementActions = actionsAfterBridge.filter(
38
+ (a) => a.type === 'inventory_movement' && a.status === 'complete',
39
+ );
40
+ expect(completedMovementActions.length).to.equal(1);
41
+ expect(completedMovementActions[0].origin).to.equal(DOMAIN_IDS.anvil1);
42
+ ```
43
+
44
+ ## 3. Don't over-filter — let aggregate assertions catch problems
45
+
46
+ Don't add `status === 'complete'` to filter predicates when a downstream assertion (like summing amounts) will fail anyway if an action is in the wrong state. Over-filtering hides bugs.
47
+
48
+ ```ts
49
+ // Good — if a deposit is incomplete, totalDeposited won't match
50
+ const allDeposits = finalActions.filter((a) => a.type === 'inventory_deposit');
51
+ expect(allDeposits.length).to.equal(2);
52
+ const totalDeposited = allDeposits.reduce((sum, a) => sum + a.amount, 0n);
53
+ expect(totalDeposited).to.equal(activeIntent.amount);
54
+
55
+ // Bad — status filter masks a deposit stuck in 'in_progress'
56
+ const allDeposits = finalActions.filter(
57
+ (a) => a.type === 'inventory_deposit' && a.status === 'complete',
58
+ );
59
+ expect(allDeposits.length).to.equal(2);
60
+ ```
61
+
62
+ Exception: filter by status when you're specifically testing state transitions (e.g. "after relay, this action should be complete").
63
+
64
+ ## 4. Use `getRouterBalances` helper for balance snapshots
65
+
66
+ Every test that asserts router balance changes repeats the same loop. Extract it into a shared helper and call it before/after the operation under test.
67
+
68
+ ```ts
69
+ // In test helpers
70
+ async function getRouterBalances(
71
+ localProviders: Map<string, providers.JsonRpcProvider>,
72
+ addresses: NativeDeployedAddresses,
73
+ ): Promise<Record<string, BigNumber>> {
74
+ const balances: Record<string, BigNumber> = {};
75
+ for (const chain of TEST_CHAINS) {
76
+ const provider = localProviders.get(chain)!;
77
+ balances[chain] = await provider.getBalance(
78
+ addresses.monitoredRoute[chain],
79
+ );
80
+ }
81
+ return balances;
82
+ }
83
+
84
+ // In tests
85
+ const before = await getRouterBalances(localProviders, nativeDeployedAddresses);
86
+ // ... execute cycle, relay, etc.
87
+ const after = await getRouterBalances(localProviders, nativeDeployedAddresses);
88
+ ```
89
+
90
+ ## 5. Use `classifyChains` helper for surplus/deficit/neutral
91
+
92
+ Tests frequently need to identify which chain is the deficit (destination), which funded the transfer (surplus), and which was uninvolved (neutral). Extract this into a helper that derives the classification from a single deposit action rather than hardcoding chain names.
93
+
94
+ ```ts
95
+ interface ChainRoles {
96
+ deficitChain: string;
97
+ surplusChain: string;
98
+ neutralChain?: string;
99
+ }
100
+
101
+ function classifyChains(
102
+ deficitChain: string,
103
+ depositAction: RebalanceAction,
104
+ ): ChainRoles {
105
+ // Surplus chain is where the router pays out on message delivery.
106
+ // For inventory deposits, that's the action's destination (swapped direction).
107
+ const surplusChain = chainFromDomain(depositAction.destination);
108
+ const neutralChain = TEST_CHAINS.find(
109
+ (c) => c !== deficitChain && c !== surplusChain,
110
+ );
111
+ return { deficitChain, surplusChain, neutralChain };
112
+ }
113
+
114
+ // In tests
115
+ const { surplusChain, neutralChain } = classifyChains('anvil2', depositAction);
116
+
117
+ expect(after.anvil2.gt(before.anvil2)).to.be.true;
118
+ expect(after[surplusChain].lt(before[surplusChain])).to.be.true;
119
+ if (neutralChain) {
120
+ expect(after[neutralChain].eq(before[neutralChain])).to.be.true;
121
+ }
122
+ ```
123
+
124
+ ## 6. Use `withInventorySignerBalances` for signer wallet setup
125
+
126
+ Don't call `anvil_setBalance` on the inventory signer directly in tests. Use the builder's `withInventorySignerBalances` method with a preset name or inline config.
127
+
128
+ ```ts
129
+ // Good — preset name from INVENTORY_SIGNER_PRESETS in routes.ts
130
+ const context = await new TestRebalancerBuilder(deploymentManager, multiProvider)
131
+ .withStrategy(buildInventoryMinAmountStrategyConfig(addresses))
132
+ .withInventoryConfig({ inventorySignerKey: ANVIL_USER_PRIVATE_KEY, nativeDeployedAddresses })
133
+ .withInventorySignerBalances('SIGNER_PARTIAL_ANVIL2')
134
+ .withExecutionMode('execute')
135
+ .build();
136
+
137
+ // Also accepted — inline Record<string, BigNumber> for one-off scenarios
138
+ .withInventorySignerBalances({ anvil2: BigNumber.from('500000000000000000') })
139
+
140
+ // Bad — setting balances outside the builder
141
+ const signer = new ethers.Wallet(ANVIL_USER_PRIVATE_KEY);
142
+ await provider.send('anvil_setBalance', [signer.address, '0x...']);
143
+ ```
144
+
145
+ Available presets: `SIGNER_PARTIAL_ANVIL2`, `SIGNER_LOW_ALL`, `SIGNER_ONLY_ANVIL1`, `SIGNER_SPLIT_SOURCES`, `SIGNER_FUNDED_ANVIL1`, `SIGNER_PARTIAL_ANVIL3`, `SIGNER_ZERO_ANVIL3`, `SIGNER_WEIGHTED_LOW_ALL`, `SIGNER_WEIGHTED_BRIDGE_SOURCES`.
146
+
147
+ ## 7. Use named constants for strategy-derived values
148
+
149
+ Don't hardcode magic numbers like `2000000000000000000n`. Derive expected values from the strategy config constants exported in `routes.ts`.
150
+
151
+ ```ts
152
+ // Good — derived from strategy config
153
+ import { INVENTORY_MIN_AMOUNT_TARGET_WEI } from './fixtures/routes.js';
154
+ const expectedDeficit = INVENTORY_MIN_AMOUNT_TARGET_WEI.toBigInt();
155
+ expect(activeIntent.amount).to.equal(expectedDeficit);
156
+
157
+ // Bad — hardcoded magic number
158
+ expect(activeIntent.amount).to.equal(2000000000000000000n);
159
+ ```
160
+
161
+ Available constants: `INVENTORY_MIN_AMOUNT_MIN` (`'1'`), `INVENTORY_MIN_AMOUNT_TARGET` (`'2'`), `INVENTORY_MIN_AMOUNT_TARGET_WEI` (target as wei BigNumber).
162
+
163
+ ## 8. Use balance presets for router balances
164
+
165
+ Don't inline `BigNumber.from(...)` objects in `.withBalances()` when a preset in `BALANCE_PRESETS` matches your scenario. Add a new preset if the scenario is reusable.
166
+
167
+ ```ts
168
+ // Good — named preset
169
+ .withBalances('INVENTORY_EMPTY_DEST')
170
+ .withBalances('INVENTORY_MULTI_DEFICIT')
171
+
172
+ // Acceptable — inline for truly one-off scenarios
173
+ .withBalances({
174
+ anvil1: BigNumber.from('9000000000000000000'),
175
+ anvil2: BigNumber.from(0),
176
+ anvil3: BigNumber.from(0),
177
+ })
178
+
179
+ // Bad — duplicating values that already exist as a preset
180
+ .withBalances({
181
+ anvil1: BigNumber.from('5000000000000000000'),
182
+ anvil2: BigNumber.from('0'),
183
+ anvil3: BigNumber.from('5000000000000000000'),
184
+ })
185
+ // ^ This is INVENTORY_EMPTY_DEST — use the preset.
186
+ ```
187
+
188
+ These helpers and conventions eliminate repeated boilerplate across tests and make intent immediately clear.
189
+
190
+ ## 9. Assert state after each cycle — no loop-to-completion
191
+
192
+ Multi-cycle tests must check state after **every** cycle. Looping with `for (let i = 0; i < N; i++)` until completion is an antipattern — it hides the per-cycle progression and makes failures impossible to diagnose.
193
+
194
+ ```ts
195
+ // Good — explicit per-cycle assertions
196
+ await executeCycle(context);
197
+ await syncAndRelay(context);
198
+ // Check cycle 1 state
199
+ expect(partialIntents[0].completedAmount > 0n).to.be.true;
200
+ expect(actions.length).to.equal(2);
201
+
202
+ await executeCycle(context);
203
+ await syncAndRelay(context);
204
+ // Check cycle 2 state
205
+ expect(partialIntents[0].completedAmount > c1Amount).to.be.true;
206
+ expect(actions.length).to.equal(3);
207
+
208
+ // ... continue until completion
209
+
210
+ // Bad — loop hides what happens per cycle
211
+ for (let i = 0; i < 5; i++) {
212
+ await executeCycle(context);
213
+ await syncAndRelay(context);
214
+ }
215
+ expect(finalIntent.status).to.equal('complete');
216
+ ```
217
+
218
+ Each cycle should assert:
219
+
220
+ - Active/partial intent state (count, completedAmount, remaining)
221
+ - Action counts by type (deposits, movements)
222
+ - Monotonic progress (completedAmount increasing across cycles)