@humanode-hyperlane/rebalancer 27.2.2-humanode.1 → 1029.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 +3 -3
- package/dist/bridges/LiFiBridge.d.ts.map +1 -1
- package/dist/bridges/LiFiBridge.js +66 -55
- package/dist/bridges/LiFiBridge.js.map +1 -1
- package/dist/bridges/LiFiBridge.test.js +213 -0
- package/dist/bridges/LiFiBridge.test.js.map +1 -1
- package/dist/config/RebalancerConfig.d.ts +4 -3
- package/dist/config/RebalancerConfig.d.ts.map +1 -1
- package/dist/config/RebalancerConfig.js +7 -5
- package/dist/config/RebalancerConfig.js.map +1 -1
- package/dist/config/RebalancerConfig.test.js +278 -2
- package/dist/config/RebalancerConfig.test.js.map +1 -1
- package/dist/config/types.d.ts +707 -2664
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +62 -7
- package/dist/config/types.js.map +1 -1
- package/dist/core/InventoryRebalancer.d.ts +13 -19
- package/dist/core/InventoryRebalancer.d.ts.map +1 -1
- package/dist/core/InventoryRebalancer.js +404 -276
- package/dist/core/InventoryRebalancer.js.map +1 -1
- package/dist/core/InventoryRebalancer.test.js +814 -25
- package/dist/core/InventoryRebalancer.test.js.map +1 -1
- package/dist/core/Rebalancer.d.ts.map +1 -1
- package/dist/core/Rebalancer.js +12 -6
- package/dist/core/Rebalancer.js.map +1 -1
- package/dist/core/Rebalancer.test.js +51 -0
- package/dist/core/Rebalancer.test.js.map +1 -1
- package/dist/core/RebalancerOrchestrator.d.ts.map +1 -1
- package/dist/core/RebalancerOrchestrator.test.js +0 -1
- package/dist/core/RebalancerOrchestrator.test.js.map +1 -1
- package/dist/core/RebalancerService.d.ts.map +1 -1
- package/dist/core/RebalancerService.js +3 -2
- package/dist/core/RebalancerService.js.map +1 -1
- package/dist/core/RebalancerService.test.js +24 -0
- package/dist/core/RebalancerService.test.js.map +1 -1
- package/dist/e2e/fixtures/routes.d.ts +3 -3
- package/dist/e2e/fixtures/routes.d.ts.map +1 -1
- package/dist/e2e/harness/BaseLocalDeploymentManager.d.ts.map +1 -1
- package/dist/e2e/harness/BaseLocalDeploymentManager.js +3 -2
- package/dist/e2e/harness/BaseLocalDeploymentManager.js.map +1 -1
- package/dist/e2e/harness/Erc20InventoryLocalDeploymentManager.d.ts.map +1 -1
- package/dist/e2e/harness/Erc20InventoryLocalDeploymentManager.js.map +1 -1
- package/dist/e2e/harness/Erc20LocalDeploymentManager.d.ts.map +1 -1
- package/dist/e2e/harness/ForkIndexer.d.ts.map +1 -1
- package/dist/e2e/harness/ForkIndexer.js.map +1 -1
- package/dist/e2e/harness/LocalProvider.d.ts +3 -0
- package/dist/e2e/harness/LocalProvider.d.ts.map +1 -0
- package/dist/e2e/harness/LocalProvider.js +9 -0
- package/dist/e2e/harness/LocalProvider.js.map +1 -0
- package/dist/e2e/harness/LocalProvider.test.d.ts +2 -0
- package/dist/e2e/harness/LocalProvider.test.d.ts.map +1 -0
- package/dist/e2e/harness/LocalProvider.test.js +14 -0
- package/dist/e2e/harness/LocalProvider.test.js.map +1 -0
- package/dist/e2e/harness/MixedLocalDeploymentManager.d.ts.map +1 -1
- package/dist/e2e/harness/MixedLocalDeploymentManager.js.map +1 -1
- package/dist/e2e/harness/MockExplorerClient.d.ts.map +1 -1
- package/dist/e2e/harness/MockExplorerClient.js.map +1 -1
- package/dist/e2e/harness/MockExternalBridge.d.ts.map +1 -1
- package/dist/e2e/harness/MockExternalBridge.js.map +1 -1
- package/dist/e2e/harness/NativeLocalDeploymentManager.d.ts.map +1 -1
- package/dist/e2e/harness/NativeLocalDeploymentManager.js +2 -1
- package/dist/e2e/harness/NativeLocalDeploymentManager.js.map +1 -1
- package/dist/e2e/harness/SnapshotHelper.d.ts.map +1 -1
- package/dist/e2e/harness/SnapshotHelper.js +3 -5
- package/dist/e2e/harness/SnapshotHelper.js.map +1 -1
- package/dist/e2e/harness/TestHelpers.js +1 -2
- package/dist/e2e/harness/TestHelpers.js.map +1 -1
- package/dist/e2e/harness/TestRebalancer.d.ts +5 -1
- package/dist/e2e/harness/TestRebalancer.d.ts.map +1 -1
- package/dist/e2e/harness/TestRebalancer.js +14 -4
- package/dist/e2e/harness/TestRebalancer.js.map +1 -1
- package/dist/e2e/relayer-denylist.e2e-test.d.ts +2 -0
- package/dist/e2e/relayer-denylist.e2e-test.d.ts.map +1 -0
- package/dist/e2e/relayer-denylist.e2e-test.js +388 -0
- package/dist/e2e/relayer-denylist.e2e-test.js.map +1 -0
- package/dist/factories/RebalancerContextFactory.d.ts.map +1 -1
- package/dist/factories/RebalancerContextFactory.js +61 -31
- package/dist/factories/RebalancerContextFactory.js.map +1 -1
- package/dist/factories/RebalancerContextFactory.test.js +336 -5
- package/dist/factories/RebalancerContextFactory.test.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces/IRebalancer.d.ts +4 -2
- package/dist/interfaces/IRebalancer.d.ts.map +1 -1
- package/dist/metrics/Metrics.d.ts.map +1 -1
- package/dist/metrics/Metrics.js +1 -1
- package/dist/metrics/Metrics.js.map +1 -1
- package/dist/metrics/PriceGetter.d.ts +1 -0
- package/dist/metrics/PriceGetter.d.ts.map +1 -1
- package/dist/metrics/PriceGetter.js +14 -4
- package/dist/metrics/PriceGetter.js.map +1 -1
- package/dist/metrics/PriceGetter.test.d.ts +2 -0
- package/dist/metrics/PriceGetter.test.d.ts.map +1 -0
- package/dist/metrics/PriceGetter.test.js +84 -0
- package/dist/metrics/PriceGetter.test.js.map +1 -0
- package/dist/metrics/scripts/metrics.d.ts +4 -4
- package/dist/monitor/Monitor.d.ts +1 -0
- package/dist/monitor/Monitor.d.ts.map +1 -1
- package/dist/monitor/Monitor.js +55 -46
- package/dist/monitor/Monitor.js.map +1 -1
- package/dist/monitor/Monitor.test.d.ts +2 -0
- package/dist/monitor/Monitor.test.d.ts.map +1 -0
- package/dist/monitor/Monitor.test.js +346 -0
- package/dist/monitor/Monitor.test.js.map +1 -0
- package/dist/service.d.ts +1 -1
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +9 -5
- package/dist/service.js.map +1 -1
- package/dist/strategy/BaseStrategy.d.ts.map +1 -1
- package/dist/strategy/BaseStrategy.js +13 -11
- package/dist/strategy/BaseStrategy.js.map +1 -1
- package/dist/strategy/CollateralDeficitStrategy.d.ts.map +1 -1
- package/dist/strategy/CollateralDeficitStrategy.js +2 -2
- package/dist/strategy/CollateralDeficitStrategy.js.map +1 -1
- package/dist/strategy/CompositeStrategy.d.ts.map +1 -1
- package/dist/strategy/CompositeStrategy.js.map +1 -1
- package/dist/strategy/CompositeStrategy.test.js.map +1 -1
- package/dist/strategy/MinAmountStrategy.d.ts +1 -0
- package/dist/strategy/MinAmountStrategy.d.ts.map +1 -1
- package/dist/strategy/MinAmountStrategy.js +12 -8
- package/dist/strategy/MinAmountStrategy.js.map +1 -1
- package/dist/strategy/MinAmountStrategy.test.js +189 -2
- package/dist/strategy/MinAmountStrategy.test.js.map +1 -1
- package/dist/strategy/StrategyFactory.d.ts.map +1 -1
- package/dist/strategy/StrategyFactory.js.map +1 -1
- package/dist/strategy/WeightedStrategy.d.ts.map +1 -1
- package/dist/test/helpers.d.ts +11 -3
- package/dist/test/helpers.d.ts.map +1 -1
- package/dist/test/helpers.js +9 -11
- package/dist/test/helpers.js.map +1 -1
- package/dist/test/lifiMocks.d.ts +6 -6
- package/dist/test/lifiMocks.d.ts.map +1 -1
- package/dist/test/lifiMocks.js +5 -2
- package/dist/test/lifiMocks.js.map +1 -1
- package/dist/test/pendingTransferMiddlewareMocks.d.ts +17 -0
- package/dist/test/pendingTransferMiddlewareMocks.d.ts.map +1 -0
- package/dist/test/pendingTransferMiddlewareMocks.js +43 -0
- package/dist/test/pendingTransferMiddlewareMocks.js.map +1 -0
- package/dist/tracking/ActionTracker.d.ts +4 -0
- package/dist/tracking/ActionTracker.d.ts.map +1 -1
- package/dist/tracking/ActionTracker.js +76 -9
- package/dist/tracking/ActionTracker.js.map +1 -1
- package/dist/tracking/ActionTracker.test.js +418 -1
- package/dist/tracking/ActionTracker.test.js.map +1 -1
- package/dist/tracking/IActionTracker.d.ts +4 -2
- package/dist/tracking/IActionTracker.d.ts.map +1 -1
- package/dist/tracking/InflightContextAdapter.d.ts.map +1 -1
- package/dist/tracking/InflightContextAdapter.js.map +1 -1
- package/dist/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.d.ts +64 -0
- package/dist/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.d.ts.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.js +474 -0
- package/dist/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.js.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.test.d.ts +2 -0
- package/dist/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.test.d.ts.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.test.js +1168 -0
- package/dist/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.test.js.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.d.ts +61 -0
- package/dist/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.d.ts.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.js +160 -0
- package/dist/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.js.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.test.d.ts +2 -0
- package/dist/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.test.d.ts.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.test.js +369 -0
- package/dist/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.test.js.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.d.ts +60 -0
- package/dist/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.d.ts.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.js +288 -0
- package/dist/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.js.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.test.d.ts +2 -0
- package/dist/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.test.d.ts.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.test.js +606 -0
- package/dist/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.test.js.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.d.ts +25 -0
- package/dist/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.d.ts.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.js +41 -0
- package/dist/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.js.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.test.d.ts +2 -0
- package/dist/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.test.d.ts.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.test.js +141 -0
- package/dist/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.test.js.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/matchBody.d.ts +12 -0
- package/dist/tracking/pendingTransferMiddlewares/matchBody.d.ts.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/matchBody.js +29 -0
- package/dist/tracking/pendingTransferMiddlewares/matchBody.js.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/relayerDenylistRules.d.ts +59 -0
- package/dist/tracking/pendingTransferMiddlewares/relayerDenylistRules.d.ts.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/relayerDenylistRules.js +661 -0
- package/dist/tracking/pendingTransferMiddlewares/relayerDenylistRules.js.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/relayerDenylistRules.test.d.ts +2 -0
- package/dist/tracking/pendingTransferMiddlewares/relayerDenylistRules.test.d.ts.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/relayerDenylistRules.test.js +1093 -0
- package/dist/tracking/pendingTransferMiddlewares/relayerDenylistRules.test.js.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/types.d.ts +2 -0
- package/dist/tracking/pendingTransferMiddlewares/types.d.ts.map +1 -0
- package/dist/tracking/pendingTransferMiddlewares/types.js +4 -0
- package/dist/tracking/pendingTransferMiddlewares/types.js.map +1 -0
- package/dist/tracking/store/InMemoryStore.d.ts.map +1 -1
- package/dist/utils/ExplorerClient.d.ts +1 -0
- package/dist/utils/ExplorerClient.d.ts.map +1 -1
- package/dist/utils/ExplorerClient.js +8 -3
- package/dist/utils/ExplorerClient.js.map +1 -1
- package/dist/utils/ExplorerClient.test.js +25 -0
- package/dist/utils/ExplorerClient.test.js.map +1 -1
- package/dist/utils/balanceUtils.d.ts +7 -1
- package/dist/utils/balanceUtils.d.ts.map +1 -1
- package/dist/utils/balanceUtils.js +39 -1
- package/dist/utils/balanceUtils.js.map +1 -1
- package/dist/utils/balanceUtils.test.js +55 -1
- package/dist/utils/balanceUtils.test.js.map +1 -1
- package/dist/utils/blockTag.d.ts +5 -4
- package/dist/utils/blockTag.d.ts.map +1 -1
- package/dist/utils/blockTag.js +26 -10
- package/dist/utils/blockTag.js.map +1 -1
- package/dist/utils/blockTag.test.d.ts +2 -0
- package/dist/utils/blockTag.test.d.ts.map +1 -0
- package/dist/utils/blockTag.test.js +132 -0
- package/dist/utils/blockTag.test.js.map +1 -0
- package/dist/utils/bridgeUtils.js.map +1 -1
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/gasEstimation.d.ts +2 -1
- package/dist/utils/gasEstimation.d.ts.map +1 -1
- package/dist/utils/gasEstimation.js +16 -13
- package/dist/utils/gasEstimation.js.map +1 -1
- package/dist/utils/gasEstimation.test.d.ts +2 -0
- package/dist/utils/gasEstimation.test.d.ts.map +1 -0
- package/dist/utils/gasEstimation.test.js +104 -0
- package/dist/utils/gasEstimation.test.js.map +1 -0
- package/dist/utils/tokenUtils.d.ts.map +1 -1
- package/dist/utils/tokenUtils.js +5 -2
- package/dist/utils/tokenUtils.js.map +1 -1
- package/package.json +23 -22
- package/src/bridges/LiFiBridge.test.ts +270 -0
- package/src/bridges/LiFiBridge.ts +90 -71
- package/src/config/RebalancerConfig.test.ts +315 -1
- package/src/config/RebalancerConfig.ts +6 -3
- package/src/config/types.ts +98 -8
- package/src/core/InventoryRebalancer.test.ts +1092 -38
- package/src/core/InventoryRebalancer.ts +584 -351
- package/src/core/Rebalancer.test.ts +84 -0
- package/src/core/Rebalancer.ts +22 -6
- package/src/core/RebalancerOrchestrator.test.ts +0 -1
- package/src/core/RebalancerService.test.ts +35 -0
- package/src/core/RebalancerService.ts +3 -2
- package/src/e2e/harness/BaseLocalDeploymentManager.ts +3 -1
- package/src/e2e/harness/LocalProvider.test.ts +16 -0
- package/src/e2e/harness/LocalProvider.ts +10 -0
- package/src/e2e/harness/NativeLocalDeploymentManager.ts +2 -1
- package/src/e2e/harness/SnapshotHelper.ts +2 -5
- package/src/e2e/harness/TestHelpers.ts +3 -3
- package/src/e2e/harness/TestRebalancer.ts +21 -1
- package/src/e2e/relayer-denylist.e2e-test.ts +558 -0
- package/src/factories/RebalancerContextFactory.test.ts +489 -8
- package/src/factories/RebalancerContextFactory.ts +86 -36
- package/src/index.ts +2 -0
- package/src/interfaces/IRebalancer.ts +4 -1
- package/src/metrics/Metrics.ts +1 -0
- package/src/metrics/PriceGetter.test.ts +113 -0
- package/src/metrics/PriceGetter.ts +18 -3
- package/src/monitor/Monitor.test.ts +408 -0
- package/src/monitor/Monitor.ts +123 -97
- package/src/service.ts +14 -8
- package/src/strategy/BaseStrategy.ts +18 -15
- package/src/strategy/CollateralDeficitStrategy.ts +4 -3
- package/src/strategy/MinAmountStrategy.test.ts +238 -2
- package/src/strategy/MinAmountStrategy.ts +29 -17
- package/src/test/helpers.ts +13 -12
- package/src/test/lifiMocks.ts +5 -2
- package/src/test/pendingTransferMiddlewareMocks.ts +65 -0
- package/src/tracking/ActionTracker.test.ts +635 -3
- package/src/tracking/ActionTracker.ts +92 -12
- package/src/tracking/IActionTracker.ts +4 -2
- package/src/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.test.ts +1693 -0
- package/src/tracking/pendingTransferMiddlewares/BlacklistIsmMiddleware.ts +784 -0
- package/src/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.test.ts +554 -0
- package/src/tracking/pendingTransferMiddlewares/PendingTransferMiddleware.ts +233 -0
- package/src/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.test.ts +894 -0
- package/src/tracking/pendingTransferMiddlewares/RelayerDenylistMiddleware.ts +404 -0
- package/src/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.test.ts +205 -0
- package/src/tracking/pendingTransferMiddlewares/buildPendingTransferMiddlewares.ts +89 -0
- package/src/tracking/pendingTransferMiddlewares/fixtures/mainnet-denylist.json +3556 -0
- package/src/tracking/pendingTransferMiddlewares/matchBody.ts +43 -0
- package/src/tracking/pendingTransferMiddlewares/relayerDenylistRules.test.ts +1220 -0
- package/src/tracking/pendingTransferMiddlewares/relayerDenylistRules.ts +934 -0
- package/src/tracking/pendingTransferMiddlewares/types.ts +3 -0
- package/src/utils/ExplorerClient.test.ts +42 -0
- package/src/utils/ExplorerClient.ts +14 -3
- package/src/utils/balanceUtils.test.ts +87 -1
- package/src/utils/balanceUtils.ts +73 -2
- package/src/utils/blockTag.test.ts +173 -0
- package/src/utils/blockTag.ts +35 -15
- package/src/utils/gasEstimation.test.ts +192 -0
- package/src/utils/gasEstimation.ts +17 -11
- package/src/utils/tokenUtils.ts +5 -2
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
import { providers } from 'ethers';
|
|
3
|
+
import { pino } from 'pino';
|
|
4
|
+
import sinon from 'sinon';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
type ChainMap,
|
|
8
|
+
type ChainMetadata,
|
|
9
|
+
EvmHypSyntheticAdapter,
|
|
10
|
+
MultiProtocolProvider,
|
|
11
|
+
Token,
|
|
12
|
+
TokenStandard,
|
|
13
|
+
WarpCore,
|
|
14
|
+
} from '@humanode-hyperlane/sdk';
|
|
15
|
+
import { ProtocolType } from '@humanode-hyperlane/utils';
|
|
16
|
+
|
|
17
|
+
import { type MonitorEvent, MonitorEventType } from '../interfaces/IMonitor.js';
|
|
18
|
+
|
|
19
|
+
import { Monitor } from './Monitor.js';
|
|
20
|
+
|
|
21
|
+
const ADDRESS = '0x0000000000000000000000000000000000000001';
|
|
22
|
+
const logger = pino({ level: 'silent' });
|
|
23
|
+
|
|
24
|
+
async function nextTurn(): Promise<void> {
|
|
25
|
+
await new Promise<void>((resolve) => setImmediate(resolve));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function setup(count: number, withInventory = false) {
|
|
29
|
+
const metadata: ChainMap<ChainMetadata> = {};
|
|
30
|
+
const tokens = Array.from({ length: count }, (_, index) => {
|
|
31
|
+
const chainName = `chain${index}`;
|
|
32
|
+
metadata[chainName] = {
|
|
33
|
+
name: chainName,
|
|
34
|
+
protocol: ProtocolType.Ethereum,
|
|
35
|
+
chainId: index + 1,
|
|
36
|
+
domainId: index + 1,
|
|
37
|
+
rpcUrls: [{ http: 'http://unused' }],
|
|
38
|
+
blocks: { reorgPeriod: 2, confirmations: 1 },
|
|
39
|
+
};
|
|
40
|
+
return new Token({
|
|
41
|
+
chainName,
|
|
42
|
+
standard: TokenStandard.EvmHypSynthetic,
|
|
43
|
+
addressOrDenom: ADDRESS,
|
|
44
|
+
decimals: 18,
|
|
45
|
+
name: 'Token',
|
|
46
|
+
symbol: 'TOK',
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
const multiProvider = new MultiProtocolProvider(metadata);
|
|
50
|
+
const blocks = tokens.map(() =>
|
|
51
|
+
sinon.createStubInstance(providers.JsonRpcProvider),
|
|
52
|
+
);
|
|
53
|
+
const adapters = tokens.map(() =>
|
|
54
|
+
sinon.createStubInstance(EvmHypSyntheticAdapter),
|
|
55
|
+
);
|
|
56
|
+
const getProvider = sinon.stub(multiProvider, 'getEthersV5Provider');
|
|
57
|
+
tokens.forEach((token, index) => {
|
|
58
|
+
getProvider.withArgs(token.chainName).returns(blocks[index]);
|
|
59
|
+
blocks[index].send.resolves('0x64');
|
|
60
|
+
adapters[index].getBridgedSupply.resolves(BigInt(index));
|
|
61
|
+
adapters[index].getBalance.resolves(BigInt(index + 10));
|
|
62
|
+
sinon.stub(token, 'getHypAdapter').returns(adapters[index]);
|
|
63
|
+
sinon.stub(token, 'getAdapter').returns(adapters[index]);
|
|
64
|
+
});
|
|
65
|
+
const monitor = new Monitor(
|
|
66
|
+
0,
|
|
67
|
+
new WarpCore(multiProvider, tokens),
|
|
68
|
+
logger,
|
|
69
|
+
withInventory
|
|
70
|
+
? {
|
|
71
|
+
chains: tokens.map((token) => token.chainName),
|
|
72
|
+
inventoryAddresses: { [ProtocolType.Ethereum]: ADDRESS },
|
|
73
|
+
}
|
|
74
|
+
: undefined,
|
|
75
|
+
);
|
|
76
|
+
return { monitor, tokens, blocks, adapters };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function setupTron(reorgPeriod: number | string) {
|
|
80
|
+
const token = new Token({
|
|
81
|
+
chainName: 'tron',
|
|
82
|
+
standard: TokenStandard.TronHypSynthetic,
|
|
83
|
+
addressOrDenom: 'TJRabPrwbZy45sbavfcjinPJC18kjpRTv8',
|
|
84
|
+
decimals: 6,
|
|
85
|
+
name: 'Token',
|
|
86
|
+
symbol: 'TOK',
|
|
87
|
+
});
|
|
88
|
+
const metadata: ChainMap<ChainMetadata> = {
|
|
89
|
+
tron: {
|
|
90
|
+
name: 'tron',
|
|
91
|
+
protocol: ProtocolType.Tron,
|
|
92
|
+
chainId: 728126428,
|
|
93
|
+
domainId: 728126428,
|
|
94
|
+
rpcUrls: [{ http: 'http://unused' }],
|
|
95
|
+
blocks: { reorgPeriod, confirmations: 1 },
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
const multiProvider = new MultiProtocolProvider(metadata);
|
|
99
|
+
const block = sinon.createStubInstance(providers.JsonRpcProvider);
|
|
100
|
+
block.send.resolves('0x64');
|
|
101
|
+
sinon.stub(multiProvider, 'getEthersV5Provider').returns(block);
|
|
102
|
+
const adapter = sinon.createStubInstance(EvmHypSyntheticAdapter);
|
|
103
|
+
adapter.getBridgedSupply.resolves(5n);
|
|
104
|
+
sinon.stub(token, 'getHypAdapter').returns(adapter);
|
|
105
|
+
const monitor = new Monitor(0, new WarpCore(multiProvider, [token]), logger);
|
|
106
|
+
return { monitor, adapter, block, token };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
describe('Monitor concurrency', () => {
|
|
110
|
+
afterEach(() => sinon.restore());
|
|
111
|
+
|
|
112
|
+
it('bounds block and inventory reads, filling slots while another chain is slow', async () => {
|
|
113
|
+
const { monitor, tokens, blocks, adapters } = setup(10, true);
|
|
114
|
+
const blockGates = blocks.map(() => sinon.promise<string>());
|
|
115
|
+
const inventoryGates = adapters.map(() => sinon.promise<bigint>());
|
|
116
|
+
blocks.forEach((block, index) => block.send.returns(blockGates[index]));
|
|
117
|
+
adapters.forEach((adapter, index) =>
|
|
118
|
+
adapter.getBalance.returns(inventoryGates[index]),
|
|
119
|
+
);
|
|
120
|
+
let event: MonitorEvent | undefined;
|
|
121
|
+
monitor.on(MonitorEventType.TokenInfo, (received) => {
|
|
122
|
+
event = received;
|
|
123
|
+
void monitor.stop();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const running = monitor.start();
|
|
127
|
+
await nextTurn();
|
|
128
|
+
expect(blocks.filter((block) => block.send.called).length).to.equal(8);
|
|
129
|
+
expect(
|
|
130
|
+
adapters.filter((adapter) => adapter.getBalance.called).length,
|
|
131
|
+
).to.equal(8);
|
|
132
|
+
void blockGates[1].resolve('0x65');
|
|
133
|
+
void inventoryGates[1].resolve(11n);
|
|
134
|
+
await nextTurn();
|
|
135
|
+
expect(blocks[8].send.calledOnce).to.equal(true);
|
|
136
|
+
expect(adapters[8].getBalance.calledOnce).to.equal(true);
|
|
137
|
+
expect(blocks[0].send.calledOnce).to.equal(true);
|
|
138
|
+
expect(blocks[9].send.called).to.equal(false);
|
|
139
|
+
expect(adapters[9].getBalance.called).to.equal(false);
|
|
140
|
+
expect(
|
|
141
|
+
adapters.every((adapter) => adapter.getBridgedSupply.notCalled),
|
|
142
|
+
).to.equal(true);
|
|
143
|
+
|
|
144
|
+
blockGates.forEach((gate, index) => {
|
|
145
|
+
if (index !== 1) void gate.resolve(`0x${(100 + index).toString(16)}`);
|
|
146
|
+
});
|
|
147
|
+
await nextTurn();
|
|
148
|
+
expect(
|
|
149
|
+
adapters.every((adapter) => adapter.getBridgedSupply.calledOnce),
|
|
150
|
+
).to.equal(true);
|
|
151
|
+
expect(event).to.equal(undefined);
|
|
152
|
+
inventoryGates.forEach((gate, index) => {
|
|
153
|
+
if (index !== 1) void gate.resolve(BigInt(index + 10));
|
|
154
|
+
});
|
|
155
|
+
await running;
|
|
156
|
+
expect(event?.tokensInfo.map(({ token }) => token)).to.deep.equal(tokens);
|
|
157
|
+
expect(event?.confirmedBlockTags.chain1).to.equal(99);
|
|
158
|
+
expect(event?.inventoryBalances?.chain9).to.equal(19n);
|
|
159
|
+
adapters.forEach((adapter, index) => {
|
|
160
|
+
expect(adapter.getBridgedSupply.firstCall.args).to.deep.equal([
|
|
161
|
+
{ blockTag: 98 + index },
|
|
162
|
+
]);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('bounds supply reads and preserves token order when reads complete out of order', async () => {
|
|
167
|
+
const { monitor, tokens, adapters } = setup(10);
|
|
168
|
+
const gates = adapters.map(() => sinon.promise<bigint>());
|
|
169
|
+
adapters.forEach((adapter, index) =>
|
|
170
|
+
adapter.getBridgedSupply.returns(gates[index]),
|
|
171
|
+
);
|
|
172
|
+
let event: MonitorEvent | undefined;
|
|
173
|
+
monitor.on(MonitorEventType.TokenInfo, (received) => {
|
|
174
|
+
event = received;
|
|
175
|
+
void monitor.stop();
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const running = monitor.start();
|
|
179
|
+
await nextTurn();
|
|
180
|
+
expect(
|
|
181
|
+
adapters.filter((adapter) => adapter.getBridgedSupply.called).length,
|
|
182
|
+
).to.equal(8);
|
|
183
|
+
void gates[1].resolve(1n);
|
|
184
|
+
await nextTurn();
|
|
185
|
+
expect(adapters[8].getBridgedSupply.calledOnce).to.equal(true);
|
|
186
|
+
gates.forEach((gate, index) => {
|
|
187
|
+
if (index !== 1) void gate.resolve(BigInt(index));
|
|
188
|
+
});
|
|
189
|
+
await running;
|
|
190
|
+
expect(event?.tokensInfo).to.deep.equal(
|
|
191
|
+
tokens.map((token, index) => ({ token, bridgedSupply: BigInt(index) })),
|
|
192
|
+
);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('drains reads after a supply failure before reporting the failed cycle', async () => {
|
|
196
|
+
const { monitor, adapters } = setup(2, true);
|
|
197
|
+
const supply = sinon.promise<bigint>();
|
|
198
|
+
const inventory = sinon.promise<bigint>();
|
|
199
|
+
adapters[0].getBridgedSupply.rejects(new Error('supply unavailable'));
|
|
200
|
+
adapters[1].getBridgedSupply.returns(supply);
|
|
201
|
+
adapters[0].getBalance.returns(inventory);
|
|
202
|
+
const handler = sinon.stub();
|
|
203
|
+
const errors = sinon.stub();
|
|
204
|
+
monitor.on(MonitorEventType.TokenInfo, handler);
|
|
205
|
+
monitor.on(MonitorEventType.Error, (error) => {
|
|
206
|
+
errors(error);
|
|
207
|
+
void monitor.stop();
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const running = monitor.start();
|
|
211
|
+
await nextTurn();
|
|
212
|
+
expect(errors.notCalled).to.equal(true);
|
|
213
|
+
void supply.resolve(1n);
|
|
214
|
+
await nextTurn();
|
|
215
|
+
expect(errors.notCalled).to.equal(true);
|
|
216
|
+
void inventory.resolve(2n);
|
|
217
|
+
await running;
|
|
218
|
+
expect(errors.calledOnce).to.equal(true);
|
|
219
|
+
expect(handler.notCalled).to.equal(true);
|
|
220
|
+
expect(adapters[0].getBridgedSupply.calledOnce).to.equal(true);
|
|
221
|
+
expect(adapters[0].getBridgedSupply.firstCall.args).to.deep.equal([
|
|
222
|
+
{ blockTag: 98 },
|
|
223
|
+
]);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('drains supply and inventory reads after an inventory failure without emitting balances', async () => {
|
|
227
|
+
const { monitor, adapters } = setup(2, true);
|
|
228
|
+
const supply = sinon.promise<bigint>();
|
|
229
|
+
const inventory = sinon.promise<bigint>();
|
|
230
|
+
adapters[0].getBalance.rejects(new Error('inventory unavailable'));
|
|
231
|
+
adapters[1].getBalance.returns(inventory);
|
|
232
|
+
adapters[0].getBridgedSupply.returns(supply);
|
|
233
|
+
const handler = sinon.stub();
|
|
234
|
+
const errors = sinon.stub();
|
|
235
|
+
monitor.on(MonitorEventType.TokenInfo, handler);
|
|
236
|
+
monitor.on(MonitorEventType.Error, (error) => {
|
|
237
|
+
errors(error);
|
|
238
|
+
void monitor.stop();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
const running = monitor.start();
|
|
242
|
+
await nextTurn();
|
|
243
|
+
expect(errors.notCalled).to.equal(true);
|
|
244
|
+
void inventory.resolve(11n);
|
|
245
|
+
await nextTurn();
|
|
246
|
+
expect(errors.notCalled).to.equal(true);
|
|
247
|
+
void supply.resolve(0n);
|
|
248
|
+
await running;
|
|
249
|
+
expect(errors.calledOnce).to.equal(true);
|
|
250
|
+
expect(errors.firstCall.args[0].message).to.contain(
|
|
251
|
+
'inventory unavailable',
|
|
252
|
+
);
|
|
253
|
+
expect(handler.notCalled).to.equal(true);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('retries a failed confirmed block lookup without emitting latest-state supply', async () => {
|
|
257
|
+
const { monitor, blocks, adapters } = setup(1, true);
|
|
258
|
+
blocks[0].send.onFirstCall().rejects(new Error('block unavailable'));
|
|
259
|
+
const errors = sinon.stub();
|
|
260
|
+
let event: MonitorEvent | undefined;
|
|
261
|
+
let supplyReadOnError = false;
|
|
262
|
+
monitor.on(MonitorEventType.Error, (error) => {
|
|
263
|
+
errors(error);
|
|
264
|
+
supplyReadOnError = adapters[0].getBridgedSupply.called;
|
|
265
|
+
});
|
|
266
|
+
monitor.on(MonitorEventType.TokenInfo, (received) => {
|
|
267
|
+
event = received;
|
|
268
|
+
void monitor.stop();
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
await monitor.start();
|
|
272
|
+
expect(errors.calledOnce).to.equal(true);
|
|
273
|
+
expect(errors.firstCall.args[0].message).to.contain(
|
|
274
|
+
'Confirmed block unavailable for chain0',
|
|
275
|
+
);
|
|
276
|
+
expect(supplyReadOnError).to.equal(false);
|
|
277
|
+
expect(blocks[0].send.calledTwice).to.equal(true);
|
|
278
|
+
expect(adapters[0].getBridgedSupply.calledOnce).to.equal(true);
|
|
279
|
+
expect(adapters[0].getBridgedSupply.firstCall.args).to.deep.equal([
|
|
280
|
+
{ blockTag: 98 },
|
|
281
|
+
]);
|
|
282
|
+
expect(event?.confirmedBlockTags.chain0).to.equal(98);
|
|
283
|
+
expect(event?.tokensInfo[0].bridgedSupply).to.equal(0n);
|
|
284
|
+
expect(event?.inventoryBalances).to.deep.equal({ chain0: 10n });
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('preserves optional block tags for Tron named reorg periods', async () => {
|
|
288
|
+
const { monitor, adapter, block, token } = setupTron('finalized');
|
|
289
|
+
const errors = sinon.stub();
|
|
290
|
+
let event: MonitorEvent | undefined;
|
|
291
|
+
monitor.on(MonitorEventType.Error, (error) => {
|
|
292
|
+
errors(error);
|
|
293
|
+
void monitor.stop();
|
|
294
|
+
});
|
|
295
|
+
monitor.on(MonitorEventType.TokenInfo, (received) => {
|
|
296
|
+
event = received;
|
|
297
|
+
void monitor.stop();
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
await monitor.start();
|
|
301
|
+
expect(errors.notCalled).to.equal(true);
|
|
302
|
+
expect(block.send.notCalled).to.equal(true);
|
|
303
|
+
expect(adapter.getBridgedSupply.calledOnce).to.equal(true);
|
|
304
|
+
expect(adapter.getBridgedSupply.firstCall.args).to.deep.equal([
|
|
305
|
+
{ blockTag: undefined },
|
|
306
|
+
]);
|
|
307
|
+
expect(event?.confirmedBlockTags.tron).to.equal(undefined);
|
|
308
|
+
expect(event?.tokensInfo).to.deep.equal([{ token, bridgedSupply: 5n }]);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
for (const failWithRpcError of [true, false]) {
|
|
312
|
+
it(`retries a numeric Tron block ${failWithRpcError ? 'RPC failure' : 'invalid response'} before emitting supply`, async () => {
|
|
313
|
+
const { monitor, adapter, block } = setupTron(20);
|
|
314
|
+
if (failWithRpcError) {
|
|
315
|
+
block.send.onFirstCall().rejects(new Error('block unavailable'));
|
|
316
|
+
} else {
|
|
317
|
+
block.send.onFirstCall().resolves(undefined);
|
|
318
|
+
}
|
|
319
|
+
const errors = sinon.stub();
|
|
320
|
+
let supplyReadOnError = false;
|
|
321
|
+
let event: MonitorEvent | undefined;
|
|
322
|
+
monitor.on(MonitorEventType.Error, (error) => {
|
|
323
|
+
errors(error);
|
|
324
|
+
supplyReadOnError = adapter.getBridgedSupply.called;
|
|
325
|
+
});
|
|
326
|
+
monitor.on(MonitorEventType.TokenInfo, (received) => {
|
|
327
|
+
event = received;
|
|
328
|
+
void monitor.stop();
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
await monitor.start();
|
|
332
|
+
expect(errors.calledOnce).to.equal(true);
|
|
333
|
+
expect(errors.firstCall.args[0].message).to.contain(
|
|
334
|
+
failWithRpcError
|
|
335
|
+
? 'block unavailable'
|
|
336
|
+
: 'Invalid eth_blockNumber response',
|
|
337
|
+
);
|
|
338
|
+
expect(supplyReadOnError).to.equal(false);
|
|
339
|
+
expect(block.send.calledTwice).to.equal(true);
|
|
340
|
+
expect(adapter.getBridgedSupply.calledOnce).to.equal(true);
|
|
341
|
+
expect(adapter.getBridgedSupply.firstCall.args).to.deep.equal([
|
|
342
|
+
{ blockTag: 80 },
|
|
343
|
+
]);
|
|
344
|
+
expect(event?.confirmedBlockTags.tron).to.equal(80);
|
|
345
|
+
expect(event?.tokensInfo[0].bridgedSupply).to.equal(5n);
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
it('emits inventory balances from a later cycle after an inventory failure', async () => {
|
|
350
|
+
const { monitor, adapters } = setup(1, true);
|
|
351
|
+
adapters[0].getBalance
|
|
352
|
+
.onFirstCall()
|
|
353
|
+
.rejects(new Error('inventory unavailable'));
|
|
354
|
+
const errors = sinon.stub();
|
|
355
|
+
const handler = sinon.stub();
|
|
356
|
+
let event: MonitorEvent | undefined;
|
|
357
|
+
monitor.on(MonitorEventType.Error, errors);
|
|
358
|
+
monitor.on(MonitorEventType.TokenInfo, (received) => {
|
|
359
|
+
handler(received);
|
|
360
|
+
event = received;
|
|
361
|
+
void monitor.stop();
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
await monitor.start();
|
|
365
|
+
expect(errors.calledOnce).to.equal(true);
|
|
366
|
+
expect(errors.firstCall.args[0].message).to.contain(
|
|
367
|
+
'inventory unavailable',
|
|
368
|
+
);
|
|
369
|
+
expect(handler.calledOnce).to.equal(true);
|
|
370
|
+
sinon.assert.callOrder(errors, handler);
|
|
371
|
+
expect(adapters[0].getBalance.calledTwice).to.equal(true);
|
|
372
|
+
expect(event?.inventoryBalances).to.deep.equal({ chain0: 10n });
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
it('emits successfully read zero inventory balances', async () => {
|
|
376
|
+
const { monitor, adapters } = setup(1, true);
|
|
377
|
+
adapters[0].getBalance.resolves(0n);
|
|
378
|
+
let event: MonitorEvent | undefined;
|
|
379
|
+
monitor.on(MonitorEventType.TokenInfo, (received) => {
|
|
380
|
+
event = received;
|
|
381
|
+
void monitor.stop();
|
|
382
|
+
});
|
|
383
|
+
await monitor.start();
|
|
384
|
+
expect(event?.inventoryBalances).to.deep.equal({ chain0: 0n });
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
it('awaits its consumer before another polling cycle and before stop completes', async () => {
|
|
388
|
+
const { monitor, adapters } = setup(1);
|
|
389
|
+
const consumer = sinon.promise<void>();
|
|
390
|
+
const handler = sinon.stub().returns(consumer);
|
|
391
|
+
monitor.on(MonitorEventType.TokenInfo, handler);
|
|
392
|
+
const running = monitor.start();
|
|
393
|
+
await nextTurn();
|
|
394
|
+
expect(handler.calledOnce).to.equal(true);
|
|
395
|
+
expect(adapters[0].getBridgedSupply.calledOnce).to.equal(true);
|
|
396
|
+
|
|
397
|
+
let stopped = false;
|
|
398
|
+
const stop = monitor.stop().then(() => {
|
|
399
|
+
stopped = true;
|
|
400
|
+
});
|
|
401
|
+
await nextTurn();
|
|
402
|
+
expect(stopped).to.equal(false);
|
|
403
|
+
expect(adapters[0].getBridgedSupply.calledOnce).to.equal(true);
|
|
404
|
+
void consumer.resolve(undefined);
|
|
405
|
+
await Promise.all([running, stop]);
|
|
406
|
+
expect(stopped).to.equal(true);
|
|
407
|
+
});
|
|
408
|
+
});
|
package/src/monitor/Monitor.ts
CHANGED
|
@@ -6,7 +6,14 @@ import {
|
|
|
6
6
|
type Token,
|
|
7
7
|
type WarpCore,
|
|
8
8
|
} from '@humanode-hyperlane/sdk';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
Address,
|
|
11
|
+
ProtocolType,
|
|
12
|
+
assert,
|
|
13
|
+
concurrentMap,
|
|
14
|
+
fromWei,
|
|
15
|
+
sleep,
|
|
16
|
+
} from '@humanode-hyperlane/utils';
|
|
10
17
|
|
|
11
18
|
import {
|
|
12
19
|
type ConfirmedBlockTag,
|
|
@@ -19,6 +26,9 @@ import {
|
|
|
19
26
|
} from '../interfaces/IMonitor.js';
|
|
20
27
|
import { getConfirmedBlockTag } from '../utils/blockTag.js';
|
|
21
28
|
|
|
29
|
+
// Bound each read group so route size cannot create unlimited RPC work.
|
|
30
|
+
const MONITOR_READ_CONCURRENCY = 8;
|
|
31
|
+
|
|
22
32
|
/**
|
|
23
33
|
* Configuration for the Monitor's inventory tracking.
|
|
24
34
|
*/
|
|
@@ -53,17 +63,43 @@ export class Monitor implements IMonitor {
|
|
|
53
63
|
const blockTags: ConfirmedBlockTags = {};
|
|
54
64
|
const chains = new Set(this.warpCore.tokens.map((t) => t.chainName));
|
|
55
65
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
await concurrentMap(
|
|
67
|
+
MONITOR_READ_CONCURRENCY,
|
|
68
|
+
[...chains],
|
|
69
|
+
async (chain) => {
|
|
70
|
+
blockTags[chain] = await getConfirmedBlockTag(
|
|
71
|
+
this.warpCore.multiProvider,
|
|
72
|
+
chain,
|
|
73
|
+
this.logger,
|
|
74
|
+
);
|
|
75
|
+
},
|
|
76
|
+
);
|
|
63
77
|
|
|
64
78
|
return blockTags;
|
|
65
79
|
}
|
|
66
80
|
|
|
81
|
+
private async fetchTokenInfo(): Promise<MonitorEvent> {
|
|
82
|
+
const confirmedBlockTags = await this.computeConfirmedBlockTags();
|
|
83
|
+
const tokensInfo = await concurrentMap(
|
|
84
|
+
MONITOR_READ_CONCURRENCY,
|
|
85
|
+
this.warpCore.tokens,
|
|
86
|
+
async (token) => {
|
|
87
|
+
this.logger.debug(
|
|
88
|
+
{
|
|
89
|
+
chain: token.chainName,
|
|
90
|
+
tokenSymbol: token.symbol,
|
|
91
|
+
tokenAddress: token.addressOrDenom,
|
|
92
|
+
},
|
|
93
|
+
'Checking token',
|
|
94
|
+
);
|
|
95
|
+
const blockTag = confirmedBlockTags[token.chainName];
|
|
96
|
+
const bridgedSupply = await this.getTokenBridgedSupply(token, blockTag);
|
|
97
|
+
return { token, bridgedSupply };
|
|
98
|
+
},
|
|
99
|
+
);
|
|
100
|
+
return { tokensInfo, confirmedBlockTags };
|
|
101
|
+
}
|
|
102
|
+
|
|
67
103
|
// overloads from IMonitor
|
|
68
104
|
on(
|
|
69
105
|
eventName: MonitorEventType.TokenInfo,
|
|
@@ -109,47 +145,40 @@ export class Monitor implements IMonitor {
|
|
|
109
145
|
try {
|
|
110
146
|
this.logger.debug('Polling cycle started');
|
|
111
147
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
{
|
|
122
|
-
chain: token.chainName,
|
|
123
|
-
tokenSymbol: token.symbol,
|
|
124
|
-
tokenAddress: token.addressOrDenom,
|
|
125
|
-
},
|
|
126
|
-
'Checking token',
|
|
127
|
-
);
|
|
128
|
-
const blockTag = confirmedBlockTags[token.chainName];
|
|
129
|
-
const bridgedSupply = await this.getTokenBridgedSupply(
|
|
130
|
-
token,
|
|
131
|
-
blockTag,
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
event.tokensInfo.push({
|
|
135
|
-
token,
|
|
136
|
-
bridgedSupply,
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const inventoryBalances = await this.fetchInventoryBalances();
|
|
148
|
+
// Drain both groups on error before a retry can start another cycle.
|
|
149
|
+
const [tokenRead, inventoryRead] = await Promise.allSettled([
|
|
150
|
+
this.fetchTokenInfo(),
|
|
151
|
+
this.fetchInventoryBalances(),
|
|
152
|
+
]);
|
|
153
|
+
if (tokenRead.status === 'rejected') throw tokenRead.reason;
|
|
154
|
+
if (inventoryRead.status === 'rejected') throw inventoryRead.reason;
|
|
155
|
+
const event = tokenRead.value;
|
|
156
|
+
const inventoryBalances = inventoryRead.value;
|
|
141
157
|
if (Object.keys(inventoryBalances).length > 0) {
|
|
142
158
|
event.inventoryBalances = inventoryBalances;
|
|
159
|
+
const tokensByChain = new Map(
|
|
160
|
+
this.warpCore.tokens.map((token) => [token.chainName, token]),
|
|
161
|
+
);
|
|
162
|
+
// CAST: inventoryBalances keys come from configured monitor chains,
|
|
163
|
+
// but Object.entries widens them to string.
|
|
164
|
+
const inventoryBalanceEntries = Object.entries(
|
|
165
|
+
inventoryBalances,
|
|
166
|
+
) as [ChainName, bigint][];
|
|
143
167
|
this.logger.info(
|
|
144
168
|
{
|
|
145
169
|
chainsMonitored: Object.keys(inventoryBalances).length,
|
|
146
|
-
balances:
|
|
147
|
-
|
|
170
|
+
balances: inventoryBalanceEntries.map(([chain, balance]) => {
|
|
171
|
+
const token = tokensByChain.get(chain);
|
|
172
|
+
return {
|
|
148
173
|
chain,
|
|
174
|
+
tokenSymbol: token?.symbol,
|
|
149
175
|
balance: balance.toString(),
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
176
|
+
balanceFormatted: fromWei(
|
|
177
|
+
balance.toString(),
|
|
178
|
+
token?.decimals,
|
|
179
|
+
),
|
|
180
|
+
};
|
|
181
|
+
}),
|
|
153
182
|
},
|
|
154
183
|
'Inventory balances fetched',
|
|
155
184
|
);
|
|
@@ -215,26 +244,16 @@ export class Monitor implements IMonitor {
|
|
|
215
244
|
return;
|
|
216
245
|
}
|
|
217
246
|
|
|
247
|
+
assert(
|
|
248
|
+
token.protocol !== ProtocolType.Ethereum || blockTag !== undefined,
|
|
249
|
+
`Confirmed block unavailable for ${token.chainName}`,
|
|
250
|
+
);
|
|
218
251
|
const adapter = token.getHypAdapter(this.warpCore.multiProvider);
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
{ chain: token.chainName, blockTag },
|
|
225
|
-
'Queried confirmed balance',
|
|
226
|
-
);
|
|
227
|
-
} catch (error) {
|
|
228
|
-
this.logger.warn(
|
|
229
|
-
{
|
|
230
|
-
chain: token.chainName,
|
|
231
|
-
blockTag,
|
|
232
|
-
error: (error as Error).message,
|
|
233
|
-
},
|
|
234
|
-
'Historical block query failed, falling back to latest',
|
|
235
|
-
);
|
|
236
|
-
bridgedSupply = await adapter.getBridgedSupply();
|
|
237
|
-
}
|
|
252
|
+
const bridgedSupply = await adapter.getBridgedSupply({ blockTag });
|
|
253
|
+
this.logger.debug(
|
|
254
|
+
{ chain: token.chainName, blockTag },
|
|
255
|
+
'Queried confirmed balance',
|
|
256
|
+
);
|
|
238
257
|
|
|
239
258
|
if (bridgedSupply === undefined) {
|
|
240
259
|
this.logger.warn(
|
|
@@ -251,51 +270,58 @@ export class Monitor implements IMonitor {
|
|
|
251
270
|
}
|
|
252
271
|
|
|
253
272
|
private async fetchInventoryBalances(): Promise<ChainMap<bigint>> {
|
|
254
|
-
|
|
273
|
+
const inventoryConfig = this.inventoryConfig;
|
|
274
|
+
if (!inventoryConfig) return {};
|
|
255
275
|
|
|
256
276
|
const balances: ChainMap<bigint> = {};
|
|
257
277
|
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
278
|
+
const results = await concurrentMap(
|
|
279
|
+
MONITOR_READ_CONCURRENCY,
|
|
280
|
+
inventoryConfig.chains,
|
|
281
|
+
async (chainName) => {
|
|
282
|
+
const token = this.warpCore.tokens.find(
|
|
283
|
+
(t) => t.chainName === chainName,
|
|
264
284
|
);
|
|
265
|
-
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
try {
|
|
269
|
-
const address =
|
|
270
|
-
this.inventoryConfig!.inventoryAddresses[token.protocol];
|
|
271
|
-
if (!address) {
|
|
285
|
+
if (!token) {
|
|
272
286
|
this.logger.warn(
|
|
273
|
-
{ chain: chainName
|
|
274
|
-
'No
|
|
287
|
+
{ chain: chainName },
|
|
288
|
+
'No token found for inventory chain',
|
|
275
289
|
);
|
|
276
290
|
return { chainName, balance: 0n };
|
|
277
291
|
}
|
|
278
|
-
const adapter = token.getAdapter(this.warpCore.multiProvider);
|
|
279
|
-
const balance = await adapter.getBalance(address);
|
|
280
|
-
this.logger.debug(
|
|
281
|
-
{
|
|
282
|
-
chain: chainName,
|
|
283
|
-
token: token.addressOrDenom,
|
|
284
|
-
balance: balance.toString(),
|
|
285
|
-
},
|
|
286
|
-
'Read inventory balance',
|
|
287
|
-
);
|
|
288
|
-
return { chainName, balance };
|
|
289
|
-
} catch (error) {
|
|
290
|
-
this.logger.error(
|
|
291
|
-
{ chain: chainName, error: (error as Error).message },
|
|
292
|
-
'Failed to read inventory balance',
|
|
293
|
-
);
|
|
294
|
-
return { chainName, balance: 0n };
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
292
|
|
|
298
|
-
|
|
293
|
+
try {
|
|
294
|
+
const address = inventoryConfig.inventoryAddresses[token.protocol];
|
|
295
|
+
if (!address) {
|
|
296
|
+
this.logger.warn(
|
|
297
|
+
{ chain: chainName, protocol: token.protocol },
|
|
298
|
+
'No inventory address for chain protocol, skipping',
|
|
299
|
+
);
|
|
300
|
+
return { chainName, balance: 0n };
|
|
301
|
+
}
|
|
302
|
+
const adapter = token.getAdapter(this.warpCore.multiProvider);
|
|
303
|
+
const balance = await adapter.getBalance(address);
|
|
304
|
+
this.logger.debug(
|
|
305
|
+
{
|
|
306
|
+
chain: chainName,
|
|
307
|
+
token: token.addressOrDenom,
|
|
308
|
+
balance: balance.toString(),
|
|
309
|
+
},
|
|
310
|
+
'Read inventory balance',
|
|
311
|
+
);
|
|
312
|
+
return { chainName, balance };
|
|
313
|
+
} catch (error) {
|
|
314
|
+
this.logger.error(
|
|
315
|
+
{
|
|
316
|
+
chain: chainName,
|
|
317
|
+
error: error instanceof Error ? error.message : String(error),
|
|
318
|
+
},
|
|
319
|
+
'Failed to read inventory balance',
|
|
320
|
+
);
|
|
321
|
+
throw error;
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
);
|
|
299
325
|
|
|
300
326
|
for (const { chainName, balance } of results) {
|
|
301
327
|
balances[chainName] = balance;
|