@hyperlane-xyz/rebalancer 2.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bridges/LiFiBridge.d.ts +67 -0
- package/dist/bridges/LiFiBridge.d.ts.map +1 -0
- package/dist/bridges/LiFiBridge.js +386 -0
- package/dist/bridges/LiFiBridge.js.map +1 -0
- package/dist/config/RebalancerConfig.d.ts +8 -2
- package/dist/config/RebalancerConfig.d.ts.map +1 -1
- package/dist/config/RebalancerConfig.js +9 -4
- package/dist/config/RebalancerConfig.js.map +1 -1
- package/dist/config/RebalancerConfig.test.js +135 -1
- package/dist/config/RebalancerConfig.test.js.map +1 -1
- package/dist/config/types.d.ts +1023 -304
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +113 -10
- package/dist/config/types.js.map +1 -1
- package/dist/core/InventoryRebalancer.d.ts +190 -0
- package/dist/core/InventoryRebalancer.d.ts.map +1 -0
- package/dist/core/InventoryRebalancer.js +892 -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 +1382 -0
- package/dist/core/InventoryRebalancer.test.js.map +1 -0
- package/dist/core/Rebalancer.d.ts +11 -4
- package/dist/core/Rebalancer.d.ts.map +1 -1
- package/dist/core/Rebalancer.js +92 -9
- package/dist/core/Rebalancer.js.map +1 -1
- package/dist/core/Rebalancer.test.js +82 -49
- package/dist/core/Rebalancer.test.js.map +1 -1
- package/dist/core/RebalancerOrchestrator.d.ts +30 -9
- package/dist/core/RebalancerOrchestrator.d.ts.map +1 -1
- package/dist/core/RebalancerOrchestrator.js +79 -71
- package/dist/core/RebalancerOrchestrator.js.map +1 -1
- 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 +719 -0
- package/dist/core/RebalancerOrchestrator.test.js.map +1 -0
- package/dist/core/RebalancerService.d.ts +7 -3
- package/dist/core/RebalancerService.d.ts.map +1 -1
- package/dist/core/RebalancerService.js +44 -24
- package/dist/core/RebalancerService.js.map +1 -1
- package/dist/core/RebalancerService.test.js +74 -110
- package/dist/core/RebalancerService.test.js.map +1 -1
- package/dist/e2e/collateral-deficit.e2e-test.js +1 -3
- package/dist/e2e/collateral-deficit.e2e-test.js.map +1 -1
- package/dist/e2e/composite.e2e-test.js.map +1 -1
- package/dist/e2e/harness/BridgeSetup.d.ts +6 -0
- package/dist/e2e/harness/BridgeSetup.d.ts.map +1 -1
- package/dist/e2e/harness/BridgeSetup.js +10 -1
- package/dist/e2e/harness/BridgeSetup.js.map +1 -1
- package/dist/e2e/harness/ForkIndexer.d.ts.map +1 -1
- package/dist/e2e/harness/ForkIndexer.js +1 -0
- package/dist/e2e/harness/ForkIndexer.js.map +1 -1
- package/dist/e2e/harness/TestHelpers.d.ts.map +1 -1
- package/dist/e2e/harness/TestHelpers.js +1 -4
- package/dist/e2e/harness/TestHelpers.js.map +1 -1
- package/dist/e2e/harness/TestRebalancer.d.ts +1 -1
- package/dist/e2e/harness/TestRebalancer.d.ts.map +1 -1
- package/dist/e2e/harness/TestRebalancer.js +9 -9
- package/dist/e2e/harness/TestRebalancer.js.map +1 -1
- package/dist/e2e/minAmount.e2e-test.js +0 -1
- package/dist/e2e/minAmount.e2e-test.js.map +1 -1
- package/dist/e2e/weighted.e2e-test.js +0 -1
- package/dist/e2e/weighted.e2e-test.js.map +1 -1
- package/dist/factories/RebalancerContextFactory.d.ts +48 -6
- package/dist/factories/RebalancerContextFactory.d.ts.map +1 -1
- package/dist/factories/RebalancerContextFactory.js +171 -17
- package/dist/factories/RebalancerContextFactory.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/interfaces/IExternalBridge.d.ts +101 -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/IMonitor.d.ts +1 -0
- package/dist/interfaces/IMonitor.d.ts.map +1 -1
- package/dist/interfaces/IRebalancer.d.ts +25 -25
- package/dist/interfaces/IRebalancer.d.ts.map +1 -1
- package/dist/interfaces/IStrategy.d.ts +36 -3
- package/dist/interfaces/IStrategy.d.ts.map +1 -1
- package/dist/interfaces/IStrategy.js +12 -1
- package/dist/interfaces/IStrategy.js.map +1 -1
- package/dist/metrics/PriceGetter.js +1 -1
- package/dist/metrics/PriceGetter.js.map +1 -1
- package/dist/metrics/scripts/metrics.d.ts +3 -3
- package/dist/monitor/Monitor.d.ts +12 -2
- package/dist/monitor/Monitor.d.ts.map +1 -1
- package/dist/monitor/Monitor.js +46 -1
- package/dist/monitor/Monitor.js.map +1 -1
- package/dist/service.js +40 -17
- package/dist/service.js.map +1 -1
- package/dist/strategy/BaseStrategy.d.ts +12 -6
- package/dist/strategy/BaseStrategy.d.ts.map +1 -1
- package/dist/strategy/BaseStrategy.js +56 -21
- package/dist/strategy/BaseStrategy.js.map +1 -1
- package/dist/strategy/CollateralDeficitStrategy.d.ts +1 -1
- package/dist/strategy/CollateralDeficitStrategy.d.ts.map +1 -1
- package/dist/strategy/CollateralDeficitStrategy.js +19 -11
- package/dist/strategy/CollateralDeficitStrategy.js.map +1 -1
- package/dist/strategy/CollateralDeficitStrategy.test.js +135 -2
- package/dist/strategy/CollateralDeficitStrategy.test.js.map +1 -1
- package/dist/strategy/CompositeStrategy.test.js +13 -0
- package/dist/strategy/CompositeStrategy.test.js.map +1 -1
- package/dist/strategy/MinAmountStrategy.test.js +4 -0
- package/dist/strategy/MinAmountStrategy.test.js.map +1 -1
- package/dist/strategy/StrategyFactory.d.ts +2 -1
- package/dist/strategy/StrategyFactory.d.ts.map +1 -1
- package/dist/strategy/StrategyFactory.js +24 -8
- package/dist/strategy/StrategyFactory.js.map +1 -1
- package/dist/strategy/WeightedStrategy.test.js +6 -0
- package/dist/strategy/WeightedStrategy.test.js.map +1 -1
- package/dist/test/helpers.d.ts +8 -7
- package/dist/test/helpers.d.ts.map +1 -1
- package/dist/test/helpers.js +23 -5
- package/dist/test/helpers.js.map +1 -1
- package/dist/test/lifiMocks.d.ts +51 -0
- package/dist/test/lifiMocks.d.ts.map +1 -0
- package/dist/test/lifiMocks.js +130 -0
- package/dist/test/lifiMocks.js.map +1 -0
- package/dist/tracking/ActionTracker.d.ts +34 -1
- package/dist/tracking/ActionTracker.d.ts.map +1 -1
- package/dist/tracking/ActionTracker.js +233 -26
- package/dist/tracking/ActionTracker.js.map +1 -1
- package/dist/tracking/ActionTracker.test.js +380 -19
- package/dist/tracking/ActionTracker.test.js.map +1 -1
- package/dist/tracking/IActionTracker.d.ts +48 -3
- package/dist/tracking/IActionTracker.d.ts.map +1 -1
- package/dist/tracking/InflightContextAdapter.d.ts.map +1 -1
- package/dist/tracking/InflightContextAdapter.js +24 -7
- package/dist/tracking/InflightContextAdapter.js.map +1 -1
- package/dist/tracking/InflightContextAdapter.test.js +7 -4
- package/dist/tracking/InflightContextAdapter.test.js.map +1 -1
- package/dist/tracking/types.d.ts +33 -2
- package/dist/tracking/types.d.ts.map +1 -1
- package/dist/utils/ExplorerClient.d.ts +3 -1
- package/dist/utils/ExplorerClient.d.ts.map +1 -1
- package/dist/utils/ExplorerClient.js +16 -8
- package/dist/utils/ExplorerClient.js.map +1 -1
- package/dist/utils/bridgeUtils.d.ts +27 -4
- package/dist/utils/bridgeUtils.d.ts.map +1 -1
- package/dist/utils/bridgeUtils.js +38 -0
- package/dist/utils/bridgeUtils.js.map +1 -1
- package/dist/utils/bridgeUtils.test.js +9 -0
- package/dist/utils/bridgeUtils.test.js.map +1 -1
- package/dist/utils/gasEstimation.d.ts +65 -0
- package/dist/utils/gasEstimation.d.ts.map +1 -0
- package/dist/utils/gasEstimation.js +176 -0
- package/dist/utils/gasEstimation.js.map +1 -0
- package/dist/utils/tokenUtils.d.ts +9 -1
- package/dist/utils/tokenUtils.d.ts.map +1 -1
- package/dist/utils/tokenUtils.js +11 -0
- package/dist/utils/tokenUtils.js.map +1 -1
- package/package.json +9 -7
- package/src/bridges/LiFiBridge.ts +538 -0
- package/src/config/RebalancerConfig.test.ts +162 -0
- package/src/config/RebalancerConfig.ts +21 -3
- package/src/config/types.ts +147 -10
- package/src/core/InventoryRebalancer.test.ts +1721 -0
- package/src/core/InventoryRebalancer.ts +1265 -0
- package/src/core/Rebalancer.test.ts +84 -30
- package/src/core/Rebalancer.ts +144 -23
- package/src/core/RebalancerOrchestrator.test.ts +869 -0
- package/src/core/RebalancerOrchestrator.ts +146 -95
- package/src/core/RebalancerService.test.ts +86 -124
- package/src/core/RebalancerService.ts +67 -33
- package/src/e2e/collateral-deficit.e2e-test.ts +2 -4
- package/src/e2e/composite.e2e-test.ts +5 -5
- package/src/e2e/harness/BridgeSetup.ts +28 -1
- package/src/e2e/harness/ForkIndexer.ts +1 -0
- package/src/e2e/harness/TestHelpers.ts +1 -4
- package/src/e2e/harness/TestRebalancer.ts +10 -7
- package/src/e2e/minAmount.e2e-test.ts +1 -2
- package/src/e2e/weighted.e2e-test.ts +1 -2
- package/src/factories/RebalancerContextFactory.ts +294 -24
- package/src/index.ts +22 -5
- package/src/interfaces/IExternalBridge.ts +115 -0
- package/src/interfaces/IMonitor.ts +1 -0
- package/src/interfaces/IRebalancer.ts +45 -29
- package/src/interfaces/IStrategy.ts +50 -3
- package/src/metrics/PriceGetter.ts +1 -1
- package/src/monitor/Monitor.ts +81 -2
- package/src/service.ts +59 -18
- package/src/strategy/BaseStrategy.ts +77 -24
- package/src/strategy/CollateralDeficitStrategy.test.ts +181 -4
- package/src/strategy/CollateralDeficitStrategy.ts +42 -15
- package/src/strategy/CompositeStrategy.test.ts +13 -0
- package/src/strategy/MinAmountStrategy.test.ts +4 -0
- package/src/strategy/StrategyFactory.ts +33 -6
- package/src/strategy/WeightedStrategy.test.ts +6 -0
- package/src/test/helpers.ts +39 -14
- package/src/test/lifiMocks.ts +174 -0
- package/src/tracking/ActionTracker.test.ts +443 -19
- package/src/tracking/ActionTracker.ts +339 -28
- package/src/tracking/IActionTracker.ts +59 -3
- package/src/tracking/InflightContextAdapter.test.ts +7 -4
- package/src/tracking/InflightContextAdapter.ts +42 -9
- package/src/tracking/types.ts +45 -2
- package/src/utils/ExplorerClient.ts +27 -10
- package/src/utils/bridgeUtils.test.ts +9 -0
- package/src/utils/bridgeUtils.ts +75 -6
- package/src/utils/gasEstimation.ts +272 -0
- package/src/utils/tokenUtils.ts +12 -0
- package/dist/tracking/index.d.ts +0 -7
- package/dist/tracking/index.d.ts.map +0 -1
- package/dist/tracking/index.js +0 -6
- package/dist/tracking/index.js.map +0 -1
- package/dist/utils/index.d.ts +0 -5
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js +0 -5
- package/dist/utils/index.js.map +0 -1
- package/src/tracking/index.ts +0 -36
- package/src/utils/index.ts +0 -4
|
@@ -233,7 +233,7 @@ describe('CompositeStrategy E2E', function () {
|
|
|
233
233
|
hyperlaneCore,
|
|
234
234
|
{
|
|
235
235
|
dispatchTx: rebalanceTxReceipt!,
|
|
236
|
-
messageId: action.messageId
|
|
236
|
+
messageId: action.messageId!,
|
|
237
237
|
origin: originChain,
|
|
238
238
|
destination: destChain,
|
|
239
239
|
},
|
|
@@ -432,7 +432,7 @@ describe('CompositeStrategy E2E', function () {
|
|
|
432
432
|
hyperlaneCore,
|
|
433
433
|
{
|
|
434
434
|
dispatchTx: rebalanceTxReceipt!,
|
|
435
|
-
messageId: action.messageId
|
|
435
|
+
messageId: action.messageId!,
|
|
436
436
|
origin: originChain,
|
|
437
437
|
destination: destChain,
|
|
438
438
|
},
|
|
@@ -651,7 +651,7 @@ describe('CompositeStrategy E2E', function () {
|
|
|
651
651
|
hyperlaneCore,
|
|
652
652
|
{
|
|
653
653
|
dispatchTx: rebalanceTxReceipt!,
|
|
654
|
-
messageId: action.messageId
|
|
654
|
+
messageId: action.messageId!,
|
|
655
655
|
origin: originChain,
|
|
656
656
|
destination: destChain,
|
|
657
657
|
},
|
|
@@ -794,7 +794,7 @@ describe('CompositeStrategy E2E', function () {
|
|
|
794
794
|
);
|
|
795
795
|
const relayResult = await tryRelayMessage(multiProvider, hyperlaneCore, {
|
|
796
796
|
dispatchTx: rebalanceTxReceipt,
|
|
797
|
-
messageId: inflightToBase.messageId
|
|
797
|
+
messageId: inflightToBase.messageId!,
|
|
798
798
|
origin: 'anvil1',
|
|
799
799
|
destination: 'anvil3',
|
|
800
800
|
});
|
|
@@ -959,7 +959,7 @@ describe('CompositeStrategy E2E', function () {
|
|
|
959
959
|
|
|
960
960
|
const relayResult = await tryRelayMessage(multiProvider, hyperlaneCore, {
|
|
961
961
|
dispatchTx: rebalanceTxReceipt,
|
|
962
|
-
messageId: action.messageId
|
|
962
|
+
messageId: action.messageId!,
|
|
963
963
|
origin: originChain,
|
|
964
964
|
destination: destChain,
|
|
965
965
|
});
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { BigNumber, ethers, providers } from 'ethers';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
ERC20__factory,
|
|
5
|
+
MovableCollateralRouter__factory,
|
|
6
|
+
} from '@hyperlane-xyz/core';
|
|
4
7
|
|
|
5
8
|
export async function setupCollateralBalances(
|
|
6
9
|
providers: Map<string, providers.JsonRpcProvider>,
|
|
@@ -65,3 +68,27 @@ export async function getAllCollateralBalances(
|
|
|
65
68
|
}
|
|
66
69
|
return balances;
|
|
67
70
|
}
|
|
71
|
+
|
|
72
|
+
export interface AllowedBridgeConfig {
|
|
73
|
+
monitoredRouterAddress: string;
|
|
74
|
+
bridgeAddress: string;
|
|
75
|
+
destinationDomain: number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export async function configureAllowedBridges(
|
|
79
|
+
provider: providers.JsonRpcProvider,
|
|
80
|
+
configs: AllowedBridgeConfig[],
|
|
81
|
+
deployerKey: string,
|
|
82
|
+
): Promise<void> {
|
|
83
|
+
if (configs.length === 0) return;
|
|
84
|
+
|
|
85
|
+
const deployer = new ethers.Wallet(deployerKey, provider);
|
|
86
|
+
const router = MovableCollateralRouter__factory.connect(
|
|
87
|
+
configs[0].monitoredRouterAddress,
|
|
88
|
+
deployer,
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
for (const config of configs) {
|
|
92
|
+
await router.addBridge(config.destinationDomain, config.bridgeAddress);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -10,6 +10,7 @@ import { addressToBytes32 } from '@hyperlane-xyz/utils';
|
|
|
10
10
|
|
|
11
11
|
import { RebalancerConfig } from '../../config/RebalancerConfig.js';
|
|
12
12
|
import {
|
|
13
|
+
DEFAULT_INTENT_TTL_MS,
|
|
13
14
|
type StrategyConfig,
|
|
14
15
|
getStrategyChainNames,
|
|
15
16
|
} from '../../config/types.js';
|
|
@@ -21,7 +22,7 @@ import { RebalancerContextFactory } from '../../factories/RebalancerContextFacto
|
|
|
21
22
|
import type { ConfirmedBlockTags } from '../../interfaces/IMonitor.js';
|
|
22
23
|
import type { IStrategy } from '../../interfaces/IStrategy.js';
|
|
23
24
|
import type { Monitor } from '../../monitor/Monitor.js';
|
|
24
|
-
import type { IActionTracker } from '../../tracking/
|
|
25
|
+
import type { IActionTracker } from '../../tracking/IActionTracker.js';
|
|
25
26
|
import type { ExplorerMessage } from '../../utils/ExplorerClient.js';
|
|
26
27
|
import {
|
|
27
28
|
ANVIL_TEST_PRIVATE_KEY,
|
|
@@ -203,6 +204,7 @@ export class TestRebalancerBuilder {
|
|
|
203
204
|
const rebalancerConfig = new RebalancerConfig(
|
|
204
205
|
MONITORED_ROUTE_ID,
|
|
205
206
|
this.strategyConfig,
|
|
207
|
+
DEFAULT_INTENT_TTL_MS,
|
|
206
208
|
);
|
|
207
209
|
|
|
208
210
|
const registry = this.deploymentManager.getRegistry();
|
|
@@ -212,6 +214,7 @@ export class TestRebalancerBuilder {
|
|
|
212
214
|
const contextFactory = await RebalancerContextFactory.create(
|
|
213
215
|
rebalancerConfig,
|
|
214
216
|
workingMultiProvider,
|
|
217
|
+
undefined,
|
|
215
218
|
mpp,
|
|
216
219
|
registry,
|
|
217
220
|
this.logger,
|
|
@@ -225,18 +228,17 @@ export class TestRebalancerBuilder {
|
|
|
225
228
|
await tracker.initialize();
|
|
226
229
|
this.logger.info('ActionTracker initialized with mock explorer');
|
|
227
230
|
|
|
228
|
-
// In execute mode, create
|
|
229
|
-
const
|
|
231
|
+
// In execute mode, create actual Rebalancers to enable intent creation and execution
|
|
232
|
+
const rebalancers =
|
|
230
233
|
this.executionMode === 'execute'
|
|
231
|
-
? contextFactory.
|
|
232
|
-
:
|
|
234
|
+
? (await contextFactory.createRebalancers(tracker)).rebalancers
|
|
235
|
+
: [];
|
|
233
236
|
|
|
234
237
|
const orchestratorDeps: RebalancerOrchestratorDeps = {
|
|
235
238
|
strategy,
|
|
236
|
-
|
|
239
|
+
rebalancers,
|
|
237
240
|
actionTracker: tracker,
|
|
238
241
|
inflightContextAdapter: adapter,
|
|
239
|
-
multiProvider: workingMultiProvider,
|
|
240
242
|
rebalancerConfig,
|
|
241
243
|
logger: this.logger,
|
|
242
244
|
};
|
|
@@ -325,6 +327,7 @@ export class TestRebalancerBuilder {
|
|
|
325
327
|
origin_tx_recipient: deployedAddresses.monitoredRoute[params.from],
|
|
326
328
|
is_delivered: false,
|
|
327
329
|
message_body: encodeWarpRouteMessageBody(warpRecipient, params.amount),
|
|
330
|
+
send_occurred_at: null,
|
|
328
331
|
};
|
|
329
332
|
|
|
330
333
|
userTransfers.push(mockTransfer);
|
|
@@ -212,7 +212,7 @@ describe('MinAmountStrategy E2E', function () {
|
|
|
212
212
|
hyperlaneCore,
|
|
213
213
|
{
|
|
214
214
|
dispatchTx: rebalanceTxReceipt,
|
|
215
|
-
messageId: actionToArbitrum.messageId
|
|
215
|
+
messageId: actionToArbitrum.messageId!,
|
|
216
216
|
origin: 'anvil1',
|
|
217
217
|
destination: 'anvil2',
|
|
218
218
|
},
|
|
@@ -236,7 +236,6 @@ describe('MinAmountStrategy E2E', function () {
|
|
|
236
236
|
activeIntents[0].id,
|
|
237
237
|
);
|
|
238
238
|
expect(completedIntent!.status).to.equal('complete');
|
|
239
|
-
expect(completedIntent!.fulfilledAmount).to.equal(70000000n);
|
|
240
239
|
});
|
|
241
240
|
|
|
242
241
|
it('should handle stuck transfer and propose routes to destination', async function () {
|
|
@@ -194,7 +194,7 @@ describe('WeightedStrategy E2E', function () {
|
|
|
194
194
|
hyperlaneCore,
|
|
195
195
|
{
|
|
196
196
|
dispatchTx: rebalanceTxReceipt,
|
|
197
|
-
messageId: actionToBase.messageId
|
|
197
|
+
messageId: actionToBase.messageId!,
|
|
198
198
|
origin: 'anvil1',
|
|
199
199
|
destination: 'anvil3',
|
|
200
200
|
},
|
|
@@ -218,7 +218,6 @@ describe('WeightedStrategy E2E', function () {
|
|
|
218
218
|
activeIntents[0].id,
|
|
219
219
|
);
|
|
220
220
|
expect(completedIntent!.status).to.equal('complete');
|
|
221
|
-
expect(completedIntent!.fulfilledAmount).to.equal(1000000000n);
|
|
222
221
|
|
|
223
222
|
// Assert: No more in-progress actions
|
|
224
223
|
const remainingActions = await context.tracker.getInProgressActions();
|
|
@@ -11,35 +11,47 @@ import {
|
|
|
11
11
|
WarpCore,
|
|
12
12
|
type WarpCoreConfig,
|
|
13
13
|
} from '@hyperlane-xyz/sdk';
|
|
14
|
-
import { objMap } from '@hyperlane-xyz/utils';
|
|
14
|
+
import { objMap, toWei } from '@hyperlane-xyz/utils';
|
|
15
15
|
|
|
16
|
+
import { LiFiBridge } from '../bridges/LiFiBridge.js';
|
|
16
17
|
import { type RebalancerConfig } from '../config/RebalancerConfig.js';
|
|
17
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
ExecutionType,
|
|
20
|
+
ExternalBridgeType,
|
|
21
|
+
getAllBridges,
|
|
22
|
+
getStrategyChainConfig,
|
|
23
|
+
getStrategyChainNames,
|
|
24
|
+
} from '../config/types.js';
|
|
25
|
+
import { InventoryRebalancer } from '../core/InventoryRebalancer.js';
|
|
18
26
|
import { Rebalancer } from '../core/Rebalancer.js';
|
|
27
|
+
import { RebalancerOrchestrator } from '../core/RebalancerOrchestrator.js';
|
|
28
|
+
import type { ExternalBridgeRegistry } from '../interfaces/IExternalBridge.js';
|
|
19
29
|
import type { IRebalancer } from '../interfaces/IRebalancer.js';
|
|
20
30
|
import type { IStrategy } from '../interfaces/IStrategy.js';
|
|
21
31
|
import { Metrics } from '../metrics/Metrics.js';
|
|
22
32
|
import { PriceGetter } from '../metrics/PriceGetter.js';
|
|
23
|
-
import { Monitor } from '../monitor/Monitor.js';
|
|
33
|
+
import { type InventoryMonitorConfig, Monitor } from '../monitor/Monitor.js';
|
|
24
34
|
import { StrategyFactory } from '../strategy/StrategyFactory.js';
|
|
25
35
|
import {
|
|
26
36
|
ActionTracker,
|
|
27
37
|
type ActionTrackerConfig,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
} from '../tracking/ActionTracker.js';
|
|
39
|
+
import type { IActionTracker } from '../tracking/IActionTracker.js';
|
|
40
|
+
import { InflightContextAdapter } from '../tracking/InflightContextAdapter.js';
|
|
41
|
+
import { InMemoryStore } from '../tracking/store/index.js';
|
|
42
|
+
import type {
|
|
43
|
+
RebalanceAction,
|
|
44
|
+
RebalanceActionStatus,
|
|
45
|
+
RebalanceIntent,
|
|
46
|
+
RebalanceIntentStatus,
|
|
47
|
+
Transfer,
|
|
48
|
+
TransferStatus,
|
|
49
|
+
} from '../tracking/types.js';
|
|
38
50
|
import {
|
|
39
51
|
ExplorerClient,
|
|
40
52
|
type IExplorerClient,
|
|
41
53
|
} from '../utils/ExplorerClient.js';
|
|
42
|
-
import { isCollateralizedTokenEligibleForRebalancing } from '../utils/
|
|
54
|
+
import { isCollateralizedTokenEligibleForRebalancing } from '../utils/tokenUtils.js';
|
|
43
55
|
|
|
44
56
|
const DEFAULT_EXPLORER_URL =
|
|
45
57
|
process.env.EXPLORER_API_URL || 'https://explorer4.hasura.app/v1/graphql';
|
|
@@ -49,7 +61,8 @@ export class RebalancerContextFactory {
|
|
|
49
61
|
* @param config - The rebalancer config
|
|
50
62
|
* @param warpCore - An instance of `WarpCore` configured for the specified `warpRouteId`.
|
|
51
63
|
* @param tokensByChainName - A map of chain->token to ease the lookup of token by chain
|
|
52
|
-
* @param multiProvider - MultiProvider instance
|
|
64
|
+
* @param multiProvider - MultiProvider instance (for movable collateral operations)
|
|
65
|
+
* @param inventoryMultiProvider - MultiProvider instance for inventory operations (optional)
|
|
53
66
|
* @param multiProtocolProvider - MultiProtocolProvider instance (with mailbox metadata)
|
|
54
67
|
* @param registry - IRegistry instance
|
|
55
68
|
* @param logger - Logger instance
|
|
@@ -59,14 +72,24 @@ export class RebalancerContextFactory {
|
|
|
59
72
|
private readonly warpCore: WarpCore,
|
|
60
73
|
private readonly tokensByChainName: ChainMap<Token>,
|
|
61
74
|
private readonly multiProvider: MultiProvider,
|
|
75
|
+
private readonly inventoryMultiProvider: MultiProvider | undefined,
|
|
62
76
|
private readonly multiProtocolProvider: MultiProtocolProvider,
|
|
63
77
|
private readonly registry: IRegistry,
|
|
64
78
|
private readonly logger: Logger,
|
|
65
79
|
) {}
|
|
66
80
|
|
|
81
|
+
/**
|
|
82
|
+
* @param config - The rebalancer config
|
|
83
|
+
* @param multiProvider - MultiProvider instance (for movable collateral operations)
|
|
84
|
+
* @param inventoryMultiProvider - MultiProvider instance for inventory operations (optional)
|
|
85
|
+
* @param multiProtocolProvider - MultiProtocolProvider instance (optional, created from multiProvider if not provided)
|
|
86
|
+
* @param registry - IRegistry instance
|
|
87
|
+
* @param logger - Logger instance
|
|
88
|
+
*/
|
|
67
89
|
public static async create(
|
|
68
90
|
config: RebalancerConfig,
|
|
69
91
|
multiProvider: MultiProvider,
|
|
92
|
+
inventoryMultiProvider: MultiProvider | undefined,
|
|
70
93
|
multiProtocolProvider: MultiProtocolProvider | undefined,
|
|
71
94
|
registry: IRegistry,
|
|
72
95
|
logger: Logger,
|
|
@@ -78,18 +101,15 @@ export class RebalancerContextFactory {
|
|
|
78
101
|
},
|
|
79
102
|
'Creating RebalancerContextFactory',
|
|
80
103
|
);
|
|
104
|
+
|
|
105
|
+
// TODO: should we pull addressed for chains we care about, i.e those in the warp config
|
|
81
106
|
const addresses = await registry.getAddresses();
|
|
82
107
|
|
|
83
108
|
// The Sealevel warp adapters require the Mailbox address, so we
|
|
84
109
|
// get mailboxes for all chains and merge them with the chain metadata.
|
|
85
110
|
const mailboxes = objMap(addresses, (_, { mailbox }) => ({ mailbox }));
|
|
86
111
|
|
|
87
|
-
//
|
|
88
|
-
const mpp =
|
|
89
|
-
multiProtocolProvider ??
|
|
90
|
-
MultiProtocolProvider.fromMultiProvider(multiProvider);
|
|
91
|
-
const extendedMultiProtocolProvider = mpp.extendChainMetadata(mailboxes);
|
|
92
|
-
|
|
112
|
+
// Fetch warp route config FIRST to get chain list
|
|
93
113
|
const warpCoreConfig =
|
|
94
114
|
warpCoreConfigOverride ??
|
|
95
115
|
(await registry.getWarpRoute(config.warpRouteId));
|
|
@@ -98,6 +118,22 @@ export class RebalancerContextFactory {
|
|
|
98
118
|
`Warp route config for ${config.warpRouteId} not found in registry`,
|
|
99
119
|
);
|
|
100
120
|
}
|
|
121
|
+
|
|
122
|
+
// Force-initialize providers for all warp route chains
|
|
123
|
+
// This ensures fromMultiProvider() snapshots actual provider instances
|
|
124
|
+
const warpChains = [
|
|
125
|
+
...new Set(warpCoreConfig.tokens.map((t: any) => t.chainName)),
|
|
126
|
+
];
|
|
127
|
+
for (const chain of warpChains) {
|
|
128
|
+
multiProvider.getProvider(chain);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Create MultiProtocolProvider (convert from MultiProvider if not provided)
|
|
132
|
+
const mpp =
|
|
133
|
+
multiProtocolProvider ??
|
|
134
|
+
MultiProtocolProvider.fromMultiProvider(multiProvider);
|
|
135
|
+
const extendedMultiProtocolProvider = mpp.extendChainMetadata(mailboxes);
|
|
136
|
+
|
|
101
137
|
const warpCore = WarpCore.FromConfig(
|
|
102
138
|
extendedMultiProtocolProvider,
|
|
103
139
|
warpCoreConfig,
|
|
@@ -117,6 +153,7 @@ export class RebalancerContextFactory {
|
|
|
117
153
|
warpCore,
|
|
118
154
|
tokensByChainName,
|
|
119
155
|
multiProvider,
|
|
156
|
+
inventoryMultiProvider,
|
|
120
157
|
extendedMultiProtocolProvider,
|
|
121
158
|
registry,
|
|
122
159
|
logger,
|
|
@@ -154,7 +191,10 @@ export class RebalancerContextFactory {
|
|
|
154
191
|
);
|
|
155
192
|
}
|
|
156
193
|
|
|
157
|
-
public createMonitor(
|
|
194
|
+
public createMonitor(
|
|
195
|
+
checkFrequency: number,
|
|
196
|
+
inventoryConfig?: InventoryMonitorConfig,
|
|
197
|
+
): Monitor {
|
|
158
198
|
this.logger.debug(
|
|
159
199
|
{
|
|
160
200
|
warpRouteId: this.config.warpRouteId,
|
|
@@ -162,7 +202,12 @@ export class RebalancerContextFactory {
|
|
|
162
202
|
},
|
|
163
203
|
'Creating Monitor',
|
|
164
204
|
);
|
|
165
|
-
return new Monitor(
|
|
205
|
+
return new Monitor(
|
|
206
|
+
checkFrequency,
|
|
207
|
+
this.warpCore,
|
|
208
|
+
this.logger,
|
|
209
|
+
inventoryConfig,
|
|
210
|
+
);
|
|
166
211
|
}
|
|
167
212
|
|
|
168
213
|
public async createStrategy(metrics?: Metrics): Promise<IStrategy> {
|
|
@@ -177,16 +222,48 @@ export class RebalancerContextFactory {
|
|
|
177
222
|
},
|
|
178
223
|
'Creating Strategy',
|
|
179
224
|
);
|
|
225
|
+
|
|
226
|
+
// Build minAmountsByChain from chain configs
|
|
227
|
+
const chainNames = getStrategyChainNames(this.config.strategyConfig);
|
|
228
|
+
const minAmountsByChain: ChainMap<bigint> = {};
|
|
229
|
+
|
|
230
|
+
for (const chainName of chainNames) {
|
|
231
|
+
const chainConfig = getStrategyChainConfig(
|
|
232
|
+
this.config.strategyConfig,
|
|
233
|
+
chainName,
|
|
234
|
+
);
|
|
235
|
+
if (chainConfig?.bridgeMinAcceptedAmount) {
|
|
236
|
+
const token = this.tokensByChainName[chainName];
|
|
237
|
+
const decimals = token?.decimals ?? 18;
|
|
238
|
+
minAmountsByChain[chainName] = BigInt(
|
|
239
|
+
toWei(chainConfig.bridgeMinAcceptedAmount, decimals),
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
this.logger.debug(
|
|
245
|
+
{
|
|
246
|
+
minAmountsByChain: Object.fromEntries(
|
|
247
|
+
Object.entries(minAmountsByChain).map(([k, v]) => [k, v.toString()]),
|
|
248
|
+
),
|
|
249
|
+
},
|
|
250
|
+
'Built minimum amounts by chain for strategy',
|
|
251
|
+
);
|
|
252
|
+
|
|
180
253
|
return StrategyFactory.createStrategy(
|
|
181
254
|
this.config.strategyConfig,
|
|
182
255
|
this.tokensByChainName,
|
|
183
256
|
await this.getInitialTotalCollateral(),
|
|
184
257
|
this.logger,
|
|
185
258
|
metrics,
|
|
259
|
+
minAmountsByChain,
|
|
186
260
|
);
|
|
187
261
|
}
|
|
188
262
|
|
|
189
|
-
|
|
263
|
+
private createMovableCollateralRebalancer(
|
|
264
|
+
actionTracker: IActionTracker,
|
|
265
|
+
metrics?: Metrics,
|
|
266
|
+
): IRebalancer {
|
|
190
267
|
this.logger.debug(
|
|
191
268
|
{ warpRouteId: this.config.warpRouteId },
|
|
192
269
|
'Creating Rebalancer',
|
|
@@ -197,6 +274,7 @@ export class RebalancerContextFactory {
|
|
|
197
274
|
this.multiProvider.metadata,
|
|
198
275
|
this.tokensByChainName,
|
|
199
276
|
this.multiProvider,
|
|
277
|
+
actionTracker,
|
|
200
278
|
this.logger,
|
|
201
279
|
metrics,
|
|
202
280
|
);
|
|
@@ -272,6 +350,8 @@ export class RebalancerContextFactory {
|
|
|
272
350
|
routersByDomain,
|
|
273
351
|
bridges,
|
|
274
352
|
rebalancerAddress,
|
|
353
|
+
inventorySignerAddress: this.config.inventorySigner,
|
|
354
|
+
intentTTL: this.config.intentTTL,
|
|
275
355
|
};
|
|
276
356
|
|
|
277
357
|
// 6. Create ActionTracker
|
|
@@ -301,6 +381,196 @@ export class RebalancerContextFactory {
|
|
|
301
381
|
return { tracker, adapter };
|
|
302
382
|
}
|
|
303
383
|
|
|
384
|
+
/**
|
|
385
|
+
* Creates inventory components for inventory-based rebalancing.
|
|
386
|
+
* Returns null if inventory config is not available.
|
|
387
|
+
*
|
|
388
|
+
* @param actionTracker - ActionTracker instance for tracking inventory actions
|
|
389
|
+
*/
|
|
390
|
+
private async createInventoryRebalancerAndConfig(
|
|
391
|
+
actionTracker: IActionTracker,
|
|
392
|
+
): Promise<{
|
|
393
|
+
inventoryRebalancer: IRebalancer;
|
|
394
|
+
externalBridgeRegistry: Partial<ExternalBridgeRegistry>;
|
|
395
|
+
inventoryConfig: InventoryMonitorConfig;
|
|
396
|
+
} | null> {
|
|
397
|
+
const { inventorySigner, externalBridges } = this.config;
|
|
398
|
+
|
|
399
|
+
if (!inventorySigner) {
|
|
400
|
+
this.logger.debug(
|
|
401
|
+
'Inventory config not available, skipping inventory components creation',
|
|
402
|
+
);
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
this.logger.debug(
|
|
407
|
+
{ warpRouteId: this.config.warpRouteId, inventorySigner },
|
|
408
|
+
'Creating inventory components',
|
|
409
|
+
);
|
|
410
|
+
|
|
411
|
+
const inventoryChains = getStrategyChainNames(
|
|
412
|
+
this.config.strategyConfig,
|
|
413
|
+
).filter((chainName) => {
|
|
414
|
+
const chainConfig = getStrategyChainConfig(
|
|
415
|
+
this.config.strategyConfig,
|
|
416
|
+
chainName,
|
|
417
|
+
);
|
|
418
|
+
return chainConfig?.executionType === ExecutionType.Inventory;
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
if (inventoryChains.length === 0) {
|
|
422
|
+
this.logger.debug('No inventory chains configured');
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Build registry dynamically from ExternalBridgeType enum
|
|
427
|
+
const externalBridgeRegistry: Partial<ExternalBridgeRegistry> = {};
|
|
428
|
+
|
|
429
|
+
for (const bridgeType of Object.values(ExternalBridgeType)) {
|
|
430
|
+
switch (bridgeType) {
|
|
431
|
+
case ExternalBridgeType.LiFi: {
|
|
432
|
+
const lifiConfig = externalBridges?.lifi;
|
|
433
|
+
if (lifiConfig?.integrator) {
|
|
434
|
+
externalBridgeRegistry[ExternalBridgeType.LiFi] = new LiFiBridge(
|
|
435
|
+
{
|
|
436
|
+
integrator: lifiConfig.integrator,
|
|
437
|
+
defaultSlippage: lifiConfig.defaultSlippage,
|
|
438
|
+
chainMetadata: this.multiProvider.metadata,
|
|
439
|
+
},
|
|
440
|
+
this.logger,
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
break;
|
|
444
|
+
}
|
|
445
|
+
default: {
|
|
446
|
+
// Exhaustive check - TypeScript will error if new enum value added
|
|
447
|
+
const _exhaustive: never = bridgeType;
|
|
448
|
+
throw new Error(`Unknown bridge type: ${_exhaustive}`);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (Object.keys(externalBridgeRegistry).length === 0) {
|
|
454
|
+
this.logger.debug(
|
|
455
|
+
'No external bridges configured, skipping inventory components',
|
|
456
|
+
);
|
|
457
|
+
return null;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// 3. Build inventory config
|
|
461
|
+
const inventoryConfig: InventoryMonitorConfig = {
|
|
462
|
+
inventoryAddress: inventorySigner,
|
|
463
|
+
chains: inventoryChains,
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
// 4. Create InventoryRebalancer
|
|
467
|
+
// Use inventoryMultiProvider for inventory operations if available, otherwise fall back to multiProvider
|
|
468
|
+
const inventoryRebalancer = new InventoryRebalancer(
|
|
469
|
+
{
|
|
470
|
+
inventorySigner,
|
|
471
|
+
inventoryMultiProvider: this.inventoryMultiProvider,
|
|
472
|
+
inventoryChains,
|
|
473
|
+
},
|
|
474
|
+
actionTracker,
|
|
475
|
+
externalBridgeRegistry,
|
|
476
|
+
this.warpCore,
|
|
477
|
+
this.multiProvider,
|
|
478
|
+
this.logger,
|
|
479
|
+
);
|
|
480
|
+
|
|
481
|
+
this.logger.info(
|
|
482
|
+
{
|
|
483
|
+
inventoryChains,
|
|
484
|
+
inventorySigner,
|
|
485
|
+
},
|
|
486
|
+
'Inventory components created successfully',
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
return { inventoryRebalancer, externalBridgeRegistry, inventoryConfig };
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Creates all rebalancers based on config execution types.
|
|
494
|
+
* Returns an array of rebalancers (movableCollateral and/or inventory)
|
|
495
|
+
* along with metadata needed for monitor and orchestrator.
|
|
496
|
+
*/
|
|
497
|
+
public async createRebalancers(
|
|
498
|
+
actionTracker: IActionTracker,
|
|
499
|
+
metrics?: Metrics,
|
|
500
|
+
): Promise<{
|
|
501
|
+
rebalancers: IRebalancer[];
|
|
502
|
+
externalBridgeRegistry: Partial<ExternalBridgeRegistry>;
|
|
503
|
+
inventoryConfig?: InventoryMonitorConfig;
|
|
504
|
+
}> {
|
|
505
|
+
const rebalancers: IRebalancer[] = [];
|
|
506
|
+
let externalBridgeRegistry: Partial<ExternalBridgeRegistry> = {};
|
|
507
|
+
let inventoryConfig: InventoryMonitorConfig | undefined;
|
|
508
|
+
|
|
509
|
+
// Check if any chains use movableCollateral execution type
|
|
510
|
+
const hasMovableCollateral = this.hasMovableCollateralChains();
|
|
511
|
+
if (hasMovableCollateral) {
|
|
512
|
+
const rebalancer = this.createMovableCollateralRebalancer(
|
|
513
|
+
actionTracker,
|
|
514
|
+
metrics,
|
|
515
|
+
);
|
|
516
|
+
rebalancers.push(rebalancer);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Check if any chains use inventory execution type
|
|
520
|
+
const inventoryComponents =
|
|
521
|
+
await this.createInventoryRebalancerAndConfig(actionTracker);
|
|
522
|
+
if (inventoryComponents) {
|
|
523
|
+
rebalancers.push(inventoryComponents.inventoryRebalancer);
|
|
524
|
+
externalBridgeRegistry = inventoryComponents.externalBridgeRegistry;
|
|
525
|
+
inventoryConfig = inventoryComponents.inventoryConfig;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
return { rebalancers, externalBridgeRegistry, inventoryConfig };
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Creates a RebalancerOrchestrator with all required dependencies.
|
|
533
|
+
*/
|
|
534
|
+
public createOrchestrator(options: {
|
|
535
|
+
strategy: IStrategy;
|
|
536
|
+
actionTracker: IActionTracker;
|
|
537
|
+
inflightContextAdapter: InflightContextAdapter;
|
|
538
|
+
rebalancers: IRebalancer[];
|
|
539
|
+
externalBridgeRegistry: Partial<ExternalBridgeRegistry>;
|
|
540
|
+
metrics?: Metrics;
|
|
541
|
+
}): RebalancerOrchestrator {
|
|
542
|
+
this.logger.debug(
|
|
543
|
+
{ warpRouteId: this.config.warpRouteId },
|
|
544
|
+
'Creating RebalancerOrchestrator',
|
|
545
|
+
);
|
|
546
|
+
|
|
547
|
+
return new RebalancerOrchestrator({
|
|
548
|
+
strategy: options.strategy,
|
|
549
|
+
actionTracker: options.actionTracker,
|
|
550
|
+
inflightContextAdapter: options.inflightContextAdapter,
|
|
551
|
+
rebalancerConfig: this.config,
|
|
552
|
+
logger: this.logger,
|
|
553
|
+
rebalancers: options.rebalancers,
|
|
554
|
+
externalBridgeRegistry: options.externalBridgeRegistry,
|
|
555
|
+
metrics: options.metrics,
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
private hasMovableCollateralChains(): boolean {
|
|
560
|
+
return getStrategyChainNames(this.config.strategyConfig).some(
|
|
561
|
+
(chainName) => {
|
|
562
|
+
const chainConfig = getStrategyChainConfig(
|
|
563
|
+
this.config.strategyConfig,
|
|
564
|
+
chainName,
|
|
565
|
+
);
|
|
566
|
+
return (
|
|
567
|
+
chainConfig?.executionType === ExecutionType.MovableCollateral ||
|
|
568
|
+
chainConfig?.executionType === undefined
|
|
569
|
+
); // Default is movableCollateral
|
|
570
|
+
},
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
|
|
304
574
|
private async getInitialTotalCollateral(): Promise<bigint> {
|
|
305
575
|
let initialTotalCollateral = 0n;
|
|
306
576
|
|