@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,735 @@
|
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
import { ethers, providers } from 'ethers';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
HyperlaneCore,
|
|
6
|
+
MultiProvider,
|
|
7
|
+
snapshot,
|
|
8
|
+
} from '@humanode-hyperlane/sdk';
|
|
9
|
+
|
|
10
|
+
import { ExternalBridgeType } from '../config/types.js';
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
ANVIL_USER_PRIVATE_KEY,
|
|
14
|
+
DOMAIN_IDS,
|
|
15
|
+
ERC20_INVENTORY_MIN_AMOUNT_TARGET_RAW,
|
|
16
|
+
type Erc20InventoryDeployedAddresses,
|
|
17
|
+
TEST_CHAINS,
|
|
18
|
+
buildErc20InventoryMinAmountStrategyConfig,
|
|
19
|
+
} from './fixtures/routes.js';
|
|
20
|
+
import { Erc20InventoryLocalDeploymentManager } from './harness/Erc20InventoryLocalDeploymentManager.js';
|
|
21
|
+
import { MockExternalBridge } from './harness/MockExternalBridge.js';
|
|
22
|
+
import { resetSnapshotsAndRefreshProviders } from './harness/SnapshotHelper.js';
|
|
23
|
+
import {
|
|
24
|
+
classifyChains,
|
|
25
|
+
getErc20RouterBalances,
|
|
26
|
+
getFirstMonitorEvent,
|
|
27
|
+
relayInProgressInventoryDeposits,
|
|
28
|
+
} from './harness/TestHelpers.js';
|
|
29
|
+
import {
|
|
30
|
+
TestRebalancerBuilder,
|
|
31
|
+
type TestRebalancerContext,
|
|
32
|
+
} from './harness/TestRebalancer.js';
|
|
33
|
+
|
|
34
|
+
describe('Erc20 InventoryMinAmountStrategy E2E', function () {
|
|
35
|
+
this.timeout(300_000);
|
|
36
|
+
|
|
37
|
+
let deploymentManager: Erc20InventoryLocalDeploymentManager;
|
|
38
|
+
let multiProvider: MultiProvider;
|
|
39
|
+
let localProviders: Map<string, providers.JsonRpcProvider>;
|
|
40
|
+
let snapshotIds: Map<string, string>;
|
|
41
|
+
let hyperlaneCore: HyperlaneCore;
|
|
42
|
+
let erc20DeployedAddresses: Erc20InventoryDeployedAddresses;
|
|
43
|
+
let mockBridge: MockExternalBridge;
|
|
44
|
+
|
|
45
|
+
const inventorySignerAddress = new ethers.Wallet(ANVIL_USER_PRIVATE_KEY)
|
|
46
|
+
.address;
|
|
47
|
+
// Expected deficit when a chain's router balance is 0:
|
|
48
|
+
// target (from strategy config) - 0 = target.
|
|
49
|
+
const expectedDeficit = ERC20_INVENTORY_MIN_AMOUNT_TARGET_RAW.toBigInt();
|
|
50
|
+
|
|
51
|
+
async function executeCycle(context: TestRebalancerContext): Promise<void> {
|
|
52
|
+
const monitor = context.createMonitor(0);
|
|
53
|
+
const event = await getFirstMonitorEvent(monitor);
|
|
54
|
+
await context.orchestrator.executeCycle(event);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
before(async function () {
|
|
58
|
+
deploymentManager = new Erc20InventoryLocalDeploymentManager(
|
|
59
|
+
inventorySignerAddress,
|
|
60
|
+
);
|
|
61
|
+
const ctx = await deploymentManager.start();
|
|
62
|
+
multiProvider = ctx.multiProvider;
|
|
63
|
+
localProviders = ctx.providers;
|
|
64
|
+
erc20DeployedAddresses = ctx.deployedAddresses;
|
|
65
|
+
|
|
66
|
+
const coreAddresses: Record<string, Record<string, string>> = {};
|
|
67
|
+
for (const chain of TEST_CHAINS) {
|
|
68
|
+
coreAddresses[chain] = {
|
|
69
|
+
mailbox: erc20DeployedAddresses.chains[chain].mailbox,
|
|
70
|
+
interchainSecurityModule: erc20DeployedAddresses.chains[chain].ism,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
hyperlaneCore = HyperlaneCore.fromAddressesMap(
|
|
74
|
+
coreAddresses,
|
|
75
|
+
multiProvider,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
mockBridge = new MockExternalBridge(
|
|
79
|
+
erc20DeployedAddresses,
|
|
80
|
+
multiProvider,
|
|
81
|
+
hyperlaneCore,
|
|
82
|
+
'erc20',
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
snapshotIds = new Map();
|
|
86
|
+
for (const [chain, provider] of localProviders) {
|
|
87
|
+
snapshotIds.set(chain, await snapshot(provider));
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
afterEach(async function () {
|
|
92
|
+
mockBridge.reset();
|
|
93
|
+
await resetSnapshotsAndRefreshProviders({
|
|
94
|
+
localProviders,
|
|
95
|
+
multiProvider,
|
|
96
|
+
snapshotIds,
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
after(async function () {
|
|
101
|
+
if (deploymentManager) await deploymentManager.stop();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('executes transferRemote when destination collateral is below minimum and inventory exists locally', async function () {
|
|
105
|
+
const context = await new TestRebalancerBuilder(
|
|
106
|
+
deploymentManager,
|
|
107
|
+
multiProvider,
|
|
108
|
+
)
|
|
109
|
+
.withStrategy(
|
|
110
|
+
buildErc20InventoryMinAmountStrategyConfig(erc20DeployedAddresses),
|
|
111
|
+
)
|
|
112
|
+
.withErc20InventoryConfig({
|
|
113
|
+
inventorySignerKey: ANVIL_USER_PRIVATE_KEY,
|
|
114
|
+
erc20DeployedAddresses,
|
|
115
|
+
})
|
|
116
|
+
.withMockExternalBridge(mockBridge)
|
|
117
|
+
.withBalances('ERC20_INVENTORY_EMPTY_DEST')
|
|
118
|
+
.withExecutionMode('execute')
|
|
119
|
+
.build();
|
|
120
|
+
|
|
121
|
+
const initialBalances = await getErc20RouterBalances(
|
|
122
|
+
localProviders,
|
|
123
|
+
erc20DeployedAddresses,
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
await executeCycle(context);
|
|
127
|
+
|
|
128
|
+
const activeIntents = await context.tracker.getActiveRebalanceIntents();
|
|
129
|
+
expect(activeIntents.length).to.equal(1);
|
|
130
|
+
expect(activeIntents[0].destination).to.equal(DOMAIN_IDS.anvil2);
|
|
131
|
+
expect(activeIntents[0].amount).to.equal(expectedDeficit);
|
|
132
|
+
|
|
133
|
+
const inProgressActions = await context.tracker.getInProgressActions();
|
|
134
|
+
expect(inProgressActions.length).to.equal(1);
|
|
135
|
+
const depositAction = inProgressActions.find(
|
|
136
|
+
(a) => a.type === 'inventory_deposit',
|
|
137
|
+
);
|
|
138
|
+
expect(depositAction).to.exist;
|
|
139
|
+
|
|
140
|
+
await relayInProgressInventoryDeposits(
|
|
141
|
+
context,
|
|
142
|
+
localProviders,
|
|
143
|
+
multiProvider,
|
|
144
|
+
hyperlaneCore,
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
const completedAction = await context.tracker.getRebalanceAction(
|
|
148
|
+
depositAction!.id,
|
|
149
|
+
);
|
|
150
|
+
expect(completedAction!.status).to.equal('complete');
|
|
151
|
+
|
|
152
|
+
const completedIntent = await context.tracker.getRebalanceIntent(
|
|
153
|
+
activeIntents[0].id,
|
|
154
|
+
);
|
|
155
|
+
expect(completedIntent!.status).to.equal('complete');
|
|
156
|
+
|
|
157
|
+
const finalBalances = await getErc20RouterBalances(
|
|
158
|
+
localProviders,
|
|
159
|
+
erc20DeployedAddresses,
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
const { surplusChain, neutralChain } = classifyChains(
|
|
163
|
+
'anvil2',
|
|
164
|
+
depositAction!,
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
expect(
|
|
168
|
+
finalBalances.anvil2.gt(initialBalances.anvil2),
|
|
169
|
+
'Destination router balance should increase',
|
|
170
|
+
).to.be.true;
|
|
171
|
+
expect(
|
|
172
|
+
finalBalances[surplusChain].lt(initialBalances[surplusChain]),
|
|
173
|
+
`Surplus router (${surplusChain}) balance should decrease`,
|
|
174
|
+
).to.be.true;
|
|
175
|
+
if (neutralChain) {
|
|
176
|
+
expect(
|
|
177
|
+
finalBalances[neutralChain].eq(initialBalances[neutralChain]),
|
|
178
|
+
'Uninvolved router balance should remain unchanged',
|
|
179
|
+
).to.be.true;
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('handles partial deposit, bridges inventory, then completes final deposit', async function () {
|
|
184
|
+
const context = await new TestRebalancerBuilder(
|
|
185
|
+
deploymentManager,
|
|
186
|
+
multiProvider,
|
|
187
|
+
)
|
|
188
|
+
.withStrategy(
|
|
189
|
+
buildErc20InventoryMinAmountStrategyConfig(erc20DeployedAddresses),
|
|
190
|
+
)
|
|
191
|
+
.withErc20InventoryConfig({
|
|
192
|
+
inventorySignerKey: ANVIL_USER_PRIVATE_KEY,
|
|
193
|
+
erc20DeployedAddresses,
|
|
194
|
+
})
|
|
195
|
+
.withMockExternalBridge(mockBridge)
|
|
196
|
+
.withBalances('ERC20_INVENTORY_EMPTY_DEST')
|
|
197
|
+
.withInventorySignerBalances('ERC20_SIGNER_PARTIAL_ANVIL2')
|
|
198
|
+
.withExecutionMode('execute')
|
|
199
|
+
.build();
|
|
200
|
+
|
|
201
|
+
const initialBalances = await getErc20RouterBalances(
|
|
202
|
+
localProviders,
|
|
203
|
+
erc20DeployedAddresses,
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
await executeCycle(context);
|
|
207
|
+
await relayInProgressInventoryDeposits(
|
|
208
|
+
context,
|
|
209
|
+
localProviders,
|
|
210
|
+
multiProvider,
|
|
211
|
+
hyperlaneCore,
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
const partialIntents =
|
|
215
|
+
await context.tracker.getPartiallyFulfilledInventoryIntents();
|
|
216
|
+
expect(partialIntents.length).to.equal(1);
|
|
217
|
+
expect(partialIntents[0].completedAmount > 0n).to.be.true;
|
|
218
|
+
expect(partialIntents[0].remaining > 0n).to.be.true;
|
|
219
|
+
expect(
|
|
220
|
+
partialIntents[0].completedAmount + partialIntents[0].remaining,
|
|
221
|
+
).to.equal(expectedDeficit);
|
|
222
|
+
expect(partialIntents[0].intent.amount).to.equal(expectedDeficit);
|
|
223
|
+
expect(partialIntents[0].intent.destination).to.equal(DOMAIN_IDS.anvil2);
|
|
224
|
+
|
|
225
|
+
const deposits = await context.tracker.getActionsForIntent(
|
|
226
|
+
partialIntents[0].intent.id,
|
|
227
|
+
);
|
|
228
|
+
expect(deposits.length).to.equal(1);
|
|
229
|
+
expect(deposits[0].type).to.equal('inventory_deposit');
|
|
230
|
+
expect(deposits[0].origin).to.equal(DOMAIN_IDS.anvil2);
|
|
231
|
+
expect(deposits[0].amount).to.equal(partialIntents[0].completedAmount);
|
|
232
|
+
|
|
233
|
+
await executeCycle(context);
|
|
234
|
+
|
|
235
|
+
const preSync = await context.tracker.getInProgressActions();
|
|
236
|
+
expect(preSync.length).to.equal(1);
|
|
237
|
+
const preSyncMovement = preSync.find(
|
|
238
|
+
(a) => a.type === 'inventory_movement',
|
|
239
|
+
);
|
|
240
|
+
expect(preSyncMovement).to.exist;
|
|
241
|
+
expect(preSyncMovement!.status).to.equal('in_progress');
|
|
242
|
+
|
|
243
|
+
// executeCycle calls syncActionTracker at the START of each cycle, so
|
|
244
|
+
// bridge actions created DURING the cycle above aren't synced yet.
|
|
245
|
+
// In production the next cycle's sync picks them up; in tests we
|
|
246
|
+
// sync manually to assert against the results between cycles.
|
|
247
|
+
await context.tracker.syncInventoryMovementActions({
|
|
248
|
+
[ExternalBridgeType.LiFi]: mockBridge,
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
const movementState = await context.tracker.getRebalanceAction(
|
|
252
|
+
preSyncMovement!.id,
|
|
253
|
+
);
|
|
254
|
+
expect(movementState?.status).to.equal('complete');
|
|
255
|
+
|
|
256
|
+
const activeIntent = partialIntents[0].intent;
|
|
257
|
+
const actionsAfterBridge = await context.tracker.getActionsForIntent(
|
|
258
|
+
activeIntent.id,
|
|
259
|
+
);
|
|
260
|
+
expect(actionsAfterBridge.length).to.equal(2);
|
|
261
|
+
const movementAction = actionsAfterBridge.find(
|
|
262
|
+
(a) => a.type === 'inventory_movement',
|
|
263
|
+
);
|
|
264
|
+
expect(movementAction).to.exist;
|
|
265
|
+
expect(movementAction!.origin).to.equal(DOMAIN_IDS.anvil1);
|
|
266
|
+
expect(movementAction!.destination).to.equal(DOMAIN_IDS.anvil2);
|
|
267
|
+
expect(movementAction!.status).to.equal('complete');
|
|
268
|
+
expect(movementAction!.amount >= partialIntents[0].remaining).to.be.true;
|
|
269
|
+
|
|
270
|
+
await executeCycle(context);
|
|
271
|
+
await relayInProgressInventoryDeposits(
|
|
272
|
+
context,
|
|
273
|
+
localProviders,
|
|
274
|
+
multiProvider,
|
|
275
|
+
hyperlaneCore,
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
const completedIntent = await context.tracker.getRebalanceIntent(
|
|
279
|
+
activeIntent.id,
|
|
280
|
+
);
|
|
281
|
+
expect(completedIntent!.status).to.equal('complete');
|
|
282
|
+
|
|
283
|
+
const partialAfterFinalCycle =
|
|
284
|
+
await context.tracker.getPartiallyFulfilledInventoryIntents();
|
|
285
|
+
expect(partialAfterFinalCycle.length).to.equal(0);
|
|
286
|
+
const finalActions = await context.tracker.getActionsForIntent(
|
|
287
|
+
activeIntent.id,
|
|
288
|
+
);
|
|
289
|
+
expect(finalActions.length).to.equal(3);
|
|
290
|
+
const allDeposits = finalActions.filter(
|
|
291
|
+
(a) => a.type === 'inventory_deposit',
|
|
292
|
+
);
|
|
293
|
+
expect(allDeposits.length).to.equal(2);
|
|
294
|
+
const totalDeposited = allDeposits.reduce((sum, a) => sum + a.amount, 0n);
|
|
295
|
+
expect(totalDeposited).to.equal(activeIntent.amount);
|
|
296
|
+
|
|
297
|
+
const finalBalances = await getErc20RouterBalances(
|
|
298
|
+
localProviders,
|
|
299
|
+
erc20DeployedAddresses,
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
const { surplusChain, neutralChain } = classifyChains(
|
|
303
|
+
'anvil2',
|
|
304
|
+
allDeposits[0],
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
expect(
|
|
308
|
+
finalBalances.anvil2.gt(initialBalances.anvil2),
|
|
309
|
+
'Destination router balance should increase',
|
|
310
|
+
).to.be.true;
|
|
311
|
+
expect(
|
|
312
|
+
finalBalances[surplusChain].lt(initialBalances[surplusChain]),
|
|
313
|
+
`Surplus router (${surplusChain}) balance should decrease`,
|
|
314
|
+
).to.be.true;
|
|
315
|
+
if (neutralChain) {
|
|
316
|
+
expect(
|
|
317
|
+
finalBalances[neutralChain].eq(initialBalances[neutralChain]),
|
|
318
|
+
'Uninvolved router balance should remain unchanged',
|
|
319
|
+
).to.be.true;
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it('loops across multiple cycles with partial fills before final completion', async function () {
|
|
324
|
+
const context = await new TestRebalancerBuilder(
|
|
325
|
+
deploymentManager,
|
|
326
|
+
multiProvider,
|
|
327
|
+
)
|
|
328
|
+
.withStrategy(
|
|
329
|
+
buildErc20InventoryMinAmountStrategyConfig(erc20DeployedAddresses),
|
|
330
|
+
)
|
|
331
|
+
.withErc20InventoryConfig({
|
|
332
|
+
inventorySignerKey: ANVIL_USER_PRIVATE_KEY,
|
|
333
|
+
erc20DeployedAddresses,
|
|
334
|
+
})
|
|
335
|
+
.withMockExternalBridge(mockBridge)
|
|
336
|
+
.withBalances('ERC20_INVENTORY_EMPTY_DEST')
|
|
337
|
+
.withInventorySignerBalances('ERC20_SIGNER_LOW_ALL')
|
|
338
|
+
.withExecutionMode('execute')
|
|
339
|
+
.build();
|
|
340
|
+
|
|
341
|
+
// Cycle 1: partial deposit from local signer inventory on anvil2
|
|
342
|
+
await executeCycle(context);
|
|
343
|
+
await context.tracker.syncInventoryMovementActions({
|
|
344
|
+
[ExternalBridgeType.LiFi]: mockBridge,
|
|
345
|
+
});
|
|
346
|
+
await relayInProgressInventoryDeposits(
|
|
347
|
+
context,
|
|
348
|
+
localProviders,
|
|
349
|
+
multiProvider,
|
|
350
|
+
hyperlaneCore,
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
let activeIntents = await context.tracker.getActiveRebalanceIntents();
|
|
354
|
+
expect(activeIntents.length).to.equal(1);
|
|
355
|
+
expect(activeIntents[0].destination).to.equal(DOMAIN_IDS.anvil2);
|
|
356
|
+
expect(activeIntents[0].amount).to.equal(expectedDeficit);
|
|
357
|
+
const targetIntentId = activeIntents[0].id;
|
|
358
|
+
|
|
359
|
+
let partialIntents =
|
|
360
|
+
await context.tracker.getPartiallyFulfilledInventoryIntents();
|
|
361
|
+
expect(partialIntents.length).to.equal(1);
|
|
362
|
+
expect(partialIntents[0].completedAmount > 0n).to.be.true;
|
|
363
|
+
expect(partialIntents[0].remaining > 0n).to.be.true;
|
|
364
|
+
expect(
|
|
365
|
+
partialIntents[0].completedAmount + partialIntents[0].remaining,
|
|
366
|
+
).to.equal(expectedDeficit);
|
|
367
|
+
const c1Amount = partialIntents[0].completedAmount;
|
|
368
|
+
|
|
369
|
+
let actions = await context.tracker.getActionsForIntent(targetIntentId);
|
|
370
|
+
let movementActions = actions.filter(
|
|
371
|
+
(a) => a.type === 'inventory_movement',
|
|
372
|
+
);
|
|
373
|
+
let depositActions = actions.filter((a) => a.type === 'inventory_deposit');
|
|
374
|
+
expect(actions.length).to.equal(1);
|
|
375
|
+
expect(movementActions.length).to.equal(0);
|
|
376
|
+
expect(depositActions.length).to.equal(1);
|
|
377
|
+
|
|
378
|
+
// Cycle 2: bridge movements from anvil1 + anvil3 — completedAmount unchanged (movements pending relay)
|
|
379
|
+
await executeCycle(context);
|
|
380
|
+
await context.tracker.syncInventoryMovementActions({
|
|
381
|
+
[ExternalBridgeType.LiFi]: mockBridge,
|
|
382
|
+
});
|
|
383
|
+
await relayInProgressInventoryDeposits(
|
|
384
|
+
context,
|
|
385
|
+
localProviders,
|
|
386
|
+
multiProvider,
|
|
387
|
+
hyperlaneCore,
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
activeIntents = await context.tracker.getActiveRebalanceIntents();
|
|
391
|
+
expect(activeIntents.length).to.equal(1);
|
|
392
|
+
partialIntents =
|
|
393
|
+
await context.tracker.getPartiallyFulfilledInventoryIntents();
|
|
394
|
+
expect(partialIntents.length).to.equal(1);
|
|
395
|
+
expect(
|
|
396
|
+
partialIntents[0].completedAmount + partialIntents[0].remaining,
|
|
397
|
+
).to.equal(expectedDeficit);
|
|
398
|
+
expect(partialIntents[0].completedAmount).to.equal(c1Amount);
|
|
399
|
+
|
|
400
|
+
actions = await context.tracker.getActionsForIntent(targetIntentId);
|
|
401
|
+
movementActions = actions.filter((a) => a.type === 'inventory_movement');
|
|
402
|
+
depositActions = actions.filter((a) => a.type === 'inventory_deposit');
|
|
403
|
+
expect(actions.length).to.equal(3);
|
|
404
|
+
expect(movementActions.length).to.equal(2);
|
|
405
|
+
expect(depositActions.length).to.equal(1);
|
|
406
|
+
const origins = new Set(movementActions.map((a) => a.origin));
|
|
407
|
+
expect(origins.has(DOMAIN_IDS.anvil1)).to.be.true;
|
|
408
|
+
expect(origins.has(DOMAIN_IDS.anvil3)).to.be.true;
|
|
409
|
+
movementActions.forEach((a) => {
|
|
410
|
+
expect(a.destination).to.equal(DOMAIN_IDS.anvil2);
|
|
411
|
+
expect(a.status).to.equal('complete');
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
// Cycle 3: final deposit covers remaining amount — intent completes
|
|
415
|
+
await executeCycle(context);
|
|
416
|
+
await context.tracker.syncInventoryMovementActions({
|
|
417
|
+
[ExternalBridgeType.LiFi]: mockBridge,
|
|
418
|
+
});
|
|
419
|
+
await relayInProgressInventoryDeposits(
|
|
420
|
+
context,
|
|
421
|
+
localProviders,
|
|
422
|
+
multiProvider,
|
|
423
|
+
hyperlaneCore,
|
|
424
|
+
);
|
|
425
|
+
|
|
426
|
+
activeIntents = await context.tracker.getActiveRebalanceIntents();
|
|
427
|
+
expect(activeIntents.length).to.equal(0);
|
|
428
|
+
partialIntents =
|
|
429
|
+
await context.tracker.getPartiallyFulfilledInventoryIntents();
|
|
430
|
+
expect(partialIntents.length).to.equal(0);
|
|
431
|
+
|
|
432
|
+
actions = await context.tracker.getActionsForIntent(targetIntentId);
|
|
433
|
+
movementActions = actions.filter((a) => a.type === 'inventory_movement');
|
|
434
|
+
depositActions = actions.filter((a) => a.type === 'inventory_deposit');
|
|
435
|
+
expect(actions.length).to.equal(4);
|
|
436
|
+
expect(movementActions.length).to.equal(2);
|
|
437
|
+
expect(depositActions.length).to.equal(2);
|
|
438
|
+
|
|
439
|
+
const finalIntent =
|
|
440
|
+
await context.tracker.getRebalanceIntent(targetIntentId);
|
|
441
|
+
expect(finalIntent!.status).to.equal('complete');
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
it('retries after bridge execution failure', async function () {
|
|
445
|
+
const context = await new TestRebalancerBuilder(
|
|
446
|
+
deploymentManager,
|
|
447
|
+
multiProvider,
|
|
448
|
+
)
|
|
449
|
+
.withStrategy(
|
|
450
|
+
buildErc20InventoryMinAmountStrategyConfig(erc20DeployedAddresses),
|
|
451
|
+
)
|
|
452
|
+
.withErc20InventoryConfig({
|
|
453
|
+
inventorySignerKey: ANVIL_USER_PRIVATE_KEY,
|
|
454
|
+
erc20DeployedAddresses,
|
|
455
|
+
})
|
|
456
|
+
.withMockExternalBridge(mockBridge)
|
|
457
|
+
.withBalances('ERC20_INVENTORY_EMPTY_DEST')
|
|
458
|
+
.withInventorySignerBalances('ERC20_SIGNER_FUNDED_ANVIL1')
|
|
459
|
+
.withExecutionMode('execute')
|
|
460
|
+
.build();
|
|
461
|
+
|
|
462
|
+
const initialBalances = await getErc20RouterBalances(
|
|
463
|
+
localProviders,
|
|
464
|
+
erc20DeployedAddresses,
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
// Cycle 1: Bridge fails — intent created but stays not_started, no actions
|
|
468
|
+
mockBridge.failNextExecute();
|
|
469
|
+
await executeCycle(context);
|
|
470
|
+
|
|
471
|
+
const activeIntents = await context.tracker.getActiveRebalanceIntents();
|
|
472
|
+
expect(activeIntents.length).to.equal(0);
|
|
473
|
+
|
|
474
|
+
const partialIntents =
|
|
475
|
+
await context.tracker.getPartiallyFulfilledInventoryIntents();
|
|
476
|
+
expect(partialIntents.length).to.equal(1);
|
|
477
|
+
expect(partialIntents[0].intent.status).to.equal('not_started');
|
|
478
|
+
expect(partialIntents[0].completedAmount).to.equal(0n);
|
|
479
|
+
expect(partialIntents[0].remaining).to.equal(expectedDeficit);
|
|
480
|
+
|
|
481
|
+
const intentId = partialIntents[0].intent.id;
|
|
482
|
+
const actionsAfterFailure =
|
|
483
|
+
await context.tracker.getActionsForIntent(intentId);
|
|
484
|
+
expect(actionsAfterFailure.length).to.equal(0);
|
|
485
|
+
|
|
486
|
+
// Cycle 2: Bridge succeeds — creates movement, intent becomes in_progress
|
|
487
|
+
await executeCycle(context);
|
|
488
|
+
await context.tracker.syncInventoryMovementActions({
|
|
489
|
+
[ExternalBridgeType.LiFi]: mockBridge,
|
|
490
|
+
});
|
|
491
|
+
await relayInProgressInventoryDeposits(
|
|
492
|
+
context,
|
|
493
|
+
localProviders,
|
|
494
|
+
multiProvider,
|
|
495
|
+
hyperlaneCore,
|
|
496
|
+
);
|
|
497
|
+
|
|
498
|
+
const cycle2Active = await context.tracker.getActiveRebalanceIntents();
|
|
499
|
+
expect(cycle2Active.length).to.equal(1);
|
|
500
|
+
const cycle2Partial =
|
|
501
|
+
await context.tracker.getPartiallyFulfilledInventoryIntents();
|
|
502
|
+
expect(cycle2Partial.length).to.equal(1);
|
|
503
|
+
|
|
504
|
+
const cycle2Actions = await context.tracker.getActionsForIntent(intentId);
|
|
505
|
+
expect(cycle2Actions.length).to.equal(1);
|
|
506
|
+
const movementAction = cycle2Actions.find(
|
|
507
|
+
(a) => a.type === 'inventory_movement',
|
|
508
|
+
);
|
|
509
|
+
expect(movementAction).to.exist;
|
|
510
|
+
expect(movementAction!.status).to.equal('complete');
|
|
511
|
+
|
|
512
|
+
const cycle2Intent = await context.tracker.getRebalanceIntent(intentId);
|
|
513
|
+
expect(cycle2Intent!.status).to.equal('in_progress');
|
|
514
|
+
|
|
515
|
+
// Cycle 3: Deposit completes the intent
|
|
516
|
+
await executeCycle(context);
|
|
517
|
+
await context.tracker.syncInventoryMovementActions({
|
|
518
|
+
[ExternalBridgeType.LiFi]: mockBridge,
|
|
519
|
+
});
|
|
520
|
+
await relayInProgressInventoryDeposits(
|
|
521
|
+
context,
|
|
522
|
+
localProviders,
|
|
523
|
+
multiProvider,
|
|
524
|
+
hyperlaneCore,
|
|
525
|
+
);
|
|
526
|
+
|
|
527
|
+
const completedIntent = await context.tracker.getRebalanceIntent(intentId);
|
|
528
|
+
expect(completedIntent!.status).to.equal('complete');
|
|
529
|
+
|
|
530
|
+
const finalActions = await context.tracker.getActionsForIntent(intentId);
|
|
531
|
+
expect(finalActions.length).to.equal(2);
|
|
532
|
+
const finalMovement = finalActions.find(
|
|
533
|
+
(a) => a.type === 'inventory_movement',
|
|
534
|
+
);
|
|
535
|
+
expect(finalMovement).to.exist;
|
|
536
|
+
const depositAction = finalActions.find(
|
|
537
|
+
(a) => a.type === 'inventory_deposit',
|
|
538
|
+
);
|
|
539
|
+
expect(depositAction).to.exist;
|
|
540
|
+
|
|
541
|
+
const finalBalances = await getErc20RouterBalances(
|
|
542
|
+
localProviders,
|
|
543
|
+
erc20DeployedAddresses,
|
|
544
|
+
);
|
|
545
|
+
const { surplusChain, neutralChain } = classifyChains(
|
|
546
|
+
'anvil2',
|
|
547
|
+
depositAction!,
|
|
548
|
+
);
|
|
549
|
+
|
|
550
|
+
expect(
|
|
551
|
+
finalBalances.anvil2.gt(initialBalances.anvil2),
|
|
552
|
+
'Destination router balance should increase',
|
|
553
|
+
).to.be.true;
|
|
554
|
+
expect(
|
|
555
|
+
finalBalances[surplusChain].lt(initialBalances[surplusChain]),
|
|
556
|
+
`Surplus router (${surplusChain}) balance should decrease`,
|
|
557
|
+
).to.be.true;
|
|
558
|
+
if (neutralChain) {
|
|
559
|
+
expect(
|
|
560
|
+
finalBalances[neutralChain].eq(initialBalances[neutralChain]),
|
|
561
|
+
'Uninvolved router balance should remain unchanged',
|
|
562
|
+
).to.be.true;
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
it('enforces single active inventory intent when multiple deficit chains exist', async function () {
|
|
567
|
+
const context = await new TestRebalancerBuilder(
|
|
568
|
+
deploymentManager,
|
|
569
|
+
multiProvider,
|
|
570
|
+
)
|
|
571
|
+
.withStrategy(
|
|
572
|
+
buildErc20InventoryMinAmountStrategyConfig(erc20DeployedAddresses),
|
|
573
|
+
)
|
|
574
|
+
.withErc20InventoryConfig({
|
|
575
|
+
inventorySignerKey: ANVIL_USER_PRIVATE_KEY,
|
|
576
|
+
erc20DeployedAddresses,
|
|
577
|
+
})
|
|
578
|
+
.withMockExternalBridge(mockBridge)
|
|
579
|
+
.withBalances('ERC20_INVENTORY_MULTI_DEFICIT')
|
|
580
|
+
.withExecutionMode('execute')
|
|
581
|
+
.build();
|
|
582
|
+
|
|
583
|
+
const initialBalances = await getErc20RouterBalances(
|
|
584
|
+
localProviders,
|
|
585
|
+
erc20DeployedAddresses,
|
|
586
|
+
);
|
|
587
|
+
|
|
588
|
+
await executeCycle(context);
|
|
589
|
+
|
|
590
|
+
let activeIntents = await context.tracker.getActiveRebalanceIntents();
|
|
591
|
+
expect(activeIntents.length).to.equal(1);
|
|
592
|
+
expect(activeIntents[0].destination).to.equal(DOMAIN_IDS.anvil2);
|
|
593
|
+
expect(activeIntents[0].amount).to.equal(expectedDeficit);
|
|
594
|
+
const firstIntentId = activeIntents[0].id;
|
|
595
|
+
|
|
596
|
+
const partialIntents =
|
|
597
|
+
await context.tracker.getPartiallyFulfilledInventoryIntents();
|
|
598
|
+
expect(partialIntents.length).to.equal(1);
|
|
599
|
+
expect(partialIntents[0].hasInflightDeposit).to.equal(true);
|
|
600
|
+
|
|
601
|
+
const actions = await context.tracker.getActionsForIntent(firstIntentId);
|
|
602
|
+
expect(actions.length).to.equal(1);
|
|
603
|
+
expect(
|
|
604
|
+
actions.filter((a) => a.type === 'inventory_movement').length,
|
|
605
|
+
).to.equal(0);
|
|
606
|
+
expect(
|
|
607
|
+
actions.filter((a) => a.type === 'inventory_deposit').length,
|
|
608
|
+
).to.equal(1);
|
|
609
|
+
|
|
610
|
+
await context.tracker.syncInventoryMovementActions({
|
|
611
|
+
[ExternalBridgeType.LiFi]: mockBridge,
|
|
612
|
+
});
|
|
613
|
+
await relayInProgressInventoryDeposits(
|
|
614
|
+
context,
|
|
615
|
+
localProviders,
|
|
616
|
+
multiProvider,
|
|
617
|
+
hyperlaneCore,
|
|
618
|
+
);
|
|
619
|
+
|
|
620
|
+
const completedFirstIntent =
|
|
621
|
+
await context.tracker.getRebalanceIntent(firstIntentId);
|
|
622
|
+
expect(completedFirstIntent!.status).to.equal('complete');
|
|
623
|
+
|
|
624
|
+
const depositAction = actions.find((a) => a.type === 'inventory_deposit');
|
|
625
|
+
const midBalances = await getErc20RouterBalances(
|
|
626
|
+
localProviders,
|
|
627
|
+
erc20DeployedAddresses,
|
|
628
|
+
);
|
|
629
|
+
const { surplusChain, neutralChain } = classifyChains(
|
|
630
|
+
'anvil2',
|
|
631
|
+
depositAction!,
|
|
632
|
+
);
|
|
633
|
+
|
|
634
|
+
expect(
|
|
635
|
+
midBalances.anvil2.gt(initialBalances.anvil2),
|
|
636
|
+
'Deficit router (anvil2) balance should increase',
|
|
637
|
+
).to.be.true;
|
|
638
|
+
expect(
|
|
639
|
+
midBalances[surplusChain].lt(initialBalances[surplusChain]),
|
|
640
|
+
`Surplus router (${surplusChain}) balance should decrease`,
|
|
641
|
+
).to.be.true;
|
|
642
|
+
if (neutralChain) {
|
|
643
|
+
expect(
|
|
644
|
+
midBalances[neutralChain].eq(initialBalances[neutralChain]),
|
|
645
|
+
'Uninvolved router balance should remain unchanged',
|
|
646
|
+
).to.be.true;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
await executeCycle(context);
|
|
650
|
+
activeIntents = await context.tracker.getActiveRebalanceIntents();
|
|
651
|
+
expect(activeIntents.length).to.equal(1);
|
|
652
|
+
expect(activeIntents[0].destination).to.equal(DOMAIN_IDS.anvil3);
|
|
653
|
+
expect(activeIntents[0].amount).to.equal(expectedDeficit);
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
it('uses multiple bridge movements from different sources before completing deposit', async function () {
|
|
657
|
+
const context = await new TestRebalancerBuilder(
|
|
658
|
+
deploymentManager,
|
|
659
|
+
multiProvider,
|
|
660
|
+
)
|
|
661
|
+
.withStrategy(
|
|
662
|
+
buildErc20InventoryMinAmountStrategyConfig(erc20DeployedAddresses),
|
|
663
|
+
)
|
|
664
|
+
.withErc20InventoryConfig({
|
|
665
|
+
inventorySignerKey: ANVIL_USER_PRIVATE_KEY,
|
|
666
|
+
erc20DeployedAddresses,
|
|
667
|
+
})
|
|
668
|
+
.withMockExternalBridge(mockBridge)
|
|
669
|
+
.withBalances('ERC20_INVENTORY_EMPTY_DEST')
|
|
670
|
+
.withInventorySignerBalances('ERC20_SIGNER_SPLIT_SOURCES')
|
|
671
|
+
.withExecutionMode('execute')
|
|
672
|
+
.build();
|
|
673
|
+
|
|
674
|
+
// Cycle 1: creates intent + both bridge movements from anvil1 and anvil3
|
|
675
|
+
await executeCycle(context);
|
|
676
|
+
|
|
677
|
+
const activeIntents = await context.tracker.getActiveRebalanceIntents();
|
|
678
|
+
expect(activeIntents.length).to.equal(1);
|
|
679
|
+
expect(activeIntents[0].destination).to.equal(DOMAIN_IDS.anvil2);
|
|
680
|
+
expect(activeIntents[0].amount).to.equal(expectedDeficit);
|
|
681
|
+
const intentId = activeIntents[0].id;
|
|
682
|
+
|
|
683
|
+
// Sync: both movements should be complete after a single cycle
|
|
684
|
+
await context.tracker.syncInventoryMovementActions({
|
|
685
|
+
[ExternalBridgeType.LiFi]: mockBridge,
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
let actions = await context.tracker.getActionsForIntent(intentId);
|
|
689
|
+
expect(actions.length).to.equal(2);
|
|
690
|
+
const movementActions = actions.filter(
|
|
691
|
+
(a) => a.type === 'inventory_movement',
|
|
692
|
+
);
|
|
693
|
+
expect(movementActions.length).to.equal(2);
|
|
694
|
+
|
|
695
|
+
// Verify movements from different sources, both targeting anvil2
|
|
696
|
+
const origins = new Set(movementActions.map((a) => a.origin));
|
|
697
|
+
expect(origins.has(DOMAIN_IDS.anvil1)).to.be.true;
|
|
698
|
+
expect(origins.has(DOMAIN_IDS.anvil3)).to.be.true;
|
|
699
|
+
movementActions.forEach((a) => {
|
|
700
|
+
expect(a.destination).to.equal(DOMAIN_IDS.anvil2);
|
|
701
|
+
expect(a.status).to.equal('complete');
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
// Cycle 2: deposit from bridged funds completes the intent
|
|
705
|
+
await executeCycle(context);
|
|
706
|
+
await context.tracker.syncInventoryMovementActions({
|
|
707
|
+
[ExternalBridgeType.LiFi]: mockBridge,
|
|
708
|
+
});
|
|
709
|
+
await relayInProgressInventoryDeposits(
|
|
710
|
+
context,
|
|
711
|
+
localProviders,
|
|
712
|
+
multiProvider,
|
|
713
|
+
hyperlaneCore,
|
|
714
|
+
);
|
|
715
|
+
|
|
716
|
+
const finalActiveIntents =
|
|
717
|
+
await context.tracker.getActiveRebalanceIntents();
|
|
718
|
+
expect(finalActiveIntents.length).to.equal(0);
|
|
719
|
+
const partialIntents =
|
|
720
|
+
await context.tracker.getPartiallyFulfilledInventoryIntents();
|
|
721
|
+
expect(partialIntents.length).to.equal(0);
|
|
722
|
+
|
|
723
|
+
actions = await context.tracker.getActionsForIntent(intentId);
|
|
724
|
+
expect(actions.length).to.equal(3);
|
|
725
|
+
expect(
|
|
726
|
+
actions.filter((a) => a.type === 'inventory_movement').length,
|
|
727
|
+
).to.equal(2);
|
|
728
|
+
expect(
|
|
729
|
+
actions.filter((a) => a.type === 'inventory_deposit').length,
|
|
730
|
+
).to.equal(1);
|
|
731
|
+
|
|
732
|
+
const finalIntent = await context.tracker.getRebalanceIntent(intentId);
|
|
733
|
+
expect(finalIntent!.status).to.equal('complete');
|
|
734
|
+
});
|
|
735
|
+
});
|