@humanode-hyperlane/rebalancer 0.0.0-stage → 27.2.2-humanode.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +193 -0
- package/README.md +297 -2
- package/dist/bridges/LiFiBridge.d.ts +93 -0
- package/dist/bridges/LiFiBridge.d.ts.map +1 -0
- package/dist/bridges/LiFiBridge.js +527 -0
- package/dist/bridges/LiFiBridge.js.map +1 -0
- package/dist/bridges/LiFiBridge.test.d.ts +2 -0
- package/dist/bridges/LiFiBridge.test.d.ts.map +1 -0
- package/dist/bridges/LiFiBridge.test.js +504 -0
- package/dist/bridges/LiFiBridge.test.js.map +1 -0
- package/dist/config/RebalancerConfig.d.ts +20 -0
- package/dist/config/RebalancerConfig.d.ts.map +1 -0
- package/dist/config/RebalancerConfig.js +35 -0
- package/dist/config/RebalancerConfig.js.map +1 -0
- package/dist/config/RebalancerConfig.test.d.ts +2 -0
- package/dist/config/RebalancerConfig.test.d.ts.map +1 -0
- package/dist/config/RebalancerConfig.test.js +798 -0
- package/dist/config/RebalancerConfig.test.js.map +1 -0
- package/dist/config/types.d.ts +3008 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +451 -0
- package/dist/config/types.js.map +1 -0
- package/dist/core/InventoryRebalancer.d.ts +201 -0
- package/dist/core/InventoryRebalancer.d.ts.map +1 -0
- package/dist/core/InventoryRebalancer.js +994 -0
- package/dist/core/InventoryRebalancer.js.map +1 -0
- package/dist/core/InventoryRebalancer.test.d.ts +2 -0
- package/dist/core/InventoryRebalancer.test.d.ts.map +1 -0
- package/dist/core/InventoryRebalancer.test.js +1511 -0
- package/dist/core/InventoryRebalancer.test.js.map +1 -0
- package/dist/core/Rebalancer.d.ts +37 -0
- package/dist/core/Rebalancer.d.ts.map +1 -0
- package/dist/core/Rebalancer.js +433 -0
- package/dist/core/Rebalancer.js.map +1 -0
- package/dist/core/Rebalancer.test.d.ts +2 -0
- package/dist/core/Rebalancer.test.d.ts.map +1 -0
- package/dist/core/Rebalancer.test.js +424 -0
- package/dist/core/Rebalancer.test.js.map +1 -0
- package/dist/core/RebalancerOrchestrator.d.ts +56 -0
- package/dist/core/RebalancerOrchestrator.d.ts.map +1 -0
- package/dist/core/RebalancerOrchestrator.js +154 -0
- package/dist/core/RebalancerOrchestrator.js.map +1 -0
- package/dist/core/RebalancerOrchestrator.test.d.ts +2 -0
- package/dist/core/RebalancerOrchestrator.test.d.ts.map +1 -0
- package/dist/core/RebalancerOrchestrator.test.js +721 -0
- package/dist/core/RebalancerOrchestrator.test.js.map +1 -0
- package/dist/core/RebalancerService.d.ts +127 -0
- package/dist/core/RebalancerService.d.ts.map +1 -0
- package/dist/core/RebalancerService.js +270 -0
- package/dist/core/RebalancerService.js.map +1 -0
- package/dist/core/RebalancerService.test.d.ts +2 -0
- package/dist/core/RebalancerService.test.d.ts.map +1 -0
- package/dist/core/RebalancerService.test.js +777 -0
- package/dist/core/RebalancerService.test.js.map +1 -0
- package/dist/e2e/collateral-deficit.e2e-test.d.ts +2 -0
- package/dist/e2e/collateral-deficit.e2e-test.d.ts.map +1 -0
- package/dist/e2e/collateral-deficit.e2e-test.js +227 -0
- package/dist/e2e/collateral-deficit.e2e-test.js.map +1 -0
- package/dist/e2e/composite.e2e-test.d.ts +2 -0
- package/dist/e2e/composite.e2e-test.d.ts.map +1 -0
- package/dist/e2e/composite.e2e-test.js +666 -0
- package/dist/e2e/composite.e2e-test.js.map +1 -0
- package/dist/e2e/fixtures/routes.d.ts +89 -0
- package/dist/e2e/fixtures/routes.d.ts.map +1 -0
- package/dist/e2e/fixtures/routes.js +420 -0
- package/dist/e2e/fixtures/routes.js.map +1 -0
- package/dist/e2e/harness/BaseLocalDeploymentManager.d.ts +38 -0
- package/dist/e2e/harness/BaseLocalDeploymentManager.d.ts.map +1 -0
- package/dist/e2e/harness/BaseLocalDeploymentManager.js +144 -0
- package/dist/e2e/harness/BaseLocalDeploymentManager.js.map +1 -0
- package/dist/e2e/harness/BridgeSetup.d.ts +11 -0
- package/dist/e2e/harness/BridgeSetup.d.ts.map +1 -0
- package/dist/e2e/harness/BridgeSetup.js +50 -0
- package/dist/e2e/harness/BridgeSetup.js.map +1 -0
- package/dist/e2e/harness/Erc20InventoryLocalDeploymentManager.d.ts +13 -0
- package/dist/e2e/harness/Erc20InventoryLocalDeploymentManager.d.ts.map +1 -0
- package/dist/e2e/harness/Erc20InventoryLocalDeploymentManager.js +105 -0
- package/dist/e2e/harness/Erc20InventoryLocalDeploymentManager.js.map +1 -0
- package/dist/e2e/harness/Erc20LocalDeploymentManager.d.ts +11 -0
- package/dist/e2e/harness/Erc20LocalDeploymentManager.d.ts.map +1 -0
- package/dist/e2e/harness/Erc20LocalDeploymentManager.js +105 -0
- package/dist/e2e/harness/Erc20LocalDeploymentManager.js.map +1 -0
- package/dist/e2e/harness/ForkIndexer.d.ts +23 -0
- package/dist/e2e/harness/ForkIndexer.d.ts.map +1 -0
- package/dist/e2e/harness/ForkIndexer.js +127 -0
- package/dist/e2e/harness/ForkIndexer.js.map +1 -0
- package/dist/e2e/harness/ForkIndexer.test.d.ts +2 -0
- package/dist/e2e/harness/ForkIndexer.test.d.ts.map +1 -0
- package/dist/e2e/harness/ForkIndexer.test.js +257 -0
- package/dist/e2e/harness/ForkIndexer.test.js.map +1 -0
- package/dist/e2e/harness/MixedLocalDeploymentManager.d.ts +21 -0
- package/dist/e2e/harness/MixedLocalDeploymentManager.d.ts.map +1 -0
- package/dist/e2e/harness/MixedLocalDeploymentManager.js +115 -0
- package/dist/e2e/harness/MixedLocalDeploymentManager.js.map +1 -0
- package/dist/e2e/harness/MockExplorerClient.d.ts +23 -0
- package/dist/e2e/harness/MockExplorerClient.d.ts.map +1 -0
- package/dist/e2e/harness/MockExplorerClient.js +57 -0
- package/dist/e2e/harness/MockExplorerClient.js.map +1 -0
- package/dist/e2e/harness/MockExternalBridge.d.ts +32 -0
- package/dist/e2e/harness/MockExternalBridge.d.ts.map +1 -0
- package/dist/e2e/harness/MockExternalBridge.js +247 -0
- package/dist/e2e/harness/MockExternalBridge.js.map +1 -0
- package/dist/e2e/harness/NativeLocalDeploymentManager.d.ts +13 -0
- package/dist/e2e/harness/NativeLocalDeploymentManager.d.ts.map +1 -0
- package/dist/e2e/harness/NativeLocalDeploymentManager.js +91 -0
- package/dist/e2e/harness/NativeLocalDeploymentManager.js.map +1 -0
- package/dist/e2e/harness/SnapshotHelper.d.ts +13 -0
- package/dist/e2e/harness/SnapshotHelper.d.ts.map +1 -0
- package/dist/e2e/harness/SnapshotHelper.js +36 -0
- package/dist/e2e/harness/SnapshotHelper.js.map +1 -0
- package/dist/e2e/harness/TestHelpers.d.ts +25 -0
- package/dist/e2e/harness/TestHelpers.d.ts.map +1 -0
- package/dist/e2e/harness/TestHelpers.js +103 -0
- package/dist/e2e/harness/TestHelpers.js.map +1 -0
- package/dist/e2e/harness/TestRebalancer.d.ts +85 -0
- package/dist/e2e/harness/TestRebalancer.d.ts.map +1 -0
- package/dist/e2e/harness/TestRebalancer.js +427 -0
- package/dist/e2e/harness/TestRebalancer.js.map +1 -0
- package/dist/e2e/harness/TransferHelper.d.ts +34 -0
- package/dist/e2e/harness/TransferHelper.d.ts.map +1 -0
- package/dist/e2e/harness/TransferHelper.js +93 -0
- package/dist/e2e/harness/TransferHelper.js.map +1 -0
- package/dist/e2e/inventory-erc20-minAmount.e2e-test.d.ts +2 -0
- package/dist/e2e/inventory-erc20-minAmount.e2e-test.d.ts.map +1 -0
- package/dist/e2e/inventory-erc20-minAmount.e2e-test.js +411 -0
- package/dist/e2e/inventory-erc20-minAmount.e2e-test.js.map +1 -0
- package/dist/e2e/inventory-erc20-weighted.e2e-test.d.ts +2 -0
- package/dist/e2e/inventory-erc20-weighted.e2e-test.d.ts.map +1 -0
- package/dist/e2e/inventory-erc20-weighted.e2e-test.js +408 -0
- package/dist/e2e/inventory-erc20-weighted.e2e-test.js.map +1 -0
- package/dist/e2e/inventory-minAmount.e2e-test.d.ts +2 -0
- package/dist/e2e/inventory-minAmount.e2e-test.d.ts.map +1 -0
- package/dist/e2e/inventory-minAmount.e2e-test.js +411 -0
- package/dist/e2e/inventory-minAmount.e2e-test.js.map +1 -0
- package/dist/e2e/inventory-weighted.e2e-test.d.ts +2 -0
- package/dist/e2e/inventory-weighted.e2e-test.d.ts.map +1 -0
- package/dist/e2e/inventory-weighted.e2e-test.js +409 -0
- package/dist/e2e/inventory-weighted.e2e-test.js.map +1 -0
- package/dist/e2e/minAmount.e2e-test.d.ts +2 -0
- package/dist/e2e/minAmount.e2e-test.d.ts.map +1 -0
- package/dist/e2e/minAmount.e2e-test.js +203 -0
- package/dist/e2e/minAmount.e2e-test.js.map +1 -0
- package/dist/e2e/mixed-weighted.e2e-test.d.ts +2 -0
- package/dist/e2e/mixed-weighted.e2e-test.d.ts.map +1 -0
- package/dist/e2e/mixed-weighted.e2e-test.js +189 -0
- package/dist/e2e/mixed-weighted.e2e-test.js.map +1 -0
- package/dist/e2e/weighted.e2e-test.d.ts +2 -0
- package/dist/e2e/weighted.e2e-test.d.ts.map +1 -0
- package/dist/e2e/weighted.e2e-test.js +198 -0
- package/dist/e2e/weighted.e2e-test.js.map +1 -0
- package/dist/factories/RebalancerContextFactory.d.ts +89 -0
- package/dist/factories/RebalancerContextFactory.d.ts.map +1 -0
- package/dist/factories/RebalancerContextFactory.js +420 -0
- package/dist/factories/RebalancerContextFactory.js.map +1 -0
- package/dist/factories/RebalancerContextFactory.test.d.ts +2 -0
- package/dist/factories/RebalancerContextFactory.test.d.ts.map +1 -0
- package/dist/factories/RebalancerContextFactory.test.js +270 -0
- package/dist/factories/RebalancerContextFactory.test.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/IExternalBridge.d.ts +103 -0
- package/dist/interfaces/IExternalBridge.d.ts.map +1 -0
- package/dist/interfaces/IExternalBridge.js +2 -0
- package/dist/interfaces/IExternalBridge.js.map +1 -0
- package/dist/interfaces/IMetrics.d.ts +5 -0
- package/dist/interfaces/IMetrics.d.ts.map +1 -0
- package/dist/interfaces/IMetrics.js +2 -0
- package/dist/interfaces/IMetrics.js.map +1 -0
- package/dist/interfaces/IMonitor.d.ts +50 -0
- package/dist/interfaces/IMonitor.d.ts.map +1 -0
- package/dist/interfaces/IMonitor.js +14 -0
- package/dist/interfaces/IMonitor.js.map +1 -0
- package/dist/interfaces/IRebalancer.d.ts +31 -0
- package/dist/interfaces/IRebalancer.d.ts.map +1 -0
- package/dist/interfaces/IRebalancer.js +2 -0
- package/dist/interfaces/IRebalancer.js.map +1 -0
- package/dist/interfaces/IStrategy.d.ts +60 -0
- package/dist/interfaces/IStrategy.d.ts.map +1 -0
- package/dist/interfaces/IStrategy.js +13 -0
- package/dist/interfaces/IStrategy.js.map +1 -0
- package/dist/metrics/Metrics.d.ts +25 -0
- package/dist/metrics/Metrics.d.ts.map +1 -0
- package/dist/metrics/Metrics.js +164 -0
- package/dist/metrics/Metrics.js.map +1 -0
- package/dist/metrics/PriceGetter.d.ts +10 -0
- package/dist/metrics/PriceGetter.d.ts.map +1 -0
- package/dist/metrics/PriceGetter.js +41 -0
- package/dist/metrics/PriceGetter.js.map +1 -0
- package/dist/metrics/scripts/metrics.d.ts +28 -0
- package/dist/metrics/scripts/metrics.d.ts.map +1 -0
- package/dist/metrics/scripts/metrics.js +61 -0
- package/dist/metrics/scripts/metrics.js.map +1 -0
- package/dist/monitor/Monitor.d.ts +40 -0
- package/dist/monitor/Monitor.d.ts.map +1 -0
- package/dist/monitor/Monitor.js +211 -0
- package/dist/monitor/Monitor.js.map +1 -0
- package/dist/service.d.ts +3 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +205 -0
- package/dist/service.js.map +1 -0
- package/dist/strategy/BaseStrategy.d.ts +86 -0
- package/dist/strategy/BaseStrategy.d.ts.map +1 -0
- package/dist/strategy/BaseStrategy.js +342 -0
- package/dist/strategy/BaseStrategy.js.map +1 -0
- package/dist/strategy/CollateralDeficitStrategy.d.ts +65 -0
- package/dist/strategy/CollateralDeficitStrategy.d.ts.map +1 -0
- package/dist/strategy/CollateralDeficitStrategy.js +253 -0
- package/dist/strategy/CollateralDeficitStrategy.js.map +1 -0
- package/dist/strategy/CollateralDeficitStrategy.test.d.ts +2 -0
- package/dist/strategy/CollateralDeficitStrategy.test.d.ts.map +1 -0
- package/dist/strategy/CollateralDeficitStrategy.test.js +497 -0
- package/dist/strategy/CollateralDeficitStrategy.test.js.map +1 -0
- package/dist/strategy/CompositeStrategy.d.ts +18 -0
- package/dist/strategy/CompositeStrategy.d.ts.map +1 -0
- package/dist/strategy/CompositeStrategy.js +63 -0
- package/dist/strategy/CompositeStrategy.js.map +1 -0
- package/dist/strategy/CompositeStrategy.test.d.ts +2 -0
- package/dist/strategy/CompositeStrategy.test.d.ts.map +1 -0
- package/dist/strategy/CompositeStrategy.test.js +278 -0
- package/dist/strategy/CompositeStrategy.test.js.map +1 -0
- package/dist/strategy/MinAmountStrategy.d.ts +35 -0
- package/dist/strategy/MinAmountStrategy.d.ts.map +1 -0
- package/dist/strategy/MinAmountStrategy.js +112 -0
- package/dist/strategy/MinAmountStrategy.js.map +1 -0
- package/dist/strategy/MinAmountStrategy.test.d.ts +2 -0
- package/dist/strategy/MinAmountStrategy.test.d.ts.map +1 -0
- package/dist/strategy/MinAmountStrategy.test.js +547 -0
- package/dist/strategy/MinAmountStrategy.test.js.map +1 -0
- package/dist/strategy/StrategyFactory.d.ts +27 -0
- package/dist/strategy/StrategyFactory.d.ts.map +1 -0
- package/dist/strategy/StrategyFactory.js +79 -0
- package/dist/strategy/StrategyFactory.js.map +1 -0
- package/dist/strategy/StrategyFactory.test.d.ts +2 -0
- package/dist/strategy/StrategyFactory.test.d.ts.map +1 -0
- package/dist/strategy/StrategyFactory.test.js +81 -0
- package/dist/strategy/StrategyFactory.test.js.map +1 -0
- package/dist/strategy/WeightedStrategy.d.ts +32 -0
- package/dist/strategy/WeightedStrategy.d.ts.map +1 -0
- package/dist/strategy/WeightedStrategy.js +73 -0
- package/dist/strategy/WeightedStrategy.js.map +1 -0
- package/dist/strategy/WeightedStrategy.test.d.ts +2 -0
- package/dist/strategy/WeightedStrategy.test.d.ts.map +1 -0
- package/dist/strategy/WeightedStrategy.test.js +403 -0
- package/dist/strategy/WeightedStrategy.test.js.map +1 -0
- package/dist/strategy/index.d.ts +7 -0
- package/dist/strategy/index.d.ts.map +1 -0
- package/dist/strategy/index.js +7 -0
- package/dist/strategy/index.js.map +1 -0
- package/dist/test/helpers.d.ts +99 -0
- package/dist/test/helpers.d.ts.map +1 -0
- package/dist/test/helpers.js +311 -0
- package/dist/test/helpers.js.map +1 -0
- package/dist/test/lifiMocks.d.ts +52 -0
- package/dist/test/lifiMocks.d.ts.map +1 -0
- package/dist/test/lifiMocks.js +160 -0
- package/dist/test/lifiMocks.js.map +1 -0
- package/dist/tracking/ActionTracker.d.ts +90 -0
- package/dist/tracking/ActionTracker.d.ts.map +1 -0
- package/dist/tracking/ActionTracker.js +678 -0
- package/dist/tracking/ActionTracker.js.map +1 -0
- package/dist/tracking/ActionTracker.test.d.ts +2 -0
- package/dist/tracking/ActionTracker.test.d.ts.map +1 -0
- package/dist/tracking/ActionTracker.test.js +1351 -0
- package/dist/tracking/ActionTracker.test.js.map +1 -0
- package/dist/tracking/IActionTracker.d.ts +157 -0
- package/dist/tracking/IActionTracker.d.ts.map +1 -0
- package/dist/tracking/IActionTracker.js +2 -0
- package/dist/tracking/IActionTracker.js.map +1 -0
- package/dist/tracking/InflightContextAdapter.d.ts +18 -0
- package/dist/tracking/InflightContextAdapter.d.ts.map +1 -0
- package/dist/tracking/InflightContextAdapter.js +52 -0
- package/dist/tracking/InflightContextAdapter.js.map +1 -0
- package/dist/tracking/InflightContextAdapter.test.d.ts +2 -0
- package/dist/tracking/InflightContextAdapter.test.d.ts.map +1 -0
- package/dist/tracking/InflightContextAdapter.test.js +175 -0
- package/dist/tracking/InflightContextAdapter.test.js.map +1 -0
- package/dist/tracking/store/IStore.d.ts +41 -0
- package/dist/tracking/store/IStore.d.ts.map +1 -0
- package/dist/tracking/store/IStore.js +2 -0
- package/dist/tracking/store/IStore.js.map +1 -0
- package/dist/tracking/store/InMemoryStore.d.ts +21 -0
- package/dist/tracking/store/InMemoryStore.d.ts.map +1 -0
- package/dist/tracking/store/InMemoryStore.js +40 -0
- package/dist/tracking/store/InMemoryStore.js.map +1 -0
- package/dist/tracking/store/InMemoryStore.test.d.ts +2 -0
- package/dist/tracking/store/InMemoryStore.test.d.ts.map +1 -0
- package/dist/tracking/store/InMemoryStore.test.js +290 -0
- package/dist/tracking/store/InMemoryStore.test.js.map +1 -0
- package/dist/tracking/store/index.d.ts +3 -0
- package/dist/tracking/store/index.d.ts.map +1 -0
- package/dist/tracking/store/index.js +2 -0
- package/dist/tracking/store/index.js.map +1 -0
- package/dist/tracking/types.d.ts +77 -0
- package/dist/tracking/types.d.ts.map +1 -0
- package/dist/tracking/types.js +2 -0
- package/dist/tracking/types.js.map +1 -0
- package/dist/utils/ExplorerClient.d.ts +68 -0
- package/dist/utils/ExplorerClient.d.ts.map +1 -0
- package/dist/utils/ExplorerClient.js +324 -0
- package/dist/utils/ExplorerClient.js.map +1 -0
- package/dist/utils/ExplorerClient.test.d.ts +2 -0
- package/dist/utils/ExplorerClient.test.d.ts.map +1 -0
- package/dist/utils/ExplorerClient.test.js +261 -0
- package/dist/utils/ExplorerClient.test.js.map +1 -0
- package/dist/utils/balanceUtils.d.ts +12 -0
- package/dist/utils/balanceUtils.d.ts.map +1 -0
- package/dist/utils/balanceUtils.js +40 -0
- package/dist/utils/balanceUtils.js.map +1 -0
- package/dist/utils/balanceUtils.test.d.ts +2 -0
- package/dist/utils/balanceUtils.test.d.ts.map +1 -0
- package/dist/utils/balanceUtils.test.js +55 -0
- package/dist/utils/balanceUtils.test.js.map +1 -0
- package/dist/utils/blockTag.d.ts +14 -0
- package/dist/utils/blockTag.d.ts.map +1 -0
- package/dist/utils/blockTag.js +46 -0
- package/dist/utils/blockTag.js.map +1 -0
- package/dist/utils/bridgeUtils.d.ts +40 -0
- package/dist/utils/bridgeUtils.d.ts.map +1 -0
- package/dist/utils/bridgeUtils.js +54 -0
- package/dist/utils/bridgeUtils.js.map +1 -0
- package/dist/utils/bridgeUtils.test.d.ts +2 -0
- package/dist/utils/bridgeUtils.test.d.ts.map +1 -0
- package/dist/utils/bridgeUtils.test.js +163 -0
- package/dist/utils/bridgeUtils.test.js.map +1 -0
- package/dist/utils/errors.d.ts +4 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +6 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/gasEstimation.d.ts +65 -0
- package/dist/utils/gasEstimation.d.ts.map +1 -0
- package/dist/utils/gasEstimation.js +206 -0
- package/dist/utils/gasEstimation.js.map +1 -0
- package/dist/utils/solanaKeyParser.d.ts +10 -0
- package/dist/utils/solanaKeyParser.d.ts.map +1 -0
- package/dist/utils/solanaKeyParser.js +87 -0
- package/dist/utils/solanaKeyParser.js.map +1 -0
- package/dist/utils/solanaKeyParser.test.d.ts +2 -0
- package/dist/utils/solanaKeyParser.test.d.ts.map +1 -0
- package/dist/utils/solanaKeyParser.test.js +71 -0
- package/dist/utils/solanaKeyParser.test.js.map +1 -0
- package/dist/utils/tokenUtils.d.ts +38 -0
- package/dist/utils/tokenUtils.d.ts.map +1 -0
- package/dist/utils/tokenUtils.js +65 -0
- package/dist/utils/tokenUtils.js.map +1 -0
- package/dist/utils/transactionUtils.d.ts +22 -0
- package/dist/utils/transactionUtils.d.ts.map +1 -0
- package/dist/utils/transactionUtils.js +26 -0
- package/dist/utils/transactionUtils.js.map +1 -0
- package/package.json +87 -3
- package/src/bridges/LiFiBridge.test.ts +615 -0
- package/src/bridges/LiFiBridge.ts +731 -0
- package/src/config/RebalancerConfig.test.ts +921 -0
- package/src/config/RebalancerConfig.ts +63 -0
- package/src/config/types.ts +613 -0
- package/src/core/InventoryRebalancer.test.ts +1858 -0
- package/src/core/InventoryRebalancer.ts +1455 -0
- package/src/core/Rebalancer.test.ts +686 -0
- package/src/core/Rebalancer.ts +686 -0
- package/src/core/RebalancerOrchestrator.test.ts +871 -0
- package/src/core/RebalancerOrchestrator.ts +273 -0
- package/src/core/RebalancerService.test.ts +1094 -0
- package/src/core/RebalancerService.ts +412 -0
- package/src/e2e/E2E_TEST_CONVENTIONS.md +222 -0
- package/src/e2e/collateral-deficit.e2e-test.ts +403 -0
- package/src/e2e/composite.e2e-test.ts +1008 -0
- package/src/e2e/fixtures/routes.ts +532 -0
- package/src/e2e/harness/BaseLocalDeploymentManager.ts +246 -0
- package/src/e2e/harness/BridgeSetup.ts +95 -0
- package/src/e2e/harness/Erc20InventoryLocalDeploymentManager.ts +183 -0
- package/src/e2e/harness/Erc20LocalDeploymentManager.ts +190 -0
- package/src/e2e/harness/ForkIndexer.test.ts +448 -0
- package/src/e2e/harness/ForkIndexer.ts +183 -0
- package/src/e2e/harness/MixedLocalDeploymentManager.ts +196 -0
- package/src/e2e/harness/MockExplorerClient.ts +94 -0
- package/src/e2e/harness/MockExternalBridge.ts +411 -0
- package/src/e2e/harness/NativeLocalDeploymentManager.ts +138 -0
- package/src/e2e/harness/SnapshotHelper.ts +56 -0
- package/src/e2e/harness/TestHelpers.ts +169 -0
- package/src/e2e/harness/TestRebalancer.ts +758 -0
- package/src/e2e/harness/TransferHelper.ts +188 -0
- package/src/e2e/inventory-erc20-minAmount.e2e-test.ts +735 -0
- package/src/e2e/inventory-erc20-weighted.e2e-test.ts +733 -0
- package/src/e2e/inventory-minAmount.e2e-test.ts +734 -0
- package/src/e2e/inventory-weighted.e2e-test.ts +734 -0
- package/src/e2e/minAmount.e2e-test.ts +313 -0
- package/src/e2e/mixed-weighted.e2e-test.ts +267 -0
- package/src/e2e/weighted.e2e-test.ts +304 -0
- package/src/factories/RebalancerContextFactory.test.ts +394 -0
- package/src/factories/RebalancerContextFactory.ts +771 -0
- package/src/index.ts +125 -0
- package/src/interfaces/IExternalBridge.ts +117 -0
- package/src/interfaces/IMetrics.ts +5 -0
- package/src/interfaces/IMonitor.ts +71 -0
- package/src/interfaces/IRebalancer.ts +57 -0
- package/src/interfaces/IStrategy.ts +81 -0
- package/src/metrics/Metrics.ts +335 -0
- package/src/metrics/PriceGetter.ts +74 -0
- package/src/metrics/scripts/metrics.ts +139 -0
- package/src/monitor/Monitor.ts +324 -0
- package/src/service.ts +285 -0
- package/src/strategy/BaseStrategy.ts +553 -0
- package/src/strategy/CollateralDeficitStrategy.test.ts +728 -0
- package/src/strategy/CollateralDeficitStrategy.ts +421 -0
- package/src/strategy/CompositeStrategy.test.ts +418 -0
- package/src/strategy/CompositeStrategy.ts +102 -0
- package/src/strategy/MinAmountStrategy.test.ts +732 -0
- package/src/strategy/MinAmountStrategy.ts +200 -0
- package/src/strategy/StrategyFactory.test.ts +108 -0
- package/src/strategy/StrategyFactory.ts +157 -0
- package/src/strategy/WeightedStrategy.test.ts +529 -0
- package/src/strategy/WeightedStrategy.ts +126 -0
- package/src/strategy/index.ts +6 -0
- package/src/test/helpers.ts +477 -0
- package/src/test/lifiMocks.ts +211 -0
- package/src/tracking/ActionTracker.test.ts +1625 -0
- package/src/tracking/ActionTracker.ts +1019 -0
- package/src/tracking/IActionTracker.ts +213 -0
- package/src/tracking/InflightContextAdapter.test.ts +206 -0
- package/src/tracking/InflightContextAdapter.ts +75 -0
- package/src/tracking/store/IStore.ts +48 -0
- package/src/tracking/store/InMemoryStore.test.ts +338 -0
- package/src/tracking/store/InMemoryStore.ts +59 -0
- package/src/tracking/store/index.ts +2 -0
- package/src/tracking/types.ts +118 -0
- package/src/utils/ExplorerClient.test.ts +386 -0
- package/src/utils/ExplorerClient.ts +439 -0
- package/src/utils/balanceUtils.test.ts +79 -0
- package/src/utils/balanceUtils.ts +65 -0
- package/src/utils/blockTag.ts +68 -0
- package/src/utils/bridgeUtils.test.ts +193 -0
- package/src/utils/bridgeUtils.ts +101 -0
- package/src/utils/errors.ts +5 -0
- package/src/utils/gasEstimation.ts +306 -0
- package/src/utils/solanaKeyParser.test.ts +103 -0
- package/src/utils/solanaKeyParser.ts +117 -0
- package/src/utils/tokenUtils.ts +89 -0
- package/src/utils/transactionUtils.ts +41 -0
|
@@ -0,0 +1,686 @@
|
|
|
1
|
+
import { type PopulatedTransaction, type providers } from 'ethers';
|
|
2
|
+
import { type Logger } from 'pino';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
type ChainMap,
|
|
6
|
+
type ChainMetadata,
|
|
7
|
+
type ChainName,
|
|
8
|
+
type EthJsonRpcBlockParameterTag,
|
|
9
|
+
EvmMovableCollateralAdapter,
|
|
10
|
+
HyperlaneCore,
|
|
11
|
+
type InterchainGasQuote,
|
|
12
|
+
type MultiProvider,
|
|
13
|
+
type Token,
|
|
14
|
+
type WarpCore,
|
|
15
|
+
} from '@humanode-hyperlane/sdk';
|
|
16
|
+
import { eqAddress, isNullish, mapAllSettled } from '@humanode-hyperlane/utils';
|
|
17
|
+
|
|
18
|
+
import type {
|
|
19
|
+
IMovableCollateralRebalancer,
|
|
20
|
+
MovableCollateralExecutionResult,
|
|
21
|
+
PreparedTransaction,
|
|
22
|
+
RebalancerType,
|
|
23
|
+
} from '../interfaces/IRebalancer.js';
|
|
24
|
+
import { MovableCollateralRoute } from '../interfaces/IStrategy.js';
|
|
25
|
+
import { type Metrics } from '../metrics/Metrics.js';
|
|
26
|
+
import type { IActionTracker } from '../tracking/IActionTracker.js';
|
|
27
|
+
import type { RebalanceIntent } from '../tracking/types.js';
|
|
28
|
+
|
|
29
|
+
// Internal types with intentId for tracking
|
|
30
|
+
type InternalExecutionResult = MovableCollateralExecutionResult & {
|
|
31
|
+
intentId: string;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
type InternalRoute = MovableCollateralRoute & { intentId: string };
|
|
35
|
+
|
|
36
|
+
export class Rebalancer implements IMovableCollateralRebalancer {
|
|
37
|
+
public readonly rebalancerType: RebalancerType = 'movableCollateral';
|
|
38
|
+
private readonly logger: Logger;
|
|
39
|
+
|
|
40
|
+
constructor(
|
|
41
|
+
private readonly warpCore: WarpCore,
|
|
42
|
+
private readonly chainMetadata: ChainMap<ChainMetadata>,
|
|
43
|
+
private readonly tokensByChainName: ChainMap<Token>,
|
|
44
|
+
private readonly multiProvider: MultiProvider,
|
|
45
|
+
private readonly actionTracker: IActionTracker,
|
|
46
|
+
logger: Logger,
|
|
47
|
+
private readonly metrics?: Metrics,
|
|
48
|
+
) {
|
|
49
|
+
this.logger = logger.child({ class: Rebalancer.name });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async rebalance(
|
|
53
|
+
routes: MovableCollateralRoute[],
|
|
54
|
+
): Promise<MovableCollateralExecutionResult[]> {
|
|
55
|
+
if (routes.length === 0) {
|
|
56
|
+
this.logger.info('No routes to execute, exiting');
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
this.logger.info({ numberOfRoutes: routes.length }, 'Rebalance initiated');
|
|
61
|
+
|
|
62
|
+
const invalidRoutes = routes.filter((r) => !r.bridge);
|
|
63
|
+
if (invalidRoutes.length > 0) {
|
|
64
|
+
this.logger.error(
|
|
65
|
+
{ count: invalidRoutes.length },
|
|
66
|
+
'Routes missing required bridge address',
|
|
67
|
+
);
|
|
68
|
+
return routes.map((r) => ({
|
|
69
|
+
route: r,
|
|
70
|
+
success: false,
|
|
71
|
+
error: r.bridge ? undefined : 'Missing required bridge address',
|
|
72
|
+
messageId: '', // Required by MovableCollateralExecutionResult, empty for validation failures
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const intents = await this.createIntents(routes);
|
|
77
|
+
|
|
78
|
+
const internalRoutes: InternalRoute[] = routes.map((route, idx) => ({
|
|
79
|
+
...route,
|
|
80
|
+
bridge: route.bridge!,
|
|
81
|
+
intentId: intents[idx].id,
|
|
82
|
+
}));
|
|
83
|
+
|
|
84
|
+
const { preparedTransactions, preparationFailureResults } =
|
|
85
|
+
await this.prepareTransactions(internalRoutes);
|
|
86
|
+
|
|
87
|
+
let executionResults: InternalExecutionResult[] = [];
|
|
88
|
+
|
|
89
|
+
if (preparedTransactions.length > 0) {
|
|
90
|
+
executionResults = await this.executeTransactions(preparedTransactions);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const allInternalResults = [
|
|
94
|
+
...preparationFailureResults,
|
|
95
|
+
...executionResults,
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
await this.processResults(allInternalResults);
|
|
99
|
+
|
|
100
|
+
const successfulResults = allInternalResults.filter((r) => r.success);
|
|
101
|
+
if (this.metrics && successfulResults.length > 0) {
|
|
102
|
+
for (const result of successfulResults) {
|
|
103
|
+
const token = this.tokensByChainName[result.route.origin];
|
|
104
|
+
if (token) {
|
|
105
|
+
this.metrics.recordRebalanceAmount(
|
|
106
|
+
result.route,
|
|
107
|
+
token.amount(result.route.amount),
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const failures = allInternalResults.filter((r) => !r.success);
|
|
114
|
+
if (failures.length > 0) {
|
|
115
|
+
this.logger.error(
|
|
116
|
+
{ failureCount: failures.length, totalRoutes: routes.length },
|
|
117
|
+
'Some rebalance operations failed.',
|
|
118
|
+
);
|
|
119
|
+
} else {
|
|
120
|
+
this.logger.info('Rebalance successful');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return this.toPublicResults(allInternalResults);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private async createIntents(
|
|
127
|
+
routes: MovableCollateralRoute[],
|
|
128
|
+
): Promise<RebalanceIntent[]> {
|
|
129
|
+
return Promise.all(
|
|
130
|
+
routes.map((route) =>
|
|
131
|
+
this.actionTracker.createRebalanceIntent({
|
|
132
|
+
origin: this.multiProvider.getDomainId(route.origin),
|
|
133
|
+
destination: this.multiProvider.getDomainId(route.destination),
|
|
134
|
+
amount: route.amount,
|
|
135
|
+
bridge: route.bridge,
|
|
136
|
+
executionMethod: 'movable_collateral',
|
|
137
|
+
}),
|
|
138
|
+
),
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private async processResults(
|
|
143
|
+
results: InternalExecutionResult[],
|
|
144
|
+
): Promise<void> {
|
|
145
|
+
for (const result of results) {
|
|
146
|
+
const intentId = result.intentId;
|
|
147
|
+
|
|
148
|
+
if (result.success && result.messageId) {
|
|
149
|
+
await this.actionTracker.createRebalanceAction({
|
|
150
|
+
intentId,
|
|
151
|
+
origin: this.multiProvider.getDomainId(result.route.origin),
|
|
152
|
+
destination: this.multiProvider.getDomainId(result.route.destination),
|
|
153
|
+
amount: result.route.amount,
|
|
154
|
+
type: 'rebalance_message',
|
|
155
|
+
messageId: result.messageId,
|
|
156
|
+
txHash: result.txHash,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
this.logger.info(
|
|
160
|
+
{
|
|
161
|
+
intentId,
|
|
162
|
+
messageId: result.messageId,
|
|
163
|
+
txHash: result.txHash,
|
|
164
|
+
origin: result.route.origin,
|
|
165
|
+
destination: result.route.destination,
|
|
166
|
+
},
|
|
167
|
+
'Rebalance action created successfully',
|
|
168
|
+
);
|
|
169
|
+
} else {
|
|
170
|
+
await this.actionTracker.failRebalanceIntent(intentId);
|
|
171
|
+
|
|
172
|
+
this.logger.warn(
|
|
173
|
+
{
|
|
174
|
+
intentId,
|
|
175
|
+
success: result.success,
|
|
176
|
+
error: result.error,
|
|
177
|
+
origin: result.route.origin,
|
|
178
|
+
destination: result.route.destination,
|
|
179
|
+
},
|
|
180
|
+
'Rebalance intent marked as failed',
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private toPublicResults(
|
|
187
|
+
internalResults: InternalExecutionResult[],
|
|
188
|
+
): MovableCollateralExecutionResult[] {
|
|
189
|
+
return internalResults.map((internal) => ({
|
|
190
|
+
route: internal.route,
|
|
191
|
+
success: internal.success,
|
|
192
|
+
error: internal.error,
|
|
193
|
+
messageId: internal.messageId || '', // Ensure messageId is always a string
|
|
194
|
+
txHash: internal.txHash,
|
|
195
|
+
}));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private async prepareTransactions(routes: InternalRoute[]): Promise<{
|
|
199
|
+
preparedTransactions: PreparedTransaction[];
|
|
200
|
+
preparationFailureResults: InternalExecutionResult[];
|
|
201
|
+
}> {
|
|
202
|
+
this.logger.info(
|
|
203
|
+
{ numRoutes: routes.length },
|
|
204
|
+
'Preparing all rebalance transactions.',
|
|
205
|
+
);
|
|
206
|
+
const { fulfilled, rejected } = await mapAllSettled(
|
|
207
|
+
routes,
|
|
208
|
+
(route) => this.prepareTransaction(route),
|
|
209
|
+
(_, i) => i,
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
// Filter out null results (validation failures logged internally)
|
|
213
|
+
const preparedTransactions = Array.from(fulfilled.values()).filter(
|
|
214
|
+
(tx): tx is PreparedTransaction => !isNullish(tx),
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
// Create failure results for tracking
|
|
218
|
+
const preparationFailureResults: InternalExecutionResult[] = [];
|
|
219
|
+
for (const [i, error] of rejected) {
|
|
220
|
+
preparationFailureResults.push({
|
|
221
|
+
route: routes[i],
|
|
222
|
+
intentId: routes[i].intentId,
|
|
223
|
+
success: false,
|
|
224
|
+
error: String(error),
|
|
225
|
+
messageId: '', // Required by MovableCollateralExecutionResult, empty for failures
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
// Also track null results (validation failures)
|
|
229
|
+
Array.from(fulfilled.entries()).forEach(([i, tx]) => {
|
|
230
|
+
if (isNullish(tx)) {
|
|
231
|
+
preparationFailureResults.push({
|
|
232
|
+
route: routes[i],
|
|
233
|
+
intentId: routes[i].intentId,
|
|
234
|
+
success: false,
|
|
235
|
+
error: 'Preparation returned null',
|
|
236
|
+
messageId: '', // Required by MovableCollateralExecutionResult, empty for failures
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
return { preparedTransactions, preparationFailureResults };
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
private async prepareTransaction(
|
|
245
|
+
route: InternalRoute,
|
|
246
|
+
): Promise<PreparedTransaction | null> {
|
|
247
|
+
const { origin, destination, amount } = route;
|
|
248
|
+
|
|
249
|
+
this.logger.info(
|
|
250
|
+
{
|
|
251
|
+
origin,
|
|
252
|
+
destination,
|
|
253
|
+
amount,
|
|
254
|
+
},
|
|
255
|
+
'Preparing transaction for route',
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
// 1. Adapter and permissions validation
|
|
259
|
+
if (!(await this.validateRoute(route))) {
|
|
260
|
+
// Errors logged in validateRoute
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const originToken = this.tokensByChainName[origin];
|
|
265
|
+
const destinationToken = this.tokensByChainName[destination];
|
|
266
|
+
const destinationChainMeta = this.chainMetadata[destination];
|
|
267
|
+
|
|
268
|
+
const originTokenAmount = originToken.amount(amount);
|
|
269
|
+
const decimalFormattedAmount =
|
|
270
|
+
originTokenAmount.getDecimalFormattedAmount();
|
|
271
|
+
const originHypAdapter = originToken.getHypAdapter(
|
|
272
|
+
this.warpCore.multiProvider,
|
|
273
|
+
) as EvmMovableCollateralAdapter;
|
|
274
|
+
|
|
275
|
+
const { bridge } = route;
|
|
276
|
+
|
|
277
|
+
// 2. Get quotes
|
|
278
|
+
let quotes: InterchainGasQuote[];
|
|
279
|
+
try {
|
|
280
|
+
quotes = await originHypAdapter.getRebalanceQuotes(
|
|
281
|
+
bridge,
|
|
282
|
+
destinationChainMeta.domainId,
|
|
283
|
+
destinationToken.addressOrDenom,
|
|
284
|
+
amount,
|
|
285
|
+
);
|
|
286
|
+
} catch (error) {
|
|
287
|
+
this.logger.error(
|
|
288
|
+
{
|
|
289
|
+
origin,
|
|
290
|
+
destination,
|
|
291
|
+
amount: decimalFormattedAmount,
|
|
292
|
+
tokenName: originToken.name,
|
|
293
|
+
error,
|
|
294
|
+
},
|
|
295
|
+
'Failed to get quotes for route.',
|
|
296
|
+
);
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// 3. Populate transaction
|
|
301
|
+
let populatedTx: PopulatedTransaction;
|
|
302
|
+
try {
|
|
303
|
+
populatedTx = await originHypAdapter.populateRebalanceTx(
|
|
304
|
+
destinationChainMeta.domainId,
|
|
305
|
+
amount,
|
|
306
|
+
bridge,
|
|
307
|
+
quotes,
|
|
308
|
+
);
|
|
309
|
+
} catch (error) {
|
|
310
|
+
this.logger.error(
|
|
311
|
+
{
|
|
312
|
+
origin,
|
|
313
|
+
destination,
|
|
314
|
+
amount: decimalFormattedAmount,
|
|
315
|
+
tokenName: originToken.name,
|
|
316
|
+
error,
|
|
317
|
+
},
|
|
318
|
+
'Failed to populate transaction for route.',
|
|
319
|
+
);
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return { populatedTx, route, originTokenAmount };
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
private async validateRoute(route: InternalRoute): Promise<boolean> {
|
|
327
|
+
const { origin, destination, amount } = route;
|
|
328
|
+
const originToken = this.tokensByChainName[origin];
|
|
329
|
+
const destinationToken = this.tokensByChainName[destination];
|
|
330
|
+
const destinationDomain = this.chainMetadata[destination];
|
|
331
|
+
|
|
332
|
+
if (!originToken) {
|
|
333
|
+
this.logger.error(
|
|
334
|
+
{ origin, destination, amount },
|
|
335
|
+
'Route validation failed: origin token not found.',
|
|
336
|
+
);
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const originTokenAmount = originToken.amount(amount);
|
|
341
|
+
const decimalFormattedAmount =
|
|
342
|
+
originTokenAmount.getDecimalFormattedAmount();
|
|
343
|
+
|
|
344
|
+
if (!destinationToken) {
|
|
345
|
+
this.logger.error(
|
|
346
|
+
{ origin, destination, amount: decimalFormattedAmount },
|
|
347
|
+
'Route validation failed: destination token not found.',
|
|
348
|
+
);
|
|
349
|
+
return false;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (!destinationDomain) {
|
|
353
|
+
this.logger.error(
|
|
354
|
+
{ origin, destination, amount: decimalFormattedAmount },
|
|
355
|
+
'Route validation failed: destination domain metadata not found.',
|
|
356
|
+
);
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const originHypAdapter = originToken.getHypAdapter(
|
|
361
|
+
this.warpCore.multiProvider,
|
|
362
|
+
);
|
|
363
|
+
if (!(originHypAdapter instanceof EvmMovableCollateralAdapter)) {
|
|
364
|
+
this.logger.error(
|
|
365
|
+
{
|
|
366
|
+
origin,
|
|
367
|
+
destination,
|
|
368
|
+
amount: decimalFormattedAmount,
|
|
369
|
+
tokenName: originToken.name,
|
|
370
|
+
},
|
|
371
|
+
'Route validation failed: Origin TokenAdapter is not an EvmHypCollateralAdapter.',
|
|
372
|
+
);
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const signer = this.multiProvider.getSigner(origin);
|
|
377
|
+
const signerAddress = await signer.getAddress();
|
|
378
|
+
if (!(await originHypAdapter.isRebalancer(signerAddress))) {
|
|
379
|
+
this.logger.error(
|
|
380
|
+
{
|
|
381
|
+
origin,
|
|
382
|
+
destination,
|
|
383
|
+
amount: decimalFormattedAmount,
|
|
384
|
+
tokenName: originToken.name,
|
|
385
|
+
tokenAddress: originToken.addressOrDenom,
|
|
386
|
+
signerAddress,
|
|
387
|
+
},
|
|
388
|
+
'Route validation failed: Signer is not a rebalancer.',
|
|
389
|
+
);
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const allowedDestination = await originHypAdapter.getAllowedDestination(
|
|
394
|
+
destinationDomain.domainId,
|
|
395
|
+
);
|
|
396
|
+
if (!eqAddress(allowedDestination, destinationToken.addressOrDenom)) {
|
|
397
|
+
this.logger.error(
|
|
398
|
+
{
|
|
399
|
+
origin,
|
|
400
|
+
destination,
|
|
401
|
+
amount: decimalFormattedAmount,
|
|
402
|
+
tokenName: originToken.name,
|
|
403
|
+
tokenAddress: originToken.addressOrDenom,
|
|
404
|
+
destinationTokenAddress: destinationToken.addressOrDenom,
|
|
405
|
+
allowedDestinationTokenAddress: allowedDestination,
|
|
406
|
+
},
|
|
407
|
+
'Route validation failed: Destination is not allowed.',
|
|
408
|
+
);
|
|
409
|
+
return false;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const { bridge } = route;
|
|
413
|
+
|
|
414
|
+
if (
|
|
415
|
+
!(await originHypAdapter.isBridgeAllowed(
|
|
416
|
+
destinationDomain.domainId,
|
|
417
|
+
bridge,
|
|
418
|
+
))
|
|
419
|
+
) {
|
|
420
|
+
this.logger.error(
|
|
421
|
+
{
|
|
422
|
+
origin,
|
|
423
|
+
destination,
|
|
424
|
+
amount: decimalFormattedAmount,
|
|
425
|
+
tokenName: originToken.name,
|
|
426
|
+
tokenAddress: originToken.addressOrDenom,
|
|
427
|
+
bridgeAddress: bridge,
|
|
428
|
+
},
|
|
429
|
+
'Route validation failed: Bridge is not allowed.',
|
|
430
|
+
);
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
return true;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
private async executeTransactions(
|
|
438
|
+
transactions: PreparedTransaction[],
|
|
439
|
+
): Promise<InternalExecutionResult[]> {
|
|
440
|
+
this.logger.info(
|
|
441
|
+
{ numTransactions: transactions.length },
|
|
442
|
+
'Estimating gas for all prepared transactions.',
|
|
443
|
+
);
|
|
444
|
+
|
|
445
|
+
const results: InternalExecutionResult[] = [];
|
|
446
|
+
|
|
447
|
+
// 1. Estimate gas for rebalance transactions
|
|
448
|
+
const gasEstimateResults = await Promise.allSettled(
|
|
449
|
+
transactions.map(async (transaction) => {
|
|
450
|
+
await this.multiProvider.estimateGas(
|
|
451
|
+
transaction.route.origin,
|
|
452
|
+
transaction.populatedTx,
|
|
453
|
+
);
|
|
454
|
+
return transaction;
|
|
455
|
+
}),
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
// 2. Filter out failed transactions and track failures
|
|
459
|
+
const validTransactions: PreparedTransaction[] = [];
|
|
460
|
+
gasEstimateResults.forEach((result, i) => {
|
|
461
|
+
if (result.status === 'fulfilled') {
|
|
462
|
+
validTransactions.push(result.value);
|
|
463
|
+
} else {
|
|
464
|
+
const failedTransaction = transactions[i];
|
|
465
|
+
this.logger.error(
|
|
466
|
+
{
|
|
467
|
+
origin: failedTransaction.route.origin,
|
|
468
|
+
destination: failedTransaction.route.destination,
|
|
469
|
+
amount:
|
|
470
|
+
failedTransaction.originTokenAmount.getDecimalFormattedAmount(),
|
|
471
|
+
tokenName: failedTransaction.originTokenAmount.token.name,
|
|
472
|
+
error: result.reason,
|
|
473
|
+
},
|
|
474
|
+
'Gas estimation failed for route.',
|
|
475
|
+
);
|
|
476
|
+
results.push({
|
|
477
|
+
route: failedTransaction.route,
|
|
478
|
+
intentId: failedTransaction.route.intentId,
|
|
479
|
+
success: false,
|
|
480
|
+
error: `Gas estimation failed: ${String(result.reason)}`,
|
|
481
|
+
messageId: '', // Required by MovableCollateralExecutionResult, empty for failures
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
if (validTransactions.length === 0) {
|
|
487
|
+
this.logger.info('No transactions to execute after gas estimation.');
|
|
488
|
+
return results;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// 3. Group transactions by origin chain
|
|
492
|
+
const txsByOrigin = new Map<ChainName, PreparedTransaction[]>();
|
|
493
|
+
for (const tx of validTransactions) {
|
|
494
|
+
const origin = tx.route.origin;
|
|
495
|
+
if (!txsByOrigin.has(origin)) {
|
|
496
|
+
txsByOrigin.set(origin, []);
|
|
497
|
+
}
|
|
498
|
+
txsByOrigin.get(origin)!.push(tx);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// 4. Send transactions - parallel across chains, sequential within each chain
|
|
502
|
+
this.logger.info(
|
|
503
|
+
{
|
|
504
|
+
numChains: txsByOrigin.size,
|
|
505
|
+
numTransactions: validTransactions.length,
|
|
506
|
+
},
|
|
507
|
+
'Sending transactions (parallel across chains, sequential within chain).',
|
|
508
|
+
);
|
|
509
|
+
|
|
510
|
+
const chainSendResults = await Promise.allSettled(
|
|
511
|
+
Array.from(txsByOrigin.entries()).map(([origin, txs]) =>
|
|
512
|
+
this.sendTransactionsForChain(origin, txs),
|
|
513
|
+
),
|
|
514
|
+
);
|
|
515
|
+
|
|
516
|
+
// 5. Collect successful sends and record send failures
|
|
517
|
+
const successfulSends: Array<{
|
|
518
|
+
transaction: PreparedTransaction;
|
|
519
|
+
receipt: providers.TransactionReceipt;
|
|
520
|
+
}> = [];
|
|
521
|
+
|
|
522
|
+
chainSendResults.forEach((chainResult) => {
|
|
523
|
+
if (chainResult.status === 'fulfilled') {
|
|
524
|
+
for (const txResult of chainResult.value) {
|
|
525
|
+
if ('receipt' in txResult) {
|
|
526
|
+
successfulSends.push(txResult);
|
|
527
|
+
} else {
|
|
528
|
+
results.push({
|
|
529
|
+
route: txResult.transaction.route,
|
|
530
|
+
intentId: txResult.transaction.route.intentId,
|
|
531
|
+
success: false,
|
|
532
|
+
error: `Transaction send failed: ${txResult.error}`,
|
|
533
|
+
messageId: '', // Required by MovableCollateralExecutionResult, empty for failures
|
|
534
|
+
});
|
|
535
|
+
this.metrics?.recordActionAttempt(
|
|
536
|
+
txResult.transaction.route,
|
|
537
|
+
false,
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
} else {
|
|
542
|
+
// This shouldn't happen since sendTransactionsForChain catches errors internally,
|
|
543
|
+
// but handle it just in case
|
|
544
|
+
this.logger.error(
|
|
545
|
+
{ error: chainResult.reason },
|
|
546
|
+
'Unexpected error during chain transaction sending.',
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
// 6. Build results from confirmed receipts
|
|
552
|
+
for (const { transaction, receipt } of successfulSends) {
|
|
553
|
+
const result = this.buildResult(transaction, receipt);
|
|
554
|
+
results.push(result);
|
|
555
|
+
this.metrics?.recordActionAttempt(result.route, result.success);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
return results;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// === Parallel Transaction Sending Methods ===
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Send all transactions for a single origin chain sequentially.
|
|
565
|
+
* Sequential sending is required to avoid nonce contention when using the same signing key.
|
|
566
|
+
*/
|
|
567
|
+
private async sendTransactionsForChain(
|
|
568
|
+
origin: ChainName,
|
|
569
|
+
transactions: PreparedTransaction[],
|
|
570
|
+
): Promise<
|
|
571
|
+
Array<
|
|
572
|
+
| {
|
|
573
|
+
transaction: PreparedTransaction;
|
|
574
|
+
receipt: providers.TransactionReceipt;
|
|
575
|
+
}
|
|
576
|
+
| { transaction: PreparedTransaction; error: string }
|
|
577
|
+
>
|
|
578
|
+
> {
|
|
579
|
+
const results: Array<
|
|
580
|
+
| {
|
|
581
|
+
transaction: PreparedTransaction;
|
|
582
|
+
receipt: providers.TransactionReceipt;
|
|
583
|
+
}
|
|
584
|
+
| { transaction: PreparedTransaction; error: string }
|
|
585
|
+
> = [];
|
|
586
|
+
|
|
587
|
+
// Send sequentially to avoid nonce contention
|
|
588
|
+
for (const transaction of transactions) {
|
|
589
|
+
try {
|
|
590
|
+
const decimalFormattedAmount =
|
|
591
|
+
transaction.originTokenAmount.getDecimalFormattedAmount();
|
|
592
|
+
const tokenName = transaction.originTokenAmount.token.name;
|
|
593
|
+
|
|
594
|
+
const reorgPeriod = this.getReorgPeriod(origin);
|
|
595
|
+
|
|
596
|
+
this.logger.info(
|
|
597
|
+
{
|
|
598
|
+
origin,
|
|
599
|
+
destination: transaction.route.destination,
|
|
600
|
+
amount: decimalFormattedAmount,
|
|
601
|
+
tokenName,
|
|
602
|
+
reorgPeriod,
|
|
603
|
+
},
|
|
604
|
+
'Sending rebalance transaction and waiting for reorgPeriod confirmations.',
|
|
605
|
+
);
|
|
606
|
+
|
|
607
|
+
const receipt = await this.multiProvider.sendTransaction(
|
|
608
|
+
origin,
|
|
609
|
+
transaction.populatedTx,
|
|
610
|
+
{
|
|
611
|
+
waitConfirmations: reorgPeriod as
|
|
612
|
+
| number
|
|
613
|
+
| EthJsonRpcBlockParameterTag,
|
|
614
|
+
},
|
|
615
|
+
);
|
|
616
|
+
|
|
617
|
+
this.logger.info(
|
|
618
|
+
{
|
|
619
|
+
origin,
|
|
620
|
+
destination: transaction.route.destination,
|
|
621
|
+
amount: decimalFormattedAmount,
|
|
622
|
+
tokenName,
|
|
623
|
+
txHash: receipt.transactionHash,
|
|
624
|
+
},
|
|
625
|
+
'Rebalance transaction confirmed at reorgPeriod depth.',
|
|
626
|
+
);
|
|
627
|
+
|
|
628
|
+
results.push({ transaction, receipt });
|
|
629
|
+
} catch (error) {
|
|
630
|
+
this.logger.error(
|
|
631
|
+
{
|
|
632
|
+
origin,
|
|
633
|
+
destination: transaction.route.destination,
|
|
634
|
+
amount: transaction.originTokenAmount.getDecimalFormattedAmount(),
|
|
635
|
+
tokenName: transaction.originTokenAmount.token.name,
|
|
636
|
+
error,
|
|
637
|
+
},
|
|
638
|
+
'Transaction send failed for route.',
|
|
639
|
+
);
|
|
640
|
+
results.push({ transaction, error: String(error) });
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
return results;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* Build the execution result from a confirmed transaction receipt.
|
|
649
|
+
* Receipt is already confirmed at reorgPeriod depth from sendTransaction.
|
|
650
|
+
*/
|
|
651
|
+
private buildResult(
|
|
652
|
+
transaction: PreparedTransaction,
|
|
653
|
+
receipt: providers.TransactionReceipt,
|
|
654
|
+
): InternalExecutionResult {
|
|
655
|
+
const { origin, destination } = transaction.route;
|
|
656
|
+
const dispatchedMessages = HyperlaneCore.getDispatchedMessages(receipt);
|
|
657
|
+
|
|
658
|
+
if (dispatchedMessages.length === 0) {
|
|
659
|
+
this.logger.error(
|
|
660
|
+
{ origin, destination, txHash: receipt.transactionHash },
|
|
661
|
+
'No Dispatch event found in confirmed rebalance receipt',
|
|
662
|
+
);
|
|
663
|
+
return {
|
|
664
|
+
route: transaction.route,
|
|
665
|
+
intentId: transaction.route.intentId,
|
|
666
|
+
success: false,
|
|
667
|
+
error: `Transaction confirmed but no Dispatch event found`,
|
|
668
|
+
messageId: '', // Required by MovableCollateralExecutionResult, empty for failures
|
|
669
|
+
txHash: receipt.transactionHash,
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
return {
|
|
674
|
+
route: transaction.route,
|
|
675
|
+
intentId: transaction.route.intentId,
|
|
676
|
+
success: true,
|
|
677
|
+
messageId: dispatchedMessages[0].id,
|
|
678
|
+
txHash: receipt.transactionHash,
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
private getReorgPeriod(chainName: string): number | string {
|
|
683
|
+
const metadata = this.multiProvider.getChainMetadata(chainName);
|
|
684
|
+
return metadata.blocks?.reorgPeriod ?? 32;
|
|
685
|
+
}
|
|
686
|
+
}
|