@humanode-hyperlane/rebalancer 27.2.2 → 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
@@ -0,0 +1,192 @@
1
+ import { expect } from 'chai';
2
+ import { BigNumber } from 'ethers';
3
+ import { pino } from 'pino';
4
+ import Sinon from 'sinon';
5
+
6
+ import type { ChainName, MultiProvider, Token } from '@humanode-hyperlane/sdk';
7
+ import { TokenStandard } from '@humanode-hyperlane/sdk';
8
+ import { ProtocolType } from '@humanode-hyperlane/utils';
9
+
10
+ import {
11
+ calculateTransferCosts,
12
+ estimateTransferRemoteGas,
13
+ } from './gasEstimation.js';
14
+
15
+ const testLogger = pino({ level: 'silent' });
16
+
17
+ describe('calculateTransferCosts — Tron vs Sealevel protocol path', () => {
18
+ afterEach(() => {
19
+ Sinon.restore();
20
+ });
21
+
22
+ function createMockDeps(protocol: ProtocolType) {
23
+ const mockAdapter = {
24
+ quoteTransferRemoteGas: Sinon.stub().resolves({
25
+ igpQuote: { amount: 1000n },
26
+ tokenFeeQuote: { amount: 0n, addressOrDenom: '' },
27
+ }),
28
+ populateTransferRemoteTx: Sinon.stub().resolves({
29
+ to: '0xRouter',
30
+ data: '0x',
31
+ value: 1000n,
32
+ }),
33
+ };
34
+
35
+ const mockToken = {
36
+ standard: TokenStandard.EvmHypNative, // Native so we reach the isEVMLike check
37
+ getHypAdapter: Sinon.stub().returns(mockAdapter),
38
+ } as unknown as Token;
39
+
40
+ const mockProvider = {
41
+ estimateGas: Sinon.stub().resolves(BigNumber.from(200000)),
42
+ getFeeData: Sinon.stub().resolves({
43
+ maxFeePerGas: BigNumber.from(10_000_000_000n),
44
+ gasPrice: BigNumber.from(10_000_000_000n),
45
+ }),
46
+ };
47
+ const multiProvider = {
48
+ getDomainId: Sinon.stub().returns(42161),
49
+ getProtocol: Sinon.stub().returns(protocol),
50
+ getProvider: Sinon.stub().returns(mockProvider),
51
+ } as unknown as MultiProvider;
52
+
53
+ const getTokenForChain = Sinon.stub().returns(mockToken);
54
+ const isNativeTokenStandard = Sinon.stub().returns(true);
55
+
56
+ return {
57
+ multiProvider,
58
+ getTokenForChain,
59
+ isNativeTokenStandard,
60
+ mockAdapter,
61
+ mockProvider,
62
+ };
63
+ }
64
+
65
+ it('uses one quote consistently for EVM-native reservation and estimation', async () => {
66
+ const {
67
+ multiProvider,
68
+ getTokenForChain,
69
+ isNativeTokenStandard,
70
+ mockAdapter,
71
+ } = createMockDeps(ProtocolType.Ethereum);
72
+ mockAdapter.quoteTransferRemoteGas
73
+ .onSecondCall()
74
+ .rejects(new Error('duplicate quote'));
75
+ const result = await calculateTransferCosts(
76
+ 'ethereum',
77
+ 'arbitrum',
78
+ 3_000_000_000_000_000n,
79
+ 3_000_000_000_000_000n,
80
+ multiProvider,
81
+ {},
82
+ getTokenForChain,
83
+ '0xInventorySigner',
84
+ isNativeTokenStandard,
85
+ testLogger,
86
+ );
87
+ expect(mockAdapter.quoteTransferRemoteGas.callCount).to.equal(1);
88
+ expect(
89
+ mockAdapter.populateTransferRemoteTx.firstCall.args[0].interchainGas,
90
+ ).to.equal(result.gasQuote);
91
+ expect(result.igpCost).to.equal(1000n);
92
+ expect(result.gasCost).to.equal(2_200_000_000_000_000n);
93
+ expect(result.totalCost).to.equal(2_200_000_000_001_000n);
94
+ expect(result.maxTransferable).to.equal(799_999_999_999_000n);
95
+ expect(result.minViableTransfer).to.equal(4_400_000_000_002_000n);
96
+ });
97
+
98
+ it('retains the fallback gas reserve when estimation fails', async () => {
99
+ const {
100
+ multiProvider,
101
+ getTokenForChain,
102
+ isNativeTokenStandard,
103
+ mockAdapter,
104
+ mockProvider,
105
+ } = createMockDeps(ProtocolType.Ethereum);
106
+ mockProvider.estimateGas.rejects(new Error('estimate unavailable'));
107
+ const result = await calculateTransferCosts(
108
+ 'ethereum',
109
+ 'arbitrum',
110
+ 10_000_000_000_000_000n,
111
+ 5_000_000_000_000_000n,
112
+ multiProvider,
113
+ {},
114
+ getTokenForChain,
115
+ '0xInventorySigner',
116
+ isNativeTokenStandard,
117
+ testLogger,
118
+ );
119
+ expect(mockAdapter.quoteTransferRemoteGas.callCount).to.equal(1);
120
+ expect(result.gasCost).to.equal(3_300_000_000_000_000n);
121
+ expect(result.igpCost).to.equal(1000n);
122
+ });
123
+
124
+ it('still obtains a quote for standalone gas estimation', async () => {
125
+ const { multiProvider, getTokenForChain, mockAdapter } = createMockDeps(
126
+ ProtocolType.Ethereum,
127
+ );
128
+ const estimate = await estimateTransferRemoteGas(
129
+ 'ethereum',
130
+ 'arbitrum',
131
+ 100n,
132
+ multiProvider,
133
+ {},
134
+ getTokenForChain,
135
+ '0xInventorySigner',
136
+ testLogger,
137
+ );
138
+ expect(estimate).to.equal(200000n);
139
+ expect(mockAdapter.quoteTransferRemoteGas.callCount).to.equal(1);
140
+ expect(mockAdapter.quoteTransferRemoteGas.firstCall.args[0]).to.deep.equal({
141
+ destination: 42161,
142
+ sender: '0xInventorySigner',
143
+ recipient: '0xInventorySigner',
144
+ amount: 100n,
145
+ });
146
+ });
147
+
148
+ it('Tron origin (EVM-like) produces non-zero gasCost for native tokens', async () => {
149
+ const { multiProvider, getTokenForChain, isNativeTokenStandard } =
150
+ createMockDeps(ProtocolType.Tron);
151
+
152
+ const result = await calculateTransferCosts(
153
+ 'tron' as ChainName,
154
+ 'arbitrum' as ChainName,
155
+ 10000000000000000000n, // 10 ETH available
156
+ 1000000000000000000n, // 1 ETH requested
157
+ multiProvider,
158
+ {} as any, // warpCoreMultiProvider
159
+ getTokenForChain,
160
+ '0xInventorySigner',
161
+ isNativeTokenStandard,
162
+ testLogger,
163
+ );
164
+
165
+ // Tron is EVM-like — gas estimation runs, producing gasCost > 0
166
+ expect(result.gasCost > 0n).to.be.true;
167
+ expect(result.igpCost).to.equal(1000n);
168
+ expect(result.maxTransferable > 0n).to.be.true;
169
+ });
170
+
171
+ it('Sealevel origin (non-EVM) returns gasCost = 0 for native tokens', async () => {
172
+ const { multiProvider, getTokenForChain, isNativeTokenStandard } =
173
+ createMockDeps(ProtocolType.Sealevel);
174
+
175
+ const result = await calculateTransferCosts(
176
+ 'solana' as ChainName,
177
+ 'arbitrum' as ChainName,
178
+ 200000000000n,
179
+ 100000000000n,
180
+ multiProvider,
181
+ {} as any,
182
+ getTokenForChain,
183
+ '0xInventorySigner',
184
+ isNativeTokenStandard,
185
+ testLogger,
186
+ );
187
+
188
+ // Sealevel is non-EVM — gasCost is 0 (skips gas estimation)
189
+ expect(result.gasCost).to.equal(0n);
190
+ expect(result.igpCost).to.equal(1000n);
191
+ });
192
+ });
@@ -11,8 +11,8 @@ import {
11
11
  } from '@humanode-hyperlane/sdk';
