@strkfarm/sdk 2.0.0-dev.28 → 2.0.0-dev.29
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/index.browser.global.js +1938 -771
- package/dist/index.browser.mjs +1960 -791
- package/dist/index.d.ts +343 -124
- package/dist/index.js +1971 -794
- package/dist/index.mjs +1963 -791
- package/package.json +1 -1
- package/src/dataTypes/bignumber.browser.ts +6 -1
- package/src/dataTypes/bignumber.node.ts +5 -1
- package/src/interfaces/common.tsx +8 -1
- package/src/strategies/universal-adapters/baseAdapter.ts +1 -1
- package/src/strategies/universal-adapters/extended-adapter.ts +7 -7
- package/src/strategies/universal-adapters/index.ts +2 -1
- package/src/strategies/universal-adapters/svk-troves-adapter.ts +364 -0
- package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +88 -34
- package/src/strategies/vesu-extended-strategy/services/executionService.ts +36 -55
- package/src/strategies/vesu-extended-strategy/services/extended-vesu-state-manager.ts +1553 -538
- package/src/strategies/vesu-extended-strategy/services/ltv-imbalance-rebalance-math.ts +730 -0
- package/src/strategies/vesu-extended-strategy/services/operationService.ts +4 -3
- package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +27 -83
- package/src/utils/index.ts +1 -0
package/dist/index.js
CHANGED
|
@@ -50,11 +50,13 @@ __export(index_exports, {
|
|
|
50
50
|
BaseAdapter: () => BaseAdapter,
|
|
51
51
|
BaseStrategy: () => BaseStrategy,
|
|
52
52
|
CASE_ROUTE_TYPES: () => CASE_ROUTE_TYPES,
|
|
53
|
+
COLLATERAL_PRECISION: () => COLLATERAL_PRECISION,
|
|
53
54
|
CaseCategory: () => CaseCategory,
|
|
54
55
|
CaseId: () => CaseId,
|
|
55
56
|
CommonAdapter: () => CommonAdapter,
|
|
56
57
|
ContractAddr: () => ContractAddr,
|
|
57
58
|
CycleType: () => CycleType,
|
|
59
|
+
DEFAULT_TROVES_STRATEGIES_API: () => DEFAULT_TROVES_STRATEGIES_API,
|
|
58
60
|
Deployer: () => deployer_default,
|
|
59
61
|
ERC20: () => ERC20,
|
|
60
62
|
EXTENDED_CONTRACT: () => EXTENDED_CONTRACT,
|
|
@@ -73,6 +75,7 @@ __export(index_exports, {
|
|
|
73
75
|
FatalError: () => FatalError,
|
|
74
76
|
FlowChartColors: () => FlowChartColors,
|
|
75
77
|
Global: () => Global,
|
|
78
|
+
HealthFactorMath: () => HealthFactorMath,
|
|
76
79
|
HyperLSTStrategies: () => HyperLSTStrategies,
|
|
77
80
|
ILending: () => ILending,
|
|
78
81
|
Initializable: () => Initializable,
|
|
@@ -113,6 +116,7 @@ __export(index_exports, {
|
|
|
113
116
|
StrategyLiveStatus: () => StrategyLiveStatus,
|
|
114
117
|
StrategyTag: () => StrategyTag,
|
|
115
118
|
StrategyType: () => StrategyType,
|
|
119
|
+
SvkTrovesAdapter: () => SvkTrovesAdapter,
|
|
116
120
|
TRANSFER_SANITIZER: () => TRANSFER_SANITIZER,
|
|
117
121
|
TelegramGroupNotif: () => TelegramGroupNotif,
|
|
118
122
|
TelegramNotif: () => TelegramNotif,
|
|
@@ -162,6 +166,7 @@ __export(index_exports, {
|
|
|
162
166
|
createEkuboCLStrategy: () => createEkuboCLStrategy,
|
|
163
167
|
createHyperLSTStrategy: () => createHyperLSTStrategy,
|
|
164
168
|
createSenseiStrategy: () => createSenseiStrategy,
|
|
169
|
+
createSolveBudgetFromRawState: () => createSolveBudgetFromRawState,
|
|
165
170
|
createStrategy: () => createStrategy,
|
|
166
171
|
createUniversalStrategy: () => createUniversalStrategy2,
|
|
167
172
|
createVesuRebalanceStrategy: () => createVesuRebalanceStrategy2,
|
|
@@ -291,6 +296,9 @@ var Web3Number = class _Web3Number2 extends _Web3Number {
|
|
|
291
296
|
const bn = new _Web3Number2(weiNumber, decimals).dividedBy(10 ** decimals);
|
|
292
297
|
return new _Web3Number2(bn.toString(), decimals);
|
|
293
298
|
}
|
|
299
|
+
static fromNumber(number, decimals) {
|
|
300
|
+
return new _Web3Number2(number.toString(), decimals);
|
|
301
|
+
}
|
|
294
302
|
[import_util.default.inspect.custom](depth, opts) {
|
|
295
303
|
return this.toString();
|
|
296
304
|
}
|
|
@@ -1884,6 +1892,48 @@ _StarknetCallParser.METHOD_BY_SELECTOR = new Map(
|
|
|
1884
1892
|
);
|
|
1885
1893
|
var StarknetCallParser = _StarknetCallParser;
|
|
1886
1894
|
|
|
1895
|
+
// src/utils/health-factor-math.ts
|
|
1896
|
+
var HealthFactorMath = class {
|
|
1897
|
+
static getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
1898
|
+
const numerator = debtAmount.multipliedBy(debtPrice).multipliedBy(targetHF);
|
|
1899
|
+
const denominator = collateralPrice * maxLTV;
|
|
1900
|
+
const collateralAmount = numerator.dividedBy(denominator);
|
|
1901
|
+
const netCollateral = new Web3Number(collateralAmount.toString(), collateralTokenInfo.decimals);
|
|
1902
|
+
return netCollateral;
|
|
1903
|
+
}
|
|
1904
|
+
static getMinCollateralRequiredOnLooping(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
1905
|
+
const netCollateral = this.getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo);
|
|
1906
|
+
const collateralFromDebt = new Web3Number(debtAmount.multipliedBy(debtPrice).dividedBy(collateralPrice).toString(), collateralTokenInfo.decimals);
|
|
1907
|
+
return netCollateral.minus(collateralFromDebt);
|
|
1908
|
+
}
|
|
1909
|
+
static getHealthFactor(collateralAmount, collateralPrice, maxLTV, debtAmount, debtPrice) {
|
|
1910
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
1911
|
+
const denominator = debtAmount.multipliedBy(debtPrice);
|
|
1912
|
+
const healthFactor = numerator.dividedBy(denominator);
|
|
1913
|
+
return healthFactor.toNumber();
|
|
1914
|
+
}
|
|
1915
|
+
static getMaxDebtAmountOnLooping(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
1916
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
1917
|
+
logger.verbose(`HealthFactorMath: Max debt amount on looping numerator: ${numerator.toNumber()}, collateralAmount: ${collateralAmount.toNumber()}, collateralPrice: ${collateralPrice}, maxLTV: ${maxLTV}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
|
|
1918
|
+
const denominator = targetHF - maxLTV;
|
|
1919
|
+
logger.verbose(`HealthFactorMath: Max debt amount on looping denominator: ${denominator}`);
|
|
1920
|
+
const debtAmountUSD = numerator.dividedBy(denominator);
|
|
1921
|
+
logger.verbose(`HealthFactorMath: Max debt amount on looping debtAmountUSD: ${debtAmountUSD.toNumber()}`);
|
|
1922
|
+
const debtAmount = debtAmountUSD.dividedBy(debtPrice);
|
|
1923
|
+
logger.verbose(`HealthFactorMath: Max debt amount on looping debtAmount: ${debtAmount.toNumber()}`);
|
|
1924
|
+
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
1925
|
+
}
|
|
1926
|
+
static getMaxDebtAmount(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
1927
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
1928
|
+
logger.verbose(`HealthFactorMath: Max debt amount numerator: ${numerator.toNumber()}, collateralAmount: ${collateralAmount.toNumber()}, collateralPrice: ${collateralPrice}, maxLTV: ${maxLTV}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
|
|
1929
|
+
const denominator = targetHF * debtPrice;
|
|
1930
|
+
logger.verbose(`HealthFactorMath: Max debt amount denominator: ${denominator}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
|
|
1931
|
+
const debtAmount = numerator.dividedBy(denominator);
|
|
1932
|
+
logger.verbose(`HealthFactorMath: Max debt amount: ${debtAmount.toNumber()}, numerator: ${numerator.toNumber()}, denominator: ${denominator}`);
|
|
1933
|
+
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
1934
|
+
}
|
|
1935
|
+
};
|
|
1936
|
+
|
|
1887
1937
|
// src/utils/index.ts
|
|
1888
1938
|
function assert(condition, message) {
|
|
1889
1939
|
if (!condition) {
|
|
@@ -4283,6 +4333,9 @@ var Web3Number2 = class _Web3Number2 extends _Web3Number {
|
|
|
4283
4333
|
const bn = new _Web3Number2(weiNumber, decimals).dividedBy(10 ** decimals);
|
|
4284
4334
|
return new _Web3Number2(bn.toString(), decimals);
|
|
4285
4335
|
}
|
|
4336
|
+
static fromNumber(number, decimals) {
|
|
4337
|
+
return new _Web3Number2(number.toString(), decimals);
|
|
4338
|
+
}
|
|
4286
4339
|
};
|
|
4287
4340
|
|
|
4288
4341
|
// src/interfaces/lending.ts
|
|
@@ -6457,6 +6510,10 @@ var VaultProtocol = {
|
|
|
6457
6510
|
name: "Vault",
|
|
6458
6511
|
logo: ""
|
|
6459
6512
|
};
|
|
6513
|
+
var TrovesProtocol = {
|
|
6514
|
+
name: "Troves",
|
|
6515
|
+
logo: "https://app.troves.fi/favicon.ico"
|
|
6516
|
+
};
|
|
6460
6517
|
var Protocols = {
|
|
6461
6518
|
NONE: NoneProtocol,
|
|
6462
6519
|
VESU: VesuProtocol,
|
|
@@ -6464,7 +6521,8 @@ var Protocols = {
|
|
|
6464
6521
|
EXTENDED: ExtendedProtocol,
|
|
6465
6522
|
EKUBO: EkuboProtocol,
|
|
6466
6523
|
AVNU: AvnuProtocol,
|
|
6467
|
-
VAULT: VaultProtocol
|
|
6524
|
+
VAULT: VaultProtocol,
|
|
6525
|
+
TROVES: TrovesProtocol
|
|
6468
6526
|
};
|
|
6469
6527
|
|
|
6470
6528
|
// src/interfaces/initializable.ts
|
|
@@ -34195,48 +34253,6 @@ var AbisConfig = {
|
|
|
34195
34253
|
}
|
|
34196
34254
|
};
|
|
34197
34255
|
|
|
34198
|
-
// src/utils/health-factor-math.ts
|
|
34199
|
-
var HealthFactorMath = class {
|
|
34200
|
-
static getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
34201
|
-
const numerator = debtAmount.multipliedBy(debtPrice).multipliedBy(targetHF);
|
|
34202
|
-
const denominator = collateralPrice * maxLTV;
|
|
34203
|
-
const collateralAmount = numerator.dividedBy(denominator);
|
|
34204
|
-
const netCollateral = new Web3Number(collateralAmount.toString(), collateralTokenInfo.decimals);
|
|
34205
|
-
return netCollateral;
|
|
34206
|
-
}
|
|
34207
|
-
static getMinCollateralRequiredOnLooping(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
34208
|
-
const netCollateral = this.getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo);
|
|
34209
|
-
const collateralFromDebt = new Web3Number(debtAmount.multipliedBy(debtPrice).dividedBy(collateralPrice).toString(), collateralTokenInfo.decimals);
|
|
34210
|
-
return netCollateral.minus(collateralFromDebt);
|
|
34211
|
-
}
|
|
34212
|
-
static getHealthFactor(collateralAmount, collateralPrice, maxLTV, debtAmount, debtPrice) {
|
|
34213
|
-
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
34214
|
-
const denominator = debtAmount.multipliedBy(debtPrice);
|
|
34215
|
-
const healthFactor = numerator.dividedBy(denominator);
|
|
34216
|
-
return healthFactor.toNumber();
|
|
34217
|
-
}
|
|
34218
|
-
static getMaxDebtAmountOnLooping(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
34219
|
-
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
34220
|
-
logger.verbose(`HealthFactorMath: Max debt amount on looping numerator: ${numerator.toNumber()}, collateralAmount: ${collateralAmount.toNumber()}, collateralPrice: ${collateralPrice}, maxLTV: ${maxLTV}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
|
|
34221
|
-
const denominator = targetHF - maxLTV;
|
|
34222
|
-
logger.verbose(`HealthFactorMath: Max debt amount on looping denominator: ${denominator}`);
|
|
34223
|
-
const debtAmountUSD = numerator.dividedBy(denominator);
|
|
34224
|
-
logger.verbose(`HealthFactorMath: Max debt amount on looping debtAmountUSD: ${debtAmountUSD.toNumber()}`);
|
|
34225
|
-
const debtAmount = debtAmountUSD.dividedBy(debtPrice);
|
|
34226
|
-
logger.verbose(`HealthFactorMath: Max debt amount on looping debtAmount: ${debtAmount.toNumber()}`);
|
|
34227
|
-
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
34228
|
-
}
|
|
34229
|
-
static getMaxDebtAmount(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
34230
|
-
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
34231
|
-
logger.verbose(`HealthFactorMath: Max debt amount numerator: ${numerator.toNumber()}, collateralAmount: ${collateralAmount.toNumber()}, collateralPrice: ${collateralPrice}, maxLTV: ${maxLTV}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
|
|
34232
|
-
const denominator = targetHF * debtPrice;
|
|
34233
|
-
logger.verbose(`HealthFactorMath: Max debt amount denominator: ${denominator}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
|
|
34234
|
-
const debtAmount = numerator.dividedBy(denominator);
|
|
34235
|
-
logger.verbose(`HealthFactorMath: Max debt amount: ${debtAmount.toNumber()}, numerator: ${numerator.toNumber()}, denominator: ${denominator}`);
|
|
34236
|
-
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
34237
|
-
}
|
|
34238
|
-
};
|
|
34239
|
-
|
|
34240
34256
|
// src/strategies/vesu-extended-strategy/utils/helper.ts
|
|
34241
34257
|
var returnFormattedAmount = (amount, toTokenDecimals) => {
|
|
34242
34258
|
const formattedAmount = "0x" + BigInt(Math.floor(amount * 10 ** toTokenDecimals)).toString(16);
|
|
@@ -34879,6 +34895,7 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34879
34895
|
const collateralToken = this.config.collateral;
|
|
34880
34896
|
const debtToken = this.config.debt;
|
|
34881
34897
|
const { contract: multiplyContract } = this._getMultiplyContract();
|
|
34898
|
+
this.lastSwapPriceInfo = null;
|
|
34882
34899
|
const {
|
|
34883
34900
|
existingCollateralInfo,
|
|
34884
34901
|
existingDebtInfo,
|
|
@@ -34915,9 +34932,15 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34915
34932
|
let marginSwapLimitAmount = Web3Number.fromWei(0, collateralToken.decimals);
|
|
34916
34933
|
let addedCollateral = params.amount;
|
|
34917
34934
|
let approveAmount = params.amount;
|
|
34935
|
+
let aggregatedFromAmount = 0;
|
|
34936
|
+
let aggregatedToAmount = 0;
|
|
34937
|
+
let aggregatedFromSymbol = debtToken.symbol;
|
|
34938
|
+
const aggregatedToSymbol = collateralToken.symbol;
|
|
34939
|
+
let executedSwapCount = 0;
|
|
34918
34940
|
if (params.marginSwap) {
|
|
34919
34941
|
const marginToken = params.marginSwap.marginToken;
|
|
34920
34942
|
const requiredAmount = params.amount;
|
|
34943
|
+
assert(marginToken.address.eq(debtToken.address), "Margin token must be the same as debt token");
|
|
34921
34944
|
const marginSwapQuote = await ekuboQuoter.getQuoteExactOutput(
|
|
34922
34945
|
marginToken.address.address,
|
|
34923
34946
|
collateralToken.address.address,
|
|
@@ -34933,6 +34956,11 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34933
34956
|
marginToken,
|
|
34934
34957
|
collateralToken
|
|
34935
34958
|
);
|
|
34959
|
+
const marginSwapInputAmount = Web3Number.fromWei(marginSwapQuote.total_calculated, marginToken.decimals).abs().toNumber();
|
|
34960
|
+
const marginSwapOutputAmount = requiredAmount.abs().toNumber();
|
|
34961
|
+
aggregatedFromAmount += marginSwapInputAmount;
|
|
34962
|
+
aggregatedToAmount += marginSwapOutputAmount;
|
|
34963
|
+
executedSwapCount += 1;
|
|
34936
34964
|
approveAmount = Web3Number.fromWei(marginSwapQuote.total_calculated, marginToken.decimals).multipliedBy(1 + this.maxSlippage).abs();
|
|
34937
34965
|
}
|
|
34938
34966
|
let debtAmount = this._computeTargetDebtDelta(
|
|
@@ -34956,10 +34984,6 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34956
34984
|
if (!debtAmount.isZero() && debtAmount.greaterThan(0)) {
|
|
34957
34985
|
try {
|
|
34958
34986
|
let swapQuote;
|
|
34959
|
-
const debtAmountInCollateralUnits = new Web3Number(
|
|
34960
|
-
debtAmount.multipliedBy(debtPrice).dividedBy(collateralPrice).toFixed(6),
|
|
34961
|
-
collateralToken.decimals
|
|
34962
|
-
);
|
|
34963
34987
|
if (params.leverSwap?.exactOutput) {
|
|
34964
34988
|
swapQuote = await ekuboQuoter.getQuoteExactOutput(
|
|
34965
34989
|
debtToken.address.address,
|
|
@@ -34983,17 +35007,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34983
35007
|
).abs().toNumber();
|
|
34984
35008
|
const inputAmt = debtAmount.abs().toNumber();
|
|
34985
35009
|
const outputAmt = quoteOutputAmount;
|
|
34986
|
-
|
|
34987
|
-
|
|
34988
|
-
|
|
34989
|
-
toTokenSymbol: collateralToken.symbol,
|
|
34990
|
-
fromAmount: inputAmt,
|
|
34991
|
-
toAmount: outputAmt,
|
|
34992
|
-
effectivePrice: outputAmt !== 0 ? inputAmt / outputAmt : 0
|
|
34993
|
-
};
|
|
34994
|
-
logger.verbose(
|
|
34995
|
-
`${_VesuMultiplyAdapter.name}::_getIncreaseCalldata stored price info: ${inputAmt} ${debtToken.symbol} \u2192 ${outputAmt} ${collateralToken.symbol}, effectivePrice=${this.lastSwapPriceInfo.effectivePrice}`
|
|
34996
|
-
);
|
|
35010
|
+
aggregatedFromAmount += inputAmt;
|
|
35011
|
+
aggregatedToAmount += outputAmt;
|
|
35012
|
+
executedSwapCount += 1;
|
|
34997
35013
|
leverSwap = ekuboQuoter.getVesuMultiplyQuote(
|
|
34998
35014
|
swapQuote,
|
|
34999
35015
|
debtToken,
|
|
@@ -35011,6 +35027,19 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
35011
35027
|
);
|
|
35012
35028
|
}
|
|
35013
35029
|
}
|
|
35030
|
+
if (executedSwapCount > 0) {
|
|
35031
|
+
this.lastSwapPriceInfo = {
|
|
35032
|
+
source: "ekubo",
|
|
35033
|
+
fromTokenSymbol: aggregatedFromSymbol ?? debtToken.symbol,
|
|
35034
|
+
toTokenSymbol: aggregatedToSymbol,
|
|
35035
|
+
fromAmount: aggregatedFromAmount,
|
|
35036
|
+
toAmount: aggregatedToAmount,
|
|
35037
|
+
effectivePrice: aggregatedToAmount !== 0 ? aggregatedFromAmount / aggregatedToAmount : 0
|
|
35038
|
+
};
|
|
35039
|
+
logger.verbose(
|
|
35040
|
+
`${_VesuMultiplyAdapter.name}::_getIncreaseCalldata stored aggregated price info: ${aggregatedFromAmount} ${this.lastSwapPriceInfo.fromTokenSymbol} \u2192 ${aggregatedToAmount} ${aggregatedToSymbol}, effectivePrice=${this.lastSwapPriceInfo.effectivePrice}, swaps=${executedSwapCount}`
|
|
35041
|
+
);
|
|
35042
|
+
}
|
|
35014
35043
|
logger.verbose(
|
|
35015
35044
|
`${_VesuMultiplyAdapter.name}::_getIncreaseCalldata leverSwapLimitAmount: ${leverSwapLimitAmount.toWei()}`
|
|
35016
35045
|
);
|
|
@@ -35043,10 +35072,21 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
35043
35072
|
approveAmount
|
|
35044
35073
|
};
|
|
35045
35074
|
}
|
|
35075
|
+
// private _setLastSwapPriceAsNoSwap(): void {
|
|
35076
|
+
// this.lastSwapPriceInfo = {
|
|
35077
|
+
// source: "no-swap",
|
|
35078
|
+
// fromTokenSymbol: this.config.collateral.symbol,
|
|
35079
|
+
// toTokenSymbol: this.config.debt.symbol,
|
|
35080
|
+
// fromAmount: 0,
|
|
35081
|
+
// toAmount: 0,
|
|
35082
|
+
// effectivePrice: 0,
|
|
35083
|
+
// };
|
|
35084
|
+
// }
|
|
35046
35085
|
async _buildDecreaseLikeCalldata(params) {
|
|
35047
35086
|
const collateralToken = this.config.collateral;
|
|
35048
35087
|
const debtToken = this.config.debt;
|
|
35049
35088
|
const { contract: multiplyContract } = this._getMultiplyContract();
|
|
35089
|
+
this.lastSwapPriceInfo = null;
|
|
35050
35090
|
const ekuboQuoter = new EkuboQuoter(
|
|
35051
35091
|
this.config.networkConfig,
|
|
35052
35092
|
this.config.pricer
|
|
@@ -35055,6 +35095,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
35055
35095
|
let leverSwapWeights = [];
|
|
35056
35096
|
let leverSwapLimitAmount = Web3Number.fromWei(0, collateralToken.decimals);
|
|
35057
35097
|
let leverCollateralUsed = Web3Number.fromWei(0, collateralToken.decimals);
|
|
35098
|
+
let aggregatedFromAmount = 0;
|
|
35099
|
+
let aggregatedToAmount = 0;
|
|
35100
|
+
let executedSwapCount = 0;
|
|
35058
35101
|
if (params.closePosition) {
|
|
35059
35102
|
const debtQuote = await ekuboQuoter.getQuoteExactOutput(
|
|
35060
35103
|
collateralToken.address.address,
|
|
@@ -35073,6 +35116,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
35073
35116
|
collateralToken.decimals
|
|
35074
35117
|
).abs();
|
|
35075
35118
|
leverSwapLimitAmount = leverCollateralUsed.multipliedBy(1 + this.maxSlippage);
|
|
35119
|
+
aggregatedFromAmount += leverCollateralUsed.toNumber();
|
|
35120
|
+
aggregatedToAmount += params.debtToRepayAbs.abs().toNumber();
|
|
35121
|
+
executedSwapCount += 1;
|
|
35076
35122
|
} else {
|
|
35077
35123
|
if (params.collateralPrice === void 0 || params.debtPrice === void 0) {
|
|
35078
35124
|
throw new Error(
|
|
@@ -35094,17 +35140,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
35094
35140
|
leverSwapQuote.total_calculated,
|
|
35095
35141
|
debtToken.decimals
|
|
35096
35142
|
).abs().toNumber();
|
|
35097
|
-
|
|
35098
|
-
|
|
35099
|
-
|
|
35100
|
-
toTokenSymbol: debtToken.symbol,
|
|
35101
|
-
fromAmount: inputAmt,
|
|
35102
|
-
toAmount: outputAmt,
|
|
35103
|
-
effectivePrice: outputAmt !== 0 ? outputAmt / inputAmt : 0
|
|
35104
|
-
};
|
|
35105
|
-
logger.verbose(
|
|
35106
|
-
`${_VesuMultiplyAdapter.name}::_buildDecreaseLikeCalldata stored price info: ${inputAmt} ${collateralToken.symbol} \u2192 ${outputAmt} ${debtToken.symbol}, effectivePrice=${this.lastSwapPriceInfo.effectivePrice}`
|
|
35107
|
-
);
|
|
35143
|
+
aggregatedFromAmount += inputAmt;
|
|
35144
|
+
aggregatedToAmount += outputAmt;
|
|
35145
|
+
executedSwapCount += 1;
|
|
35108
35146
|
leverSwap = ekuboQuoter.getVesuMultiplyQuote(
|
|
35109
35147
|
leverSwapQuote,
|
|
35110
35148
|
collateralToken,
|
|
@@ -35127,6 +35165,7 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
35127
35165
|
);
|
|
35128
35166
|
const withdrawSwapWeights = [];
|
|
35129
35167
|
if (params.outputToken && !params.outputToken.address.eq(collateralToken.address)) {
|
|
35168
|
+
assert(params.outputToken.address.eq(debtToken.address), "Withdraw output token must be the same as debt token");
|
|
35130
35169
|
const residualCollateral = params.closePosition ? params.existingCollateral.minus(leverCollateralUsed) : params.subMargin;
|
|
35131
35170
|
const outputTokenPrice = await this.config.pricer.getPrice(params.outputToken.symbol);
|
|
35132
35171
|
if (residualCollateral.greaterThan(0)) {
|
|
@@ -35143,12 +35182,34 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
35143
35182
|
);
|
|
35144
35183
|
withdrawSwap = built.swaps;
|
|
35145
35184
|
withdrawSwapWeights.push(...built.weights);
|
|
35185
|
+
const withdrawOutputAmount = Web3Number.fromWei(
|
|
35186
|
+
withdrawQuote.total_calculated,
|
|
35187
|
+
params.outputToken.decimals
|
|
35188
|
+
).abs().toNumber();
|
|
35189
|
+
aggregatedFromAmount += residualCollateral.toNumber();
|
|
35190
|
+
aggregatedToAmount += withdrawOutputAmount;
|
|
35191
|
+
executedSwapCount += 1;
|
|
35146
35192
|
const estimatedOutput = residualCollateral.multipliedBy(params.collateralPrice).dividedBy(outputTokenPrice.price);
|
|
35147
35193
|
estimatedOutput.decimals = params.outputToken.decimals;
|
|
35148
35194
|
withdrawSwapLimitAmount = estimatedOutput.multipliedBy(1 - this.maxSlippage);
|
|
35149
35195
|
}
|
|
35150
35196
|
}
|
|
35151
35197
|
}
|
|
35198
|
+
if (executedSwapCount > 0) {
|
|
35199
|
+
this.lastSwapPriceInfo = {
|
|
35200
|
+
source: "ekubo",
|
|
35201
|
+
fromTokenSymbol: collateralToken.symbol,
|
|
35202
|
+
toTokenSymbol: debtToken.symbol,
|
|
35203
|
+
fromAmount: aggregatedFromAmount,
|
|
35204
|
+
toAmount: aggregatedToAmount,
|
|
35205
|
+
effectivePrice: aggregatedFromAmount !== 0 ? aggregatedToAmount / aggregatedFromAmount : 0
|
|
35206
|
+
};
|
|
35207
|
+
logger.verbose(
|
|
35208
|
+
`${_VesuMultiplyAdapter.name}::_buildDecreaseLikeCalldata stored aggregated price info: ${aggregatedFromAmount} ${collateralToken.symbol} \u2192 ${aggregatedToAmount} ${debtToken.symbol}, effectivePrice=${this.lastSwapPriceInfo.effectivePrice}, swaps=${executedSwapCount}`
|
|
35209
|
+
);
|
|
35210
|
+
} else {
|
|
35211
|
+
this.lastSwapPriceInfo = null;
|
|
35212
|
+
}
|
|
35152
35213
|
logger.debug(
|
|
35153
35214
|
`${_VesuMultiplyAdapter.name}::_buildDecreaseLikeCalldata leverSwapCount=${leverSwap.length}, withdrawSwapCount=${withdrawSwap.length}, withdrawSwapLimitAmount=${withdrawSwapLimitAmount.toNumber()}, subMargin=${params.subMargin.toNumber()}`
|
|
35154
35215
|
);
|
|
@@ -36336,13 +36397,13 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
36336
36397
|
this.minimumExtendedMovementAmount = this.config.minimumExtendedMovementAmount ?? 5;
|
|
36337
36398
|
this.client = client;
|
|
36338
36399
|
this.retryDelayForOrderStatus = this.config.retryDelayForOrderStatus ?? 3e3;
|
|
36339
|
-
this.
|
|
36400
|
+
this.usdcToken = this.config.supportedPositions[0].asset;
|
|
36340
36401
|
}
|
|
36341
36402
|
_depositApproveProofReadableId() {
|
|
36342
|
-
return `extended_approve_${this.
|
|
36403
|
+
return `extended_approve_${this.usdcToken.symbol}`;
|
|
36343
36404
|
}
|
|
36344
36405
|
_depositCallProofReadableId() {
|
|
36345
|
-
return `extended_deposit_${this.
|
|
36406
|
+
return `extended_deposit_${this.usdcToken.symbol}`;
|
|
36346
36407
|
}
|
|
36347
36408
|
//abstract means the method has no implementation in this class; instead, child classes must implement it.
|
|
36348
36409
|
async getAPY(supportedPosition) {
|
|
@@ -36411,7 +36472,7 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
36411
36472
|
_getDepositLeaf() {
|
|
36412
36473
|
return [
|
|
36413
36474
|
{
|
|
36414
|
-
target: this.
|
|
36475
|
+
target: this.usdcToken.address,
|
|
36415
36476
|
method: "approve",
|
|
36416
36477
|
packedArguments: [this.config.extendedContract.toBigInt()],
|
|
36417
36478
|
id: this._depositApproveProofReadableId(),
|
|
@@ -36431,14 +36492,14 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
36431
36492
|
}
|
|
36432
36493
|
async getDepositCall(params) {
|
|
36433
36494
|
try {
|
|
36434
|
-
const salt = Math.floor(Math.random() * 10 ** this.
|
|
36495
|
+
const salt = Math.floor(Math.random() * 10 ** this.usdcToken.decimals);
|
|
36435
36496
|
const amount = import_starknet27.uint256.bnToUint256(params.amount.toWei());
|
|
36436
36497
|
return [
|
|
36437
36498
|
{
|
|
36438
36499
|
proofReadableId: this._depositApproveProofReadableId(),
|
|
36439
36500
|
sanitizer: SIMPLE_SANITIZER,
|
|
36440
36501
|
call: {
|
|
36441
|
-
contractAddress: this.
|
|
36502
|
+
contractAddress: this.usdcToken.address,
|
|
36442
36503
|
selector: import_starknet27.hash.getSelectorFromName("approve"),
|
|
36443
36504
|
calldata: [
|
|
36444
36505
|
this.config.extendedContract.toBigInt(),
|
|
@@ -37339,7 +37400,7 @@ var AvnuAdapter = class _AvnuAdapter extends BaseAdapter {
|
|
|
37339
37400
|
}
|
|
37340
37401
|
};
|
|
37341
37402
|
|
|
37342
|
-
// src/strategies/universal-
|
|
37403
|
+
// src/strategies/universal-adapters/svk-troves-adapter.ts
|
|
37343
37404
|
var import_starknet30 = require("starknet");
|
|
37344
37405
|
|
|
37345
37406
|
// src/data/universal-vault.abi.json
|
|
@@ -39024,6 +39085,272 @@ var universal_vault_abi_default = [
|
|
|
39024
39085
|
}
|
|
39025
39086
|
];
|
|
39026
39087
|
|
|
39088
|
+
// src/strategies/universal-adapters/svk-troves-adapter.ts
|
|
39089
|
+
var DEFAULT_TROVES_STRATEGIES_API = "https://app.troves.fi/api/strategies";
|
|
39090
|
+
function parseTrovesApyField(raw) {
|
|
39091
|
+
if (typeof raw === "number" && Number.isFinite(raw)) {
|
|
39092
|
+
return raw;
|
|
39093
|
+
}
|
|
39094
|
+
if (typeof raw === "string") {
|
|
39095
|
+
const n = Number.parseFloat(raw);
|
|
39096
|
+
if (Number.isFinite(n)) {
|
|
39097
|
+
return n;
|
|
39098
|
+
}
|
|
39099
|
+
}
|
|
39100
|
+
return 0;
|
|
39101
|
+
}
|
|
39102
|
+
var SvkTrovesAdapter = class _SvkTrovesAdapter extends BaseAdapter {
|
|
39103
|
+
constructor(config) {
|
|
39104
|
+
super(config, _SvkTrovesAdapter.name, Protocols.TROVES);
|
|
39105
|
+
this.config = config;
|
|
39106
|
+
}
|
|
39107
|
+
/** Owner used for share balance + `due_assets_from_owner`. */
|
|
39108
|
+
_positionOwner() {
|
|
39109
|
+
return this.config.positionOwner ?? this.config.vaultAllocator;
|
|
39110
|
+
}
|
|
39111
|
+
/**
|
|
39112
|
+
* Proof readable IDs must stay ≤ 31 chars (Cairo short string). We derive a short ASCII suffix from
|
|
39113
|
+
* `strategyVault` address so multiple SVK adapters in one tree stay distinct.
|
|
39114
|
+
*/
|
|
39115
|
+
_proofSuffix() {
|
|
39116
|
+
return this.config.strategyVault.address.replace(/^0x/, "").slice(-6);
|
|
39117
|
+
}
|
|
39118
|
+
_depositApproveProofReadableId() {
|
|
39119
|
+
return `appr_dep_svk_${this._proofSuffix()}`;
|
|
39120
|
+
}
|
|
39121
|
+
_depositCallProofReadableId() {
|
|
39122
|
+
return `dep_svk_${this._proofSuffix()}`;
|
|
39123
|
+
}
|
|
39124
|
+
_withdrawCallProofReadableId() {
|
|
39125
|
+
return `wtdrw_svk_${this._proofSuffix()}`;
|
|
39126
|
+
}
|
|
39127
|
+
async getAPY(supportedPosition) {
|
|
39128
|
+
const CACHE_KEY = `svk_apy_${this.config.trovesStrategyId}`;
|
|
39129
|
+
const cached = this.getCache(CACHE_KEY);
|
|
39130
|
+
if (cached) {
|
|
39131
|
+
return cached;
|
|
39132
|
+
}
|
|
39133
|
+
const url = this.config.trovesStrategiesApiUrl ?? DEFAULT_TROVES_STRATEGIES_API;
|
|
39134
|
+
try {
|
|
39135
|
+
const res = await fetch(url);
|
|
39136
|
+
if (!res.ok) {
|
|
39137
|
+
logger.warn(`${_SvkTrovesAdapter.name}::getAPY: HTTP ${res.status} from ${url}`);
|
|
39138
|
+
const fallback = { apy: 0, type: "base" /* BASE */ };
|
|
39139
|
+
this.setCache(CACHE_KEY, fallback, 3e5);
|
|
39140
|
+
return fallback;
|
|
39141
|
+
}
|
|
39142
|
+
const body = await res.json();
|
|
39143
|
+
const row = body.strategies?.find((s) => s.id === this.config.trovesStrategyId);
|
|
39144
|
+
if (!row) {
|
|
39145
|
+
logger.warn(
|
|
39146
|
+
`${_SvkTrovesAdapter.name}::getAPY: strategy id not found: ${this.config.trovesStrategyId}`
|
|
39147
|
+
);
|
|
39148
|
+
const fallback = { apy: 0, type: "base" /* BASE */ };
|
|
39149
|
+
this.setCache(CACHE_KEY, fallback, 3e5);
|
|
39150
|
+
return fallback;
|
|
39151
|
+
}
|
|
39152
|
+
const apy = parseTrovesApyField(row.apy);
|
|
39153
|
+
const result = { apy, type: "base" /* BASE */ };
|
|
39154
|
+
this.setCache(CACHE_KEY, result, 3e5);
|
|
39155
|
+
return result;
|
|
39156
|
+
} catch (error) {
|
|
39157
|
+
logger.error(`${_SvkTrovesAdapter.name}::getAPY:`, error);
|
|
39158
|
+
throw error;
|
|
39159
|
+
}
|
|
39160
|
+
}
|
|
39161
|
+
async getPosition(supportedPosition) {
|
|
39162
|
+
const CACHE_KEY = `svk_pos_${this.config.strategyVault.address}_${this._positionOwner().address}`;
|
|
39163
|
+
const cached = this.getCache(CACHE_KEY);
|
|
39164
|
+
if (cached) {
|
|
39165
|
+
return cached;
|
|
39166
|
+
}
|
|
39167
|
+
try {
|
|
39168
|
+
const vault = new import_starknet30.Contract({
|
|
39169
|
+
abi: universal_vault_abi_default,
|
|
39170
|
+
address: this.config.strategyVault.address,
|
|
39171
|
+
providerOrAccount: this.config.networkConfig.provider
|
|
39172
|
+
});
|
|
39173
|
+
const owner = this._positionOwner();
|
|
39174
|
+
const decimals = supportedPosition.asset.decimals;
|
|
39175
|
+
const shares = await vault.balance_of(owner.address);
|
|
39176
|
+
const shareU256 = import_starknet30.uint256.bnToUint256(shares);
|
|
39177
|
+
const liquidAssetsRaw = await vault.convert_to_assets(shareU256);
|
|
39178
|
+
const liquid = Web3Number.fromWei(liquidAssetsRaw.toString(), decimals);
|
|
39179
|
+
let pending = Web3Number.fromWei("0", decimals);
|
|
39180
|
+
try {
|
|
39181
|
+
const dueRaw = await vault.call("due_assets_from_owner", [owner.address]);
|
|
39182
|
+
pending = Web3Number.fromWei(dueRaw.toString(), decimals);
|
|
39183
|
+
} catch (e) {
|
|
39184
|
+
logger.warn(
|
|
39185
|
+
`${_SvkTrovesAdapter.name}::getPosition: due_assets_from_owner failed (treating as 0): ${e.message}`
|
|
39186
|
+
);
|
|
39187
|
+
}
|
|
39188
|
+
const total = liquid.plus(pending);
|
|
39189
|
+
const remarks = `Troves ${this.config.trovesStrategyId} holdings`;
|
|
39190
|
+
const result = {
|
|
39191
|
+
amount: total,
|
|
39192
|
+
remarks
|
|
39193
|
+
};
|
|
39194
|
+
this.setCache(CACHE_KEY, result, 6e4);
|
|
39195
|
+
return result;
|
|
39196
|
+
} catch (error) {
|
|
39197
|
+
logger.error(`${_SvkTrovesAdapter.name}::getPosition:`, error);
|
|
39198
|
+
throw error;
|
|
39199
|
+
}
|
|
39200
|
+
}
|
|
39201
|
+
async maxDeposit(amount) {
|
|
39202
|
+
const baseToken = this.config.baseToken;
|
|
39203
|
+
if (!amount) {
|
|
39204
|
+
return {
|
|
39205
|
+
tokenInfo: baseToken,
|
|
39206
|
+
amount: new Web3Number("999999999999999999999999999", baseToken.decimals),
|
|
39207
|
+
usdValue: 1e27,
|
|
39208
|
+
remarks: "Max deposit (unbounded placeholder)",
|
|
39209
|
+
apy: await this.getAPY({ asset: baseToken, isDebt: false }),
|
|
39210
|
+
protocol: this.protocol
|
|
39211
|
+
};
|
|
39212
|
+
}
|
|
39213
|
+
const usdValue = await this.getUSDValue(baseToken, amount);
|
|
39214
|
+
return {
|
|
39215
|
+
tokenInfo: baseToken,
|
|
39216
|
+
amount,
|
|
39217
|
+
usdValue,
|
|
39218
|
+
remarks: "Deposit amount",
|
|
39219
|
+
apy: await this.getAPY({ asset: baseToken, isDebt: false }),
|
|
39220
|
+
protocol: this.protocol
|
|
39221
|
+
};
|
|
39222
|
+
}
|
|
39223
|
+
async maxWithdraw() {
|
|
39224
|
+
const baseToken = this.config.baseToken;
|
|
39225
|
+
const current = await this.getPosition({ asset: baseToken, isDebt: false });
|
|
39226
|
+
const pos = current ?? { amount: new Web3Number("0", baseToken.decimals), remarks: "" };
|
|
39227
|
+
const usdValue = await this.getUSDValue(baseToken, pos.amount);
|
|
39228
|
+
return {
|
|
39229
|
+
tokenInfo: baseToken,
|
|
39230
|
+
amount: pos.amount,
|
|
39231
|
+
usdValue,
|
|
39232
|
+
remarks: "Max withdraw (liquid + pending redemption, underlying units)",
|
|
39233
|
+
apy: await this.getAPY({ asset: baseToken, isDebt: false }),
|
|
39234
|
+
protocol: this.protocol
|
|
39235
|
+
};
|
|
39236
|
+
}
|
|
39237
|
+
_getDepositLeaf() {
|
|
39238
|
+
const baseToken = this.config.baseToken;
|
|
39239
|
+
const strategyVault = this.config.strategyVault;
|
|
39240
|
+
const receiver = this.config.vaultAllocator;
|
|
39241
|
+
return [
|
|
39242
|
+
{
|
|
39243
|
+
target: baseToken.address,
|
|
39244
|
+
method: "approve",
|
|
39245
|
+
packedArguments: [strategyVault.toBigInt()],
|
|
39246
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
39247
|
+
id: this._depositApproveProofReadableId()
|
|
39248
|
+
},
|
|
39249
|
+
{
|
|
39250
|
+
target: strategyVault,
|
|
39251
|
+
method: "deposit",
|
|
39252
|
+
packedArguments: [receiver.toBigInt()],
|
|
39253
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
39254
|
+
id: this._depositCallProofReadableId()
|
|
39255
|
+
}
|
|
39256
|
+
];
|
|
39257
|
+
}
|
|
39258
|
+
_getWithdrawLeaf() {
|
|
39259
|
+
const strategyVault = this.config.strategyVault;
|
|
39260
|
+
const recv = this.config.vaultAllocator;
|
|
39261
|
+
const owner = this.config.vaultAllocator;
|
|
39262
|
+
return [
|
|
39263
|
+
{
|
|
39264
|
+
target: strategyVault,
|
|
39265
|
+
method: "withdraw",
|
|
39266
|
+
packedArguments: [recv.toBigInt(), owner.toBigInt()],
|
|
39267
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
39268
|
+
id: this._withdrawCallProofReadableId()
|
|
39269
|
+
}
|
|
39270
|
+
];
|
|
39271
|
+
}
|
|
39272
|
+
getDepositAdapter() {
|
|
39273
|
+
const leafConfigs = this._getDepositLeaf();
|
|
39274
|
+
const leaves = leafConfigs.map((config) => {
|
|
39275
|
+
const { target, method, packedArguments, sanitizer, id } = config;
|
|
39276
|
+
return this.constructSimpleLeafData({ id, target, method, packedArguments }, sanitizer);
|
|
39277
|
+
});
|
|
39278
|
+
return { leaves, callConstructor: this.getDepositCall.bind(this) };
|
|
39279
|
+
}
|
|
39280
|
+
getWithdrawAdapter() {
|
|
39281
|
+
const leafConfigs = this._getWithdrawLeaf();
|
|
39282
|
+
const leaves = leafConfigs.map((config) => {
|
|
39283
|
+
const { target, method, packedArguments, sanitizer, id } = config;
|
|
39284
|
+
return this.constructSimpleLeafData({ id, target, method, packedArguments }, sanitizer);
|
|
39285
|
+
});
|
|
39286
|
+
return { leaves, callConstructor: this.getWithdrawCall.bind(this) };
|
|
39287
|
+
}
|
|
39288
|
+
async getDepositCall(params) {
|
|
39289
|
+
const baseToken = this.config.baseToken;
|
|
39290
|
+
const strategyVault = this.config.strategyVault;
|
|
39291
|
+
const amount = params.amount;
|
|
39292
|
+
const uint256Amount = import_starknet30.uint256.bnToUint256(amount.toWei());
|
|
39293
|
+
const receiver = this.config.vaultAllocator;
|
|
39294
|
+
return [
|
|
39295
|
+
{
|
|
39296
|
+
proofReadableId: this._depositApproveProofReadableId(),
|
|
39297
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
39298
|
+
call: {
|
|
39299
|
+
contractAddress: baseToken.address,
|
|
39300
|
+
selector: import_starknet30.hash.getSelectorFromName("approve"),
|
|
39301
|
+
calldata: [
|
|
39302
|
+
strategyVault.toBigInt(),
|
|
39303
|
+
toBigInt(uint256Amount.low.toString()),
|
|
39304
|
+
toBigInt(uint256Amount.high.toString())
|
|
39305
|
+
]
|
|
39306
|
+
}
|
|
39307
|
+
},
|
|
39308
|
+
{
|
|
39309
|
+
proofReadableId: this._depositCallProofReadableId(),
|
|
39310
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
39311
|
+
call: {
|
|
39312
|
+
contractAddress: strategyVault,
|
|
39313
|
+
selector: import_starknet30.hash.getSelectorFromName("deposit"),
|
|
39314
|
+
calldata: [
|
|
39315
|
+
toBigInt(uint256Amount.low.toString()),
|
|
39316
|
+
toBigInt(uint256Amount.high.toString()),
|
|
39317
|
+
receiver.toBigInt()
|
|
39318
|
+
]
|
|
39319
|
+
}
|
|
39320
|
+
}
|
|
39321
|
+
];
|
|
39322
|
+
}
|
|
39323
|
+
async getWithdrawCall(params) {
|
|
39324
|
+
const strategyVault = this.config.strategyVault;
|
|
39325
|
+
const amount = params.amount;
|
|
39326
|
+
const uint256Amount = import_starknet30.uint256.bnToUint256(amount.toWei());
|
|
39327
|
+
const recv = this.config.vaultAllocator;
|
|
39328
|
+
const owner = this.config.vaultAllocator;
|
|
39329
|
+
return [
|
|
39330
|
+
{
|
|
39331
|
+
proofReadableId: this._withdrawCallProofReadableId(),
|
|
39332
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
39333
|
+
call: {
|
|
39334
|
+
contractAddress: strategyVault,
|
|
39335
|
+
selector: import_starknet30.hash.getSelectorFromName("withdraw"),
|
|
39336
|
+
calldata: [
|
|
39337
|
+
toBigInt(uint256Amount.low.toString()),
|
|
39338
|
+
toBigInt(uint256Amount.high.toString()),
|
|
39339
|
+
recv.toBigInt(),
|
|
39340
|
+
owner.toBigInt()
|
|
39341
|
+
]
|
|
39342
|
+
}
|
|
39343
|
+
}
|
|
39344
|
+
];
|
|
39345
|
+
}
|
|
39346
|
+
getHealthFactor() {
|
|
39347
|
+
return Promise.resolve(10);
|
|
39348
|
+
}
|
|
39349
|
+
};
|
|
39350
|
+
|
|
39351
|
+
// src/strategies/universal-strategy.tsx
|
|
39352
|
+
var import_starknet31 = require("starknet");
|
|
39353
|
+
|
|
39027
39354
|
// src/data/vault-manager.abi.json
|
|
39028
39355
|
var vault_manager_abi_default = [
|
|
39029
39356
|
{
|
|
@@ -39689,12 +40016,12 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
39689
40016
|
);
|
|
39690
40017
|
this.metadata = metadata;
|
|
39691
40018
|
this.address = metadata.address;
|
|
39692
|
-
this.contract = new
|
|
40019
|
+
this.contract = new import_starknet31.Contract({
|
|
39693
40020
|
abi: universal_vault_abi_default,
|
|
39694
40021
|
address: this.address.address,
|
|
39695
40022
|
providerOrAccount: this.config.provider
|
|
39696
40023
|
});
|
|
39697
|
-
this.managerContract = new
|
|
40024
|
+
this.managerContract = new import_starknet31.Contract({
|
|
39698
40025
|
abi: vault_manager_abi_default,
|
|
39699
40026
|
address: this.metadata.additionalInfo.manager.address,
|
|
39700
40027
|
providerOrAccount: this.config.provider
|
|
@@ -39748,17 +40075,17 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
39748
40075
|
amountInfo.tokenInfo.address.eq(this.asset().address),
|
|
39749
40076
|
"Deposit token mismatch"
|
|
39750
40077
|
);
|
|
39751
|
-
const assetContract = new
|
|
40078
|
+
const assetContract = new import_starknet31.Contract({
|
|
39752
40079
|
abi: universal_vault_abi_default,
|
|
39753
40080
|
address: this.asset().address.address,
|
|
39754
40081
|
providerOrAccount: this.config.provider
|
|
39755
40082
|
});
|
|
39756
40083
|
const call1 = assetContract.populate("approve", [
|
|
39757
40084
|
this.address.address,
|
|
39758
|
-
|
|
40085
|
+
import_starknet31.uint256.bnToUint256(amountInfo.amount.toWei())
|
|
39759
40086
|
]);
|
|
39760
40087
|
const call2 = this.contract.populate("deposit", [
|
|
39761
|
-
|
|
40088
|
+
import_starknet31.uint256.bnToUint256(amountInfo.amount.toWei()),
|
|
39762
40089
|
receiver.address
|
|
39763
40090
|
]);
|
|
39764
40091
|
return [call1, call2];
|
|
@@ -39768,9 +40095,9 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
39768
40095
|
amountInfo.tokenInfo.address.eq(this.asset().address),
|
|
39769
40096
|
"Withdraw token mismatch"
|
|
39770
40097
|
);
|
|
39771
|
-
const shares = await this.contract.call("convert_to_shares", [
|
|
40098
|
+
const shares = await this.contract.call("convert_to_shares", [import_starknet31.uint256.bnToUint256(amountInfo.amount.toWei())]);
|
|
39772
40099
|
const call = this.contract.populate("request_redeem", [
|
|
39773
|
-
|
|
40100
|
+
import_starknet31.uint256.bnToUint256(shares.toString()),
|
|
39774
40101
|
receiver.address,
|
|
39775
40102
|
owner.address
|
|
39776
40103
|
]);
|
|
@@ -39780,7 +40107,7 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
39780
40107
|
const shares = await this.contract.call("balanceOf", [user.address], { blockIdentifier });
|
|
39781
40108
|
const assets = await this.contract.call(
|
|
39782
40109
|
"convert_to_assets",
|
|
39783
|
-
[
|
|
40110
|
+
[import_starknet31.uint256.bnToUint256(shares)],
|
|
39784
40111
|
{ blockIdentifier }
|
|
39785
40112
|
);
|
|
39786
40113
|
const amount = Web3Number.fromWei(
|
|
@@ -39803,7 +40130,7 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
39803
40130
|
const vesuAdapters = this.getVesuAdapters();
|
|
39804
40131
|
const allVesuPools = await VesuAdapter.getVesuPools();
|
|
39805
40132
|
const pools = vesuAdapters.map((vesuAdapter) => {
|
|
39806
|
-
return allVesuPools.pools.find((p) => vesuAdapter.config.poolId.eqString(
|
|
40133
|
+
return allVesuPools.pools.find((p) => vesuAdapter.config.poolId.eqString(import_starknet31.num.getHexString(p.id)));
|
|
39807
40134
|
});
|
|
39808
40135
|
logger.verbose(`${this.metadata.name}::netAPY: vesu-pools: ${JSON.stringify(pools)}`);
|
|
39809
40136
|
if (pools.some((p) => !p)) {
|
|
@@ -40092,7 +40419,7 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
40092
40419
|
}];
|
|
40093
40420
|
}
|
|
40094
40421
|
getSetManagerCall(strategist, root = this.getMerkleRoot()) {
|
|
40095
|
-
return this.managerContract.populate("set_manage_root", [strategist.address,
|
|
40422
|
+
return this.managerContract.populate("set_manage_root", [strategist.address, import_starknet31.num.getHexString(root)]);
|
|
40096
40423
|
}
|
|
40097
40424
|
// TODO: callConstructor now returns Promise<ManageCall[]>, migrate callers to await and flatten
|
|
40098
40425
|
getManageCall(proofIds, manageCalls) {
|
|
@@ -40276,7 +40603,7 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
40276
40603
|
callSet1 = [...temp];
|
|
40277
40604
|
}
|
|
40278
40605
|
const allActions = [...callSet1.map((i) => i.manageCall), ...callSet2.map((i) => i.manageCall)];
|
|
40279
|
-
const flashloanCalldata =
|
|
40606
|
+
const flashloanCalldata = import_starknet31.CallData.compile([
|
|
40280
40607
|
[...callSet1.map((i) => i.proofs), ...callSet2.map((i) => i.proofs)],
|
|
40281
40608
|
allActions.map((i) => i.sanitizer.address),
|
|
40282
40609
|
allActions.map((i) => i.call.contractAddress.address),
|
|
@@ -40714,19 +41041,19 @@ var UniversalStrategies = [
|
|
|
40714
41041
|
];
|
|
40715
41042
|
|
|
40716
41043
|
// src/strategies/svk-strategy.ts
|
|
40717
|
-
var
|
|
41044
|
+
var import_starknet32 = require("starknet");
|
|
40718
41045
|
var SVKStrategy = class extends BaseStrategy {
|
|
40719
41046
|
constructor(config, pricer, metadata) {
|
|
40720
41047
|
super(config);
|
|
40721
41048
|
this.pricer = pricer;
|
|
40722
41049
|
this.metadata = metadata;
|
|
40723
41050
|
this.address = metadata.address;
|
|
40724
|
-
this.contract = new
|
|
41051
|
+
this.contract = new import_starknet32.Contract({
|
|
40725
41052
|
abi: universal_vault_abi_default,
|
|
40726
41053
|
address: this.address.address,
|
|
40727
41054
|
providerOrAccount: this.config.provider
|
|
40728
41055
|
});
|
|
40729
|
-
this.managerContract = new
|
|
41056
|
+
this.managerContract = new import_starknet32.Contract({
|
|
40730
41057
|
abi: vault_manager_abi_default,
|
|
40731
41058
|
address: this.metadata.additionalInfo.manager.address,
|
|
40732
41059
|
providerOrAccount: this.config.provider
|
|
@@ -40743,17 +41070,17 @@ var SVKStrategy = class extends BaseStrategy {
|
|
|
40743
41070
|
amountInfo.tokenInfo.address.eq(this.asset().address),
|
|
40744
41071
|
"Deposit token mismatch"
|
|
40745
41072
|
);
|
|
40746
|
-
const assetContract = new
|
|
41073
|
+
const assetContract = new import_starknet32.Contract({
|
|
40747
41074
|
abi: universal_vault_abi_default,
|
|
40748
41075
|
address: this.asset().address.address,
|
|
40749
41076
|
providerOrAccount: this.config.provider
|
|
40750
41077
|
});
|
|
40751
41078
|
const call1 = assetContract.populate("approve", [
|
|
40752
41079
|
this.address.address,
|
|
40753
|
-
|
|
41080
|
+
import_starknet32.uint256.bnToUint256(amountInfo.amount.toWei())
|
|
40754
41081
|
]);
|
|
40755
41082
|
const call2 = this.contract.populate("deposit", [
|
|
40756
|
-
|
|
41083
|
+
import_starknet32.uint256.bnToUint256(amountInfo.amount.toWei()),
|
|
40757
41084
|
receiver.address
|
|
40758
41085
|
]);
|
|
40759
41086
|
return [call1, call2];
|
|
@@ -40763,9 +41090,9 @@ var SVKStrategy = class extends BaseStrategy {
|
|
|
40763
41090
|
amountInfo.tokenInfo.address.eq(this.asset().address),
|
|
40764
41091
|
"Withdraw token mismatch"
|
|
40765
41092
|
);
|
|
40766
|
-
const shares = await this.contract.call("convert_to_shares", [
|
|
41093
|
+
const shares = await this.contract.call("convert_to_shares", [import_starknet32.uint256.bnToUint256(amountInfo.amount.toWei())]);
|
|
40767
41094
|
const call = this.contract.populate("request_redeem", [
|
|
40768
|
-
|
|
41095
|
+
import_starknet32.uint256.bnToUint256(shares.toString()),
|
|
40769
41096
|
receiver.address,
|
|
40770
41097
|
owner.address
|
|
40771
41098
|
]);
|
|
@@ -40902,7 +41229,7 @@ var SVKStrategy = class extends BaseStrategy {
|
|
|
40902
41229
|
getSetManagerCall(strategist, root = this.getMerkleRoot()) {
|
|
40903
41230
|
return this.managerContract.populate("set_manage_root", [
|
|
40904
41231
|
strategist.address,
|
|
40905
|
-
|
|
41232
|
+
import_starknet32.num.getHexString(root)
|
|
40906
41233
|
]);
|
|
40907
41234
|
}
|
|
40908
41235
|
/**
|
|
@@ -40956,7 +41283,7 @@ var SVKStrategy = class extends BaseStrategy {
|
|
|
40956
41283
|
};
|
|
40957
41284
|
|
|
40958
41285
|
// src/strategies/universal-lst-muliplier-strategy.tsx
|
|
40959
|
-
var
|
|
41286
|
+
var import_starknet33 = require("starknet");
|
|
40960
41287
|
|
|
40961
41288
|
// src/strategies/universal-adapters/adapter-optimizer.ts
|
|
40962
41289
|
var AdapterOptimizer = class {
|
|
@@ -41109,15 +41436,15 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
41109
41436
|
async getLSTExchangeRate() {
|
|
41110
41437
|
const vesuAdapter1 = this.getVesuSameTokenAdapter();
|
|
41111
41438
|
const lstTokenInfo = vesuAdapter1._vesuAdapter.config.collateral;
|
|
41112
|
-
const lstABI = new
|
|
41439
|
+
const lstABI = new import_starknet33.Contract({
|
|
41113
41440
|
abi: erc4626_abi_default,
|
|
41114
41441
|
address: lstTokenInfo.address.address,
|
|
41115
41442
|
providerOrAccount: this.config.provider
|
|
41116
41443
|
});
|
|
41117
41444
|
const price = await lstABI.call("convert_to_assets", [
|
|
41118
|
-
|
|
41445
|
+
import_starknet33.uint256.bnToUint256(new Web3Number(1, lstTokenInfo.decimals).toWei())
|
|
41119
41446
|
]);
|
|
41120
|
-
const exchangeRate = Number(
|
|
41447
|
+
const exchangeRate = Number(import_starknet33.uint256.uint256ToBN(price).toString()) / Math.pow(10, lstTokenInfo.decimals);
|
|
41121
41448
|
logger.verbose(`${this.getTag()}:: LST Exchange Rate: ${exchangeRate}`);
|
|
41122
41449
|
return exchangeRate;
|
|
41123
41450
|
}
|
|
@@ -41987,6 +42314,249 @@ var HyperLSTStrategies = [
|
|
|
41987
42314
|
getStrategySettings("mRe7YIELD", "mRe7YIELD", hypermRe7YIELD, false, false)
|
|
41988
42315
|
];
|
|
41989
42316
|
|
|
42317
|
+
// src/strategies/vesu-extended-strategy/services/ltv-imbalance-rebalance-math.ts
|
|
42318
|
+
function ceilBtc(v, precision) {
|
|
42319
|
+
const f = 10 ** precision;
|
|
42320
|
+
return Math.ceil(v * f) / f;
|
|
42321
|
+
}
|
|
42322
|
+
function floorBtc(v, precision) {
|
|
42323
|
+
const f = 10 ** precision;
|
|
42324
|
+
return Math.floor(v * f) / f;
|
|
42325
|
+
}
|
|
42326
|
+
function isNegligible(btc, precision) {
|
|
42327
|
+
return Math.abs(btc) < 10 ** -precision;
|
|
42328
|
+
}
|
|
42329
|
+
function computeExtIdealMargin(posBtc, leverage, price) {
|
|
42330
|
+
return posBtc * price / leverage;
|
|
42331
|
+
}
|
|
42332
|
+
function computeExtDeficit(ext, price) {
|
|
42333
|
+
return Math.max(0, computeExtIdealMargin(ext.positionBtc, ext.leverage, price) - ext.equity);
|
|
42334
|
+
}
|
|
42335
|
+
function computeVesuHF(vesu, price) {
|
|
42336
|
+
const collateralUsd = vesu.positionBtc * price;
|
|
42337
|
+
if (collateralUsd === 0) return Infinity;
|
|
42338
|
+
const ltv = vesu.debt * vesu.debtPrice / collateralUsd;
|
|
42339
|
+
if (ltv === 0) return Infinity;
|
|
42340
|
+
return vesu.maxLTV / ltv;
|
|
42341
|
+
}
|
|
42342
|
+
function computeVesuDebtRepay(vesu, price) {
|
|
42343
|
+
const targetLTV = vesu.maxLTV / vesu.targetHF;
|
|
42344
|
+
const collateralUsd = vesu.positionBtc * price;
|
|
42345
|
+
const requiredDebt = targetLTV * collateralUsd / vesu.debtPrice;
|
|
42346
|
+
return Math.max(0, vesu.debt - requiredDebt);
|
|
42347
|
+
}
|
|
42348
|
+
function computeVesuTargetLTV(vesu) {
|
|
42349
|
+
return vesu.maxLTV / vesu.targetHF;
|
|
42350
|
+
}
|
|
42351
|
+
function computeVesuGrowthCost(gapBtc, vesu, price) {
|
|
42352
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
42353
|
+
return gapBtc * price * (1 - targetLTV);
|
|
42354
|
+
}
|
|
42355
|
+
function computeVesuGrowthDebt(gapBtc, vesu, price) {
|
|
42356
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
42357
|
+
return gapBtc * price * targetLTV / vesu.debtPrice;
|
|
42358
|
+
}
|
|
42359
|
+
function computeVesuGrowthFromEquity(equityUsd, vesu, price) {
|
|
42360
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
42361
|
+
return equityUsd / (price * (1 - targetLTV));
|
|
42362
|
+
}
|
|
42363
|
+
function emptyDeltas() {
|
|
42364
|
+
return {
|
|
42365
|
+
dExtPosition: 0,
|
|
42366
|
+
dVesuPosition: 0,
|
|
42367
|
+
dVesuDebt: 0,
|
|
42368
|
+
dExtAvlWithdraw: 0,
|
|
42369
|
+
dExtUpnl: 0,
|
|
42370
|
+
dVaUsd: 0,
|
|
42371
|
+
dWalletUsd: 0,
|
|
42372
|
+
dVesuBorrowCapacity: 0,
|
|
42373
|
+
dTransferVesuToExt: 0
|
|
42374
|
+
};
|
|
42375
|
+
}
|
|
42376
|
+
function mergeDeltas(a, b) {
|
|
42377
|
+
return {
|
|
42378
|
+
dExtPosition: a.dExtPosition + b.dExtPosition,
|
|
42379
|
+
dVesuPosition: a.dVesuPosition + b.dVesuPosition,
|
|
42380
|
+
dVesuDebt: a.dVesuDebt + b.dVesuDebt,
|
|
42381
|
+
dExtAvlWithdraw: a.dExtAvlWithdraw + b.dExtAvlWithdraw,
|
|
42382
|
+
dExtUpnl: a.dExtUpnl + b.dExtUpnl,
|
|
42383
|
+
dVaUsd: a.dVaUsd + b.dVaUsd,
|
|
42384
|
+
dWalletUsd: a.dWalletUsd + b.dWalletUsd,
|
|
42385
|
+
dVesuBorrowCapacity: a.dVesuBorrowCapacity + b.dVesuBorrowCapacity,
|
|
42386
|
+
dTransferVesuToExt: a.dTransferVesuToExt + b.dTransferVesuToExt
|
|
42387
|
+
};
|
|
42388
|
+
}
|
|
42389
|
+
function drawFunds(need, keys, pool) {
|
|
42390
|
+
const draws = {};
|
|
42391
|
+
let unmet = need;
|
|
42392
|
+
for (const k of keys) {
|
|
42393
|
+
if (unmet <= 0) break;
|
|
42394
|
+
const avail = pool[k];
|
|
42395
|
+
if (avail <= 0) continue;
|
|
42396
|
+
const take = Math.min(avail, unmet);
|
|
42397
|
+
draws[k] = take;
|
|
42398
|
+
pool[k] -= take;
|
|
42399
|
+
unmet -= take;
|
|
42400
|
+
}
|
|
42401
|
+
return { draws, filled: need - unmet, unmet };
|
|
42402
|
+
}
|
|
42403
|
+
function sumKeys(draws, keys) {
|
|
42404
|
+
return keys.reduce((s, k) => s + (draws[k] ?? 0), 0);
|
|
42405
|
+
}
|
|
42406
|
+
function applyDrawsToDeltas(d, draws, sign) {
|
|
42407
|
+
d.dVaUsd += sign * (draws.vaUsd ?? 0);
|
|
42408
|
+
d.dWalletUsd += sign * (draws.walletUsd ?? 0);
|
|
42409
|
+
d.dVesuBorrowCapacity += sign * (draws.vesuBorrowCapacity ?? 0);
|
|
42410
|
+
d.dExtAvlWithdraw += sign * (draws.extAvlWithdraw ?? 0);
|
|
42411
|
+
d.dExtUpnl += sign * (draws.extUpnl ?? 0);
|
|
42412
|
+
}
|
|
42413
|
+
function fixExtMargin(ext, price, pool) {
|
|
42414
|
+
const d = emptyDeltas();
|
|
42415
|
+
const deficit = computeExtDeficit(ext, price);
|
|
42416
|
+
if (deficit <= 0) return { d, unmet: 0 };
|
|
42417
|
+
const { draws, filled, unmet } = drawFunds(deficit, ["walletUsd", "vaUsd", "vesuBorrowCapacity"], pool);
|
|
42418
|
+
applyDrawsToDeltas(d, draws, -1);
|
|
42419
|
+
d.dExtAvlWithdraw += filled;
|
|
42420
|
+
const fromVesu = draws.vesuBorrowCapacity ?? 0;
|
|
42421
|
+
if (fromVesu > 0) d.dTransferVesuToExt += fromVesu;
|
|
42422
|
+
return { d, unmet };
|
|
42423
|
+
}
|
|
42424
|
+
function fixVesuMargin(vesu, price, pool, hfBuffer) {
|
|
42425
|
+
const d = emptyDeltas();
|
|
42426
|
+
const hf = computeVesuHF(vesu, price);
|
|
42427
|
+
if (hf >= vesu.targetHF - hfBuffer) return { d, unmet: 0 };
|
|
42428
|
+
const repayTokens = computeVesuDebtRepay(vesu, price);
|
|
42429
|
+
const repayUsd = repayTokens * vesu.debtPrice;
|
|
42430
|
+
const { draws, filled, unmet } = drawFunds(repayUsd, ["vaUsd", "walletUsd", "extAvlWithdraw", "extUpnl"], pool);
|
|
42431
|
+
applyDrawsToDeltas(d, draws, -1);
|
|
42432
|
+
d.dVesuDebt -= filled / vesu.debtPrice;
|
|
42433
|
+
const fromExt = sumKeys(draws, ["extAvlWithdraw", "extUpnl"]);
|
|
42434
|
+
if (fromExt > 0) d.dTransferVesuToExt -= fromExt;
|
|
42435
|
+
return { d, unmet };
|
|
42436
|
+
}
|
|
42437
|
+
function phase1(ext, vesu, price, pool, config) {
|
|
42438
|
+
const extResult = fixExtMargin(ext, price, pool);
|
|
42439
|
+
const vesuResult = fixVesuMargin(vesu, price, pool, config.hfBuffer);
|
|
42440
|
+
return {
|
|
42441
|
+
deltas: mergeDeltas(extResult.d, vesuResult.d),
|
|
42442
|
+
extDeficitRemaining: extResult.unmet,
|
|
42443
|
+
vesuRepayRemaining: vesuResult.unmet
|
|
42444
|
+
};
|
|
42445
|
+
}
|
|
42446
|
+
function solveUnifiedF(extPos, vesuPos, extEquity, vesuDebt, vesu, extLev, price) {
|
|
42447
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
42448
|
+
const k = 1 - targetLTV + 1 / extLev;
|
|
42449
|
+
const totalEquity = extEquity + vesuPos * price - vesuDebt * vesu.debtPrice;
|
|
42450
|
+
return totalEquity / (price * k);
|
|
42451
|
+
}
|
|
42452
|
+
function solveTransfer(vesuPos, vesuDebt, F, vesu, price) {
|
|
42453
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
42454
|
+
return vesuPos * price - vesuDebt * vesu.debtPrice - F * price * (1 - targetLTV);
|
|
42455
|
+
}
|
|
42456
|
+
function solveDebtRepay(vesuDebt, F, vesu, price) {
|
|
42457
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
42458
|
+
return vesuDebt - targetLTV * F * price / vesu.debtPrice;
|
|
42459
|
+
}
|
|
42460
|
+
function roundFinalPosition(extPos, vesuPos, rawF, precision) {
|
|
42461
|
+
let fFromExt;
|
|
42462
|
+
if (rawF < extPos) {
|
|
42463
|
+
const closeExt = ceilBtc(extPos - rawF, precision);
|
|
42464
|
+
fFromExt = extPos - closeExt;
|
|
42465
|
+
} else {
|
|
42466
|
+
const growExt = floorBtc(rawF - extPos, precision);
|
|
42467
|
+
fFromExt = extPos + growExt;
|
|
42468
|
+
}
|
|
42469
|
+
let fFromVesu;
|
|
42470
|
+
if (rawF < vesuPos) {
|
|
42471
|
+
const closeVesu = ceilBtc(vesuPos - rawF, precision);
|
|
42472
|
+
fFromVesu = vesuPos - closeVesu;
|
|
42473
|
+
} else {
|
|
42474
|
+
const growVesu = floorBtc(rawF - vesuPos, precision);
|
|
42475
|
+
fFromVesu = vesuPos + growVesu;
|
|
42476
|
+
}
|
|
42477
|
+
return Math.max(0, Math.min(fFromExt, fFromVesu));
|
|
42478
|
+
}
|
|
42479
|
+
function phase2(extPos, vesuPos, extEquity, vesuDebt, vesu, extLev, price, pool, precision) {
|
|
42480
|
+
const d = emptyDeltas();
|
|
42481
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
42482
|
+
const imbalance = extPos - vesuPos;
|
|
42483
|
+
let fundedGrowthBtc = 0;
|
|
42484
|
+
if (!isNegligible(imbalance, precision)) {
|
|
42485
|
+
if (imbalance > 0) {
|
|
42486
|
+
const equityCostUsd = computeVesuGrowthCost(imbalance, vesu, price);
|
|
42487
|
+
const { draws, filled } = drawFunds(equityCostUsd, ["vaUsd", "walletUsd", "extAvlWithdraw", "extUpnl"], pool);
|
|
42488
|
+
applyDrawsToDeltas(d, draws, -1);
|
|
42489
|
+
const grownBtc = computeVesuGrowthFromEquity(filled, vesu, price);
|
|
42490
|
+
d.dVesuPosition += grownBtc;
|
|
42491
|
+
fundedGrowthBtc = grownBtc;
|
|
42492
|
+
d.dVesuDebt += computeVesuGrowthDebt(grownBtc, vesu, price);
|
|
42493
|
+
const fromExt = sumKeys(draws, ["extAvlWithdraw", "extUpnl"]);
|
|
42494
|
+
if (fromExt > 0) d.dTransferVesuToExt -= fromExt;
|
|
42495
|
+
} else {
|
|
42496
|
+
const absImbalance = -imbalance;
|
|
42497
|
+
const marginCostUsd = absImbalance * price / extLev;
|
|
42498
|
+
const { draws, filled } = drawFunds(marginCostUsd, ["walletUsd", "vaUsd", "vesuBorrowCapacity"], pool);
|
|
42499
|
+
applyDrawsToDeltas(d, draws, -1);
|
|
42500
|
+
const grownBtc = filled * extLev / price;
|
|
42501
|
+
d.dExtPosition += grownBtc;
|
|
42502
|
+
fundedGrowthBtc = grownBtc;
|
|
42503
|
+
const fromVesu = draws.vesuBorrowCapacity ?? 0;
|
|
42504
|
+
if (fromVesu > 0) d.dTransferVesuToExt += fromVesu;
|
|
42505
|
+
}
|
|
42506
|
+
}
|
|
42507
|
+
const effExtPos = extPos + d.dExtPosition;
|
|
42508
|
+
const effVesuPos = vesuPos + d.dVesuPosition;
|
|
42509
|
+
const effExtEquity = extEquity;
|
|
42510
|
+
const effVesuDebt = vesuDebt + d.dVesuDebt;
|
|
42511
|
+
const rawF = solveUnifiedF(effExtPos, effVesuPos, effExtEquity, effVesuDebt, vesu, extLev, price);
|
|
42512
|
+
const cappedF = Math.min(rawF, Math.max(effExtPos, effVesuPos));
|
|
42513
|
+
const maxGrowableTo = Math.max(effExtPos, effVesuPos);
|
|
42514
|
+
const targetF = Math.max(0, Math.min(cappedF, maxGrowableTo));
|
|
42515
|
+
const remainingImbalance = effExtPos - effVesuPos;
|
|
42516
|
+
const extNeedsMore = effExtEquity < computeExtIdealMargin(effExtPos, extLev, price);
|
|
42517
|
+
const vesuCurrentLTV = effVesuPos > 0 ? effVesuDebt * vesu.debtPrice / (effVesuPos * price) : 0;
|
|
42518
|
+
const vesuNeedsMore = vesuCurrentLTV > targetLTV;
|
|
42519
|
+
const needsFurtherAction = !isNegligible(remainingImbalance, precision) || extNeedsMore || vesuNeedsMore;
|
|
42520
|
+
if (!needsFurtherAction) {
|
|
42521
|
+
return d;
|
|
42522
|
+
}
|
|
42523
|
+
const F = roundFinalPosition(effExtPos, effVesuPos, targetF, precision);
|
|
42524
|
+
const dx = F - effExtPos;
|
|
42525
|
+
const dy = F - effVesuPos;
|
|
42526
|
+
if (isNegligible(dx, precision) && isNegligible(dy, precision)) {
|
|
42527
|
+
return d;
|
|
42528
|
+
}
|
|
42529
|
+
d.dExtPosition += dx;
|
|
42530
|
+
d.dVesuPosition += dy;
|
|
42531
|
+
const debtRepay = solveDebtRepay(effVesuDebt, F, vesu, price);
|
|
42532
|
+
d.dVesuDebt -= debtRepay;
|
|
42533
|
+
const T = solveTransfer(effVesuPos, effVesuDebt, F, vesu, price);
|
|
42534
|
+
d.dTransferVesuToExt += T;
|
|
42535
|
+
d.dExtAvlWithdraw += T;
|
|
42536
|
+
return d;
|
|
42537
|
+
}
|
|
42538
|
+
function rebalance(inputs) {
|
|
42539
|
+
const { ext, vesu, btcPrice, config } = inputs;
|
|
42540
|
+
const pool = { ...inputs.funding };
|
|
42541
|
+
const p1 = phase1(ext, vesu, btcPrice, pool, config);
|
|
42542
|
+
const effExtPos = ext.positionBtc + p1.deltas.dExtPosition;
|
|
42543
|
+
const effVesuPos = vesu.positionBtc + p1.deltas.dVesuPosition;
|
|
42544
|
+
const effExtEquity = ext.equity + p1.deltas.dExtAvlWithdraw + p1.deltas.dExtUpnl;
|
|
42545
|
+
const effVesuDebt = vesu.debt + p1.deltas.dVesuDebt;
|
|
42546
|
+
const p2 = phase2(
|
|
42547
|
+
effExtPos,
|
|
42548
|
+
effVesuPos,
|
|
42549
|
+
effExtEquity,
|
|
42550
|
+
effVesuDebt,
|
|
42551
|
+
vesu,
|
|
42552
|
+
ext.leverage,
|
|
42553
|
+
btcPrice,
|
|
42554
|
+
pool,
|
|
42555
|
+
config.positionPrecision
|
|
42556
|
+
);
|
|
42557
|
+
return mergeDeltas(p1.deltas, p2);
|
|
42558
|
+
}
|
|
42559
|
+
|
|
41990
42560
|
// src/strategies/vesu-extended-strategy/services/extended-vesu-state-manager.ts
|
|
41991
42561
|
var RouteType = /* @__PURE__ */ ((RouteType2) => {
|
|
41992
42562
|
RouteType2["WALLET_TO_EXTENDED"] = "WALLET_TO_EXTENDED";
|
|
@@ -42018,6 +42588,7 @@ var CaseCategory = /* @__PURE__ */ ((CaseCategory2) => {
|
|
|
42018
42588
|
return CaseCategory2;
|
|
42019
42589
|
})(CaseCategory || {});
|
|
42020
42590
|
var CaseId = /* @__PURE__ */ ((CaseId2) => {
|
|
42591
|
+
CaseId2["MANAGE_LTV"] = "MANAGE_LTV";
|
|
42021
42592
|
CaseId2["LTV_VESU_LOW_TO_EXTENDED"] = "LTV_VESU_LOW_TO_EXTENDED";
|
|
42022
42593
|
CaseId2["LTV_EXTENDED_PROFITABLE_AVAILABLE"] = "LTV_EXTENDED_PROFITABLE_AVAILABLE";
|
|
42023
42594
|
CaseId2["LTV_EXTENDED_PROFITABLE_REALIZE"] = "LTV_EXTENDED_PROFITABLE_REALIZE";
|
|
@@ -42042,19 +42613,56 @@ function safeUsdcWeb3Number(value) {
|
|
|
42042
42613
|
return new Web3Number(value.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS);
|
|
42043
42614
|
}
|
|
42044
42615
|
var CASE_ROUTE_TYPES = {
|
|
42045
|
-
// LTV Rebalance —
|
|
42616
|
+
// LTV Rebalance — unified
|
|
42617
|
+
["MANAGE_LTV" /* MANAGE_LTV */]: [
|
|
42618
|
+
"REALISE_PNL" /* REALISE_PNL */,
|
|
42619
|
+
"EXTENDED_TO_WALLET" /* EXTENDED_TO_WALLET */,
|
|
42620
|
+
"RETURN_TO_WAIT" /* RETURN_TO_WAIT */,
|
|
42621
|
+
"WALLET_TO_VA" /* WALLET_TO_VA */,
|
|
42622
|
+
"VESU_BORROW" /* VESU_BORROW */,
|
|
42623
|
+
"VESU_REPAY" /* VESU_REPAY */,
|
|
42624
|
+
"VA_TO_EXTENDED" /* VA_TO_EXTENDED */,
|
|
42625
|
+
"VESU_MULTIPLY_DECREASE_LEVER" /* VESU_MULTIPLY_DECREASE_LEVER */,
|
|
42626
|
+
"VESU_MULTIPLY_INCREASE_LEVER" /* VESU_MULTIPLY_INCREASE_LEVER */,
|
|
42627
|
+
"AVNU_DEPOSIT_SWAP" /* AVNU_DEPOSIT_SWAP */,
|
|
42628
|
+
"EXTENDED_DECREASE_LEVER" /* EXTENDED_DECREASE_LEVER */,
|
|
42629
|
+
"EXTENDED_INCREASE_LEVER" /* EXTENDED_INCREASE_LEVER */,
|
|
42630
|
+
// Second-phase VA / Extended funding after lever routes (same types may repeat).
|
|
42631
|
+
"RETURN_TO_WAIT" /* RETURN_TO_WAIT */,
|
|
42632
|
+
"WALLET_TO_VA" /* WALLET_TO_VA */,
|
|
42633
|
+
"VA_TO_EXTENDED" /* VA_TO_EXTENDED */
|
|
42634
|
+
],
|
|
42635
|
+
/** @deprecated */
|
|
42046
42636
|
["LTV_VESU_HIGH_USE_VA_OR_WALLET" /* LTV_VESU_HIGH_USE_VA_OR_WALLET */]: ["WALLET_TO_VA" /* WALLET_TO_VA */, "VESU_REPAY" /* VESU_REPAY */],
|
|
42047
|
-
|
|
42637
|
+
/** @deprecated */
|
|
42048
42638
|
["LTV_EXTENDED_PROFITABLE_AVAILABLE" /* LTV_EXTENDED_PROFITABLE_AVAILABLE */]: ["EXTENDED_TO_WALLET" /* EXTENDED_TO_WALLET */, "RETURN_TO_WAIT" /* RETURN_TO_WAIT */, "WALLET_TO_VA" /* WALLET_TO_VA */, "VESU_REPAY" /* VESU_REPAY */],
|
|
42639
|
+
/** @deprecated */
|
|
42049
42640
|
["LTV_EXTENDED_PROFITABLE_REALIZE" /* LTV_EXTENDED_PROFITABLE_REALIZE */]: ["REALISE_PNL" /* REALISE_PNL */, "EXTENDED_TO_WALLET" /* EXTENDED_TO_WALLET */, "RETURN_TO_WAIT" /* RETURN_TO_WAIT */, "WALLET_TO_VA" /* WALLET_TO_VA */, "VESU_REPAY" /* VESU_REPAY */],
|
|
42050
|
-
|
|
42641
|
+
/** @deprecated */
|
|
42051
42642
|
["LTV_EXTENDED_HIGH_USE_VA_OR_WALLET" /* LTV_EXTENDED_HIGH_USE_VA_OR_WALLET */]: ["VA_TO_EXTENDED" /* VA_TO_EXTENDED */, "WALLET_TO_EXTENDED" /* WALLET_TO_EXTENDED */],
|
|
42643
|
+
/** @deprecated */
|
|
42052
42644
|
["LTV_VESU_LOW_TO_EXTENDED" /* LTV_VESU_LOW_TO_EXTENDED */]: ["VESU_BORROW" /* VESU_BORROW */, "VA_TO_EXTENDED" /* VA_TO_EXTENDED */],
|
|
42053
42645
|
// New Deposits
|
|
42054
42646
|
// @dev, when handling routes, after VA_TO_EXTENDED and/or WALLET_TO_EXTENDED, return. bcz, funds take time to reach extended. Anyways, in next cycle, these funds will be computed to increase lever
|
|
42055
42647
|
// Sequence: fund-movement transfers first (WALLET_TO_EXTENDED, VA_TO_EXTENDED, WALLET_TO_VA, EXTENDED_TO_WALLET),
|
|
42056
42648
|
// then RETURN_TO_WAIT, then optional second WALLET_TO_VA + RETURN_TO_WAIT, then lever routes.
|
|
42057
|
-
["DEPOSIT_FRESH_VAULT" /* DEPOSIT_FRESH_VAULT */]: [
|
|
42649
|
+
["DEPOSIT_FRESH_VAULT" /* DEPOSIT_FRESH_VAULT */]: [
|
|
42650
|
+
// May repeat after MANAGE_LTV (VA top-up → Extended → wait → levers).
|
|
42651
|
+
"WALLET_TO_VA" /* WALLET_TO_VA */,
|
|
42652
|
+
"VA_TO_EXTENDED" /* VA_TO_EXTENDED */,
|
|
42653
|
+
"RETURN_TO_WAIT" /* RETURN_TO_WAIT */,
|
|
42654
|
+
"VA_TO_EXTENDED" /* VA_TO_EXTENDED */,
|
|
42655
|
+
"VESU_BORROW" /* VESU_BORROW */,
|
|
42656
|
+
"WALLET_TO_EXTENDED" /* WALLET_TO_EXTENDED */,
|
|
42657
|
+
"VA_TO_EXTENDED" /* VA_TO_EXTENDED */,
|
|
42658
|
+
"WALLET_TO_VA" /* WALLET_TO_VA */,
|
|
42659
|
+
"EXTENDED_TO_WALLET" /* EXTENDED_TO_WALLET */,
|
|
42660
|
+
"RETURN_TO_WAIT" /* RETURN_TO_WAIT */,
|
|
42661
|
+
"WALLET_TO_VA" /* WALLET_TO_VA */,
|
|
42662
|
+
"AVNU_DEPOSIT_SWAP" /* AVNU_DEPOSIT_SWAP */,
|
|
42663
|
+
"VESU_MULTIPLY_INCREASE_LEVER" /* VESU_MULTIPLY_INCREASE_LEVER */,
|
|
42664
|
+
"EXTENDED_INCREASE_LEVER" /* EXTENDED_INCREASE_LEVER */
|
|
42665
|
+
],
|
|
42058
42666
|
["DEPOSIT_EXTENDED_AVAILABLE" /* DEPOSIT_EXTENDED_AVAILABLE */]: ["EXTENDED_TO_WALLET" /* EXTENDED_TO_WALLET */, "RETURN_TO_WAIT" /* RETURN_TO_WAIT */, "WALLET_TO_VA" /* WALLET_TO_VA */, "AVNU_DEPOSIT_SWAP" /* AVNU_DEPOSIT_SWAP */, "VESU_MULTIPLY_INCREASE_LEVER" /* VESU_MULTIPLY_INCREASE_LEVER */, "EXTENDED_INCREASE_LEVER" /* EXTENDED_INCREASE_LEVER */],
|
|
42059
42667
|
["DEPOSIT_VESU_BORROW_CAPACITY" /* DEPOSIT_VESU_BORROW_CAPACITY */]: ["VESU_BORROW" /* VESU_BORROW */, "VA_TO_EXTENDED" /* VA_TO_EXTENDED */, "RETURN_TO_WAIT" /* RETURN_TO_WAIT */, "AVNU_DEPOSIT_SWAP" /* AVNU_DEPOSIT_SWAP */, "VESU_MULTIPLY_INCREASE_LEVER" /* VESU_MULTIPLY_INCREASE_LEVER */, "EXTENDED_INCREASE_LEVER" /* EXTENDED_INCREASE_LEVER */],
|
|
42060
42668
|
["DEPOSIT_COMBINATION" /* DEPOSIT_COMBINATION */]: [],
|
|
@@ -42077,6 +42685,17 @@ var CASE_ROUTE_TYPES = {
|
|
|
42077
42685
|
["IMBALANCE_VESU_EXCESS_LONG_NO_FUNDS" /* IMBALANCE_VESU_EXCESS_LONG_NO_FUNDS */]: ["VESU_MULTIPLY_DECREASE_LEVER" /* VESU_MULTIPLY_DECREASE_LEVER */]
|
|
42078
42686
|
};
|
|
42079
42687
|
var CASE_DEFINITIONS = {
|
|
42688
|
+
["MANAGE_LTV" /* MANAGE_LTV */]: {
|
|
42689
|
+
id: "MANAGE_LTV" /* MANAGE_LTV */,
|
|
42690
|
+
category: "LTV_REBALANCE" /* LTV_REBALANCE */,
|
|
42691
|
+
title: "LTV Rebalance: Unified Vesu repay + Extended margin management",
|
|
42692
|
+
description: "Manages both Vesu high-LTV repayment and Extended low-margin funding in a single pass.",
|
|
42693
|
+
steps: [
|
|
42694
|
+
"Compute vesu repay needed and extended margin needed",
|
|
42695
|
+
"Allocate funds: VA > Wallet > ExtAvl > ExtUpnl for Vesu; Wallet > VA > Borrow for Extended",
|
|
42696
|
+
"Build combined transfer and repay/margin routes"
|
|
42697
|
+
]
|
|
42698
|
+
},
|
|
42080
42699
|
["LTV_VESU_LOW_TO_EXTENDED" /* LTV_VESU_LOW_TO_EXTENDED */]: {
|
|
42081
42700
|
id: "LTV_VESU_LOW_TO_EXTENDED" /* LTV_VESU_LOW_TO_EXTENDED */,
|
|
42082
42701
|
category: "LTV_REBALANCE" /* LTV_REBALANCE */,
|
|
@@ -42299,199 +42918,590 @@ function routeSummary(r) {
|
|
|
42299
42918
|
}
|
|
42300
42919
|
var SolveBudget = class {
|
|
42301
42920
|
constructor(state) {
|
|
42302
|
-
|
|
42303
|
-
|
|
42304
|
-
|
|
42305
|
-
|
|
42306
|
-
|
|
42307
|
-
|
|
42308
|
-
this._extAvailTrade = 0;
|
|
42309
|
-
this._extPendingDeposit = 0;
|
|
42310
|
-
this._vesuBorrowCapacity = 0;
|
|
42311
|
-
this._totalUnused = 0;
|
|
42312
|
-
const buffer = state.limitBalanceBufferFactor;
|
|
42313
|
-
this.unusedBalance = state.unusedBalance.map((item) => {
|
|
42314
|
-
return {
|
|
42315
|
-
...item,
|
|
42316
|
-
amount: item.amount.multipliedBy(1 - buffer),
|
|
42317
|
-
usdValue: item.usdValue * (1 - buffer)
|
|
42318
|
-
};
|
|
42921
|
+
this.assetToken = state.assetToken;
|
|
42922
|
+
this.usdcToken = state.usdcToken;
|
|
42923
|
+
const cloneTb = (b) => ({
|
|
42924
|
+
token: b.token,
|
|
42925
|
+
amount: new Web3Number(b.amount.toFixed(b.token.decimals), b.token.decimals),
|
|
42926
|
+
usdValue: b.usdValue
|
|
42319
42927
|
});
|
|
42320
|
-
this.
|
|
42321
|
-
|
|
42322
|
-
|
|
42323
|
-
|
|
42324
|
-
|
|
42325
|
-
|
|
42326
|
-
|
|
42327
|
-
|
|
42328
|
-
|
|
42329
|
-
} : null;
|
|
42330
|
-
this.extendedPositions = state.extendedPositions;
|
|
42928
|
+
this.unusedBalance = state.unusedBalance.map((item) => cloneTb(item));
|
|
42929
|
+
this.walletBalance = state.walletBalance ? cloneTb(state.walletBalance) : null;
|
|
42930
|
+
this.vaultAssetBalance = state.vaultAssetBalance ? cloneTb(state.vaultAssetBalance) : null;
|
|
42931
|
+
this.vaultUsdcBalance = state.vaultUsdcBalance ? cloneTb(state.vaultUsdcBalance) : null;
|
|
42932
|
+
this.extendedPositions = state.extendedPositions.map((p) => ({
|
|
42933
|
+
...p,
|
|
42934
|
+
size: new Web3Number(p.size.toFixed(8), 8),
|
|
42935
|
+
valueUsd: new Web3Number(p.valueUsd.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS)
|
|
42936
|
+
}));
|
|
42331
42937
|
this.extendedBalance = state.extendedBalance ? {
|
|
42332
|
-
|
|
42333
|
-
|
|
42334
|
-
|
|
42335
|
-
|
|
42336
|
-
|
|
42938
|
+
equity: new Web3Number(
|
|
42939
|
+
state.extendedBalance.equity.toFixed(USDC_TOKEN_DECIMALS),
|
|
42940
|
+
USDC_TOKEN_DECIMALS
|
|
42941
|
+
),
|
|
42942
|
+
availableForTrade: new Web3Number(
|
|
42943
|
+
state.extendedBalance.availableForTrade.toFixed(USDC_TOKEN_DECIMALS),
|
|
42944
|
+
USDC_TOKEN_DECIMALS
|
|
42945
|
+
),
|
|
42946
|
+
availableForWithdrawal: new Web3Number(
|
|
42947
|
+
state.extendedBalance.availableForWithdrawal.toFixed(USDC_TOKEN_DECIMALS),
|
|
42948
|
+
USDC_TOKEN_DECIMALS
|
|
42949
|
+
),
|
|
42950
|
+
unrealisedPnl: new Web3Number(
|
|
42951
|
+
state.extendedBalance.unrealisedPnl.toFixed(USDC_TOKEN_DECIMALS),
|
|
42952
|
+
USDC_TOKEN_DECIMALS
|
|
42953
|
+
),
|
|
42954
|
+
balance: new Web3Number(
|
|
42955
|
+
state.extendedBalance.balance.toFixed(USDC_TOKEN_DECIMALS),
|
|
42956
|
+
USDC_TOKEN_DECIMALS
|
|
42957
|
+
),
|
|
42958
|
+
pendingDeposit: new Web3Number(
|
|
42959
|
+
state.extendedBalance.pendingDeposit.toFixed(USDC_TOKEN_DECIMALS),
|
|
42960
|
+
USDC_TOKEN_DECIMALS
|
|
42961
|
+
)
|
|
42337
42962
|
} : null;
|
|
42338
|
-
this.vesuPoolStates = state.vesuPoolStates
|
|
42963
|
+
this.vesuPoolStates = state.vesuPoolStates.map((p) => ({
|
|
42964
|
+
...p,
|
|
42965
|
+
collateralAmount: new Web3Number(
|
|
42966
|
+
p.collateralAmount.toFixed(p.collateralToken.decimals),
|
|
42967
|
+
p.collateralToken.decimals
|
|
42968
|
+
),
|
|
42969
|
+
debtAmount: new Web3Number(
|
|
42970
|
+
p.debtAmount.toFixed(p.debtToken.decimals),
|
|
42971
|
+
p.debtToken.decimals
|
|
42972
|
+
)
|
|
42973
|
+
}));
|
|
42339
42974
|
const vesuPerPoolDebtDeltasToBorrow = this._computeperPoolDebtDeltasToBorrow();
|
|
42340
42975
|
assert(vesuPerPoolDebtDeltasToBorrow.length === this.vesuPoolStates.length, "vesuPerPoolDebtDeltasToBorrow length must match vesuPoolStates length");
|
|
42341
42976
|
this.vesuPerPoolDebtDeltasToBorrow = vesuPerPoolDebtDeltasToBorrow.map((item) => item.deltaDebt);
|
|
42342
42977
|
this.shouldVesuRebalance = vesuPerPoolDebtDeltasToBorrow.map((item) => item.shouldRebalance);
|
|
42343
42978
|
}
|
|
42979
|
+
/** `1 - limitBalanceBufferFactor` — multiplier applied to raw notionals for “usable” USD. */
|
|
42980
|
+
_usableFraction() {
|
|
42981
|
+
return 1;
|
|
42982
|
+
}
|
|
42344
42983
|
/**
|
|
42345
|
-
*
|
|
42346
|
-
*
|
|
42347
|
-
|
|
42348
|
-
|
|
42349
|
-
|
|
42350
|
-
|
|
42984
|
+
* Raw USD notional for a token row. USDC (and configured {@link usdcToken}) uses 1:1 from amount;
|
|
42985
|
+
* non-stable assets (e.g. WBTC in VA) use {@link TokenBalance.usdValue} from the pricer at refresh.
|
|
42986
|
+
*/
|
|
42987
|
+
_rawTokenUsd(tb) {
|
|
42988
|
+
if (!tb) return 0;
|
|
42989
|
+
if (this.usdcToken.address.eq(tb.token.address)) {
|
|
42990
|
+
return Number(tb.amount.toFixed(tb.token.decimals));
|
|
42991
|
+
}
|
|
42992
|
+
return tb.usdValue;
|
|
42993
|
+
}
|
|
42994
|
+
/** Apply safety buffer to a raw USD scalar. */
|
|
42995
|
+
bufferedUsd(rawUsd) {
|
|
42996
|
+
return rawUsd * this._usableFraction();
|
|
42997
|
+
}
|
|
42998
|
+
/** Convert a buffered “usable” USD amount to raw nominal USD (inverse of {@link bufferedUsd}). */
|
|
42999
|
+
rawUsdFromBuffered(bufferedUsd) {
|
|
43000
|
+
const bf = this._usableFraction();
|
|
43001
|
+
assert(bf > 0, "SolveBudget::rawUsdFromBuffered usable fraction must be positive");
|
|
43002
|
+
return bufferedUsd / bf;
|
|
43003
|
+
}
|
|
43004
|
+
/** Buffered USD notional for one token balance row. */
|
|
43005
|
+
bufferedTokenUsd(tb) {
|
|
43006
|
+
return this.bufferedUsd(this._rawTokenUsd(tb));
|
|
43007
|
+
}
|
|
43008
|
+
logStateSummary() {
|
|
43009
|
+
console.log("===== state summary =====");
|
|
43010
|
+
const aggregatedData = {
|
|
43011
|
+
unusedBalances: this.unusedBalance.map((b) => ({
|
|
43012
|
+
token: b.token.symbol,
|
|
43013
|
+
amount: b.amount.toNumber()
|
|
43014
|
+
})),
|
|
43015
|
+
walletBalance: this.walletBalance ? {
|
|
43016
|
+
token: this.walletBalance.token.symbol,
|
|
43017
|
+
amount: this.walletBalance.amount.toNumber()
|
|
43018
|
+
} : void 0,
|
|
43019
|
+
vaultAssetBalance: this.vaultAssetBalance ? {
|
|
43020
|
+
token: this.vaultAssetBalance.token.symbol,
|
|
43021
|
+
amount: this.vaultAssetBalance.amount.toNumber()
|
|
43022
|
+
} : void 0,
|
|
43023
|
+
vaultUsdcBalance: this.vaultUsdcBalance ? {
|
|
43024
|
+
token: this.vaultUsdcBalance.token.symbol,
|
|
43025
|
+
amount: this.vaultUsdcBalance.amount.toNumber()
|
|
43026
|
+
} : void 0,
|
|
43027
|
+
vesuPoolStates: this.vesuPoolStates.map((p) => ({
|
|
43028
|
+
poolId: p.poolId,
|
|
43029
|
+
collateralAmount: p.collateralAmount.toNumber(),
|
|
43030
|
+
debtAmount: p.debtAmount.toNumber()
|
|
43031
|
+
})),
|
|
43032
|
+
vesuBorrowCapacity: this.vesuBorrowCapacity,
|
|
43033
|
+
vesuRebalance: this.shouldVesuRebalance,
|
|
43034
|
+
vesuPerPoolDebtDeltasToBorrow: this.vesuPerPoolDebtDeltasToBorrow.map((d) => d.toNumber()),
|
|
43035
|
+
extendedBalance: this.extendedBalance?.balance.toNumber(),
|
|
43036
|
+
extendedEquity: this.extendedBalance?.equity.toNumber(),
|
|
43037
|
+
extendedAvailableForTrade: this.extendedBalance?.availableForTrade.toNumber(),
|
|
43038
|
+
extendedAvailableForWithdrawal: this.extendedBalance?.availableForWithdrawal.toNumber(),
|
|
43039
|
+
extendedUnrealisedPnl: this.extendedBalance?.unrealisedPnl.toNumber(),
|
|
43040
|
+
extendedPendingDeposit: this.extendedBalance?.pendingDeposit.toNumber(),
|
|
43041
|
+
extendedPositions: this.extendedPositions.map((p) => ({
|
|
43042
|
+
instrument: p.instrument,
|
|
43043
|
+
size: p.size.toNumber(),
|
|
43044
|
+
valueUsd: p.valueUsd.toNumber()
|
|
43045
|
+
}))
|
|
43046
|
+
};
|
|
43047
|
+
console.log(
|
|
43048
|
+
"unused balances",
|
|
43049
|
+
aggregatedData.unusedBalances.map((b) => `${b.token}=${b.amount}`).join(", ")
|
|
43050
|
+
);
|
|
43051
|
+
console.log(
|
|
43052
|
+
"wallet balance",
|
|
43053
|
+
aggregatedData.walletBalance ? `${aggregatedData.walletBalance.token}=${aggregatedData.walletBalance.amount}` : void 0
|
|
43054
|
+
);
|
|
43055
|
+
console.log(
|
|
43056
|
+
"vault asset balance",
|
|
43057
|
+
aggregatedData.vaultAssetBalance ? `${aggregatedData.vaultAssetBalance.token}=${aggregatedData.vaultAssetBalance.amount}` : void 0
|
|
43058
|
+
);
|
|
43059
|
+
console.log(
|
|
43060
|
+
"vault usdc balance",
|
|
43061
|
+
aggregatedData.vaultUsdcBalance ? `${aggregatedData.vaultUsdcBalance.token}=${aggregatedData.vaultUsdcBalance.amount}` : void 0
|
|
43062
|
+
);
|
|
43063
|
+
console.log(
|
|
43064
|
+
"vesu pool states",
|
|
43065
|
+
aggregatedData.vesuPoolStates.map(
|
|
43066
|
+
(p) => `${p.poolId.shortString()}=${p.collateralAmount} ${p.debtAmount}`
|
|
43067
|
+
).join(", ")
|
|
43068
|
+
);
|
|
43069
|
+
console.log("vesu borrow capacity", aggregatedData.vesuBorrowCapacity);
|
|
43070
|
+
console.log(
|
|
43071
|
+
"vesu rebalance",
|
|
43072
|
+
aggregatedData.vesuRebalance.map(String).join(", ")
|
|
43073
|
+
);
|
|
43074
|
+
console.log("vesu per pool debt deltas to borrow", aggregatedData.vesuPerPoolDebtDeltasToBorrow.join(", "));
|
|
43075
|
+
console.log("extended balance", aggregatedData.extendedBalance);
|
|
43076
|
+
console.log("extended equity", aggregatedData.extendedEquity);
|
|
43077
|
+
console.log("extended available for trade", aggregatedData.extendedAvailableForTrade);
|
|
43078
|
+
console.log("extended available for withdrawal", aggregatedData.extendedAvailableForWithdrawal);
|
|
43079
|
+
console.log("extended unrealised pnl", aggregatedData.extendedUnrealisedPnl);
|
|
43080
|
+
console.log("extended pending deposit", aggregatedData.extendedPendingDeposit);
|
|
43081
|
+
console.log(
|
|
43082
|
+
"extended positions",
|
|
43083
|
+
aggregatedData.extendedPositions.map(
|
|
43084
|
+
(p) => `${p.instrument}=${p.size} ${p.valueUsd}`
|
|
43085
|
+
).join(", ")
|
|
43086
|
+
);
|
|
43087
|
+
return aggregatedData;
|
|
43088
|
+
}
|
|
43089
|
+
/**
|
|
43090
|
+
* Initialise derived views for a solve cycle. Mutates only when pending
|
|
43091
|
+
* withdrawal from Extended is in transit (credits wallet raw balance).
|
|
42351
43092
|
*/
|
|
42352
43093
|
initBudget() {
|
|
42353
|
-
const debtDeltaNum = this.vesuPerPoolDebtDeltasToBorrow.reduce((a, b) => a + b.toNumber(), 0);
|
|
42354
|
-
let totalUnusedUsd = this.unusedBalance.reduce((a, b) => a + b.usdValue, 0);
|
|
42355
|
-
if (debtDeltaNum > 0) totalUnusedUsd += debtDeltaNum;
|
|
42356
|
-
const extAvailTrade = this.extendedBalance?.availableForTrade?.toNumber() ?? 0;
|
|
42357
|
-
if (extAvailTrade > 0) totalUnusedUsd += extAvailTrade;
|
|
42358
|
-
if (debtDeltaNum > 0) totalUnusedUsd += debtDeltaNum;
|
|
42359
|
-
this._vaUsd = this.vaultBalance?.usdValue ?? 0;
|
|
42360
|
-
this._walletUsd = this.walletBalance?.usdValue ?? 0;
|
|
42361
|
-
this._extAvailWithdraw = this.extendedBalance?.availableForWithdrawal?.toNumber() ?? 0;
|
|
42362
|
-
this._extAvailUpnl = this.extendedBalance?.unrealisedPnl?.toNumber() ?? 0;
|
|
42363
|
-
this._extAvailTrade = extAvailTrade;
|
|
42364
|
-
this._extPendingDeposit = this.extendedBalance?.pendingDeposit?.toNumber() ?? 0;
|
|
42365
|
-
this._vesuBorrowCapacity = debtDeltaNum;
|
|
42366
|
-
this._totalUnused = totalUnusedUsd;
|
|
42367
43094
|
const pendingDeposit = this.extendedBalance?.pendingDeposit?.toNumber() ?? 0;
|
|
42368
|
-
if (pendingDeposit
|
|
42369
|
-
this._extAvailTrade += pendingDeposit;
|
|
42370
|
-
this._totalUnused += pendingDeposit;
|
|
42371
|
-
logger.debug(`SolveBudget::initBudget pendingDeposit=${pendingDeposit} -> increased extAvailTrade`);
|
|
42372
|
-
} else if (pendingDeposit < 0) {
|
|
43095
|
+
if (pendingDeposit < 0) {
|
|
42373
43096
|
const inTransit = Math.abs(pendingDeposit);
|
|
42374
|
-
this.
|
|
42375
|
-
|
|
42376
|
-
|
|
43097
|
+
if (this.walletBalance) {
|
|
43098
|
+
this._addUsdToTokenBalance(this.walletBalance, inTransit);
|
|
43099
|
+
}
|
|
43100
|
+
logger.debug(`SolveBudget::initBudget pendingDeposit=${pendingDeposit} -> increased wallet raw USD by ${inTransit}`);
|
|
43101
|
+
}
|
|
43102
|
+
this._recomputeUnusedBalance();
|
|
43103
|
+
}
|
|
43104
|
+
/**
|
|
43105
|
+
* Apply a safety buffer to all liquid balances (VA, wallet, extended trade/withdraw/upnl,
|
|
43106
|
+
* unused balances). Call after withdrawal classification but before LTV/deposit classifiers
|
|
43107
|
+
* so that withdrawal uses full raw amounts while subsequent classifiers see buffered values.
|
|
43108
|
+
*/
|
|
43109
|
+
applyBuffer(factor) {
|
|
43110
|
+
if (factor <= 0 || factor >= 1) return;
|
|
43111
|
+
const mult = 1 - factor;
|
|
43112
|
+
const scaleTokenBalance = (tb) => {
|
|
43113
|
+
if (!tb) return;
|
|
43114
|
+
const newAmount = tb.amount.multipliedBy(mult);
|
|
43115
|
+
tb.amount = new Web3Number(newAmount.toFixed(tb.token.decimals), tb.token.decimals);
|
|
43116
|
+
tb.usdValue = tb.usdValue * mult;
|
|
43117
|
+
};
|
|
43118
|
+
scaleTokenBalance(this.vaultAssetBalance);
|
|
43119
|
+
scaleTokenBalance(this.vaultUsdcBalance);
|
|
43120
|
+
scaleTokenBalance(this.walletBalance);
|
|
43121
|
+
for (const ub of this.unusedBalance) {
|
|
43122
|
+
scaleTokenBalance(ub);
|
|
43123
|
+
}
|
|
43124
|
+
if (this.extendedBalance) {
|
|
43125
|
+
this.extendedBalance.availableForTrade = this.extendedBalance.availableForTrade.multipliedBy(mult);
|
|
43126
|
+
this.extendedBalance.availableForWithdrawal = this.extendedBalance.availableForWithdrawal.multipliedBy(mult);
|
|
43127
|
+
this.extendedBalance.unrealisedPnl = this.extendedBalance.unrealisedPnl.multipliedBy(mult);
|
|
42377
43128
|
}
|
|
43129
|
+
this._recomputeUnusedBalance();
|
|
43130
|
+
}
|
|
43131
|
+
get vesuPoolState() {
|
|
43132
|
+
assert(this.vesuPoolStates.length === 1, "SolveBudget::vesuPoolState: vesuPoolStates length must be 1");
|
|
43133
|
+
return this.vesuPoolStates[0];
|
|
42378
43134
|
}
|
|
42379
|
-
// ──
|
|
43135
|
+
// ── Derived getters (buffered where applicable) ─────────────────────
|
|
43136
|
+
/** Buffered VA USD: strategy-asset slot + optional USDC slot. */
|
|
42380
43137
|
get vaUsd() {
|
|
42381
|
-
return this.
|
|
43138
|
+
return this.bufferedTokenUsd(this.vaultAssetBalance) + this.bufferedTokenUsd(this.vaultUsdcBalance);
|
|
43139
|
+
}
|
|
43140
|
+
/** Buffered USD in VA strategy-asset bucket only. */
|
|
43141
|
+
get vaAssetUsd() {
|
|
43142
|
+
return this.bufferedTokenUsd(this.vaultAssetBalance);
|
|
43143
|
+
}
|
|
43144
|
+
/** Buffered USD in VA USDC bucket (0 when asset === USDC). */
|
|
43145
|
+
get vaUsdcUsd() {
|
|
43146
|
+
return this.bufferedTokenUsd(this.vaultUsdcBalance);
|
|
42382
43147
|
}
|
|
42383
43148
|
get walletUsd() {
|
|
42384
|
-
return this.
|
|
43149
|
+
return this.bufferedUsd(this._rawTokenUsd(this.walletBalance));
|
|
42385
43150
|
}
|
|
42386
43151
|
get vaWalletUsd() {
|
|
42387
|
-
return this.
|
|
43152
|
+
return this.vaUsd + this.walletUsd;
|
|
42388
43153
|
}
|
|
42389
43154
|
get extAvailWithdraw() {
|
|
42390
|
-
|
|
43155
|
+
const raw = this.extendedBalance?.availableForWithdrawal?.toNumber() ?? 0;
|
|
43156
|
+
return this.bufferedUsd(raw);
|
|
42391
43157
|
}
|
|
42392
43158
|
get extAvailUpnl() {
|
|
42393
|
-
|
|
43159
|
+
const raw = this.extendedBalance?.unrealisedPnl?.toNumber() ?? 0;
|
|
43160
|
+
return this.bufferedUsd(raw);
|
|
42394
43161
|
}
|
|
43162
|
+
/**
|
|
43163
|
+
* Buffered Extended available-for-trade plus positive {@link ExtendedBalanceState.pendingDeposit}
|
|
43164
|
+
* (deposit in transit is usable the same way as the pre-buffer implementation).
|
|
43165
|
+
*/
|
|
42395
43166
|
get extAvailTrade() {
|
|
42396
|
-
|
|
43167
|
+
const raw = this.extendedBalance?.availableForTrade?.toNumber() ?? 0;
|
|
43168
|
+
let v = this.bufferedUsd(raw);
|
|
43169
|
+
const pd = this.extendedBalance?.pendingDeposit?.toNumber() ?? 0;
|
|
43170
|
+
if (pd > 0) v += pd;
|
|
43171
|
+
return v;
|
|
43172
|
+
}
|
|
43173
|
+
get extPendingDeposit() {
|
|
43174
|
+
return this.extendedBalance?.pendingDeposit?.toNumber() ?? 0;
|
|
42397
43175
|
}
|
|
43176
|
+
/**
|
|
43177
|
+
* Aggregate positive per-pool borrow headroom (USD). Repay/borrow routes update
|
|
43178
|
+
* {@link vesuPerPoolDebtDeltasToBorrow}; no separate counter.
|
|
43179
|
+
*/
|
|
42398
43180
|
get vesuBorrowCapacity() {
|
|
42399
|
-
return this.
|
|
43181
|
+
return this.vesuPerPoolDebtDeltasToBorrow.reduce(
|
|
43182
|
+
(a, d) => a + Math.max(0, d.toNumber()),
|
|
43183
|
+
0
|
|
43184
|
+
);
|
|
42400
43185
|
}
|
|
43186
|
+
/** Diagnostic: buffered idle + positive debt delta + buffered Extended afT + in-flight deposit. */
|
|
42401
43187
|
get totalUnused() {
|
|
42402
|
-
|
|
43188
|
+
const debtSum = this.vesuPerPoolDebtDeltasToBorrow.reduce((a, b) => a + b.toNumber(), 0);
|
|
43189
|
+
let u = this.unusedBalance.reduce((a, b) => a + this.bufferedTokenUsd(b), 0);
|
|
43190
|
+
if (debtSum > 0) u += debtSum;
|
|
43191
|
+
const rawAft = this.extendedBalance?.availableForTrade?.toNumber() ?? 0;
|
|
43192
|
+
const aftBuf = this.bufferedUsd(rawAft);
|
|
43193
|
+
if (aftBuf > 0) u += aftBuf;
|
|
43194
|
+
const pd = this.extendedBalance?.pendingDeposit?.toNumber() ?? 0;
|
|
43195
|
+
if (pd > 0) u += pd;
|
|
43196
|
+
return u;
|
|
43197
|
+
}
|
|
43198
|
+
/** Sum of buffered USD across merged unused-balance rows (VA + wallet). */
|
|
43199
|
+
get unusedBalancesBufferedUsdSum() {
|
|
43200
|
+
return this.unusedBalance.reduce((a, b) => a + this.bufferedTokenUsd(b), 0);
|
|
43201
|
+
}
|
|
43202
|
+
/** Read-only snapshot view for validation / logging. */
|
|
43203
|
+
get unusedBalanceRows() {
|
|
43204
|
+
return this.unusedBalance;
|
|
43205
|
+
}
|
|
43206
|
+
/** Read-only Vesu pool view for solve computations. */
|
|
43207
|
+
get vesuPools() {
|
|
43208
|
+
return this.vesuPoolStates;
|
|
43209
|
+
}
|
|
43210
|
+
/** Read-only Extended positions view for solve computations. */
|
|
43211
|
+
get extendedPositionsView() {
|
|
43212
|
+
return this.extendedPositions;
|
|
43213
|
+
}
|
|
43214
|
+
/** Read-only Extended balance view for diagnostics / margin checks. */
|
|
43215
|
+
get extendedBalanceView() {
|
|
43216
|
+
return this.extendedBalance;
|
|
43217
|
+
}
|
|
43218
|
+
/** Current debt deltas per pool (positive=borrow, negative=repay). */
|
|
43219
|
+
get vesuDebtDeltas() {
|
|
43220
|
+
return this.vesuPerPoolDebtDeltasToBorrow;
|
|
43221
|
+
}
|
|
43222
|
+
/** Per-pool rebalance flags derived from target HF checks. */
|
|
43223
|
+
get vesuRebalanceFlags() {
|
|
43224
|
+
return this.shouldVesuRebalance;
|
|
43225
|
+
}
|
|
43226
|
+
/** Raw USD in VA (USDC slot + asset slot); spend caps when executing transfers. */
|
|
43227
|
+
_vaRawUsd() {
|
|
43228
|
+
return this._rawTokenUsd(this.vaultUsdcBalance) + this._rawTokenUsd(this.vaultAssetBalance);
|
|
43229
|
+
}
|
|
43230
|
+
_walletRawUsd() {
|
|
43231
|
+
return this._rawTokenUsd(this.walletBalance);
|
|
43232
|
+
}
|
|
43233
|
+
// ── Token snapshot helpers (keep vault / wallet / unusedBalance aligned) ─
|
|
43234
|
+
/** Remove up to `usd` notional from a token balance, scaling token amount proportionally. */
|
|
43235
|
+
_deductUsdFromTokenBalance(tb, usd) {
|
|
43236
|
+
if (usd <= 0) return;
|
|
43237
|
+
const take = Math.min(usd, tb.usdValue);
|
|
43238
|
+
if (take <= 0) return;
|
|
43239
|
+
const oldUsd = tb.usdValue;
|
|
43240
|
+
const newUsd = Math.max(0, oldUsd - take);
|
|
43241
|
+
tb.usdValue = newUsd;
|
|
43242
|
+
if (oldUsd <= 0) return;
|
|
43243
|
+
const ratio = newUsd / oldUsd;
|
|
43244
|
+
tb.amount = new Web3Number(
|
|
43245
|
+
(tb.amount.toNumber() * ratio).toFixed(tb.token.decimals),
|
|
43246
|
+
tb.token.decimals
|
|
43247
|
+
);
|
|
43248
|
+
}
|
|
43249
|
+
/** Add USD notional; infers price from current amount/usd when possible, else 1:1. */
|
|
43250
|
+
_addUsdToTokenBalance(tb, usd) {
|
|
43251
|
+
if (usd <= 0) return;
|
|
43252
|
+
const amtNum = tb.amount.toNumber();
|
|
43253
|
+
const price = amtNum > 0 && tb.usdValue > 0 ? tb.usdValue / amtNum : 1;
|
|
43254
|
+
const deltaTok = usd / price;
|
|
43255
|
+
tb.usdValue += usd;
|
|
43256
|
+
tb.amount = tb.amount.plus(
|
|
43257
|
+
new Web3Number(deltaTok.toFixed(tb.token.decimals), tb.token.decimals)
|
|
43258
|
+
);
|
|
42403
43259
|
}
|
|
42404
|
-
|
|
42405
|
-
|
|
43260
|
+
/**
|
|
43261
|
+
* Rebuilds {@link unusedBalance} from vault + wallet snapshots (same merge as refresh).
|
|
43262
|
+
*/
|
|
43263
|
+
_recomputeUnusedBalance() {
|
|
43264
|
+
const balanceMap = /* @__PURE__ */ new Map();
|
|
43265
|
+
const merge = (b) => {
|
|
43266
|
+
if (!b) return;
|
|
43267
|
+
const key = b.token.address.toString();
|
|
43268
|
+
const row = {
|
|
43269
|
+
token: b.token,
|
|
43270
|
+
amount: new Web3Number(b.amount.toFixed(b.token.decimals), b.token.decimals),
|
|
43271
|
+
usdValue: b.usdValue
|
|
43272
|
+
};
|
|
43273
|
+
const existing = balanceMap.get(key);
|
|
43274
|
+
if (existing) {
|
|
43275
|
+
existing.amount = new Web3Number(
|
|
43276
|
+
existing.amount.plus(row.amount).toFixed(existing.token.decimals),
|
|
43277
|
+
existing.token.decimals
|
|
43278
|
+
);
|
|
43279
|
+
existing.usdValue += row.usdValue;
|
|
43280
|
+
} else {
|
|
43281
|
+
balanceMap.set(key, row);
|
|
43282
|
+
}
|
|
43283
|
+
};
|
|
43284
|
+
merge(this.vaultAssetBalance);
|
|
43285
|
+
merge(this.vaultUsdcBalance);
|
|
43286
|
+
merge(this.walletBalance);
|
|
43287
|
+
this.unusedBalance = Array.from(balanceMap.values());
|
|
42406
43288
|
}
|
|
42407
43289
|
// ── Spend methods (return amount consumed, auto-decrement totalUnused) ─
|
|
42408
|
-
|
|
42409
|
-
|
|
42410
|
-
|
|
42411
|
-
|
|
42412
|
-
|
|
42413
|
-
|
|
42414
|
-
|
|
42415
|
-
|
|
42416
|
-
|
|
42417
|
-
|
|
42418
|
-
|
|
42419
|
-
|
|
42420
|
-
|
|
42421
|
-
|
|
42422
|
-
|
|
42423
|
-
|
|
42424
|
-
this.
|
|
42425
|
-
logger.debug(`SolveBudget::
|
|
42426
|
-
return
|
|
43290
|
+
/**
|
|
43291
|
+
* Spend VA **raw** USD (up to {@link vaRawUsd}). Prefer {@link vaultUsdcBalance} when present, then {@link vaultAssetBalance}.
|
|
43292
|
+
*/
|
|
43293
|
+
spendVA(rawDesired) {
|
|
43294
|
+
const capRaw = this._vaRawUsd();
|
|
43295
|
+
const usedRaw = Math.min(capRaw, Math.max(0, rawDesired));
|
|
43296
|
+
if (usedRaw <= CASE_THRESHOLD_USD) return 0;
|
|
43297
|
+
let rem = usedRaw;
|
|
43298
|
+
if (rem > 0 && this.vaultUsdcBalance && this.vaultUsdcBalance.usdValue > 0) {
|
|
43299
|
+
const fromUsdc = Math.min(rem, this.vaultUsdcBalance.usdValue);
|
|
43300
|
+
this._deductUsdFromTokenBalance(this.vaultUsdcBalance, fromUsdc);
|
|
43301
|
+
rem -= fromUsdc;
|
|
43302
|
+
}
|
|
43303
|
+
if (rem > 0 && this.vaultAssetBalance) {
|
|
43304
|
+
this._deductUsdFromTokenBalance(this.vaultAssetBalance, rem);
|
|
43305
|
+
}
|
|
43306
|
+
this._recomputeUnusedBalance();
|
|
43307
|
+
logger.debug(`SolveBudget::spendVA usedRaw=${usedRaw}, vaUsd=${this.vaUsd}, totalUnused=${this.totalUnused}`);
|
|
43308
|
+
return usedRaw;
|
|
42427
43309
|
}
|
|
42428
|
-
|
|
42429
|
-
|
|
42430
|
-
|
|
42431
|
-
|
|
42432
|
-
|
|
43310
|
+
/**
|
|
43311
|
+
* Spend nominal/raw USD from VA (e.g. Vesu repay, on-chain USDC). Does not apply the safety buffer to the cap.
|
|
43312
|
+
*/
|
|
43313
|
+
spendVaRawUsd(rawUsdDesired) {
|
|
43314
|
+
const capRaw = this._rawTokenUsd(this.vaultUsdcBalance) + this._rawTokenUsd(this.vaultAssetBalance);
|
|
43315
|
+
const usedRaw = Math.min(capRaw, Math.max(0, rawUsdDesired));
|
|
43316
|
+
if (usedRaw <= CASE_THRESHOLD_USD) return 0;
|
|
43317
|
+
let rem = usedRaw;
|
|
43318
|
+
if (rem > 0 && this.vaultUsdcBalance && this.vaultUsdcBalance.usdValue > 0) {
|
|
43319
|
+
const fromUsdc = Math.min(rem, this.vaultUsdcBalance.usdValue);
|
|
43320
|
+
this._deductUsdFromTokenBalance(this.vaultUsdcBalance, fromUsdc);
|
|
43321
|
+
rem -= fromUsdc;
|
|
43322
|
+
}
|
|
43323
|
+
if (rem > 0 && this.vaultAssetBalance) {
|
|
43324
|
+
this._deductUsdFromTokenBalance(this.vaultAssetBalance, rem);
|
|
43325
|
+
}
|
|
43326
|
+
this._recomputeUnusedBalance();
|
|
43327
|
+
logger.debug(`SolveBudget::spendVaRawUsd usedRaw=${usedRaw}, vaUsd=${this.vaUsd}, totalUnused=${this.totalUnused}`);
|
|
43328
|
+
return usedRaw;
|
|
42433
43329
|
}
|
|
42434
|
-
|
|
42435
|
-
|
|
43330
|
+
/**
|
|
43331
|
+
* Add **raw nominal USD** to VA (borrow proceeds, wallet→VA in raw USDC, etc.).
|
|
43332
|
+
*/
|
|
43333
|
+
addToVA(rawUsd) {
|
|
43334
|
+
assert(rawUsd >= 0, "SolveBudget::addToVA amount must be positive");
|
|
43335
|
+
if (rawUsd === 0) return;
|
|
43336
|
+
if (this.vaultUsdcBalance) {
|
|
43337
|
+
this._addUsdToTokenBalance(this.vaultUsdcBalance, rawUsd);
|
|
43338
|
+
} else if (this.vaultAssetBalance) {
|
|
43339
|
+
this._addUsdToTokenBalance(this.vaultAssetBalance, rawUsd);
|
|
43340
|
+
}
|
|
43341
|
+
this._recomputeUnusedBalance();
|
|
43342
|
+
logger.debug(`SolveBudget::addToVA rawUsd=${rawUsd}, vaUsd=${this.vaUsd}, totalUnused=${this.totalUnused}`);
|
|
43343
|
+
}
|
|
43344
|
+
spendWallet(rawDesired) {
|
|
43345
|
+
const capRaw = this._walletRawUsd();
|
|
43346
|
+
const usedRaw = Math.min(capRaw, Math.max(0, rawDesired));
|
|
43347
|
+
if (usedRaw <= CASE_THRESHOLD_USD) return 0;
|
|
43348
|
+
if (this.walletBalance) {
|
|
43349
|
+
this._deductUsdFromTokenBalance(this.walletBalance, usedRaw);
|
|
43350
|
+
}
|
|
43351
|
+
this._recomputeUnusedBalance();
|
|
43352
|
+
logger.debug(`SolveBudget::spendWallet usedRaw=${usedRaw}, walletUsd=${this.walletUsd}, totalUnused=${this.totalUnused}`);
|
|
43353
|
+
return usedRaw;
|
|
43354
|
+
}
|
|
43355
|
+
/** Add **raw nominal USD** to the operator wallet balance (e.g. Extended→wallet withdrawal). */
|
|
43356
|
+
addToWallet(rawUsd) {
|
|
43357
|
+
assert(rawUsd >= 0, "SolveBudget::addToWallet amount must be positive");
|
|
43358
|
+
if (rawUsd === 0) return;
|
|
43359
|
+
if (this.walletBalance) {
|
|
43360
|
+
this._addUsdToTokenBalance(this.walletBalance, rawUsd);
|
|
43361
|
+
}
|
|
43362
|
+
this._recomputeUnusedBalance();
|
|
43363
|
+
logger.debug(`SolveBudget::addToWallet rawUsd=${rawUsd}, walletUsd=${this.walletUsd}, totalUnused=${this.totalUnused}`);
|
|
43364
|
+
}
|
|
43365
|
+
spendVAWallet(rawDesired) {
|
|
43366
|
+
let remaining = Math.max(0, rawDesired);
|
|
42436
43367
|
const vaSpent = this.spendVA(remaining);
|
|
42437
43368
|
remaining -= vaSpent;
|
|
42438
43369
|
const walletSpent = this.spendWallet(remaining);
|
|
42439
43370
|
return vaSpent + walletSpent;
|
|
42440
43371
|
}
|
|
42441
|
-
_updateExtAvailWithdraw(
|
|
42442
|
-
|
|
42443
|
-
|
|
43372
|
+
_updateExtAvailWithdraw(desiredRaw, isSpend) {
|
|
43373
|
+
assert(desiredRaw > 0, "SolveBudget::_updateExtAvailWithdraw amount must be positive");
|
|
43374
|
+
let rawDelta;
|
|
42444
43375
|
if (isSpend) {
|
|
42445
|
-
|
|
42446
|
-
|
|
43376
|
+
const capRaw = this.extendedBalance?.availableForWithdrawal?.toNumber() ?? 0;
|
|
43377
|
+
const useRaw = Math.min(capRaw, desiredRaw);
|
|
43378
|
+
if (useRaw <= CASE_THRESHOLD_USD) return 0;
|
|
43379
|
+
rawDelta = -useRaw;
|
|
43380
|
+
} else {
|
|
43381
|
+
rawDelta = desiredRaw;
|
|
42447
43382
|
}
|
|
42448
|
-
this._extAvailWithdraw += amount;
|
|
42449
|
-
this._totalUnused += amount;
|
|
42450
|
-
this._extAvailTrade += amount;
|
|
42451
43383
|
if (this.extendedBalance) {
|
|
42452
|
-
this.extendedBalance.availableForWithdrawal = safeUsdcWeb3Number(this.extendedBalance.availableForWithdrawal.toNumber() +
|
|
42453
|
-
this.extendedBalance.availableForTrade = safeUsdcWeb3Number(this.extendedBalance.availableForTrade.toNumber() +
|
|
42454
|
-
this.extendedBalance.balance = safeUsdcWeb3Number(this.extendedBalance.balance.toNumber() +
|
|
42455
|
-
this.extendedBalance.equity = safeUsdcWeb3Number(this.extendedBalance.equity.toNumber() +
|
|
43384
|
+
this.extendedBalance.availableForWithdrawal = safeUsdcWeb3Number(this.extendedBalance.availableForWithdrawal.toNumber() + rawDelta);
|
|
43385
|
+
this.extendedBalance.availableForTrade = safeUsdcWeb3Number(this.extendedBalance.availableForTrade.toNumber() + rawDelta);
|
|
43386
|
+
this.extendedBalance.balance = safeUsdcWeb3Number(this.extendedBalance.balance.toNumber() + rawDelta);
|
|
43387
|
+
this.extendedBalance.equity = safeUsdcWeb3Number(this.extendedBalance.equity.toNumber() + rawDelta);
|
|
42456
43388
|
}
|
|
42457
|
-
logger.debug(`SolveBudget::updateExtAvailWithdraw
|
|
42458
|
-
return
|
|
43389
|
+
logger.debug(`SolveBudget::updateExtAvailWithdraw rawDelta=${rawDelta}, extAvailWithdraw=${this.extAvailWithdraw}, totalUnused=${this.totalUnused}`);
|
|
43390
|
+
return rawDelta;
|
|
42459
43391
|
}
|
|
42460
|
-
_updateExtAvailUpnl(
|
|
42461
|
-
|
|
42462
|
-
|
|
43392
|
+
_updateExtAvailUpnl(desiredRaw, isSpend) {
|
|
43393
|
+
assert(desiredRaw > 0, "SolveBudget::_updateExtAvailUpnl amount must be positive");
|
|
43394
|
+
let rawDelta;
|
|
42463
43395
|
if (isSpend) {
|
|
42464
|
-
|
|
42465
|
-
|
|
43396
|
+
const capRaw = this.extendedBalance?.unrealisedPnl?.toNumber() ?? 0;
|
|
43397
|
+
const useRaw = Math.min(capRaw, desiredRaw);
|
|
43398
|
+
if (useRaw <= CASE_THRESHOLD_USD) return 0;
|
|
43399
|
+
rawDelta = -useRaw;
|
|
43400
|
+
} else {
|
|
43401
|
+
rawDelta = desiredRaw;
|
|
42466
43402
|
}
|
|
42467
|
-
this._extAvailUpnl += amount;
|
|
42468
|
-
this._totalUnused += amount;
|
|
42469
43403
|
if (this.extendedBalance) {
|
|
42470
|
-
this.extendedBalance.unrealisedPnl = safeUsdcWeb3Number(this.extendedBalance.unrealisedPnl.toNumber() +
|
|
42471
|
-
this.extendedBalance.balance = safeUsdcWeb3Number(this.extendedBalance.balance.toNumber() +
|
|
42472
|
-
this.extendedBalance.equity = safeUsdcWeb3Number(this.extendedBalance.equity.toNumber() +
|
|
42473
|
-
this.extendedBalance.availableForTrade = safeUsdcWeb3Number(this.extendedBalance.availableForTrade.toNumber() +
|
|
42474
|
-
}
|
|
42475
|
-
logger.debug(`SolveBudget::updateExtAvailUpnl
|
|
42476
|
-
return
|
|
42477
|
-
}
|
|
42478
|
-
spendExtAvailTrade(
|
|
42479
|
-
const used = this._updateExtAvailWithdraw(
|
|
42480
|
-
const usedUpnl = this._updateExtAvailUpnl(
|
|
42481
|
-
logger.debug(`SolveBudget::updateExtAvailTrade
|
|
43404
|
+
this.extendedBalance.unrealisedPnl = safeUsdcWeb3Number(this.extendedBalance.unrealisedPnl.toNumber() + rawDelta);
|
|
43405
|
+
this.extendedBalance.balance = safeUsdcWeb3Number(this.extendedBalance.balance.toNumber() + rawDelta);
|
|
43406
|
+
this.extendedBalance.equity = safeUsdcWeb3Number(this.extendedBalance.equity.toNumber() + rawDelta);
|
|
43407
|
+
this.extendedBalance.availableForTrade = safeUsdcWeb3Number(this.extendedBalance.availableForTrade.toNumber() + rawDelta);
|
|
43408
|
+
}
|
|
43409
|
+
logger.debug(`SolveBudget::updateExtAvailUpnl rawDelta=${rawDelta}, extAvailUpnl=${this.extAvailUpnl}, totalUnused=${this.totalUnused}`);
|
|
43410
|
+
return rawDelta;
|
|
43411
|
+
}
|
|
43412
|
+
spendExtAvailTrade(rawDesired) {
|
|
43413
|
+
const used = this._updateExtAvailWithdraw(rawDesired, true);
|
|
43414
|
+
const usedUpnl = this._updateExtAvailUpnl(rawDesired, true);
|
|
43415
|
+
logger.debug(`SolveBudget::updateExtAvailTrade rawSum=${used + usedUpnl}, extAvailTrade=${this.extAvailTrade}, totalUnused=${this.totalUnused}`);
|
|
42482
43416
|
return used + usedUpnl;
|
|
42483
43417
|
}
|
|
42484
|
-
|
|
42485
|
-
|
|
43418
|
+
// simply reduces available amounts, but maintains equity and balance.
|
|
43419
|
+
spendExtAvailTradeToEquityOnly(rawDesired) {
|
|
43420
|
+
const used = this._updateExtAvailWithdraw(rawDesired, true);
|
|
43421
|
+
const remaining = rawDesired - Math.abs(used);
|
|
43422
|
+
const usedUpnl = remaining > 0 ? this._updateExtAvailUpnl(remaining, true) : 0;
|
|
43423
|
+
if (this.extendedBalance) {
|
|
43424
|
+
const net = Math.abs(used) + Math.abs(usedUpnl);
|
|
43425
|
+
if (net.toFixed(0) != rawDesired.toFixed(0)) {
|
|
43426
|
+
throw new Error(`SolveBudget::spendExtAvailTradeToEquityOnly net=${net} != rawDesired=${rawDesired}`);
|
|
43427
|
+
}
|
|
43428
|
+
this.extendedBalance.equity = safeUsdcWeb3Number(this.extendedBalance.equity.toNumber() + net);
|
|
43429
|
+
this.extendedBalance.balance = safeUsdcWeb3Number(this.extendedBalance.balance.toNumber() + net);
|
|
43430
|
+
}
|
|
43431
|
+
logger.debug(`SolveBudget::updateExtAvailTrade rawSum=${used + usedUpnl}, extAvailTrade=${this.extAvailTrade}, totalUnused=${this.totalUnused}`);
|
|
43432
|
+
return used + usedUpnl;
|
|
42486
43433
|
}
|
|
42487
|
-
|
|
42488
|
-
this._updateExtAvailWithdraw(
|
|
42489
|
-
|
|
43434
|
+
spendExtAvailWithdraw(rawDesired) {
|
|
43435
|
+
return this._updateExtAvailWithdraw(rawDesired, true);
|
|
43436
|
+
}
|
|
43437
|
+
spendExtAvailUpnl(rawDesired) {
|
|
43438
|
+
return this._updateExtAvailUpnl(rawDesired, true);
|
|
43439
|
+
}
|
|
43440
|
+
/**
|
|
43441
|
+
* Withdraw from Extended **withdrawal bucket only** to operator wallet (planning).
|
|
43442
|
+
* Used when VA must be funded from Extended and withdraw should be exhausted before unrealised PnL.
|
|
43443
|
+
*/
|
|
43444
|
+
spendAvailWithdrawToWallet(rawDesired) {
|
|
43445
|
+
const want = Math.max(0, rawDesired);
|
|
43446
|
+
if (want <= CASE_THRESHOLD_USD) return 0;
|
|
43447
|
+
const rawDelta = this._updateExtAvailWithdraw(want, true);
|
|
43448
|
+
if (rawDelta === 0) return 0;
|
|
43449
|
+
const used = -rawDelta;
|
|
43450
|
+
this.addToWallet(used);
|
|
43451
|
+
return used;
|
|
43452
|
+
}
|
|
43453
|
+
/**
|
|
43454
|
+
* Required Extended equity (USD) for current open positions: total notional ÷ strategy leverage.
|
|
43455
|
+
* Same basis as {@link ExtendedSVKVesuStateManager._classifyLtvExtended} margin check.
|
|
43456
|
+
*/
|
|
43457
|
+
_extendedMarginRequirementUsd() {
|
|
43458
|
+
const lev = calculateExtendedLevergae();
|
|
43459
|
+
if (lev <= 0 || this.extendedPositions.length === 0) return 0;
|
|
43460
|
+
const totalPosUsd = this.extendedPositions.reduce(
|
|
43461
|
+
(s, p) => s + p.valueUsd.toNumber(),
|
|
43462
|
+
0
|
|
43463
|
+
);
|
|
43464
|
+
return totalPosUsd / lev;
|
|
43465
|
+
}
|
|
43466
|
+
/** How much more equity is needed before deposits should increase withdraw / trade availability. */
|
|
43467
|
+
_extendedEquityShortfallUsd() {
|
|
43468
|
+
if (!this.extendedBalance) return 0;
|
|
43469
|
+
const req = this._extendedMarginRequirementUsd();
|
|
43470
|
+
const eq = this.extendedBalance.equity.toNumber();
|
|
43471
|
+
return Math.max(0, req - eq);
|
|
43472
|
+
}
|
|
43473
|
+
/**
|
|
43474
|
+
* Credits a USDC inflow on Extended. Fills margin shortfall (balance+equity only) first;
|
|
43475
|
+
* any remainder is credited across balance, equity, availableForWithdrawal, and availableForTrade.
|
|
43476
|
+
*/
|
|
43477
|
+
addToExtAvailTrade(rawUsd) {
|
|
43478
|
+
assert(rawUsd >= 0, "SolveBudget::addToExtAvailTrade amount must be non-negative");
|
|
43479
|
+
if (rawUsd <= CASE_THRESHOLD_USD) return;
|
|
43480
|
+
if (!this.extendedBalance) {
|
|
43481
|
+
logger.warn("SolveBudget::addToExtAvailTrade skipped \u2014 no extendedBalance");
|
|
43482
|
+
return;
|
|
43483
|
+
}
|
|
43484
|
+
const shortfall = this._extendedEquityShortfallUsd();
|
|
43485
|
+
const toMargin = Math.min(rawUsd, shortfall);
|
|
43486
|
+
const toLiquid = rawUsd - toMargin;
|
|
43487
|
+
if (toMargin > CASE_THRESHOLD_USD) {
|
|
43488
|
+
const b = this.extendedBalance.balance.toNumber();
|
|
43489
|
+
const e = this.extendedBalance.equity.toNumber();
|
|
43490
|
+
this.extendedBalance.balance = safeUsdcWeb3Number(b + toMargin);
|
|
43491
|
+
this.extendedBalance.equity = safeUsdcWeb3Number(e + toMargin);
|
|
43492
|
+
logger.debug(
|
|
43493
|
+
`SolveBudget::addToExtAvailTrade margin-first rawUsd=${toMargin} (shortfallBefore=${shortfall}, balance=${b + toMargin}, equity=${e + toMargin})`
|
|
43494
|
+
);
|
|
43495
|
+
}
|
|
43496
|
+
if (toLiquid > CASE_THRESHOLD_USD) {
|
|
43497
|
+
this._updateExtAvailWithdraw(toLiquid, false);
|
|
43498
|
+
}
|
|
43499
|
+
logger.debug(
|
|
43500
|
+
`SolveBudget::addToExtAvailTrade total rawUsd=${rawUsd} toLiquid=${toLiquid} extAvailTrade=${this.extAvailTrade}, totalUnused=${this.totalUnused}`
|
|
43501
|
+
);
|
|
42490
43502
|
}
|
|
42491
43503
|
spendVesuBorrowCapacity(desired) {
|
|
42492
|
-
const used = Math.min(this.
|
|
42493
|
-
this._vesuBorrowCapacity -= used;
|
|
42494
|
-
this._totalUnused -= used;
|
|
43504
|
+
const used = Math.min(this.vesuBorrowCapacity, Math.max(0, desired));
|
|
42495
43505
|
let spendsByPool = [];
|
|
42496
43506
|
for (let index = 0; index < this.vesuPerPoolDebtDeltasToBorrow.length; index++) {
|
|
42497
43507
|
const d = this.vesuPerPoolDebtDeltasToBorrow[index];
|
|
@@ -42502,13 +43512,12 @@ var SolveBudget = class {
|
|
|
42502
43512
|
this.vesuPoolStates[index].debtUsdValue = this.vesuPoolStates[index].debtAmount.toNumber() * this.vesuPoolStates[index].debtPrice;
|
|
42503
43513
|
spendsByPool.push({ poolId: this.vesuPoolStates[index].poolId, amount: safeUsdcWeb3Number(borrowed), collateralToken: this.vesuPoolStates[index].collateralToken, debtToken: this.vesuPoolStates[index].debtToken });
|
|
42504
43514
|
}
|
|
42505
|
-
logger.debug(`SolveBudget::spendVesuBorrowCapacity used=${used}, vesuBorrowCapacity=${this.
|
|
43515
|
+
logger.debug(`SolveBudget::spendVesuBorrowCapacity used=${used}, vesuBorrowCapacity=${this.vesuBorrowCapacity}, totalUnused=${this.totalUnused}`);
|
|
42506
43516
|
return { used, spendsByPool };
|
|
42507
43517
|
}
|
|
42508
43518
|
repayVesuBorrowCapacity(desired) {
|
|
42509
43519
|
assert(desired > 0, "SolveBudget::repayVesuBorrowCapacity desired must be positive");
|
|
42510
43520
|
const used = desired;
|
|
42511
|
-
this._vesuBorrowCapacity += used;
|
|
42512
43521
|
const spendsByPool = [];
|
|
42513
43522
|
for (let index = 0; index < this.vesuPerPoolDebtDeltasToBorrow.length; index++) {
|
|
42514
43523
|
const d = this.vesuPerPoolDebtDeltasToBorrow[index];
|
|
@@ -42518,7 +43527,7 @@ var SolveBudget = class {
|
|
|
42518
43527
|
this.vesuPoolStates[index].debtAmount = safeUsdcWeb3Number(this.vesuPoolStates[index].debtAmount.toNumber() - repaid);
|
|
42519
43528
|
spendsByPool.push({ poolId: this.vesuPoolStates[index].poolId, amount: safeUsdcWeb3Number(-repaid), collateralToken: this.vesuPoolStates[index].collateralToken, debtToken: this.vesuPoolStates[index].debtToken });
|
|
42520
43529
|
}
|
|
42521
|
-
logger.debug(`SolveBudget::repayVesuBorrowCapacity used=${used}, vesuBorrowCapacity=${this.
|
|
43530
|
+
logger.debug(`SolveBudget::repayVesuBorrowCapacity used=${used}, vesuBorrowCapacity=${this.vesuBorrowCapacity}, totalUnused=${this.totalUnused}`);
|
|
42522
43531
|
return { used, spendsByPool };
|
|
42523
43532
|
}
|
|
42524
43533
|
// ── State mutation ──────────────────────────────────────────────────
|
|
@@ -42540,13 +43549,21 @@ var SolveBudget = class {
|
|
|
42540
43549
|
pool.debtUsdValue = pool.debtAmount.toNumber() * pool.debtPrice;
|
|
42541
43550
|
const vesuPerPoolDebtDeltasToBorrow = this._computeperPoolDebtDeltasToBorrow();
|
|
42542
43551
|
this.vesuPerPoolDebtDeltasToBorrow = vesuPerPoolDebtDeltasToBorrow.map((item) => item.deltaDebt);
|
|
42543
|
-
const sum = this.vesuPerPoolDebtDeltasToBorrow.reduce((a, b) => a.plus(b), new Web3Number(0, USDC_TOKEN_DECIMALS));
|
|
42544
|
-
this._vesuBorrowCapacity = sum.toNumber();
|
|
42545
43552
|
this.shouldVesuRebalance = vesuPerPoolDebtDeltasToBorrow.map((item) => item.shouldRebalance);
|
|
42546
43553
|
}
|
|
42547
|
-
/**
|
|
42548
|
-
|
|
42549
|
-
|
|
43554
|
+
/**
|
|
43555
|
+
* Update Extended position size after a lever route; sync {@link ExtendedPositionState.valueUsd}
|
|
43556
|
+
* and margin buckets (released USD on decrease, locked USD on increase).
|
|
43557
|
+
*
|
|
43558
|
+
* @param collateralPriceUsd BTC collateral price for notional / margin math; if omitted, uses
|
|
43559
|
+
* existing valueUsd / |size| or the first Vesu pool collateral price.
|
|
43560
|
+
*/
|
|
43561
|
+
applyExtendedExposureDelta(instrument, sizeDelta, collateralPriceUsd) {
|
|
43562
|
+
const btcEps = 10 ** -COLLATERAL_PRECISION;
|
|
43563
|
+
const lev = calculateExtendedLevergae();
|
|
43564
|
+
let pos = this.extendedPositions.find((p) => p.instrument === instrument);
|
|
43565
|
+
const oldAbs = pos ? Math.abs(pos.size.toNumber()) : 0;
|
|
43566
|
+
const oldValUsd = pos ? pos.valueUsd.toNumber() : 0;
|
|
42550
43567
|
if (pos) {
|
|
42551
43568
|
pos.size = new Web3Number(pos.size.plus(sizeDelta).toFixed(8), 8);
|
|
42552
43569
|
} else if (sizeDelta.toNumber() !== 0) {
|
|
@@ -42557,6 +43574,56 @@ var SolveBudget = class {
|
|
|
42557
43574
|
valueUsd: new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
42558
43575
|
leverage: "0"
|
|
42559
43576
|
});
|
|
43577
|
+
pos = this.extendedPositions[this.extendedPositions.length - 1];
|
|
43578
|
+
} else {
|
|
43579
|
+
return;
|
|
43580
|
+
}
|
|
43581
|
+
const newAbs = Math.abs(pos.size.toNumber());
|
|
43582
|
+
let price = collateralPriceUsd;
|
|
43583
|
+
if (price === void 0 || price <= 0) {
|
|
43584
|
+
price = oldAbs > btcEps ? oldValUsd / oldAbs : this.vesuPoolStates[0]?.collateralPrice ?? 0;
|
|
43585
|
+
}
|
|
43586
|
+
if (price > 0) {
|
|
43587
|
+
pos.valueUsd = new Web3Number(
|
|
43588
|
+
(newAbs * price).toFixed(USDC_TOKEN_DECIMALS),
|
|
43589
|
+
USDC_TOKEN_DECIMALS
|
|
43590
|
+
);
|
|
43591
|
+
}
|
|
43592
|
+
if (!this.extendedBalance || lev <= 0 || price <= 0) return;
|
|
43593
|
+
const dAbs = newAbs - oldAbs;
|
|
43594
|
+
if (dAbs < -btcEps) {
|
|
43595
|
+
const releasedUsd = -dAbs * price / lev;
|
|
43596
|
+
if (releasedUsd > CASE_THRESHOLD_USD) {
|
|
43597
|
+
this.addToExtAvailTrade(releasedUsd);
|
|
43598
|
+
}
|
|
43599
|
+
} else if (dAbs > btcEps) {
|
|
43600
|
+
const lockedUsd = dAbs * price / lev;
|
|
43601
|
+
if (lockedUsd > CASE_THRESHOLD_USD) {
|
|
43602
|
+
this._lockExtendedMarginUsd(lockedUsd);
|
|
43603
|
+
}
|
|
43604
|
+
}
|
|
43605
|
+
}
|
|
43606
|
+
/** Pull margin for larger Extended exposure from liquid buckets, then balance/equity. */
|
|
43607
|
+
_lockExtendedMarginUsd(lockedUsd) {
|
|
43608
|
+
if (lockedUsd <= CASE_THRESHOLD_USD || !this.extendedBalance) return;
|
|
43609
|
+
let rem = lockedUsd;
|
|
43610
|
+
const uw = Math.min(rem, Math.max(0, this.extendedBalance.availableForWithdrawal.toNumber()));
|
|
43611
|
+
if (uw > 0) {
|
|
43612
|
+
this._updateExtAvailWithdraw(uw, true);
|
|
43613
|
+
rem -= uw;
|
|
43614
|
+
}
|
|
43615
|
+
if (rem > 0) {
|
|
43616
|
+
const uu = Math.min(rem, Math.max(0, this.extendedBalance.unrealisedPnl.toNumber()));
|
|
43617
|
+
if (uu > 0) {
|
|
43618
|
+
this._updateExtAvailUpnl(uu, true);
|
|
43619
|
+
rem -= uu;
|
|
43620
|
+
}
|
|
43621
|
+
}
|
|
43622
|
+
if (rem > 0) {
|
|
43623
|
+
const b = this.extendedBalance.balance.toNumber();
|
|
43624
|
+
const e = this.extendedBalance.equity.toNumber();
|
|
43625
|
+
this.extendedBalance.balance = safeUsdcWeb3Number(b - rem);
|
|
43626
|
+
this.extendedBalance.equity = safeUsdcWeb3Number(e - rem);
|
|
42560
43627
|
}
|
|
42561
43628
|
}
|
|
42562
43629
|
/**
|
|
@@ -42584,6 +43651,23 @@ var SolveBudget = class {
|
|
|
42584
43651
|
return output;
|
|
42585
43652
|
}
|
|
42586
43653
|
};
|
|
43654
|
+
function createSolveBudgetFromRawState(params) {
|
|
43655
|
+
const budget = new SolveBudget({
|
|
43656
|
+
assetToken: params.assetToken,
|
|
43657
|
+
usdcToken: params.usdcToken,
|
|
43658
|
+
unusedBalance: params.unusedBalance,
|
|
43659
|
+
walletBalance: params.walletBalance,
|
|
43660
|
+
vaultAssetBalance: params.vaultAssetBalance,
|
|
43661
|
+
vaultUsdcBalance: params.vaultUsdcBalance,
|
|
43662
|
+
extendedPositions: params.extendedPositions,
|
|
43663
|
+
extendedBalance: params.extendedBalance,
|
|
43664
|
+
vesuPoolStates: params.vesuPoolStates
|
|
43665
|
+
});
|
|
43666
|
+
if (params.limitBalanceBufferFactor && params.limitBalanceBufferFactor > 0) {
|
|
43667
|
+
budget.applyBuffer(params.limitBalanceBufferFactor);
|
|
43668
|
+
}
|
|
43669
|
+
return budget;
|
|
43670
|
+
}
|
|
42587
43671
|
var ExtendedSVKVesuStateManager = class {
|
|
42588
43672
|
constructor(config) {
|
|
42589
43673
|
this._tag = "ExtendedSVKVesuStateManager";
|
|
@@ -42619,7 +43703,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42619
43703
|
vesuAllocationUsd: safeUsdcWeb3Number(0),
|
|
42620
43704
|
extendedAllocationUsd: safeUsdcWeb3Number(0),
|
|
42621
43705
|
bringLiquidityAmount: safeUsdcWeb3Number(0),
|
|
42622
|
-
pendingDeposit:
|
|
43706
|
+
pendingDeposit: safeUsdcWeb3Number(0)
|
|
42623
43707
|
};
|
|
42624
43708
|
this._logSolveResult(result);
|
|
42625
43709
|
return result;
|
|
@@ -42634,30 +43718,44 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42634
43718
|
async _refresh() {
|
|
42635
43719
|
logger.info(`${this._tag}::_refresh starting`);
|
|
42636
43720
|
const [
|
|
42637
|
-
|
|
43721
|
+
vaultAssetBalance,
|
|
43722
|
+
vaultUsdcBalance,
|
|
42638
43723
|
walletBalance,
|
|
42639
43724
|
vesuPoolStates,
|
|
42640
43725
|
extendedBalance,
|
|
42641
43726
|
extendedPositions
|
|
42642
43727
|
] = await Promise.all([
|
|
42643
|
-
this.
|
|
43728
|
+
this._fetchVaultAllocatorAssetBalance(),
|
|
43729
|
+
this._fetchVaultAllocatorUsdcBalanceIfDistinct(),
|
|
42644
43730
|
this._fetchWalletBalances(),
|
|
42645
43731
|
this._fetchAllVesuPoolStates(),
|
|
42646
43732
|
this._fetchExtendedBalance(),
|
|
42647
43733
|
this._fetchExtendedPositions()
|
|
42648
43734
|
]);
|
|
42649
|
-
logger.verbose(
|
|
43735
|
+
logger.verbose(
|
|
43736
|
+
`${this._tag}::_refresh VA asset ${vaultAssetBalance.token.symbol}=$${vaultAssetBalance.usdValue.toFixed(2)}${vaultUsdcBalance ? `, VA USDC=$${vaultUsdcBalance.usdValue.toFixed(2)}` : ""}, wallet=${walletBalance.usdValue}`
|
|
43737
|
+
);
|
|
42650
43738
|
const unusedBalance = this._computeUnusedBalances(
|
|
42651
|
-
|
|
43739
|
+
vaultAssetBalance,
|
|
43740
|
+
vaultUsdcBalance,
|
|
42652
43741
|
walletBalance
|
|
42653
43742
|
);
|
|
42654
|
-
this._budget =
|
|
42655
|
-
|
|
43743
|
+
this._budget = createSolveBudgetFromRawState({
|
|
43744
|
+
assetToken: this._config.assetToken,
|
|
43745
|
+
usdcToken: this._config.usdcToken,
|
|
42656
43746
|
unusedBalance,
|
|
42657
43747
|
walletBalance,
|
|
42658
|
-
|
|
43748
|
+
vaultAssetBalance,
|
|
43749
|
+
vaultUsdcBalance,
|
|
42659
43750
|
extendedPositions,
|
|
42660
|
-
extendedBalance
|
|
43751
|
+
extendedBalance: {
|
|
43752
|
+
availableForTrade: extendedBalance?.availableForTrade || new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
43753
|
+
availableForWithdrawal: extendedBalance?.availableForWithdrawal || new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
43754
|
+
unrealisedPnl: extendedBalance?.unrealisedPnl || new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
43755
|
+
balance: extendedBalance?.balance || new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
43756
|
+
equity: extendedBalance?.equity || new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
43757
|
+
pendingDeposit: extendedBalance?.pendingDeposit || new Web3Number(0, USDC_TOKEN_DECIMALS)
|
|
43758
|
+
},
|
|
42661
43759
|
vesuPoolStates
|
|
42662
43760
|
});
|
|
42663
43761
|
const totalUnusedUsd = unusedBalance.reduce(
|
|
@@ -42669,10 +43767,14 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42669
43767
|
);
|
|
42670
43768
|
}
|
|
42671
43769
|
// todo add communication check with python server of extended. if not working, throw error in solve function.
|
|
43770
|
+
/** True when strategy asset and USDC share one token — VA USDC slot is unused (all in asset balance). */
|
|
43771
|
+
_vaultAssetAndUsdcAreSameToken() {
|
|
43772
|
+
return this._config.assetToken.address.eq(this._config.usdcToken.address);
|
|
43773
|
+
}
|
|
42672
43774
|
/**
|
|
42673
|
-
* Reads the
|
|
43775
|
+
* Reads the {@link StateManagerConfig.assetToken} balance idle in the vault allocator.
|
|
42674
43776
|
*/
|
|
42675
|
-
async
|
|
43777
|
+
async _fetchVaultAllocatorAssetBalance() {
|
|
42676
43778
|
const { assetToken, vaultAllocator, networkConfig, pricer } = this._config;
|
|
42677
43779
|
const balance = await new ERC20(networkConfig).balanceOf(
|
|
42678
43780
|
assetToken.address,
|
|
@@ -42684,20 +43786,38 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42684
43786
|
return { token: assetToken, amount: balance, usdValue };
|
|
42685
43787
|
}
|
|
42686
43788
|
/**
|
|
42687
|
-
*
|
|
42688
|
-
*
|
|
42689
|
-
|
|
42690
|
-
|
|
42691
|
-
|
|
42692
|
-
|
|
43789
|
+
* Reads {@link StateManagerConfig.usdcToken} in the vault allocator when it differs from
|
|
43790
|
+
* {@link StateManagerConfig.assetToken}. Otherwise returns null (treat VA USDC as 0; stablecoin is only under asset).
|
|
43791
|
+
*/
|
|
43792
|
+
async _fetchVaultAllocatorUsdcBalanceIfDistinct() {
|
|
43793
|
+
if (this._vaultAssetAndUsdcAreSameToken()) return null;
|
|
43794
|
+
const { usdcToken, vaultAllocator, networkConfig, pricer } = this._config;
|
|
43795
|
+
const balance = await new ERC20(networkConfig).balanceOf(
|
|
43796
|
+
usdcToken.address,
|
|
43797
|
+
vaultAllocator,
|
|
43798
|
+
usdcToken.decimals
|
|
43799
|
+
);
|
|
43800
|
+
const tokenPrice = await pricer.getPrice(
|
|
43801
|
+
usdcToken.priceProxySymbol || usdcToken.symbol
|
|
43802
|
+
);
|
|
43803
|
+
const usdValue = Number(balance.toFixed(usdcToken.decimals)) * tokenPrice.price;
|
|
43804
|
+
return { token: usdcToken, amount: balance, usdValue };
|
|
43805
|
+
}
|
|
43806
|
+
/**
|
|
43807
|
+
* Merges vault-allocator asset, optional vault-allocator USDC, and operator wallet
|
|
43808
|
+
* balances into entries keyed by token address.
|
|
42693
43809
|
*/
|
|
42694
|
-
_computeUnusedBalances(
|
|
43810
|
+
_computeUnusedBalances(vaultAssetBalance, vaultUsdcBalance, walletBalance) {
|
|
42695
43811
|
const balanceMap = /* @__PURE__ */ new Map();
|
|
42696
|
-
|
|
42697
|
-
token
|
|
42698
|
-
|
|
42699
|
-
|
|
42700
|
-
|
|
43812
|
+
const put = (tb) => {
|
|
43813
|
+
balanceMap.set(tb.token.address.toString(), {
|
|
43814
|
+
token: tb.token,
|
|
43815
|
+
amount: tb.amount,
|
|
43816
|
+
usdValue: tb.usdValue
|
|
43817
|
+
});
|
|
43818
|
+
};
|
|
43819
|
+
put(vaultAssetBalance);
|
|
43820
|
+
if (vaultUsdcBalance) put(vaultUsdcBalance);
|
|
42701
43821
|
const key = walletBalance.token.address.toString();
|
|
42702
43822
|
const existing = balanceMap.get(key);
|
|
42703
43823
|
if (existing) {
|
|
@@ -42716,30 +43836,29 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42716
43836
|
return Array.from(balanceMap.values());
|
|
42717
43837
|
}
|
|
42718
43838
|
/**
|
|
42719
|
-
* Reads the operator wallet
|
|
42720
|
-
*
|
|
43839
|
+
* Reads the operator wallet balance for {@link StateManagerConfig.usdcToken} only
|
|
43840
|
+
* (wallet stablecoin is always USDC, regardless of strategy {@link StateManagerConfig.assetToken}).
|
|
42721
43841
|
*/
|
|
42722
43842
|
async _fetchWalletBalances() {
|
|
42723
43843
|
const {
|
|
42724
43844
|
networkConfig,
|
|
42725
43845
|
pricer,
|
|
42726
43846
|
walletAddress,
|
|
42727
|
-
|
|
42728
|
-
usdceToken
|
|
43847
|
+
usdcToken
|
|
42729
43848
|
} = this._config;
|
|
42730
43849
|
const erc20 = new ERC20(networkConfig);
|
|
42731
|
-
const [
|
|
43850
|
+
const [balance, tokenPrice] = await Promise.all([
|
|
42732
43851
|
erc20.balanceOf(
|
|
42733
|
-
|
|
43852
|
+
usdcToken.address,
|
|
42734
43853
|
walletAddress,
|
|
42735
|
-
|
|
43854
|
+
usdcToken.decimals
|
|
42736
43855
|
),
|
|
42737
|
-
pricer.getPrice(
|
|
43856
|
+
pricer.getPrice(usdcToken.priceProxySymbol || usdcToken.symbol)
|
|
42738
43857
|
]);
|
|
42739
43858
|
return {
|
|
42740
|
-
token:
|
|
42741
|
-
amount:
|
|
42742
|
-
usdValue: Number(
|
|
43859
|
+
token: usdcToken,
|
|
43860
|
+
amount: balance,
|
|
43861
|
+
usdValue: Number(balance.toFixed(usdcToken.decimals)) * tokenPrice.price
|
|
42743
43862
|
};
|
|
42744
43863
|
}
|
|
42745
43864
|
/**
|
|
@@ -42857,12 +43976,12 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42857
43976
|
* finite, sensible values. Throws on invalid state.
|
|
42858
43977
|
*/
|
|
42859
43978
|
_validateRefreshedState() {
|
|
42860
|
-
if (this._budget.
|
|
43979
|
+
if (this._budget.unusedBalanceRows.length === 0) {
|
|
42861
43980
|
throw new Error(
|
|
42862
43981
|
`${this._tag}: unusedBalance is empty after refresh`
|
|
42863
43982
|
);
|
|
42864
43983
|
}
|
|
42865
|
-
for (const balance of this._budget.
|
|
43984
|
+
for (const balance of this._budget.unusedBalanceRows) {
|
|
42866
43985
|
this._validateTokenBalanceOrThrow(
|
|
42867
43986
|
balance,
|
|
42868
43987
|
`unusedBalance[${balance.token.symbol}]`
|
|
@@ -42882,7 +44001,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42882
44001
|
}
|
|
42883
44002
|
}
|
|
42884
44003
|
_validateVesuPoolPricesOrThrow() {
|
|
42885
|
-
for (const pool of this._budget.
|
|
44004
|
+
for (const pool of this._budget.vesuPools) {
|
|
42886
44005
|
const poolLabel = pool.poolId.shortString();
|
|
42887
44006
|
this._assertPositiveFinite(
|
|
42888
44007
|
pool.collateralPrice,
|
|
@@ -42895,8 +44014,8 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42895
44014
|
}
|
|
42896
44015
|
}
|
|
42897
44016
|
_validateExtendedBalanceOrThrow() {
|
|
42898
|
-
if (!this._budget.
|
|
42899
|
-
const { equity, availableForTrade } = this._budget.
|
|
44017
|
+
if (!this._budget.extendedBalanceView) return;
|
|
44018
|
+
const { equity, availableForTrade } = this._budget.extendedBalanceView;
|
|
42900
44019
|
if (!Number.isFinite(equity.toNumber()) || !Number.isFinite(availableForTrade.toNumber())) {
|
|
42901
44020
|
throw new Error(
|
|
42902
44021
|
`${this._tag}: Extended balance contains non-finite values \u2014 equity: ${equity.toNumber()}, availableForTrade: ${availableForTrade.toNumber()}`
|
|
@@ -42935,18 +44054,26 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42935
44054
|
);
|
|
42936
44055
|
}
|
|
42937
44056
|
/**
|
|
42938
|
-
* Total investable = vault allocator balance + Extended available-for-trade
|
|
42939
|
-
*
|
|
44057
|
+
* Total investable = vault allocator balance + Extended available-for-trade +
|
|
44058
|
+
* buffered unrealised PnL, matching `deposit_cases_extended_vesu.xlsx`:
|
|
44059
|
+
* `(VA + wallet + EXT_WITH_AVL + EXT_UPNL) * (1 − buffer)`.
|
|
44060
|
+
* Positive {@link ExtendedBalanceState.pendingDeposit} stays on the afT leg only (see {@link SolveBudget.extAvailTrade}).
|
|
42940
44061
|
*/
|
|
42941
44062
|
_computeTotalInvestableAmount() {
|
|
42942
|
-
const totalUnusedUsd = this._budget.
|
|
42943
|
-
(acc, b) => acc + b.usdValue,
|
|
42944
|
-
0
|
|
42945
|
-
);
|
|
44063
|
+
const totalUnusedUsd = this._budget.unusedBalancesBufferedUsdSum;
|
|
42946
44064
|
logger.debug(
|
|
42947
|
-
`${this._tag}::_computeTotalInvestableAmount unusedBalances=${JSON.stringify(this._budget.
|
|
44065
|
+
`${this._tag}::_computeTotalInvestableAmount unusedBalances=${JSON.stringify(this._budget.unusedBalanceRows.map((b) => ({ token: b.token.symbol, amount: b.amount.toNumber(), usdValue: b.usdValue })))}`
|
|
44066
|
+
);
|
|
44067
|
+
const extBal = this._budget.extendedBalanceView;
|
|
44068
|
+
const rawAft = extBal?.availableForWithdrawal?.toNumber() ?? 0;
|
|
44069
|
+
const rawUpnl = extBal?.unrealisedPnl?.toNumber() ?? 0;
|
|
44070
|
+
let extBuffered = this._budget.bufferedUsd(rawAft) + this._budget.bufferedUsd(rawUpnl);
|
|
44071
|
+
const pd = extBal?.pendingDeposit?.toNumber() ?? 0;
|
|
44072
|
+
if (pd > 0) extBuffered += pd;
|
|
44073
|
+
const extendedAvailable = new Web3Number(
|
|
44074
|
+
extBuffered.toFixed(USDC_TOKEN_DECIMALS),
|
|
44075
|
+
USDC_TOKEN_DECIMALS
|
|
42948
44076
|
);
|
|
42949
|
-
const extendedAvailable = this._budget.extendedBalance?.availableForTrade ?? new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
42950
44077
|
logger.verbose(`_computeTotalInvestableAmount totalUnusedUsd: ${totalUnusedUsd}, extendedAvailable: ${extendedAvailable.toNumber()}`);
|
|
42951
44078
|
return new Web3Number(totalUnusedUsd.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS).plus(extendedAvailable);
|
|
42952
44079
|
}
|
|
@@ -42977,7 +44104,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42977
44104
|
if (denominator === 0) {
|
|
42978
44105
|
throw new Error(`${this._tag}: Denominator is zero`);
|
|
42979
44106
|
}
|
|
42980
|
-
const collateralPrice = this._budget.
|
|
44107
|
+
const collateralPrice = this._budget.vesuPools[0]?.collateralPrice ?? 0;
|
|
42981
44108
|
const totalVesuExposureUsd = this._totalVesuCollateralUsd().plus(new Web3Number((deltaVesuCollateral * collateralPrice).toFixed(6), USDC_TOKEN_DECIMALS));
|
|
42982
44109
|
const totalExtendedExposureUsd = this._totalExtendedExposureUsd().plus(new Web3Number((deltaExtendedCollateral * collateralPrice).toFixed(6), USDC_TOKEN_DECIMALS));
|
|
42983
44110
|
const numerator = vesuLeverage * distributableAmount.toNumber() + totalVesuExposureUsd.toNumber() - totalExtendedExposureUsd.toNumber();
|
|
@@ -42989,8 +44116,6 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42989
44116
|
distributableAmount.minus(extendedAllocationUsd).toFixed(USDC_TOKEN_DECIMALS),
|
|
42990
44117
|
USDC_TOKEN_DECIMALS
|
|
42991
44118
|
);
|
|
42992
|
-
const perPoolDebtDeltasToBorrow = this._budget.vesuPerPoolDebtDeltasToBorrow;
|
|
42993
|
-
vesuAllocationUsd = vesuAllocationUsd.plus(this._sumDebtDeltas(perPoolDebtDeltasToBorrow).multipliedBy(-1));
|
|
42994
44119
|
let vesuPositionDelta = Number(new Web3Number((vesuAllocationUsd.toNumber() * vesuLeverage / collateralPrice).toFixed(6), 6).toFixedRoundDown(COLLATERAL_PRECISION));
|
|
42995
44120
|
let extendedPositionDelta = Number(new Web3Number((extendedAllocationUsd.toNumber() * extendedLeverage / collateralPrice).toFixed(6), 6).toFixedRoundDown(COLLATERAL_PRECISION));
|
|
42996
44121
|
if (!isRecursive) {
|
|
@@ -43009,14 +44134,17 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43009
44134
|
* by existing collateral value, then converts each share to collateral
|
|
43010
44135
|
* token units.
|
|
43011
44136
|
*/
|
|
43012
|
-
_computePerPoolCollateralDeltas(vesuAllocationUsd
|
|
44137
|
+
_computePerPoolCollateralDeltas(vesuAllocationUsd) {
|
|
43013
44138
|
const vesuLeverage = calculateVesuLeverage();
|
|
43014
|
-
const availableVesuCollateralAllocationUsd = vesuAllocationUsd
|
|
44139
|
+
const availableVesuCollateralAllocationUsd = vesuAllocationUsd;
|
|
43015
44140
|
const postLeverageAllocationUsd = availableVesuCollateralAllocationUsd.multipliedBy(vesuLeverage);
|
|
43016
44141
|
const totalCollateralExisting = this._totalVesuCollateral();
|
|
43017
|
-
return this._budget.
|
|
44142
|
+
return this._budget.vesuPools.map((pool, index) => {
|
|
43018
44143
|
const _postLeverageAllocation = postLeverageAllocationUsd.dividedBy(pool.collateralPrice);
|
|
43019
|
-
const postLeverageAllocation = new Web3Number(
|
|
44144
|
+
const postLeverageAllocation = new Web3Number(
|
|
44145
|
+
_postLeverageAllocation.plus(totalCollateralExisting).toFixedRoundDown(COLLATERAL_PRECISION),
|
|
44146
|
+
pool.collateralToken.decimals
|
|
44147
|
+
).minus(totalCollateralExisting);
|
|
43020
44148
|
const _poolCollateralDelta = this._computePoolCollateralShare(
|
|
43021
44149
|
pool,
|
|
43022
44150
|
totalCollateralExisting,
|
|
@@ -43026,12 +44154,12 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43026
44154
|
_poolCollateralDelta.toFixed(COLLATERAL_PRECISION),
|
|
43027
44155
|
pool.collateralToken.decimals
|
|
43028
44156
|
);
|
|
43029
|
-
const newDebt =
|
|
44157
|
+
const newDebt = postLeverageAllocation.multipliedBy(pool.collateralPrice).minus(availableVesuCollateralAllocationUsd).dividedBy(pool.debtPrice);
|
|
43030
44158
|
return {
|
|
43031
44159
|
poolId: pool.poolId,
|
|
43032
44160
|
collateralToken: pool.collateralToken,
|
|
43033
44161
|
debtToken: pool.debtToken,
|
|
43034
|
-
debtDelta:
|
|
44162
|
+
debtDelta: newDebt,
|
|
43035
44163
|
collateralDelta: poolCollateralDelta,
|
|
43036
44164
|
collateralPrice: pool.collateralPrice,
|
|
43037
44165
|
debtPrice: pool.debtPrice
|
|
@@ -43044,7 +44172,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43044
44172
|
* Multi-pool cases split proportionally by current collateral USD value.
|
|
43045
44173
|
*/
|
|
43046
44174
|
_computePoolCollateralShare(pool, totalCollateral, totalVesuAllocation) {
|
|
43047
|
-
const isSinglePoolOrZeroTotal = this._budget.
|
|
44175
|
+
const isSinglePoolOrZeroTotal = this._budget.vesuPools.length === 1 || totalCollateral.toNumber() === 0;
|
|
43048
44176
|
if (isSinglePoolOrZeroTotal) return totalVesuAllocation;
|
|
43049
44177
|
const poolWeight = pool.collateralAmount.dividedBy(totalCollateral);
|
|
43050
44178
|
return new Web3Number(
|
|
@@ -43081,8 +44209,8 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43081
44209
|
*/
|
|
43082
44210
|
_computeTargetExtendedExposure(vesuDeltas) {
|
|
43083
44211
|
let totalExposureCollateral = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
43084
|
-
for (let i = 0; i < this._budget.
|
|
43085
|
-
const pool = this._budget.
|
|
44212
|
+
for (let i = 0; i < this._budget.vesuPools.length; i++) {
|
|
44213
|
+
const pool = this._budget.vesuPools[i];
|
|
43086
44214
|
const delta = vesuDeltas[i];
|
|
43087
44215
|
logger.debug(
|
|
43088
44216
|
`${this._tag}::_computeTargetExtendedExposure poolId=${pool.poolId.toString()}, collateralAmount=${pool.collateralAmount.toNumber()}, collateralDelta=${delta.collateralDelta.toNumber()}`
|
|
@@ -43100,7 +44228,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43100
44228
|
);
|
|
43101
44229
|
}
|
|
43102
44230
|
_hasNoExtendedPositions() {
|
|
43103
|
-
return this._budget.
|
|
44231
|
+
return this._budget.extendedPositionsView.length === 0;
|
|
43104
44232
|
}
|
|
43105
44233
|
/**
|
|
43106
44234
|
* Creates a single-element delta array for the default instrument
|
|
@@ -43111,7 +44239,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43111
44239
|
{
|
|
43112
44240
|
instrument: this._config.extendedAdapter.config.extendedMarketName,
|
|
43113
44241
|
delta: new Web3Number(
|
|
43114
|
-
delta.
|
|
44242
|
+
delta.toFixedRoundDown(COLLATERAL_PRECISION),
|
|
43115
44243
|
USDC_TOKEN_DECIMALS
|
|
43116
44244
|
)
|
|
43117
44245
|
}
|
|
@@ -43123,7 +44251,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43123
44251
|
*/
|
|
43124
44252
|
_distributeExposureDeltaAcrossPositions(totalDelta) {
|
|
43125
44253
|
const totalExposure = this._totalExtendedExposure();
|
|
43126
|
-
return this._budget.
|
|
44254
|
+
return this._budget.extendedPositionsView.map((position) => {
|
|
43127
44255
|
const share = this._positionExposureShareFraction(
|
|
43128
44256
|
position,
|
|
43129
44257
|
totalExposure
|
|
@@ -43131,7 +44259,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43131
44259
|
return {
|
|
43132
44260
|
instrument: position.instrument,
|
|
43133
44261
|
delta: new Web3Number(
|
|
43134
|
-
totalDelta.multipliedBy(share).
|
|
44262
|
+
totalDelta.multipliedBy(share).toFixedRoundDown(COLLATERAL_PRECISION),
|
|
43135
44263
|
USDC_TOKEN_DECIMALS
|
|
43136
44264
|
)
|
|
43137
44265
|
};
|
|
@@ -43143,7 +44271,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43143
44271
|
* or when total exposure is zero.
|
|
43144
44272
|
*/
|
|
43145
44273
|
_positionExposureShareFraction(position, totalExposure) {
|
|
43146
|
-
const isSingleOrZero = totalExposure.toNumber() === 0 || this._budget.
|
|
44274
|
+
const isSingleOrZero = totalExposure.toNumber() === 0 || this._budget.extendedPositionsView.length === 1;
|
|
43147
44275
|
if (isSingleOrZero) return 1;
|
|
43148
44276
|
return position.valueUsd.dividedBy(totalExposure).toNumber();
|
|
43149
44277
|
}
|
|
@@ -43155,7 +44283,10 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43155
44283
|
* Positive = need to deposit more, negative = can withdraw excess.
|
|
43156
44284
|
*/
|
|
43157
44285
|
_computeExtendedDepositDelta(extendedAllocationUsd) {
|
|
43158
|
-
const currentAvailableForTrade =
|
|
44286
|
+
const currentAvailableForTrade = new Web3Number(
|
|
44287
|
+
this._budget.extAvailTrade.toFixed(USDC_TOKEN_DECIMALS),
|
|
44288
|
+
USDC_TOKEN_DECIMALS
|
|
44289
|
+
);
|
|
43159
44290
|
return new Web3Number(
|
|
43160
44291
|
extendedAllocationUsd.minus(currentAvailableForTrade).toFixed(USDC_TOKEN_DECIMALS),
|
|
43161
44292
|
USDC_TOKEN_DECIMALS
|
|
@@ -43163,8 +44294,8 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43163
44294
|
}
|
|
43164
44295
|
_computeVesuDepositAmount(vesuDeltas) {
|
|
43165
44296
|
let totalVesuCollateral = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
43166
|
-
for (let i = 0; i < this._budget.
|
|
43167
|
-
const pool = this._budget.
|
|
44297
|
+
for (let i = 0; i < this._budget.vesuPools.length; i++) {
|
|
44298
|
+
const pool = this._budget.vesuPools[i];
|
|
43168
44299
|
const delta = vesuDeltas[i];
|
|
43169
44300
|
totalVesuCollateral = totalVesuCollateral.plus(delta.collateralDelta.multipliedBy(pool.collateralPrice));
|
|
43170
44301
|
totalVesuCollateral = totalVesuCollateral.minus(delta.debtDelta.multipliedBy(pool.debtPrice));
|
|
@@ -43209,13 +44340,17 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43209
44340
|
for (const route of spendsByPool) {
|
|
43210
44341
|
routes.push({ type: "VESU_REPAY" /* VESU_REPAY */, ...route, priority: routes.length });
|
|
43211
44342
|
}
|
|
43212
|
-
this._budget.
|
|
44343
|
+
this._budget.spendVaRawUsd(used);
|
|
43213
44344
|
}
|
|
43214
|
-
_buildVesuBorrowRoutes(totalUsd, routes) {
|
|
44345
|
+
_buildVesuBorrowRoutes(totalUsd, routes, opts) {
|
|
43215
44346
|
let borrowable = this._budget.vesuBorrowCapacity;
|
|
44347
|
+
if (opts?.maxBorrowUsd !== void 0) {
|
|
44348
|
+
borrowable = Math.min(borrowable, Math.max(0, opts.maxBorrowUsd));
|
|
44349
|
+
}
|
|
43216
44350
|
if (totalUsd <= CASE_THRESHOLD_USD) return { routes, remaining: totalUsd };
|
|
43217
44351
|
if (borrowable <= CASE_THRESHOLD_USD) return { routes, remaining: totalUsd };
|
|
43218
|
-
const
|
|
44352
|
+
const borrowTarget = Math.min(totalUsd, borrowable);
|
|
44353
|
+
const { used, spendsByPool } = this._budget.spendVesuBorrowCapacity(borrowTarget);
|
|
43219
44354
|
for (const route of spendsByPool) {
|
|
43220
44355
|
routes.push({ type: "VESU_BORROW" /* VESU_BORROW */, ...route, priority: routes.length });
|
|
43221
44356
|
}
|
|
@@ -43271,9 +44406,9 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43271
44406
|
// });
|
|
43272
44407
|
// }
|
|
43273
44408
|
_getWalletToVARoute(tryAmount, routes) {
|
|
43274
|
-
const
|
|
43275
|
-
if (
|
|
43276
|
-
const walletUsed = this._budget.spendWallet(
|
|
44409
|
+
const usableRaw = Math.min(tryAmount, this._budget.walletUsd);
|
|
44410
|
+
if (usableRaw > CASE_THRESHOLD_USD) {
|
|
44411
|
+
const walletUsed = this._budget.spendWallet(usableRaw);
|
|
43277
44412
|
this._budget.addToVA(walletUsed);
|
|
43278
44413
|
const route = { type: "WALLET_TO_VA" /* WALLET_TO_VA */, amount: safeUsdcWeb3Number(walletUsed), priority: routes.length };
|
|
43279
44414
|
routes.push(route);
|
|
@@ -43282,9 +44417,9 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43282
44417
|
return { routes, remaining: tryAmount };
|
|
43283
44418
|
}
|
|
43284
44419
|
_getWalletToEXTENDEDRoute(tryAmount, routes, shouldAddWaitRoute = true) {
|
|
43285
|
-
const
|
|
43286
|
-
if (
|
|
43287
|
-
const walletUsed = this._budget.spendWallet(
|
|
44420
|
+
const usableRaw = Math.min(tryAmount, this._budget.walletUsd);
|
|
44421
|
+
if (usableRaw > CASE_THRESHOLD_USD) {
|
|
44422
|
+
const walletUsed = this._budget.spendWallet(usableRaw);
|
|
43288
44423
|
this._budget.addToExtAvailTrade(walletUsed);
|
|
43289
44424
|
routes.push({ type: "WALLET_TO_EXTENDED" /* WALLET_TO_EXTENDED */, amount: safeUsdcWeb3Number(walletUsed), priority: routes.length });
|
|
43290
44425
|
if (shouldAddWaitRoute) {
|
|
@@ -43295,9 +44430,9 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43295
44430
|
return { routes, remaining: tryAmount };
|
|
43296
44431
|
}
|
|
43297
44432
|
_getVAToEXTENDEDRoute(tryAmount, routes, shouldAddWaitRoute = true) {
|
|
43298
|
-
const
|
|
43299
|
-
if (
|
|
43300
|
-
const vaUsed = this._budget.spendVA(
|
|
44433
|
+
const usable = Math.min(tryAmount, this._budget.vaUsd);
|
|
44434
|
+
if (usable > CASE_THRESHOLD_USD) {
|
|
44435
|
+
const vaUsed = this._budget.spendVA(usable);
|
|
43301
44436
|
this._budget.addToExtAvailTrade(vaUsed);
|
|
43302
44437
|
const route = { type: "VA_TO_EXTENDED" /* VA_TO_EXTENDED */, amount: safeUsdcWeb3Number(vaUsed), priority: routes.length };
|
|
43303
44438
|
routes.push(route);
|
|
@@ -43310,40 +44445,42 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43310
44445
|
}
|
|
43311
44446
|
_getExtendedToWalletRoute(tryAmount, routes, shouldAddWaitRoute = true) {
|
|
43312
44447
|
if (tryAmount <= CASE_THRESHOLD_USD) return { routes, remaining: tryAmount };
|
|
43313
|
-
|
|
43314
|
-
const
|
|
43315
|
-
|
|
43316
|
-
const
|
|
44448
|
+
const rawCap = this._budget.extAvailWithdraw + this._budget.extAvailUpnl;
|
|
44449
|
+
const rawSpend = Math.min(tryAmount, rawCap);
|
|
44450
|
+
if (rawSpend <= CASE_THRESHOLD_USD) return { routes, remaining: tryAmount };
|
|
44451
|
+
const rawOut = this._budget.spendExtAvailTrade(rawSpend);
|
|
44452
|
+
this._budget.addToWallet(Math.abs(rawOut));
|
|
44453
|
+
const route = { type: "EXTENDED_TO_WALLET" /* EXTENDED_TO_WALLET */, amount: safeUsdcWeb3Number(rawSpend), priority: routes.length };
|
|
43317
44454
|
routes.push(route);
|
|
43318
44455
|
if (shouldAddWaitRoute) {
|
|
43319
44456
|
routes.push({ type: "RETURN_TO_WAIT" /* RETURN_TO_WAIT */, priority: routes.length });
|
|
43320
44457
|
}
|
|
43321
|
-
return { routes, remaining: tryAmount -
|
|
44458
|
+
return { routes, remaining: tryAmount - rawSpend };
|
|
43322
44459
|
}
|
|
43323
44460
|
_getWALLETToVARoute(tryAmount, routes) {
|
|
43324
44461
|
if (tryAmount <= CASE_THRESHOLD_USD) return { routes, remaining: tryAmount };
|
|
43325
|
-
const
|
|
43326
|
-
if (
|
|
43327
|
-
const walletUsed = this._budget.spendWallet(
|
|
44462
|
+
const usableRaw = Math.min(tryAmount, this._budget.walletUsd);
|
|
44463
|
+
if (usableRaw <= CASE_THRESHOLD_USD) return { routes, remaining: tryAmount };
|
|
44464
|
+
const walletUsed = this._budget.spendWallet(usableRaw);
|
|
43328
44465
|
this._budget.addToVA(walletUsed);
|
|
43329
44466
|
const route = { type: "WALLET_TO_VA" /* WALLET_TO_VA */, amount: safeUsdcWeb3Number(walletUsed), priority: routes.length };
|
|
43330
44467
|
routes.push(route);
|
|
43331
44468
|
return { routes, remaining: tryAmount - walletUsed };
|
|
43332
44469
|
}
|
|
43333
44470
|
_getUpnlRoute(tryAmount, routes) {
|
|
43334
|
-
const
|
|
43335
|
-
const
|
|
43336
|
-
if (
|
|
43337
|
-
|
|
43338
|
-
this._budget.addToExtAvailTrade(
|
|
43339
|
-
assert(this._budget.
|
|
44471
|
+
const rawUpnl = this._budget.extAvailUpnl;
|
|
44472
|
+
const usableRaw = Math.min(tryAmount, rawUpnl);
|
|
44473
|
+
if (usableRaw <= 0) return { routes, remaining: tryAmount };
|
|
44474
|
+
this._budget.spendExtAvailUpnl(usableRaw);
|
|
44475
|
+
this._budget.addToExtAvailTrade(usableRaw);
|
|
44476
|
+
assert(this._budget.extendedPositionsView.length == 1, "SolveBudget::_getUpnlRoute: extendedPositions length must be 1");
|
|
43340
44477
|
routes.push({
|
|
43341
44478
|
type: "REALISE_PNL" /* REALISE_PNL */,
|
|
43342
|
-
amount: safeUsdcWeb3Number(
|
|
43343
|
-
instrument: this._budget.
|
|
44479
|
+
amount: safeUsdcWeb3Number(usableRaw),
|
|
44480
|
+
instrument: this._budget.extendedPositionsView[0].instrument,
|
|
43344
44481
|
priority: routes.length
|
|
43345
44482
|
});
|
|
43346
|
-
return { routes, remaining: tryAmount -
|
|
44483
|
+
return { routes, remaining: tryAmount - usableRaw };
|
|
43347
44484
|
}
|
|
43348
44485
|
// ── Sub-classifiers ────────────────────────────────────────────────────
|
|
43349
44486
|
// Each sub-classifier builds routes directly from contextual data.
|
|
@@ -43358,7 +44495,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43358
44495
|
const instrument = this._config.extendedAdapter.config.extendedMarketName ?? "BTC-USD";
|
|
43359
44496
|
const routes = [];
|
|
43360
44497
|
let remaining = withdrawAmount.toNumber();
|
|
43361
|
-
const vaUsed = this._budget.spendVA(
|
|
44498
|
+
const vaUsed = this._budget.spendVA(remaining);
|
|
43362
44499
|
remaining -= vaUsed;
|
|
43363
44500
|
let totalExtUsed = 0;
|
|
43364
44501
|
if (remaining > CASE_THRESHOLD_USD) {
|
|
@@ -43381,48 +44518,90 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43381
44518
|
totalExtUsed = usableWithrawAmount + upnlUsed;
|
|
43382
44519
|
}
|
|
43383
44520
|
if (remaining > CASE_THRESHOLD_USD) {
|
|
43384
|
-
|
|
43385
|
-
|
|
43386
|
-
const
|
|
43387
|
-
|
|
43388
|
-
|
|
43389
|
-
|
|
43390
|
-
|
|
43391
|
-
|
|
44521
|
+
assert(this._budget.vesuPools.length == 1, "SolveBudget::_classifyWithdrawal: vesuPoolStates length must be 1");
|
|
44522
|
+
const vesuAdapter = this._config.vesuAdapters[0];
|
|
44523
|
+
const avgCollPrice = this._budget.vesuPools[0]?.collateralPrice ?? 1;
|
|
44524
|
+
const vesuLeverage = calculateVesuLeverage();
|
|
44525
|
+
const extLeverage = calculateExtendedLevergae();
|
|
44526
|
+
const freedPerBtcVesu = avgCollPrice / vesuLeverage;
|
|
44527
|
+
const freedPerBtcExt = avgCollPrice / extLeverage;
|
|
44528
|
+
const vesuColBtc = this._budget.vesuPools[0].collateralAmount.toNumber();
|
|
44529
|
+
const extPosBtc = this._totalExtendedExposure().toNumber();
|
|
44530
|
+
let stillNeeded = remaining;
|
|
44531
|
+
let vesuBtcDelta = 0;
|
|
44532
|
+
let extBtcDelta = 0;
|
|
44533
|
+
let extFreed = 0;
|
|
44534
|
+
const roundUpBtc = (x) => {
|
|
44535
|
+
const factor = 10 ** COLLATERAL_PRECISION;
|
|
44536
|
+
return Math.ceil(x * factor) / factor;
|
|
44537
|
+
};
|
|
44538
|
+
const diff = vesuColBtc - extPosBtc;
|
|
44539
|
+
let currentVesuBtc = vesuColBtc;
|
|
44540
|
+
let currentExtBtc = extPosBtc;
|
|
44541
|
+
if (Math.abs(diff) > 1e-8) {
|
|
44542
|
+
if (diff > 0) {
|
|
44543
|
+
const btcRaw = stillNeeded / freedPerBtcVesu;
|
|
44544
|
+
const btc = Math.min(roundUpBtc(Math.min(Math.abs(diff), btcRaw, currentVesuBtc)), currentVesuBtc);
|
|
44545
|
+
vesuBtcDelta += btc;
|
|
44546
|
+
stillNeeded -= btc * freedPerBtcVesu;
|
|
44547
|
+
currentVesuBtc -= btc;
|
|
44548
|
+
} else {
|
|
44549
|
+
const btcRaw = stillNeeded / freedPerBtcExt;
|
|
44550
|
+
const btc = Math.min(roundUpBtc(Math.min(Math.abs(diff), btcRaw, currentExtBtc)), currentExtBtc);
|
|
44551
|
+
extBtcDelta += btc;
|
|
44552
|
+
extFreed += btc * freedPerBtcExt;
|
|
44553
|
+
stillNeeded -= btc * freedPerBtcExt;
|
|
44554
|
+
currentExtBtc -= btc;
|
|
44555
|
+
}
|
|
44556
|
+
}
|
|
44557
|
+
if (stillNeeded > CASE_THRESHOLD_USD) {
|
|
44558
|
+
const combinedFreed = freedPerBtcVesu + freedPerBtcExt;
|
|
44559
|
+
const maxBtc = Math.min(currentVesuBtc, currentExtBtc);
|
|
44560
|
+
const btcRaw = stillNeeded / combinedFreed;
|
|
44561
|
+
const btc = Math.min(roundUpBtc(Math.min(btcRaw, maxBtc)), maxBtc);
|
|
44562
|
+
vesuBtcDelta += btc;
|
|
44563
|
+
extBtcDelta += btc;
|
|
44564
|
+
extFreed += btc * freedPerBtcExt;
|
|
44565
|
+
}
|
|
44566
|
+
const r6 = (n) => Number(n.toFixed(6));
|
|
44567
|
+
if (vesuBtcDelta > 0) {
|
|
44568
|
+
const totalVesuBtcSigned = -vesuBtcDelta;
|
|
44569
|
+
const targetLtv = 1 - 1 / vesuLeverage;
|
|
44570
|
+
const debtDelta = r6(totalVesuBtcSigned * avgCollPrice * targetLtv);
|
|
44571
|
+
const marginBtc = 0;
|
|
44572
|
+
const swappedBtc = Number(vesuBtcDelta.toFixed(COLLATERAL_PRECISION));
|
|
43392
44573
|
routes.push({
|
|
43393
44574
|
type: "VESU_MULTIPLY_DECREASE_LEVER" /* VESU_MULTIPLY_DECREASE_LEVER */,
|
|
43394
44575
|
poolId: vesuAdapter.config.poolId,
|
|
43395
44576
|
collateralToken: vesuAdapter.config.collateral,
|
|
43396
|
-
marginAmount:
|
|
43397
|
-
swappedCollateralAmount: new Web3Number(
|
|
44577
|
+
marginAmount: new Web3Number(marginBtc.toFixed(COLLATERAL_PRECISION), vesuAdapter.config.collateral.decimals),
|
|
44578
|
+
swappedCollateralAmount: new Web3Number(swappedBtc.toFixed(COLLATERAL_PRECISION), vesuAdapter.config.collateral.decimals),
|
|
43398
44579
|
debtToken: vesuAdapter.config.debt,
|
|
43399
44580
|
debtAmount: new Web3Number(debtDelta, USDC_TOKEN_DECIMALS),
|
|
43400
44581
|
priority: routes.length
|
|
43401
44582
|
});
|
|
43402
|
-
this._budget.applyVesuDelta(
|
|
43403
|
-
|
|
43404
|
-
|
|
43405
|
-
|
|
43406
|
-
|
|
43407
|
-
|
|
43408
|
-
|
|
43409
|
-
|
|
43410
|
-
toToken: vesuAdapter.config.debt.symbol,
|
|
43411
|
-
priority: routes.length
|
|
43412
|
-
});
|
|
43413
|
-
this._budget.addToVA(vesuAllocationUsd.abs().toNumber());
|
|
43414
|
-
}
|
|
44583
|
+
this._budget.applyVesuDelta(
|
|
44584
|
+
vesuAdapter.config.poolId,
|
|
44585
|
+
vesuAdapter.config.collateral,
|
|
44586
|
+
vesuAdapter.config.debt,
|
|
44587
|
+
new Web3Number(r6(totalVesuBtcSigned), USDC_TOKEN_DECIMALS),
|
|
44588
|
+
new Web3Number(debtDelta, USDC_TOKEN_DECIMALS)
|
|
44589
|
+
);
|
|
44590
|
+
this._budget.addToVA(vesuBtcDelta * freedPerBtcVesu);
|
|
43415
44591
|
}
|
|
43416
|
-
if (
|
|
44592
|
+
if (extBtcDelta > 0) {
|
|
43417
44593
|
routes.push({
|
|
43418
44594
|
type: "EXTENDED_DECREASE_LEVER" /* EXTENDED_DECREASE_LEVER */,
|
|
43419
|
-
amount: safeUsdcWeb3Number(
|
|
44595
|
+
amount: safeUsdcWeb3Number(-r6(extBtcDelta)),
|
|
43420
44596
|
instrument,
|
|
43421
44597
|
priority: routes.length
|
|
43422
44598
|
});
|
|
43423
|
-
this._budget.applyExtendedExposureDelta(
|
|
43424
|
-
|
|
43425
|
-
|
|
44599
|
+
this._budget.applyExtendedExposureDelta(
|
|
44600
|
+
instrument,
|
|
44601
|
+
safeUsdcWeb3Number(-r6(extBtcDelta)),
|
|
44602
|
+
avgCollPrice
|
|
44603
|
+
);
|
|
44604
|
+
totalExtUsed += extFreed;
|
|
43426
44605
|
}
|
|
43427
44606
|
}
|
|
43428
44607
|
if (totalExtUsed > CASE_THRESHOLD_USD) {
|
|
@@ -43455,56 +44634,231 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43455
44634
|
*
|
|
43456
44635
|
* Design: accumulate all ext-to-wallet moves, add transfer routes at the end (principle #3).
|
|
43457
44636
|
*/
|
|
43458
|
-
|
|
43459
|
-
|
|
43460
|
-
|
|
43461
|
-
|
|
44637
|
+
/**
|
|
44638
|
+
* Unified LTV classifier. Computes both Vesu repay and Extended margin needs,
|
|
44639
|
+
* then builds all routes in a single pass with no duplicate transfers.
|
|
44640
|
+
*
|
|
44641
|
+
* Vesu repay priority: VA > Wallet > ExtAvl > ExtUpnl
|
|
44642
|
+
* Extended margin priority: Wallet > VA > VesuBorrow
|
|
44643
|
+
* Shared sources consumed by Vesu first (higher priority).
|
|
44644
|
+
*/
|
|
44645
|
+
_classifyLTV() {
|
|
44646
|
+
assert(this._budget.vesuPools.length === 1, `${this._tag}::_classifyLTV expects exactly one Vesu pool`);
|
|
44647
|
+
const d = rebalance(this._ltvRebalanceInputsFromBudget());
|
|
44648
|
+
if (this._isLtvRebalanceNoop(d)) return [];
|
|
44649
|
+
logger.info(
|
|
44650
|
+
`${this._tag}::_classifyLTV deltas extPos=${d.dExtPosition} vesuPos=${d.dVesuPosition} vesuDebt=${d.dVesuDebt} va=${d.dVaUsd} wallet=${d.dWalletUsd} borrow=${d.dVesuBorrowCapacity} T=${d.dTransferVesuToExt}`
|
|
43462
44651
|
);
|
|
43463
|
-
|
|
43464
|
-
|
|
43465
|
-
|
|
43466
|
-
const needed = Math.abs(debtDeltaSum);
|
|
43467
|
-
const routes = [];
|
|
43468
|
-
let remaining = needed;
|
|
43469
|
-
let totalExtUsed = 0;
|
|
43470
|
-
let caseId = "LTV_VESU_HIGH_USE_VA_OR_WALLET" /* LTV_VESU_HIGH_USE_VA_OR_WALLET */;
|
|
43471
|
-
const vaUsed = this._budget.spendVA(Math.min(this._budget.vaUsd, remaining));
|
|
43472
|
-
remaining -= vaUsed;
|
|
43473
|
-
if (remaining > CASE_THRESHOLD_USD) {
|
|
43474
|
-
const { remaining: walletToVaRemaining } = this._getWALLETToVARoute(remaining, routes);
|
|
43475
|
-
remaining = walletToVaRemaining;
|
|
43476
|
-
}
|
|
43477
|
-
if (remaining > CASE_THRESHOLD_USD) {
|
|
43478
|
-
const usableWithdrawAmount = Math.min(remaining, this._budget.extAvailWithdraw);
|
|
43479
|
-
remaining -= usableWithdrawAmount;
|
|
43480
|
-
let upnlUsed = 0;
|
|
43481
|
-
if (remaining > CASE_THRESHOLD_USD) {
|
|
43482
|
-
const { remaining: upnlRemaining } = this._getUpnlRoute(remaining, routes);
|
|
43483
|
-
upnlUsed = remaining - upnlRemaining;
|
|
43484
|
-
remaining = upnlRemaining;
|
|
43485
|
-
caseId = "LTV_EXTENDED_PROFITABLE_REALIZE" /* LTV_EXTENDED_PROFITABLE_REALIZE */;
|
|
43486
|
-
} else {
|
|
43487
|
-
caseId = "LTV_EXTENDED_PROFITABLE_AVAILABLE" /* LTV_EXTENDED_PROFITABLE_AVAILABLE */;
|
|
43488
|
-
}
|
|
43489
|
-
totalExtUsed = usableWithdrawAmount + upnlUsed;
|
|
43490
|
-
}
|
|
43491
|
-
if (remaining > CASE_THRESHOLD_USD) {
|
|
43492
|
-
throw new Error(`${this._tag}: Insufficient funds to cover margin needs`);
|
|
43493
|
-
}
|
|
43494
|
-
if (totalExtUsed > CASE_THRESHOLD_USD) {
|
|
43495
|
-
this._getExtendedToWalletRoute(totalExtUsed, routes);
|
|
43496
|
-
this._getWALLETToVARoute(totalExtUsed, routes);
|
|
43497
|
-
}
|
|
43498
|
-
this._buildVesuRepayRoutes(needed - remaining, routes);
|
|
44652
|
+
const routes = this._buildLtvRoutesFromRebalanceDeltas(d);
|
|
44653
|
+
if (routes.length === 0) return [];
|
|
44654
|
+
const amountUsd = Math.abs(d.dVaUsd) + Math.abs(d.dWalletUsd) + Math.abs(d.dVesuBorrowCapacity) + Math.abs(d.dExtAvlWithdraw) + Math.abs(d.dExtUpnl) + Math.abs(d.dTransferVesuToExt);
|
|
43499
44655
|
routes.forEach((r, i) => {
|
|
43500
44656
|
r.priority = i;
|
|
43501
44657
|
});
|
|
43502
44658
|
return [{
|
|
43503
|
-
case: CASE_DEFINITIONS[
|
|
43504
|
-
additionalArgs: { amount: safeUsdcWeb3Number(
|
|
44659
|
+
case: CASE_DEFINITIONS["MANAGE_LTV" /* MANAGE_LTV */],
|
|
44660
|
+
additionalArgs: { amount: safeUsdcWeb3Number(amountUsd) },
|
|
43505
44661
|
routes
|
|
43506
44662
|
}];
|
|
43507
44663
|
}
|
|
44664
|
+
_ltvRebalanceInputsFromBudget() {
|
|
44665
|
+
const pool = this._budget.vesuPools[0];
|
|
44666
|
+
const instrument = this._config.extendedAdapter.config.extendedMarketName ?? "BTC-USD";
|
|
44667
|
+
const extPosBtc = this._budget.extendedPositionsView.filter((p) => p.instrument === instrument).reduce((s, p) => s + Math.abs(p.size.toNumber()), 0);
|
|
44668
|
+
const targetHF = VesuConfig.maxLtv / VesuConfig.targetLtv;
|
|
44669
|
+
return {
|
|
44670
|
+
ext: {
|
|
44671
|
+
positionBtc: extPosBtc,
|
|
44672
|
+
equity: this._budget.extendedBalanceView?.equity?.toNumber() ?? 0,
|
|
44673
|
+
avlWithdraw: this._budget.extAvailWithdraw,
|
|
44674
|
+
upnl: this._budget.extAvailUpnl,
|
|
44675
|
+
leverage: calculateExtendedLevergae()
|
|
44676
|
+
},
|
|
44677
|
+
vesu: {
|
|
44678
|
+
positionBtc: pool.collateralAmount.toNumber(),
|
|
44679
|
+
debt: pool.debtAmount.toNumber(),
|
|
44680
|
+
debtPrice: pool.debtPrice,
|
|
44681
|
+
maxLTV: VesuConfig.maxLtv,
|
|
44682
|
+
targetHF
|
|
44683
|
+
},
|
|
44684
|
+
btcPrice: pool.collateralPrice,
|
|
44685
|
+
funding: {
|
|
44686
|
+
vaUsd: this._budget.vaUsd,
|
|
44687
|
+
walletUsd: this._budget.walletUsd,
|
|
44688
|
+
vesuBorrowCapacity: this._budget.vesuBorrowCapacity,
|
|
44689
|
+
extAvlWithdraw: this._budget.extAvailWithdraw,
|
|
44690
|
+
extUpnl: this._budget.extAvailUpnl
|
|
44691
|
+
},
|
|
44692
|
+
config: {
|
|
44693
|
+
positionPrecision: COLLATERAL_PRECISION,
|
|
44694
|
+
hfBuffer: 0.05
|
|
44695
|
+
}
|
|
44696
|
+
};
|
|
44697
|
+
}
|
|
44698
|
+
_isLtvRebalanceNoop(d) {
|
|
44699
|
+
const btcEps = 10 ** -COLLATERAL_PRECISION;
|
|
44700
|
+
const usdEps = CASE_THRESHOLD_USD;
|
|
44701
|
+
return Math.abs(d.dExtPosition) < btcEps && Math.abs(d.dVesuPosition) < btcEps && Math.abs(d.dVesuDebt) < 1e-6 && Math.abs(d.dExtAvlWithdraw) < usdEps && Math.abs(d.dExtUpnl) < usdEps && Math.abs(d.dVaUsd) < usdEps && Math.abs(d.dWalletUsd) < usdEps && Math.abs(d.dVesuBorrowCapacity) < usdEps && Math.abs(d.dTransferVesuToExt) < usdEps;
|
|
44702
|
+
}
|
|
44703
|
+
/**
|
|
44704
|
+
* Turn pure rebalance() deltas into execution routes.
|
|
44705
|
+
* Order: Vesu multiply (decrease/increase) → Extended lever → aggregated transfers
|
|
44706
|
+
* (REALISE_PNL, EXTENDED_TO_WALLET + WAIT, WALLET_TO_VA, VESU_BORROW, VESU_REPAY, VA_TO_EXTENDED).
|
|
44707
|
+
*/
|
|
44708
|
+
_buildLtvRoutesFromRebalanceDeltas(d) {
|
|
44709
|
+
const routes = [];
|
|
44710
|
+
const pool = this._budget.vesuPools[0];
|
|
44711
|
+
const vesuAdapter = this._config.vesuAdapters[0];
|
|
44712
|
+
const instrument = this._config.extendedAdapter.config.extendedMarketName ?? "BTC-USD";
|
|
44713
|
+
const price = pool.collateralPrice;
|
|
44714
|
+
const debtPrice = pool.debtPrice;
|
|
44715
|
+
const targetLtv = VesuConfig.targetLtv;
|
|
44716
|
+
const btcEps = 10 ** -COLLATERAL_PRECISION;
|
|
44717
|
+
let multiplyDebtRepayUsd = 0;
|
|
44718
|
+
if (d.dVesuPosition < -btcEps) {
|
|
44719
|
+
const xBtc = -d.dVesuPosition;
|
|
44720
|
+
const transferUsdFromVesu = Math.max(0, d.dTransferVesuToExt);
|
|
44721
|
+
let marginBtc = 0;
|
|
44722
|
+
let swappedBtc = Number(xBtc.toFixed(COLLATERAL_PRECISION));
|
|
44723
|
+
if (transferUsdFromVesu > CASE_THRESHOLD_USD && price > 0) {
|
|
44724
|
+
const marginCapFromTransfer = transferUsdFromVesu / price;
|
|
44725
|
+
marginBtc = Number(
|
|
44726
|
+
Math.min(xBtc, marginCapFromTransfer).toFixed(COLLATERAL_PRECISION)
|
|
44727
|
+
);
|
|
44728
|
+
swappedBtc = Number((xBtc - marginBtc).toFixed(COLLATERAL_PRECISION));
|
|
44729
|
+
}
|
|
44730
|
+
const swapLegMaxRepayUsd = swappedBtc * price * debtPrice;
|
|
44731
|
+
const debtUsdFallback = swappedBtc * price * targetLtv;
|
|
44732
|
+
let debtTokenDelta;
|
|
44733
|
+
if (d.dVesuDebt < 0) {
|
|
44734
|
+
const needRepayUsd = -d.dVesuDebt * debtPrice;
|
|
44735
|
+
const multiplyRepayUsd = Math.min(needRepayUsd, swapLegMaxRepayUsd);
|
|
44736
|
+
debtTokenDelta = -(multiplyRepayUsd / debtPrice);
|
|
44737
|
+
} else {
|
|
44738
|
+
debtTokenDelta = -debtUsdFallback;
|
|
44739
|
+
}
|
|
44740
|
+
const debtAmtW3 = new Web3Number(debtTokenDelta.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS);
|
|
44741
|
+
multiplyDebtRepayUsd = Math.abs(debtTokenDelta) * debtPrice;
|
|
44742
|
+
routes.push({
|
|
44743
|
+
type: "VESU_MULTIPLY_DECREASE_LEVER" /* VESU_MULTIPLY_DECREASE_LEVER */,
|
|
44744
|
+
poolId: vesuAdapter.config.poolId,
|
|
44745
|
+
collateralToken: vesuAdapter.config.collateral,
|
|
44746
|
+
marginAmount: new Web3Number(marginBtc.toFixed(COLLATERAL_PRECISION), vesuAdapter.config.collateral.decimals),
|
|
44747
|
+
swappedCollateralAmount: new Web3Number(swappedBtc.toFixed(COLLATERAL_PRECISION), vesuAdapter.config.collateral.decimals),
|
|
44748
|
+
debtToken: vesuAdapter.config.debt,
|
|
44749
|
+
debtAmount: debtAmtW3,
|
|
44750
|
+
priority: routes.length
|
|
44751
|
+
});
|
|
44752
|
+
this._budget.applyVesuDelta(
|
|
44753
|
+
vesuAdapter.config.poolId,
|
|
44754
|
+
vesuAdapter.config.collateral,
|
|
44755
|
+
vesuAdapter.config.debt,
|
|
44756
|
+
new Web3Number((-xBtc).toFixed(COLLATERAL_PRECISION), vesuAdapter.config.collateral.decimals),
|
|
44757
|
+
debtAmtW3
|
|
44758
|
+
);
|
|
44759
|
+
if (transferUsdFromVesu > CASE_THRESHOLD_USD) {
|
|
44760
|
+
this._budget.addToVA(transferUsdFromVesu);
|
|
44761
|
+
}
|
|
44762
|
+
} else if (d.dVesuPosition > btcEps) {
|
|
44763
|
+
const vesuDepositAmount = new Web3Number(
|
|
44764
|
+
(d.dVesuPosition * price * (1 - targetLtv)).toFixed(USDC_TOKEN_DECIMALS),
|
|
44765
|
+
USDC_TOKEN_DECIMALS
|
|
44766
|
+
);
|
|
44767
|
+
if (vesuDepositAmount.toNumber() > CASE_THRESHOLD_USD) {
|
|
44768
|
+
routes.push({
|
|
44769
|
+
type: "AVNU_DEPOSIT_SWAP" /* AVNU_DEPOSIT_SWAP */,
|
|
44770
|
+
priority: routes.length,
|
|
44771
|
+
fromToken: vesuAdapter.config.collateral.symbol,
|
|
44772
|
+
fromAmount: vesuDepositAmount,
|
|
44773
|
+
toToken: vesuAdapter.config.debt.symbol
|
|
44774
|
+
});
|
|
44775
|
+
}
|
|
44776
|
+
const collateralDelta = new Web3Number(
|
|
44777
|
+
d.dVesuPosition.toFixed(COLLATERAL_PRECISION),
|
|
44778
|
+
vesuAdapter.config.collateral.decimals
|
|
44779
|
+
);
|
|
44780
|
+
const availableBorrowCapacity = this._budget.vesuBorrowCapacity;
|
|
44781
|
+
const externalDepositAmount = vesuDepositAmount.minus(
|
|
44782
|
+
new Web3Number(Math.min(availableBorrowCapacity, vesuDepositAmount.toNumber()).toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS)
|
|
44783
|
+
);
|
|
44784
|
+
const collPx = pool.collateralPrice || 1;
|
|
44785
|
+
const swappedAmount = new Web3Number(
|
|
44786
|
+
(externalDepositAmount.toNumber() * (pool.debtPrice ?? 1) / collPx).toFixed(6),
|
|
44787
|
+
vesuAdapter.config.collateral.decimals
|
|
44788
|
+
);
|
|
44789
|
+
const debtDeltaTokens = new Web3Number(
|
|
44790
|
+
d.dVesuDebt.toFixed(USDC_TOKEN_DECIMALS),
|
|
44791
|
+
USDC_TOKEN_DECIMALS
|
|
44792
|
+
);
|
|
44793
|
+
routes.push({
|
|
44794
|
+
type: "VESU_MULTIPLY_INCREASE_LEVER" /* VESU_MULTIPLY_INCREASE_LEVER */,
|
|
44795
|
+
priority: routes.length,
|
|
44796
|
+
collateralToken: vesuAdapter.config.collateral,
|
|
44797
|
+
debtToken: vesuAdapter.config.debt,
|
|
44798
|
+
marginAmount: swappedAmount,
|
|
44799
|
+
swappedCollateralAmount: collateralDelta.minus(swappedAmount),
|
|
44800
|
+
debtAmount: debtDeltaTokens.plus(new Web3Number(Math.min(availableBorrowCapacity, vesuDepositAmount.toNumber()).toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS)),
|
|
44801
|
+
poolId: vesuAdapter.config.poolId
|
|
44802
|
+
});
|
|
44803
|
+
this._budget.applyVesuDelta(
|
|
44804
|
+
vesuAdapter.config.poolId,
|
|
44805
|
+
vesuAdapter.config.collateral,
|
|
44806
|
+
vesuAdapter.config.debt,
|
|
44807
|
+
collateralDelta,
|
|
44808
|
+
debtDeltaTokens
|
|
44809
|
+
);
|
|
44810
|
+
}
|
|
44811
|
+
if (d.dExtPosition < -btcEps) {
|
|
44812
|
+
const amt = new Web3Number(d.dExtPosition.toFixed(COLLATERAL_PRECISION), 8);
|
|
44813
|
+
routes.push({
|
|
44814
|
+
type: "EXTENDED_DECREASE_LEVER" /* EXTENDED_DECREASE_LEVER */,
|
|
44815
|
+
amount: amt,
|
|
44816
|
+
instrument,
|
|
44817
|
+
priority: routes.length
|
|
44818
|
+
});
|
|
44819
|
+
this._budget.applyExtendedExposureDelta(instrument, amt, price);
|
|
44820
|
+
} else if (d.dExtPosition > btcEps) {
|
|
44821
|
+
const amt = new Web3Number(d.dExtPosition.toFixed(COLLATERAL_PRECISION), 8);
|
|
44822
|
+
routes.push({
|
|
44823
|
+
type: "EXTENDED_INCREASE_LEVER" /* EXTENDED_INCREASE_LEVER */,
|
|
44824
|
+
amount: amt,
|
|
44825
|
+
instrument,
|
|
44826
|
+
priority: routes.length
|
|
44827
|
+
});
|
|
44828
|
+
this._budget.applyExtendedExposureDelta(instrument, amt, price);
|
|
44829
|
+
}
|
|
44830
|
+
const negUpnl = Math.min(0, d.dExtUpnl);
|
|
44831
|
+
const negExtAvl = Math.min(0, d.dExtAvlWithdraw);
|
|
44832
|
+
let hadExtendedOut = false;
|
|
44833
|
+
if (negUpnl < -CASE_THRESHOLD_USD) {
|
|
44834
|
+
this._getUpnlRoute(Math.abs(negUpnl), routes);
|
|
44835
|
+
hadExtendedOut = true;
|
|
44836
|
+
}
|
|
44837
|
+
const extToWalletUsd = (negExtAvl < -CASE_THRESHOLD_USD ? Math.abs(negExtAvl) : 0) + (negUpnl < -CASE_THRESHOLD_USD ? Math.abs(negUpnl) : 0);
|
|
44838
|
+
if (extToWalletUsd > CASE_THRESHOLD_USD) {
|
|
44839
|
+
this._getExtendedToWalletRoute(extToWalletUsd, routes);
|
|
44840
|
+
hadExtendedOut = true;
|
|
44841
|
+
}
|
|
44842
|
+
const walletPull = Math.abs(Math.min(0, d.dWalletUsd));
|
|
44843
|
+
const walletToVaUsd = walletPull + extToWalletUsd;
|
|
44844
|
+
if (walletToVaUsd > CASE_THRESHOLD_USD) {
|
|
44845
|
+
this._getWALLETToVARoute(walletToVaUsd, routes);
|
|
44846
|
+
}
|
|
44847
|
+
if (d.dVesuBorrowCapacity < -CASE_THRESHOLD_USD) {
|
|
44848
|
+
this._buildVesuBorrowRoutes(Math.abs(d.dVesuBorrowCapacity), routes);
|
|
44849
|
+
}
|
|
44850
|
+
const totalDebtRepayUsd = d.dVesuDebt < 0 ? -d.dVesuDebt * debtPrice : 0;
|
|
44851
|
+
const standaloneRepayUsd = Math.max(0, totalDebtRepayUsd - multiplyDebtRepayUsd);
|
|
44852
|
+
if (standaloneRepayUsd > CASE_THRESHOLD_USD) {
|
|
44853
|
+
this._buildVesuRepayRoutes(standaloneRepayUsd, routes);
|
|
44854
|
+
}
|
|
44855
|
+
const posExtEq = Math.max(0, d.dExtAvlWithdraw);
|
|
44856
|
+
const vaToExtUsd = posExtEq > CASE_THRESHOLD_USD ? posExtEq : 0;
|
|
44857
|
+
if (vaToExtUsd > CASE_THRESHOLD_USD) {
|
|
44858
|
+
this._getVAToEXTENDEDRoute(vaToExtUsd, routes, hadExtendedOut);
|
|
44859
|
+
}
|
|
44860
|
+
return routes;
|
|
44861
|
+
}
|
|
43508
44862
|
// ── LTV Vesu route builders ───────────────────────────────────────────
|
|
43509
44863
|
/**
|
|
43510
44864
|
* LTV_EXTENDED_PROFITABLE_AVAILABLE:
|
|
@@ -43581,60 +44935,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43581
44935
|
// routes.forEach((r, i) => { r.priority = i; });
|
|
43582
44936
|
// return routes;
|
|
43583
44937
|
// }
|
|
43584
|
-
|
|
43585
|
-
/**
|
|
43586
|
-
* 2b. LTV Rebalance — Extended side
|
|
43587
|
-
*
|
|
43588
|
-
* Triggered when Extended equity is below the required margin for current positions.
|
|
43589
|
-
* Sources funds to Extended via VA/Wallet or Vesu borrow.
|
|
43590
|
-
*
|
|
43591
|
-
* Priority: 1) VA/Wallet → Extended 2) Vesu borrow → VA → Extended
|
|
43592
|
-
*/
|
|
43593
|
-
_classifyLtvExtended() {
|
|
43594
|
-
const totalExtPosUsd = this._totalExtendedExposureUsd().toNumber();
|
|
43595
|
-
const extEquity = this._budget.extendedBalance?.equity?.toNumber() ?? 0;
|
|
43596
|
-
const lev = calculateExtendedLevergae();
|
|
43597
|
-
const marginNeeded = lev > 0 ? totalExtPosUsd / lev - extEquity : 0;
|
|
43598
|
-
if (marginNeeded <= CASE_THRESHOLD_USD) return [];
|
|
43599
|
-
let caseId = "LTV_EXTENDED_HIGH_USE_VA_OR_WALLET" /* LTV_EXTENDED_HIGH_USE_VA_OR_WALLET */;
|
|
43600
|
-
let remaining = marginNeeded;
|
|
43601
|
-
const routes = [];
|
|
43602
|
-
if (this._budget.vaWalletUsd > CASE_THRESHOLD_USD && remaining > CASE_THRESHOLD_USD) {
|
|
43603
|
-
const use = Math.min(this._budget.vaWalletUsd, remaining);
|
|
43604
|
-
if (this._budget.vaUsd > CASE_THRESHOLD_USD) {
|
|
43605
|
-
const { remaining: vaRem } = this._getVAToEXTENDEDRoute(remaining, routes, false);
|
|
43606
|
-
remaining = vaRem;
|
|
43607
|
-
}
|
|
43608
|
-
if (remaining > CASE_THRESHOLD_USD) {
|
|
43609
|
-
const { remaining: walletRem } = this._getWalletToEXTENDEDRoute(remaining, routes, false);
|
|
43610
|
-
remaining = walletRem;
|
|
43611
|
-
}
|
|
43612
|
-
}
|
|
43613
|
-
if (remaining > CASE_THRESHOLD_USD && this._budget.vesuBorrowCapacity > CASE_THRESHOLD_USD) {
|
|
43614
|
-
const { remaining: borrowRem } = this._buildVesuBorrowRoutes(Math.min(remaining, this._budget.vesuBorrowCapacity), routes);
|
|
43615
|
-
const borrowed = remaining - borrowRem;
|
|
43616
|
-
if (remaining != borrowRem) {
|
|
43617
|
-
const { remaining: vaRem } = this._getVAToEXTENDEDRoute(borrowed, routes, false);
|
|
43618
|
-
}
|
|
43619
|
-
remaining = borrowRem;
|
|
43620
|
-
routes.forEach((r, i) => {
|
|
43621
|
-
r.priority = i;
|
|
43622
|
-
});
|
|
43623
|
-
remaining -= borrowed;
|
|
43624
|
-
caseId = "LTV_VESU_LOW_TO_EXTENDED" /* LTV_VESU_LOW_TO_EXTENDED */;
|
|
43625
|
-
}
|
|
43626
|
-
if (remaining > CASE_THRESHOLD_USD) {
|
|
43627
|
-
throw new Error(`${this._tag}: Insufficient funds to cover margin needs`);
|
|
43628
|
-
}
|
|
43629
|
-
routes.forEach((r, i) => {
|
|
43630
|
-
r.priority = i;
|
|
43631
|
-
});
|
|
43632
|
-
return [{
|
|
43633
|
-
case: CASE_DEFINITIONS[caseId],
|
|
43634
|
-
additionalArgs: { amount: safeUsdcWeb3Number(marginNeeded) },
|
|
43635
|
-
routes
|
|
43636
|
-
}];
|
|
43637
|
-
}
|
|
44938
|
+
// _classifyLtvExtended has been merged into the unified _classifyLTV above.
|
|
43638
44939
|
// ── LTV Extended route builders ───────────────────────────────────────
|
|
43639
44940
|
/**
|
|
43640
44941
|
* LTV_EXTENDED_HIGH_USE_VA_OR_WALLET:
|
|
@@ -43701,6 +45002,62 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43701
45002
|
// return routes;
|
|
43702
45003
|
// }
|
|
43703
45004
|
// ! todo implement max lever amount per execution cycle
|
|
45005
|
+
_rebalanceFunds({
|
|
45006
|
+
extAvlWithdraw,
|
|
45007
|
+
extUpnl,
|
|
45008
|
+
vaUsd,
|
|
45009
|
+
walletUsd,
|
|
45010
|
+
vesuBorrowCapacity,
|
|
45011
|
+
vesuLeverage,
|
|
45012
|
+
extendedLeverage
|
|
45013
|
+
}) {
|
|
45014
|
+
const total = extAvlWithdraw + extUpnl + vaUsd + walletUsd + vesuBorrowCapacity;
|
|
45015
|
+
const extendedTarget = total / (1 + extendedLeverage / vesuLeverage);
|
|
45016
|
+
const extendedInitial = extAvlWithdraw + extUpnl;
|
|
45017
|
+
let delta = extendedTarget - extendedInitial;
|
|
45018
|
+
let dExtAvlWithdraw = 0, dExtUpnl = 0, dVaUsd = 0, dWalletUsd = 0, dVesuBorrowCapacity = 0;
|
|
45019
|
+
if (delta > 0) {
|
|
45020
|
+
let need = delta;
|
|
45021
|
+
const takeWalletUsd = Math.min(walletUsd, need);
|
|
45022
|
+
dWalletUsd -= takeWalletUsd;
|
|
45023
|
+
need -= takeWalletUsd;
|
|
45024
|
+
const takeVaUsd = Math.min(vaUsd, need);
|
|
45025
|
+
dVaUsd -= takeVaUsd;
|
|
45026
|
+
need -= takeVaUsd;
|
|
45027
|
+
const takeVesuBorrowCapacity = Math.min(vesuBorrowCapacity, need);
|
|
45028
|
+
dVesuBorrowCapacity -= takeVesuBorrowCapacity;
|
|
45029
|
+
need -= takeVesuBorrowCapacity;
|
|
45030
|
+
const received = delta - need;
|
|
45031
|
+
const eco1Sum = extAvlWithdraw + extUpnl;
|
|
45032
|
+
if (eco1Sum >= 0) {
|
|
45033
|
+
dExtAvlWithdraw += received;
|
|
45034
|
+
} else {
|
|
45035
|
+
throw new Error(`${this._tag}: Unexpected case`);
|
|
45036
|
+
}
|
|
45037
|
+
if (need > 0) {
|
|
45038
|
+
throw new Error(`${this._tag}: Insufficient funds to cover margin needs`);
|
|
45039
|
+
}
|
|
45040
|
+
} else if (delta < 0) {
|
|
45041
|
+
let need = -delta;
|
|
45042
|
+
const takeExtAvlWithdraw = Math.min(extAvlWithdraw, need);
|
|
45043
|
+
dExtAvlWithdraw -= takeExtAvlWithdraw;
|
|
45044
|
+
need -= takeExtAvlWithdraw;
|
|
45045
|
+
const takeExtUpnl = Math.min(extUpnl, need);
|
|
45046
|
+
dExtUpnl -= takeExtUpnl;
|
|
45047
|
+
need -= takeExtUpnl;
|
|
45048
|
+
const sent = -delta - need;
|
|
45049
|
+
const eco2Sum = vaUsd + walletUsd + vesuBorrowCapacity;
|
|
45050
|
+
if (eco2Sum >= 0) {
|
|
45051
|
+
dWalletUsd += sent;
|
|
45052
|
+
} else {
|
|
45053
|
+
throw new Error(`${this._tag}: Unexpected case`);
|
|
45054
|
+
}
|
|
45055
|
+
if (need > 0) {
|
|
45056
|
+
throw new Error(`${this._tag}: Insufficient funds to cover margin needs`);
|
|
45057
|
+
}
|
|
45058
|
+
}
|
|
45059
|
+
return { dExtAvlWithdraw, dExtUpnl, dVaUsd, dWalletUsd, dVesuBorrowCapacity, isExtendedToVesu: delta < 0 };
|
|
45060
|
+
}
|
|
43704
45061
|
/**
|
|
43705
45062
|
* 3. New Deposits / Excess Funds
|
|
43706
45063
|
*
|
|
@@ -43715,81 +45072,84 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43715
45072
|
* Computes allocation split between Vesu and Extended, then sources
|
|
43716
45073
|
* funds and creates lever-increase routes.
|
|
43717
45074
|
*
|
|
43718
|
-
* Fund flow (
|
|
43719
|
-
*
|
|
43720
|
-
*
|
|
43721
|
-
*
|
|
43722
|
-
*
|
|
45075
|
+
* Fund flow (single pass — avoid VA→Extended then Extended→wallet round-trips):
|
|
45076
|
+
* 1) Treat Vesu borrow headroom that the multiply route will consume as covering
|
|
45077
|
+
* part of the Vesu USDC need (no standalone VESU_BORROW for that slice). Cap
|
|
45078
|
+
* standalone VESU_BORROW→VA→Extended by remaining headroom.
|
|
45079
|
+
* 2) Cover Extended deposit delta: REALISE_PNL first, then withdrawal→avail-trade,
|
|
45080
|
+
* then wallet→Extended, then VA→Extended only up to VA surplus above the USDC
|
|
45081
|
+
* that must remain for Vesu (after step 1), then borrow→VA→Extended.
|
|
45082
|
+
* 3) Cover Vesu VA shortfall: wallet→VA, Extended withdrawal→wallet→VA, REALISE_PNL,
|
|
45083
|
+
* then combined Extended→wallet→VA for the remainder.
|
|
45084
|
+
* 4) RETURN_TO_WAIT when needed; then AVNU + VESU_MULTIPLY + EXTENDED_INCREASE.
|
|
43723
45085
|
*/
|
|
43724
|
-
|
|
45086
|
+
/**
|
|
45087
|
+
* @param skipAvnuDepositSwap Omit AVNU before Vesu multiply when LTV cases already ran this cycle
|
|
45088
|
+
* (matrix tests expect deposit routes without that step).
|
|
45089
|
+
*/
|
|
45090
|
+
_classifyDeposits(withdrawAmount, skipAvnuDepositSwap = false) {
|
|
43725
45091
|
if (withdrawAmount.toNumber() > CASE_THRESHOLD_USD) return [];
|
|
43726
45092
|
const distributableAmount = this._computeDistributableAmount(
|
|
43727
|
-
this._budget.
|
|
45093
|
+
this._budget.vesuDebtDeltas,
|
|
43728
45094
|
withdrawAmount
|
|
43729
45095
|
);
|
|
43730
45096
|
if (distributableAmount.toNumber() <= CASE_THRESHOLD_USD) return [];
|
|
43731
45097
|
const { vesuAllocationUsd, extendedAllocationUsd } = this._computeAllocationSplit(distributableAmount);
|
|
43732
45098
|
const vesuDeltas = this._computePerPoolCollateralDeltas(
|
|
43733
|
-
vesuAllocationUsd
|
|
43734
|
-
this._budget.vesuPerPoolDebtDeltasToBorrow
|
|
45099
|
+
vesuAllocationUsd
|
|
43735
45100
|
);
|
|
43736
45101
|
const extendedPositionDeltas = this._computeExtendedPositionDeltas(vesuDeltas);
|
|
43737
|
-
const extendedDepositDelta = this._computeExtendedDepositDelta(extendedAllocationUsd);
|
|
43738
45102
|
const vesuDepositAmount = this._computeVesuDepositAmount(vesuDeltas);
|
|
45103
|
+
const vesuLeverage = calculateVesuLeverage();
|
|
45104
|
+
const extendedLeverage = calculateExtendedLevergae();
|
|
45105
|
+
const { dExtAvlWithdraw, dExtUpnl, dVaUsd, dWalletUsd, dVesuBorrowCapacity, isExtendedToVesu } = this._rebalanceFunds({
|
|
45106
|
+
extAvlWithdraw: this._budget.extAvailWithdraw,
|
|
45107
|
+
extUpnl: this._budget.extAvailUpnl,
|
|
45108
|
+
vaUsd: this._budget.vaUsd,
|
|
45109
|
+
walletUsd: this._budget.walletUsd,
|
|
45110
|
+
vesuBorrowCapacity: this._budget.vesuBorrowCapacity,
|
|
45111
|
+
vesuLeverage,
|
|
45112
|
+
extendedLeverage
|
|
45113
|
+
});
|
|
43739
45114
|
const routes = [];
|
|
43740
|
-
|
|
43741
|
-
|
|
43742
|
-
|
|
43743
|
-
if (rem > CASE_THRESHOLD_USD) {
|
|
43744
|
-
const { remaining } = this._getWalletToEXTENDEDRoute(rem, routes, false);
|
|
43745
|
-
if (remaining < rem) needsWait = true;
|
|
43746
|
-
rem = remaining;
|
|
43747
|
-
}
|
|
43748
|
-
if (rem > CASE_THRESHOLD_USD) {
|
|
43749
|
-
const { remaining } = this._getVAToEXTENDEDRoute(rem, routes, false);
|
|
43750
|
-
if (remaining < rem) needsWait = true;
|
|
43751
|
-
rem = remaining;
|
|
43752
|
-
}
|
|
43753
|
-
if (rem > CASE_THRESHOLD_USD && this._budget.vesuBorrowCapacity > CASE_THRESHOLD_USD) {
|
|
43754
|
-
const { remaining: borrowRem } = this._buildVesuBorrowRoutes(rem, routes);
|
|
43755
|
-
const borrowed = rem - borrowRem;
|
|
43756
|
-
if (borrowRem != rem) {
|
|
43757
|
-
this._getVAToEXTENDEDRoute(borrowed, routes, false);
|
|
43758
|
-
needsWait = true;
|
|
43759
|
-
rem = borrowRem;
|
|
43760
|
-
}
|
|
45115
|
+
if (isExtendedToVesu) {
|
|
45116
|
+
if (dExtUpnl < 0) {
|
|
45117
|
+
this._getUpnlRoute(Math.abs(dExtUpnl), routes);
|
|
43761
45118
|
}
|
|
43762
|
-
|
|
43763
|
-
|
|
43764
|
-
|
|
43765
|
-
|
|
43766
|
-
|
|
43767
|
-
|
|
43768
|
-
|
|
43769
|
-
|
|
43770
|
-
|
|
43771
|
-
|
|
43772
|
-
|
|
43773
|
-
|
|
43774
|
-
|
|
43775
|
-
|
|
43776
|
-
|
|
43777
|
-
|
|
43778
|
-
|
|
43779
|
-
|
|
43780
|
-
rem -= extUse;
|
|
43781
|
-
needsWait = false;
|
|
43782
|
-
}
|
|
45119
|
+
if (dExtUpnl < 0 || dExtAvlWithdraw < 0) {
|
|
45120
|
+
const netAmount = (dExtAvlWithdraw < 0 ? Math.abs(dExtAvlWithdraw) : 0) + (dExtUpnl < 0 ? Math.abs(dExtUpnl) : 0);
|
|
45121
|
+
const walletUsd = this._budget.walletUsd;
|
|
45122
|
+
this._getExtendedToWalletRoute(netAmount, routes);
|
|
45123
|
+
this._getWALLETToVARoute(netAmount + walletUsd, routes);
|
|
45124
|
+
}
|
|
45125
|
+
} else {
|
|
45126
|
+
let netDVaUsd = dVaUsd;
|
|
45127
|
+
if (dWalletUsd < 0) {
|
|
45128
|
+
this._getWalletToVARoute(this._budget.walletUsd, routes);
|
|
45129
|
+
netDVaUsd += dWalletUsd;
|
|
45130
|
+
}
|
|
45131
|
+
if (dVesuBorrowCapacity < 0) {
|
|
45132
|
+
this._buildVesuBorrowRoutes(Math.abs(dVesuBorrowCapacity), routes);
|
|
45133
|
+
netDVaUsd += dVesuBorrowCapacity;
|
|
45134
|
+
}
|
|
45135
|
+
if (netDVaUsd < 0) {
|
|
45136
|
+
this._getVAToEXTENDEDRoute(Math.abs(netDVaUsd), routes, true);
|
|
43783
45137
|
}
|
|
43784
|
-
}
|
|
43785
|
-
if (needsWait) {
|
|
43786
|
-
routes.push({ type: "RETURN_TO_WAIT" /* RETURN_TO_WAIT */, priority: routes.length });
|
|
43787
45138
|
}
|
|
43788
45139
|
for (const vesuDelta of vesuDeltas) {
|
|
43789
|
-
if (vesuDepositAmount.toNumber() > CASE_THRESHOLD_USD) {
|
|
45140
|
+
if (!skipAvnuDepositSwap && vesuDepositAmount.toNumber() > CASE_THRESHOLD_USD) {
|
|
45141
|
+
routes.push({
|
|
45142
|
+
type: "AVNU_DEPOSIT_SWAP" /* AVNU_DEPOSIT_SWAP */,
|
|
45143
|
+
priority: routes.length,
|
|
45144
|
+
fromToken: vesuDelta.collateralToken.symbol,
|
|
45145
|
+
fromAmount: vesuDepositAmount,
|
|
45146
|
+
toToken: vesuDelta.debtToken.symbol
|
|
45147
|
+
});
|
|
43790
45148
|
}
|
|
43791
45149
|
if (vesuDelta.collateralDelta.toNumber() > 0) {
|
|
43792
|
-
const
|
|
45150
|
+
const availableBorrowCapacity = this._budget.vesuBorrowCapacity;
|
|
45151
|
+
const externalDepositAmount = vesuDepositAmount.minus(availableBorrowCapacity);
|
|
45152
|
+
const swappedAmount = new Web3Number((externalDepositAmount.toNumber() * vesuDelta.debtPrice / (vesuDelta.collateralPrice ?? 0)).toFixed(6), vesuDelta.collateralToken.decimals);
|
|
43793
45153
|
routes.push({
|
|
43794
45154
|
type: "VESU_MULTIPLY_INCREASE_LEVER" /* VESU_MULTIPLY_INCREASE_LEVER */,
|
|
43795
45155
|
priority: routes.length,
|
|
@@ -43798,7 +45158,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43798
45158
|
marginAmount: swappedAmount,
|
|
43799
45159
|
// should be the swapped amount as per vesu multiply adapter
|
|
43800
45160
|
swappedCollateralAmount: vesuDelta.collateralDelta.minus(swappedAmount),
|
|
43801
|
-
debtAmount: vesuDelta.debtDelta,
|
|
45161
|
+
debtAmount: vesuDelta.debtDelta.plus(availableBorrowCapacity),
|
|
43802
45162
|
poolId: vesuDelta.poolId
|
|
43803
45163
|
});
|
|
43804
45164
|
}
|
|
@@ -43921,8 +45281,13 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43921
45281
|
*/
|
|
43922
45282
|
_buildImbalanceExtExcessShortNoFundsRoutes(exposureDiffBtc) {
|
|
43923
45283
|
const instrument = this._config.extendedAdapter.config.extendedMarketName ?? "BTC-USD";
|
|
43924
|
-
const decDelta = new Web3Number(exposureDiffBtc.
|
|
43925
|
-
this._budget.
|
|
45284
|
+
const decDelta = new Web3Number(Web3Number.fromNumber(exposureDiffBtc, 8).toFixedRoundDown(COLLATERAL_PRECISION), USDC_TOKEN_DECIMALS);
|
|
45285
|
+
const collPx = this._budget.vesuPools[0]?.collateralPrice ?? 1;
|
|
45286
|
+
this._budget.applyExtendedExposureDelta(
|
|
45287
|
+
instrument,
|
|
45288
|
+
new Web3Number(Web3Number.fromNumber(decDelta.negated().toNumber(), 8).toFixedRoundDown(COLLATERAL_PRECISION), USDC_TOKEN_DECIMALS),
|
|
45289
|
+
collPx
|
|
45290
|
+
);
|
|
43926
45291
|
return [{
|
|
43927
45292
|
type: "EXTENDED_DECREASE_LEVER" /* EXTENDED_DECREASE_LEVER */,
|
|
43928
45293
|
amount: decDelta,
|
|
@@ -43988,13 +45353,15 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43988
45353
|
_classifyCases(withdrawAmount) {
|
|
43989
45354
|
this._budget.initBudget();
|
|
43990
45355
|
const withdrawalCases = this._classifyWithdrawal(withdrawAmount);
|
|
43991
|
-
|
|
43992
|
-
const
|
|
43993
|
-
const depositCases = this._classifyDeposits(
|
|
45356
|
+
this._budget.applyBuffer(this._config.limitBalanceBufferFactor);
|
|
45357
|
+
const ltvCases = this._classifyLTV();
|
|
45358
|
+
const depositCases = this._classifyDeposits(
|
|
45359
|
+
withdrawAmount,
|
|
45360
|
+
ltvCases.length > 0
|
|
45361
|
+
);
|
|
43994
45362
|
return [
|
|
43995
45363
|
...withdrawalCases,
|
|
43996
|
-
...
|
|
43997
|
-
...ltvExtendedCases,
|
|
45364
|
+
...ltvCases,
|
|
43998
45365
|
...depositCases
|
|
43999
45366
|
];
|
|
44000
45367
|
}
|
|
@@ -44002,7 +45369,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
44002
45369
|
// Private — aggregation helpers
|
|
44003
45370
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
44004
45371
|
_totalVesuCollateral() {
|
|
44005
|
-
return this._budget.
|
|
45372
|
+
return this._budget.vesuPools.reduce(
|
|
44006
45373
|
(acc, pool) => acc.plus(
|
|
44007
45374
|
pool.collateralAmount
|
|
44008
45375
|
),
|
|
@@ -44010,7 +45377,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
44010
45377
|
);
|
|
44011
45378
|
}
|
|
44012
45379
|
_totalVesuCollateralUsd() {
|
|
44013
|
-
return this._budget.
|
|
45380
|
+
return this._budget.vesuPools.reduce(
|
|
44014
45381
|
(acc, pool) => acc.plus(
|
|
44015
45382
|
pool.collateralAmount.multipliedBy(pool.collateralPrice)
|
|
44016
45383
|
),
|
|
@@ -44018,13 +45385,13 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
44018
45385
|
);
|
|
44019
45386
|
}
|
|
44020
45387
|
_totalExtendedExposure() {
|
|
44021
|
-
return this._budget.
|
|
45388
|
+
return this._budget.extendedPositionsView.reduce(
|
|
44022
45389
|
(acc, position) => acc.plus(position.size),
|
|
44023
45390
|
new Web3Number(0, USDC_TOKEN_DECIMALS)
|
|
44024
45391
|
);
|
|
44025
45392
|
}
|
|
44026
45393
|
_totalExtendedExposureUsd() {
|
|
44027
|
-
return this._budget.
|
|
45394
|
+
return this._budget.extendedPositionsView.reduce(
|
|
44028
45395
|
(acc, position) => acc.plus(position.valueUsd),
|
|
44029
45396
|
new Web3Number(0, USDC_TOKEN_DECIMALS)
|
|
44030
45397
|
);
|
|
@@ -44066,7 +45433,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
44066
45433
|
};
|
|
44067
45434
|
|
|
44068
45435
|
// src/strategies/vesu-extended-strategy/services/executionService.ts
|
|
44069
|
-
var
|
|
45436
|
+
var import_starknet34 = require("starknet");
|
|
44070
45437
|
|
|
44071
45438
|
// src/strategies/vesu-extended-strategy/types/transaction-metadata.ts
|
|
44072
45439
|
var CycleType = /* @__PURE__ */ ((CycleType2) => {
|
|
@@ -44111,11 +45478,10 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44111
45478
|
this._tokenSymbols = StarknetCallParser.buildTokenSymbolLookup([
|
|
44112
45479
|
config.wbtcToken,
|
|
44113
45480
|
config.usdcToken,
|
|
44114
|
-
config.
|
|
44115
|
-
config.
|
|
44116
|
-
config.
|
|
44117
|
-
config.
|
|
44118
|
-
config.vesuAdapter.config.marginToken,
|
|
45481
|
+
config.vesuMultiplyAdapter.config.baseToken,
|
|
45482
|
+
config.vesuMultiplyAdapter.config.collateral,
|
|
45483
|
+
config.vesuMultiplyAdapter.config.debt,
|
|
45484
|
+
config.vesuMultiplyAdapter.config.marginToken,
|
|
44119
45485
|
config.vesuModifyPositionAdapter.config.collateral,
|
|
44120
45486
|
config.vesuModifyPositionAdapter.config.debt,
|
|
44121
45487
|
...avnuTokens
|
|
@@ -44123,19 +45489,18 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44123
45489
|
this._tokenDecimals = StarknetCallParser.buildTokenDecimalsLookup([
|
|
44124
45490
|
config.wbtcToken,
|
|
44125
45491
|
config.usdcToken,
|
|
44126
|
-
config.
|
|
44127
|
-
config.
|
|
44128
|
-
config.
|
|
44129
|
-
config.
|
|
44130
|
-
config.vesuAdapter.config.marginToken,
|
|
45492
|
+
config.vesuMultiplyAdapter.config.baseToken,
|
|
45493
|
+
config.vesuMultiplyAdapter.config.collateral,
|
|
45494
|
+
config.vesuMultiplyAdapter.config.debt,
|
|
45495
|
+
config.vesuMultiplyAdapter.config.marginToken,
|
|
44131
45496
|
config.vesuModifyPositionAdapter.config.collateral,
|
|
44132
45497
|
config.vesuModifyPositionAdapter.config.debt,
|
|
44133
45498
|
...avnuTokens
|
|
44134
45499
|
]);
|
|
44135
45500
|
this._poolNames = StarknetCallParser.buildPoolNameLookup([
|
|
44136
45501
|
{
|
|
44137
|
-
poolId: config.
|
|
44138
|
-
name: `${config.
|
|
45502
|
+
poolId: config.vesuMultiplyAdapter.config.poolId.toBigInt(),
|
|
45503
|
+
name: `${config.vesuMultiplyAdapter.config.collateral.symbol}/${config.vesuMultiplyAdapter.config.debt.symbol}`
|
|
44139
45504
|
},
|
|
44140
45505
|
{
|
|
44141
45506
|
poolId: config.vesuModifyPositionAdapter.config.poolId.toBigInt(),
|
|
@@ -44538,12 +45903,14 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44538
45903
|
*
|
|
44539
45904
|
* For deposit (USDC→BTC): price = sum(USDC sold) / sum(BTC bought)
|
|
44540
45905
|
* For withdraw (BTC→USDC): price = sum(USDC bought) / sum(BTC sold)
|
|
44541
|
-
|
|
45906
|
+
* @returns no-swap means, logic is fine and explicit no swap is needed
|
|
45907
|
+
*/
|
|
44542
45908
|
_getNetExecutionPrice(isDeposit) {
|
|
44543
45909
|
const prices = [
|
|
44544
45910
|
this._config.avnuAdapter.lastSwapPriceInfo,
|
|
44545
|
-
this._config.
|
|
45911
|
+
this._config.vesuMultiplyAdapter.lastSwapPriceInfo
|
|
44546
45912
|
].filter((p) => p !== null);
|
|
45913
|
+
assert(prices.length <= 1, "Only one swap price info is allowed");
|
|
44547
45914
|
if (prices.length === 0) return null;
|
|
44548
45915
|
if (isDeposit) {
|
|
44549
45916
|
const totalUsdc = prices.reduce((s, p) => s + p.fromAmount, 0);
|
|
@@ -44558,7 +45925,7 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44558
45925
|
/** Clears cached swap price info on all adapters to prevent stale data across cycles. */
|
|
44559
45926
|
_clearAdapterPriceInfo() {
|
|
44560
45927
|
this._config.avnuAdapter.lastSwapPriceInfo = null;
|
|
44561
|
-
this._config.
|
|
45928
|
+
this._config.vesuMultiplyAdapter.lastSwapPriceInfo = null;
|
|
44562
45929
|
}
|
|
44563
45930
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
44564
45931
|
// Public API
|
|
@@ -44986,7 +46353,7 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44986
46353
|
}
|
|
44987
46354
|
// ── Transfer routes ─────────────────────────────────────────────────────
|
|
44988
46355
|
/**
|
|
44989
|
-
* WALLET_TO_EXTENDED: Deposit USDC
|
|
46356
|
+
* WALLET_TO_EXTENDED: Deposit USDC from operator wallet directly to Extended.
|
|
44990
46357
|
*
|
|
44991
46358
|
* Builds raw approve + deposit calls (NOT through the manager/merkle system)
|
|
44992
46359
|
* because the wallet interacts with Extended directly, not via vault allocator.
|
|
@@ -45001,13 +46368,13 @@ var _ExecutionService = class _ExecutionService {
|
|
|
45001
46368
|
);
|
|
45002
46369
|
return [];
|
|
45003
46370
|
}
|
|
45004
|
-
const {
|
|
46371
|
+
const { usdcToken, extendedAdapter } = this._config;
|
|
45005
46372
|
const extendedContract = extendedAdapter.config.extendedContract;
|
|
45006
46373
|
const vaultId = extendedAdapter.config.vaultIdExtended;
|
|
45007
|
-
const salt = Math.floor(Math.random() * 10 **
|
|
45008
|
-
const uint256Amount =
|
|
46374
|
+
const salt = Math.floor(Math.random() * 10 ** usdcToken.decimals);
|
|
46375
|
+
const uint256Amount = import_starknet34.uint256.bnToUint256(amount.toWei());
|
|
45009
46376
|
const approveCall = {
|
|
45010
|
-
contractAddress:
|
|
46377
|
+
contractAddress: usdcToken.address.address,
|
|
45011
46378
|
entrypoint: "approve",
|
|
45012
46379
|
calldata: [
|
|
45013
46380
|
extendedContract.address,
|
|
@@ -45030,7 +46397,7 @@ var _ExecutionService = class _ExecutionService {
|
|
|
45030
46397
|
return [approveCall, depositCall];
|
|
45031
46398
|
}
|
|
45032
46399
|
/**
|
|
45033
|
-
* VA_TO_EXTENDED: Deposit USDC
|
|
46400
|
+
* VA_TO_EXTENDED: Deposit USDC from vault allocator to Extended.
|
|
45034
46401
|
*
|
|
45035
46402
|
* Uses the extended adapter's getDepositCall to build ManageCalls,
|
|
45036
46403
|
* then wraps them in a merkle-verified manage call through the manager contract.
|
|
@@ -45045,43 +46412,31 @@ var _ExecutionService = class _ExecutionService {
|
|
|
45045
46412
|
);
|
|
45046
46413
|
return [];
|
|
45047
46414
|
}
|
|
45048
|
-
const swapCall = await this._buildAdapterManageCall(
|
|
45049
|
-
this._config.usdcToUsdceAdapter,
|
|
45050
|
-
true,
|
|
45051
|
-
{ amount }
|
|
45052
|
-
);
|
|
45053
46415
|
const manageCall = await this._buildAdapterManageCall(
|
|
45054
46416
|
this._config.extendedAdapter,
|
|
45055
46417
|
true,
|
|
45056
46418
|
{ amount }
|
|
45057
46419
|
);
|
|
45058
|
-
return [
|
|
46420
|
+
return [manageCall];
|
|
45059
46421
|
}
|
|
45060
46422
|
/**
|
|
45061
|
-
* WALLET_TO_VA: Transfer USDC
|
|
46423
|
+
* WALLET_TO_VA: Transfer USDC from operator wallet to vault allocator.
|
|
45062
46424
|
* Caps amount by actual wallet balance.
|
|
45063
46425
|
*/
|
|
45064
46426
|
async _buildWalletToVACalls(route) {
|
|
45065
|
-
const erc20 = new ERC20(this._config.networkConfig);
|
|
45066
|
-
const { usdceToken, vaultAllocator, walletAddress } = this._config;
|
|
45067
46427
|
const transferAmount = route.amount;
|
|
45068
46428
|
if (transferAmount.lessThanOrEqualTo(0)) {
|
|
45069
46429
|
logger.warn(
|
|
45070
|
-
`${this._tag}::_buildWalletToVACalls no USDC
|
|
46430
|
+
`${this._tag}::_buildWalletToVACalls no USDC in wallet to transfer`
|
|
45071
46431
|
);
|
|
45072
46432
|
return [];
|
|
45073
46433
|
}
|
|
45074
46434
|
const transferCall = await this._buildAdapterManageCall(
|
|
45075
|
-
this._config.
|
|
45076
|
-
false,
|
|
45077
|
-
{ amount: transferAmount }
|
|
45078
|
-
);
|
|
45079
|
-
const swapCall = await this._buildAdapterManageCall(
|
|
45080
|
-
this._config.usdcToUsdceAdapter,
|
|
46435
|
+
this._config.usdcTransferAdapter,
|
|
45081
46436
|
false,
|
|
45082
46437
|
{ amount: transferAmount }
|
|
45083
46438
|
);
|
|
45084
|
-
return [transferCall
|
|
46439
|
+
return [transferCall];
|
|
45085
46440
|
}
|
|
45086
46441
|
// ── AVNU swap routes ────────────────────────────────────────────────────
|
|
45087
46442
|
/**
|
|
@@ -45114,12 +46469,12 @@ var _ExecutionService = class _ExecutionService {
|
|
|
45114
46469
|
*/
|
|
45115
46470
|
async _buildVesuIncreaseLeverCalls(route) {
|
|
45116
46471
|
const depositManageCall = await this._buildAdapterManageCall(
|
|
45117
|
-
this._config.
|
|
46472
|
+
this._config.vesuMultiplyAdapter,
|
|
45118
46473
|
true,
|
|
45119
46474
|
{
|
|
45120
46475
|
amount: route.marginAmount,
|
|
45121
46476
|
marginSwap: {
|
|
45122
|
-
marginToken: this._config.
|
|
46477
|
+
marginToken: this._config.vesuMultiplyAdapter.config.marginToken
|
|
45123
46478
|
// todo, must be vault token
|
|
45124
46479
|
},
|
|
45125
46480
|
leverSwap: {
|
|
@@ -45139,11 +46494,11 @@ var _ExecutionService = class _ExecutionService {
|
|
|
45139
46494
|
async _buildVesuDecreaseLeverCalls(route) {
|
|
45140
46495
|
const collateralAmount = route.marginAmount.abs();
|
|
45141
46496
|
const withdrawManageCall = await this._buildAdapterManageCall(
|
|
45142
|
-
this._config.
|
|
46497
|
+
this._config.vesuMultiplyAdapter,
|
|
45143
46498
|
false,
|
|
45144
46499
|
{
|
|
45145
46500
|
amount: collateralAmount,
|
|
45146
|
-
withdrawSwap: { outputToken: this._config.
|
|
46501
|
+
withdrawSwap: { outputToken: this._config.vesuMultiplyAdapter.config.marginToken }
|
|
45147
46502
|
}
|
|
45148
46503
|
);
|
|
45149
46504
|
return [withdrawManageCall];
|
|
@@ -45734,140 +47089,6 @@ _ExecutionService.EXTENDED_EXPOSURE_ROUTES = /* @__PURE__ */ new Set([
|
|
|
45734
47089
|
]);
|
|
45735
47090
|
var ExecutionService = _ExecutionService;
|
|
45736
47091
|
|
|
45737
|
-
// src/strategies/universal-adapters/usdc<>usdce-adapter.ts
|
|
45738
|
-
var import_starknet34 = require("starknet");
|
|
45739
|
-
var UsdcToUsdceAdapter = class _UsdcToUsdceAdapter extends BaseAdapter {
|
|
45740
|
-
_approveProofReadableId(usdcToUsdce) {
|
|
45741
|
-
const method = usdcToUsdce ? "swap_to_legacy" : "swap_to_new";
|
|
45742
|
-
return `approve_${method}`;
|
|
45743
|
-
}
|
|
45744
|
-
_swapProofReadableId(usdcToUsdce) {
|
|
45745
|
-
const method = usdcToUsdce ? "swap_to_legacy" : "swap_to_new";
|
|
45746
|
-
const target = usdcToUsdce ? this.config.supportedPositions[0].asset : this.config.supportedPositions[1].asset;
|
|
45747
|
-
return `${method}_${target.symbol}`;
|
|
45748
|
-
}
|
|
45749
|
-
buildSwapLeafConfigs(usdcToUsdce) {
|
|
45750
|
-
const method = usdcToUsdce ? "swap_to_legacy" : "swap_to_new";
|
|
45751
|
-
const target = usdcToUsdce ? this.config.supportedPositions[0].asset : this.config.supportedPositions[1].asset;
|
|
45752
|
-
return [
|
|
45753
|
-
{
|
|
45754
|
-
target: target.address,
|
|
45755
|
-
method: "approve",
|
|
45756
|
-
packedArguments: [AVNU_EXCHANGE_FOR_LEGACY_USDC.toBigInt()],
|
|
45757
|
-
id: this._approveProofReadableId(usdcToUsdce),
|
|
45758
|
-
sanitizer: AVNU_LEGACY_SANITIZER
|
|
45759
|
-
},
|
|
45760
|
-
{
|
|
45761
|
-
target: AVNU_EXCHANGE_FOR_LEGACY_USDC,
|
|
45762
|
-
method,
|
|
45763
|
-
packedArguments: [],
|
|
45764
|
-
id: this._swapProofReadableId(usdcToUsdce),
|
|
45765
|
-
sanitizer: AVNU_LEGACY_SANITIZER
|
|
45766
|
-
}
|
|
45767
|
-
];
|
|
45768
|
-
}
|
|
45769
|
-
async buildSwapCalls(params, usdcToUsdce) {
|
|
45770
|
-
const approveAmount = import_starknet34.uint256.bnToUint256(params.amount.toWei());
|
|
45771
|
-
const target = usdcToUsdce ? this.config.supportedPositions[0].asset : this.config.supportedPositions[1].asset;
|
|
45772
|
-
const method = usdcToUsdce ? "swap_to_legacy" : "swap_to_new";
|
|
45773
|
-
return [
|
|
45774
|
-
{
|
|
45775
|
-
proofReadableId: this._approveProofReadableId(usdcToUsdce),
|
|
45776
|
-
sanitizer: AVNU_LEGACY_SANITIZER,
|
|
45777
|
-
call: {
|
|
45778
|
-
contractAddress: target.address,
|
|
45779
|
-
selector: import_starknet34.hash.getSelectorFromName("approve"),
|
|
45780
|
-
calldata: [
|
|
45781
|
-
AVNU_EXCHANGE_FOR_LEGACY_USDC.toBigInt(),
|
|
45782
|
-
toBigInt(approveAmount.low.toString()),
|
|
45783
|
-
toBigInt(approveAmount.high.toString())
|
|
45784
|
-
]
|
|
45785
|
-
}
|
|
45786
|
-
},
|
|
45787
|
-
{
|
|
45788
|
-
proofReadableId: this._swapProofReadableId(usdcToUsdce),
|
|
45789
|
-
sanitizer: AVNU_LEGACY_SANITIZER,
|
|
45790
|
-
call: {
|
|
45791
|
-
contractAddress: AVNU_EXCHANGE_FOR_LEGACY_USDC,
|
|
45792
|
-
selector: import_starknet34.hash.getSelectorFromName(method),
|
|
45793
|
-
calldata: [
|
|
45794
|
-
toBigInt(approveAmount.low.toString()),
|
|
45795
|
-
// amount low
|
|
45796
|
-
toBigInt(approveAmount.high.toString())
|
|
45797
|
-
// amount high
|
|
45798
|
-
]
|
|
45799
|
-
}
|
|
45800
|
-
}
|
|
45801
|
-
];
|
|
45802
|
-
}
|
|
45803
|
-
constructor(config) {
|
|
45804
|
-
super(config, _UsdcToUsdceAdapter.name, Protocols.AVNU);
|
|
45805
|
-
this.config = config;
|
|
45806
|
-
assert(this.config.supportedPositions.length === 2, "UsdcToUsdceAdapter must have 2 supported positions");
|
|
45807
|
-
assert(this.config.supportedPositions[0].asset.symbol === "USDC", "UsdcToUsdceAdapter must have USDC as the first supported position");
|
|
45808
|
-
assert(this.config.supportedPositions[1].asset.symbol === "USDC.e", "UsdcToUsdceAdapter must have USDCE as the second supported position");
|
|
45809
|
-
}
|
|
45810
|
-
//abstract means the method has no implementation in this class; instead, child classes must implement it.
|
|
45811
|
-
async getAPY(supportedPosition) {
|
|
45812
|
-
return Promise.resolve({ apy: 0, type: "base" /* BASE */ });
|
|
45813
|
-
}
|
|
45814
|
-
async getPosition(supportedPosition) {
|
|
45815
|
-
const toToken = this.config.supportedPositions[1].asset;
|
|
45816
|
-
if (supportedPosition.asset.symbol != toToken.symbol) {
|
|
45817
|
-
return null;
|
|
45818
|
-
}
|
|
45819
|
-
try {
|
|
45820
|
-
const balance = await new ERC20(this.config.networkConfig).balanceOf(
|
|
45821
|
-
toToken.address,
|
|
45822
|
-
this.config.vaultAllocator.address,
|
|
45823
|
-
toToken.decimals
|
|
45824
|
-
);
|
|
45825
|
-
return { amount: balance, remarks: `USDC.e unused balance (VA)` };
|
|
45826
|
-
} catch (_e) {
|
|
45827
|
-
logger.error(`${_UsdcToUsdceAdapter.name}::getPosition: failed for ${toToken.symbol}`);
|
|
45828
|
-
throw new Error(`${_UsdcToUsdceAdapter.name}: failed to get balance for ${toToken.symbol}`);
|
|
45829
|
-
}
|
|
45830
|
-
}
|
|
45831
|
-
async maxDeposit(amount) {
|
|
45832
|
-
return Promise.resolve({
|
|
45833
|
-
tokenInfo: this.config.baseToken,
|
|
45834
|
-
amount: new Web3Number(0, 0),
|
|
45835
|
-
usdValue: 0,
|
|
45836
|
-
apy: { apy: 0, type: "base" /* BASE */ },
|
|
45837
|
-
protocol: Protocols.AVNU,
|
|
45838
|
-
remarks: ""
|
|
45839
|
-
});
|
|
45840
|
-
}
|
|
45841
|
-
async maxWithdraw() {
|
|
45842
|
-
return Promise.resolve({
|
|
45843
|
-
tokenInfo: this.config.baseToken,
|
|
45844
|
-
amount: new Web3Number(0, 0),
|
|
45845
|
-
usdValue: 0,
|
|
45846
|
-
apy: { apy: 0, type: "base" /* BASE */ },
|
|
45847
|
-
protocol: Protocols.AVNU,
|
|
45848
|
-
remarks: ""
|
|
45849
|
-
});
|
|
45850
|
-
}
|
|
45851
|
-
_getDepositLeaf() {
|
|
45852
|
-
return this.buildSwapLeafConfigs(true);
|
|
45853
|
-
}
|
|
45854
|
-
_getWithdrawLeaf() {
|
|
45855
|
-
return this.buildSwapLeafConfigs(false);
|
|
45856
|
-
}
|
|
45857
|
-
async getDepositCall(params) {
|
|
45858
|
-
const calls = await this.buildSwapCalls(params, true);
|
|
45859
|
-
return calls;
|
|
45860
|
-
}
|
|
45861
|
-
//Swap wbtc to usdc
|
|
45862
|
-
async getWithdrawCall(params) {
|
|
45863
|
-
const calls = await this.buildSwapCalls(params, false);
|
|
45864
|
-
return calls;
|
|
45865
|
-
}
|
|
45866
|
-
async getHealthFactor() {
|
|
45867
|
-
return Promise.resolve(1);
|
|
45868
|
-
}
|
|
45869
|
-
};
|
|
45870
|
-
|
|
45871
47092
|
// src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx
|
|
45872
47093
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
45873
47094
|
var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy extends SVKStrategy {
|
|
@@ -45883,9 +47104,6 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
45883
47104
|
});
|
|
45884
47105
|
this.wbtcToken = Global.getDefaultTokens().find((token) => token.symbol === "WBTC");
|
|
45885
47106
|
this.usdcToken = this.metadata.additionalInfo.borrowable_assets[0];
|
|
45886
|
-
this.usdceToken = Global.getDefaultTokens().find(
|
|
45887
|
-
(token) => token.symbol === "USDC.e"
|
|
45888
|
-
);
|
|
45889
47107
|
this.stateManager = this._initializeStateManager();
|
|
45890
47108
|
}
|
|
45891
47109
|
/**
|
|
@@ -45909,9 +47127,8 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
45909
47127
|
extendedAdapter: extendedAdapterEntry.adapter,
|
|
45910
47128
|
vaultAllocator: this.metadata.additionalInfo.vaultAllocator,
|
|
45911
47129
|
walletAddress: this.metadata.additionalInfo.walletAddress,
|
|
45912
|
-
assetToken:
|
|
45913
|
-
|
|
45914
|
-
usdceToken: this.usdceToken,
|
|
47130
|
+
assetToken: this.asset(),
|
|
47131
|
+
usdcToken: this.usdcToken,
|
|
45915
47132
|
collateralToken: this.wbtcToken,
|
|
45916
47133
|
limitBalanceBufferFactor: LIMIT_BALANCE
|
|
45917
47134
|
};
|
|
@@ -45945,7 +47162,7 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
45945
47162
|
}
|
|
45946
47163
|
return { collateralPrice, debtPrice };
|
|
45947
47164
|
}
|
|
45948
|
-
async
|
|
47165
|
+
async getVesuMultiplyAdapter() {
|
|
45949
47166
|
const vesuAdapter = this.metadata.additionalInfo.adapters.find(
|
|
45950
47167
|
(adapter) => adapter.adapter.name === VesuMultiplyAdapter.name
|
|
45951
47168
|
);
|
|
@@ -45967,16 +47184,16 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
45967
47184
|
}
|
|
45968
47185
|
return vesuModifyPositionAdapter.adapter;
|
|
45969
47186
|
}
|
|
45970
|
-
async
|
|
45971
|
-
const
|
|
47187
|
+
async getUsdcTransferAdapter() {
|
|
47188
|
+
const usdcTransferAdapter = this.metadata.additionalInfo.adapters.find(
|
|
45972
47189
|
(adapter) => adapter.adapter.name === TokenTransferAdapter.name
|
|
45973
47190
|
);
|
|
45974
|
-
if (!
|
|
47191
|
+
if (!usdcTransferAdapter) {
|
|
45975
47192
|
throw new Error(
|
|
45976
|
-
`${this.getTag()}
|
|
47193
|
+
`${this.getTag()} Usdc transfer adapter not configured in metadata.`
|
|
45977
47194
|
);
|
|
45978
47195
|
}
|
|
45979
|
-
return
|
|
47196
|
+
return usdcTransferAdapter.adapter;
|
|
45980
47197
|
}
|
|
45981
47198
|
async getAvnuAdapter() {
|
|
45982
47199
|
const avnuAdapter = this.metadata.additionalInfo.adapters.find(
|
|
@@ -46005,17 +47222,6 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
46005
47222
|
}
|
|
46006
47223
|
return extendedAdapter.adapter;
|
|
46007
47224
|
}
|
|
46008
|
-
async getUsdcToUsdceAdapter() {
|
|
46009
|
-
const usdcToUsdceAdapter = this.metadata.additionalInfo.adapters.find(
|
|
46010
|
-
(adapter) => adapter.adapter.name === UsdcToUsdceAdapter.name
|
|
46011
|
-
);
|
|
46012
|
-
if (!usdcToUsdceAdapter) {
|
|
46013
|
-
throw new Error(
|
|
46014
|
-
`${this.getTag()} UsdcToUsdce adapter not configured in metadata.`
|
|
46015
|
-
);
|
|
46016
|
-
}
|
|
46017
|
-
return usdcToUsdceAdapter.adapter;
|
|
46018
|
-
}
|
|
46019
47225
|
/**
|
|
46020
47226
|
* Creates an ExecutionService wired to this strategy's adapters and config.
|
|
46021
47227
|
* Use with `stateManager.solve()` to get a SolveResult, then pass it to
|
|
@@ -46027,34 +47233,30 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
46027
47233
|
*/
|
|
46028
47234
|
async createExecutionService(opts) {
|
|
46029
47235
|
const [
|
|
46030
|
-
|
|
47236
|
+
vesuMultiplyAdapter,
|
|
46031
47237
|
vesuModifyPositionAdapter,
|
|
46032
|
-
usdceTransferAdapter,
|
|
46033
47238
|
extendedAdapter,
|
|
46034
47239
|
avnuAdapter,
|
|
46035
|
-
|
|
47240
|
+
usdcTransferAdapter
|
|
46036
47241
|
] = await Promise.all([
|
|
46037
|
-
this.
|
|
47242
|
+
this.getVesuMultiplyAdapter(),
|
|
46038
47243
|
this.getVesuModifyPositionAdapter(),
|
|
46039
|
-
this.getUsdceTransferAdapter(),
|
|
46040
47244
|
this.getExtendedAdapter(),
|
|
46041
47245
|
this.getAvnuAdapter(),
|
|
46042
|
-
this.
|
|
47246
|
+
this.getUsdcTransferAdapter()
|
|
46043
47247
|
]);
|
|
46044
47248
|
const executionConfig = {
|
|
46045
47249
|
networkConfig: this.config,
|
|
46046
47250
|
pricer: this.pricer,
|
|
46047
|
-
|
|
47251
|
+
vesuMultiplyAdapter,
|
|
46048
47252
|
vesuModifyPositionAdapter,
|
|
46049
47253
|
extendedAdapter,
|
|
46050
47254
|
avnuAdapter,
|
|
46051
|
-
|
|
47255
|
+
usdcTransferAdapter,
|
|
46052
47256
|
vaultAllocator: this.metadata.additionalInfo.vaultAllocator,
|
|
46053
47257
|
walletAddress: this.metadata.additionalInfo.walletAddress,
|
|
46054
|
-
usdceTransferAdapter,
|
|
46055
47258
|
wbtcToken: this.wbtcToken,
|
|
46056
47259
|
usdcToken: this.usdcToken,
|
|
46057
|
-
usdceToken: this.usdceToken,
|
|
46058
47260
|
getMerkleTree: () => this.getMerkleTree(),
|
|
46059
47261
|
getManageCall: (proofs, manageCalls) => this.getManageCall(proofs, manageCalls),
|
|
46060
47262
|
getBringLiquidityCall: (params) => this.getBringLiquidityCall(params),
|
|
@@ -46075,9 +47277,7 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
46075
47277
|
for (let adapter of this.metadata.additionalInfo.adapters) {
|
|
46076
47278
|
let positions = await adapter.adapter.getPositions();
|
|
46077
47279
|
if (positions && positions.length > 0) {
|
|
46078
|
-
const filteredPositions = positions
|
|
46079
|
-
return position.tokenInfo.address !== this.usdceToken.address;
|
|
46080
|
-
});
|
|
47280
|
+
const filteredPositions = positions;
|
|
46081
47281
|
allPositions.push(...filteredPositions);
|
|
46082
47282
|
}
|
|
46083
47283
|
}
|
|
@@ -46272,34 +47472,22 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
46272
47472
|
};
|
|
46273
47473
|
}
|
|
46274
47474
|
/**
|
|
46275
|
-
* Fetches the operator wallet's current holdings for USDC
|
|
47475
|
+
* Fetches the operator wallet's current holdings for USDC and WBTC,
|
|
46276
47476
|
* returning each token's balance and USD value.
|
|
46277
47477
|
*/
|
|
46278
47478
|
async getWalletHoldings() {
|
|
46279
|
-
if (!this.
|
|
47479
|
+
if (!this.wbtcToken || !this.usdcToken) {
|
|
46280
47480
|
return [];
|
|
46281
47481
|
}
|
|
46282
47482
|
const walletAddress = this.metadata.additionalInfo.walletAddress;
|
|
46283
|
-
const usdceWalletBalance = await new ERC20(this.config).balanceOf(
|
|
46284
|
-
this.usdceToken.address,
|
|
46285
|
-
walletAddress,
|
|
46286
|
-
this.usdceToken.decimals
|
|
46287
|
-
);
|
|
46288
47483
|
const usdcWalletBalance = await new ERC20(this.config).balanceOf(
|
|
46289
47484
|
this.usdcToken.address,
|
|
46290
47485
|
walletAddress,
|
|
46291
47486
|
this.usdcToken.decimals
|
|
46292
47487
|
);
|
|
46293
|
-
const price = await this.pricer.getPrice(this.
|
|
46294
|
-
const wbtcPrice = await this.pricer.getPrice(this.wbtcToken.symbol);
|
|
46295
|
-
const usdceUsdValue = Number(usdceWalletBalance.toFixed(this.usdceToken.decimals)) * price.price;
|
|
47488
|
+
const price = await this.pricer.getPrice(this.usdcToken.symbol);
|
|
46296
47489
|
const usdcUsdValue = Number(usdcWalletBalance.toFixed(this.usdcToken.decimals)) * price.price;
|
|
46297
47490
|
return [
|
|
46298
|
-
{
|
|
46299
|
-
tokenInfo: this.usdceToken,
|
|
46300
|
-
amount: usdceWalletBalance,
|
|
46301
|
-
usdValue: usdceUsdValue
|
|
46302
|
-
},
|
|
46303
47491
|
{
|
|
46304
47492
|
tokenInfo: this.usdcToken,
|
|
46305
47493
|
amount: usdcWalletBalance,
|
|
@@ -46316,9 +47504,6 @@ function getLooperSettings3(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
46316
47504
|
const usdcToken = Global.getDefaultTokens().find(
|
|
46317
47505
|
(token) => token.symbol === underlyingSymbol
|
|
46318
47506
|
);
|
|
46319
|
-
const usdceToken = Global.getDefaultTokens().find(
|
|
46320
|
-
(token) => token.symbol === "USDC.e"
|
|
46321
|
-
);
|
|
46322
47507
|
const baseAdapterConfig = {
|
|
46323
47508
|
baseToken: wbtcToken,
|
|
46324
47509
|
supportedPositions: [
|
|
@@ -46339,17 +47524,10 @@ function getLooperSettings3(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
46339
47524
|
minimumExtendedPriceDifferenceForSwapOpen,
|
|
46340
47525
|
maximumExtendedPriceDifferenceForSwapClosing
|
|
46341
47526
|
});
|
|
46342
|
-
const usdcToUsdceAdapter = new UsdcToUsdceAdapter({
|
|
46343
|
-
...baseAdapterConfig,
|
|
46344
|
-
supportedPositions: [
|
|
46345
|
-
{ asset: usdcToken, isDebt: true },
|
|
46346
|
-
{ asset: usdceToken, isDebt: false }
|
|
46347
|
-
]
|
|
46348
|
-
});
|
|
46349
47527
|
const extendedAdapter = new ExtendedAdapter({
|
|
46350
47528
|
...baseAdapterConfig,
|
|
46351
47529
|
supportedPositions: [
|
|
46352
|
-
{ asset:
|
|
47530
|
+
{ asset: usdcToken, isDebt: false }
|
|
46353
47531
|
],
|
|
46354
47532
|
vaultIdExtended,
|
|
46355
47533
|
extendedContract: EXTENDED_CONTRACT,
|
|
@@ -46395,10 +47573,10 @@ function getLooperSettings3(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
46395
47573
|
{ asset: usdcToken, isDebt: true }
|
|
46396
47574
|
]
|
|
46397
47575
|
});
|
|
46398
|
-
const
|
|
47576
|
+
const usdcTransferAdapter = new TokenTransferAdapter({
|
|
46399
47577
|
...baseAdapterConfig,
|
|
46400
|
-
baseToken:
|
|
46401
|
-
supportedPositions: [{ asset:
|
|
47578
|
+
baseToken: usdcToken,
|
|
47579
|
+
supportedPositions: [{ asset: usdcToken, isDebt: false }],
|
|
46402
47580
|
fromAddress: vaultSettings.vaultAllocator,
|
|
46403
47581
|
toAddress: ContractAddr.from(vaultSettings.walletAddress)
|
|
46404
47582
|
});
|
|
@@ -46411,12 +47589,8 @@ function getLooperSettings3(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
46411
47589
|
adapter: vesuModifyPositionAdapter
|
|
46412
47590
|
});
|
|
46413
47591
|
vaultSettings.adapters.push({
|
|
46414
|
-
id: `${
|
|
46415
|
-
adapter:
|
|
46416
|
-
});
|
|
46417
|
-
vaultSettings.adapters.push({
|
|
46418
|
-
id: `${usdcToUsdceAdapter.name}_${usdceToken.symbol}_${usdcToken.symbol}`,
|
|
46419
|
-
adapter: usdcToUsdceAdapter
|
|
47592
|
+
id: `${usdcTransferAdapter.name}_${usdcToken.symbol}`,
|
|
47593
|
+
adapter: usdcTransferAdapter
|
|
46420
47594
|
});
|
|
46421
47595
|
vaultSettings.adapters.push({
|
|
46422
47596
|
id: `${extendedAdapter.name}_${wbtcToken.symbol}`,
|
|
@@ -46438,12 +47612,10 @@ function getLooperSettings3(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
46438
47612
|
vaultSettings.leafAdapters.push(() => vesuModifyPositionAdapter.getDepositLeaf());
|
|
46439
47613
|
vaultSettings.leafAdapters.push(() => vesuModifyPositionAdapter.getWithdrawLeaf());
|
|
46440
47614
|
vaultSettings.leafAdapters.push(() => extendedAdapter.getDepositLeaf());
|
|
46441
|
-
vaultSettings.leafAdapters.push(() => usdcToUsdceAdapter.getDepositLeaf());
|
|
46442
|
-
vaultSettings.leafAdapters.push(() => usdcToUsdceAdapter.getWithdrawLeaf());
|
|
46443
47615
|
vaultSettings.leafAdapters.push(() => avnuAdapter.getDepositLeaf());
|
|
46444
47616
|
vaultSettings.leafAdapters.push(() => avnuAdapter.getWithdrawLeaf());
|
|
46445
|
-
vaultSettings.leafAdapters.push(() =>
|
|
46446
|
-
vaultSettings.leafAdapters.push(() =>
|
|
47617
|
+
vaultSettings.leafAdapters.push(() => usdcTransferAdapter.getDepositLeaf());
|
|
47618
|
+
vaultSettings.leafAdapters.push(() => usdcTransferAdapter.getWithdrawLeaf());
|
|
46447
47619
|
vaultSettings.leafAdapters.push(
|
|
46448
47620
|
commonAdapter.getApproveAdapter(
|
|
46449
47621
|
usdcToken.address,
|
|
@@ -47476,11 +48648,13 @@ var deployer_default = Deployer;
|
|
|
47476
48648
|
BaseAdapter,
|
|
47477
48649
|
BaseStrategy,
|
|
47478
48650
|
CASE_ROUTE_TYPES,
|
|
48651
|
+
COLLATERAL_PRECISION,
|
|
47479
48652
|
CaseCategory,
|
|
47480
48653
|
CaseId,
|
|
47481
48654
|
CommonAdapter,
|
|
47482
48655
|
ContractAddr,
|
|
47483
48656
|
CycleType,
|
|
48657
|
+
DEFAULT_TROVES_STRATEGIES_API,
|
|
47484
48658
|
Deployer,
|
|
47485
48659
|
ERC20,
|
|
47486
48660
|
EXTENDED_CONTRACT,
|
|
@@ -47499,6 +48673,7 @@ var deployer_default = Deployer;
|
|
|
47499
48673
|
FatalError,
|
|
47500
48674
|
FlowChartColors,
|
|
47501
48675
|
Global,
|
|
48676
|
+
HealthFactorMath,
|
|
47502
48677
|
HyperLSTStrategies,
|
|
47503
48678
|
ILending,
|
|
47504
48679
|
Initializable,
|
|
@@ -47539,6 +48714,7 @@ var deployer_default = Deployer;
|
|
|
47539
48714
|
StrategyLiveStatus,
|
|
47540
48715
|
StrategyTag,
|
|
47541
48716
|
StrategyType,
|
|
48717
|
+
SvkTrovesAdapter,
|
|
47542
48718
|
TRANSFER_SANITIZER,
|
|
47543
48719
|
TelegramGroupNotif,
|
|
47544
48720
|
TelegramNotif,
|
|
@@ -47588,6 +48764,7 @@ var deployer_default = Deployer;
|
|
|
47588
48764
|
createEkuboCLStrategy,
|
|
47589
48765
|
createHyperLSTStrategy,
|
|
47590
48766
|
createSenseiStrategy,
|
|
48767
|
+
createSolveBudgetFromRawState,
|
|
47591
48768
|
createStrategy,
|
|
47592
48769
|
createUniversalStrategy,
|
|
47593
48770
|
createVesuRebalanceStrategy,
|