@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.browser.mjs
CHANGED
|
@@ -91,6 +91,9 @@ var Web3Number = class _Web3Number2 extends _Web3Number {
|
|
|
91
91
|
const bn = new _Web3Number2(weiNumber, decimals).dividedBy(10 ** decimals);
|
|
92
92
|
return new _Web3Number2(bn.toString(), decimals);
|
|
93
93
|
}
|
|
94
|
+
static fromNumber(number, decimals) {
|
|
95
|
+
return new _Web3Number2(number.toString(), decimals);
|
|
96
|
+
}
|
|
94
97
|
};
|
|
95
98
|
|
|
96
99
|
// src/dataTypes/address.ts
|
|
@@ -1485,6 +1488,48 @@ _StarknetCallParser.METHOD_BY_SELECTOR = new Map(
|
|
|
1485
1488
|
);
|
|
1486
1489
|
var StarknetCallParser = _StarknetCallParser;
|
|
1487
1490
|
|
|
1491
|
+
// src/utils/health-factor-math.ts
|
|
1492
|
+
var HealthFactorMath = class {
|
|
1493
|
+
static getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
1494
|
+
const numerator = debtAmount.multipliedBy(debtPrice).multipliedBy(targetHF);
|
|
1495
|
+
const denominator = collateralPrice * maxLTV;
|
|
1496
|
+
const collateralAmount = numerator.dividedBy(denominator);
|
|
1497
|
+
const netCollateral = new Web3Number(collateralAmount.toString(), collateralTokenInfo.decimals);
|
|
1498
|
+
return netCollateral;
|
|
1499
|
+
}
|
|
1500
|
+
static getMinCollateralRequiredOnLooping(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
1501
|
+
const netCollateral = this.getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo);
|
|
1502
|
+
const collateralFromDebt = new Web3Number(debtAmount.multipliedBy(debtPrice).dividedBy(collateralPrice).toString(), collateralTokenInfo.decimals);
|
|
1503
|
+
return netCollateral.minus(collateralFromDebt);
|
|
1504
|
+
}
|
|
1505
|
+
static getHealthFactor(collateralAmount, collateralPrice, maxLTV, debtAmount, debtPrice) {
|
|
1506
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
1507
|
+
const denominator = debtAmount.multipliedBy(debtPrice);
|
|
1508
|
+
const healthFactor = numerator.dividedBy(denominator);
|
|
1509
|
+
return healthFactor.toNumber();
|
|
1510
|
+
}
|
|
1511
|
+
static getMaxDebtAmountOnLooping(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
1512
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
1513
|
+
logger.verbose(`HealthFactorMath: Max debt amount on looping numerator: ${numerator.toNumber()}, collateralAmount: ${collateralAmount.toNumber()}, collateralPrice: ${collateralPrice}, maxLTV: ${maxLTV}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
|
|
1514
|
+
const denominator = targetHF - maxLTV;
|
|
1515
|
+
logger.verbose(`HealthFactorMath: Max debt amount on looping denominator: ${denominator}`);
|
|
1516
|
+
const debtAmountUSD = numerator.dividedBy(denominator);
|
|
1517
|
+
logger.verbose(`HealthFactorMath: Max debt amount on looping debtAmountUSD: ${debtAmountUSD.toNumber()}`);
|
|
1518
|
+
const debtAmount = debtAmountUSD.dividedBy(debtPrice);
|
|
1519
|
+
logger.verbose(`HealthFactorMath: Max debt amount on looping debtAmount: ${debtAmount.toNumber()}`);
|
|
1520
|
+
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
1521
|
+
}
|
|
1522
|
+
static getMaxDebtAmount(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
1523
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
1524
|
+
logger.verbose(`HealthFactorMath: Max debt amount numerator: ${numerator.toNumber()}, collateralAmount: ${collateralAmount.toNumber()}, collateralPrice: ${collateralPrice}, maxLTV: ${maxLTV}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
|
|
1525
|
+
const denominator = targetHF * debtPrice;
|
|
1526
|
+
logger.verbose(`HealthFactorMath: Max debt amount denominator: ${denominator}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
|
|
1527
|
+
const debtAmount = numerator.dividedBy(denominator);
|
|
1528
|
+
logger.verbose(`HealthFactorMath: Max debt amount: ${debtAmount.toNumber()}, numerator: ${numerator.toNumber()}, denominator: ${denominator}`);
|
|
1529
|
+
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
1530
|
+
}
|
|
1531
|
+
};
|
|
1532
|
+
|
|
1488
1533
|
// src/utils/index.ts
|
|
1489
1534
|
function assert(condition, message) {
|
|
1490
1535
|
if (!condition) {
|
|
@@ -6477,6 +6522,10 @@ var VaultProtocol = {
|
|
|
6477
6522
|
name: "Vault",
|
|
6478
6523
|
logo: ""
|
|
6479
6524
|
};
|
|
6525
|
+
var TrovesProtocol = {
|
|
6526
|
+
name: "Troves",
|
|
6527
|
+
logo: "https://app.troves.fi/favicon.ico"
|
|
6528
|
+
};
|
|
6480
6529
|
var Protocols = {
|
|
6481
6530
|
NONE: NoneProtocol,
|
|
6482
6531
|
VESU: VesuProtocol,
|
|
@@ -6484,7 +6533,8 @@ var Protocols = {
|
|
|
6484
6533
|
EXTENDED: ExtendedProtocol,
|
|
6485
6534
|
EKUBO: EkuboProtocol,
|
|
6486
6535
|
AVNU: AvnuProtocol,
|
|
6487
|
-
VAULT: VaultProtocol
|
|
6536
|
+
VAULT: VaultProtocol,
|
|
6537
|
+
TROVES: TrovesProtocol
|
|
6488
6538
|
};
|
|
6489
6539
|
|
|
6490
6540
|
// src/interfaces/initializable.ts
|
|
@@ -34219,48 +34269,6 @@ var AbisConfig = {
|
|
|
34219
34269
|
}
|
|
34220
34270
|
};
|
|
34221
34271
|
|
|
34222
|
-
// src/utils/health-factor-math.ts
|
|
34223
|
-
var HealthFactorMath = class {
|
|
34224
|
-
static getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
34225
|
-
const numerator = debtAmount.multipliedBy(debtPrice).multipliedBy(targetHF);
|
|
34226
|
-
const denominator = collateralPrice * maxLTV;
|
|
34227
|
-
const collateralAmount = numerator.dividedBy(denominator);
|
|
34228
|
-
const netCollateral = new Web3Number(collateralAmount.toString(), collateralTokenInfo.decimals);
|
|
34229
|
-
return netCollateral;
|
|
34230
|
-
}
|
|
34231
|
-
static getMinCollateralRequiredOnLooping(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
34232
|
-
const netCollateral = this.getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo);
|
|
34233
|
-
const collateralFromDebt = new Web3Number(debtAmount.multipliedBy(debtPrice).dividedBy(collateralPrice).toString(), collateralTokenInfo.decimals);
|
|
34234
|
-
return netCollateral.minus(collateralFromDebt);
|
|
34235
|
-
}
|
|
34236
|
-
static getHealthFactor(collateralAmount, collateralPrice, maxLTV, debtAmount, debtPrice) {
|
|
34237
|
-
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
34238
|
-
const denominator = debtAmount.multipliedBy(debtPrice);
|
|
34239
|
-
const healthFactor = numerator.dividedBy(denominator);
|
|
34240
|
-
return healthFactor.toNumber();
|
|
34241
|
-
}
|
|
34242
|
-
static getMaxDebtAmountOnLooping(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
34243
|
-
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
34244
|
-
logger.verbose(`HealthFactorMath: Max debt amount on looping numerator: ${numerator.toNumber()}, collateralAmount: ${collateralAmount.toNumber()}, collateralPrice: ${collateralPrice}, maxLTV: ${maxLTV}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
|
|
34245
|
-
const denominator = targetHF - maxLTV;
|
|
34246
|
-
logger.verbose(`HealthFactorMath: Max debt amount on looping denominator: ${denominator}`);
|
|
34247
|
-
const debtAmountUSD = numerator.dividedBy(denominator);
|
|
34248
|
-
logger.verbose(`HealthFactorMath: Max debt amount on looping debtAmountUSD: ${debtAmountUSD.toNumber()}`);
|
|
34249
|
-
const debtAmount = debtAmountUSD.dividedBy(debtPrice);
|
|
34250
|
-
logger.verbose(`HealthFactorMath: Max debt amount on looping debtAmount: ${debtAmount.toNumber()}`);
|
|
34251
|
-
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
34252
|
-
}
|
|
34253
|
-
static getMaxDebtAmount(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
34254
|
-
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
34255
|
-
logger.verbose(`HealthFactorMath: Max debt amount numerator: ${numerator.toNumber()}, collateralAmount: ${collateralAmount.toNumber()}, collateralPrice: ${collateralPrice}, maxLTV: ${maxLTV}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
|
|
34256
|
-
const denominator = targetHF * debtPrice;
|
|
34257
|
-
logger.verbose(`HealthFactorMath: Max debt amount denominator: ${denominator}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
|
|
34258
|
-
const debtAmount = numerator.dividedBy(denominator);
|
|
34259
|
-
logger.verbose(`HealthFactorMath: Max debt amount: ${debtAmount.toNumber()}, numerator: ${numerator.toNumber()}, denominator: ${denominator}`);
|
|
34260
|
-
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
34261
|
-
}
|
|
34262
|
-
};
|
|
34263
|
-
|
|
34264
34272
|
// src/strategies/vesu-extended-strategy/utils/helper.ts
|
|
34265
34273
|
var returnFormattedAmount = (amount, toTokenDecimals) => {
|
|
34266
34274
|
const formattedAmount = "0x" + BigInt(Math.floor(amount * 10 ** toTokenDecimals)).toString(16);
|
|
@@ -34903,6 +34911,7 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34903
34911
|
const collateralToken = this.config.collateral;
|
|
34904
34912
|
const debtToken = this.config.debt;
|
|
34905
34913
|
const { contract: multiplyContract } = this._getMultiplyContract();
|
|
34914
|
+
this.lastSwapPriceInfo = null;
|
|
34906
34915
|
const {
|
|
34907
34916
|
existingCollateralInfo,
|
|
34908
34917
|
existingDebtInfo,
|
|
@@ -34939,9 +34948,15 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34939
34948
|
let marginSwapLimitAmount = Web3Number.fromWei(0, collateralToken.decimals);
|
|
34940
34949
|
let addedCollateral = params.amount;
|
|
34941
34950
|
let approveAmount = params.amount;
|
|
34951
|
+
let aggregatedFromAmount = 0;
|
|
34952
|
+
let aggregatedToAmount = 0;
|
|
34953
|
+
let aggregatedFromSymbol = debtToken.symbol;
|
|
34954
|
+
const aggregatedToSymbol = collateralToken.symbol;
|
|
34955
|
+
let executedSwapCount = 0;
|
|
34942
34956
|
if (params.marginSwap) {
|
|
34943
34957
|
const marginToken = params.marginSwap.marginToken;
|
|
34944
34958
|
const requiredAmount = params.amount;
|
|
34959
|
+
assert(marginToken.address.eq(debtToken.address), "Margin token must be the same as debt token");
|
|
34945
34960
|
const marginSwapQuote = await ekuboQuoter.getQuoteExactOutput(
|
|
34946
34961
|
marginToken.address.address,
|
|
34947
34962
|
collateralToken.address.address,
|
|
@@ -34957,6 +34972,11 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34957
34972
|
marginToken,
|
|
34958
34973
|
collateralToken
|
|
34959
34974
|
);
|
|
34975
|
+
const marginSwapInputAmount = Web3Number.fromWei(marginSwapQuote.total_calculated, marginToken.decimals).abs().toNumber();
|
|
34976
|
+
const marginSwapOutputAmount = requiredAmount.abs().toNumber();
|
|
34977
|
+
aggregatedFromAmount += marginSwapInputAmount;
|
|
34978
|
+
aggregatedToAmount += marginSwapOutputAmount;
|
|
34979
|
+
executedSwapCount += 1;
|
|
34960
34980
|
approveAmount = Web3Number.fromWei(marginSwapQuote.total_calculated, marginToken.decimals).multipliedBy(1 + this.maxSlippage).abs();
|
|
34961
34981
|
}
|
|
34962
34982
|
let debtAmount = this._computeTargetDebtDelta(
|
|
@@ -34980,10 +35000,6 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34980
35000
|
if (!debtAmount.isZero() && debtAmount.greaterThan(0)) {
|
|
34981
35001
|
try {
|
|
34982
35002
|
let swapQuote;
|
|
34983
|
-
const debtAmountInCollateralUnits = new Web3Number(
|
|
34984
|
-
debtAmount.multipliedBy(debtPrice).dividedBy(collateralPrice).toFixed(6),
|
|
34985
|
-
collateralToken.decimals
|
|
34986
|
-
);
|
|
34987
35003
|
if (params.leverSwap?.exactOutput) {
|
|
34988
35004
|
swapQuote = await ekuboQuoter.getQuoteExactOutput(
|
|
34989
35005
|
debtToken.address.address,
|
|
@@ -35007,17 +35023,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
35007
35023
|
).abs().toNumber();
|
|
35008
35024
|
const inputAmt = debtAmount.abs().toNumber();
|
|
35009
35025
|
const outputAmt = quoteOutputAmount;
|
|
35010
|
-
|
|
35011
|
-
|
|
35012
|
-
|
|
35013
|
-
toTokenSymbol: collateralToken.symbol,
|
|
35014
|
-
fromAmount: inputAmt,
|
|
35015
|
-
toAmount: outputAmt,
|
|
35016
|
-
effectivePrice: outputAmt !== 0 ? inputAmt / outputAmt : 0
|
|
35017
|
-
};
|
|
35018
|
-
logger.verbose(
|
|
35019
|
-
`${_VesuMultiplyAdapter.name}::_getIncreaseCalldata stored price info: ${inputAmt} ${debtToken.symbol} \u2192 ${outputAmt} ${collateralToken.symbol}, effectivePrice=${this.lastSwapPriceInfo.effectivePrice}`
|
|
35020
|
-
);
|
|
35026
|
+
aggregatedFromAmount += inputAmt;
|
|
35027
|
+
aggregatedToAmount += outputAmt;
|
|
35028
|
+
executedSwapCount += 1;
|
|
35021
35029
|
leverSwap = ekuboQuoter.getVesuMultiplyQuote(
|
|
35022
35030
|
swapQuote,
|
|
35023
35031
|
debtToken,
|
|
@@ -35035,6 +35043,19 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
35035
35043
|
);
|
|
35036
35044
|
}
|
|
35037
35045
|
}
|
|
35046
|
+
if (executedSwapCount > 0) {
|
|
35047
|
+
this.lastSwapPriceInfo = {
|
|
35048
|
+
source: "ekubo",
|
|
35049
|
+
fromTokenSymbol: aggregatedFromSymbol ?? debtToken.symbol,
|
|
35050
|
+
toTokenSymbol: aggregatedToSymbol,
|
|
35051
|
+
fromAmount: aggregatedFromAmount,
|
|
35052
|
+
toAmount: aggregatedToAmount,
|
|
35053
|
+
effectivePrice: aggregatedToAmount !== 0 ? aggregatedFromAmount / aggregatedToAmount : 0
|
|
35054
|
+
};
|
|
35055
|
+
logger.verbose(
|
|
35056
|
+
`${_VesuMultiplyAdapter.name}::_getIncreaseCalldata stored aggregated price info: ${aggregatedFromAmount} ${this.lastSwapPriceInfo.fromTokenSymbol} \u2192 ${aggregatedToAmount} ${aggregatedToSymbol}, effectivePrice=${this.lastSwapPriceInfo.effectivePrice}, swaps=${executedSwapCount}`
|
|
35057
|
+
);
|
|
35058
|
+
}
|
|
35038
35059
|
logger.verbose(
|
|
35039
35060
|
`${_VesuMultiplyAdapter.name}::_getIncreaseCalldata leverSwapLimitAmount: ${leverSwapLimitAmount.toWei()}`
|
|
35040
35061
|
);
|
|
@@ -35067,10 +35088,21 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
35067
35088
|
approveAmount
|
|
35068
35089
|
};
|
|
35069
35090
|
}
|
|
35091
|
+
// private _setLastSwapPriceAsNoSwap(): void {
|
|
35092
|
+
// this.lastSwapPriceInfo = {
|
|
35093
|
+
// source: "no-swap",
|
|
35094
|
+
// fromTokenSymbol: this.config.collateral.symbol,
|
|
35095
|
+
// toTokenSymbol: this.config.debt.symbol,
|
|
35096
|
+
// fromAmount: 0,
|
|
35097
|
+
// toAmount: 0,
|
|
35098
|
+
// effectivePrice: 0,
|
|
35099
|
+
// };
|
|
35100
|
+
// }
|
|
35070
35101
|
async _buildDecreaseLikeCalldata(params) {
|
|
35071
35102
|
const collateralToken = this.config.collateral;
|
|
35072
35103
|
const debtToken = this.config.debt;
|
|
35073
35104
|
const { contract: multiplyContract } = this._getMultiplyContract();
|
|
35105
|
+
this.lastSwapPriceInfo = null;
|
|
35074
35106
|
const ekuboQuoter = new EkuboQuoter(
|
|
35075
35107
|
this.config.networkConfig,
|
|
35076
35108
|
this.config.pricer
|
|
@@ -35079,6 +35111,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
35079
35111
|
let leverSwapWeights = [];
|
|
35080
35112
|
let leverSwapLimitAmount = Web3Number.fromWei(0, collateralToken.decimals);
|
|
35081
35113
|
let leverCollateralUsed = Web3Number.fromWei(0, collateralToken.decimals);
|
|
35114
|
+
let aggregatedFromAmount = 0;
|
|
35115
|
+
let aggregatedToAmount = 0;
|
|
35116
|
+
let executedSwapCount = 0;
|
|
35082
35117
|
if (params.closePosition) {
|
|
35083
35118
|
const debtQuote = await ekuboQuoter.getQuoteExactOutput(
|
|
35084
35119
|
collateralToken.address.address,
|
|
@@ -35097,6 +35132,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
35097
35132
|
collateralToken.decimals
|
|
35098
35133
|
).abs();
|
|
35099
35134
|
leverSwapLimitAmount = leverCollateralUsed.multipliedBy(1 + this.maxSlippage);
|
|
35135
|
+
aggregatedFromAmount += leverCollateralUsed.toNumber();
|
|
35136
|
+
aggregatedToAmount += params.debtToRepayAbs.abs().toNumber();
|
|
35137
|
+
executedSwapCount += 1;
|
|
35100
35138
|
} else {
|
|
35101
35139
|
if (params.collateralPrice === void 0 || params.debtPrice === void 0) {
|
|
35102
35140
|
throw new Error(
|
|
@@ -35118,17 +35156,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
35118
35156
|
leverSwapQuote.total_calculated,
|
|
35119
35157
|
debtToken.decimals
|
|
35120
35158
|
).abs().toNumber();
|
|
35121
|
-
|
|
35122
|
-
|
|
35123
|
-
|
|
35124
|
-
toTokenSymbol: debtToken.symbol,
|
|
35125
|
-
fromAmount: inputAmt,
|
|
35126
|
-
toAmount: outputAmt,
|
|
35127
|
-
effectivePrice: outputAmt !== 0 ? outputAmt / inputAmt : 0
|
|
35128
|
-
};
|
|
35129
|
-
logger.verbose(
|
|
35130
|
-
`${_VesuMultiplyAdapter.name}::_buildDecreaseLikeCalldata stored price info: ${inputAmt} ${collateralToken.symbol} \u2192 ${outputAmt} ${debtToken.symbol}, effectivePrice=${this.lastSwapPriceInfo.effectivePrice}`
|
|
35131
|
-
);
|
|
35159
|
+
aggregatedFromAmount += inputAmt;
|
|
35160
|
+
aggregatedToAmount += outputAmt;
|
|
35161
|
+
executedSwapCount += 1;
|
|
35132
35162
|
leverSwap = ekuboQuoter.getVesuMultiplyQuote(
|
|
35133
35163
|
leverSwapQuote,
|
|
35134
35164
|
collateralToken,
|
|
@@ -35151,6 +35181,7 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
35151
35181
|
);
|
|
35152
35182
|
const withdrawSwapWeights = [];
|
|
35153
35183
|
if (params.outputToken && !params.outputToken.address.eq(collateralToken.address)) {
|
|
35184
|
+
assert(params.outputToken.address.eq(debtToken.address), "Withdraw output token must be the same as debt token");
|
|
35154
35185
|
const residualCollateral = params.closePosition ? params.existingCollateral.minus(leverCollateralUsed) : params.subMargin;
|
|
35155
35186
|
const outputTokenPrice = await this.config.pricer.getPrice(params.outputToken.symbol);
|
|
35156
35187
|
if (residualCollateral.greaterThan(0)) {
|
|
@@ -35167,12 +35198,34 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
35167
35198
|
);
|
|
35168
35199
|
withdrawSwap = built.swaps;
|
|
35169
35200
|
withdrawSwapWeights.push(...built.weights);
|
|
35201
|
+
const withdrawOutputAmount = Web3Number.fromWei(
|
|
35202
|
+
withdrawQuote.total_calculated,
|
|
35203
|
+
params.outputToken.decimals
|
|
35204
|
+
).abs().toNumber();
|
|
35205
|
+
aggregatedFromAmount += residualCollateral.toNumber();
|
|
35206
|
+
aggregatedToAmount += withdrawOutputAmount;
|
|
35207
|
+
executedSwapCount += 1;
|
|
35170
35208
|
const estimatedOutput = residualCollateral.multipliedBy(params.collateralPrice).dividedBy(outputTokenPrice.price);
|
|
35171
35209
|
estimatedOutput.decimals = params.outputToken.decimals;
|
|
35172
35210
|
withdrawSwapLimitAmount = estimatedOutput.multipliedBy(1 - this.maxSlippage);
|
|
35173
35211
|
}
|
|
35174
35212
|
}
|
|
35175
35213
|
}
|
|
35214
|
+
if (executedSwapCount > 0) {
|
|
35215
|
+
this.lastSwapPriceInfo = {
|
|
35216
|
+
source: "ekubo",
|
|
35217
|
+
fromTokenSymbol: collateralToken.symbol,
|
|
35218
|
+
toTokenSymbol: debtToken.symbol,
|
|
35219
|
+
fromAmount: aggregatedFromAmount,
|
|
35220
|
+
toAmount: aggregatedToAmount,
|
|
35221
|
+
effectivePrice: aggregatedFromAmount !== 0 ? aggregatedToAmount / aggregatedFromAmount : 0
|
|
35222
|
+
};
|
|
35223
|
+
logger.verbose(
|
|
35224
|
+
`${_VesuMultiplyAdapter.name}::_buildDecreaseLikeCalldata stored aggregated price info: ${aggregatedFromAmount} ${collateralToken.symbol} \u2192 ${aggregatedToAmount} ${debtToken.symbol}, effectivePrice=${this.lastSwapPriceInfo.effectivePrice}, swaps=${executedSwapCount}`
|
|
35225
|
+
);
|
|
35226
|
+
} else {
|
|
35227
|
+
this.lastSwapPriceInfo = null;
|
|
35228
|
+
}
|
|
35176
35229
|
logger.debug(
|
|
35177
35230
|
`${_VesuMultiplyAdapter.name}::_buildDecreaseLikeCalldata leverSwapCount=${leverSwap.length}, withdrawSwapCount=${withdrawSwap.length}, withdrawSwapLimitAmount=${withdrawSwapLimitAmount.toNumber()}, subMargin=${params.subMargin.toNumber()}`
|
|
35178
35231
|
);
|
|
@@ -35981,13 +36034,13 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
35981
36034
|
this.minimumExtendedMovementAmount = this.config.minimumExtendedMovementAmount ?? 5;
|
|
35982
36035
|
this.client = client;
|
|
35983
36036
|
this.retryDelayForOrderStatus = this.config.retryDelayForOrderStatus ?? 3e3;
|
|
35984
|
-
this.
|
|
36037
|
+
this.usdcToken = this.config.supportedPositions[0].asset;
|
|
35985
36038
|
}
|
|
35986
36039
|
_depositApproveProofReadableId() {
|
|
35987
|
-
return `extended_approve_${this.
|
|
36040
|
+
return `extended_approve_${this.usdcToken.symbol}`;
|
|
35988
36041
|
}
|
|
35989
36042
|
_depositCallProofReadableId() {
|
|
35990
|
-
return `extended_deposit_${this.
|
|
36043
|
+
return `extended_deposit_${this.usdcToken.symbol}`;
|
|
35991
36044
|
}
|
|
35992
36045
|
//abstract means the method has no implementation in this class; instead, child classes must implement it.
|
|
35993
36046
|
async getAPY(supportedPosition) {
|
|
@@ -36056,7 +36109,7 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
36056
36109
|
_getDepositLeaf() {
|
|
36057
36110
|
return [
|
|
36058
36111
|
{
|
|
36059
|
-
target: this.
|
|
36112
|
+
target: this.usdcToken.address,
|
|
36060
36113
|
method: "approve",
|
|
36061
36114
|
packedArguments: [this.config.extendedContract.toBigInt()],
|
|
36062
36115
|
id: this._depositApproveProofReadableId(),
|
|
@@ -36076,14 +36129,14 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
36076
36129
|
}
|
|
36077
36130
|
async getDepositCall(params) {
|
|
36078
36131
|
try {
|
|
36079
|
-
const salt = Math.floor(Math.random() * 10 ** this.
|
|
36132
|
+
const salt = Math.floor(Math.random() * 10 ** this.usdcToken.decimals);
|
|
36080
36133
|
const amount = uint25616.bnToUint256(params.amount.toWei());
|
|
36081
36134
|
return [
|
|
36082
36135
|
{
|
|
36083
36136
|
proofReadableId: this._depositApproveProofReadableId(),
|
|
36084
36137
|
sanitizer: SIMPLE_SANITIZER,
|
|
36085
36138
|
call: {
|
|
36086
|
-
contractAddress: this.
|
|
36139
|
+
contractAddress: this.usdcToken.address,
|
|
36087
36140
|
selector: hash8.getSelectorFromName("approve"),
|
|
36088
36141
|
calldata: [
|
|
36089
36142
|
this.config.extendedContract.toBigInt(),
|
|
@@ -36984,8 +37037,8 @@ var AvnuAdapter = class _AvnuAdapter extends BaseAdapter {
|
|
|
36984
37037
|
}
|
|
36985
37038
|
};
|
|
36986
37039
|
|
|
36987
|
-
// src/strategies/universal-
|
|
36988
|
-
import {
|
|
37040
|
+
// src/strategies/universal-adapters/svk-troves-adapter.ts
|
|
37041
|
+
import { hash as hash11, uint256 as uint25619, Contract as Contract14 } from "starknet";
|
|
36989
37042
|
|
|
36990
37043
|
// src/data/universal-vault.abi.json
|
|
36991
37044
|
var universal_vault_abi_default = [
|
|
@@ -38669,6 +38722,272 @@ var universal_vault_abi_default = [
|
|
|
38669
38722
|
}
|
|
38670
38723
|
];
|
|
38671
38724
|
|
|
38725
|
+
// src/strategies/universal-adapters/svk-troves-adapter.ts
|
|
38726
|
+
var DEFAULT_TROVES_STRATEGIES_API = "https://app.troves.fi/api/strategies";
|
|
38727
|
+
function parseTrovesApyField(raw) {
|
|
38728
|
+
if (typeof raw === "number" && Number.isFinite(raw)) {
|
|
38729
|
+
return raw;
|
|
38730
|
+
}
|
|
38731
|
+
if (typeof raw === "string") {
|
|
38732
|
+
const n = Number.parseFloat(raw);
|
|
38733
|
+
if (Number.isFinite(n)) {
|
|
38734
|
+
return n;
|
|
38735
|
+
}
|
|
38736
|
+
}
|
|
38737
|
+
return 0;
|
|
38738
|
+
}
|
|
38739
|
+
var SvkTrovesAdapter = class _SvkTrovesAdapter extends BaseAdapter {
|
|
38740
|
+
constructor(config) {
|
|
38741
|
+
super(config, _SvkTrovesAdapter.name, Protocols.TROVES);
|
|
38742
|
+
this.config = config;
|
|
38743
|
+
}
|
|
38744
|
+
/** Owner used for share balance + `due_assets_from_owner`. */
|
|
38745
|
+
_positionOwner() {
|
|
38746
|
+
return this.config.positionOwner ?? this.config.vaultAllocator;
|
|
38747
|
+
}
|
|
38748
|
+
/**
|
|
38749
|
+
* Proof readable IDs must stay ≤ 31 chars (Cairo short string). We derive a short ASCII suffix from
|
|
38750
|
+
* `strategyVault` address so multiple SVK adapters in one tree stay distinct.
|
|
38751
|
+
*/
|
|
38752
|
+
_proofSuffix() {
|
|
38753
|
+
return this.config.strategyVault.address.replace(/^0x/, "").slice(-6);
|
|
38754
|
+
}
|
|
38755
|
+
_depositApproveProofReadableId() {
|
|
38756
|
+
return `appr_dep_svk_${this._proofSuffix()}`;
|
|
38757
|
+
}
|
|
38758
|
+
_depositCallProofReadableId() {
|
|
38759
|
+
return `dep_svk_${this._proofSuffix()}`;
|
|
38760
|
+
}
|
|
38761
|
+
_withdrawCallProofReadableId() {
|
|
38762
|
+
return `wtdrw_svk_${this._proofSuffix()}`;
|
|
38763
|
+
}
|
|
38764
|
+
async getAPY(supportedPosition) {
|
|
38765
|
+
const CACHE_KEY = `svk_apy_${this.config.trovesStrategyId}`;
|
|
38766
|
+
const cached = this.getCache(CACHE_KEY);
|
|
38767
|
+
if (cached) {
|
|
38768
|
+
return cached;
|
|
38769
|
+
}
|
|
38770
|
+
const url = this.config.trovesStrategiesApiUrl ?? DEFAULT_TROVES_STRATEGIES_API;
|
|
38771
|
+
try {
|
|
38772
|
+
const res = await fetch(url);
|
|
38773
|
+
if (!res.ok) {
|
|
38774
|
+
logger.warn(`${_SvkTrovesAdapter.name}::getAPY: HTTP ${res.status} from ${url}`);
|
|
38775
|
+
const fallback = { apy: 0, type: "base" /* BASE */ };
|
|
38776
|
+
this.setCache(CACHE_KEY, fallback, 3e5);
|
|
38777
|
+
return fallback;
|
|
38778
|
+
}
|
|
38779
|
+
const body = await res.json();
|
|
38780
|
+
const row = body.strategies?.find((s) => s.id === this.config.trovesStrategyId);
|
|
38781
|
+
if (!row) {
|
|
38782
|
+
logger.warn(
|
|
38783
|
+
`${_SvkTrovesAdapter.name}::getAPY: strategy id not found: ${this.config.trovesStrategyId}`
|
|
38784
|
+
);
|
|
38785
|
+
const fallback = { apy: 0, type: "base" /* BASE */ };
|
|
38786
|
+
this.setCache(CACHE_KEY, fallback, 3e5);
|
|
38787
|
+
return fallback;
|
|
38788
|
+
}
|
|
38789
|
+
const apy = parseTrovesApyField(row.apy);
|
|
38790
|
+
const result = { apy, type: "base" /* BASE */ };
|
|
38791
|
+
this.setCache(CACHE_KEY, result, 3e5);
|
|
38792
|
+
return result;
|
|
38793
|
+
} catch (error) {
|
|
38794
|
+
logger.error(`${_SvkTrovesAdapter.name}::getAPY:`, error);
|
|
38795
|
+
throw error;
|
|
38796
|
+
}
|
|
38797
|
+
}
|
|
38798
|
+
async getPosition(supportedPosition) {
|
|
38799
|
+
const CACHE_KEY = `svk_pos_${this.config.strategyVault.address}_${this._positionOwner().address}`;
|
|
38800
|
+
const cached = this.getCache(CACHE_KEY);
|
|
38801
|
+
if (cached) {
|
|
38802
|
+
return cached;
|
|
38803
|
+
}
|
|
38804
|
+
try {
|
|
38805
|
+
const vault = new Contract14({
|
|
38806
|
+
abi: universal_vault_abi_default,
|
|
38807
|
+
address: this.config.strategyVault.address,
|
|
38808
|
+
providerOrAccount: this.config.networkConfig.provider
|
|
38809
|
+
});
|
|
38810
|
+
const owner = this._positionOwner();
|
|
38811
|
+
const decimals = supportedPosition.asset.decimals;
|
|
38812
|
+
const shares = await vault.balance_of(owner.address);
|
|
38813
|
+
const shareU256 = uint25619.bnToUint256(shares);
|
|
38814
|
+
const liquidAssetsRaw = await vault.convert_to_assets(shareU256);
|
|
38815
|
+
const liquid = Web3Number.fromWei(liquidAssetsRaw.toString(), decimals);
|
|
38816
|
+
let pending = Web3Number.fromWei("0", decimals);
|
|
38817
|
+
try {
|
|
38818
|
+
const dueRaw = await vault.call("due_assets_from_owner", [owner.address]);
|
|
38819
|
+
pending = Web3Number.fromWei(dueRaw.toString(), decimals);
|
|
38820
|
+
} catch (e) {
|
|
38821
|
+
logger.warn(
|
|
38822
|
+
`${_SvkTrovesAdapter.name}::getPosition: due_assets_from_owner failed (treating as 0): ${e.message}`
|
|
38823
|
+
);
|
|
38824
|
+
}
|
|
38825
|
+
const total = liquid.plus(pending);
|
|
38826
|
+
const remarks = `Troves ${this.config.trovesStrategyId} holdings`;
|
|
38827
|
+
const result = {
|
|
38828
|
+
amount: total,
|
|
38829
|
+
remarks
|
|
38830
|
+
};
|
|
38831
|
+
this.setCache(CACHE_KEY, result, 6e4);
|
|
38832
|
+
return result;
|
|
38833
|
+
} catch (error) {
|
|
38834
|
+
logger.error(`${_SvkTrovesAdapter.name}::getPosition:`, error);
|
|
38835
|
+
throw error;
|
|
38836
|
+
}
|
|
38837
|
+
}
|
|
38838
|
+
async maxDeposit(amount) {
|
|
38839
|
+
const baseToken = this.config.baseToken;
|
|
38840
|
+
if (!amount) {
|
|
38841
|
+
return {
|
|
38842
|
+
tokenInfo: baseToken,
|
|
38843
|
+
amount: new Web3Number("999999999999999999999999999", baseToken.decimals),
|
|
38844
|
+
usdValue: 1e27,
|
|
38845
|
+
remarks: "Max deposit (unbounded placeholder)",
|
|
38846
|
+
apy: await this.getAPY({ asset: baseToken, isDebt: false }),
|
|
38847
|
+
protocol: this.protocol
|
|
38848
|
+
};
|
|
38849
|
+
}
|
|
38850
|
+
const usdValue = await this.getUSDValue(baseToken, amount);
|
|
38851
|
+
return {
|
|
38852
|
+
tokenInfo: baseToken,
|
|
38853
|
+
amount,
|
|
38854
|
+
usdValue,
|
|
38855
|
+
remarks: "Deposit amount",
|
|
38856
|
+
apy: await this.getAPY({ asset: baseToken, isDebt: false }),
|
|
38857
|
+
protocol: this.protocol
|
|
38858
|
+
};
|
|
38859
|
+
}
|
|
38860
|
+
async maxWithdraw() {
|
|
38861
|
+
const baseToken = this.config.baseToken;
|
|
38862
|
+
const current = await this.getPosition({ asset: baseToken, isDebt: false });
|
|
38863
|
+
const pos = current ?? { amount: new Web3Number("0", baseToken.decimals), remarks: "" };
|
|
38864
|
+
const usdValue = await this.getUSDValue(baseToken, pos.amount);
|
|
38865
|
+
return {
|
|
38866
|
+
tokenInfo: baseToken,
|
|
38867
|
+
amount: pos.amount,
|
|
38868
|
+
usdValue,
|
|
38869
|
+
remarks: "Max withdraw (liquid + pending redemption, underlying units)",
|
|
38870
|
+
apy: await this.getAPY({ asset: baseToken, isDebt: false }),
|
|
38871
|
+
protocol: this.protocol
|
|
38872
|
+
};
|
|
38873
|
+
}
|
|
38874
|
+
_getDepositLeaf() {
|
|
38875
|
+
const baseToken = this.config.baseToken;
|
|
38876
|
+
const strategyVault = this.config.strategyVault;
|
|
38877
|
+
const receiver = this.config.vaultAllocator;
|
|
38878
|
+
return [
|
|
38879
|
+
{
|
|
38880
|
+
target: baseToken.address,
|
|
38881
|
+
method: "approve",
|
|
38882
|
+
packedArguments: [strategyVault.toBigInt()],
|
|
38883
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
38884
|
+
id: this._depositApproveProofReadableId()
|
|
38885
|
+
},
|
|
38886
|
+
{
|
|
38887
|
+
target: strategyVault,
|
|
38888
|
+
method: "deposit",
|
|
38889
|
+
packedArguments: [receiver.toBigInt()],
|
|
38890
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
38891
|
+
id: this._depositCallProofReadableId()
|
|
38892
|
+
}
|
|
38893
|
+
];
|
|
38894
|
+
}
|
|
38895
|
+
_getWithdrawLeaf() {
|
|
38896
|
+
const strategyVault = this.config.strategyVault;
|
|
38897
|
+
const recv = this.config.vaultAllocator;
|
|
38898
|
+
const owner = this.config.vaultAllocator;
|
|
38899
|
+
return [
|
|
38900
|
+
{
|
|
38901
|
+
target: strategyVault,
|
|
38902
|
+
method: "withdraw",
|
|
38903
|
+
packedArguments: [recv.toBigInt(), owner.toBigInt()],
|
|
38904
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
38905
|
+
id: this._withdrawCallProofReadableId()
|
|
38906
|
+
}
|
|
38907
|
+
];
|
|
38908
|
+
}
|
|
38909
|
+
getDepositAdapter() {
|
|
38910
|
+
const leafConfigs = this._getDepositLeaf();
|
|
38911
|
+
const leaves = leafConfigs.map((config) => {
|
|
38912
|
+
const { target, method, packedArguments, sanitizer, id } = config;
|
|
38913
|
+
return this.constructSimpleLeafData({ id, target, method, packedArguments }, sanitizer);
|
|
38914
|
+
});
|
|
38915
|
+
return { leaves, callConstructor: this.getDepositCall.bind(this) };
|
|
38916
|
+
}
|
|
38917
|
+
getWithdrawAdapter() {
|
|
38918
|
+
const leafConfigs = this._getWithdrawLeaf();
|
|
38919
|
+
const leaves = leafConfigs.map((config) => {
|
|
38920
|
+
const { target, method, packedArguments, sanitizer, id } = config;
|
|
38921
|
+
return this.constructSimpleLeafData({ id, target, method, packedArguments }, sanitizer);
|
|
38922
|
+
});
|
|
38923
|
+
return { leaves, callConstructor: this.getWithdrawCall.bind(this) };
|
|
38924
|
+
}
|
|
38925
|
+
async getDepositCall(params) {
|
|
38926
|
+
const baseToken = this.config.baseToken;
|
|
38927
|
+
const strategyVault = this.config.strategyVault;
|
|
38928
|
+
const amount = params.amount;
|
|
38929
|
+
const uint256Amount = uint25619.bnToUint256(amount.toWei());
|
|
38930
|
+
const receiver = this.config.vaultAllocator;
|
|
38931
|
+
return [
|
|
38932
|
+
{
|
|
38933
|
+
proofReadableId: this._depositApproveProofReadableId(),
|
|
38934
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
38935
|
+
call: {
|
|
38936
|
+
contractAddress: baseToken.address,
|
|
38937
|
+
selector: hash11.getSelectorFromName("approve"),
|
|
38938
|
+
calldata: [
|
|
38939
|
+
strategyVault.toBigInt(),
|
|
38940
|
+
toBigInt(uint256Amount.low.toString()),
|
|
38941
|
+
toBigInt(uint256Amount.high.toString())
|
|
38942
|
+
]
|
|
38943
|
+
}
|
|
38944
|
+
},
|
|
38945
|
+
{
|
|
38946
|
+
proofReadableId: this._depositCallProofReadableId(),
|
|
38947
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
38948
|
+
call: {
|
|
38949
|
+
contractAddress: strategyVault,
|
|
38950
|
+
selector: hash11.getSelectorFromName("deposit"),
|
|
38951
|
+
calldata: [
|
|
38952
|
+
toBigInt(uint256Amount.low.toString()),
|
|
38953
|
+
toBigInt(uint256Amount.high.toString()),
|
|
38954
|
+
receiver.toBigInt()
|
|
38955
|
+
]
|
|
38956
|
+
}
|
|
38957
|
+
}
|
|
38958
|
+
];
|
|
38959
|
+
}
|
|
38960
|
+
async getWithdrawCall(params) {
|
|
38961
|
+
const strategyVault = this.config.strategyVault;
|
|
38962
|
+
const amount = params.amount;
|
|
38963
|
+
const uint256Amount = uint25619.bnToUint256(amount.toWei());
|
|
38964
|
+
const recv = this.config.vaultAllocator;
|
|
38965
|
+
const owner = this.config.vaultAllocator;
|
|
38966
|
+
return [
|
|
38967
|
+
{
|
|
38968
|
+
proofReadableId: this._withdrawCallProofReadableId(),
|
|
38969
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
38970
|
+
call: {
|
|
38971
|
+
contractAddress: strategyVault,
|
|
38972
|
+
selector: hash11.getSelectorFromName("withdraw"),
|
|
38973
|
+
calldata: [
|
|
38974
|
+
toBigInt(uint256Amount.low.toString()),
|
|
38975
|
+
toBigInt(uint256Amount.high.toString()),
|
|
38976
|
+
recv.toBigInt(),
|
|
38977
|
+
owner.toBigInt()
|
|
38978
|
+
]
|
|
38979
|
+
}
|
|
38980
|
+
}
|
|
38981
|
+
];
|
|
38982
|
+
}
|
|
38983
|
+
getHealthFactor() {
|
|
38984
|
+
return Promise.resolve(10);
|
|
38985
|
+
}
|
|
38986
|
+
};
|
|
38987
|
+
|
|
38988
|
+
// src/strategies/universal-strategy.tsx
|
|
38989
|
+
import { CallData, Contract as Contract15, num as num12, uint256 as uint25620 } from "starknet";
|
|
38990
|
+
|
|
38672
38991
|
// src/data/vault-manager.abi.json
|
|
38673
38992
|
var vault_manager_abi_default = [
|
|
38674
38993
|
{
|
|
@@ -39334,12 +39653,12 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
39334
39653
|
);
|
|
39335
39654
|
this.metadata = metadata;
|
|
39336
39655
|
this.address = metadata.address;
|
|
39337
|
-
this.contract = new
|
|
39656
|
+
this.contract = new Contract15({
|
|
39338
39657
|
abi: universal_vault_abi_default,
|
|
39339
39658
|
address: this.address.address,
|
|
39340
39659
|
providerOrAccount: this.config.provider
|
|
39341
39660
|
});
|
|
39342
|
-
this.managerContract = new
|
|
39661
|
+
this.managerContract = new Contract15({
|
|
39343
39662
|
abi: vault_manager_abi_default,
|
|
39344
39663
|
address: this.metadata.additionalInfo.manager.address,
|
|
39345
39664
|
providerOrAccount: this.config.provider
|
|
@@ -39393,17 +39712,17 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
39393
39712
|
amountInfo.tokenInfo.address.eq(this.asset().address),
|
|
39394
39713
|
"Deposit token mismatch"
|
|
39395
39714
|
);
|
|
39396
|
-
const assetContract = new
|
|
39715
|
+
const assetContract = new Contract15({
|
|
39397
39716
|
abi: universal_vault_abi_default,
|
|
39398
39717
|
address: this.asset().address.address,
|
|
39399
39718
|
providerOrAccount: this.config.provider
|
|
39400
39719
|
});
|
|
39401
39720
|
const call1 = assetContract.populate("approve", [
|
|
39402
39721
|
this.address.address,
|
|
39403
|
-
|
|
39722
|
+
uint25620.bnToUint256(amountInfo.amount.toWei())
|
|
39404
39723
|
]);
|
|
39405
39724
|
const call2 = this.contract.populate("deposit", [
|
|
39406
|
-
|
|
39725
|
+
uint25620.bnToUint256(amountInfo.amount.toWei()),
|
|
39407
39726
|
receiver.address
|
|
39408
39727
|
]);
|
|
39409
39728
|
return [call1, call2];
|
|
@@ -39413,9 +39732,9 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
39413
39732
|
amountInfo.tokenInfo.address.eq(this.asset().address),
|
|
39414
39733
|
"Withdraw token mismatch"
|
|
39415
39734
|
);
|
|
39416
|
-
const shares = await this.contract.call("convert_to_shares", [
|
|
39735
|
+
const shares = await this.contract.call("convert_to_shares", [uint25620.bnToUint256(amountInfo.amount.toWei())]);
|
|
39417
39736
|
const call = this.contract.populate("request_redeem", [
|
|
39418
|
-
|
|
39737
|
+
uint25620.bnToUint256(shares.toString()),
|
|
39419
39738
|
receiver.address,
|
|
39420
39739
|
owner.address
|
|
39421
39740
|
]);
|
|
@@ -39425,7 +39744,7 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
39425
39744
|
const shares = await this.contract.call("balanceOf", [user.address], { blockIdentifier });
|
|
39426
39745
|
const assets = await this.contract.call(
|
|
39427
39746
|
"convert_to_assets",
|
|
39428
|
-
[
|
|
39747
|
+
[uint25620.bnToUint256(shares)],
|
|
39429
39748
|
{ blockIdentifier }
|
|
39430
39749
|
);
|
|
39431
39750
|
const amount = Web3Number.fromWei(
|
|
@@ -40359,19 +40678,19 @@ var UniversalStrategies = [
|
|
|
40359
40678
|
];
|
|
40360
40679
|
|
|
40361
40680
|
// src/strategies/svk-strategy.ts
|
|
40362
|
-
import { Contract as
|
|
40681
|
+
import { Contract as Contract16, num as num13, uint256 as uint25621 } from "starknet";
|
|
40363
40682
|
var SVKStrategy = class extends BaseStrategy {
|
|
40364
40683
|
constructor(config, pricer, metadata) {
|
|
40365
40684
|
super(config);
|
|
40366
40685
|
this.pricer = pricer;
|
|
40367
40686
|
this.metadata = metadata;
|
|
40368
40687
|
this.address = metadata.address;
|
|
40369
|
-
this.contract = new
|
|
40688
|
+
this.contract = new Contract16({
|
|
40370
40689
|
abi: universal_vault_abi_default,
|
|
40371
40690
|
address: this.address.address,
|
|
40372
40691
|
providerOrAccount: this.config.provider
|
|
40373
40692
|
});
|
|
40374
|
-
this.managerContract = new
|
|
40693
|
+
this.managerContract = new Contract16({
|
|
40375
40694
|
abi: vault_manager_abi_default,
|
|
40376
40695
|
address: this.metadata.additionalInfo.manager.address,
|
|
40377
40696
|
providerOrAccount: this.config.provider
|
|
@@ -40388,17 +40707,17 @@ var SVKStrategy = class extends BaseStrategy {
|
|
|
40388
40707
|
amountInfo.tokenInfo.address.eq(this.asset().address),
|
|
40389
40708
|
"Deposit token mismatch"
|
|
40390
40709
|
);
|
|
40391
|
-
const assetContract = new
|
|
40710
|
+
const assetContract = new Contract16({
|
|
40392
40711
|
abi: universal_vault_abi_default,
|
|
40393
40712
|
address: this.asset().address.address,
|
|
40394
40713
|
providerOrAccount: this.config.provider
|
|
40395
40714
|
});
|
|
40396
40715
|
const call1 = assetContract.populate("approve", [
|
|
40397
40716
|
this.address.address,
|
|
40398
|
-
|
|
40717
|
+
uint25621.bnToUint256(amountInfo.amount.toWei())
|
|
40399
40718
|
]);
|
|
40400
40719
|
const call2 = this.contract.populate("deposit", [
|
|
40401
|
-
|
|
40720
|
+
uint25621.bnToUint256(amountInfo.amount.toWei()),
|
|
40402
40721
|
receiver.address
|
|
40403
40722
|
]);
|
|
40404
40723
|
return [call1, call2];
|
|
@@ -40408,9 +40727,9 @@ var SVKStrategy = class extends BaseStrategy {
|
|
|
40408
40727
|
amountInfo.tokenInfo.address.eq(this.asset().address),
|
|
40409
40728
|
"Withdraw token mismatch"
|
|
40410
40729
|
);
|
|
40411
|
-
const shares = await this.contract.call("convert_to_shares", [
|
|
40730
|
+
const shares = await this.contract.call("convert_to_shares", [uint25621.bnToUint256(amountInfo.amount.toWei())]);
|
|
40412
40731
|
const call = this.contract.populate("request_redeem", [
|
|
40413
|
-
|
|
40732
|
+
uint25621.bnToUint256(shares.toString()),
|
|
40414
40733
|
receiver.address,
|
|
40415
40734
|
owner.address
|
|
40416
40735
|
]);
|
|
@@ -40601,7 +40920,7 @@ var SVKStrategy = class extends BaseStrategy {
|
|
|
40601
40920
|
};
|
|
40602
40921
|
|
|
40603
40922
|
// src/strategies/universal-lst-muliplier-strategy.tsx
|
|
40604
|
-
import { Contract as
|
|
40923
|
+
import { Contract as Contract17, uint256 as uint25622 } from "starknet";
|
|
40605
40924
|
|
|
40606
40925
|
// src/strategies/universal-adapters/adapter-optimizer.ts
|
|
40607
40926
|
var AdapterOptimizer = class {
|
|
@@ -40754,15 +41073,15 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
40754
41073
|
async getLSTExchangeRate() {
|
|
40755
41074
|
const vesuAdapter1 = this.getVesuSameTokenAdapter();
|
|
40756
41075
|
const lstTokenInfo = vesuAdapter1._vesuAdapter.config.collateral;
|
|
40757
|
-
const lstABI = new
|
|
41076
|
+
const lstABI = new Contract17({
|
|
40758
41077
|
abi: erc4626_abi_default,
|
|
40759
41078
|
address: lstTokenInfo.address.address,
|
|
40760
41079
|
providerOrAccount: this.config.provider
|
|
40761
41080
|
});
|
|
40762
41081
|
const price = await lstABI.call("convert_to_assets", [
|
|
40763
|
-
|
|
41082
|
+
uint25622.bnToUint256(new Web3Number(1, lstTokenInfo.decimals).toWei())
|
|
40764
41083
|
]);
|
|
40765
|
-
const exchangeRate = Number(
|
|
41084
|
+
const exchangeRate = Number(uint25622.uint256ToBN(price).toString()) / Math.pow(10, lstTokenInfo.decimals);
|
|
40766
41085
|
logger.verbose(`${this.getTag()}:: LST Exchange Rate: ${exchangeRate}`);
|
|
40767
41086
|
return exchangeRate;
|
|
40768
41087
|
}
|
|
@@ -41632,6 +41951,249 @@ var HyperLSTStrategies = [
|
|
|
41632
41951
|
getStrategySettings("mRe7YIELD", "mRe7YIELD", hypermRe7YIELD, false, false)
|
|
41633
41952
|
];
|
|
41634
41953
|
|
|
41954
|
+
// src/strategies/vesu-extended-strategy/services/ltv-imbalance-rebalance-math.ts
|
|
41955
|
+
function ceilBtc(v, precision) {
|
|
41956
|
+
const f = 10 ** precision;
|
|
41957
|
+
return Math.ceil(v * f) / f;
|
|
41958
|
+
}
|
|
41959
|
+
function floorBtc(v, precision) {
|
|
41960
|
+
const f = 10 ** precision;
|
|
41961
|
+
return Math.floor(v * f) / f;
|
|
41962
|
+
}
|
|
41963
|
+
function isNegligible(btc, precision) {
|
|
41964
|
+
return Math.abs(btc) < 10 ** -precision;
|
|
41965
|
+
}
|
|
41966
|
+
function computeExtIdealMargin(posBtc, leverage, price) {
|
|
41967
|
+
return posBtc * price / leverage;
|
|
41968
|
+
}
|
|
41969
|
+
function computeExtDeficit(ext, price) {
|
|
41970
|
+
return Math.max(0, computeExtIdealMargin(ext.positionBtc, ext.leverage, price) - ext.equity);
|
|
41971
|
+
}
|
|
41972
|
+
function computeVesuHF(vesu, price) {
|
|
41973
|
+
const collateralUsd = vesu.positionBtc * price;
|
|
41974
|
+
if (collateralUsd === 0) return Infinity;
|
|
41975
|
+
const ltv = vesu.debt * vesu.debtPrice / collateralUsd;
|
|
41976
|
+
if (ltv === 0) return Infinity;
|
|
41977
|
+
return vesu.maxLTV / ltv;
|
|
41978
|
+
}
|
|
41979
|
+
function computeVesuDebtRepay(vesu, price) {
|
|
41980
|
+
const targetLTV = vesu.maxLTV / vesu.targetHF;
|
|
41981
|
+
const collateralUsd = vesu.positionBtc * price;
|
|
41982
|
+
const requiredDebt = targetLTV * collateralUsd / vesu.debtPrice;
|
|
41983
|
+
return Math.max(0, vesu.debt - requiredDebt);
|
|
41984
|
+
}
|
|
41985
|
+
function computeVesuTargetLTV(vesu) {
|
|
41986
|
+
return vesu.maxLTV / vesu.targetHF;
|
|
41987
|
+
}
|
|
41988
|
+
function computeVesuGrowthCost(gapBtc, vesu, price) {
|
|
41989
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
41990
|
+
return gapBtc * price * (1 - targetLTV);
|
|
41991
|
+
}
|
|
41992
|
+
function computeVesuGrowthDebt(gapBtc, vesu, price) {
|
|
41993
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
41994
|
+
return gapBtc * price * targetLTV / vesu.debtPrice;
|
|
41995
|
+
}
|
|
41996
|
+
function computeVesuGrowthFromEquity(equityUsd, vesu, price) {
|
|
41997
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
41998
|
+
return equityUsd / (price * (1 - targetLTV));
|
|
41999
|
+
}
|
|
42000
|
+
function emptyDeltas() {
|
|
42001
|
+
return {
|
|
42002
|
+
dExtPosition: 0,
|
|
42003
|
+
dVesuPosition: 0,
|
|
42004
|
+
dVesuDebt: 0,
|
|
42005
|
+
dExtAvlWithdraw: 0,
|
|
42006
|
+
dExtUpnl: 0,
|
|
42007
|
+
dVaUsd: 0,
|
|
42008
|
+
dWalletUsd: 0,
|
|
42009
|
+
dVesuBorrowCapacity: 0,
|
|
42010
|
+
dTransferVesuToExt: 0
|
|
42011
|
+
};
|
|
42012
|
+
}
|
|
42013
|
+
function mergeDeltas(a, b) {
|
|
42014
|
+
return {
|
|
42015
|
+
dExtPosition: a.dExtPosition + b.dExtPosition,
|
|
42016
|
+
dVesuPosition: a.dVesuPosition + b.dVesuPosition,
|
|
42017
|
+
dVesuDebt: a.dVesuDebt + b.dVesuDebt,
|
|
42018
|
+
dExtAvlWithdraw: a.dExtAvlWithdraw + b.dExtAvlWithdraw,
|
|
42019
|
+
dExtUpnl: a.dExtUpnl + b.dExtUpnl,
|
|
42020
|
+
dVaUsd: a.dVaUsd + b.dVaUsd,
|
|
42021
|
+
dWalletUsd: a.dWalletUsd + b.dWalletUsd,
|
|
42022
|
+
dVesuBorrowCapacity: a.dVesuBorrowCapacity + b.dVesuBorrowCapacity,
|
|
42023
|
+
dTransferVesuToExt: a.dTransferVesuToExt + b.dTransferVesuToExt
|
|
42024
|
+
};
|
|
42025
|
+
}
|
|
42026
|
+
function drawFunds(need, keys, pool) {
|
|
42027
|
+
const draws = {};
|
|
42028
|
+
let unmet = need;
|
|
42029
|
+
for (const k of keys) {
|
|
42030
|
+
if (unmet <= 0) break;
|
|
42031
|
+
const avail = pool[k];
|
|
42032
|
+
if (avail <= 0) continue;
|
|
42033
|
+
const take = Math.min(avail, unmet);
|
|
42034
|
+
draws[k] = take;
|
|
42035
|
+
pool[k] -= take;
|
|
42036
|
+
unmet -= take;
|
|
42037
|
+
}
|
|
42038
|
+
return { draws, filled: need - unmet, unmet };
|
|
42039
|
+
}
|
|
42040
|
+
function sumKeys(draws, keys) {
|
|
42041
|
+
return keys.reduce((s, k) => s + (draws[k] ?? 0), 0);
|
|
42042
|
+
}
|
|
42043
|
+
function applyDrawsToDeltas(d, draws, sign) {
|
|
42044
|
+
d.dVaUsd += sign * (draws.vaUsd ?? 0);
|
|
42045
|
+
d.dWalletUsd += sign * (draws.walletUsd ?? 0);
|
|
42046
|
+
d.dVesuBorrowCapacity += sign * (draws.vesuBorrowCapacity ?? 0);
|
|
42047
|
+
d.dExtAvlWithdraw += sign * (draws.extAvlWithdraw ?? 0);
|
|
42048
|
+
d.dExtUpnl += sign * (draws.extUpnl ?? 0);
|
|
42049
|
+
}
|
|
42050
|
+
function fixExtMargin(ext, price, pool) {
|
|
42051
|
+
const d = emptyDeltas();
|
|
42052
|
+
const deficit = computeExtDeficit(ext, price);
|
|
42053
|
+
if (deficit <= 0) return { d, unmet: 0 };
|
|
42054
|
+
const { draws, filled, unmet } = drawFunds(deficit, ["walletUsd", "vaUsd", "vesuBorrowCapacity"], pool);
|
|
42055
|
+
applyDrawsToDeltas(d, draws, -1);
|
|
42056
|
+
d.dExtAvlWithdraw += filled;
|
|
42057
|
+
const fromVesu = draws.vesuBorrowCapacity ?? 0;
|
|
42058
|
+
if (fromVesu > 0) d.dTransferVesuToExt += fromVesu;
|
|
42059
|
+
return { d, unmet };
|
|
42060
|
+
}
|
|
42061
|
+
function fixVesuMargin(vesu, price, pool, hfBuffer) {
|
|
42062
|
+
const d = emptyDeltas();
|
|
42063
|
+
const hf = computeVesuHF(vesu, price);
|
|
42064
|
+
if (hf >= vesu.targetHF - hfBuffer) return { d, unmet: 0 };
|
|
42065
|
+
const repayTokens = computeVesuDebtRepay(vesu, price);
|
|
42066
|
+
const repayUsd = repayTokens * vesu.debtPrice;
|
|
42067
|
+
const { draws, filled, unmet } = drawFunds(repayUsd, ["vaUsd", "walletUsd", "extAvlWithdraw", "extUpnl"], pool);
|
|
42068
|
+
applyDrawsToDeltas(d, draws, -1);
|
|
42069
|
+
d.dVesuDebt -= filled / vesu.debtPrice;
|
|
42070
|
+
const fromExt = sumKeys(draws, ["extAvlWithdraw", "extUpnl"]);
|
|
42071
|
+
if (fromExt > 0) d.dTransferVesuToExt -= fromExt;
|
|
42072
|
+
return { d, unmet };
|
|
42073
|
+
}
|
|
42074
|
+
function phase1(ext, vesu, price, pool, config) {
|
|
42075
|
+
const extResult = fixExtMargin(ext, price, pool);
|
|
42076
|
+
const vesuResult = fixVesuMargin(vesu, price, pool, config.hfBuffer);
|
|
42077
|
+
return {
|
|
42078
|
+
deltas: mergeDeltas(extResult.d, vesuResult.d),
|
|
42079
|
+
extDeficitRemaining: extResult.unmet,
|
|
42080
|
+
vesuRepayRemaining: vesuResult.unmet
|
|
42081
|
+
};
|
|
42082
|
+
}
|
|
42083
|
+
function solveUnifiedF(extPos, vesuPos, extEquity, vesuDebt, vesu, extLev, price) {
|
|
42084
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
42085
|
+
const k = 1 - targetLTV + 1 / extLev;
|
|
42086
|
+
const totalEquity = extEquity + vesuPos * price - vesuDebt * vesu.debtPrice;
|
|
42087
|
+
return totalEquity / (price * k);
|
|
42088
|
+
}
|
|
42089
|
+
function solveTransfer(vesuPos, vesuDebt, F, vesu, price) {
|
|
42090
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
42091
|
+
return vesuPos * price - vesuDebt * vesu.debtPrice - F * price * (1 - targetLTV);
|
|
42092
|
+
}
|
|
42093
|
+
function solveDebtRepay(vesuDebt, F, vesu, price) {
|
|
42094
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
42095
|
+
return vesuDebt - targetLTV * F * price / vesu.debtPrice;
|
|
42096
|
+
}
|
|
42097
|
+
function roundFinalPosition(extPos, vesuPos, rawF, precision) {
|
|
42098
|
+
let fFromExt;
|
|
42099
|
+
if (rawF < extPos) {
|
|
42100
|
+
const closeExt = ceilBtc(extPos - rawF, precision);
|
|
42101
|
+
fFromExt = extPos - closeExt;
|
|
42102
|
+
} else {
|
|
42103
|
+
const growExt = floorBtc(rawF - extPos, precision);
|
|
42104
|
+
fFromExt = extPos + growExt;
|
|
42105
|
+
}
|
|
42106
|
+
let fFromVesu;
|
|
42107
|
+
if (rawF < vesuPos) {
|
|
42108
|
+
const closeVesu = ceilBtc(vesuPos - rawF, precision);
|
|
42109
|
+
fFromVesu = vesuPos - closeVesu;
|
|
42110
|
+
} else {
|
|
42111
|
+
const growVesu = floorBtc(rawF - vesuPos, precision);
|
|
42112
|
+
fFromVesu = vesuPos + growVesu;
|
|
42113
|
+
}
|
|
42114
|
+
return Math.max(0, Math.min(fFromExt, fFromVesu));
|
|
42115
|
+
}
|
|
42116
|
+
function phase2(extPos, vesuPos, extEquity, vesuDebt, vesu, extLev, price, pool, precision) {
|
|
42117
|
+
const d = emptyDeltas();
|
|
42118
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
42119
|
+
const imbalance = extPos - vesuPos;
|
|
42120
|
+
let fundedGrowthBtc = 0;
|
|
42121
|
+
if (!isNegligible(imbalance, precision)) {
|
|
42122
|
+
if (imbalance > 0) {
|
|
42123
|
+
const equityCostUsd = computeVesuGrowthCost(imbalance, vesu, price);
|
|
42124
|
+
const { draws, filled } = drawFunds(equityCostUsd, ["vaUsd", "walletUsd", "extAvlWithdraw", "extUpnl"], pool);
|
|
42125
|
+
applyDrawsToDeltas(d, draws, -1);
|
|
42126
|
+
const grownBtc = computeVesuGrowthFromEquity(filled, vesu, price);
|
|
42127
|
+
d.dVesuPosition += grownBtc;
|
|
42128
|
+
fundedGrowthBtc = grownBtc;
|
|
42129
|
+
d.dVesuDebt += computeVesuGrowthDebt(grownBtc, vesu, price);
|
|
42130
|
+
const fromExt = sumKeys(draws, ["extAvlWithdraw", "extUpnl"]);
|
|
42131
|
+
if (fromExt > 0) d.dTransferVesuToExt -= fromExt;
|
|
42132
|
+
} else {
|
|
42133
|
+
const absImbalance = -imbalance;
|
|
42134
|
+
const marginCostUsd = absImbalance * price / extLev;
|
|
42135
|
+
const { draws, filled } = drawFunds(marginCostUsd, ["walletUsd", "vaUsd", "vesuBorrowCapacity"], pool);
|
|
42136
|
+
applyDrawsToDeltas(d, draws, -1);
|
|
42137
|
+
const grownBtc = filled * extLev / price;
|
|
42138
|
+
d.dExtPosition += grownBtc;
|
|
42139
|
+
fundedGrowthBtc = grownBtc;
|
|
42140
|
+
const fromVesu = draws.vesuBorrowCapacity ?? 0;
|
|
42141
|
+
if (fromVesu > 0) d.dTransferVesuToExt += fromVesu;
|
|
42142
|
+
}
|
|
42143
|
+
}
|
|
42144
|
+
const effExtPos = extPos + d.dExtPosition;
|
|
42145
|
+
const effVesuPos = vesuPos + d.dVesuPosition;
|
|
42146
|
+
const effExtEquity = extEquity;
|
|
42147
|
+
const effVesuDebt = vesuDebt + d.dVesuDebt;
|
|
42148
|
+
const rawF = solveUnifiedF(effExtPos, effVesuPos, effExtEquity, effVesuDebt, vesu, extLev, price);
|
|
42149
|
+
const cappedF = Math.min(rawF, Math.max(effExtPos, effVesuPos));
|
|
42150
|
+
const maxGrowableTo = Math.max(effExtPos, effVesuPos);
|
|
42151
|
+
const targetF = Math.max(0, Math.min(cappedF, maxGrowableTo));
|
|
42152
|
+
const remainingImbalance = effExtPos - effVesuPos;
|
|
42153
|
+
const extNeedsMore = effExtEquity < computeExtIdealMargin(effExtPos, extLev, price);
|
|
42154
|
+
const vesuCurrentLTV = effVesuPos > 0 ? effVesuDebt * vesu.debtPrice / (effVesuPos * price) : 0;
|
|
42155
|
+
const vesuNeedsMore = vesuCurrentLTV > targetLTV;
|
|
42156
|
+
const needsFurtherAction = !isNegligible(remainingImbalance, precision) || extNeedsMore || vesuNeedsMore;
|
|
42157
|
+
if (!needsFurtherAction) {
|
|
42158
|
+
return d;
|
|
42159
|
+
}
|
|
42160
|
+
const F = roundFinalPosition(effExtPos, effVesuPos, targetF, precision);
|
|
42161
|
+
const dx = F - effExtPos;
|
|
42162
|
+
const dy = F - effVesuPos;
|
|
42163
|
+
if (isNegligible(dx, precision) && isNegligible(dy, precision)) {
|
|
42164
|
+
return d;
|
|
42165
|
+
}
|
|
42166
|
+
d.dExtPosition += dx;
|
|
42167
|
+
d.dVesuPosition += dy;
|
|
42168
|
+
const debtRepay = solveDebtRepay(effVesuDebt, F, vesu, price);
|
|
42169
|
+
d.dVesuDebt -= debtRepay;
|
|
42170
|
+
const T = solveTransfer(effVesuPos, effVesuDebt, F, vesu, price);
|
|
42171
|
+
d.dTransferVesuToExt += T;
|
|
42172
|
+
d.dExtAvlWithdraw += T;
|
|
42173
|
+
return d;
|
|
42174
|
+
}
|
|
42175
|
+
function rebalance(inputs) {
|
|
42176
|
+
const { ext, vesu, btcPrice, config } = inputs;
|
|
42177
|
+
const pool = { ...inputs.funding };
|
|
42178
|
+
const p1 = phase1(ext, vesu, btcPrice, pool, config);
|
|
42179
|
+
const effExtPos = ext.positionBtc + p1.deltas.dExtPosition;
|
|
42180
|
+
const effVesuPos = vesu.positionBtc + p1.deltas.dVesuPosition;
|
|
42181
|
+
const effExtEquity = ext.equity + p1.deltas.dExtAvlWithdraw + p1.deltas.dExtUpnl;
|
|
42182
|
+
const effVesuDebt = vesu.debt + p1.deltas.dVesuDebt;
|
|
42183
|
+
const p2 = phase2(
|
|
42184
|
+
effExtPos,
|
|
42185
|
+
effVesuPos,
|
|
42186
|
+
effExtEquity,
|
|
42187
|
+
effVesuDebt,
|
|
42188
|
+
vesu,
|
|
42189
|
+
ext.leverage,
|
|
42190
|
+
btcPrice,
|
|
42191
|
+
pool,
|
|
42192
|
+
config.positionPrecision
|
|
42193
|
+
);
|
|
42194
|
+
return mergeDeltas(p1.deltas, p2);
|
|
42195
|
+
}
|
|
42196
|
+
|
|
41635
42197
|
// src/strategies/vesu-extended-strategy/services/extended-vesu-state-manager.ts
|
|
41636
42198
|
var RouteType = /* @__PURE__ */ ((RouteType2) => {
|
|
41637
42199
|
RouteType2["WALLET_TO_EXTENDED"] = "WALLET_TO_EXTENDED";
|
|
@@ -41663,6 +42225,7 @@ var CaseCategory = /* @__PURE__ */ ((CaseCategory2) => {
|
|
|
41663
42225
|
return CaseCategory2;
|
|
41664
42226
|
})(CaseCategory || {});
|
|
41665
42227
|
var CaseId = /* @__PURE__ */ ((CaseId2) => {
|
|
42228
|
+
CaseId2["MANAGE_LTV"] = "MANAGE_LTV";
|
|
41666
42229
|
CaseId2["LTV_VESU_LOW_TO_EXTENDED"] = "LTV_VESU_LOW_TO_EXTENDED";
|
|
41667
42230
|
CaseId2["LTV_EXTENDED_PROFITABLE_AVAILABLE"] = "LTV_EXTENDED_PROFITABLE_AVAILABLE";
|
|
41668
42231
|
CaseId2["LTV_EXTENDED_PROFITABLE_REALIZE"] = "LTV_EXTENDED_PROFITABLE_REALIZE";
|
|
@@ -41687,19 +42250,56 @@ function safeUsdcWeb3Number(value) {
|
|
|
41687
42250
|
return new Web3Number(value.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS);
|
|
41688
42251
|
}
|
|
41689
42252
|
var CASE_ROUTE_TYPES = {
|
|
41690
|
-
// LTV Rebalance —
|
|
42253
|
+
// LTV Rebalance — unified
|
|
42254
|
+
["MANAGE_LTV" /* MANAGE_LTV */]: [
|
|
42255
|
+
"REALISE_PNL" /* REALISE_PNL */,
|
|
42256
|
+
"EXTENDED_TO_WALLET" /* EXTENDED_TO_WALLET */,
|
|
42257
|
+
"RETURN_TO_WAIT" /* RETURN_TO_WAIT */,
|
|
42258
|
+
"WALLET_TO_VA" /* WALLET_TO_VA */,
|
|
42259
|
+
"VESU_BORROW" /* VESU_BORROW */,
|
|
42260
|
+
"VESU_REPAY" /* VESU_REPAY */,
|
|
42261
|
+
"VA_TO_EXTENDED" /* VA_TO_EXTENDED */,
|
|
42262
|
+
"VESU_MULTIPLY_DECREASE_LEVER" /* VESU_MULTIPLY_DECREASE_LEVER */,
|
|
42263
|
+
"VESU_MULTIPLY_INCREASE_LEVER" /* VESU_MULTIPLY_INCREASE_LEVER */,
|
|
42264
|
+
"AVNU_DEPOSIT_SWAP" /* AVNU_DEPOSIT_SWAP */,
|
|
42265
|
+
"EXTENDED_DECREASE_LEVER" /* EXTENDED_DECREASE_LEVER */,
|
|
42266
|
+
"EXTENDED_INCREASE_LEVER" /* EXTENDED_INCREASE_LEVER */,
|
|
42267
|
+
// Second-phase VA / Extended funding after lever routes (same types may repeat).
|
|
42268
|
+
"RETURN_TO_WAIT" /* RETURN_TO_WAIT */,
|
|
42269
|
+
"WALLET_TO_VA" /* WALLET_TO_VA */,
|
|
42270
|
+
"VA_TO_EXTENDED" /* VA_TO_EXTENDED */
|
|
42271
|
+
],
|
|
42272
|
+
/** @deprecated */
|
|
41691
42273
|
["LTV_VESU_HIGH_USE_VA_OR_WALLET" /* LTV_VESU_HIGH_USE_VA_OR_WALLET */]: ["WALLET_TO_VA" /* WALLET_TO_VA */, "VESU_REPAY" /* VESU_REPAY */],
|
|
41692
|
-
|
|
42274
|
+
/** @deprecated */
|
|
41693
42275
|
["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 */],
|
|
42276
|
+
/** @deprecated */
|
|
41694
42277
|
["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 */],
|
|
41695
|
-
|
|
42278
|
+
/** @deprecated */
|
|
41696
42279
|
["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 */],
|
|
42280
|
+
/** @deprecated */
|
|
41697
42281
|
["LTV_VESU_LOW_TO_EXTENDED" /* LTV_VESU_LOW_TO_EXTENDED */]: ["VESU_BORROW" /* VESU_BORROW */, "VA_TO_EXTENDED" /* VA_TO_EXTENDED */],
|
|
41698
42282
|
// New Deposits
|
|
41699
42283
|
// @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
|
|
41700
42284
|
// Sequence: fund-movement transfers first (WALLET_TO_EXTENDED, VA_TO_EXTENDED, WALLET_TO_VA, EXTENDED_TO_WALLET),
|
|
41701
42285
|
// then RETURN_TO_WAIT, then optional second WALLET_TO_VA + RETURN_TO_WAIT, then lever routes.
|
|
41702
|
-
["DEPOSIT_FRESH_VAULT" /* DEPOSIT_FRESH_VAULT */]: [
|
|
42286
|
+
["DEPOSIT_FRESH_VAULT" /* DEPOSIT_FRESH_VAULT */]: [
|
|
42287
|
+
// May repeat after MANAGE_LTV (VA top-up → Extended → wait → levers).
|
|
42288
|
+
"WALLET_TO_VA" /* WALLET_TO_VA */,
|
|
42289
|
+
"VA_TO_EXTENDED" /* VA_TO_EXTENDED */,
|
|
42290
|
+
"RETURN_TO_WAIT" /* RETURN_TO_WAIT */,
|
|
42291
|
+
"VA_TO_EXTENDED" /* VA_TO_EXTENDED */,
|
|
42292
|
+
"VESU_BORROW" /* VESU_BORROW */,
|
|
42293
|
+
"WALLET_TO_EXTENDED" /* WALLET_TO_EXTENDED */,
|
|
42294
|
+
"VA_TO_EXTENDED" /* VA_TO_EXTENDED */,
|
|
42295
|
+
"WALLET_TO_VA" /* WALLET_TO_VA */,
|
|
42296
|
+
"EXTENDED_TO_WALLET" /* EXTENDED_TO_WALLET */,
|
|
42297
|
+
"RETURN_TO_WAIT" /* RETURN_TO_WAIT */,
|
|
42298
|
+
"WALLET_TO_VA" /* WALLET_TO_VA */,
|
|
42299
|
+
"AVNU_DEPOSIT_SWAP" /* AVNU_DEPOSIT_SWAP */,
|
|
42300
|
+
"VESU_MULTIPLY_INCREASE_LEVER" /* VESU_MULTIPLY_INCREASE_LEVER */,
|
|
42301
|
+
"EXTENDED_INCREASE_LEVER" /* EXTENDED_INCREASE_LEVER */
|
|
42302
|
+
],
|
|
41703
42303
|
["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 */],
|
|
41704
42304
|
["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 */],
|
|
41705
42305
|
["DEPOSIT_COMBINATION" /* DEPOSIT_COMBINATION */]: [],
|
|
@@ -41722,6 +42322,17 @@ var CASE_ROUTE_TYPES = {
|
|
|
41722
42322
|
["IMBALANCE_VESU_EXCESS_LONG_NO_FUNDS" /* IMBALANCE_VESU_EXCESS_LONG_NO_FUNDS */]: ["VESU_MULTIPLY_DECREASE_LEVER" /* VESU_MULTIPLY_DECREASE_LEVER */]
|
|
41723
42323
|
};
|
|
41724
42324
|
var CASE_DEFINITIONS = {
|
|
42325
|
+
["MANAGE_LTV" /* MANAGE_LTV */]: {
|
|
42326
|
+
id: "MANAGE_LTV" /* MANAGE_LTV */,
|
|
42327
|
+
category: "LTV_REBALANCE" /* LTV_REBALANCE */,
|
|
42328
|
+
title: "LTV Rebalance: Unified Vesu repay + Extended margin management",
|
|
42329
|
+
description: "Manages both Vesu high-LTV repayment and Extended low-margin funding in a single pass.",
|
|
42330
|
+
steps: [
|
|
42331
|
+
"Compute vesu repay needed and extended margin needed",
|
|
42332
|
+
"Allocate funds: VA > Wallet > ExtAvl > ExtUpnl for Vesu; Wallet > VA > Borrow for Extended",
|
|
42333
|
+
"Build combined transfer and repay/margin routes"
|
|
42334
|
+
]
|
|
42335
|
+
},
|
|
41725
42336
|
["LTV_VESU_LOW_TO_EXTENDED" /* LTV_VESU_LOW_TO_EXTENDED */]: {
|
|
41726
42337
|
id: "LTV_VESU_LOW_TO_EXTENDED" /* LTV_VESU_LOW_TO_EXTENDED */,
|
|
41727
42338
|
category: "LTV_REBALANCE" /* LTV_REBALANCE */,
|
|
@@ -41944,199 +42555,590 @@ function routeSummary(r) {
|
|
|
41944
42555
|
}
|
|
41945
42556
|
var SolveBudget = class {
|
|
41946
42557
|
constructor(state) {
|
|
41947
|
-
|
|
41948
|
-
|
|
41949
|
-
|
|
41950
|
-
|
|
41951
|
-
|
|
41952
|
-
|
|
41953
|
-
this._extAvailTrade = 0;
|
|
41954
|
-
this._extPendingDeposit = 0;
|
|
41955
|
-
this._vesuBorrowCapacity = 0;
|
|
41956
|
-
this._totalUnused = 0;
|
|
41957
|
-
const buffer = state.limitBalanceBufferFactor;
|
|
41958
|
-
this.unusedBalance = state.unusedBalance.map((item) => {
|
|
41959
|
-
return {
|
|
41960
|
-
...item,
|
|
41961
|
-
amount: item.amount.multipliedBy(1 - buffer),
|
|
41962
|
-
usdValue: item.usdValue * (1 - buffer)
|
|
41963
|
-
};
|
|
42558
|
+
this.assetToken = state.assetToken;
|
|
42559
|
+
this.usdcToken = state.usdcToken;
|
|
42560
|
+
const cloneTb = (b) => ({
|
|
42561
|
+
token: b.token,
|
|
42562
|
+
amount: new Web3Number(b.amount.toFixed(b.token.decimals), b.token.decimals),
|
|
42563
|
+
usdValue: b.usdValue
|
|
41964
42564
|
});
|
|
41965
|
-
this.
|
|
41966
|
-
|
|
41967
|
-
|
|
41968
|
-
|
|
41969
|
-
|
|
41970
|
-
|
|
41971
|
-
|
|
41972
|
-
|
|
41973
|
-
|
|
41974
|
-
} : null;
|
|
41975
|
-
this.extendedPositions = state.extendedPositions;
|
|
42565
|
+
this.unusedBalance = state.unusedBalance.map((item) => cloneTb(item));
|
|
42566
|
+
this.walletBalance = state.walletBalance ? cloneTb(state.walletBalance) : null;
|
|
42567
|
+
this.vaultAssetBalance = state.vaultAssetBalance ? cloneTb(state.vaultAssetBalance) : null;
|
|
42568
|
+
this.vaultUsdcBalance = state.vaultUsdcBalance ? cloneTb(state.vaultUsdcBalance) : null;
|
|
42569
|
+
this.extendedPositions = state.extendedPositions.map((p) => ({
|
|
42570
|
+
...p,
|
|
42571
|
+
size: new Web3Number(p.size.toFixed(8), 8),
|
|
42572
|
+
valueUsd: new Web3Number(p.valueUsd.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS)
|
|
42573
|
+
}));
|
|
41976
42574
|
this.extendedBalance = state.extendedBalance ? {
|
|
41977
|
-
|
|
41978
|
-
|
|
41979
|
-
|
|
41980
|
-
|
|
41981
|
-
|
|
42575
|
+
equity: new Web3Number(
|
|
42576
|
+
state.extendedBalance.equity.toFixed(USDC_TOKEN_DECIMALS),
|
|
42577
|
+
USDC_TOKEN_DECIMALS
|
|
42578
|
+
),
|
|
42579
|
+
availableForTrade: new Web3Number(
|
|
42580
|
+
state.extendedBalance.availableForTrade.toFixed(USDC_TOKEN_DECIMALS),
|
|
42581
|
+
USDC_TOKEN_DECIMALS
|
|
42582
|
+
),
|
|
42583
|
+
availableForWithdrawal: new Web3Number(
|
|
42584
|
+
state.extendedBalance.availableForWithdrawal.toFixed(USDC_TOKEN_DECIMALS),
|
|
42585
|
+
USDC_TOKEN_DECIMALS
|
|
42586
|
+
),
|
|
42587
|
+
unrealisedPnl: new Web3Number(
|
|
42588
|
+
state.extendedBalance.unrealisedPnl.toFixed(USDC_TOKEN_DECIMALS),
|
|
42589
|
+
USDC_TOKEN_DECIMALS
|
|
42590
|
+
),
|
|
42591
|
+
balance: new Web3Number(
|
|
42592
|
+
state.extendedBalance.balance.toFixed(USDC_TOKEN_DECIMALS),
|
|
42593
|
+
USDC_TOKEN_DECIMALS
|
|
42594
|
+
),
|
|
42595
|
+
pendingDeposit: new Web3Number(
|
|
42596
|
+
state.extendedBalance.pendingDeposit.toFixed(USDC_TOKEN_DECIMALS),
|
|
42597
|
+
USDC_TOKEN_DECIMALS
|
|
42598
|
+
)
|
|
41982
42599
|
} : null;
|
|
41983
|
-
this.vesuPoolStates = state.vesuPoolStates
|
|
42600
|
+
this.vesuPoolStates = state.vesuPoolStates.map((p) => ({
|
|
42601
|
+
...p,
|
|
42602
|
+
collateralAmount: new Web3Number(
|
|
42603
|
+
p.collateralAmount.toFixed(p.collateralToken.decimals),
|
|
42604
|
+
p.collateralToken.decimals
|
|
42605
|
+
),
|
|
42606
|
+
debtAmount: new Web3Number(
|
|
42607
|
+
p.debtAmount.toFixed(p.debtToken.decimals),
|
|
42608
|
+
p.debtToken.decimals
|
|
42609
|
+
)
|
|
42610
|
+
}));
|
|
41984
42611
|
const vesuPerPoolDebtDeltasToBorrow = this._computeperPoolDebtDeltasToBorrow();
|
|
41985
42612
|
assert(vesuPerPoolDebtDeltasToBorrow.length === this.vesuPoolStates.length, "vesuPerPoolDebtDeltasToBorrow length must match vesuPoolStates length");
|
|
41986
42613
|
this.vesuPerPoolDebtDeltasToBorrow = vesuPerPoolDebtDeltasToBorrow.map((item) => item.deltaDebt);
|
|
41987
42614
|
this.shouldVesuRebalance = vesuPerPoolDebtDeltasToBorrow.map((item) => item.shouldRebalance);
|
|
41988
42615
|
}
|
|
42616
|
+
/** `1 - limitBalanceBufferFactor` — multiplier applied to raw notionals for “usable” USD. */
|
|
42617
|
+
_usableFraction() {
|
|
42618
|
+
return 1;
|
|
42619
|
+
}
|
|
41989
42620
|
/**
|
|
41990
|
-
*
|
|
41991
|
-
*
|
|
41992
|
-
|
|
41993
|
-
|
|
41994
|
-
|
|
41995
|
-
|
|
42621
|
+
* Raw USD notional for a token row. USDC (and configured {@link usdcToken}) uses 1:1 from amount;
|
|
42622
|
+
* non-stable assets (e.g. WBTC in VA) use {@link TokenBalance.usdValue} from the pricer at refresh.
|
|
42623
|
+
*/
|
|
42624
|
+
_rawTokenUsd(tb) {
|
|
42625
|
+
if (!tb) return 0;
|
|
42626
|
+
if (this.usdcToken.address.eq(tb.token.address)) {
|
|
42627
|
+
return Number(tb.amount.toFixed(tb.token.decimals));
|
|
42628
|
+
}
|
|
42629
|
+
return tb.usdValue;
|
|
42630
|
+
}
|
|
42631
|
+
/** Apply safety buffer to a raw USD scalar. */
|
|
42632
|
+
bufferedUsd(rawUsd) {
|
|
42633
|
+
return rawUsd * this._usableFraction();
|
|
42634
|
+
}
|
|
42635
|
+
/** Convert a buffered “usable” USD amount to raw nominal USD (inverse of {@link bufferedUsd}). */
|
|
42636
|
+
rawUsdFromBuffered(bufferedUsd) {
|
|
42637
|
+
const bf = this._usableFraction();
|
|
42638
|
+
assert(bf > 0, "SolveBudget::rawUsdFromBuffered usable fraction must be positive");
|
|
42639
|
+
return bufferedUsd / bf;
|
|
42640
|
+
}
|
|
42641
|
+
/** Buffered USD notional for one token balance row. */
|
|
42642
|
+
bufferedTokenUsd(tb) {
|
|
42643
|
+
return this.bufferedUsd(this._rawTokenUsd(tb));
|
|
42644
|
+
}
|
|
42645
|
+
logStateSummary() {
|
|
42646
|
+
console.log("===== state summary =====");
|
|
42647
|
+
const aggregatedData = {
|
|
42648
|
+
unusedBalances: this.unusedBalance.map((b) => ({
|
|
42649
|
+
token: b.token.symbol,
|
|
42650
|
+
amount: b.amount.toNumber()
|
|
42651
|
+
})),
|
|
42652
|
+
walletBalance: this.walletBalance ? {
|
|
42653
|
+
token: this.walletBalance.token.symbol,
|
|
42654
|
+
amount: this.walletBalance.amount.toNumber()
|
|
42655
|
+
} : void 0,
|
|
42656
|
+
vaultAssetBalance: this.vaultAssetBalance ? {
|
|
42657
|
+
token: this.vaultAssetBalance.token.symbol,
|
|
42658
|
+
amount: this.vaultAssetBalance.amount.toNumber()
|
|
42659
|
+
} : void 0,
|
|
42660
|
+
vaultUsdcBalance: this.vaultUsdcBalance ? {
|
|
42661
|
+
token: this.vaultUsdcBalance.token.symbol,
|
|
42662
|
+
amount: this.vaultUsdcBalance.amount.toNumber()
|
|
42663
|
+
} : void 0,
|
|
42664
|
+
vesuPoolStates: this.vesuPoolStates.map((p) => ({
|
|
42665
|
+
poolId: p.poolId,
|
|
42666
|
+
collateralAmount: p.collateralAmount.toNumber(),
|
|
42667
|
+
debtAmount: p.debtAmount.toNumber()
|
|
42668
|
+
})),
|
|
42669
|
+
vesuBorrowCapacity: this.vesuBorrowCapacity,
|
|
42670
|
+
vesuRebalance: this.shouldVesuRebalance,
|
|
42671
|
+
vesuPerPoolDebtDeltasToBorrow: this.vesuPerPoolDebtDeltasToBorrow.map((d) => d.toNumber()),
|
|
42672
|
+
extendedBalance: this.extendedBalance?.balance.toNumber(),
|
|
42673
|
+
extendedEquity: this.extendedBalance?.equity.toNumber(),
|
|
42674
|
+
extendedAvailableForTrade: this.extendedBalance?.availableForTrade.toNumber(),
|
|
42675
|
+
extendedAvailableForWithdrawal: this.extendedBalance?.availableForWithdrawal.toNumber(),
|
|
42676
|
+
extendedUnrealisedPnl: this.extendedBalance?.unrealisedPnl.toNumber(),
|
|
42677
|
+
extendedPendingDeposit: this.extendedBalance?.pendingDeposit.toNumber(),
|
|
42678
|
+
extendedPositions: this.extendedPositions.map((p) => ({
|
|
42679
|
+
instrument: p.instrument,
|
|
42680
|
+
size: p.size.toNumber(),
|
|
42681
|
+
valueUsd: p.valueUsd.toNumber()
|
|
42682
|
+
}))
|
|
42683
|
+
};
|
|
42684
|
+
console.log(
|
|
42685
|
+
"unused balances",
|
|
42686
|
+
aggregatedData.unusedBalances.map((b) => `${b.token}=${b.amount}`).join(", ")
|
|
42687
|
+
);
|
|
42688
|
+
console.log(
|
|
42689
|
+
"wallet balance",
|
|
42690
|
+
aggregatedData.walletBalance ? `${aggregatedData.walletBalance.token}=${aggregatedData.walletBalance.amount}` : void 0
|
|
42691
|
+
);
|
|
42692
|
+
console.log(
|
|
42693
|
+
"vault asset balance",
|
|
42694
|
+
aggregatedData.vaultAssetBalance ? `${aggregatedData.vaultAssetBalance.token}=${aggregatedData.vaultAssetBalance.amount}` : void 0
|
|
42695
|
+
);
|
|
42696
|
+
console.log(
|
|
42697
|
+
"vault usdc balance",
|
|
42698
|
+
aggregatedData.vaultUsdcBalance ? `${aggregatedData.vaultUsdcBalance.token}=${aggregatedData.vaultUsdcBalance.amount}` : void 0
|
|
42699
|
+
);
|
|
42700
|
+
console.log(
|
|
42701
|
+
"vesu pool states",
|
|
42702
|
+
aggregatedData.vesuPoolStates.map(
|
|
42703
|
+
(p) => `${p.poolId.shortString()}=${p.collateralAmount} ${p.debtAmount}`
|
|
42704
|
+
).join(", ")
|
|
42705
|
+
);
|
|
42706
|
+
console.log("vesu borrow capacity", aggregatedData.vesuBorrowCapacity);
|
|
42707
|
+
console.log(
|
|
42708
|
+
"vesu rebalance",
|
|
42709
|
+
aggregatedData.vesuRebalance.map(String).join(", ")
|
|
42710
|
+
);
|
|
42711
|
+
console.log("vesu per pool debt deltas to borrow", aggregatedData.vesuPerPoolDebtDeltasToBorrow.join(", "));
|
|
42712
|
+
console.log("extended balance", aggregatedData.extendedBalance);
|
|
42713
|
+
console.log("extended equity", aggregatedData.extendedEquity);
|
|
42714
|
+
console.log("extended available for trade", aggregatedData.extendedAvailableForTrade);
|
|
42715
|
+
console.log("extended available for withdrawal", aggregatedData.extendedAvailableForWithdrawal);
|
|
42716
|
+
console.log("extended unrealised pnl", aggregatedData.extendedUnrealisedPnl);
|
|
42717
|
+
console.log("extended pending deposit", aggregatedData.extendedPendingDeposit);
|
|
42718
|
+
console.log(
|
|
42719
|
+
"extended positions",
|
|
42720
|
+
aggregatedData.extendedPositions.map(
|
|
42721
|
+
(p) => `${p.instrument}=${p.size} ${p.valueUsd}`
|
|
42722
|
+
).join(", ")
|
|
42723
|
+
);
|
|
42724
|
+
return aggregatedData;
|
|
42725
|
+
}
|
|
42726
|
+
/**
|
|
42727
|
+
* Initialise derived views for a solve cycle. Mutates only when pending
|
|
42728
|
+
* withdrawal from Extended is in transit (credits wallet raw balance).
|
|
41996
42729
|
*/
|
|
41997
42730
|
initBudget() {
|
|
41998
|
-
const debtDeltaNum = this.vesuPerPoolDebtDeltasToBorrow.reduce((a, b) => a + b.toNumber(), 0);
|
|
41999
|
-
let totalUnusedUsd = this.unusedBalance.reduce((a, b) => a + b.usdValue, 0);
|
|
42000
|
-
if (debtDeltaNum > 0) totalUnusedUsd += debtDeltaNum;
|
|
42001
|
-
const extAvailTrade = this.extendedBalance?.availableForTrade?.toNumber() ?? 0;
|
|
42002
|
-
if (extAvailTrade > 0) totalUnusedUsd += extAvailTrade;
|
|
42003
|
-
if (debtDeltaNum > 0) totalUnusedUsd += debtDeltaNum;
|
|
42004
|
-
this._vaUsd = this.vaultBalance?.usdValue ?? 0;
|
|
42005
|
-
this._walletUsd = this.walletBalance?.usdValue ?? 0;
|
|
42006
|
-
this._extAvailWithdraw = this.extendedBalance?.availableForWithdrawal?.toNumber() ?? 0;
|
|
42007
|
-
this._extAvailUpnl = this.extendedBalance?.unrealisedPnl?.toNumber() ?? 0;
|
|
42008
|
-
this._extAvailTrade = extAvailTrade;
|
|
42009
|
-
this._extPendingDeposit = this.extendedBalance?.pendingDeposit?.toNumber() ?? 0;
|
|
42010
|
-
this._vesuBorrowCapacity = debtDeltaNum;
|
|
42011
|
-
this._totalUnused = totalUnusedUsd;
|
|
42012
42731
|
const pendingDeposit = this.extendedBalance?.pendingDeposit?.toNumber() ?? 0;
|
|
42013
|
-
if (pendingDeposit
|
|
42014
|
-
this._extAvailTrade += pendingDeposit;
|
|
42015
|
-
this._totalUnused += pendingDeposit;
|
|
42016
|
-
logger.debug(`SolveBudget::initBudget pendingDeposit=${pendingDeposit} -> increased extAvailTrade`);
|
|
42017
|
-
} else if (pendingDeposit < 0) {
|
|
42732
|
+
if (pendingDeposit < 0) {
|
|
42018
42733
|
const inTransit = Math.abs(pendingDeposit);
|
|
42019
|
-
this.
|
|
42020
|
-
|
|
42021
|
-
|
|
42734
|
+
if (this.walletBalance) {
|
|
42735
|
+
this._addUsdToTokenBalance(this.walletBalance, inTransit);
|
|
42736
|
+
}
|
|
42737
|
+
logger.debug(`SolveBudget::initBudget pendingDeposit=${pendingDeposit} -> increased wallet raw USD by ${inTransit}`);
|
|
42738
|
+
}
|
|
42739
|
+
this._recomputeUnusedBalance();
|
|
42740
|
+
}
|
|
42741
|
+
/**
|
|
42742
|
+
* Apply a safety buffer to all liquid balances (VA, wallet, extended trade/withdraw/upnl,
|
|
42743
|
+
* unused balances). Call after withdrawal classification but before LTV/deposit classifiers
|
|
42744
|
+
* so that withdrawal uses full raw amounts while subsequent classifiers see buffered values.
|
|
42745
|
+
*/
|
|
42746
|
+
applyBuffer(factor) {
|
|
42747
|
+
if (factor <= 0 || factor >= 1) return;
|
|
42748
|
+
const mult = 1 - factor;
|
|
42749
|
+
const scaleTokenBalance = (tb) => {
|
|
42750
|
+
if (!tb) return;
|
|
42751
|
+
const newAmount = tb.amount.multipliedBy(mult);
|
|
42752
|
+
tb.amount = new Web3Number(newAmount.toFixed(tb.token.decimals), tb.token.decimals);
|
|
42753
|
+
tb.usdValue = tb.usdValue * mult;
|
|
42754
|
+
};
|
|
42755
|
+
scaleTokenBalance(this.vaultAssetBalance);
|
|
42756
|
+
scaleTokenBalance(this.vaultUsdcBalance);
|
|
42757
|
+
scaleTokenBalance(this.walletBalance);
|
|
42758
|
+
for (const ub of this.unusedBalance) {
|
|
42759
|
+
scaleTokenBalance(ub);
|
|
42760
|
+
}
|
|
42761
|
+
if (this.extendedBalance) {
|
|
42762
|
+
this.extendedBalance.availableForTrade = this.extendedBalance.availableForTrade.multipliedBy(mult);
|
|
42763
|
+
this.extendedBalance.availableForWithdrawal = this.extendedBalance.availableForWithdrawal.multipliedBy(mult);
|
|
42764
|
+
this.extendedBalance.unrealisedPnl = this.extendedBalance.unrealisedPnl.multipliedBy(mult);
|
|
42022
42765
|
}
|
|
42766
|
+
this._recomputeUnusedBalance();
|
|
42023
42767
|
}
|
|
42024
|
-
|
|
42768
|
+
get vesuPoolState() {
|
|
42769
|
+
assert(this.vesuPoolStates.length === 1, "SolveBudget::vesuPoolState: vesuPoolStates length must be 1");
|
|
42770
|
+
return this.vesuPoolStates[0];
|
|
42771
|
+
}
|
|
42772
|
+
// ── Derived getters (buffered where applicable) ─────────────────────
|
|
42773
|
+
/** Buffered VA USD: strategy-asset slot + optional USDC slot. */
|
|
42025
42774
|
get vaUsd() {
|
|
42026
|
-
return this.
|
|
42775
|
+
return this.bufferedTokenUsd(this.vaultAssetBalance) + this.bufferedTokenUsd(this.vaultUsdcBalance);
|
|
42776
|
+
}
|
|
42777
|
+
/** Buffered USD in VA strategy-asset bucket only. */
|
|
42778
|
+
get vaAssetUsd() {
|
|
42779
|
+
return this.bufferedTokenUsd(this.vaultAssetBalance);
|
|
42780
|
+
}
|
|
42781
|
+
/** Buffered USD in VA USDC bucket (0 when asset === USDC). */
|
|
42782
|
+
get vaUsdcUsd() {
|
|
42783
|
+
return this.bufferedTokenUsd(this.vaultUsdcBalance);
|
|
42027
42784
|
}
|
|
42028
42785
|
get walletUsd() {
|
|
42029
|
-
return this.
|
|
42786
|
+
return this.bufferedUsd(this._rawTokenUsd(this.walletBalance));
|
|
42030
42787
|
}
|
|
42031
42788
|
get vaWalletUsd() {
|
|
42032
|
-
return this.
|
|
42789
|
+
return this.vaUsd + this.walletUsd;
|
|
42033
42790
|
}
|
|
42034
42791
|
get extAvailWithdraw() {
|
|
42035
|
-
|
|
42792
|
+
const raw = this.extendedBalance?.availableForWithdrawal?.toNumber() ?? 0;
|
|
42793
|
+
return this.bufferedUsd(raw);
|
|
42036
42794
|
}
|
|
42037
42795
|
get extAvailUpnl() {
|
|
42038
|
-
|
|
42796
|
+
const raw = this.extendedBalance?.unrealisedPnl?.toNumber() ?? 0;
|
|
42797
|
+
return this.bufferedUsd(raw);
|
|
42039
42798
|
}
|
|
42799
|
+
/**
|
|
42800
|
+
* Buffered Extended available-for-trade plus positive {@link ExtendedBalanceState.pendingDeposit}
|
|
42801
|
+
* (deposit in transit is usable the same way as the pre-buffer implementation).
|
|
42802
|
+
*/
|
|
42040
42803
|
get extAvailTrade() {
|
|
42041
|
-
|
|
42804
|
+
const raw = this.extendedBalance?.availableForTrade?.toNumber() ?? 0;
|
|
42805
|
+
let v = this.bufferedUsd(raw);
|
|
42806
|
+
const pd = this.extendedBalance?.pendingDeposit?.toNumber() ?? 0;
|
|
42807
|
+
if (pd > 0) v += pd;
|
|
42808
|
+
return v;
|
|
42809
|
+
}
|
|
42810
|
+
get extPendingDeposit() {
|
|
42811
|
+
return this.extendedBalance?.pendingDeposit?.toNumber() ?? 0;
|
|
42042
42812
|
}
|
|
42813
|
+
/**
|
|
42814
|
+
* Aggregate positive per-pool borrow headroom (USD). Repay/borrow routes update
|
|
42815
|
+
* {@link vesuPerPoolDebtDeltasToBorrow}; no separate counter.
|
|
42816
|
+
*/
|
|
42043
42817
|
get vesuBorrowCapacity() {
|
|
42044
|
-
return this.
|
|
42818
|
+
return this.vesuPerPoolDebtDeltasToBorrow.reduce(
|
|
42819
|
+
(a, d) => a + Math.max(0, d.toNumber()),
|
|
42820
|
+
0
|
|
42821
|
+
);
|
|
42045
42822
|
}
|
|
42823
|
+
/** Diagnostic: buffered idle + positive debt delta + buffered Extended afT + in-flight deposit. */
|
|
42046
42824
|
get totalUnused() {
|
|
42047
|
-
|
|
42825
|
+
const debtSum = this.vesuPerPoolDebtDeltasToBorrow.reduce((a, b) => a + b.toNumber(), 0);
|
|
42826
|
+
let u = this.unusedBalance.reduce((a, b) => a + this.bufferedTokenUsd(b), 0);
|
|
42827
|
+
if (debtSum > 0) u += debtSum;
|
|
42828
|
+
const rawAft = this.extendedBalance?.availableForTrade?.toNumber() ?? 0;
|
|
42829
|
+
const aftBuf = this.bufferedUsd(rawAft);
|
|
42830
|
+
if (aftBuf > 0) u += aftBuf;
|
|
42831
|
+
const pd = this.extendedBalance?.pendingDeposit?.toNumber() ?? 0;
|
|
42832
|
+
if (pd > 0) u += pd;
|
|
42833
|
+
return u;
|
|
42834
|
+
}
|
|
42835
|
+
/** Sum of buffered USD across merged unused-balance rows (VA + wallet). */
|
|
42836
|
+
get unusedBalancesBufferedUsdSum() {
|
|
42837
|
+
return this.unusedBalance.reduce((a, b) => a + this.bufferedTokenUsd(b), 0);
|
|
42838
|
+
}
|
|
42839
|
+
/** Read-only snapshot view for validation / logging. */
|
|
42840
|
+
get unusedBalanceRows() {
|
|
42841
|
+
return this.unusedBalance;
|
|
42842
|
+
}
|
|
42843
|
+
/** Read-only Vesu pool view for solve computations. */
|
|
42844
|
+
get vesuPools() {
|
|
42845
|
+
return this.vesuPoolStates;
|
|
42846
|
+
}
|
|
42847
|
+
/** Read-only Extended positions view for solve computations. */
|
|
42848
|
+
get extendedPositionsView() {
|
|
42849
|
+
return this.extendedPositions;
|
|
42850
|
+
}
|
|
42851
|
+
/** Read-only Extended balance view for diagnostics / margin checks. */
|
|
42852
|
+
get extendedBalanceView() {
|
|
42853
|
+
return this.extendedBalance;
|
|
42854
|
+
}
|
|
42855
|
+
/** Current debt deltas per pool (positive=borrow, negative=repay). */
|
|
42856
|
+
get vesuDebtDeltas() {
|
|
42857
|
+
return this.vesuPerPoolDebtDeltasToBorrow;
|
|
42858
|
+
}
|
|
42859
|
+
/** Per-pool rebalance flags derived from target HF checks. */
|
|
42860
|
+
get vesuRebalanceFlags() {
|
|
42861
|
+
return this.shouldVesuRebalance;
|
|
42862
|
+
}
|
|
42863
|
+
/** Raw USD in VA (USDC slot + asset slot); spend caps when executing transfers. */
|
|
42864
|
+
_vaRawUsd() {
|
|
42865
|
+
return this._rawTokenUsd(this.vaultUsdcBalance) + this._rawTokenUsd(this.vaultAssetBalance);
|
|
42866
|
+
}
|
|
42867
|
+
_walletRawUsd() {
|
|
42868
|
+
return this._rawTokenUsd(this.walletBalance);
|
|
42869
|
+
}
|
|
42870
|
+
// ── Token snapshot helpers (keep vault / wallet / unusedBalance aligned) ─
|
|
42871
|
+
/** Remove up to `usd` notional from a token balance, scaling token amount proportionally. */
|
|
42872
|
+
_deductUsdFromTokenBalance(tb, usd) {
|
|
42873
|
+
if (usd <= 0) return;
|
|
42874
|
+
const take = Math.min(usd, tb.usdValue);
|
|
42875
|
+
if (take <= 0) return;
|
|
42876
|
+
const oldUsd = tb.usdValue;
|
|
42877
|
+
const newUsd = Math.max(0, oldUsd - take);
|
|
42878
|
+
tb.usdValue = newUsd;
|
|
42879
|
+
if (oldUsd <= 0) return;
|
|
42880
|
+
const ratio = newUsd / oldUsd;
|
|
42881
|
+
tb.amount = new Web3Number(
|
|
42882
|
+
(tb.amount.toNumber() * ratio).toFixed(tb.token.decimals),
|
|
42883
|
+
tb.token.decimals
|
|
42884
|
+
);
|
|
42885
|
+
}
|
|
42886
|
+
/** Add USD notional; infers price from current amount/usd when possible, else 1:1. */
|
|
42887
|
+
_addUsdToTokenBalance(tb, usd) {
|
|
42888
|
+
if (usd <= 0) return;
|
|
42889
|
+
const amtNum = tb.amount.toNumber();
|
|
42890
|
+
const price = amtNum > 0 && tb.usdValue > 0 ? tb.usdValue / amtNum : 1;
|
|
42891
|
+
const deltaTok = usd / price;
|
|
42892
|
+
tb.usdValue += usd;
|
|
42893
|
+
tb.amount = tb.amount.plus(
|
|
42894
|
+
new Web3Number(deltaTok.toFixed(tb.token.decimals), tb.token.decimals)
|
|
42895
|
+
);
|
|
42048
42896
|
}
|
|
42049
|
-
|
|
42050
|
-
|
|
42897
|
+
/**
|
|
42898
|
+
* Rebuilds {@link unusedBalance} from vault + wallet snapshots (same merge as refresh).
|
|
42899
|
+
*/
|
|
42900
|
+
_recomputeUnusedBalance() {
|
|
42901
|
+
const balanceMap = /* @__PURE__ */ new Map();
|
|
42902
|
+
const merge = (b) => {
|
|
42903
|
+
if (!b) return;
|
|
42904
|
+
const key = b.token.address.toString();
|
|
42905
|
+
const row = {
|
|
42906
|
+
token: b.token,
|
|
42907
|
+
amount: new Web3Number(b.amount.toFixed(b.token.decimals), b.token.decimals),
|
|
42908
|
+
usdValue: b.usdValue
|
|
42909
|
+
};
|
|
42910
|
+
const existing = balanceMap.get(key);
|
|
42911
|
+
if (existing) {
|
|
42912
|
+
existing.amount = new Web3Number(
|
|
42913
|
+
existing.amount.plus(row.amount).toFixed(existing.token.decimals),
|
|
42914
|
+
existing.token.decimals
|
|
42915
|
+
);
|
|
42916
|
+
existing.usdValue += row.usdValue;
|
|
42917
|
+
} else {
|
|
42918
|
+
balanceMap.set(key, row);
|
|
42919
|
+
}
|
|
42920
|
+
};
|
|
42921
|
+
merge(this.vaultAssetBalance);
|
|
42922
|
+
merge(this.vaultUsdcBalance);
|
|
42923
|
+
merge(this.walletBalance);
|
|
42924
|
+
this.unusedBalance = Array.from(balanceMap.values());
|
|
42051
42925
|
}
|
|
42052
42926
|
// ── Spend methods (return amount consumed, auto-decrement totalUnused) ─
|
|
42053
|
-
|
|
42054
|
-
|
|
42055
|
-
|
|
42056
|
-
|
|
42057
|
-
|
|
42058
|
-
|
|
42059
|
-
|
|
42060
|
-
|
|
42061
|
-
|
|
42062
|
-
|
|
42063
|
-
|
|
42064
|
-
|
|
42065
|
-
|
|
42066
|
-
|
|
42067
|
-
|
|
42068
|
-
|
|
42069
|
-
this.
|
|
42070
|
-
logger.debug(`SolveBudget::
|
|
42071
|
-
return
|
|
42927
|
+
/**
|
|
42928
|
+
* Spend VA **raw** USD (up to {@link vaRawUsd}). Prefer {@link vaultUsdcBalance} when present, then {@link vaultAssetBalance}.
|
|
42929
|
+
*/
|
|
42930
|
+
spendVA(rawDesired) {
|
|
42931
|
+
const capRaw = this._vaRawUsd();
|
|
42932
|
+
const usedRaw = Math.min(capRaw, Math.max(0, rawDesired));
|
|
42933
|
+
if (usedRaw <= CASE_THRESHOLD_USD) return 0;
|
|
42934
|
+
let rem = usedRaw;
|
|
42935
|
+
if (rem > 0 && this.vaultUsdcBalance && this.vaultUsdcBalance.usdValue > 0) {
|
|
42936
|
+
const fromUsdc = Math.min(rem, this.vaultUsdcBalance.usdValue);
|
|
42937
|
+
this._deductUsdFromTokenBalance(this.vaultUsdcBalance, fromUsdc);
|
|
42938
|
+
rem -= fromUsdc;
|
|
42939
|
+
}
|
|
42940
|
+
if (rem > 0 && this.vaultAssetBalance) {
|
|
42941
|
+
this._deductUsdFromTokenBalance(this.vaultAssetBalance, rem);
|
|
42942
|
+
}
|
|
42943
|
+
this._recomputeUnusedBalance();
|
|
42944
|
+
logger.debug(`SolveBudget::spendVA usedRaw=${usedRaw}, vaUsd=${this.vaUsd}, totalUnused=${this.totalUnused}`);
|
|
42945
|
+
return usedRaw;
|
|
42072
42946
|
}
|
|
42073
|
-
|
|
42074
|
-
|
|
42075
|
-
|
|
42076
|
-
|
|
42077
|
-
|
|
42947
|
+
/**
|
|
42948
|
+
* Spend nominal/raw USD from VA (e.g. Vesu repay, on-chain USDC). Does not apply the safety buffer to the cap.
|
|
42949
|
+
*/
|
|
42950
|
+
spendVaRawUsd(rawUsdDesired) {
|
|
42951
|
+
const capRaw = this._rawTokenUsd(this.vaultUsdcBalance) + this._rawTokenUsd(this.vaultAssetBalance);
|
|
42952
|
+
const usedRaw = Math.min(capRaw, Math.max(0, rawUsdDesired));
|
|
42953
|
+
if (usedRaw <= CASE_THRESHOLD_USD) return 0;
|
|
42954
|
+
let rem = usedRaw;
|
|
42955
|
+
if (rem > 0 && this.vaultUsdcBalance && this.vaultUsdcBalance.usdValue > 0) {
|
|
42956
|
+
const fromUsdc = Math.min(rem, this.vaultUsdcBalance.usdValue);
|
|
42957
|
+
this._deductUsdFromTokenBalance(this.vaultUsdcBalance, fromUsdc);
|
|
42958
|
+
rem -= fromUsdc;
|
|
42959
|
+
}
|
|
42960
|
+
if (rem > 0 && this.vaultAssetBalance) {
|
|
42961
|
+
this._deductUsdFromTokenBalance(this.vaultAssetBalance, rem);
|
|
42962
|
+
}
|
|
42963
|
+
this._recomputeUnusedBalance();
|
|
42964
|
+
logger.debug(`SolveBudget::spendVaRawUsd usedRaw=${usedRaw}, vaUsd=${this.vaUsd}, totalUnused=${this.totalUnused}`);
|
|
42965
|
+
return usedRaw;
|
|
42078
42966
|
}
|
|
42079
|
-
|
|
42080
|
-
|
|
42967
|
+
/**
|
|
42968
|
+
* Add **raw nominal USD** to VA (borrow proceeds, wallet→VA in raw USDC, etc.).
|
|
42969
|
+
*/
|
|
42970
|
+
addToVA(rawUsd) {
|
|
42971
|
+
assert(rawUsd >= 0, "SolveBudget::addToVA amount must be positive");
|
|
42972
|
+
if (rawUsd === 0) return;
|
|
42973
|
+
if (this.vaultUsdcBalance) {
|
|
42974
|
+
this._addUsdToTokenBalance(this.vaultUsdcBalance, rawUsd);
|
|
42975
|
+
} else if (this.vaultAssetBalance) {
|
|
42976
|
+
this._addUsdToTokenBalance(this.vaultAssetBalance, rawUsd);
|
|
42977
|
+
}
|
|
42978
|
+
this._recomputeUnusedBalance();
|
|
42979
|
+
logger.debug(`SolveBudget::addToVA rawUsd=${rawUsd}, vaUsd=${this.vaUsd}, totalUnused=${this.totalUnused}`);
|
|
42980
|
+
}
|
|
42981
|
+
spendWallet(rawDesired) {
|
|
42982
|
+
const capRaw = this._walletRawUsd();
|
|
42983
|
+
const usedRaw = Math.min(capRaw, Math.max(0, rawDesired));
|
|
42984
|
+
if (usedRaw <= CASE_THRESHOLD_USD) return 0;
|
|
42985
|
+
if (this.walletBalance) {
|
|
42986
|
+
this._deductUsdFromTokenBalance(this.walletBalance, usedRaw);
|
|
42987
|
+
}
|
|
42988
|
+
this._recomputeUnusedBalance();
|
|
42989
|
+
logger.debug(`SolveBudget::spendWallet usedRaw=${usedRaw}, walletUsd=${this.walletUsd}, totalUnused=${this.totalUnused}`);
|
|
42990
|
+
return usedRaw;
|
|
42991
|
+
}
|
|
42992
|
+
/** Add **raw nominal USD** to the operator wallet balance (e.g. Extended→wallet withdrawal). */
|
|
42993
|
+
addToWallet(rawUsd) {
|
|
42994
|
+
assert(rawUsd >= 0, "SolveBudget::addToWallet amount must be positive");
|
|
42995
|
+
if (rawUsd === 0) return;
|
|
42996
|
+
if (this.walletBalance) {
|
|
42997
|
+
this._addUsdToTokenBalance(this.walletBalance, rawUsd);
|
|
42998
|
+
}
|
|
42999
|
+
this._recomputeUnusedBalance();
|
|
43000
|
+
logger.debug(`SolveBudget::addToWallet rawUsd=${rawUsd}, walletUsd=${this.walletUsd}, totalUnused=${this.totalUnused}`);
|
|
43001
|
+
}
|
|
43002
|
+
spendVAWallet(rawDesired) {
|
|
43003
|
+
let remaining = Math.max(0, rawDesired);
|
|
42081
43004
|
const vaSpent = this.spendVA(remaining);
|
|
42082
43005
|
remaining -= vaSpent;
|
|
42083
43006
|
const walletSpent = this.spendWallet(remaining);
|
|
42084
43007
|
return vaSpent + walletSpent;
|
|
42085
43008
|
}
|
|
42086
|
-
_updateExtAvailWithdraw(
|
|
42087
|
-
|
|
42088
|
-
|
|
43009
|
+
_updateExtAvailWithdraw(desiredRaw, isSpend) {
|
|
43010
|
+
assert(desiredRaw > 0, "SolveBudget::_updateExtAvailWithdraw amount must be positive");
|
|
43011
|
+
let rawDelta;
|
|
42089
43012
|
if (isSpend) {
|
|
42090
|
-
|
|
42091
|
-
|
|
43013
|
+
const capRaw = this.extendedBalance?.availableForWithdrawal?.toNumber() ?? 0;
|
|
43014
|
+
const useRaw = Math.min(capRaw, desiredRaw);
|
|
43015
|
+
if (useRaw <= CASE_THRESHOLD_USD) return 0;
|
|
43016
|
+
rawDelta = -useRaw;
|
|
43017
|
+
} else {
|
|
43018
|
+
rawDelta = desiredRaw;
|
|
42092
43019
|
}
|
|
42093
|
-
this._extAvailWithdraw += amount;
|
|
42094
|
-
this._totalUnused += amount;
|
|
42095
|
-
this._extAvailTrade += amount;
|
|
42096
43020
|
if (this.extendedBalance) {
|
|
42097
|
-
this.extendedBalance.availableForWithdrawal = safeUsdcWeb3Number(this.extendedBalance.availableForWithdrawal.toNumber() +
|
|
42098
|
-
this.extendedBalance.availableForTrade = safeUsdcWeb3Number(this.extendedBalance.availableForTrade.toNumber() +
|
|
42099
|
-
this.extendedBalance.balance = safeUsdcWeb3Number(this.extendedBalance.balance.toNumber() +
|
|
42100
|
-
this.extendedBalance.equity = safeUsdcWeb3Number(this.extendedBalance.equity.toNumber() +
|
|
43021
|
+
this.extendedBalance.availableForWithdrawal = safeUsdcWeb3Number(this.extendedBalance.availableForWithdrawal.toNumber() + rawDelta);
|
|
43022
|
+
this.extendedBalance.availableForTrade = safeUsdcWeb3Number(this.extendedBalance.availableForTrade.toNumber() + rawDelta);
|
|
43023
|
+
this.extendedBalance.balance = safeUsdcWeb3Number(this.extendedBalance.balance.toNumber() + rawDelta);
|
|
43024
|
+
this.extendedBalance.equity = safeUsdcWeb3Number(this.extendedBalance.equity.toNumber() + rawDelta);
|
|
42101
43025
|
}
|
|
42102
|
-
logger.debug(`SolveBudget::updateExtAvailWithdraw
|
|
42103
|
-
return
|
|
43026
|
+
logger.debug(`SolveBudget::updateExtAvailWithdraw rawDelta=${rawDelta}, extAvailWithdraw=${this.extAvailWithdraw}, totalUnused=${this.totalUnused}`);
|
|
43027
|
+
return rawDelta;
|
|
42104
43028
|
}
|
|
42105
|
-
_updateExtAvailUpnl(
|
|
42106
|
-
|
|
42107
|
-
|
|
43029
|
+
_updateExtAvailUpnl(desiredRaw, isSpend) {
|
|
43030
|
+
assert(desiredRaw > 0, "SolveBudget::_updateExtAvailUpnl amount must be positive");
|
|
43031
|
+
let rawDelta;
|
|
42108
43032
|
if (isSpend) {
|
|
42109
|
-
|
|
42110
|
-
|
|
43033
|
+
const capRaw = this.extendedBalance?.unrealisedPnl?.toNumber() ?? 0;
|
|
43034
|
+
const useRaw = Math.min(capRaw, desiredRaw);
|
|
43035
|
+
if (useRaw <= CASE_THRESHOLD_USD) return 0;
|
|
43036
|
+
rawDelta = -useRaw;
|
|
43037
|
+
} else {
|
|
43038
|
+
rawDelta = desiredRaw;
|
|
42111
43039
|
}
|
|
42112
|
-
this._extAvailUpnl += amount;
|
|
42113
|
-
this._totalUnused += amount;
|
|
42114
43040
|
if (this.extendedBalance) {
|
|
42115
|
-
this.extendedBalance.unrealisedPnl = safeUsdcWeb3Number(this.extendedBalance.unrealisedPnl.toNumber() +
|
|
42116
|
-
this.extendedBalance.balance = safeUsdcWeb3Number(this.extendedBalance.balance.toNumber() +
|
|
42117
|
-
this.extendedBalance.equity = safeUsdcWeb3Number(this.extendedBalance.equity.toNumber() +
|
|
42118
|
-
this.extendedBalance.availableForTrade = safeUsdcWeb3Number(this.extendedBalance.availableForTrade.toNumber() +
|
|
42119
|
-
}
|
|
42120
|
-
logger.debug(`SolveBudget::updateExtAvailUpnl
|
|
42121
|
-
return
|
|
42122
|
-
}
|
|
42123
|
-
spendExtAvailTrade(
|
|
42124
|
-
const used = this._updateExtAvailWithdraw(
|
|
42125
|
-
const usedUpnl = this._updateExtAvailUpnl(
|
|
42126
|
-
logger.debug(`SolveBudget::updateExtAvailTrade
|
|
43041
|
+
this.extendedBalance.unrealisedPnl = safeUsdcWeb3Number(this.extendedBalance.unrealisedPnl.toNumber() + rawDelta);
|
|
43042
|
+
this.extendedBalance.balance = safeUsdcWeb3Number(this.extendedBalance.balance.toNumber() + rawDelta);
|
|
43043
|
+
this.extendedBalance.equity = safeUsdcWeb3Number(this.extendedBalance.equity.toNumber() + rawDelta);
|
|
43044
|
+
this.extendedBalance.availableForTrade = safeUsdcWeb3Number(this.extendedBalance.availableForTrade.toNumber() + rawDelta);
|
|
43045
|
+
}
|
|
43046
|
+
logger.debug(`SolveBudget::updateExtAvailUpnl rawDelta=${rawDelta}, extAvailUpnl=${this.extAvailUpnl}, totalUnused=${this.totalUnused}`);
|
|
43047
|
+
return rawDelta;
|
|
43048
|
+
}
|
|
43049
|
+
spendExtAvailTrade(rawDesired) {
|
|
43050
|
+
const used = this._updateExtAvailWithdraw(rawDesired, true);
|
|
43051
|
+
const usedUpnl = this._updateExtAvailUpnl(rawDesired, true);
|
|
43052
|
+
logger.debug(`SolveBudget::updateExtAvailTrade rawSum=${used + usedUpnl}, extAvailTrade=${this.extAvailTrade}, totalUnused=${this.totalUnused}`);
|
|
42127
43053
|
return used + usedUpnl;
|
|
42128
43054
|
}
|
|
42129
|
-
|
|
42130
|
-
|
|
43055
|
+
// simply reduces available amounts, but maintains equity and balance.
|
|
43056
|
+
spendExtAvailTradeToEquityOnly(rawDesired) {
|
|
43057
|
+
const used = this._updateExtAvailWithdraw(rawDesired, true);
|
|
43058
|
+
const remaining = rawDesired - Math.abs(used);
|
|
43059
|
+
const usedUpnl = remaining > 0 ? this._updateExtAvailUpnl(remaining, true) : 0;
|
|
43060
|
+
if (this.extendedBalance) {
|
|
43061
|
+
const net = Math.abs(used) + Math.abs(usedUpnl);
|
|
43062
|
+
if (net.toFixed(0) != rawDesired.toFixed(0)) {
|
|
43063
|
+
throw new Error(`SolveBudget::spendExtAvailTradeToEquityOnly net=${net} != rawDesired=${rawDesired}`);
|
|
43064
|
+
}
|
|
43065
|
+
this.extendedBalance.equity = safeUsdcWeb3Number(this.extendedBalance.equity.toNumber() + net);
|
|
43066
|
+
this.extendedBalance.balance = safeUsdcWeb3Number(this.extendedBalance.balance.toNumber() + net);
|
|
43067
|
+
}
|
|
43068
|
+
logger.debug(`SolveBudget::updateExtAvailTrade rawSum=${used + usedUpnl}, extAvailTrade=${this.extAvailTrade}, totalUnused=${this.totalUnused}`);
|
|
43069
|
+
return used + usedUpnl;
|
|
43070
|
+
}
|
|
43071
|
+
spendExtAvailWithdraw(rawDesired) {
|
|
43072
|
+
return this._updateExtAvailWithdraw(rawDesired, true);
|
|
43073
|
+
}
|
|
43074
|
+
spendExtAvailUpnl(rawDesired) {
|
|
43075
|
+
return this._updateExtAvailUpnl(rawDesired, true);
|
|
43076
|
+
}
|
|
43077
|
+
/**
|
|
43078
|
+
* Withdraw from Extended **withdrawal bucket only** to operator wallet (planning).
|
|
43079
|
+
* Used when VA must be funded from Extended and withdraw should be exhausted before unrealised PnL.
|
|
43080
|
+
*/
|
|
43081
|
+
spendAvailWithdrawToWallet(rawDesired) {
|
|
43082
|
+
const want = Math.max(0, rawDesired);
|
|
43083
|
+
if (want <= CASE_THRESHOLD_USD) return 0;
|
|
43084
|
+
const rawDelta = this._updateExtAvailWithdraw(want, true);
|
|
43085
|
+
if (rawDelta === 0) return 0;
|
|
43086
|
+
const used = -rawDelta;
|
|
43087
|
+
this.addToWallet(used);
|
|
43088
|
+
return used;
|
|
43089
|
+
}
|
|
43090
|
+
/**
|
|
43091
|
+
* Required Extended equity (USD) for current open positions: total notional ÷ strategy leverage.
|
|
43092
|
+
* Same basis as {@link ExtendedSVKVesuStateManager._classifyLtvExtended} margin check.
|
|
43093
|
+
*/
|
|
43094
|
+
_extendedMarginRequirementUsd() {
|
|
43095
|
+
const lev = calculateExtendedLevergae();
|
|
43096
|
+
if (lev <= 0 || this.extendedPositions.length === 0) return 0;
|
|
43097
|
+
const totalPosUsd = this.extendedPositions.reduce(
|
|
43098
|
+
(s, p) => s + p.valueUsd.toNumber(),
|
|
43099
|
+
0
|
|
43100
|
+
);
|
|
43101
|
+
return totalPosUsd / lev;
|
|
43102
|
+
}
|
|
43103
|
+
/** How much more equity is needed before deposits should increase withdraw / trade availability. */
|
|
43104
|
+
_extendedEquityShortfallUsd() {
|
|
43105
|
+
if (!this.extendedBalance) return 0;
|
|
43106
|
+
const req = this._extendedMarginRequirementUsd();
|
|
43107
|
+
const eq = this.extendedBalance.equity.toNumber();
|
|
43108
|
+
return Math.max(0, req - eq);
|
|
42131
43109
|
}
|
|
42132
|
-
|
|
42133
|
-
|
|
42134
|
-
|
|
43110
|
+
/**
|
|
43111
|
+
* Credits a USDC inflow on Extended. Fills margin shortfall (balance+equity only) first;
|
|
43112
|
+
* any remainder is credited across balance, equity, availableForWithdrawal, and availableForTrade.
|
|
43113
|
+
*/
|
|
43114
|
+
addToExtAvailTrade(rawUsd) {
|
|
43115
|
+
assert(rawUsd >= 0, "SolveBudget::addToExtAvailTrade amount must be non-negative");
|
|
43116
|
+
if (rawUsd <= CASE_THRESHOLD_USD) return;
|
|
43117
|
+
if (!this.extendedBalance) {
|
|
43118
|
+
logger.warn("SolveBudget::addToExtAvailTrade skipped \u2014 no extendedBalance");
|
|
43119
|
+
return;
|
|
43120
|
+
}
|
|
43121
|
+
const shortfall = this._extendedEquityShortfallUsd();
|
|
43122
|
+
const toMargin = Math.min(rawUsd, shortfall);
|
|
43123
|
+
const toLiquid = rawUsd - toMargin;
|
|
43124
|
+
if (toMargin > CASE_THRESHOLD_USD) {
|
|
43125
|
+
const b = this.extendedBalance.balance.toNumber();
|
|
43126
|
+
const e = this.extendedBalance.equity.toNumber();
|
|
43127
|
+
this.extendedBalance.balance = safeUsdcWeb3Number(b + toMargin);
|
|
43128
|
+
this.extendedBalance.equity = safeUsdcWeb3Number(e + toMargin);
|
|
43129
|
+
logger.debug(
|
|
43130
|
+
`SolveBudget::addToExtAvailTrade margin-first rawUsd=${toMargin} (shortfallBefore=${shortfall}, balance=${b + toMargin}, equity=${e + toMargin})`
|
|
43131
|
+
);
|
|
43132
|
+
}
|
|
43133
|
+
if (toLiquid > CASE_THRESHOLD_USD) {
|
|
43134
|
+
this._updateExtAvailWithdraw(toLiquid, false);
|
|
43135
|
+
}
|
|
43136
|
+
logger.debug(
|
|
43137
|
+
`SolveBudget::addToExtAvailTrade total rawUsd=${rawUsd} toLiquid=${toLiquid} extAvailTrade=${this.extAvailTrade}, totalUnused=${this.totalUnused}`
|
|
43138
|
+
);
|
|
42135
43139
|
}
|
|
42136
43140
|
spendVesuBorrowCapacity(desired) {
|
|
42137
|
-
const used = Math.min(this.
|
|
42138
|
-
this._vesuBorrowCapacity -= used;
|
|
42139
|
-
this._totalUnused -= used;
|
|
43141
|
+
const used = Math.min(this.vesuBorrowCapacity, Math.max(0, desired));
|
|
42140
43142
|
let spendsByPool = [];
|
|
42141
43143
|
for (let index = 0; index < this.vesuPerPoolDebtDeltasToBorrow.length; index++) {
|
|
42142
43144
|
const d = this.vesuPerPoolDebtDeltasToBorrow[index];
|
|
@@ -42147,13 +43149,12 @@ var SolveBudget = class {
|
|
|
42147
43149
|
this.vesuPoolStates[index].debtUsdValue = this.vesuPoolStates[index].debtAmount.toNumber() * this.vesuPoolStates[index].debtPrice;
|
|
42148
43150
|
spendsByPool.push({ poolId: this.vesuPoolStates[index].poolId, amount: safeUsdcWeb3Number(borrowed), collateralToken: this.vesuPoolStates[index].collateralToken, debtToken: this.vesuPoolStates[index].debtToken });
|
|
42149
43151
|
}
|
|
42150
|
-
logger.debug(`SolveBudget::spendVesuBorrowCapacity used=${used}, vesuBorrowCapacity=${this.
|
|
43152
|
+
logger.debug(`SolveBudget::spendVesuBorrowCapacity used=${used}, vesuBorrowCapacity=${this.vesuBorrowCapacity}, totalUnused=${this.totalUnused}`);
|
|
42151
43153
|
return { used, spendsByPool };
|
|
42152
43154
|
}
|
|
42153
43155
|
repayVesuBorrowCapacity(desired) {
|
|
42154
43156
|
assert(desired > 0, "SolveBudget::repayVesuBorrowCapacity desired must be positive");
|
|
42155
43157
|
const used = desired;
|
|
42156
|
-
this._vesuBorrowCapacity += used;
|
|
42157
43158
|
const spendsByPool = [];
|
|
42158
43159
|
for (let index = 0; index < this.vesuPerPoolDebtDeltasToBorrow.length; index++) {
|
|
42159
43160
|
const d = this.vesuPerPoolDebtDeltasToBorrow[index];
|
|
@@ -42163,7 +43164,7 @@ var SolveBudget = class {
|
|
|
42163
43164
|
this.vesuPoolStates[index].debtAmount = safeUsdcWeb3Number(this.vesuPoolStates[index].debtAmount.toNumber() - repaid);
|
|
42164
43165
|
spendsByPool.push({ poolId: this.vesuPoolStates[index].poolId, amount: safeUsdcWeb3Number(-repaid), collateralToken: this.vesuPoolStates[index].collateralToken, debtToken: this.vesuPoolStates[index].debtToken });
|
|
42165
43166
|
}
|
|
42166
|
-
logger.debug(`SolveBudget::repayVesuBorrowCapacity used=${used}, vesuBorrowCapacity=${this.
|
|
43167
|
+
logger.debug(`SolveBudget::repayVesuBorrowCapacity used=${used}, vesuBorrowCapacity=${this.vesuBorrowCapacity}, totalUnused=${this.totalUnused}`);
|
|
42167
43168
|
return { used, spendsByPool };
|
|
42168
43169
|
}
|
|
42169
43170
|
// ── State mutation ──────────────────────────────────────────────────
|
|
@@ -42185,13 +43186,21 @@ var SolveBudget = class {
|
|
|
42185
43186
|
pool.debtUsdValue = pool.debtAmount.toNumber() * pool.debtPrice;
|
|
42186
43187
|
const vesuPerPoolDebtDeltasToBorrow = this._computeperPoolDebtDeltasToBorrow();
|
|
42187
43188
|
this.vesuPerPoolDebtDeltasToBorrow = vesuPerPoolDebtDeltasToBorrow.map((item) => item.deltaDebt);
|
|
42188
|
-
const sum = this.vesuPerPoolDebtDeltasToBorrow.reduce((a, b) => a.plus(b), new Web3Number(0, USDC_TOKEN_DECIMALS));
|
|
42189
|
-
this._vesuBorrowCapacity = sum.toNumber();
|
|
42190
43189
|
this.shouldVesuRebalance = vesuPerPoolDebtDeltasToBorrow.map((item) => item.shouldRebalance);
|
|
42191
43190
|
}
|
|
42192
|
-
/**
|
|
42193
|
-
|
|
42194
|
-
|
|
43191
|
+
/**
|
|
43192
|
+
* Update Extended position size after a lever route; sync {@link ExtendedPositionState.valueUsd}
|
|
43193
|
+
* and margin buckets (released USD on decrease, locked USD on increase).
|
|
43194
|
+
*
|
|
43195
|
+
* @param collateralPriceUsd BTC collateral price for notional / margin math; if omitted, uses
|
|
43196
|
+
* existing valueUsd / |size| or the first Vesu pool collateral price.
|
|
43197
|
+
*/
|
|
43198
|
+
applyExtendedExposureDelta(instrument, sizeDelta, collateralPriceUsd) {
|
|
43199
|
+
const btcEps = 10 ** -COLLATERAL_PRECISION;
|
|
43200
|
+
const lev = calculateExtendedLevergae();
|
|
43201
|
+
let pos = this.extendedPositions.find((p) => p.instrument === instrument);
|
|
43202
|
+
const oldAbs = pos ? Math.abs(pos.size.toNumber()) : 0;
|
|
43203
|
+
const oldValUsd = pos ? pos.valueUsd.toNumber() : 0;
|
|
42195
43204
|
if (pos) {
|
|
42196
43205
|
pos.size = new Web3Number(pos.size.plus(sizeDelta).toFixed(8), 8);
|
|
42197
43206
|
} else if (sizeDelta.toNumber() !== 0) {
|
|
@@ -42202,6 +43211,56 @@ var SolveBudget = class {
|
|
|
42202
43211
|
valueUsd: new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
42203
43212
|
leverage: "0"
|
|
42204
43213
|
});
|
|
43214
|
+
pos = this.extendedPositions[this.extendedPositions.length - 1];
|
|
43215
|
+
} else {
|
|
43216
|
+
return;
|
|
43217
|
+
}
|
|
43218
|
+
const newAbs = Math.abs(pos.size.toNumber());
|
|
43219
|
+
let price = collateralPriceUsd;
|
|
43220
|
+
if (price === void 0 || price <= 0) {
|
|
43221
|
+
price = oldAbs > btcEps ? oldValUsd / oldAbs : this.vesuPoolStates[0]?.collateralPrice ?? 0;
|
|
43222
|
+
}
|
|
43223
|
+
if (price > 0) {
|
|
43224
|
+
pos.valueUsd = new Web3Number(
|
|
43225
|
+
(newAbs * price).toFixed(USDC_TOKEN_DECIMALS),
|
|
43226
|
+
USDC_TOKEN_DECIMALS
|
|
43227
|
+
);
|
|
43228
|
+
}
|
|
43229
|
+
if (!this.extendedBalance || lev <= 0 || price <= 0) return;
|
|
43230
|
+
const dAbs = newAbs - oldAbs;
|
|
43231
|
+
if (dAbs < -btcEps) {
|
|
43232
|
+
const releasedUsd = -dAbs * price / lev;
|
|
43233
|
+
if (releasedUsd > CASE_THRESHOLD_USD) {
|
|
43234
|
+
this.addToExtAvailTrade(releasedUsd);
|
|
43235
|
+
}
|
|
43236
|
+
} else if (dAbs > btcEps) {
|
|
43237
|
+
const lockedUsd = dAbs * price / lev;
|
|
43238
|
+
if (lockedUsd > CASE_THRESHOLD_USD) {
|
|
43239
|
+
this._lockExtendedMarginUsd(lockedUsd);
|
|
43240
|
+
}
|
|
43241
|
+
}
|
|
43242
|
+
}
|
|
43243
|
+
/** Pull margin for larger Extended exposure from liquid buckets, then balance/equity. */
|
|
43244
|
+
_lockExtendedMarginUsd(lockedUsd) {
|
|
43245
|
+
if (lockedUsd <= CASE_THRESHOLD_USD || !this.extendedBalance) return;
|
|
43246
|
+
let rem = lockedUsd;
|
|
43247
|
+
const uw = Math.min(rem, Math.max(0, this.extendedBalance.availableForWithdrawal.toNumber()));
|
|
43248
|
+
if (uw > 0) {
|
|
43249
|
+
this._updateExtAvailWithdraw(uw, true);
|
|
43250
|
+
rem -= uw;
|
|
43251
|
+
}
|
|
43252
|
+
if (rem > 0) {
|
|
43253
|
+
const uu = Math.min(rem, Math.max(0, this.extendedBalance.unrealisedPnl.toNumber()));
|
|
43254
|
+
if (uu > 0) {
|
|
43255
|
+
this._updateExtAvailUpnl(uu, true);
|
|
43256
|
+
rem -= uu;
|
|
43257
|
+
}
|
|
43258
|
+
}
|
|
43259
|
+
if (rem > 0) {
|
|
43260
|
+
const b = this.extendedBalance.balance.toNumber();
|
|
43261
|
+
const e = this.extendedBalance.equity.toNumber();
|
|
43262
|
+
this.extendedBalance.balance = safeUsdcWeb3Number(b - rem);
|
|
43263
|
+
this.extendedBalance.equity = safeUsdcWeb3Number(e - rem);
|
|
42205
43264
|
}
|
|
42206
43265
|
}
|
|
42207
43266
|
/**
|
|
@@ -42229,6 +43288,23 @@ var SolveBudget = class {
|
|
|
42229
43288
|
return output;
|
|
42230
43289
|
}
|
|
42231
43290
|
};
|
|
43291
|
+
function createSolveBudgetFromRawState(params) {
|
|
43292
|
+
const budget = new SolveBudget({
|
|
43293
|
+
assetToken: params.assetToken,
|
|
43294
|
+
usdcToken: params.usdcToken,
|
|
43295
|
+
unusedBalance: params.unusedBalance,
|
|
43296
|
+
walletBalance: params.walletBalance,
|
|
43297
|
+
vaultAssetBalance: params.vaultAssetBalance,
|
|
43298
|
+
vaultUsdcBalance: params.vaultUsdcBalance,
|
|
43299
|
+
extendedPositions: params.extendedPositions,
|
|
43300
|
+
extendedBalance: params.extendedBalance,
|
|
43301
|
+
vesuPoolStates: params.vesuPoolStates
|
|
43302
|
+
});
|
|
43303
|
+
if (params.limitBalanceBufferFactor && params.limitBalanceBufferFactor > 0) {
|
|
43304
|
+
budget.applyBuffer(params.limitBalanceBufferFactor);
|
|
43305
|
+
}
|
|
43306
|
+
return budget;
|
|
43307
|
+
}
|
|
42232
43308
|
var ExtendedSVKVesuStateManager = class {
|
|
42233
43309
|
constructor(config) {
|
|
42234
43310
|
this._tag = "ExtendedSVKVesuStateManager";
|
|
@@ -42264,7 +43340,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42264
43340
|
vesuAllocationUsd: safeUsdcWeb3Number(0),
|
|
42265
43341
|
extendedAllocationUsd: safeUsdcWeb3Number(0),
|
|
42266
43342
|
bringLiquidityAmount: safeUsdcWeb3Number(0),
|
|
42267
|
-
pendingDeposit:
|
|
43343
|
+
pendingDeposit: safeUsdcWeb3Number(0)
|
|
42268
43344
|
};
|
|
42269
43345
|
this._logSolveResult(result);
|
|
42270
43346
|
return result;
|
|
@@ -42279,30 +43355,44 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42279
43355
|
async _refresh() {
|
|
42280
43356
|
logger.info(`${this._tag}::_refresh starting`);
|
|
42281
43357
|
const [
|
|
42282
|
-
|
|
43358
|
+
vaultAssetBalance,
|
|
43359
|
+
vaultUsdcBalance,
|
|
42283
43360
|
walletBalance,
|
|
42284
43361
|
vesuPoolStates,
|
|
42285
43362
|
extendedBalance,
|
|
42286
43363
|
extendedPositions
|
|
42287
43364
|
] = await Promise.all([
|
|
42288
|
-
this.
|
|
43365
|
+
this._fetchVaultAllocatorAssetBalance(),
|
|
43366
|
+
this._fetchVaultAllocatorUsdcBalanceIfDistinct(),
|
|
42289
43367
|
this._fetchWalletBalances(),
|
|
42290
43368
|
this._fetchAllVesuPoolStates(),
|
|
42291
43369
|
this._fetchExtendedBalance(),
|
|
42292
43370
|
this._fetchExtendedPositions()
|
|
42293
43371
|
]);
|
|
42294
|
-
logger.verbose(
|
|
43372
|
+
logger.verbose(
|
|
43373
|
+
`${this._tag}::_refresh VA asset ${vaultAssetBalance.token.symbol}=$${vaultAssetBalance.usdValue.toFixed(2)}${vaultUsdcBalance ? `, VA USDC=$${vaultUsdcBalance.usdValue.toFixed(2)}` : ""}, wallet=${walletBalance.usdValue}`
|
|
43374
|
+
);
|
|
42295
43375
|
const unusedBalance = this._computeUnusedBalances(
|
|
42296
|
-
|
|
43376
|
+
vaultAssetBalance,
|
|
43377
|
+
vaultUsdcBalance,
|
|
42297
43378
|
walletBalance
|
|
42298
43379
|
);
|
|
42299
|
-
this._budget =
|
|
42300
|
-
|
|
43380
|
+
this._budget = createSolveBudgetFromRawState({
|
|
43381
|
+
assetToken: this._config.assetToken,
|
|
43382
|
+
usdcToken: this._config.usdcToken,
|
|
42301
43383
|
unusedBalance,
|
|
42302
43384
|
walletBalance,
|
|
42303
|
-
|
|
43385
|
+
vaultAssetBalance,
|
|
43386
|
+
vaultUsdcBalance,
|
|
42304
43387
|
extendedPositions,
|
|
42305
|
-
extendedBalance
|
|
43388
|
+
extendedBalance: {
|
|
43389
|
+
availableForTrade: extendedBalance?.availableForTrade || new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
43390
|
+
availableForWithdrawal: extendedBalance?.availableForWithdrawal || new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
43391
|
+
unrealisedPnl: extendedBalance?.unrealisedPnl || new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
43392
|
+
balance: extendedBalance?.balance || new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
43393
|
+
equity: extendedBalance?.equity || new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
43394
|
+
pendingDeposit: extendedBalance?.pendingDeposit || new Web3Number(0, USDC_TOKEN_DECIMALS)
|
|
43395
|
+
},
|
|
42306
43396
|
vesuPoolStates
|
|
42307
43397
|
});
|
|
42308
43398
|
const totalUnusedUsd = unusedBalance.reduce(
|
|
@@ -42314,10 +43404,14 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42314
43404
|
);
|
|
42315
43405
|
}
|
|
42316
43406
|
// todo add communication check with python server of extended. if not working, throw error in solve function.
|
|
43407
|
+
/** True when strategy asset and USDC share one token — VA USDC slot is unused (all in asset balance). */
|
|
43408
|
+
_vaultAssetAndUsdcAreSameToken() {
|
|
43409
|
+
return this._config.assetToken.address.eq(this._config.usdcToken.address);
|
|
43410
|
+
}
|
|
42317
43411
|
/**
|
|
42318
|
-
* Reads the
|
|
43412
|
+
* Reads the {@link StateManagerConfig.assetToken} balance idle in the vault allocator.
|
|
42319
43413
|
*/
|
|
42320
|
-
async
|
|
43414
|
+
async _fetchVaultAllocatorAssetBalance() {
|
|
42321
43415
|
const { assetToken, vaultAllocator, networkConfig, pricer } = this._config;
|
|
42322
43416
|
const balance = await new ERC20(networkConfig).balanceOf(
|
|
42323
43417
|
assetToken.address,
|
|
@@ -42329,20 +43423,38 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42329
43423
|
return { token: assetToken, amount: balance, usdValue };
|
|
42330
43424
|
}
|
|
42331
43425
|
/**
|
|
42332
|
-
*
|
|
42333
|
-
*
|
|
42334
|
-
|
|
42335
|
-
|
|
42336
|
-
|
|
42337
|
-
|
|
43426
|
+
* Reads {@link StateManagerConfig.usdcToken} in the vault allocator when it differs from
|
|
43427
|
+
* {@link StateManagerConfig.assetToken}. Otherwise returns null (treat VA USDC as 0; stablecoin is only under asset).
|
|
43428
|
+
*/
|
|
43429
|
+
async _fetchVaultAllocatorUsdcBalanceIfDistinct() {
|
|
43430
|
+
if (this._vaultAssetAndUsdcAreSameToken()) return null;
|
|
43431
|
+
const { usdcToken, vaultAllocator, networkConfig, pricer } = this._config;
|
|
43432
|
+
const balance = await new ERC20(networkConfig).balanceOf(
|
|
43433
|
+
usdcToken.address,
|
|
43434
|
+
vaultAllocator,
|
|
43435
|
+
usdcToken.decimals
|
|
43436
|
+
);
|
|
43437
|
+
const tokenPrice = await pricer.getPrice(
|
|
43438
|
+
usdcToken.priceProxySymbol || usdcToken.symbol
|
|
43439
|
+
);
|
|
43440
|
+
const usdValue = Number(balance.toFixed(usdcToken.decimals)) * tokenPrice.price;
|
|
43441
|
+
return { token: usdcToken, amount: balance, usdValue };
|
|
43442
|
+
}
|
|
43443
|
+
/**
|
|
43444
|
+
* Merges vault-allocator asset, optional vault-allocator USDC, and operator wallet
|
|
43445
|
+
* balances into entries keyed by token address.
|
|
42338
43446
|
*/
|
|
42339
|
-
_computeUnusedBalances(
|
|
43447
|
+
_computeUnusedBalances(vaultAssetBalance, vaultUsdcBalance, walletBalance) {
|
|
42340
43448
|
const balanceMap = /* @__PURE__ */ new Map();
|
|
42341
|
-
|
|
42342
|
-
token
|
|
42343
|
-
|
|
42344
|
-
|
|
42345
|
-
|
|
43449
|
+
const put = (tb) => {
|
|
43450
|
+
balanceMap.set(tb.token.address.toString(), {
|
|
43451
|
+
token: tb.token,
|
|
43452
|
+
amount: tb.amount,
|
|
43453
|
+
usdValue: tb.usdValue
|
|
43454
|
+
});
|
|
43455
|
+
};
|
|
43456
|
+
put(vaultAssetBalance);
|
|
43457
|
+
if (vaultUsdcBalance) put(vaultUsdcBalance);
|
|
42346
43458
|
const key = walletBalance.token.address.toString();
|
|
42347
43459
|
const existing = balanceMap.get(key);
|
|
42348
43460
|
if (existing) {
|
|
@@ -42361,30 +43473,29 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42361
43473
|
return Array.from(balanceMap.values());
|
|
42362
43474
|
}
|
|
42363
43475
|
/**
|
|
42364
|
-
* Reads the operator wallet
|
|
42365
|
-
*
|
|
43476
|
+
* Reads the operator wallet balance for {@link StateManagerConfig.usdcToken} only
|
|
43477
|
+
* (wallet stablecoin is always USDC, regardless of strategy {@link StateManagerConfig.assetToken}).
|
|
42366
43478
|
*/
|
|
42367
43479
|
async _fetchWalletBalances() {
|
|
42368
43480
|
const {
|
|
42369
43481
|
networkConfig,
|
|
42370
43482
|
pricer,
|
|
42371
43483
|
walletAddress,
|
|
42372
|
-
|
|
42373
|
-
usdceToken
|
|
43484
|
+
usdcToken
|
|
42374
43485
|
} = this._config;
|
|
42375
43486
|
const erc20 = new ERC20(networkConfig);
|
|
42376
|
-
const [
|
|
43487
|
+
const [balance, tokenPrice] = await Promise.all([
|
|
42377
43488
|
erc20.balanceOf(
|
|
42378
|
-
|
|
43489
|
+
usdcToken.address,
|
|
42379
43490
|
walletAddress,
|
|
42380
|
-
|
|
43491
|
+
usdcToken.decimals
|
|
42381
43492
|
),
|
|
42382
|
-
pricer.getPrice(
|
|
43493
|
+
pricer.getPrice(usdcToken.priceProxySymbol || usdcToken.symbol)
|
|
42383
43494
|
]);
|
|
42384
43495
|
return {
|
|
42385
|
-
token:
|
|
42386
|
-
amount:
|
|
42387
|
-
usdValue: Number(
|
|
43496
|
+
token: usdcToken,
|
|
43497
|
+
amount: balance,
|
|
43498
|
+
usdValue: Number(balance.toFixed(usdcToken.decimals)) * tokenPrice.price
|
|
42388
43499
|
};
|
|
42389
43500
|
}
|
|
42390
43501
|
/**
|
|
@@ -42502,12 +43613,12 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42502
43613
|
* finite, sensible values. Throws on invalid state.
|
|
42503
43614
|
*/
|
|
42504
43615
|
_validateRefreshedState() {
|
|
42505
|
-
if (this._budget.
|
|
43616
|
+
if (this._budget.unusedBalanceRows.length === 0) {
|
|
42506
43617
|
throw new Error(
|
|
42507
43618
|
`${this._tag}: unusedBalance is empty after refresh`
|
|
42508
43619
|
);
|
|
42509
43620
|
}
|
|
42510
|
-
for (const balance of this._budget.
|
|
43621
|
+
for (const balance of this._budget.unusedBalanceRows) {
|
|
42511
43622
|
this._validateTokenBalanceOrThrow(
|
|
42512
43623
|
balance,
|
|
42513
43624
|
`unusedBalance[${balance.token.symbol}]`
|
|
@@ -42527,7 +43638,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42527
43638
|
}
|
|
42528
43639
|
}
|
|
42529
43640
|
_validateVesuPoolPricesOrThrow() {
|
|
42530
|
-
for (const pool of this._budget.
|
|
43641
|
+
for (const pool of this._budget.vesuPools) {
|
|
42531
43642
|
const poolLabel = pool.poolId.shortString();
|
|
42532
43643
|
this._assertPositiveFinite(
|
|
42533
43644
|
pool.collateralPrice,
|
|
@@ -42540,8 +43651,8 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42540
43651
|
}
|
|
42541
43652
|
}
|
|
42542
43653
|
_validateExtendedBalanceOrThrow() {
|
|
42543
|
-
if (!this._budget.
|
|
42544
|
-
const { equity, availableForTrade } = this._budget.
|
|
43654
|
+
if (!this._budget.extendedBalanceView) return;
|
|
43655
|
+
const { equity, availableForTrade } = this._budget.extendedBalanceView;
|
|
42545
43656
|
if (!Number.isFinite(equity.toNumber()) || !Number.isFinite(availableForTrade.toNumber())) {
|
|
42546
43657
|
throw new Error(
|
|
42547
43658
|
`${this._tag}: Extended balance contains non-finite values \u2014 equity: ${equity.toNumber()}, availableForTrade: ${availableForTrade.toNumber()}`
|
|
@@ -42580,18 +43691,26 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42580
43691
|
);
|
|
42581
43692
|
}
|
|
42582
43693
|
/**
|
|
42583
|
-
* Total investable = vault allocator balance + Extended available-for-trade
|
|
42584
|
-
*
|
|
43694
|
+
* Total investable = vault allocator balance + Extended available-for-trade +
|
|
43695
|
+
* buffered unrealised PnL, matching `deposit_cases_extended_vesu.xlsx`:
|
|
43696
|
+
* `(VA + wallet + EXT_WITH_AVL + EXT_UPNL) * (1 − buffer)`.
|
|
43697
|
+
* Positive {@link ExtendedBalanceState.pendingDeposit} stays on the afT leg only (see {@link SolveBudget.extAvailTrade}).
|
|
42585
43698
|
*/
|
|
42586
43699
|
_computeTotalInvestableAmount() {
|
|
42587
|
-
const totalUnusedUsd = this._budget.
|
|
42588
|
-
(acc, b) => acc + b.usdValue,
|
|
42589
|
-
0
|
|
42590
|
-
);
|
|
43700
|
+
const totalUnusedUsd = this._budget.unusedBalancesBufferedUsdSum;
|
|
42591
43701
|
logger.debug(
|
|
42592
|
-
`${this._tag}::_computeTotalInvestableAmount unusedBalances=${JSON.stringify(this._budget.
|
|
43702
|
+
`${this._tag}::_computeTotalInvestableAmount unusedBalances=${JSON.stringify(this._budget.unusedBalanceRows.map((b) => ({ token: b.token.symbol, amount: b.amount.toNumber(), usdValue: b.usdValue })))}`
|
|
43703
|
+
);
|
|
43704
|
+
const extBal = this._budget.extendedBalanceView;
|
|
43705
|
+
const rawAft = extBal?.availableForWithdrawal?.toNumber() ?? 0;
|
|
43706
|
+
const rawUpnl = extBal?.unrealisedPnl?.toNumber() ?? 0;
|
|
43707
|
+
let extBuffered = this._budget.bufferedUsd(rawAft) + this._budget.bufferedUsd(rawUpnl);
|
|
43708
|
+
const pd = extBal?.pendingDeposit?.toNumber() ?? 0;
|
|
43709
|
+
if (pd > 0) extBuffered += pd;
|
|
43710
|
+
const extendedAvailable = new Web3Number(
|
|
43711
|
+
extBuffered.toFixed(USDC_TOKEN_DECIMALS),
|
|
43712
|
+
USDC_TOKEN_DECIMALS
|
|
42593
43713
|
);
|
|
42594
|
-
const extendedAvailable = this._budget.extendedBalance?.availableForTrade ?? new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
42595
43714
|
logger.verbose(`_computeTotalInvestableAmount totalUnusedUsd: ${totalUnusedUsd}, extendedAvailable: ${extendedAvailable.toNumber()}`);
|
|
42596
43715
|
return new Web3Number(totalUnusedUsd.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS).plus(extendedAvailable);
|
|
42597
43716
|
}
|
|
@@ -42622,7 +43741,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42622
43741
|
if (denominator === 0) {
|
|
42623
43742
|
throw new Error(`${this._tag}: Denominator is zero`);
|
|
42624
43743
|
}
|
|
42625
|
-
const collateralPrice = this._budget.
|
|
43744
|
+
const collateralPrice = this._budget.vesuPools[0]?.collateralPrice ?? 0;
|
|
42626
43745
|
const totalVesuExposureUsd = this._totalVesuCollateralUsd().plus(new Web3Number((deltaVesuCollateral * collateralPrice).toFixed(6), USDC_TOKEN_DECIMALS));
|
|
42627
43746
|
const totalExtendedExposureUsd = this._totalExtendedExposureUsd().plus(new Web3Number((deltaExtendedCollateral * collateralPrice).toFixed(6), USDC_TOKEN_DECIMALS));
|
|
42628
43747
|
const numerator = vesuLeverage * distributableAmount.toNumber() + totalVesuExposureUsd.toNumber() - totalExtendedExposureUsd.toNumber();
|
|
@@ -42634,8 +43753,6 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42634
43753
|
distributableAmount.minus(extendedAllocationUsd).toFixed(USDC_TOKEN_DECIMALS),
|
|
42635
43754
|
USDC_TOKEN_DECIMALS
|
|
42636
43755
|
);
|
|
42637
|
-
const perPoolDebtDeltasToBorrow = this._budget.vesuPerPoolDebtDeltasToBorrow;
|
|
42638
|
-
vesuAllocationUsd = vesuAllocationUsd.plus(this._sumDebtDeltas(perPoolDebtDeltasToBorrow).multipliedBy(-1));
|
|
42639
43756
|
let vesuPositionDelta = Number(new Web3Number((vesuAllocationUsd.toNumber() * vesuLeverage / collateralPrice).toFixed(6), 6).toFixedRoundDown(COLLATERAL_PRECISION));
|
|
42640
43757
|
let extendedPositionDelta = Number(new Web3Number((extendedAllocationUsd.toNumber() * extendedLeverage / collateralPrice).toFixed(6), 6).toFixedRoundDown(COLLATERAL_PRECISION));
|
|
42641
43758
|
if (!isRecursive) {
|
|
@@ -42654,14 +43771,17 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42654
43771
|
* by existing collateral value, then converts each share to collateral
|
|
42655
43772
|
* token units.
|
|
42656
43773
|
*/
|
|
42657
|
-
_computePerPoolCollateralDeltas(vesuAllocationUsd
|
|
43774
|
+
_computePerPoolCollateralDeltas(vesuAllocationUsd) {
|
|
42658
43775
|
const vesuLeverage = calculateVesuLeverage();
|
|
42659
|
-
const availableVesuCollateralAllocationUsd = vesuAllocationUsd
|
|
43776
|
+
const availableVesuCollateralAllocationUsd = vesuAllocationUsd;
|
|
42660
43777
|
const postLeverageAllocationUsd = availableVesuCollateralAllocationUsd.multipliedBy(vesuLeverage);
|
|
42661
43778
|
const totalCollateralExisting = this._totalVesuCollateral();
|
|
42662
|
-
return this._budget.
|
|
43779
|
+
return this._budget.vesuPools.map((pool, index) => {
|
|
42663
43780
|
const _postLeverageAllocation = postLeverageAllocationUsd.dividedBy(pool.collateralPrice);
|
|
42664
|
-
const postLeverageAllocation = new Web3Number(
|
|
43781
|
+
const postLeverageAllocation = new Web3Number(
|
|
43782
|
+
_postLeverageAllocation.plus(totalCollateralExisting).toFixedRoundDown(COLLATERAL_PRECISION),
|
|
43783
|
+
pool.collateralToken.decimals
|
|
43784
|
+
).minus(totalCollateralExisting);
|
|
42665
43785
|
const _poolCollateralDelta = this._computePoolCollateralShare(
|
|
42666
43786
|
pool,
|
|
42667
43787
|
totalCollateralExisting,
|
|
@@ -42671,12 +43791,12 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42671
43791
|
_poolCollateralDelta.toFixed(COLLATERAL_PRECISION),
|
|
42672
43792
|
pool.collateralToken.decimals
|
|
42673
43793
|
);
|
|
42674
|
-
const newDebt =
|
|
43794
|
+
const newDebt = postLeverageAllocation.multipliedBy(pool.collateralPrice).minus(availableVesuCollateralAllocationUsd).dividedBy(pool.debtPrice);
|
|
42675
43795
|
return {
|
|
42676
43796
|
poolId: pool.poolId,
|
|
42677
43797
|
collateralToken: pool.collateralToken,
|
|
42678
43798
|
debtToken: pool.debtToken,
|
|
42679
|
-
debtDelta:
|
|
43799
|
+
debtDelta: newDebt,
|
|
42680
43800
|
collateralDelta: poolCollateralDelta,
|
|
42681
43801
|
collateralPrice: pool.collateralPrice,
|
|
42682
43802
|
debtPrice: pool.debtPrice
|
|
@@ -42689,7 +43809,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42689
43809
|
* Multi-pool cases split proportionally by current collateral USD value.
|
|
42690
43810
|
*/
|
|
42691
43811
|
_computePoolCollateralShare(pool, totalCollateral, totalVesuAllocation) {
|
|
42692
|
-
const isSinglePoolOrZeroTotal = this._budget.
|
|
43812
|
+
const isSinglePoolOrZeroTotal = this._budget.vesuPools.length === 1 || totalCollateral.toNumber() === 0;
|
|
42693
43813
|
if (isSinglePoolOrZeroTotal) return totalVesuAllocation;
|
|
42694
43814
|
const poolWeight = pool.collateralAmount.dividedBy(totalCollateral);
|
|
42695
43815
|
return new Web3Number(
|
|
@@ -42726,8 +43846,8 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42726
43846
|
*/
|
|
42727
43847
|
_computeTargetExtendedExposure(vesuDeltas) {
|
|
42728
43848
|
let totalExposureCollateral = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
42729
|
-
for (let i = 0; i < this._budget.
|
|
42730
|
-
const pool = this._budget.
|
|
43849
|
+
for (let i = 0; i < this._budget.vesuPools.length; i++) {
|
|
43850
|
+
const pool = this._budget.vesuPools[i];
|
|
42731
43851
|
const delta = vesuDeltas[i];
|
|
42732
43852
|
logger.debug(
|
|
42733
43853
|
`${this._tag}::_computeTargetExtendedExposure poolId=${pool.poolId.toString()}, collateralAmount=${pool.collateralAmount.toNumber()}, collateralDelta=${delta.collateralDelta.toNumber()}`
|
|
@@ -42745,7 +43865,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42745
43865
|
);
|
|
42746
43866
|
}
|
|
42747
43867
|
_hasNoExtendedPositions() {
|
|
42748
|
-
return this._budget.
|
|
43868
|
+
return this._budget.extendedPositionsView.length === 0;
|
|
42749
43869
|
}
|
|
42750
43870
|
/**
|
|
42751
43871
|
* Creates a single-element delta array for the default instrument
|
|
@@ -42756,7 +43876,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42756
43876
|
{
|
|
42757
43877
|
instrument: this._config.extendedAdapter.config.extendedMarketName,
|
|
42758
43878
|
delta: new Web3Number(
|
|
42759
|
-
delta.
|
|
43879
|
+
delta.toFixedRoundDown(COLLATERAL_PRECISION),
|
|
42760
43880
|
USDC_TOKEN_DECIMALS
|
|
42761
43881
|
)
|
|
42762
43882
|
}
|
|
@@ -42768,7 +43888,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42768
43888
|
*/
|
|
42769
43889
|
_distributeExposureDeltaAcrossPositions(totalDelta) {
|
|
42770
43890
|
const totalExposure = this._totalExtendedExposure();
|
|
42771
|
-
return this._budget.
|
|
43891
|
+
return this._budget.extendedPositionsView.map((position) => {
|
|
42772
43892
|
const share = this._positionExposureShareFraction(
|
|
42773
43893
|
position,
|
|
42774
43894
|
totalExposure
|
|
@@ -42776,7 +43896,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42776
43896
|
return {
|
|
42777
43897
|
instrument: position.instrument,
|
|
42778
43898
|
delta: new Web3Number(
|
|
42779
|
-
totalDelta.multipliedBy(share).
|
|
43899
|
+
totalDelta.multipliedBy(share).toFixedRoundDown(COLLATERAL_PRECISION),
|
|
42780
43900
|
USDC_TOKEN_DECIMALS
|
|
42781
43901
|
)
|
|
42782
43902
|
};
|
|
@@ -42788,7 +43908,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42788
43908
|
* or when total exposure is zero.
|
|
42789
43909
|
*/
|
|
42790
43910
|
_positionExposureShareFraction(position, totalExposure) {
|
|
42791
|
-
const isSingleOrZero = totalExposure.toNumber() === 0 || this._budget.
|
|
43911
|
+
const isSingleOrZero = totalExposure.toNumber() === 0 || this._budget.extendedPositionsView.length === 1;
|
|
42792
43912
|
if (isSingleOrZero) return 1;
|
|
42793
43913
|
return position.valueUsd.dividedBy(totalExposure).toNumber();
|
|
42794
43914
|
}
|
|
@@ -42800,7 +43920,10 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42800
43920
|
* Positive = need to deposit more, negative = can withdraw excess.
|
|
42801
43921
|
*/
|
|
42802
43922
|
_computeExtendedDepositDelta(extendedAllocationUsd) {
|
|
42803
|
-
const currentAvailableForTrade =
|
|
43923
|
+
const currentAvailableForTrade = new Web3Number(
|
|
43924
|
+
this._budget.extAvailTrade.toFixed(USDC_TOKEN_DECIMALS),
|
|
43925
|
+
USDC_TOKEN_DECIMALS
|
|
43926
|
+
);
|
|
42804
43927
|
return new Web3Number(
|
|
42805
43928
|
extendedAllocationUsd.minus(currentAvailableForTrade).toFixed(USDC_TOKEN_DECIMALS),
|
|
42806
43929
|
USDC_TOKEN_DECIMALS
|
|
@@ -42808,8 +43931,8 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42808
43931
|
}
|
|
42809
43932
|
_computeVesuDepositAmount(vesuDeltas) {
|
|
42810
43933
|
let totalVesuCollateral = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
42811
|
-
for (let i = 0; i < this._budget.
|
|
42812
|
-
const pool = this._budget.
|
|
43934
|
+
for (let i = 0; i < this._budget.vesuPools.length; i++) {
|
|
43935
|
+
const pool = this._budget.vesuPools[i];
|
|
42813
43936
|
const delta = vesuDeltas[i];
|
|
42814
43937
|
totalVesuCollateral = totalVesuCollateral.plus(delta.collateralDelta.multipliedBy(pool.collateralPrice));
|
|
42815
43938
|
totalVesuCollateral = totalVesuCollateral.minus(delta.debtDelta.multipliedBy(pool.debtPrice));
|
|
@@ -42854,13 +43977,17 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42854
43977
|
for (const route of spendsByPool) {
|
|
42855
43978
|
routes.push({ type: "VESU_REPAY" /* VESU_REPAY */, ...route, priority: routes.length });
|
|
42856
43979
|
}
|
|
42857
|
-
this._budget.
|
|
43980
|
+
this._budget.spendVaRawUsd(used);
|
|
42858
43981
|
}
|
|
42859
|
-
_buildVesuBorrowRoutes(totalUsd, routes) {
|
|
43982
|
+
_buildVesuBorrowRoutes(totalUsd, routes, opts) {
|
|
42860
43983
|
let borrowable = this._budget.vesuBorrowCapacity;
|
|
43984
|
+
if (opts?.maxBorrowUsd !== void 0) {
|
|
43985
|
+
borrowable = Math.min(borrowable, Math.max(0, opts.maxBorrowUsd));
|
|
43986
|
+
}
|
|
42861
43987
|
if (totalUsd <= CASE_THRESHOLD_USD) return { routes, remaining: totalUsd };
|
|
42862
43988
|
if (borrowable <= CASE_THRESHOLD_USD) return { routes, remaining: totalUsd };
|
|
42863
|
-
const
|
|
43989
|
+
const borrowTarget = Math.min(totalUsd, borrowable);
|
|
43990
|
+
const { used, spendsByPool } = this._budget.spendVesuBorrowCapacity(borrowTarget);
|
|
42864
43991
|
for (const route of spendsByPool) {
|
|
42865
43992
|
routes.push({ type: "VESU_BORROW" /* VESU_BORROW */, ...route, priority: routes.length });
|
|
42866
43993
|
}
|
|
@@ -42916,9 +44043,9 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42916
44043
|
// });
|
|
42917
44044
|
// }
|
|
42918
44045
|
_getWalletToVARoute(tryAmount, routes) {
|
|
42919
|
-
const
|
|
42920
|
-
if (
|
|
42921
|
-
const walletUsed = this._budget.spendWallet(
|
|
44046
|
+
const usableRaw = Math.min(tryAmount, this._budget.walletUsd);
|
|
44047
|
+
if (usableRaw > CASE_THRESHOLD_USD) {
|
|
44048
|
+
const walletUsed = this._budget.spendWallet(usableRaw);
|
|
42922
44049
|
this._budget.addToVA(walletUsed);
|
|
42923
44050
|
const route = { type: "WALLET_TO_VA" /* WALLET_TO_VA */, amount: safeUsdcWeb3Number(walletUsed), priority: routes.length };
|
|
42924
44051
|
routes.push(route);
|
|
@@ -42927,9 +44054,9 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42927
44054
|
return { routes, remaining: tryAmount };
|
|
42928
44055
|
}
|
|
42929
44056
|
_getWalletToEXTENDEDRoute(tryAmount, routes, shouldAddWaitRoute = true) {
|
|
42930
|
-
const
|
|
42931
|
-
if (
|
|
42932
|
-
const walletUsed = this._budget.spendWallet(
|
|
44057
|
+
const usableRaw = Math.min(tryAmount, this._budget.walletUsd);
|
|
44058
|
+
if (usableRaw > CASE_THRESHOLD_USD) {
|
|
44059
|
+
const walletUsed = this._budget.spendWallet(usableRaw);
|
|
42933
44060
|
this._budget.addToExtAvailTrade(walletUsed);
|
|
42934
44061
|
routes.push({ type: "WALLET_TO_EXTENDED" /* WALLET_TO_EXTENDED */, amount: safeUsdcWeb3Number(walletUsed), priority: routes.length });
|
|
42935
44062
|
if (shouldAddWaitRoute) {
|
|
@@ -42940,9 +44067,9 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42940
44067
|
return { routes, remaining: tryAmount };
|
|
42941
44068
|
}
|
|
42942
44069
|
_getVAToEXTENDEDRoute(tryAmount, routes, shouldAddWaitRoute = true) {
|
|
42943
|
-
const
|
|
42944
|
-
if (
|
|
42945
|
-
const vaUsed = this._budget.spendVA(
|
|
44070
|
+
const usable = Math.min(tryAmount, this._budget.vaUsd);
|
|
44071
|
+
if (usable > CASE_THRESHOLD_USD) {
|
|
44072
|
+
const vaUsed = this._budget.spendVA(usable);
|
|
42946
44073
|
this._budget.addToExtAvailTrade(vaUsed);
|
|
42947
44074
|
const route = { type: "VA_TO_EXTENDED" /* VA_TO_EXTENDED */, amount: safeUsdcWeb3Number(vaUsed), priority: routes.length };
|
|
42948
44075
|
routes.push(route);
|
|
@@ -42955,40 +44082,42 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42955
44082
|
}
|
|
42956
44083
|
_getExtendedToWalletRoute(tryAmount, routes, shouldAddWaitRoute = true) {
|
|
42957
44084
|
if (tryAmount <= CASE_THRESHOLD_USD) return { routes, remaining: tryAmount };
|
|
42958
|
-
|
|
42959
|
-
const
|
|
42960
|
-
|
|
42961
|
-
const
|
|
44085
|
+
const rawCap = this._budget.extAvailWithdraw + this._budget.extAvailUpnl;
|
|
44086
|
+
const rawSpend = Math.min(tryAmount, rawCap);
|
|
44087
|
+
if (rawSpend <= CASE_THRESHOLD_USD) return { routes, remaining: tryAmount };
|
|
44088
|
+
const rawOut = this._budget.spendExtAvailTrade(rawSpend);
|
|
44089
|
+
this._budget.addToWallet(Math.abs(rawOut));
|
|
44090
|
+
const route = { type: "EXTENDED_TO_WALLET" /* EXTENDED_TO_WALLET */, amount: safeUsdcWeb3Number(rawSpend), priority: routes.length };
|
|
42962
44091
|
routes.push(route);
|
|
42963
44092
|
if (shouldAddWaitRoute) {
|
|
42964
44093
|
routes.push({ type: "RETURN_TO_WAIT" /* RETURN_TO_WAIT */, priority: routes.length });
|
|
42965
44094
|
}
|
|
42966
|
-
return { routes, remaining: tryAmount -
|
|
44095
|
+
return { routes, remaining: tryAmount - rawSpend };
|
|
42967
44096
|
}
|
|
42968
44097
|
_getWALLETToVARoute(tryAmount, routes) {
|
|
42969
44098
|
if (tryAmount <= CASE_THRESHOLD_USD) return { routes, remaining: tryAmount };
|
|
42970
|
-
const
|
|
42971
|
-
if (
|
|
42972
|
-
const walletUsed = this._budget.spendWallet(
|
|
44099
|
+
const usableRaw = Math.min(tryAmount, this._budget.walletUsd);
|
|
44100
|
+
if (usableRaw <= CASE_THRESHOLD_USD) return { routes, remaining: tryAmount };
|
|
44101
|
+
const walletUsed = this._budget.spendWallet(usableRaw);
|
|
42973
44102
|
this._budget.addToVA(walletUsed);
|
|
42974
44103
|
const route = { type: "WALLET_TO_VA" /* WALLET_TO_VA */, amount: safeUsdcWeb3Number(walletUsed), priority: routes.length };
|
|
42975
44104
|
routes.push(route);
|
|
42976
44105
|
return { routes, remaining: tryAmount - walletUsed };
|
|
42977
44106
|
}
|
|
42978
44107
|
_getUpnlRoute(tryAmount, routes) {
|
|
42979
|
-
const
|
|
42980
|
-
const
|
|
42981
|
-
if (
|
|
42982
|
-
|
|
42983
|
-
this._budget.addToExtAvailTrade(
|
|
42984
|
-
assert(this._budget.
|
|
44108
|
+
const rawUpnl = this._budget.extAvailUpnl;
|
|
44109
|
+
const usableRaw = Math.min(tryAmount, rawUpnl);
|
|
44110
|
+
if (usableRaw <= 0) return { routes, remaining: tryAmount };
|
|
44111
|
+
this._budget.spendExtAvailUpnl(usableRaw);
|
|
44112
|
+
this._budget.addToExtAvailTrade(usableRaw);
|
|
44113
|
+
assert(this._budget.extendedPositionsView.length == 1, "SolveBudget::_getUpnlRoute: extendedPositions length must be 1");
|
|
42985
44114
|
routes.push({
|
|
42986
44115
|
type: "REALISE_PNL" /* REALISE_PNL */,
|
|
42987
|
-
amount: safeUsdcWeb3Number(
|
|
42988
|
-
instrument: this._budget.
|
|
44116
|
+
amount: safeUsdcWeb3Number(usableRaw),
|
|
44117
|
+
instrument: this._budget.extendedPositionsView[0].instrument,
|
|
42989
44118
|
priority: routes.length
|
|
42990
44119
|
});
|
|
42991
|
-
return { routes, remaining: tryAmount -
|
|
44120
|
+
return { routes, remaining: tryAmount - usableRaw };
|
|
42992
44121
|
}
|
|
42993
44122
|
// ── Sub-classifiers ────────────────────────────────────────────────────
|
|
42994
44123
|
// Each sub-classifier builds routes directly from contextual data.
|
|
@@ -43003,7 +44132,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43003
44132
|
const instrument = this._config.extendedAdapter.config.extendedMarketName ?? "BTC-USD";
|
|
43004
44133
|
const routes = [];
|
|
43005
44134
|
let remaining = withdrawAmount.toNumber();
|
|
43006
|
-
const vaUsed = this._budget.spendVA(
|
|
44135
|
+
const vaUsed = this._budget.spendVA(remaining);
|
|
43007
44136
|
remaining -= vaUsed;
|
|
43008
44137
|
let totalExtUsed = 0;
|
|
43009
44138
|
if (remaining > CASE_THRESHOLD_USD) {
|
|
@@ -43026,48 +44155,90 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43026
44155
|
totalExtUsed = usableWithrawAmount + upnlUsed;
|
|
43027
44156
|
}
|
|
43028
44157
|
if (remaining > CASE_THRESHOLD_USD) {
|
|
43029
|
-
|
|
43030
|
-
|
|
43031
|
-
const
|
|
43032
|
-
|
|
43033
|
-
|
|
43034
|
-
|
|
43035
|
-
|
|
43036
|
-
|
|
44158
|
+
assert(this._budget.vesuPools.length == 1, "SolveBudget::_classifyWithdrawal: vesuPoolStates length must be 1");
|
|
44159
|
+
const vesuAdapter = this._config.vesuAdapters[0];
|
|
44160
|
+
const avgCollPrice = this._budget.vesuPools[0]?.collateralPrice ?? 1;
|
|
44161
|
+
const vesuLeverage = calculateVesuLeverage();
|
|
44162
|
+
const extLeverage = calculateExtendedLevergae();
|
|
44163
|
+
const freedPerBtcVesu = avgCollPrice / vesuLeverage;
|
|
44164
|
+
const freedPerBtcExt = avgCollPrice / extLeverage;
|
|
44165
|
+
const vesuColBtc = this._budget.vesuPools[0].collateralAmount.toNumber();
|
|
44166
|
+
const extPosBtc = this._totalExtendedExposure().toNumber();
|
|
44167
|
+
let stillNeeded = remaining;
|
|
44168
|
+
let vesuBtcDelta = 0;
|
|
44169
|
+
let extBtcDelta = 0;
|
|
44170
|
+
let extFreed = 0;
|
|
44171
|
+
const roundUpBtc = (x) => {
|
|
44172
|
+
const factor = 10 ** COLLATERAL_PRECISION;
|
|
44173
|
+
return Math.ceil(x * factor) / factor;
|
|
44174
|
+
};
|
|
44175
|
+
const diff = vesuColBtc - extPosBtc;
|
|
44176
|
+
let currentVesuBtc = vesuColBtc;
|
|
44177
|
+
let currentExtBtc = extPosBtc;
|
|
44178
|
+
if (Math.abs(diff) > 1e-8) {
|
|
44179
|
+
if (diff > 0) {
|
|
44180
|
+
const btcRaw = stillNeeded / freedPerBtcVesu;
|
|
44181
|
+
const btc = Math.min(roundUpBtc(Math.min(Math.abs(diff), btcRaw, currentVesuBtc)), currentVesuBtc);
|
|
44182
|
+
vesuBtcDelta += btc;
|
|
44183
|
+
stillNeeded -= btc * freedPerBtcVesu;
|
|
44184
|
+
currentVesuBtc -= btc;
|
|
44185
|
+
} else {
|
|
44186
|
+
const btcRaw = stillNeeded / freedPerBtcExt;
|
|
44187
|
+
const btc = Math.min(roundUpBtc(Math.min(Math.abs(diff), btcRaw, currentExtBtc)), currentExtBtc);
|
|
44188
|
+
extBtcDelta += btc;
|
|
44189
|
+
extFreed += btc * freedPerBtcExt;
|
|
44190
|
+
stillNeeded -= btc * freedPerBtcExt;
|
|
44191
|
+
currentExtBtc -= btc;
|
|
44192
|
+
}
|
|
44193
|
+
}
|
|
44194
|
+
if (stillNeeded > CASE_THRESHOLD_USD) {
|
|
44195
|
+
const combinedFreed = freedPerBtcVesu + freedPerBtcExt;
|
|
44196
|
+
const maxBtc = Math.min(currentVesuBtc, currentExtBtc);
|
|
44197
|
+
const btcRaw = stillNeeded / combinedFreed;
|
|
44198
|
+
const btc = Math.min(roundUpBtc(Math.min(btcRaw, maxBtc)), maxBtc);
|
|
44199
|
+
vesuBtcDelta += btc;
|
|
44200
|
+
extBtcDelta += btc;
|
|
44201
|
+
extFreed += btc * freedPerBtcExt;
|
|
44202
|
+
}
|
|
44203
|
+
const r6 = (n) => Number(n.toFixed(6));
|
|
44204
|
+
if (vesuBtcDelta > 0) {
|
|
44205
|
+
const totalVesuBtcSigned = -vesuBtcDelta;
|
|
44206
|
+
const targetLtv = 1 - 1 / vesuLeverage;
|
|
44207
|
+
const debtDelta = r6(totalVesuBtcSigned * avgCollPrice * targetLtv);
|
|
44208
|
+
const marginBtc = 0;
|
|
44209
|
+
const swappedBtc = Number(vesuBtcDelta.toFixed(COLLATERAL_PRECISION));
|
|
43037
44210
|
routes.push({
|
|
43038
44211
|
type: "VESU_MULTIPLY_DECREASE_LEVER" /* VESU_MULTIPLY_DECREASE_LEVER */,
|
|
43039
44212
|
poolId: vesuAdapter.config.poolId,
|
|
43040
44213
|
collateralToken: vesuAdapter.config.collateral,
|
|
43041
|
-
marginAmount:
|
|
43042
|
-
swappedCollateralAmount: new Web3Number(
|
|
44214
|
+
marginAmount: new Web3Number(marginBtc.toFixed(COLLATERAL_PRECISION), vesuAdapter.config.collateral.decimals),
|
|
44215
|
+
swappedCollateralAmount: new Web3Number(swappedBtc.toFixed(COLLATERAL_PRECISION), vesuAdapter.config.collateral.decimals),
|
|
43043
44216
|
debtToken: vesuAdapter.config.debt,
|
|
43044
44217
|
debtAmount: new Web3Number(debtDelta, USDC_TOKEN_DECIMALS),
|
|
43045
44218
|
priority: routes.length
|
|
43046
44219
|
});
|
|
43047
|
-
this._budget.applyVesuDelta(
|
|
43048
|
-
|
|
43049
|
-
|
|
43050
|
-
|
|
43051
|
-
|
|
43052
|
-
|
|
43053
|
-
|
|
43054
|
-
|
|
43055
|
-
toToken: vesuAdapter.config.debt.symbol,
|
|
43056
|
-
priority: routes.length
|
|
43057
|
-
});
|
|
43058
|
-
this._budget.addToVA(vesuAllocationUsd.abs().toNumber());
|
|
43059
|
-
}
|
|
44220
|
+
this._budget.applyVesuDelta(
|
|
44221
|
+
vesuAdapter.config.poolId,
|
|
44222
|
+
vesuAdapter.config.collateral,
|
|
44223
|
+
vesuAdapter.config.debt,
|
|
44224
|
+
new Web3Number(r6(totalVesuBtcSigned), USDC_TOKEN_DECIMALS),
|
|
44225
|
+
new Web3Number(debtDelta, USDC_TOKEN_DECIMALS)
|
|
44226
|
+
);
|
|
44227
|
+
this._budget.addToVA(vesuBtcDelta * freedPerBtcVesu);
|
|
43060
44228
|
}
|
|
43061
|
-
if (
|
|
44229
|
+
if (extBtcDelta > 0) {
|
|
43062
44230
|
routes.push({
|
|
43063
44231
|
type: "EXTENDED_DECREASE_LEVER" /* EXTENDED_DECREASE_LEVER */,
|
|
43064
|
-
amount: safeUsdcWeb3Number(
|
|
44232
|
+
amount: safeUsdcWeb3Number(-r6(extBtcDelta)),
|
|
43065
44233
|
instrument,
|
|
43066
44234
|
priority: routes.length
|
|
43067
44235
|
});
|
|
43068
|
-
this._budget.applyExtendedExposureDelta(
|
|
43069
|
-
|
|
43070
|
-
|
|
44236
|
+
this._budget.applyExtendedExposureDelta(
|
|
44237
|
+
instrument,
|
|
44238
|
+
safeUsdcWeb3Number(-r6(extBtcDelta)),
|
|
44239
|
+
avgCollPrice
|
|
44240
|
+
);
|
|
44241
|
+
totalExtUsed += extFreed;
|
|
43071
44242
|
}
|
|
43072
44243
|
}
|
|
43073
44244
|
if (totalExtUsed > CASE_THRESHOLD_USD) {
|
|
@@ -43100,56 +44271,231 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43100
44271
|
*
|
|
43101
44272
|
* Design: accumulate all ext-to-wallet moves, add transfer routes at the end (principle #3).
|
|
43102
44273
|
*/
|
|
43103
|
-
|
|
43104
|
-
|
|
43105
|
-
|
|
43106
|
-
|
|
44274
|
+
/**
|
|
44275
|
+
* Unified LTV classifier. Computes both Vesu repay and Extended margin needs,
|
|
44276
|
+
* then builds all routes in a single pass with no duplicate transfers.
|
|
44277
|
+
*
|
|
44278
|
+
* Vesu repay priority: VA > Wallet > ExtAvl > ExtUpnl
|
|
44279
|
+
* Extended margin priority: Wallet > VA > VesuBorrow
|
|
44280
|
+
* Shared sources consumed by Vesu first (higher priority).
|
|
44281
|
+
*/
|
|
44282
|
+
_classifyLTV() {
|
|
44283
|
+
assert(this._budget.vesuPools.length === 1, `${this._tag}::_classifyLTV expects exactly one Vesu pool`);
|
|
44284
|
+
const d = rebalance(this._ltvRebalanceInputsFromBudget());
|
|
44285
|
+
if (this._isLtvRebalanceNoop(d)) return [];
|
|
44286
|
+
logger.info(
|
|
44287
|
+
`${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}`
|
|
43107
44288
|
);
|
|
43108
|
-
|
|
43109
|
-
|
|
43110
|
-
|
|
43111
|
-
const needed = Math.abs(debtDeltaSum);
|
|
43112
|
-
const routes = [];
|
|
43113
|
-
let remaining = needed;
|
|
43114
|
-
let totalExtUsed = 0;
|
|
43115
|
-
let caseId = "LTV_VESU_HIGH_USE_VA_OR_WALLET" /* LTV_VESU_HIGH_USE_VA_OR_WALLET */;
|
|
43116
|
-
const vaUsed = this._budget.spendVA(Math.min(this._budget.vaUsd, remaining));
|
|
43117
|
-
remaining -= vaUsed;
|
|
43118
|
-
if (remaining > CASE_THRESHOLD_USD) {
|
|
43119
|
-
const { remaining: walletToVaRemaining } = this._getWALLETToVARoute(remaining, routes);
|
|
43120
|
-
remaining = walletToVaRemaining;
|
|
43121
|
-
}
|
|
43122
|
-
if (remaining > CASE_THRESHOLD_USD) {
|
|
43123
|
-
const usableWithdrawAmount = Math.min(remaining, this._budget.extAvailWithdraw);
|
|
43124
|
-
remaining -= usableWithdrawAmount;
|
|
43125
|
-
let upnlUsed = 0;
|
|
43126
|
-
if (remaining > CASE_THRESHOLD_USD) {
|
|
43127
|
-
const { remaining: upnlRemaining } = this._getUpnlRoute(remaining, routes);
|
|
43128
|
-
upnlUsed = remaining - upnlRemaining;
|
|
43129
|
-
remaining = upnlRemaining;
|
|
43130
|
-
caseId = "LTV_EXTENDED_PROFITABLE_REALIZE" /* LTV_EXTENDED_PROFITABLE_REALIZE */;
|
|
43131
|
-
} else {
|
|
43132
|
-
caseId = "LTV_EXTENDED_PROFITABLE_AVAILABLE" /* LTV_EXTENDED_PROFITABLE_AVAILABLE */;
|
|
43133
|
-
}
|
|
43134
|
-
totalExtUsed = usableWithdrawAmount + upnlUsed;
|
|
43135
|
-
}
|
|
43136
|
-
if (remaining > CASE_THRESHOLD_USD) {
|
|
43137
|
-
throw new Error(`${this._tag}: Insufficient funds to cover margin needs`);
|
|
43138
|
-
}
|
|
43139
|
-
if (totalExtUsed > CASE_THRESHOLD_USD) {
|
|
43140
|
-
this._getExtendedToWalletRoute(totalExtUsed, routes);
|
|
43141
|
-
this._getWALLETToVARoute(totalExtUsed, routes);
|
|
43142
|
-
}
|
|
43143
|
-
this._buildVesuRepayRoutes(needed - remaining, routes);
|
|
44289
|
+
const routes = this._buildLtvRoutesFromRebalanceDeltas(d);
|
|
44290
|
+
if (routes.length === 0) return [];
|
|
44291
|
+
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);
|
|
43144
44292
|
routes.forEach((r, i) => {
|
|
43145
44293
|
r.priority = i;
|
|
43146
44294
|
});
|
|
43147
44295
|
return [{
|
|
43148
|
-
case: CASE_DEFINITIONS[
|
|
43149
|
-
additionalArgs: { amount: safeUsdcWeb3Number(
|
|
44296
|
+
case: CASE_DEFINITIONS["MANAGE_LTV" /* MANAGE_LTV */],
|
|
44297
|
+
additionalArgs: { amount: safeUsdcWeb3Number(amountUsd) },
|
|
43150
44298
|
routes
|
|
43151
44299
|
}];
|
|
43152
44300
|
}
|
|
44301
|
+
_ltvRebalanceInputsFromBudget() {
|
|
44302
|
+
const pool = this._budget.vesuPools[0];
|
|
44303
|
+
const instrument = this._config.extendedAdapter.config.extendedMarketName ?? "BTC-USD";
|
|
44304
|
+
const extPosBtc = this._budget.extendedPositionsView.filter((p) => p.instrument === instrument).reduce((s, p) => s + Math.abs(p.size.toNumber()), 0);
|
|
44305
|
+
const targetHF = VesuConfig.maxLtv / VesuConfig.targetLtv;
|
|
44306
|
+
return {
|
|
44307
|
+
ext: {
|
|
44308
|
+
positionBtc: extPosBtc,
|
|
44309
|
+
equity: this._budget.extendedBalanceView?.equity?.toNumber() ?? 0,
|
|
44310
|
+
avlWithdraw: this._budget.extAvailWithdraw,
|
|
44311
|
+
upnl: this._budget.extAvailUpnl,
|
|
44312
|
+
leverage: calculateExtendedLevergae()
|
|
44313
|
+
},
|
|
44314
|
+
vesu: {
|
|
44315
|
+
positionBtc: pool.collateralAmount.toNumber(),
|
|
44316
|
+
debt: pool.debtAmount.toNumber(),
|
|
44317
|
+
debtPrice: pool.debtPrice,
|
|
44318
|
+
maxLTV: VesuConfig.maxLtv,
|
|
44319
|
+
targetHF
|
|
44320
|
+
},
|
|
44321
|
+
btcPrice: pool.collateralPrice,
|
|
44322
|
+
funding: {
|
|
44323
|
+
vaUsd: this._budget.vaUsd,
|
|
44324
|
+
walletUsd: this._budget.walletUsd,
|
|
44325
|
+
vesuBorrowCapacity: this._budget.vesuBorrowCapacity,
|
|
44326
|
+
extAvlWithdraw: this._budget.extAvailWithdraw,
|
|
44327
|
+
extUpnl: this._budget.extAvailUpnl
|
|
44328
|
+
},
|
|
44329
|
+
config: {
|
|
44330
|
+
positionPrecision: COLLATERAL_PRECISION,
|
|
44331
|
+
hfBuffer: 0.05
|
|
44332
|
+
}
|
|
44333
|
+
};
|
|
44334
|
+
}
|
|
44335
|
+
_isLtvRebalanceNoop(d) {
|
|
44336
|
+
const btcEps = 10 ** -COLLATERAL_PRECISION;
|
|
44337
|
+
const usdEps = CASE_THRESHOLD_USD;
|
|
44338
|
+
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;
|
|
44339
|
+
}
|
|
44340
|
+
/**
|
|
44341
|
+
* Turn pure rebalance() deltas into execution routes.
|
|
44342
|
+
* Order: Vesu multiply (decrease/increase) → Extended lever → aggregated transfers
|
|
44343
|
+
* (REALISE_PNL, EXTENDED_TO_WALLET + WAIT, WALLET_TO_VA, VESU_BORROW, VESU_REPAY, VA_TO_EXTENDED).
|
|
44344
|
+
*/
|
|
44345
|
+
_buildLtvRoutesFromRebalanceDeltas(d) {
|
|
44346
|
+
const routes = [];
|
|
44347
|
+
const pool = this._budget.vesuPools[0];
|
|
44348
|
+
const vesuAdapter = this._config.vesuAdapters[0];
|
|
44349
|
+
const instrument = this._config.extendedAdapter.config.extendedMarketName ?? "BTC-USD";
|
|
44350
|
+
const price = pool.collateralPrice;
|
|
44351
|
+
const debtPrice = pool.debtPrice;
|
|
44352
|
+
const targetLtv = VesuConfig.targetLtv;
|
|
44353
|
+
const btcEps = 10 ** -COLLATERAL_PRECISION;
|
|
44354
|
+
let multiplyDebtRepayUsd = 0;
|
|
44355
|
+
if (d.dVesuPosition < -btcEps) {
|
|
44356
|
+
const xBtc = -d.dVesuPosition;
|
|
44357
|
+
const transferUsdFromVesu = Math.max(0, d.dTransferVesuToExt);
|
|
44358
|
+
let marginBtc = 0;
|
|
44359
|
+
let swappedBtc = Number(xBtc.toFixed(COLLATERAL_PRECISION));
|
|
44360
|
+
if (transferUsdFromVesu > CASE_THRESHOLD_USD && price > 0) {
|
|
44361
|
+
const marginCapFromTransfer = transferUsdFromVesu / price;
|
|
44362
|
+
marginBtc = Number(
|
|
44363
|
+
Math.min(xBtc, marginCapFromTransfer).toFixed(COLLATERAL_PRECISION)
|
|
44364
|
+
);
|
|
44365
|
+
swappedBtc = Number((xBtc - marginBtc).toFixed(COLLATERAL_PRECISION));
|
|
44366
|
+
}
|
|
44367
|
+
const swapLegMaxRepayUsd = swappedBtc * price * debtPrice;
|
|
44368
|
+
const debtUsdFallback = swappedBtc * price * targetLtv;
|
|
44369
|
+
let debtTokenDelta;
|
|
44370
|
+
if (d.dVesuDebt < 0) {
|
|
44371
|
+
const needRepayUsd = -d.dVesuDebt * debtPrice;
|
|
44372
|
+
const multiplyRepayUsd = Math.min(needRepayUsd, swapLegMaxRepayUsd);
|
|
44373
|
+
debtTokenDelta = -(multiplyRepayUsd / debtPrice);
|
|
44374
|
+
} else {
|
|
44375
|
+
debtTokenDelta = -debtUsdFallback;
|
|
44376
|
+
}
|
|
44377
|
+
const debtAmtW3 = new Web3Number(debtTokenDelta.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS);
|
|
44378
|
+
multiplyDebtRepayUsd = Math.abs(debtTokenDelta) * debtPrice;
|
|
44379
|
+
routes.push({
|
|
44380
|
+
type: "VESU_MULTIPLY_DECREASE_LEVER" /* VESU_MULTIPLY_DECREASE_LEVER */,
|
|
44381
|
+
poolId: vesuAdapter.config.poolId,
|
|
44382
|
+
collateralToken: vesuAdapter.config.collateral,
|
|
44383
|
+
marginAmount: new Web3Number(marginBtc.toFixed(COLLATERAL_PRECISION), vesuAdapter.config.collateral.decimals),
|
|
44384
|
+
swappedCollateralAmount: new Web3Number(swappedBtc.toFixed(COLLATERAL_PRECISION), vesuAdapter.config.collateral.decimals),
|
|
44385
|
+
debtToken: vesuAdapter.config.debt,
|
|
44386
|
+
debtAmount: debtAmtW3,
|
|
44387
|
+
priority: routes.length
|
|
44388
|
+
});
|
|
44389
|
+
this._budget.applyVesuDelta(
|
|
44390
|
+
vesuAdapter.config.poolId,
|
|
44391
|
+
vesuAdapter.config.collateral,
|
|
44392
|
+
vesuAdapter.config.debt,
|
|
44393
|
+
new Web3Number((-xBtc).toFixed(COLLATERAL_PRECISION), vesuAdapter.config.collateral.decimals),
|
|
44394
|
+
debtAmtW3
|
|
44395
|
+
);
|
|
44396
|
+
if (transferUsdFromVesu > CASE_THRESHOLD_USD) {
|
|
44397
|
+
this._budget.addToVA(transferUsdFromVesu);
|
|
44398
|
+
}
|
|
44399
|
+
} else if (d.dVesuPosition > btcEps) {
|
|
44400
|
+
const vesuDepositAmount = new Web3Number(
|
|
44401
|
+
(d.dVesuPosition * price * (1 - targetLtv)).toFixed(USDC_TOKEN_DECIMALS),
|
|
44402
|
+
USDC_TOKEN_DECIMALS
|
|
44403
|
+
);
|
|
44404
|
+
if (vesuDepositAmount.toNumber() > CASE_THRESHOLD_USD) {
|
|
44405
|
+
routes.push({
|
|
44406
|
+
type: "AVNU_DEPOSIT_SWAP" /* AVNU_DEPOSIT_SWAP */,
|
|
44407
|
+
priority: routes.length,
|
|
44408
|
+
fromToken: vesuAdapter.config.collateral.symbol,
|
|
44409
|
+
fromAmount: vesuDepositAmount,
|
|
44410
|
+
toToken: vesuAdapter.config.debt.symbol
|
|
44411
|
+
});
|
|
44412
|
+
}
|
|
44413
|
+
const collateralDelta = new Web3Number(
|
|
44414
|
+
d.dVesuPosition.toFixed(COLLATERAL_PRECISION),
|
|
44415
|
+
vesuAdapter.config.collateral.decimals
|
|
44416
|
+
);
|
|
44417
|
+
const availableBorrowCapacity = this._budget.vesuBorrowCapacity;
|
|
44418
|
+
const externalDepositAmount = vesuDepositAmount.minus(
|
|
44419
|
+
new Web3Number(Math.min(availableBorrowCapacity, vesuDepositAmount.toNumber()).toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS)
|
|
44420
|
+
);
|
|
44421
|
+
const collPx = pool.collateralPrice || 1;
|
|
44422
|
+
const swappedAmount = new Web3Number(
|
|
44423
|
+
(externalDepositAmount.toNumber() * (pool.debtPrice ?? 1) / collPx).toFixed(6),
|
|
44424
|
+
vesuAdapter.config.collateral.decimals
|
|
44425
|
+
);
|
|
44426
|
+
const debtDeltaTokens = new Web3Number(
|
|
44427
|
+
d.dVesuDebt.toFixed(USDC_TOKEN_DECIMALS),
|
|
44428
|
+
USDC_TOKEN_DECIMALS
|
|
44429
|
+
);
|
|
44430
|
+
routes.push({
|
|
44431
|
+
type: "VESU_MULTIPLY_INCREASE_LEVER" /* VESU_MULTIPLY_INCREASE_LEVER */,
|
|
44432
|
+
priority: routes.length,
|
|
44433
|
+
collateralToken: vesuAdapter.config.collateral,
|
|
44434
|
+
debtToken: vesuAdapter.config.debt,
|
|
44435
|
+
marginAmount: swappedAmount,
|
|
44436
|
+
swappedCollateralAmount: collateralDelta.minus(swappedAmount),
|
|
44437
|
+
debtAmount: debtDeltaTokens.plus(new Web3Number(Math.min(availableBorrowCapacity, vesuDepositAmount.toNumber()).toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS)),
|
|
44438
|
+
poolId: vesuAdapter.config.poolId
|
|
44439
|
+
});
|
|
44440
|
+
this._budget.applyVesuDelta(
|
|
44441
|
+
vesuAdapter.config.poolId,
|
|
44442
|
+
vesuAdapter.config.collateral,
|
|
44443
|
+
vesuAdapter.config.debt,
|
|
44444
|
+
collateralDelta,
|
|
44445
|
+
debtDeltaTokens
|
|
44446
|
+
);
|
|
44447
|
+
}
|
|
44448
|
+
if (d.dExtPosition < -btcEps) {
|
|
44449
|
+
const amt = new Web3Number(d.dExtPosition.toFixed(COLLATERAL_PRECISION), 8);
|
|
44450
|
+
routes.push({
|
|
44451
|
+
type: "EXTENDED_DECREASE_LEVER" /* EXTENDED_DECREASE_LEVER */,
|
|
44452
|
+
amount: amt,
|
|
44453
|
+
instrument,
|
|
44454
|
+
priority: routes.length
|
|
44455
|
+
});
|
|
44456
|
+
this._budget.applyExtendedExposureDelta(instrument, amt, price);
|
|
44457
|
+
} else if (d.dExtPosition > btcEps) {
|
|
44458
|
+
const amt = new Web3Number(d.dExtPosition.toFixed(COLLATERAL_PRECISION), 8);
|
|
44459
|
+
routes.push({
|
|
44460
|
+
type: "EXTENDED_INCREASE_LEVER" /* EXTENDED_INCREASE_LEVER */,
|
|
44461
|
+
amount: amt,
|
|
44462
|
+
instrument,
|
|
44463
|
+
priority: routes.length
|
|
44464
|
+
});
|
|
44465
|
+
this._budget.applyExtendedExposureDelta(instrument, amt, price);
|
|
44466
|
+
}
|
|
44467
|
+
const negUpnl = Math.min(0, d.dExtUpnl);
|
|
44468
|
+
const negExtAvl = Math.min(0, d.dExtAvlWithdraw);
|
|
44469
|
+
let hadExtendedOut = false;
|
|
44470
|
+
if (negUpnl < -CASE_THRESHOLD_USD) {
|
|
44471
|
+
this._getUpnlRoute(Math.abs(negUpnl), routes);
|
|
44472
|
+
hadExtendedOut = true;
|
|
44473
|
+
}
|
|
44474
|
+
const extToWalletUsd = (negExtAvl < -CASE_THRESHOLD_USD ? Math.abs(negExtAvl) : 0) + (negUpnl < -CASE_THRESHOLD_USD ? Math.abs(negUpnl) : 0);
|
|
44475
|
+
if (extToWalletUsd > CASE_THRESHOLD_USD) {
|
|
44476
|
+
this._getExtendedToWalletRoute(extToWalletUsd, routes);
|
|
44477
|
+
hadExtendedOut = true;
|
|
44478
|
+
}
|
|
44479
|
+
const walletPull = Math.abs(Math.min(0, d.dWalletUsd));
|
|
44480
|
+
const walletToVaUsd = walletPull + extToWalletUsd;
|
|
44481
|
+
if (walletToVaUsd > CASE_THRESHOLD_USD) {
|
|
44482
|
+
this._getWALLETToVARoute(walletToVaUsd, routes);
|
|
44483
|
+
}
|
|
44484
|
+
if (d.dVesuBorrowCapacity < -CASE_THRESHOLD_USD) {
|
|
44485
|
+
this._buildVesuBorrowRoutes(Math.abs(d.dVesuBorrowCapacity), routes);
|
|
44486
|
+
}
|
|
44487
|
+
const totalDebtRepayUsd = d.dVesuDebt < 0 ? -d.dVesuDebt * debtPrice : 0;
|
|
44488
|
+
const standaloneRepayUsd = Math.max(0, totalDebtRepayUsd - multiplyDebtRepayUsd);
|
|
44489
|
+
if (standaloneRepayUsd > CASE_THRESHOLD_USD) {
|
|
44490
|
+
this._buildVesuRepayRoutes(standaloneRepayUsd, routes);
|
|
44491
|
+
}
|
|
44492
|
+
const posExtEq = Math.max(0, d.dExtAvlWithdraw);
|
|
44493
|
+
const vaToExtUsd = posExtEq > CASE_THRESHOLD_USD ? posExtEq : 0;
|
|
44494
|
+
if (vaToExtUsd > CASE_THRESHOLD_USD) {
|
|
44495
|
+
this._getVAToEXTENDEDRoute(vaToExtUsd, routes, hadExtendedOut);
|
|
44496
|
+
}
|
|
44497
|
+
return routes;
|
|
44498
|
+
}
|
|
43153
44499
|
// ── LTV Vesu route builders ───────────────────────────────────────────
|
|
43154
44500
|
/**
|
|
43155
44501
|
* LTV_EXTENDED_PROFITABLE_AVAILABLE:
|
|
@@ -43226,60 +44572,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43226
44572
|
// routes.forEach((r, i) => { r.priority = i; });
|
|
43227
44573
|
// return routes;
|
|
43228
44574
|
// }
|
|
43229
|
-
|
|
43230
|
-
/**
|
|
43231
|
-
* 2b. LTV Rebalance — Extended side
|
|
43232
|
-
*
|
|
43233
|
-
* Triggered when Extended equity is below the required margin for current positions.
|
|
43234
|
-
* Sources funds to Extended via VA/Wallet or Vesu borrow.
|
|
43235
|
-
*
|
|
43236
|
-
* Priority: 1) VA/Wallet → Extended 2) Vesu borrow → VA → Extended
|
|
43237
|
-
*/
|
|
43238
|
-
_classifyLtvExtended() {
|
|
43239
|
-
const totalExtPosUsd = this._totalExtendedExposureUsd().toNumber();
|
|
43240
|
-
const extEquity = this._budget.extendedBalance?.equity?.toNumber() ?? 0;
|
|
43241
|
-
const lev = calculateExtendedLevergae();
|
|
43242
|
-
const marginNeeded = lev > 0 ? totalExtPosUsd / lev - extEquity : 0;
|
|
43243
|
-
if (marginNeeded <= CASE_THRESHOLD_USD) return [];
|
|
43244
|
-
let caseId = "LTV_EXTENDED_HIGH_USE_VA_OR_WALLET" /* LTV_EXTENDED_HIGH_USE_VA_OR_WALLET */;
|
|
43245
|
-
let remaining = marginNeeded;
|
|
43246
|
-
const routes = [];
|
|
43247
|
-
if (this._budget.vaWalletUsd > CASE_THRESHOLD_USD && remaining > CASE_THRESHOLD_USD) {
|
|
43248
|
-
const use = Math.min(this._budget.vaWalletUsd, remaining);
|
|
43249
|
-
if (this._budget.vaUsd > CASE_THRESHOLD_USD) {
|
|
43250
|
-
const { remaining: vaRem } = this._getVAToEXTENDEDRoute(remaining, routes, false);
|
|
43251
|
-
remaining = vaRem;
|
|
43252
|
-
}
|
|
43253
|
-
if (remaining > CASE_THRESHOLD_USD) {
|
|
43254
|
-
const { remaining: walletRem } = this._getWalletToEXTENDEDRoute(remaining, routes, false);
|
|
43255
|
-
remaining = walletRem;
|
|
43256
|
-
}
|
|
43257
|
-
}
|
|
43258
|
-
if (remaining > CASE_THRESHOLD_USD && this._budget.vesuBorrowCapacity > CASE_THRESHOLD_USD) {
|
|
43259
|
-
const { remaining: borrowRem } = this._buildVesuBorrowRoutes(Math.min(remaining, this._budget.vesuBorrowCapacity), routes);
|
|
43260
|
-
const borrowed = remaining - borrowRem;
|
|
43261
|
-
if (remaining != borrowRem) {
|
|
43262
|
-
const { remaining: vaRem } = this._getVAToEXTENDEDRoute(borrowed, routes, false);
|
|
43263
|
-
}
|
|
43264
|
-
remaining = borrowRem;
|
|
43265
|
-
routes.forEach((r, i) => {
|
|
43266
|
-
r.priority = i;
|
|
43267
|
-
});
|
|
43268
|
-
remaining -= borrowed;
|
|
43269
|
-
caseId = "LTV_VESU_LOW_TO_EXTENDED" /* LTV_VESU_LOW_TO_EXTENDED */;
|
|
43270
|
-
}
|
|
43271
|
-
if (remaining > CASE_THRESHOLD_USD) {
|
|
43272
|
-
throw new Error(`${this._tag}: Insufficient funds to cover margin needs`);
|
|
43273
|
-
}
|
|
43274
|
-
routes.forEach((r, i) => {
|
|
43275
|
-
r.priority = i;
|
|
43276
|
-
});
|
|
43277
|
-
return [{
|
|
43278
|
-
case: CASE_DEFINITIONS[caseId],
|
|
43279
|
-
additionalArgs: { amount: safeUsdcWeb3Number(marginNeeded) },
|
|
43280
|
-
routes
|
|
43281
|
-
}];
|
|
43282
|
-
}
|
|
44575
|
+
// _classifyLtvExtended has been merged into the unified _classifyLTV above.
|
|
43283
44576
|
// ── LTV Extended route builders ───────────────────────────────────────
|
|
43284
44577
|
/**
|
|
43285
44578
|
* LTV_EXTENDED_HIGH_USE_VA_OR_WALLET:
|
|
@@ -43346,6 +44639,62 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43346
44639
|
// return routes;
|
|
43347
44640
|
// }
|
|
43348
44641
|
// ! todo implement max lever amount per execution cycle
|
|
44642
|
+
_rebalanceFunds({
|
|
44643
|
+
extAvlWithdraw,
|
|
44644
|
+
extUpnl,
|
|
44645
|
+
vaUsd,
|
|
44646
|
+
walletUsd,
|
|
44647
|
+
vesuBorrowCapacity,
|
|
44648
|
+
vesuLeverage,
|
|
44649
|
+
extendedLeverage
|
|
44650
|
+
}) {
|
|
44651
|
+
const total = extAvlWithdraw + extUpnl + vaUsd + walletUsd + vesuBorrowCapacity;
|
|
44652
|
+
const extendedTarget = total / (1 + extendedLeverage / vesuLeverage);
|
|
44653
|
+
const extendedInitial = extAvlWithdraw + extUpnl;
|
|
44654
|
+
let delta = extendedTarget - extendedInitial;
|
|
44655
|
+
let dExtAvlWithdraw = 0, dExtUpnl = 0, dVaUsd = 0, dWalletUsd = 0, dVesuBorrowCapacity = 0;
|
|
44656
|
+
if (delta > 0) {
|
|
44657
|
+
let need = delta;
|
|
44658
|
+
const takeWalletUsd = Math.min(walletUsd, need);
|
|
44659
|
+
dWalletUsd -= takeWalletUsd;
|
|
44660
|
+
need -= takeWalletUsd;
|
|
44661
|
+
const takeVaUsd = Math.min(vaUsd, need);
|
|
44662
|
+
dVaUsd -= takeVaUsd;
|
|
44663
|
+
need -= takeVaUsd;
|
|
44664
|
+
const takeVesuBorrowCapacity = Math.min(vesuBorrowCapacity, need);
|
|
44665
|
+
dVesuBorrowCapacity -= takeVesuBorrowCapacity;
|
|
44666
|
+
need -= takeVesuBorrowCapacity;
|
|
44667
|
+
const received = delta - need;
|
|
44668
|
+
const eco1Sum = extAvlWithdraw + extUpnl;
|
|
44669
|
+
if (eco1Sum >= 0) {
|
|
44670
|
+
dExtAvlWithdraw += received;
|
|
44671
|
+
} else {
|
|
44672
|
+
throw new Error(`${this._tag}: Unexpected case`);
|
|
44673
|
+
}
|
|
44674
|
+
if (need > 0) {
|
|
44675
|
+
throw new Error(`${this._tag}: Insufficient funds to cover margin needs`);
|
|
44676
|
+
}
|
|
44677
|
+
} else if (delta < 0) {
|
|
44678
|
+
let need = -delta;
|
|
44679
|
+
const takeExtAvlWithdraw = Math.min(extAvlWithdraw, need);
|
|
44680
|
+
dExtAvlWithdraw -= takeExtAvlWithdraw;
|
|
44681
|
+
need -= takeExtAvlWithdraw;
|
|
44682
|
+
const takeExtUpnl = Math.min(extUpnl, need);
|
|
44683
|
+
dExtUpnl -= takeExtUpnl;
|
|
44684
|
+
need -= takeExtUpnl;
|
|
44685
|
+
const sent = -delta - need;
|
|
44686
|
+
const eco2Sum = vaUsd + walletUsd + vesuBorrowCapacity;
|
|
44687
|
+
if (eco2Sum >= 0) {
|
|
44688
|
+
dWalletUsd += sent;
|
|
44689
|
+
} else {
|
|
44690
|
+
throw new Error(`${this._tag}: Unexpected case`);
|
|
44691
|
+
}
|
|
44692
|
+
if (need > 0) {
|
|
44693
|
+
throw new Error(`${this._tag}: Insufficient funds to cover margin needs`);
|
|
44694
|
+
}
|
|
44695
|
+
}
|
|
44696
|
+
return { dExtAvlWithdraw, dExtUpnl, dVaUsd, dWalletUsd, dVesuBorrowCapacity, isExtendedToVesu: delta < 0 };
|
|
44697
|
+
}
|
|
43349
44698
|
/**
|
|
43350
44699
|
* 3. New Deposits / Excess Funds
|
|
43351
44700
|
*
|
|
@@ -43360,81 +44709,84 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43360
44709
|
* Computes allocation split between Vesu and Extended, then sources
|
|
43361
44710
|
* funds and creates lever-increase routes.
|
|
43362
44711
|
*
|
|
43363
|
-
* Fund flow (
|
|
43364
|
-
*
|
|
43365
|
-
*
|
|
43366
|
-
*
|
|
43367
|
-
*
|
|
44712
|
+
* Fund flow (single pass — avoid VA→Extended then Extended→wallet round-trips):
|
|
44713
|
+
* 1) Treat Vesu borrow headroom that the multiply route will consume as covering
|
|
44714
|
+
* part of the Vesu USDC need (no standalone VESU_BORROW for that slice). Cap
|
|
44715
|
+
* standalone VESU_BORROW→VA→Extended by remaining headroom.
|
|
44716
|
+
* 2) Cover Extended deposit delta: REALISE_PNL first, then withdrawal→avail-trade,
|
|
44717
|
+
* then wallet→Extended, then VA→Extended only up to VA surplus above the USDC
|
|
44718
|
+
* that must remain for Vesu (after step 1), then borrow→VA→Extended.
|
|
44719
|
+
* 3) Cover Vesu VA shortfall: wallet→VA, Extended withdrawal→wallet→VA, REALISE_PNL,
|
|
44720
|
+
* then combined Extended→wallet→VA for the remainder.
|
|
44721
|
+
* 4) RETURN_TO_WAIT when needed; then AVNU + VESU_MULTIPLY + EXTENDED_INCREASE.
|
|
44722
|
+
*/
|
|
44723
|
+
/**
|
|
44724
|
+
* @param skipAvnuDepositSwap Omit AVNU before Vesu multiply when LTV cases already ran this cycle
|
|
44725
|
+
* (matrix tests expect deposit routes without that step).
|
|
43368
44726
|
*/
|
|
43369
|
-
_classifyDeposits(withdrawAmount) {
|
|
44727
|
+
_classifyDeposits(withdrawAmount, skipAvnuDepositSwap = false) {
|
|
43370
44728
|
if (withdrawAmount.toNumber() > CASE_THRESHOLD_USD) return [];
|
|
43371
44729
|
const distributableAmount = this._computeDistributableAmount(
|
|
43372
|
-
this._budget.
|
|
44730
|
+
this._budget.vesuDebtDeltas,
|
|
43373
44731
|
withdrawAmount
|
|
43374
44732
|
);
|
|
43375
44733
|
if (distributableAmount.toNumber() <= CASE_THRESHOLD_USD) return [];
|
|
43376
44734
|
const { vesuAllocationUsd, extendedAllocationUsd } = this._computeAllocationSplit(distributableAmount);
|
|
43377
44735
|
const vesuDeltas = this._computePerPoolCollateralDeltas(
|
|
43378
|
-
vesuAllocationUsd
|
|
43379
|
-
this._budget.vesuPerPoolDebtDeltasToBorrow
|
|
44736
|
+
vesuAllocationUsd
|
|
43380
44737
|
);
|
|
43381
44738
|
const extendedPositionDeltas = this._computeExtendedPositionDeltas(vesuDeltas);
|
|
43382
|
-
const extendedDepositDelta = this._computeExtendedDepositDelta(extendedAllocationUsd);
|
|
43383
44739
|
const vesuDepositAmount = this._computeVesuDepositAmount(vesuDeltas);
|
|
44740
|
+
const vesuLeverage = calculateVesuLeverage();
|
|
44741
|
+
const extendedLeverage = calculateExtendedLevergae();
|
|
44742
|
+
const { dExtAvlWithdraw, dExtUpnl, dVaUsd, dWalletUsd, dVesuBorrowCapacity, isExtendedToVesu } = this._rebalanceFunds({
|
|
44743
|
+
extAvlWithdraw: this._budget.extAvailWithdraw,
|
|
44744
|
+
extUpnl: this._budget.extAvailUpnl,
|
|
44745
|
+
vaUsd: this._budget.vaUsd,
|
|
44746
|
+
walletUsd: this._budget.walletUsd,
|
|
44747
|
+
vesuBorrowCapacity: this._budget.vesuBorrowCapacity,
|
|
44748
|
+
vesuLeverage,
|
|
44749
|
+
extendedLeverage
|
|
44750
|
+
});
|
|
43384
44751
|
const routes = [];
|
|
43385
|
-
|
|
43386
|
-
|
|
43387
|
-
|
|
43388
|
-
if (rem > CASE_THRESHOLD_USD) {
|
|
43389
|
-
const { remaining } = this._getWalletToEXTENDEDRoute(rem, routes, false);
|
|
43390
|
-
if (remaining < rem) needsWait = true;
|
|
43391
|
-
rem = remaining;
|
|
43392
|
-
}
|
|
43393
|
-
if (rem > CASE_THRESHOLD_USD) {
|
|
43394
|
-
const { remaining } = this._getVAToEXTENDEDRoute(rem, routes, false);
|
|
43395
|
-
if (remaining < rem) needsWait = true;
|
|
43396
|
-
rem = remaining;
|
|
43397
|
-
}
|
|
43398
|
-
if (rem > CASE_THRESHOLD_USD && this._budget.vesuBorrowCapacity > CASE_THRESHOLD_USD) {
|
|
43399
|
-
const { remaining: borrowRem } = this._buildVesuBorrowRoutes(rem, routes);
|
|
43400
|
-
const borrowed = rem - borrowRem;
|
|
43401
|
-
if (borrowRem != rem) {
|
|
43402
|
-
this._getVAToEXTENDEDRoute(borrowed, routes, false);
|
|
43403
|
-
needsWait = true;
|
|
43404
|
-
rem = borrowRem;
|
|
43405
|
-
}
|
|
44752
|
+
if (isExtendedToVesu) {
|
|
44753
|
+
if (dExtUpnl < 0) {
|
|
44754
|
+
this._getUpnlRoute(Math.abs(dExtUpnl), routes);
|
|
43406
44755
|
}
|
|
43407
|
-
|
|
43408
|
-
|
|
43409
|
-
|
|
43410
|
-
|
|
43411
|
-
|
|
43412
|
-
|
|
43413
|
-
|
|
43414
|
-
|
|
43415
|
-
|
|
43416
|
-
|
|
43417
|
-
|
|
43418
|
-
|
|
43419
|
-
|
|
43420
|
-
|
|
43421
|
-
|
|
43422
|
-
|
|
43423
|
-
|
|
43424
|
-
|
|
43425
|
-
rem -= extUse;
|
|
43426
|
-
needsWait = false;
|
|
43427
|
-
}
|
|
44756
|
+
if (dExtUpnl < 0 || dExtAvlWithdraw < 0) {
|
|
44757
|
+
const netAmount = (dExtAvlWithdraw < 0 ? Math.abs(dExtAvlWithdraw) : 0) + (dExtUpnl < 0 ? Math.abs(dExtUpnl) : 0);
|
|
44758
|
+
const walletUsd = this._budget.walletUsd;
|
|
44759
|
+
this._getExtendedToWalletRoute(netAmount, routes);
|
|
44760
|
+
this._getWALLETToVARoute(netAmount + walletUsd, routes);
|
|
44761
|
+
}
|
|
44762
|
+
} else {
|
|
44763
|
+
let netDVaUsd = dVaUsd;
|
|
44764
|
+
if (dWalletUsd < 0) {
|
|
44765
|
+
this._getWalletToVARoute(this._budget.walletUsd, routes);
|
|
44766
|
+
netDVaUsd += dWalletUsd;
|
|
44767
|
+
}
|
|
44768
|
+
if (dVesuBorrowCapacity < 0) {
|
|
44769
|
+
this._buildVesuBorrowRoutes(Math.abs(dVesuBorrowCapacity), routes);
|
|
44770
|
+
netDVaUsd += dVesuBorrowCapacity;
|
|
44771
|
+
}
|
|
44772
|
+
if (netDVaUsd < 0) {
|
|
44773
|
+
this._getVAToEXTENDEDRoute(Math.abs(netDVaUsd), routes, true);
|
|
43428
44774
|
}
|
|
43429
|
-
}
|
|
43430
|
-
if (needsWait) {
|
|
43431
|
-
routes.push({ type: "RETURN_TO_WAIT" /* RETURN_TO_WAIT */, priority: routes.length });
|
|
43432
44775
|
}
|
|
43433
44776
|
for (const vesuDelta of vesuDeltas) {
|
|
43434
|
-
if (vesuDepositAmount.toNumber() > CASE_THRESHOLD_USD) {
|
|
44777
|
+
if (!skipAvnuDepositSwap && vesuDepositAmount.toNumber() > CASE_THRESHOLD_USD) {
|
|
44778
|
+
routes.push({
|
|
44779
|
+
type: "AVNU_DEPOSIT_SWAP" /* AVNU_DEPOSIT_SWAP */,
|
|
44780
|
+
priority: routes.length,
|
|
44781
|
+
fromToken: vesuDelta.collateralToken.symbol,
|
|
44782
|
+
fromAmount: vesuDepositAmount,
|
|
44783
|
+
toToken: vesuDelta.debtToken.symbol
|
|
44784
|
+
});
|
|
43435
44785
|
}
|
|
43436
44786
|
if (vesuDelta.collateralDelta.toNumber() > 0) {
|
|
43437
|
-
const
|
|
44787
|
+
const availableBorrowCapacity = this._budget.vesuBorrowCapacity;
|
|
44788
|
+
const externalDepositAmount = vesuDepositAmount.minus(availableBorrowCapacity);
|
|
44789
|
+
const swappedAmount = new Web3Number((externalDepositAmount.toNumber() * vesuDelta.debtPrice / (vesuDelta.collateralPrice ?? 0)).toFixed(6), vesuDelta.collateralToken.decimals);
|
|
43438
44790
|
routes.push({
|
|
43439
44791
|
type: "VESU_MULTIPLY_INCREASE_LEVER" /* VESU_MULTIPLY_INCREASE_LEVER */,
|
|
43440
44792
|
priority: routes.length,
|
|
@@ -43443,7 +44795,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43443
44795
|
marginAmount: swappedAmount,
|
|
43444
44796
|
// should be the swapped amount as per vesu multiply adapter
|
|
43445
44797
|
swappedCollateralAmount: vesuDelta.collateralDelta.minus(swappedAmount),
|
|
43446
|
-
debtAmount: vesuDelta.debtDelta,
|
|
44798
|
+
debtAmount: vesuDelta.debtDelta.plus(availableBorrowCapacity),
|
|
43447
44799
|
poolId: vesuDelta.poolId
|
|
43448
44800
|
});
|
|
43449
44801
|
}
|
|
@@ -43566,8 +44918,13 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43566
44918
|
*/
|
|
43567
44919
|
_buildImbalanceExtExcessShortNoFundsRoutes(exposureDiffBtc) {
|
|
43568
44920
|
const instrument = this._config.extendedAdapter.config.extendedMarketName ?? "BTC-USD";
|
|
43569
|
-
const decDelta = new Web3Number(exposureDiffBtc.
|
|
43570
|
-
this._budget.
|
|
44921
|
+
const decDelta = new Web3Number(Web3Number.fromNumber(exposureDiffBtc, 8).toFixedRoundDown(COLLATERAL_PRECISION), USDC_TOKEN_DECIMALS);
|
|
44922
|
+
const collPx = this._budget.vesuPools[0]?.collateralPrice ?? 1;
|
|
44923
|
+
this._budget.applyExtendedExposureDelta(
|
|
44924
|
+
instrument,
|
|
44925
|
+
new Web3Number(Web3Number.fromNumber(decDelta.negated().toNumber(), 8).toFixedRoundDown(COLLATERAL_PRECISION), USDC_TOKEN_DECIMALS),
|
|
44926
|
+
collPx
|
|
44927
|
+
);
|
|
43571
44928
|
return [{
|
|
43572
44929
|
type: "EXTENDED_DECREASE_LEVER" /* EXTENDED_DECREASE_LEVER */,
|
|
43573
44930
|
amount: decDelta,
|
|
@@ -43633,13 +44990,15 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43633
44990
|
_classifyCases(withdrawAmount) {
|
|
43634
44991
|
this._budget.initBudget();
|
|
43635
44992
|
const withdrawalCases = this._classifyWithdrawal(withdrawAmount);
|
|
43636
|
-
|
|
43637
|
-
const
|
|
43638
|
-
const depositCases = this._classifyDeposits(
|
|
44993
|
+
this._budget.applyBuffer(this._config.limitBalanceBufferFactor);
|
|
44994
|
+
const ltvCases = this._classifyLTV();
|
|
44995
|
+
const depositCases = this._classifyDeposits(
|
|
44996
|
+
withdrawAmount,
|
|
44997
|
+
ltvCases.length > 0
|
|
44998
|
+
);
|
|
43639
44999
|
return [
|
|
43640
45000
|
...withdrawalCases,
|
|
43641
|
-
...
|
|
43642
|
-
...ltvExtendedCases,
|
|
45001
|
+
...ltvCases,
|
|
43643
45002
|
...depositCases
|
|
43644
45003
|
];
|
|
43645
45004
|
}
|
|
@@ -43647,7 +45006,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43647
45006
|
// Private — aggregation helpers
|
|
43648
45007
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
43649
45008
|
_totalVesuCollateral() {
|
|
43650
|
-
return this._budget.
|
|
45009
|
+
return this._budget.vesuPools.reduce(
|
|
43651
45010
|
(acc, pool) => acc.plus(
|
|
43652
45011
|
pool.collateralAmount
|
|
43653
45012
|
),
|
|
@@ -43655,7 +45014,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43655
45014
|
);
|
|
43656
45015
|
}
|
|
43657
45016
|
_totalVesuCollateralUsd() {
|
|
43658
|
-
return this._budget.
|
|
45017
|
+
return this._budget.vesuPools.reduce(
|
|
43659
45018
|
(acc, pool) => acc.plus(
|
|
43660
45019
|
pool.collateralAmount.multipliedBy(pool.collateralPrice)
|
|
43661
45020
|
),
|
|
@@ -43663,13 +45022,13 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43663
45022
|
);
|
|
43664
45023
|
}
|
|
43665
45024
|
_totalExtendedExposure() {
|
|
43666
|
-
return this._budget.
|
|
45025
|
+
return this._budget.extendedPositionsView.reduce(
|
|
43667
45026
|
(acc, position) => acc.plus(position.size),
|
|
43668
45027
|
new Web3Number(0, USDC_TOKEN_DECIMALS)
|
|
43669
45028
|
);
|
|
43670
45029
|
}
|
|
43671
45030
|
_totalExtendedExposureUsd() {
|
|
43672
|
-
return this._budget.
|
|
45031
|
+
return this._budget.extendedPositionsView.reduce(
|
|
43673
45032
|
(acc, position) => acc.plus(position.valueUsd),
|
|
43674
45033
|
new Web3Number(0, USDC_TOKEN_DECIMALS)
|
|
43675
45034
|
);
|
|
@@ -43711,7 +45070,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43711
45070
|
};
|
|
43712
45071
|
|
|
43713
45072
|
// src/strategies/vesu-extended-strategy/services/executionService.ts
|
|
43714
|
-
import { uint256 as
|
|
45073
|
+
import { uint256 as uint25623 } from "starknet";
|
|
43715
45074
|
|
|
43716
45075
|
// src/strategies/vesu-extended-strategy/types/transaction-metadata.ts
|
|
43717
45076
|
var CycleType = /* @__PURE__ */ ((CycleType2) => {
|
|
@@ -43756,11 +45115,10 @@ var _ExecutionService = class _ExecutionService {
|
|
|
43756
45115
|
this._tokenSymbols = StarknetCallParser.buildTokenSymbolLookup([
|
|
43757
45116
|
config.wbtcToken,
|
|
43758
45117
|
config.usdcToken,
|
|
43759
|
-
config.
|
|
43760
|
-
config.
|
|
43761
|
-
config.
|
|
43762
|
-
config.
|
|
43763
|
-
config.vesuAdapter.config.marginToken,
|
|
45118
|
+
config.vesuMultiplyAdapter.config.baseToken,
|
|
45119
|
+
config.vesuMultiplyAdapter.config.collateral,
|
|
45120
|
+
config.vesuMultiplyAdapter.config.debt,
|
|
45121
|
+
config.vesuMultiplyAdapter.config.marginToken,
|
|
43764
45122
|
config.vesuModifyPositionAdapter.config.collateral,
|
|
43765
45123
|
config.vesuModifyPositionAdapter.config.debt,
|
|
43766
45124
|
...avnuTokens
|
|
@@ -43768,19 +45126,18 @@ var _ExecutionService = class _ExecutionService {
|
|
|
43768
45126
|
this._tokenDecimals = StarknetCallParser.buildTokenDecimalsLookup([
|
|
43769
45127
|
config.wbtcToken,
|
|
43770
45128
|
config.usdcToken,
|
|
43771
|
-
config.
|
|
43772
|
-
config.
|
|
43773
|
-
config.
|
|
43774
|
-
config.
|
|
43775
|
-
config.vesuAdapter.config.marginToken,
|
|
45129
|
+
config.vesuMultiplyAdapter.config.baseToken,
|
|
45130
|
+
config.vesuMultiplyAdapter.config.collateral,
|
|
45131
|
+
config.vesuMultiplyAdapter.config.debt,
|
|
45132
|
+
config.vesuMultiplyAdapter.config.marginToken,
|
|
43776
45133
|
config.vesuModifyPositionAdapter.config.collateral,
|
|
43777
45134
|
config.vesuModifyPositionAdapter.config.debt,
|
|
43778
45135
|
...avnuTokens
|
|
43779
45136
|
]);
|
|
43780
45137
|
this._poolNames = StarknetCallParser.buildPoolNameLookup([
|
|
43781
45138
|
{
|
|
43782
|
-
poolId: config.
|
|
43783
|
-
name: `${config.
|
|
45139
|
+
poolId: config.vesuMultiplyAdapter.config.poolId.toBigInt(),
|
|
45140
|
+
name: `${config.vesuMultiplyAdapter.config.collateral.symbol}/${config.vesuMultiplyAdapter.config.debt.symbol}`
|
|
43784
45141
|
},
|
|
43785
45142
|
{
|
|
43786
45143
|
poolId: config.vesuModifyPositionAdapter.config.poolId.toBigInt(),
|
|
@@ -44183,12 +45540,14 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44183
45540
|
*
|
|
44184
45541
|
* For deposit (USDC→BTC): price = sum(USDC sold) / sum(BTC bought)
|
|
44185
45542
|
* For withdraw (BTC→USDC): price = sum(USDC bought) / sum(BTC sold)
|
|
44186
|
-
|
|
45543
|
+
* @returns no-swap means, logic is fine and explicit no swap is needed
|
|
45544
|
+
*/
|
|
44187
45545
|
_getNetExecutionPrice(isDeposit) {
|
|
44188
45546
|
const prices = [
|
|
44189
45547
|
this._config.avnuAdapter.lastSwapPriceInfo,
|
|
44190
|
-
this._config.
|
|
45548
|
+
this._config.vesuMultiplyAdapter.lastSwapPriceInfo
|
|
44191
45549
|
].filter((p) => p !== null);
|
|
45550
|
+
assert(prices.length <= 1, "Only one swap price info is allowed");
|
|
44192
45551
|
if (prices.length === 0) return null;
|
|
44193
45552
|
if (isDeposit) {
|
|
44194
45553
|
const totalUsdc = prices.reduce((s, p) => s + p.fromAmount, 0);
|
|
@@ -44203,7 +45562,7 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44203
45562
|
/** Clears cached swap price info on all adapters to prevent stale data across cycles. */
|
|
44204
45563
|
_clearAdapterPriceInfo() {
|
|
44205
45564
|
this._config.avnuAdapter.lastSwapPriceInfo = null;
|
|
44206
|
-
this._config.
|
|
45565
|
+
this._config.vesuMultiplyAdapter.lastSwapPriceInfo = null;
|
|
44207
45566
|
}
|
|
44208
45567
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
44209
45568
|
// Public API
|
|
@@ -44631,7 +45990,7 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44631
45990
|
}
|
|
44632
45991
|
// ── Transfer routes ─────────────────────────────────────────────────────
|
|
44633
45992
|
/**
|
|
44634
|
-
* WALLET_TO_EXTENDED: Deposit USDC
|
|
45993
|
+
* WALLET_TO_EXTENDED: Deposit USDC from operator wallet directly to Extended.
|
|
44635
45994
|
*
|
|
44636
45995
|
* Builds raw approve + deposit calls (NOT through the manager/merkle system)
|
|
44637
45996
|
* because the wallet interacts with Extended directly, not via vault allocator.
|
|
@@ -44646,13 +46005,13 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44646
46005
|
);
|
|
44647
46006
|
return [];
|
|
44648
46007
|
}
|
|
44649
|
-
const {
|
|
46008
|
+
const { usdcToken, extendedAdapter } = this._config;
|
|
44650
46009
|
const extendedContract = extendedAdapter.config.extendedContract;
|
|
44651
46010
|
const vaultId = extendedAdapter.config.vaultIdExtended;
|
|
44652
|
-
const salt = Math.floor(Math.random() * 10 **
|
|
44653
|
-
const uint256Amount =
|
|
46011
|
+
const salt = Math.floor(Math.random() * 10 ** usdcToken.decimals);
|
|
46012
|
+
const uint256Amount = uint25623.bnToUint256(amount.toWei());
|
|
44654
46013
|
const approveCall = {
|
|
44655
|
-
contractAddress:
|
|
46014
|
+
contractAddress: usdcToken.address.address,
|
|
44656
46015
|
entrypoint: "approve",
|
|
44657
46016
|
calldata: [
|
|
44658
46017
|
extendedContract.address,
|
|
@@ -44675,7 +46034,7 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44675
46034
|
return [approveCall, depositCall];
|
|
44676
46035
|
}
|
|
44677
46036
|
/**
|
|
44678
|
-
* VA_TO_EXTENDED: Deposit USDC
|
|
46037
|
+
* VA_TO_EXTENDED: Deposit USDC from vault allocator to Extended.
|
|
44679
46038
|
*
|
|
44680
46039
|
* Uses the extended adapter's getDepositCall to build ManageCalls,
|
|
44681
46040
|
* then wraps them in a merkle-verified manage call through the manager contract.
|
|
@@ -44690,43 +46049,31 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44690
46049
|
);
|
|
44691
46050
|
return [];
|
|
44692
46051
|
}
|
|
44693
|
-
const swapCall = await this._buildAdapterManageCall(
|
|
44694
|
-
this._config.usdcToUsdceAdapter,
|
|
44695
|
-
true,
|
|
44696
|
-
{ amount }
|
|
44697
|
-
);
|
|
44698
46052
|
const manageCall = await this._buildAdapterManageCall(
|
|
44699
46053
|
this._config.extendedAdapter,
|
|
44700
46054
|
true,
|
|
44701
46055
|
{ amount }
|
|
44702
46056
|
);
|
|
44703
|
-
return [
|
|
46057
|
+
return [manageCall];
|
|
44704
46058
|
}
|
|
44705
46059
|
/**
|
|
44706
|
-
* WALLET_TO_VA: Transfer USDC
|
|
46060
|
+
* WALLET_TO_VA: Transfer USDC from operator wallet to vault allocator.
|
|
44707
46061
|
* Caps amount by actual wallet balance.
|
|
44708
46062
|
*/
|
|
44709
46063
|
async _buildWalletToVACalls(route) {
|
|
44710
|
-
const erc20 = new ERC20(this._config.networkConfig);
|
|
44711
|
-
const { usdceToken, vaultAllocator, walletAddress } = this._config;
|
|
44712
46064
|
const transferAmount = route.amount;
|
|
44713
46065
|
if (transferAmount.lessThanOrEqualTo(0)) {
|
|
44714
46066
|
logger.warn(
|
|
44715
|
-
`${this._tag}::_buildWalletToVACalls no USDC
|
|
46067
|
+
`${this._tag}::_buildWalletToVACalls no USDC in wallet to transfer`
|
|
44716
46068
|
);
|
|
44717
46069
|
return [];
|
|
44718
46070
|
}
|
|
44719
46071
|
const transferCall = await this._buildAdapterManageCall(
|
|
44720
|
-
this._config.
|
|
46072
|
+
this._config.usdcTransferAdapter,
|
|
44721
46073
|
false,
|
|
44722
46074
|
{ amount: transferAmount }
|
|
44723
46075
|
);
|
|
44724
|
-
|
|
44725
|
-
this._config.usdcToUsdceAdapter,
|
|
44726
|
-
false,
|
|
44727
|
-
{ amount: transferAmount }
|
|
44728
|
-
);
|
|
44729
|
-
return [transferCall, swapCall];
|
|
46076
|
+
return [transferCall];
|
|
44730
46077
|
}
|
|
44731
46078
|
// ── AVNU swap routes ────────────────────────────────────────────────────
|
|
44732
46079
|
/**
|
|
@@ -44759,12 +46106,12 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44759
46106
|
*/
|
|
44760
46107
|
async _buildVesuIncreaseLeverCalls(route) {
|
|
44761
46108
|
const depositManageCall = await this._buildAdapterManageCall(
|
|
44762
|
-
this._config.
|
|
46109
|
+
this._config.vesuMultiplyAdapter,
|
|
44763
46110
|
true,
|
|
44764
46111
|
{
|
|
44765
46112
|
amount: route.marginAmount,
|
|
44766
46113
|
marginSwap: {
|
|
44767
|
-
marginToken: this._config.
|
|
46114
|
+
marginToken: this._config.vesuMultiplyAdapter.config.marginToken
|
|
44768
46115
|
// todo, must be vault token
|
|
44769
46116
|
},
|
|
44770
46117
|
leverSwap: {
|
|
@@ -44784,11 +46131,11 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44784
46131
|
async _buildVesuDecreaseLeverCalls(route) {
|
|
44785
46132
|
const collateralAmount = route.marginAmount.abs();
|
|
44786
46133
|
const withdrawManageCall = await this._buildAdapterManageCall(
|
|
44787
|
-
this._config.
|
|
46134
|
+
this._config.vesuMultiplyAdapter,
|
|
44788
46135
|
false,
|
|
44789
46136
|
{
|
|
44790
46137
|
amount: collateralAmount,
|
|
44791
|
-
withdrawSwap: { outputToken: this._config.
|
|
46138
|
+
withdrawSwap: { outputToken: this._config.vesuMultiplyAdapter.config.marginToken }
|
|
44792
46139
|
}
|
|
44793
46140
|
);
|
|
44794
46141
|
return [withdrawManageCall];
|
|
@@ -45379,140 +46726,6 @@ _ExecutionService.EXTENDED_EXPOSURE_ROUTES = /* @__PURE__ */ new Set([
|
|
|
45379
46726
|
]);
|
|
45380
46727
|
var ExecutionService = _ExecutionService;
|
|
45381
46728
|
|
|
45382
|
-
// src/strategies/universal-adapters/usdc<>usdce-adapter.ts
|
|
45383
|
-
import { hash as hash11, uint256 as uint25623 } from "starknet";
|
|
45384
|
-
var UsdcToUsdceAdapter = class _UsdcToUsdceAdapter extends BaseAdapter {
|
|
45385
|
-
_approveProofReadableId(usdcToUsdce) {
|
|
45386
|
-
const method = usdcToUsdce ? "swap_to_legacy" : "swap_to_new";
|
|
45387
|
-
return `approve_${method}`;
|
|
45388
|
-
}
|
|
45389
|
-
_swapProofReadableId(usdcToUsdce) {
|
|
45390
|
-
const method = usdcToUsdce ? "swap_to_legacy" : "swap_to_new";
|
|
45391
|
-
const target = usdcToUsdce ? this.config.supportedPositions[0].asset : this.config.supportedPositions[1].asset;
|
|
45392
|
-
return `${method}_${target.symbol}`;
|
|
45393
|
-
}
|
|
45394
|
-
buildSwapLeafConfigs(usdcToUsdce) {
|
|
45395
|
-
const method = usdcToUsdce ? "swap_to_legacy" : "swap_to_new";
|
|
45396
|
-
const target = usdcToUsdce ? this.config.supportedPositions[0].asset : this.config.supportedPositions[1].asset;
|
|
45397
|
-
return [
|
|
45398
|
-
{
|
|
45399
|
-
target: target.address,
|
|
45400
|
-
method: "approve",
|
|
45401
|
-
packedArguments: [AVNU_EXCHANGE_FOR_LEGACY_USDC.toBigInt()],
|
|
45402
|
-
id: this._approveProofReadableId(usdcToUsdce),
|
|
45403
|
-
sanitizer: AVNU_LEGACY_SANITIZER
|
|
45404
|
-
},
|
|
45405
|
-
{
|
|
45406
|
-
target: AVNU_EXCHANGE_FOR_LEGACY_USDC,
|
|
45407
|
-
method,
|
|
45408
|
-
packedArguments: [],
|
|
45409
|
-
id: this._swapProofReadableId(usdcToUsdce),
|
|
45410
|
-
sanitizer: AVNU_LEGACY_SANITIZER
|
|
45411
|
-
}
|
|
45412
|
-
];
|
|
45413
|
-
}
|
|
45414
|
-
async buildSwapCalls(params, usdcToUsdce) {
|
|
45415
|
-
const approveAmount = uint25623.bnToUint256(params.amount.toWei());
|
|
45416
|
-
const target = usdcToUsdce ? this.config.supportedPositions[0].asset : this.config.supportedPositions[1].asset;
|
|
45417
|
-
const method = usdcToUsdce ? "swap_to_legacy" : "swap_to_new";
|
|
45418
|
-
return [
|
|
45419
|
-
{
|
|
45420
|
-
proofReadableId: this._approveProofReadableId(usdcToUsdce),
|
|
45421
|
-
sanitizer: AVNU_LEGACY_SANITIZER,
|
|
45422
|
-
call: {
|
|
45423
|
-
contractAddress: target.address,
|
|
45424
|
-
selector: hash11.getSelectorFromName("approve"),
|
|
45425
|
-
calldata: [
|
|
45426
|
-
AVNU_EXCHANGE_FOR_LEGACY_USDC.toBigInt(),
|
|
45427
|
-
toBigInt(approveAmount.low.toString()),
|
|
45428
|
-
toBigInt(approveAmount.high.toString())
|
|
45429
|
-
]
|
|
45430
|
-
}
|
|
45431
|
-
},
|
|
45432
|
-
{
|
|
45433
|
-
proofReadableId: this._swapProofReadableId(usdcToUsdce),
|
|
45434
|
-
sanitizer: AVNU_LEGACY_SANITIZER,
|
|
45435
|
-
call: {
|
|
45436
|
-
contractAddress: AVNU_EXCHANGE_FOR_LEGACY_USDC,
|
|
45437
|
-
selector: hash11.getSelectorFromName(method),
|
|
45438
|
-
calldata: [
|
|
45439
|
-
toBigInt(approveAmount.low.toString()),
|
|
45440
|
-
// amount low
|
|
45441
|
-
toBigInt(approveAmount.high.toString())
|
|
45442
|
-
// amount high
|
|
45443
|
-
]
|
|
45444
|
-
}
|
|
45445
|
-
}
|
|
45446
|
-
];
|
|
45447
|
-
}
|
|
45448
|
-
constructor(config) {
|
|
45449
|
-
super(config, _UsdcToUsdceAdapter.name, Protocols.AVNU);
|
|
45450
|
-
this.config = config;
|
|
45451
|
-
assert(this.config.supportedPositions.length === 2, "UsdcToUsdceAdapter must have 2 supported positions");
|
|
45452
|
-
assert(this.config.supportedPositions[0].asset.symbol === "USDC", "UsdcToUsdceAdapter must have USDC as the first supported position");
|
|
45453
|
-
assert(this.config.supportedPositions[1].asset.symbol === "USDC.e", "UsdcToUsdceAdapter must have USDCE as the second supported position");
|
|
45454
|
-
}
|
|
45455
|
-
//abstract means the method has no implementation in this class; instead, child classes must implement it.
|
|
45456
|
-
async getAPY(supportedPosition) {
|
|
45457
|
-
return Promise.resolve({ apy: 0, type: "base" /* BASE */ });
|
|
45458
|
-
}
|
|
45459
|
-
async getPosition(supportedPosition) {
|
|
45460
|
-
const toToken = this.config.supportedPositions[1].asset;
|
|
45461
|
-
if (supportedPosition.asset.symbol != toToken.symbol) {
|
|
45462
|
-
return null;
|
|
45463
|
-
}
|
|
45464
|
-
try {
|
|
45465
|
-
const balance = await new ERC20(this.config.networkConfig).balanceOf(
|
|
45466
|
-
toToken.address,
|
|
45467
|
-
this.config.vaultAllocator.address,
|
|
45468
|
-
toToken.decimals
|
|
45469
|
-
);
|
|
45470
|
-
return { amount: balance, remarks: `USDC.e unused balance (VA)` };
|
|
45471
|
-
} catch (_e) {
|
|
45472
|
-
logger.error(`${_UsdcToUsdceAdapter.name}::getPosition: failed for ${toToken.symbol}`);
|
|
45473
|
-
throw new Error(`${_UsdcToUsdceAdapter.name}: failed to get balance for ${toToken.symbol}`);
|
|
45474
|
-
}
|
|
45475
|
-
}
|
|
45476
|
-
async maxDeposit(amount) {
|
|
45477
|
-
return Promise.resolve({
|
|
45478
|
-
tokenInfo: this.config.baseToken,
|
|
45479
|
-
amount: new Web3Number(0, 0),
|
|
45480
|
-
usdValue: 0,
|
|
45481
|
-
apy: { apy: 0, type: "base" /* BASE */ },
|
|
45482
|
-
protocol: Protocols.AVNU,
|
|
45483
|
-
remarks: ""
|
|
45484
|
-
});
|
|
45485
|
-
}
|
|
45486
|
-
async maxWithdraw() {
|
|
45487
|
-
return Promise.resolve({
|
|
45488
|
-
tokenInfo: this.config.baseToken,
|
|
45489
|
-
amount: new Web3Number(0, 0),
|
|
45490
|
-
usdValue: 0,
|
|
45491
|
-
apy: { apy: 0, type: "base" /* BASE */ },
|
|
45492
|
-
protocol: Protocols.AVNU,
|
|
45493
|
-
remarks: ""
|
|
45494
|
-
});
|
|
45495
|
-
}
|
|
45496
|
-
_getDepositLeaf() {
|
|
45497
|
-
return this.buildSwapLeafConfigs(true);
|
|
45498
|
-
}
|
|
45499
|
-
_getWithdrawLeaf() {
|
|
45500
|
-
return this.buildSwapLeafConfigs(false);
|
|
45501
|
-
}
|
|
45502
|
-
async getDepositCall(params) {
|
|
45503
|
-
const calls = await this.buildSwapCalls(params, true);
|
|
45504
|
-
return calls;
|
|
45505
|
-
}
|
|
45506
|
-
//Swap wbtc to usdc
|
|
45507
|
-
async getWithdrawCall(params) {
|
|
45508
|
-
const calls = await this.buildSwapCalls(params, false);
|
|
45509
|
-
return calls;
|
|
45510
|
-
}
|
|
45511
|
-
async getHealthFactor() {
|
|
45512
|
-
return Promise.resolve(1);
|
|
45513
|
-
}
|
|
45514
|
-
};
|
|
45515
|
-
|
|
45516
46729
|
// src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx
|
|
45517
46730
|
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
45518
46731
|
var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy extends SVKStrategy {
|
|
@@ -45528,9 +46741,6 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
45528
46741
|
});
|
|
45529
46742
|
this.wbtcToken = Global.getDefaultTokens().find((token) => token.symbol === "WBTC");
|
|
45530
46743
|
this.usdcToken = this.metadata.additionalInfo.borrowable_assets[0];
|
|
45531
|
-
this.usdceToken = Global.getDefaultTokens().find(
|
|
45532
|
-
(token) => token.symbol === "USDC.e"
|
|
45533
|
-
);
|
|
45534
46744
|
this.stateManager = this._initializeStateManager();
|
|
45535
46745
|
}
|
|
45536
46746
|
/**
|
|
@@ -45554,9 +46764,8 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
45554
46764
|
extendedAdapter: extendedAdapterEntry.adapter,
|
|
45555
46765
|
vaultAllocator: this.metadata.additionalInfo.vaultAllocator,
|
|
45556
46766
|
walletAddress: this.metadata.additionalInfo.walletAddress,
|
|
45557
|
-
assetToken:
|
|
45558
|
-
|
|
45559
|
-
usdceToken: this.usdceToken,
|
|
46767
|
+
assetToken: this.asset(),
|
|
46768
|
+
usdcToken: this.usdcToken,
|
|
45560
46769
|
collateralToken: this.wbtcToken,
|
|
45561
46770
|
limitBalanceBufferFactor: LIMIT_BALANCE
|
|
45562
46771
|
};
|
|
@@ -45590,7 +46799,7 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
45590
46799
|
}
|
|
45591
46800
|
return { collateralPrice, debtPrice };
|
|
45592
46801
|
}
|
|
45593
|
-
async
|
|
46802
|
+
async getVesuMultiplyAdapter() {
|
|
45594
46803
|
const vesuAdapter = this.metadata.additionalInfo.adapters.find(
|
|
45595
46804
|
(adapter) => adapter.adapter.name === VesuMultiplyAdapter.name
|
|
45596
46805
|
);
|
|
@@ -45612,16 +46821,16 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
45612
46821
|
}
|
|
45613
46822
|
return vesuModifyPositionAdapter.adapter;
|
|
45614
46823
|
}
|
|
45615
|
-
async
|
|
45616
|
-
const
|
|
46824
|
+
async getUsdcTransferAdapter() {
|
|
46825
|
+
const usdcTransferAdapter = this.metadata.additionalInfo.adapters.find(
|
|
45617
46826
|
(adapter) => adapter.adapter.name === TokenTransferAdapter.name
|
|
45618
46827
|
);
|
|
45619
|
-
if (!
|
|
46828
|
+
if (!usdcTransferAdapter) {
|
|
45620
46829
|
throw new Error(
|
|
45621
|
-
`${this.getTag()}
|
|
46830
|
+
`${this.getTag()} Usdc transfer adapter not configured in metadata.`
|
|
45622
46831
|
);
|
|
45623
46832
|
}
|
|
45624
|
-
return
|
|
46833
|
+
return usdcTransferAdapter.adapter;
|
|
45625
46834
|
}
|
|
45626
46835
|
async getAvnuAdapter() {
|
|
45627
46836
|
const avnuAdapter = this.metadata.additionalInfo.adapters.find(
|
|
@@ -45650,17 +46859,6 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
45650
46859
|
}
|
|
45651
46860
|
return extendedAdapter.adapter;
|
|
45652
46861
|
}
|
|
45653
|
-
async getUsdcToUsdceAdapter() {
|
|
45654
|
-
const usdcToUsdceAdapter = this.metadata.additionalInfo.adapters.find(
|
|
45655
|
-
(adapter) => adapter.adapter.name === UsdcToUsdceAdapter.name
|
|
45656
|
-
);
|
|
45657
|
-
if (!usdcToUsdceAdapter) {
|
|
45658
|
-
throw new Error(
|
|
45659
|
-
`${this.getTag()} UsdcToUsdce adapter not configured in metadata.`
|
|
45660
|
-
);
|
|
45661
|
-
}
|
|
45662
|
-
return usdcToUsdceAdapter.adapter;
|
|
45663
|
-
}
|
|
45664
46862
|
/**
|
|
45665
46863
|
* Creates an ExecutionService wired to this strategy's adapters and config.
|
|
45666
46864
|
* Use with `stateManager.solve()` to get a SolveResult, then pass it to
|
|
@@ -45672,34 +46870,30 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
45672
46870
|
*/
|
|
45673
46871
|
async createExecutionService(opts) {
|
|
45674
46872
|
const [
|
|
45675
|
-
|
|
46873
|
+
vesuMultiplyAdapter,
|
|
45676
46874
|
vesuModifyPositionAdapter,
|
|
45677
|
-
usdceTransferAdapter,
|
|
45678
46875
|
extendedAdapter,
|
|
45679
46876
|
avnuAdapter,
|
|
45680
|
-
|
|
46877
|
+
usdcTransferAdapter
|
|
45681
46878
|
] = await Promise.all([
|
|
45682
|
-
this.
|
|
46879
|
+
this.getVesuMultiplyAdapter(),
|
|
45683
46880
|
this.getVesuModifyPositionAdapter(),
|
|
45684
|
-
this.getUsdceTransferAdapter(),
|
|
45685
46881
|
this.getExtendedAdapter(),
|
|
45686
46882
|
this.getAvnuAdapter(),
|
|
45687
|
-
this.
|
|
46883
|
+
this.getUsdcTransferAdapter()
|
|
45688
46884
|
]);
|
|
45689
46885
|
const executionConfig = {
|
|
45690
46886
|
networkConfig: this.config,
|
|
45691
46887
|
pricer: this.pricer,
|
|
45692
|
-
|
|
46888
|
+
vesuMultiplyAdapter,
|
|
45693
46889
|
vesuModifyPositionAdapter,
|
|
45694
46890
|
extendedAdapter,
|
|
45695
46891
|
avnuAdapter,
|
|
45696
|
-
|
|
46892
|
+
usdcTransferAdapter,
|
|
45697
46893
|
vaultAllocator: this.metadata.additionalInfo.vaultAllocator,
|
|
45698
46894
|
walletAddress: this.metadata.additionalInfo.walletAddress,
|
|
45699
|
-
usdceTransferAdapter,
|
|
45700
46895
|
wbtcToken: this.wbtcToken,
|
|
45701
46896
|
usdcToken: this.usdcToken,
|
|
45702
|
-
usdceToken: this.usdceToken,
|
|
45703
46897
|
getMerkleTree: () => this.getMerkleTree(),
|
|
45704
46898
|
getManageCall: (proofs, manageCalls) => this.getManageCall(proofs, manageCalls),
|
|
45705
46899
|
getBringLiquidityCall: (params) => this.getBringLiquidityCall(params),
|
|
@@ -45720,9 +46914,7 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
45720
46914
|
for (let adapter of this.metadata.additionalInfo.adapters) {
|
|
45721
46915
|
let positions = await adapter.adapter.getPositions();
|
|
45722
46916
|
if (positions && positions.length > 0) {
|
|
45723
|
-
const filteredPositions = positions
|
|
45724
|
-
return position.tokenInfo.address !== this.usdceToken.address;
|
|
45725
|
-
});
|
|
46917
|
+
const filteredPositions = positions;
|
|
45726
46918
|
allPositions.push(...filteredPositions);
|
|
45727
46919
|
}
|
|
45728
46920
|
}
|
|
@@ -45917,34 +47109,22 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
45917
47109
|
};
|
|
45918
47110
|
}
|
|
45919
47111
|
/**
|
|
45920
|
-
* Fetches the operator wallet's current holdings for USDC
|
|
47112
|
+
* Fetches the operator wallet's current holdings for USDC and WBTC,
|
|
45921
47113
|
* returning each token's balance and USD value.
|
|
45922
47114
|
*/
|
|
45923
47115
|
async getWalletHoldings() {
|
|
45924
|
-
if (!this.
|
|
47116
|
+
if (!this.wbtcToken || !this.usdcToken) {
|
|
45925
47117
|
return [];
|
|
45926
47118
|
}
|
|
45927
47119
|
const walletAddress = this.metadata.additionalInfo.walletAddress;
|
|
45928
|
-
const usdceWalletBalance = await new ERC20(this.config).balanceOf(
|
|
45929
|
-
this.usdceToken.address,
|
|
45930
|
-
walletAddress,
|
|
45931
|
-
this.usdceToken.decimals
|
|
45932
|
-
);
|
|
45933
47120
|
const usdcWalletBalance = await new ERC20(this.config).balanceOf(
|
|
45934
47121
|
this.usdcToken.address,
|
|
45935
47122
|
walletAddress,
|
|
45936
47123
|
this.usdcToken.decimals
|
|
45937
47124
|
);
|
|
45938
|
-
const price = await this.pricer.getPrice(this.
|
|
45939
|
-
const wbtcPrice = await this.pricer.getPrice(this.wbtcToken.symbol);
|
|
45940
|
-
const usdceUsdValue = Number(usdceWalletBalance.toFixed(this.usdceToken.decimals)) * price.price;
|
|
47125
|
+
const price = await this.pricer.getPrice(this.usdcToken.symbol);
|
|
45941
47126
|
const usdcUsdValue = Number(usdcWalletBalance.toFixed(this.usdcToken.decimals)) * price.price;
|
|
45942
47127
|
return [
|
|
45943
|
-
{
|
|
45944
|
-
tokenInfo: this.usdceToken,
|
|
45945
|
-
amount: usdceWalletBalance,
|
|
45946
|
-
usdValue: usdceUsdValue
|
|
45947
|
-
},
|
|
45948
47128
|
{
|
|
45949
47129
|
tokenInfo: this.usdcToken,
|
|
45950
47130
|
amount: usdcWalletBalance,
|
|
@@ -45961,9 +47141,6 @@ function getLooperSettings3(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
45961
47141
|
const usdcToken = Global.getDefaultTokens().find(
|
|
45962
47142
|
(token) => token.symbol === underlyingSymbol
|
|
45963
47143
|
);
|
|
45964
|
-
const usdceToken = Global.getDefaultTokens().find(
|
|
45965
|
-
(token) => token.symbol === "USDC.e"
|
|
45966
|
-
);
|
|
45967
47144
|
const baseAdapterConfig = {
|
|
45968
47145
|
baseToken: wbtcToken,
|
|
45969
47146
|
supportedPositions: [
|
|
@@ -45984,17 +47161,10 @@ function getLooperSettings3(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
45984
47161
|
minimumExtendedPriceDifferenceForSwapOpen,
|
|
45985
47162
|
maximumExtendedPriceDifferenceForSwapClosing
|
|
45986
47163
|
});
|
|
45987
|
-
const usdcToUsdceAdapter = new UsdcToUsdceAdapter({
|
|
45988
|
-
...baseAdapterConfig,
|
|
45989
|
-
supportedPositions: [
|
|
45990
|
-
{ asset: usdcToken, isDebt: true },
|
|
45991
|
-
{ asset: usdceToken, isDebt: false }
|
|
45992
|
-
]
|
|
45993
|
-
});
|
|
45994
47164
|
const extendedAdapter = new ExtendedAdapter({
|
|
45995
47165
|
...baseAdapterConfig,
|
|
45996
47166
|
supportedPositions: [
|
|
45997
|
-
{ asset:
|
|
47167
|
+
{ asset: usdcToken, isDebt: false }
|
|
45998
47168
|
],
|
|
45999
47169
|
vaultIdExtended,
|
|
46000
47170
|
extendedContract: EXTENDED_CONTRACT,
|
|
@@ -46040,10 +47210,10 @@ function getLooperSettings3(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
46040
47210
|
{ asset: usdcToken, isDebt: true }
|
|
46041
47211
|
]
|
|
46042
47212
|
});
|
|
46043
|
-
const
|
|
47213
|
+
const usdcTransferAdapter = new TokenTransferAdapter({
|
|
46044
47214
|
...baseAdapterConfig,
|
|
46045
|
-
baseToken:
|
|
46046
|
-
supportedPositions: [{ asset:
|
|
47215
|
+
baseToken: usdcToken,
|
|
47216
|
+
supportedPositions: [{ asset: usdcToken, isDebt: false }],
|
|
46047
47217
|
fromAddress: vaultSettings.vaultAllocator,
|
|
46048
47218
|
toAddress: ContractAddr.from(vaultSettings.walletAddress)
|
|
46049
47219
|
});
|
|
@@ -46056,12 +47226,8 @@ function getLooperSettings3(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
46056
47226
|
adapter: vesuModifyPositionAdapter
|
|
46057
47227
|
});
|
|
46058
47228
|
vaultSettings.adapters.push({
|
|
46059
|
-
id: `${
|
|
46060
|
-
adapter:
|
|
46061
|
-
});
|
|
46062
|
-
vaultSettings.adapters.push({
|
|
46063
|
-
id: `${usdcToUsdceAdapter.name}_${usdceToken.symbol}_${usdcToken.symbol}`,
|
|
46064
|
-
adapter: usdcToUsdceAdapter
|
|
47229
|
+
id: `${usdcTransferAdapter.name}_${usdcToken.symbol}`,
|
|
47230
|
+
adapter: usdcTransferAdapter
|
|
46065
47231
|
});
|
|
46066
47232
|
vaultSettings.adapters.push({
|
|
46067
47233
|
id: `${extendedAdapter.name}_${wbtcToken.symbol}`,
|
|
@@ -46083,12 +47249,10 @@ function getLooperSettings3(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
46083
47249
|
vaultSettings.leafAdapters.push(() => vesuModifyPositionAdapter.getDepositLeaf());
|
|
46084
47250
|
vaultSettings.leafAdapters.push(() => vesuModifyPositionAdapter.getWithdrawLeaf());
|
|
46085
47251
|
vaultSettings.leafAdapters.push(() => extendedAdapter.getDepositLeaf());
|
|
46086
|
-
vaultSettings.leafAdapters.push(() => usdcToUsdceAdapter.getDepositLeaf());
|
|
46087
|
-
vaultSettings.leafAdapters.push(() => usdcToUsdceAdapter.getWithdrawLeaf());
|
|
46088
47252
|
vaultSettings.leafAdapters.push(() => avnuAdapter.getDepositLeaf());
|
|
46089
47253
|
vaultSettings.leafAdapters.push(() => avnuAdapter.getWithdrawLeaf());
|
|
46090
|
-
vaultSettings.leafAdapters.push(() =>
|
|
46091
|
-
vaultSettings.leafAdapters.push(() =>
|
|
47254
|
+
vaultSettings.leafAdapters.push(() => usdcTransferAdapter.getDepositLeaf());
|
|
47255
|
+
vaultSettings.leafAdapters.push(() => usdcTransferAdapter.getWithdrawLeaf());
|
|
46092
47256
|
vaultSettings.leafAdapters.push(
|
|
46093
47257
|
commonAdapter.getApproveAdapter(
|
|
46094
47258
|
usdcToken.address,
|
|
@@ -46533,11 +47697,13 @@ export {
|
|
|
46533
47697
|
BaseAdapter,
|
|
46534
47698
|
BaseStrategy,
|
|
46535
47699
|
CASE_ROUTE_TYPES,
|
|
47700
|
+
COLLATERAL_PRECISION,
|
|
46536
47701
|
CaseCategory,
|
|
46537
47702
|
CaseId,
|
|
46538
47703
|
CommonAdapter,
|
|
46539
47704
|
ContractAddr,
|
|
46540
47705
|
CycleType,
|
|
47706
|
+
DEFAULT_TROVES_STRATEGIES_API,
|
|
46541
47707
|
ERC20,
|
|
46542
47708
|
EXTENDED_CONTRACT,
|
|
46543
47709
|
EXTENDED_SANITIZER,
|
|
@@ -46555,6 +47721,7 @@ export {
|
|
|
46555
47721
|
FatalError,
|
|
46556
47722
|
FlowChartColors,
|
|
46557
47723
|
Global,
|
|
47724
|
+
HealthFactorMath,
|
|
46558
47725
|
HyperLSTStrategies,
|
|
46559
47726
|
ILending,
|
|
46560
47727
|
Initializable,
|
|
@@ -46592,6 +47759,7 @@ export {
|
|
|
46592
47759
|
StrategyLiveStatus,
|
|
46593
47760
|
StrategyTag,
|
|
46594
47761
|
StrategyType,
|
|
47762
|
+
SvkTrovesAdapter,
|
|
46595
47763
|
TRANSFER_SANITIZER,
|
|
46596
47764
|
TimeInForce,
|
|
46597
47765
|
TokenMarketData,
|
|
@@ -46639,6 +47807,7 @@ export {
|
|
|
46639
47807
|
createEkuboCLStrategy,
|
|
46640
47808
|
createHyperLSTStrategy,
|
|
46641
47809
|
createSenseiStrategy,
|
|
47810
|
+
createSolveBudgetFromRawState,
|
|
46642
47811
|
createStrategy,
|
|
46643
47812
|
createUniversalStrategy2 as createUniversalStrategy,
|
|
46644
47813
|
createVesuRebalanceStrategy2 as createVesuRebalanceStrategy,
|