@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,1008 @@
1
+ import { expect } from 'chai';
2
+ import { BigNumber, ethers, providers } from 'ethers';
3
+
4
+ import { ERC20__factory } from '@humanode-hyperlane/core';
5
+ import {
6
+ HyperlaneCore,
7
+ MultiProvider,
8
+ snapshot,
9
+ } from '@humanode-hyperlane/sdk';
10
+
11
+ import {
12
+ RebalancerMinAmountType,
13
+ RebalancerStrategyOptions,
14
+ } from '../config/types.js';
15
+
16
+ import {
17
+ ANVIL_TEST_PRIVATE_KEY,
18
+ ANVIL_USER_PRIVATE_KEY,
19
+ DOMAIN_IDS,
20
+ type DeployedAddresses,
21
+ TEST_CHAINS,
22
+ type TestChain,
23
+ } from './fixtures/routes.js';
24
+ import { type LocalDeploymentContext } from './harness/BaseLocalDeploymentManager.js';
25
+ import { Erc20LocalDeploymentManager } from './harness/Erc20LocalDeploymentManager.js';
26
+ import { resetSnapshotsAndRefreshProviders } from './harness/SnapshotHelper.js';
27
+ import { getFirstMonitorEvent } from './harness/TestHelpers.js';
28
+ import { TestRebalancer } from './harness/TestRebalancer.js';
29
+ import {
30
+ executeWarpTransfer,
31
+ tryRelayMessage,
32
+ } from './harness/TransferHelper.js';
33
+
34
+ describe('CompositeStrategy E2E', function () {
35
+ this.timeout(300_000);
36
+
37
+ let deploymentManager: Erc20LocalDeploymentManager;
38
+ let multiProvider: MultiProvider;
39
+ let localProviders: Map<string, providers.JsonRpcProvider>;
40
+ let userAddress: string;
41
+ let snapshotIds: Map<string, string>;
42
+ let hyperlaneCore: HyperlaneCore;
43
+ let deployedAddresses: DeployedAddresses;
44
+
45
+ before(async function () {
46
+ const wallet = new ethers.Wallet(ANVIL_USER_PRIVATE_KEY);
47
+ userAddress = wallet.address;
48
+
49
+ deploymentManager = new Erc20LocalDeploymentManager();
50
+ const ctx: LocalDeploymentContext<DeployedAddresses> =
51
+ await deploymentManager.start();
52
+ multiProvider = ctx.multiProvider;
53
+ localProviders = ctx.providers;
54
+ deployedAddresses = ctx.deployedAddresses;
55
+
56
+ const coreAddresses: Record<string, Record<string, string>> = {};
57
+ for (const chain of TEST_CHAINS) {
58
+ coreAddresses[chain] = {
59
+ mailbox: deployedAddresses.chains[chain].mailbox,
60
+ interchainSecurityModule: deployedAddresses.chains[chain].ism,
61
+ };
62
+ }
63
+ hyperlaneCore = HyperlaneCore.fromAddressesMap(
64
+ coreAddresses,
65
+ multiProvider,
66
+ );
67
+
68
+ snapshotIds = new Map();
69
+ for (const [chain, provider] of localProviders) {
70
+ snapshotIds.set(chain, await snapshot(provider));
71
+ }
72
+ });
73
+
74
+ afterEach(async function () {
75
+ await resetSnapshotsAndRefreshProviders({
76
+ localProviders,
77
+ multiProvider,
78
+ snapshotIds,
79
+ });
80
+ });
81
+
82
+ after(async function () {
83
+ if (deploymentManager) {
84
+ await deploymentManager.stop();
85
+ }
86
+ });
87
+
88
+ it('collateralDeficit + weighted: routes use different bridges', async function () {
89
+ const transferAmount = BigNumber.from('600000000'); // 600 USDC
90
+
91
+ const context = await TestRebalancer.builder(
92
+ deploymentManager,
93
+ multiProvider,
94
+ )
95
+ .withStrategy([
96
+ {
97
+ rebalanceStrategy: RebalancerStrategyOptions.CollateralDeficit,
98
+ chains: {
99
+ anvil1: {
100
+ buffer: '0',
101
+ bridge: deployedAddresses.bridgeRoute1.anvil1,
102
+ },
103
+ anvil2: {
104
+ buffer: '0',
105
+ bridge: deployedAddresses.bridgeRoute1.anvil2,
106
+ },
107
+ anvil3: {
108
+ buffer: '0',
109
+ bridge: deployedAddresses.bridgeRoute1.anvil3,
110
+ },
111
+ },
112
+ },
113
+ {
114
+ rebalanceStrategy: RebalancerStrategyOptions.Weighted,
115
+ chains: {
116
+ anvil1: {
117
+ weighted: { weight: 60n, tolerance: 5n },
118
+ bridge: deployedAddresses.bridgeRoute2.anvil1,
119
+ },
120
+ anvil2: {
121
+ weighted: { weight: 20n, tolerance: 5n },
122
+ bridge: deployedAddresses.bridgeRoute2.anvil2,
123
+ },
124
+ anvil3: {
125
+ weighted: { weight: 20n, tolerance: 5n },
126
+ bridge: deployedAddresses.bridgeRoute2.anvil3,
127
+ },
128
+ },
129
+ },
130
+ ])
131
+ .withBalances('COMPOSITE_DEFICIT_IMBALANCE')
132
+ .withExecutionMode('execute')
133
+ .build();
134
+
135
+ // Fund user and execute actual warp transfer
136
+ const ethProvider = localProviders.get('anvil1')!;
137
+ const deployer = new ethers.Wallet(ANVIL_TEST_PRIVATE_KEY, ethProvider);
138
+ const token = ERC20__factory.connect(
139
+ deployedAddresses.tokens.anvil1,
140
+ deployer,
141
+ );
142
+ const tx = await token.transfer(userAddress, transferAmount.mul(2));
143
+ await tx.wait();
144
+
145
+ const transferResult = await executeWarpTransfer(
146
+ context.multiProvider,
147
+ {
148
+ originChain: 'anvil1',
149
+ destinationChain: 'anvil2',
150
+ routerAddress: deployedAddresses.monitoredRoute.anvil1,
151
+ tokenAddress: deployedAddresses.tokens.anvil1,
152
+ amount: transferAmount,
153
+ recipient: userAddress,
154
+ senderAddress: userAddress,
155
+ },
156
+ ethProvider,
157
+ );
158
+
159
+ const blockTags = await context.getConfirmedBlockTags();
160
+ await context.tracker.syncTransfers(blockTags);
161
+
162
+ // Verify transfer was tracked
163
+ const transfersBeforeRebalance =
164
+ await context.tracker.getInProgressTransfers();
165
+ expect(transfersBeforeRebalance.length).to.equal(
166
+ 1,
167
+ 'Should have exactly 1 in-progress transfer',
168
+ );
169
+
170
+ const monitor = context.createMonitor(0);
171
+ const event = await getFirstMonitorEvent(monitor);
172
+ await context.orchestrator.executeCycle(event);
173
+
174
+ // Assert using ActionTracker: Both SUPERSEED (CollateralDeficit) and SUBTENSOR intent should exist
175
+ const activeIntents = await context.tracker.getActiveRebalanceIntents();
176
+ expect(
177
+ activeIntents.length,
178
+ 'Should have active rebalance intents',
179
+ ).to.be.equal(3, 'Should have exactly 3 active rebalance intents');
180
+
181
+ const inProgressActions = await context.tracker.getInProgressActions();
182
+
183
+ // Check for SUPERSEED actions (CollateralDeficit strategy routes to arbitrum)
184
+ const superseedActions = [];
185
+ for (const action of inProgressActions) {
186
+ const intent = activeIntents.find((i) => i.id === action.intentId);
187
+ if (intent?.bridge) {
188
+ const originChain = Object.entries(DOMAIN_IDS).find(
189
+ ([, id]) => id === action.origin,
190
+ )?.[0] as TestChain | undefined;
191
+ if (
192
+ originChain &&
193
+ intent.bridge === deployedAddresses.bridgeRoute1[originChain]
194
+ ) {
195
+ superseedActions.push(action);
196
+ }
197
+ }
198
+ }
199
+ expect(
200
+ superseedActions.length,
201
+ 'Should have SUPERSEED actions from CollateralDeficit',
202
+ ).to.be.equal(1);
203
+
204
+ // Verify SUPERSEED route goes to arbitrum (has deficit from pending transfer)
205
+ const actionToArbitrum = superseedActions.find(
206
+ (a) => a.destination === DOMAIN_IDS.anvil2,
207
+ );
208
+ expect(actionToArbitrum, 'Should have SUPERSEED action to arbitrum').to
209
+ .exist;
210
+
211
+ // Relay SUPERSEED actions and verify completion
212
+ for (const action of superseedActions) {
213
+ if (!action.txHash) continue;
214
+ const originChain = Object.entries(DOMAIN_IDS).find(
215
+ ([, id]) => id === action.origin,
216
+ )?.[0] as TestChain | undefined;
217
+ const destChain = Object.entries(DOMAIN_IDS).find(
218
+ ([, id]) => id === action.destination,
219
+ )?.[0] as TestChain | undefined;
220
+
221
+ if (originChain && destChain) {
222
+ const originProvider = localProviders.get(originChain);
223
+ expect(originProvider, `Provider should exist for ${originChain}`).to
224
+ .exist;
225
+ const rebalanceTxReceipt = await originProvider!.getTransactionReceipt(
226
+ action.txHash,
227
+ );
228
+ expect(rebalanceTxReceipt, `Receipt should exist for ${action.id}`).to
229
+ .exist;
230
+
231
+ const relayResult = await tryRelayMessage(
232
+ multiProvider,
233
+ hyperlaneCore,
234
+ {
235
+ dispatchTx: rebalanceTxReceipt!,
236
+ messageId: action.messageId!,
237
+ origin: originChain,
238
+ destination: destChain,
239
+ },
240
+ );
241
+ expect(
242
+ relayResult.success,
243
+ `SUPERSEED relay should succeed: ${relayResult.error}`,
244
+ ).to.be.true;
245
+ }
246
+ }
247
+
248
+ const blockTags2 = await context.getConfirmedBlockTags();
249
+ await context.tracker.syncRebalanceActions(blockTags2);
250
+
251
+ for (const action of superseedActions) {
252
+ const completedAction = await context.tracker.getRebalanceAction(
253
+ action.id,
254
+ );
255
+ expect(completedAction!.status).to.equal('complete');
256
+ }
257
+
258
+ // Relay the original user transfer now that collateral has been rebalanced
259
+ const userTransferRelay = await tryRelayMessage(
260
+ context.multiProvider,
261
+ hyperlaneCore,
262
+ transferResult,
263
+ );
264
+ expect(
265
+ userTransferRelay.success,
266
+ `User transfer relay should succeed: ${userTransferRelay.error}`,
267
+ ).to.be.true;
268
+
269
+ const blockTags3 = await context.getConfirmedBlockTags();
270
+ await context.tracker.syncTransfers(blockTags3);
271
+ const completedTransfer = await context.tracker.getTransfer(
272
+ transferResult.messageId,
273
+ );
274
+ expect(completedTransfer!.status).to.equal('complete');
275
+ });
276
+
277
+ it('collateralDeficit + minAmount: routes use different bridges', async function () {
278
+ const transferAmount = BigNumber.from('600000000'); // 600 USDC
279
+ const customBalances = {
280
+ anvil1: BigNumber.from('8000000000'),
281
+ anvil2: BigNumber.from('500000000'),
282
+ anvil3: BigNumber.from('50000000'), // below minAmount threshold (100 USDC)
283
+ };
284
+
285
+ const context = await TestRebalancer.builder(
286
+ deploymentManager,
287
+ multiProvider,
288
+ )
289
+ .withStrategy([
290
+ {
291
+ rebalanceStrategy: RebalancerStrategyOptions.CollateralDeficit,
292
+ chains: {
293
+ anvil1: {
294
+ buffer: '0',
295
+ bridge: deployedAddresses.bridgeRoute1.anvil1,
296
+ },
297
+ anvil2: {
298
+ buffer: '0',
299
+ bridge: deployedAddresses.bridgeRoute1.anvil2,
300
+ },
301
+ anvil3: {
302
+ buffer: '0',
303
+ bridge: deployedAddresses.bridgeRoute1.anvil3,
304
+ },
305
+ },
306
+ },
307
+ {
308
+ rebalanceStrategy: RebalancerStrategyOptions.MinAmount,
309
+ chains: {
310
+ anvil1: {
311
+ minAmount: {
312
+ min: '100',
313
+ target: '120',
314
+ type: RebalancerMinAmountType.Absolute,
315
+ },
316
+ bridge: deployedAddresses.bridgeRoute2.anvil1,
317
+ },
318
+ anvil2: {
319
+ minAmount: {
320
+ min: '100',
321
+ target: '120',
322
+ type: RebalancerMinAmountType.Absolute,
323
+ },
324
+ bridge: deployedAddresses.bridgeRoute2.anvil2,
325
+ },
326
+ anvil3: {
327
+ minAmount: {
328
+ min: '100',
329
+ target: '120',
330
+ type: RebalancerMinAmountType.Absolute,
331
+ },
332
+ bridge: deployedAddresses.bridgeRoute2.anvil3,
333
+ },
334
+ },
335
+ },
336
+ ])
337
+ .withBalances(customBalances)
338
+ .withExecutionMode('execute')
339
+ .build();
340
+
341
+ const ethProvider = localProviders.get('anvil1')!;
342
+ const deployer2 = new ethers.Wallet(ANVIL_TEST_PRIVATE_KEY, ethProvider);
343
+ const token2 = ERC20__factory.connect(
344
+ deployedAddresses.tokens.anvil1,
345
+ deployer2,
346
+ );
347
+ await token2.transfer(userAddress, transferAmount.mul(2));
348
+
349
+ const transferResult = await executeWarpTransfer(
350
+ context.multiProvider,
351
+ {
352
+ originChain: 'anvil1',
353
+ destinationChain: 'anvil2',
354
+ routerAddress: deployedAddresses.monitoredRoute.anvil1,
355
+ tokenAddress: deployedAddresses.tokens.anvil1,
356
+ amount: transferAmount,
357
+ recipient: userAddress,
358
+ senderAddress: userAddress,
359
+ },
360
+ ethProvider,
361
+ );
362
+
363
+ const blockTags4 = await context.getConfirmedBlockTags();
364
+ await context.tracker.syncTransfers(blockTags4);
365
+
366
+ const transfersBeforeRebalance =
367
+ await context.tracker.getInProgressTransfers();
368
+ expect(transfersBeforeRebalance.length).to.equal(
369
+ 1,
370
+ 'Should have exactly 1 in-progress transfer',
371
+ );
372
+
373
+ const monitor = context.createMonitor(0);
374
+ const event = await getFirstMonitorEvent(monitor);
375
+ await context.orchestrator.executeCycle(event);
376
+
377
+ const activeIntents = await context.tracker.getActiveRebalanceIntents();
378
+ expect(
379
+ activeIntents.length,
380
+ 'Should have active rebalance intents',
381
+ ).to.be.greaterThan(0);
382
+
383
+ const inProgressActions = await context.tracker.getInProgressActions();
384
+
385
+ const superseedActions = [];
386
+ for (const action of inProgressActions) {
387
+ const intent = activeIntents.find((i) => i.id === action.intentId);
388
+ if (intent?.bridge) {
389
+ const originChain = Object.entries(DOMAIN_IDS).find(
390
+ ([, id]) => id === action.origin,
391
+ )?.[0] as TestChain | undefined;
392
+ if (
393
+ originChain &&
394
+ intent.bridge === deployedAddresses.bridgeRoute1[originChain]
395
+ ) {
396
+ superseedActions.push(action);
397
+ }
398
+ }
399
+ }
400
+ expect(
401
+ superseedActions.length,
402
+ 'Should have SUPERSEED actions from CollateralDeficit',
403
+ ).to.be.greaterThan(0);
404
+
405
+ const actionToArbitrum = superseedActions.find(
406
+ (a) => a.destination === DOMAIN_IDS.anvil2,
407
+ );
408
+ expect(actionToArbitrum, 'Should have SUPERSEED action to arbitrum').to
409
+ .exist;
410
+
411
+ for (const action of superseedActions) {
412
+ if (!action.txHash) continue;
413
+ const originChain = Object.entries(DOMAIN_IDS).find(
414
+ ([, id]) => id === action.origin,
415
+ )?.[0] as TestChain | undefined;
416
+ const destChain = Object.entries(DOMAIN_IDS).find(
417
+ ([, id]) => id === action.destination,
418
+ )?.[0] as TestChain | undefined;
419
+
420
+ if (originChain && destChain) {
421
+ const originProvider = localProviders.get(originChain);
422
+ expect(originProvider, `Provider should exist for ${originChain}`).to
423
+ .exist;
424
+ const rebalanceTxReceipt = await originProvider!.getTransactionReceipt(
425
+ action.txHash,
426
+ );
427
+ expect(rebalanceTxReceipt, `Receipt should exist for ${action.id}`).to
428
+ .exist;
429
+
430
+ const relayResult = await tryRelayMessage(
431
+ multiProvider,
432
+ hyperlaneCore,
433
+ {
434
+ dispatchTx: rebalanceTxReceipt!,
435
+ messageId: action.messageId!,
436
+ origin: originChain,
437
+ destination: destChain,
438
+ },
439
+ );
440
+ expect(
441
+ relayResult.success,
442
+ `SUPERSEED relay should succeed: ${relayResult.error}`,
443
+ ).to.be.true;
444
+ }
445
+ }
446
+
447
+ const blockTags5 = await context.getConfirmedBlockTags();
448
+ await context.tracker.syncRebalanceActions(blockTags5);
449
+
450
+ for (const action of superseedActions) {
451
+ const completedAction = await context.tracker.getRebalanceAction(
452
+ action.id,
453
+ );
454
+ expect(completedAction!.status).to.equal('complete');
455
+ }
456
+
457
+ const userTransferRelay = await tryRelayMessage(
458
+ context.multiProvider,
459
+ hyperlaneCore,
460
+ transferResult,
461
+ );
462
+ expect(
463
+ userTransferRelay.success,
464
+ `User transfer relay should succeed: ${userTransferRelay.error}`,
465
+ ).to.be.true;
466
+
467
+ const blockTags6 = await context.getConfirmedBlockTags();
468
+ await context.tracker.syncTransfers(blockTags6);
469
+ const completedTransfer = await context.tracker.getTransfer(
470
+ transferResult.messageId,
471
+ );
472
+ expect(completedTransfer!.status).to.equal('complete');
473
+ });
474
+
475
+ it('should propose collateralDeficit rebalance even when slow rebalance is inflight', async function () {
476
+ const ethProvider = localProviders.get('anvil1')!;
477
+ const transferAmount = BigNumber.from('600000000');
478
+
479
+ // Build context with Composite strategy from the start
480
+ // COMPOSITE_DEFICIT_IMBALANCE: eth=8000, arb=500, base=1500
481
+ // Weighted sees: eth surplus (target=6000), base deficit (target=2000)
482
+ // Cycle 1: Weighted creates SUBTENSOR rebalance eth→base
483
+ const context = await TestRebalancer.builder(
484
+ deploymentManager,
485
+ multiProvider,
486
+ )
487
+ .withStrategy([
488
+ {
489
+ rebalanceStrategy: RebalancerStrategyOptions.CollateralDeficit,
490
+ chains: {
491
+ anvil1: {
492
+ buffer: '0',
493
+ bridge: deployedAddresses.bridgeRoute1.anvil1,
494
+ },
495
+ anvil2: {
496
+ buffer: '0',
497
+ bridge: deployedAddresses.bridgeRoute1.anvil2,
498
+ },
499
+ anvil3: {
500
+ buffer: '0',
501
+ bridge: deployedAddresses.bridgeRoute1.anvil3,
502
+ },
503
+ },
504
+ },
505
+ {
506
+ rebalanceStrategy: RebalancerStrategyOptions.Weighted,
507
+ chains: {
508
+ anvil1: {
509
+ weighted: { weight: 60n, tolerance: 5n },
510
+ bridge: deployedAddresses.bridgeRoute2.anvil1,
511
+ },
512
+ anvil2: {
513
+ weighted: { weight: 20n, tolerance: 5n },
514
+ bridge: deployedAddresses.bridgeRoute2.anvil2,
515
+ },
516
+ anvil3: {
517
+ weighted: { weight: 20n, tolerance: 5n },
518
+ bridge: deployedAddresses.bridgeRoute2.anvil3,
519
+ },
520
+ },
521
+ },
522
+ ])
523
+ .withBalances('COMPOSITE_DEFICIT_IMBALANCE')
524
+ .withExecutionMode('execute')
525
+ .build();
526
+
527
+ // ===== CYCLE 1: Execute Weighted rebalance (no deficit yet) =====
528
+ // Initial: eth=7000, arb=2000, base=1000. Target: eth=6000, arb=2000, base=2000
529
+ // CollateralDeficit finds no deficit (no pending transfers), so Weighted runs
530
+ const monitor1 = context.createMonitor(0);
531
+ const event1 = await getFirstMonitorEvent(monitor1);
532
+ await context.orchestrator.executeCycle(event1);
533
+
534
+ const blockTags7 = await context.getConfirmedBlockTags();
535
+ await context.tracker.syncRebalanceActions(blockTags7);
536
+ const inflightAfterCycle1 = await context.tracker.getInProgressActions();
537
+ expect(
538
+ inflightAfterCycle1.length,
539
+ 'Cycle 1 should create inflight actions',
540
+ ).to.be.greaterThan(0);
541
+
542
+ const activeIntents1 = await context.tracker.getActiveRebalanceIntents();
543
+ const subtensorInflight = inflightAfterCycle1.find((action) => {
544
+ const intent = activeIntents1.find((i) => i.id === action.intentId);
545
+ if (!intent?.bridge) return false;
546
+ const originChain = Object.entries(DOMAIN_IDS).find(
547
+ ([, id]) => id === action.origin,
548
+ )?.[0] as TestChain | undefined;
549
+ return (
550
+ originChain &&
551
+ intent.bridge === deployedAddresses.bridgeRoute2[originChain]
552
+ );
553
+ });
554
+ expect(
555
+ subtensorInflight,
556
+ 'Should have SUBTENSOR inflight from Weighted strategy',
557
+ ).to.exist;
558
+
559
+ // ===== CYCLE 2: Add pending transfer to create deficit, then execute =====
560
+ // Fund user and execute a warp transfer eth→arbitrum to create deficit on arbitrum
561
+ const deployer3 = new ethers.Wallet(ANVIL_TEST_PRIVATE_KEY, ethProvider);
562
+ const token3 = ERC20__factory.connect(
563
+ deployedAddresses.tokens.anvil1,
564
+ deployer3,
565
+ );
566
+ await token3.transfer(userAddress, transferAmount.mul(2));
567
+
568
+ const transferResult = await executeWarpTransfer(
569
+ context.multiProvider,
570
+ {
571
+ originChain: 'anvil1',
572
+ destinationChain: 'anvil2',
573
+ routerAddress: deployedAddresses.monitoredRoute.anvil1,
574
+ tokenAddress: deployedAddresses.tokens.anvil1,
575
+ amount: transferAmount,
576
+ recipient: userAddress,
577
+ senderAddress: userAddress,
578
+ },
579
+ ethProvider,
580
+ );
581
+
582
+ const blockTags8 = await context.getConfirmedBlockTags();
583
+ await context.tracker.syncTransfers(blockTags8);
584
+
585
+ // Verify transfer tracked
586
+ const transfersBeforeCycle2 =
587
+ await context.tracker.getInProgressTransfers();
588
+ expect(transfersBeforeCycle2.length).to.equal(
589
+ 1,
590
+ 'Should have 1 in-progress transfer',
591
+ );
592
+
593
+ // Execute cycle 2 - now CollateralDeficit should see deficit on arbitrum
594
+ const monitor2 = context.createMonitor(0);
595
+ const event2 = await getFirstMonitorEvent(monitor2);
596
+ await context.orchestrator.executeCycle(event2);
597
+
598
+ const blockTags9 = await context.getConfirmedBlockTags();
599
+ await context.tracker.syncRebalanceActions(blockTags9);
600
+
601
+ const inProgressAfterCycle2 = await context.tracker.getInProgressActions();
602
+ const activeIntents2 = await context.tracker.getActiveRebalanceIntents();
603
+
604
+ const superseedActions = inProgressAfterCycle2.filter((action) => {
605
+ const intent = activeIntents2.find((i) => i.id === action.intentId);
606
+ if (!intent?.bridge) return false;
607
+ const originChain = Object.entries(DOMAIN_IDS).find(
608
+ ([, id]) => id === action.origin,
609
+ )?.[0] as TestChain | undefined;
610
+ return (
611
+ originChain &&
612
+ intent.bridge === deployedAddresses.bridgeRoute1[originChain]
613
+ );
614
+ });
615
+
616
+ expect(
617
+ superseedActions.length,
618
+ 'Should have SUPERSEED actions from CollateralDeficit despite SUBTENSOR inflight',
619
+ ).to.be.greaterThan(0);
620
+
621
+ const superseedToArbitrum = superseedActions.find(
622
+ (a) => a.destination === DOMAIN_IDS.anvil2,
623
+ );
624
+ expect(
625
+ superseedToArbitrum,
626
+ 'Should have SUPERSEED action to arbitrum for deficit',
627
+ ).to.exist;
628
+
629
+ // Relay SUPERSEED actions and verify completion
630
+ for (const action of superseedActions) {
631
+ if (!action.txHash) continue;
632
+ const originChain = Object.entries(DOMAIN_IDS).find(
633
+ ([, id]) => id === action.origin,
634
+ )?.[0] as TestChain | undefined;
635
+ const destChain = Object.entries(DOMAIN_IDS).find(
636
+ ([, id]) => id === action.destination,
637
+ )?.[0] as TestChain | undefined;
638
+
639
+ if (originChain && destChain) {
640
+ const originProvider = localProviders.get(originChain);
641
+ expect(originProvider, `Provider should exist for ${originChain}`).to
642
+ .exist;
643
+ const rebalanceTxReceipt = await originProvider!.getTransactionReceipt(
644
+ action.txHash,
645
+ );
646
+ expect(rebalanceTxReceipt, `Receipt should exist for ${action.id}`).to
647
+ .exist;
648
+
649
+ const relayResult = await tryRelayMessage(
650
+ multiProvider,
651
+ hyperlaneCore,
652
+ {
653
+ dispatchTx: rebalanceTxReceipt!,
654
+ messageId: action.messageId!,
655
+ origin: originChain,
656
+ destination: destChain,
657
+ },
658
+ );
659
+ expect(
660
+ relayResult.success,
661
+ `SUPERSEED relay should succeed: ${relayResult.error}`,
662
+ ).to.be.true;
663
+ }
664
+ }
665
+
666
+ const blockTags10 = await context.getConfirmedBlockTags();
667
+ await context.tracker.syncRebalanceActions(blockTags10);
668
+
669
+ for (const action of superseedActions) {
670
+ const completedAction = await context.tracker.getRebalanceAction(
671
+ action.id,
672
+ );
673
+ expect(completedAction!.status).to.equal('complete');
674
+ }
675
+
676
+ // Relay the original user transfer now that collateral has been rebalanced
677
+ const userTransferRelay = await tryRelayMessage(
678
+ context.multiProvider,
679
+ hyperlaneCore,
680
+ transferResult,
681
+ );
682
+ expect(
683
+ userTransferRelay.success,
684
+ `User transfer relay should succeed: ${userTransferRelay.error}`,
685
+ ).to.be.true;
686
+ });
687
+
688
+ it('should simulate end state accounting for inflight rebalances', async function () {
689
+ const ethProvider = localProviders.get('anvil1')!;
690
+
691
+ // Build context with Weighted strategy
692
+ // Initial: eth=7000, arb=2000, base=1000 (total=10000)
693
+ // Target: eth=60% (6000), arb=20% (2000), base=20% (2000)
694
+ // Cycle 1 will create inflight eth→base for ~1000 USDC
695
+ const context = await TestRebalancer.builder(
696
+ deploymentManager,
697
+ multiProvider,
698
+ )
699
+ .withStrategy([
700
+ {
701
+ rebalanceStrategy: RebalancerStrategyOptions.Weighted,
702
+ chains: {
703
+ anvil1: {
704
+ weighted: { weight: 60n, tolerance: 5n },
705
+ bridge: deployedAddresses.bridgeRoute2.anvil1,
706
+ },
707
+ anvil2: {
708
+ weighted: { weight: 20n, tolerance: 5n },
709
+ bridge: deployedAddresses.bridgeRoute2.anvil2,
710
+ },
711
+ anvil3: {
712
+ weighted: { weight: 20n, tolerance: 5n },
713
+ bridge: deployedAddresses.bridgeRoute2.anvil3,
714
+ },
715
+ },
716
+ },
717
+ ])
718
+ .withBalances({
719
+ anvil1: BigNumber.from('7000000000'),
720
+ anvil2: BigNumber.from('2000000000'),
721
+ anvil3: BigNumber.from('1000000000'),
722
+ })
723
+ .withExecutionMode('execute')
724
+ .build();
725
+
726
+ // ===== CYCLE 1: Execute rebalance to create inflight eth→base =====
727
+ const monitor1 = context.createMonitor(0);
728
+ const event1 = await getFirstMonitorEvent(monitor1);
729
+ await context.orchestrator.executeCycle(event1);
730
+
731
+ const blockTags11 = await context.getConfirmedBlockTags();
732
+ await context.tracker.syncRebalanceActions(blockTags11);
733
+
734
+ const inflightAfterCycle1 = await context.tracker.getInProgressActions();
735
+ expect(
736
+ inflightAfterCycle1.length,
737
+ 'Cycle 1 should create inflight action',
738
+ ).to.be.greaterThan(0);
739
+
740
+ const inflightToBase = inflightAfterCycle1.find(
741
+ (a) =>
742
+ a.destination === DOMAIN_IDS.anvil3 && a.origin === DOMAIN_IDS.anvil1,
743
+ );
744
+ expect(inflightToBase, 'Should have inflight action eth→base').to.exist;
745
+
746
+ const inflightAmount = BigNumber.from(inflightToBase!.amount);
747
+ expect(inflightAmount.gt(0), 'Inflight amount should be positive').to.be
748
+ .true;
749
+
750
+ // ===== CYCLE 2: Execute again - should account for inflight =====
751
+ // Weighted now sees: base effective = current + inflight ≈ 2000 (target)
752
+ // Should propose reduced amount or nothing to base
753
+ const monitor2 = context.createMonitor(0);
754
+ const event2 = await getFirstMonitorEvent(monitor2);
755
+ await context.orchestrator.executeCycle(event2);
756
+
757
+ const blockTags12 = await context.getConfirmedBlockTags();
758
+ await context.tracker.syncRebalanceActions(blockTags12);
759
+
760
+ // Check if new routes to base were proposed
761
+ const inProgressAfterCycle2 = await context.tracker.getInProgressActions();
762
+ const newActionsToBase = inProgressAfterCycle2.filter(
763
+ (a) =>
764
+ a.destination === DOMAIN_IDS.anvil3 &&
765
+ a.id !== inflightToBase!.id &&
766
+ a.status === 'in_progress',
767
+ );
768
+
769
+ if (newActionsToBase.length > 0) {
770
+ // If route was proposed, should be much smaller than original 1000 USDC
771
+ const proposedAmount = BigNumber.from(
772
+ newActionsToBase[0].amount,
773
+ ).toBigInt();
774
+ expect(
775
+ proposedAmount < 500000000n,
776
+ `Amount to base (${proposedAmount}) should be reduced accounting for inflight`,
777
+ ).to.be.true;
778
+ }
779
+ // If no new route to base, that's valid (within tolerance after inflight)
780
+
781
+ // Verify inflight still exists and action tracking is working
782
+ const finalInProgress = await context.tracker.getInProgressActions();
783
+ const inflightStillActive = finalInProgress.find(
784
+ (a) => a.id === inflightToBase!.id,
785
+ );
786
+ expect(inflightStillActive, 'Inflight action should still be tracked').to
787
+ .exist;
788
+ expect(inflightStillActive!.status).to.equal('in_progress');
789
+
790
+ // Relay the inflight from cycle 1
791
+ if (inflightToBase?.txHash) {
792
+ const rebalanceTxReceipt = await ethProvider.getTransactionReceipt(
793
+ inflightToBase.txHash,
794
+ );
795
+ const relayResult = await tryRelayMessage(multiProvider, hyperlaneCore, {
796
+ dispatchTx: rebalanceTxReceipt,
797
+ messageId: inflightToBase.messageId!,
798
+ origin: 'anvil1',
799
+ destination: 'anvil3',
800
+ });
801
+
802
+ if (relayResult.success) {
803
+ const blockTags13 = await context.getConfirmedBlockTags();
804
+ await context.tracker.syncRebalanceActions(blockTags13);
805
+
806
+ const completedAction = await context.tracker.getRebalanceAction(
807
+ inflightToBase!.id,
808
+ );
809
+ expect(completedAction!.status).to.equal('complete');
810
+ }
811
+ // Relay may fail due to ISM configuration in test environment - main assertion already passed
812
+ }
813
+ });
814
+
815
+ it('should execute collateralDeficit portion; slow bridge intents fail', async function () {
816
+ const transferAmount = BigNumber.from('600000000'); // 600 USDC
817
+
818
+ // Use balances that trigger both strategies
819
+ // - Weighted: ethereum has too much (needs rebalance to base)
820
+ // - CollateralDeficit: pending transfer will create deficit on arbitrum
821
+ const context = await TestRebalancer.builder(
822
+ deploymentManager,
823
+ multiProvider,
824
+ )
825
+ .withStrategy([
826
+ {
827
+ rebalanceStrategy: RebalancerStrategyOptions.CollateralDeficit,
828
+ chains: {
829
+ anvil1: {
830
+ buffer: '0',
831
+ bridge: deployedAddresses.bridgeRoute1.anvil1,
832
+ },
833
+ anvil2: {
834
+ buffer: '0',
835
+ bridge: deployedAddresses.bridgeRoute1.anvil2,
836
+ },
837
+ anvil3: {
838
+ buffer: '0',
839
+ bridge: deployedAddresses.bridgeRoute1.anvil3,
840
+ },
841
+ },
842
+ },
843
+ {
844
+ rebalanceStrategy: RebalancerStrategyOptions.Weighted,
845
+ chains: {
846
+ anvil1: {
847
+ weighted: { weight: 60n, tolerance: 5n },
848
+ bridge: deployedAddresses.bridgeRoute2.anvil1,
849
+ },
850
+ anvil2: {
851
+ weighted: { weight: 20n, tolerance: 5n },
852
+ bridge: deployedAddresses.bridgeRoute2.anvil2,
853
+ },
854
+ anvil3: {
855
+ weighted: { weight: 20n, tolerance: 5n },
856
+ bridge: deployedAddresses.bridgeRoute2.anvil3,
857
+ },
858
+ },
859
+ },
860
+ ])
861
+ .withBalances('COMPOSITE_DEFICIT_IMBALANCE')
862
+ .withExecutionMode('execute')
863
+ .build();
864
+
865
+ // Fund user and execute warp transfer to create deficit
866
+ const ethProvider = localProviders.get('anvil1')!;
867
+ const deployer4 = new ethers.Wallet(ANVIL_TEST_PRIVATE_KEY, ethProvider);
868
+ const token4 = ERC20__factory.connect(
869
+ deployedAddresses.tokens.anvil1,
870
+ deployer4,
871
+ );
872
+ await token4.transfer(userAddress, transferAmount.mul(2));
873
+
874
+ const transferResult = await executeWarpTransfer(
875
+ context.multiProvider,
876
+ {
877
+ originChain: 'anvil1',
878
+ destinationChain: 'anvil2',
879
+ routerAddress: deployedAddresses.monitoredRoute.anvil1,
880
+ tokenAddress: deployedAddresses.tokens.anvil1,
881
+ amount: transferAmount,
882
+ recipient: userAddress,
883
+ senderAddress: userAddress,
884
+ },
885
+ ethProvider,
886
+ );
887
+
888
+ const blockTags14 = await context.getConfirmedBlockTags();
889
+ await context.tracker.syncTransfers(blockTags14);
890
+
891
+ // Verify transfer was tracked
892
+ const transfersBeforeRebalance =
893
+ await context.tracker.getInProgressTransfers();
894
+ expect(transfersBeforeRebalance.length).to.equal(
895
+ 1,
896
+ 'Should have exactly 1 in-progress transfer',
897
+ );
898
+
899
+ // Execute cycle
900
+ const monitor = context.createMonitor(0);
901
+ const event = await getFirstMonitorEvent(monitor);
902
+ await context.orchestrator.executeCycle(event);
903
+
904
+ // Verify BOTH bridge types have intents/actions
905
+ const activeIntents = await context.tracker.getActiveRebalanceIntents();
906
+ const inProgressActions = await context.tracker.getInProgressActions();
907
+
908
+ expect(
909
+ activeIntents.length,
910
+ 'Should have active rebalance intents',
911
+ ).to.be.greaterThan(0);
912
+
913
+ // Helper to get chain name from domain
914
+ const getChainFromDomain = (domain: number): TestChain | undefined =>
915
+ Object.entries(DOMAIN_IDS).find(([, id]) => id === domain)?.[0] as
916
+ | TestChain
917
+ | undefined;
918
+
919
+ // Identify SUPERSEED and SUBTENSOR actions
920
+ const superseedActions = [];
921
+ const subtensorActions = [];
922
+ for (const action of inProgressActions) {
923
+ const intent = activeIntents.find((i) => i.id === action.intentId);
924
+ if (intent?.bridge) {
925
+ const originChain = getChainFromDomain(action.origin);
926
+ if (originChain) {
927
+ if (intent.bridge === deployedAddresses.bridgeRoute1[originChain]) {
928
+ superseedActions.push(action);
929
+ } else if (
930
+ intent.bridge === deployedAddresses.bridgeRoute2[originChain]
931
+ ) {
932
+ subtensorActions.push(action);
933
+ }
934
+ }
935
+ }
936
+ }
937
+
938
+ expect(
939
+ superseedActions.length,
940
+ 'Should have SUPERSEED actions from CollateralDeficit',
941
+ ).to.be.greaterThan(0);
942
+ expect(
943
+ subtensorActions.length,
944
+ 'Should have SUBTENSOR actions from Weighted',
945
+ ).to.be.greaterThan(0);
946
+
947
+ // Relay SUPERSEED actions (SUBTENSOR relay requires CCIP-read metadata not available in test env)
948
+ for (const action of superseedActions) {
949
+ if (!action.txHash) continue;
950
+
951
+ const originChain = getChainFromDomain(action.origin);
952
+ const destChain = getChainFromDomain(action.destination);
953
+ if (!originChain || !destChain) continue;
954
+
955
+ const provider = localProviders.get(originChain)!;
956
+ const rebalanceTxReceipt = await provider.getTransactionReceipt(
957
+ action.txHash,
958
+ );
959
+
960
+ const relayResult = await tryRelayMessage(multiProvider, hyperlaneCore, {
961
+ dispatchTx: rebalanceTxReceipt,
962
+ messageId: action.messageId!,
963
+ origin: originChain,
964
+ destination: destChain,
965
+ });
966
+ expect(
967
+ relayResult.success,
968
+ `SUPERSEED relay should succeed: ${relayResult.error}`,
969
+ ).to.be.true;
970
+ }
971
+
972
+ const blockTags15 = await context.getConfirmedBlockTags();
973
+ await context.tracker.syncRebalanceActions(blockTags15);
974
+
975
+ for (const action of superseedActions) {
976
+ const completedAction = await context.tracker.getRebalanceAction(
977
+ action.id,
978
+ );
979
+ expect(completedAction!.status).to.equal('complete');
980
+ }
981
+
982
+ // Verify SUBTENSOR actions are still in progress (relay not possible in test env)
983
+ for (const action of subtensorActions) {
984
+ const trackedAction = await context.tracker.getRebalanceAction(action.id);
985
+ expect(trackedAction, `SUBTENSOR action ${action.id} should exist`).to
986
+ .exist;
987
+ expect(trackedAction!.status).to.equal('in_progress');
988
+ }
989
+
990
+ // Relay the original user transfer now that collateral has been rebalanced
991
+ const userTransferRelay = await tryRelayMessage(
992
+ context.multiProvider,
993
+ hyperlaneCore,
994
+ transferResult,
995
+ );
996
+ expect(
997
+ userTransferRelay.success,
998
+ `User transfer relay should succeed: ${userTransferRelay.error}`,
999
+ ).to.be.true;
1000
+
1001
+ const blockTags16 = await context.getConfirmedBlockTags();
1002
+ await context.tracker.syncTransfers(blockTags16);
1003
+ const completedTransfer = await context.tracker.getTransfer(
1004
+ transferResult.messageId,
1005
+ );
1006
+ expect(completedTransfer!.status).to.equal('complete');
1007
+ });
1008
+ });