@humanode-hyperlane/rebalancer 27.2.2-humanode.1 → 1029.1.0

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 (295) hide show
  1. package/dist/bridges/LiFiBridge.d.ts +3 -3
  2. package/dist/bridges/LiFiBridge.d.ts.map +1 -1
  3. package/dist/bridges/LiFiBridge.js +66 -55
  4. package/dist/bridges/LiFiBridge.js.map +1 -1
  5. package/dist/bridges/LiFiBridge.test.js +213 -0
  6. package/dist/bridges/LiFiBridge.test.js.map +1 -1
  7. package/dist/config/RebalancerConfig.d.ts +4 -3
  8. package/dist/config/RebalancerConfig.d.ts.map +1 -1
  9. package/dist/config/RebalancerConfig.js +7 -5
  10. package/dist/config/RebalancerConfig.js.map +1 -1
  11. package/dist/config/RebalancerConfig.test.js +278 -2
  12. package/dist/config/RebalancerConfig.test.js.map +1 -1
  13. package/dist/config/types.d.ts +707 -2664
  14. package/dist/config/types.d.ts.map +1 -1
  15. package/dist/config/types.js +62 -7
  16. package/dist/config/types.js.map +1 -1
  17. package/dist/core/InventoryRebalancer.d.ts +13 -19
  18. package/dist/core/InventoryRebalancer.d.ts.map +1 -1
  19. package/dist/core/InventoryRebalancer.js +404 -276
  20. package/dist/core/InventoryRebalancer.js.map +1 -1
  21. package/dist/core/InventoryRebalancer.test.js +814 -25
  22. package/dist/core/InventoryRebalancer.test.js.map +1 -1
  23. package/dist/core/Rebalancer.d.ts.map +1 -1
  24. package/dist/core/Rebalancer.js +12 -6
  25. package/dist/core/Rebalancer.js.map +1 -1
  26. package/dist/core/Rebalancer.test.js +51 -0
  27. package/dist/core/Rebalancer.test.js.map +1 -1
  28. package/dist/core/RebalancerOrchestrator.d.ts.map +1 -1
  29. package/dist/core/RebalancerOrchestrator.test.js +0 -1
  30. package/dist/core/RebalancerOrchestrator.test.js.map +1 -1
  31. package/dist/core/RebalancerService.d.ts.map +1 -1
  32. package/dist/core/RebalancerService.js +3 -2
  33. package/dist/core/RebalancerService.js.map +1 -1
  34. package/dist/core/RebalancerService.test.js +24 -0
  35. package/dist/core/RebalancerService.test.js.map +1 -1
  36. package/dist/e2e/fixtures/routes.d.ts +3 -3
  37. package/dist/e2e/fixtures/routes.d.ts.map +1 -1
  38. package/dist/e2e/harness/BaseLocalDeploymentManager.d.ts.map +1 -1
  39. package/dist/e2e/harness/BaseLocalDeploymentManager.js +3 -2
  40. package/dist/e2e/harness/BaseLocalDeploymentManager.js.map +1 -1
  41. package/dist/e2e/harness/Erc20InventoryLocalDeploymentManager.d.ts.map +1 -1
  42. package/dist/e2e/harness/Erc20InventoryLocalDeploymentManager.js.map +1 -1
  43. package/dist/e2e/harness/Erc20LocalDeploymentManager.d.ts.map +1 -1
  44. package/dist/e2e/harness/ForkIndexer.d.ts.map +1 -1
  45. package/dist/e2e/harness/ForkIndexer.js.map +1 -1
  46. package/dist/e2e/harness/LocalProvider.d.ts +3 -0
  47. package/dist/e2e/harness/LocalProvider.d.ts.map +1 -0
  48. package/dist/e2e/harness/LocalProvider.js +9 -0
  49. package/dist/e2e/harness/LocalProvider.js.map +1 -0
  50. package/dist/e2e/harness/LocalProvider.test.d.ts +2 -0
  51. package/dist/e2e/harness/LocalProvider.test.d.ts.map +1 -0
  52. package/dist/e2e/harness/LocalProvider.test.js +14 -0
  53. package/dist/e2e/harness/LocalProvider.test.js.map +1 -0
  54. package/dist/e2e/harness/MixedLocalDeploymentManager.d.ts.map +1 -1
  55. package/dist/e2e/harness/MixedLocalDeploymentManager.js.map +1 -1
  56. package/dist/e2e/harness/MockExplorerClient.d.ts.map +1 -1
  57. package/dist/e2e/harness/MockExplorerClient.js.map +1 -1
  58. package/dist/e2e/harness/MockExternalBridge.d.ts.map +1 -1
  59. package/dist/e2e/harness/MockExternalBridge.js.map +1 -1
  60. package/dist/e2e/harness/NativeLocalDeploymentManager.d.ts.map +1 -1
  61. package/dist/e2e/harness/NativeLocalDeploymentManager.js +2 -1
  62. package/dist/e2e/harness/NativeLocalDeploymentManager.js.map +1 -1
  63. package/dist/e2e/harness/SnapshotHelper.d.ts.map +1 -1
  64. package/dist/e2e/harness/SnapshotHelper.js +3 -5
  65. package/dist/e2e/harness/SnapshotHelper.js.map +1 -1
  66. package/dist/e2e/harness/TestHelpers.js +1 -2
  67. package/dist/e2e/harness/TestHelpers.js.map +1 -1
  68. package/dist/e2e/harness/TestRebalancer.d.ts +5 -1
  69. package/dist/e2e/harness/TestRebalancer.d.ts.map +1 -1
  70. package/dist/e2e/harness/TestRebalancer.js +14 -4
  71. package/dist/e2e/harness/TestRebalancer.js.map +1 -1
  72. package/dist/e2e/relayer-denylist.e2e-test.d.ts +2 -0
  73. package/dist/e2e/relayer-denylist.e2e-test.d.ts.map +1 -0
  74. package/dist/e2e/relayer-denylist.e2e-test.js +388 -0
  75. package/dist/e2e/relayer-denylist.e2e-test.js.map +1 -0
  76. package/dist/factories/RebalancerContextFactory.d.ts.map +1 -1
  77. package/dist/factories/RebalancerContextFactory.js +61 -31
  78. package/dist/factories/RebalancerContextFactory.js.map +1 -1
  79. package/dist/factories/RebalancerContextFactory.test.js +336 -5
  80. package/dist/factories/RebalancerContextFactory.test.js.map +1 -1
  81. package/dist/index.d.ts +2 -2
  82. package/dist/index.d.ts.map +1 -1
  83. package/dist/index.js +1 -1
  84. package/dist/index.js.map +1 -1
  85. package/dist/interfaces/IRebalancer.d.ts +4 -2
  86. package/dist/interfaces/IRebalancer.d.ts.map +1 -1
  87. package/dist/metrics/Metrics.d.ts.map +1 -1
  88. package/dist/metrics/Metrics.js +1 -1
  89. package/dist/metrics/Metrics.js.map +1 -1
  90. package/dist/metrics/PriceGetter.d.ts +1 -0
  91. package/dist/metrics/PriceGetter.d.ts.map +1 -1
  92. package/dist/metrics/PriceGetter.js +14 -4
  93. package/dist/metrics/PriceGetter.js.map +1 -1
  94. package/dist/metrics/PriceGetter.test.d.ts +2 -0
  95. package/dist/metrics/PriceGetter.test.d.ts.map +1 -0
  96. package/dist/metrics/PriceGetter.test.js +84 -0
  97. package/dist/metrics/PriceGetter.test.js.map +1 -0
  98. package/dist/metrics/scripts/metrics.d.ts +4 -4
  99. package/dist/monitor/Monitor.d.ts +1 -0
  100. package/dist/monitor/Monitor.d.ts.map +1 -1
  101. package/dist/monitor/Monitor.js +55 -46
  102. package/dist/monitor/Monitor.js.map +1 -1
  103. package/dist/monitor/Monitor.test.d.ts +2 -0
  104. package/dist/monitor/Monitor.test.d.ts.map +1 -0
  105. package/dist/monitor/Monitor.test.js +346 -0
  106. package/dist/monitor/Monitor.test.js.map +1 -0
  107. package/dist/service.d.ts +1 -1
  108. package/dist/service.d.ts.map +1 -1
  109. package/dist/service.js +9 -5
  110. package/dist/service.js.map +1 -1
  111. package/dist/strategy/BaseStrategy.d.ts.map +1 -1
  112. package/dist/strategy/BaseStrategy.js +13 -11
  113. package/dist/strategy/BaseStrategy.js.map +1 -1
  114. package/dist/strategy/CollateralDeficitStrategy.d.ts.map +1 -1
  115. package/dist/strategy/CollateralDeficitStrategy.js +2 -2
  116. package/dist/strategy/CollateralDeficitStrategy.js.map +1 -1
  117. package/dist/strategy/CompositeStrategy.d.ts.map +1 -1
  118. package/dist/strategy/CompositeStrategy.js.map +1 -1
  119. package/dist/strategy/CompositeStrategy.test.js.map +1 -1
  120. package/dist/strategy/MinAmountStrategy.d.ts +1 -0
  121. package/dist/strategy/MinAmountStrategy.d.ts.map +1 -1
  122. package/dist/strategy/MinAmountStrategy.js +12 -8
  123. package/dist/strategy/MinAmountStrategy.js.map +1 -1
  124. package/dist/strategy/MinAmountStrategy.test.js +189 -2
  125. package/dist/strategy/MinAmountStrategy.test.js.map +1 -1
  126. package/dist/strategy/StrategyFactory.d.ts.map +1 -1
  127. package/dist/strategy/StrategyFactory.js.map +1 -1
  128. package/dist/strategy/WeightedStrategy.d.ts.map +1 -1
  129. package/dist/test/helpers.d.ts +11 -3
  130. package/dist/test/helpers.d.ts.map +1 -1
  131. package/dist/test/helpers.js +9 -11
  132. package/dist/test/helpers.js.map +1 -1
  133. package/dist/test/lifiMocks.d.ts +6 -6
  134. package/dist/test/lifiMocks.d.ts.map +1 -1
  135. package/dist/test/lifiMocks.js +5 -2
  136. package/dist/test/lifiMocks.js.map +1 -1
  137. package/dist/test/pendingTransferMiddlewareMocks.d.ts +17 -0
  138. package/dist/test/pendingTransferMiddlewareMocks.d.ts.map +1 -0
  139. package/dist/test/pendingTransferMiddlewareMocks.js +43 -0
  140. package/dist/test/pendingTransferMiddlewareMocks.js.map +1 -0
  141. package/dist/tracking/ActionTracker.d.ts +4 -0
  142. package/dist/tracking/ActionTracker.d.ts.map +1 -1
  143. package/dist/tracking/ActionTracker.js +76 -9
  144. package/dist/tracking/ActionTracker.js.map +1 -1
  145. package/dist/tracking/ActionTracker.test.js +418 -1
  146. package/dist/tracking/ActionTracker.test.js.map +1 -1
  147. package/dist/tracking/IActionTracker.d.ts +4 -2
  148. package/dist/tracking/IActionTracker.d.ts.map +1 -1
  149. package/dist/tracking/InflightContextAdapter.d.ts.map +1 -1
  150. package/dist/tracking/InflightContextAdapter.js.map +1 -1
  151. package/dist/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.d.ts +64 -0
  152. package/dist/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.d.ts.map +1 -0
  153. package/dist/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.js +474 -0
  154. package/dist/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.js.map +1 -0
  155. package/dist/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.test.d.ts +2 -0
  156. package/dist/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.test.d.ts.map +1 -0
  157. package/dist/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.test.js +1168 -0
  158. package/dist/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.test.js.map +1 -0
  159. package/dist/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.d.ts +61 -0
  160. package/dist/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.d.ts.map +1 -0
  161. package/dist/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.js +160 -0
  162. package/dist/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.js.map +1 -0
  163. package/dist/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.test.d.ts +2 -0
  164. package/dist/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.test.d.ts.map +1 -0
  165. package/dist/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.test.js +369 -0
  166. package/dist/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.test.js.map +1 -0
  167. package/dist/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.d.ts +60 -0
  168. package/dist/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.d.ts.map +1 -0
  169. package/dist/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.js +288 -0
  170. package/dist/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.js.map +1 -0
  171. package/dist/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.test.d.ts +2 -0
  172. package/dist/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.test.d.ts.map +1 -0
  173. package/dist/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.test.js +606 -0
  174. package/dist/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.test.js.map +1 -0
  175. package/dist/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.d.ts +25 -0
  176. package/dist/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.d.ts.map +1 -0
  177. package/dist/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.js +41 -0
  178. package/dist/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.js.map +1 -0
  179. package/dist/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.test.d.ts +2 -0
  180. package/dist/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.test.d.ts.map +1 -0
  181. package/dist/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.test.js +141 -0
  182. package/dist/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.test.js.map +1 -0
  183. package/dist/tracking/pendingTransferMiddlewares/matchBody.d.ts +12 -0
  184. package/dist/tracking/pendingTransferMiddlewares/matchBody.d.ts.map +1 -0
  185. package/dist/tracking/pendingTransferMiddlewares/matchBody.js +29 -0
  186. package/dist/tracking/pendingTransferMiddlewares/matchBody.js.map +1 -0
  187. package/dist/tracking/pendingTransferMiddlewares/relayerDenylistRules.d.ts +59 -0
  188. package/dist/tracking/pendingTransferMiddlewares/relayerDenylistRules.d.ts.map +1 -0
  189. package/dist/tracking/pendingTransferMiddlewares/relayerDenylistRules.js +661 -0
  190. package/dist/tracking/pendingTransferMiddlewares/relayerDenylistRules.js.map +1 -0
  191. package/dist/tracking/pendingTransferMiddlewares/relayerDenylistRules.test.d.ts +2 -0
  192. package/dist/tracking/pendingTransferMiddlewares/relayerDenylistRules.test.d.ts.map +1 -0
  193. package/dist/tracking/pendingTransferMiddlewares/relayerDenylistRules.test.js +1093 -0
  194. package/dist/tracking/pendingTransferMiddlewares/relayerDenylistRules.test.js.map +1 -0
  195. package/dist/tracking/pendingTransferMiddlewares/types.d.ts +2 -0
  196. package/dist/tracking/pendingTransferMiddlewares/types.d.ts.map +1 -0
  197. package/dist/tracking/pendingTransferMiddlewares/types.js +4 -0
  198. package/dist/tracking/pendingTransferMiddlewares/types.js.map +1 -0
  199. package/dist/tracking/store/InMemoryStore.d.ts.map +1 -1
  200. package/dist/utils/ExplorerClient.d.ts +1 -0
  201. package/dist/utils/ExplorerClient.d.ts.map +1 -1
  202. package/dist/utils/ExplorerClient.js +8 -3
  203. package/dist/utils/ExplorerClient.js.map +1 -1
  204. package/dist/utils/ExplorerClient.test.js +25 -0
  205. package/dist/utils/ExplorerClient.test.js.map +1 -1
  206. package/dist/utils/balanceUtils.d.ts +7 -1
  207. package/dist/utils/balanceUtils.d.ts.map +1 -1
  208. package/dist/utils/balanceUtils.js +39 -1
  209. package/dist/utils/balanceUtils.js.map +1 -1
  210. package/dist/utils/balanceUtils.test.js +55 -1
  211. package/dist/utils/balanceUtils.test.js.map +1 -1
  212. package/dist/utils/blockTag.d.ts +5 -4
  213. package/dist/utils/blockTag.d.ts.map +1 -1
  214. package/dist/utils/blockTag.js +26 -10
  215. package/dist/utils/blockTag.js.map +1 -1
  216. package/dist/utils/blockTag.test.d.ts +2 -0
  217. package/dist/utils/blockTag.test.d.ts.map +1 -0
  218. package/dist/utils/blockTag.test.js +132 -0
  219. package/dist/utils/blockTag.test.js.map +1 -0
  220. package/dist/utils/bridgeUtils.js.map +1 -1
  221. package/dist/utils/errors.d.ts.map +1 -1
  222. package/dist/utils/gasEstimation.d.ts +2 -1
  223. package/dist/utils/gasEstimation.d.ts.map +1 -1
  224. package/dist/utils/gasEstimation.js +16 -13
  225. package/dist/utils/gasEstimation.js.map +1 -1
  226. package/dist/utils/gasEstimation.test.d.ts +2 -0
  227. package/dist/utils/gasEstimation.test.d.ts.map +1 -0
  228. package/dist/utils/gasEstimation.test.js +104 -0
  229. package/dist/utils/gasEstimation.test.js.map +1 -0
  230. package/dist/utils/tokenUtils.d.ts.map +1 -1
  231. package/dist/utils/tokenUtils.js +5 -2
  232. package/dist/utils/tokenUtils.js.map +1 -1
  233. package/package.json +23 -22
  234. package/src/bridges/LiFiBridge.test.ts +270 -0
  235. package/src/bridges/LiFiBridge.ts +90 -71
  236. package/src/config/RebalancerConfig.test.ts +315 -1
  237. package/src/config/RebalancerConfig.ts +6 -3
  238. package/src/config/types.ts +98 -8
  239. package/src/core/InventoryRebalancer.test.ts +1092 -38
  240. package/src/core/InventoryRebalancer.ts +584 -351
  241. package/src/core/Rebalancer.test.ts +84 -0
  242. package/src/core/Rebalancer.ts +22 -6
  243. package/src/core/RebalancerOrchestrator.test.ts +0 -1
  244. package/src/core/RebalancerService.test.ts +35 -0
  245. package/src/core/RebalancerService.ts +3 -2
  246. package/src/e2e/harness/BaseLocalDeploymentManager.ts +3 -1
  247. package/src/e2e/harness/LocalProvider.test.ts +16 -0
  248. package/src/e2e/harness/LocalProvider.ts +10 -0
  249. package/src/e2e/harness/NativeLocalDeploymentManager.ts +2 -1
  250. package/src/e2e/harness/SnapshotHelper.ts +2 -5
  251. package/src/e2e/harness/TestHelpers.ts +3 -3
  252. package/src/e2e/harness/TestRebalancer.ts +21 -1
  253. package/src/e2e/relayer-denylist.e2e-test.ts +558 -0
  254. package/src/factories/RebalancerContextFactory.test.ts +489 -8
  255. package/src/factories/RebalancerContextFactory.ts +86 -36
  256. package/src/index.ts +2 -0
  257. package/src/interfaces/IRebalancer.ts +4 -1
  258. package/src/metrics/Metrics.ts +1 -0
  259. package/src/metrics/PriceGetter.test.ts +113 -0
  260. package/src/metrics/PriceGetter.ts +18 -3
  261. package/src/monitor/Monitor.test.ts +408 -0
  262. package/src/monitor/Monitor.ts +123 -97
  263. package/src/service.ts +14 -8
  264. package/src/strategy/BaseStrategy.ts +18 -15
  265. package/src/strategy/CollateralDeficitStrategy.ts +4 -3
  266. package/src/strategy/MinAmountStrategy.test.ts +238 -2
  267. package/src/strategy/MinAmountStrategy.ts +29 -17
  268. package/src/test/helpers.ts +13 -12
  269. package/src/test/lifiMocks.ts +5 -2
  270. package/src/test/pendingTransferMiddlewareMocks.ts +65 -0
  271. package/src/tracking/ActionTracker.test.ts +635 -3
  272. package/src/tracking/ActionTracker.ts +92 -12
  273. package/src/tracking/IActionTracker.ts +4 -2
  274. package/src/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.test.ts +1693 -0
  275. package/src/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.ts +784 -0
  276. package/src/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.test.ts +554 -0
  277. package/src/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.ts +233 -0
  278. package/src/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.test.ts +894 -0
  279. package/src/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.ts +404 -0
  280. package/src/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.test.ts +205 -0
  281. package/src/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.ts +89 -0
  282. package/src/tracking/pendingTransferMiddlewares/fixtures/mainnet-denylist.json +3556 -0
  283. package/src/tracking/pendingTransferMiddlewares/matchBody.ts +43 -0
  284. package/src/tracking/pendingTransferMiddlewares/relayerDenylistRules.test.ts +1220 -0
  285. package/src/tracking/pendingTransferMiddlewares/relayerDenylistRules.ts +934 -0
  286. package/src/tracking/pendingTransferMiddlewares/types.ts +3 -0
  287. package/src/utils/ExplorerClient.test.ts +42 -0
  288. package/src/utils/ExplorerClient.ts +14 -3
  289. package/src/utils/balanceUtils.test.ts +87 -1
  290. package/src/utils/balanceUtils.ts +73 -2
  291. package/src/utils/blockTag.test.ts +173 -0
  292. package/src/utils/blockTag.ts +35 -15
  293. package/src/utils/gasEstimation.test.ts +192 -0
  294. package/src/utils/gasEstimation.ts +17 -11
  295. package/src/utils/tokenUtils.ts +5 -2
