@hyperlane-xyz/rebalancer 2.0.0 → 3.0.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 +7 -2
- package/dist/config/RebalancerConfig.d.ts.map +1 -1
- package/dist/config/RebalancerConfig.js +7 -4
- package/dist/config/RebalancerConfig.js.map +1 -1
- package/dist/config/RebalancerConfig.test.js +134 -1
- package/dist/config/RebalancerConfig.test.js.map +1 -1
- package/dist/config/types.d.ts +1016 -304
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +105 -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 +885 -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 +1351 -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 +714 -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 +71 -109
- 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/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 +6 -7
- 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 +170 -17
- package/dist/factories/RebalancerContextFactory.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- 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 +33 -1
- package/dist/tracking/ActionTracker.d.ts.map +1 -1
- package/dist/tracking/ActionTracker.js +193 -22
- package/dist/tracking/ActionTracker.js.map +1 -1
- package/dist/tracking/ActionTracker.test.js +107 -19
- package/dist/tracking/ActionTracker.test.js.map +1 -1
- package/dist/tracking/IActionTracker.d.ts +47 -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 +31 -2
- package/dist/tracking/types.d.ts.map +1 -1
- package/dist/utils/ExplorerClient.d.ts +2 -1
- package/dist/utils/ExplorerClient.d.ts.map +1 -1
- package/dist/utils/ExplorerClient.js +13 -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 +160 -0
- package/src/config/RebalancerConfig.ts +14 -3
- package/src/config/types.ts +136 -10
- package/src/core/InventoryRebalancer.test.ts +1684 -0
- package/src/core/InventoryRebalancer.ts +1255 -0
- package/src/core/Rebalancer.test.ts +84 -30
- package/src/core/Rebalancer.ts +144 -23
- package/src/core/RebalancerOrchestrator.test.ts +860 -0
- package/src/core/RebalancerOrchestrator.ts +146 -95
- package/src/core/RebalancerService.test.ts +80 -123
- 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/TestHelpers.ts +1 -4
- package/src/e2e/harness/TestRebalancer.ts +7 -7
- package/src/e2e/minAmount.e2e-test.ts +1 -2
- package/src/e2e/weighted.e2e-test.ts +1 -2
- package/src/factories/RebalancerContextFactory.ts +293 -24
- package/src/index.ts +20 -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 +122 -19
- package/src/tracking/ActionTracker.ts +284 -24
- package/src/tracking/IActionTracker.ts +58 -3
- package/src/tracking/InflightContextAdapter.test.ts +7 -4
- package/src/tracking/InflightContextAdapter.ts +42 -9
- package/src/tracking/types.ts +43 -2
- package/src/utils/ExplorerClient.ts +23 -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
|
@@ -5,6 +5,7 @@ import type { MultiProtocolCore } from '@hyperlane-xyz/sdk';
|
|
|
5
5
|
import type { Address, Domain } from '@hyperlane-xyz/utils';
|
|
6
6
|
import { 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,7 @@ 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
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
/**
|
|
@@ -68,6 +72,7 @@ export class ActionTracker implements IActionTracker {
|
|
|
68
72
|
bridges: this.config.bridges,
|
|
69
73
|
routersByDomain: this.config.routersByDomain,
|
|
70
74
|
rebalancerAddress: this.config.rebalancerAddress,
|
|
75
|
+
inventorySignerAddress: this.config.inventorySignerAddress,
|
|
71
76
|
},
|
|
72
77
|
this.logger,
|
|
73
78
|
);
|
|
@@ -98,10 +103,16 @@ export class ActionTracker implements IActionTracker {
|
|
|
98
103
|
async syncTransfers(confirmedBlockTags?: ConfirmedBlockTags): Promise<void> {
|
|
99
104
|
this.logger.debug('Syncing transfers');
|
|
100
105
|
|
|
106
|
+
// Build list of addresses to exclude (rebalancer + optional inventory signer)
|
|
107
|
+
const excludeTxSenders = [this.config.rebalancerAddress];
|
|
108
|
+
if (this.config.inventorySignerAddress) {
|
|
109
|
+
excludeTxSenders.push(this.config.inventorySignerAddress);
|
|
110
|
+
}
|
|
111
|
+
|
|
101
112
|
const inflightMessages = await this.explorerClient.getInflightUserTransfers(
|
|
102
113
|
{
|
|
103
114
|
routersByDomain: this.config.routersByDomain,
|
|
104
|
-
|
|
115
|
+
excludeTxSenders,
|
|
105
116
|
},
|
|
106
117
|
this.logger,
|
|
107
118
|
);
|
|
@@ -200,11 +211,12 @@ export class ActionTracker implements IActionTracker {
|
|
|
200
211
|
async syncRebalanceIntents(): Promise<void> {
|
|
201
212
|
this.logger.debug('Syncing rebalance intents');
|
|
202
213
|
|
|
203
|
-
// Check in_progress intents for completion
|
|
214
|
+
// Check in_progress intents for completion by deriving from action states
|
|
204
215
|
const inProgressIntents =
|
|
205
216
|
await this.rebalanceIntentStore.getByStatus('in_progress');
|
|
206
217
|
for (const intent of inProgressIntents) {
|
|
207
|
-
|
|
218
|
+
const completedAmount = await this.getCompletedAmountForIntent(intent.id);
|
|
219
|
+
if (completedAmount >= intent.amount) {
|
|
208
220
|
await this.rebalanceIntentStore.update(intent.id, {
|
|
209
221
|
status: 'complete',
|
|
210
222
|
});
|
|
@@ -229,6 +241,7 @@ export class ActionTracker implements IActionTracker {
|
|
|
229
241
|
bridges: this.config.bridges,
|
|
230
242
|
routersByDomain: this.config.routersByDomain,
|
|
231
243
|
rebalancerAddress: this.config.rebalancerAddress,
|
|
244
|
+
inventorySignerAddress: this.config.inventorySignerAddress,
|
|
232
245
|
},
|
|
233
246
|
this.logger,
|
|
234
247
|
);
|
|
@@ -257,9 +270,17 @@ export class ActionTracker implements IActionTracker {
|
|
|
257
270
|
}
|
|
258
271
|
}
|
|
259
272
|
|
|
273
|
+
// Check delivery status for all in-progress actions in our store
|
|
274
|
+
// Only check delivery for actions that have a messageId (rebalance_message, inventory_deposit)
|
|
275
|
+
// inventory_movement actions are synced separately via LiFi status API
|
|
260
276
|
const inProgressActions =
|
|
261
277
|
await this.rebalanceActionStore.getByStatus('in_progress');
|
|
262
278
|
for (const action of inProgressActions) {
|
|
279
|
+
// Skip actions without messageId (e.g., inventory_movement)
|
|
280
|
+
if (!action.messageId) {
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
|
|
263
284
|
const blockTag = await this.getConfirmedBlockTag(
|
|
264
285
|
action.destination,
|
|
265
286
|
confirmedBlockTags,
|
|
@@ -333,17 +354,23 @@ export class ActionTracker implements IActionTracker {
|
|
|
333
354
|
origin: params.origin,
|
|
334
355
|
destination: params.destination,
|
|
335
356
|
amount: params.amount,
|
|
336
|
-
fulfilledAmount: 0n,
|
|
337
357
|
bridge: params.bridge,
|
|
338
358
|
priority: params.priority,
|
|
339
359
|
strategyType: params.strategyType,
|
|
360
|
+
executionMethod: params.executionMethod,
|
|
361
|
+
externalBridge: params.externalBridge,
|
|
340
362
|
createdAt: Date.now(),
|
|
341
363
|
updatedAt: Date.now(),
|
|
342
364
|
};
|
|
343
365
|
|
|
344
366
|
await this.rebalanceIntentStore.save(intent);
|
|
345
367
|
this.logger.debug(
|
|
346
|
-
{
|
|
368
|
+
{
|
|
369
|
+
id: intent.id,
|
|
370
|
+
origin: intent.origin,
|
|
371
|
+
destination: intent.destination,
|
|
372
|
+
executionMethod: intent.executionMethod,
|
|
373
|
+
},
|
|
347
374
|
'Created RebalanceIntent',
|
|
348
375
|
);
|
|
349
376
|
|
|
@@ -383,9 +410,12 @@ export class ActionTracker implements IActionTracker {
|
|
|
383
410
|
const action: RebalanceAction = {
|
|
384
411
|
id: uuidv4(),
|
|
385
412
|
status: 'in_progress',
|
|
413
|
+
type: params.type,
|
|
386
414
|
intentId: params.intentId,
|
|
387
415
|
messageId: params.messageId,
|
|
388
416
|
txHash: params.txHash,
|
|
417
|
+
externalBridgeTransferId: params.externalBridgeTransferId,
|
|
418
|
+
externalBridgeId: params.externalBridgeId,
|
|
389
419
|
origin: params.origin,
|
|
390
420
|
destination: params.destination,
|
|
391
421
|
amount: params.amount,
|
|
@@ -408,7 +438,7 @@ export class ActionTracker implements IActionTracker {
|
|
|
408
438
|
}
|
|
409
439
|
|
|
410
440
|
this.logger.debug(
|
|
411
|
-
{ id: action.id, intentId: action.intentId },
|
|
441
|
+
{ id: action.id, intentId: action.intentId, type: action.type },
|
|
412
442
|
'Created RebalanceAction',
|
|
413
443
|
);
|
|
414
444
|
|
|
@@ -423,32 +453,262 @@ export class ActionTracker implements IActionTracker {
|
|
|
423
453
|
|
|
424
454
|
await this.rebalanceActionStore.update(id, { status: 'complete' });
|
|
425
455
|
|
|
426
|
-
//
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
456
|
+
// Check if parent intent is now complete (derive from action states)
|
|
457
|
+
await this.checkAndCompleteIntent(action.intentId);
|
|
458
|
+
|
|
459
|
+
this.logger.info(
|
|
460
|
+
{ id, intentId: action.intentId, type: action.type },
|
|
461
|
+
'Action completed',
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Check if an intent is fully fulfilled based on completed action amounts.
|
|
467
|
+
* Only `inventory_deposit` and `rebalance_message` actions count toward fulfillment.
|
|
468
|
+
*/
|
|
469
|
+
private async checkAndCompleteIntent(intentId: string): Promise<void> {
|
|
470
|
+
const intent = await this.rebalanceIntentStore.get(intentId);
|
|
471
|
+
if (!intent || intent.status === 'complete') return;
|
|
472
|
+
|
|
473
|
+
const completedAmount = await this.getCompletedAmountForIntent(intentId);
|
|
474
|
+
|
|
475
|
+
if (completedAmount >= intent.amount) {
|
|
476
|
+
await this.rebalanceIntentStore.update(intentId, { status: 'complete' });
|
|
477
|
+
this.logger.debug(
|
|
478
|
+
{ intentId, completedAmount: completedAmount.toString() },
|
|
479
|
+
'RebalanceIntent fully fulfilled',
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
433
483
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
484
|
+
/**
|
|
485
|
+
* Get the total completed amount for an intent from its actions.
|
|
486
|
+
* Only `inventory_deposit` and `rebalance_message` actions count.
|
|
487
|
+
*/
|
|
488
|
+
private async getCompletedAmountForIntent(intentId: string): Promise<bigint> {
|
|
489
|
+
const actions = await this.getActionsForIntent(intentId);
|
|
490
|
+
return actions
|
|
491
|
+
.filter(
|
|
492
|
+
(a) =>
|
|
493
|
+
a.status === 'complete' &&
|
|
494
|
+
(a.type === 'inventory_deposit' || a.type === 'rebalance_message'),
|
|
495
|
+
)
|
|
496
|
+
.reduce((sum, a) => sum + a.amount, 0n);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
async failRebalanceAction(id: string): Promise<void> {
|
|
500
|
+
await this.rebalanceActionStore.update(id, { status: 'failed' });
|
|
501
|
+
this.logger.info({ id }, 'Action failed');
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// === RebalanceAction Queries ===
|
|
505
|
+
|
|
506
|
+
async getActionsByType(type: ActionType): Promise<RebalanceAction[]> {
|
|
507
|
+
const allActions = await this.rebalanceActionStore.getAll();
|
|
508
|
+
return allActions.filter((action) => action.type === type);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
async getInflightInventoryMovements(origin: Domain): Promise<bigint> {
|
|
512
|
+
const allActions = await this.rebalanceActionStore.getAll();
|
|
513
|
+
const inflightMovements = allActions.filter(
|
|
514
|
+
(action) =>
|
|
515
|
+
action.type === 'inventory_movement' &&
|
|
516
|
+
action.status === 'in_progress' &&
|
|
517
|
+
action.origin === origin,
|
|
518
|
+
);
|
|
519
|
+
|
|
520
|
+
return inflightMovements.reduce(
|
|
521
|
+
(sum, action) => sum + action.amount,
|
|
522
|
+
BigInt(0),
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Get inventory intents that are in_progress or not_started but not fully fulfilled,
|
|
528
|
+
* and have no in-flight actions (safe to continue).
|
|
529
|
+
* Returns enriched data with computed values derived from action states.
|
|
530
|
+
*
|
|
531
|
+
* NOTE: We include 'not_started' intents because they may have been created
|
|
532
|
+
* but failed to execute (e.g., all bridges failed viability check). Without
|
|
533
|
+
* checking for these, we would create duplicate intents every polling cycle.
|
|
534
|
+
*/
|
|
535
|
+
async getPartiallyFulfilledInventoryIntents(): Promise<
|
|
536
|
+
PartialInventoryIntent[]
|
|
537
|
+
> {
|
|
538
|
+
// Query both in_progress AND not_started intents
|
|
539
|
+
// not_started intents may exist if execution failed before any action was created
|
|
540
|
+
const [inProgressIntents, notStartedIntents] = await Promise.all([
|
|
541
|
+
this.rebalanceIntentStore.getByStatus('in_progress'),
|
|
542
|
+
this.rebalanceIntentStore.getByStatus('not_started'),
|
|
543
|
+
]);
|
|
544
|
+
|
|
545
|
+
const allActiveIntents = [...inProgressIntents, ...notStartedIntents];
|
|
546
|
+
const partialIntents: PartialInventoryIntent[] = [];
|
|
547
|
+
|
|
548
|
+
for (const intent of allActiveIntents) {
|
|
549
|
+
// Only inventory execution method
|
|
550
|
+
if (intent.executionMethod !== 'inventory') continue;
|
|
551
|
+
|
|
552
|
+
const actions = await this.getActionsForIntent(intent.id);
|
|
553
|
+
|
|
554
|
+
// Check for in-flight inventory_movement actions
|
|
555
|
+
// Skip intents that have a bridge in progress - wait for it to complete
|
|
556
|
+
const hasInflightMovement = actions.some(
|
|
557
|
+
(a) => a.status === 'in_progress' && a.type === 'inventory_movement',
|
|
558
|
+
);
|
|
559
|
+
|
|
560
|
+
if (hasInflightMovement) {
|
|
437
561
|
this.logger.debug(
|
|
438
562
|
{ intentId: intent.id },
|
|
439
|
-
'
|
|
563
|
+
'Skipping partial intent - has in-flight inventory movement',
|
|
440
564
|
);
|
|
565
|
+
continue;
|
|
441
566
|
}
|
|
442
567
|
|
|
443
|
-
|
|
568
|
+
// Compute amounts from action states
|
|
569
|
+
const completedAmount = actions
|
|
570
|
+
.filter(
|
|
571
|
+
(a) => a.status === 'complete' && a.type === 'inventory_deposit',
|
|
572
|
+
)
|
|
573
|
+
.reduce((sum, a) => sum + a.amount, 0n);
|
|
574
|
+
|
|
575
|
+
const inflightAmount = actions
|
|
576
|
+
.filter(
|
|
577
|
+
(a) => a.status === 'in_progress' && a.type === 'inventory_deposit',
|
|
578
|
+
)
|
|
579
|
+
.reduce((sum, a) => sum + a.amount, 0n);
|
|
580
|
+
|
|
581
|
+
const remaining = intent.amount - completedAmount - inflightAmount;
|
|
582
|
+
|
|
583
|
+
// Safe to continue if: remaining > 0 AND no in-flight inventory_deposit
|
|
584
|
+
if (remaining > 0n && inflightAmount === 0n) {
|
|
585
|
+
partialIntents.push({ intent, completedAmount, remaining });
|
|
586
|
+
}
|
|
444
587
|
}
|
|
445
588
|
|
|
446
|
-
|
|
589
|
+
return partialIntents;
|
|
447
590
|
}
|
|
448
591
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
592
|
+
/**
|
|
593
|
+
* Get all actions associated with a specific intent.
|
|
594
|
+
*/
|
|
595
|
+
async getActionsForIntent(intentId: string): Promise<RebalanceAction[]> {
|
|
596
|
+
const allActions = await this.rebalanceActionStore.getAll();
|
|
597
|
+
return allActions.filter((a) => a.intentId === intentId);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
async syncInventoryMovementActions(
|
|
601
|
+
externalBridgeRegistry: Partial<ExternalBridgeRegistry>,
|
|
602
|
+
): Promise<{ completed: number; failed: number }> {
|
|
603
|
+
this.logger.debug('Syncing inventory movement actions');
|
|
604
|
+
|
|
605
|
+
let completed = 0;
|
|
606
|
+
let failed = 0;
|
|
607
|
+
|
|
608
|
+
// Get all in-progress inventory_movement actions
|
|
609
|
+
const inProgressActions =
|
|
610
|
+
await this.rebalanceActionStore.getByStatus('in_progress');
|
|
611
|
+
const inventoryMovements = inProgressActions.filter(
|
|
612
|
+
(a) => a.type === 'inventory_movement',
|
|
613
|
+
);
|
|
614
|
+
|
|
615
|
+
this.logger.debug(
|
|
616
|
+
{ count: inventoryMovements.length },
|
|
617
|
+
'Found in-progress inventory movements',
|
|
618
|
+
);
|
|
619
|
+
|
|
620
|
+
for (const action of inventoryMovements) {
|
|
621
|
+
// Skip if no txHash (shouldn't happen but be safe)
|
|
622
|
+
if (!action.txHash) {
|
|
623
|
+
this.logger.warn(
|
|
624
|
+
{ actionId: action.id },
|
|
625
|
+
'Inventory movement action has no txHash',
|
|
626
|
+
);
|
|
627
|
+
continue;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// Skip if no externalBridgeId (shouldn't happen but be safe)
|
|
631
|
+
if (!action.externalBridgeId) {
|
|
632
|
+
this.logger.warn(
|
|
633
|
+
{ actionId: action.id },
|
|
634
|
+
'Inventory movement action has no externalBridgeId',
|
|
635
|
+
);
|
|
636
|
+
continue;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
const externalBridge = externalBridgeRegistry[action.externalBridgeId];
|
|
640
|
+
if (!externalBridge) {
|
|
641
|
+
this.logger.warn(
|
|
642
|
+
{ actionId: action.id, bridgeId: action.externalBridgeId },
|
|
643
|
+
'Bridge not found in registry',
|
|
644
|
+
);
|
|
645
|
+
continue;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
try {
|
|
649
|
+
const status = await externalBridge.getStatus(
|
|
650
|
+
action.txHash,
|
|
651
|
+
action.origin,
|
|
652
|
+
action.destination,
|
|
653
|
+
);
|
|
654
|
+
|
|
655
|
+
if (status.status === 'complete') {
|
|
656
|
+
await this.completeRebalanceAction(action.id);
|
|
657
|
+
completed++;
|
|
658
|
+
this.logger.info(
|
|
659
|
+
{
|
|
660
|
+
actionId: action.id,
|
|
661
|
+
txHash: action.txHash,
|
|
662
|
+
receivedAmount: status.receivedAmount?.toString(),
|
|
663
|
+
},
|
|
664
|
+
'Inventory movement completed',
|
|
665
|
+
);
|
|
666
|
+
} else if (status.status === 'failed') {
|
|
667
|
+
await this.failRebalanceAction(action.id);
|
|
668
|
+
failed++;
|
|
669
|
+
this.logger.warn(
|
|
670
|
+
{
|
|
671
|
+
actionId: action.id,
|
|
672
|
+
txHash: action.txHash,
|
|
673
|
+
error: status.error,
|
|
674
|
+
},
|
|
675
|
+
'Inventory movement failed',
|
|
676
|
+
);
|
|
677
|
+
} else if (status.status === 'pending') {
|
|
678
|
+
this.logger.debug(
|
|
679
|
+
{
|
|
680
|
+
actionId: action.id,
|
|
681
|
+
txHash: action.txHash,
|
|
682
|
+
substatus: status.substatus,
|
|
683
|
+
},
|
|
684
|
+
'Inventory movement still pending',
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
// status === 'not_found' - wait for next cycle
|
|
688
|
+
} catch (error) {
|
|
689
|
+
this.logger.debug(
|
|
690
|
+
{
|
|
691
|
+
actionId: action.id,
|
|
692
|
+
txHash: action.txHash,
|
|
693
|
+
error: (error as Error).message,
|
|
694
|
+
},
|
|
695
|
+
'Failed to get inventory movement status',
|
|
696
|
+
);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
if (inventoryMovements.length > 0) {
|
|
701
|
+
this.logger.info(
|
|
702
|
+
{
|
|
703
|
+
completed,
|
|
704
|
+
failed,
|
|
705
|
+
pending: inventoryMovements.length - completed - failed,
|
|
706
|
+
},
|
|
707
|
+
'Inventory movements synced',
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
return { completed, failed };
|
|
452
712
|
}
|
|
453
713
|
|
|
454
714
|
// === Debug Helpers ===
|
|
@@ -609,7 +869,6 @@ export class ActionTracker implements IActionTracker {
|
|
|
609
869
|
origin: msg.origin_domain_id,
|
|
610
870
|
destination: msg.destination_domain_id,
|
|
611
871
|
amount,
|
|
612
|
-
fulfilledAmount: 0n,
|
|
613
872
|
priority: undefined,
|
|
614
873
|
strategyType: undefined,
|
|
615
874
|
createdAt: Date.now(),
|
|
@@ -622,10 +881,11 @@ export class ActionTracker implements IActionTracker {
|
|
|
622
881
|
'Created synthetic RebalanceIntent',
|
|
623
882
|
);
|
|
624
883
|
|
|
625
|
-
// Create action
|
|
884
|
+
// Create action (recovered actions are always rebalance_message type)
|
|
626
885
|
const action: RebalanceAction = {
|
|
627
886
|
id: msg.msg_id,
|
|
628
887
|
status: 'in_progress',
|
|
888
|
+
type: 'rebalance_message',
|
|
629
889
|
intentId: intent.id,
|
|
630
890
|
messageId: msg.msg_id,
|
|
631
891
|
txHash: msg.origin_tx_hash,
|
|
@@ -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,13 @@ export interface IActionTracker {
|
|
|
92
118
|
destination: Domain,
|
|
93
119
|
): Promise<RebalanceIntent[]>;
|
|
94
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Get inventory intents that are in_progress but not fully fulfilled,
|
|
123
|
+
* and have no in-flight actions (safe to continue).
|
|
124
|
+
* Returns enriched data with computed values derived from action states.
|
|
125
|
+
*/
|
|
126
|
+
getPartiallyFulfilledInventoryIntents(): Promise<PartialInventoryIntent[]>;
|
|
127
|
+
|
|
95
128
|
// === RebalanceIntent Management ===
|
|
96
129
|
|
|
97
130
|
/**
|
|
@@ -121,6 +154,28 @@ export interface IActionTracker {
|
|
|
121
154
|
|
|
122
155
|
// === RebalanceAction Queries ===
|
|
123
156
|
|
|
157
|
+
/**
|
|
158
|
+
* Get actions filtered by type.
|
|
159
|
+
* @param type - Action type to filter by
|
|
160
|
+
*/
|
|
161
|
+
getActionsByType(type: ActionType): Promise<RebalanceAction[]>;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Get all actions associated with a specific intent.
|
|
165
|
+
* @param intentId - ID of the intent
|
|
166
|
+
*/
|
|
167
|
+
getActionsForIntent(intentId: string): Promise<RebalanceAction[]>;
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Get total inflight inventory movement amount from a specific chain.
|
|
171
|
+
* Returns the sum of amounts for all in_progress inventory_movement actions
|
|
172
|
+
* that originate from the specified domain.
|
|
173
|
+
*
|
|
174
|
+
* @param origin - Domain ID of the origin chain
|
|
175
|
+
* @returns Total amount being moved out via inventory movements
|
|
176
|
+
*/
|
|
177
|
+
getInflightInventoryMovements(origin: Domain): Promise<bigint>;
|
|
178
|
+
|
|
124
179
|
/**
|
|
125
180
|
* Get a single rebalance action by ID.
|
|
126
181
|
*/
|
|
@@ -139,7 +194,7 @@ export interface IActionTracker {
|
|
|
139
194
|
|
|
140
195
|
/**
|
|
141
196
|
* Mark a rebalance action as complete.
|
|
142
|
-
*
|
|
197
|
+
* Checks if parent intent is now fully fulfilled and marks it complete if so.
|
|
143
198
|
*/
|
|
144
199
|
completeRebalanceAction(id: string): Promise<void>;
|
|
145
200
|
|
|
@@ -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');
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { MultiProvider } from '@hyperlane-xyz/sdk';
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
InflightContext,
|
|
5
|
+
RouteWithContext,
|
|
6
|
+
} from '../interfaces/IStrategy.js';
|
|
4
7
|
|
|
5
8
|
import type { IActionTracker } from './IActionTracker.js';
|
|
6
9
|
|
|
@@ -22,14 +25,44 @@ export class InflightContextAdapter {
|
|
|
22
25
|
const intents = await this.actionTracker.getActiveRebalanceIntents();
|
|
23
26
|
const transfers = await this.actionTracker.getInProgressTransfers();
|
|
24
27
|
|
|
25
|
-
const pendingRebalances =
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
const pendingRebalances: RouteWithContext[] = await Promise.all(
|
|
29
|
+
intents.map(async (intent) => {
|
|
30
|
+
let deliveredAmount = 0n;
|
|
31
|
+
let awaitingDeliveryAmount = 0n;
|
|
32
|
+
|
|
33
|
+
// For inventory intents, compute delivered and awaiting amounts from actions
|
|
34
|
+
if (intent.executionMethod === 'inventory') {
|
|
35
|
+
const actions = await this.actionTracker.getActionsForIntent(
|
|
36
|
+
intent.id,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
// Sum of complete inventory_deposit actions (message delivered)
|
|
40
|
+
deliveredAmount = actions
|
|
41
|
+
.filter(
|
|
42
|
+
(a) => a.type === 'inventory_deposit' && a.status === 'complete',
|
|
43
|
+
)
|
|
44
|
+
.reduce((sum, a) => sum + a.amount, 0n);
|
|
45
|
+
|
|
46
|
+
// Sum of in_progress inventory_deposit actions (tx confirmed, message pending)
|
|
47
|
+
awaitingDeliveryAmount = actions
|
|
48
|
+
.filter(
|
|
49
|
+
(a) =>
|
|
50
|
+
a.type === 'inventory_deposit' && a.status === 'in_progress',
|
|
51
|
+
)
|
|
52
|
+
.reduce((sum, a) => sum + a.amount, 0n);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
origin: this.multiProvider.getChainName(intent.origin),
|
|
57
|
+
destination: this.multiProvider.getChainName(intent.destination),
|
|
58
|
+
amount: intent.amount,
|
|
59
|
+
deliveredAmount,
|
|
60
|
+
awaitingDeliveryAmount,
|
|
61
|
+
executionMethod: intent.executionMethod,
|
|
62
|
+
bridge: intent.bridge,
|
|
63
|
+
};
|
|
64
|
+
}),
|
|
65
|
+
);
|
|
33
66
|
|
|
34
67
|
const pendingTransfers = transfers.map((transfer) => ({
|
|
35
68
|
origin: this.multiProvider.getChainName(transfer.origin),
|