@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,412 @@
|
|
|
1
|
+
import { Logger } from 'pino';
|
|
2
|
+
|
|
3
|
+
import { IRegistry } from '@humanode-hyperlane/registry';
|
|
4
|
+
import {
|
|
5
|
+
type MultiProtocolProvider,
|
|
6
|
+
type MultiProvider,
|
|
7
|
+
Token,
|
|
8
|
+
} from '@humanode-hyperlane/sdk';
|
|
9
|
+
import { ProtocolType, assert, toWei } from '@humanode-hyperlane/utils';
|
|
10
|
+
|
|
11
|
+
import { RebalancerConfig } from '../config/RebalancerConfig.js';
|
|
12
|
+
import {
|
|
13
|
+
getStrategyChainConfig,
|
|
14
|
+
getStrategyChainNames,
|
|
15
|
+
} from '../config/types.js';
|
|
16
|
+
import { RebalancerContextFactory } from '../factories/RebalancerContextFactory.js';
|
|
17
|
+
import type { ExternalBridgeRegistry } from '../interfaces/IExternalBridge.js';
|
|
18
|
+
import {
|
|
19
|
+
MonitorEvent,
|
|
20
|
+
MonitorEventType,
|
|
21
|
+
MonitorPollingError,
|
|
22
|
+
MonitorStartError,
|
|
23
|
+
} from '../interfaces/IMonitor.js';
|
|
24
|
+
import type { IRebalancer } from '../interfaces/IRebalancer.js';
|
|
25
|
+
import type {
|
|
26
|
+
IStrategy,
|
|
27
|
+
MovableCollateralRoute,
|
|
28
|
+
} from '../interfaces/IStrategy.js';
|
|
29
|
+
import { Metrics } from '../metrics/Metrics.js';
|
|
30
|
+
import { type InventoryMonitorConfig, Monitor } from '../monitor/Monitor.js';
|
|
31
|
+
import type { IActionTracker } from '../tracking/IActionTracker.js';
|
|
32
|
+
import { InflightContextAdapter } from '../tracking/InflightContextAdapter.js';
|
|
33
|
+
|
|
34
|
+
import type { RebalancerOrchestrator } from './RebalancerOrchestrator.js';
|
|
35
|
+
|
|
36
|
+
export interface RebalancerServiceConfig {
|
|
37
|
+
/** Execution mode: 'manual' for one-off execution, 'daemon' for continuous monitoring */
|
|
38
|
+
mode: 'manual' | 'daemon';
|
|
39
|
+
|
|
40
|
+
/** Frequency to check balances in milliseconds (daemon mode only) */
|
|
41
|
+
checkFrequency?: number;
|
|
42
|
+
|
|
43
|
+
/** Enable monitor-only mode (no transactions executed) */
|
|
44
|
+
monitorOnly?: boolean;
|
|
45
|
+
|
|
46
|
+
/** Enable Prometheus metrics collection */
|
|
47
|
+
withMetrics?: boolean;
|
|
48
|
+
|
|
49
|
+
/** CoinGecko API key for token price fetching (required for metrics) */
|
|
50
|
+
coingeckoApiKey?: string;
|
|
51
|
+
|
|
52
|
+
/** Logger instance */
|
|
53
|
+
logger: Logger;
|
|
54
|
+
|
|
55
|
+
/** Service version for logging */
|
|
56
|
+
version?: string;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Optional pre-configured ActionTracker.
|
|
60
|
+
* If provided, skips ActionTracker creation and uses this directly.
|
|
61
|
+
* Useful for simulation/testing where tracking is mocked externally.
|
|
62
|
+
*/
|
|
63
|
+
actionTracker?: IActionTracker;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface ManualRebalanceRequest {
|
|
67
|
+
origin: string;
|
|
68
|
+
destination: string;
|
|
69
|
+
amount: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* RebalancerService is the main orchestrator for the Hyperlane Warp Route Rebalancer.
|
|
74
|
+
* It supports both manual one-off rebalances and continuous daemon mode.
|
|
75
|
+
*
|
|
76
|
+
* @example Manual execution
|
|
77
|
+
* ```typescript
|
|
78
|
+
* const service = new RebalancerService(
|
|
79
|
+
* multiProvider,
|
|
80
|
+
* multiProtocolProvider,
|
|
81
|
+
* registry,
|
|
82
|
+
* rebalancerConfig,
|
|
83
|
+
* {
|
|
84
|
+
* mode: 'manual',
|
|
85
|
+
* logger: console,
|
|
86
|
+
* }
|
|
87
|
+
* );
|
|
88
|
+
* await service.executeManual({
|
|
89
|
+
* origin: 'ethereum',
|
|
90
|
+
* destination: 'arbitrum',
|
|
91
|
+
* amount: '1000',
|
|
92
|
+
* });
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* @example Daemon mode
|
|
96
|
+
* ```typescript
|
|
97
|
+
* const service = new RebalancerService(
|
|
98
|
+
* multiProvider,
|
|
99
|
+
* multiProtocolProvider,
|
|
100
|
+
* registry,
|
|
101
|
+
* rebalancerConfig,
|
|
102
|
+
* {
|
|
103
|
+
* mode: 'daemon',
|
|
104
|
+
* checkFrequency: 60_000,
|
|
105
|
+
* withMetrics: true,
|
|
106
|
+
* coingeckoApiKey: process.env.COINGECKO_API_KEY,
|
|
107
|
+
* logger: console,
|
|
108
|
+
* }
|
|
109
|
+
* );
|
|
110
|
+
* await service.start();
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
export class RebalancerService {
|
|
114
|
+
private isExiting = false;
|
|
115
|
+
private logger: Logger;
|
|
116
|
+
private contextFactory?: RebalancerContextFactory;
|
|
117
|
+
private monitor?: Monitor;
|
|
118
|
+
private strategy?: IStrategy;
|
|
119
|
+
private rebalancer?: IRebalancer;
|
|
120
|
+
private metrics?: Metrics;
|
|
121
|
+
private mode: 'manual' | 'daemon';
|
|
122
|
+
private actionTracker?: IActionTracker;
|
|
123
|
+
private inflightContextAdapter?: InflightContextAdapter;
|
|
124
|
+
private orchestrator?: RebalancerOrchestrator;
|
|
125
|
+
constructor(
|
|
126
|
+
private readonly multiProvider: MultiProvider,
|
|
127
|
+
private readonly multiProtocolProvider: MultiProtocolProvider | undefined,
|
|
128
|
+
private readonly registry: IRegistry,
|
|
129
|
+
private readonly rebalancerConfig: RebalancerConfig,
|
|
130
|
+
private readonly config: RebalancerServiceConfig,
|
|
131
|
+
private readonly inventorySignerKeysByProtocol?: Partial<
|
|
132
|
+
Record<ProtocolType, string>
|
|
133
|
+
>,
|
|
134
|
+
) {
|
|
135
|
+
this.logger = config.logger;
|
|
136
|
+
this.mode = config.mode;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Initialize the service components
|
|
141
|
+
*/
|
|
142
|
+
private async initialize(): Promise<void> {
|
|
143
|
+
if (this.contextFactory) {
|
|
144
|
+
// Already initialized
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
this.logger.info('Initializing RebalancerService...');
|
|
149
|
+
|
|
150
|
+
// Create context factory
|
|
151
|
+
this.contextFactory = await RebalancerContextFactory.create(
|
|
152
|
+
this.rebalancerConfig,
|
|
153
|
+
this.multiProvider,
|
|
154
|
+
this.multiProtocolProvider,
|
|
155
|
+
this.registry,
|
|
156
|
+
this.logger,
|
|
157
|
+
this.inventorySignerKeysByProtocol,
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
// Create metrics if enabled
|
|
161
|
+
if (this.config.withMetrics) {
|
|
162
|
+
this.metrics = await this.contextFactory.createMetrics(
|
|
163
|
+
this.config.coingeckoApiKey,
|
|
164
|
+
);
|
|
165
|
+
this.logger.info('Metrics collection enabled');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Create strategy
|
|
169
|
+
this.strategy = await this.contextFactory.createStrategy(this.metrics);
|
|
170
|
+
|
|
171
|
+
// Create or use provided ActionTracker for tracking inflight actions
|
|
172
|
+
// Must be created BEFORE rebalancer since rebalancer needs it
|
|
173
|
+
if (this.config.actionTracker) {
|
|
174
|
+
// Use externally provided ActionTracker (e.g., for simulation/testing)
|
|
175
|
+
this.actionTracker = this.config.actionTracker;
|
|
176
|
+
this.inflightContextAdapter = new InflightContextAdapter(
|
|
177
|
+
this.actionTracker,
|
|
178
|
+
this.multiProvider,
|
|
179
|
+
);
|
|
180
|
+
await this.actionTracker.initialize();
|
|
181
|
+
this.logger.info('Using externally provided ActionTracker');
|
|
182
|
+
} else {
|
|
183
|
+
const { tracker, adapter } =
|
|
184
|
+
await this.contextFactory.createActionTracker();
|
|
185
|
+
this.actionTracker = tracker;
|
|
186
|
+
this.inflightContextAdapter = adapter;
|
|
187
|
+
await this.actionTracker.initialize();
|
|
188
|
+
this.logger.info('ActionTracker initialized');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Create rebalancers (both movableCollateral and inventory if configured)
|
|
192
|
+
let rebalancers: IRebalancer[] = [];
|
|
193
|
+
let externalBridgeRegistry: Partial<ExternalBridgeRegistry> = {};
|
|
194
|
+
let inventoryConfig: InventoryMonitorConfig | undefined;
|
|
195
|
+
|
|
196
|
+
if (!this.config.monitorOnly) {
|
|
197
|
+
const result = await this.contextFactory.createRebalancers(
|
|
198
|
+
this.actionTracker,
|
|
199
|
+
this.metrics,
|
|
200
|
+
);
|
|
201
|
+
rebalancers = result.rebalancers;
|
|
202
|
+
externalBridgeRegistry = result.externalBridgeRegistry;
|
|
203
|
+
inventoryConfig = result.inventoryConfig;
|
|
204
|
+
|
|
205
|
+
if (rebalancers.length > 0) {
|
|
206
|
+
this.logger.info(`${rebalancers.length} rebalancer(s) created`);
|
|
207
|
+
}
|
|
208
|
+
} else {
|
|
209
|
+
this.logger.warn(
|
|
210
|
+
'Running in monitorOnly mode: no transactions will be executed.',
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Set instance variable for backward compatibility with executeManual
|
|
215
|
+
// (Task 5 will remove this when refactoring executeManual)
|
|
216
|
+
if (rebalancers.length > 0) {
|
|
217
|
+
this.rebalancer = rebalancers[0];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (this.mode === 'daemon') {
|
|
221
|
+
const checkFrequency = this.config.checkFrequency ?? 60_000;
|
|
222
|
+
this.monitor = this.contextFactory.createMonitor(
|
|
223
|
+
checkFrequency,
|
|
224
|
+
inventoryConfig,
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
this.orchestrator = this.contextFactory.createOrchestrator({
|
|
229
|
+
strategy: this.strategy,
|
|
230
|
+
actionTracker: this.actionTracker,
|
|
231
|
+
inflightContextAdapter: this.inflightContextAdapter,
|
|
232
|
+
rebalancers,
|
|
233
|
+
externalBridgeRegistry: externalBridgeRegistry,
|
|
234
|
+
metrics: this.metrics,
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
this.logger.info(
|
|
238
|
+
{
|
|
239
|
+
warpRouteId: this.rebalancerConfig.warpRouteId,
|
|
240
|
+
strategyTypes: this.rebalancerConfig.strategyConfig.map(
|
|
241
|
+
(s) => s.rebalanceStrategy,
|
|
242
|
+
),
|
|
243
|
+
chains: getStrategyChainNames(this.rebalancerConfig.strategyConfig),
|
|
244
|
+
},
|
|
245
|
+
'RebalancerService initialized',
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Execute a manual one-off rebalance
|
|
251
|
+
*/
|
|
252
|
+
async executeManual(request: ManualRebalanceRequest): Promise<void> {
|
|
253
|
+
await this.initialize();
|
|
254
|
+
|
|
255
|
+
assert(
|
|
256
|
+
this.rebalancer,
|
|
257
|
+
'Rebalancer not available. MonitorOnly mode cannot execute manual rebalances.',
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
const { origin, destination, amount } = request;
|
|
261
|
+
|
|
262
|
+
this.logger.info(
|
|
263
|
+
`Manual rebalance strategy selected. Origin: ${origin}, Destination: ${destination}, Amount: ${amount}`,
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
const warpCore = this.contextFactory!.getWarpCore();
|
|
267
|
+
const originToken = warpCore.tokens.find(
|
|
268
|
+
(t: Token) => t.chainName === origin,
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
if (!originToken) {
|
|
272
|
+
const error = `Origin token not found for chain ${origin}`;
|
|
273
|
+
this.logger.error(error);
|
|
274
|
+
throw new Error(error);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Validate amount
|
|
278
|
+
const amountNum = Number(amount);
|
|
279
|
+
assert(!isNaN(amountNum), 'Amount must be a valid number');
|
|
280
|
+
assert(amountNum > 0, 'Amount must be greater than 0');
|
|
281
|
+
|
|
282
|
+
const originConfig = getStrategyChainConfig(
|
|
283
|
+
this.rebalancerConfig.strategyConfig,
|
|
284
|
+
origin,
|
|
285
|
+
);
|
|
286
|
+
assert(
|
|
287
|
+
originConfig?.bridge,
|
|
288
|
+
`No bridge configured for origin chain ${origin}`,
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
// Use destination-specific bridge override if configured, otherwise use default
|
|
292
|
+
const bridge =
|
|
293
|
+
originConfig.override?.[destination]?.bridge ?? originConfig.bridge;
|
|
294
|
+
|
|
295
|
+
try {
|
|
296
|
+
const manualRoute: MovableCollateralRoute & { intentId: string } = {
|
|
297
|
+
origin,
|
|
298
|
+
destination,
|
|
299
|
+
amount: BigInt(toWei(amount, originToken.decimals)),
|
|
300
|
+
executionType: 'movableCollateral',
|
|
301
|
+
bridge,
|
|
302
|
+
intentId: `manual-${Date.now()}`,
|
|
303
|
+
};
|
|
304
|
+
await this.rebalancer.rebalance([manualRoute]);
|
|
305
|
+
this.logger.info(
|
|
306
|
+
`✅ Manual rebalance from ${origin} to ${destination} for amount ${amount} submitted successfully.`,
|
|
307
|
+
);
|
|
308
|
+
} catch (error) {
|
|
309
|
+
this.logger.error(
|
|
310
|
+
{ error },
|
|
311
|
+
`❌ Manual rebalance from ${origin} to ${destination} failed`,
|
|
312
|
+
);
|
|
313
|
+
throw error;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Start the rebalancer in daemon mode (continuous monitoring)
|
|
319
|
+
*/
|
|
320
|
+
async start(): Promise<void> {
|
|
321
|
+
if (this.mode !== 'daemon') {
|
|
322
|
+
throw new Error('start() can only be called in daemon mode');
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
await this.initialize();
|
|
326
|
+
|
|
327
|
+
assert(this.monitor, 'Monitor must be initialized for daemon mode');
|
|
328
|
+
|
|
329
|
+
// Setup monitor event listeners
|
|
330
|
+
this.monitor
|
|
331
|
+
.on(MonitorEventType.TokenInfo, this.onTokenInfo.bind(this))
|
|
332
|
+
.on(MonitorEventType.Error, this.onMonitorError.bind(this))
|
|
333
|
+
.on(MonitorEventType.Start, this.onMonitorStart.bind(this));
|
|
334
|
+
|
|
335
|
+
// Set up signal handlers for graceful shutdown
|
|
336
|
+
process.on('SIGINT', () => this.gracefulShutdown());
|
|
337
|
+
process.on('SIGTERM', () => this.gracefulShutdown());
|
|
338
|
+
|
|
339
|
+
try {
|
|
340
|
+
await this.monitor.start();
|
|
341
|
+
} catch (error) {
|
|
342
|
+
this.logger.error({ error }, 'Rebalancer startup error');
|
|
343
|
+
throw error;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Stop the rebalancer daemon
|
|
349
|
+
*/
|
|
350
|
+
async stop(): Promise<void> {
|
|
351
|
+
if (this.monitor) {
|
|
352
|
+
await this.monitor.stop();
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Gracefully shutdown the service
|
|
358
|
+
*/
|
|
359
|
+
async gracefulShutdown(): Promise<void> {
|
|
360
|
+
if (this.isExiting) {
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
this.isExiting = true;
|
|
364
|
+
|
|
365
|
+
this.logger.info('Gracefully shutting down rebalancer...');
|
|
366
|
+
await this.stop();
|
|
367
|
+
|
|
368
|
+
// Unregister listeners to prevent them from being called again during shutdown
|
|
369
|
+
process.removeAllListeners('SIGINT');
|
|
370
|
+
process.removeAllListeners('SIGTERM');
|
|
371
|
+
|
|
372
|
+
this.logger.info('Rebalancer shutdown complete');
|
|
373
|
+
process.exit(0);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Handle token info events from monitor by delegating to orchestrator
|
|
378
|
+
*/
|
|
379
|
+
private async onTokenInfo(event: MonitorEvent): Promise<void> {
|
|
380
|
+
if (!this.orchestrator) {
|
|
381
|
+
this.logger.error('Orchestrator not initialized');
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
await this.orchestrator.executeCycle(event);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Event handler for monitor errors
|
|
390
|
+
*/
|
|
391
|
+
private onMonitorError(error: Error): void {
|
|
392
|
+
if (error instanceof MonitorPollingError) {
|
|
393
|
+
this.logger.error(error.message);
|
|
394
|
+
this.metrics?.recordPollingError();
|
|
395
|
+
} else if (error instanceof MonitorStartError) {
|
|
396
|
+
this.logger.error(error.message);
|
|
397
|
+
throw error;
|
|
398
|
+
} else {
|
|
399
|
+
this.logger.error(
|
|
400
|
+
{ error },
|
|
401
|
+
'An unexpected error occurred in the monitor',
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Event handler for monitor start
|
|
408
|
+
*/
|
|
409
|
+
private onMonitorStart(): void {
|
|
410
|
+
this.logger.info('Rebalancer started successfully 🚀');
|
|
411
|
+
}
|
|
412
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# E2E Test Conventions
|
|
2
|
+
|
|
3
|
+
Guidelines for writing and updating rebalancer e2e tests.
|
|
4
|
+
|
|
5
|
+
## 1. Assert total action counts at each stage
|
|
6
|
+
|
|
7
|
+
Don't just filter for the action type you care about. Assert the total count first, then find/filter within it. This catches unexpected extra actions.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// Good
|
|
11
|
+
const actionsAfterBridge = await context.tracker.getActionsForIntent(intent.id);
|
|
12
|
+
expect(actionsAfterBridge.length).to.equal(2); // 1 deposit + 1 movement
|
|
13
|
+
const movementAction = actionsAfterBridge.find(
|
|
14
|
+
(a) => a.type === 'inventory_movement',
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
// Bad — doesn't catch unexpected extra actions
|
|
18
|
+
const movementActions = actionsAfterBridge.filter(
|
|
19
|
+
(a) => a.type === 'inventory_movement' && a.status === 'complete',
|
|
20
|
+
);
|
|
21
|
+
expect(movementActions.length).to.equal(1);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 2. Use `find` + `expect(x).to.exist` for single items
|
|
25
|
+
|
|
26
|
+
When you expect exactly one action of a type, use `find` instead of `filter` + length check. It reads as "there should be one of these" and gives you a non-null reference.
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
// Good
|
|
30
|
+
const movementAction = actionsAfterBridge.find(
|
|
31
|
+
(a) => a.type === 'inventory_movement',
|
|
32
|
+
);
|
|
33
|
+
expect(movementAction).to.exist;
|
|
34
|
+
expect(movementAction!.origin).to.equal(DOMAIN_IDS.anvil1);
|
|
35
|
+
|
|
36
|
+
// Bad — extra ceremony for the same thing
|
|
37
|
+
const completedMovementActions = actionsAfterBridge.filter(
|
|
38
|
+
(a) => a.type === 'inventory_movement' && a.status === 'complete',
|
|
39
|
+
);
|
|
40
|
+
expect(completedMovementActions.length).to.equal(1);
|
|
41
|
+
expect(completedMovementActions[0].origin).to.equal(DOMAIN_IDS.anvil1);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 3. Don't over-filter — let aggregate assertions catch problems
|
|
45
|
+
|
|
46
|
+
Don't add `status === 'complete'` to filter predicates when a downstream assertion (like summing amounts) will fail anyway if an action is in the wrong state. Over-filtering hides bugs.
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
// Good — if a deposit is incomplete, totalDeposited won't match
|
|
50
|
+
const allDeposits = finalActions.filter((a) => a.type === 'inventory_deposit');
|
|
51
|
+
expect(allDeposits.length).to.equal(2);
|
|
52
|
+
const totalDeposited = allDeposits.reduce((sum, a) => sum + a.amount, 0n);
|
|
53
|
+
expect(totalDeposited).to.equal(activeIntent.amount);
|
|
54
|
+
|
|
55
|
+
// Bad — status filter masks a deposit stuck in 'in_progress'
|
|
56
|
+
const allDeposits = finalActions.filter(
|
|
57
|
+
(a) => a.type === 'inventory_deposit' && a.status === 'complete',
|
|
58
|
+
);
|
|
59
|
+
expect(allDeposits.length).to.equal(2);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Exception: filter by status when you're specifically testing state transitions (e.g. "after relay, this action should be complete").
|
|
63
|
+
|
|
64
|
+
## 4. Use `getRouterBalances` helper for balance snapshots
|
|
65
|
+
|
|
66
|
+
Every test that asserts router balance changes repeats the same loop. Extract it into a shared helper and call it before/after the operation under test.
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
// In test helpers
|
|
70
|
+
async function getRouterBalances(
|
|
71
|
+
localProviders: Map<string, providers.JsonRpcProvider>,
|
|
72
|
+
addresses: NativeDeployedAddresses,
|
|
73
|
+
): Promise<Record<string, BigNumber>> {
|
|
74
|
+
const balances: Record<string, BigNumber> = {};
|
|
75
|
+
for (const chain of TEST_CHAINS) {
|
|
76
|
+
const provider = localProviders.get(chain)!;
|
|
77
|
+
balances[chain] = await provider.getBalance(
|
|
78
|
+
addresses.monitoredRoute[chain],
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
return balances;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// In tests
|
|
85
|
+
const before = await getRouterBalances(localProviders, nativeDeployedAddresses);
|
|
86
|
+
// ... execute cycle, relay, etc.
|
|
87
|
+
const after = await getRouterBalances(localProviders, nativeDeployedAddresses);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## 5. Use `classifyChains` helper for surplus/deficit/neutral
|
|
91
|
+
|
|
92
|
+
Tests frequently need to identify which chain is the deficit (destination), which funded the transfer (surplus), and which was uninvolved (neutral). Extract this into a helper that derives the classification from a single deposit action rather than hardcoding chain names.
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
interface ChainRoles {
|
|
96
|
+
deficitChain: string;
|
|
97
|
+
surplusChain: string;
|
|
98
|
+
neutralChain?: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function classifyChains(
|
|
102
|
+
deficitChain: string,
|
|
103
|
+
depositAction: RebalanceAction,
|
|
104
|
+
): ChainRoles {
|
|
105
|
+
// Surplus chain is where the router pays out on message delivery.
|
|
106
|
+
// For inventory deposits, that's the action's destination (swapped direction).
|
|
107
|
+
const surplusChain = chainFromDomain(depositAction.destination);
|
|
108
|
+
const neutralChain = TEST_CHAINS.find(
|
|
109
|
+
(c) => c !== deficitChain && c !== surplusChain,
|
|
110
|
+
);
|
|
111
|
+
return { deficitChain, surplusChain, neutralChain };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// In tests
|
|
115
|
+
const { surplusChain, neutralChain } = classifyChains('anvil2', depositAction);
|
|
116
|
+
|
|
117
|
+
expect(after.anvil2.gt(before.anvil2)).to.be.true;
|
|
118
|
+
expect(after[surplusChain].lt(before[surplusChain])).to.be.true;
|
|
119
|
+
if (neutralChain) {
|
|
120
|
+
expect(after[neutralChain].eq(before[neutralChain])).to.be.true;
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## 6. Use `withInventorySignerBalances` for signer wallet setup
|
|
125
|
+
|
|
126
|
+
Don't call `anvil_setBalance` on the inventory signer directly in tests. Use the builder's `withInventorySignerBalances` method with a preset name or inline config.
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
// Good — preset name from INVENTORY_SIGNER_PRESETS in routes.ts
|
|
130
|
+
const context = await new TestRebalancerBuilder(deploymentManager, multiProvider)
|
|
131
|
+
.withStrategy(buildInventoryMinAmountStrategyConfig(addresses))
|
|
132
|
+
.withInventoryConfig({ inventorySignerKey: ANVIL_USER_PRIVATE_KEY, nativeDeployedAddresses })
|
|
133
|
+
.withInventorySignerBalances('SIGNER_PARTIAL_ANVIL2')
|
|
134
|
+
.withExecutionMode('execute')
|
|
135
|
+
.build();
|
|
136
|
+
|
|
137
|
+
// Also accepted — inline Record<string, BigNumber> for one-off scenarios
|
|
138
|
+
.withInventorySignerBalances({ anvil2: BigNumber.from('500000000000000000') })
|
|
139
|
+
|
|
140
|
+
// Bad — setting balances outside the builder
|
|
141
|
+
const signer = new ethers.Wallet(ANVIL_USER_PRIVATE_KEY);
|
|
142
|
+
await provider.send('anvil_setBalance', [signer.address, '0x...']);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Available presets: `SIGNER_PARTIAL_ANVIL2`, `SIGNER_LOW_ALL`, `SIGNER_ONLY_ANVIL1`, `SIGNER_SPLIT_SOURCES`, `SIGNER_FUNDED_ANVIL1`, `SIGNER_PARTIAL_ANVIL3`, `SIGNER_ZERO_ANVIL3`, `SIGNER_WEIGHTED_LOW_ALL`, `SIGNER_WEIGHTED_BRIDGE_SOURCES`.
|
|
146
|
+
|
|
147
|
+
## 7. Use named constants for strategy-derived values
|
|
148
|
+
|
|
149
|
+
Don't hardcode magic numbers like `2000000000000000000n`. Derive expected values from the strategy config constants exported in `routes.ts`.
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
// Good — derived from strategy config
|
|
153
|
+
import { INVENTORY_MIN_AMOUNT_TARGET_WEI } from './fixtures/routes.js';
|
|
154
|
+
const expectedDeficit = INVENTORY_MIN_AMOUNT_TARGET_WEI.toBigInt();
|
|
155
|
+
expect(activeIntent.amount).to.equal(expectedDeficit);
|
|
156
|
+
|
|
157
|
+
// Bad — hardcoded magic number
|
|
158
|
+
expect(activeIntent.amount).to.equal(2000000000000000000n);
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Available constants: `INVENTORY_MIN_AMOUNT_MIN` (`'1'`), `INVENTORY_MIN_AMOUNT_TARGET` (`'2'`), `INVENTORY_MIN_AMOUNT_TARGET_WEI` (target as wei BigNumber).
|
|
162
|
+
|
|
163
|
+
## 8. Use balance presets for router balances
|
|
164
|
+
|
|
165
|
+
Don't inline `BigNumber.from(...)` objects in `.withBalances()` when a preset in `BALANCE_PRESETS` matches your scenario. Add a new preset if the scenario is reusable.
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
// Good — named preset
|
|
169
|
+
.withBalances('INVENTORY_EMPTY_DEST')
|
|
170
|
+
.withBalances('INVENTORY_MULTI_DEFICIT')
|
|
171
|
+
|
|
172
|
+
// Acceptable — inline for truly one-off scenarios
|
|
173
|
+
.withBalances({
|
|
174
|
+
anvil1: BigNumber.from('9000000000000000000'),
|
|
175
|
+
anvil2: BigNumber.from(0),
|
|
176
|
+
anvil3: BigNumber.from(0),
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
// Bad — duplicating values that already exist as a preset
|
|
180
|
+
.withBalances({
|
|
181
|
+
anvil1: BigNumber.from('5000000000000000000'),
|
|
182
|
+
anvil2: BigNumber.from('0'),
|
|
183
|
+
anvil3: BigNumber.from('5000000000000000000'),
|
|
184
|
+
})
|
|
185
|
+
// ^ This is INVENTORY_EMPTY_DEST — use the preset.
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
These helpers and conventions eliminate repeated boilerplate across tests and make intent immediately clear.
|
|
189
|
+
|
|
190
|
+
## 9. Assert state after each cycle — no loop-to-completion
|
|
191
|
+
|
|
192
|
+
Multi-cycle tests must check state after **every** cycle. Looping with `for (let i = 0; i < N; i++)` until completion is an antipattern — it hides the per-cycle progression and makes failures impossible to diagnose.
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
// Good — explicit per-cycle assertions
|
|
196
|
+
await executeCycle(context);
|
|
197
|
+
await syncAndRelay(context);
|
|
198
|
+
// Check cycle 1 state
|
|
199
|
+
expect(partialIntents[0].completedAmount > 0n).to.be.true;
|
|
200
|
+
expect(actions.length).to.equal(2);
|
|
201
|
+
|
|
202
|
+
await executeCycle(context);
|
|
203
|
+
await syncAndRelay(context);
|
|
204
|
+
// Check cycle 2 state
|
|
205
|
+
expect(partialIntents[0].completedAmount > c1Amount).to.be.true;
|
|
206
|
+
expect(actions.length).to.equal(3);
|
|
207
|
+
|
|
208
|
+
// ... continue until completion
|
|
209
|
+
|
|
210
|
+
// Bad — loop hides what happens per cycle
|
|
211
|
+
for (let i = 0; i < 5; i++) {
|
|
212
|
+
await executeCycle(context);
|
|
213
|
+
await syncAndRelay(context);
|
|
214
|
+
}
|
|
215
|
+
expect(finalIntent.status).to.equal('complete');
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Each cycle should assert:
|
|
219
|
+
|
|
220
|
+
- Active/partial intent state (count, completedAmount, remaining)
|
|
221
|
+
- Action counts by type (deposits, movements)
|
|
222
|
+
- Monotonic progress (completedAmount increasing across cycles)
|