@@ -15,6 +15,7 @@ const testLogger = pino({ level: 'silent' });
15
15
 
16
16
  const TEST_PRIVATE_KEY =
17
17
  '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
18
+ const OTHER_PRIVATE_KEY = `${TEST_PRIVATE_KEY.slice(0, -1)}1`;
18
19
 
19
20
  const BRIDGE_CONFIG: ExternalBridgeConfig = {
20
21
  integrator: 'test-rebalancer',
@@ -34,6 +35,58 @@ const SOLANA_CHAIN_METADATA_CONFIG: ExternalBridgeConfig = {
34
35
  },
35
36
  };
36
37
 
38
+ const DUPLICATE_CHAIN_ID_CONFIG: ExternalBridgeConfig = {
39
+ integrator: 'test-rebalancer',
40
+ chainMetadata: {
41
+ ethereum: {
42
+ chainId: 1,
43
+ protocol: ProtocolType.Ethereum,
44
+ name: 'ethereum',
45
+ displayName: 'Ethereum',
46
+ domainId: 1,
47
+ rpcUrls: [{ http: 'https://ethereum-rpc.local' }],
48
+ },
49
+ radix: {
50
+ chainId: 1,
51
+ protocol: ProtocolType.Radix,
52
+ name: 'radix',
53
+ displayName: 'Radix',
54
+ domainId: 1001,
55
+ rpcUrls: [{ http: 'https://radix-rpc.local' }],
56
+ },
57
+ solanamainnet: {
58
+ chainId: 1399811149,
59
+ protocol: ProtocolType.Sealevel,
60
+ name: 'solanamainnet',
61
+ displayName: 'Solana',
62
+ domainId: 1399811149,
63
+ rpcUrls: [{ http: 'https://api.mainnet-beta.solana.com' }],
64
+ },
65
+ },
66
+ };
67
+
68
+ const NON_EVM_DOMAIN_COLLISION_CONFIG: ExternalBridgeConfig = {
69
+ integrator: 'test-rebalancer',
70
+ chainMetadata: {
71
+ ethereum: {
72
+ chainId: 1,
73
+ protocol: ProtocolType.Ethereum,
74
+ name: 'ethereum',
75
+ displayName: 'Ethereum',
76
+ domainId: 1,
77
+ rpcUrls: [{ http: 'https://ethereum-rpc.local' }],
78
+ },
79
+ cosmos: {
80
+ chainId: 999999999,
81
+ protocol: ProtocolType.Cosmos,
82
+ name: 'cosmos',
83
+ displayName: 'Cosmos',
84
+ domainId: 1,
85
+ rpcUrls: [{ http: 'https://rpc.cosmos.invalid' }],
86
+ },
87
+ },
88
+ };
89
+
37
90
  // Use all-digit hex addresses to avoid EIP-55 checksum case mutations
