@humanode-hyperlane/rebalancer 0.0.0-stage → 27.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (439) hide show
  1. package/LICENSE.md +193 -0
  2. package/README.md +297 -2
  3. package/dist/bridges/LiFiBridge.d.ts +93 -0
  4. package/dist/bridges/LiFiBridge.d.ts.map +1 -0
  5. package/dist/bridges/LiFiBridge.js +527 -0
  6. package/dist/bridges/LiFiBridge.js.map +1 -0
  7. package/dist/bridges/LiFiBridge.test.d.ts +2 -0
  8. package/dist/bridges/LiFiBridge.test.d.ts.map +1 -0
  9. package/dist/bridges/LiFiBridge.test.js +504 -0
  10. package/dist/bridges/LiFiBridge.test.js.map +1 -0
  11. package/dist/config/RebalancerConfig.d.ts +20 -0
  12. package/dist/config/RebalancerConfig.d.ts.map +1 -0
  13. package/dist/config/RebalancerConfig.js +35 -0
  14. package/dist/config/RebalancerConfig.js.map +1 -0
  15. package/dist/config/RebalancerConfig.test.d.ts +2 -0
  16. package/dist/config/RebalancerConfig.test.d.ts.map +1 -0
  17. package/dist/config/RebalancerConfig.test.js +798 -0
  18. package/dist/config/RebalancerConfig.test.js.map +1 -0
  19. package/dist/config/types.d.ts +3008 -0
  20. package/dist/config/types.d.ts.map +1 -0
  21. package/dist/config/types.js +451 -0
  22. package/dist/config/types.js.map +1 -0
  23. package/dist/core/InventoryRebalancer.d.ts +201 -0
  24. package/dist/core/InventoryRebalancer.d.ts.map +1 -0
  25. package/dist/core/InventoryRebalancer.js +994 -0
  26. package/dist/core/InventoryRebalancer.js.map +1 -0
  27. package/dist/core/InventoryRebalancer.test.d.ts +2 -0
  28. package/dist/core/InventoryRebalancer.test.d.ts.map +1 -0
  29. package/dist/core/InventoryRebalancer.test.js +1511 -0
  30. package/dist/core/InventoryRebalancer.test.js.map +1 -0
  31. package/dist/core/Rebalancer.d.ts +37 -0
  32. package/dist/core/Rebalancer.d.ts.map +1 -0
  33. package/dist/core/Rebalancer.js +433 -0
  34. package/dist/core/Rebalancer.js.map +1 -0
  35. package/dist/core/Rebalancer.test.d.ts +2 -0
  36. package/dist/core/Rebalancer.test.d.ts.map +1 -0
  37. package/dist/core/Rebalancer.test.js +424 -0
  38. package/dist/core/Rebalancer.test.js.map +1 -0
  39. package/dist/core/RebalancerOrchestrator.d.ts +56 -0
  40. package/dist/core/RebalancerOrchestrator.d.ts.map +1 -0
  41. package/dist/core/RebalancerOrchestrator.js +154 -0
  42. package/dist/core/RebalancerOrchestrator.js.map +1 -0
  43. package/dist/core/RebalancerOrchestrator.test.d.ts +2 -0
  44. package/dist/core/RebalancerOrchestrator.test.d.ts.map +1 -0
  45. package/dist/core/RebalancerOrchestrator.test.js +721 -0
  46. package/dist/core/RebalancerOrchestrator.test.js.map +1 -0
  47. package/dist/core/RebalancerService.d.ts +127 -0
  48. package/dist/core/RebalancerService.d.ts.map +1 -0
  49. package/dist/core/RebalancerService.js +270 -0
  50. package/dist/core/RebalancerService.js.map +1 -0
  51. package/dist/core/RebalancerService.test.d.ts +2 -0
  52. package/dist/core/RebalancerService.test.d.ts.map +1 -0
  53. package/dist/core/RebalancerService.test.js +777 -0
  54. package/dist/core/RebalancerService.test.js.map +1 -0
  55. package/dist/e2e/collateral-deficit.e2e-test.d.ts +2 -0
  56. package/dist/e2e/collateral-deficit.e2e-test.d.ts.map +1 -0
  57. package/dist/e2e/collateral-deficit.e2e-test.js +227 -0
  58. package/dist/e2e/collateral-deficit.e2e-test.js.map +1 -0
  59. package/dist/e2e/composite.e2e-test.d.ts +2 -0
  60. package/dist/e2e/composite.e2e-test.d.ts.map +1 -0
  61. package/dist/e2e/composite.e2e-test.js +666 -0
  62. package/dist/e2e/composite.e2e-test.js.map +1 -0
  63. package/dist/e2e/fixtures/routes.d.ts +89 -0
  64. package/dist/e2e/fixtures/routes.d.ts.map +1 -0
  65. package/dist/e2e/fixtures/routes.js +420 -0
  66. package/dist/e2e/fixtures/routes.js.map +1 -0
  67. package/dist/e2e/harness/BaseLocalDeploymentManager.d.ts +38 -0
  68. package/dist/e2e/harness/BaseLocalDeploymentManager.d.ts.map +1 -0
  69. package/dist/e2e/harness/BaseLocalDeploymentManager.js +144 -0
  70. package/dist/e2e/harness/BaseLocalDeploymentManager.js.map +1 -0
  71. package/dist/e2e/harness/BridgeSetup.d.ts +11 -0
  72. package/dist/e2e/harness/BridgeSetup.d.ts.map +1 -0
  73. package/dist/e2e/harness/BridgeSetup.js +50 -0
  74. package/dist/e2e/harness/BridgeSetup.js.map +1 -0
  75. package/dist/e2e/harness/Erc20InventoryLocalDeploymentManager.d.ts +13 -0
  76. package/dist/e2e/harness/Erc20InventoryLocalDeploymentManager.d.ts.map +1 -0
  77. package/dist/e2e/harness/Erc20InventoryLocalDeploymentManager.js +105 -0
  78. package/dist/e2e/harness/Erc20InventoryLocalDeploymentManager.js.map +1 -0
  79. package/dist/e2e/harness/Erc20LocalDeploymentManager.d.ts +11 -0
  80. package/dist/e2e/harness/Erc20LocalDeploymentManager.d.ts.map +1 -0
  81. package/dist/e2e/harness/Erc20LocalDeploymentManager.js +105 -0
  82. package/dist/e2e/harness/Erc20LocalDeploymentManager.js.map +1 -0
  83. package/dist/e2e/harness/ForkIndexer.d.ts +23 -0
  84. package/dist/e2e/harness/ForkIndexer.d.ts.map +1 -0
  85. package/dist/e2e/harness/ForkIndexer.js +127 -0
  86. package/dist/e2e/harness/ForkIndexer.js.map +1 -0
  87. package/dist/e2e/harness/ForkIndexer.test.d.ts +2 -0
  88. package/dist/e2e/harness/ForkIndexer.test.d.ts.map +1 -0
  89. package/dist/e2e/harness/ForkIndexer.test.js +257 -0
  90. package/dist/e2e/harness/ForkIndexer.test.js.map +1 -0
  91. package/dist/e2e/harness/MixedLocalDeploymentManager.d.ts +21 -0
  92. package/dist/e2e/harness/MixedLocalDeploymentManager.d.ts.map +1 -0
  93. package/dist/e2e/harness/MixedLocalDeploymentManager.js +115 -0
  94. package/dist/e2e/harness/MixedLocalDeploymentManager.js.map +1 -0
  95. package/dist/e2e/harness/MockExplorerClient.d.ts +23 -0
  96. package/dist/e2e/harness/MockExplorerClient.d.ts.map +1 -0
  97. package/dist/e2e/harness/MockExplorerClient.js +57 -0
  98. package/dist/e2e/harness/MockExplorerClient.js.map +1 -0
  99. package/dist/e2e/harness/MockExternalBridge.d.ts +32 -0
  100. package/dist/e2e/harness/MockExternalBridge.d.ts.map +1 -0
  101. package/dist/e2e/harness/MockExternalBridge.js +247 -0
  102. package/dist/e2e/harness/MockExternalBridge.js.map +1 -0
  103. package/dist/e2e/harness/NativeLocalDeploymentManager.d.ts +13 -0
  104. package/dist/e2e/harness/NativeLocalDeploymentManager.d.ts.map +1 -0
  105. package/dist/e2e/harness/NativeLocalDeploymentManager.js +91 -0
  106. package/dist/e2e/harness/NativeLocalDeploymentManager.js.map +1 -0
  107. package/dist/e2e/harness/SnapshotHelper.d.ts +13 -0
  108. package/dist/e2e/harness/SnapshotHelper.d.ts.map +1 -0
  109. package/dist/e2e/harness/SnapshotHelper.js +36 -0
  110. package/dist/e2e/harness/SnapshotHelper.js.map +1 -0
  111. package/dist/e2e/harness/TestHelpers.d.ts +25 -0
  112. package/dist/e2e/harness/TestHelpers.d.ts.map +1 -0
  113. package/dist/e2e/harness/TestHelpers.js +103 -0
  114. package/dist/e2e/harness/TestHelpers.js.map +1 -0
  115. package/dist/e2e/harness/TestRebalancer.d.ts +85 -0
  116. package/dist/e2e/harness/TestRebalancer.d.ts.map +1 -0
  117. package/dist/e2e/harness/TestRebalancer.js +427 -0
  118. package/dist/e2e/harness/TestRebalancer.js.map +1 -0
  119. package/dist/e2e/harness/TransferHelper.d.ts +34 -0
  120. package/dist/e2e/harness/TransferHelper.d.ts.map +1 -0
  121. package/dist/e2e/harness/TransferHelper.js +93 -0
  122. package/dist/e2e/harness/TransferHelper.js.map +1 -0
  123. package/dist/e2e/inventory-erc20-minAmount.e2e-test.d.ts +2 -0
  124. package/dist/e2e/inventory-erc20-minAmount.e2e-test.d.ts.map +1 -0
  125. package/dist/e2e/inventory-erc20-minAmount.e2e-test.js +411 -0
  126. package/dist/e2e/inventory-erc20-minAmount.e2e-test.js.map +1 -0
  127. package/dist/e2e/inventory-erc20-weighted.e2e-test.d.ts +2 -0
  128. package/dist/e2e/inventory-erc20-weighted.e2e-test.d.ts.map +1 -0
  129. package/dist/e2e/inventory-erc20-weighted.e2e-test.js +408 -0
  130. package/dist/e2e/inventory-erc20-weighted.e2e-test.js.map +1 -0
  131. package/dist/e2e/inventory-minAmount.e2e-test.d.ts +2 -0
  132. package/dist/e2e/inventory-minAmount.e2e-test.d.ts.map +1 -0
  133. package/dist/e2e/inventory-minAmount.e2e-test.js +411 -0
  134. package/dist/e2e/inventory-minAmount.e2e-test.js.map +1 -0
  135. package/dist/e2e/inventory-weighted.e2e-test.d.ts +2 -0
  136. package/dist/e2e/inventory-weighted.e2e-test.d.ts.map +1 -0
  137. package/dist/e2e/inventory-weighted.e2e-test.js +409 -0
  138. package/dist/e2e/inventory-weighted.e2e-test.js.map +1 -0
  139. package/dist/e2e/minAmount.e2e-test.d.ts +2 -0
  140. package/dist/e2e/minAmount.e2e-test.d.ts.map +1 -0
  141. package/dist/e2e/minAmount.e2e-test.js +203 -0
  142. package/dist/e2e/minAmount.e2e-test.js.map +1 -0
  143. package/dist/e2e/mixed-weighted.e2e-test.d.ts +2 -0
  144. package/dist/e2e/mixed-weighted.e2e-test.d.ts.map +1 -0
  145. package/dist/e2e/mixed-weighted.e2e-test.js +189 -0
  146. package/dist/e2e/mixed-weighted.e2e-test.js.map +1 -0
  147. package/dist/e2e/weighted.e2e-test.d.ts +2 -0
  148. package/dist/e2e/weighted.e2e-test.d.ts.map +1 -0
  149. package/dist/e2e/weighted.e2e-test.js +198 -0
  150. package/dist/e2e/weighted.e2e-test.js.map +1 -0
  151. package/dist/factories/RebalancerContextFactory.d.ts +89 -0
  152. package/dist/factories/RebalancerContextFactory.d.ts.map +1 -0
  153. package/dist/factories/RebalancerContextFactory.js +420 -0
  154. package/dist/factories/RebalancerContextFactory.js.map +1 -0
  155. package/dist/factories/RebalancerContextFactory.test.d.ts +2 -0
  156. package/dist/factories/RebalancerContextFactory.test.d.ts.map +1 -0
  157. package/dist/factories/RebalancerContextFactory.test.js +270 -0
  158. package/dist/factories/RebalancerContextFactory.test.js.map +1 -0
  159. package/dist/index.d.ts +37 -0
  160. package/dist/index.d.ts.map +1 -0
  161. package/dist/index.js +37 -0
  162. package/dist/index.js.map +1 -0
  163. package/dist/interfaces/IExternalBridge.d.ts +103 -0
  164. package/dist/interfaces/IExternalBridge.d.ts.map +1 -0
  165. package/dist/interfaces/IExternalBridge.js +2 -0
  166. package/dist/interfaces/IExternalBridge.js.map +1 -0
  167. package/dist/interfaces/IMetrics.d.ts +5 -0
  168. package/dist/interfaces/IMetrics.d.ts.map +1 -0
  169. package/dist/interfaces/IMetrics.js +2 -0
  170. package/dist/interfaces/IMetrics.js.map +1 -0
  171. package/dist/interfaces/IMonitor.d.ts +50 -0
  172. package/dist/interfaces/IMonitor.d.ts.map +1 -0
  173. package/dist/interfaces/IMonitor.js +14 -0
  174. package/dist/interfaces/IMonitor.js.map +1 -0
  175. package/dist/interfaces/IRebalancer.d.ts +31 -0
  176. package/dist/interfaces/IRebalancer.d.ts.map +1 -0
  177. package/dist/interfaces/IRebalancer.js +2 -0
  178. package/dist/interfaces/IRebalancer.js.map +1 -0
  179. package/dist/interfaces/IStrategy.d.ts +60 -0
  180. package/dist/interfaces/IStrategy.d.ts.map +1 -0
  181. package/dist/interfaces/IStrategy.js +13 -0
  182. package/dist/interfaces/IStrategy.js.map +1 -0
  183. package/dist/metrics/Metrics.d.ts +25 -0
  184. package/dist/metrics/Metrics.d.ts.map +1 -0
  185. package/dist/metrics/Metrics.js +164 -0
  186. package/dist/metrics/Metrics.js.map +1 -0
  187. package/dist/metrics/PriceGetter.d.ts +10 -0
  188. package/dist/metrics/PriceGetter.d.ts.map +1 -0
  189. package/dist/metrics/PriceGetter.js +41 -0
  190. package/dist/metrics/PriceGetter.js.map +1 -0
  191. package/dist/metrics/scripts/metrics.d.ts +28 -0
  192. package/dist/metrics/scripts/metrics.d.ts.map +1 -0
  193. package/dist/metrics/scripts/metrics.js +61 -0
  194. package/dist/metrics/scripts/metrics.js.map +1 -0
  195. package/dist/monitor/Monitor.d.ts +40 -0
  196. package/dist/monitor/Monitor.d.ts.map +1 -0
  197. package/dist/monitor/Monitor.js +211 -0
  198. package/dist/monitor/Monitor.js.map +1 -0
  199. package/dist/service.d.ts +3 -0
  200. package/dist/service.d.ts.map +1 -0
  201. package/dist/service.js +205 -0
  202. package/dist/service.js.map +1 -0
  203. package/dist/strategy/BaseStrategy.d.ts +86 -0
  204. package/dist/strategy/BaseStrategy.d.ts.map +1 -0
  205. package/dist/strategy/BaseStrategy.js +342 -0
  206. package/dist/strategy/BaseStrategy.js.map +1 -0
  207. package/dist/strategy/CollateralDeficitStrategy.d.ts +65 -0
  208. package/dist/strategy/CollateralDeficitStrategy.d.ts.map +1 -0
  209. package/dist/strategy/CollateralDeficitStrategy.js +253 -0
  210. package/dist/strategy/CollateralDeficitStrategy.js.map +1 -0
  211. package/dist/strategy/CollateralDeficitStrategy.test.d.ts +2 -0
  212. package/dist/strategy/CollateralDeficitStrategy.test.d.ts.map +1 -0
  213. package/dist/strategy/CollateralDeficitStrategy.test.js +497 -0
  214. package/dist/strategy/CollateralDeficitStrategy.test.js.map +1 -0
  215. package/dist/strategy/CompositeStrategy.d.ts +18 -0
  216. package/dist/strategy/CompositeStrategy.d.ts.map +1 -0
  217. package/dist/strategy/CompositeStrategy.js +63 -0
  218. package/dist/strategy/CompositeStrategy.js.map +1 -0
  219. package/dist/strategy/CompositeStrategy.test.d.ts +2 -0
  220. package/dist/strategy/CompositeStrategy.test.d.ts.map +1 -0
  221. package/dist/strategy/CompositeStrategy.test.js +278 -0
  222. package/dist/strategy/CompositeStrategy.test.js.map +1 -0
  223. package/dist/strategy/MinAmountStrategy.d.ts +35 -0
  224. package/dist/strategy/MinAmountStrategy.d.ts.map +1 -0
  225. package/dist/strategy/MinAmountStrategy.js +112 -0
  226. package/dist/strategy/MinAmountStrategy.js.map +1 -0
  227. package/dist/strategy/MinAmountStrategy.test.d.ts +2 -0
  228. package/dist/strategy/MinAmountStrategy.test.d.ts.map +1 -0
  229. package/dist/strategy/MinAmountStrategy.test.js +547 -0
  230. package/dist/strategy/MinAmountStrategy.test.js.map +1 -0
  231. package/dist/strategy/StrategyFactory.d.ts +27 -0
  232. package/dist/strategy/StrategyFactory.d.ts.map +1 -0
  233. package/dist/strategy/StrategyFactory.js +79 -0
  234. package/dist/strategy/StrategyFactory.js.map +1 -0
  235. package/dist/strategy/StrategyFactory.test.d.ts +2 -0
  236. package/dist/strategy/StrategyFactory.test.d.ts.map +1 -0
  237. package/dist/strategy/StrategyFactory.test.js +81 -0
  238. package/dist/strategy/StrategyFactory.test.js.map +1 -0
  239. package/dist/strategy/WeightedStrategy.d.ts +32 -0
  240. package/dist/strategy/WeightedStrategy.d.ts.map +1 -0
  241. package/dist/strategy/WeightedStrategy.js +73 -0
  242. package/dist/strategy/WeightedStrategy.js.map +1 -0
  243. package/dist/strategy/WeightedStrategy.test.d.ts +2 -0
  244. package/dist/strategy/WeightedStrategy.test.d.ts.map +1 -0
  245. package/dist/strategy/WeightedStrategy.test.js +403 -0
  246. package/dist/strategy/WeightedStrategy.test.js.map +1 -0
  247. package/dist/strategy/index.d.ts +7 -0
  248. package/dist/strategy/index.d.ts.map +1 -0
  249. package/dist/strategy/index.js +7 -0
  250. package/dist/strategy/index.js.map +1 -0
  251. package/dist/test/helpers.d.ts +99 -0
  252. package/dist/test/helpers.d.ts.map +1 -0
  253. package/dist/test/helpers.js +311 -0
  254. package/dist/test/helpers.js.map +1 -0
  255. package/dist/test/lifiMocks.d.ts +52 -0
  256. package/dist/test/lifiMocks.d.ts.map +1 -0
  257. package/dist/test/lifiMocks.js +160 -0
  258. package/dist/test/lifiMocks.js.map +1 -0
  259. package/dist/tracking/ActionTracker.d.ts +90 -0
  260. package/dist/tracking/ActionTracker.d.ts.map +1 -0
  261. package/dist/tracking/ActionTracker.js +678 -0
  262. package/dist/tracking/ActionTracker.js.map +1 -0
  263. package/dist/tracking/ActionTracker.test.d.ts +2 -0
  264. package/dist/tracking/ActionTracker.test.d.ts.map +1 -0
  265. package/dist/tracking/ActionTracker.test.js +1351 -0
  266. package/dist/tracking/ActionTracker.test.js.map +1 -0
  267. package/dist/tracking/IActionTracker.d.ts +157 -0
  268. package/dist/tracking/IActionTracker.d.ts.map +1 -0
  269. package/dist/tracking/IActionTracker.js +2 -0
  270. package/dist/tracking/IActionTracker.js.map +1 -0
  271. package/dist/tracking/InflightContextAdapter.d.ts +18 -0
  272. package/dist/tracking/InflightContextAdapter.d.ts.map +1 -0
  273. package/dist/tracking/InflightContextAdapter.js +52 -0
  274. package/dist/tracking/InflightContextAdapter.js.map +1 -0
  275. package/dist/tracking/InflightContextAdapter.test.d.ts +2 -0
  276. package/dist/tracking/InflightContextAdapter.test.d.ts.map +1 -0
  277. package/dist/tracking/InflightContextAdapter.test.js +175 -0
  278. package/dist/tracking/InflightContextAdapter.test.js.map +1 -0
  279. package/dist/tracking/store/IStore.d.ts +41 -0
  280. package/dist/tracking/store/IStore.d.ts.map +1 -0
  281. package/dist/tracking/store/IStore.js +2 -0
  282. package/dist/tracking/store/IStore.js.map +1 -0
  283. package/dist/tracking/store/InMemoryStore.d.ts +21 -0
  284. package/dist/tracking/store/InMemoryStore.d.ts.map +1 -0
  285. package/dist/tracking/store/InMemoryStore.js +40 -0
  286. package/dist/tracking/store/InMemoryStore.js.map +1 -0
  287. package/dist/tracking/store/InMemoryStore.test.d.ts +2 -0
  288. package/dist/tracking/store/InMemoryStore.test.d.ts.map +1 -0
  289. package/dist/tracking/store/InMemoryStore.test.js +290 -0
  290. package/dist/tracking/store/InMemoryStore.test.js.map +1 -0
  291. package/dist/tracking/store/index.d.ts +3 -0
  292. package/dist/tracking/store/index.d.ts.map +1 -0
  293. package/dist/tracking/store/index.js +2 -0
  294. package/dist/tracking/store/index.js.map +1 -0
  295. package/dist/tracking/types.d.ts +77 -0
  296. package/dist/tracking/types.d.ts.map +1 -0
  297. package/dist/tracking/types.js +2 -0
  298. package/dist/tracking/types.js.map +1 -0
  299. package/dist/utils/ExplorerClient.d.ts +68 -0
  300. package/dist/utils/ExplorerClient.d.ts.map +1 -0
  301. package/dist/utils/ExplorerClient.js +324 -0
  302. package/dist/utils/ExplorerClient.js.map +1 -0
  303. package/dist/utils/ExplorerClient.test.d.ts +2 -0
  304. package/dist/utils/ExplorerClient.test.d.ts.map +1 -0
  305. package/dist/utils/ExplorerClient.test.js +261 -0
  306. package/dist/utils/ExplorerClient.test.js.map +1 -0
  307. package/dist/utils/balanceUtils.d.ts +12 -0
  308. package/dist/utils/balanceUtils.d.ts.map +1 -0
  309. package/dist/utils/balanceUtils.js +40 -0
  310. package/dist/utils/balanceUtils.js.map +1 -0
  311. package/dist/utils/balanceUtils.test.d.ts +2 -0
  312. package/dist/utils/balanceUtils.test.d.ts.map +1 -0
  313. package/dist/utils/balanceUtils.test.js +55 -0
  314. package/dist/utils/balanceUtils.test.js.map +1 -0
  315. package/dist/utils/blockTag.d.ts +14 -0
  316. package/dist/utils/blockTag.d.ts.map +1 -0
  317. package/dist/utils/blockTag.js +46 -0
  318. package/dist/utils/blockTag.js.map +1 -0
  319. package/dist/utils/bridgeUtils.d.ts +40 -0
  320. package/dist/utils/bridgeUtils.d.ts.map +1 -0
  321. package/dist/utils/bridgeUtils.js +54 -0
  322. package/dist/utils/bridgeUtils.js.map +1 -0
  323. package/dist/utils/bridgeUtils.test.d.ts +2 -0
  324. package/dist/utils/bridgeUtils.test.d.ts.map +1 -0
  325. package/dist/utils/bridgeUtils.test.js +163 -0
  326. package/dist/utils/bridgeUtils.test.js.map +1 -0
  327. package/dist/utils/errors.d.ts +4 -0
  328. package/dist/utils/errors.d.ts.map +1 -0
  329. package/dist/utils/errors.js +6 -0
  330. package/dist/utils/errors.js.map +1 -0
  331. package/dist/utils/gasEstimation.d.ts +65 -0
  332. package/dist/utils/gasEstimation.d.ts.map +1 -0
  333. package/dist/utils/gasEstimation.js +206 -0
  334. package/dist/utils/gasEstimation.js.map +1 -0
  335. package/dist/utils/solanaKeyParser.d.ts +10 -0
  336. package/dist/utils/solanaKeyParser.d.ts.map +1 -0
  337. package/dist/utils/solanaKeyParser.js +87 -0
  338. package/dist/utils/solanaKeyParser.js.map +1 -0
  339. package/dist/utils/solanaKeyParser.test.d.ts +2 -0
  340. package/dist/utils/solanaKeyParser.test.d.ts.map +1 -0
  341. package/dist/utils/solanaKeyParser.test.js +71 -0
  342. package/dist/utils/solanaKeyParser.test.js.map +1 -0
  343. package/dist/utils/tokenUtils.d.ts +38 -0
  344. package/dist/utils/tokenUtils.d.ts.map +1 -0
  345. package/dist/utils/tokenUtils.js +65 -0
  346. package/dist/utils/tokenUtils.js.map +1 -0
  347. package/dist/utils/transactionUtils.d.ts +22 -0
  348. package/dist/utils/transactionUtils.d.ts.map +1 -0
  349. package/dist/utils/transactionUtils.js +26 -0
  350. package/dist/utils/transactionUtils.js.map +1 -0
  351. package/package.json +87 -3
  352. package/src/bridges/LiFiBridge.test.ts +615 -0
  353. package/src/bridges/LiFiBridge.ts +731 -0
  354. package/src/config/RebalancerConfig.test.ts +921 -0
  355. package/src/config/RebalancerConfig.ts +63 -0
  356. package/src/config/types.ts +613 -0
  357. package/src/core/InventoryRebalancer.test.ts +1858 -0
  358. package/src/core/InventoryRebalancer.ts +1455 -0
  359. package/src/core/Rebalancer.test.ts +686 -0
  360. package/src/core/Rebalancer.ts +686 -0
  361. package/src/core/RebalancerOrchestrator.test.ts +871 -0
  362. package/src/core/RebalancerOrchestrator.ts +273 -0
  363. package/src/core/RebalancerService.test.ts +1094 -0
  364. package/src/core/RebalancerService.ts +412 -0
  365. package/src/e2e/E2E_TEST_CONVENTIONS.md +222 -0
  366. package/src/e2e/collateral-deficit.e2e-test.ts +403 -0
  367. package/src/e2e/composite.e2e-test.ts +1008 -0
  368. package/src/e2e/fixtures/routes.ts +532 -0
  369. package/src/e2e/harness/BaseLocalDeploymentManager.ts +246 -0
  370. package/src/e2e/harness/BridgeSetup.ts +95 -0
  371. package/src/e2e/harness/Erc20InventoryLocalDeploymentManager.ts +183 -0
  372. package/src/e2e/harness/Erc20LocalDeploymentManager.ts +190 -0
  373. package/src/e2e/harness/ForkIndexer.test.ts +448 -0
  374. package/src/e2e/harness/ForkIndexer.ts +183 -0
  375. package/src/e2e/harness/MixedLocalDeploymentManager.ts +196 -0
  376. package/src/e2e/harness/MockExplorerClient.ts +94 -0
  377. package/src/e2e/harness/MockExternalBridge.ts +411 -0
  378. package/src/e2e/harness/NativeLocalDeploymentManager.ts +138 -0
  379. package/src/e2e/harness/SnapshotHelper.ts +56 -0
  380. package/src/e2e/harness/TestHelpers.ts +169 -0
  381. package/src/e2e/harness/TestRebalancer.ts +758 -0
  382. package/src/e2e/harness/TransferHelper.ts +188 -0
  383. package/src/e2e/inventory-erc20-minAmount.e2e-test.ts +735 -0
  384. package/src/e2e/inventory-erc20-weighted.e2e-test.ts +733 -0
  385. package/src/e2e/inventory-minAmount.e2e-test.ts +734 -0
  386. package/src/e2e/inventory-weighted.e2e-test.ts +734 -0
  387. package/src/e2e/minAmount.e2e-test.ts +313 -0
  388. package/src/e2e/mixed-weighted.e2e-test.ts +267 -0
  389. package/src/e2e/weighted.e2e-test.ts +304 -0
  390. package/src/factories/RebalancerContextFactory.test.ts +394 -0
  391. package/src/factories/RebalancerContextFactory.ts +771 -0
  392. package/src/index.ts +125 -0
  393. package/src/interfaces/IExternalBridge.ts +117 -0
  394. package/src/interfaces/IMetrics.ts +5 -0
  395. package/src/interfaces/IMonitor.ts +71 -0
  396. package/src/interfaces/IRebalancer.ts +57 -0
  397. package/src/interfaces/IStrategy.ts +81 -0
  398. package/src/metrics/Metrics.ts +335 -0
  399. package/src/metrics/PriceGetter.ts +74 -0
  400. package/src/metrics/scripts/metrics.ts +139 -0
  401. package/src/monitor/Monitor.ts +324 -0
  402. package/src/service.ts +285 -0
  403. package/src/strategy/BaseStrategy.ts +553 -0
  404. package/src/strategy/CollateralDeficitStrategy.test.ts +728 -0
  405. package/src/strategy/CollateralDeficitStrategy.ts +421 -0
  406. package/src/strategy/CompositeStrategy.test.ts +418 -0
  407. package/src/strategy/CompositeStrategy.ts +102 -0
  408. package/src/strategy/MinAmountStrategy.test.ts +732 -0
  409. package/src/strategy/MinAmountStrategy.ts +200 -0
  410. package/src/strategy/StrategyFactory.test.ts +108 -0
  411. package/src/strategy/StrategyFactory.ts +157 -0
  412. package/src/strategy/WeightedStrategy.test.ts +529 -0
  413. package/src/strategy/WeightedStrategy.ts +126 -0
  414. package/src/strategy/index.ts +6 -0
  415. package/src/test/helpers.ts +477 -0
  416. package/src/test/lifiMocks.ts +211 -0
  417. package/src/tracking/ActionTracker.test.ts +1625 -0
  418. package/src/tracking/ActionTracker.ts +1019 -0
  419. package/src/tracking/IActionTracker.ts +213 -0
  420. package/src/tracking/InflightContextAdapter.test.ts +206 -0
  421. package/src/tracking/InflightContextAdapter.ts +75 -0
  422. package/src/tracking/store/IStore.ts +48 -0
  423. package/src/tracking/store/InMemoryStore.test.ts +338 -0
  424. package/src/tracking/store/InMemoryStore.ts +59 -0
  425. package/src/tracking/store/index.ts +2 -0
  426. package/src/tracking/types.ts +118 -0
  427. package/src/utils/ExplorerClient.test.ts +386 -0
  428. package/src/utils/ExplorerClient.ts +439 -0
  429. package/src/utils/balanceUtils.test.ts +79 -0
  430. package/src/utils/balanceUtils.ts +65 -0
  431. package/src/utils/blockTag.ts +68 -0
  432. package/src/utils/bridgeUtils.test.ts +193 -0
  433. package/src/utils/bridgeUtils.ts +101 -0
  434. package/src/utils/errors.ts +5 -0
  435. package/src/utils/gasEstimation.ts +306 -0
  436. package/src/utils/solanaKeyParser.test.ts +103 -0
  437. package/src/utils/solanaKeyParser.ts +117 -0
  438. package/src/utils/tokenUtils.ts +89 -0
  439. package/src/utils/transactionUtils.ts +41 -0
