@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
|
@@ -3,8 +3,9 @@ import { v4 as uuidv4 } from 'uuid';
|
|
|
3
3
|
|
|
4
4
|
import type { MultiProtocolCore } from '@hyperlane-xyz/sdk';
|
|
5
5
|
import type { Address, Domain } from '@hyperlane-xyz/utils';
|
|
6
|
-
import { parseWarpRouteMessage } from '@hyperlane-xyz/utils';
|
|
6
|
+
import { assert, parseWarpRouteMessage } from '@hyperlane-xyz/utils';
|
|
7
7
|
|
|
8
|
+
import type { ExternalBridgeRegistry } from '../interfaces/IExternalBridge.js';
|
|
8
9
|
import type { ConfirmedBlockTags } from '../interfaces/IMonitor.js';
|
|
9
10
|
import type {
|
|
10
11
|
ExplorerMessage,
|
|
@@ -18,9 +19,11 @@ import type {
|
|
|
18
19
|
IActionTracker,
|
|
19
20
|
} from './IActionTracker.js';
|
|
20
21
|
import type {
|
|
22
|
+
ActionType,
|
|
21
23
|
IRebalanceActionStore,
|
|
22
24
|
IRebalanceIntentStore,
|
|
23
25
|
ITransferStore,
|
|
26
|
+
PartialInventoryIntent,
|
|
24
27
|
RebalanceAction,
|
|
25
28
|
RebalanceIntent,
|
|
26
29
|
Transfer,
|
|
@@ -30,6 +33,8 @@ export interface ActionTrackerConfig {
|
|
|
30
33
|
routersByDomain: Record<number, string>; // Domain ID → router address (source of truth for routers and domains)
|
|
31
34
|
bridges: Address[]; // Bridge contract addresses for rebalance action queries
|
|
32
35
|
rebalancerAddress: Address;
|
|
36
|
+
inventorySignerAddress?: Address; // Optional - for excluding inventory signer from user transfers query
|
|
37
|
+
intentTTL: number; // Max age in ms before in-progress intent is expired
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
/**
|
|
@@ -68,6 +73,7 @@ export class ActionTracker implements IActionTracker {
|
|
|
68
73
|
bridges: this.config.bridges,
|
|
69
74
|
routersByDomain: this.config.routersByDomain,
|
|
70
75
|
rebalancerAddress: this.config.rebalancerAddress,
|
|
76
|
+
inventorySignerAddress: this.config.inventorySignerAddress,
|
|
71
77
|
},
|
|
72
78
|
this.logger,
|
|
73
79
|
);
|
|
@@ -98,10 +104,16 @@ export class ActionTracker implements IActionTracker {
|
|
|
98
104
|
async syncTransfers(confirmedBlockTags?: ConfirmedBlockTags): Promise<void> {
|
|
99
105
|
this.logger.debug('Syncing transfers');
|
|
100
106
|
|
|
107
|
+
// Build list of addresses to exclude (rebalancer + optional inventory signer)
|
|
108
|
+
const excludeTxSenders = [this.config.rebalancerAddress];
|
|
109
|
+
if (this.config.inventorySignerAddress) {
|
|
110
|
+
excludeTxSenders.push(this.config.inventorySignerAddress);
|
|
111
|
+
}
|
|
112
|
+
|
|
101
113
|
const inflightMessages = await this.explorerClient.getInflightUserTransfers(
|
|
102
114
|
{
|
|
103
115
|
routersByDomain: this.config.routersByDomain,
|
|
104
|
-
|
|
116
|
+
excludeTxSenders,
|
|
105
117
|
},
|
|
106
118
|
this.logger,
|
|
107
119
|
);
|
|
@@ -200,15 +212,52 @@ export class ActionTracker implements IActionTracker {
|
|
|
200
212
|
async syncRebalanceIntents(): Promise<void> {
|
|
201
213
|
this.logger.debug('Syncing rebalance intents');
|
|
202
214
|
|
|
203
|
-
// Check in_progress intents for completion
|
|
215
|
+
// Check in_progress intents for completion or TTL expiry
|
|
204
216
|
const inProgressIntents =
|
|
205
217
|
await this.rebalanceIntentStore.getByStatus('in_progress');
|
|
218
|
+
const allInProgressActions =
|
|
219
|
+
await this.rebalanceActionStore.getByStatus('in_progress');
|
|
220
|
+
const now = Date.now();
|
|
206
221
|
for (const intent of inProgressIntents) {
|
|
207
|
-
|
|
222
|
+
const completedAmount = await this.getCompletedAmountForIntent(intent.id);
|
|
223
|
+
if (completedAmount >= intent.amount) {
|
|
208
224
|
await this.rebalanceIntentStore.update(intent.id, {
|
|
209
225
|
status: 'complete',
|
|
210
226
|
});
|
|
211
227
|
this.logger.debug({ id: intent.id }, 'RebalanceIntent completed');
|
|
228
|
+
} else if (now - intent.createdAt > this.config.intentTTL) {
|
|
229
|
+
await this.rebalanceIntentStore.update(intent.id, {
|
|
230
|
+
status: 'failed',
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Fail any in-progress actions associated with the expired intent
|
|
234
|
+
for (const action of allInProgressActions) {
|
|
235
|
+
if (action.intentId === intent.id) {
|
|
236
|
+
await this.rebalanceActionStore.update(action.id, {
|
|
237
|
+
status: 'failed',
|
|
238
|
+
});
|
|
239
|
+
this.logger.warn(
|
|
240
|
+
{ actionId: action.id, intentId: intent.id },
|
|
241
|
+
'RebalanceAction failed due to parent intent TTL expiry',
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
this.logger.debug(
|
|
247
|
+
{
|
|
248
|
+
id: intent.id,
|
|
249
|
+
origin: intent.origin,
|
|
250
|
+
destination: intent.destination,
|
|
251
|
+
amount: intent.amount.toString(),
|
|
252
|
+
ageMs: now - intent.createdAt,
|
|
253
|
+
ttlMs: this.config.intentTTL,
|
|
254
|
+
},
|
|
255
|
+
'RebalanceIntent TTL expiry details',
|
|
256
|
+
);
|
|
257
|
+
this.logger.warn(
|
|
258
|
+
{ id: intent.id },
|
|
259
|
+
'RebalanceIntent expired due to TTL',
|
|
260
|
+
);
|
|
212
261
|
}
|
|
213
262
|
}
|
|
214
263
|
|
|
@@ -229,6 +278,7 @@ export class ActionTracker implements IActionTracker {
|
|
|
229
278
|
bridges: this.config.bridges,
|
|
230
279
|
routersByDomain: this.config.routersByDomain,
|
|
231
280
|
rebalancerAddress: this.config.rebalancerAddress,
|
|
281
|
+
inventorySignerAddress: this.config.inventorySignerAddress,
|
|
232
282
|
},
|
|
233
283
|
this.logger,
|
|
234
284
|
);
|
|
@@ -257,9 +307,17 @@ export class ActionTracker implements IActionTracker {
|
|
|
257
307
|
}
|
|
258
308
|
}
|
|
259
309
|
|
|
310
|
+
// Check delivery status for all in-progress actions in our store
|
|
311
|
+
// Only check delivery for actions that have a messageId (rebalance_message, inventory_deposit)
|
|
312
|
+
// inventory_movement actions are synced separately via LiFi status API
|
|
260
313
|
const inProgressActions =
|
|
261
314
|
await this.rebalanceActionStore.getByStatus('in_progress');
|
|
262
315
|
for (const action of inProgressActions) {
|
|
316
|
+
// Skip actions without messageId (e.g., inventory_movement)
|
|
317
|
+
if (!action.messageId) {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
|
|
263
321
|
const blockTag = await this.getConfirmedBlockTag(
|
|
264
322
|
action.destination,
|
|
265
323
|
confirmedBlockTags,
|
|
@@ -333,17 +391,23 @@ export class ActionTracker implements IActionTracker {
|
|
|
333
391
|
origin: params.origin,
|
|
334
392
|
destination: params.destination,
|
|
335
393
|
amount: params.amount,
|
|
336
|
-
fulfilledAmount: 0n,
|
|
337
394
|
bridge: params.bridge,
|
|
338
395
|
priority: params.priority,
|
|
339
396
|
strategyType: params.strategyType,
|
|
397
|
+
executionMethod: params.executionMethod,
|
|
398
|
+
externalBridge: params.externalBridge,
|
|
340
399
|
createdAt: Date.now(),
|
|
341
400
|
updatedAt: Date.now(),
|
|
342
401
|
};
|
|
343
402
|
|
|
344
403
|
await this.rebalanceIntentStore.save(intent);
|
|
345
404
|
this.logger.debug(
|
|
346
|
-
{
|
|
405
|
+
{
|
|
406
|
+
id: intent.id,
|
|
407
|
+
origin: intent.origin,
|
|
408
|
+
destination: intent.destination,
|
|
409
|
+
executionMethod: intent.executionMethod,
|
|
410
|
+
},
|
|
347
411
|
'Created RebalanceIntent',
|
|
348
412
|
);
|
|
349
413
|
|
|
@@ -383,9 +447,12 @@ export class ActionTracker implements IActionTracker {
|
|
|
383
447
|
const action: RebalanceAction = {
|
|
384
448
|
id: uuidv4(),
|
|
385
449
|
status: 'in_progress',
|
|
450
|
+
type: params.type,
|
|
386
451
|
intentId: params.intentId,
|
|
387
452
|
messageId: params.messageId,
|
|
388
453
|
txHash: params.txHash,
|
|
454
|
+
externalBridgeTransferId: params.externalBridgeTransferId,
|
|
455
|
+
externalBridgeId: params.externalBridgeId,
|
|
389
456
|
origin: params.origin,
|
|
390
457
|
destination: params.destination,
|
|
391
458
|
amount: params.amount,
|
|
@@ -408,7 +475,7 @@ export class ActionTracker implements IActionTracker {
|
|
|
408
475
|
}
|
|
409
476
|
|
|
410
477
|
this.logger.debug(
|
|
411
|
-
{ id: action.id, intentId: action.intentId },
|
|
478
|
+
{ id: action.id, intentId: action.intentId, type: action.type },
|
|
412
479
|
'Created RebalanceAction',
|
|
413
480
|
);
|
|
414
481
|
|
|
@@ -423,32 +490,266 @@ export class ActionTracker implements IActionTracker {
|
|
|
423
490
|
|
|
424
491
|
await this.rebalanceActionStore.update(id, { status: 'complete' });
|
|
425
492
|
|
|
426
|
-
//
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
493
|
+
// Check if parent intent is now complete (derive from action states)
|
|
494
|
+
await this.checkAndCompleteIntent(action.intentId);
|
|
495
|
+
|
|
496
|
+
this.logger.info(
|
|
497
|
+
{ id, intentId: action.intentId, type: action.type },
|
|
498
|
+
'Action completed',
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Check if an intent is fully fulfilled based on completed action amounts.
|
|
504
|
+
* Only `inventory_deposit` and `rebalance_message` actions count toward fulfillment.
|
|
505
|
+
*/
|
|
506
|
+
private async checkAndCompleteIntent(intentId: string): Promise<void> {
|
|
507
|
+
const intent = await this.rebalanceIntentStore.get(intentId);
|
|
508
|
+
if (!intent || intent.status === 'complete') return;
|
|
509
|
+
|
|
510
|
+
const completedAmount = await this.getCompletedAmountForIntent(intentId);
|
|
511
|
+
|
|
512
|
+
if (completedAmount >= intent.amount) {
|
|
513
|
+
await this.rebalanceIntentStore.update(intentId, { status: 'complete' });
|
|
514
|
+
this.logger.debug(
|
|
515
|
+
{ intentId, completedAmount: completedAmount.toString() },
|
|
516
|
+
'RebalanceIntent fully fulfilled',
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* Get the total completed amount for an intent from its actions.
|
|
523
|
+
* Only `inventory_deposit` and `rebalance_message` actions count.
|
|
524
|
+
*/
|
|
525
|
+
private async getCompletedAmountForIntent(intentId: string): Promise<bigint> {
|
|
526
|
+
const actions = await this.getActionsForIntent(intentId);
|
|
527
|
+
return actions
|
|
528
|
+
.filter(
|
|
529
|
+
(a) =>
|
|
530
|
+
a.status === 'complete' &&
|
|
531
|
+
(a.type === 'inventory_deposit' || a.type === 'rebalance_message'),
|
|
532
|
+
)
|
|
533
|
+
.reduce((sum, a) => sum + a.amount, 0n);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
async failRebalanceAction(id: string): Promise<void> {
|
|
537
|
+
await this.rebalanceActionStore.update(id, { status: 'failed' });
|
|
538
|
+
this.logger.info({ id }, 'Action failed');
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// === RebalanceAction Queries ===
|
|
433
542
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
543
|
+
async getActionsByType(type: ActionType): Promise<RebalanceAction[]> {
|
|
544
|
+
const allActions = await this.rebalanceActionStore.getAll();
|
|
545
|
+
return allActions.filter((action) => action.type === type);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
async getInflightInventoryMovements(origin: Domain): Promise<bigint> {
|
|
549
|
+
const allActions = await this.rebalanceActionStore.getAll();
|
|
550
|
+
const inflightMovements = allActions.filter(
|
|
551
|
+
(action) =>
|
|
552
|
+
action.type === 'inventory_movement' &&
|
|
553
|
+
action.status === 'in_progress' &&
|
|
554
|
+
action.origin === origin,
|
|
555
|
+
);
|
|
556
|
+
|
|
557
|
+
return inflightMovements.reduce(
|
|
558
|
+
(sum, action) => sum + action.amount,
|
|
559
|
+
BigInt(0),
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Get inventory intents that are in_progress or not_started but not fully settled.
|
|
565
|
+
* Intents with in-flight deposits are included but flagged via hasInflightDeposit.
|
|
566
|
+
* Returns enriched data with computed values derived from action states.
|
|
567
|
+
*
|
|
568
|
+
* NOTE: We include 'not_started' intents because they may have been created
|
|
569
|
+
* but failed to execute (e.g., all bridges failed viability check). Without
|
|
570
|
+
* checking for these, we would create duplicate intents every polling cycle.
|
|
571
|
+
*/
|
|
572
|
+
async getPartiallyFulfilledInventoryIntents(): Promise<
|
|
573
|
+
PartialInventoryIntent[]
|
|
574
|
+
> {
|
|
575
|
+
// Query both in_progress AND not_started intents
|
|
576
|
+
// not_started intents may exist if execution failed before any action was created
|
|
577
|
+
const [inProgressIntents, notStartedIntents] = await Promise.all([
|
|
578
|
+
this.rebalanceIntentStore.getByStatus('in_progress'),
|
|
579
|
+
this.rebalanceIntentStore.getByStatus('not_started'),
|
|
580
|
+
]);
|
|
581
|
+
|
|
582
|
+
const allActiveIntents = [...inProgressIntents, ...notStartedIntents];
|
|
583
|
+
const partialIntents: PartialInventoryIntent[] = [];
|
|
584
|
+
|
|
585
|
+
for (const intent of allActiveIntents) {
|
|
586
|
+
// Only inventory execution method
|
|
587
|
+
if (intent.executionMethod !== 'inventory') continue;
|
|
588
|
+
|
|
589
|
+
const actions = await this.getActionsForIntent(intent.id);
|
|
590
|
+
|
|
591
|
+
// Check for in-flight inventory_movement actions
|
|
592
|
+
// Skip intents that have a bridge in progress - wait for it to complete
|
|
593
|
+
const hasInflightMovement = actions.some(
|
|
594
|
+
(a) => a.status === 'in_progress' && a.type === 'inventory_movement',
|
|
595
|
+
);
|
|
596
|
+
|
|
597
|
+
if (hasInflightMovement) {
|
|
437
598
|
this.logger.debug(
|
|
438
599
|
{ intentId: intent.id },
|
|
439
|
-
'
|
|
600
|
+
'Skipping partial intent - has in-flight inventory movement',
|
|
440
601
|
);
|
|
602
|
+
continue;
|
|
441
603
|
}
|
|
442
604
|
|
|
443
|
-
|
|
605
|
+
// Compute amounts from action states
|
|
606
|
+
const completedAmount = actions
|
|
607
|
+
.filter(
|
|
608
|
+
(a) => a.status === 'complete' && a.type === 'inventory_deposit',
|
|
609
|
+
)
|
|
610
|
+
.reduce((sum, a) => sum + a.amount, 0n);
|
|
611
|
+
|
|
612
|
+
const inflightAmount = actions
|
|
613
|
+
.filter(
|
|
614
|
+
(a) => a.status === 'in_progress' && a.type === 'inventory_deposit',
|
|
615
|
+
)
|
|
616
|
+
.reduce((sum, a) => sum + a.amount, 0n);
|
|
617
|
+
|
|
618
|
+
const remaining = intent.amount - completedAmount - inflightAmount;
|
|
619
|
+
|
|
620
|
+
if (remaining > 0n || inflightAmount > 0n) {
|
|
621
|
+
partialIntents.push({
|
|
622
|
+
intent,
|
|
623
|
+
completedAmount,
|
|
624
|
+
remaining,
|
|
625
|
+
hasInflightDeposit: inflightAmount > 0n,
|
|
626
|
+
});
|
|
627
|
+
}
|
|
444
628
|
}
|
|
445
629
|
|
|
446
|
-
|
|
630
|
+
return partialIntents;
|
|
447
631
|
}
|
|
448
632
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
633
|
+
/**
|
|
634
|
+
* Get all actions associated with a specific intent.
|
|
635
|
+
*/
|
|
636
|
+
async getActionsForIntent(intentId: string): Promise<RebalanceAction[]> {
|
|
637
|
+
const allActions = await this.rebalanceActionStore.getAll();
|
|
638
|
+
return allActions.filter((a) => a.intentId === intentId);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
async syncInventoryMovementActions(
|
|
642
|
+
externalBridgeRegistry: Partial<ExternalBridgeRegistry>,
|
|
643
|
+
): Promise<{ completed: number; failed: number }> {
|
|
644
|
+
this.logger.debug('Syncing inventory movement actions');
|
|
645
|
+
|
|
646
|
+
let completed = 0;
|
|
647
|
+
let failed = 0;
|
|
648
|
+
|
|
649
|
+
// Get all in-progress inventory_movement actions
|
|
650
|
+
const inProgressActions =
|
|
651
|
+
await this.rebalanceActionStore.getByStatus('in_progress');
|
|
652
|
+
const inventoryMovements = inProgressActions.filter(
|
|
653
|
+
(a) => a.type === 'inventory_movement',
|
|
654
|
+
);
|
|
655
|
+
|
|
656
|
+
this.logger.debug(
|
|
657
|
+
{ count: inventoryMovements.length },
|
|
658
|
+
'Found in-progress inventory movements',
|
|
659
|
+
);
|
|
660
|
+
|
|
661
|
+
for (const action of inventoryMovements) {
|
|
662
|
+
// Skip if no txHash (shouldn't happen but be safe)
|
|
663
|
+
if (!action.txHash) {
|
|
664
|
+
this.logger.warn(
|
|
665
|
+
{ actionId: action.id },
|
|
666
|
+
'Inventory movement action has no txHash',
|
|
667
|
+
);
|
|
668
|
+
continue;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// Skip if no externalBridgeId (shouldn't happen but be safe)
|
|
672
|
+
if (!action.externalBridgeId) {
|
|
673
|
+
this.logger.warn(
|
|
674
|
+
{ actionId: action.id },
|
|
675
|
+
'Inventory movement action has no externalBridgeId',
|
|
676
|
+
);
|
|
677
|
+
continue;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
const externalBridge = externalBridgeRegistry[action.externalBridgeId];
|
|
681
|
+
if (!externalBridge) {
|
|
682
|
+
this.logger.warn(
|
|
683
|
+
{ actionId: action.id, bridgeId: action.externalBridgeId },
|
|
684
|
+
'Bridge not found in registry',
|
|
685
|
+
);
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
try {
|
|
690
|
+
const status = await externalBridge.getStatus(
|
|
691
|
+
action.txHash,
|
|
692
|
+
action.origin,
|
|
693
|
+
action.destination,
|
|
694
|
+
);
|
|
695
|
+
|
|
696
|
+
if (status.status === 'complete') {
|
|
697
|
+
await this.completeRebalanceAction(action.id);
|
|
698
|
+
completed++;
|
|
699
|
+
this.logger.info(
|
|
700
|
+
{
|
|
701
|
+
actionId: action.id,
|
|
702
|
+
txHash: action.txHash,
|
|
703
|
+
receivedAmount: status.receivedAmount?.toString(),
|
|
704
|
+
},
|
|
705
|
+
'Inventory movement completed',
|
|
706
|
+
);
|
|
707
|
+
} else if (status.status === 'failed') {
|
|
708
|
+
await this.failRebalanceAction(action.id);
|
|
709
|
+
failed++;
|
|
710
|
+
this.logger.warn(
|
|
711
|
+
{
|
|
712
|
+
actionId: action.id,
|
|
713
|
+
txHash: action.txHash,
|
|
714
|
+
error: status.error,
|
|
715
|
+
},
|
|
716
|
+
'Inventory movement failed',
|
|
717
|
+
);
|
|
718
|
+
} else if (status.status === 'pending') {
|
|
719
|
+
this.logger.debug(
|
|
720
|
+
{
|
|
721
|
+
actionId: action.id,
|
|
722
|
+
txHash: action.txHash,
|
|
723
|
+
substatus: status.substatus,
|
|
724
|
+
},
|
|
725
|
+
'Inventory movement still pending',
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
// status === 'not_found' - wait for next cycle
|
|
729
|
+
} catch (error) {
|
|
730
|
+
this.logger.debug(
|
|
731
|
+
{
|
|
732
|
+
actionId: action.id,
|
|
733
|
+
txHash: action.txHash,
|
|
734
|
+
error: (error as Error).message,
|
|
735
|
+
},
|
|
736
|
+
'Failed to get inventory movement status',
|
|
737
|
+
);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
if (inventoryMovements.length > 0) {
|
|
742
|
+
this.logger.info(
|
|
743
|
+
{
|
|
744
|
+
completed,
|
|
745
|
+
failed,
|
|
746
|
+
pending: inventoryMovements.length - completed - failed,
|
|
747
|
+
},
|
|
748
|
+
'Inventory movements synced',
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
return { completed, failed };
|
|
452
753
|
}
|
|
453
754
|
|
|
454
755
|
// === Debug Helpers ===
|
|
@@ -603,36 +904,46 @@ export class ActionTracker implements IActionTracker {
|
|
|
603
904
|
try {
|
|
604
905
|
// Create synthetic intent
|
|
605
906
|
const { amount } = parseWarpRouteMessage(msg.message_body);
|
|
907
|
+
// Hasura returns block timestamps as UTC without 'Z' suffix (e.g. "2024-01-15T12:30:45").
|
|
908
|
+
// Null when the scraper hasn't indexed the origin block yet, so fall back to now.
|
|
909
|
+
// Note: when null, TTL effectively extends by scraper lag since recoverAction won't update createdAt later.
|
|
910
|
+
const createdAt = msg.send_occurred_at
|
|
911
|
+
? new Date(msg.send_occurred_at + 'Z').getTime()
|
|
912
|
+
: Date.now();
|
|
913
|
+
assert(
|
|
914
|
+
!isNaN(createdAt),
|
|
915
|
+
`Invalid send_occurred_at timestamp: ${msg.send_occurred_at}`,
|
|
916
|
+
);
|
|
606
917
|
const intent: RebalanceIntent = {
|
|
607
918
|
id: uuidv4(),
|
|
608
919
|
status: 'in_progress',
|
|
609
920
|
origin: msg.origin_domain_id,
|
|
610
921
|
destination: msg.destination_domain_id,
|
|
611
922
|
amount,
|
|
612
|
-
fulfilledAmount: 0n,
|
|
613
923
|
priority: undefined,
|
|
614
924
|
strategyType: undefined,
|
|
615
|
-
createdAt
|
|
925
|
+
createdAt,
|
|
616
926
|
updatedAt: Date.now(),
|
|
617
927
|
};
|
|
618
928
|
|
|
619
929
|
await this.rebalanceIntentStore.save(intent);
|
|
620
930
|
this.logger.debug(
|
|
621
|
-
{ id: intent.id, amount: amount.toString() },
|
|
931
|
+
{ id: intent.id, amount: amount.toString(), createdAt },
|
|
622
932
|
'Created synthetic RebalanceIntent',
|
|
623
933
|
);
|
|
624
934
|
|
|
625
|
-
// Create action
|
|
935
|
+
// Create action (recovered actions are always rebalance_message type)
|
|
626
936
|
const action: RebalanceAction = {
|
|
627
937
|
id: msg.msg_id,
|
|
628
938
|
status: 'in_progress',
|
|
939
|
+
type: 'rebalance_message',
|
|
629
940
|
intentId: intent.id,
|
|
630
941
|
messageId: msg.msg_id,
|
|
631
942
|
txHash: msg.origin_tx_hash,
|
|
632
943
|
origin: msg.origin_domain_id,
|
|
633
944
|
destination: msg.destination_domain_id,
|
|
634
945
|
amount,
|
|
635
|
-
createdAt
|
|
946
|
+
createdAt,
|
|
636
947
|
updatedAt: Date.now(),
|
|
637
948
|
};
|
|
638
949
|
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import type { Address, Domain } from '@hyperlane-xyz/utils';
|
|
2
2
|
|
|
3
|
+
import type { ExternalBridgeType } from '../config/types.js';
|
|
4
|
+
import type { ExternalBridgeRegistry } from '../interfaces/IExternalBridge.js';
|
|
3
5
|
import type { ConfirmedBlockTags } from '../interfaces/IMonitor.js';
|
|
4
6
|
|
|
5
|
-
import type {
|
|
7
|
+
import type {
|
|
8
|
+
ActionType,
|
|
9
|
+
ExecutionMethod,
|
|
10
|
+
PartialInventoryIntent,
|
|
11
|
+
RebalanceAction,
|
|
12
|
+
RebalanceIntent,
|
|
13
|
+
Transfer,
|
|
14
|
+
} from './types.js';
|
|
6
15
|
|
|
7
16
|
export interface CreateRebalanceIntentParams {
|
|
8
17
|
origin: Domain;
|
|
@@ -11,6 +20,8 @@ export interface CreateRebalanceIntentParams {
|
|
|
11
20
|
bridge?: Address;
|
|
12
21
|
priority?: number;
|
|
13
22
|
strategyType?: string;
|
|
23
|
+
executionMethod?: ExecutionMethod;
|
|
24
|
+
externalBridge?: ExternalBridgeType;
|
|
14
25
|
}
|
|
15
26
|
|
|
16
27
|
export interface CreateRebalanceActionParams {
|
|
@@ -18,8 +29,11 @@ export interface CreateRebalanceActionParams {
|
|
|
18
29
|
origin: Domain;
|
|
19
30
|
destination: Domain;
|
|
20
31
|
amount: bigint;
|
|
21
|
-
|
|
32
|
+
type: ActionType; // Required - type of action being created
|
|
33
|
+
messageId?: string; // Optional - not needed for inventory_movement
|
|
22
34
|
txHash?: string;
|
|
35
|
+
externalBridgeTransferId?: string; // Optional - for inventory_movement (external transfer bridge ID)
|
|
36
|
+
externalBridgeId?: ExternalBridgeType; // Optional - for inventory_movement (e.g., 'lifi')
|
|
23
37
|
}
|
|
24
38
|
|
|
25
39
|
/**
|
|
@@ -56,6 +70,18 @@ export interface IActionTracker {
|
|
|
56
70
|
*/
|
|
57
71
|
syncRebalanceActions(confirmedBlockTags?: ConfirmedBlockTags): Promise<void>;
|
|
58
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Sync inventory_movement actions by checking their status via external bridge API.
|
|
75
|
+
* This is separate from syncRebalanceActions because inventory_movement actions
|
|
76
|
+
* don't use Hyperlane messages and need to query the bridge's status API.
|
|
77
|
+
*
|
|
78
|
+
* @param externalBridgeRegistry - Bridge registry to query for status
|
|
79
|
+
* @returns Count of completed and failed actions
|
|
80
|
+
*/
|
|
81
|
+
syncInventoryMovementActions(
|
|
82
|
+
externalBridgeRegistry: Partial<ExternalBridgeRegistry>,
|
|
83
|
+
): Promise<{ completed: number; failed: number }>;
|
|
84
|
+
|
|
59
85
|
// === Transfer Queries ===
|
|
60
86
|
|
|
61
87
|
/**
|
|
@@ -92,6 +118,14 @@ export interface IActionTracker {
|
|
|
92
118
|
destination: Domain,
|
|
93
119
|
): Promise<RebalanceIntent[]>;
|
|
94
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Returns inventory intents that have remaining work.
|
|
123
|
+
* Intents with in-flight deposits are included but marked via hasInflightDeposit —
|
|
124
|
+
* callers must check before continuing.
|
|
125
|
+
* Returns enriched data with computed values derived from action states.
|
|
126
|
+
*/
|
|
127
|
+
getPartiallyFulfilledInventoryIntents(): Promise<PartialInventoryIntent[]>;
|
|
128
|
+
|
|
95
129
|
// === RebalanceIntent Management ===
|
|
96
130
|
|
|
97
131
|
/**
|
|
@@ -121,6 +155,28 @@ export interface IActionTracker {
|
|
|
121
155
|
|
|
122
156
|
// === RebalanceAction Queries ===
|
|
123
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Get actions filtered by type.
|
|
160
|
+
* @param type - Action type to filter by
|
|
161
|
+
*/
|
|
162
|
+
getActionsByType(type: ActionType): Promise<RebalanceAction[]>;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Get all actions associated with a specific intent.
|
|
166
|
+
* @param intentId - ID of the intent
|
|
167
|
+
*/
|
|
168
|
+
getActionsForIntent(intentId: string): Promise<RebalanceAction[]>;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Get total inflight inventory movement amount from a specific chain.
|
|
172
|
+
* Returns the sum of amounts for all in_progress inventory_movement actions
|
|
173
|
+
* that originate from the specified domain.
|
|
174
|
+
*
|
|
175
|
+
* @param origin - Domain ID of the origin chain
|
|
176
|
+
* @returns Total amount being moved out via inventory movements
|
|
177
|
+
*/
|
|
178
|
+
getInflightInventoryMovements(origin: Domain): Promise<bigint>;
|
|
179
|
+
|
|
124
180
|
/**
|
|
125
181
|
* Get a single rebalance action by ID.
|
|
126
182
|
*/
|
|
@@ -139,7 +195,7 @@ export interface IActionTracker {
|
|
|
139
195
|
|
|
140
196
|
/**
|
|
141
197
|
* Mark a rebalance action as complete.
|
|
142
|
-
*
|
|
198
|
+
* Checks if parent intent is now fully fulfilled and marks it complete if so.
|
|
143
199
|
*/
|
|
144
200
|
completeRebalanceAction(id: string): Promise<void>;
|
|
145
201
|
|
|
@@ -16,6 +16,7 @@ describe('InflightContextAdapter', () => {
|
|
|
16
16
|
actionTracker = {
|
|
17
17
|
getActiveRebalanceIntents: Sinon.stub(),
|
|
18
18
|
getInProgressTransfers: Sinon.stub(),
|
|
19
|
+
getActionsForIntent: Sinon.stub(),
|
|
19
20
|
} as any;
|
|
20
21
|
|
|
21
22
|
multiProvider = {
|
|
@@ -40,7 +41,6 @@ describe('InflightContextAdapter', () => {
|
|
|
40
41
|
origin: 1,
|
|
41
42
|
destination: 2,
|
|
42
43
|
amount: 1000n,
|
|
43
|
-
fulfilledAmount: 0n,
|
|
44
44
|
status: 'not_started',
|
|
45
45
|
createdAt: Date.now(),
|
|
46
46
|
updatedAt: Date.now(),
|
|
@@ -64,6 +64,7 @@ describe('InflightContextAdapter', () => {
|
|
|
64
64
|
|
|
65
65
|
actionTracker.getActiveRebalanceIntents.resolves(mockIntents);
|
|
66
66
|
actionTracker.getInProgressTransfers.resolves(mockTransfers);
|
|
67
|
+
actionTracker.getActionsForIntent.resolves([]); // No actions
|
|
67
68
|
multiProvider.getChainName.withArgs(1).returns('ethereum');
|
|
68
69
|
multiProvider.getChainName.withArgs(2).returns('arbitrum');
|
|
69
70
|
|
|
@@ -74,6 +75,9 @@ describe('InflightContextAdapter', () => {
|
|
|
74
75
|
origin: 'ethereum',
|
|
75
76
|
destination: 'arbitrum',
|
|
76
77
|
amount: 1000n,
|
|
78
|
+
deliveredAmount: 0n,
|
|
79
|
+
awaitingDeliveryAmount: 0n,
|
|
80
|
+
executionMethod: undefined,
|
|
77
81
|
bridge: undefined,
|
|
78
82
|
});
|
|
79
83
|
|
|
@@ -102,7 +106,6 @@ describe('InflightContextAdapter', () => {
|
|
|
102
106
|
origin: 137,
|
|
103
107
|
destination: 10,
|
|
104
108
|
amount: 2000n,
|
|
105
|
-
fulfilledAmount: 0n,
|
|
106
109
|
status: 'not_started',
|
|
107
110
|
createdAt: Date.now(),
|
|
108
111
|
updatedAt: Date.now(),
|
|
@@ -126,6 +129,7 @@ describe('InflightContextAdapter', () => {
|
|
|
126
129
|
|
|
127
130
|
actionTracker.getActiveRebalanceIntents.resolves(mockIntents);
|
|
128
131
|
actionTracker.getInProgressTransfers.resolves(mockTransfers);
|
|
132
|
+
actionTracker.getActionsForIntent.resolves([]);
|
|
129
133
|
multiProvider.getChainName.withArgs(137).returns('polygon');
|
|
130
134
|
multiProvider.getChainName.withArgs(10).returns('optimism');
|
|
131
135
|
|
|
@@ -144,7 +148,6 @@ describe('InflightContextAdapter', () => {
|
|
|
144
148
|
origin: 1,
|
|
145
149
|
destination: 2,
|
|
146
150
|
amount: 1000n,
|
|
147
|
-
fulfilledAmount: 0n,
|
|
148
151
|
status: 'not_started',
|
|
149
152
|
createdAt: Date.now(),
|
|
150
153
|
updatedAt: Date.now(),
|
|
@@ -154,7 +157,6 @@ describe('InflightContextAdapter', () => {
|
|
|
154
157
|
origin: 2,
|
|
155
158
|
destination: 3,
|
|
156
159
|
amount: 1500n,
|
|
157
|
-
fulfilledAmount: 0n,
|
|
158
160
|
status: 'in_progress',
|
|
159
161
|
createdAt: Date.now(),
|
|
160
162
|
updatedAt: Date.now(),
|
|
@@ -190,6 +192,7 @@ describe('InflightContextAdapter', () => {
|
|
|
190
192
|
|
|
191
193
|
actionTracker.getActiveRebalanceIntents.resolves(mockIntents);
|
|
192
194
|
actionTracker.getInProgressTransfers.resolves(mockTransfers);
|
|
195
|
+
actionTracker.getActionsForIntent.resolves([]);
|
|
193
196
|
multiProvider.getChainName.withArgs(1).returns('ethereum');
|
|
194
197
|
multiProvider.getChainName.withArgs(2).returns('arbitrum');
|
|
195
198
|
multiProvider.getChainName.withArgs(3).returns('optimism');
|