@humanode-hyperlane/rebalancer 27.2.2 → 1029.1.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 (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
@@ -229,6 +229,53 @@ describe('Rebalancer', () => {
229
229
  expect(results[0].success).to.be.false;
230
230
  });
231
231
 
232
+ it('should log scaled route amounts using origin local units', async () => {
233
+ const ctx = createRebalancerTestContext(['ethereum']);
234
+ ctx.tokensByChainName.ethereum.scale = {
235
+ numerator: 1,
236
+ denominator: 1_000_000_000_000,
237
+ };
238
+
239
+ const logger = {
240
+ child: Sinon.stub(),
241
+ info: Sinon.stub(),
242
+ warn: Sinon.stub(),
243
+ error: Sinon.stub(),
244
+ };
245
+ logger.child.returns(logger);
246
+
247
+ const rebalancer = new Rebalancer(
248
+ ctx.warpCore,
249
+ ctx.chainMetadata,
250
+ ctx.tokensByChainName,
251
+ ctx.multiProvider as any,
252
+ createMockActionTracker(),
253
+ logger as any,
254
+ );
255
+
256
+ const route = buildTestMovableCollateralRoute({
257
+ origin: 'ethereum',
258
+ destination: 'arbitrum',
259
+ amount: 1_000_000n,
260
+ });
261
+ const results = await rebalancer.rebalance([route]);
262
+
263
+ expect(results).to.have.lengthOf(1);
264
+ expect(results[0].success).to.be.false;
265
+ const validationErrorCall = logger.error
266
+ .getCalls()
267
+ .find(
268
+ (call) =>
269
+ call.args[1] ===
270
+ 'Route validation failed: destination token not found.',
271
+ );
272
+ expect(validationErrorCall).to.not.be.undefined;
273
+ expect(validationErrorCall!.args[0].amount).to.equal(1);
274
+ expect(validationErrorCall!.args[1]).to.equal(
275
+ 'Route validation failed: destination token not found.',
276
+ );
277
+ });
278
+
232
279
  it('should fail when signer is not a rebalancer', async () => {
233
280
  const ctx = createRebalancerTestContext(['ethereum', 'arbitrum'], {
234
281
  ethereum: { isRebalancer: false },
@@ -337,6 +384,43 @@ describe('Rebalancer', () => {
337
384
  expect(results).to.have.lengthOf(1);
338
385
  expect(results[0].success).to.be.false;
339
386
  });
387
+
388
+ it('should denormalize canonical route amounts before quote and populate calls', async () => {
389
+ const ctx = createRebalancerTestContext(['ethereum', 'arbitrum']);
390
+ ctx.tokensByChainName.ethereum.scale = {
391
+ numerator: 1,
392
+ denominator: 1_000_000_000_000,
393
+ };
394
+
395
+ sandbox.stub(HyperlaneCore, 'getDispatchedMessages').returns([
396
+ {
397
+ id: '0x1111111111111111111111111111111111111111111111111111111111111111',
398
+ } as any,
399
+ ]);
400
+
401
+ const rebalancer = new Rebalancer(
402
+ ctx.warpCore,
403
+ ctx.chainMetadata,
404
+ ctx.tokensByChainName,
405
+ ctx.multiProvider as any,
406
+ createMockActionTracker(),
407
+ testLogger,
408
+ );
409
+
410
+ await rebalancer.rebalance([
411
+ buildTestMovableCollateralRoute({
412
+ amount: 1_000_000n,
413
+ }),
414
+ ]);
415
+
416
+ expect(ctx.adapters.ethereum.getRebalanceQuotes.calledOnce).to.be.true;
417
+ expect(
418
+ ctx.adapters.ethereum.getRebalanceQuotes.firstCall.args[3],
419
+ ).to.equal(1_000_000_000_000_000_000n);
420
+ expect(
421
+ ctx.adapters.ethereum.populateRebalanceTx.firstCall.args[1],
422
+ ).to.equal(1_000_000_000_000_000_000n);
423
+ });
340
424
  });
341
425
 
342
426
  describe('executeTransactions()', () => {
@@ -25,10 +25,16 @@ import { MovableCollateralRoute } from '../interfaces/IStrategy.js';
25
25
  import { type Metrics } from '../metrics/Metrics.js';
26
26
  import type { IActionTracker } from '../tracking/IActionTracker.js';
27
27
  import type { RebalanceIntent } from '../tracking/types.js';
28
+ import {
29
+ denormalizeToLocal,
30
+ normalizeToCanonical,
31
+ } from '../utils/balanceUtils.js';
28
32
 
29
33
  // Internal types with intentId for tracking
30
34
  type InternalExecutionResult = MovableCollateralExecutionResult & {
31
35
  intentId: string;
36
+ canonicalAmount?: bigint;
37
+ localAmount?: bigint;
32
38
  };
33
39
 
34
40
  type InternalRoute = MovableCollateralRoute & { intentId: string };
@@ -104,7 +110,10 @@ export class Rebalancer implements IMovableCollateralRebalancer {
104
110
  if (token) {
105
111
  this.metrics.recordRebalanceAmount(
106
112
  result.route,
107
- token.amount(result.route.amount),
113
+ token.amount(
114
+ result.localAmount ??
115
+ denormalizeToLocal(result.route.amount, token),
116
+ ),
108
117
  );
109
118
  }
110
119
  }
@@ -150,7 +159,7 @@ export class Rebalancer implements IMovableCollateralRebalancer {
150
159
  intentId,
151
160
  origin: this.multiProvider.getDomainId(result.route.origin),
152
161
  destination: this.multiProvider.getDomainId(result.route.destination),
153
- amount: result.route.amount,
162
+ amount: result.canonicalAmount ?? result.route.amount,
154
163
  type: 'rebalance_message',
155
164
  messageId: result.messageId,
156
165
  txHash: result.txHash,
@@ -264,8 +273,9 @@ export class Rebalancer implements IMovableCollateralRebalancer {
264
273
  const originToken = this.tokensByChainName[origin];
265
274
  const destinationToken = this.tokensByChainName[destination];
266
275
  const destinationChainMeta = this.chainMetadata[destination];
276
+ const localAmount = denormalizeToLocal(amount, originToken);
267
277
 
268
- const originTokenAmount = originToken.amount(amount);
278
+ const originTokenAmount = originToken.amount(localAmount);
269
279
  const decimalFormattedAmount =
270
280
  originTokenAmount.getDecimalFormattedAmount();
271
281
  const originHypAdapter = originToken.getHypAdapter(
@@ -281,7 +291,7 @@ export class Rebalancer implements IMovableCollateralRebalancer {
281
291
  bridge,
282
292
  destinationChainMeta.domainId,
283
293
  destinationToken.addressOrDenom,
284
- amount,
294
+ localAmount,
285
295
  );
286
296
  } catch (error) {
287
297
  this.logger.error(
@@ -302,7 +312,7 @@ export class Rebalancer implements IMovableCollateralRebalancer {
302
312
  try {
303
313
  populatedTx = await originHypAdapter.populateRebalanceTx(
304
314
  destinationChainMeta.domainId,
305
- amount,
315
+ localAmount,
306
316
  bridge,
307
317
  quotes,
308
318
  );
@@ -337,7 +347,8 @@ export class Rebalancer implements IMovableCollateralRebalancer {
337
347
  return false;
338
348
  }
339
349
 
340
- const originTokenAmount = originToken.amount(amount);
350
+ const localAmount = denormalizeToLocal(amount, originToken);
351
+ const originTokenAmount = originToken.amount(localAmount);
341
352
  const decimalFormattedAmount =
342
353
  originTokenAmount.getDecimalFormattedAmount();
343
354
 
@@ -676,6 +687,11 @@ export class Rebalancer implements IMovableCollateralRebalancer {
676
687
  success: true,
677
688
  messageId: dispatchedMessages[0].id,
678
689
  txHash: receipt.transactionHash,
690
+ canonicalAmount: normalizeToCanonical(
691
+ transaction.originTokenAmount.amount,
692
+ transaction.originTokenAmount.token,
693
+ ),
694
+ localAmount: transaction.originTokenAmount.amount,
679
695
  };
680
696
  }
681
697
 
@@ -646,7 +646,6 @@ describe('RebalancerOrchestrator', () => {
646
646
  expect(inventoryRebalancer.rebalance.calledWith([])).to.be.false;
647
647
  });
648
648
 
649
- // eslint-disable-next-line jest/expect-expect
650
649
  it('should NOT call inventoryRebalancer.rebalance([]) when inventoryRebalancer is not in rebalancers', async () => {
651
650
  const strategy = createMockStrategy();
652
651
  strategy.getRebalancingRoutes.returns([]);
@@ -366,6 +366,41 @@ describe('RebalancerService', () => {
366
366
  expect(calledRoutes[0].destination).to.equal('arbitrum');
367
367
  });
368
368
 
369
+ it('should normalize manual amount to canonical units when token has scale', async () => {
370
+ const rebalancer = createMockRebalancer();
371
+ const warpCore = {
372
+ tokens: [
373
+ {
374
+ ...createMockToken('ethereum'),
375
+ decimals: 18,
376
+ scale: { numerator: 1n, denominator: 1_000_000_000_000n },
377
+ },
378
+ createMockToken('arbitrum'),
379
+ ],
380
+ multiProvider: createMockMultiProvider(),
381
+ } as unknown as WarpCore;
382
+
383
+ const contextFactory = createMockContextFactory({ rebalancer, warpCore });
384
+ sandbox.stub(RebalancerContextFactory, 'create').resolves(contextFactory);
385
+
386
+ const service = new RebalancerService(
387
+ createMockMultiProvider(),
388
+ undefined,
389
+ {} as any,
390
+ createMockRebalancerConfig(),
391
+ { mode: 'manual', logger: testLogger },
392
+ );
393
+
394
+ await service.executeManual({
395
+ origin: 'ethereum',
396
+ destination: 'arbitrum',
397
+ amount: '1',
398
+ });
399
+
400
+ const calledRoutes = rebalancer.rebalance.firstCall.args[0];
401
+ expect(calledRoutes[0].amount).to.equal(1_000_000n);
402
+ });
403
+
369
404
  it('should throw when origin token not found', async () => {
370
405
  const warpCore = {
371
406
  tokens: [createMockToken('arbitrum')],
@@ -6,7 +6,7 @@ import {
6
6
  type MultiProvider,
7
7
  Token,
8
8
  } from '@humanode-hyperlane/sdk';
9
- import { ProtocolType, assert, toWei } from '@humanode-hyperlane/utils';
9
+ import { ProtocolType, assert } from '@humanode-hyperlane/utils';
10
10
 
11
11
  import { RebalancerConfig } from '../config/RebalancerConfig.js';
12
12
  import {
@@ -30,6 +30,7 @@ import { Metrics } from '../metrics/Metrics.js';
30
30
  import { type InventoryMonitorConfig, Monitor } from '../monitor/Monitor.js';
31
31
  import type { IActionTracker } from '../tracking/IActionTracker.js';
32
32
  import { InflightContextAdapter } from '../tracking/InflightContextAdapter.js';
33
+ import { normalizeConfiguredAmount } from '../utils/balanceUtils.js';
33
34
 
34
35
  import type { RebalancerOrchestrator } from './RebalancerOrchestrator.js';
35
36
 
@@ -296,7 +297,7 @@ export class RebalancerService {
296
297
  const manualRoute: MovableCollateralRoute & { intentId: string } = {
297
298
  origin,
298
299
  destination,
299
- amount: BigInt(toWei(amount, originToken.decimals)),
300
+ amount: normalizeConfiguredAmount(amount, originToken),
300
301
  executionType: 'movableCollateral',
301
302
  bridge,
302
303
  intentId: `manual-${Date.now()}`,
@@ -24,6 +24,8 @@ import {
24
24
  TEST_CHAIN_CONFIGS,
25
25
  } from '../fixtures/routes.js';
26
26
 
27
+ import { createLocalProvider } from './LocalProvider.js';
28
+
27
29
  export interface LocalDeploymentContext<
28
30
  TDeployedAddresses extends {
29
31
  chains: Record<string, { mailbox: string; ism: string }>;
@@ -94,7 +96,7 @@ export abstract class BaseLocalDeploymentManager<
94
96
  );
95
97
  this.containers.set(config.name, container);
96
98
  const endpoint = `http://${container.getHost()}:${container.getMappedPort(8545)}`;
97
- const provider = new providers.JsonRpcProvider(endpoint);
99
+ const provider = createLocalProvider(endpoint);
98
100
  providersByChain.set(config.name, provider);
99
101
 
100
102
  await provider.send('anvil_setBalance', [
@@ -0,0 +1,16 @@
1
+ import { expect } from 'chai';
2
+
3
+ import { createLocalProvider } from './LocalProvider.js';
4
+
5
+ describe('createLocalProvider', () => {
6
+ it('uses fast polling for each fresh local provider', () => {
7
+ const url = 'http://127.0.0.1:8545';
8
+ const first = createLocalProvider(url);
9
+ const replacement = createLocalProvider(url);
10
+
11
+ expect(first.pollingInterval).to.equal(100);
12
+ expect(replacement.pollingInterval).to.equal(100);
13
+ expect(replacement).not.to.equal(first);
14
+ expect(replacement.connection.url).to.equal(url);
15
+ });
16
+ });
@@ -0,0 +1,10 @@
1
+ import { providers } from 'ethers';
2
+
3
+ // Anvil mines immediately; ethers' 4s default adds idle time to transaction waits.
4
+ const LOCAL_POLLING_INTERVAL_MS = 100;
5
+
6
+ export function createLocalProvider(url: string): providers.JsonRpcProvider {
7
+ const provider = new providers.JsonRpcProvider(url);
8
+ provider.pollingInterval = LOCAL_POLLING_INTERVAL_MS;
9
+ return provider;
10
+ }
@@ -115,10 +115,11 @@ export class NativeLocalDeploymentManager extends BaseLocalDeploymentManager<Nat
115
115
  for (const chain of TEST_CHAIN_CONFIGS) {
116
116
  const provider = providersByChain.get(chain.name)!;
117
117
  const deployer = deployerWallet.connect(provider);
118
- await deployer.sendTransaction({
118
+ const seedTx = await deployer.sendTransaction({
119
119
  to: bridgeRouters[chain.name].address,
120
120
  value: bridgeSeedAmount,
121
121
  });
122
+ await seedTx.wait();
122
123
  }
123
124
 
124
125
  return {
@@ -8,10 +8,7 @@ import {
8
8
  import { assert, retryAsync } from '@humanode-hyperlane/utils';
9
9
 
10
10
  import { ANVIL_TEST_PRIVATE_KEY, TEST_CHAINS } from '../fixtures/routes.js';
11
-
12
- function createFreshProvider(url: string): providers.JsonRpcProvider {
13
- return new providers.JsonRpcProvider(url);
14
- }
11
+ import { createLocalProvider } from './LocalProvider.js';
15
12
 
16
13
  /**
17
14
  * Revert all chains to their snapshots, take new snapshots, and refresh
@@ -39,7 +36,7 @@ export async function resetSnapshotsAndRefreshProviders({
39
36
 
40
37
  for (const [chain, oldProvider] of Array.from(localProviders.entries())) {
41
38
  const url = oldProvider.connection.url;
42
- const freshProvider = createFreshProvider(url);
39
+ const freshProvider = createLocalProvider(url);
43
40
  localProviders.set(chain, freshProvider);
44
41
  multiProvider.setProvider(chain, freshProvider);
45
42
  multiProvider.setSigner(chain, signerWallet.connect(freshProvider));
@@ -25,9 +25,9 @@ export async function getFirstMonitorEvent(
25
25
  return new Promise((resolve, reject) => {
26
26
  let settled = false;
27
27
 
28
- async function finalize(
29
- cb: (v: any) => void, // eslint-disable-line @typescript-eslint/no-explicit-any -- accepts both resolve and reject
30
- value: unknown,
28
+ async function finalize<T>(
29
+ cb: (v: T) => void,
30
+ value: T,
31
31
  timer: ReturnType<typeof setTimeout>,
32
32
  ) {
33
33
  if (settled) return;
@@ -18,6 +18,7 @@ import { RebalancerConfig } from '../../config/RebalancerConfig.js';
18
18
  import {
19
19
  DEFAULT_INTENT_TTL_MS,
20
20
  ExternalBridgeType,
21
+ type PendingTransferMiddlewareConfig,
21
22
  type StrategyConfig,
22
23
  getStrategyChainNames,
23
24
  } from '../../config/types.js';
@@ -112,6 +113,8 @@ export class TestRebalancerBuilder {
112
113
  private balanceConfig: BalanceConfig = 'BALANCED';
113
114
  private pendingTransfers: PendingTransferParams[] = [];
114
115
  private mockTransfers: ExplorerMessage[] = [];
116
+ private mockRebalanceActions: ExplorerMessage[] = [];
117
+ private pendingTransferMiddlewares: PendingTransferMiddlewareConfig[] = [];
115
118
  private executionMode: ExecutionMode = 'propose';
116
119
  private inventoryConfig: TestInventoryConfig | undefined;
117
120
  private erc20InventoryConfig: TestErc20InventoryConfig | undefined;
@@ -150,6 +153,18 @@ export class TestRebalancerBuilder {
150
153
  return this;
151
154
  }
152
155
 
156
+ withMockRebalanceAction(message: ExplorerMessage): this {
157
+ this.mockRebalanceActions.push(message);
158
+ return this;
159
+ }
160
+
161
+ withPendingTransferMiddlewares(
162
+ configs: PendingTransferMiddlewareConfig[],
163
+ ): this {
164
+ this.pendingTransferMiddlewares = configs;
165
+ return this;
166
+ }
167
+
153
168
  withExecutionMode(mode: ExecutionMode): this {
154
169
  this.executionMode = mode;
155
170
  return this;
@@ -310,6 +325,7 @@ export class TestRebalancerBuilder {
310
325
  },
311
326
  },
312
327
  { lifi: { integrator: 'test' } },
328
+ this.pendingTransferMiddlewares,
313
329
  );
314
330
  warpCoreConfig = buildErc20InventoryWarpRouteConfig(
315
331
  erc20InventoryModeConfig.erc20DeployedAddresses,
@@ -330,6 +346,7 @@ export class TestRebalancerBuilder {
330
346
  },
331
347
  },
332
348
  { lifi: { integrator: 'test' } },
349
+ this.pendingTransferMiddlewares,
333
350
  );
334
351
  warpCoreConfig = buildNativeWarpRouteConfig(
335
352
  inventoryModeConfig.nativeDeployedAddresses,
@@ -342,6 +359,9 @@ export class TestRebalancerBuilder {
342
359
  MONITORED_ROUTE_ID,
343
360
  this.strategyConfig,
344
361
  DEFAULT_INTENT_TTL_MS,
362
+ undefined,
363
+ undefined,
364
+ this.pendingTransferMiddlewares,
345
365
  );
346
366
  warpCoreConfig = buildWarpRouteConfig(deployedAddresses);
347
367
  }
@@ -701,7 +721,7 @@ export class TestRebalancerBuilder {
701
721
 
702
722
  return {
703
723
  userTransfers,
704
- rebalanceActions: [],
724
+ rebalanceActions: [...this.mockRebalanceActions],
705
725
  };
706
726
  }
707
727