38
91
  const TOKEN_ADDR = '0x1234567890123456789012345678901234567890';
39
92
  const SENDER_ADDR = '0x9876543210987654321098765432109876543210';
@@ -557,6 +610,49 @@ describe('LiFiBridge.quote() input validation', function () {
557
610
  });
558
611
  });
559
612
 
613
+ describe('LiFiBridge.quote() routing policy', function () {
614
+ let bridge: LiFiBridge;
615
+
616
+ beforeEach(() => {
617
+ bridge = new LiFiBridge(BRIDGE_CONFIG, testLogger);
618
+ });
619
+
620
+ it('should use RECOMMENDED order for reverse toAmount quotes', async () => {
621
+ const originalFetch = globalThis.fetch;
622
+ let requestUrl = '';
623
+
624
+ globalThis.fetch = (async (input: URL | RequestInfo) => {
625
+ requestUrl = String(input);
626
+ return {
627
+ ok: true,
628
+ json: async () =>
629
+ createLiFiStep({
630
+ toChainId: 1151111081099710,
631
+ toAmount: '5000000000',
632
+ }),
633
+ } as Response;
634
+ }) as typeof fetch;
635
+
636
+ try {
637
+ const quote = await bridge.quote({
638
+ fromChain: 42161,
639
+ toChain: 1151111081099710,
640
+ fromToken: TOKEN_ADDR,
641
+ toToken: TOKEN_ADDR,
642
+ fromAddress: SENDER_ADDR,
643
+ toAddress: SENDER_ADDR,
644
+ toAmount: 5000000000n,
645
+ });
646
+ const params = new URL(requestUrl).searchParams;
647
+
648
+ expect(params.get('order')).to.equal('RECOMMENDED');
649
+ expect(quote.requestParams.toAmount).to.equal(5000000000n);
650
+ } finally {
651
+ globalThis.fetch = originalFetch;
652
+ }
653
+ });
654
+ });
655
+
560
656
  describe('LiFiBridge.getStatus()', function () {
561
657
  let bridge: LiFiBridge;
562
658
 
@@ -612,4 +708,178 @@ describe('LiFiBridge constructor chainMetadataByChainId', function () {
612
708
  expect(msg).to.include('does not match requested');
613
709
  }
614
710
  });
711
+
712
+ it('should prefer Ethereum metadata for LiFi chainId lookups when non-EVM chainIds collide', () => {
713
+ const bridge = new LiFiBridge(DUPLICATE_CHAIN_ID_CONFIG, testLogger);
714
+ const quote = createTestQuote(
715
+ { fromChainId: 1 },
716
+ {
717
+ fromChain: 1,
718
+ toChain: 1151111081099710,
719
+ },
720
+ );
721
+
722
+ return bridge
723
+ .execute(quote, {
724
+ [ProtocolType.Ethereum]: '0x1234',
725
+ })
726
+ .catch((error: unknown) => {
727
+ const msg = error instanceof Error ? error.message : String(error);
728
+ expect(
729
+ isValidationError(msg),
730
+ `Expected non-validation error but got: ${msg}`,
731
+ ).to.equal(false);
732
+ expect(msg).to.not.include('Missing private key');
733
+ expect(msg).to.not.include('protocol radix');
734
+ expect(msg.toLowerCase()).to.include('private key');
735
+ });
736
+ });
737
+
738
+ it('should index Tron by chainId even when domainId differs', () => {
739
+ const TRON_CHAIN_ID = 728126428;
740
+ const bridge = new LiFiBridge(
741
+ {
742
+ integrator: 'test-rebalancer',
743
+ chainMetadata: {
744
+ tron: {
745
+ chainId: TRON_CHAIN_ID,
746
+ protocol: ProtocolType.Tron,
747
+ name: 'tron',
748
+ displayName: 'Tron',
749
+ domainId: 999000999,
750
+ rpcUrls: [{ http: 'https://api.trongrid.io/jsonrpc' }],
751
+ },
752
+ },
753
+ },
754
+ testLogger,
755
+ );
756
+ const getProtocolTypeForChainId = (
757
+ bridge as any
758
+ ).getProtocolTypeForChainId.bind(bridge);
759
+
760
+ expect(getProtocolTypeForChainId(TRON_CHAIN_ID)).to.equal(
761
+ ProtocolType.Tron,
762
+ );
763
+ expect(getProtocolTypeForChainId(999000999)).to.equal(undefined);
764
+ });
765
+
766
+ it('should not let non-EVM domainIds overwrite EVM chainId lookups', () => {
767
+ const bridge = new LiFiBridge(NON_EVM_DOMAIN_COLLISION_CONFIG, testLogger);
768
+ const getProtocolTypeForChainId = (
769
+ bridge as any
770
+ ).getProtocolTypeForChainId.bind(bridge);
771
+
772
+ expect(getProtocolTypeForChainId(1)).to.equal(ProtocolType.Ethereum);
773
+ expect(getProtocolTypeForChainId(999999999)).to.equal(ProtocolType.Cosmos);
774
+ });
775
+ });
776
+
777
+ describe('LiFiBridge source protocol handling', function () {
778
+ it('ignores unrelated Tron keys when executing an Ethereum LiFi route', async () => {
779
+ const bridge = new LiFiBridge(BRIDGE_CONFIG, testLogger);
780
+ (bridge as any).configureLiFiProvider = (
781
+ protocol: ProtocolType,
782
+ key: string,
783
+ fromChain: number,
784
+ ) => {
785
+ expect(protocol).to.equal(ProtocolType.Ethereum);
786
+ expect(key).to.equal(TEST_PRIVATE_KEY);
787
+ expect(fromChain).to.equal(42161);
788
+ throw new Error('expected downstream error');
789
+ };
790
+
791
+ const quote = createTestQuote();
792
+
793
+ try {
794
+ await bridge.execute(quote, {
795
+ [ProtocolType.Ethereum]: TEST_PRIVATE_KEY,
796
+ [ProtocolType.Tron]: OTHER_PRIVATE_KEY,
797
+ });
798
+ expect.fail('Expected execute to throw');
799
+ } catch (error: unknown) {
800
+ const msg = (error as Error).message;
801
+ expect(msg).to.equal('expected downstream error');
802
+ }
803
+ });
804
+
805
+ it('addressesEqual keeps Sealevel base58 comparison case-sensitive', () => {
806
+ const bridge = new LiFiBridge(SOLANA_CHAIN_METADATA_CONFIG, testLogger);
807
+ const addressesEqualFn = (bridge as any).addressesEqual.bind(bridge);
808
+
809
+ expect(
810
+ addressesEqualFn(
811
+ 'SoLANAAddReSs1234567890123456789012345678',
812
+ 'solanaaddress1234567890123456789012345678',
813
+ 1399811149,
814
+ ),
815
+ ).to.be.false;
816
+ });
817
+
818
+ it('throws when the route source protocol is Tron', async () => {
819
+ const TRON_CHAIN_ID = 728126428;
820
+ const bridge = new LiFiBridge(
821
+ {
822
+ integrator: 'test-rebalancer',
823
+ chainMetadata: {
824
+ tron: {
825
+ chainId: TRON_CHAIN_ID,
826
+ protocol: ProtocolType.Tron,
827
+ name: 'tron',
828
+ displayName: 'Tron',
829
+ domainId: TRON_CHAIN_ID,
830
+ rpcUrls: [{ http: 'https://api.trongrid.io/jsonrpc' }],
831
+ },
832
+ },
833
+ },
834
+ testLogger,
835
+ );
836
+ const quote = createTestQuote(
837
+ { fromChainId: TRON_CHAIN_ID },
838
+ { fromChain: TRON_CHAIN_ID },
839
+ );
840
+
841
+ try {
842
+ await bridge.execute(quote, {
843
+ [ProtocolType.Tron]: TEST_PRIVATE_KEY,
844
+ });
845
+ expect.fail('Should have thrown for unsupported source protocol Tron');
846
+ } catch (error: unknown) {
847
+ const msg = (error as Error).message;
848
+ expect(msg).to.include("Unsupported protocol type 'tron'");
849
+ }
850
+ });
851
+
852
+ it('throws when the route source protocol is an unsupported non-Tron chain', async () => {
853
+ const COSMOS_CHAIN_ID = 999999999;
854
+ const bridge = new LiFiBridge(
855
+ {
856
+ integrator: 'test-rebalancer',
857
+ chainMetadata: {
858
+ cosmos: {
859
+ chainId: COSMOS_CHAIN_ID,
860
+ protocol: ProtocolType.Cosmos,
861
+ name: 'cosmos',
862
+ displayName: 'Cosmos',
863
+ domainId: COSMOS_CHAIN_ID,
864
+ rpcUrls: [{ http: 'https://rpc.cosmos.invalid' }],
865
+ },
866
+ },
867
+ },
868
+ testLogger,
869
+ );
870
+ const quote = createTestQuote(
871
+ { fromChainId: COSMOS_CHAIN_ID },
872
+ { fromChain: COSMOS_CHAIN_ID },
873
+ );
874
+
875
+ try {
876
+ await bridge.execute(quote, {
877
+ [ProtocolType.Cosmos]: TEST_PRIVATE_KEY,
878
+ });
879
+ expect.fail('Should have thrown for unsupported source protocol Cosmos');
880
+ } catch (error: unknown) {
881
+ const msg = (error as Error).message;
882
+ expect(msg).to.include("Unsupported protocol type 'cosmos'");
883
+ }
884
+ });
615
885
  });
