@humanode-hyperlane/rebalancer 0.0.0-stage → 27.2.2

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,733 @@
1
+ import { expect } from 'chai';
2
+ import { ethers, providers } from 'ethers';
3
+
4
+ import {
5
+ HyperlaneCore,
6
+ MultiProvider,
7
+ snapshot,
8
+ } from '@humanode-hyperlane/sdk';
9
+
10
+ import { ExternalBridgeType } from '../config/types.js';
11
+
12
+ import {
13
+ ANVIL_USER_PRIVATE_KEY,
14
+ DOMAIN_IDS,
15
+ ERC20_WEIGHTED_EXPECTED_DEFICIT_1000USDC,
16
+ ERC20_WEIGHTED_EXPECTED_DEFICIT_1200USDC,
17
+ ERC20_WEIGHTED_EXPECTED_DEFICIT_2000USDC,
18
+ type Erc20InventoryDeployedAddresses,
19
+ TEST_CHAINS,
20
+ buildErc20InventoryWeightedStrategyConfig,
21
+ } from './fixtures/routes.js';
22
+ import { Erc20InventoryLocalDeploymentManager } from './harness/Erc20InventoryLocalDeploymentManager.js';
23
+ import { MockExternalBridge } from './harness/MockExternalBridge.js';
24
+ import { resetSnapshotsAndRefreshProviders } from './harness/SnapshotHelper.js';
25
+ import {
26
+ classifyChains,
27
+ getErc20RouterBalances,
28
+ getFirstMonitorEvent,
29
+ relayInProgressInventoryDeposits,
30
+ } from './harness/TestHelpers.js';
31
+ import {
32
+ TestRebalancerBuilder,
33
+ type TestRebalancerContext,
34
+ } from './harness/TestRebalancer.js';
35
+
36
+ describe('Erc20 Inventory WeightedStrategy E2E', function () {
37
+ this.timeout(300_000);
38
+
39
+ let deploymentManager: Erc20InventoryLocalDeploymentManager;
40
+ let multiProvider: MultiProvider;
41
+ let localProviders: Map<string, providers.JsonRpcProvider>;
42
+ let snapshotIds: Map<string, string>;
43
+ let hyperlaneCore: HyperlaneCore;
44
+ let erc20DeployedAddresses: Erc20InventoryDeployedAddresses;
45
+ let weightedStrategyConfig: ReturnType<
46
+ typeof buildErc20InventoryWeightedStrategyConfig
47
+ >;
48
+ let mockBridge: MockExternalBridge;
49
+
50
+ const inventorySignerAddress = new ethers.Wallet(ANVIL_USER_PRIVATE_KEY)
51
+ .address;
52
+
53
+ async function executeCycle(context: TestRebalancerContext): Promise<void> {
54
+ const monitor = context.createMonitor(0);
55
+ const event = await getFirstMonitorEvent(monitor);
56
+ await context.orchestrator.executeCycle(event);
57
+ }
58
+
59
+ before(async function () {
60
+ deploymentManager = new Erc20InventoryLocalDeploymentManager(
61
+ inventorySignerAddress,
62
+ );
63
+ const ctx = await deploymentManager.start();
64
+ multiProvider = ctx.multiProvider;
65
+ localProviders = ctx.providers;
66
+ erc20DeployedAddresses = ctx.deployedAddresses;
67
+
68
+ const coreAddresses: Record<string, Record<string, string>> = {};
69
+ for (const chain of TEST_CHAINS) {
70
+ coreAddresses[chain] = {
71
+ mailbox: erc20DeployedAddresses.chains[chain].mailbox,
72
+ interchainSecurityModule: erc20DeployedAddresses.chains[chain].ism,
73
+ };
74
+ }
75
+ hyperlaneCore = HyperlaneCore.fromAddressesMap(
76
+ coreAddresses,
77
+ multiProvider,
78
+ );
79
+
80
+ weightedStrategyConfig = buildErc20InventoryWeightedStrategyConfig(
81
+ erc20DeployedAddresses,
82
+ );
83
+ mockBridge = new MockExternalBridge(
84
+ erc20DeployedAddresses,
85
+ multiProvider,
86
+ hyperlaneCore,
87
+ 'erc20',
88
+ );
89
+
90
+ snapshotIds = new Map();
91
+ for (const [chain, provider] of localProviders) {
92
+ snapshotIds.set(chain, await snapshot(provider));
93
+ }
94
+ });
95
+
96
+ afterEach(async function () {
97
+ mockBridge.reset();
98
+ await resetSnapshotsAndRefreshProviders({
99
+ localProviders,
100
+ multiProvider,
101
+ snapshotIds,
102
+ });
103
+ });
104
+
105
+ after(async function () {
106
+ if (deploymentManager) {
107
+ await deploymentManager.stop();
108
+ }
109
+ });
110
+
111
+ it('creates direct inventory_deposit when destination has enough inventory', async function () {
112
+ const context = await new TestRebalancerBuilder(
113
+ deploymentManager,
114
+ multiProvider,
115
+ )
116
+ .withStrategy(weightedStrategyConfig)
117
+ .withExecutionMode('execute')
118
+ .withErc20InventoryConfig({
119
+ inventorySignerKey: ANVIL_USER_PRIVATE_KEY,
120
+ erc20DeployedAddresses,
121
+ })
122
+ .withMockExternalBridge(mockBridge)
123
+ .withBalances('ERC20_INVENTORY_WEIGHTED_IMBALANCED')
124
+ .build();
125
+
126
+ const initialBalances = await getErc20RouterBalances(
127
+ localProviders,
128
+ erc20DeployedAddresses,
129
+ );
130
+
131
+ await executeCycle(context);
132
+
133
+ const activeIntents = await context.tracker.getActiveRebalanceIntents();
134
+ expect(activeIntents.length).to.equal(1);
135
+ expect(activeIntents[0].destination).to.equal(DOMAIN_IDS.anvil3);
136
+ expect(activeIntents[0].amount).to.equal(
137
+ ERC20_WEIGHTED_EXPECTED_DEFICIT_1000USDC.toBigInt(),
138
+ );
139
+ const inProgressActions = await context.tracker.getInProgressActions();
140
+ expect(inProgressActions.length).to.equal(1);
141
+ const depositAction = inProgressActions.find(
142
+ (a) => a.type === 'inventory_deposit',
143
+ );
144
+ expect(depositAction).to.exist;
145
+
146
+ await relayInProgressInventoryDeposits(
147
+ context,
148
+ localProviders,
149
+ multiProvider,
150
+ hyperlaneCore,
151
+ );
152
+
153
+ const completedAction = await context.tracker.getRebalanceAction(
154
+ depositAction!.id,
155
+ );
156
+ expect(completedAction!.status).to.equal('complete');
157
+
158
+ const completedIntent = await context.tracker.getRebalanceIntent(
159
+ activeIntents[0].id,
160
+ );
161
+ expect(completedIntent?.status).to.equal('complete');
162
+
163
+ const finalBalances = await getErc20RouterBalances(
164
+ localProviders,
165
+ erc20DeployedAddresses,
166
+ );
167
+ const { surplusChain, neutralChain } = classifyChains(
168
+ 'anvil3',
169
+ depositAction!,
170
+ );
171
+
172
+ expect(
173
+ finalBalances.anvil3.gt(initialBalances.anvil3),
174
+ 'Deficit router (anvil3) balance should increase',
175
+ ).to.be.true;
176
+ expect(
177
+ finalBalances[surplusChain].lt(initialBalances[surplusChain]),
178
+ `Surplus router (${surplusChain}) balance should decrease`,
179
+ ).to.be.true;
180
+ if (neutralChain) {
181
+ expect(
182
+ finalBalances[neutralChain].eq(initialBalances[neutralChain]),
183
+ 'Uninvolved router balance should remain unchanged',
184
+ ).to.be.true;
185
+ }
186
+ });
187
+
188
+ it('handles partial deposit, then bridge, then final deposit', async function () {
189
+ const context = await new TestRebalancerBuilder(
190
+ deploymentManager,
191
+ multiProvider,
192
+ )
193
+ .withStrategy(weightedStrategyConfig)
194
+ .withExecutionMode('execute')
195
+ .withErc20InventoryConfig({
196
+ inventorySignerKey: ANVIL_USER_PRIVATE_KEY,
197
+ erc20DeployedAddresses,
198
+ })
199
+ .withMockExternalBridge(mockBridge)
200
+ .withInventorySignerBalances('ERC20_SIGNER_PARTIAL_ANVIL3')
201
+ .withBalances('ERC20_INVENTORY_WEIGHTED_IMBALANCED')
202
+ .build();
203
+
204
+ await executeCycle(context);
205
+ await relayInProgressInventoryDeposits(
206
+ context,
207
+ localProviders,
208
+ multiProvider,
209
+ hyperlaneCore,
210
+ );
211
+
212
+ const partialIntents =
213
+ await context.tracker.getPartiallyFulfilledInventoryIntents();
214
+ expect(partialIntents.length).to.equal(1);
215
+ expect(partialIntents[0].intent.amount).to.equal(
216
+ ERC20_WEIGHTED_EXPECTED_DEFICIT_1000USDC.toBigInt(),
217
+ );
218
+ expect(partialIntents[0].intent.destination).to.equal(DOMAIN_IDS.anvil3);
219
+ expect(partialIntents[0].completedAmount > 0n).to.be.true;
220
+ expect(
221
+ partialIntents[0].completedAmount + partialIntents[0].remaining,
222
+ ).to.equal(ERC20_WEIGHTED_EXPECTED_DEFICIT_1000USDC.toBigInt());
223
+
224
+ const firstCycleActions = await context.tracker.getActionsForIntent(
225
+ partialIntents[0].intent.id,
226
+ );
227
+ expect(firstCycleActions.length).to.equal(1);
228
+ expect(firstCycleActions[0].type).to.equal('inventory_deposit');
229
+ expect(firstCycleActions[0].origin).to.equal(DOMAIN_IDS.anvil3);
230
+ expect(firstCycleActions[0].amount).to.equal(
231
+ partialIntents[0].completedAmount,
232
+ );
233
+
234
+ const intentId = partialIntents[0].intent.id;
235
+
236
+ await executeCycle(context);
237
+
238
+ const inProgressActions = await context.tracker.getInProgressActions();
239
+ expect(inProgressActions.length).to.equal(1);
240
+ const movementAction = inProgressActions.find(
241
+ (action) => action.type === 'inventory_movement',
242
+ );
243
+ expect(movementAction).to.exist;
244
+ expect(movementAction!.origin).to.equal(DOMAIN_IDS.anvil1);
245
+ expect(movementAction!.destination).to.equal(DOMAIN_IDS.anvil3);
246
+ expect(movementAction!.status).to.equal('in_progress');
247
+
248
+ await context.tracker.syncInventoryMovementActions({
249
+ [ExternalBridgeType.LiFi]: mockBridge,
250
+ });
251
+
252
+ const movementState = await context.tracker.getRebalanceAction(
253
+ movementAction!.id,
254
+ );
255
+ expect(movementState?.status).to.equal('complete');
256
+
257
+ await executeCycle(context);
258
+ await context.tracker.syncInventoryMovementActions({
259
+ [ExternalBridgeType.LiFi]: mockBridge,
260
+ });
261
+ await relayInProgressInventoryDeposits(
262
+ context,
263
+ localProviders,
264
+ multiProvider,
265
+ hyperlaneCore,
266
+ );
267
+
268
+ const partialAfterFinalCycle =
269
+ await context.tracker.getPartiallyFulfilledInventoryIntents();
270
+ expect(partialAfterFinalCycle.length).to.equal(0);
271
+
272
+ const completedIntent = await context.tracker.getRebalanceIntent(intentId);
273
+ expect(completedIntent?.status).to.equal('complete');
274
+
275
+ const actions = await context.tracker.getActionsForIntent(intentId);
276
+ const allDeposits = actions.filter((a) => a.type === 'inventory_deposit');
277
+ const movements = actions.filter((a) => a.type === 'inventory_movement');
278
+ expect(actions.length).to.equal(3);
279
+ expect(movements.length).to.equal(1);
280
+ expect(allDeposits.length).to.equal(2);
281
+ const totalDeposited = allDeposits.reduce((sum, a) => sum + a.amount, 0n);
282
+ expect(totalDeposited).to.equal(completedIntent!.amount);
283
+ });
284
+
285
+ it('completes intent after multiple partial inventory fill cycles', async function () {
286
+ const context = await new TestRebalancerBuilder(
287
+ deploymentManager,
288
+ multiProvider,
289
+ )
290
+ .withStrategy(weightedStrategyConfig)
291
+ .withExecutionMode('execute')
292
+ .withErc20InventoryConfig({
293
+ inventorySignerKey: ANVIL_USER_PRIVATE_KEY,
294
+ erc20DeployedAddresses,
295
+ })
296
+ .withMockExternalBridge(mockBridge)
297
+ .withInventorySignerBalances('ERC20_SIGNER_WEIGHTED_LOW_ALL')
298
+ .withBalances('ERC20_INVENTORY_WEIGHTED_ALL_ANVIL1')
299
+ .build();
300
+
301
+ await executeCycle(context);
302
+ await context.tracker.syncInventoryMovementActions({
303
+ [ExternalBridgeType.LiFi]: mockBridge,
304
+ });
305
+ await relayInProgressInventoryDeposits(
306
+ context,
307
+ localProviders,
308
+ multiProvider,
309
+ hyperlaneCore,
310
+ );
311
+
312
+ let activeIntents = await context.tracker.getActiveRebalanceIntents();
313
+ expect(activeIntents.length).to.equal(1);
314
+ expect(activeIntents[0].destination).to.equal(DOMAIN_IDS.anvil2);
315
+ expect(activeIntents[0].amount).to.equal(
316
+ ERC20_WEIGHTED_EXPECTED_DEFICIT_2000USDC.toBigInt(),
317
+ );
318
+ const trackedIntentId = activeIntents[0].id;
319
+
320
+ let partialIntents =
321
+ await context.tracker.getPartiallyFulfilledInventoryIntents();
322
+ expect(partialIntents.length).to.equal(1);
323
+ expect(partialIntents[0].completedAmount > 0n).to.be.true;
324
+ expect(
325
+ partialIntents[0].completedAmount + partialIntents[0].remaining,
326
+ ).to.equal(ERC20_WEIGHTED_EXPECTED_DEFICIT_2000USDC.toBigInt());
327
+
328
+ let actions = await context.tracker.getActionsForIntent(trackedIntentId);
329
+ let movementActions = actions.filter(
330
+ (a) => a.type === 'inventory_movement',
331
+ );
332
+ let depositActions = actions.filter((a) => a.type === 'inventory_deposit');
333
+ expect(actions.length).to.equal(1);
334
+ expect(movementActions.length).to.equal(0);
335
+ expect(depositActions.length).to.equal(1);
336
+ const c0Amount = partialIntents[0].completedAmount;
337
+
338
+ await executeCycle(context);
339
+ await context.tracker.syncInventoryMovementActions({
340
+ [ExternalBridgeType.LiFi]: mockBridge,
341
+ });
342
+ await relayInProgressInventoryDeposits(
343
+ context,
344
+ localProviders,
345
+ multiProvider,
346
+ hyperlaneCore,
347
+ );
348
+
349
+ activeIntents = await context.tracker.getActiveRebalanceIntents();
350
+ expect(activeIntents.length).to.equal(1);
351
+ partialIntents =
352
+ await context.tracker.getPartiallyFulfilledInventoryIntents();
353
+ expect(partialIntents.length).to.equal(1);
354
+ expect(
355
+ partialIntents[0].completedAmount + partialIntents[0].remaining,
356
+ ).to.equal(ERC20_WEIGHTED_EXPECTED_DEFICIT_2000USDC.toBigInt());
357
+
358
+ actions = await context.tracker.getActionsForIntent(trackedIntentId);
359
+ movementActions = actions.filter((a) => a.type === 'inventory_movement');
360
+ depositActions = actions.filter((a) => a.type === 'inventory_deposit');
361
+ expect(actions.length).to.equal(2);
362
+ expect(movementActions.length).to.equal(1);
363
+ expect(depositActions.length).to.equal(1);
364
+ expect(movementActions[0].origin).to.equal(DOMAIN_IDS.anvil1);
365
+ expect(movementActions[0].destination).to.equal(DOMAIN_IDS.anvil2);
366
+ expect(movementActions[0].status).to.equal('complete');
367
+ expect(partialIntents[0].completedAmount).to.equal(c0Amount);
368
+
369
+ await executeCycle(context);
370
+ await context.tracker.syncInventoryMovementActions({
371
+ [ExternalBridgeType.LiFi]: mockBridge,
372
+ });
373
+ await relayInProgressInventoryDeposits(
374
+ context,
375
+ localProviders,
376
+ multiProvider,
377
+ hyperlaneCore,
378
+ );
379
+
380
+ activeIntents = await context.tracker.getActiveRebalanceIntents();
381
+ expect(activeIntents.length).to.equal(0);
382
+ partialIntents =
383
+ await context.tracker.getPartiallyFulfilledInventoryIntents();
384
+ expect(partialIntents.length).to.equal(0);
385
+
386
+ actions = await context.tracker.getActionsForIntent(trackedIntentId);
387
+ movementActions = actions.filter((a) => a.type === 'inventory_movement');
388
+ depositActions = actions.filter((a) => a.type === 'inventory_deposit');
389
+ expect(actions.length).to.equal(3);
390
+ expect(movementActions.length).to.equal(1);
391
+ expect(depositActions.length).to.equal(2);
392
+
393
+ const completedIntent =
394
+ await context.tracker.getRebalanceIntent(trackedIntentId);
395
+ expect(completedIntent?.status).to.equal('complete');
396
+ });
397
+
398
+ it('retries after bridge execution failure', async function () {
399
+ const context = await new TestRebalancerBuilder(
400
+ deploymentManager,
401
+ multiProvider,
402
+ )
403
+ .withStrategy(weightedStrategyConfig)
404
+ .withExecutionMode('execute')
405
+ .withErc20InventoryConfig({
406
+ inventorySignerKey: ANVIL_USER_PRIVATE_KEY,
407
+ erc20DeployedAddresses,
408
+ })
409
+ .withMockExternalBridge(mockBridge)
410
+ .withInventorySignerBalances('ERC20_SIGNER_ZERO_ANVIL3')
411
+ .withBalances('ERC20_INVENTORY_WEIGHTED_IMBALANCED')
412
+ .build();
413
+
414
+ const initialBalances = await getErc20RouterBalances(
415
+ localProviders,
416
+ erc20DeployedAddresses,
417
+ );
418
+
419
+ // Cycle 1: Bridge fails — intent created but stays not_started, no actions
420
+ mockBridge.failNextExecute();
421
+ await executeCycle(context);
422
+
423
+ const activeIntents = await context.tracker.getActiveRebalanceIntents();
424
+ expect(activeIntents.length).to.equal(0);
425
+
426
+ const partialIntents =
427
+ await context.tracker.getPartiallyFulfilledInventoryIntents();
428
+ expect(partialIntents.length).to.equal(1);
429
+ expect(partialIntents[0].intent.status).to.equal('not_started');
430
+ expect(partialIntents[0].completedAmount).to.equal(0n);
431
+ expect(partialIntents[0].remaining).to.equal(
432
+ ERC20_WEIGHTED_EXPECTED_DEFICIT_1000USDC.toBigInt(),
433
+ );
434
+
435
+ const intentId = partialIntents[0].intent.id;
436
+ const actionsAfterFailure =
437
+ await context.tracker.getActionsForIntent(intentId);
438
+ expect(actionsAfterFailure.length).to.equal(0);
439
+
440
+ // Cycle 2: Bridge succeeds — creates movement, intent becomes in_progress
441
+ await executeCycle(context);
442
+ await context.tracker.syncInventoryMovementActions({
443
+ [ExternalBridgeType.LiFi]: mockBridge,
444
+ });
445
+ await relayInProgressInventoryDeposits(
446
+ context,
447
+ localProviders,
448
+ multiProvider,
449
+ hyperlaneCore,
450
+ );
451
+
452
+ const cycle2Active = await context.tracker.getActiveRebalanceIntents();
453
+ expect(cycle2Active.length).to.equal(1);
454
+ const cycle2Partial =
455
+ await context.tracker.getPartiallyFulfilledInventoryIntents();
456
+ expect(cycle2Partial.length).to.equal(1);
457
+
458
+ const cycle2Actions = await context.tracker.getActionsForIntent(intentId);
459
+ expect(cycle2Actions.length).to.equal(1);
460
+ const movementAction = cycle2Actions.find(
461
+ (a) => a.type === 'inventory_movement',
462
+ );
463
+ expect(movementAction).to.exist;
464
+ expect(movementAction!.status).to.equal('complete');
465
+
466
+ const cycle2Intent = await context.tracker.getRebalanceIntent(intentId);
467
+ expect(cycle2Intent!.status).to.equal('in_progress');
468
+
469
+ // Cycle 3: Deposit completes the intent
470
+ await executeCycle(context);
471
+ await context.tracker.syncInventoryMovementActions({
472
+ [ExternalBridgeType.LiFi]: mockBridge,
473
+ });
474
+ await relayInProgressInventoryDeposits(
475
+ context,
476
+ localProviders,
477
+ multiProvider,
478
+ hyperlaneCore,
479
+ );
480
+
481
+ const completedIntent = await context.tracker.getRebalanceIntent(intentId);
482
+ expect(completedIntent!.status).to.equal('complete');
483
+
484
+ const finalActions = await context.tracker.getActionsForIntent(intentId);
485
+ expect(finalActions.length).to.equal(2);
486
+ const finalMovement = finalActions.find(
487
+ (a) => a.type === 'inventory_movement',
488
+ );
489
+ expect(finalMovement).to.exist;
490
+ const depositAction = finalActions.find(
491
+ (a) => a.type === 'inventory_deposit',
492
+ );
493
+ expect(depositAction).to.exist;
494
+
495
+ const finalBalances = await getErc20RouterBalances(
496
+ localProviders,
497
+ erc20DeployedAddresses,
498
+ );
499
+ const { surplusChain, neutralChain } = classifyChains(
500
+ 'anvil3',
501
+ depositAction!,
502
+ );
503
+
504
+ expect(
505
+ finalBalances.anvil3.gt(initialBalances.anvil3),
506
+ 'Deficit router (anvil3) balance should increase',
507
+ ).to.be.true;
508
+ expect(
509
+ finalBalances[surplusChain].lt(initialBalances[surplusChain]),
510
+ `Surplus router (${surplusChain}) balance should decrease`,
511
+ ).to.be.true;
512
+ if (neutralChain) {
513
+ expect(
514
+ finalBalances[neutralChain].eq(initialBalances[neutralChain]),
515
+ 'Uninvolved router balance should remain unchanged',
516
+ ).to.be.true;
517
+ }
518
+ });
519
+
520
+ it('enforces single active inventory intent when multiple routes are proposed', async function () {
521
+ const context = await new TestRebalancerBuilder(
522
+ deploymentManager,
523
+ multiProvider,
524
+ )
525
+ .withStrategy(weightedStrategyConfig)
526
+ .withExecutionMode('execute')
527
+ .withErc20InventoryConfig({
528
+ inventorySignerKey: ANVIL_USER_PRIVATE_KEY,
529
+ erc20DeployedAddresses,
530
+ })
531
+ .withMockExternalBridge(mockBridge)
532
+ .withBalances('ERC20_INVENTORY_WEIGHTED_ALL_ANVIL1')
533
+ .build();
534
+
535
+ const initialBalances = await getErc20RouterBalances(
536
+ localProviders,
537
+ erc20DeployedAddresses,
538
+ );
539
+
540
+ await executeCycle(context);
541
+
542
+ const firstCycleIntents = await context.tracker.getActiveRebalanceIntents();
543
+ expect(firstCycleIntents.length).to.equal(1);
544
+ expect(firstCycleIntents[0].destination).to.equal(DOMAIN_IDS.anvil2);
545
+ expect(firstCycleIntents[0].amount).to.equal(
546
+ ERC20_WEIGHTED_EXPECTED_DEFICIT_2000USDC.toBigInt(),
547
+ );
548
+
549
+ const firstIntentId = firstCycleIntents[0].id;
550
+ let partialIntents =
551
+ await context.tracker.getPartiallyFulfilledInventoryIntents();
552
+ expect(partialIntents.length).to.equal(1);
553
+ expect(partialIntents[0].hasInflightDeposit).to.equal(true);
554
+
555
+ await context.tracker.syncInventoryMovementActions({
556
+ [ExternalBridgeType.LiFi]: mockBridge,
557
+ });
558
+ await relayInProgressInventoryDeposits(
559
+ context,
560
+ localProviders,
561
+ multiProvider,
562
+ hyperlaneCore,
563
+ );
564
+
565
+ partialIntents =
566
+ await context.tracker.getPartiallyFulfilledInventoryIntents();
567
+ expect(partialIntents.length).to.equal(0);
568
+ const actions = await context.tracker.getActionsForIntent(firstIntentId);
569
+ expect(actions.length).to.equal(1);
570
+ const movementCount = actions.filter(
571
+ (a) => a.type === 'inventory_movement',
572
+ ).length;
573
+ const depositCount = actions.filter(
574
+ (a) => a.type === 'inventory_deposit',
575
+ ).length;
576
+ expect(movementCount).to.equal(0);
577
+ expect(depositCount).to.equal(1);
578
+
579
+ const completedFirstIntent =
580
+ await context.tracker.getRebalanceIntent(firstIntentId);
581
+ expect(completedFirstIntent?.status).to.equal('complete');
582
+
583
+ const finalBalances = await getErc20RouterBalances(
584
+ localProviders,
585
+ erc20DeployedAddresses,
586
+ );
587
+ const depositAction = await context.tracker.getRebalanceAction(
588
+ actions.find((a) => a.type === 'inventory_deposit')!.id,
589
+ );
590
+ const { surplusChain, neutralChain } = classifyChains(
591
+ 'anvil2',
592
+ depositAction!,
593
+ );
594
+
595
+ expect(
596
+ finalBalances.anvil2.gt(initialBalances.anvil2),
597
+ 'Deficit router (anvil2) balance should increase',
598
+ ).to.be.true;
599
+ expect(
600
+ finalBalances[surplusChain].lt(initialBalances[surplusChain]),
601
+ `Surplus router (${surplusChain}) balance should decrease`,
602
+ ).to.be.true;
603
+ if (neutralChain) {
604
+ expect(
605
+ finalBalances[neutralChain].eq(initialBalances[neutralChain]),
606
+ 'Uninvolved router balance should remain unchanged',
607
+ ).to.be.true;
608
+ }
609
+
610
+ await executeCycle(context);
611
+ const secondCycleIntents =
612
+ await context.tracker.getActiveRebalanceIntents();
613
+ expect(secondCycleIntents.length).to.equal(1);
614
+ expect(secondCycleIntents[0].destination).to.equal(DOMAIN_IDS.anvil3);
615
+ expect(secondCycleIntents[0].amount).to.equal(
616
+ ERC20_WEIGHTED_EXPECTED_DEFICIT_2000USDC.toBigInt(),
617
+ );
618
+ });
619
+
620
+ it('uses bridge movements from different source chains before completion', async function () {
621
+ const context = await new TestRebalancerBuilder(
622
+ deploymentManager,
623
+ multiProvider,
624
+ )
625
+ .withStrategy(weightedStrategyConfig)
626
+ .withExecutionMode('execute')
627
+ .withErc20InventoryConfig({
628
+ inventorySignerKey: ANVIL_USER_PRIVATE_KEY,
629
+ erc20DeployedAddresses,
630
+ })
631
+ .withMockExternalBridge(mockBridge)
632
+ .withInventorySignerBalances('ERC20_SIGNER_WEIGHTED_BRIDGE_SOURCES')
633
+ .withBalances('ERC20_INVENTORY_WEIGHTED_PARTIAL_SUPPLY')
634
+ .build();
635
+
636
+ await executeCycle(context);
637
+ await context.tracker.syncInventoryMovementActions({
638
+ [ExternalBridgeType.LiFi]: mockBridge,
639
+ });
640
+ await relayInProgressInventoryDeposits(
641
+ context,
642
+ localProviders,
643
+ multiProvider,
644
+ hyperlaneCore,
645
+ );
646
+
647
+ const cycle1ActiveIntents =
648
+ await context.tracker.getActiveRebalanceIntents();
649
+ expect(cycle1ActiveIntents.length).to.equal(1);
650
+ expect(cycle1ActiveIntents[0].destination).to.equal(DOMAIN_IDS.anvil3);
651
+ expect(cycle1ActiveIntents[0].amount).to.equal(
652
+ ERC20_WEIGHTED_EXPECTED_DEFICIT_1200USDC.toBigInt(),
653
+ );
654
+ const intentId = cycle1ActiveIntents[0].id;
655
+
656
+ const cycle1PartialIntents =
657
+ await context.tracker.getPartiallyFulfilledInventoryIntents();
658
+ expect(cycle1PartialIntents.length).to.equal(1);
659
+ expect(cycle1PartialIntents[0].intent.id).to.equal(intentId);
660
+ expect(cycle1PartialIntents[0].remaining > 0n).to.be.true;
661
+ expect(
662
+ cycle1PartialIntents[0].completedAmount +
663
+ cycle1PartialIntents[0].remaining,
664
+ ).to.equal(ERC20_WEIGHTED_EXPECTED_DEFICIT_1200USDC.toBigInt());
665
+
666
+ let actions = await context.tracker.getActionsForIntent(intentId);
667
+ expect(actions.length).to.equal(1);
668
+ expect(
669
+ actions.filter((a) => a.type === 'inventory_deposit').length,
670
+ ).to.equal(1);
671
+ expect(
672
+ actions.filter((a) => a.type === 'inventory_movement').length,
673
+ ).to.equal(0);
674
+
675
+ await executeCycle(context);
676
+ await context.tracker.syncInventoryMovementActions({
677
+ [ExternalBridgeType.LiFi]: mockBridge,
678
+ });
679
+ await relayInProgressInventoryDeposits(
680
+ context,
681
+ localProviders,
682
+ multiProvider,
683
+ hyperlaneCore,
684
+ );
685
+
686
+ actions = await context.tracker.getActionsForIntent(intentId);
687
+ expect(actions.length).to.equal(3);
688
+
689
+ const movementActions = actions.filter(
690
+ (a) => a.type === 'inventory_movement',
691
+ );
692
+ expect(movementActions.length).to.equal(2);
693
+ const origins = new Set(movementActions.map((a) => a.origin));
694
+ expect(origins.has(DOMAIN_IDS.anvil1)).to.be.true;
695
+ expect(origins.has(DOMAIN_IDS.anvil2)).to.be.true;
696
+ movementActions.forEach((a) => {
697
+ expect(a.destination).to.equal(DOMAIN_IDS.anvil3);
698
+ expect(a.status).to.equal('complete');
699
+ });
700
+
701
+ const depositActions = actions.filter(
702
+ (a) => a.type === 'inventory_deposit',
703
+ );
704
+ expect(depositActions.length).to.equal(1);
705
+ const cycle2ActiveIntents =
706
+ await context.tracker.getActiveRebalanceIntents();
707
+ expect(cycle2ActiveIntents.length).to.equal(1);
708
+ const cycle2PartialIntents =
709
+ await context.tracker.getPartiallyFulfilledInventoryIntents();
710
+ expect(cycle2PartialIntents.length).to.equal(1);
711
+
712
+ await executeCycle(context);
713
+ await context.tracker.syncInventoryMovementActions({
714
+ [ExternalBridgeType.LiFi]: mockBridge,
715
+ });
716
+ await relayInProgressInventoryDeposits(
717
+ context,
718
+ localProviders,
719
+ multiProvider,
720
+ hyperlaneCore,
721
+ );
722
+
723
+ const finalActiveIntents =
724
+ await context.tracker.getActiveRebalanceIntents();
725
+ expect(finalActiveIntents.length).to.equal(0);
726
+ const finalPartialIntents =
727
+ await context.tracker.getPartiallyFulfilledInventoryIntents();
728
+ expect(finalPartialIntents.length).to.equal(0);
729
+
730
+ const finalIntent = await context.tracker.getRebalanceIntent(intentId);
731
+ expect(finalIntent?.status).to.equal('complete');
732
+ });
733
+ });