@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,686 @@
1
+ import { type PopulatedTransaction, type providers } from 'ethers';
2
+ import { type Logger } from 'pino';
3
+
4
+ import {
5
+ type ChainMap,
6
+ type ChainMetadata,
7
+ type ChainName,
8
+ type EthJsonRpcBlockParameterTag,
9
+ EvmMovableCollateralAdapter,
10
+ HyperlaneCore,
11
+ type InterchainGasQuote,
12
+ type MultiProvider,
13
+ type Token,
14
+ type WarpCore,
15
+ } from '@humanode-hyperlane/sdk';
16
+ import { eqAddress, isNullish, mapAllSettled } from '@humanode-hyperlane/utils';
17
+
18
+ import type {
19
+ IMovableCollateralRebalancer,
20
+ MovableCollateralExecutionResult,
21
+ PreparedTransaction,
22
+ RebalancerType,
23
+ } from '../interfaces/IRebalancer.js';
24
+ import { MovableCollateralRoute } from '../interfaces/IStrategy.js';
25
+ import { type Metrics } from '../metrics/Metrics.js';
26
+ import type { IActionTracker } from '../tracking/IActionTracker.js';
27
+ import type { RebalanceIntent } from '../tracking/types.js';
28
+
29
+ // Internal types with intentId for tracking
30
+ type InternalExecutionResult = MovableCollateralExecutionResult & {
31
+ intentId: string;
32
+ };
33
+
34
+ type InternalRoute = MovableCollateralRoute & { intentId: string };
35
+
36
+ export class Rebalancer implements IMovableCollateralRebalancer {
37
+ public readonly rebalancerType: RebalancerType = 'movableCollateral';
38
+ private readonly logger: Logger;
39
+
40
+ constructor(
41
+ private readonly warpCore: WarpCore,
42
+ private readonly chainMetadata: ChainMap<ChainMetadata>,
43
+ private readonly tokensByChainName: ChainMap<Token>,
44
+ private readonly multiProvider: MultiProvider,
45
+ private readonly actionTracker: IActionTracker,
46
+ logger: Logger,
47
+ private readonly metrics?: Metrics,
48
+ ) {
49
+ this.logger = logger.child({ class: Rebalancer.name });
50
+ }
51
+
52
+ async rebalance(
53
+ routes: MovableCollateralRoute[],
54
+ ): Promise<MovableCollateralExecutionResult[]> {
55
+ if (routes.length === 0) {
56
+ this.logger.info('No routes to execute, exiting');
57
+ return [];
58
+ }
59
+
60
+ this.logger.info({ numberOfRoutes: routes.length }, 'Rebalance initiated');
61
+
62
+ const invalidRoutes = routes.filter((r) => !r.bridge);
63
+ if (invalidRoutes.length > 0) {
64
+ this.logger.error(
65
+ { count: invalidRoutes.length },
66
+ 'Routes missing required bridge address',
67
+ );
68
+ return routes.map((r) => ({
69
+ route: r,
70
+ success: false,
71
+ error: r.bridge ? undefined : 'Missing required bridge address',
72
+ messageId: '', // Required by MovableCollateralExecutionResult, empty for validation failures
73
+ }));
74
+ }
75
+
76
+ const intents = await this.createIntents(routes);
77
+
78
+ const internalRoutes: InternalRoute[] = routes.map((route, idx) => ({
79
+ ...route,
80
+ bridge: route.bridge!,
81
+ intentId: intents[idx].id,
82
+ }));
83
+
84
+ const { preparedTransactions, preparationFailureResults } =
85
+ await this.prepareTransactions(internalRoutes);
86
+
87
+ let executionResults: InternalExecutionResult[] = [];
88
+
89
+ if (preparedTransactions.length > 0) {
90
+ executionResults = await this.executeTransactions(preparedTransactions);
91
+ }
92
+
93
+ const allInternalResults = [
94
+ ...preparationFailureResults,
95
+ ...executionResults,
96
+ ];
97
+
98
+ await this.processResults(allInternalResults);
99
+
100
+ const successfulResults = allInternalResults.filter((r) => r.success);
101
+ if (this.metrics && successfulResults.length > 0) {
102
+ for (const result of successfulResults) {
103
+ const token = this.tokensByChainName[result.route.origin];
104
+ if (token) {
105
+ this.metrics.recordRebalanceAmount(
106
+ result.route,
107
+ token.amount(result.route.amount),
108
+ );
109
+ }
110
+ }
111
+ }
112
+
113
+ const failures = allInternalResults.filter((r) => !r.success);
114
+ if (failures.length > 0) {
115
+ this.logger.error(
116
+ { failureCount: failures.length, totalRoutes: routes.length },
117
+ 'Some rebalance operations failed.',
118
+ );
119
+ } else {
120
+ this.logger.info('Rebalance successful');
121
+ }
122
+
123
+ return this.toPublicResults(allInternalResults);
124
+ }
125
+
126
+ private async createIntents(
127
+ routes: MovableCollateralRoute[],
128
+ ): Promise<RebalanceIntent[]> {
129
+ return Promise.all(
130
+ routes.map((route) =>
131
+ this.actionTracker.createRebalanceIntent({
132
+ origin: this.multiProvider.getDomainId(route.origin),
133
+ destination: this.multiProvider.getDomainId(route.destination),
134
+ amount: route.amount,
135
+ bridge: route.bridge,
136
+ executionMethod: 'movable_collateral',
137
+ }),
138
+ ),
139
+ );
140
+ }
141
+
142
+ private async processResults(
143
+ results: InternalExecutionResult[],
144
+ ): Promise<void> {
145
+ for (const result of results) {
146
+ const intentId = result.intentId;
147
+
148
+ if (result.success && result.messageId) {
149
+ await this.actionTracker.createRebalanceAction({
150
+ intentId,
151
+ origin: this.multiProvider.getDomainId(result.route.origin),
152
+ destination: this.multiProvider.getDomainId(result.route.destination),
153
+ amount: result.route.amount,
154
+ type: 'rebalance_message',
155
+ messageId: result.messageId,
156
+ txHash: result.txHash,
157
+ });
158
+
159
+ this.logger.info(
160
+ {
161
+ intentId,
162
+ messageId: result.messageId,
163
+ txHash: result.txHash,
164
+ origin: result.route.origin,
165
+ destination: result.route.destination,
166
+ },
167
+ 'Rebalance action created successfully',
168
+ );
169
+ } else {
170
+ await this.actionTracker.failRebalanceIntent(intentId);
171
+
172
+ this.logger.warn(
173
+ {
174
+ intentId,
175
+ success: result.success,
176
+ error: result.error,
177
+ origin: result.route.origin,
178
+ destination: result.route.destination,
179
+ },
180
+ 'Rebalance intent marked as failed',
181
+ );
182
+ }
183
+ }
184
+ }
185
+
186
+ private toPublicResults(
187
+ internalResults: InternalExecutionResult[],
188
+ ): MovableCollateralExecutionResult[] {
189
+ return internalResults.map((internal) => ({
190
+ route: internal.route,
191
+ success: internal.success,
192
+ error: internal.error,
193
+ messageId: internal.messageId || '', // Ensure messageId is always a string
194
+ txHash: internal.txHash,
195
+ }));
196
+ }
197
+
198
+ private async prepareTransactions(routes: InternalRoute[]): Promise<{
199
+ preparedTransactions: PreparedTransaction[];
200
+ preparationFailureResults: InternalExecutionResult[];
201
+ }> {
202
+ this.logger.info(
203
+ { numRoutes: routes.length },
204
+ 'Preparing all rebalance transactions.',
205
+ );
206
+ const { fulfilled, rejected } = await mapAllSettled(
207
+ routes,
208
+ (route) => this.prepareTransaction(route),
209
+ (_, i) => i,
210
+ );
211
+
212
+ // Filter out null results (validation failures logged internally)
213
+ const preparedTransactions = Array.from(fulfilled.values()).filter(
214
+ (tx): tx is PreparedTransaction => !isNullish(tx),
215
+ );
216
+
217
+ // Create failure results for tracking
218
+ const preparationFailureResults: InternalExecutionResult[] = [];
219
+ for (const [i, error] of rejected) {
220
+ preparationFailureResults.push({
221
+ route: routes[i],
222
+ intentId: routes[i].intentId,
223
+ success: false,
224
+ error: String(error),
225
+ messageId: '', // Required by MovableCollateralExecutionResult, empty for failures
226
+ });
227
+ }
228
+ // Also track null results (validation failures)
229
+ Array.from(fulfilled.entries()).forEach(([i, tx]) => {
230
+ if (isNullish(tx)) {
231
+ preparationFailureResults.push({
232
+ route: routes[i],
233
+ intentId: routes[i].intentId,
234
+ success: false,
235
+ error: 'Preparation returned null',
236
+ messageId: '', // Required by MovableCollateralExecutionResult, empty for failures
237
+ });
238
+ }
239
+ });
240
+
241
+ return { preparedTransactions, preparationFailureResults };
242
+ }
243
+
244
+ private async prepareTransaction(
245
+ route: InternalRoute,
246
+ ): Promise<PreparedTransaction | null> {
247
+ const { origin, destination, amount } = route;
248
+
249
+ this.logger.info(
250
+ {
251
+ origin,
252
+ destination,
253
+ amount,
254
+ },
255
+ 'Preparing transaction for route',
256
+ );
257
+
258
+ // 1. Adapter and permissions validation
259
+ if (!(await this.validateRoute(route))) {
260
+ // Errors logged in validateRoute
261
+ return null;
262
+ }
263
+
264
+ const originToken = this.tokensByChainName[origin];
265
+ const destinationToken = this.tokensByChainName[destination];
266
+ const destinationChainMeta = this.chainMetadata[destination];
267
+
268
+ const originTokenAmount = originToken.amount(amount);
269
+ const decimalFormattedAmount =
270
+ originTokenAmount.getDecimalFormattedAmount();
271
+ const originHypAdapter = originToken.getHypAdapter(
272
+ this.warpCore.multiProvider,
273
+ ) as EvmMovableCollateralAdapter;
274
+
275
+ const { bridge } = route;
276
+
277
+ // 2. Get quotes
278
+ let quotes: InterchainGasQuote[];
279
+ try {
280
+ quotes = await originHypAdapter.getRebalanceQuotes(
281
+ bridge,
282
+ destinationChainMeta.domainId,
283
+ destinationToken.addressOrDenom,
284
+ amount,
285
+ );
286
+ } catch (error) {
287
+ this.logger.error(
288
+ {
289
+ origin,
290
+ destination,
291
+ amount: decimalFormattedAmount,
292
+ tokenName: originToken.name,
293
+ error,
294
+ },
295
+ 'Failed to get quotes for route.',
296
+ );
297
+ return null;
298
+ }
299
+
300
+ // 3. Populate transaction
301
+ let populatedTx: PopulatedTransaction;
302
+ try {
303
+ populatedTx = await originHypAdapter.populateRebalanceTx(
304
+ destinationChainMeta.domainId,
305
+ amount,
306
+ bridge,
307
+ quotes,
308
+ );
309
+ } catch (error) {
310
+ this.logger.error(
311
+ {
312
+ origin,
313
+ destination,
314
+ amount: decimalFormattedAmount,
315
+ tokenName: originToken.name,
316
+ error,
317
+ },
318
+ 'Failed to populate transaction for route.',
319
+ );
320
+ return null;
321
+ }
322
+
323
+ return { populatedTx, route, originTokenAmount };
324
+ }
325
+
326
+ private async validateRoute(route: InternalRoute): Promise<boolean> {
327
+ const { origin, destination, amount } = route;
328
+ const originToken = this.tokensByChainName[origin];
329
+ const destinationToken = this.tokensByChainName[destination];
330
+ const destinationDomain = this.chainMetadata[destination];
331
+
332
+ if (!originToken) {
333
+ this.logger.error(
334
+ { origin, destination, amount },
335
+ 'Route validation failed: origin token not found.',
336
+ );
337
+ return false;
338
+ }
339
+
340
+ const originTokenAmount = originToken.amount(amount);
341
+ const decimalFormattedAmount =
342
+ originTokenAmount.getDecimalFormattedAmount();
343
+
344
+ if (!destinationToken) {
345
+ this.logger.error(
346
+ { origin, destination, amount: decimalFormattedAmount },
347
+ 'Route validation failed: destination token not found.',
348
+ );
349
+ return false;
350
+ }
351
+
352
+ if (!destinationDomain) {
353
+ this.logger.error(
354
+ { origin, destination, amount: decimalFormattedAmount },
355
+ 'Route validation failed: destination domain metadata not found.',
356
+ );
357
+ return false;
358
+ }
359
+
360
+ const originHypAdapter = originToken.getHypAdapter(
361
+ this.warpCore.multiProvider,
362
+ );
363
+ if (!(originHypAdapter instanceof EvmMovableCollateralAdapter)) {
364
+ this.logger.error(
365
+ {
366
+ origin,
367
+ destination,
368
+ amount: decimalFormattedAmount,
369
+ tokenName: originToken.name,
370
+ },
371
+ 'Route validation failed: Origin TokenAdapter is not an EvmHypCollateralAdapter.',
372
+ );
373
+ return false;
374
+ }
375
+
376
+ const signer = this.multiProvider.getSigner(origin);
377
+ const signerAddress = await signer.getAddress();
378
+ if (!(await originHypAdapter.isRebalancer(signerAddress))) {
379
+ this.logger.error(
380
+ {
381
+ origin,
382
+ destination,
383
+ amount: decimalFormattedAmount,
384
+ tokenName: originToken.name,
385
+ tokenAddress: originToken.addressOrDenom,
386
+ signerAddress,
387
+ },
388
+ 'Route validation failed: Signer is not a rebalancer.',
389
+ );
390
+ return false;
391
+ }
392
+
393
+ const allowedDestination = await originHypAdapter.getAllowedDestination(
394
+ destinationDomain.domainId,
395
+ );
396
+ if (!eqAddress(allowedDestination, destinationToken.addressOrDenom)) {
397
+ this.logger.error(
398
+ {
399
+ origin,
400
+ destination,
401
+ amount: decimalFormattedAmount,
402
+ tokenName: originToken.name,
403
+ tokenAddress: originToken.addressOrDenom,
404
+ destinationTokenAddress: destinationToken.addressOrDenom,
405
+ allowedDestinationTokenAddress: allowedDestination,
406
+ },
407
+ 'Route validation failed: Destination is not allowed.',
408
+ );
409
+ return false;
410
+ }
411
+
412
+ const { bridge } = route;
413
+
414
+ if (
415
+ !(await originHypAdapter.isBridgeAllowed(
416
+ destinationDomain.domainId,
417
+ bridge,
418
+ ))
419
+ ) {
420
+ this.logger.error(
421
+ {
422
+ origin,
423
+ destination,
424
+ amount: decimalFormattedAmount,
425
+ tokenName: originToken.name,
426
+ tokenAddress: originToken.addressOrDenom,
427
+ bridgeAddress: bridge,
428
+ },
429
+ 'Route validation failed: Bridge is not allowed.',
430
+ );
431
+ return false;
432
+ }
433
+
434
+ return true;
435
+ }
436
+
437
+ private async executeTransactions(
438
+ transactions: PreparedTransaction[],
439
+ ): Promise<InternalExecutionResult[]> {
440
+ this.logger.info(
441
+ { numTransactions: transactions.length },
442
+ 'Estimating gas for all prepared transactions.',
443
+ );
444
+
445
+ const results: InternalExecutionResult[] = [];
446
+
447
+ // 1. Estimate gas for rebalance transactions
448
+ const gasEstimateResults = await Promise.allSettled(
449
+ transactions.map(async (transaction) => {
450
+ await this.multiProvider.estimateGas(
451
+ transaction.route.origin,
452
+ transaction.populatedTx,
453
+ );
454
+ return transaction;
455
+ }),
456
+ );
457
+
458
+ // 2. Filter out failed transactions and track failures
459
+ const validTransactions: PreparedTransaction[] = [];
460
+ gasEstimateResults.forEach((result, i) => {
461
+ if (result.status === 'fulfilled') {
462
+ validTransactions.push(result.value);
463
+ } else {
464
+ const failedTransaction = transactions[i];
465
+ this.logger.error(
466
+ {
467
+ origin: failedTransaction.route.origin,
468
+ destination: failedTransaction.route.destination,
469
+ amount:
470
+ failedTransaction.originTokenAmount.getDecimalFormattedAmount(),
471
+ tokenName: failedTransaction.originTokenAmount.token.name,
472
+ error: result.reason,
473
+ },
474
+ 'Gas estimation failed for route.',
475
+ );
476
+ results.push({
477
+ route: failedTransaction.route,
478
+ intentId: failedTransaction.route.intentId,
479
+ success: false,
480
+ error: `Gas estimation failed: ${String(result.reason)}`,
481
+ messageId: '', // Required by MovableCollateralExecutionResult, empty for failures
482
+ });
483
+ }
484
+ });
485
+
486
+ if (validTransactions.length === 0) {
487
+ this.logger.info('No transactions to execute after gas estimation.');
488
+ return results;
489
+ }
490
+
491
+ // 3. Group transactions by origin chain
492
+ const txsByOrigin = new Map<ChainName, PreparedTransaction[]>();
493
+ for (const tx of validTransactions) {
494
+ const origin = tx.route.origin;
495
+ if (!txsByOrigin.has(origin)) {
496
+ txsByOrigin.set(origin, []);
497
+ }
498
+ txsByOrigin.get(origin)!.push(tx);
499
+ }
500
+
501
+ // 4. Send transactions - parallel across chains, sequential within each chain
502
+ this.logger.info(
503
+ {
504
+ numChains: txsByOrigin.size,
505
+ numTransactions: validTransactions.length,
506
+ },
507
+ 'Sending transactions (parallel across chains, sequential within chain).',
508
+ );
509
+
510
+ const chainSendResults = await Promise.allSettled(
511
+ Array.from(txsByOrigin.entries()).map(([origin, txs]) =>
512
+ this.sendTransactionsForChain(origin, txs),
513
+ ),
514
+ );
515
+
516
+ // 5. Collect successful sends and record send failures
517
+ const successfulSends: Array<{
518
+ transaction: PreparedTransaction;
519
+ receipt: providers.TransactionReceipt;
520
+ }> = [];
521
+
522
+ chainSendResults.forEach((chainResult) => {
523
+ if (chainResult.status === 'fulfilled') {
524
+ for (const txResult of chainResult.value) {
525
+ if ('receipt' in txResult) {
526
+ successfulSends.push(txResult);
527
+ } else {
528
+ results.push({
529
+ route: txResult.transaction.route,
530
+ intentId: txResult.transaction.route.intentId,
531
+ success: false,
532
+ error: `Transaction send failed: ${txResult.error}`,
533
+ messageId: '', // Required by MovableCollateralExecutionResult, empty for failures
534
+ });
535
+ this.metrics?.recordActionAttempt(
536
+ txResult.transaction.route,
537
+ false,
538
+ );
539
+ }
540
+ }
541
+ } else {
542
+ // This shouldn't happen since sendTransactionsForChain catches errors internally,
543
+ // but handle it just in case
544
+ this.logger.error(
545
+ { error: chainResult.reason },
546
+ 'Unexpected error during chain transaction sending.',
547
+ );
548
+ }
549
+ });
550
+
551
+ // 6. Build results from confirmed receipts
552
+ for (const { transaction, receipt } of successfulSends) {
553
+ const result = this.buildResult(transaction, receipt);
554
+ results.push(result);
555
+ this.metrics?.recordActionAttempt(result.route, result.success);
556
+ }
557
+
558
+ return results;
559
+ }
560
+
561
+ // === Parallel Transaction Sending Methods ===
562
+
563
+ /**
564
+ * Send all transactions for a single origin chain sequentially.
565
+ * Sequential sending is required to avoid nonce contention when using the same signing key.
566
+ */
567
+ private async sendTransactionsForChain(
568
+ origin: ChainName,
569
+ transactions: PreparedTransaction[],
570
+ ): Promise<
571
+ Array<
572
+ | {
573
+ transaction: PreparedTransaction;
574
+ receipt: providers.TransactionReceipt;
575
+ }
576
+ | { transaction: PreparedTransaction; error: string }
577
+ >
578
+ > {
579
+ const results: Array<
580
+ | {
581
+ transaction: PreparedTransaction;
582
+ receipt: providers.TransactionReceipt;
583
+ }
584
+ | { transaction: PreparedTransaction; error: string }
585
+ > = [];
586
+
587
+ // Send sequentially to avoid nonce contention
588
+ for (const transaction of transactions) {
589
+ try {
590
+ const decimalFormattedAmount =
591
+ transaction.originTokenAmount.getDecimalFormattedAmount();
592
+ const tokenName = transaction.originTokenAmount.token.name;
593
+
594
+ const reorgPeriod = this.getReorgPeriod(origin);
595
+
596
+ this.logger.info(
597
+ {
598
+ origin,
599
+ destination: transaction.route.destination,
600
+ amount: decimalFormattedAmount,
601
+ tokenName,
602
+ reorgPeriod,
603
+ },
604
+ 'Sending rebalance transaction and waiting for reorgPeriod confirmations.',
605
+ );
606
+
607
+ const receipt = await this.multiProvider.sendTransaction(
608
+ origin,
609
+ transaction.populatedTx,
610
+ {
611
+ waitConfirmations: reorgPeriod as
612
+ | number
613
+ | EthJsonRpcBlockParameterTag,
614
+ },
615
+ );
616
+
617
+ this.logger.info(
618
+ {
619
+ origin,
620
+ destination: transaction.route.destination,
621
+ amount: decimalFormattedAmount,
622
+ tokenName,
623
+ txHash: receipt.transactionHash,
624
+ },
625
+ 'Rebalance transaction confirmed at reorgPeriod depth.',
626
+ );
627
+
628
+ results.push({ transaction, receipt });
629
+ } catch (error) {
630
+ this.logger.error(
631
+ {
632
+ origin,
633
+ destination: transaction.route.destination,
634
+ amount: transaction.originTokenAmount.getDecimalFormattedAmount(),
635
+ tokenName: transaction.originTokenAmount.token.name,
636
+ error,
637
+ },
638
+ 'Transaction send failed for route.',
639
+ );
640
+ results.push({ transaction, error: String(error) });
641
+ }
642
+ }
643
+
644
+ return results;
645
+ }
646
+
647
+ /**
648
+ * Build the execution result from a confirmed transaction receipt.
649
+ * Receipt is already confirmed at reorgPeriod depth from sendTransaction.
650
+ */
651
+ private buildResult(
652
+ transaction: PreparedTransaction,
653
+ receipt: providers.TransactionReceipt,
654
+ ): InternalExecutionResult {
655
+ const { origin, destination } = transaction.route;
656
+ const dispatchedMessages = HyperlaneCore.getDispatchedMessages(receipt);
657
+
658
+ if (dispatchedMessages.length === 0) {
659
+ this.logger.error(
660
+ { origin, destination, txHash: receipt.transactionHash },
661
+ 'No Dispatch event found in confirmed rebalance receipt',
662
+ );
663
+ return {
664
+ route: transaction.route,
665
+ intentId: transaction.route.intentId,
666
+ success: false,
667
+ error: `Transaction confirmed but no Dispatch event found`,
668
+ messageId: '', // Required by MovableCollateralExecutionResult, empty for failures
669
+ txHash: receipt.transactionHash,
670
+ };
671
+ }
672
+
673
+ return {
674
+ route: transaction.route,
675
+ intentId: transaction.route.intentId,
676
+ success: true,
677
+ messageId: dispatchedMessages[0].id,
678
+ txHash: receipt.transactionHash,
679
+ };
680
+ }
681
+
682
+ private getReorgPeriod(chainName: string): number | string {
683
+ const metadata = this.multiProvider.getChainMetadata(chainName);
684
+ return metadata.blocks?.reorgPeriod ?? 32;
685
+ }
686
+ }