@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
package/package.json CHANGED
@@ -1,6 +1,90 @@
1
1
  {
2
2
  "name": "@humanode-hyperlane/rebalancer",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "27.2.2-humanode.1",
4
+ "description": "Hyperlane Warp Route Collateral Rebalancer Service",
5
+ "keywords": [
6
+ "blockchain",
7
+ "collateral",
8
+ "hyperlane",
9
+ "interchain",
10
+ "rebalancer",
11
+ "warp-route"
12
+ ],
13
+ "license": "Apache-2.0",
14
+ "author": "Abacus Works, Inc.",
15
+ "repository": "https://github.com/humanode-network/hyperlane-monorepo",
16
+ "bin": {
17
+ "hyperlane-rebalancer": "./dist/service.js"
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "src"
22
+ ],
23
+ "type": "module",
24
+ "main": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "dependencies": {
27
+ "@google-cloud/pino-logging-gcp-config": "^1.3.0",
28
+ "@humanode-hyperlane/registry": "23.12.0",
29
+ "@inquirer/prompts": "3.3.2",
30
+ "@inquirer/select": "^1.0.0",
31
+ "@lifi/sdk": "^3.15.4",
32
+ "@solana/web3.js": "^1.98.4",
33
+ "bignumber.js": "^9.1.1",
34
+ "bs58": "^6.0.0",
35
+ "ethers": "^5.8.0",
36
+ "express": "^5.1.0",
37
+ "pino": "^8.19.0",
38
+ "pino-pretty": "^13.0.0",
39
+ "prom-client": "^14.0.1",
40
+ "uuid": "^10.0.0",
41
+ "viem": "^2.21.45",
42
+ "yaml": "2.4.5",
43
+ "zod": "^3.21.2",
44
+ "zod-validation-error": "^3.3.0",
45
+ "@humanode-hyperlane/core": "11.2.0-humanode.1",
46
+ "@humanode-hyperlane/metrics": "0.2.8-humanode.1",
47
+ "@humanode-hyperlane/provider-sdk": "4.2.3-humanode.1",
48
+ "@humanode-hyperlane/sdk": "30.0.0-humanode.1",
49
+ "@humanode-hyperlane/utils": "30.0.0-humanode.1"
50
+ },
51
+ "devDependencies": {
52
+ "@ethersproject/constants": "*",
53
+ "@types/chai": "^4.3.11",
54
+ "@types/chai-as-promised": "^8",
55
+ "@types/express": "^5.0.3",
56
+ "@types/mocha": "^10.0.1",
57
+ "@types/node": "^24.10.9",
58
+ "@types/sinon": "^17.0.1",
59
+ "@types/uuid": "^10.0.0",
60
+ "@vercel/ncc": "^0.38.3",
61
+ "chai": "^4.5.0",
62
+ "chai-as-promised": "^8.0.1",
63
+ "mocha": "^11.5.0",
64
+ "oxfmt": "^0.42.0",
65
+ "sinon": "^13.0.2",
66
+ "testcontainers": "11.12.0",
67
+ "tsx": "^4.19.1",
68
+ "typescript": "6.0.2",
69
+ "@humanode-hyperlane/relayer": "1.1.15-humanode.1",
70
+ "@humanode-hyperlane/tsconfig": "^30.0.0"
71
+ },
72
+ "engines": {
73
+ "node": ">=18"
74
+ },
75
+ "scripts": {
76
+ "build": "tsc",
77
+ "build:dist": "tsc -p tsconfig.build.json",
78
+ "bundle": "pnpm build:dist && rm -rf ./bundle && ncc build ./dist/service.js -o bundle -e @google-cloud/pino-logging-gcp-config && node ../../scripts/ncc.post-bundle.mjs",
79
+ "clean": "rm -rf dist cache bundle",
80
+ "dev": "tsc --watch",
81
+ "lint": "oxlint -c ../../oxlint.json",
82
+ "format": "oxfmt --write ./src",
83
+ "test": "mocha --config .mocharc.json './src/**/*.test.ts' --exit",
84
+ "test:e2e": "mocha --config .mocharc.e2e.json",
85
+ "test:e2e:ci": "sh -c 'mocha --config .mocharc.e2e.json \"src/e2e/*${REBALANCER_E2E_TEST}*.e2e-test.ts\" --exit'",
86
+ "test:ci": "pnpm test",
87
+ "start": "node dist/service.js",
88
+ "start:dev": "tsx src/service.ts"
89
+ }
6
90
  }