@@ -0,0 +1,439 @@
1
+ import type { Logger } from 'pino';
2
+
3
+ import {
4
+ addressToByteHexString,
5
+ isEVMLike,
6
+ ProtocolType,
7
+ } from '@humanode-hyperlane/utils';
8
+
9
+ export type InflightRebalanceQueryParams = {
10
+ bridges: string[];
11
+ routersByDomain: Record<number, string>; // Domain ID → router address (derive routers and domains from this)
12
+ txSender: string;
13
+ limit?: number;
14
+ };
15
+
16
+ export type UserTransferQueryParams = {
17
+ routersByDomain: Record<number, string>; // Domain ID → router address (derive routers and domains from this)
18
+ excludeTxSenders: string[]; // Addresses to exclude (rebalancer + inventory signer)
19
+ limit?: number;
20
+ };
21
+
22
+ export type RebalanceActionQueryParams = {
23
+ bridges: string[]; // Bridge contract addresses
24
+ routersByDomain: Record<number, string>; // Domain ID → router address (derive routers and domains from this)
25
+ rebalancerAddress: string; // Include rebalancer's txs
26
+ inventorySignerAddresses?: string[]; // Optional: also include inventory signers' txs (for inventory_deposit actions)
27
+ limit?: number;
28
+ };
29
+
30
+ export type ExplorerMessage = {
31
+ msg_id: string;
32
+ origin_domain_id: number;
33
+ destination_domain_id: number;
34
+ sender: string;
35
+ recipient: string;
36
+ origin_tx_hash: string;
37
+ origin_tx_sender: string;
38
+ origin_tx_recipient: string;
39
+ is_delivered: boolean;
40
+ message_body: string;
41
+ send_occurred_at: string | null;
42
+ };
43
+
44
+ export interface IExplorerClient {
45
+ getInflightUserTransfers(
46
+ params: UserTransferQueryParams,
47
+ logger: Logger,
48
+ ): Promise<ExplorerMessage[]>;
49
+ getInflightRebalanceActions(
50
+ params: RebalanceActionQueryParams,
51
+ logger: Logger,
52
+ ): Promise<ExplorerMessage[]>;
53
+ }
54
+
55
+ export class ExplorerClient implements IExplorerClient {
56
+ constructor(
57
+ private readonly baseUrl: string,
58
+ private readonly getProtocol: (domainId: number) => ProtocolType,
59
+ ) {}
60
+
61
+ /**
62
+ * Convert an address to PostgreSQL bytea format (\\x-prefixed hex).
63
+ * When `domain` is provided, resolves the chain's protocol to encode
64
+ * non-EVM addresses (e.g. base58 Solana, 32-byte Starknet) correctly
65
+ * via `addressToByteHexString`. Without `domain`, assumes the address
66
+ * is already EVM-format hex (used for bridges, txSender, etc. which
67
+ * are always EVM addresses).
68
+ */
69
+ private toBytea(addr: string, domain?: number): string {
70
+ const protocol =
71
+ domain !== undefined ? this.getProtocol(domain) : undefined;
72
+ if (protocol && !isEVMLike(protocol)) {
73
+ const hex = addressToByteHexString(addr, protocol);
74
+ return hex.replace(/^0x/i, '\\x').toLowerCase();
75
+ }
76
+ return addr.replace(/^0x/i, '\\x').toLowerCase();
77
+ }
78
+
79
+ /**
80
+ * Normalize all hex fields in Explorer response from PostgreSQL bytea format (\\x) to standard hex (0x)
81
+ */
82
+ private normalizeExplorerMessage(msg: any): ExplorerMessage {
83
+ const normalizeHex = (hex: string): string => {
84
+ if (!hex) return hex;
85
+ return hex.startsWith('\\x') ? '0x' + hex.slice(2) : hex;
86
+ };
87
+
88
+ return {
89
+ msg_id: normalizeHex(msg.msg_id),
90
+ origin_domain_id: msg.origin_domain_id,
91
+ destination_domain_id: msg.destination_domain_id,
92
+ sender: normalizeHex(msg.sender),
93
+ recipient: normalizeHex(msg.recipient),
94
+ origin_tx_hash: normalizeHex(msg.origin_tx_hash),
95
+ origin_tx_sender: normalizeHex(msg.origin_tx_sender),
96
+ origin_tx_recipient: normalizeHex(msg.origin_tx_recipient),
97
+ is_delivered: msg.is_delivered,
98
+ message_body: normalizeHex(msg.message_body),
99
+ send_occurred_at: msg.send_occurred_at ?? null,
100
+ };
101
+ }
102
+
103
+ async hasUndeliveredRebalance(
104
+ params: InflightRebalanceQueryParams,
105
+ logger: Logger,
106
+ ): Promise<boolean> {
107
+ const { bridges, routersByDomain, txSender, limit = 5 } = params;
108
+
109
+ // Derive routers and domains from routersByDomain
110
+ const routerEntries = Object.entries(routersByDomain);
111
+ const domains = Object.keys(routersByDomain).map(Number);
112
+
113
+ const variables = {
114
+ // NOTE: bridges are always EVM addresses; pass domain here if non-EVM bridges are added
115
+ senders: bridges.map((a) => this.toBytea(a)),
116
+ // NOTE: bridges are always EVM addresses; pass domain here if non-EVM bridges are added
117
+ recipients: bridges.map((a) => this.toBytea(a)),
118
+ originTxRecipients: routerEntries.map(([domain, addr]) =>
119
+ this.toBytea(addr, Number(domain)),
120
+ ),
121
+ originDomains: domains,
122
+ destDomains: domains,
123
+ // NOTE: txSender is always an EVM address (rebalancer signer)
124
+ txSenders: [this.toBytea(txSender)],
125
+ limit,
126
+ };
127
+
128
+ logger.debug({ variables }, 'Explorer query variables');
129
+
130
+ const query = `
131
+ query InflightRebalancesForRoute(
132
+ $senders: [bytea!],
133
+ $recipients: [bytea!],
134
+ $originTxRecipients: [bytea!],
135
+ $originDomains: [Int!],
136
+ $destDomains: [Int!],
137
+ $txSenders: [bytea!],
138
+ $limit: Int = 25
139
+ ) {
140
+ message_view(
141
+ where: {
142
+ _and: [
143
+ { is_delivered: { _eq: false } },
144
+ { sender: { _in: $senders } },
145
+ { recipient: { _in: $recipients } },
146
+ { origin_tx_recipient: { _in: $originTxRecipients } },
147
+ { origin_domain_id: { _in: $originDomains } },
148
+ { destination_domain_id: { _in: $destDomains } },
149
+ { origin_tx_sender: { _in: $txSenders } }
150
+ ]
151
+ }
152
+ order_by: { origin_tx_id: desc }
153
+ limit: $limit
154
+ ) {
155
+ msg_id
156
+ origin_domain_id
157
+ destination_domain_id
158
+ sender
159
+ recipient
160
+ origin_tx_hash
161
+ origin_tx_sender
162
+ origin_tx_recipient
163
+ is_delivered
164
+ message_body
165
+ }
166
+ }`;
167
+
168
+ const res = await fetch(this.baseUrl, {
169
+ method: 'POST',
170
+ headers: { 'Content-Type': 'application/json' },
171
+ body: JSON.stringify({ query, variables }),
172
+ });
173
+
174
+ logger.debug({ status: res.status }, 'Explorer query response');
175
+
176
+ if (!res.ok) {
177
+ let errorDetails: string;
178
+ try {
179
+ const errorJson = await res.json();
180
+ errorDetails = JSON.stringify(errorJson);
181
+ } catch (_e) {
182
+ try {
183
+ // Fallback to text if JSON parsing fails
184
+ errorDetails = await res.text();
185
+ } catch (_textError) {
186
+ errorDetails = 'Unable to read response body';
187
+ }
188
+ }
189
+ throw new Error(`Explorer query failed: ${res.status} ${errorDetails}`);
190
+ }
191
+
192
+ const json = await res.json();
193
+ const rows = json?.data?.message_view ?? [];
194
+
195
+ logger.debug({ rows }, 'Explorer query rows');
196
+
197
+ // Post-query validation: verify each message's origin domain matches the expected router
198
+ const validatedRows = rows.filter((msg: any) => {
199
+ const expectedRouter = routersByDomain[msg.origin_domain_id];
200
+ if (!expectedRouter) return false;
201
+ const protocol = this.getProtocol(msg.origin_domain_id);
202
+ const normalizedMsgRouter = msg.origin_tx_recipient?.startsWith('\\x')
203
+ ? '0x' + msg.origin_tx_recipient.slice(2)
204
+ : msg.origin_tx_recipient;
205
+ if (protocol && !isEVMLike(protocol)) {
206
+ const expectedHex = addressToByteHexString(
207
+ expectedRouter,
208
+ protocol,
209
+ ).toLowerCase();
210
+ return normalizedMsgRouter?.toLowerCase() === expectedHex;
211
+ }
212
+ return (
213
+ normalizedMsgRouter?.toLowerCase() === expectedRouter.toLowerCase()
214
+ );
215
+ });
216
+
217
+ logger.debug(
218
+ { totalRows: rows.length, validatedRows: validatedRows.length },
219
+ 'Post-query validation results',
220
+ );
221
+
222
+ return validatedRows.length > 0;
223
+ }
224
+
225
+ /**
226
+ * Query inflight user transfers from the Explorer.
227
+ * Returns transfers where sender/recipient are routers, excluding rebalancer's own transactions.
228
+ */
229
+ async getInflightUserTransfers(
230
+ params: UserTransferQueryParams,
231
+ logger: Logger,
232
+ ): Promise<ExplorerMessage[]> {
233
+ const { routersByDomain, excludeTxSenders, limit = 100 } = params;
234
+
235
+ // Derive routers and domains from routersByDomain
236
+ const routerEntries = Object.entries(routersByDomain);
237
+ const domains = Object.keys(routersByDomain).map(Number);
238
+
239
+ const variables = {
240
+ senders: routerEntries.map(([domain, addr]) =>
241
+ this.toBytea(addr, Number(domain)),
242
+ ),
243
+ recipients: routerEntries.map(([domain, addr]) =>
244
+ this.toBytea(addr, Number(domain)),
245
+ ),
246
+ originDomains: domains,
247
+ destDomains: domains,
248
+ // NOTE: excludeTxSenders are always EVM addresses
249
+ excludeTxSenders: excludeTxSenders.map((a) => this.toBytea(a)),
250
+ limit,
251
+ };
252
+
253
+ logger.debug({ variables }, 'Explorer getInflightUserTransfers query');
254
+
255
+ const query = `
256
+ query InflightUserTransfers(
257
+ $senders: [bytea!],
258
+ $recipients: [bytea!],
259
+ $originDomains: [Int!],
260
+ $destDomains: [Int!],
261
+ $excludeTxSenders: [bytea!],
262
+ $limit: Int = 100
263
+ ) {
264
+ message_view(
265
+ where: {
266
+ _and: [
267
+ { is_delivered: { _eq: false } },
268
+ { sender: { _in: $senders } },
269
+ { recipient: { _in: $recipients } },
270
+ { origin_domain_id: { _in: $originDomains } },
271
+ { destination_domain_id: { _in: $destDomains } },
272
+ { origin_tx_sender: { _nin: $excludeTxSenders } }
273
+ ]
274
+ }
275
+ order_by: { origin_tx_id: desc }
276
+ limit: $limit
277
+ ) {
278
+ msg_id
279
+ origin_domain_id
280
+ destination_domain_id
281
+ sender
282
+ recipient
283
+ origin_tx_hash
284
+ origin_tx_sender
285
+ origin_tx_recipient
286
+ is_delivered
287
+ message_body
288
+ send_occurred_at
289
+ }
290
+ }`;
291
+
292
+ const res = await fetch(this.baseUrl, {
293
+ method: 'POST',
294
+ headers: { 'Content-Type': 'application/json' },
295
+ body: JSON.stringify({ query, variables }),
296
+ });
297
+
298
+ logger.debug(
299
+ { status: res.status },
300
+ 'Explorer getInflightUserTransfers response',
301
+ );
302
+
303
+ if (!res.ok) {
304
+ let errorDetails: string;
305
+ try {
306
+ const errorJson = await res.json();
307
+ errorDetails = JSON.stringify(errorJson);
308
+ } catch (_e) {
309
+ try {
310
+ errorDetails = await res.text();
311
+ } catch (_textError) {
312
+ errorDetails = 'Unable to read response body';
313
+ }
314
+ }
315
+ throw new Error(`Explorer query failed: ${res.status} ${errorDetails}`);
316
+ }
317
+
318
+ const json = await res.json();
319
+ const messages = json?.data?.message_view ?? [];
320
+ return messages.map((msg: any) => this.normalizeExplorerMessage(msg));
321
+ }
322
+
323
+ /**
324
+ * Query inflight rebalance actions from the Explorer.
325
+ * Returns messages where sender/recipient are bridges, tx sender is the rebalancer,
326
+ * and origin_tx_recipient is one of this warp route's routers.
327
+ */
328
+ async getInflightRebalanceActions(
329
+ params: RebalanceActionQueryParams,
330
+ logger: Logger,
331
+ ): Promise<ExplorerMessage[]> {
332
+ const {
333
+ bridges,
334
+ routersByDomain,
335
+ rebalancerAddress,
336
+ inventorySignerAddresses,
337
+ limit = 100,
338
+ } = params;
339
+
340
+ // Derive routers and domains from routersByDomain
341
+ const routerEntries = Object.entries(routersByDomain);
342
+ const domains = Object.keys(routersByDomain).map(Number);
343
+
344
+ // Build list of tx senders to include (rebalancer + optional inventory signer)
345
+ // NOTE: rebalancerAddress is always an EVM address (rebalancer signer)
346
+ const txSenders = [this.toBytea(rebalancerAddress)];
347
+ if (inventorySignerAddresses) {
348
+ for (const addr of inventorySignerAddresses) {
349
+ // NOTE: inventorySignerAddresses are filtered to ProtocolType.Ethereum
350
+ txSenders.push(this.toBytea(addr));
351
+ }
352
+ }
353
+
354
+ const variables = {
355
+ // NOTE: bridges are always EVM addresses; pass domain here if non-EVM bridges are added
356
+ senders: bridges.map((a) => this.toBytea(a)),
357
+ // NOTE: bridges are always EVM addresses; pass domain here if non-EVM bridges are added
358
+ recipients: bridges.map((a) => this.toBytea(a)),
359
+ originTxRecipients: routerEntries.map(([domain, addr]) =>
360
+ this.toBytea(addr, Number(domain)),
361
+ ),
362
+ originDomains: domains,
363
+ destDomains: domains,
364
+ txSenders,
365
+ limit,
366
+ };
367
+
368
+ logger.debug({ variables }, 'Explorer getInflightRebalanceActions query');
369
+
370
+ const query = `
371
+ query InflightRebalanceActions(
372
+ $senders: [bytea!],
373
+ $recipients: [bytea!],
374
+ $originTxRecipients: [bytea!],
375
+ $originDomains: [Int!],
376
+ $destDomains: [Int!],
377
+ $txSenders: [bytea!],
378
+ $limit: Int = 100
379
+ ) {
380
+ message_view(
381
+ where: {
382
+ _and: [
383
+ { is_delivered: { _eq: false } },
384
+ { sender: { _in: $senders } },
385
+ { recipient: { _in: $recipients } },
386
+ { origin_tx_recipient: { _in: $originTxRecipients } },
387
+ { origin_domain_id: { _in: $originDomains } },
388
+ { destination_domain_id: { _in: $destDomains } },
389
+ { origin_tx_sender: { _in: $txSenders } }
390
+ ]
391
+ }
392
+ order_by: { origin_tx_id: desc }
393
+ limit: $limit
394
+ ) {
395
+ msg_id
396
+ origin_domain_id
397
+ destination_domain_id
398
+ sender
399
+ recipient
400
+ origin_tx_hash
401
+ origin_tx_sender
402
+ origin_tx_recipient
403
+ is_delivered
404
+ message_body
405
+ send_occurred_at
406
+ }
407
+ }`;
408
+
409
+ const res = await fetch(this.baseUrl, {
410
+ method: 'POST',
411
+ headers: { 'Content-Type': 'application/json' },
412
+ body: JSON.stringify({ query, variables }),
413
+ });
414
+
415
+ logger.debug(
416
+ { status: res.status },
417
+ 'Explorer getInflightRebalanceActions response',
418
+ );
419
+
420
+ if (!res.ok) {
421
+ let errorDetails: string;
422
+ try {
423
+ const errorJson = await res.json();
424
+ errorDetails = JSON.stringify(errorJson);
425
+ } catch (_e) {
426
+ try {
427
+ errorDetails = await res.text();
428
+ } catch (_textError) {
429
+ errorDetails = 'Unable to read response body';
430
+ }
431
+ }
432
+ throw new Error(`Explorer query failed: ${res.status} ${errorDetails}`);
433
+ }
434
+
435
+ const json = await res.json();
436
+ const messages = json?.data?.message_view ?? [];
437
+ return messages.map((msg: any) => this.normalizeExplorerMessage(msg));
438
+ }
439
+ }
@@ -0,0 +1,79 @@
1
+ import { expect } from 'chai';
2
+ import { pino } from 'pino';
3
+ import sinon from 'sinon';
4
+
5
+ import {
6
+ type ChainName,
7
+ type Token,
8
+ TokenStandard,
9
+ } from '@humanode-hyperlane/sdk';
10
+
11
+ import { type MonitorEvent } from '../interfaces/IMonitor.js';
12
+
13
+ import { getRawBalances } from './balanceUtils.js';
14
+
15
+ const testLogger = pino({ level: 'silent' });
16
+
17
+ describe('getRawBalances', () => {
18
+ let chains: ChainName[];
19
+ let token: Token;
20
+ let tokenBridgedSupply: bigint;
21
+ let event: MonitorEvent;
22
+
23
+ beforeEach(() => {
24
+ chains = ['mainnet'];
25
+
26
+ token = {
27
+ chainName: 'mainnet',
28
+ addressOrDenom: '0xAddress',
29
+ isCollateralized: sinon.stub().returns(true),
30
+ standard: TokenStandard.EvmHypCollateral,
31
+ } as unknown as Token;
32
+
33
+ tokenBridgedSupply = 100n;
34
+
35
+ event = {
36
+ tokensInfo: [
37
+ {
38
+ token,
39
+ bridgedSupply: tokenBridgedSupply,
40
+ },
41
+ ],
42
+ confirmedBlockTags: { mainnet: 1000 },
43
+ };
44
+ });
45
+
46
+ it('should return the bridged supply for the token (EvmHypCollateral)', () => {
47
+ expect(getRawBalances(chains, event, testLogger)).to.deep.equal({
48
+ mainnet: tokenBridgedSupply,
49
+ });
50
+ });
51
+
52
+ it('should return the bridged supply for the token (EvmHypNative)', () => {
53
+ token.standard = TokenStandard.EvmHypNative;
54
+
55
+ expect(getRawBalances(chains, event, testLogger)).to.deep.equal({
56
+ mainnet: tokenBridgedSupply,
57
+ });
58
+ });
59
+
60
+ it('should ignore non supported token standards', () => {
61
+ token.standard = TokenStandard.EvmHypOwnerCollateral;
62
+
63
+ expect(getRawBalances(chains, event, testLogger)).to.deep.equal({});
64
+ });
65
+
66
+ it('should ignore tokens that are not in the chains list', () => {
67
+ chains = [];
68
+
69
+ expect(getRawBalances(chains, event, testLogger)).to.deep.equal({});
70
+ });
71
+
72
+ it('should throw if the bridged supply is undefined', () => {
73
+ delete event.tokensInfo[0].bridgedSupply;
74
+
75
+ expect(() => getRawBalances(chains, event, testLogger)).to.throw(
76
+ 'bridgedSupply should not be undefined for collateralized token 0xAddress',
77
+ );
78
+ });
79
+ });
@@ -0,0 +1,65 @@
1
+ import { type Logger } from 'pino';
2
+
3
+ import { type ChainName } from '@humanode-hyperlane/sdk';
4
+
5
+ import { type MonitorEvent } from '../interfaces/IMonitor.js';
6
+ import { type RawBalances } from '../interfaces/IStrategy.js';
7
+
8
+ import { isCollateralizedTokenEligibleForRebalancing } from './tokenUtils.js';
9
+
10
+ /**
11
+ * Returns the raw balances required by the strategies from the monitor event
12
+ * @param chains - The chains that should be included in the raw balances (e.g. the chains in the rebalancer config)
13
+ * @param event - The monitor event to extract the raw balances from
14
+ * @returns An object mapping chain names to their raw balances.
15
+ */
16
+ export function getRawBalances(
17
+ chains: ChainName[],
18
+ event: MonitorEvent,
19
+ logger: Logger,
20
+ ): RawBalances {
21
+ const balances: RawBalances = {};
22
+ const chainSet = new Set(chains);
23
+
24
+ for (const tokenInfo of event.tokensInfo) {
25
+ const { token, bridgedSupply } = tokenInfo;
26
+
27
+ // Ignore tokens that are not in the provided chains list
28
+ if (!chainSet.has(token.chainName)) {
29
+ logger.debug(
30
+ {
31
+ context: getRawBalances.name,
32
+ chain: token.chainName,
33
+ tokenSymbol: token.symbol,
34
+ tokenAddress: token.addressOrDenom,
35
+ },
36
+ 'Skipping token: not in configured chains list',
37
+ );
38
+ continue;
39
+ }
40
+
41
+ // Ignore tokens that are not collateralized or are otherwise ineligible
42
+ if (!isCollateralizedTokenEligibleForRebalancing(token)) {
43
+ logger.debug(
44
+ {
45
+ context: getRawBalances.name,
46
+ chain: token.chainName,
47
+ tokenSymbol: token.symbol,
48
+ tokenAddress: token.addressOrDenom,
49
+ },
50
+ 'Skipping token: not collateralized or ineligible for rebalancing',
51
+ );
52
+ continue;
53
+ }
54
+
55
+ if (bridgedSupply === undefined) {
56
+ throw new Error(
57
+ `bridgedSupply should not be undefined for collateralized token ${token.addressOrDenom}`,
58
+ );
59
+ }
60
+
61
+ balances[token.chainName] = bridgedSupply;
62
+ }
63
+
64
+ return balances;
65
+ }
@@ -0,0 +1,68 @@
1
+ import type { Logger } from 'pino';
2
+
3
+ import { providers } from 'ethers';
4
+
5
+ import {
6
+ EthJsonRpcBlockParameterTag,
7
+ MultiProtocolProvider,
8
+ } from '@humanode-hyperlane/sdk';
9
+ import { ProtocolType } from '@humanode-hyperlane/utils';
10
+ import type { ConfirmedBlockTag } from '../interfaces/IMonitor.js';
11
+
12
+ /**
13
+ * Get the confirmed block tag for a chain, accounting for reorg period.
14
+ * Returns a block number that is safe from reorgs, or a named tag like 'finalized'.
15
+ *
16
+ * @param multiProvider - MultiProtocolProvider instance
17
+ * @param chainName - Name of the chain
18
+ * @param logger - Optional logger for warnings
19
+ * @returns Confirmed block tag (number, named tag, or undefined on error)
20
+ */
21
+ export async function getConfirmedBlockTag(
22
+ multiProvider: MultiProtocolProvider,
23
+ chainName: string,
24
+ logger?: Logger,
25
+ ): Promise<ConfirmedBlockTag> {
26
+ try {
27
+ const metadata = multiProvider.getChainMetadata(chainName);
28
+
29
+ // Only EVM chains support block tag queries
30
+ if (metadata.protocol !== ProtocolType.Ethereum) {
31
+ return undefined;
32
+ }
33
+
34
+ const reorgPeriod = metadata.blocks?.reorgPeriod ?? 32;
35
+ if (typeof reorgPeriod === 'string') {
36
+ return reorgPeriod as EthJsonRpcBlockParameterTag;
37
+ }
38
+
39
+ const provider = multiProvider.getEthersV5Provider(chainName);
40
+ let latestBlock: number;
41
+ if (provider instanceof providers.JsonRpcProvider) {
42
+ const latestBlockHex = await provider.send('eth_blockNumber', []);
43
+ if (
44
+ typeof latestBlockHex !== 'string' ||
45
+ !/^0x[0-9a-fA-F]+$/.test(latestBlockHex)
46
+ ) {
47
+ throw new Error(
48
+ `Invalid eth_blockNumber response for ${chainName}: ${latestBlockHex}`,
49
+ );
50
+ }
51
+ latestBlock = parseInt(latestBlockHex, 16);
52
+ if (!Number.isFinite(latestBlock)) {
53
+ throw new Error(
54
+ `Parsed block number is not finite for ${chainName}: ${latestBlockHex}`,
55
+ );
56
+ }
57
+ } else {
58
+ latestBlock = await provider.getBlockNumber();
59
+ }
60
+ return Math.max(0, latestBlock - reorgPeriod);
61
+ } catch (error) {
62
+ logger?.warn(
63
+ { chain: chainName, error: (error as Error).message },
64
+ 'Failed to get confirmed block, using latest',
65
+ );
66
+ return undefined;
67
+ }
68
+ }