12
12
  import {
13
13
  addBufferToGasLimit,
14
+ isEVMLike,
14
15
  isZeroishAddress,
15
- ProtocolType,
16
16
  } from '@humanode-hyperlane/utils';
17
17
 
18
18
  /**
@@ -60,6 +60,7 @@ export interface TransferCostEstimate {
60
60
  * @param getTokenForChain - Function to get token for a chain
61
61
  * @param inventorySigner - Address of the inventory signer
62
62
  * @param logger - Logger instance
63
+ * @param providedGasQuote - Quote already obtained for this exact transfer-cost calculation
63
64
  * @returns Estimated gas limit for the transaction
64
65
  */
65
66
  export async function estimateTransferRemoteGas(
@@ -71,6 +72,7 @@ export async function estimateTransferRemoteGas(
71
72
  getTokenForChain: (chain: ChainName) => Token | undefined,
72
73
  inventorySigner: string,
73
74
  logger: Logger,
75
+ providedGasQuote?: InterchainGasQuote,
74
76
  ): Promise<bigint> {
75
77
  const originToken = getTokenForChain(originChain);
76
78
  if (!originToken) {
@@ -85,13 +87,16 @@ export async function estimateTransferRemoteGas(
85
87
  const destinationDomain = multiProvider.getDomainId(destinationChain);
86
88
  const adapter = originToken.getHypAdapter(warpCoreMultiProvider);
87
89
 
88
- // Quote the IGP gas first (needed for the full transaction)
89
- const gasQuote = await adapter.quoteTransferRemoteGas({
90
- destination: destinationDomain,
91
- sender: inventorySigner,
92
- recipient: inventorySigner,
93
- amount,
94
- });
90
+ // Reuse the quote from this cost calculation when supplied; standalone
91
+ // estimation still obtains a fresh quote for its own transfer parameters.
92
+ const gasQuote =
93
+ providedGasQuote ??
94
+ (await adapter.quoteTransferRemoteGas({
95
+ destination: destinationDomain,
96
+ sender: inventorySigner,
97
+ recipient: inventorySigner,
98
+ amount,
99
+ }));
95
100
 
96
101
  // Populate with minimal amount for gas estimation
97
102
  // Gas cost is independent of transfer size (just a require check in _transferFromSender),
@@ -211,13 +216,13 @@ export async function calculateTransferCosts(
211
216
  ? (gasQuote.tokenFeeQuote?.amount ?? 0n)
212
217
  : 0n;
213
218
 
214
- // Skip gas estimation for non-EVM chains (e.g., Solana).
219
+ // Skip gas estimation for non-EVM-like chains (e.g., Solana).
215
220
  // Non-EVM chains have negligible base fees (~5000 lamports ~$0.0001 on Solana)
216
221
  // compared to EVM gas costs ($0.50-$50/tx). The IGP (Interchain Gas Paymaster)
217
222
  // reservation dominates the cost, not chain-specific gas. Thus gasCost=0 is a
218
- // safe approximation for non-EVM origin chains.
223
+ // safe approximation for non-EVM-like origin chains.
219
224
  const originProtocol = multiProvider.getProtocol(originChain);
220
- if (originProtocol !== ProtocolType.Ethereum) {
225
+ if (!isEVMLike(originProtocol)) {
221
226
  const totalCost = igpCost + tokenFeeCost;
222
227
  let maxTransferable: bigint;
223
228
  if (availableInventory <= totalCost) {
@@ -251,6 +256,7 @@ export async function calculateTransferCosts(
251
256
  getTokenForChain,
252
257
  inventorySigner,
253
258
  logger,
259
+ gasQuote,
254
260
  );
255
261
  const bufferedGasLimit = addBufferToGasLimit(
256
262
  BigNumber.from(estimatedGasLimit.toString()),
@@ -13,15 +13,18 @@ const REBALANCEABLE_TOKEN_COLLATERALIZED_STANDARDS = new Set<TokenStandard>([
13
13
  TokenStandard.EvmHypNative,
14
14
  TokenStandard.SealevelHypCollateral,
15
15
  TokenStandard.SealevelHypNative,
16
+ TokenStandard.TronHypCollateral,
17
+ TokenStandard.TronHypNative,
16
18
  ]);
17
19
 
18
- // SDK-backed native token standard check scoped to EVM and Sealevel only (2-protocol scope).
20
+ // SDK-backed native token standard check scoped to EVM, Sealevel, and Tron (3-protocol scope).
19
21
  // NOTE: We intentionally do NOT use the full PROTOCOL_TO_HYP_NATIVE_STANDARD map (all 7 protocols)
20
- // because the rebalancer only supports EVM and Sealevel native token bridging.
22
+ // because the rebalancer only supports EVM, Sealevel, and Tron native token bridging.
21
23
  // Expanding this would change gas reservation behavior for other protocols.
22
24
  const REBALANCER_NATIVE_STANDARDS = new Set([
23
25
  PROTOCOL_TO_HYP_NATIVE_STANDARD[ProtocolType.Ethereum],
24
26
  PROTOCOL_TO_HYP_NATIVE_STANDARD[ProtocolType.Sealevel],
27
+ PROTOCOL_TO_HYP_NATIVE_STANDARD[ProtocolType.Tron],
25
28
  ]);
26
29
 
27
30
  /**