@@ -14,7 +14,12 @@ import {
14
14
  } from '@lifi/sdk';
15
15
  import bs58 from 'bs58';
16
16
  import type { ChainMetadata } from '@humanode-hyperlane/sdk';
17
- import { ProtocolType, assert, ensure0x } from '@humanode-hyperlane/utils';
17
+ import {
18
+ ProtocolType,
19
+ assert,
20
+ ensure0x,
21
+ isEVMLike,
22
+ } from '@humanode-hyperlane/utils';
18
23
  import type { Logger } from 'pino';
19
24
  import { type Chain, createWalletClient, http } from 'viem';
20
25
  import { privateKeyToAccount } from 'viem/accounts';
@@ -30,6 +35,10 @@ import type {
30
35
  } from '../interfaces/IExternalBridge.js';
31
36
  import { parseSolanaPrivateKey } from '../utils/solanaKeyParser.js';
32
37
 
38
+ const TRAILING_ZEROES_REGEX = /\.?0+$/;
39
+ const API_KEY_REGEX = /apiKey=[^&]+/;
40
+ const TRANSACTION_LINK_REGEX = /\/tx\/([^/]+)/;
41
+
33
42
  /**
34
43
  * LiFi API base URL for REST endpoints.
35
44
  * The SDK doesn't support toAmount quotes, so we use REST API directly.
@@ -133,21 +142,25 @@ export class LiFiBridge implements IExternalBridge {
133
142
  constructor(config: ExternalBridgeConfig, logger: Logger) {
134
143
  this.config = config;
135
144
  this.logger = logger;
136
- // Build chainId -> metadata map for O(1) lookups
145
+ // Build LiFi chainId -> metadata map for O(1) lookups.
146
+ // Numeric chainIds are only unique for EVM chains; non-EVM chains can
147
+ // legitimately collide (e.g. radix and ethereum both use 1), so index
148
+ // non-EVM chains only through explicit Hyperlane-domain -> LiFi mappings.
137
149
  this.chainMetadataByChainId = new Map();
138
150
  if (config.chainMetadata) {
151
+ const metadataByDomainId = new Map<number, ChainMetadata>();
139
152
  for (const metadata of Object.values(config.chainMetadata)) {
140
- if (metadata.chainId !== undefined) {
153
+ metadataByDomainId.set(metadata.domainId, metadata);
154
+ if (metadata.chainId !== undefined && isEVMLike(metadata.protocol)) {
141
155
  this.chainMetadataByChainId.set(Number(metadata.chainId), metadata);
142
156
  }
143
157
  }
144
- // Also key by LiFi chain IDs so both Hyperlane domains and LiFi IDs resolve to the same metadata.
158
+ // Also key by LiFi chain IDs so both Hyperlane domains and LiFi IDs
159
+ // resolve to the same metadata for non-EVM chains like Solana.
145
160
  for (const [hyperlaneDomainId, lifiChainId] of Object.entries(
146
161
  HYPERLANE_TO_LIFI_CHAIN_IDS,
147
162
  )) {
148
- const metadata = this.chainMetadataByChainId.get(
149
- Number(hyperlaneDomainId),
150
- );
163
+ const metadata = metadataByDomainId.get(Number(hyperlaneDomainId));
151
164
  if (metadata !== undefined) {
152
165
  this.chainMetadataByChainId.set(Number(lifiChainId), metadata);
153
166
  }
@@ -179,11 +192,24 @@ export class LiFiBridge implements IExternalBridge {
179
192
  * Iterates metadata to find matching chainId and returns first HTTP RPC URL.
180
193
  */