@@ -0,0 +1,615 @@
1
+ import { expect } from 'chai';
2
+ import { pino } from 'pino';
3
+
4
+ import type { LiFiStep } from '@lifi/sdk';
5
+ import { ProtocolType } from '@humanode-hyperlane/utils';
6
+
7
+ import type {
8
+ BridgeQuote,
9
+ BridgeQuoteParams,
10
+ ExternalBridgeConfig,
11
+ } from '../interfaces/IExternalBridge.js';
12
+ import { LiFiBridge } from './LiFiBridge.js';
13
+
14
+ const testLogger = pino({ level: 'silent' });
15
+
16
+ const TEST_PRIVATE_KEY =
17
+ '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
18
+
19
+ const BRIDGE_CONFIG: ExternalBridgeConfig = {
20
+ integrator: 'test-rebalancer',
21
+ };
22
+
23
+ const SOLANA_CHAIN_METADATA_CONFIG: ExternalBridgeConfig = {
24
+ integrator: 'test-rebalancer',
25
+ chainMetadata: {
26
+ solana: {
27
+ chainId: 1399811149,
28
+ protocol: ProtocolType.Sealevel,
29
+ name: 'solana',
30
+ displayName: 'Solana',
31
+ domainId: 1399811149,
32
+ rpcUrls: [{ http: 'https://api.mainnet-beta.solana.com' }],
33
+ },
34
+ },
35
+ };
36
+
37
+ // Use all-digit hex addresses to avoid EIP-55 checksum case mutations
38
+ const TOKEN_ADDR = '0x1234567890123456789012345678901234567890';
39
+ const SENDER_ADDR = '0x9876543210987654321098765432109876543210';
40
+ const BAD_ADDR = '0x1111111111111111111111111111111111111111';
41
+
42
+ /**
43
+ * Creates a LiFiStep object that convertQuoteToRoute can consume.
44
+ * The SDK's convertQuoteToRoute reads action.fromToken.chainId, action.toToken.chainId, etc.
45
+ */
46
+ function createLiFiStep(overrides?: {
47
+ fromChainId?: number;
48
+ toChainId?: number;
49
+ fromTokenAddress?: string;
50
+ toTokenAddress?: string;
51
+ toAddress?: string;
52
+ fromAmount?: string;
53
+ toAmount?: string;
54
+ fromAddress?: string;
55
+ }): LiFiStep {
56
+ const fromChainId = overrides?.fromChainId ?? 42161;
57
+ const toChainId = overrides?.toChainId ?? 1151111081099710;
58
+ const fromTokenAddress = overrides?.fromTokenAddress ?? TOKEN_ADDR;
59
+ const toTokenAddress = overrides?.toTokenAddress ?? TOKEN_ADDR;
60
+ const fromAmount = overrides?.fromAmount ?? '10000000000';
61
+ const fromAddress = overrides?.fromAddress ?? SENDER_ADDR;
62
+ const toAddress = overrides?.toAddress ?? SENDER_ADDR;
63
+
64
+ return {
65
+ id: 'quote-123',
66
+ type: 'lifi' as const,
67
+ tool: 'across',
68
+ toolDetails: { key: 'across', name: 'Across', logoURI: '' },
69
+ includedSteps: [],
70
+ action: {
71
+ fromToken: {
72
+ chainId: fromChainId,
73
+ address: fromTokenAddress,
74
+ symbol: 'USDC',
75
+ decimals: 6,
76
+ name: 'USD Coin',
77
+ priceUSD: '1',
78
+ },
79
+ toToken: {
80
+ chainId: toChainId,
81
+ address: toTokenAddress,
82
+ symbol: 'USDC',
83
+ decimals: 6,
84
+ name: 'USD Coin',
85
+ priceUSD: '1',
86
+ },
87
+ fromAmount,
88
+ fromAddress,
89
+ toAddress,
90
+ fromChainId,
91
+ toChainId,
92
+ slippage: 0.005,
93
+ },
94
+ estimate: {
95
+ tool: 'across',
96
+ fromAmount,
97
+ fromAmountUSD: '10000',
98
+ toAmount: overrides?.toAmount ?? '9950000000',
99
+ toAmountMin: '9900000000',
100
+ toAmountUSD: '9950',
101
+ approvalAddress: '0x0000000000000000000000000000000000000000',
102
+ executionDuration: 300,
103
+ gasCosts: [
104
+ {
105
+ type: 'SEND' as const,
106
+ price: '50',
107
+ estimate: '21000',
108
+ limit: '26250',
109
+ amount: '50000000',
110
+ amountUSD: '5',
111
+ token: {
112
+ chainId: fromChainId,
113
+ address: '0x0000000000000000000000000000000000000000',
114
+ symbol: 'ETH',
115
+ decimals: 18,
116
+ name: 'Ethereum',
117
+ priceUSD: '3000',
118
+ },
119
+ },
120
+ ],
121
+ },
122
+ };
123
+ }
124
+
125
+ /**
126
+ * Creates a BridgeQuote with matching requestParams for the default LiFi step.
127
+ */
128
+ function createTestQuote(
129
+ routeOverrides?: Parameters<typeof createLiFiStep>[0],
130
+ paramOverrides?: Partial<BridgeQuoteParams>,
131
+ ): BridgeQuote<LiFiStep> {
132
+ const lifiStep = createLiFiStep(routeOverrides);
133
+
134
+ const defaultParams: BridgeQuoteParams = {
135
+ fromChain: 42161,
136
+ toChain: 1151111081099710,
137
+ fromToken: TOKEN_ADDR,
138
+ toToken: TOKEN_ADDR,
139
+ fromAddress: SENDER_ADDR,
140
+ toAddress: SENDER_ADDR,
141
+ fromAmount: 10000000000n,
142
+ };
143
+
144
+ return {
145
+ id: 'quote-123',
146
+ tool: 'across',
147
+ fromAmount: 10000000000n,
148
+ toAmount: 9950000000n,
149
+ toAmountMin: 9900000000n,
150
+ executionDuration: 300,
151
+ gasCosts: 50000000n,
152
+ feeCosts: 0n,
153
+ route: lifiStep,
154
+ requestParams: { ...defaultParams, ...paramOverrides },
155
+ };
156
+ }
157
+
158
+ /**
159
+ * Validation regex patterns used by LiFiBridge.execute() assertion messages.
160
+ * If an error message matches any of these, it came from route validation.
161
+ */
162
+ const VALIDATION_PATTERNS = [
163
+ /Route fromChainId .* does not match requested/,
164
+ /Route toChainId .* does not match requested/,
165
+ /Route fromToken .* does not match requested/,
166
+ /Route toToken .* does not match requested/,
167
+ /Route toAddress .* does not match requested/,
168
+ /Route fromAddress .* does not match requested/,
169
+ /Route fromAmount .* does not match requested/,
170
+ /Route toAmount .* is less than requested/,
171
+ /Route fromAmount must be positive/,
172
+ ];
173
+
174
+ function isValidationError(msg: string): boolean {
175
+ return VALIDATION_PATTERNS.some((pattern) => pattern.test(msg));
176
+ }
177
+
178
+ describe('LiFiBridge.execute() route validation', function () {
179
+ // Allow extra time for tests that pass validation and reach SDK execution
180
+ this.timeout(15000);
181
+
182
+ let bridge: LiFiBridge;
183
+
184
+ beforeEach(() => {
185
+ bridge = new LiFiBridge(BRIDGE_CONFIG, testLogger);
186
+ });
187
+
188
+ it('should pass validation when all route fields match requestParams', async () => {
189
+ const quote = createTestQuote();
190
+
191
+ try {
192
+ await bridge.execute(quote, {
193
+ [ProtocolType.Ethereum]: TEST_PRIVATE_KEY,
194
+ });
195
+ // If it resolves, validation definitely passed
196
+ } catch (error: unknown) {
197
+ const msg = (error as Error).message;
198
+ // Post-validation error (SDK/RPC). Verify it is NOT a route validation error.
199
+ expect(
200
+ isValidationError(msg),
201
+ `Expected non-validation error but got: ${msg}`,
202
+ ).to.equal(false);
203
+ }
204
+ });
205
+
206
+ it('should throw when route fromChainId does not match requested', async () => {
207
+ const quote = createTestQuote({ fromChainId: 999 }, { fromChain: 42161 });
208
+
209
+ try {
210
+ await bridge.execute(quote, {
211
+ [ProtocolType.Ethereum]: TEST_PRIVATE_KEY,
212
+ });
213
+ expect.fail('Expected execute to throw');
214
+ } catch (error: unknown) {
215
+ const msg = (error as Error).message;
216
+ expect(msg).to.include('999');
217
+ expect(msg).to.include('42161');
218
+ expect(msg).to.include('fromChainId');
219
+ }
220
+ });
221
+
222
+ it('should throw when route toChainId does not match requested', async () => {
223
+ const quote = createTestQuote(
224
+ { toChainId: 888 },
225
+ { toChain: 1151111081099710 },
226
+ );
227
+
228
+ try {
229
+ await bridge.execute(quote, {
230
+ [ProtocolType.Ethereum]: TEST_PRIVATE_KEY,
231
+ });
232
+ expect.fail('Expected execute to throw');
233
+ } catch (error: unknown) {
234
+ const msg = (error as Error).message;
235
+ expect(msg).to.include('888');
236
+ expect(msg).to.include('1151111081099710');
237
+ expect(msg).to.include('toChainId');
238
+ }
239
+ });
240
+
241
+ it('should throw when route fromToken does not match requested', async () => {
242
+ const quote = createTestQuote(
243
+ { fromTokenAddress: BAD_ADDR },
244
+ { fromToken: TOKEN_ADDR },
245
+ );
246
+
247
+ try {
248
+ await bridge.execute(quote, {
249
+ [ProtocolType.Ethereum]: TEST_PRIVATE_KEY,
250
+ });
251
+ expect.fail('Expected execute to throw');
252
+ } catch (error: unknown) {
253
+ const msg = (error as Error).message;
254
+ expect(msg).to.include('fromToken');
255
+ // Error message should contain the mismatched address value
256
+ expect(msg.toLowerCase()).to.include(BAD_ADDR.toLowerCase());
257
+ }
258
+ });
259
+
260
+ it('should throw when route toToken does not match requested', async () => {
261
+ const quote = createTestQuote(
262
+ { toTokenAddress: BAD_ADDR },
263
+ { toToken: TOKEN_ADDR },
264
+ );
265
+
266
+ try {
267
+ await bridge.execute(quote, {
268
+ [ProtocolType.Ethereum]: TEST_PRIVATE_KEY,
269
+ });
270
+ expect.fail('Expected execute to throw');
271
+ } catch (error: unknown) {
272
+ const msg = (error as Error).message;
273
+ expect(msg).to.include('toToken');
274
+ expect(msg.toLowerCase()).to.include(BAD_ADDR.toLowerCase());
275
+ }
276
+ });
277
+
278
+ it('should throw when route toAddress does not match requested', async () => {
279
+ const quote = createTestQuote(
280
+ { toAddress: BAD_ADDR },
281
+ { toAddress: SENDER_ADDR },
282
+ );
283
+
284
+ try {
285
+ await bridge.execute(quote, {
286
+ [ProtocolType.Ethereum]: TEST_PRIVATE_KEY,
287
+ });
288
+ expect.fail('Expected execute to throw');
289
+ } catch (error: unknown) {
290
+ const msg = (error as Error).message;
291
+ expect(msg).to.include('toAddress');
292
+ }
293
+ });
294
+
295
+ it('should throw when route fromAddress does not match requested', async () => {
296
+ const quote = createTestQuote(
297
+ { fromAddress: BAD_ADDR },
298
+ { fromAddress: SENDER_ADDR },
299
+ );
300
+
301
+ try {
302
+ await bridge.execute(quote, {
303
+ [ProtocolType.Ethereum]: TEST_PRIVATE_KEY,
304
+ });
305
+ expect.fail('Expected execute to throw');
306
+ } catch (error: unknown) {
307
+ const msg = (error as Error).message;
308
+ expect(msg).to.include('fromAddress');
309
+ }
310
+ });
311
+
312
+ it('should pass validation when fromAmount is omitted in requestParams', async () => {
313
+ // Route has fromAmount='99999' but requestParams has no fromAmount.
314
+ // The fromAmount assertion is skipped when requestParams.fromAmount is undefined.
315
+ // The positive amount check still passes (99999 > 0).
316
+ const quote = createTestQuote(
317
+ { fromAmount: '99999' },
318
+ { fromAmount: undefined },
319
+ );
320
+
321
+ try {
322
+ await bridge.execute(quote, {
323
+ [ProtocolType.Ethereum]: TEST_PRIVATE_KEY,
324
+ });
325
+ } catch (error: unknown) {
326
+ const msg = (error as Error).message;
327
+ expect(
328
+ isValidationError(msg),
329
+ `Expected non-validation error but got: ${msg}`,
330
+ ).to.equal(false);
331
+ }
332
+ });
333
+
334
+ it('should throw when route fromAmount does not match requested', async () => {
335
+ const quote = createTestQuote(
336
+ { fromAmount: '9999999999' },
337
+ { fromAmount: 10000000000n },
338
+ );
339
+
340
+ try {
341
+ await bridge.execute(quote, {
342
+ [ProtocolType.Ethereum]: TEST_PRIVATE_KEY,
343
+ });
344
+ expect.fail('Expected execute to throw');
345
+ } catch (error: unknown) {
346
+ const msg = (error as Error).message;
347
+ expect(msg).to.include('9999999999');
348
+ expect(msg).to.include('10000000000');
349
+ expect(msg).to.include('fromAmount');
350
+ }
351
+ });
352
+
353
+ it('should throw when route fromAmount is zero', async () => {
354
+ // fromAmount=0n is falsy, so the mismatch assertion is skipped.
355
+ // But the positive amount check catches it.
356
+ const quote = createTestQuote(
357
+ { fromAmount: '0' },
358
+ { fromAmount: undefined },
359
+ );
360
+
361
+ try {
362
+ await bridge.execute(quote, {
363
+ [ProtocolType.Ethereum]: TEST_PRIVATE_KEY,
364
+ });
365
+ expect.fail('Expected execute to throw');
366
+ } catch (error: unknown) {
367
+ const msg = (error as Error).message;
368
+ expect(msg).to.include('must be positive');
369
+ }
370
+ });
371
+
372
+ it('should match addresses case-insensitively (mixed vs uppercase)', async () => {
373
+ // Route uses lowercase a-f, requestParams uses uppercase A-F
374
+ // Both should match after toLowerCase()
375
+ const mixedCaseToken = '0xaabb000000000000000000000000000000001122';
376
+ const upperCaseToken = '0xAABB000000000000000000000000000000001122';
377
+ const mixedCaseSender = '0xddee000000000000000000000000000000003344';
378
+ const upperCaseSender = '0xDDEE000000000000000000000000000000003344';
379
+
380
+ const quote = createTestQuote(
381
+ {
382
+ fromTokenAddress: mixedCaseToken,
383
+ toTokenAddress: mixedCaseToken,
384
+ fromAddress: mixedCaseSender,
385
+ toAddress: mixedCaseSender,
386
+ },
387
+ {
388
+ fromToken: upperCaseToken,
389
+ toToken: upperCaseToken,
390
+ fromAddress: upperCaseSender,
391
+ toAddress: upperCaseSender,
392
+ },
393
+ );
394
+
395
+ try {
396
+ await bridge.execute(quote, {
397
+ [ProtocolType.Ethereum]: TEST_PRIVATE_KEY,
398
+ });
399
+ } catch (error: unknown) {
400
+ const msg = (error as Error).message;
401
+ expect(
402
+ isValidationError(msg),
403
+ `Expected non-validation error but got: ${msg}`,
404
+ ).to.equal(false);
405
+ }
406
+ });
407
+
408
+ it('should throw when requestParams.fromAmount is 0n and route has positive amount', async () => {
409
+ // Validates the fix for the fromAmount=0n truthiness bypass:
410
+ // 0n was falsy so `if (requestParams.fromAmount)` would skip the comparison.
411
+ // With `!== undefined`, a 0n request is correctly compared against the route amount.
412
+ const quote = createTestQuote({ fromAmount: '1' }, { fromAmount: 0n });
413
+ try {
414
+ await bridge.execute(quote, {
415
+ [ProtocolType.Ethereum]: TEST_PRIVATE_KEY,
416
+ });
417
+ expect.fail('Expected execute to throw');
418
+ } catch (error: unknown) {
419
+ const msg = (error as Error).message;
420
+ expect(msg).to.include('fromAmount');
421
+ }
422
+ });
423
+
424
+ it('should pass validation for toAmount quote path (fromAmount undefined, toAmount present)', async () => {
425
+ // Tests reverse-quote pattern where toAmount is set and fromAmount is undefined.
426
+ // The fromAmount equality check is skipped when requestParams.fromAmount is undefined.
427
+ // The toAmount equality check passes because route.toAmount matches requestParams.toAmount.
428
+ const quote = createTestQuote(
429
+ { fromAmount: '5000000000', toAmount: '5000000000' },
430
+ { fromAmount: undefined, toAmount: 5000000000n },
431
+ );
432
+ try {
433
+ await bridge.execute(quote, {
434
+ [ProtocolType.Ethereum]: TEST_PRIVATE_KEY,
435
+ });
436
+ } catch (error: unknown) {
437
+ const msg = (error as Error).message;
438
+ expect(
439
+ isValidationError(msg),
440
+ `Expected non-validation error but got: ${msg}`,
441
+ ).to.equal(false);
442
+ }
443
+ });
444
+
445
+ it('should throw when route toAmount is less than requested for reverse quote', async () => {
446
+ // Route estimate.toAmount='100' but requestParams.toAmount=123n -> 100 < 123, should throw
447
+ const quote = createTestQuote(
448
+ { toAmount: '100' },
449
+ { fromAmount: undefined, toAmount: 123n },
450
+ );
451
+ try {
452
+ await bridge.execute(quote, {
453
+ [ProtocolType.Ethereum]: TEST_PRIVATE_KEY,
454
+ });
455
+ expect.fail('Expected execute to throw');
456
+ } catch (error: unknown) {
457
+ const msg = (error as Error).message;
458
+ expect(msg).to.include('toAmount');
459
+ expect(msg).to.include('100');
460
+ expect(msg).to.include('123');
461
+ expect(msg).to.include('is less than');
462
+ }
463
+ });
464
+
465
+ it('should pass validation when route toAmount exceeds requested (reverse quote)', async () => {
466
+ // paulbalaji reproduction: requested 1000000, LiFi returned 1000002.
467
+ // >= semantics: 1000002 >= 1000000 passes validation.
468
+ const quote = createTestQuote(
469
+ { toAmount: '1000002' },
470
+ { fromAmount: undefined, toAmount: 1000000n },
471
+ );
472
+ try {
473
+ await bridge.execute(quote, {
474
+ [ProtocolType.Ethereum]: TEST_PRIVATE_KEY,
475
+ });
476
+ } catch (error: unknown) {
477
+ const msg = (error as Error).message;
478
+ expect(
479
+ isValidationError(msg),
480
+ `Expected non-validation error but got: ${msg}`,
481
+ ).to.equal(false);
482
+ }
483
+ });
484
+ });
485
+
486
+ describe('LiFiBridge.quote() input validation', function () {
487
+ let bridge: LiFiBridge;
488
+
489
+ beforeEach(() => {
490
+ bridge = new LiFiBridge(BRIDGE_CONFIG, testLogger);
491
+ });
492
+
493
+ it('should throw when fromAmount is 0n', async () => {
494
+ try {
495
+ await bridge.quote({
496
+ fromChain: 42161,
497
+ toChain: 1151111081099710,
498
+ fromToken: TOKEN_ADDR,
499
+ toToken: TOKEN_ADDR,
500
+ fromAddress: SENDER_ADDR,
501
+ fromAmount: 0n,
502
+ });
503
+ expect.fail('Expected quote to throw');
504
+ } catch (error: unknown) {
505
+ expect((error as Error).message).to.include(
506
+ 'fromAmount must be positive',
507
+ );
508
+ }
509
+ });
510
+
511
+ it('should throw when toAmount is 0n', async () => {
512
+ try {
513
+ await bridge.quote({
514
+ fromChain: 42161,
515
+ toChain: 1151111081099710,
516
+ fromToken: TOKEN_ADDR,
517
+ toToken: TOKEN_ADDR,
518
+ fromAddress: SENDER_ADDR,
519
+ toAmount: 0n,
520
+ });
521
+ expect.fail('Expected quote to throw');
522
+ } catch (error: unknown) {
523
+ expect((error as Error).message).to.include('toAmount must be positive');
524
+ }
525
+ });
526
+
527
+ it('should throw when both fromAmount and toAmount are provided', async () => {
528
+ try {
529
+ await bridge.quote({
530
+ fromChain: 42161,
531
+ toChain: 1151111081099710,
532
+ fromToken: TOKEN_ADDR,
533
+ toToken: TOKEN_ADDR,
534
+ fromAddress: SENDER_ADDR,
535
+ fromAmount: 10000000000n,
536
+ toAmount: 5000000000n,
537
+ });
538
+ expect.fail('Expected quote to throw');
539
+ } catch (error: unknown) {
540
+ expect((error as Error).message).to.include('Cannot specify both');
541
+ }
542
+ });
543
+
544
+ it('should throw when neither fromAmount nor toAmount is provided', async () => {
545
+ try {
546
+ await bridge.quote({
547
+ fromChain: 42161,
548
+ toChain: 1151111081099710,
549
+ fromToken: TOKEN_ADDR,
550
+ toToken: TOKEN_ADDR,
551
+ fromAddress: SENDER_ADDR,
552
+ });
553
+ expect.fail('Expected quote to throw');
554
+ } catch (error: unknown) {
555
+ expect((error as Error).message).to.include('Must specify either');
556
+ }
557
+ });
558
+ });
559
+
560
+ describe('LiFiBridge.getStatus()', function () {
561
+ let bridge: LiFiBridge;
562
+
563
+ beforeEach(() => {
564
+ bridge = new LiFiBridge(BRIDGE_CONFIG, testLogger);
565
+ });
566
+
567
+ it('should translate Hyperlane domain IDs to LiFi chain IDs before SDK status lookup', async () => {
568
+ const originalFetch = globalThis.fetch;
569
+ let requestUrl = '';
570
+
571
+ globalThis.fetch = (async (input: URL | RequestInfo) => {
572
+ requestUrl = String(input);
573
+ return {
574
+ ok: true,
575
+ json: async () => ({ status: 'NOT_FOUND' }),
576
+ } as Response;
577
+ }) as typeof fetch;
578
+
579
+ try {
580
+ const result = await bridge.getStatus('0x1234', 1399811149, 1399811149);
581
+ const params = new URL(requestUrl).searchParams;
582
+
583
+ expect(result.status).to.equal('not_found');
584
+ expect(params.get('fromChain')).to.equal('1151111081099710');
585
+ expect(params.get('toChain')).to.equal('1151111081099710');
586
+ } finally {
587
+ globalThis.fetch = originalFetch;
588
+ }
589
+ });
590
+ });
591
+
592
+ describe('LiFiBridge constructor chainMetadataByChainId', function () {
593
+ it('should resolve Sealevel protocol using a LiFi chain ID mapped from Hyperlane metadata', async () => {
594
+ const bridge = new LiFiBridge(SOLANA_CHAIN_METADATA_CONFIG, testLogger);
595
+ const quote = createTestQuote(
596
+ {
597
+ toTokenAddress: 'Abcdef123456789ABCDEFGHijklmnopQRSTUVwx',
598
+ },
599
+ {
600
+ toToken: 'abcdef123456789abcdefghijklmnopqrstuvwx',
601
+ },
602
+ );
603
+
604
+ try {
605
+ await bridge.execute(quote, {
606
+ [ProtocolType.Ethereum]: TEST_PRIVATE_KEY,
607
+ });
608
+ expect.fail('Expected execute to throw');
609
+ } catch (error: unknown) {
610
+ const msg = (error as Error).message;
611
+ expect(msg).to.include('toToken');
612
+ expect(msg).to.include('does not match requested');
613
+ }
614
+ });
615
+ });