@hyperlane-xyz/rebalancer 0.1.0-beta.5a8bd28ab
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/README.md +178 -0
- package/dist/config/RebalancerConfig.d.ts +12 -0
- package/dist/config/RebalancerConfig.d.ts.map +1 -0
- package/dist/config/RebalancerConfig.js +29 -0
- package/dist/config/RebalancerConfig.js.map +1 -0
- package/dist/config/RebalancerConfig.test.d.ts +2 -0
- package/dist/config/RebalancerConfig.test.d.ts.map +1 -0
- package/dist/config/RebalancerConfig.test.js +325 -0
- package/dist/config/RebalancerConfig.test.js.map +1 -0
- package/dist/core/Rebalancer.d.ts +23 -0
- package/dist/core/Rebalancer.d.ts.map +1 -0
- package/dist/core/Rebalancer.js +290 -0
- package/dist/core/Rebalancer.js.map +1 -0
- package/dist/core/RebalancerService.d.ts +115 -0
- package/dist/core/RebalancerService.d.ts.map +1 -0
- package/dist/core/RebalancerService.js +227 -0
- package/dist/core/RebalancerService.js.map +1 -0
- package/dist/core/WithInflightGuard.d.ts +20 -0
- package/dist/core/WithInflightGuard.d.ts.map +1 -0
- package/dist/core/WithInflightGuard.js +47 -0
- package/dist/core/WithInflightGuard.js.map +1 -0
- package/dist/core/WithInflightGuard.test.d.ts +2 -0
- package/dist/core/WithInflightGuard.test.d.ts.map +1 -0
- package/dist/core/WithInflightGuard.test.js +64 -0
- package/dist/core/WithInflightGuard.test.js.map +1 -0
- package/dist/core/WithSemaphore.d.ts +22 -0
- package/dist/core/WithSemaphore.d.ts.map +1 -0
- package/dist/core/WithSemaphore.js +67 -0
- package/dist/core/WithSemaphore.js.map +1 -0
- package/dist/core/WithSemaphore.test.d.ts +2 -0
- package/dist/core/WithSemaphore.test.d.ts.map +1 -0
- package/dist/core/WithSemaphore.test.js +83 -0
- package/dist/core/WithSemaphore.test.js.map +1 -0
- package/dist/factories/RebalancerContextFactory.d.ts +41 -0
- package/dist/factories/RebalancerContextFactory.d.ts.map +1 -0
- package/dist/factories/RebalancerContextFactory.js +115 -0
- package/dist/factories/RebalancerContextFactory.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/IMetrics.d.ts +5 -0
- package/dist/interfaces/IMetrics.d.ts.map +1 -0
- package/dist/interfaces/IMetrics.js +2 -0
- package/dist/interfaces/IMetrics.js.map +1 -0
- package/dist/interfaces/IMonitor.d.ts +51 -0
- package/dist/interfaces/IMonitor.d.ts.map +1 -0
- package/dist/interfaces/IMonitor.js +14 -0
- package/dist/interfaces/IMonitor.js.map +1 -0
- package/dist/interfaces/IRebalancer.d.ts +15 -0
- package/dist/interfaces/IRebalancer.d.ts.map +1 -0
- package/dist/interfaces/IRebalancer.js +2 -0
- package/dist/interfaces/IRebalancer.js.map +1 -0
- package/dist/interfaces/IStrategy.d.ts +11 -0
- package/dist/interfaces/IStrategy.d.ts.map +1 -0
- package/dist/interfaces/IStrategy.js +2 -0
- package/dist/interfaces/IStrategy.js.map +1 -0
- package/dist/metrics/Metrics.d.ts +31 -0
- package/dist/metrics/Metrics.d.ts.map +1 -0
- package/dist/metrics/Metrics.js +302 -0
- package/dist/metrics/Metrics.js.map +1 -0
- package/dist/metrics/PriceGetter.d.ts +10 -0
- package/dist/metrics/PriceGetter.d.ts.map +1 -0
- package/dist/metrics/PriceGetter.js +41 -0
- package/dist/metrics/PriceGetter.js.map +1 -0
- package/dist/metrics/scripts/metrics.d.ts +14 -0
- package/dist/metrics/scripts/metrics.d.ts.map +1 -0
- package/dist/metrics/scripts/metrics.js +198 -0
- package/dist/metrics/scripts/metrics.js.map +1 -0
- package/dist/metrics/types.d.ts +24 -0
- package/dist/metrics/types.d.ts.map +1 -0
- package/dist/metrics/types.js +2 -0
- package/dist/metrics/types.js.map +1 -0
- package/dist/metrics/utils/metrics.d.ts +12 -0
- package/dist/metrics/utils/metrics.d.ts.map +1 -0
- package/dist/metrics/utils/metrics.js +28 -0
- package/dist/metrics/utils/metrics.js.map +1 -0
- package/dist/monitor/Monitor.d.ts +26 -0
- package/dist/monitor/Monitor.d.ts.map +1 -0
- package/dist/monitor/Monitor.js +116 -0
- package/dist/monitor/Monitor.js.map +1 -0
- package/dist/service.d.ts +3 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +125 -0
- package/dist/service.js.map +1 -0
- package/dist/strategy/BaseStrategy.d.ts +34 -0
- package/dist/strategy/BaseStrategy.d.ts.map +1 -0
- package/dist/strategy/BaseStrategy.js +127 -0
- package/dist/strategy/BaseStrategy.js.map +1 -0
- package/dist/strategy/MinAmountStrategy.d.ts +27 -0
- package/dist/strategy/MinAmountStrategy.d.ts.map +1 -0
- package/dist/strategy/MinAmountStrategy.js +103 -0
- package/dist/strategy/MinAmountStrategy.js.map +1 -0
- package/dist/strategy/MinAmountStrategy.test.d.ts +2 -0
- package/dist/strategy/MinAmountStrategy.test.d.ts.map +1 -0
- package/dist/strategy/MinAmountStrategy.test.js +472 -0
- package/dist/strategy/MinAmountStrategy.test.js.map +1 -0
- package/dist/strategy/StrategyFactory.d.ts +16 -0
- package/dist/strategy/StrategyFactory.d.ts.map +1 -0
- package/dist/strategy/StrategyFactory.js +25 -0
- package/dist/strategy/StrategyFactory.js.map +1 -0
- package/dist/strategy/StrategyFactory.test.d.ts +2 -0
- package/dist/strategy/StrategyFactory.test.d.ts.map +1 -0
- package/dist/strategy/StrategyFactory.test.js +80 -0
- package/dist/strategy/StrategyFactory.test.js.map +1 -0
- package/dist/strategy/WeightedStrategy.d.ts +23 -0
- package/dist/strategy/WeightedStrategy.d.ts.map +1 -0
- package/dist/strategy/WeightedStrategy.js +61 -0
- package/dist/strategy/WeightedStrategy.js.map +1 -0
- package/dist/strategy/WeightedStrategy.test.d.ts +2 -0
- package/dist/strategy/WeightedStrategy.test.d.ts.map +1 -0
- package/dist/strategy/WeightedStrategy.test.js +307 -0
- package/dist/strategy/WeightedStrategy.test.js.map +1 -0
- package/dist/strategy/index.d.ts +5 -0
- package/dist/strategy/index.d.ts.map +1 -0
- package/dist/strategy/index.js +5 -0
- package/dist/strategy/index.js.map +1 -0
- package/dist/test/helpers.d.ts +8 -0
- package/dist/test/helpers.d.ts.map +1 -0
- package/dist/test/helpers.js +33 -0
- package/dist/test/helpers.js.map +1 -0
- package/dist/utils/ExplorerClient.d.ts +14 -0
- package/dist/utils/ExplorerClient.d.ts.map +1 -0
- package/dist/utils/ExplorerClient.js +82 -0
- package/dist/utils/ExplorerClient.js.map +1 -0
- package/dist/utils/balanceUtils.d.ts +13 -0
- package/dist/utils/balanceUtils.d.ts.map +1 -0
- package/dist/utils/balanceUtils.js +43 -0
- package/dist/utils/balanceUtils.js.map +1 -0
- package/dist/utils/balanceUtils.test.d.ts +2 -0
- package/dist/utils/balanceUtils.test.d.ts.map +1 -0
- package/dist/utils/balanceUtils.test.js +54 -0
- package/dist/utils/balanceUtils.test.js.map +1 -0
- package/dist/utils/bridgeUtils.d.ts +19 -0
- package/dist/utils/bridgeUtils.d.ts.map +1 -0
- package/dist/utils/bridgeUtils.js +20 -0
- package/dist/utils/bridgeUtils.js.map +1 -0
- package/dist/utils/bridgeUtils.test.d.ts +2 -0
- package/dist/utils/bridgeUtils.test.d.ts.map +1 -0
- package/dist/utils/bridgeUtils.test.js +77 -0
- package/dist/utils/bridgeUtils.test.js.map +1 -0
- package/dist/utils/errors.d.ts +4 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +6 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/files.d.ts +35 -0
- package/dist/utils/files.d.ts.map +1 -0
- package/dist/utils/files.js +190 -0
- package/dist/utils/files.js.map +1 -0
- package/dist/utils/generalUtils.d.ts +3 -0
- package/dist/utils/generalUtils.d.ts.map +1 -0
- package/dist/utils/generalUtils.js +9 -0
- package/dist/utils/generalUtils.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/tokenUtils.d.ts +14 -0
- package/dist/utils/tokenUtils.d.ts.map +1 -0
- package/dist/utils/tokenUtils.js +21 -0
- package/dist/utils/tokenUtils.js.map +1 -0
- package/package.json +70 -0
- package/src/config/RebalancerConfig.test.ts +388 -0
- package/src/config/RebalancerConfig.ts +39 -0
- package/src/core/Rebalancer.ts +471 -0
- package/src/core/RebalancerService.ts +333 -0
- package/src/core/WithInflightGuard.test.ts +131 -0
- package/src/core/WithInflightGuard.ts +67 -0
- package/src/core/WithSemaphore.test.ts +112 -0
- package/src/core/WithSemaphore.ts +92 -0
- package/src/factories/RebalancerContextFactory.ts +210 -0
- package/src/index.ts +68 -0
- package/src/interfaces/IMetrics.ts +5 -0
- package/src/interfaces/IMonitor.ts +63 -0
- package/src/interfaces/IRebalancer.ts +20 -0
- package/src/interfaces/IStrategy.ts +13 -0
- package/src/metrics/Metrics.ts +558 -0
- package/src/metrics/PriceGetter.ts +74 -0
- package/src/metrics/scripts/metrics.ts +298 -0
- package/src/metrics/types.ts +27 -0
- package/src/metrics/utils/metrics.ts +33 -0
- package/src/monitor/Monitor.ts +174 -0
- package/src/service.ts +154 -0
- package/src/strategy/BaseStrategy.ts +210 -0
- package/src/strategy/MinAmountStrategy.test.ts +625 -0
- package/src/strategy/MinAmountStrategy.ts +170 -0
- package/src/strategy/StrategyFactory.test.ts +109 -0
- package/src/strategy/StrategyFactory.ts +48 -0
- package/src/strategy/WeightedStrategy.test.ts +408 -0
- package/src/strategy/WeightedStrategy.ts +93 -0
- package/src/strategy/index.ts +4 -0
- package/src/test/helpers.ts +46 -0
- package/src/utils/ExplorerClient.ts +99 -0
- package/src/utils/balanceUtils.test.ts +74 -0
- package/src/utils/balanceUtils.ts +69 -0
- package/src/utils/bridgeUtils.test.ts +92 -0
- package/src/utils/bridgeUtils.ts +42 -0
- package/src/utils/errors.ts +5 -0
- package/src/utils/files.ts +276 -0
- package/src/utils/generalUtils.ts +13 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/tokenUtils.ts +26 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base abstract class for rebalancing strategies
|
|
3
|
+
*/
|
|
4
|
+
export class BaseStrategy {
|
|
5
|
+
chains;
|
|
6
|
+
metrics;
|
|
7
|
+
logger;
|
|
8
|
+
constructor(chains, logger, metrics) {
|
|
9
|
+
// Rebalancing makes sense only with more than one chain.
|
|
10
|
+
if (chains.length < 2) {
|
|
11
|
+
throw new Error('At least two chains must be configured');
|
|
12
|
+
}
|
|
13
|
+
this.chains = chains;
|
|
14
|
+
this.logger = logger;
|
|
15
|
+
this.metrics = metrics;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Main method to get rebalancing routes
|
|
19
|
+
*/
|
|
20
|
+
getRebalancingRoutes(rawBalances) {
|
|
21
|
+
this.logger.info({
|
|
22
|
+
context: this.constructor.name,
|
|
23
|
+
rawBalances,
|
|
24
|
+
}, 'Input rawBalances');
|
|
25
|
+
this.logger.info({
|
|
26
|
+
context: this.constructor.name,
|
|
27
|
+
}, 'Calculating rebalancing routes');
|
|
28
|
+
this.validateRawBalances(rawBalances);
|
|
29
|
+
// Get balances categorized by surplus and deficit
|
|
30
|
+
const { surpluses, deficits } = this.getCategorizedBalances(rawBalances);
|
|
31
|
+
this.logger.debug({
|
|
32
|
+
context: this.constructor.name,
|
|
33
|
+
surpluses,
|
|
34
|
+
}, 'Surpluses calculated');
|
|
35
|
+
this.logger.debug({
|
|
36
|
+
context: this.constructor.name,
|
|
37
|
+
deficits,
|
|
38
|
+
}, 'Deficits calculated');
|
|
39
|
+
// Calculate sums of surpluses and deficits
|
|
40
|
+
const totalSurplus = surpluses.reduce((sum, surplus) => sum + surplus.amount, 0n);
|
|
41
|
+
const totalDeficit = deficits.reduce((sum, deficit) => sum + deficit.amount, 0n);
|
|
42
|
+
this.logger.debug({
|
|
43
|
+
context: this.constructor.name,
|
|
44
|
+
totalSurplus: totalSurplus.toString(),
|
|
45
|
+
}, 'Total surplus calculated');
|
|
46
|
+
this.logger.debug({
|
|
47
|
+
context: this.constructor.name,
|
|
48
|
+
totalDeficit: totalDeficit.toString(),
|
|
49
|
+
}, 'Total deficit calculated');
|
|
50
|
+
// If total surplus is less than total deficit, scale down deficits proportionally
|
|
51
|
+
if (totalSurplus < totalDeficit) {
|
|
52
|
+
this.logger.warn({
|
|
53
|
+
context: this.constructor.name,
|
|
54
|
+
totalSurplus: totalSurplus.toString(),
|
|
55
|
+
totalDeficit: totalDeficit.toString(),
|
|
56
|
+
}, 'Deficits are greater than surpluses. Scaling deficits');
|
|
57
|
+
// we consider this a failure because we cannot rebalance the route completely
|
|
58
|
+
// however we can still transfer some amount of the deficit to reduce the imbalances
|
|
59
|
+
this.metrics?.recordRebalancerFailure();
|
|
60
|
+
for (const deficit of deficits) {
|
|
61
|
+
const newAmount = (deficit.amount * totalSurplus) / totalDeficit;
|
|
62
|
+
deficit.amount = newAmount;
|
|
63
|
+
}
|
|
64
|
+
this.logger.debug({
|
|
65
|
+
context: this.constructor.name,
|
|
66
|
+
deficits,
|
|
67
|
+
}, 'Scaled deficits');
|
|
68
|
+
}
|
|
69
|
+
// Sort from largest to smallest amounts as to always transfer largest amounts
|
|
70
|
+
// first and decrease the amount of routes required
|
|
71
|
+
surpluses.sort((a, b) => (a.amount > b.amount ? -1 : 1));
|
|
72
|
+
deficits.sort((a, b) => (a.amount > b.amount ? -1 : 1));
|
|
73
|
+
const routes = [];
|
|
74
|
+
// Transfer from surplus to deficit until all deficits are balanced.
|
|
75
|
+
while (deficits.length > 0 && surpluses.length > 0) {
|
|
76
|
+
const surplus = surpluses[0];
|
|
77
|
+
const deficit = deficits[0];
|
|
78
|
+
// Transfers the whole surplus or just the amount to balance the deficit
|
|
79
|
+
const transferAmount = surplus.amount > deficit.amount ? deficit.amount : surplus.amount;
|
|
80
|
+
// Creates the balancing route
|
|
81
|
+
routes.push({
|
|
82
|
+
origin: surplus.chain,
|
|
83
|
+
destination: deficit.chain,
|
|
84
|
+
amount: transferAmount,
|
|
85
|
+
});
|
|
86
|
+
// Decreases the amounts for the following iterations
|
|
87
|
+
deficit.amount -= transferAmount;
|
|
88
|
+
surplus.amount -= transferAmount;
|
|
89
|
+
// Removes the deficit if it is fully balanced
|
|
90
|
+
if (!deficit.amount) {
|
|
91
|
+
deficits.shift();
|
|
92
|
+
}
|
|
93
|
+
// Removes the surplus if it has been drained
|
|
94
|
+
if (!surplus.amount) {
|
|
95
|
+
surpluses.shift();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
this.logger.debug({
|
|
99
|
+
context: this.constructor.name,
|
|
100
|
+
routes,
|
|
101
|
+
}, 'Generated routes');
|
|
102
|
+
this.logger.info({
|
|
103
|
+
context: this.constructor.name,
|
|
104
|
+
numberOfRoutes: routes.length,
|
|
105
|
+
}, 'Found rebalancing routes');
|
|
106
|
+
return routes;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Validates the raw balances against the chains configuration
|
|
110
|
+
*/
|
|
111
|
+
validateRawBalances(rawBalances) {
|
|
112
|
+
const rawBalancesChains = Object.keys(rawBalances);
|
|
113
|
+
if (this.chains.length !== rawBalancesChains.length) {
|
|
114
|
+
throw new Error('Config chains do not match raw balances chains length');
|
|
115
|
+
}
|
|
116
|
+
for (const chain of this.chains) {
|
|
117
|
+
const balance = rawBalances[chain];
|
|
118
|
+
if (balance === undefined) {
|
|
119
|
+
throw new Error(`Raw balance for chain ${chain} not found`);
|
|
120
|
+
}
|
|
121
|
+
if (balance < 0n) {
|
|
122
|
+
throw new Error(`Raw balance for chain ${chain} is negative`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=BaseStrategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseStrategy.js","sourceRoot":"","sources":["../../src/strategy/BaseStrategy.ts"],"names":[],"mappings":"AAaA;;GAEG;AACH,MAAM,OAAgB,YAAY;IACb,MAAM,CAAc;IACpB,OAAO,CAAW;IAClB,MAAM,CAAS;IAElC,YAAY,MAAmB,EAAE,MAAc,EAAE,OAAiB;QAChE,yDAAyD;QACzD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,oBAAoB,CAAC,WAAwB;QAC3C,IAAI,CAAC,MAAM,CAAC,IAAI,CACd;YACE,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;YAC9B,WAAW;SACZ,EACD,mBAAmB,CACpB,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,IAAI,CACd;YACE,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;SAC/B,EACD,gCAAgC,CACjC,CAAC;QACF,IAAI,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;QAEtC,kDAAkD;QAClD,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,sBAAsB,CAAC,WAAW,CAAC,CAAC;QAEzE,IAAI,CAAC,MAAM,CAAC,KAAK,CACf;YACE,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;YAC9B,SAAS;SACV,EACD,sBAAsB,CACvB,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,KAAK,CACf;YACE,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;YAC9B,QAAQ;SACT,EACD,qBAAqB,CACtB,CAAC;QAEF,2CAA2C;QAC3C,MAAM,YAAY,GAAG,SAAS,CAAC,MAAM,CACnC,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,GAAG,OAAO,CAAC,MAAM,EACtC,EAAE,CACH,CAAC;QACF,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAClC,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,GAAG,OAAO,CAAC,MAAM,EACtC,EAAE,CACH,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,KAAK,CACf;YACE,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;YAC9B,YAAY,EAAE,YAAY,CAAC,QAAQ,EAAE;SACtC,EACD,0BAA0B,CAC3B,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,KAAK,CACf;YACE,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;YAC9B,YAAY,EAAE,YAAY,CAAC,QAAQ,EAAE;SACtC,EACD,0BAA0B,CAC3B,CAAC;QAEF,kFAAkF;QAClF,IAAI,YAAY,GAAG,YAAY,EAAE,CAAC;YAChC,IAAI,CAAC,MAAM,CAAC,IAAI,CACd;gBACE,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;gBAC9B,YAAY,EAAE,YAAY,CAAC,QAAQ,EAAE;gBACrC,YAAY,EAAE,YAAY,CAAC,QAAQ,EAAE;aACtC,EACD,uDAAuD,CACxD,CAAC;YAEF,8EAA8E;YAC9E,oFAAoF;YACpF,IAAI,CAAC,OAAO,EAAE,uBAAuB,EAAE,CAAC;YAExC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC/B,MAAM,SAAS,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,YAAY,CAAC,GAAG,YAAY,CAAC;gBAEjE,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;YAC7B,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,KAAK,CACf;gBACE,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;gBAC9B,QAAQ;aACT,EACD,iBAAiB,CAClB,CAAC;QACJ,CAAC;QAED,8EAA8E;QAC9E,mDAAmD;QACnD,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACzD,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAExD,MAAM,MAAM,GAAuB,EAAE,CAAC;QAEtC,oEAAoE;QACpE,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnD,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;YAC7B,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;YAE5B,wEAAwE;YACxE,MAAM,cAAc,GAClB,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;YAEpE,8BAA8B;YAC9B,MAAM,CAAC,IAAI,CAAC;gBACV,MAAM,EAAE,OAAO,CAAC,KAAK;gBACrB,WAAW,EAAE,OAAO,CAAC,KAAK;gBAC1B,MAAM,EAAE,cAAc;aACvB,CAAC,CAAC;YAEH,qDAAqD;YACrD,OAAO,CAAC,MAAM,IAAI,cAAc,CAAC;YACjC,OAAO,CAAC,MAAM,IAAI,cAAc,CAAC;YAEjC,8CAA8C;YAC9C,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBACpB,QAAQ,CAAC,KAAK,EAAE,CAAC;YACnB,CAAC;YAED,6CAA6C;YAC7C,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBACpB,SAAS,CAAC,KAAK,EAAE,CAAC;YACpB,CAAC;QACH,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,KAAK,CACf;YACE,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;YAC9B,MAAM;SACP,EACD,kBAAkB,CACnB,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,IAAI,CACd;YACE,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;YAC9B,cAAc,EAAE,MAAM,CAAC,MAAM;SAC9B,EACD,0BAA0B,CAC3B,CAAC;QACF,OAAO,MAAM,CAAC;IAChB,CAAC;IAWD;;OAEG;IACO,mBAAmB,CAAC,WAAwB;QACpD,MAAM,iBAAiB,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAEnD,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,iBAAiB,CAAC,MAAM,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC3E,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChC,MAAM,OAAO,GAAuB,WAAW,CAAC,KAAK,CAAC,CAAC;YAEvD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC1B,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,YAAY,CAAC,CAAC;YAC9D,CAAC;YAED,IAAI,OAAO,GAAG,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,cAAc,CAAC,CAAC;YAChE,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Logger } from 'pino';
|
|
2
|
+
import { type ChainMap, type MinAmountStrategyConfig, type Token } from '@hyperlane-xyz/sdk';
|
|
3
|
+
import type { RawBalances } from '../interfaces/IStrategy.js';
|
|
4
|
+
import { Metrics } from '../metrics/Metrics.js';
|
|
5
|
+
import { BaseStrategy, type Delta } from './BaseStrategy.js';
|
|
6
|
+
/**
|
|
7
|
+
* Strategy implementation that rebalance based on minimum amounts
|
|
8
|
+
* It ensures each chain has at least the specified minimum amount
|
|
9
|
+
*/
|
|
10
|
+
export declare class MinAmountStrategy extends BaseStrategy {
|
|
11
|
+
private readonly tokensByChainName;
|
|
12
|
+
private readonly config;
|
|
13
|
+
protected readonly logger: Logger;
|
|
14
|
+
constructor(config: MinAmountStrategyConfig, tokensByChainName: ChainMap<Token>, initialTotalCollateral: bigint, logger: Logger, metrics?: Metrics);
|
|
15
|
+
/**
|
|
16
|
+
* Gets balances categorized by surplus and deficit based on minimum amounts and targets
|
|
17
|
+
* - For absolute values: Uses exact token amounts
|
|
18
|
+
* - For relative values: Uses percentages of total balance across all chains
|
|
19
|
+
*/
|
|
20
|
+
protected getCategorizedBalances(rawBalances: RawBalances): {
|
|
21
|
+
surpluses: Delta[];
|
|
22
|
+
deficits: Delta[];
|
|
23
|
+
};
|
|
24
|
+
protected getTokenByChainName(chainName: string): Token;
|
|
25
|
+
private validateAmounts;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=MinAmountStrategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MinAmountStrategy.d.ts","sourceRoot":"","sources":["../../src/strategy/MinAmountStrategy.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAE9B,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,uBAAuB,EAE5B,KAAK,KAAK,EACX,MAAM,oBAAoB,CAAC;AAG5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhD,OAAO,EAAE,YAAY,EAAE,KAAK,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE7D;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,YAAY;IAM/C,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IALpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+B;IACtD,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAGhC,MAAM,EAAE,uBAAuB,EACd,iBAAiB,EAAE,QAAQ,CAAC,KAAK,CAAC,EACnD,sBAAsB,EAAE,MAAM,EAC9B,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,OAAO;IAqCnB;;;;OAIG;IACH,SAAS,CAAC,sBAAsB,CAAC,WAAW,EAAE,WAAW,GAAG;QAC1D,SAAS,EAAE,KAAK,EAAE,CAAC;QACnB,QAAQ,EAAE,KAAK,EAAE,CAAC;KACnB;IAmDD,SAAS,CAAC,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,KAAK;IAUvD,OAAO,CAAC,eAAe;CAkCxB"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { BigNumber } from 'bignumber.js';
|
|
2
|
+
import { RebalancerMinAmountType, } from '@hyperlane-xyz/sdk';
|
|
3
|
+
import { fromWei, toWei } from '@hyperlane-xyz/utils';
|
|
4
|
+
import { BaseStrategy } from './BaseStrategy.js';
|
|
5
|
+
/**
|
|
6
|
+
* Strategy implementation that rebalance based on minimum amounts
|
|
7
|
+
* It ensures each chain has at least the specified minimum amount
|
|
8
|
+
*/
|
|
9
|
+
export class MinAmountStrategy extends BaseStrategy {
|
|
10
|
+
tokensByChainName;
|
|
11
|
+
config = {};
|
|
12
|
+
logger;
|
|
13
|
+
constructor(config, tokensByChainName, initialTotalCollateral, logger, metrics) {
|
|
14
|
+
const chains = Object.keys(config);
|
|
15
|
+
const log = logger.child({ class: MinAmountStrategy.name });
|
|
16
|
+
super(chains, log, metrics);
|
|
17
|
+
this.tokensByChainName = tokensByChainName;
|
|
18
|
+
this.logger = log;
|
|
19
|
+
const minAmountType = config[chains[0]].minAmount.type;
|
|
20
|
+
this.validateAmounts(initialTotalCollateral, minAmountType, config);
|
|
21
|
+
for (const chain of chains) {
|
|
22
|
+
const { min, target } = config[chain].minAmount;
|
|
23
|
+
// check range constraints
|
|
24
|
+
if (BigNumber(target).lt(min)) {
|
|
25
|
+
throw new Error(`Target (${target}) must be greater than or equal to min (${min}) for chain ${chain}`);
|
|
26
|
+
}
|
|
27
|
+
if (BigNumber(min).lt(0)) {
|
|
28
|
+
throw new Error(`Minimum amount (${min}) cannot be negative for chain ${chain}`);
|
|
29
|
+
}
|
|
30
|
+
if (BigNumber(target).lt(0)) {
|
|
31
|
+
throw new Error(`Target amount (${target}) cannot be negative for chain ${chain}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
this.config = config;
|
|
35
|
+
this.logger.info('MinAmountStrategy created');
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Gets balances categorized by surplus and deficit based on minimum amounts and targets
|
|
39
|
+
* - For absolute values: Uses exact token amounts
|
|
40
|
+
* - For relative values: Uses percentages of total balance across all chains
|
|
41
|
+
*/
|
|
42
|
+
getCategorizedBalances(rawBalances) {
|
|
43
|
+
const totalCollateral = this.chains.reduce((sum, chain) => sum + rawBalances[chain], 0n);
|
|
44
|
+
return this.chains.reduce((acc, chain) => {
|
|
45
|
+
const config = this.config[chain];
|
|
46
|
+
const balance = rawBalances[chain];
|
|
47
|
+
let minAmount;
|
|
48
|
+
let targetAmount;
|
|
49
|
+
if (config.minAmount.type === RebalancerMinAmountType.Absolute) {
|
|
50
|
+
const token = this.getTokenByChainName(chain);
|
|
51
|
+
minAmount = BigInt(toWei(config.minAmount.min, token.decimals));
|
|
52
|
+
targetAmount = BigInt(toWei(config.minAmount.target, token.decimals));
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
minAmount = BigInt(BigNumber(totalCollateral.toString())
|
|
56
|
+
.times(config.minAmount.min)
|
|
57
|
+
.toFixed(0, BigNumber.ROUND_FLOOR));
|
|
58
|
+
targetAmount = BigInt(BigNumber(totalCollateral.toString())
|
|
59
|
+
.times(config.minAmount.target)
|
|
60
|
+
.toFixed(0, BigNumber.ROUND_FLOOR));
|
|
61
|
+
}
|
|
62
|
+
// If balance is less than minAmount, it has a deficit
|
|
63
|
+
if (balance < minAmount) {
|
|
64
|
+
acc.deficits.push({ chain, amount: targetAmount - balance });
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
// Any chain with more than minAmount potentially has surplus
|
|
68
|
+
const surplus = balance - minAmount;
|
|
69
|
+
if (surplus > 0n) {
|
|
70
|
+
acc.surpluses.push({ chain, amount: surplus });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return acc;
|
|
74
|
+
}, {
|
|
75
|
+
surpluses: [],
|
|
76
|
+
deficits: [],
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
getTokenByChainName(chainName) {
|
|
80
|
+
const token = this.tokensByChainName[chainName];
|
|
81
|
+
if (token === undefined) {
|
|
82
|
+
throw new Error(`Token not found for chain ${chainName}`);
|
|
83
|
+
}
|
|
84
|
+
return token;
|
|
85
|
+
}
|
|
86
|
+
validateAmounts(totalCollateral, minAmountType, config) {
|
|
87
|
+
config ??= this.config;
|
|
88
|
+
if (minAmountType === RebalancerMinAmountType.Absolute) {
|
|
89
|
+
let totalTargets = 0n;
|
|
90
|
+
let decimals = 0;
|
|
91
|
+
for (const chainName of this.chains) {
|
|
92
|
+
const token = this.getTokenByChainName(chainName);
|
|
93
|
+
// all the tokens have the same amount of decimals
|
|
94
|
+
decimals = token.decimals;
|
|
95
|
+
totalTargets += BigInt(toWei(config[chainName].minAmount.target, token.decimals));
|
|
96
|
+
}
|
|
97
|
+
if (totalTargets > totalCollateral) {
|
|
98
|
+
throw new Error(`Consider reducing the targets as the sum (${fromWei(totalTargets.toString(), decimals)}) is greater than sum of collaterals (${fromWei(totalCollateral.toString(), decimals)})`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=MinAmountStrategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MinAmountStrategy.js","sourceRoot":"","sources":["../../src/strategy/MinAmountStrategy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MinAmountStrategy.test.d.ts","sourceRoot":"","sources":["../../src/strategy/MinAmountStrategy.test.ts"],"names":[],"mappings":""}
|