181
194
  private getRpcUrlForChainId(chainId: number): string | undefined {
182
- return this.chainMetadataByChainId.get(chainId)?.rpcUrls?.[0]?.http;
195
+ return this.getMetadataForChainId(chainId)?.rpcUrls?.[0]?.http;
183
196
  }
184
197
 
185
198
  private getProtocolTypeForChainId(chainId: number): ProtocolType | undefined {
186
- return this.chainMetadataByChainId.get(chainId)?.protocol;
199
+ return this.getMetadataForChainId(chainId)?.protocol;
200
+ }
201
+
202
+ private getMetadataForChainId(chainId: number): ChainMetadata | undefined {
203
+ const directMetadata = this.chainMetadataByChainId.get(chainId);
204
+ if (directMetadata) {
205
+ return directMetadata;
206
+ }
207
+
208
+ const matches = Object.values(this.config.chainMetadata ?? {}).filter(
209
+ (metadata) =>
210
+ metadata.chainId !== undefined && Number(metadata.chainId) === chainId,
211
+ );
212
+ return matches.length === 1 ? matches[0] : undefined;
187
213
  }
188
214
 
189
215
  private addressesEqual(a: string, b: string, chainId: number): boolean {
@@ -196,58 +222,53 @@ export class LiFiBridge implements IExternalBridge {
196
222
  }
197
223
 
198
224
  /**
199
- * Configure LiFi SDK providers from the given private keys.
200
- * Sets up wallet/signer for each protocol type present in the keys map.
225
+ * Configure the LiFi SDK provider for the route source protocol.
201
226
  */
202
- private configureLiFiProviders(
203
- privateKeys: Partial<Record<ProtocolType, string>>,
227
+ private configureLiFiProvider(
228
+ protocol: ProtocolType,
229
+ key: string,
204
230
  fromChain: number,
205
231
  fromRpcUrl: string | undefined,
206
232
  ): void {
207
233
  const providers: Parameters<typeof lifiConfig.setProviders>[0] = [];
208
- for (const [protocol, key] of Object.entries(privateKeys)) {
209
- switch (protocol) {
210
- case ProtocolType.Ethereum: {
211
- const account = privateKeyToAccount(ensure0x(key) as `0x${string}`);
212
- const chain = getViemChain(fromChain, fromRpcUrl);
213
- const walletClient = createWalletClient({
214
- account,
215
- chain,
216
- transport: http(fromRpcUrl),
217
- });
218
- providers.push(
219
- EVM({
220
- getWalletClient: async () => walletClient,
221
- switchChain: async (requiredChainId: number) => {
222
- const switchRpcUrl = this.getRpcUrlForChainId(requiredChainId);
223
- const requiredChain = getViemChain(
224
- requiredChainId,
225
- switchRpcUrl,
226
- );
227
- return createWalletClient({
228
- account,
229
- chain: requiredChain,
230
- transport: http(switchRpcUrl),
231
- });
232
- },
233
- }),
234
- );
235
- break;
236
- }
237
- case ProtocolType.Sealevel: {
238
- const base58Key = toBase58SolanaKey(key);
239
- providers.push(
240
- Solana({
241
- getWalletAdapter: async () => new KeypairWalletAdapter(base58Key),
242
- }),
243
- );
244
- break;
245
- }
246
- default:
247
- throw new Error(
248
- `Unsupported protocol type '${protocol}' for LiFi provider`,
249
- );
234
+ switch (protocol) {
235
+ case ProtocolType.Ethereum: {
236
+ const account = privateKeyToAccount(ensure0x(key) as `0x${string}`);
237
+ const chain = getViemChain(fromChain, fromRpcUrl);
238
+ const walletClient = createWalletClient({
239
+ account,
240
+ chain,
241
+ transport: http(fromRpcUrl),
242
+ });
243
+ providers.push(
244
+ EVM({
245
+ getWalletClient: async () => walletClient,
246
+ switchChain: async (requiredChainId: number) => {
247
+ const switchRpcUrl = this.getRpcUrlForChainId(requiredChainId);
248
+ const requiredChain = getViemChain(requiredChainId, switchRpcUrl);
249
+ return createWalletClient({
250
+ account,
251
+ chain: requiredChain,
252
+ transport: http(switchRpcUrl),
253
+ });
254
+ },
255
+ }),
256
+ );
257
+ break;
258
+ }
259
+ case ProtocolType.Sealevel: {
260
+ const base58Key = toBase58SolanaKey(key);
261
+ providers.push(
262
+ Solana({
263
+ getWalletAdapter: async () => new KeypairWalletAdapter(base58Key),
264
+ }),
265
+ );
266
+ break;
250
267
  }
268
+ default:
269
+ throw new Error(
270
+ `Unsupported protocol type '${protocol}' for LiFi provider`,
271
+ );
251
272
  }
252
273
 
253
274
  lifiConfig.setProviders(providers);
@@ -255,9 +276,9 @@ export class LiFiBridge implements IExternalBridge {
255
276
  this.logger.debug(
256
277
  {
257
278
  fromChain,
258
- protocols: Object.keys(privateKeys),
279
+ protocol,
259
280
  },
260
- 'Configured LiFi providers for route execution',
281
+ 'Configured LiFi provider for route execution',
261
282
  );
262
283
  }
263
284
 
@@ -380,8 +401,8 @@ export class LiFiBridge implements IExternalBridge {
380
401
  toAddress: params.toAddress ?? params.fromAddress,
381
402
  slippage: (params.slippage ?? this.config.defaultSlippage ?? 0.005)
382
403
  .toFixed(4)
383
- .replace(/\.?0+$/, ''),
384
- order: 'CHEAPEST',
404
+ .replace(TRAILING_ZEROES_REGEX, ''),
405
+ order: 'RECOMMENDED',
385
406
  integrator: this.config.integrator,
386
407
  });
387
408
 
@@ -391,7 +412,7 @@ export class LiFiBridge implements IExternalBridge {
391
412
 
392
413
  const url = `${LIFI_API_BASE}/quote/toAmount?${queryParams.toString()}`;
393
414
  this.logger.debug(
394
- { url: url.replace(/apiKey=[^&]+/, 'apiKey=***') },
415
+ { url: url.replace(API_KEY_REGEX, 'apiKey=***') },
395
416
  'Fetching LiFi toAmount quote',
396
417
  );
397
418
 
@@ -491,9 +512,10 @@ export class LiFiBridge implements IExternalBridge {
491
512
  const fromChain = route.fromChainId;
492
513
  const toChain = route.toChainId;
493
514
  const fromProtocol = this.getProtocolTypeForChainId(fromChain);
515
+ const sourceProtocol = fromProtocol ?? ProtocolType.Ethereum;
494
516
  assert(
495
- privateKeys[fromProtocol ?? ProtocolType.Ethereum],
496
- `Missing private key for source chain protocol ${fromProtocol ?? ProtocolType.Ethereum}`,
517
+ privateKeys[sourceProtocol],
518
+ `Missing private key for source chain protocol ${sourceProtocol}`,
497
519
  );
498
520
 
499
521
  this.logger.info(
@@ -521,14 +543,11 @@ export class LiFiBridge implements IExternalBridge {
521
543
  let executedRoute!: RouteExtended;
522
544
 
523
545
  try {
524
- this.configureLiFiProviders(privateKeys, fromChain, fromRpcUrl);
525
-
526
- this.logger.debug(
527
- {
528
- fromChain,
529
- protocols: Object.keys(privateKeys),
530
- },
531
- 'Configured LiFi providers for route execution',
546
+ this.configureLiFiProvider(
547
+ sourceProtocol,
548
+ privateKeys[sourceProtocol]!,
549
+ fromChain,
550
+ fromRpcUrl,
532
551
  );
533
552
 
534
553
  // Execute route with update callbacks
@@ -586,7 +605,7 @@ export class LiFiBridge implements IExternalBridge {
586
605
  if (txInfo && 'lifiExplorerLink' in txInfo) {
587
606
  // Extract transfer ID from explorer link if available
588
607
  const link = (txInfo as { lifiExplorerLink?: string }).lifiExplorerLink;
589
- const match = link?.match(/\/tx\/([^/]+)/);
608
+ const match = link?.match(TRANSACTION_LINK_REGEX);
590
609
  if (match) {
591
610
  transferId = match[1];
592
611
  }