@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.mjs
CHANGED
|
@@ -94,6 +94,9 @@ var Web3Number = class _Web3Number2 extends _Web3Number {
|
|
|
94
94
|
const bn = new _Web3Number2(weiNumber, decimals).dividedBy(10 ** decimals);
|
|
95
95
|
return new _Web3Number2(bn.toString(), decimals);
|
|
96
96
|
}
|
|
97
|
+
static fromNumber(number, decimals) {
|
|
98
|
+
return new _Web3Number2(number.toString(), decimals);
|
|
99
|
+
}
|
|
97
100
|
[util.inspect.custom](depth, opts) {
|
|
98
101
|
return this.toString();
|
|
99
102
|
}
|
|
@@ -1687,6 +1690,48 @@ _StarknetCallParser.METHOD_BY_SELECTOR = new Map(
|
|
|
1687
1690
|
);
|
|
1688
1691
|
var StarknetCallParser = _StarknetCallParser;
|
|
1689
1692
|
|
|
1693
|
+
// src/utils/health-factor-math.ts
|
|
1694
|
+
var HealthFactorMath = class {
|
|
1695
|
+
static getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
1696
|
+
const numerator = debtAmount.multipliedBy(debtPrice).multipliedBy(targetHF);
|
|
1697
|
+
const denominator = collateralPrice * maxLTV;
|
|
1698
|
+
const collateralAmount = numerator.dividedBy(denominator);
|
|
1699
|
+
const netCollateral = new Web3Number(collateralAmount.toString(), collateralTokenInfo.decimals);
|
|
1700
|
+
return netCollateral;
|
|
1701
|
+
}
|
|
1702
|
+
static getMinCollateralRequiredOnLooping(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
1703
|
+
const netCollateral = this.getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo);
|
|
1704
|
+
const collateralFromDebt = new Web3Number(debtAmount.multipliedBy(debtPrice).dividedBy(collateralPrice).toString(), collateralTokenInfo.decimals);
|
|
1705
|
+
return netCollateral.minus(collateralFromDebt);
|
|
1706
|
+
}
|
|
1707
|
+
static getHealthFactor(collateralAmount, collateralPrice, maxLTV, debtAmount, debtPrice) {
|
|
1708
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
1709
|
+
const denominator = debtAmount.multipliedBy(debtPrice);
|
|
1710
|
+
const healthFactor = numerator.dividedBy(denominator);
|
|
1711
|
+
return healthFactor.toNumber();
|
|
1712
|
+
}
|
|
1713
|
+
static getMaxDebtAmountOnLooping(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
1714
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
1715
|
+
logger.verbose(`HealthFactorMath: Max debt amount on looping numerator: ${numerator.toNumber()}, collateralAmount: ${collateralAmount.toNumber()}, collateralPrice: ${collateralPrice}, maxLTV: ${maxLTV}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
|
|
1716
|
+
const denominator = targetHF - maxLTV;
|
|
1717
|
+
logger.verbose(`HealthFactorMath: Max debt amount on looping denominator: ${denominator}`);
|
|
1718
|
+
const debtAmountUSD = numerator.dividedBy(denominator);
|
|
1719
|
+
logger.verbose(`HealthFactorMath: Max debt amount on looping debtAmountUSD: ${debtAmountUSD.toNumber()}`);
|
|
1720
|
+
const debtAmount = debtAmountUSD.dividedBy(debtPrice);
|
|
1721
|
+
logger.verbose(`HealthFactorMath: Max debt amount on looping debtAmount: ${debtAmount.toNumber()}`);
|
|
1722
|
+
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
1723
|
+
}
|
|
1724
|
+
static getMaxDebtAmount(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
1725
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
1726
|
+
logger.verbose(`HealthFactorMath: Max debt amount numerator: ${numerator.toNumber()}, collateralAmount: ${collateralAmount.toNumber()}, collateralPrice: ${collateralPrice}, maxLTV: ${maxLTV}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
|
|
1727
|
+
const denominator = targetHF * debtPrice;
|
|
1728
|
+
logger.verbose(`HealthFactorMath: Max debt amount denominator: ${denominator}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
|
|
1729
|
+
const debtAmount = numerator.dividedBy(denominator);
|
|
1730
|
+
logger.verbose(`HealthFactorMath: Max debt amount: ${debtAmount.toNumber()}, numerator: ${numerator.toNumber()}, denominator: ${denominator}`);
|
|
1731
|
+
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
1732
|
+
}
|
|
1733
|
+
};
|
|
1734
|
+
|
|
1690
1735
|
// src/utils/index.ts
|
|
1691
1736
|
function assert(condition, message) {
|
|
1692
1737
|
if (!condition) {
|
|
@@ -4086,6 +4131,9 @@ var Web3Number2 = class _Web3Number2 extends _Web3Number {
|
|
|
4086
4131
|
const bn = new _Web3Number2(weiNumber, decimals).dividedBy(10 ** decimals);
|
|
4087
4132
|
return new _Web3Number2(bn.toString(), decimals);
|
|
4088
4133
|
}
|
|
4134
|
+
static fromNumber(number, decimals) {
|
|
4135
|
+
return new _Web3Number2(number.toString(), decimals);
|
|
4136
|
+
}
|
|
4089
4137
|
};
|
|
4090
4138
|
|
|
4091
4139
|
// src/interfaces/lending.ts
|
|
@@ -6260,6 +6308,10 @@ var VaultProtocol = {
|
|
|
6260
6308
|
name: "Vault",
|
|
6261
6309
|
logo: ""
|
|
6262
6310
|
};
|
|
6311
|
+
var TrovesProtocol = {
|
|
6312
|
+
name: "Troves",
|
|
6313
|
+
logo: "https://app.troves.fi/favicon.ico"
|
|
6314
|
+
};
|
|
6263
6315
|
var Protocols = {
|
|
6264
6316
|
NONE: NoneProtocol,
|
|
6265
6317
|
VESU: VesuProtocol,
|
|
@@ -6267,7 +6319,8 @@ var Protocols = {
|
|
|
6267
6319
|
EXTENDED: ExtendedProtocol,
|
|
6268
6320
|
EKUBO: EkuboProtocol,
|
|
6269
6321
|
AVNU: AvnuProtocol,
|
|
6270
|
-
VAULT: VaultProtocol
|
|
6322
|
+
VAULT: VaultProtocol,
|
|
6323
|
+
TROVES: TrovesProtocol
|
|
6271
6324
|
};
|
|
6272
6325
|
|
|
6273
6326
|
// src/interfaces/initializable.ts
|
|
@@ -34002,48 +34055,6 @@ var AbisConfig = {
|
|
|
34002
34055
|
}
|
|
34003
34056
|
};
|
|
34004
34057
|
|
|
34005
|
-
// src/utils/health-factor-math.ts
|
|
34006
|
-
var HealthFactorMath = class {
|
|
34007
|
-
static getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
34008
|
-
const numerator = debtAmount.multipliedBy(debtPrice).multipliedBy(targetHF);
|
|
34009
|
-
const denominator = collateralPrice * maxLTV;
|
|
34010
|
-
const collateralAmount = numerator.dividedBy(denominator);
|
|
34011
|
-
const netCollateral = new Web3Number(collateralAmount.toString(), collateralTokenInfo.decimals);
|
|
34012
|
-
return netCollateral;
|
|
34013
|
-
}
|
|
34014
|
-
static getMinCollateralRequiredOnLooping(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
34015
|
-
const netCollateral = this.getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo);
|
|
34016
|
-
const collateralFromDebt = new Web3Number(debtAmount.multipliedBy(debtPrice).dividedBy(collateralPrice).toString(), collateralTokenInfo.decimals);
|
|
34017
|
-
return netCollateral.minus(collateralFromDebt);
|
|
34018
|
-
}
|
|
34019
|
-
static getHealthFactor(collateralAmount, collateralPrice, maxLTV, debtAmount, debtPrice) {
|
|
34020
|
-
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
34021
|
-
const denominator = debtAmount.multipliedBy(debtPrice);
|
|
34022
|
-
const healthFactor = numerator.dividedBy(denominator);
|
|
34023
|
-
return healthFactor.toNumber();
|
|
34024
|
-
}
|
|
34025
|
-
static getMaxDebtAmountOnLooping(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
34026
|
-
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
34027
|
-
logger.verbose(`HealthFactorMath: Max debt amount on looping numerator: ${numerator.toNumber()}, collateralAmount: ${collateralAmount.toNumber()}, collateralPrice: ${collateralPrice}, maxLTV: ${maxLTV}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
|
|
34028
|
-
const denominator = targetHF - maxLTV;
|
|
34029
|
-
logger.verbose(`HealthFactorMath: Max debt amount on looping denominator: ${denominator}`);
|
|
34030
|
-
const debtAmountUSD = numerator.dividedBy(denominator);
|
|
34031
|
-
logger.verbose(`HealthFactorMath: Max debt amount on looping debtAmountUSD: ${debtAmountUSD.toNumber()}`);
|
|
34032
|
-
const debtAmount = debtAmountUSD.dividedBy(debtPrice);
|
|
34033
|
-
logger.verbose(`HealthFactorMath: Max debt amount on looping debtAmount: ${debtAmount.toNumber()}`);
|
|
34034
|
-
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
34035
|
-
}
|
|
34036
|
-
static getMaxDebtAmount(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
34037
|
-
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
34038
|
-
logger.verbose(`HealthFactorMath: Max debt amount numerator: ${numerator.toNumber()}, collateralAmount: ${collateralAmount.toNumber()}, collateralPrice: ${collateralPrice}, maxLTV: ${maxLTV}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
|
|
34039
|
-
const denominator = targetHF * debtPrice;
|
|
34040
|
-
logger.verbose(`HealthFactorMath: Max debt amount denominator: ${denominator}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
|
|
34041
|
-
const debtAmount = numerator.dividedBy(denominator);
|
|
34042
|
-
logger.verbose(`HealthFactorMath: Max debt amount: ${debtAmount.toNumber()}, numerator: ${numerator.toNumber()}, denominator: ${denominator}`);
|
|
34043
|
-
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
34044
|
-
}
|
|
34045
|
-
};
|
|
34046
|
-
|
|
34047
34058
|
// src/strategies/vesu-extended-strategy/utils/helper.ts
|
|
34048
34059
|
var returnFormattedAmount = (amount, toTokenDecimals) => {
|
|
34049
34060
|
const formattedAmount = "0x" + BigInt(Math.floor(amount * 10 ** toTokenDecimals)).toString(16);
|
|
@@ -34686,6 +34697,7 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34686
34697
|
const collateralToken = this.config.collateral;
|
|
34687
34698
|
const debtToken = this.config.debt;
|
|
34688
34699
|
const { contract: multiplyContract } = this._getMultiplyContract();
|
|
34700
|
+
this.lastSwapPriceInfo = null;
|
|
34689
34701
|
const {
|
|
34690
34702
|
existingCollateralInfo,
|
|
34691
34703
|
existingDebtInfo,
|
|
@@ -34722,9 +34734,15 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34722
34734
|
let marginSwapLimitAmount = Web3Number.fromWei(0, collateralToken.decimals);
|
|
34723
34735
|
let addedCollateral = params.amount;
|
|
34724
34736
|
let approveAmount = params.amount;
|
|
34737
|
+
let aggregatedFromAmount = 0;
|
|
34738
|
+
let aggregatedToAmount = 0;
|
|
34739
|
+
let aggregatedFromSymbol = debtToken.symbol;
|
|
34740
|
+
const aggregatedToSymbol = collateralToken.symbol;
|
|
34741
|
+
let executedSwapCount = 0;
|
|
34725
34742
|
if (params.marginSwap) {
|
|
34726
34743
|
const marginToken = params.marginSwap.marginToken;
|
|
34727
34744
|
const requiredAmount = params.amount;
|
|
34745
|
+
assert(marginToken.address.eq(debtToken.address), "Margin token must be the same as debt token");
|
|
34728
34746
|
const marginSwapQuote = await ekuboQuoter.getQuoteExactOutput(
|
|
34729
34747
|
marginToken.address.address,
|
|
34730
34748
|
collateralToken.address.address,
|
|
@@ -34740,6 +34758,11 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34740
34758
|
marginToken,
|
|
34741
34759
|
collateralToken
|
|
34742
34760
|
);
|
|
34761
|
+
const marginSwapInputAmount = Web3Number.fromWei(marginSwapQuote.total_calculated, marginToken.decimals).abs().toNumber();
|
|
34762
|
+
const marginSwapOutputAmount = requiredAmount.abs().toNumber();
|
|
34763
|
+
aggregatedFromAmount += marginSwapInputAmount;
|
|
34764
|
+
aggregatedToAmount += marginSwapOutputAmount;
|
|
34765
|
+
executedSwapCount += 1;
|
|
34743
34766
|
approveAmount = Web3Number.fromWei(marginSwapQuote.total_calculated, marginToken.decimals).multipliedBy(1 + this.maxSlippage).abs();
|
|
34744
34767
|
}
|
|
34745
34768
|
let debtAmount = this._computeTargetDebtDelta(
|
|
@@ -34763,10 +34786,6 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34763
34786
|
if (!debtAmount.isZero() && debtAmount.greaterThan(0)) {
|
|
34764
34787
|
try {
|
|
34765
34788
|
let swapQuote;
|
|
34766
|
-
const debtAmountInCollateralUnits = new Web3Number(
|
|
34767
|
-
debtAmount.multipliedBy(debtPrice).dividedBy(collateralPrice).toFixed(6),
|
|
34768
|
-
collateralToken.decimals
|
|
34769
|
-
);
|
|
34770
34789
|
if (params.leverSwap?.exactOutput) {
|
|
34771
34790
|
swapQuote = await ekuboQuoter.getQuoteExactOutput(
|
|
34772
34791
|
debtToken.address.address,
|
|
@@ -34790,17 +34809,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34790
34809
|
).abs().toNumber();
|
|
34791
34810
|
const inputAmt = debtAmount.abs().toNumber();
|
|
34792
34811
|
const outputAmt = quoteOutputAmount;
|
|
34793
|
-
|
|
34794
|
-
|
|
34795
|
-
|
|
34796
|
-
toTokenSymbol: collateralToken.symbol,
|
|
34797
|
-
fromAmount: inputAmt,
|
|
34798
|
-
toAmount: outputAmt,
|
|
34799
|
-
effectivePrice: outputAmt !== 0 ? inputAmt / outputAmt : 0
|
|
34800
|
-
};
|
|
34801
|
-
logger.verbose(
|
|
34802
|
-
`${_VesuMultiplyAdapter.name}::_getIncreaseCalldata stored price info: ${inputAmt} ${debtToken.symbol} \u2192 ${outputAmt} ${collateralToken.symbol}, effectivePrice=${this.lastSwapPriceInfo.effectivePrice}`
|
|
34803
|
-
);
|
|
34812
|
+
aggregatedFromAmount += inputAmt;
|
|
34813
|
+
aggregatedToAmount += outputAmt;
|
|
34814
|
+
executedSwapCount += 1;
|
|
34804
34815
|
leverSwap = ekuboQuoter.getVesuMultiplyQuote(
|
|
34805
34816
|
swapQuote,
|
|
34806
34817
|
debtToken,
|
|
@@ -34818,6 +34829,19 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34818
34829
|
);
|
|
34819
34830
|
}
|
|
34820
34831
|
}
|
|
34832
|
+
if (executedSwapCount > 0) {
|
|
34833
|
+
this.lastSwapPriceInfo = {
|
|
34834
|
+
source: "ekubo",
|
|
34835
|
+
fromTokenSymbol: aggregatedFromSymbol ?? debtToken.symbol,
|
|
34836
|
+
toTokenSymbol: aggregatedToSymbol,
|
|
34837
|
+
fromAmount: aggregatedFromAmount,
|
|
34838
|
+
toAmount: aggregatedToAmount,
|
|
34839
|
+
effectivePrice: aggregatedToAmount !== 0 ? aggregatedFromAmount / aggregatedToAmount : 0
|
|
34840
|
+
};
|
|
34841
|
+
logger.verbose(
|
|
34842
|
+
`${_VesuMultiplyAdapter.name}::_getIncreaseCalldata stored aggregated price info: ${aggregatedFromAmount} ${this.lastSwapPriceInfo.fromTokenSymbol} \u2192 ${aggregatedToAmount} ${aggregatedToSymbol}, effectivePrice=${this.lastSwapPriceInfo.effectivePrice}, swaps=${executedSwapCount}`
|
|
34843
|
+
);
|
|
34844
|
+
}
|
|
34821
34845
|
logger.verbose(
|
|
34822
34846
|
`${_VesuMultiplyAdapter.name}::_getIncreaseCalldata leverSwapLimitAmount: ${leverSwapLimitAmount.toWei()}`
|
|
34823
34847
|
);
|
|
@@ -34850,10 +34874,21 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34850
34874
|
approveAmount
|
|
34851
34875
|
};
|
|
34852
34876
|
}
|
|
34877
|
+
// private _setLastSwapPriceAsNoSwap(): void {
|
|
34878
|
+
// this.lastSwapPriceInfo = {
|
|
34879
|
+
// source: "no-swap",
|
|
34880
|
+
// fromTokenSymbol: this.config.collateral.symbol,
|
|
34881
|
+
// toTokenSymbol: this.config.debt.symbol,
|
|
34882
|
+
// fromAmount: 0,
|
|
34883
|
+
// toAmount: 0,
|
|
34884
|
+
// effectivePrice: 0,
|
|
34885
|
+
// };
|
|
34886
|
+
// }
|
|
34853
34887
|
async _buildDecreaseLikeCalldata(params) {
|
|
34854
34888
|
const collateralToken = this.config.collateral;
|
|
34855
34889
|
const debtToken = this.config.debt;
|
|
34856
34890
|
const { contract: multiplyContract } = this._getMultiplyContract();
|
|
34891
|
+
this.lastSwapPriceInfo = null;
|
|
34857
34892
|
const ekuboQuoter = new EkuboQuoter(
|
|
34858
34893
|
this.config.networkConfig,
|
|
34859
34894
|
this.config.pricer
|
|
@@ -34862,6 +34897,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34862
34897
|
let leverSwapWeights = [];
|
|
34863
34898
|
let leverSwapLimitAmount = Web3Number.fromWei(0, collateralToken.decimals);
|
|
34864
34899
|
let leverCollateralUsed = Web3Number.fromWei(0, collateralToken.decimals);
|
|
34900
|
+
let aggregatedFromAmount = 0;
|
|
34901
|
+
let aggregatedToAmount = 0;
|
|
34902
|
+
let executedSwapCount = 0;
|
|
34865
34903
|
if (params.closePosition) {
|
|
34866
34904
|
const debtQuote = await ekuboQuoter.getQuoteExactOutput(
|
|
34867
34905
|
collateralToken.address.address,
|
|
@@ -34880,6 +34918,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34880
34918
|
collateralToken.decimals
|
|
34881
34919
|
).abs();
|
|
34882
34920
|
leverSwapLimitAmount = leverCollateralUsed.multipliedBy(1 + this.maxSlippage);
|
|
34921
|
+
aggregatedFromAmount += leverCollateralUsed.toNumber();
|
|
34922
|
+
aggregatedToAmount += params.debtToRepayAbs.abs().toNumber();
|
|
34923
|
+
executedSwapCount += 1;
|
|
34883
34924
|
} else {
|
|
34884
34925
|
if (params.collateralPrice === void 0 || params.debtPrice === void 0) {
|
|
34885
34926
|
throw new Error(
|
|
@@ -34901,17 +34942,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34901
34942
|
leverSwapQuote.total_calculated,
|
|
34902
34943
|
debtToken.decimals
|
|
34903
34944
|
).abs().toNumber();
|
|
34904
|
-
|
|
34905
|
-
|
|
34906
|
-
|
|
34907
|
-
toTokenSymbol: debtToken.symbol,
|
|
34908
|
-
fromAmount: inputAmt,
|
|
34909
|
-
toAmount: outputAmt,
|
|
34910
|
-
effectivePrice: outputAmt !== 0 ? outputAmt / inputAmt : 0
|
|
34911
|
-
};
|
|
34912
|
-
logger.verbose(
|
|
34913
|
-
`${_VesuMultiplyAdapter.name}::_buildDecreaseLikeCalldata stored price info: ${inputAmt} ${collateralToken.symbol} \u2192 ${outputAmt} ${debtToken.symbol}, effectivePrice=${this.lastSwapPriceInfo.effectivePrice}`
|
|
34914
|
-
);
|
|
34945
|
+
aggregatedFromAmount += inputAmt;
|
|
34946
|
+
aggregatedToAmount += outputAmt;
|
|
34947
|
+
executedSwapCount += 1;
|
|
34915
34948
|
leverSwap = ekuboQuoter.getVesuMultiplyQuote(
|
|
34916
34949
|
leverSwapQuote,
|
|
34917
34950
|
collateralToken,
|
|
@@ -34934,6 +34967,7 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34934
34967
|
);
|
|
34935
34968
|
const withdrawSwapWeights = [];
|
|
34936
34969
|
if (params.outputToken && !params.outputToken.address.eq(collateralToken.address)) {
|
|
34970
|
+
assert(params.outputToken.address.eq(debtToken.address), "Withdraw output token must be the same as debt token");
|
|
34937
34971
|
const residualCollateral = params.closePosition ? params.existingCollateral.minus(leverCollateralUsed) : params.subMargin;
|
|
34938
34972
|
const outputTokenPrice = await this.config.pricer.getPrice(params.outputToken.symbol);
|
|
34939
34973
|
if (residualCollateral.greaterThan(0)) {
|
|
@@ -34950,12 +34984,34 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
34950
34984
|
);
|
|
34951
34985
|
withdrawSwap = built.swaps;
|
|
34952
34986
|
withdrawSwapWeights.push(...built.weights);
|
|
34987
|
+
const withdrawOutputAmount = Web3Number.fromWei(
|
|
34988
|
+
withdrawQuote.total_calculated,
|
|
34989
|
+
params.outputToken.decimals
|
|
34990
|
+
).abs().toNumber();
|
|
34991
|
+
aggregatedFromAmount += residualCollateral.toNumber();
|
|
34992
|
+
aggregatedToAmount += withdrawOutputAmount;
|
|
34993
|
+
executedSwapCount += 1;
|
|
34953
34994
|
const estimatedOutput = residualCollateral.multipliedBy(params.collateralPrice).dividedBy(outputTokenPrice.price);
|
|
34954
34995
|
estimatedOutput.decimals = params.outputToken.decimals;
|
|
34955
34996
|
withdrawSwapLimitAmount = estimatedOutput.multipliedBy(1 - this.maxSlippage);
|
|
34956
34997
|
}
|
|
34957
34998
|
}
|
|
34958
34999
|
}
|
|
35000
|
+
if (executedSwapCount > 0) {
|
|
35001
|
+
this.lastSwapPriceInfo = {
|
|
35002
|
+
source: "ekubo",
|
|
35003
|
+
fromTokenSymbol: collateralToken.symbol,
|
|
35004
|
+
toTokenSymbol: debtToken.symbol,
|
|
35005
|
+
fromAmount: aggregatedFromAmount,
|
|
35006
|
+
toAmount: aggregatedToAmount,
|
|
35007
|
+
effectivePrice: aggregatedFromAmount !== 0 ? aggregatedToAmount / aggregatedFromAmount : 0
|
|
35008
|
+
};
|
|
35009
|
+
logger.verbose(
|
|
35010
|
+
`${_VesuMultiplyAdapter.name}::_buildDecreaseLikeCalldata stored aggregated price info: ${aggregatedFromAmount} ${collateralToken.symbol} \u2192 ${aggregatedToAmount} ${debtToken.symbol}, effectivePrice=${this.lastSwapPriceInfo.effectivePrice}, swaps=${executedSwapCount}`
|
|
35011
|
+
);
|
|
35012
|
+
} else {
|
|
35013
|
+
this.lastSwapPriceInfo = null;
|
|
35014
|
+
}
|
|
34959
35015
|
logger.debug(
|
|
34960
35016
|
`${_VesuMultiplyAdapter.name}::_buildDecreaseLikeCalldata leverSwapCount=${leverSwap.length}, withdrawSwapCount=${withdrawSwap.length}, withdrawSwapLimitAmount=${withdrawSwapLimitAmount.toNumber()}, subMargin=${params.subMargin.toNumber()}`
|
|
34961
35017
|
);
|
|
@@ -36143,13 +36199,13 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
36143
36199
|
this.minimumExtendedMovementAmount = this.config.minimumExtendedMovementAmount ?? 5;
|
|
36144
36200
|
this.client = client;
|
|
36145
36201
|
this.retryDelayForOrderStatus = this.config.retryDelayForOrderStatus ?? 3e3;
|
|
36146
|
-
this.
|
|
36202
|
+
this.usdcToken = this.config.supportedPositions[0].asset;
|
|
36147
36203
|
}
|
|
36148
36204
|
_depositApproveProofReadableId() {
|
|
36149
|
-
return `extended_approve_${this.
|
|
36205
|
+
return `extended_approve_${this.usdcToken.symbol}`;
|
|
36150
36206
|
}
|
|
36151
36207
|
_depositCallProofReadableId() {
|
|
36152
|
-
return `extended_deposit_${this.
|
|
36208
|
+
return `extended_deposit_${this.usdcToken.symbol}`;
|
|
36153
36209
|
}
|
|
36154
36210
|
//abstract means the method has no implementation in this class; instead, child classes must implement it.
|
|
36155
36211
|
async getAPY(supportedPosition) {
|
|
@@ -36218,7 +36274,7 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
36218
36274
|
_getDepositLeaf() {
|
|
36219
36275
|
return [
|
|
36220
36276
|
{
|
|
36221
|
-
target: this.
|
|
36277
|
+
target: this.usdcToken.address,
|
|
36222
36278
|
method: "approve",
|
|
36223
36279
|
packedArguments: [this.config.extendedContract.toBigInt()],
|
|
36224
36280
|
id: this._depositApproveProofReadableId(),
|
|
@@ -36238,14 +36294,14 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
36238
36294
|
}
|
|
36239
36295
|
async getDepositCall(params) {
|
|
36240
36296
|
try {
|
|
36241
|
-
const salt = Math.floor(Math.random() * 10 ** this.
|
|
36297
|
+
const salt = Math.floor(Math.random() * 10 ** this.usdcToken.decimals);
|
|
36242
36298
|
const amount = uint25616.bnToUint256(params.amount.toWei());
|
|
36243
36299
|
return [
|
|
36244
36300
|
{
|
|
36245
36301
|
proofReadableId: this._depositApproveProofReadableId(),
|
|
36246
36302
|
sanitizer: SIMPLE_SANITIZER,
|
|
36247
36303
|
call: {
|
|
36248
|
-
contractAddress: this.
|
|
36304
|
+
contractAddress: this.usdcToken.address,
|
|
36249
36305
|
selector: hash8.getSelectorFromName("approve"),
|
|
36250
36306
|
calldata: [
|
|
36251
36307
|
this.config.extendedContract.toBigInt(),
|
|
@@ -37146,8 +37202,8 @@ var AvnuAdapter = class _AvnuAdapter extends BaseAdapter {
|
|
|
37146
37202
|
}
|
|
37147
37203
|
};
|
|
37148
37204
|
|
|
37149
|
-
// src/strategies/universal-
|
|
37150
|
-
import {
|
|
37205
|
+
// src/strategies/universal-adapters/svk-troves-adapter.ts
|
|
37206
|
+
import { hash as hash11, uint256 as uint25619, Contract as Contract14 } from "starknet";
|
|
37151
37207
|
|
|
37152
37208
|
// src/data/universal-vault.abi.json
|
|
37153
37209
|
var universal_vault_abi_default = [
|
|
@@ -38831,6 +38887,272 @@ var universal_vault_abi_default = [
|
|
|
38831
38887
|
}
|
|
38832
38888
|
];
|
|
38833
38889
|
|
|
38890
|
+
// src/strategies/universal-adapters/svk-troves-adapter.ts
|
|
38891
|
+
var DEFAULT_TROVES_STRATEGIES_API = "https://app.troves.fi/api/strategies";
|
|
38892
|
+
function parseTrovesApyField(raw) {
|
|
38893
|
+
if (typeof raw === "number" && Number.isFinite(raw)) {
|
|
38894
|
+
return raw;
|
|
38895
|
+
}
|
|
38896
|
+
if (typeof raw === "string") {
|
|
38897
|
+
const n = Number.parseFloat(raw);
|
|
38898
|
+
if (Number.isFinite(n)) {
|
|
38899
|
+
return n;
|
|
38900
|
+
}
|
|
38901
|
+
}
|
|
38902
|
+
return 0;
|
|
38903
|
+
}
|
|
38904
|
+
var SvkTrovesAdapter = class _SvkTrovesAdapter extends BaseAdapter {
|
|
38905
|
+
constructor(config) {
|
|
38906
|
+
super(config, _SvkTrovesAdapter.name, Protocols.TROVES);
|
|
38907
|
+
this.config = config;
|
|
38908
|
+
}
|
|
38909
|
+
/** Owner used for share balance + `due_assets_from_owner`. */
|
|
38910
|
+
_positionOwner() {
|
|
38911
|
+
return this.config.positionOwner ?? this.config.vaultAllocator;
|
|
38912
|
+
}
|
|
38913
|
+
/**
|
|
38914
|
+
* Proof readable IDs must stay ≤ 31 chars (Cairo short string). We derive a short ASCII suffix from
|
|
38915
|
+
* `strategyVault` address so multiple SVK adapters in one tree stay distinct.
|
|
38916
|
+
*/
|
|
38917
|
+
_proofSuffix() {
|
|
38918
|
+
return this.config.strategyVault.address.replace(/^0x/, "").slice(-6);
|
|
38919
|
+
}
|
|
38920
|
+
_depositApproveProofReadableId() {
|
|
38921
|
+
return `appr_dep_svk_${this._proofSuffix()}`;
|
|
38922
|
+
}
|
|
38923
|
+
_depositCallProofReadableId() {
|
|
38924
|
+
return `dep_svk_${this._proofSuffix()}`;
|
|
38925
|
+
}
|
|
38926
|
+
_withdrawCallProofReadableId() {
|
|
38927
|
+
return `wtdrw_svk_${this._proofSuffix()}`;
|
|
38928
|
+
}
|
|
38929
|
+
async getAPY(supportedPosition) {
|
|
38930
|
+
const CACHE_KEY = `svk_apy_${this.config.trovesStrategyId}`;
|
|
38931
|
+
const cached = this.getCache(CACHE_KEY);
|
|
38932
|
+
if (cached) {
|
|
38933
|
+
return cached;
|
|
38934
|
+
}
|
|
38935
|
+
const url = this.config.trovesStrategiesApiUrl ?? DEFAULT_TROVES_STRATEGIES_API;
|
|
38936
|
+
try {
|
|
38937
|
+
const res = await fetch(url);
|
|
38938
|
+
if (!res.ok) {
|
|
38939
|
+
logger.warn(`${_SvkTrovesAdapter.name}::getAPY: HTTP ${res.status} from ${url}`);
|
|
38940
|
+
const fallback = { apy: 0, type: "base" /* BASE */ };
|
|
38941
|
+
this.setCache(CACHE_KEY, fallback, 3e5);
|
|
38942
|
+
return fallback;
|
|
38943
|
+
}
|
|
38944
|
+
const body = await res.json();
|
|
38945
|
+
const row = body.strategies?.find((s) => s.id === this.config.trovesStrategyId);
|
|
38946
|
+
if (!row) {
|
|
38947
|
+
logger.warn(
|
|
38948
|
+
`${_SvkTrovesAdapter.name}::getAPY: strategy id not found: ${this.config.trovesStrategyId}`
|
|
38949
|
+
);
|
|
38950
|
+
const fallback = { apy: 0, type: "base" /* BASE */ };
|
|
38951
|
+
this.setCache(CACHE_KEY, fallback, 3e5);
|
|
38952
|
+
return fallback;
|
|
38953
|
+
}
|
|
38954
|
+
const apy = parseTrovesApyField(row.apy);
|
|
38955
|
+
const result = { apy, type: "base" /* BASE */ };
|
|
38956
|
+
this.setCache(CACHE_KEY, result, 3e5);
|
|
38957
|
+
return result;
|
|
38958
|
+
} catch (error) {
|
|
38959
|
+
logger.error(`${_SvkTrovesAdapter.name}::getAPY:`, error);
|
|
38960
|
+
throw error;
|
|
38961
|
+
}
|
|
38962
|
+
}
|
|
38963
|
+
async getPosition(supportedPosition) {
|
|
38964
|
+
const CACHE_KEY = `svk_pos_${this.config.strategyVault.address}_${this._positionOwner().address}`;
|
|
38965
|
+
const cached = this.getCache(CACHE_KEY);
|
|
38966
|
+
if (cached) {
|
|
38967
|
+
return cached;
|
|
38968
|
+
}
|
|
38969
|
+
try {
|
|
38970
|
+
const vault = new Contract14({
|
|
38971
|
+
abi: universal_vault_abi_default,
|
|
38972
|
+
address: this.config.strategyVault.address,
|
|
38973
|
+
providerOrAccount: this.config.networkConfig.provider
|
|
38974
|
+
});
|
|
38975
|
+
const owner = this._positionOwner();
|
|
38976
|
+
const decimals = supportedPosition.asset.decimals;
|
|
38977
|
+
const shares = await vault.balance_of(owner.address);
|
|
38978
|
+
const shareU256 = uint25619.bnToUint256(shares);
|
|
38979
|
+
const liquidAssetsRaw = await vault.convert_to_assets(shareU256);
|
|
38980
|
+
const liquid = Web3Number.fromWei(liquidAssetsRaw.toString(), decimals);
|
|
38981
|
+
let pending = Web3Number.fromWei("0", decimals);
|
|
38982
|
+
try {
|
|
38983
|
+
const dueRaw = await vault.call("due_assets_from_owner", [owner.address]);
|
|
38984
|
+
pending = Web3Number.fromWei(dueRaw.toString(), decimals);
|
|
38985
|
+
} catch (e) {
|
|
38986
|
+
logger.warn(
|
|
38987
|
+
`${_SvkTrovesAdapter.name}::getPosition: due_assets_from_owner failed (treating as 0): ${e.message}`
|
|
38988
|
+
);
|
|
38989
|
+
}
|
|
38990
|
+
const total = liquid.plus(pending);
|
|
38991
|
+
const remarks = `Troves ${this.config.trovesStrategyId} holdings`;
|
|
38992
|
+
const result = {
|
|
38993
|
+
amount: total,
|
|
38994
|
+
remarks
|
|
38995
|
+
};
|
|
38996
|
+
this.setCache(CACHE_KEY, result, 6e4);
|
|
38997
|
+
return result;
|
|
38998
|
+
} catch (error) {
|
|
38999
|
+
logger.error(`${_SvkTrovesAdapter.name}::getPosition:`, error);
|
|
39000
|
+
throw error;
|
|
39001
|
+
}
|
|
39002
|
+
}
|
|
39003
|
+
async maxDeposit(amount) {
|
|
39004
|
+
const baseToken = this.config.baseToken;
|
|
39005
|
+
if (!amount) {
|
|
39006
|
+
return {
|
|
39007
|
+
tokenInfo: baseToken,
|
|
39008
|
+
amount: new Web3Number("999999999999999999999999999", baseToken.decimals),
|
|
39009
|
+
usdValue: 1e27,
|
|
39010
|
+
remarks: "Max deposit (unbounded placeholder)",
|
|
39011
|
+
apy: await this.getAPY({ asset: baseToken, isDebt: false }),
|
|
39012
|
+
protocol: this.protocol
|
|
39013
|
+
};
|
|
39014
|
+
}
|
|
39015
|
+
const usdValue = await this.getUSDValue(baseToken, amount);
|
|
39016
|
+
return {
|
|
39017
|
+
tokenInfo: baseToken,
|
|
39018
|
+
amount,
|
|
39019
|
+
usdValue,
|
|
39020
|
+
remarks: "Deposit amount",
|
|
39021
|
+
apy: await this.getAPY({ asset: baseToken, isDebt: false }),
|
|
39022
|
+
protocol: this.protocol
|
|
39023
|
+
};
|
|
39024
|
+
}
|
|
39025
|
+
async maxWithdraw() {
|
|
39026
|
+
const baseToken = this.config.baseToken;
|
|
39027
|
+
const current = await this.getPosition({ asset: baseToken, isDebt: false });
|
|
39028
|
+
const pos = current ?? { amount: new Web3Number("0", baseToken.decimals), remarks: "" };
|
|
39029
|
+
const usdValue = await this.getUSDValue(baseToken, pos.amount);
|
|
39030
|
+
return {
|
|
39031
|
+
tokenInfo: baseToken,
|
|
39032
|
+
amount: pos.amount,
|
|
39033
|
+
usdValue,
|
|
39034
|
+
remarks: "Max withdraw (liquid + pending redemption, underlying units)",
|
|
39035
|
+
apy: await this.getAPY({ asset: baseToken, isDebt: false }),
|
|
39036
|
+
protocol: this.protocol
|
|
39037
|
+
};
|
|
39038
|
+
}
|
|
39039
|
+
_getDepositLeaf() {
|
|
39040
|
+
const baseToken = this.config.baseToken;
|
|
39041
|
+
const strategyVault = this.config.strategyVault;
|
|
39042
|
+
const receiver = this.config.vaultAllocator;
|
|
39043
|
+
return [
|
|
39044
|
+
{
|
|
39045
|
+
target: baseToken.address,
|
|
39046
|
+
method: "approve",
|
|
39047
|
+
packedArguments: [strategyVault.toBigInt()],
|
|
39048
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
39049
|
+
id: this._depositApproveProofReadableId()
|
|
39050
|
+
},
|
|
39051
|
+
{
|
|
39052
|
+
target: strategyVault,
|
|
39053
|
+
method: "deposit",
|
|
39054
|
+
packedArguments: [receiver.toBigInt()],
|
|
39055
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
39056
|
+
id: this._depositCallProofReadableId()
|
|
39057
|
+
}
|
|
39058
|
+
];
|
|
39059
|
+
}
|
|
39060
|
+
_getWithdrawLeaf() {
|
|
39061
|
+
const strategyVault = this.config.strategyVault;
|
|
39062
|
+
const recv = this.config.vaultAllocator;
|
|
39063
|
+
const owner = this.config.vaultAllocator;
|
|
39064
|
+
return [
|
|
39065
|
+
{
|
|
39066
|
+
target: strategyVault,
|
|
39067
|
+
method: "withdraw",
|
|
39068
|
+
packedArguments: [recv.toBigInt(), owner.toBigInt()],
|
|
39069
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
39070
|
+
id: this._withdrawCallProofReadableId()
|
|
39071
|
+
}
|
|
39072
|
+
];
|
|
39073
|
+
}
|
|
39074
|
+
getDepositAdapter() {
|
|
39075
|
+
const leafConfigs = this._getDepositLeaf();
|
|
39076
|
+
const leaves = leafConfigs.map((config) => {
|
|
39077
|
+
const { target, method, packedArguments, sanitizer, id } = config;
|
|
39078
|
+
return this.constructSimpleLeafData({ id, target, method, packedArguments }, sanitizer);
|
|
39079
|
+
});
|
|
39080
|
+
return { leaves, callConstructor: this.getDepositCall.bind(this) };
|
|
39081
|
+
}
|
|
39082
|
+
getWithdrawAdapter() {
|
|
39083
|
+
const leafConfigs = this._getWithdrawLeaf();
|
|
39084
|
+
const leaves = leafConfigs.map((config) => {
|
|
39085
|
+
const { target, method, packedArguments, sanitizer, id } = config;
|
|
39086
|
+
return this.constructSimpleLeafData({ id, target, method, packedArguments }, sanitizer);
|
|
39087
|
+
});
|
|
39088
|
+
return { leaves, callConstructor: this.getWithdrawCall.bind(this) };
|
|
39089
|
+
}
|
|
39090
|
+
async getDepositCall(params) {
|
|
39091
|
+
const baseToken = this.config.baseToken;
|
|
39092
|
+
const strategyVault = this.config.strategyVault;
|
|
39093
|
+
const amount = params.amount;
|
|
39094
|
+
const uint256Amount = uint25619.bnToUint256(amount.toWei());
|
|
39095
|
+
const receiver = this.config.vaultAllocator;
|
|
39096
|
+
return [
|
|
39097
|
+
{
|
|
39098
|
+
proofReadableId: this._depositApproveProofReadableId(),
|
|
39099
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
39100
|
+
call: {
|
|
39101
|
+
contractAddress: baseToken.address,
|
|
39102
|
+
selector: hash11.getSelectorFromName("approve"),
|
|
39103
|
+
calldata: [
|
|
39104
|
+
strategyVault.toBigInt(),
|
|
39105
|
+
toBigInt(uint256Amount.low.toString()),
|
|
39106
|
+
toBigInt(uint256Amount.high.toString())
|
|
39107
|
+
]
|
|
39108
|
+
}
|
|
39109
|
+
},
|
|
39110
|
+
{
|
|
39111
|
+
proofReadableId: this._depositCallProofReadableId(),
|
|
39112
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
39113
|
+
call: {
|
|
39114
|
+
contractAddress: strategyVault,
|
|
39115
|
+
selector: hash11.getSelectorFromName("deposit"),
|
|
39116
|
+
calldata: [
|
|
39117
|
+
toBigInt(uint256Amount.low.toString()),
|
|
39118
|
+
toBigInt(uint256Amount.high.toString()),
|
|
39119
|
+
receiver.toBigInt()
|
|
39120
|
+
]
|
|
39121
|
+
}
|
|
39122
|
+
}
|
|
39123
|
+
];
|
|
39124
|
+
}
|
|
39125
|
+
async getWithdrawCall(params) {
|
|
39126
|
+
const strategyVault = this.config.strategyVault;
|
|
39127
|
+
const amount = params.amount;
|
|
39128
|
+
const uint256Amount = uint25619.bnToUint256(amount.toWei());
|
|
39129
|
+
const recv = this.config.vaultAllocator;
|
|
39130
|
+
const owner = this.config.vaultAllocator;
|
|
39131
|
+
return [
|
|
39132
|
+
{
|
|
39133
|
+
proofReadableId: this._withdrawCallProofReadableId(),
|
|
39134
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
39135
|
+
call: {
|
|
39136
|
+
contractAddress: strategyVault,
|
|
39137
|
+
selector: hash11.getSelectorFromName("withdraw"),
|
|
39138
|
+
calldata: [
|
|
39139
|
+
toBigInt(uint256Amount.low.toString()),
|
|
39140
|
+
toBigInt(uint256Amount.high.toString()),
|
|
39141
|
+
recv.toBigInt(),
|
|
39142
|
+
owner.toBigInt()
|
|
39143
|
+
]
|
|
39144
|
+
}
|
|
39145
|
+
}
|
|
39146
|
+
];
|
|
39147
|
+
}
|
|
39148
|
+
getHealthFactor() {
|
|
39149
|
+
return Promise.resolve(10);
|
|
39150
|
+
}
|
|
39151
|
+
};
|
|
39152
|
+
|
|
39153
|
+
// src/strategies/universal-strategy.tsx
|
|
39154
|
+
import { CallData, Contract as Contract15, num as num12, uint256 as uint25620 } from "starknet";
|
|
39155
|
+
|
|
38834
39156
|
// src/data/vault-manager.abi.json
|
|
38835
39157
|
var vault_manager_abi_default = [
|
|
38836
39158
|
{
|
|
@@ -39496,12 +39818,12 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
39496
39818
|
);
|
|
39497
39819
|
this.metadata = metadata;
|
|
39498
39820
|
this.address = metadata.address;
|
|
39499
|
-
this.contract = new
|
|
39821
|
+
this.contract = new Contract15({
|
|
39500
39822
|
abi: universal_vault_abi_default,
|
|
39501
39823
|
address: this.address.address,
|
|
39502
39824
|
providerOrAccount: this.config.provider
|
|
39503
39825
|
});
|
|
39504
|
-
this.managerContract = new
|
|
39826
|
+
this.managerContract = new Contract15({
|
|
39505
39827
|
abi: vault_manager_abi_default,
|
|
39506
39828
|
address: this.metadata.additionalInfo.manager.address,
|
|
39507
39829
|
providerOrAccount: this.config.provider
|
|
@@ -39555,17 +39877,17 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
39555
39877
|
amountInfo.tokenInfo.address.eq(this.asset().address),
|
|
39556
39878
|
"Deposit token mismatch"
|
|
39557
39879
|
);
|
|
39558
|
-
const assetContract = new
|
|
39880
|
+
const assetContract = new Contract15({
|
|
39559
39881
|
abi: universal_vault_abi_default,
|
|
39560
39882
|
address: this.asset().address.address,
|
|
39561
39883
|
providerOrAccount: this.config.provider
|
|
39562
39884
|
});
|
|
39563
39885
|
const call1 = assetContract.populate("approve", [
|
|
39564
39886
|
this.address.address,
|
|
39565
|
-
|
|
39887
|
+
uint25620.bnToUint256(amountInfo.amount.toWei())
|
|
39566
39888
|
]);
|
|
39567
39889
|
const call2 = this.contract.populate("deposit", [
|
|
39568
|
-
|
|
39890
|
+
uint25620.bnToUint256(amountInfo.amount.toWei()),
|
|
39569
39891
|
receiver.address
|
|
39570
39892
|
]);
|
|
39571
39893
|
return [call1, call2];
|
|
@@ -39575,9 +39897,9 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
39575
39897
|
amountInfo.tokenInfo.address.eq(this.asset().address),
|
|
39576
39898
|
"Withdraw token mismatch"
|
|
39577
39899
|
);
|
|
39578
|
-
const shares = await this.contract.call("convert_to_shares", [
|
|
39900
|
+
const shares = await this.contract.call("convert_to_shares", [uint25620.bnToUint256(amountInfo.amount.toWei())]);
|
|
39579
39901
|
const call = this.contract.populate("request_redeem", [
|
|
39580
|
-
|
|
39902
|
+
uint25620.bnToUint256(shares.toString()),
|
|
39581
39903
|
receiver.address,
|
|
39582
39904
|
owner.address
|
|
39583
39905
|
]);
|
|
@@ -39587,7 +39909,7 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
39587
39909
|
const shares = await this.contract.call("balanceOf", [user.address], { blockIdentifier });
|
|
39588
39910
|
const assets = await this.contract.call(
|
|
39589
39911
|
"convert_to_assets",
|
|
39590
|
-
[
|
|
39912
|
+
[uint25620.bnToUint256(shares)],
|
|
39591
39913
|
{ blockIdentifier }
|
|
39592
39914
|
);
|
|
39593
39915
|
const amount = Web3Number.fromWei(
|
|
@@ -40521,19 +40843,19 @@ var UniversalStrategies = [
|
|
|
40521
40843
|
];
|
|
40522
40844
|
|
|
40523
40845
|
// src/strategies/svk-strategy.ts
|
|
40524
|
-
import { Contract as
|
|
40846
|
+
import { Contract as Contract16, num as num13, uint256 as uint25621 } from "starknet";
|
|
40525
40847
|
var SVKStrategy = class extends BaseStrategy {
|
|
40526
40848
|
constructor(config, pricer, metadata) {
|
|
40527
40849
|
super(config);
|
|
40528
40850
|
this.pricer = pricer;
|
|
40529
40851
|
this.metadata = metadata;
|
|
40530
40852
|
this.address = metadata.address;
|
|
40531
|
-
this.contract = new
|
|
40853
|
+
this.contract = new Contract16({
|
|
40532
40854
|
abi: universal_vault_abi_default,
|
|
40533
40855
|
address: this.address.address,
|
|
40534
40856
|
providerOrAccount: this.config.provider
|
|
40535
40857
|
});
|
|
40536
|
-
this.managerContract = new
|
|
40858
|
+
this.managerContract = new Contract16({
|
|
40537
40859
|
abi: vault_manager_abi_default,
|
|
40538
40860
|
address: this.metadata.additionalInfo.manager.address,
|
|
40539
40861
|
providerOrAccount: this.config.provider
|
|
@@ -40550,17 +40872,17 @@ var SVKStrategy = class extends BaseStrategy {
|
|
|
40550
40872
|
amountInfo.tokenInfo.address.eq(this.asset().address),
|
|
40551
40873
|
"Deposit token mismatch"
|
|
40552
40874
|
);
|
|
40553
|
-
const assetContract = new
|
|
40875
|
+
const assetContract = new Contract16({
|
|
40554
40876
|
abi: universal_vault_abi_default,
|
|
40555
40877
|
address: this.asset().address.address,
|
|
40556
40878
|
providerOrAccount: this.config.provider
|
|
40557
40879
|
});
|
|
40558
40880
|
const call1 = assetContract.populate("approve", [
|
|
40559
40881
|
this.address.address,
|
|
40560
|
-
|
|
40882
|
+
uint25621.bnToUint256(amountInfo.amount.toWei())
|
|
40561
40883
|
]);
|
|
40562
40884
|
const call2 = this.contract.populate("deposit", [
|
|
40563
|
-
|
|
40885
|
+
uint25621.bnToUint256(amountInfo.amount.toWei()),
|
|
40564
40886
|
receiver.address
|
|
40565
40887
|
]);
|
|
40566
40888
|
return [call1, call2];
|
|
@@ -40570,9 +40892,9 @@ var SVKStrategy = class extends BaseStrategy {
|
|
|
40570
40892
|
amountInfo.tokenInfo.address.eq(this.asset().address),
|
|
40571
40893
|
"Withdraw token mismatch"
|
|
40572
40894
|
);
|
|
40573
|
-
const shares = await this.contract.call("convert_to_shares", [
|
|
40895
|
+
const shares = await this.contract.call("convert_to_shares", [uint25621.bnToUint256(amountInfo.amount.toWei())]);
|
|
40574
40896
|
const call = this.contract.populate("request_redeem", [
|
|
40575
|
-
|
|
40897
|
+
uint25621.bnToUint256(shares.toString()),
|
|
40576
40898
|
receiver.address,
|
|
40577
40899
|
owner.address
|
|
40578
40900
|
]);
|
|
@@ -40763,7 +41085,7 @@ var SVKStrategy = class extends BaseStrategy {
|
|
|
40763
41085
|
};
|
|
40764
41086
|
|
|
40765
41087
|
// src/strategies/universal-lst-muliplier-strategy.tsx
|
|
40766
|
-
import { Contract as
|
|
41088
|
+
import { Contract as Contract17, uint256 as uint25622 } from "starknet";
|
|
40767
41089
|
|
|
40768
41090
|
// src/strategies/universal-adapters/adapter-optimizer.ts
|
|
40769
41091
|
var AdapterOptimizer = class {
|
|
@@ -40916,15 +41238,15 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
40916
41238
|
async getLSTExchangeRate() {
|
|
40917
41239
|
const vesuAdapter1 = this.getVesuSameTokenAdapter();
|
|
40918
41240
|
const lstTokenInfo = vesuAdapter1._vesuAdapter.config.collateral;
|
|
40919
|
-
const lstABI = new
|
|
41241
|
+
const lstABI = new Contract17({
|
|
40920
41242
|
abi: erc4626_abi_default,
|
|
40921
41243
|
address: lstTokenInfo.address.address,
|
|
40922
41244
|
providerOrAccount: this.config.provider
|
|
40923
41245
|
});
|
|
40924
41246
|
const price = await lstABI.call("convert_to_assets", [
|
|
40925
|
-
|
|
41247
|
+
uint25622.bnToUint256(new Web3Number(1, lstTokenInfo.decimals).toWei())
|
|
40926
41248
|
]);
|
|
40927
|
-
const exchangeRate = Number(
|
|
41249
|
+
const exchangeRate = Number(uint25622.uint256ToBN(price).toString()) / Math.pow(10, lstTokenInfo.decimals);
|
|
40928
41250
|
logger.verbose(`${this.getTag()}:: LST Exchange Rate: ${exchangeRate}`);
|
|
40929
41251
|
return exchangeRate;
|
|
40930
41252
|
}
|
|
@@ -41794,6 +42116,249 @@ var HyperLSTStrategies = [
|
|
|
41794
42116
|
getStrategySettings("mRe7YIELD", "mRe7YIELD", hypermRe7YIELD, false, false)
|
|
41795
42117
|
];
|
|
41796
42118
|
|
|
42119
|
+
// src/strategies/vesu-extended-strategy/services/ltv-imbalance-rebalance-math.ts
|
|
42120
|
+
function ceilBtc(v, precision) {
|
|
42121
|
+
const f = 10 ** precision;
|
|
42122
|
+
return Math.ceil(v * f) / f;
|
|
42123
|
+
}
|
|
42124
|
+
function floorBtc(v, precision) {
|
|
42125
|
+
const f = 10 ** precision;
|
|
42126
|
+
return Math.floor(v * f) / f;
|
|
42127
|
+
}
|
|
42128
|
+
function isNegligible(btc, precision) {
|
|
42129
|
+
return Math.abs(btc) < 10 ** -precision;
|
|
42130
|
+
}
|
|
42131
|
+
function computeExtIdealMargin(posBtc, leverage, price) {
|
|
42132
|
+
return posBtc * price / leverage;
|
|
42133
|
+
}
|
|
42134
|
+
function computeExtDeficit(ext, price) {
|
|
42135
|
+
return Math.max(0, computeExtIdealMargin(ext.positionBtc, ext.leverage, price) - ext.equity);
|
|
42136
|
+
}
|
|
42137
|
+
function computeVesuHF(vesu, price) {
|
|
42138
|
+
const collateralUsd = vesu.positionBtc * price;
|
|
42139
|
+
if (collateralUsd === 0) return Infinity;
|
|
42140
|
+
const ltv = vesu.debt * vesu.debtPrice / collateralUsd;
|
|
42141
|
+
if (ltv === 0) return Infinity;
|
|
42142
|
+
return vesu.maxLTV / ltv;
|
|
42143
|
+
}
|
|
42144
|
+
function computeVesuDebtRepay(vesu, price) {
|
|
42145
|
+
const targetLTV = vesu.maxLTV / vesu.targetHF;
|
|
42146
|
+
const collateralUsd = vesu.positionBtc * price;
|
|
42147
|
+
const requiredDebt = targetLTV * collateralUsd / vesu.debtPrice;
|
|
42148
|
+
return Math.max(0, vesu.debt - requiredDebt);
|
|
42149
|
+
}
|
|
42150
|
+
function computeVesuTargetLTV(vesu) {
|
|
42151
|
+
return vesu.maxLTV / vesu.targetHF;
|
|
42152
|
+
}
|
|
42153
|
+
function computeVesuGrowthCost(gapBtc, vesu, price) {
|
|
42154
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
42155
|
+
return gapBtc * price * (1 - targetLTV);
|
|
42156
|
+
}
|
|
42157
|
+
function computeVesuGrowthDebt(gapBtc, vesu, price) {
|
|
42158
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
42159
|
+
return gapBtc * price * targetLTV / vesu.debtPrice;
|
|
42160
|
+
}
|
|
42161
|
+
function computeVesuGrowthFromEquity(equityUsd, vesu, price) {
|
|
42162
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
42163
|
+
return equityUsd / (price * (1 - targetLTV));
|
|
42164
|
+
}
|
|
42165
|
+
function emptyDeltas() {
|
|
42166
|
+
return {
|
|
42167
|
+
dExtPosition: 0,
|
|
42168
|
+
dVesuPosition: 0,
|
|
42169
|
+
dVesuDebt: 0,
|
|
42170
|
+
dExtAvlWithdraw: 0,
|
|
42171
|
+
dExtUpnl: 0,
|
|
42172
|
+
dVaUsd: 0,
|
|
42173
|
+
dWalletUsd: 0,
|
|
42174
|
+
dVesuBorrowCapacity: 0,
|
|
42175
|
+
dTransferVesuToExt: 0
|
|
42176
|
+
};
|
|
42177
|
+
}
|
|
42178
|
+
function mergeDeltas(a, b) {
|
|
42179
|
+
return {
|
|
42180
|
+
dExtPosition: a.dExtPosition + b.dExtPosition,
|
|
42181
|
+
dVesuPosition: a.dVesuPosition + b.dVesuPosition,
|
|
42182
|
+
dVesuDebt: a.dVesuDebt + b.dVesuDebt,
|
|
42183
|
+
dExtAvlWithdraw: a.dExtAvlWithdraw + b.dExtAvlWithdraw,
|
|
42184
|
+
dExtUpnl: a.dExtUpnl + b.dExtUpnl,
|
|
42185
|
+
dVaUsd: a.dVaUsd + b.dVaUsd,
|
|
42186
|
+
dWalletUsd: a.dWalletUsd + b.dWalletUsd,
|
|
42187
|
+
dVesuBorrowCapacity: a.dVesuBorrowCapacity + b.dVesuBorrowCapacity,
|
|
42188
|
+
dTransferVesuToExt: a.dTransferVesuToExt + b.dTransferVesuToExt
|
|
42189
|
+
};
|
|
42190
|
+
}
|
|
42191
|
+
function drawFunds(need, keys, pool) {
|
|
42192
|
+
const draws = {};
|
|
42193
|
+
let unmet = need;
|
|
42194
|
+
for (const k of keys) {
|
|
42195
|
+
if (unmet <= 0) break;
|
|
42196
|
+
const avail = pool[k];
|
|
42197
|
+
if (avail <= 0) continue;
|
|
42198
|
+
const take = Math.min(avail, unmet);
|
|
42199
|
+
draws[k] = take;
|
|
42200
|
+
pool[k] -= take;
|
|
42201
|
+
unmet -= take;
|
|
42202
|
+
}
|
|
42203
|
+
return { draws, filled: need - unmet, unmet };
|
|
42204
|
+
}
|
|
42205
|
+
function sumKeys(draws, keys) {
|
|
42206
|
+
return keys.reduce((s, k) => s + (draws[k] ?? 0), 0);
|
|
42207
|
+
}
|
|
42208
|
+
function applyDrawsToDeltas(d, draws, sign) {
|
|
42209
|
+
d.dVaUsd += sign * (draws.vaUsd ?? 0);
|
|
42210
|
+
d.dWalletUsd += sign * (draws.walletUsd ?? 0);
|
|
42211
|
+
d.dVesuBorrowCapacity += sign * (draws.vesuBorrowCapacity ?? 0);
|
|
42212
|
+
d.dExtAvlWithdraw += sign * (draws.extAvlWithdraw ?? 0);
|
|
42213
|
+
d.dExtUpnl += sign * (draws.extUpnl ?? 0);
|
|
42214
|
+
}
|
|
42215
|
+
function fixExtMargin(ext, price, pool) {
|
|
42216
|
+
const d = emptyDeltas();
|
|
42217
|
+
const deficit = computeExtDeficit(ext, price);
|
|
42218
|
+
if (deficit <= 0) return { d, unmet: 0 };
|
|
42219
|
+
const { draws, filled, unmet } = drawFunds(deficit, ["walletUsd", "vaUsd", "vesuBorrowCapacity"], pool);
|
|
42220
|
+
applyDrawsToDeltas(d, draws, -1);
|
|
42221
|
+
d.dExtAvlWithdraw += filled;
|
|
42222
|
+
const fromVesu = draws.vesuBorrowCapacity ?? 0;
|
|
42223
|
+
if (fromVesu > 0) d.dTransferVesuToExt += fromVesu;
|
|
42224
|
+
return { d, unmet };
|
|
42225
|
+
}
|
|
42226
|
+
function fixVesuMargin(vesu, price, pool, hfBuffer) {
|
|
42227
|
+
const d = emptyDeltas();
|
|
42228
|
+
const hf = computeVesuHF(vesu, price);
|
|
42229
|
+
if (hf >= vesu.targetHF - hfBuffer) return { d, unmet: 0 };
|
|
42230
|
+
const repayTokens = computeVesuDebtRepay(vesu, price);
|
|
42231
|
+
const repayUsd = repayTokens * vesu.debtPrice;
|
|
42232
|
+
const { draws, filled, unmet } = drawFunds(repayUsd, ["vaUsd", "walletUsd", "extAvlWithdraw", "extUpnl"], pool);
|
|
42233
|
+
applyDrawsToDeltas(d, draws, -1);
|
|
42234
|
+
d.dVesuDebt -= filled / vesu.debtPrice;
|
|
42235
|
+
const fromExt = sumKeys(draws, ["extAvlWithdraw", "extUpnl"]);
|
|
42236
|
+
if (fromExt > 0) d.dTransferVesuToExt -= fromExt;
|
|
42237
|
+
return { d, unmet };
|
|
42238
|
+
}
|
|
42239
|
+
function phase1(ext, vesu, price, pool, config) {
|
|
42240
|
+
const extResult = fixExtMargin(ext, price, pool);
|
|
42241
|
+
const vesuResult = fixVesuMargin(vesu, price, pool, config.hfBuffer);
|
|
42242
|
+
return {
|
|
42243
|
+
deltas: mergeDeltas(extResult.d, vesuResult.d),
|
|
42244
|
+
extDeficitRemaining: extResult.unmet,
|
|
42245
|
+
vesuRepayRemaining: vesuResult.unmet
|
|
42246
|
+
};
|
|
42247
|
+
}
|
|
42248
|
+
function solveUnifiedF(extPos, vesuPos, extEquity, vesuDebt, vesu, extLev, price) {
|
|
42249
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
42250
|
+
const k = 1 - targetLTV + 1 / extLev;
|
|
42251
|
+
const totalEquity = extEquity + vesuPos * price - vesuDebt * vesu.debtPrice;
|
|
42252
|
+
return totalEquity / (price * k);
|
|
42253
|
+
}
|
|
42254
|
+
function solveTransfer(vesuPos, vesuDebt, F, vesu, price) {
|
|
42255
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
42256
|
+
return vesuPos * price - vesuDebt * vesu.debtPrice - F * price * (1 - targetLTV);
|
|
42257
|
+
}
|
|
42258
|
+
function solveDebtRepay(vesuDebt, F, vesu, price) {
|
|
42259
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
42260
|
+
return vesuDebt - targetLTV * F * price / vesu.debtPrice;
|
|
42261
|
+
}
|
|
42262
|
+
function roundFinalPosition(extPos, vesuPos, rawF, precision) {
|
|
42263
|
+
let fFromExt;
|
|
42264
|
+
if (rawF < extPos) {
|
|
42265
|
+
const closeExt = ceilBtc(extPos - rawF, precision);
|
|
42266
|
+
fFromExt = extPos - closeExt;
|
|
42267
|
+
} else {
|
|
42268
|
+
const growExt = floorBtc(rawF - extPos, precision);
|
|
42269
|
+
fFromExt = extPos + growExt;
|
|
42270
|
+
}
|
|
42271
|
+
let fFromVesu;
|
|
42272
|
+
if (rawF < vesuPos) {
|
|
42273
|
+
const closeVesu = ceilBtc(vesuPos - rawF, precision);
|
|
42274
|
+
fFromVesu = vesuPos - closeVesu;
|
|
42275
|
+
} else {
|
|
42276
|
+
const growVesu = floorBtc(rawF - vesuPos, precision);
|
|
42277
|
+
fFromVesu = vesuPos + growVesu;
|
|
42278
|
+
}
|
|
42279
|
+
return Math.max(0, Math.min(fFromExt, fFromVesu));
|
|
42280
|
+
}
|
|
42281
|
+
function phase2(extPos, vesuPos, extEquity, vesuDebt, vesu, extLev, price, pool, precision) {
|
|
42282
|
+
const d = emptyDeltas();
|
|
42283
|
+
const targetLTV = computeVesuTargetLTV(vesu);
|
|
42284
|
+
const imbalance = extPos - vesuPos;
|
|
42285
|
+
let fundedGrowthBtc = 0;
|
|
42286
|
+
if (!isNegligible(imbalance, precision)) {
|
|
42287
|
+
if (imbalance > 0) {
|
|
42288
|
+
const equityCostUsd = computeVesuGrowthCost(imbalance, vesu, price);
|
|
42289
|
+
const { draws, filled } = drawFunds(equityCostUsd, ["vaUsd", "walletUsd", "extAvlWithdraw", "extUpnl"], pool);
|
|
42290
|
+
applyDrawsToDeltas(d, draws, -1);
|
|
42291
|
+
const grownBtc = computeVesuGrowthFromEquity(filled, vesu, price);
|
|
42292
|
+
d.dVesuPosition += grownBtc;
|
|
42293
|
+
fundedGrowthBtc = grownBtc;
|
|
42294
|
+
d.dVesuDebt += computeVesuGrowthDebt(grownBtc, vesu, price);
|
|
42295
|
+
const fromExt = sumKeys(draws, ["extAvlWithdraw", "extUpnl"]);
|
|
42296
|
+
if (fromExt > 0) d.dTransferVesuToExt -= fromExt;
|
|
42297
|
+
} else {
|
|
42298
|
+
const absImbalance = -imbalance;
|
|
42299
|
+
const marginCostUsd = absImbalance * price / extLev;
|
|
42300
|
+
const { draws, filled } = drawFunds(marginCostUsd, ["walletUsd", "vaUsd", "vesuBorrowCapacity"], pool);
|
|
42301
|
+
applyDrawsToDeltas(d, draws, -1);
|
|
42302
|
+
const grownBtc = filled * extLev / price;
|
|
42303
|
+
d.dExtPosition += grownBtc;
|
|
42304
|
+
fundedGrowthBtc = grownBtc;
|
|
42305
|
+
const fromVesu = draws.vesuBorrowCapacity ?? 0;
|
|
42306
|
+
if (fromVesu > 0) d.dTransferVesuToExt += fromVesu;
|
|
42307
|
+
}
|
|
42308
|
+
}
|
|
42309
|
+
const effExtPos = extPos + d.dExtPosition;
|
|
42310
|
+
const effVesuPos = vesuPos + d.dVesuPosition;
|
|
42311
|
+
const effExtEquity = extEquity;
|
|
42312
|
+
const effVesuDebt = vesuDebt + d.dVesuDebt;
|
|
42313
|
+
const rawF = solveUnifiedF(effExtPos, effVesuPos, effExtEquity, effVesuDebt, vesu, extLev, price);
|
|
42314
|
+
const cappedF = Math.min(rawF, Math.max(effExtPos, effVesuPos));
|
|
42315
|
+
const maxGrowableTo = Math.max(effExtPos, effVesuPos);
|
|
42316
|
+
const targetF = Math.max(0, Math.min(cappedF, maxGrowableTo));
|
|
42317
|
+
const remainingImbalance = effExtPos - effVesuPos;
|
|
42318
|
+
const extNeedsMore = effExtEquity < computeExtIdealMargin(effExtPos, extLev, price);
|
|
42319
|
+
const vesuCurrentLTV = effVesuPos > 0 ? effVesuDebt * vesu.debtPrice / (effVesuPos * price) : 0;
|
|
42320
|
+
const vesuNeedsMore = vesuCurrentLTV > targetLTV;
|
|
42321
|
+
const needsFurtherAction = !isNegligible(remainingImbalance, precision) || extNeedsMore || vesuNeedsMore;
|
|
42322
|
+
if (!needsFurtherAction) {
|
|
42323
|
+
return d;
|
|
42324
|
+
}
|
|
42325
|
+
const F = roundFinalPosition(effExtPos, effVesuPos, targetF, precision);
|
|
42326
|
+
const dx = F - effExtPos;
|
|
42327
|
+
const dy = F - effVesuPos;
|
|
42328
|
+
if (isNegligible(dx, precision) && isNegligible(dy, precision)) {
|
|
42329
|
+
return d;
|
|
42330
|
+
}
|
|
42331
|
+
d.dExtPosition += dx;
|
|
42332
|
+
d.dVesuPosition += dy;
|
|
42333
|
+
const debtRepay = solveDebtRepay(effVesuDebt, F, vesu, price);
|
|
42334
|
+
d.dVesuDebt -= debtRepay;
|
|
42335
|
+
const T = solveTransfer(effVesuPos, effVesuDebt, F, vesu, price);
|
|
42336
|
+
d.dTransferVesuToExt += T;
|
|
42337
|
+
d.dExtAvlWithdraw += T;
|
|
42338
|
+
return d;
|
|
42339
|
+
}
|
|
42340
|
+
function rebalance(inputs) {
|
|
42341
|
+
const { ext, vesu, btcPrice, config } = inputs;
|
|
42342
|
+
const pool = { ...inputs.funding };
|
|
42343
|
+
const p1 = phase1(ext, vesu, btcPrice, pool, config);
|
|
42344
|
+
const effExtPos = ext.positionBtc + p1.deltas.dExtPosition;
|
|
42345
|
+
const effVesuPos = vesu.positionBtc + p1.deltas.dVesuPosition;
|
|
42346
|
+
const effExtEquity = ext.equity + p1.deltas.dExtAvlWithdraw + p1.deltas.dExtUpnl;
|
|
42347
|
+
const effVesuDebt = vesu.debt + p1.deltas.dVesuDebt;
|
|
42348
|
+
const p2 = phase2(
|
|
42349
|
+
effExtPos,
|
|
42350
|
+
effVesuPos,
|
|
42351
|
+
effExtEquity,
|
|
42352
|
+
effVesuDebt,
|
|
42353
|
+
vesu,
|
|
42354
|
+
ext.leverage,
|
|
42355
|
+
btcPrice,
|
|
42356
|
+
pool,
|
|
42357
|
+
config.positionPrecision
|
|
42358
|
+
);
|
|
42359
|
+
return mergeDeltas(p1.deltas, p2);
|
|
42360
|
+
}
|
|
42361
|
+
|
|
41797
42362
|
// src/strategies/vesu-extended-strategy/services/extended-vesu-state-manager.ts
|
|
41798
42363
|
var RouteType = /* @__PURE__ */ ((RouteType2) => {
|
|
41799
42364
|
RouteType2["WALLET_TO_EXTENDED"] = "WALLET_TO_EXTENDED";
|
|
@@ -41825,6 +42390,7 @@ var CaseCategory = /* @__PURE__ */ ((CaseCategory2) => {
|
|
|
41825
42390
|
return CaseCategory2;
|
|
41826
42391
|
})(CaseCategory || {});
|
|
41827
42392
|
var CaseId = /* @__PURE__ */ ((CaseId2) => {
|
|
42393
|
+
CaseId2["MANAGE_LTV"] = "MANAGE_LTV";
|
|
41828
42394
|
CaseId2["LTV_VESU_LOW_TO_EXTENDED"] = "LTV_VESU_LOW_TO_EXTENDED";
|
|
41829
42395
|
CaseId2["LTV_EXTENDED_PROFITABLE_AVAILABLE"] = "LTV_EXTENDED_PROFITABLE_AVAILABLE";
|
|
41830
42396
|
CaseId2["LTV_EXTENDED_PROFITABLE_REALIZE"] = "LTV_EXTENDED_PROFITABLE_REALIZE";
|
|
@@ -41849,19 +42415,56 @@ function safeUsdcWeb3Number(value) {
|
|
|
41849
42415
|
return new Web3Number(value.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS);
|
|
41850
42416
|
}
|
|
41851
42417
|
var CASE_ROUTE_TYPES = {
|
|
41852
|
-
// LTV Rebalance —
|
|
42418
|
+
// LTV Rebalance — unified
|
|
42419
|
+
["MANAGE_LTV" /* MANAGE_LTV */]: [
|
|
42420
|
+
"REALISE_PNL" /* REALISE_PNL */,
|
|
42421
|
+
"EXTENDED_TO_WALLET" /* EXTENDED_TO_WALLET */,
|
|
42422
|
+
"RETURN_TO_WAIT" /* RETURN_TO_WAIT */,
|
|
42423
|
+
"WALLET_TO_VA" /* WALLET_TO_VA */,
|
|
42424
|
+
"VESU_BORROW" /* VESU_BORROW */,
|
|
42425
|
+
"VESU_REPAY" /* VESU_REPAY */,
|
|
42426
|
+
"VA_TO_EXTENDED" /* VA_TO_EXTENDED */,
|
|
42427
|
+
"VESU_MULTIPLY_DECREASE_LEVER" /* VESU_MULTIPLY_DECREASE_LEVER */,
|
|
42428
|
+
"VESU_MULTIPLY_INCREASE_LEVER" /* VESU_MULTIPLY_INCREASE_LEVER */,
|
|
42429
|
+
"AVNU_DEPOSIT_SWAP" /* AVNU_DEPOSIT_SWAP */,
|
|
42430
|
+
"EXTENDED_DECREASE_LEVER" /* EXTENDED_DECREASE_LEVER */,
|
|
42431
|
+
"EXTENDED_INCREASE_LEVER" /* EXTENDED_INCREASE_LEVER */,
|
|
42432
|
+
// Second-phase VA / Extended funding after lever routes (same types may repeat).
|
|
42433
|
+
"RETURN_TO_WAIT" /* RETURN_TO_WAIT */,
|
|
42434
|
+
"WALLET_TO_VA" /* WALLET_TO_VA */,
|
|
42435
|
+
"VA_TO_EXTENDED" /* VA_TO_EXTENDED */
|
|
42436
|
+
],
|
|
42437
|
+
/** @deprecated */
|
|
41853
42438
|
["LTV_VESU_HIGH_USE_VA_OR_WALLET" /* LTV_VESU_HIGH_USE_VA_OR_WALLET */]: ["WALLET_TO_VA" /* WALLET_TO_VA */, "VESU_REPAY" /* VESU_REPAY */],
|
|
41854
|
-
|
|
42439
|
+
/** @deprecated */
|
|
41855
42440
|
["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 */],
|
|
42441
|
+
/** @deprecated */
|
|
41856
42442
|
["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 */],
|
|
41857
|
-
|
|
42443
|
+
/** @deprecated */
|
|
41858
42444
|
["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 */],
|
|
42445
|
+
/** @deprecated */
|
|
41859
42446
|
["LTV_VESU_LOW_TO_EXTENDED" /* LTV_VESU_LOW_TO_EXTENDED */]: ["VESU_BORROW" /* VESU_BORROW */, "VA_TO_EXTENDED" /* VA_TO_EXTENDED */],
|
|
41860
42447
|
// New Deposits
|
|
41861
42448
|
// @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
|
|
41862
42449
|
// Sequence: fund-movement transfers first (WALLET_TO_EXTENDED, VA_TO_EXTENDED, WALLET_TO_VA, EXTENDED_TO_WALLET),
|
|
41863
42450
|
// then RETURN_TO_WAIT, then optional second WALLET_TO_VA + RETURN_TO_WAIT, then lever routes.
|
|
41864
|
-
["DEPOSIT_FRESH_VAULT" /* DEPOSIT_FRESH_VAULT */]: [
|
|
42451
|
+
["DEPOSIT_FRESH_VAULT" /* DEPOSIT_FRESH_VAULT */]: [
|
|
42452
|
+
// May repeat after MANAGE_LTV (VA top-up → Extended → wait → levers).
|
|
42453
|
+
"WALLET_TO_VA" /* WALLET_TO_VA */,
|
|
42454
|
+
"VA_TO_EXTENDED" /* VA_TO_EXTENDED */,
|
|
42455
|
+
"RETURN_TO_WAIT" /* RETURN_TO_WAIT */,
|
|
42456
|
+
"VA_TO_EXTENDED" /* VA_TO_EXTENDED */,
|
|
42457
|
+
"VESU_BORROW" /* VESU_BORROW */,
|
|
42458
|
+
"WALLET_TO_EXTENDED" /* WALLET_TO_EXTENDED */,
|
|
42459
|
+
"VA_TO_EXTENDED" /* VA_TO_EXTENDED */,
|
|
42460
|
+
"WALLET_TO_VA" /* WALLET_TO_VA */,
|
|
42461
|
+
"EXTENDED_TO_WALLET" /* EXTENDED_TO_WALLET */,
|
|
42462
|
+
"RETURN_TO_WAIT" /* RETURN_TO_WAIT */,
|
|
42463
|
+
"WALLET_TO_VA" /* WALLET_TO_VA */,
|
|
42464
|
+
"AVNU_DEPOSIT_SWAP" /* AVNU_DEPOSIT_SWAP */,
|
|
42465
|
+
"VESU_MULTIPLY_INCREASE_LEVER" /* VESU_MULTIPLY_INCREASE_LEVER */,
|
|
42466
|
+
"EXTENDED_INCREASE_LEVER" /* EXTENDED_INCREASE_LEVER */
|
|
42467
|
+
],
|
|
41865
42468
|
["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 */],
|
|
41866
42469
|
["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 */],
|
|
41867
42470
|
["DEPOSIT_COMBINATION" /* DEPOSIT_COMBINATION */]: [],
|
|
@@ -41884,6 +42487,17 @@ var CASE_ROUTE_TYPES = {
|
|
|
41884
42487
|
["IMBALANCE_VESU_EXCESS_LONG_NO_FUNDS" /* IMBALANCE_VESU_EXCESS_LONG_NO_FUNDS */]: ["VESU_MULTIPLY_DECREASE_LEVER" /* VESU_MULTIPLY_DECREASE_LEVER */]
|
|
41885
42488
|
};
|
|
41886
42489
|
var CASE_DEFINITIONS = {
|
|
42490
|
+
["MANAGE_LTV" /* MANAGE_LTV */]: {
|
|
42491
|
+
id: "MANAGE_LTV" /* MANAGE_LTV */,
|
|
42492
|
+
category: "LTV_REBALANCE" /* LTV_REBALANCE */,
|
|
42493
|
+
title: "LTV Rebalance: Unified Vesu repay + Extended margin management",
|
|
42494
|
+
description: "Manages both Vesu high-LTV repayment and Extended low-margin funding in a single pass.",
|
|
42495
|
+
steps: [
|
|
42496
|
+
"Compute vesu repay needed and extended margin needed",
|
|
42497
|
+
"Allocate funds: VA > Wallet > ExtAvl > ExtUpnl for Vesu; Wallet > VA > Borrow for Extended",
|
|
42498
|
+
"Build combined transfer and repay/margin routes"
|
|
42499
|
+
]
|
|
42500
|
+
},
|
|
41887
42501
|
["LTV_VESU_LOW_TO_EXTENDED" /* LTV_VESU_LOW_TO_EXTENDED */]: {
|
|
41888
42502
|
id: "LTV_VESU_LOW_TO_EXTENDED" /* LTV_VESU_LOW_TO_EXTENDED */,
|
|
41889
42503
|
category: "LTV_REBALANCE" /* LTV_REBALANCE */,
|
|
@@ -42106,199 +42720,590 @@ function routeSummary(r) {
|
|
|
42106
42720
|
}
|
|
42107
42721
|
var SolveBudget = class {
|
|
42108
42722
|
constructor(state) {
|
|
42109
|
-
|
|
42110
|
-
|
|
42111
|
-
|
|
42112
|
-
|
|
42113
|
-
|
|
42114
|
-
|
|
42115
|
-
this._extAvailTrade = 0;
|
|
42116
|
-
this._extPendingDeposit = 0;
|
|
42117
|
-
this._vesuBorrowCapacity = 0;
|
|
42118
|
-
this._totalUnused = 0;
|
|
42119
|
-
const buffer = state.limitBalanceBufferFactor;
|
|
42120
|
-
this.unusedBalance = state.unusedBalance.map((item) => {
|
|
42121
|
-
return {
|
|
42122
|
-
...item,
|
|
42123
|
-
amount: item.amount.multipliedBy(1 - buffer),
|
|
42124
|
-
usdValue: item.usdValue * (1 - buffer)
|
|
42125
|
-
};
|
|
42723
|
+
this.assetToken = state.assetToken;
|
|
42724
|
+
this.usdcToken = state.usdcToken;
|
|
42725
|
+
const cloneTb = (b) => ({
|
|
42726
|
+
token: b.token,
|
|
42727
|
+
amount: new Web3Number(b.amount.toFixed(b.token.decimals), b.token.decimals),
|
|
42728
|
+
usdValue: b.usdValue
|
|
42126
42729
|
});
|
|
42127
|
-
this.
|
|
42128
|
-
|
|
42129
|
-
|
|
42130
|
-
|
|
42131
|
-
|
|
42132
|
-
|
|
42133
|
-
|
|
42134
|
-
|
|
42135
|
-
|
|
42136
|
-
} : null;
|
|
42137
|
-
this.extendedPositions = state.extendedPositions;
|
|
42730
|
+
this.unusedBalance = state.unusedBalance.map((item) => cloneTb(item));
|
|
42731
|
+
this.walletBalance = state.walletBalance ? cloneTb(state.walletBalance) : null;
|
|
42732
|
+
this.vaultAssetBalance = state.vaultAssetBalance ? cloneTb(state.vaultAssetBalance) : null;
|
|
42733
|
+
this.vaultUsdcBalance = state.vaultUsdcBalance ? cloneTb(state.vaultUsdcBalance) : null;
|
|
42734
|
+
this.extendedPositions = state.extendedPositions.map((p) => ({
|
|
42735
|
+
...p,
|
|
42736
|
+
size: new Web3Number(p.size.toFixed(8), 8),
|
|
42737
|
+
valueUsd: new Web3Number(p.valueUsd.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS)
|
|
42738
|
+
}));
|
|
42138
42739
|
this.extendedBalance = state.extendedBalance ? {
|
|
42139
|
-
|
|
42140
|
-
|
|
42141
|
-
|
|
42142
|
-
|
|
42143
|
-
|
|
42740
|
+
equity: new Web3Number(
|
|
42741
|
+
state.extendedBalance.equity.toFixed(USDC_TOKEN_DECIMALS),
|
|
42742
|
+
USDC_TOKEN_DECIMALS
|
|
42743
|
+
),
|
|
42744
|
+
availableForTrade: new Web3Number(
|
|
42745
|
+
state.extendedBalance.availableForTrade.toFixed(USDC_TOKEN_DECIMALS),
|
|
42746
|
+
USDC_TOKEN_DECIMALS
|
|
42747
|
+
),
|
|
42748
|
+
availableForWithdrawal: new Web3Number(
|
|
42749
|
+
state.extendedBalance.availableForWithdrawal.toFixed(USDC_TOKEN_DECIMALS),
|
|
42750
|
+
USDC_TOKEN_DECIMALS
|
|
42751
|
+
),
|
|
42752
|
+
unrealisedPnl: new Web3Number(
|
|
42753
|
+
state.extendedBalance.unrealisedPnl.toFixed(USDC_TOKEN_DECIMALS),
|
|
42754
|
+
USDC_TOKEN_DECIMALS
|
|
42755
|
+
),
|
|
42756
|
+
balance: new Web3Number(
|
|
42757
|
+
state.extendedBalance.balance.toFixed(USDC_TOKEN_DECIMALS),
|
|
42758
|
+
USDC_TOKEN_DECIMALS
|
|
42759
|
+
),
|
|
42760
|
+
pendingDeposit: new Web3Number(
|
|
42761
|
+
state.extendedBalance.pendingDeposit.toFixed(USDC_TOKEN_DECIMALS),
|
|
42762
|
+
USDC_TOKEN_DECIMALS
|
|
42763
|
+
)
|
|
42144
42764
|
} : null;
|
|
42145
|
-
this.vesuPoolStates = state.vesuPoolStates
|
|
42765
|
+
this.vesuPoolStates = state.vesuPoolStates.map((p) => ({
|
|
42766
|
+
...p,
|
|
42767
|
+
collateralAmount: new Web3Number(
|
|
42768
|
+
p.collateralAmount.toFixed(p.collateralToken.decimals),
|
|
42769
|
+
p.collateralToken.decimals
|
|
42770
|
+
),
|
|
42771
|
+
debtAmount: new Web3Number(
|
|
42772
|
+
p.debtAmount.toFixed(p.debtToken.decimals),
|
|
42773
|
+
p.debtToken.decimals
|
|
42774
|
+
)
|
|
42775
|
+
}));
|
|
42146
42776
|
const vesuPerPoolDebtDeltasToBorrow = this._computeperPoolDebtDeltasToBorrow();
|
|
42147
42777
|
assert(vesuPerPoolDebtDeltasToBorrow.length === this.vesuPoolStates.length, "vesuPerPoolDebtDeltasToBorrow length must match vesuPoolStates length");
|
|
42148
42778
|
this.vesuPerPoolDebtDeltasToBorrow = vesuPerPoolDebtDeltasToBorrow.map((item) => item.deltaDebt);
|
|
42149
42779
|
this.shouldVesuRebalance = vesuPerPoolDebtDeltasToBorrow.map((item) => item.shouldRebalance);
|
|
42150
42780
|
}
|
|
42781
|
+
/** `1 - limitBalanceBufferFactor` — multiplier applied to raw notionals for “usable” USD. */
|
|
42782
|
+
_usableFraction() {
|
|
42783
|
+
return 1;
|
|
42784
|
+
}
|
|
42151
42785
|
/**
|
|
42152
|
-
*
|
|
42153
|
-
*
|
|
42154
|
-
|
|
42155
|
-
|
|
42156
|
-
|
|
42157
|
-
|
|
42786
|
+
* Raw USD notional for a token row. USDC (and configured {@link usdcToken}) uses 1:1 from amount;
|
|
42787
|
+
* non-stable assets (e.g. WBTC in VA) use {@link TokenBalance.usdValue} from the pricer at refresh.
|
|
42788
|
+
*/
|
|
42789
|
+
_rawTokenUsd(tb) {
|
|
42790
|
+
if (!tb) return 0;
|
|
42791
|
+
if (this.usdcToken.address.eq(tb.token.address)) {
|
|
42792
|
+
return Number(tb.amount.toFixed(tb.token.decimals));
|
|
42793
|
+
}
|
|
42794
|
+
return tb.usdValue;
|
|
42795
|
+
}
|
|
42796
|
+
/** Apply safety buffer to a raw USD scalar. */
|
|
42797
|
+
bufferedUsd(rawUsd) {
|
|
42798
|
+
return rawUsd * this._usableFraction();
|
|
42799
|
+
}
|
|
42800
|
+
/** Convert a buffered “usable” USD amount to raw nominal USD (inverse of {@link bufferedUsd}). */
|
|
42801
|
+
rawUsdFromBuffered(bufferedUsd) {
|
|
42802
|
+
const bf = this._usableFraction();
|
|
42803
|
+
assert(bf > 0, "SolveBudget::rawUsdFromBuffered usable fraction must be positive");
|
|
42804
|
+
return bufferedUsd / bf;
|
|
42805
|
+
}
|
|
42806
|
+
/** Buffered USD notional for one token balance row. */
|
|
42807
|
+
bufferedTokenUsd(tb) {
|
|
42808
|
+
return this.bufferedUsd(this._rawTokenUsd(tb));
|
|
42809
|
+
}
|
|
42810
|
+
logStateSummary() {
|
|
42811
|
+
console.log("===== state summary =====");
|
|
42812
|
+
const aggregatedData = {
|
|
42813
|
+
unusedBalances: this.unusedBalance.map((b) => ({
|
|
42814
|
+
token: b.token.symbol,
|
|
42815
|
+
amount: b.amount.toNumber()
|
|
42816
|
+
})),
|
|
42817
|
+
walletBalance: this.walletBalance ? {
|
|
42818
|
+
token: this.walletBalance.token.symbol,
|
|
42819
|
+
amount: this.walletBalance.amount.toNumber()
|
|
42820
|
+
} : void 0,
|
|
42821
|
+
vaultAssetBalance: this.vaultAssetBalance ? {
|
|
42822
|
+
token: this.vaultAssetBalance.token.symbol,
|
|
42823
|
+
amount: this.vaultAssetBalance.amount.toNumber()
|
|
42824
|
+
} : void 0,
|
|
42825
|
+
vaultUsdcBalance: this.vaultUsdcBalance ? {
|
|
42826
|
+
token: this.vaultUsdcBalance.token.symbol,
|
|
42827
|
+
amount: this.vaultUsdcBalance.amount.toNumber()
|
|
42828
|
+
} : void 0,
|
|
42829
|
+
vesuPoolStates: this.vesuPoolStates.map((p) => ({
|
|
42830
|
+
poolId: p.poolId,
|
|
42831
|
+
collateralAmount: p.collateralAmount.toNumber(),
|
|
42832
|
+
debtAmount: p.debtAmount.toNumber()
|
|
42833
|
+
})),
|
|
42834
|
+
vesuBorrowCapacity: this.vesuBorrowCapacity,
|
|
42835
|
+
vesuRebalance: this.shouldVesuRebalance,
|
|
42836
|
+
vesuPerPoolDebtDeltasToBorrow: this.vesuPerPoolDebtDeltasToBorrow.map((d) => d.toNumber()),
|
|
42837
|
+
extendedBalance: this.extendedBalance?.balance.toNumber(),
|
|
42838
|
+
extendedEquity: this.extendedBalance?.equity.toNumber(),
|
|
42839
|
+
extendedAvailableForTrade: this.extendedBalance?.availableForTrade.toNumber(),
|
|
42840
|
+
extendedAvailableForWithdrawal: this.extendedBalance?.availableForWithdrawal.toNumber(),
|
|
42841
|
+
extendedUnrealisedPnl: this.extendedBalance?.unrealisedPnl.toNumber(),
|
|
42842
|
+
extendedPendingDeposit: this.extendedBalance?.pendingDeposit.toNumber(),
|
|
42843
|
+
extendedPositions: this.extendedPositions.map((p) => ({
|
|
42844
|
+
instrument: p.instrument,
|
|
42845
|
+
size: p.size.toNumber(),
|
|
42846
|
+
valueUsd: p.valueUsd.toNumber()
|
|
42847
|
+
}))
|
|
42848
|
+
};
|
|
42849
|
+
console.log(
|
|
42850
|
+
"unused balances",
|
|
42851
|
+
aggregatedData.unusedBalances.map((b) => `${b.token}=${b.amount}`).join(", ")
|
|
42852
|
+
);
|
|
42853
|
+
console.log(
|
|
42854
|
+
"wallet balance",
|
|
42855
|
+
aggregatedData.walletBalance ? `${aggregatedData.walletBalance.token}=${aggregatedData.walletBalance.amount}` : void 0
|
|
42856
|
+
);
|
|
42857
|
+
console.log(
|
|
42858
|
+
"vault asset balance",
|
|
42859
|
+
aggregatedData.vaultAssetBalance ? `${aggregatedData.vaultAssetBalance.token}=${aggregatedData.vaultAssetBalance.amount}` : void 0
|
|
42860
|
+
);
|
|
42861
|
+
console.log(
|
|
42862
|
+
"vault usdc balance",
|
|
42863
|
+
aggregatedData.vaultUsdcBalance ? `${aggregatedData.vaultUsdcBalance.token}=${aggregatedData.vaultUsdcBalance.amount}` : void 0
|
|
42864
|
+
);
|
|
42865
|
+
console.log(
|
|
42866
|
+
"vesu pool states",
|
|
42867
|
+
aggregatedData.vesuPoolStates.map(
|
|
42868
|
+
(p) => `${p.poolId.shortString()}=${p.collateralAmount} ${p.debtAmount}`
|
|
42869
|
+
).join(", ")
|
|
42870
|
+
);
|
|
42871
|
+
console.log("vesu borrow capacity", aggregatedData.vesuBorrowCapacity);
|
|
42872
|
+
console.log(
|
|
42873
|
+
"vesu rebalance",
|
|
42874
|
+
aggregatedData.vesuRebalance.map(String).join(", ")
|
|
42875
|
+
);
|
|
42876
|
+
console.log("vesu per pool debt deltas to borrow", aggregatedData.vesuPerPoolDebtDeltasToBorrow.join(", "));
|
|
42877
|
+
console.log("extended balance", aggregatedData.extendedBalance);
|
|
42878
|
+
console.log("extended equity", aggregatedData.extendedEquity);
|
|
42879
|
+
console.log("extended available for trade", aggregatedData.extendedAvailableForTrade);
|
|
42880
|
+
console.log("extended available for withdrawal", aggregatedData.extendedAvailableForWithdrawal);
|
|
42881
|
+
console.log("extended unrealised pnl", aggregatedData.extendedUnrealisedPnl);
|
|
42882
|
+
console.log("extended pending deposit", aggregatedData.extendedPendingDeposit);
|
|
42883
|
+
console.log(
|
|
42884
|
+
"extended positions",
|
|
42885
|
+
aggregatedData.extendedPositions.map(
|
|
42886
|
+
(p) => `${p.instrument}=${p.size} ${p.valueUsd}`
|
|
42887
|
+
).join(", ")
|
|
42888
|
+
);
|
|
42889
|
+
return aggregatedData;
|
|
42890
|
+
}
|
|
42891
|
+
/**
|
|
42892
|
+
* Initialise derived views for a solve cycle. Mutates only when pending
|
|
42893
|
+
* withdrawal from Extended is in transit (credits wallet raw balance).
|
|
42158
42894
|
*/
|
|
42159
42895
|
initBudget() {
|
|
42160
|
-
const debtDeltaNum = this.vesuPerPoolDebtDeltasToBorrow.reduce((a, b) => a + b.toNumber(), 0);
|
|
42161
|
-
let totalUnusedUsd = this.unusedBalance.reduce((a, b) => a + b.usdValue, 0);
|
|
42162
|
-
if (debtDeltaNum > 0) totalUnusedUsd += debtDeltaNum;
|
|
42163
|
-
const extAvailTrade = this.extendedBalance?.availableForTrade?.toNumber() ?? 0;
|
|
42164
|
-
if (extAvailTrade > 0) totalUnusedUsd += extAvailTrade;
|
|
42165
|
-
if (debtDeltaNum > 0) totalUnusedUsd += debtDeltaNum;
|
|
42166
|
-
this._vaUsd = this.vaultBalance?.usdValue ?? 0;
|
|
42167
|
-
this._walletUsd = this.walletBalance?.usdValue ?? 0;
|
|
42168
|
-
this._extAvailWithdraw = this.extendedBalance?.availableForWithdrawal?.toNumber() ?? 0;
|
|
42169
|
-
this._extAvailUpnl = this.extendedBalance?.unrealisedPnl?.toNumber() ?? 0;
|
|
42170
|
-
this._extAvailTrade = extAvailTrade;
|
|
42171
|
-
this._extPendingDeposit = this.extendedBalance?.pendingDeposit?.toNumber() ?? 0;
|
|
42172
|
-
this._vesuBorrowCapacity = debtDeltaNum;
|
|
42173
|
-
this._totalUnused = totalUnusedUsd;
|
|
42174
42896
|
const pendingDeposit = this.extendedBalance?.pendingDeposit?.toNumber() ?? 0;
|
|
42175
|
-
if (pendingDeposit
|
|
42176
|
-
this._extAvailTrade += pendingDeposit;
|
|
42177
|
-
this._totalUnused += pendingDeposit;
|
|
42178
|
-
logger.debug(`SolveBudget::initBudget pendingDeposit=${pendingDeposit} -> increased extAvailTrade`);
|
|
42179
|
-
} else if (pendingDeposit < 0) {
|
|
42897
|
+
if (pendingDeposit < 0) {
|
|
42180
42898
|
const inTransit = Math.abs(pendingDeposit);
|
|
42181
|
-
this.
|
|
42182
|
-
|
|
42183
|
-
|
|
42899
|
+
if (this.walletBalance) {
|
|
42900
|
+
this._addUsdToTokenBalance(this.walletBalance, inTransit);
|
|
42901
|
+
}
|
|
42902
|
+
logger.debug(`SolveBudget::initBudget pendingDeposit=${pendingDeposit} -> increased wallet raw USD by ${inTransit}`);
|
|
42903
|
+
}
|
|
42904
|
+
this._recomputeUnusedBalance();
|
|
42905
|
+
}
|
|
42906
|
+
/**
|
|
42907
|
+
* Apply a safety buffer to all liquid balances (VA, wallet, extended trade/withdraw/upnl,
|
|
42908
|
+
* unused balances). Call after withdrawal classification but before LTV/deposit classifiers
|
|
42909
|
+
* so that withdrawal uses full raw amounts while subsequent classifiers see buffered values.
|
|
42910
|
+
*/
|
|
42911
|
+
applyBuffer(factor) {
|
|
42912
|
+
if (factor <= 0 || factor >= 1) return;
|
|
42913
|
+
const mult = 1 - factor;
|
|
42914
|
+
const scaleTokenBalance = (tb) => {
|
|
42915
|
+
if (!tb) return;
|
|
42916
|
+
const newAmount = tb.amount.multipliedBy(mult);
|
|
42917
|
+
tb.amount = new Web3Number(newAmount.toFixed(tb.token.decimals), tb.token.decimals);
|
|
42918
|
+
tb.usdValue = tb.usdValue * mult;
|
|
42919
|
+
};
|
|
42920
|
+
scaleTokenBalance(this.vaultAssetBalance);
|
|
42921
|
+
scaleTokenBalance(this.vaultUsdcBalance);
|
|
42922
|
+
scaleTokenBalance(this.walletBalance);
|
|
42923
|
+
for (const ub of this.unusedBalance) {
|
|
42924
|
+
scaleTokenBalance(ub);
|
|
42925
|
+
}
|
|
42926
|
+
if (this.extendedBalance) {
|
|
42927
|
+
this.extendedBalance.availableForTrade = this.extendedBalance.availableForTrade.multipliedBy(mult);
|
|
42928
|
+
this.extendedBalance.availableForWithdrawal = this.extendedBalance.availableForWithdrawal.multipliedBy(mult);
|
|
42929
|
+
this.extendedBalance.unrealisedPnl = this.extendedBalance.unrealisedPnl.multipliedBy(mult);
|
|
42184
42930
|
}
|
|
42931
|
+
this._recomputeUnusedBalance();
|
|
42185
42932
|
}
|
|
42186
|
-
|
|
42933
|
+
get vesuPoolState() {
|
|
42934
|
+
assert(this.vesuPoolStates.length === 1, "SolveBudget::vesuPoolState: vesuPoolStates length must be 1");
|
|
42935
|
+
return this.vesuPoolStates[0];
|
|
42936
|
+
}
|
|
42937
|
+
// ── Derived getters (buffered where applicable) ─────────────────────
|
|
42938
|
+
/** Buffered VA USD: strategy-asset slot + optional USDC slot. */
|
|
42187
42939
|
get vaUsd() {
|
|
42188
|
-
return this.
|
|
42940
|
+
return this.bufferedTokenUsd(this.vaultAssetBalance) + this.bufferedTokenUsd(this.vaultUsdcBalance);
|
|
42941
|
+
}
|
|
42942
|
+
/** Buffered USD in VA strategy-asset bucket only. */
|
|
42943
|
+
get vaAssetUsd() {
|
|
42944
|
+
return this.bufferedTokenUsd(this.vaultAssetBalance);
|
|
42945
|
+
}
|
|
42946
|
+
/** Buffered USD in VA USDC bucket (0 when asset === USDC). */
|
|
42947
|
+
get vaUsdcUsd() {
|
|
42948
|
+
return this.bufferedTokenUsd(this.vaultUsdcBalance);
|
|
42189
42949
|
}
|
|
42190
42950
|
get walletUsd() {
|
|
42191
|
-
return this.
|
|
42951
|
+
return this.bufferedUsd(this._rawTokenUsd(this.walletBalance));
|
|
42192
42952
|
}
|
|
42193
42953
|
get vaWalletUsd() {
|
|
42194
|
-
return this.
|
|
42954
|
+
return this.vaUsd + this.walletUsd;
|
|
42195
42955
|
}
|
|
42196
42956
|
get extAvailWithdraw() {
|
|
42197
|
-
|
|
42957
|
+
const raw = this.extendedBalance?.availableForWithdrawal?.toNumber() ?? 0;
|
|
42958
|
+
return this.bufferedUsd(raw);
|
|
42198
42959
|
}
|
|
42199
42960
|
get extAvailUpnl() {
|
|
42200
|
-
|
|
42961
|
+
const raw = this.extendedBalance?.unrealisedPnl?.toNumber() ?? 0;
|
|
42962
|
+
return this.bufferedUsd(raw);
|
|
42201
42963
|
}
|
|
42964
|
+
/**
|
|
42965
|
+
* Buffered Extended available-for-trade plus positive {@link ExtendedBalanceState.pendingDeposit}
|
|
42966
|
+
* (deposit in transit is usable the same way as the pre-buffer implementation).
|
|
42967
|
+
*/
|
|
42202
42968
|
get extAvailTrade() {
|
|
42203
|
-
|
|
42969
|
+
const raw = this.extendedBalance?.availableForTrade?.toNumber() ?? 0;
|
|
42970
|
+
let v = this.bufferedUsd(raw);
|
|
42971
|
+
const pd = this.extendedBalance?.pendingDeposit?.toNumber() ?? 0;
|
|
42972
|
+
if (pd > 0) v += pd;
|
|
42973
|
+
return v;
|
|
42974
|
+
}
|
|
42975
|
+
get extPendingDeposit() {
|
|
42976
|
+
return this.extendedBalance?.pendingDeposit?.toNumber() ?? 0;
|
|
42204
42977
|
}
|
|
42978
|
+
/**
|
|
42979
|
+
* Aggregate positive per-pool borrow headroom (USD). Repay/borrow routes update
|
|
42980
|
+
* {@link vesuPerPoolDebtDeltasToBorrow}; no separate counter.
|
|
42981
|
+
*/
|
|
42205
42982
|
get vesuBorrowCapacity() {
|
|
42206
|
-
return this.
|
|
42983
|
+
return this.vesuPerPoolDebtDeltasToBorrow.reduce(
|
|
42984
|
+
(a, d) => a + Math.max(0, d.toNumber()),
|
|
42985
|
+
0
|
|
42986
|
+
);
|
|
42207
42987
|
}
|
|
42988
|
+
/** Diagnostic: buffered idle + positive debt delta + buffered Extended afT + in-flight deposit. */
|
|
42208
42989
|
get totalUnused() {
|
|
42209
|
-
|
|
42990
|
+
const debtSum = this.vesuPerPoolDebtDeltasToBorrow.reduce((a, b) => a + b.toNumber(), 0);
|
|
42991
|
+
let u = this.unusedBalance.reduce((a, b) => a + this.bufferedTokenUsd(b), 0);
|
|
42992
|
+
if (debtSum > 0) u += debtSum;
|
|
42993
|
+
const rawAft = this.extendedBalance?.availableForTrade?.toNumber() ?? 0;
|
|
42994
|
+
const aftBuf = this.bufferedUsd(rawAft);
|
|
42995
|
+
if (aftBuf > 0) u += aftBuf;
|
|
42996
|
+
const pd = this.extendedBalance?.pendingDeposit?.toNumber() ?? 0;
|
|
42997
|
+
if (pd > 0) u += pd;
|
|
42998
|
+
return u;
|
|
42999
|
+
}
|
|
43000
|
+
/** Sum of buffered USD across merged unused-balance rows (VA + wallet). */
|
|
43001
|
+
get unusedBalancesBufferedUsdSum() {
|
|
43002
|
+
return this.unusedBalance.reduce((a, b) => a + this.bufferedTokenUsd(b), 0);
|
|
43003
|
+
}
|
|
43004
|
+
/** Read-only snapshot view for validation / logging. */
|
|
43005
|
+
get unusedBalanceRows() {
|
|
43006
|
+
return this.unusedBalance;
|
|
43007
|
+
}
|
|
43008
|
+
/** Read-only Vesu pool view for solve computations. */
|
|
43009
|
+
get vesuPools() {
|
|
43010
|
+
return this.vesuPoolStates;
|
|
43011
|
+
}
|
|
43012
|
+
/** Read-only Extended positions view for solve computations. */
|
|
43013
|
+
get extendedPositionsView() {
|
|
43014
|
+
return this.extendedPositions;
|
|
43015
|
+
}
|
|
43016
|
+
/** Read-only Extended balance view for diagnostics / margin checks. */
|
|
43017
|
+
get extendedBalanceView() {
|
|
43018
|
+
return this.extendedBalance;
|
|
43019
|
+
}
|
|
43020
|
+
/** Current debt deltas per pool (positive=borrow, negative=repay). */
|
|
43021
|
+
get vesuDebtDeltas() {
|
|
43022
|
+
return this.vesuPerPoolDebtDeltasToBorrow;
|
|
43023
|
+
}
|
|
43024
|
+
/** Per-pool rebalance flags derived from target HF checks. */
|
|
43025
|
+
get vesuRebalanceFlags() {
|
|
43026
|
+
return this.shouldVesuRebalance;
|
|
43027
|
+
}
|
|
43028
|
+
/** Raw USD in VA (USDC slot + asset slot); spend caps when executing transfers. */
|
|
43029
|
+
_vaRawUsd() {
|
|
43030
|
+
return this._rawTokenUsd(this.vaultUsdcBalance) + this._rawTokenUsd(this.vaultAssetBalance);
|
|
43031
|
+
}
|
|
43032
|
+
_walletRawUsd() {
|
|
43033
|
+
return this._rawTokenUsd(this.walletBalance);
|
|
43034
|
+
}
|
|
43035
|
+
// ── Token snapshot helpers (keep vault / wallet / unusedBalance aligned) ─
|
|
43036
|
+
/** Remove up to `usd` notional from a token balance, scaling token amount proportionally. */
|
|
43037
|
+
_deductUsdFromTokenBalance(tb, usd) {
|
|
43038
|
+
if (usd <= 0) return;
|
|
43039
|
+
const take = Math.min(usd, tb.usdValue);
|
|
43040
|
+
if (take <= 0) return;
|
|
43041
|
+
const oldUsd = tb.usdValue;
|
|
43042
|
+
const newUsd = Math.max(0, oldUsd - take);
|
|
43043
|
+
tb.usdValue = newUsd;
|
|
43044
|
+
if (oldUsd <= 0) return;
|
|
43045
|
+
const ratio = newUsd / oldUsd;
|
|
43046
|
+
tb.amount = new Web3Number(
|
|
43047
|
+
(tb.amount.toNumber() * ratio).toFixed(tb.token.decimals),
|
|
43048
|
+
tb.token.decimals
|
|
43049
|
+
);
|
|
43050
|
+
}
|
|
43051
|
+
/** Add USD notional; infers price from current amount/usd when possible, else 1:1. */
|
|
43052
|
+
_addUsdToTokenBalance(tb, usd) {
|
|
43053
|
+
if (usd <= 0) return;
|
|
43054
|
+
const amtNum = tb.amount.toNumber();
|
|
43055
|
+
const price = amtNum > 0 && tb.usdValue > 0 ? tb.usdValue / amtNum : 1;
|
|
43056
|
+
const deltaTok = usd / price;
|
|
43057
|
+
tb.usdValue += usd;
|
|
43058
|
+
tb.amount = tb.amount.plus(
|
|
43059
|
+
new Web3Number(deltaTok.toFixed(tb.token.decimals), tb.token.decimals)
|
|
43060
|
+
);
|
|
42210
43061
|
}
|
|
42211
|
-
|
|
42212
|
-
|
|
43062
|
+
/**
|
|
43063
|
+
* Rebuilds {@link unusedBalance} from vault + wallet snapshots (same merge as refresh).
|
|
43064
|
+
*/
|
|
43065
|
+
_recomputeUnusedBalance() {
|
|
43066
|
+
const balanceMap = /* @__PURE__ */ new Map();
|
|
43067
|
+
const merge = (b) => {
|
|
43068
|
+
if (!b) return;
|
|
43069
|
+
const key = b.token.address.toString();
|
|
43070
|
+
const row = {
|
|
43071
|
+
token: b.token,
|
|
43072
|
+
amount: new Web3Number(b.amount.toFixed(b.token.decimals), b.token.decimals),
|
|
43073
|
+
usdValue: b.usdValue
|
|
43074
|
+
};
|
|
43075
|
+
const existing = balanceMap.get(key);
|
|
43076
|
+
if (existing) {
|
|
43077
|
+
existing.amount = new Web3Number(
|
|
43078
|
+
existing.amount.plus(row.amount).toFixed(existing.token.decimals),
|
|
43079
|
+
existing.token.decimals
|
|
43080
|
+
);
|
|
43081
|
+
existing.usdValue += row.usdValue;
|
|
43082
|
+
} else {
|
|
43083
|
+
balanceMap.set(key, row);
|
|
43084
|
+
}
|
|
43085
|
+
};
|
|
43086
|
+
merge(this.vaultAssetBalance);
|
|
43087
|
+
merge(this.vaultUsdcBalance);
|
|
43088
|
+
merge(this.walletBalance);
|
|
43089
|
+
this.unusedBalance = Array.from(balanceMap.values());
|
|
42213
43090
|
}
|
|
42214
43091
|
// ── Spend methods (return amount consumed, auto-decrement totalUnused) ─
|
|
42215
|
-
|
|
42216
|
-
|
|
42217
|
-
|
|
42218
|
-
|
|
42219
|
-
|
|
42220
|
-
|
|
42221
|
-
|
|
42222
|
-
|
|
42223
|
-
|
|
42224
|
-
|
|
42225
|
-
|
|
42226
|
-
|
|
42227
|
-
|
|
42228
|
-
|
|
42229
|
-
|
|
42230
|
-
|
|
42231
|
-
this.
|
|
42232
|
-
logger.debug(`SolveBudget::
|
|
42233
|
-
return
|
|
43092
|
+
/**
|
|
43093
|
+
* Spend VA **raw** USD (up to {@link vaRawUsd}). Prefer {@link vaultUsdcBalance} when present, then {@link vaultAssetBalance}.
|
|
43094
|
+
*/
|
|
43095
|
+
spendVA(rawDesired) {
|
|
43096
|
+
const capRaw = this._vaRawUsd();
|
|
43097
|
+
const usedRaw = Math.min(capRaw, Math.max(0, rawDesired));
|
|
43098
|
+
if (usedRaw <= CASE_THRESHOLD_USD) return 0;
|
|
43099
|
+
let rem = usedRaw;
|
|
43100
|
+
if (rem > 0 && this.vaultUsdcBalance && this.vaultUsdcBalance.usdValue > 0) {
|
|
43101
|
+
const fromUsdc = Math.min(rem, this.vaultUsdcBalance.usdValue);
|
|
43102
|
+
this._deductUsdFromTokenBalance(this.vaultUsdcBalance, fromUsdc);
|
|
43103
|
+
rem -= fromUsdc;
|
|
43104
|
+
}
|
|
43105
|
+
if (rem > 0 && this.vaultAssetBalance) {
|
|
43106
|
+
this._deductUsdFromTokenBalance(this.vaultAssetBalance, rem);
|
|
43107
|
+
}
|
|
43108
|
+
this._recomputeUnusedBalance();
|
|
43109
|
+
logger.debug(`SolveBudget::spendVA usedRaw=${usedRaw}, vaUsd=${this.vaUsd}, totalUnused=${this.totalUnused}`);
|
|
43110
|
+
return usedRaw;
|
|
42234
43111
|
}
|
|
42235
|
-
|
|
42236
|
-
|
|
42237
|
-
|
|
42238
|
-
|
|
42239
|
-
|
|
43112
|
+
/**
|
|
43113
|
+
* Spend nominal/raw USD from VA (e.g. Vesu repay, on-chain USDC). Does not apply the safety buffer to the cap.
|
|
43114
|
+
*/
|
|
43115
|
+
spendVaRawUsd(rawUsdDesired) {
|
|
43116
|
+
const capRaw = this._rawTokenUsd(this.vaultUsdcBalance) + this._rawTokenUsd(this.vaultAssetBalance);
|
|
43117
|
+
const usedRaw = Math.min(capRaw, Math.max(0, rawUsdDesired));
|
|
43118
|
+
if (usedRaw <= CASE_THRESHOLD_USD) return 0;
|
|
43119
|
+
let rem = usedRaw;
|
|
43120
|
+
if (rem > 0 && this.vaultUsdcBalance && this.vaultUsdcBalance.usdValue > 0) {
|
|
43121
|
+
const fromUsdc = Math.min(rem, this.vaultUsdcBalance.usdValue);
|
|
43122
|
+
this._deductUsdFromTokenBalance(this.vaultUsdcBalance, fromUsdc);
|
|
43123
|
+
rem -= fromUsdc;
|
|
43124
|
+
}
|
|
43125
|
+
if (rem > 0 && this.vaultAssetBalance) {
|
|
43126
|
+
this._deductUsdFromTokenBalance(this.vaultAssetBalance, rem);
|
|
43127
|
+
}
|
|
43128
|
+
this._recomputeUnusedBalance();
|
|
43129
|
+
logger.debug(`SolveBudget::spendVaRawUsd usedRaw=${usedRaw}, vaUsd=${this.vaUsd}, totalUnused=${this.totalUnused}`);
|
|
43130
|
+
return usedRaw;
|
|
42240
43131
|
}
|
|
42241
|
-
|
|
42242
|
-
|
|
43132
|
+
/**
|
|
43133
|
+
* Add **raw nominal USD** to VA (borrow proceeds, wallet→VA in raw USDC, etc.).
|
|
43134
|
+
*/
|
|
43135
|
+
addToVA(rawUsd) {
|
|
43136
|
+
assert(rawUsd >= 0, "SolveBudget::addToVA amount must be positive");
|
|
43137
|
+
if (rawUsd === 0) return;
|
|
43138
|
+
if (this.vaultUsdcBalance) {
|
|
43139
|
+
this._addUsdToTokenBalance(this.vaultUsdcBalance, rawUsd);
|
|
43140
|
+
} else if (this.vaultAssetBalance) {
|
|
43141
|
+
this._addUsdToTokenBalance(this.vaultAssetBalance, rawUsd);
|
|
43142
|
+
}
|
|
43143
|
+
this._recomputeUnusedBalance();
|
|
43144
|
+
logger.debug(`SolveBudget::addToVA rawUsd=${rawUsd}, vaUsd=${this.vaUsd}, totalUnused=${this.totalUnused}`);
|
|
43145
|
+
}
|
|
43146
|
+
spendWallet(rawDesired) {
|
|
43147
|
+
const capRaw = this._walletRawUsd();
|
|
43148
|
+
const usedRaw = Math.min(capRaw, Math.max(0, rawDesired));
|
|
43149
|
+
if (usedRaw <= CASE_THRESHOLD_USD) return 0;
|
|
43150
|
+
if (this.walletBalance) {
|
|
43151
|
+
this._deductUsdFromTokenBalance(this.walletBalance, usedRaw);
|
|
43152
|
+
}
|
|
43153
|
+
this._recomputeUnusedBalance();
|
|
43154
|
+
logger.debug(`SolveBudget::spendWallet usedRaw=${usedRaw}, walletUsd=${this.walletUsd}, totalUnused=${this.totalUnused}`);
|
|
43155
|
+
return usedRaw;
|
|
43156
|
+
}
|
|
43157
|
+
/** Add **raw nominal USD** to the operator wallet balance (e.g. Extended→wallet withdrawal). */
|
|
43158
|
+
addToWallet(rawUsd) {
|
|
43159
|
+
assert(rawUsd >= 0, "SolveBudget::addToWallet amount must be positive");
|
|
43160
|
+
if (rawUsd === 0) return;
|
|
43161
|
+
if (this.walletBalance) {
|
|
43162
|
+
this._addUsdToTokenBalance(this.walletBalance, rawUsd);
|
|
43163
|
+
}
|
|
43164
|
+
this._recomputeUnusedBalance();
|
|
43165
|
+
logger.debug(`SolveBudget::addToWallet rawUsd=${rawUsd}, walletUsd=${this.walletUsd}, totalUnused=${this.totalUnused}`);
|
|
43166
|
+
}
|
|
43167
|
+
spendVAWallet(rawDesired) {
|
|
43168
|
+
let remaining = Math.max(0, rawDesired);
|
|
42243
43169
|
const vaSpent = this.spendVA(remaining);
|
|
42244
43170
|
remaining -= vaSpent;
|
|
42245
43171
|
const walletSpent = this.spendWallet(remaining);
|
|
42246
43172
|
return vaSpent + walletSpent;
|
|
42247
43173
|
}
|
|
42248
|
-
_updateExtAvailWithdraw(
|
|
42249
|
-
|
|
42250
|
-
|
|
43174
|
+
_updateExtAvailWithdraw(desiredRaw, isSpend) {
|
|
43175
|
+
assert(desiredRaw > 0, "SolveBudget::_updateExtAvailWithdraw amount must be positive");
|
|
43176
|
+
let rawDelta;
|
|
42251
43177
|
if (isSpend) {
|
|
42252
|
-
|
|
42253
|
-
|
|
43178
|
+
const capRaw = this.extendedBalance?.availableForWithdrawal?.toNumber() ?? 0;
|
|
43179
|
+
const useRaw = Math.min(capRaw, desiredRaw);
|
|
43180
|
+
if (useRaw <= CASE_THRESHOLD_USD) return 0;
|
|
43181
|
+
rawDelta = -useRaw;
|
|
43182
|
+
} else {
|
|
43183
|
+
rawDelta = desiredRaw;
|
|
42254
43184
|
}
|
|
42255
|
-
this._extAvailWithdraw += amount;
|
|
42256
|
-
this._totalUnused += amount;
|
|
42257
|
-
this._extAvailTrade += amount;
|
|
42258
43185
|
if (this.extendedBalance) {
|
|
42259
|
-
this.extendedBalance.availableForWithdrawal = safeUsdcWeb3Number(this.extendedBalance.availableForWithdrawal.toNumber() +
|
|
42260
|
-
this.extendedBalance.availableForTrade = safeUsdcWeb3Number(this.extendedBalance.availableForTrade.toNumber() +
|
|
42261
|
-
this.extendedBalance.balance = safeUsdcWeb3Number(this.extendedBalance.balance.toNumber() +
|
|
42262
|
-
this.extendedBalance.equity = safeUsdcWeb3Number(this.extendedBalance.equity.toNumber() +
|
|
43186
|
+
this.extendedBalance.availableForWithdrawal = safeUsdcWeb3Number(this.extendedBalance.availableForWithdrawal.toNumber() + rawDelta);
|
|
43187
|
+
this.extendedBalance.availableForTrade = safeUsdcWeb3Number(this.extendedBalance.availableForTrade.toNumber() + rawDelta);
|
|
43188
|
+
this.extendedBalance.balance = safeUsdcWeb3Number(this.extendedBalance.balance.toNumber() + rawDelta);
|
|
43189
|
+
this.extendedBalance.equity = safeUsdcWeb3Number(this.extendedBalance.equity.toNumber() + rawDelta);
|
|
42263
43190
|
}
|
|
42264
|
-
logger.debug(`SolveBudget::updateExtAvailWithdraw
|
|
42265
|
-
return
|
|
43191
|
+
logger.debug(`SolveBudget::updateExtAvailWithdraw rawDelta=${rawDelta}, extAvailWithdraw=${this.extAvailWithdraw}, totalUnused=${this.totalUnused}`);
|
|
43192
|
+
return rawDelta;
|
|
42266
43193
|
}
|
|
42267
|
-
_updateExtAvailUpnl(
|
|
42268
|
-
|
|
42269
|
-
|
|
43194
|
+
_updateExtAvailUpnl(desiredRaw, isSpend) {
|
|
43195
|
+
assert(desiredRaw > 0, "SolveBudget::_updateExtAvailUpnl amount must be positive");
|
|
43196
|
+
let rawDelta;
|
|
42270
43197
|
if (isSpend) {
|
|
42271
|
-
|
|
42272
|
-
|
|
43198
|
+
const capRaw = this.extendedBalance?.unrealisedPnl?.toNumber() ?? 0;
|
|
43199
|
+
const useRaw = Math.min(capRaw, desiredRaw);
|
|
43200
|
+
if (useRaw <= CASE_THRESHOLD_USD) return 0;
|
|
43201
|
+
rawDelta = -useRaw;
|
|
43202
|
+
} else {
|
|
43203
|
+
rawDelta = desiredRaw;
|
|
42273
43204
|
}
|
|
42274
|
-
this._extAvailUpnl += amount;
|
|
42275
|
-
this._totalUnused += amount;
|
|
42276
43205
|
if (this.extendedBalance) {
|
|
42277
|
-
this.extendedBalance.unrealisedPnl = safeUsdcWeb3Number(this.extendedBalance.unrealisedPnl.toNumber() +
|
|
42278
|
-
this.extendedBalance.balance = safeUsdcWeb3Number(this.extendedBalance.balance.toNumber() +
|
|
42279
|
-
this.extendedBalance.equity = safeUsdcWeb3Number(this.extendedBalance.equity.toNumber() +
|
|
42280
|
-
this.extendedBalance.availableForTrade = safeUsdcWeb3Number(this.extendedBalance.availableForTrade.toNumber() +
|
|
42281
|
-
}
|
|
42282
|
-
logger.debug(`SolveBudget::updateExtAvailUpnl
|
|
42283
|
-
return
|
|
42284
|
-
}
|
|
42285
|
-
spendExtAvailTrade(
|
|
42286
|
-
const used = this._updateExtAvailWithdraw(
|
|
42287
|
-
const usedUpnl = this._updateExtAvailUpnl(
|
|
42288
|
-
logger.debug(`SolveBudget::updateExtAvailTrade
|
|
43206
|
+
this.extendedBalance.unrealisedPnl = safeUsdcWeb3Number(this.extendedBalance.unrealisedPnl.toNumber() + rawDelta);
|
|
43207
|
+
this.extendedBalance.balance = safeUsdcWeb3Number(this.extendedBalance.balance.toNumber() + rawDelta);
|
|
43208
|
+
this.extendedBalance.equity = safeUsdcWeb3Number(this.extendedBalance.equity.toNumber() + rawDelta);
|
|
43209
|
+
this.extendedBalance.availableForTrade = safeUsdcWeb3Number(this.extendedBalance.availableForTrade.toNumber() + rawDelta);
|
|
43210
|
+
}
|
|
43211
|
+
logger.debug(`SolveBudget::updateExtAvailUpnl rawDelta=${rawDelta}, extAvailUpnl=${this.extAvailUpnl}, totalUnused=${this.totalUnused}`);
|
|
43212
|
+
return rawDelta;
|
|
43213
|
+
}
|
|
43214
|
+
spendExtAvailTrade(rawDesired) {
|
|
43215
|
+
const used = this._updateExtAvailWithdraw(rawDesired, true);
|
|
43216
|
+
const usedUpnl = this._updateExtAvailUpnl(rawDesired, true);
|
|
43217
|
+
logger.debug(`SolveBudget::updateExtAvailTrade rawSum=${used + usedUpnl}, extAvailTrade=${this.extAvailTrade}, totalUnused=${this.totalUnused}`);
|
|
42289
43218
|
return used + usedUpnl;
|
|
42290
43219
|
}
|
|
42291
|
-
|
|
42292
|
-
|
|
43220
|
+
// simply reduces available amounts, but maintains equity and balance.
|
|
43221
|
+
spendExtAvailTradeToEquityOnly(rawDesired) {
|
|
43222
|
+
const used = this._updateExtAvailWithdraw(rawDesired, true);
|
|
43223
|
+
const remaining = rawDesired - Math.abs(used);
|
|
43224
|
+
const usedUpnl = remaining > 0 ? this._updateExtAvailUpnl(remaining, true) : 0;
|
|
43225
|
+
if (this.extendedBalance) {
|
|
43226
|
+
const net = Math.abs(used) + Math.abs(usedUpnl);
|
|
43227
|
+
if (net.toFixed(0) != rawDesired.toFixed(0)) {
|
|
43228
|
+
throw new Error(`SolveBudget::spendExtAvailTradeToEquityOnly net=${net} != rawDesired=${rawDesired}`);
|
|
43229
|
+
}
|
|
43230
|
+
this.extendedBalance.equity = safeUsdcWeb3Number(this.extendedBalance.equity.toNumber() + net);
|
|
43231
|
+
this.extendedBalance.balance = safeUsdcWeb3Number(this.extendedBalance.balance.toNumber() + net);
|
|
43232
|
+
}
|
|
43233
|
+
logger.debug(`SolveBudget::updateExtAvailTrade rawSum=${used + usedUpnl}, extAvailTrade=${this.extAvailTrade}, totalUnused=${this.totalUnused}`);
|
|
43234
|
+
return used + usedUpnl;
|
|
43235
|
+
}
|
|
43236
|
+
spendExtAvailWithdraw(rawDesired) {
|
|
43237
|
+
return this._updateExtAvailWithdraw(rawDesired, true);
|
|
43238
|
+
}
|
|
43239
|
+
spendExtAvailUpnl(rawDesired) {
|
|
43240
|
+
return this._updateExtAvailUpnl(rawDesired, true);
|
|
42293
43241
|
}
|
|
42294
|
-
|
|
42295
|
-
|
|
42296
|
-
|
|
43242
|
+
/**
|
|
43243
|
+
* Withdraw from Extended **withdrawal bucket only** to operator wallet (planning).
|
|
43244
|
+
* Used when VA must be funded from Extended and withdraw should be exhausted before unrealised PnL.
|
|
43245
|
+
*/
|
|
43246
|
+
spendAvailWithdrawToWallet(rawDesired) {
|
|
43247
|
+
const want = Math.max(0, rawDesired);
|
|
43248
|
+
if (want <= CASE_THRESHOLD_USD) return 0;
|
|
43249
|
+
const rawDelta = this._updateExtAvailWithdraw(want, true);
|
|
43250
|
+
if (rawDelta === 0) return 0;
|
|
43251
|
+
const used = -rawDelta;
|
|
43252
|
+
this.addToWallet(used);
|
|
43253
|
+
return used;
|
|
43254
|
+
}
|
|
43255
|
+
/**
|
|
43256
|
+
* Required Extended equity (USD) for current open positions: total notional ÷ strategy leverage.
|
|
43257
|
+
* Same basis as {@link ExtendedSVKVesuStateManager._classifyLtvExtended} margin check.
|
|
43258
|
+
*/
|
|
43259
|
+
_extendedMarginRequirementUsd() {
|
|
43260
|
+
const lev = calculateExtendedLevergae();
|
|
43261
|
+
if (lev <= 0 || this.extendedPositions.length === 0) return 0;
|
|
43262
|
+
const totalPosUsd = this.extendedPositions.reduce(
|
|
43263
|
+
(s, p) => s + p.valueUsd.toNumber(),
|
|
43264
|
+
0
|
|
43265
|
+
);
|
|
43266
|
+
return totalPosUsd / lev;
|
|
43267
|
+
}
|
|
43268
|
+
/** How much more equity is needed before deposits should increase withdraw / trade availability. */
|
|
43269
|
+
_extendedEquityShortfallUsd() {
|
|
43270
|
+
if (!this.extendedBalance) return 0;
|
|
43271
|
+
const req = this._extendedMarginRequirementUsd();
|
|
43272
|
+
const eq = this.extendedBalance.equity.toNumber();
|
|
43273
|
+
return Math.max(0, req - eq);
|
|
43274
|
+
}
|
|
43275
|
+
/**
|
|
43276
|
+
* Credits a USDC inflow on Extended. Fills margin shortfall (balance+equity only) first;
|
|
43277
|
+
* any remainder is credited across balance, equity, availableForWithdrawal, and availableForTrade.
|
|
43278
|
+
*/
|
|
43279
|
+
addToExtAvailTrade(rawUsd) {
|
|
43280
|
+
assert(rawUsd >= 0, "SolveBudget::addToExtAvailTrade amount must be non-negative");
|
|
43281
|
+
if (rawUsd <= CASE_THRESHOLD_USD) return;
|
|
43282
|
+
if (!this.extendedBalance) {
|
|
43283
|
+
logger.warn("SolveBudget::addToExtAvailTrade skipped \u2014 no extendedBalance");
|
|
43284
|
+
return;
|
|
43285
|
+
}
|
|
43286
|
+
const shortfall = this._extendedEquityShortfallUsd();
|
|
43287
|
+
const toMargin = Math.min(rawUsd, shortfall);
|
|
43288
|
+
const toLiquid = rawUsd - toMargin;
|
|
43289
|
+
if (toMargin > CASE_THRESHOLD_USD) {
|
|
43290
|
+
const b = this.extendedBalance.balance.toNumber();
|
|
43291
|
+
const e = this.extendedBalance.equity.toNumber();
|
|
43292
|
+
this.extendedBalance.balance = safeUsdcWeb3Number(b + toMargin);
|
|
43293
|
+
this.extendedBalance.equity = safeUsdcWeb3Number(e + toMargin);
|
|
43294
|
+
logger.debug(
|
|
43295
|
+
`SolveBudget::addToExtAvailTrade margin-first rawUsd=${toMargin} (shortfallBefore=${shortfall}, balance=${b + toMargin}, equity=${e + toMargin})`
|
|
43296
|
+
);
|
|
43297
|
+
}
|
|
43298
|
+
if (toLiquid > CASE_THRESHOLD_USD) {
|
|
43299
|
+
this._updateExtAvailWithdraw(toLiquid, false);
|
|
43300
|
+
}
|
|
43301
|
+
logger.debug(
|
|
43302
|
+
`SolveBudget::addToExtAvailTrade total rawUsd=${rawUsd} toLiquid=${toLiquid} extAvailTrade=${this.extAvailTrade}, totalUnused=${this.totalUnused}`
|
|
43303
|
+
);
|
|
42297
43304
|
}
|
|
42298
43305
|
spendVesuBorrowCapacity(desired) {
|
|
42299
|
-
const used = Math.min(this.
|
|
42300
|
-
this._vesuBorrowCapacity -= used;
|
|
42301
|
-
this._totalUnused -= used;
|
|
43306
|
+
const used = Math.min(this.vesuBorrowCapacity, Math.max(0, desired));
|
|
42302
43307
|
let spendsByPool = [];
|
|
42303
43308
|
for (let index = 0; index < this.vesuPerPoolDebtDeltasToBorrow.length; index++) {
|
|
42304
43309
|
const d = this.vesuPerPoolDebtDeltasToBorrow[index];
|
|
@@ -42309,13 +43314,12 @@ var SolveBudget = class {
|
|
|
42309
43314
|
this.vesuPoolStates[index].debtUsdValue = this.vesuPoolStates[index].debtAmount.toNumber() * this.vesuPoolStates[index].debtPrice;
|
|
42310
43315
|
spendsByPool.push({ poolId: this.vesuPoolStates[index].poolId, amount: safeUsdcWeb3Number(borrowed), collateralToken: this.vesuPoolStates[index].collateralToken, debtToken: this.vesuPoolStates[index].debtToken });
|
|
42311
43316
|
}
|
|
42312
|
-
logger.debug(`SolveBudget::spendVesuBorrowCapacity used=${used}, vesuBorrowCapacity=${this.
|
|
43317
|
+
logger.debug(`SolveBudget::spendVesuBorrowCapacity used=${used}, vesuBorrowCapacity=${this.vesuBorrowCapacity}, totalUnused=${this.totalUnused}`);
|
|
42313
43318
|
return { used, spendsByPool };
|
|
42314
43319
|
}
|
|
42315
43320
|
repayVesuBorrowCapacity(desired) {
|
|
42316
43321
|
assert(desired > 0, "SolveBudget::repayVesuBorrowCapacity desired must be positive");
|
|
42317
43322
|
const used = desired;
|
|
42318
|
-
this._vesuBorrowCapacity += used;
|
|
42319
43323
|
const spendsByPool = [];
|
|
42320
43324
|
for (let index = 0; index < this.vesuPerPoolDebtDeltasToBorrow.length; index++) {
|
|
42321
43325
|
const d = this.vesuPerPoolDebtDeltasToBorrow[index];
|
|
@@ -42325,7 +43329,7 @@ var SolveBudget = class {
|
|
|
42325
43329
|
this.vesuPoolStates[index].debtAmount = safeUsdcWeb3Number(this.vesuPoolStates[index].debtAmount.toNumber() - repaid);
|
|
42326
43330
|
spendsByPool.push({ poolId: this.vesuPoolStates[index].poolId, amount: safeUsdcWeb3Number(-repaid), collateralToken: this.vesuPoolStates[index].collateralToken, debtToken: this.vesuPoolStates[index].debtToken });
|
|
42327
43331
|
}
|
|
42328
|
-
logger.debug(`SolveBudget::repayVesuBorrowCapacity used=${used}, vesuBorrowCapacity=${this.
|
|
43332
|
+
logger.debug(`SolveBudget::repayVesuBorrowCapacity used=${used}, vesuBorrowCapacity=${this.vesuBorrowCapacity}, totalUnused=${this.totalUnused}`);
|
|
42329
43333
|
return { used, spendsByPool };
|
|
42330
43334
|
}
|
|
42331
43335
|
// ── State mutation ──────────────────────────────────────────────────
|
|
@@ -42347,13 +43351,21 @@ var SolveBudget = class {
|
|
|
42347
43351
|
pool.debtUsdValue = pool.debtAmount.toNumber() * pool.debtPrice;
|
|
42348
43352
|
const vesuPerPoolDebtDeltasToBorrow = this._computeperPoolDebtDeltasToBorrow();
|
|
42349
43353
|
this.vesuPerPoolDebtDeltasToBorrow = vesuPerPoolDebtDeltasToBorrow.map((item) => item.deltaDebt);
|
|
42350
|
-
const sum = this.vesuPerPoolDebtDeltasToBorrow.reduce((a, b) => a.plus(b), new Web3Number(0, USDC_TOKEN_DECIMALS));
|
|
42351
|
-
this._vesuBorrowCapacity = sum.toNumber();
|
|
42352
43354
|
this.shouldVesuRebalance = vesuPerPoolDebtDeltasToBorrow.map((item) => item.shouldRebalance);
|
|
42353
43355
|
}
|
|
42354
|
-
/**
|
|
42355
|
-
|
|
42356
|
-
|
|
43356
|
+
/**
|
|
43357
|
+
* Update Extended position size after a lever route; sync {@link ExtendedPositionState.valueUsd}
|
|
43358
|
+
* and margin buckets (released USD on decrease, locked USD on increase).
|
|
43359
|
+
*
|
|
43360
|
+
* @param collateralPriceUsd BTC collateral price for notional / margin math; if omitted, uses
|
|
43361
|
+
* existing valueUsd / |size| or the first Vesu pool collateral price.
|
|
43362
|
+
*/
|
|
43363
|
+
applyExtendedExposureDelta(instrument, sizeDelta, collateralPriceUsd) {
|
|
43364
|
+
const btcEps = 10 ** -COLLATERAL_PRECISION;
|
|
43365
|
+
const lev = calculateExtendedLevergae();
|
|
43366
|
+
let pos = this.extendedPositions.find((p) => p.instrument === instrument);
|
|
43367
|
+
const oldAbs = pos ? Math.abs(pos.size.toNumber()) : 0;
|
|
43368
|
+
const oldValUsd = pos ? pos.valueUsd.toNumber() : 0;
|
|
42357
43369
|
if (pos) {
|
|
42358
43370
|
pos.size = new Web3Number(pos.size.plus(sizeDelta).toFixed(8), 8);
|
|
42359
43371
|
} else if (sizeDelta.toNumber() !== 0) {
|
|
@@ -42364,6 +43376,56 @@ var SolveBudget = class {
|
|
|
42364
43376
|
valueUsd: new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
42365
43377
|
leverage: "0"
|
|
42366
43378
|
});
|
|
43379
|
+
pos = this.extendedPositions[this.extendedPositions.length - 1];
|
|
43380
|
+
} else {
|
|
43381
|
+
return;
|
|
43382
|
+
}
|
|
43383
|
+
const newAbs = Math.abs(pos.size.toNumber());
|
|
43384
|
+
let price = collateralPriceUsd;
|
|
43385
|
+
if (price === void 0 || price <= 0) {
|
|
43386
|
+
price = oldAbs > btcEps ? oldValUsd / oldAbs : this.vesuPoolStates[0]?.collateralPrice ?? 0;
|
|
43387
|
+
}
|
|
43388
|
+
if (price > 0) {
|
|
43389
|
+
pos.valueUsd = new Web3Number(
|
|
43390
|
+
(newAbs * price).toFixed(USDC_TOKEN_DECIMALS),
|
|
43391
|
+
USDC_TOKEN_DECIMALS
|
|
43392
|
+
);
|
|
43393
|
+
}
|
|
43394
|
+
if (!this.extendedBalance || lev <= 0 || price <= 0) return;
|
|
43395
|
+
const dAbs = newAbs - oldAbs;
|
|
43396
|
+
if (dAbs < -btcEps) {
|
|
43397
|
+
const releasedUsd = -dAbs * price / lev;
|
|
43398
|
+
if (releasedUsd > CASE_THRESHOLD_USD) {
|
|
43399
|
+
this.addToExtAvailTrade(releasedUsd);
|
|
43400
|
+
}
|
|
43401
|
+
} else if (dAbs > btcEps) {
|
|
43402
|
+
const lockedUsd = dAbs * price / lev;
|
|
43403
|
+
if (lockedUsd > CASE_THRESHOLD_USD) {
|
|
43404
|
+
this._lockExtendedMarginUsd(lockedUsd);
|
|
43405
|
+
}
|
|
43406
|
+
}
|
|
43407
|
+
}
|
|
43408
|
+
/** Pull margin for larger Extended exposure from liquid buckets, then balance/equity. */
|
|
43409
|
+
_lockExtendedMarginUsd(lockedUsd) {
|
|
43410
|
+
if (lockedUsd <= CASE_THRESHOLD_USD || !this.extendedBalance) return;
|
|
43411
|
+
let rem = lockedUsd;
|
|
43412
|
+
const uw = Math.min(rem, Math.max(0, this.extendedBalance.availableForWithdrawal.toNumber()));
|
|
43413
|
+
if (uw > 0) {
|
|
43414
|
+
this._updateExtAvailWithdraw(uw, true);
|
|
43415
|
+
rem -= uw;
|
|
43416
|
+
}
|
|
43417
|
+
if (rem > 0) {
|
|
43418
|
+
const uu = Math.min(rem, Math.max(0, this.extendedBalance.unrealisedPnl.toNumber()));
|
|
43419
|
+
if (uu > 0) {
|
|
43420
|
+
this._updateExtAvailUpnl(uu, true);
|
|
43421
|
+
rem -= uu;
|
|
43422
|
+
}
|
|
43423
|
+
}
|
|
43424
|
+
if (rem > 0) {
|
|
43425
|
+
const b = this.extendedBalance.balance.toNumber();
|
|
43426
|
+
const e = this.extendedBalance.equity.toNumber();
|
|
43427
|
+
this.extendedBalance.balance = safeUsdcWeb3Number(b - rem);
|
|
43428
|
+
this.extendedBalance.equity = safeUsdcWeb3Number(e - rem);
|
|
42367
43429
|
}
|
|
42368
43430
|
}
|
|
42369
43431
|
/**
|
|
@@ -42391,6 +43453,23 @@ var SolveBudget = class {
|
|
|
42391
43453
|
return output;
|
|
42392
43454
|
}
|
|
42393
43455
|
};
|
|
43456
|
+
function createSolveBudgetFromRawState(params) {
|
|
43457
|
+
const budget = new SolveBudget({
|
|
43458
|
+
assetToken: params.assetToken,
|
|
43459
|
+
usdcToken: params.usdcToken,
|
|
43460
|
+
unusedBalance: params.unusedBalance,
|
|
43461
|
+
walletBalance: params.walletBalance,
|
|
43462
|
+
vaultAssetBalance: params.vaultAssetBalance,
|
|
43463
|
+
vaultUsdcBalance: params.vaultUsdcBalance,
|
|
43464
|
+
extendedPositions: params.extendedPositions,
|
|
43465
|
+
extendedBalance: params.extendedBalance,
|
|
43466
|
+
vesuPoolStates: params.vesuPoolStates
|
|
43467
|
+
});
|
|
43468
|
+
if (params.limitBalanceBufferFactor && params.limitBalanceBufferFactor > 0) {
|
|
43469
|
+
budget.applyBuffer(params.limitBalanceBufferFactor);
|
|
43470
|
+
}
|
|
43471
|
+
return budget;
|
|
43472
|
+
}
|
|
42394
43473
|
var ExtendedSVKVesuStateManager = class {
|
|
42395
43474
|
constructor(config) {
|
|
42396
43475
|
this._tag = "ExtendedSVKVesuStateManager";
|
|
@@ -42426,7 +43505,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42426
43505
|
vesuAllocationUsd: safeUsdcWeb3Number(0),
|
|
42427
43506
|
extendedAllocationUsd: safeUsdcWeb3Number(0),
|
|
42428
43507
|
bringLiquidityAmount: safeUsdcWeb3Number(0),
|
|
42429
|
-
pendingDeposit:
|
|
43508
|
+
pendingDeposit: safeUsdcWeb3Number(0)
|
|
42430
43509
|
};
|
|
42431
43510
|
this._logSolveResult(result);
|
|
42432
43511
|
return result;
|
|
@@ -42441,30 +43520,44 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42441
43520
|
async _refresh() {
|
|
42442
43521
|
logger.info(`${this._tag}::_refresh starting`);
|
|
42443
43522
|
const [
|
|
42444
|
-
|
|
43523
|
+
vaultAssetBalance,
|
|
43524
|
+
vaultUsdcBalance,
|
|
42445
43525
|
walletBalance,
|
|
42446
43526
|
vesuPoolStates,
|
|
42447
43527
|
extendedBalance,
|
|
42448
43528
|
extendedPositions
|
|
42449
43529
|
] = await Promise.all([
|
|
42450
|
-
this.
|
|
43530
|
+
this._fetchVaultAllocatorAssetBalance(),
|
|
43531
|
+
this._fetchVaultAllocatorUsdcBalanceIfDistinct(),
|
|
42451
43532
|
this._fetchWalletBalances(),
|
|
42452
43533
|
this._fetchAllVesuPoolStates(),
|
|
42453
43534
|
this._fetchExtendedBalance(),
|
|
42454
43535
|
this._fetchExtendedPositions()
|
|
42455
43536
|
]);
|
|
42456
|
-
logger.verbose(
|
|
43537
|
+
logger.verbose(
|
|
43538
|
+
`${this._tag}::_refresh VA asset ${vaultAssetBalance.token.symbol}=$${vaultAssetBalance.usdValue.toFixed(2)}${vaultUsdcBalance ? `, VA USDC=$${vaultUsdcBalance.usdValue.toFixed(2)}` : ""}, wallet=${walletBalance.usdValue}`
|
|
43539
|
+
);
|
|
42457
43540
|
const unusedBalance = this._computeUnusedBalances(
|
|
42458
|
-
|
|
43541
|
+
vaultAssetBalance,
|
|
43542
|
+
vaultUsdcBalance,
|
|
42459
43543
|
walletBalance
|
|
42460
43544
|
);
|
|
42461
|
-
this._budget =
|
|
42462
|
-
|
|
43545
|
+
this._budget = createSolveBudgetFromRawState({
|
|
43546
|
+
assetToken: this._config.assetToken,
|
|
43547
|
+
usdcToken: this._config.usdcToken,
|
|
42463
43548
|
unusedBalance,
|
|
42464
43549
|
walletBalance,
|
|
42465
|
-
|
|
43550
|
+
vaultAssetBalance,
|
|
43551
|
+
vaultUsdcBalance,
|
|
42466
43552
|
extendedPositions,
|
|
42467
|
-
extendedBalance
|
|
43553
|
+
extendedBalance: {
|
|
43554
|
+
availableForTrade: extendedBalance?.availableForTrade || new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
43555
|
+
availableForWithdrawal: extendedBalance?.availableForWithdrawal || new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
43556
|
+
unrealisedPnl: extendedBalance?.unrealisedPnl || new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
43557
|
+
balance: extendedBalance?.balance || new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
43558
|
+
equity: extendedBalance?.equity || new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
43559
|
+
pendingDeposit: extendedBalance?.pendingDeposit || new Web3Number(0, USDC_TOKEN_DECIMALS)
|
|
43560
|
+
},
|
|
42468
43561
|
vesuPoolStates
|
|
42469
43562
|
});
|
|
42470
43563
|
const totalUnusedUsd = unusedBalance.reduce(
|
|
@@ -42476,10 +43569,14 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42476
43569
|
);
|
|
42477
43570
|
}
|
|
42478
43571
|
// todo add communication check with python server of extended. if not working, throw error in solve function.
|
|
43572
|
+
/** True when strategy asset and USDC share one token — VA USDC slot is unused (all in asset balance). */
|
|
43573
|
+
_vaultAssetAndUsdcAreSameToken() {
|
|
43574
|
+
return this._config.assetToken.address.eq(this._config.usdcToken.address);
|
|
43575
|
+
}
|
|
42479
43576
|
/**
|
|
42480
|
-
* Reads the
|
|
43577
|
+
* Reads the {@link StateManagerConfig.assetToken} balance idle in the vault allocator.
|
|
42481
43578
|
*/
|
|
42482
|
-
async
|
|
43579
|
+
async _fetchVaultAllocatorAssetBalance() {
|
|
42483
43580
|
const { assetToken, vaultAllocator, networkConfig, pricer } = this._config;
|
|
42484
43581
|
const balance = await new ERC20(networkConfig).balanceOf(
|
|
42485
43582
|
assetToken.address,
|
|
@@ -42491,20 +43588,38 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42491
43588
|
return { token: assetToken, amount: balance, usdValue };
|
|
42492
43589
|
}
|
|
42493
43590
|
/**
|
|
42494
|
-
*
|
|
42495
|
-
*
|
|
42496
|
-
*
|
|
42497
|
-
* e.g. VA has USDC, wallet has USDC + USDC.e → returns
|
|
42498
|
-
* [{ token: USDC, amount: VA+wallet, usdValue: … },
|
|
42499
|
-
* { token: USDC.e, amount: wallet, usdValue: … }]
|
|
43591
|
+
* Reads {@link StateManagerConfig.usdcToken} in the vault allocator when it differs from
|
|
43592
|
+
* {@link StateManagerConfig.assetToken}. Otherwise returns null (treat VA USDC as 0; stablecoin is only under asset).
|
|
42500
43593
|
*/
|
|
42501
|
-
|
|
43594
|
+
async _fetchVaultAllocatorUsdcBalanceIfDistinct() {
|
|
43595
|
+
if (this._vaultAssetAndUsdcAreSameToken()) return null;
|
|
43596
|
+
const { usdcToken, vaultAllocator, networkConfig, pricer } = this._config;
|
|
43597
|
+
const balance = await new ERC20(networkConfig).balanceOf(
|
|
43598
|
+
usdcToken.address,
|
|
43599
|
+
vaultAllocator,
|
|
43600
|
+
usdcToken.decimals
|
|
43601
|
+
);
|
|
43602
|
+
const tokenPrice = await pricer.getPrice(
|
|
43603
|
+
usdcToken.priceProxySymbol || usdcToken.symbol
|
|
43604
|
+
);
|
|
43605
|
+
const usdValue = Number(balance.toFixed(usdcToken.decimals)) * tokenPrice.price;
|
|
43606
|
+
return { token: usdcToken, amount: balance, usdValue };
|
|
43607
|
+
}
|
|
43608
|
+
/**
|
|
43609
|
+
* Merges vault-allocator asset, optional vault-allocator USDC, and operator wallet
|
|
43610
|
+
* balances into entries keyed by token address.
|
|
43611
|
+
*/
|
|
43612
|
+
_computeUnusedBalances(vaultAssetBalance, vaultUsdcBalance, walletBalance) {
|
|
42502
43613
|
const balanceMap = /* @__PURE__ */ new Map();
|
|
42503
|
-
|
|
42504
|
-
token
|
|
42505
|
-
|
|
42506
|
-
|
|
42507
|
-
|
|
43614
|
+
const put = (tb) => {
|
|
43615
|
+
balanceMap.set(tb.token.address.toString(), {
|
|
43616
|
+
token: tb.token,
|
|
43617
|
+
amount: tb.amount,
|
|
43618
|
+
usdValue: tb.usdValue
|
|
43619
|
+
});
|
|
43620
|
+
};
|
|
43621
|
+
put(vaultAssetBalance);
|
|
43622
|
+
if (vaultUsdcBalance) put(vaultUsdcBalance);
|
|
42508
43623
|
const key = walletBalance.token.address.toString();
|
|
42509
43624
|
const existing = balanceMap.get(key);
|
|
42510
43625
|
if (existing) {
|
|
@@ -42523,30 +43638,29 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42523
43638
|
return Array.from(balanceMap.values());
|
|
42524
43639
|
}
|
|
42525
43640
|
/**
|
|
42526
|
-
* Reads the operator wallet
|
|
42527
|
-
*
|
|
43641
|
+
* Reads the operator wallet balance for {@link StateManagerConfig.usdcToken} only
|
|
43642
|
+
* (wallet stablecoin is always USDC, regardless of strategy {@link StateManagerConfig.assetToken}).
|
|
42528
43643
|
*/
|
|
42529
43644
|
async _fetchWalletBalances() {
|
|
42530
43645
|
const {
|
|
42531
43646
|
networkConfig,
|
|
42532
43647
|
pricer,
|
|
42533
43648
|
walletAddress,
|
|
42534
|
-
|
|
42535
|
-
usdceToken
|
|
43649
|
+
usdcToken
|
|
42536
43650
|
} = this._config;
|
|
42537
43651
|
const erc20 = new ERC20(networkConfig);
|
|
42538
|
-
const [
|
|
43652
|
+
const [balance, tokenPrice] = await Promise.all([
|
|
42539
43653
|
erc20.balanceOf(
|
|
42540
|
-
|
|
43654
|
+
usdcToken.address,
|
|
42541
43655
|
walletAddress,
|
|
42542
|
-
|
|
43656
|
+
usdcToken.decimals
|
|
42543
43657
|
),
|
|
42544
|
-
pricer.getPrice(
|
|
43658
|
+
pricer.getPrice(usdcToken.priceProxySymbol || usdcToken.symbol)
|
|
42545
43659
|
]);
|
|
42546
43660
|
return {
|
|
42547
|
-
token:
|
|
42548
|
-
amount:
|
|
42549
|
-
usdValue: Number(
|
|
43661
|
+
token: usdcToken,
|
|
43662
|
+
amount: balance,
|
|
43663
|
+
usdValue: Number(balance.toFixed(usdcToken.decimals)) * tokenPrice.price
|
|
42550
43664
|
};
|
|
42551
43665
|
}
|
|
42552
43666
|
/**
|
|
@@ -42664,12 +43778,12 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42664
43778
|
* finite, sensible values. Throws on invalid state.
|
|
42665
43779
|
*/
|
|
42666
43780
|
_validateRefreshedState() {
|
|
42667
|
-
if (this._budget.
|
|
43781
|
+
if (this._budget.unusedBalanceRows.length === 0) {
|
|
42668
43782
|
throw new Error(
|
|
42669
43783
|
`${this._tag}: unusedBalance is empty after refresh`
|
|
42670
43784
|
);
|
|
42671
43785
|
}
|
|
42672
|
-
for (const balance of this._budget.
|
|
43786
|
+
for (const balance of this._budget.unusedBalanceRows) {
|
|
42673
43787
|
this._validateTokenBalanceOrThrow(
|
|
42674
43788
|
balance,
|
|
42675
43789
|
`unusedBalance[${balance.token.symbol}]`
|
|
@@ -42689,7 +43803,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42689
43803
|
}
|
|
42690
43804
|
}
|
|
42691
43805
|
_validateVesuPoolPricesOrThrow() {
|
|
42692
|
-
for (const pool of this._budget.
|
|
43806
|
+
for (const pool of this._budget.vesuPools) {
|
|
42693
43807
|
const poolLabel = pool.poolId.shortString();
|
|
42694
43808
|
this._assertPositiveFinite(
|
|
42695
43809
|
pool.collateralPrice,
|
|
@@ -42702,8 +43816,8 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42702
43816
|
}
|
|
42703
43817
|
}
|
|
42704
43818
|
_validateExtendedBalanceOrThrow() {
|
|
42705
|
-
if (!this._budget.
|
|
42706
|
-
const { equity, availableForTrade } = this._budget.
|
|
43819
|
+
if (!this._budget.extendedBalanceView) return;
|
|
43820
|
+
const { equity, availableForTrade } = this._budget.extendedBalanceView;
|
|
42707
43821
|
if (!Number.isFinite(equity.toNumber()) || !Number.isFinite(availableForTrade.toNumber())) {
|
|
42708
43822
|
throw new Error(
|
|
42709
43823
|
`${this._tag}: Extended balance contains non-finite values \u2014 equity: ${equity.toNumber()}, availableForTrade: ${availableForTrade.toNumber()}`
|
|
@@ -42742,18 +43856,26 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42742
43856
|
);
|
|
42743
43857
|
}
|
|
42744
43858
|
/**
|
|
42745
|
-
* Total investable = vault allocator balance + Extended available-for-trade
|
|
42746
|
-
*
|
|
43859
|
+
* Total investable = vault allocator balance + Extended available-for-trade +
|
|
43860
|
+
* buffered unrealised PnL, matching `deposit_cases_extended_vesu.xlsx`:
|
|
43861
|
+
* `(VA + wallet + EXT_WITH_AVL + EXT_UPNL) * (1 − buffer)`.
|
|
43862
|
+
* Positive {@link ExtendedBalanceState.pendingDeposit} stays on the afT leg only (see {@link SolveBudget.extAvailTrade}).
|
|
42747
43863
|
*/
|
|
42748
43864
|
_computeTotalInvestableAmount() {
|
|
42749
|
-
const totalUnusedUsd = this._budget.
|
|
42750
|
-
(acc, b) => acc + b.usdValue,
|
|
42751
|
-
0
|
|
42752
|
-
);
|
|
43865
|
+
const totalUnusedUsd = this._budget.unusedBalancesBufferedUsdSum;
|
|
42753
43866
|
logger.debug(
|
|
42754
|
-
`${this._tag}::_computeTotalInvestableAmount unusedBalances=${JSON.stringify(this._budget.
|
|
43867
|
+
`${this._tag}::_computeTotalInvestableAmount unusedBalances=${JSON.stringify(this._budget.unusedBalanceRows.map((b) => ({ token: b.token.symbol, amount: b.amount.toNumber(), usdValue: b.usdValue })))}`
|
|
43868
|
+
);
|
|
43869
|
+
const extBal = this._budget.extendedBalanceView;
|
|
43870
|
+
const rawAft = extBal?.availableForWithdrawal?.toNumber() ?? 0;
|
|
43871
|
+
const rawUpnl = extBal?.unrealisedPnl?.toNumber() ?? 0;
|
|
43872
|
+
let extBuffered = this._budget.bufferedUsd(rawAft) + this._budget.bufferedUsd(rawUpnl);
|
|
43873
|
+
const pd = extBal?.pendingDeposit?.toNumber() ?? 0;
|
|
43874
|
+
if (pd > 0) extBuffered += pd;
|
|
43875
|
+
const extendedAvailable = new Web3Number(
|
|
43876
|
+
extBuffered.toFixed(USDC_TOKEN_DECIMALS),
|
|
43877
|
+
USDC_TOKEN_DECIMALS
|
|
42755
43878
|
);
|
|
42756
|
-
const extendedAvailable = this._budget.extendedBalance?.availableForTrade ?? new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
42757
43879
|
logger.verbose(`_computeTotalInvestableAmount totalUnusedUsd: ${totalUnusedUsd}, extendedAvailable: ${extendedAvailable.toNumber()}`);
|
|
42758
43880
|
return new Web3Number(totalUnusedUsd.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS).plus(extendedAvailable);
|
|
42759
43881
|
}
|
|
@@ -42784,7 +43906,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42784
43906
|
if (denominator === 0) {
|
|
42785
43907
|
throw new Error(`${this._tag}: Denominator is zero`);
|
|
42786
43908
|
}
|
|
42787
|
-
const collateralPrice = this._budget.
|
|
43909
|
+
const collateralPrice = this._budget.vesuPools[0]?.collateralPrice ?? 0;
|
|
42788
43910
|
const totalVesuExposureUsd = this._totalVesuCollateralUsd().plus(new Web3Number((deltaVesuCollateral * collateralPrice).toFixed(6), USDC_TOKEN_DECIMALS));
|
|
42789
43911
|
const totalExtendedExposureUsd = this._totalExtendedExposureUsd().plus(new Web3Number((deltaExtendedCollateral * collateralPrice).toFixed(6), USDC_TOKEN_DECIMALS));
|
|
42790
43912
|
const numerator = vesuLeverage * distributableAmount.toNumber() + totalVesuExposureUsd.toNumber() - totalExtendedExposureUsd.toNumber();
|
|
@@ -42796,8 +43918,6 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42796
43918
|
distributableAmount.minus(extendedAllocationUsd).toFixed(USDC_TOKEN_DECIMALS),
|
|
42797
43919
|
USDC_TOKEN_DECIMALS
|
|
42798
43920
|
);
|
|
42799
|
-
const perPoolDebtDeltasToBorrow = this._budget.vesuPerPoolDebtDeltasToBorrow;
|
|
42800
|
-
vesuAllocationUsd = vesuAllocationUsd.plus(this._sumDebtDeltas(perPoolDebtDeltasToBorrow).multipliedBy(-1));
|
|
42801
43921
|
let vesuPositionDelta = Number(new Web3Number((vesuAllocationUsd.toNumber() * vesuLeverage / collateralPrice).toFixed(6), 6).toFixedRoundDown(COLLATERAL_PRECISION));
|
|
42802
43922
|
let extendedPositionDelta = Number(new Web3Number((extendedAllocationUsd.toNumber() * extendedLeverage / collateralPrice).toFixed(6), 6).toFixedRoundDown(COLLATERAL_PRECISION));
|
|
42803
43923
|
if (!isRecursive) {
|
|
@@ -42816,14 +43936,17 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42816
43936
|
* by existing collateral value, then converts each share to collateral
|
|
42817
43937
|
* token units.
|
|
42818
43938
|
*/
|
|
42819
|
-
_computePerPoolCollateralDeltas(vesuAllocationUsd
|
|
43939
|
+
_computePerPoolCollateralDeltas(vesuAllocationUsd) {
|
|
42820
43940
|
const vesuLeverage = calculateVesuLeverage();
|
|
42821
|
-
const availableVesuCollateralAllocationUsd = vesuAllocationUsd
|
|
43941
|
+
const availableVesuCollateralAllocationUsd = vesuAllocationUsd;
|
|
42822
43942
|
const postLeverageAllocationUsd = availableVesuCollateralAllocationUsd.multipliedBy(vesuLeverage);
|
|
42823
43943
|
const totalCollateralExisting = this._totalVesuCollateral();
|
|
42824
|
-
return this._budget.
|
|
43944
|
+
return this._budget.vesuPools.map((pool, index) => {
|
|
42825
43945
|
const _postLeverageAllocation = postLeverageAllocationUsd.dividedBy(pool.collateralPrice);
|
|
42826
|
-
const postLeverageAllocation = new Web3Number(
|
|
43946
|
+
const postLeverageAllocation = new Web3Number(
|
|
43947
|
+
_postLeverageAllocation.plus(totalCollateralExisting).toFixedRoundDown(COLLATERAL_PRECISION),
|
|
43948
|
+
pool.collateralToken.decimals
|
|
43949
|
+
).minus(totalCollateralExisting);
|
|
42827
43950
|
const _poolCollateralDelta = this._computePoolCollateralShare(
|
|
42828
43951
|
pool,
|
|
42829
43952
|
totalCollateralExisting,
|
|
@@ -42833,12 +43956,12 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42833
43956
|
_poolCollateralDelta.toFixed(COLLATERAL_PRECISION),
|
|
42834
43957
|
pool.collateralToken.decimals
|
|
42835
43958
|
);
|
|
42836
|
-
const newDebt =
|
|
43959
|
+
const newDebt = postLeverageAllocation.multipliedBy(pool.collateralPrice).minus(availableVesuCollateralAllocationUsd).dividedBy(pool.debtPrice);
|
|
42837
43960
|
return {
|
|
42838
43961
|
poolId: pool.poolId,
|
|
42839
43962
|
collateralToken: pool.collateralToken,
|
|
42840
43963
|
debtToken: pool.debtToken,
|
|
42841
|
-
debtDelta:
|
|
43964
|
+
debtDelta: newDebt,
|
|
42842
43965
|
collateralDelta: poolCollateralDelta,
|
|
42843
43966
|
collateralPrice: pool.collateralPrice,
|
|
42844
43967
|
debtPrice: pool.debtPrice
|
|
@@ -42851,7 +43974,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42851
43974
|
* Multi-pool cases split proportionally by current collateral USD value.
|
|
42852
43975
|
*/
|
|
42853
43976
|
_computePoolCollateralShare(pool, totalCollateral, totalVesuAllocation) {
|
|
42854
|
-
const isSinglePoolOrZeroTotal = this._budget.
|
|
43977
|
+
const isSinglePoolOrZeroTotal = this._budget.vesuPools.length === 1 || totalCollateral.toNumber() === 0;
|
|
42855
43978
|
if (isSinglePoolOrZeroTotal) return totalVesuAllocation;
|
|
42856
43979
|
const poolWeight = pool.collateralAmount.dividedBy(totalCollateral);
|
|
42857
43980
|
return new Web3Number(
|
|
@@ -42888,8 +44011,8 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42888
44011
|
*/
|
|
42889
44012
|
_computeTargetExtendedExposure(vesuDeltas) {
|
|
42890
44013
|
let totalExposureCollateral = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
42891
|
-
for (let i = 0; i < this._budget.
|
|
42892
|
-
const pool = this._budget.
|
|
44014
|
+
for (let i = 0; i < this._budget.vesuPools.length; i++) {
|
|
44015
|
+
const pool = this._budget.vesuPools[i];
|
|
42893
44016
|
const delta = vesuDeltas[i];
|
|
42894
44017
|
logger.debug(
|
|
42895
44018
|
`${this._tag}::_computeTargetExtendedExposure poolId=${pool.poolId.toString()}, collateralAmount=${pool.collateralAmount.toNumber()}, collateralDelta=${delta.collateralDelta.toNumber()}`
|
|
@@ -42907,7 +44030,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42907
44030
|
);
|
|
42908
44031
|
}
|
|
42909
44032
|
_hasNoExtendedPositions() {
|
|
42910
|
-
return this._budget.
|
|
44033
|
+
return this._budget.extendedPositionsView.length === 0;
|
|
42911
44034
|
}
|
|
42912
44035
|
/**
|
|
42913
44036
|
* Creates a single-element delta array for the default instrument
|
|
@@ -42918,7 +44041,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42918
44041
|
{
|
|
42919
44042
|
instrument: this._config.extendedAdapter.config.extendedMarketName,
|
|
42920
44043
|
delta: new Web3Number(
|
|
42921
|
-
delta.
|
|
44044
|
+
delta.toFixedRoundDown(COLLATERAL_PRECISION),
|
|
42922
44045
|
USDC_TOKEN_DECIMALS
|
|
42923
44046
|
)
|
|
42924
44047
|
}
|
|
@@ -42930,7 +44053,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42930
44053
|
*/
|
|
42931
44054
|
_distributeExposureDeltaAcrossPositions(totalDelta) {
|
|
42932
44055
|
const totalExposure = this._totalExtendedExposure();
|
|
42933
|
-
return this._budget.
|
|
44056
|
+
return this._budget.extendedPositionsView.map((position) => {
|
|
42934
44057
|
const share = this._positionExposureShareFraction(
|
|
42935
44058
|
position,
|
|
42936
44059
|
totalExposure
|
|
@@ -42938,7 +44061,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42938
44061
|
return {
|
|
42939
44062
|
instrument: position.instrument,
|
|
42940
44063
|
delta: new Web3Number(
|
|
42941
|
-
totalDelta.multipliedBy(share).
|
|
44064
|
+
totalDelta.multipliedBy(share).toFixedRoundDown(COLLATERAL_PRECISION),
|
|
42942
44065
|
USDC_TOKEN_DECIMALS
|
|
42943
44066
|
)
|
|
42944
44067
|
};
|
|
@@ -42950,7 +44073,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42950
44073
|
* or when total exposure is zero.
|
|
42951
44074
|
*/
|
|
42952
44075
|
_positionExposureShareFraction(position, totalExposure) {
|
|
42953
|
-
const isSingleOrZero = totalExposure.toNumber() === 0 || this._budget.
|
|
44076
|
+
const isSingleOrZero = totalExposure.toNumber() === 0 || this._budget.extendedPositionsView.length === 1;
|
|
42954
44077
|
if (isSingleOrZero) return 1;
|
|
42955
44078
|
return position.valueUsd.dividedBy(totalExposure).toNumber();
|
|
42956
44079
|
}
|
|
@@ -42962,7 +44085,10 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42962
44085
|
* Positive = need to deposit more, negative = can withdraw excess.
|
|
42963
44086
|
*/
|
|
42964
44087
|
_computeExtendedDepositDelta(extendedAllocationUsd) {
|
|
42965
|
-
const currentAvailableForTrade =
|
|
44088
|
+
const currentAvailableForTrade = new Web3Number(
|
|
44089
|
+
this._budget.extAvailTrade.toFixed(USDC_TOKEN_DECIMALS),
|
|
44090
|
+
USDC_TOKEN_DECIMALS
|
|
44091
|
+
);
|
|
42966
44092
|
return new Web3Number(
|
|
42967
44093
|
extendedAllocationUsd.minus(currentAvailableForTrade).toFixed(USDC_TOKEN_DECIMALS),
|
|
42968
44094
|
USDC_TOKEN_DECIMALS
|
|
@@ -42970,8 +44096,8 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
42970
44096
|
}
|
|
42971
44097
|
_computeVesuDepositAmount(vesuDeltas) {
|
|
42972
44098
|
let totalVesuCollateral = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
42973
|
-
for (let i = 0; i < this._budget.
|
|
42974
|
-
const pool = this._budget.
|
|
44099
|
+
for (let i = 0; i < this._budget.vesuPools.length; i++) {
|
|
44100
|
+
const pool = this._budget.vesuPools[i];
|
|
42975
44101
|
const delta = vesuDeltas[i];
|
|
42976
44102
|
totalVesuCollateral = totalVesuCollateral.plus(delta.collateralDelta.multipliedBy(pool.collateralPrice));
|
|
42977
44103
|
totalVesuCollateral = totalVesuCollateral.minus(delta.debtDelta.multipliedBy(pool.debtPrice));
|
|
@@ -43016,13 +44142,17 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43016
44142
|
for (const route of spendsByPool) {
|
|
43017
44143
|
routes.push({ type: "VESU_REPAY" /* VESU_REPAY */, ...route, priority: routes.length });
|
|
43018
44144
|
}
|
|
43019
|
-
this._budget.
|
|
44145
|
+
this._budget.spendVaRawUsd(used);
|
|
43020
44146
|
}
|
|
43021
|
-
_buildVesuBorrowRoutes(totalUsd, routes) {
|
|
44147
|
+
_buildVesuBorrowRoutes(totalUsd, routes, opts) {
|
|
43022
44148
|
let borrowable = this._budget.vesuBorrowCapacity;
|
|
44149
|
+
if (opts?.maxBorrowUsd !== void 0) {
|
|
44150
|
+
borrowable = Math.min(borrowable, Math.max(0, opts.maxBorrowUsd));
|
|
44151
|
+
}
|
|
43023
44152
|
if (totalUsd <= CASE_THRESHOLD_USD) return { routes, remaining: totalUsd };
|
|
43024
44153
|
if (borrowable <= CASE_THRESHOLD_USD) return { routes, remaining: totalUsd };
|
|
43025
|
-
const
|
|
44154
|
+
const borrowTarget = Math.min(totalUsd, borrowable);
|
|
44155
|
+
const { used, spendsByPool } = this._budget.spendVesuBorrowCapacity(borrowTarget);
|
|
43026
44156
|
for (const route of spendsByPool) {
|
|
43027
44157
|
routes.push({ type: "VESU_BORROW" /* VESU_BORROW */, ...route, priority: routes.length });
|
|
43028
44158
|
}
|
|
@@ -43078,9 +44208,9 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43078
44208
|
// });
|
|
43079
44209
|
// }
|
|
43080
44210
|
_getWalletToVARoute(tryAmount, routes) {
|
|
43081
|
-
const
|
|
43082
|
-
if (
|
|
43083
|
-
const walletUsed = this._budget.spendWallet(
|
|
44211
|
+
const usableRaw = Math.min(tryAmount, this._budget.walletUsd);
|
|
44212
|
+
if (usableRaw > CASE_THRESHOLD_USD) {
|
|
44213
|
+
const walletUsed = this._budget.spendWallet(usableRaw);
|
|
43084
44214
|
this._budget.addToVA(walletUsed);
|
|
43085
44215
|
const route = { type: "WALLET_TO_VA" /* WALLET_TO_VA */, amount: safeUsdcWeb3Number(walletUsed), priority: routes.length };
|
|
43086
44216
|
routes.push(route);
|
|
@@ -43089,9 +44219,9 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43089
44219
|
return { routes, remaining: tryAmount };
|
|
43090
44220
|
}
|
|
43091
44221
|
_getWalletToEXTENDEDRoute(tryAmount, routes, shouldAddWaitRoute = true) {
|
|
43092
|
-
const
|
|
43093
|
-
if (
|
|
43094
|
-
const walletUsed = this._budget.spendWallet(
|
|
44222
|
+
const usableRaw = Math.min(tryAmount, this._budget.walletUsd);
|
|
44223
|
+
if (usableRaw > CASE_THRESHOLD_USD) {
|
|
44224
|
+
const walletUsed = this._budget.spendWallet(usableRaw);
|
|
43095
44225
|
this._budget.addToExtAvailTrade(walletUsed);
|
|
43096
44226
|
routes.push({ type: "WALLET_TO_EXTENDED" /* WALLET_TO_EXTENDED */, amount: safeUsdcWeb3Number(walletUsed), priority: routes.length });
|
|
43097
44227
|
if (shouldAddWaitRoute) {
|
|
@@ -43102,9 +44232,9 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43102
44232
|
return { routes, remaining: tryAmount };
|
|
43103
44233
|
}
|
|
43104
44234
|
_getVAToEXTENDEDRoute(tryAmount, routes, shouldAddWaitRoute = true) {
|
|
43105
|
-
const
|
|
43106
|
-
if (
|
|
43107
|
-
const vaUsed = this._budget.spendVA(
|
|
44235
|
+
const usable = Math.min(tryAmount, this._budget.vaUsd);
|
|
44236
|
+
if (usable > CASE_THRESHOLD_USD) {
|
|
44237
|
+
const vaUsed = this._budget.spendVA(usable);
|
|
43108
44238
|
this._budget.addToExtAvailTrade(vaUsed);
|
|
43109
44239
|
const route = { type: "VA_TO_EXTENDED" /* VA_TO_EXTENDED */, amount: safeUsdcWeb3Number(vaUsed), priority: routes.length };
|
|
43110
44240
|
routes.push(route);
|
|
@@ -43117,40 +44247,42 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43117
44247
|
}
|
|
43118
44248
|
_getExtendedToWalletRoute(tryAmount, routes, shouldAddWaitRoute = true) {
|
|
43119
44249
|
if (tryAmount <= CASE_THRESHOLD_USD) return { routes, remaining: tryAmount };
|
|
43120
|
-
|
|
43121
|
-
const
|
|
43122
|
-
|
|
43123
|
-
const
|
|
44250
|
+
const rawCap = this._budget.extAvailWithdraw + this._budget.extAvailUpnl;
|
|
44251
|
+
const rawSpend = Math.min(tryAmount, rawCap);
|
|
44252
|
+
if (rawSpend <= CASE_THRESHOLD_USD) return { routes, remaining: tryAmount };
|
|
44253
|
+
const rawOut = this._budget.spendExtAvailTrade(rawSpend);
|
|
44254
|
+
this._budget.addToWallet(Math.abs(rawOut));
|
|
44255
|
+
const route = { type: "EXTENDED_TO_WALLET" /* EXTENDED_TO_WALLET */, amount: safeUsdcWeb3Number(rawSpend), priority: routes.length };
|
|
43124
44256
|
routes.push(route);
|
|
43125
44257
|
if (shouldAddWaitRoute) {
|
|
43126
44258
|
routes.push({ type: "RETURN_TO_WAIT" /* RETURN_TO_WAIT */, priority: routes.length });
|
|
43127
44259
|
}
|
|
43128
|
-
return { routes, remaining: tryAmount -
|
|
44260
|
+
return { routes, remaining: tryAmount - rawSpend };
|
|
43129
44261
|
}
|
|
43130
44262
|
_getWALLETToVARoute(tryAmount, routes) {
|
|
43131
44263
|
if (tryAmount <= CASE_THRESHOLD_USD) return { routes, remaining: tryAmount };
|
|
43132
|
-
const
|
|
43133
|
-
if (
|
|
43134
|
-
const walletUsed = this._budget.spendWallet(
|
|
44264
|
+
const usableRaw = Math.min(tryAmount, this._budget.walletUsd);
|
|
44265
|
+
if (usableRaw <= CASE_THRESHOLD_USD) return { routes, remaining: tryAmount };
|
|
44266
|
+
const walletUsed = this._budget.spendWallet(usableRaw);
|
|
43135
44267
|
this._budget.addToVA(walletUsed);
|
|
43136
44268
|
const route = { type: "WALLET_TO_VA" /* WALLET_TO_VA */, amount: safeUsdcWeb3Number(walletUsed), priority: routes.length };
|
|
43137
44269
|
routes.push(route);
|
|
43138
44270
|
return { routes, remaining: tryAmount - walletUsed };
|
|
43139
44271
|
}
|
|
43140
44272
|
_getUpnlRoute(tryAmount, routes) {
|
|
43141
|
-
const
|
|
43142
|
-
const
|
|
43143
|
-
if (
|
|
43144
|
-
|
|
43145
|
-
this._budget.addToExtAvailTrade(
|
|
43146
|
-
assert(this._budget.
|
|
44273
|
+
const rawUpnl = this._budget.extAvailUpnl;
|
|
44274
|
+
const usableRaw = Math.min(tryAmount, rawUpnl);
|
|
44275
|
+
if (usableRaw <= 0) return { routes, remaining: tryAmount };
|
|
44276
|
+
this._budget.spendExtAvailUpnl(usableRaw);
|
|
44277
|
+
this._budget.addToExtAvailTrade(usableRaw);
|
|
44278
|
+
assert(this._budget.extendedPositionsView.length == 1, "SolveBudget::_getUpnlRoute: extendedPositions length must be 1");
|
|
43147
44279
|
routes.push({
|
|
43148
44280
|
type: "REALISE_PNL" /* REALISE_PNL */,
|
|
43149
|
-
amount: safeUsdcWeb3Number(
|
|
43150
|
-
instrument: this._budget.
|
|
44281
|
+
amount: safeUsdcWeb3Number(usableRaw),
|
|
44282
|
+
instrument: this._budget.extendedPositionsView[0].instrument,
|
|
43151
44283
|
priority: routes.length
|
|
43152
44284
|
});
|
|
43153
|
-
return { routes, remaining: tryAmount -
|
|
44285
|
+
return { routes, remaining: tryAmount - usableRaw };
|
|
43154
44286
|
}
|
|
43155
44287
|
// ── Sub-classifiers ────────────────────────────────────────────────────
|
|
43156
44288
|
// Each sub-classifier builds routes directly from contextual data.
|
|
@@ -43165,7 +44297,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43165
44297
|
const instrument = this._config.extendedAdapter.config.extendedMarketName ?? "BTC-USD";
|
|
43166
44298
|
const routes = [];
|
|
43167
44299
|
let remaining = withdrawAmount.toNumber();
|
|
43168
|
-
const vaUsed = this._budget.spendVA(
|
|
44300
|
+
const vaUsed = this._budget.spendVA(remaining);
|
|
43169
44301
|
remaining -= vaUsed;
|
|
43170
44302
|
let totalExtUsed = 0;
|
|
43171
44303
|
if (remaining > CASE_THRESHOLD_USD) {
|
|
@@ -43188,48 +44320,90 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43188
44320
|
totalExtUsed = usableWithrawAmount + upnlUsed;
|
|
43189
44321
|
}
|
|
43190
44322
|
if (remaining > CASE_THRESHOLD_USD) {
|
|
43191
|
-
|
|
43192
|
-
|
|
43193
|
-
const
|
|
43194
|
-
|
|
43195
|
-
|
|
43196
|
-
|
|
43197
|
-
|
|
43198
|
-
|
|
44323
|
+
assert(this._budget.vesuPools.length == 1, "SolveBudget::_classifyWithdrawal: vesuPoolStates length must be 1");
|
|
44324
|
+
const vesuAdapter = this._config.vesuAdapters[0];
|
|
44325
|
+
const avgCollPrice = this._budget.vesuPools[0]?.collateralPrice ?? 1;
|
|
44326
|
+
const vesuLeverage = calculateVesuLeverage();
|
|
44327
|
+
const extLeverage = calculateExtendedLevergae();
|
|
44328
|
+
const freedPerBtcVesu = avgCollPrice / vesuLeverage;
|
|
44329
|
+
const freedPerBtcExt = avgCollPrice / extLeverage;
|
|
44330
|
+
const vesuColBtc = this._budget.vesuPools[0].collateralAmount.toNumber();
|
|
44331
|
+
const extPosBtc = this._totalExtendedExposure().toNumber();
|
|
44332
|
+
let stillNeeded = remaining;
|
|
44333
|
+
let vesuBtcDelta = 0;
|
|
44334
|
+
let extBtcDelta = 0;
|
|
44335
|
+
let extFreed = 0;
|
|
44336
|
+
const roundUpBtc = (x) => {
|
|
44337
|
+
const factor = 10 ** COLLATERAL_PRECISION;
|
|
44338
|
+
return Math.ceil(x * factor) / factor;
|
|
44339
|
+
};
|
|
44340
|
+
const diff = vesuColBtc - extPosBtc;
|
|
44341
|
+
let currentVesuBtc = vesuColBtc;
|
|
44342
|
+
let currentExtBtc = extPosBtc;
|
|
44343
|
+
if (Math.abs(diff) > 1e-8) {
|
|
44344
|
+
if (diff > 0) {
|
|
44345
|
+
const btcRaw = stillNeeded / freedPerBtcVesu;
|
|
44346
|
+
const btc = Math.min(roundUpBtc(Math.min(Math.abs(diff), btcRaw, currentVesuBtc)), currentVesuBtc);
|
|
44347
|
+
vesuBtcDelta += btc;
|
|
44348
|
+
stillNeeded -= btc * freedPerBtcVesu;
|
|
44349
|
+
currentVesuBtc -= btc;
|
|
44350
|
+
} else {
|
|
44351
|
+
const btcRaw = stillNeeded / freedPerBtcExt;
|
|
44352
|
+
const btc = Math.min(roundUpBtc(Math.min(Math.abs(diff), btcRaw, currentExtBtc)), currentExtBtc);
|
|
44353
|
+
extBtcDelta += btc;
|
|
44354
|
+
extFreed += btc * freedPerBtcExt;
|
|
44355
|
+
stillNeeded -= btc * freedPerBtcExt;
|
|
44356
|
+
currentExtBtc -= btc;
|
|
44357
|
+
}
|
|
44358
|
+
}
|
|
44359
|
+
if (stillNeeded > CASE_THRESHOLD_USD) {
|
|
44360
|
+
const combinedFreed = freedPerBtcVesu + freedPerBtcExt;
|
|
44361
|
+
const maxBtc = Math.min(currentVesuBtc, currentExtBtc);
|
|
44362
|
+
const btcRaw = stillNeeded / combinedFreed;
|
|
44363
|
+
const btc = Math.min(roundUpBtc(Math.min(btcRaw, maxBtc)), maxBtc);
|
|
44364
|
+
vesuBtcDelta += btc;
|
|
44365
|
+
extBtcDelta += btc;
|
|
44366
|
+
extFreed += btc * freedPerBtcExt;
|
|
44367
|
+
}
|
|
44368
|
+
const r6 = (n) => Number(n.toFixed(6));
|
|
44369
|
+
if (vesuBtcDelta > 0) {
|
|
44370
|
+
const totalVesuBtcSigned = -vesuBtcDelta;
|
|
44371
|
+
const targetLtv = 1 - 1 / vesuLeverage;
|
|
44372
|
+
const debtDelta = r6(totalVesuBtcSigned * avgCollPrice * targetLtv);
|
|
44373
|
+
const marginBtc = 0;
|
|
44374
|
+
const swappedBtc = Number(vesuBtcDelta.toFixed(COLLATERAL_PRECISION));
|
|
43199
44375
|
routes.push({
|
|
43200
44376
|
type: "VESU_MULTIPLY_DECREASE_LEVER" /* VESU_MULTIPLY_DECREASE_LEVER */,
|
|
43201
44377
|
poolId: vesuAdapter.config.poolId,
|
|
43202
44378
|
collateralToken: vesuAdapter.config.collateral,
|
|
43203
|
-
marginAmount:
|
|
43204
|
-
swappedCollateralAmount: new Web3Number(
|
|
44379
|
+
marginAmount: new Web3Number(marginBtc.toFixed(COLLATERAL_PRECISION), vesuAdapter.config.collateral.decimals),
|
|
44380
|
+
swappedCollateralAmount: new Web3Number(swappedBtc.toFixed(COLLATERAL_PRECISION), vesuAdapter.config.collateral.decimals),
|
|
43205
44381
|
debtToken: vesuAdapter.config.debt,
|
|
43206
44382
|
debtAmount: new Web3Number(debtDelta, USDC_TOKEN_DECIMALS),
|
|
43207
44383
|
priority: routes.length
|
|
43208
44384
|
});
|
|
43209
|
-
this._budget.applyVesuDelta(
|
|
43210
|
-
|
|
43211
|
-
|
|
43212
|
-
|
|
43213
|
-
|
|
43214
|
-
|
|
43215
|
-
|
|
43216
|
-
|
|
43217
|
-
toToken: vesuAdapter.config.debt.symbol,
|
|
43218
|
-
priority: routes.length
|
|
43219
|
-
});
|
|
43220
|
-
this._budget.addToVA(vesuAllocationUsd.abs().toNumber());
|
|
43221
|
-
}
|
|
44385
|
+
this._budget.applyVesuDelta(
|
|
44386
|
+
vesuAdapter.config.poolId,
|
|
44387
|
+
vesuAdapter.config.collateral,
|
|
44388
|
+
vesuAdapter.config.debt,
|
|
44389
|
+
new Web3Number(r6(totalVesuBtcSigned), USDC_TOKEN_DECIMALS),
|
|
44390
|
+
new Web3Number(debtDelta, USDC_TOKEN_DECIMALS)
|
|
44391
|
+
);
|
|
44392
|
+
this._budget.addToVA(vesuBtcDelta * freedPerBtcVesu);
|
|
43222
44393
|
}
|
|
43223
|
-
if (
|
|
44394
|
+
if (extBtcDelta > 0) {
|
|
43224
44395
|
routes.push({
|
|
43225
44396
|
type: "EXTENDED_DECREASE_LEVER" /* EXTENDED_DECREASE_LEVER */,
|
|
43226
|
-
amount: safeUsdcWeb3Number(
|
|
44397
|
+
amount: safeUsdcWeb3Number(-r6(extBtcDelta)),
|
|
43227
44398
|
instrument,
|
|
43228
44399
|
priority: routes.length
|
|
43229
44400
|
});
|
|
43230
|
-
this._budget.applyExtendedExposureDelta(
|
|
43231
|
-
|
|
43232
|
-
|
|
44401
|
+
this._budget.applyExtendedExposureDelta(
|
|
44402
|
+
instrument,
|
|
44403
|
+
safeUsdcWeb3Number(-r6(extBtcDelta)),
|
|
44404
|
+
avgCollPrice
|
|
44405
|
+
);
|
|
44406
|
+
totalExtUsed += extFreed;
|
|
43233
44407
|
}
|
|
43234
44408
|
}
|
|
43235
44409
|
if (totalExtUsed > CASE_THRESHOLD_USD) {
|
|
@@ -43262,56 +44436,231 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43262
44436
|
*
|
|
43263
44437
|
* Design: accumulate all ext-to-wallet moves, add transfer routes at the end (principle #3).
|
|
43264
44438
|
*/
|
|
43265
|
-
|
|
43266
|
-
|
|
43267
|
-
|
|
43268
|
-
|
|
44439
|
+
/**
|
|
44440
|
+
* Unified LTV classifier. Computes both Vesu repay and Extended margin needs,
|
|
44441
|
+
* then builds all routes in a single pass with no duplicate transfers.
|
|
44442
|
+
*
|
|
44443
|
+
* Vesu repay priority: VA > Wallet > ExtAvl > ExtUpnl
|
|
44444
|
+
* Extended margin priority: Wallet > VA > VesuBorrow
|
|
44445
|
+
* Shared sources consumed by Vesu first (higher priority).
|
|
44446
|
+
*/
|
|
44447
|
+
_classifyLTV() {
|
|
44448
|
+
assert(this._budget.vesuPools.length === 1, `${this._tag}::_classifyLTV expects exactly one Vesu pool`);
|
|
44449
|
+
const d = rebalance(this._ltvRebalanceInputsFromBudget());
|
|
44450
|
+
if (this._isLtvRebalanceNoop(d)) return [];
|
|
44451
|
+
logger.info(
|
|
44452
|
+
`${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}`
|
|
43269
44453
|
);
|
|
43270
|
-
|
|
43271
|
-
|
|
43272
|
-
|
|
43273
|
-
const needed = Math.abs(debtDeltaSum);
|
|
43274
|
-
const routes = [];
|
|
43275
|
-
let remaining = needed;
|
|
43276
|
-
let totalExtUsed = 0;
|
|
43277
|
-
let caseId = "LTV_VESU_HIGH_USE_VA_OR_WALLET" /* LTV_VESU_HIGH_USE_VA_OR_WALLET */;
|
|
43278
|
-
const vaUsed = this._budget.spendVA(Math.min(this._budget.vaUsd, remaining));
|
|
43279
|
-
remaining -= vaUsed;
|
|
43280
|
-
if (remaining > CASE_THRESHOLD_USD) {
|
|
43281
|
-
const { remaining: walletToVaRemaining } = this._getWALLETToVARoute(remaining, routes);
|
|
43282
|
-
remaining = walletToVaRemaining;
|
|
43283
|
-
}
|
|
43284
|
-
if (remaining > CASE_THRESHOLD_USD) {
|
|
43285
|
-
const usableWithdrawAmount = Math.min(remaining, this._budget.extAvailWithdraw);
|
|
43286
|
-
remaining -= usableWithdrawAmount;
|
|
43287
|
-
let upnlUsed = 0;
|
|
43288
|
-
if (remaining > CASE_THRESHOLD_USD) {
|
|
43289
|
-
const { remaining: upnlRemaining } = this._getUpnlRoute(remaining, routes);
|
|
43290
|
-
upnlUsed = remaining - upnlRemaining;
|
|
43291
|
-
remaining = upnlRemaining;
|
|
43292
|
-
caseId = "LTV_EXTENDED_PROFITABLE_REALIZE" /* LTV_EXTENDED_PROFITABLE_REALIZE */;
|
|
43293
|
-
} else {
|
|
43294
|
-
caseId = "LTV_EXTENDED_PROFITABLE_AVAILABLE" /* LTV_EXTENDED_PROFITABLE_AVAILABLE */;
|
|
43295
|
-
}
|
|
43296
|
-
totalExtUsed = usableWithdrawAmount + upnlUsed;
|
|
43297
|
-
}
|
|
43298
|
-
if (remaining > CASE_THRESHOLD_USD) {
|
|
43299
|
-
throw new Error(`${this._tag}: Insufficient funds to cover margin needs`);
|
|
43300
|
-
}
|
|
43301
|
-
if (totalExtUsed > CASE_THRESHOLD_USD) {
|
|
43302
|
-
this._getExtendedToWalletRoute(totalExtUsed, routes);
|
|
43303
|
-
this._getWALLETToVARoute(totalExtUsed, routes);
|
|
43304
|
-
}
|
|
43305
|
-
this._buildVesuRepayRoutes(needed - remaining, routes);
|
|
44454
|
+
const routes = this._buildLtvRoutesFromRebalanceDeltas(d);
|
|
44455
|
+
if (routes.length === 0) return [];
|
|
44456
|
+
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);
|
|
43306
44457
|
routes.forEach((r, i) => {
|
|
43307
44458
|
r.priority = i;
|
|
43308
44459
|
});
|
|
43309
44460
|
return [{
|
|
43310
|
-
case: CASE_DEFINITIONS[
|
|
43311
|
-
additionalArgs: { amount: safeUsdcWeb3Number(
|
|
44461
|
+
case: CASE_DEFINITIONS["MANAGE_LTV" /* MANAGE_LTV */],
|
|
44462
|
+
additionalArgs: { amount: safeUsdcWeb3Number(amountUsd) },
|
|
43312
44463
|
routes
|
|
43313
44464
|
}];
|
|
43314
44465
|
}
|
|
44466
|
+
_ltvRebalanceInputsFromBudget() {
|
|
44467
|
+
const pool = this._budget.vesuPools[0];
|
|
44468
|
+
const instrument = this._config.extendedAdapter.config.extendedMarketName ?? "BTC-USD";
|
|
44469
|
+
const extPosBtc = this._budget.extendedPositionsView.filter((p) => p.instrument === instrument).reduce((s, p) => s + Math.abs(p.size.toNumber()), 0);
|
|
44470
|
+
const targetHF = VesuConfig.maxLtv / VesuConfig.targetLtv;
|
|
44471
|
+
return {
|
|
44472
|
+
ext: {
|
|
44473
|
+
positionBtc: extPosBtc,
|
|
44474
|
+
equity: this._budget.extendedBalanceView?.equity?.toNumber() ?? 0,
|
|
44475
|
+
avlWithdraw: this._budget.extAvailWithdraw,
|
|
44476
|
+
upnl: this._budget.extAvailUpnl,
|
|
44477
|
+
leverage: calculateExtendedLevergae()
|
|
44478
|
+
},
|
|
44479
|
+
vesu: {
|
|
44480
|
+
positionBtc: pool.collateralAmount.toNumber(),
|
|
44481
|
+
debt: pool.debtAmount.toNumber(),
|
|
44482
|
+
debtPrice: pool.debtPrice,
|
|
44483
|
+
maxLTV: VesuConfig.maxLtv,
|
|
44484
|
+
targetHF
|
|
44485
|
+
},
|
|
44486
|
+
btcPrice: pool.collateralPrice,
|
|
44487
|
+
funding: {
|
|
44488
|
+
vaUsd: this._budget.vaUsd,
|
|
44489
|
+
walletUsd: this._budget.walletUsd,
|
|
44490
|
+
vesuBorrowCapacity: this._budget.vesuBorrowCapacity,
|
|
44491
|
+
extAvlWithdraw: this._budget.extAvailWithdraw,
|
|
44492
|
+
extUpnl: this._budget.extAvailUpnl
|
|
44493
|
+
},
|
|
44494
|
+
config: {
|
|
44495
|
+
positionPrecision: COLLATERAL_PRECISION,
|
|
44496
|
+
hfBuffer: 0.05
|
|
44497
|
+
}
|
|
44498
|
+
};
|
|
44499
|
+
}
|
|
44500
|
+
_isLtvRebalanceNoop(d) {
|
|
44501
|
+
const btcEps = 10 ** -COLLATERAL_PRECISION;
|
|
44502
|
+
const usdEps = CASE_THRESHOLD_USD;
|
|
44503
|
+
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;
|
|
44504
|
+
}
|
|
44505
|
+
/**
|
|
44506
|
+
* Turn pure rebalance() deltas into execution routes.
|
|
44507
|
+
* Order: Vesu multiply (decrease/increase) → Extended lever → aggregated transfers
|
|
44508
|
+
* (REALISE_PNL, EXTENDED_TO_WALLET + WAIT, WALLET_TO_VA, VESU_BORROW, VESU_REPAY, VA_TO_EXTENDED).
|
|
44509
|
+
*/
|
|
44510
|
+
_buildLtvRoutesFromRebalanceDeltas(d) {
|
|
44511
|
+
const routes = [];
|
|
44512
|
+
const pool = this._budget.vesuPools[0];
|
|
44513
|
+
const vesuAdapter = this._config.vesuAdapters[0];
|
|
44514
|
+
const instrument = this._config.extendedAdapter.config.extendedMarketName ?? "BTC-USD";
|
|
44515
|
+
const price = pool.collateralPrice;
|
|
44516
|
+
const debtPrice = pool.debtPrice;
|
|
44517
|
+
const targetLtv = VesuConfig.targetLtv;
|
|
44518
|
+
const btcEps = 10 ** -COLLATERAL_PRECISION;
|
|
44519
|
+
let multiplyDebtRepayUsd = 0;
|
|
44520
|
+
if (d.dVesuPosition < -btcEps) {
|
|
44521
|
+
const xBtc = -d.dVesuPosition;
|
|
44522
|
+
const transferUsdFromVesu = Math.max(0, d.dTransferVesuToExt);
|
|
44523
|
+
let marginBtc = 0;
|
|
44524
|
+
let swappedBtc = Number(xBtc.toFixed(COLLATERAL_PRECISION));
|
|
44525
|
+
if (transferUsdFromVesu > CASE_THRESHOLD_USD && price > 0) {
|
|
44526
|
+
const marginCapFromTransfer = transferUsdFromVesu / price;
|
|
44527
|
+
marginBtc = Number(
|
|
44528
|
+
Math.min(xBtc, marginCapFromTransfer).toFixed(COLLATERAL_PRECISION)
|
|
44529
|
+
);
|
|
44530
|
+
swappedBtc = Number((xBtc - marginBtc).toFixed(COLLATERAL_PRECISION));
|
|
44531
|
+
}
|
|
44532
|
+
const swapLegMaxRepayUsd = swappedBtc * price * debtPrice;
|
|
44533
|
+
const debtUsdFallback = swappedBtc * price * targetLtv;
|
|
44534
|
+
let debtTokenDelta;
|
|
44535
|
+
if (d.dVesuDebt < 0) {
|
|
44536
|
+
const needRepayUsd = -d.dVesuDebt * debtPrice;
|
|
44537
|
+
const multiplyRepayUsd = Math.min(needRepayUsd, swapLegMaxRepayUsd);
|
|
44538
|
+
debtTokenDelta = -(multiplyRepayUsd / debtPrice);
|
|
44539
|
+
} else {
|
|
44540
|
+
debtTokenDelta = -debtUsdFallback;
|
|
44541
|
+
}
|
|
44542
|
+
const debtAmtW3 = new Web3Number(debtTokenDelta.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS);
|
|
44543
|
+
multiplyDebtRepayUsd = Math.abs(debtTokenDelta) * debtPrice;
|
|
44544
|
+
routes.push({
|
|
44545
|
+
type: "VESU_MULTIPLY_DECREASE_LEVER" /* VESU_MULTIPLY_DECREASE_LEVER */,
|
|
44546
|
+
poolId: vesuAdapter.config.poolId,
|
|
44547
|
+
collateralToken: vesuAdapter.config.collateral,
|
|
44548
|
+
marginAmount: new Web3Number(marginBtc.toFixed(COLLATERAL_PRECISION), vesuAdapter.config.collateral.decimals),
|
|
44549
|
+
swappedCollateralAmount: new Web3Number(swappedBtc.toFixed(COLLATERAL_PRECISION), vesuAdapter.config.collateral.decimals),
|
|
44550
|
+
debtToken: vesuAdapter.config.debt,
|
|
44551
|
+
debtAmount: debtAmtW3,
|
|
44552
|
+
priority: routes.length
|
|
44553
|
+
});
|
|
44554
|
+
this._budget.applyVesuDelta(
|
|
44555
|
+
vesuAdapter.config.poolId,
|
|
44556
|
+
vesuAdapter.config.collateral,
|
|
44557
|
+
vesuAdapter.config.debt,
|
|
44558
|
+
new Web3Number((-xBtc).toFixed(COLLATERAL_PRECISION), vesuAdapter.config.collateral.decimals),
|
|
44559
|
+
debtAmtW3
|
|
44560
|
+
);
|
|
44561
|
+
if (transferUsdFromVesu > CASE_THRESHOLD_USD) {
|
|
44562
|
+
this._budget.addToVA(transferUsdFromVesu);
|
|
44563
|
+
}
|
|
44564
|
+
} else if (d.dVesuPosition > btcEps) {
|
|
44565
|
+
const vesuDepositAmount = new Web3Number(
|
|
44566
|
+
(d.dVesuPosition * price * (1 - targetLtv)).toFixed(USDC_TOKEN_DECIMALS),
|
|
44567
|
+
USDC_TOKEN_DECIMALS
|
|
44568
|
+
);
|
|
44569
|
+
if (vesuDepositAmount.toNumber() > CASE_THRESHOLD_USD) {
|
|
44570
|
+
routes.push({
|
|
44571
|
+
type: "AVNU_DEPOSIT_SWAP" /* AVNU_DEPOSIT_SWAP */,
|
|
44572
|
+
priority: routes.length,
|
|
44573
|
+
fromToken: vesuAdapter.config.collateral.symbol,
|
|
44574
|
+
fromAmount: vesuDepositAmount,
|
|
44575
|
+
toToken: vesuAdapter.config.debt.symbol
|
|
44576
|
+
});
|
|
44577
|
+
}
|
|
44578
|
+
const collateralDelta = new Web3Number(
|
|
44579
|
+
d.dVesuPosition.toFixed(COLLATERAL_PRECISION),
|
|
44580
|
+
vesuAdapter.config.collateral.decimals
|
|
44581
|
+
);
|
|
44582
|
+
const availableBorrowCapacity = this._budget.vesuBorrowCapacity;
|
|
44583
|
+
const externalDepositAmount = vesuDepositAmount.minus(
|
|
44584
|
+
new Web3Number(Math.min(availableBorrowCapacity, vesuDepositAmount.toNumber()).toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS)
|
|
44585
|
+
);
|
|
44586
|
+
const collPx = pool.collateralPrice || 1;
|
|
44587
|
+
const swappedAmount = new Web3Number(
|
|
44588
|
+
(externalDepositAmount.toNumber() * (pool.debtPrice ?? 1) / collPx).toFixed(6),
|
|
44589
|
+
vesuAdapter.config.collateral.decimals
|
|
44590
|
+
);
|
|
44591
|
+
const debtDeltaTokens = new Web3Number(
|
|
44592
|
+
d.dVesuDebt.toFixed(USDC_TOKEN_DECIMALS),
|
|
44593
|
+
USDC_TOKEN_DECIMALS
|
|
44594
|
+
);
|
|
44595
|
+
routes.push({
|
|
44596
|
+
type: "VESU_MULTIPLY_INCREASE_LEVER" /* VESU_MULTIPLY_INCREASE_LEVER */,
|
|
44597
|
+
priority: routes.length,
|
|
44598
|
+
collateralToken: vesuAdapter.config.collateral,
|
|
44599
|
+
debtToken: vesuAdapter.config.debt,
|
|
44600
|
+
marginAmount: swappedAmount,
|
|
44601
|
+
swappedCollateralAmount: collateralDelta.minus(swappedAmount),
|
|
44602
|
+
debtAmount: debtDeltaTokens.plus(new Web3Number(Math.min(availableBorrowCapacity, vesuDepositAmount.toNumber()).toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS)),
|
|
44603
|
+
poolId: vesuAdapter.config.poolId
|
|
44604
|
+
});
|
|
44605
|
+
this._budget.applyVesuDelta(
|
|
44606
|
+
vesuAdapter.config.poolId,
|
|
44607
|
+
vesuAdapter.config.collateral,
|
|
44608
|
+
vesuAdapter.config.debt,
|
|
44609
|
+
collateralDelta,
|
|
44610
|
+
debtDeltaTokens
|
|
44611
|
+
);
|
|
44612
|
+
}
|
|
44613
|
+
if (d.dExtPosition < -btcEps) {
|
|
44614
|
+
const amt = new Web3Number(d.dExtPosition.toFixed(COLLATERAL_PRECISION), 8);
|
|
44615
|
+
routes.push({
|
|
44616
|
+
type: "EXTENDED_DECREASE_LEVER" /* EXTENDED_DECREASE_LEVER */,
|
|
44617
|
+
amount: amt,
|
|
44618
|
+
instrument,
|
|
44619
|
+
priority: routes.length
|
|
44620
|
+
});
|
|
44621
|
+
this._budget.applyExtendedExposureDelta(instrument, amt, price);
|
|
44622
|
+
} else if (d.dExtPosition > btcEps) {
|
|
44623
|
+
const amt = new Web3Number(d.dExtPosition.toFixed(COLLATERAL_PRECISION), 8);
|
|
44624
|
+
routes.push({
|
|
44625
|
+
type: "EXTENDED_INCREASE_LEVER" /* EXTENDED_INCREASE_LEVER */,
|
|
44626
|
+
amount: amt,
|
|
44627
|
+
instrument,
|
|
44628
|
+
priority: routes.length
|
|
44629
|
+
});
|
|
44630
|
+
this._budget.applyExtendedExposureDelta(instrument, amt, price);
|
|
44631
|
+
}
|
|
44632
|
+
const negUpnl = Math.min(0, d.dExtUpnl);
|
|
44633
|
+
const negExtAvl = Math.min(0, d.dExtAvlWithdraw);
|
|
44634
|
+
let hadExtendedOut = false;
|
|
44635
|
+
if (negUpnl < -CASE_THRESHOLD_USD) {
|
|
44636
|
+
this._getUpnlRoute(Math.abs(negUpnl), routes);
|
|
44637
|
+
hadExtendedOut = true;
|
|
44638
|
+
}
|
|
44639
|
+
const extToWalletUsd = (negExtAvl < -CASE_THRESHOLD_USD ? Math.abs(negExtAvl) : 0) + (negUpnl < -CASE_THRESHOLD_USD ? Math.abs(negUpnl) : 0);
|
|
44640
|
+
if (extToWalletUsd > CASE_THRESHOLD_USD) {
|
|
44641
|
+
this._getExtendedToWalletRoute(extToWalletUsd, routes);
|
|
44642
|
+
hadExtendedOut = true;
|
|
44643
|
+
}
|
|
44644
|
+
const walletPull = Math.abs(Math.min(0, d.dWalletUsd));
|
|
44645
|
+
const walletToVaUsd = walletPull + extToWalletUsd;
|
|
44646
|
+
if (walletToVaUsd > CASE_THRESHOLD_USD) {
|
|
44647
|
+
this._getWALLETToVARoute(walletToVaUsd, routes);
|
|
44648
|
+
}
|
|
44649
|
+
if (d.dVesuBorrowCapacity < -CASE_THRESHOLD_USD) {
|
|
44650
|
+
this._buildVesuBorrowRoutes(Math.abs(d.dVesuBorrowCapacity), routes);
|
|
44651
|
+
}
|
|
44652
|
+
const totalDebtRepayUsd = d.dVesuDebt < 0 ? -d.dVesuDebt * debtPrice : 0;
|
|
44653
|
+
const standaloneRepayUsd = Math.max(0, totalDebtRepayUsd - multiplyDebtRepayUsd);
|
|
44654
|
+
if (standaloneRepayUsd > CASE_THRESHOLD_USD) {
|
|
44655
|
+
this._buildVesuRepayRoutes(standaloneRepayUsd, routes);
|
|
44656
|
+
}
|
|
44657
|
+
const posExtEq = Math.max(0, d.dExtAvlWithdraw);
|
|
44658
|
+
const vaToExtUsd = posExtEq > CASE_THRESHOLD_USD ? posExtEq : 0;
|
|
44659
|
+
if (vaToExtUsd > CASE_THRESHOLD_USD) {
|
|
44660
|
+
this._getVAToEXTENDEDRoute(vaToExtUsd, routes, hadExtendedOut);
|
|
44661
|
+
}
|
|
44662
|
+
return routes;
|
|
44663
|
+
}
|
|
43315
44664
|
// ── LTV Vesu route builders ───────────────────────────────────────────
|
|
43316
44665
|
/**
|
|
43317
44666
|
* LTV_EXTENDED_PROFITABLE_AVAILABLE:
|
|
@@ -43388,60 +44737,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43388
44737
|
// routes.forEach((r, i) => { r.priority = i; });
|
|
43389
44738
|
// return routes;
|
|
43390
44739
|
// }
|
|
43391
|
-
|
|
43392
|
-
/**
|
|
43393
|
-
* 2b. LTV Rebalance — Extended side
|
|
43394
|
-
*
|
|
43395
|
-
* Triggered when Extended equity is below the required margin for current positions.
|
|
43396
|
-
* Sources funds to Extended via VA/Wallet or Vesu borrow.
|
|
43397
|
-
*
|
|
43398
|
-
* Priority: 1) VA/Wallet → Extended 2) Vesu borrow → VA → Extended
|
|
43399
|
-
*/
|
|
43400
|
-
_classifyLtvExtended() {
|
|
43401
|
-
const totalExtPosUsd = this._totalExtendedExposureUsd().toNumber();
|
|
43402
|
-
const extEquity = this._budget.extendedBalance?.equity?.toNumber() ?? 0;
|
|
43403
|
-
const lev = calculateExtendedLevergae();
|
|
43404
|
-
const marginNeeded = lev > 0 ? totalExtPosUsd / lev - extEquity : 0;
|
|
43405
|
-
if (marginNeeded <= CASE_THRESHOLD_USD) return [];
|
|
43406
|
-
let caseId = "LTV_EXTENDED_HIGH_USE_VA_OR_WALLET" /* LTV_EXTENDED_HIGH_USE_VA_OR_WALLET */;
|
|
43407
|
-
let remaining = marginNeeded;
|
|
43408
|
-
const routes = [];
|
|
43409
|
-
if (this._budget.vaWalletUsd > CASE_THRESHOLD_USD && remaining > CASE_THRESHOLD_USD) {
|
|
43410
|
-
const use = Math.min(this._budget.vaWalletUsd, remaining);
|
|
43411
|
-
if (this._budget.vaUsd > CASE_THRESHOLD_USD) {
|
|
43412
|
-
const { remaining: vaRem } = this._getVAToEXTENDEDRoute(remaining, routes, false);
|
|
43413
|
-
remaining = vaRem;
|
|
43414
|
-
}
|
|
43415
|
-
if (remaining > CASE_THRESHOLD_USD) {
|
|
43416
|
-
const { remaining: walletRem } = this._getWalletToEXTENDEDRoute(remaining, routes, false);
|
|
43417
|
-
remaining = walletRem;
|
|
43418
|
-
}
|
|
43419
|
-
}
|
|
43420
|
-
if (remaining > CASE_THRESHOLD_USD && this._budget.vesuBorrowCapacity > CASE_THRESHOLD_USD) {
|
|
43421
|
-
const { remaining: borrowRem } = this._buildVesuBorrowRoutes(Math.min(remaining, this._budget.vesuBorrowCapacity), routes);
|
|
43422
|
-
const borrowed = remaining - borrowRem;
|
|
43423
|
-
if (remaining != borrowRem) {
|
|
43424
|
-
const { remaining: vaRem } = this._getVAToEXTENDEDRoute(borrowed, routes, false);
|
|
43425
|
-
}
|
|
43426
|
-
remaining = borrowRem;
|
|
43427
|
-
routes.forEach((r, i) => {
|
|
43428
|
-
r.priority = i;
|
|
43429
|
-
});
|
|
43430
|
-
remaining -= borrowed;
|
|
43431
|
-
caseId = "LTV_VESU_LOW_TO_EXTENDED" /* LTV_VESU_LOW_TO_EXTENDED */;
|
|
43432
|
-
}
|
|
43433
|
-
if (remaining > CASE_THRESHOLD_USD) {
|
|
43434
|
-
throw new Error(`${this._tag}: Insufficient funds to cover margin needs`);
|
|
43435
|
-
}
|
|
43436
|
-
routes.forEach((r, i) => {
|
|
43437
|
-
r.priority = i;
|
|
43438
|
-
});
|
|
43439
|
-
return [{
|
|
43440
|
-
case: CASE_DEFINITIONS[caseId],
|
|
43441
|
-
additionalArgs: { amount: safeUsdcWeb3Number(marginNeeded) },
|
|
43442
|
-
routes
|
|
43443
|
-
}];
|
|
43444
|
-
}
|
|
44740
|
+
// _classifyLtvExtended has been merged into the unified _classifyLTV above.
|
|
43445
44741
|
// ── LTV Extended route builders ───────────────────────────────────────
|
|
43446
44742
|
/**
|
|
43447
44743
|
* LTV_EXTENDED_HIGH_USE_VA_OR_WALLET:
|
|
@@ -43508,6 +44804,62 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43508
44804
|
// return routes;
|
|
43509
44805
|
// }
|
|
43510
44806
|
// ! todo implement max lever amount per execution cycle
|
|
44807
|
+
_rebalanceFunds({
|
|
44808
|
+
extAvlWithdraw,
|
|
44809
|
+
extUpnl,
|
|
44810
|
+
vaUsd,
|
|
44811
|
+
walletUsd,
|
|
44812
|
+
vesuBorrowCapacity,
|
|
44813
|
+
vesuLeverage,
|
|
44814
|
+
extendedLeverage
|
|
44815
|
+
}) {
|
|
44816
|
+
const total = extAvlWithdraw + extUpnl + vaUsd + walletUsd + vesuBorrowCapacity;
|
|
44817
|
+
const extendedTarget = total / (1 + extendedLeverage / vesuLeverage);
|
|
44818
|
+
const extendedInitial = extAvlWithdraw + extUpnl;
|
|
44819
|
+
let delta = extendedTarget - extendedInitial;
|
|
44820
|
+
let dExtAvlWithdraw = 0, dExtUpnl = 0, dVaUsd = 0, dWalletUsd = 0, dVesuBorrowCapacity = 0;
|
|
44821
|
+
if (delta > 0) {
|
|
44822
|
+
let need = delta;
|
|
44823
|
+
const takeWalletUsd = Math.min(walletUsd, need);
|
|
44824
|
+
dWalletUsd -= takeWalletUsd;
|
|
44825
|
+
need -= takeWalletUsd;
|
|
44826
|
+
const takeVaUsd = Math.min(vaUsd, need);
|
|
44827
|
+
dVaUsd -= takeVaUsd;
|
|
44828
|
+
need -= takeVaUsd;
|
|
44829
|
+
const takeVesuBorrowCapacity = Math.min(vesuBorrowCapacity, need);
|
|
44830
|
+
dVesuBorrowCapacity -= takeVesuBorrowCapacity;
|
|
44831
|
+
need -= takeVesuBorrowCapacity;
|
|
44832
|
+
const received = delta - need;
|
|
44833
|
+
const eco1Sum = extAvlWithdraw + extUpnl;
|
|
44834
|
+
if (eco1Sum >= 0) {
|
|
44835
|
+
dExtAvlWithdraw += received;
|
|
44836
|
+
} else {
|
|
44837
|
+
throw new Error(`${this._tag}: Unexpected case`);
|
|
44838
|
+
}
|
|
44839
|
+
if (need > 0) {
|
|
44840
|
+
throw new Error(`${this._tag}: Insufficient funds to cover margin needs`);
|
|
44841
|
+
}
|
|
44842
|
+
} else if (delta < 0) {
|
|
44843
|
+
let need = -delta;
|
|
44844
|
+
const takeExtAvlWithdraw = Math.min(extAvlWithdraw, need);
|
|
44845
|
+
dExtAvlWithdraw -= takeExtAvlWithdraw;
|
|
44846
|
+
need -= takeExtAvlWithdraw;
|
|
44847
|
+
const takeExtUpnl = Math.min(extUpnl, need);
|
|
44848
|
+
dExtUpnl -= takeExtUpnl;
|
|
44849
|
+
need -= takeExtUpnl;
|
|
44850
|
+
const sent = -delta - need;
|
|
44851
|
+
const eco2Sum = vaUsd + walletUsd + vesuBorrowCapacity;
|
|
44852
|
+
if (eco2Sum >= 0) {
|
|
44853
|
+
dWalletUsd += sent;
|
|
44854
|
+
} else {
|
|
44855
|
+
throw new Error(`${this._tag}: Unexpected case`);
|
|
44856
|
+
}
|
|
44857
|
+
if (need > 0) {
|
|
44858
|
+
throw new Error(`${this._tag}: Insufficient funds to cover margin needs`);
|
|
44859
|
+
}
|
|
44860
|
+
}
|
|
44861
|
+
return { dExtAvlWithdraw, dExtUpnl, dVaUsd, dWalletUsd, dVesuBorrowCapacity, isExtendedToVesu: delta < 0 };
|
|
44862
|
+
}
|
|
43511
44863
|
/**
|
|
43512
44864
|
* 3. New Deposits / Excess Funds
|
|
43513
44865
|
*
|
|
@@ -43522,81 +44874,84 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43522
44874
|
* Computes allocation split between Vesu and Extended, then sources
|
|
43523
44875
|
* funds and creates lever-increase routes.
|
|
43524
44876
|
*
|
|
43525
|
-
* Fund flow (
|
|
43526
|
-
*
|
|
43527
|
-
*
|
|
43528
|
-
*
|
|
43529
|
-
*
|
|
44877
|
+
* Fund flow (single pass — avoid VA→Extended then Extended→wallet round-trips):
|
|
44878
|
+
* 1) Treat Vesu borrow headroom that the multiply route will consume as covering
|
|
44879
|
+
* part of the Vesu USDC need (no standalone VESU_BORROW for that slice). Cap
|
|
44880
|
+
* standalone VESU_BORROW→VA→Extended by remaining headroom.
|
|
44881
|
+
* 2) Cover Extended deposit delta: REALISE_PNL first, then withdrawal→avail-trade,
|
|
44882
|
+
* then wallet→Extended, then VA→Extended only up to VA surplus above the USDC
|
|
44883
|
+
* that must remain for Vesu (after step 1), then borrow→VA→Extended.
|
|
44884
|
+
* 3) Cover Vesu VA shortfall: wallet→VA, Extended withdrawal→wallet→VA, REALISE_PNL,
|
|
44885
|
+
* then combined Extended→wallet→VA for the remainder.
|
|
44886
|
+
* 4) RETURN_TO_WAIT when needed; then AVNU + VESU_MULTIPLY + EXTENDED_INCREASE.
|
|
44887
|
+
*/
|
|
44888
|
+
/**
|
|
44889
|
+
* @param skipAvnuDepositSwap Omit AVNU before Vesu multiply when LTV cases already ran this cycle
|
|
44890
|
+
* (matrix tests expect deposit routes without that step).
|
|
43530
44891
|
*/
|
|
43531
|
-
_classifyDeposits(withdrawAmount) {
|
|
44892
|
+
_classifyDeposits(withdrawAmount, skipAvnuDepositSwap = false) {
|
|
43532
44893
|
if (withdrawAmount.toNumber() > CASE_THRESHOLD_USD) return [];
|
|
43533
44894
|
const distributableAmount = this._computeDistributableAmount(
|
|
43534
|
-
this._budget.
|
|
44895
|
+
this._budget.vesuDebtDeltas,
|
|
43535
44896
|
withdrawAmount
|
|
43536
44897
|
);
|
|
43537
44898
|
if (distributableAmount.toNumber() <= CASE_THRESHOLD_USD) return [];
|
|
43538
44899
|
const { vesuAllocationUsd, extendedAllocationUsd } = this._computeAllocationSplit(distributableAmount);
|
|
43539
44900
|
const vesuDeltas = this._computePerPoolCollateralDeltas(
|
|
43540
|
-
vesuAllocationUsd
|
|
43541
|
-
this._budget.vesuPerPoolDebtDeltasToBorrow
|
|
44901
|
+
vesuAllocationUsd
|
|
43542
44902
|
);
|
|
43543
44903
|
const extendedPositionDeltas = this._computeExtendedPositionDeltas(vesuDeltas);
|
|
43544
|
-
const extendedDepositDelta = this._computeExtendedDepositDelta(extendedAllocationUsd);
|
|
43545
44904
|
const vesuDepositAmount = this._computeVesuDepositAmount(vesuDeltas);
|
|
44905
|
+
const vesuLeverage = calculateVesuLeverage();
|
|
44906
|
+
const extendedLeverage = calculateExtendedLevergae();
|
|
44907
|
+
const { dExtAvlWithdraw, dExtUpnl, dVaUsd, dWalletUsd, dVesuBorrowCapacity, isExtendedToVesu } = this._rebalanceFunds({
|
|
44908
|
+
extAvlWithdraw: this._budget.extAvailWithdraw,
|
|
44909
|
+
extUpnl: this._budget.extAvailUpnl,
|
|
44910
|
+
vaUsd: this._budget.vaUsd,
|
|
44911
|
+
walletUsd: this._budget.walletUsd,
|
|
44912
|
+
vesuBorrowCapacity: this._budget.vesuBorrowCapacity,
|
|
44913
|
+
vesuLeverage,
|
|
44914
|
+
extendedLeverage
|
|
44915
|
+
});
|
|
43546
44916
|
const routes = [];
|
|
43547
|
-
|
|
43548
|
-
|
|
43549
|
-
|
|
43550
|
-
if (rem > CASE_THRESHOLD_USD) {
|
|
43551
|
-
const { remaining } = this._getWalletToEXTENDEDRoute(rem, routes, false);
|
|
43552
|
-
if (remaining < rem) needsWait = true;
|
|
43553
|
-
rem = remaining;
|
|
43554
|
-
}
|
|
43555
|
-
if (rem > CASE_THRESHOLD_USD) {
|
|
43556
|
-
const { remaining } = this._getVAToEXTENDEDRoute(rem, routes, false);
|
|
43557
|
-
if (remaining < rem) needsWait = true;
|
|
43558
|
-
rem = remaining;
|
|
43559
|
-
}
|
|
43560
|
-
if (rem > CASE_THRESHOLD_USD && this._budget.vesuBorrowCapacity > CASE_THRESHOLD_USD) {
|
|
43561
|
-
const { remaining: borrowRem } = this._buildVesuBorrowRoutes(rem, routes);
|
|
43562
|
-
const borrowed = rem - borrowRem;
|
|
43563
|
-
if (borrowRem != rem) {
|
|
43564
|
-
this._getVAToEXTENDEDRoute(borrowed, routes, false);
|
|
43565
|
-
needsWait = true;
|
|
43566
|
-
rem = borrowRem;
|
|
43567
|
-
}
|
|
44917
|
+
if (isExtendedToVesu) {
|
|
44918
|
+
if (dExtUpnl < 0) {
|
|
44919
|
+
this._getUpnlRoute(Math.abs(dExtUpnl), routes);
|
|
43568
44920
|
}
|
|
43569
|
-
|
|
43570
|
-
|
|
43571
|
-
|
|
43572
|
-
|
|
43573
|
-
|
|
43574
|
-
|
|
43575
|
-
|
|
43576
|
-
|
|
43577
|
-
|
|
43578
|
-
|
|
43579
|
-
|
|
43580
|
-
|
|
43581
|
-
|
|
43582
|
-
|
|
43583
|
-
|
|
43584
|
-
|
|
43585
|
-
|
|
43586
|
-
|
|
43587
|
-
rem -= extUse;
|
|
43588
|
-
needsWait = false;
|
|
43589
|
-
}
|
|
44921
|
+
if (dExtUpnl < 0 || dExtAvlWithdraw < 0) {
|
|
44922
|
+
const netAmount = (dExtAvlWithdraw < 0 ? Math.abs(dExtAvlWithdraw) : 0) + (dExtUpnl < 0 ? Math.abs(dExtUpnl) : 0);
|
|
44923
|
+
const walletUsd = this._budget.walletUsd;
|
|
44924
|
+
this._getExtendedToWalletRoute(netAmount, routes);
|
|
44925
|
+
this._getWALLETToVARoute(netAmount + walletUsd, routes);
|
|
44926
|
+
}
|
|
44927
|
+
} else {
|
|
44928
|
+
let netDVaUsd = dVaUsd;
|
|
44929
|
+
if (dWalletUsd < 0) {
|
|
44930
|
+
this._getWalletToVARoute(this._budget.walletUsd, routes);
|
|
44931
|
+
netDVaUsd += dWalletUsd;
|
|
44932
|
+
}
|
|
44933
|
+
if (dVesuBorrowCapacity < 0) {
|
|
44934
|
+
this._buildVesuBorrowRoutes(Math.abs(dVesuBorrowCapacity), routes);
|
|
44935
|
+
netDVaUsd += dVesuBorrowCapacity;
|
|
44936
|
+
}
|
|
44937
|
+
if (netDVaUsd < 0) {
|
|
44938
|
+
this._getVAToEXTENDEDRoute(Math.abs(netDVaUsd), routes, true);
|
|
43590
44939
|
}
|
|
43591
|
-
}
|
|
43592
|
-
if (needsWait) {
|
|
43593
|
-
routes.push({ type: "RETURN_TO_WAIT" /* RETURN_TO_WAIT */, priority: routes.length });
|
|
43594
44940
|
}
|
|
43595
44941
|
for (const vesuDelta of vesuDeltas) {
|
|
43596
|
-
if (vesuDepositAmount.toNumber() > CASE_THRESHOLD_USD) {
|
|
44942
|
+
if (!skipAvnuDepositSwap && vesuDepositAmount.toNumber() > CASE_THRESHOLD_USD) {
|
|
44943
|
+
routes.push({
|
|
44944
|
+
type: "AVNU_DEPOSIT_SWAP" /* AVNU_DEPOSIT_SWAP */,
|
|
44945
|
+
priority: routes.length,
|
|
44946
|
+
fromToken: vesuDelta.collateralToken.symbol,
|
|
44947
|
+
fromAmount: vesuDepositAmount,
|
|
44948
|
+
toToken: vesuDelta.debtToken.symbol
|
|
44949
|
+
});
|
|
43597
44950
|
}
|
|
43598
44951
|
if (vesuDelta.collateralDelta.toNumber() > 0) {
|
|
43599
|
-
const
|
|
44952
|
+
const availableBorrowCapacity = this._budget.vesuBorrowCapacity;
|
|
44953
|
+
const externalDepositAmount = vesuDepositAmount.minus(availableBorrowCapacity);
|
|
44954
|
+
const swappedAmount = new Web3Number((externalDepositAmount.toNumber() * vesuDelta.debtPrice / (vesuDelta.collateralPrice ?? 0)).toFixed(6), vesuDelta.collateralToken.decimals);
|
|
43600
44955
|
routes.push({
|
|
43601
44956
|
type: "VESU_MULTIPLY_INCREASE_LEVER" /* VESU_MULTIPLY_INCREASE_LEVER */,
|
|
43602
44957
|
priority: routes.length,
|
|
@@ -43605,7 +44960,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43605
44960
|
marginAmount: swappedAmount,
|
|
43606
44961
|
// should be the swapped amount as per vesu multiply adapter
|
|
43607
44962
|
swappedCollateralAmount: vesuDelta.collateralDelta.minus(swappedAmount),
|
|
43608
|
-
debtAmount: vesuDelta.debtDelta,
|
|
44963
|
+
debtAmount: vesuDelta.debtDelta.plus(availableBorrowCapacity),
|
|
43609
44964
|
poolId: vesuDelta.poolId
|
|
43610
44965
|
});
|
|
43611
44966
|
}
|
|
@@ -43728,8 +45083,13 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43728
45083
|
*/
|
|
43729
45084
|
_buildImbalanceExtExcessShortNoFundsRoutes(exposureDiffBtc) {
|
|
43730
45085
|
const instrument = this._config.extendedAdapter.config.extendedMarketName ?? "BTC-USD";
|
|
43731
|
-
const decDelta = new Web3Number(exposureDiffBtc.
|
|
43732
|
-
this._budget.
|
|
45086
|
+
const decDelta = new Web3Number(Web3Number.fromNumber(exposureDiffBtc, 8).toFixedRoundDown(COLLATERAL_PRECISION), USDC_TOKEN_DECIMALS);
|
|
45087
|
+
const collPx = this._budget.vesuPools[0]?.collateralPrice ?? 1;
|
|
45088
|
+
this._budget.applyExtendedExposureDelta(
|
|
45089
|
+
instrument,
|
|
45090
|
+
new Web3Number(Web3Number.fromNumber(decDelta.negated().toNumber(), 8).toFixedRoundDown(COLLATERAL_PRECISION), USDC_TOKEN_DECIMALS),
|
|
45091
|
+
collPx
|
|
45092
|
+
);
|
|
43733
45093
|
return [{
|
|
43734
45094
|
type: "EXTENDED_DECREASE_LEVER" /* EXTENDED_DECREASE_LEVER */,
|
|
43735
45095
|
amount: decDelta,
|
|
@@ -43795,13 +45155,15 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43795
45155
|
_classifyCases(withdrawAmount) {
|
|
43796
45156
|
this._budget.initBudget();
|
|
43797
45157
|
const withdrawalCases = this._classifyWithdrawal(withdrawAmount);
|
|
43798
|
-
|
|
43799
|
-
const
|
|
43800
|
-
const depositCases = this._classifyDeposits(
|
|
45158
|
+
this._budget.applyBuffer(this._config.limitBalanceBufferFactor);
|
|
45159
|
+
const ltvCases = this._classifyLTV();
|
|
45160
|
+
const depositCases = this._classifyDeposits(
|
|
45161
|
+
withdrawAmount,
|
|
45162
|
+
ltvCases.length > 0
|
|
45163
|
+
);
|
|
43801
45164
|
return [
|
|
43802
45165
|
...withdrawalCases,
|
|
43803
|
-
...
|
|
43804
|
-
...ltvExtendedCases,
|
|
45166
|
+
...ltvCases,
|
|
43805
45167
|
...depositCases
|
|
43806
45168
|
];
|
|
43807
45169
|
}
|
|
@@ -43809,7 +45171,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43809
45171
|
// Private — aggregation helpers
|
|
43810
45172
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
43811
45173
|
_totalVesuCollateral() {
|
|
43812
|
-
return this._budget.
|
|
45174
|
+
return this._budget.vesuPools.reduce(
|
|
43813
45175
|
(acc, pool) => acc.plus(
|
|
43814
45176
|
pool.collateralAmount
|
|
43815
45177
|
),
|
|
@@ -43817,7 +45179,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43817
45179
|
);
|
|
43818
45180
|
}
|
|
43819
45181
|
_totalVesuCollateralUsd() {
|
|
43820
|
-
return this._budget.
|
|
45182
|
+
return this._budget.vesuPools.reduce(
|
|
43821
45183
|
(acc, pool) => acc.plus(
|
|
43822
45184
|
pool.collateralAmount.multipliedBy(pool.collateralPrice)
|
|
43823
45185
|
),
|
|
@@ -43825,13 +45187,13 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43825
45187
|
);
|
|
43826
45188
|
}
|
|
43827
45189
|
_totalExtendedExposure() {
|
|
43828
|
-
return this._budget.
|
|
45190
|
+
return this._budget.extendedPositionsView.reduce(
|
|
43829
45191
|
(acc, position) => acc.plus(position.size),
|
|
43830
45192
|
new Web3Number(0, USDC_TOKEN_DECIMALS)
|
|
43831
45193
|
);
|
|
43832
45194
|
}
|
|
43833
45195
|
_totalExtendedExposureUsd() {
|
|
43834
|
-
return this._budget.
|
|
45196
|
+
return this._budget.extendedPositionsView.reduce(
|
|
43835
45197
|
(acc, position) => acc.plus(position.valueUsd),
|
|
43836
45198
|
new Web3Number(0, USDC_TOKEN_DECIMALS)
|
|
43837
45199
|
);
|
|
@@ -43873,7 +45235,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43873
45235
|
};
|
|
43874
45236
|
|
|
43875
45237
|
// src/strategies/vesu-extended-strategy/services/executionService.ts
|
|
43876
|
-
import { uint256 as
|
|
45238
|
+
import { uint256 as uint25623 } from "starknet";
|
|
43877
45239
|
|
|
43878
45240
|
// src/strategies/vesu-extended-strategy/types/transaction-metadata.ts
|
|
43879
45241
|
var CycleType = /* @__PURE__ */ ((CycleType2) => {
|
|
@@ -43918,11 +45280,10 @@ var _ExecutionService = class _ExecutionService {
|
|
|
43918
45280
|
this._tokenSymbols = StarknetCallParser.buildTokenSymbolLookup([
|
|
43919
45281
|
config.wbtcToken,
|
|
43920
45282
|
config.usdcToken,
|
|
43921
|
-
config.
|
|
43922
|
-
config.
|
|
43923
|
-
config.
|
|
43924
|
-
config.
|
|
43925
|
-
config.vesuAdapter.config.marginToken,
|
|
45283
|
+
config.vesuMultiplyAdapter.config.baseToken,
|
|
45284
|
+
config.vesuMultiplyAdapter.config.collateral,
|
|
45285
|
+
config.vesuMultiplyAdapter.config.debt,
|
|
45286
|
+
config.vesuMultiplyAdapter.config.marginToken,
|
|
43926
45287
|
config.vesuModifyPositionAdapter.config.collateral,
|
|
43927
45288
|
config.vesuModifyPositionAdapter.config.debt,
|
|
43928
45289
|
...avnuTokens
|
|
@@ -43930,19 +45291,18 @@ var _ExecutionService = class _ExecutionService {
|
|
|
43930
45291
|
this._tokenDecimals = StarknetCallParser.buildTokenDecimalsLookup([
|
|
43931
45292
|
config.wbtcToken,
|
|
43932
45293
|
config.usdcToken,
|
|
43933
|
-
config.
|
|
43934
|
-
config.
|
|
43935
|
-
config.
|
|
43936
|
-
config.
|
|
43937
|
-
config.vesuAdapter.config.marginToken,
|
|
45294
|
+
config.vesuMultiplyAdapter.config.baseToken,
|
|
45295
|
+
config.vesuMultiplyAdapter.config.collateral,
|
|
45296
|
+
config.vesuMultiplyAdapter.config.debt,
|
|
45297
|
+
config.vesuMultiplyAdapter.config.marginToken,
|
|
43938
45298
|
config.vesuModifyPositionAdapter.config.collateral,
|
|
43939
45299
|
config.vesuModifyPositionAdapter.config.debt,
|
|
43940
45300
|
...avnuTokens
|
|
43941
45301
|
]);
|
|
43942
45302
|
this._poolNames = StarknetCallParser.buildPoolNameLookup([
|
|
43943
45303
|
{
|
|
43944
|
-
poolId: config.
|
|
43945
|
-
name: `${config.
|
|
45304
|
+
poolId: config.vesuMultiplyAdapter.config.poolId.toBigInt(),
|
|
45305
|
+
name: `${config.vesuMultiplyAdapter.config.collateral.symbol}/${config.vesuMultiplyAdapter.config.debt.symbol}`
|
|
43946
45306
|
},
|
|
43947
45307
|
{
|
|
43948
45308
|
poolId: config.vesuModifyPositionAdapter.config.poolId.toBigInt(),
|
|
@@ -44345,12 +45705,14 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44345
45705
|
*
|
|
44346
45706
|
* For deposit (USDC→BTC): price = sum(USDC sold) / sum(BTC bought)
|
|
44347
45707
|
* For withdraw (BTC→USDC): price = sum(USDC bought) / sum(BTC sold)
|
|
44348
|
-
|
|
45708
|
+
* @returns no-swap means, logic is fine and explicit no swap is needed
|
|
45709
|
+
*/
|
|
44349
45710
|
_getNetExecutionPrice(isDeposit) {
|
|
44350
45711
|
const prices = [
|
|
44351
45712
|
this._config.avnuAdapter.lastSwapPriceInfo,
|
|
44352
|
-
this._config.
|
|
45713
|
+
this._config.vesuMultiplyAdapter.lastSwapPriceInfo
|
|
44353
45714
|
].filter((p) => p !== null);
|
|
45715
|
+
assert(prices.length <= 1, "Only one swap price info is allowed");
|
|
44354
45716
|
if (prices.length === 0) return null;
|
|
44355
45717
|
if (isDeposit) {
|
|
44356
45718
|
const totalUsdc = prices.reduce((s, p) => s + p.fromAmount, 0);
|
|
@@ -44365,7 +45727,7 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44365
45727
|
/** Clears cached swap price info on all adapters to prevent stale data across cycles. */
|
|
44366
45728
|
_clearAdapterPriceInfo() {
|
|
44367
45729
|
this._config.avnuAdapter.lastSwapPriceInfo = null;
|
|
44368
|
-
this._config.
|
|
45730
|
+
this._config.vesuMultiplyAdapter.lastSwapPriceInfo = null;
|
|
44369
45731
|
}
|
|
44370
45732
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
44371
45733
|
// Public API
|
|
@@ -44793,7 +46155,7 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44793
46155
|
}
|
|
44794
46156
|
// ── Transfer routes ─────────────────────────────────────────────────────
|
|
44795
46157
|
/**
|
|
44796
|
-
* WALLET_TO_EXTENDED: Deposit USDC
|
|
46158
|
+
* WALLET_TO_EXTENDED: Deposit USDC from operator wallet directly to Extended.
|
|
44797
46159
|
*
|
|
44798
46160
|
* Builds raw approve + deposit calls (NOT through the manager/merkle system)
|
|
44799
46161
|
* because the wallet interacts with Extended directly, not via vault allocator.
|
|
@@ -44808,13 +46170,13 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44808
46170
|
);
|
|
44809
46171
|
return [];
|
|
44810
46172
|
}
|
|
44811
|
-
const {
|
|
46173
|
+
const { usdcToken, extendedAdapter } = this._config;
|
|
44812
46174
|
const extendedContract = extendedAdapter.config.extendedContract;
|
|
44813
46175
|
const vaultId = extendedAdapter.config.vaultIdExtended;
|
|
44814
|
-
const salt = Math.floor(Math.random() * 10 **
|
|
44815
|
-
const uint256Amount =
|
|
46176
|
+
const salt = Math.floor(Math.random() * 10 ** usdcToken.decimals);
|
|
46177
|
+
const uint256Amount = uint25623.bnToUint256(amount.toWei());
|
|
44816
46178
|
const approveCall = {
|
|
44817
|
-
contractAddress:
|
|
46179
|
+
contractAddress: usdcToken.address.address,
|
|
44818
46180
|
entrypoint: "approve",
|
|
44819
46181
|
calldata: [
|
|
44820
46182
|
extendedContract.address,
|
|
@@ -44837,7 +46199,7 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44837
46199
|
return [approveCall, depositCall];
|
|
44838
46200
|
}
|
|
44839
46201
|
/**
|
|
44840
|
-
* VA_TO_EXTENDED: Deposit USDC
|
|
46202
|
+
* VA_TO_EXTENDED: Deposit USDC from vault allocator to Extended.
|
|
44841
46203
|
*
|
|
44842
46204
|
* Uses the extended adapter's getDepositCall to build ManageCalls,
|
|
44843
46205
|
* then wraps them in a merkle-verified manage call through the manager contract.
|
|
@@ -44852,43 +46214,31 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44852
46214
|
);
|
|
44853
46215
|
return [];
|
|
44854
46216
|
}
|
|
44855
|
-
const swapCall = await this._buildAdapterManageCall(
|
|
44856
|
-
this._config.usdcToUsdceAdapter,
|
|
44857
|
-
true,
|
|
44858
|
-
{ amount }
|
|
44859
|
-
);
|
|
44860
46217
|
const manageCall = await this._buildAdapterManageCall(
|
|
44861
46218
|
this._config.extendedAdapter,
|
|
44862
46219
|
true,
|
|
44863
46220
|
{ amount }
|
|
44864
46221
|
);
|
|
44865
|
-
return [
|
|
46222
|
+
return [manageCall];
|
|
44866
46223
|
}
|
|
44867
46224
|
/**
|
|
44868
|
-
* WALLET_TO_VA: Transfer USDC
|
|
46225
|
+
* WALLET_TO_VA: Transfer USDC from operator wallet to vault allocator.
|
|
44869
46226
|
* Caps amount by actual wallet balance.
|
|
44870
46227
|
*/
|
|
44871
46228
|
async _buildWalletToVACalls(route) {
|
|
44872
|
-
const erc20 = new ERC20(this._config.networkConfig);
|
|
44873
|
-
const { usdceToken, vaultAllocator, walletAddress } = this._config;
|
|
44874
46229
|
const transferAmount = route.amount;
|
|
44875
46230
|
if (transferAmount.lessThanOrEqualTo(0)) {
|
|
44876
46231
|
logger.warn(
|
|
44877
|
-
`${this._tag}::_buildWalletToVACalls no USDC
|
|
46232
|
+
`${this._tag}::_buildWalletToVACalls no USDC in wallet to transfer`
|
|
44878
46233
|
);
|
|
44879
46234
|
return [];
|
|
44880
46235
|
}
|
|
44881
46236
|
const transferCall = await this._buildAdapterManageCall(
|
|
44882
|
-
this._config.
|
|
44883
|
-
false,
|
|
44884
|
-
{ amount: transferAmount }
|
|
44885
|
-
);
|
|
44886
|
-
const swapCall = await this._buildAdapterManageCall(
|
|
44887
|
-
this._config.usdcToUsdceAdapter,
|
|
46237
|
+
this._config.usdcTransferAdapter,
|
|
44888
46238
|
false,
|
|
44889
46239
|
{ amount: transferAmount }
|
|
44890
46240
|
);
|
|
44891
|
-
return [transferCall
|
|
46241
|
+
return [transferCall];
|
|
44892
46242
|
}
|
|
44893
46243
|
// ── AVNU swap routes ────────────────────────────────────────────────────
|
|
44894
46244
|
/**
|
|
@@ -44921,12 +46271,12 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44921
46271
|
*/
|
|
44922
46272
|
async _buildVesuIncreaseLeverCalls(route) {
|
|
44923
46273
|
const depositManageCall = await this._buildAdapterManageCall(
|
|
44924
|
-
this._config.
|
|
46274
|
+
this._config.vesuMultiplyAdapter,
|
|
44925
46275
|
true,
|
|
44926
46276
|
{
|
|
44927
46277
|
amount: route.marginAmount,
|
|
44928
46278
|
marginSwap: {
|
|
44929
|
-
marginToken: this._config.
|
|
46279
|
+
marginToken: this._config.vesuMultiplyAdapter.config.marginToken
|
|
44930
46280
|
// todo, must be vault token
|
|
44931
46281
|
},
|
|
44932
46282
|
leverSwap: {
|
|
@@ -44946,11 +46296,11 @@ var _ExecutionService = class _ExecutionService {
|
|
|
44946
46296
|
async _buildVesuDecreaseLeverCalls(route) {
|
|
44947
46297
|
const collateralAmount = route.marginAmount.abs();
|
|
44948
46298
|
const withdrawManageCall = await this._buildAdapterManageCall(
|
|
44949
|
-
this._config.
|
|
46299
|
+
this._config.vesuMultiplyAdapter,
|
|
44950
46300
|
false,
|
|
44951
46301
|
{
|
|
44952
46302
|
amount: collateralAmount,
|
|
44953
|
-
withdrawSwap: { outputToken: this._config.
|
|
46303
|
+
withdrawSwap: { outputToken: this._config.vesuMultiplyAdapter.config.marginToken }
|
|
44954
46304
|
}
|
|
44955
46305
|
);
|
|
44956
46306
|
return [withdrawManageCall];
|
|
@@ -45541,140 +46891,6 @@ _ExecutionService.EXTENDED_EXPOSURE_ROUTES = /* @__PURE__ */ new Set([
|
|
|
45541
46891
|
]);
|
|
45542
46892
|
var ExecutionService = _ExecutionService;
|
|
45543
46893
|
|
|
45544
|
-
// src/strategies/universal-adapters/usdc<>usdce-adapter.ts
|
|
45545
|
-
import { hash as hash11, uint256 as uint25623 } from "starknet";
|
|
45546
|
-
var UsdcToUsdceAdapter = class _UsdcToUsdceAdapter extends BaseAdapter {
|
|
45547
|
-
_approveProofReadableId(usdcToUsdce) {
|
|
45548
|
-
const method = usdcToUsdce ? "swap_to_legacy" : "swap_to_new";
|
|
45549
|
-
return `approve_${method}`;
|
|
45550
|
-
}
|
|
45551
|
-
_swapProofReadableId(usdcToUsdce) {
|
|
45552
|
-
const method = usdcToUsdce ? "swap_to_legacy" : "swap_to_new";
|
|
45553
|
-
const target = usdcToUsdce ? this.config.supportedPositions[0].asset : this.config.supportedPositions[1].asset;
|
|
45554
|
-
return `${method}_${target.symbol}`;
|
|
45555
|
-
}
|
|
45556
|
-
buildSwapLeafConfigs(usdcToUsdce) {
|
|
45557
|
-
const method = usdcToUsdce ? "swap_to_legacy" : "swap_to_new";
|
|
45558
|
-
const target = usdcToUsdce ? this.config.supportedPositions[0].asset : this.config.supportedPositions[1].asset;
|
|
45559
|
-
return [
|
|
45560
|
-
{
|
|
45561
|
-
target: target.address,
|
|
45562
|
-
method: "approve",
|
|
45563
|
-
packedArguments: [AVNU_EXCHANGE_FOR_LEGACY_USDC.toBigInt()],
|
|
45564
|
-
id: this._approveProofReadableId(usdcToUsdce),
|
|
45565
|
-
sanitizer: AVNU_LEGACY_SANITIZER
|
|
45566
|
-
},
|
|
45567
|
-
{
|
|
45568
|
-
target: AVNU_EXCHANGE_FOR_LEGACY_USDC,
|
|
45569
|
-
method,
|
|
45570
|
-
packedArguments: [],
|
|
45571
|
-
id: this._swapProofReadableId(usdcToUsdce),
|
|
45572
|
-
sanitizer: AVNU_LEGACY_SANITIZER
|
|
45573
|
-
}
|
|
45574
|
-
];
|
|
45575
|
-
}
|
|
45576
|
-
async buildSwapCalls(params, usdcToUsdce) {
|
|
45577
|
-
const approveAmount = uint25623.bnToUint256(params.amount.toWei());
|
|
45578
|
-
const target = usdcToUsdce ? this.config.supportedPositions[0].asset : this.config.supportedPositions[1].asset;
|
|
45579
|
-
const method = usdcToUsdce ? "swap_to_legacy" : "swap_to_new";
|
|
45580
|
-
return [
|
|
45581
|
-
{
|
|
45582
|
-
proofReadableId: this._approveProofReadableId(usdcToUsdce),
|
|
45583
|
-
sanitizer: AVNU_LEGACY_SANITIZER,
|
|
45584
|
-
call: {
|
|
45585
|
-
contractAddress: target.address,
|
|
45586
|
-
selector: hash11.getSelectorFromName("approve"),
|
|
45587
|
-
calldata: [
|
|
45588
|
-
AVNU_EXCHANGE_FOR_LEGACY_USDC.toBigInt(),
|
|
45589
|
-
toBigInt(approveAmount.low.toString()),
|
|
45590
|
-
toBigInt(approveAmount.high.toString())
|
|
45591
|
-
]
|
|
45592
|
-
}
|
|
45593
|
-
},
|
|
45594
|
-
{
|
|
45595
|
-
proofReadableId: this._swapProofReadableId(usdcToUsdce),
|
|
45596
|
-
sanitizer: AVNU_LEGACY_SANITIZER,
|
|
45597
|
-
call: {
|
|
45598
|
-
contractAddress: AVNU_EXCHANGE_FOR_LEGACY_USDC,
|
|
45599
|
-
selector: hash11.getSelectorFromName(method),
|
|
45600
|
-
calldata: [
|
|
45601
|
-
toBigInt(approveAmount.low.toString()),
|
|
45602
|
-
// amount low
|
|
45603
|
-
toBigInt(approveAmount.high.toString())
|
|
45604
|
-
// amount high
|
|
45605
|
-
]
|
|
45606
|
-
}
|
|
45607
|
-
}
|
|
45608
|
-
];
|
|
45609
|
-
}
|
|
45610
|
-
constructor(config) {
|
|
45611
|
-
super(config, _UsdcToUsdceAdapter.name, Protocols.AVNU);
|
|
45612
|
-
this.config = config;
|
|
45613
|
-
assert(this.config.supportedPositions.length === 2, "UsdcToUsdceAdapter must have 2 supported positions");
|
|
45614
|
-
assert(this.config.supportedPositions[0].asset.symbol === "USDC", "UsdcToUsdceAdapter must have USDC as the first supported position");
|
|
45615
|
-
assert(this.config.supportedPositions[1].asset.symbol === "USDC.e", "UsdcToUsdceAdapter must have USDCE as the second supported position");
|
|
45616
|
-
}
|
|
45617
|
-
//abstract means the method has no implementation in this class; instead, child classes must implement it.
|
|
45618
|
-
async getAPY(supportedPosition) {
|
|
45619
|
-
return Promise.resolve({ apy: 0, type: "base" /* BASE */ });
|
|
45620
|
-
}
|
|
45621
|
-
async getPosition(supportedPosition) {
|
|
45622
|
-
const toToken = this.config.supportedPositions[1].asset;
|
|
45623
|
-
if (supportedPosition.asset.symbol != toToken.symbol) {
|
|
45624
|
-
return null;
|
|
45625
|
-
}
|
|
45626
|
-
try {
|
|
45627
|
-
const balance = await new ERC20(this.config.networkConfig).balanceOf(
|
|
45628
|
-
toToken.address,
|
|
45629
|
-
this.config.vaultAllocator.address,
|
|
45630
|
-
toToken.decimals
|
|
45631
|
-
);
|
|
45632
|
-
return { amount: balance, remarks: `USDC.e unused balance (VA)` };
|
|
45633
|
-
} catch (_e) {
|
|
45634
|
-
logger.error(`${_UsdcToUsdceAdapter.name}::getPosition: failed for ${toToken.symbol}`);
|
|
45635
|
-
throw new Error(`${_UsdcToUsdceAdapter.name}: failed to get balance for ${toToken.symbol}`);
|
|
45636
|
-
}
|
|
45637
|
-
}
|
|
45638
|
-
async maxDeposit(amount) {
|
|
45639
|
-
return Promise.resolve({
|
|
45640
|
-
tokenInfo: this.config.baseToken,
|
|
45641
|
-
amount: new Web3Number(0, 0),
|
|
45642
|
-
usdValue: 0,
|
|
45643
|
-
apy: { apy: 0, type: "base" /* BASE */ },
|
|
45644
|
-
protocol: Protocols.AVNU,
|
|
45645
|
-
remarks: ""
|
|
45646
|
-
});
|
|
45647
|
-
}
|
|
45648
|
-
async maxWithdraw() {
|
|
45649
|
-
return Promise.resolve({
|
|
45650
|
-
tokenInfo: this.config.baseToken,
|
|
45651
|
-
amount: new Web3Number(0, 0),
|
|
45652
|
-
usdValue: 0,
|
|
45653
|
-
apy: { apy: 0, type: "base" /* BASE */ },
|
|
45654
|
-
protocol: Protocols.AVNU,
|
|
45655
|
-
remarks: ""
|
|
45656
|
-
});
|
|
45657
|
-
}
|
|
45658
|
-
_getDepositLeaf() {
|
|
45659
|
-
return this.buildSwapLeafConfigs(true);
|
|
45660
|
-
}
|
|
45661
|
-
_getWithdrawLeaf() {
|
|
45662
|
-
return this.buildSwapLeafConfigs(false);
|
|
45663
|
-
}
|
|
45664
|
-
async getDepositCall(params) {
|
|
45665
|
-
const calls = await this.buildSwapCalls(params, true);
|
|
45666
|
-
return calls;
|
|
45667
|
-
}
|
|
45668
|
-
//Swap wbtc to usdc
|
|
45669
|
-
async getWithdrawCall(params) {
|
|
45670
|
-
const calls = await this.buildSwapCalls(params, false);
|
|
45671
|
-
return calls;
|
|
45672
|
-
}
|
|
45673
|
-
async getHealthFactor() {
|
|
45674
|
-
return Promise.resolve(1);
|
|
45675
|
-
}
|
|
45676
|
-
};
|
|
45677
|
-
|
|
45678
46894
|
// src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx
|
|
45679
46895
|
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
45680
46896
|
var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy extends SVKStrategy {
|
|
@@ -45690,9 +46906,6 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
45690
46906
|
});
|
|
45691
46907
|
this.wbtcToken = Global.getDefaultTokens().find((token) => token.symbol === "WBTC");
|
|
45692
46908
|
this.usdcToken = this.metadata.additionalInfo.borrowable_assets[0];
|
|
45693
|
-
this.usdceToken = Global.getDefaultTokens().find(
|
|
45694
|
-
(token) => token.symbol === "USDC.e"
|
|
45695
|
-
);
|
|
45696
46909
|
this.stateManager = this._initializeStateManager();
|
|
45697
46910
|
}
|
|
45698
46911
|
/**
|
|
@@ -45716,9 +46929,8 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
45716
46929
|
extendedAdapter: extendedAdapterEntry.adapter,
|
|
45717
46930
|
vaultAllocator: this.metadata.additionalInfo.vaultAllocator,
|
|
45718
46931
|
walletAddress: this.metadata.additionalInfo.walletAddress,
|
|
45719
|
-
assetToken:
|
|
45720
|
-
|
|
45721
|
-
usdceToken: this.usdceToken,
|
|
46932
|
+
assetToken: this.asset(),
|
|
46933
|
+
usdcToken: this.usdcToken,
|
|
45722
46934
|
collateralToken: this.wbtcToken,
|
|
45723
46935
|
limitBalanceBufferFactor: LIMIT_BALANCE
|
|
45724
46936
|
};
|
|
@@ -45752,7 +46964,7 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
45752
46964
|
}
|
|
45753
46965
|
return { collateralPrice, debtPrice };
|
|
45754
46966
|
}
|
|
45755
|
-
async
|
|
46967
|
+
async getVesuMultiplyAdapter() {
|
|
45756
46968
|
const vesuAdapter = this.metadata.additionalInfo.adapters.find(
|
|
45757
46969
|
(adapter) => adapter.adapter.name === VesuMultiplyAdapter.name
|
|
45758
46970
|
);
|
|
@@ -45774,16 +46986,16 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
45774
46986
|
}
|
|
45775
46987
|
return vesuModifyPositionAdapter.adapter;
|
|
45776
46988
|
}
|
|
45777
|
-
async
|
|
45778
|
-
const
|
|
46989
|
+
async getUsdcTransferAdapter() {
|
|
46990
|
+
const usdcTransferAdapter = this.metadata.additionalInfo.adapters.find(
|
|
45779
46991
|
(adapter) => adapter.adapter.name === TokenTransferAdapter.name
|
|
45780
46992
|
);
|
|
45781
|
-
if (!
|
|
46993
|
+
if (!usdcTransferAdapter) {
|
|
45782
46994
|
throw new Error(
|
|
45783
|
-
`${this.getTag()}
|
|
46995
|
+
`${this.getTag()} Usdc transfer adapter not configured in metadata.`
|
|
45784
46996
|
);
|
|
45785
46997
|
}
|
|
45786
|
-
return
|
|
46998
|
+
return usdcTransferAdapter.adapter;
|
|
45787
46999
|
}
|
|
45788
47000
|
async getAvnuAdapter() {
|
|
45789
47001
|
const avnuAdapter = this.metadata.additionalInfo.adapters.find(
|
|
@@ -45812,17 +47024,6 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
45812
47024
|
}
|
|
45813
47025
|
return extendedAdapter.adapter;
|
|
45814
47026
|
}
|
|
45815
|
-
async getUsdcToUsdceAdapter() {
|
|
45816
|
-
const usdcToUsdceAdapter = this.metadata.additionalInfo.adapters.find(
|
|
45817
|
-
(adapter) => adapter.adapter.name === UsdcToUsdceAdapter.name
|
|
45818
|
-
);
|
|
45819
|
-
if (!usdcToUsdceAdapter) {
|
|
45820
|
-
throw new Error(
|
|
45821
|
-
`${this.getTag()} UsdcToUsdce adapter not configured in metadata.`
|
|
45822
|
-
);
|
|
45823
|
-
}
|
|
45824
|
-
return usdcToUsdceAdapter.adapter;
|
|
45825
|
-
}
|
|
45826
47027
|
/**
|
|
45827
47028
|
* Creates an ExecutionService wired to this strategy's adapters and config.
|
|
45828
47029
|
* Use with `stateManager.solve()` to get a SolveResult, then pass it to
|
|
@@ -45834,34 +47035,30 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
45834
47035
|
*/
|
|
45835
47036
|
async createExecutionService(opts) {
|
|
45836
47037
|
const [
|
|
45837
|
-
|
|
47038
|
+
vesuMultiplyAdapter,
|
|
45838
47039
|
vesuModifyPositionAdapter,
|
|
45839
|
-
usdceTransferAdapter,
|
|
45840
47040
|
extendedAdapter,
|
|
45841
47041
|
avnuAdapter,
|
|
45842
|
-
|
|
47042
|
+
usdcTransferAdapter
|
|
45843
47043
|
] = await Promise.all([
|
|
45844
|
-
this.
|
|
47044
|
+
this.getVesuMultiplyAdapter(),
|
|
45845
47045
|
this.getVesuModifyPositionAdapter(),
|
|
45846
|
-
this.getUsdceTransferAdapter(),
|
|
45847
47046
|
this.getExtendedAdapter(),
|
|
45848
47047
|
this.getAvnuAdapter(),
|
|
45849
|
-
this.
|
|
47048
|
+
this.getUsdcTransferAdapter()
|
|
45850
47049
|
]);
|
|
45851
47050
|
const executionConfig = {
|
|
45852
47051
|
networkConfig: this.config,
|
|
45853
47052
|
pricer: this.pricer,
|
|
45854
|
-
|
|
47053
|
+
vesuMultiplyAdapter,
|
|
45855
47054
|
vesuModifyPositionAdapter,
|
|
45856
47055
|
extendedAdapter,
|
|
45857
47056
|
avnuAdapter,
|
|
45858
|
-
|
|
47057
|
+
usdcTransferAdapter,
|
|
45859
47058
|
vaultAllocator: this.metadata.additionalInfo.vaultAllocator,
|
|
45860
47059
|
walletAddress: this.metadata.additionalInfo.walletAddress,
|
|
45861
|
-
usdceTransferAdapter,
|
|
45862
47060
|
wbtcToken: this.wbtcToken,
|
|
45863
47061
|
usdcToken: this.usdcToken,
|
|
45864
|
-
usdceToken: this.usdceToken,
|
|
45865
47062
|
getMerkleTree: () => this.getMerkleTree(),
|
|
45866
47063
|
getManageCall: (proofs, manageCalls) => this.getManageCall(proofs, manageCalls),
|
|
45867
47064
|
getBringLiquidityCall: (params) => this.getBringLiquidityCall(params),
|
|
@@ -45882,9 +47079,7 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
45882
47079
|
for (let adapter of this.metadata.additionalInfo.adapters) {
|
|
45883
47080
|
let positions = await adapter.adapter.getPositions();
|
|
45884
47081
|
if (positions && positions.length > 0) {
|
|
45885
|
-
const filteredPositions = positions
|
|
45886
|
-
return position.tokenInfo.address !== this.usdceToken.address;
|
|
45887
|
-
});
|
|
47082
|
+
const filteredPositions = positions;
|
|
45888
47083
|
allPositions.push(...filteredPositions);
|
|
45889
47084
|
}
|
|
45890
47085
|
}
|
|
@@ -46079,34 +47274,22 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
46079
47274
|
};
|
|
46080
47275
|
}
|
|
46081
47276
|
/**
|
|
46082
|
-
* Fetches the operator wallet's current holdings for USDC
|
|
47277
|
+
* Fetches the operator wallet's current holdings for USDC and WBTC,
|
|
46083
47278
|
* returning each token's balance and USD value.
|
|
46084
47279
|
*/
|
|
46085
47280
|
async getWalletHoldings() {
|
|
46086
|
-
if (!this.
|
|
47281
|
+
if (!this.wbtcToken || !this.usdcToken) {
|
|
46087
47282
|
return [];
|
|
46088
47283
|
}
|
|
46089
47284
|
const walletAddress = this.metadata.additionalInfo.walletAddress;
|
|
46090
|
-
const usdceWalletBalance = await new ERC20(this.config).balanceOf(
|
|
46091
|
-
this.usdceToken.address,
|
|
46092
|
-
walletAddress,
|
|
46093
|
-
this.usdceToken.decimals
|
|
46094
|
-
);
|
|
46095
47285
|
const usdcWalletBalance = await new ERC20(this.config).balanceOf(
|
|
46096
47286
|
this.usdcToken.address,
|
|
46097
47287
|
walletAddress,
|
|
46098
47288
|
this.usdcToken.decimals
|
|
46099
47289
|
);
|
|
46100
|
-
const price = await this.pricer.getPrice(this.
|
|
46101
|
-
const wbtcPrice = await this.pricer.getPrice(this.wbtcToken.symbol);
|
|
46102
|
-
const usdceUsdValue = Number(usdceWalletBalance.toFixed(this.usdceToken.decimals)) * price.price;
|
|
47290
|
+
const price = await this.pricer.getPrice(this.usdcToken.symbol);
|
|
46103
47291
|
const usdcUsdValue = Number(usdcWalletBalance.toFixed(this.usdcToken.decimals)) * price.price;
|
|
46104
47292
|
return [
|
|
46105
|
-
{
|
|
46106
|
-
tokenInfo: this.usdceToken,
|
|
46107
|
-
amount: usdceWalletBalance,
|
|
46108
|
-
usdValue: usdceUsdValue
|
|
46109
|
-
},
|
|
46110
47293
|
{
|
|
46111
47294
|
tokenInfo: this.usdcToken,
|
|
46112
47295
|
amount: usdcWalletBalance,
|
|
@@ -46123,9 +47306,6 @@ function getLooperSettings3(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
46123
47306
|
const usdcToken = Global.getDefaultTokens().find(
|
|
46124
47307
|
(token) => token.symbol === underlyingSymbol
|
|
46125
47308
|
);
|
|
46126
|
-
const usdceToken = Global.getDefaultTokens().find(
|
|
46127
|
-
(token) => token.symbol === "USDC.e"
|
|
46128
|
-
);
|
|
46129
47309
|
const baseAdapterConfig = {
|
|
46130
47310
|
baseToken: wbtcToken,
|
|
46131
47311
|
supportedPositions: [
|
|
@@ -46146,17 +47326,10 @@ function getLooperSettings3(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
46146
47326
|
minimumExtendedPriceDifferenceForSwapOpen,
|
|
46147
47327
|
maximumExtendedPriceDifferenceForSwapClosing
|
|
46148
47328
|
});
|
|
46149
|
-
const usdcToUsdceAdapter = new UsdcToUsdceAdapter({
|
|
46150
|
-
...baseAdapterConfig,
|
|
46151
|
-
supportedPositions: [
|
|
46152
|
-
{ asset: usdcToken, isDebt: true },
|
|
46153
|
-
{ asset: usdceToken, isDebt: false }
|
|
46154
|
-
]
|
|
46155
|
-
});
|
|
46156
47329
|
const extendedAdapter = new ExtendedAdapter({
|
|
46157
47330
|
...baseAdapterConfig,
|
|
46158
47331
|
supportedPositions: [
|
|
46159
|
-
{ asset:
|
|
47332
|
+
{ asset: usdcToken, isDebt: false }
|
|
46160
47333
|
],
|
|
46161
47334
|
vaultIdExtended,
|
|
46162
47335
|
extendedContract: EXTENDED_CONTRACT,
|
|
@@ -46202,10 +47375,10 @@ function getLooperSettings3(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
46202
47375
|
{ asset: usdcToken, isDebt: true }
|
|
46203
47376
|
]
|
|
46204
47377
|
});
|
|
46205
|
-
const
|
|
47378
|
+
const usdcTransferAdapter = new TokenTransferAdapter({
|
|
46206
47379
|
...baseAdapterConfig,
|
|
46207
|
-
baseToken:
|
|
46208
|
-
supportedPositions: [{ asset:
|
|
47380
|
+
baseToken: usdcToken,
|
|
47381
|
+
supportedPositions: [{ asset: usdcToken, isDebt: false }],
|
|
46209
47382
|
fromAddress: vaultSettings.vaultAllocator,
|
|
46210
47383
|
toAddress: ContractAddr.from(vaultSettings.walletAddress)
|
|
46211
47384
|
});
|
|
@@ -46218,12 +47391,8 @@ function getLooperSettings3(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
46218
47391
|
adapter: vesuModifyPositionAdapter
|
|
46219
47392
|
});
|
|
46220
47393
|
vaultSettings.adapters.push({
|
|
46221
|
-
id: `${
|
|
46222
|
-
adapter:
|
|
46223
|
-
});
|
|
46224
|
-
vaultSettings.adapters.push({
|
|
46225
|
-
id: `${usdcToUsdceAdapter.name}_${usdceToken.symbol}_${usdcToken.symbol}`,
|
|
46226
|
-
adapter: usdcToUsdceAdapter
|
|
47394
|
+
id: `${usdcTransferAdapter.name}_${usdcToken.symbol}`,
|
|
47395
|
+
adapter: usdcTransferAdapter
|
|
46227
47396
|
});
|
|
46228
47397
|
vaultSettings.adapters.push({
|
|
46229
47398
|
id: `${extendedAdapter.name}_${wbtcToken.symbol}`,
|
|
@@ -46245,12 +47414,10 @@ function getLooperSettings3(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
46245
47414
|
vaultSettings.leafAdapters.push(() => vesuModifyPositionAdapter.getDepositLeaf());
|
|
46246
47415
|
vaultSettings.leafAdapters.push(() => vesuModifyPositionAdapter.getWithdrawLeaf());
|
|
46247
47416
|
vaultSettings.leafAdapters.push(() => extendedAdapter.getDepositLeaf());
|
|
46248
|
-
vaultSettings.leafAdapters.push(() => usdcToUsdceAdapter.getDepositLeaf());
|
|
46249
|
-
vaultSettings.leafAdapters.push(() => usdcToUsdceAdapter.getWithdrawLeaf());
|
|
46250
47417
|
vaultSettings.leafAdapters.push(() => avnuAdapter.getDepositLeaf());
|
|
46251
47418
|
vaultSettings.leafAdapters.push(() => avnuAdapter.getWithdrawLeaf());
|
|
46252
|
-
vaultSettings.leafAdapters.push(() =>
|
|
46253
|
-
vaultSettings.leafAdapters.push(() =>
|
|
47419
|
+
vaultSettings.leafAdapters.push(() => usdcTransferAdapter.getDepositLeaf());
|
|
47420
|
+
vaultSettings.leafAdapters.push(() => usdcTransferAdapter.getWithdrawLeaf());
|
|
46254
47421
|
vaultSettings.leafAdapters.push(
|
|
46255
47422
|
commonAdapter.getApproveAdapter(
|
|
46256
47423
|
usdcToken.address,
|
|
@@ -47282,11 +48449,13 @@ export {
|
|
|
47282
48449
|
BaseAdapter,
|
|
47283
48450
|
BaseStrategy,
|
|
47284
48451
|
CASE_ROUTE_TYPES,
|
|
48452
|
+
COLLATERAL_PRECISION,
|
|
47285
48453
|
CaseCategory,
|
|
47286
48454
|
CaseId,
|
|
47287
48455
|
CommonAdapter,
|
|
47288
48456
|
ContractAddr,
|
|
47289
48457
|
CycleType,
|
|
48458
|
+
DEFAULT_TROVES_STRATEGIES_API,
|
|
47290
48459
|
deployer_default as Deployer,
|
|
47291
48460
|
ERC20,
|
|
47292
48461
|
EXTENDED_CONTRACT,
|
|
@@ -47305,6 +48474,7 @@ export {
|
|
|
47305
48474
|
FatalError,
|
|
47306
48475
|
FlowChartColors,
|
|
47307
48476
|
Global,
|
|
48477
|
+
HealthFactorMath,
|
|
47308
48478
|
HyperLSTStrategies,
|
|
47309
48479
|
ILending,
|
|
47310
48480
|
Initializable,
|
|
@@ -47345,6 +48515,7 @@ export {
|
|
|
47345
48515
|
StrategyLiveStatus,
|
|
47346
48516
|
StrategyTag,
|
|
47347
48517
|
StrategyType,
|
|
48518
|
+
SvkTrovesAdapter,
|
|
47348
48519
|
TRANSFER_SANITIZER,
|
|
47349
48520
|
TelegramGroupNotif,
|
|
47350
48521
|
TelegramNotif,
|
|
@@ -47394,6 +48565,7 @@ export {
|
|
|
47394
48565
|
createEkuboCLStrategy,
|
|
47395
48566
|
createHyperLSTStrategy,
|
|
47396
48567
|
createSenseiStrategy,
|
|
48568
|
+
createSolveBudgetFromRawState,
|
|
47397
48569
|
createStrategy,
|
|
47398
48570
|
createUniversalStrategy2 as createUniversalStrategy,
|
|
47399
48571
|
createVesuRebalanceStrategy2 as createVesuRebalanceStrategy,
|