@strkfarm/sdk 1.1.69 → 2.0.0-dev.1

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.
Files changed (52) hide show
  1. package/dist/cli.js +2 -2
  2. package/dist/cli.mjs +2 -2
  3. package/dist/index.browser.global.js +66861 -59746
  4. package/dist/index.browser.mjs +24970 -18579
  5. package/dist/index.d.ts +1969 -776
  6. package/dist/index.js +25259 -18845
  7. package/dist/index.mjs +25464 -19090
  8. package/package.json +80 -76
  9. package/src/data/extended-deposit.abi.json +3613 -0
  10. package/src/data/universal-vault.abi.json +135 -20
  11. package/src/dataTypes/address.ts +8 -1
  12. package/src/global.ts +240 -193
  13. package/src/interfaces/common.tsx +26 -2
  14. package/src/modules/ExtendedWrapperSDk/index.ts +62 -0
  15. package/src/modules/ExtendedWrapperSDk/types.ts +311 -0
  16. package/src/modules/ExtendedWrapperSDk/wrapper.ts +395 -0
  17. package/src/modules/avnu.ts +17 -4
  18. package/src/modules/ekubo-quoter.ts +99 -11
  19. package/src/modules/erc20.ts +67 -21
  20. package/src/modules/harvests.ts +16 -29
  21. package/src/modules/index.ts +5 -1
  22. package/src/modules/lst-apr.ts +36 -0
  23. package/src/modules/midas.ts +159 -0
  24. package/src/modules/pricer-from-api.ts +2 -2
  25. package/src/modules/pricer.ts +3 -38
  26. package/src/modules/token-market-data.ts +202 -0
  27. package/src/node/deployer.ts +1 -36
  28. package/src/strategies/autoCompounderStrk.ts +1 -1
  29. package/src/strategies/base-strategy.ts +20 -3
  30. package/src/strategies/ekubo-cl-vault.tsx +123 -306
  31. package/src/strategies/index.ts +4 -1
  32. package/src/strategies/svk-strategy.ts +247 -0
  33. package/src/strategies/universal-adapters/adapter-optimizer.ts +65 -0
  34. package/src/strategies/universal-adapters/adapter-utils.ts +5 -1
  35. package/src/strategies/universal-adapters/avnu-adapter.ts +418 -0
  36. package/src/strategies/universal-adapters/baseAdapter.ts +181 -153
  37. package/src/strategies/universal-adapters/common-adapter.ts +98 -77
  38. package/src/strategies/universal-adapters/extended-adapter.ts +544 -0
  39. package/src/strategies/universal-adapters/index.ts +5 -1
  40. package/src/strategies/universal-adapters/unused-balance-adapter.ts +109 -0
  41. package/src/strategies/universal-adapters/vesu-adapter.ts +220 -218
  42. package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +924 -0
  43. package/src/strategies/universal-adapters/vesu-supply-only-adapter.ts +58 -51
  44. package/src/strategies/universal-lst-muliplier-strategy.tsx +707 -774
  45. package/src/strategies/universal-strategy.tsx +1098 -1180
  46. package/src/strategies/vesu-extended-strategy/services/operationService.ts +28 -0
  47. package/src/strategies/vesu-extended-strategy/utils/config.runtime.ts +77 -0
  48. package/src/strategies/vesu-extended-strategy/utils/constants.ts +48 -0
  49. package/src/strategies/vesu-extended-strategy/utils/helper.ts +374 -0
  50. package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +992 -0
  51. package/src/strategies/vesu-rebalance.tsx +16 -19
  52. package/src/utils/health-factor-math.ts +11 -5
@@ -1,31 +1,36 @@
1
- import { FAQ, getNoRiskTags, highlightTextWithLinks, IConfig, IStrategyMetadata, Protocols, RiskFactor, RiskType, TokenInfo } from "@/interfaces";
2
- import { AUMTypes, getContractDetails, UNIVERSAL_ADAPTERS, UNIVERSAL_MANAGE_IDS, UniversalManageCall, UniversalStrategy, UniversalStrategySettings } from "./universal-strategy";
1
+ import { FAQ, getMainnetConfig, getNoRiskTags, highlightTextWithLinks, IConfig, IStrategyMetadata, Protocols, RiskFactor, RiskType, TokenInfo, VaultPosition } from "@/interfaces";
2
+ import { AUMTypes, getContractDetails, UNIVERSAL_MANAGE_IDS, UniversalManageCall, UniversalStrategySettings } from "./universal-strategy";
3
3
  import { PricerBase } from "@/modules/pricerBase";
4
4
  import { ContractAddr, Web3Number } from "@/dataTypes";
5
5
  import { Global } from "@/global";
6
- import { ApproveCallParams, AvnuSwapCallParams, CommonAdapter, getVesuSingletonAddress, ManageCall, Swap, VesuAdapter, VesuModifyDelegationCallParams, VesuModifyPositionCallParams, VesuMultiplyCallParams, VesuPools } from "./universal-adapters";
6
+ import { ApproveCallParams, APYType, AvnuSwapCallParams, BaseAdapterConfig, CommonAdapter, ManageCall, PositionInfo, UnusedBalanceAdapter, VesuMultiplyAdapter, VesuPools, VesuSupplyOnlyAdapter } from "./universal-adapters";
7
7
  import { AVNU_EXCHANGE } from "./universal-adapters/adapter-utils";
8
8
  import { DepegRiskLevel, LiquidationRiskLevel, SmartContractRiskLevel, TechnicalRiskLevel } from "@/interfaces/risks";
9
- import { AvnuWrapper, EkuboQuoter, ERC20, LSTAPRService, PricerLST } from "@/modules";
9
+ import { AvnuWrapper, EkuboQuoter, ERC20, PricerFromApi, PricerLST } from "@/modules";
10
10
  import { assert, logger } from "@/utils";
11
- import { SingleTokenInfo } from "./base-strategy";
12
- import { Call, Contract, uint256 } from "starknet";
11
+ import { SingleActionAmount, SingleTokenInfo } from "./base-strategy";
12
+ import { SVKStrategy } from "./svk-strategy";
13
+ import { Call, uint256 } from "starknet";
13
14
  import ERC4626Abi from "@/data/erc4626.abi.json";
14
- import { HealthFactorMath } from "@/utils/health-factor-math";
15
- import { findMaxInputWithSlippage } from "@/utils/math-utils";
15
+ import { AdapterOptimizer } from "./universal-adapters/adapter-optimizer";
16
+ import { MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP } from "./vesu-extended-strategy/utils/constants";
17
+ import { VesuExtendedStrategySettings } from "./vesu-extended-strategy/vesu-extended-strategy";
16
18
 
17
19
  export interface HyperLSTStrategySettings extends UniversalStrategySettings {
18
20
  borrowable_assets: TokenInfo[];
19
21
  underlyingToken: TokenInfo;
22
+ quoteAmountToFetchPrice: Web3Number;
23
+ targetHealthFactor: number;
24
+ minHealthFactor: number;
25
+ aumOracle: ContractAddr;
20
26
  }
21
27
 
22
- export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTStrategySettings> {
23
-
28
+ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings> extends SVKStrategy<S> {
29
+
24
30
  private quoteAmountToFetchPrice = new Web3Number(1, 18);
25
31
 
26
- constructor(config: IConfig, pricer: PricerBase, metadata: IStrategyMetadata<HyperLSTStrategySettings>) {
32
+ constructor(config: IConfig, pricer: PricerBase, metadata: IStrategyMetadata<S>) {
27
33
  super(config, pricer, metadata);
28
-
29
34
  const STRKToken = Global.getDefaultTokens().find(token => token.symbol === 'STRK')!;
30
35
  const underlyingToken = this.getLSTUnderlyingTokenInfo();
31
36
  if (underlyingToken.address.eq(STRKToken.address)) {
@@ -34,10 +39,15 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
34
39
  // else this BTC
35
40
  this.quoteAmountToFetchPrice = new Web3Number(0.01, this.asset().decimals);
36
41
  }
37
- }
38
42
 
39
- asset() {
40
- return this.getVesuSameTokenAdapter().config.collateral;
43
+ this.metadata.additionalInfo.adapters.forEach(adapter => {
44
+ adapter.adapter.config.networkConfig = this.config;
45
+ adapter.adapter.config.pricer = this.pricer;
46
+ if ((adapter.adapter as VesuMultiplyAdapter).vesuAdapter) {
47
+ (adapter.adapter as VesuMultiplyAdapter).vesuAdapter.networkConfig = this.config;
48
+ (adapter.adapter as VesuMultiplyAdapter).vesuAdapter.pricer = this.pricer;
49
+ }
50
+ });
41
51
  }
42
52
 
43
53
  getTag() {
@@ -46,376 +56,352 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
46
56
 
47
57
  // Vesu adapter with LST and base token match
48
58
  getVesuSameTokenAdapter() {
49
- const baseAdapter = this.getAdapter(getVesuLegId(UNIVERSAL_MANAGE_IDS.VESU_LEG1, this.metadata.additionalInfo.underlyingToken.symbol)) as VesuAdapter;
50
- baseAdapter.networkConfig = this.config;
51
- baseAdapter.pricer = this.pricer;
59
+ const vesuMultipleAdapters = this.getVesuAdapters();
60
+ console.log(vesuMultipleAdapters.map(adapter => adapter.config.debt.symbol));
61
+ const baseAdapter = vesuMultipleAdapters.find((adapter) => {
62
+ return adapter.config.debt.address.eq(this.metadata.additionalInfo.underlyingToken.address);
63
+ })
64
+ if (!baseAdapter) {
65
+ throw new Error(`${this.getTag()}::getVesuSameTokenAdapter: base adapter not found`);
66
+ }
67
+ baseAdapter.config.networkConfig = this.config;
68
+ baseAdapter.config.pricer = this.pricer;
52
69
  return baseAdapter;
53
70
  }
54
71
 
55
72
  // only one leg is used
56
73
  // todo support lending assets of underlying as well (like if xSTRK looping is not viable, simply supply STRK)
57
74
  getVesuAdapters() {
58
- const adapters: VesuAdapter[] = [];
59
- const baseAdapter = this.getVesuSameTokenAdapter();
60
- for (const asset of this.metadata.additionalInfo.borrowable_assets) {
61
- const vesuAdapter1 = new VesuAdapter({
62
- poolId: baseAdapter.config.poolId,
63
- collateral: this.asset(),
64
- debt: asset,
65
- vaultAllocator: this.metadata.additionalInfo.vaultAllocator,
66
- id: ''
67
- })
68
- vesuAdapter1.pricer = this.pricer;
69
- vesuAdapter1.networkConfig = this.config;
70
- adapters.push(vesuAdapter1);
71
- }
72
- return adapters;
73
- }
75
+ const vesuMultipleAdapters = this.metadata.additionalInfo.adapters
76
+ .filter(adapter => adapter.adapter.name === VesuMultiplyAdapter.name)
77
+ .map(adapter => adapter.adapter) as VesuMultiplyAdapter[]
74
78
 
75
- // not applicable for this strategy
76
- // No rewards on collateral or borrowing of LST assets
77
- protected async getRewardsAUM(prevAum: Web3Number): Promise<Web3Number> {
78
- const lstToken = this.asset();
79
- if (lstToken.symbol === 'xSTRK') {
80
- return super.getRewardsAUM(prevAum);
79
+ for (const vesuAdapter of vesuMultipleAdapters) {
80
+ vesuAdapter.config.pricer = this.pricer;
81
+ vesuAdapter.config.networkConfig = this.config;
81
82
  }
82
- return Web3Number.fromWei("0", lstToken.decimals);
83
- }
84
-
85
- async getLSTDexPrice() {
86
- const ekuboQuoter = new EkuboQuoter(this.config);
87
- const lstTokenInfo = this.asset();
88
- const lstUnderlyingTokenInfo = this.getLSTUnderlyingTokenInfo();
89
- const quote = await ekuboQuoter.getQuote(
90
- lstTokenInfo.address.address,
91
- lstUnderlyingTokenInfo.address.address,
92
- this.quoteAmountToFetchPrice
93
- );
94
-
95
- // in Underlying
96
- const outputAmount = Web3Number.fromWei(quote.total_calculated, lstUnderlyingTokenInfo.decimals);
97
- const price = outputAmount.toNumber() / this.quoteAmountToFetchPrice.toNumber();
98
- logger.verbose(`${this.getTag()}:: LST Dex Price: ${price}`);
99
- return price;
83
+ return vesuMultipleAdapters;
100
84
  }
101
85
 
102
86
 
103
- async getAvnuSwapMultiplyCall(params: {
104
- isDeposit: boolean,
105
- leg1DepositAmount: Web3Number
106
- }) {
107
- assert(params.isDeposit, 'Only deposit is supported in getAvnuSwapMultiplyCall')
108
- // TODO use a varibale for 1.02
109
- const maxBorrowableAmounts = await this.getMaxBorrowableAmount({ isAPYComputation: false });
110
- const allVesuAdapters = this.getVesuAdapters();
111
- let remainingAmount = params.leg1DepositAmount;
112
- const lstExRate = await this.getLSTExchangeRate();
113
- const baseAssetPrice = await this.pricer.getPrice(this.getLSTUnderlyingTokenInfo().symbol);
114
- const lstPrice = baseAssetPrice.price * lstExRate;
115
- for (let i = 0; i < maxBorrowableAmounts.maxBorrowables.length; i++) {
116
- const maxBorrowable = maxBorrowableAmounts.maxBorrowables[i];
117
- const vesuAdapter = allVesuAdapters.find(adapter => adapter.config.debt.address.eq(maxBorrowable.borrowableAsset.address));
118
- if (!vesuAdapter) {
119
- throw new Error(`${this.getTag()}::getAvnuSwapMultiplyCall: vesuAdapter not found for borrowable asset: ${maxBorrowable.borrowableAsset.symbol}`);
120
- }
121
- const maxLTV = await vesuAdapter.getLTVConfig(this.config);
122
- const debtPrice = await this.pricer.getPrice(maxBorrowable.borrowableAsset.symbol);
123
- const maxAmountToDeposit = HealthFactorMath.getMinCollateralRequiredOnLooping(
124
- maxBorrowable.amount,
125
- debtPrice.price,
126
- this.metadata.additionalInfo.targetHealthFactor,
127
- maxLTV,
128
- lstPrice,
129
- this.asset()
130
- )
131
- const amountToDeposit = remainingAmount.minimum(maxAmountToDeposit);
132
- logger.verbose(`${this.getTag()}::getAvnuSwapMultiplyCall::${vesuAdapter.config.debt.symbol}:: remainingAmount: ${remainingAmount}, amountToDeposit: ${amountToDeposit}, depositAmount: ${amountToDeposit}, maxBorrowable: ${maxBorrowable.amount}`);
133
- const call = await this._getAvnuDepositSwapLegCall({
134
- isDeposit: params.isDeposit,
135
- // adjust decimals of debt asset
136
- leg1DepositAmount: amountToDeposit,
137
- minHF: 1.1, // undo
138
- vesuAdapter: vesuAdapter
139
- });
140
- remainingAmount = remainingAmount.minus(amountToDeposit);
141
-
142
- // return the first possible call because computing all calls at a time
143
- // is not efficinet for swaps
144
- return {call, vesuAdapter};
145
- }
146
- throw new Error(`${this.getTag()}::getAvnuSwapMultiplyCall: no calls found`);
147
- }
148
-
149
- async _getAvnuDepositSwapLegCall(params: {
150
- isDeposit: boolean,
151
- leg1DepositAmount: Web3Number,
152
- minHF: number, // e.g. 1.01
153
- vesuAdapter: VesuAdapter
154
- }) {
155
- const { vesuAdapter } = params;
156
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall params: ${JSON.stringify(params)}`);
157
- assert(params.isDeposit, 'Only deposit is supported in _getAvnuDepositSwapLegCall')
158
- // add collateral
159
- // borrow STRK (e.g.)
160
- // approve and swap strk
161
- // add collateral again
87
+ // async getAvnuSwapMultiplyCall(params: {
88
+ // isDeposit: boolean,
89
+ // leg1DepositAmount: Web3Number
90
+ // }) {
91
+ // assert(params.isDeposit, 'Only deposit is supported in getAvnuSwapMultiplyCall')
92
+ // // TODO use a varibale for 1.02
93
+ // const maxBorrowableAmounts = await this.getMaxBorrowableAmount({ isAPYComputation: false });
94
+ // const allVesuAdapters = this.getVesuAdapters();
95
+ // let remainingAmount = params.leg1DepositAmount;
96
+ // const lstExRate = await this.getLSTExchangeRate();
97
+ // const baseAssetPrice = await this.pricer.getPrice(this.getLSTUnderlyingTokenInfo().symbol);
98
+ // const lstPrice = baseAssetPrice.price * lstExRate;
99
+ // for (let i = 0; i < maxBorrowableAmounts.maxBorrowables.length; i++) {
100
+ // const maxBorrowable = maxBorrowableAmounts.maxBorrowables[i];
101
+ // const vesuAdapter = allVesuAdapters.find(adapter => adapter.config.debt.address.eq(maxBorrowable.borrowableAsset.address));
102
+ // if (!vesuAdapter) {
103
+ // throw new Error(`${this.getTag()}::getAvnuSwapMultiplyCall: vesuAdapter not found for borrowable asset: ${maxBorrowable.borrowableAsset.symbol}`);
104
+ // }
105
+ // const maxLTV = await vesuAdapter.getLTVConfig(this.config);
106
+ // const debtPrice = await this.pricer.getPrice(maxBorrowable.borrowableAsset.symbol);
107
+ // const maxAmountToDeposit = HealthFactorMath.getMinCollateralRequiredOnLooping(
108
+ // maxBorrowable.amount,
109
+ // debtPrice.price,
110
+ // this.metadata.additionalInfo.targetHealthFactor,
111
+ // maxLTV,
112
+ // lstPrice,
113
+ // this.asset()
114
+ // )
115
+ // const amountToDeposit = remainingAmount.minimum(maxAmountToDeposit);
116
+ // logger.verbose(`${this.getTag()}::getAvnuSwapMultiplyCall::${vesuAdapter.config.debt.symbol}:: remainingAmount: ${remainingAmount}, amountToDeposit: ${amountToDeposit}, depositAmount: ${amountToDeposit}, maxBorrowable: ${maxBorrowable.amount}`);
117
+ // const call = await this._getAvnuDepositSwapLegCall({
118
+ // isDeposit: params.isDeposit,
119
+ // // adjust decimals of debt asset
120
+ // leg1DepositAmount: amountToDeposit,
121
+ // minHF: 1.1, // undo
122
+ // vesuAdapter: vesuAdapter
123
+ // });
124
+ // remainingAmount = remainingAmount.minus(amountToDeposit);
125
+
126
+ // // return the first possible call because computing all calls at a time
127
+ // // is not efficinet for swaps
128
+ // return {call, vesuAdapter};
129
+ // }
130
+ // throw new Error(`${this.getTag()}::getAvnuSwapMultiplyCall: no calls found`);
131
+ // }
132
+
133
+ // async _getAvnuDepositSwapLegCall(params: {
134
+ // isDeposit: boolean,
135
+ // leg1DepositAmount: Web3Number,
136
+ // minHF: number, // e.g. 1.01
137
+ // vesuAdapter: VesuAdapter
138
+ // }) {
139
+ // const { vesuAdapter } = params;
140
+ // logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall params: ${JSON.stringify(params)}`);
141
+ // assert(params.isDeposit, 'Only deposit is supported in _getAvnuDepositSwapLegCall')
142
+ // // add collateral
143
+ // // borrow STRK (e.g.)
144
+ // // approve and swap strk
145
+ // // add collateral again
162
146
 
163
147
 
164
- const legLTV = await vesuAdapter.getLTVConfig(this.config);
165
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall legLTV: ${legLTV}`);
166
- const existingPositions = await vesuAdapter.getPositions(this.config);
167
- const collateralisation = await vesuAdapter.getCollateralization(this.config);
168
- const existingCollateralInfo = existingPositions[0];
169
- const existingDebtInfo = existingPositions[1];
170
- logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
171
- existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
172
-
173
- // - Prices as seen by Vesu contracts, ideal for HF math
174
- // Price 1 is ok as fallback bcz that would relatively price the
175
- // collateral and debt as equal.
176
- const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
177
- const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
178
- logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
179
-
180
-
181
- const debtTokenInfo = vesuAdapter.config.debt;
182
- let newDepositAmount = params.leg1DepositAmount;
183
- const totalCollateral = existingCollateralInfo.amount.plus(params.leg1DepositAmount);
184
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalCollateral: ${totalCollateral}`);
185
- const totalDebtAmount = new Web3Number(
186
- totalCollateral.multipliedBy(collateralPrice).multipliedBy(legLTV).dividedBy(debtPrice).dividedBy(params.minHF).toString(),
187
- debtTokenInfo.decimals
188
- );
189
- let debtAmount = totalDebtAmount.minus(existingDebtInfo.amount);
190
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalDebtAmount: ${totalDebtAmount}, initial computed debt: ${debtAmount}`);
191
- const maxBorrowable = await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, false);
192
-
193
- // if the debt amount is greater than 0 and the max borrowable amount is 0, skip
194
- if (debtAmount.gt(0) && maxBorrowable.amount.eq(0)) {
195
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall maxBorrowable is 0, skipping`);
196
- return undefined;
197
- } else if (debtAmount.gt(0) && maxBorrowable.amount.gt(0)) {
198
- debtAmount = maxBorrowable.amount.minimum(debtAmount);
199
- const newDebtUSDValue = debtAmount.multipliedBy(debtPrice);
200
- const totalCollateralRequired = HealthFactorMath.getCollateralRequired(
201
- debtAmount.plus(existingDebtInfo.amount),
202
- debtPrice,
203
- params.minHF,
204
- legLTV,
205
- collateralPrice,
206
- this.asset()
207
- );
208
- newDepositAmount = totalCollateralRequired.minus(existingCollateralInfo.amount);
209
- if (newDepositAmount.lt(0)) {
210
- throw new Error(`${this.getTag()}::_getAvnuDepositSwapLegCall newDepositAmount is less than 0, newDepositAmount: ${newDepositAmount}, totalCollateralRequired: ${totalCollateralRequired}, existingCollateralInfo.amount: ${existingCollateralInfo.amount}`);
211
- }
212
- if (newDebtUSDValue.toNumber() < 100) {
213
- // too less debt, skip
214
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall newDebtUSDValue is less than 100, skipping`);
215
- return undefined;
216
- }
217
- }
218
-
219
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall debtAmount: ${debtAmount}`);
220
- if (debtAmount.lt(0)) {
221
- // this is to unwind the position to optimal HF.
222
- const lstDEXPrice = await this.getLSTDexPrice();
223
- const debtAmountInLST = debtAmount.abs().dividedBy(lstDEXPrice);
224
- const calls = await this.getVesuMultiplyCall({
225
- isDeposit: false,
226
- leg1DepositAmount: debtAmountInLST
227
- })
228
- assert(calls.length == 1, `Expected 1 call for unwind, got ${calls.length}`);
229
- return calls[0];
230
- }
231
- console.log(`debtAmount`, debtAmount.toWei(), params.leg1DepositAmount.toWei());
232
- const STEP0 = UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN1;
233
- const manage0Info = this.getProofs<ApproveCallParams>(STEP0);
234
- const manageCall0 = manage0Info.callConstructor({
235
- amount: newDepositAmount
236
- });
237
- const STEP1 = getVesuLegId(UNIVERSAL_MANAGE_IDS.VESU_LEG1, vesuAdapter.config.debt.symbol);
238
- const manage1Info = this.getProofs<VesuModifyPositionCallParams>(STEP1);
239
- const manageCall1 = manage1Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
240
- collateralAmount: newDepositAmount,
241
- isAddCollateral: params.isDeposit,
242
- debtAmount: debtAmount,
243
- isBorrow: params.isDeposit
244
- }));
245
-
246
- console.log(`manageCall1`, manageCall1.call, debtAmount.toWei(), newDepositAmount.toWei());
148
+ // const legLTV = await vesuAdapter.getLTVConfig(this.config);
149
+ // logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall legLTV: ${legLTV}`);
150
+ // const existingPositions = await vesuAdapter.getPositions(this.config);
151
+ // const collateralisation = await vesuAdapter.getCollateralization(this.config);
152
+ // const existingCollateralInfo = existingPositions[0];
153
+ // const existingDebtInfo = existingPositions[1];
154
+ // logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
155
+ // existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
156
+
157
+ // // - Prices as seen by Vesu contracts, ideal for HF math
158
+ // // Price 1 is ok as fallback bcz that would relatively price the
159
+ // // collateral and debt as equal.
160
+ // const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
161
+ // const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
162
+ // logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
163
+
164
+
165
+ // const debtTokenInfo = vesuAdapter.config.debt;
166
+ // let newDepositAmount = params.leg1DepositAmount;
167
+ // const totalCollateral = existingCollateralInfo.amount.plus(params.leg1DepositAmount);
168
+ // logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalCollateral: ${totalCollateral}`);
169
+ // const totalDebtAmount = new Web3Number(
170
+ // totalCollateral.multipliedBy(collateralPrice).multipliedBy(legLTV).dividedBy(debtPrice).dividedBy(params.minHF).toString(),
171
+ // debtTokenInfo.decimals
172
+ // );
173
+ // let debtAmount = totalDebtAmount.minus(existingDebtInfo.amount);
174
+ // logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalDebtAmount: ${totalDebtAmount}, initial computed debt: ${debtAmount}`);
175
+ // const maxBorrowable = await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, false);
176
+
177
+ // // if the debt amount is greater than 0 and the max borrowable amount is 0, skip
178
+ // if (debtAmount.gt(0) && maxBorrowable.amount.eq(0)) {
179
+ // logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall maxBorrowable is 0, skipping`);
180
+ // return undefined;
181
+ // } else if (debtAmount.gt(0) && maxBorrowable.amount.gt(0)) {
182
+ // debtAmount = maxBorrowable.amount.minimum(debtAmount);
183
+ // const newDebtUSDValue = debtAmount.multipliedBy(debtPrice);
184
+ // const totalCollateralRequired = HealthFactorMath.getCollateralRequired(
185
+ // debtAmount.plus(existingDebtInfo.amount),
186
+ // debtPrice,
187
+ // params.minHF,
188
+ // legLTV,
189
+ // collateralPrice,
190
+ // this.asset()
191
+ // );
192
+ // newDepositAmount = totalCollateralRequired.minus(existingCollateralInfo.amount);
193
+ // if (newDepositAmount.lt(0)) {
194
+ // throw new Error(`${this.getTag()}::_getAvnuDepositSwapLegCall newDepositAmount is less than 0, newDepositAmount: ${newDepositAmount}, totalCollateralRequired: ${totalCollateralRequired}, existingCollateralInfo.amount: ${existingCollateralInfo.amount}`);
195
+ // }
196
+ // if (newDebtUSDValue.toNumber() < 100) {
197
+ // // too less debt, skip
198
+ // logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall newDebtUSDValue is less than 100, skipping`);
199
+ // return undefined;
200
+ // }
201
+ // }
202
+
203
+ // logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall debtAmount: ${debtAmount}`);
204
+ // if (debtAmount.lt(0)) {
205
+ // // this is to unwind the position to optimal HF.
206
+ // const lstDEXPrice = await this.getLSTDexPrice();
207
+ // const debtAmountInLST = debtAmount.abs().dividedBy(lstDEXPrice);
208
+ // const calls = await this.getVesuMultiplyCall({
209
+ // isDeposit: false,
210
+ // leg1DepositAmount: debtAmountInLST
211
+ // })
212
+ // assert(calls.length == 1, `Expected 1 call for unwind, got ${calls.length}`);
213
+ // return calls[0];
214
+ // }
215
+ // console.log(`debtAmount`, debtAmount.toWei(), params.leg1DepositAmount.toWei());
216
+ // const STEP0 = UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN1;
217
+ // const manage0Info = this.getProofs<ApproveCallParams>(STEP0);
218
+ // const manageCall0 = manage0Info.callConstructor({
219
+ // amount: newDepositAmount
220
+ // });
221
+ // const STEP1 = getVesuLegId(UNIVERSAL_MANAGE_IDS.VESU_LEG1, vesuAdapter.config.debt.symbol);
222
+ // const manage1Info = this.getProofs<VesuModifyPositionCallParams>(STEP1);
223
+ // const manageCall1 = manage1Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
224
+ // collateralAmount: newDepositAmount,
225
+ // isAddCollateral: params.isDeposit,
226
+ // debtAmount: debtAmount,
227
+ // isBorrow: params.isDeposit
228
+ // }));
229
+
230
+ // console.log(`manageCall1`, manageCall1.call, debtAmount.toWei(), newDepositAmount.toWei());
247
231
 
248
- const proofIds: string[] = [STEP0, STEP1];
249
- const manageCalls: ManageCall[] = [manageCall0, manageCall1];
250
-
251
- // approve and swap to LST using avnu
252
- if (debtAmount.gt(0)) {
253
- const STEP2 = getAvnuManageIDs(LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_APPROVE_DEPOSIT, vesuAdapter.config.debt.symbol);
254
- const manage2Info = this.getProofs<ApproveCallParams>(STEP2);
255
- const manageCall2 = manage2Info.callConstructor({
256
- amount: debtAmount
257
- });
258
-
259
- const debtTokenInfo = vesuAdapter.config.debt;
260
- const lstTokenInfo = this.asset();
261
- const avnuModule = new AvnuWrapper();
262
- const quote = await avnuModule.getQuotes(
263
- debtTokenInfo.address.address,
264
- lstTokenInfo.address.address,
265
- debtAmount.toWei(),
266
- this.metadata.additionalInfo.vaultAllocator.address
267
- );
268
- const minAmount = await this._getMinOutputAmountLSTBuy(debtAmount);
269
- const minAmountWei = (minAmount).toWei();
270
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall minAmount: ${minAmount}`);
271
- const swapInfo = await avnuModule.getSwapInfo(
272
- quote,
273
- this.metadata.additionalInfo.vaultAllocator.address,
274
- 0,
275
- this.address.address,
276
- minAmountWei
277
- );
278
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall swapInfo: ${JSON.stringify(swapInfo)}`);
279
- const STEP3 = getAvnuManageIDs(LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_SWAP_DEPOSIT, vesuAdapter.config.debt.symbol);
280
- const manage3Info = this.getProofs<AvnuSwapCallParams>(STEP3);
281
- const manageCall3 = manage3Info.callConstructor({
282
- props: swapInfo
283
- });
284
- proofIds.push(STEP2);
285
- proofIds.push(STEP3);
286
- manageCalls.push(manageCall2, manageCall3);
287
-
288
-
289
- // if the created debt, when added is collateral will put the total HF above min, but below (target + 0.05),
290
- // then lets close the looping cycle by adding this as collateral.
291
- const newCollateral = minAmount.plus(totalCollateral);
292
- const newHF = newCollateral.multipliedBy(collateralPrice).multipliedBy(legLTV).dividedBy(totalDebtAmount).dividedBy(debtPrice).toNumber();
293
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall newHF: ${newHF}`);
294
- if (newHF > this.metadata.additionalInfo.minHealthFactor && newHF < this.metadata.additionalInfo.targetHealthFactor + 0.05) {
295
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall newHF is above min and below target + 0.05, adding collateral on vesu`);
296
- // approve and add collateral on vesu (modify position)
297
- const STEP4 = UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN1;
298
- const manage4Info = this.getProofs<ApproveCallParams>(STEP4);
299
- const manageCall4 = manage4Info.callConstructor({
300
- amount: minAmount
301
- });
232
+ // const proofIds: string[] = [STEP0, STEP1];
233
+ // const manageCalls: ManageCall[] = [manageCall0, manageCall1];
234
+
235
+ // // approve and swap to LST using avnu
236
+ // if (debtAmount.gt(0)) {
237
+ // const STEP2 = getAvnuManageIDs(LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_APPROVE_DEPOSIT, vesuAdapter.config.debt.symbol);
238
+ // const manage2Info = this.getProofs<ApproveCallParams>(STEP2);
239
+ // const manageCall2 = manage2Info.callConstructor({
240
+ // amount: debtAmount
241
+ // });
242
+
243
+ // const debtTokenInfo = vesuAdapter.config.debt;
244
+ // const lstTokenInfo = this.asset();
245
+ // const avnuModule = new AvnuWrapper();
246
+ // const quote = await avnuModule.getQuotes(
247
+ // debtTokenInfo.address.address,
248
+ // lstTokenInfo.address.address,
249
+ // debtAmount.toWei(),
250
+ // this.metadata.additionalInfo.vaultAllocator.address
251
+ // );
252
+ // const minAmount = await this._getMinOutputAmountLSTBuy(debtAmount);
253
+ // const minAmountWei = (minAmount).toWei();
254
+ // logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall minAmount: ${minAmount}`);
255
+ // const swapInfo = await avnuModule.getSwapInfo(
256
+ // quote,
257
+ // this.metadata.additionalInfo.vaultAllocator.address,
258
+ // 0,
259
+ // this.address.address,
260
+ // minAmountWei
261
+ // );
262
+ // logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall swapInfo: ${JSON.stringify(swapInfo)}`);
263
+ // const STEP3 = getAvnuManageIDs(LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_SWAP_DEPOSIT, vesuAdapter.config.debt.symbol);
264
+ // const manage3Info = this.getProofs<AvnuSwapCallParams>(STEP3);
265
+ // const manageCall3 = manage3Info.callConstructor({
266
+ // props: swapInfo
267
+ // });
268
+ // proofIds.push(STEP2);
269
+ // proofIds.push(STEP3);
270
+ // manageCalls.push(manageCall2, manageCall3);
271
+
272
+
273
+ // // if the created debt, when added is collateral will put the total HF above min, but below (target + 0.05),
274
+ // // then lets close the looping cycle by adding this as collateral.
275
+ // const newCollateral = minAmount.plus(totalCollateral);
276
+ // const newHF = newCollateral.multipliedBy(collateralPrice).multipliedBy(legLTV).dividedBy(totalDebtAmount).dividedBy(debtPrice).toNumber();
277
+ // logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall newHF: ${newHF}`);
278
+ // if (newHF > this.metadata.additionalInfo.minHealthFactor && newHF < this.metadata.additionalInfo.targetHealthFactor + 0.05) {
279
+ // logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall newHF is above min and below target + 0.05, adding collateral on vesu`);
280
+ // // approve and add collateral on vesu (modify position)
281
+ // const STEP4 = UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN1;
282
+ // const manage4Info = this.getProofs<ApproveCallParams>(STEP4);
283
+ // const manageCall4 = manage4Info.callConstructor({
284
+ // amount: minAmount
285
+ // });
302
286
 
303
- const STEP5 = getVesuLegId(UNIVERSAL_MANAGE_IDS.VESU_LEG1, vesuAdapter.config.debt.symbol);
304
- const manage5Info = this.getProofs<VesuModifyPositionCallParams>(STEP5);
305
- const manageCall5 = manage5Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
306
- collateralAmount: minAmount,
307
- isAddCollateral: true,
308
- debtAmount: Web3Number.fromWei('0', this.asset().decimals),
309
- isBorrow: params.isDeposit
310
- }));
311
- proofIds.push(STEP4, STEP5);
312
- manageCalls.push(manageCall4, manageCall5);
313
- }
314
- }
315
-
316
- const manageCall = this.getManageCall(proofIds, manageCalls);
317
- return manageCall;
318
- }
287
+ // const STEP5 = getVesuLegId(UNIVERSAL_MANAGE_IDS.VESU_LEG1, vesuAdapter.config.debt.symbol);
288
+ // const manage5Info = this.getProofs<VesuModifyPositionCallParams>(STEP5);
289
+ // const manageCall5 = manage5Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
290
+ // collateralAmount: minAmount,
291
+ // isAddCollateral: true,
292
+ // debtAmount: Web3Number.fromWei('0', this.asset().decimals),
293
+ // isBorrow: params.isDeposit
294
+ // }));
295
+ // proofIds.push(STEP4, STEP5);
296
+ // manageCalls.push(manageCall4, manageCall5);
297
+ // }
298
+ // }
299
+
300
+ // const manageCall = this.getManageCall(proofIds, manageCalls);
301
+ // return manageCall;
302
+ // }
319
303
 
320
304
  // todo unwind or not deposit when the yield is bad.
321
305
 
322
- async getLSTMultiplierRebalanceCall(): Promise<{ shouldRebalance: boolean, manageCalls: {vesuAdapter: VesuAdapter, manageCall: Call}[] }> {
323
- let shouldRebalance = false;
324
- const calls: {vesuAdapter: VesuAdapter, manageCall: Call}[] = [];
325
- // todo undo
326
- const allVesuAdapters = this.getVesuAdapters().filter(vesuAdapter => vesuAdapter.config.debt.symbol === 'LBTC');
327
- for (const vesuAdapter of allVesuAdapters) {
328
- const call = await this._getLSTMultiplierRebalanceCall(vesuAdapter);
329
- if (call.shouldRebalance && call.manageCall) {
330
- shouldRebalance = true;
331
- calls.push({vesuAdapter, manageCall: call.manageCall});
332
- }
333
- }
334
- return { shouldRebalance, manageCalls: calls };
335
- }
336
-
337
- async _getLSTMultiplierRebalanceCall(vesuAdapter: VesuAdapter): Promise<{ shouldRebalance: boolean, manageCall: Call | undefined }> {
338
- const positions = await vesuAdapter.getPositions(this.config);
339
- assert(positions.length == 2, 'Rebalance call is only supported for 2 positions');
340
- const existingCollateralInfo = positions[0];
341
- const existingDebtInfo = positions[1];
342
- const unusedBalance = await this.getUnusedBalance();
343
- const healthFactor = await vesuAdapter.getHealthFactor();
344
-
345
- const collateralisation = await vesuAdapter.getCollateralization(this.config);
346
- logger.debug(`${this.getTag()}::getVesuMultiplyCall::${vesuAdapter.config.debt.symbol} existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
347
- existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
348
-
349
- // - Prices as seen by Vesu contracts, ideal for HF math
350
- // Price 1 is ok as fallback bcz that would relatively price the
351
- // collateral and debt as equal.
352
- const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
353
- const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
354
- logger.debug(`${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
355
- logger.debug(`${this.getTag()}::getVesuMultiplyCall healthFactor: ${healthFactor}`);
356
-
357
- const isHFTooLow = healthFactor < this.metadata.additionalInfo.minHealthFactor;
358
- const isHFTooHigh = healthFactor > this.metadata.additionalInfo.targetHealthFactor + 0.05;
359
- if (isHFTooLow || isHFTooHigh || 1) {
360
- // use unused collateral to target more.
361
- const manageCall = await this._getAvnuDepositSwapLegCall({
362
- isDeposit: true,
363
- leg1DepositAmount: unusedBalance.amount,
364
- minHF: 1.02, // todo, shouldnt use this 1.02 HF, if there isn;t more looping left.
365
- vesuAdapter
366
- })
367
- return { shouldRebalance: true, manageCall };
368
- } else {
369
- // do nothing
370
- return { shouldRebalance: false, manageCall: undefined };
371
- }
372
- }
373
-
374
- protected async getVesuAUM(adapter: VesuAdapter) {
375
- const legAUM = await adapter.getPositions(this.config);
376
- const underlying = this.asset();
377
- // assert its an LST of Endur
378
- assert(underlying.symbol.startsWith('x'), 'Underlying is not an LST of Endur');
379
-
380
- let vesuAum = Web3Number.fromWei("0", underlying.decimals);
306
+ // async getLSTMultiplierRebalanceCall(): Promise<{ shouldRebalance: boolean, manageCalls: {vesuAdapter: VesuAdapter, manageCall: Call}[] }> {
307
+ // let shouldRebalance = false;
308
+ // const calls: {vesuAdapter: VesuAdapter, manageCall: Call}[] = [];
309
+ // // todo undo
310
+ // const allVesuAdapters = this.getVesuAdapters().filter(vesuAdapter => vesuAdapter.config.debt.symbol === 'LBTC');
311
+ // for (const vesuAdapter of allVesuAdapters) {
312
+ // const call = await this._getLSTMultiplierRebalanceCall(vesuAdapter);
313
+ // if (call.shouldRebalance && call.manageCall) {
314
+ // shouldRebalance = true;
315
+ // calls.push({vesuAdapter, manageCall: call.manageCall});
316
+ // }
317
+ // }
318
+ // return { shouldRebalance, manageCalls: calls };
319
+ // }
320
+
321
+ // async _getLSTMultiplierRebalanceCall(vesuAdapter: VesuAdapter): Promise<{ shouldRebalance: boolean, manageCall: Call | undefined }> {
322
+ // const positions = await vesuAdapter.getPositions(this.config);
323
+ // assert(positions.length == 2, 'Rebalance call is only supported for 2 positions');
324
+ // const existingCollateralInfo = positions[0];
325
+ // const existingDebtInfo = positions[1];
326
+ // const unusedBalance = await this.getUnusedBalance();
327
+ // const healthFactor = await vesuAdapter.getHealthFactor();
328
+
329
+ // const collateralisation = await vesuAdapter.getCollateralization(this.config);
330
+ // logger.debug(`${this.getTag()}::getVesuMultiplyCall::${vesuAdapter.config.debt.symbol} existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
331
+ // existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
332
+
333
+ // // - Prices as seen by Vesu contracts, ideal for HF math
334
+ // // Price 1 is ok as fallback bcz that would relatively price the
335
+ // // collateral and debt as equal.
336
+ // const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
337
+ // const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
338
+ // logger.debug(`${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
339
+ // logger.debug(`${this.getTag()}::getVesuMultiplyCall healthFactor: ${healthFactor}`);
340
+
341
+ // const isHFTooLow = healthFactor < this.metadata.additionalInfo.minHealthFactor;
342
+ // const isHFTooHigh = healthFactor > this.metadata.additionalInfo.targetHealthFactor + 0.05;
343
+ // if (isHFTooLow || isHFTooHigh || 1) {
344
+ // // use unused collateral to target more.
345
+ // const manageCall = await this._getAvnuDepositSwapLegCall({
346
+ // isDeposit: true,
347
+ // leg1DepositAmount: unusedBalance.amount,
348
+ // minHF: 1.02, // todo, shouldnt use this 1.02 HF, if there isn;t more looping left.
349
+ // vesuAdapter
350
+ // })
351
+ // return { shouldRebalance: true, manageCall };
352
+ // } else {
353
+ // // do nothing
354
+ // return { shouldRebalance: false, manageCall: undefined };
355
+ // }
356
+ // }
357
+
358
+ // protected async getVesuAUM(adapter: VesuAdapter) {
359
+ // const legAUM = await adapter.getPositions(this.config);
360
+ // const underlying = this.asset();
361
+ // // assert its an LST of Endur
362
+ // assert(underlying.symbol.startsWith('x'), 'Underlying is not an LST of Endur');
363
+
364
+ // let vesuAum = Web3Number.fromWei("0", underlying.decimals);
381
365
 
382
- let tokenUnderlyingPrice = await this.getLSTExchangeRate();
383
- // to offset for usual DEX lag, we multiply by 0.998 (i.e. 0.2% loss)
384
- tokenUnderlyingPrice = tokenUnderlyingPrice * 0.998;
385
- logger.verbose(`${this.getTag()} tokenUnderlyingPrice: ${tokenUnderlyingPrice}`);
366
+ // let tokenUnderlyingPrice = await this.getLSTExchangeRate();
367
+ // // to offset for usual DEX lag, we multiply by 0.998 (i.e. 0.2% loss)
368
+ // tokenUnderlyingPrice = tokenUnderlyingPrice * 0.998;
369
+ // logger.verbose(`${this.getTag()} tokenUnderlyingPrice: ${tokenUnderlyingPrice}`);
386
370
 
387
- // handle collateral
388
- if (legAUM[0].token.address.eq(underlying.address)) {
389
- vesuAum = vesuAum.plus(legAUM[0].amount);
390
- } else {
391
- vesuAum = vesuAum.plus(legAUM[0].amount.dividedBy(tokenUnderlyingPrice));
392
- }
371
+ // // handle collateral
372
+ // if (legAUM[0].token.address.eq(underlying.address)) {
373
+ // vesuAum = vesuAum.plus(legAUM[0].amount);
374
+ // } else {
375
+ // vesuAum = vesuAum.plus(legAUM[0].amount.dividedBy(tokenUnderlyingPrice));
376
+ // }
377
+
378
+ // // handle debt
379
+ // if (legAUM[1].token.address.eq(underlying.address)) {
380
+ // vesuAum = vesuAum.minus(legAUM[1].amount);
381
+ // } else {
382
+ // vesuAum = vesuAum.minus(legAUM[1].amount.dividedBy(tokenUnderlyingPrice));
383
+ // };
384
+
385
+ // logger.verbose(`${this.getTag()} Vesu AUM: ${vesuAum}, legCollateral: ${legAUM[0].amount.toNumber()}, legDebt: ${legAUM[1].amount.toNumber()}`);
386
+ // return vesuAum;
387
+ // }
393
388
 
394
- // handle debt
395
- if (legAUM[1].token.address.eq(underlying.address)) {
396
- vesuAum = vesuAum.minus(legAUM[1].amount);
397
- } else {
398
- vesuAum = vesuAum.minus(legAUM[1].amount.dividedBy(tokenUnderlyingPrice));
399
- };
389
+ //
390
+ // private async _getMinOutputAmountLSTBuy(amountInUnderlying: Web3Number) {
391
+ // const lstTruePrice = await this.getLSTExchangeRate();
392
+ // // during buy, the purchase should always be <= true LST price.
393
+ // const minOutputAmount = amountInUnderlying.dividedBy(lstTruePrice).multipliedBy(0.99979); // minus 0.021% to account for avnu fees
394
+ // return new Web3Number(minOutputAmount.toString(), this.asset().decimals);
395
+ // }
400
396
 
401
- logger.verbose(`${this.getTag()} Vesu AUM: ${vesuAum}, legCollateral: ${legAUM[0].amount.toNumber()}, legDebt: ${legAUM[1].amount.toNumber()}`);
402
- return vesuAum;
403
- }
397
+ // private async _getMinOutputAmountLSTSell(amountInLST: Web3Number) {
398
+ // const lstTruePrice = await this.getLSTExchangeRate();
399
+ // // during sell, the purchase should always be > 0.995 * true LST price.
400
+ // const minOutputAmount = amountInLST.multipliedBy(lstTruePrice).multipliedBy(0.995);
401
+ // return minOutputAmount;
402
+ // }
404
403
 
405
- //
406
- private async _getMinOutputAmountLSTBuy(amountInUnderlying: Web3Number) {
407
- const lstTruePrice = await this.getLSTExchangeRate();
408
- // during buy, the purchase should always be <= true LST price.
409
- const minOutputAmount = amountInUnderlying.dividedBy(lstTruePrice).multipliedBy(0.99979); // minus 0.021% to account for avnu fees
410
- return new Web3Number(minOutputAmount.toString(), this.asset().decimals);
411
- }
412
404
 
413
- private async _getMinOutputAmountLSTSell(amountInLST: Web3Number) {
414
- const lstTruePrice = await this.getLSTExchangeRate();
415
- // during sell, the purchase should always be > 0.995 * true LST price.
416
- const minOutputAmount = amountInLST.multipliedBy(lstTruePrice).multipliedBy(0.995);
417
- return minOutputAmount;
418
- }
419
405
 
420
406
  // todo add a function to findout max borrowable amount without fucking yield
421
407
  // if the current net yield < LST yield, add a function to calculate how much to unwind.
@@ -425,376 +411,275 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
425
411
  * Deposit amount is in LST
426
412
  * @param params
427
413
  */
428
- async getVesuMultiplyCall(params: {
414
+ async getFundManagementCall(params: {
429
415
  isDeposit: boolean,
430
- leg1DepositAmount: Web3Number,
431
- maxEkuboPriceImpact?: number
416
+ leg1DepositAmount: Web3Number
432
417
  }) {
433
- const maxEkuboPriceImpact = params.maxEkuboPriceImpact || 0.01;
434
- const vesuAdapter1 = this.getVesuSameTokenAdapter();
435
- const legLTV = await vesuAdapter1.getLTVConfig(this.config);
436
- logger.verbose(`${this.getTag()}::getVesuMultiplyCall legLTV: ${legLTV}`);
437
-
418
+ logger.verbose(`${this.getTag()}::getFundManagementCall params: ${JSON.stringify(params)}`);
419
+ // const legLTV = await vesuAdapter1.getLTVConfig(this.config);
420
+ // logger.verbose(`${this.getTag()}::getVesuMultiplyCall legLTV: ${legLTV}`);
421
+ const allAdapters = this.metadata.additionalInfo.adapters.map(adapter => adapter.adapter);
438
422
  if (!params.isDeposit) {
439
423
  // try using unused balance to unwind.
440
424
  // no need to unwind.
441
425
  const unusedBalance = await this.getUnusedBalance();
442
426
  logger.verbose(`${this.getTag()}::getVesuMultiplyCall unusedBalance: ${unusedBalance.amount.toString()}, required: ${params.leg1DepositAmount.toString()}`);
443
- // undo
444
- // if (unusedBalance.amount.gte(params.leg1DepositAmount)) {
445
- // return [];
446
- // }
447
- // throw new Error('Unused balance is less than the amount to unwind');
427
+ if (unusedBalance.amount.gte(params.leg1DepositAmount)) {
428
+ return null;
429
+ } else {
430
+ const adapters = await AdapterOptimizer.getAdapterToUse(allAdapters, false, params.leg1DepositAmount);
431
+ if (adapters.length > 0) {
432
+ const proofsInfo = adapters.map(adapter => adapter.getProofs(false, this.getMerkleTree()));
433
+ const calls: Call[] = [];
434
+ for (const info of proofsInfo) {
435
+ const proofGroups = info.proofs;
436
+ const call = this.getManageCall(proofGroups, await info.callConstructor({amount: params.leg1DepositAmount}));
437
+ calls.push(call);
438
+ }
439
+ return calls;
440
+ } else {
441
+ throw new Error(`${this.getTag()}::getVesuMultiplyCall: no adapters to use for unused balance: ${unusedBalance.amount.toString()}`);
442
+ }
443
+ }
448
444
  }
449
445
 
450
- const existingPositions = await vesuAdapter1.getPositions(this.config);
451
- const collateralisation = await vesuAdapter1.getCollateralization(this.config);
452
- const existingCollateralInfo = existingPositions[0];
453
- const existingDebtInfo = existingPositions[1];
454
- logger.debug(`${this.getTag()}::getVesuMultiplyCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
455
- existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
456
-
457
- // - Prices as seen by Vesu contracts, ideal for HF math
458
- // Price 1 is ok as fallback bcz that would relatively price the
459
- // collateral and debt as equal.
460
- const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
461
- const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
462
- logger.debug(`${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
463
-
464
- // - Prices as seen by actual swap price
465
- const dexPrice = await this.getLSTDexPrice();
466
-
467
- // compute optimal amount of collateral and debt post addition/removal
468
- // target hf = collateral * collateralPrice * ltv / debt * debtPrice
469
- // assuming X to be the usd amount of debt borrowed or repaied (negative).
470
- // target hf = (((collateral + legDepositAmount) * collateralPrice + X)) * ltv / (debt * debtPrice + X)
471
- // => X * target hf = (((collateral + legDepositAmount) * collateralPrice + X)) * ltv - (debt * debtPrice * target hf)
472
- // => X * (target hf - ltv)= ((collateral + legDepositAmount) * collateralPrice * ltv) - (debt * debtPrice * target hf)
473
- // => X = (((collateral + legDepositAmount) * collateralPrice * ltv) - (debt * debtPrice * target hf)) / (target hf - ltv)
474
- const addedCollateral = params.leg1DepositAmount
475
- .multipliedBy(params.isDeposit ? 1 : -1)
476
- logger.verbose(`${this.getTag()}::getVesuMultiplyCall addedCollateral: ${addedCollateral}`);
477
- const numeratorPart1 = (existingCollateralInfo.amount.plus((addedCollateral))).multipliedBy(collateralPrice).multipliedBy(legLTV);
478
- logger.verbose(`${this.getTag()}::getVesuMultiplyCall numeratorPart1: ${numeratorPart1}`);
479
- const numeratorPart2 = existingDebtInfo.amount.multipliedBy(debtPrice).multipliedBy(this.metadata.additionalInfo.targetHealthFactor);
480
- logger.verbose(`${this.getTag()}::getVesuMultiplyCall numeratorPart2: ${numeratorPart2}`);
481
- const denominatorPart = this.metadata.additionalInfo.targetHealthFactor - (legLTV / dexPrice);
482
- logger.verbose(`${this.getTag()}::getVesuMultiplyCall denominatorPart: ${denominatorPart}`);
483
- const x_debt_usd = numeratorPart1.minus(numeratorPart2).dividedBy(denominatorPart);
484
- logger.verbose(`${this.getTag()}::getVesuMultiplyCall x_debt_usd: ${x_debt_usd}`);
485
- logger.debug(`${this.getTag()}::getVesuMultiplyCall numeratorPart1: ${numeratorPart1}, numeratorPart2: ${numeratorPart2}, denominatorPart: ${denominatorPart}`);
486
-
487
- // both in underlying
488
- let debtAmount = x_debt_usd.dividedBy(debtPrice);
489
- const marginAmount = addedCollateral;
490
- logger.verbose(`${this.getTag()}::getVesuMultiplyCall debtAmount: ${debtAmount}, marginAmount: ${marginAmount}`);
491
-
492
- if (marginAmount.lt(0) && debtAmount.gt(0)) {
493
- // if we want to withdraw, but debt can go high, its conflicting between
494
- // increasing and reducing lever. and in this case, the HF will go high,
495
- // which is ok.
496
- debtAmount = Web3Number.fromWei(0, this.asset().decimals);
446
+ const adapters = await AdapterOptimizer.getAdapterToUse(allAdapters, true, params.leg1DepositAmount);
447
+ if (adapters.length > 0) {
448
+ const proofsInfo = adapters.map(adapter => adapter.getProofs(true, this.getMerkleTree()));
449
+ const calls: Call[] = [];
450
+ for (const info of proofsInfo) {
451
+ const proofGroups = info.proofs;
452
+ const call = this.getManageCall(proofGroups, await info.callConstructor({amount: params.leg1DepositAmount}));
453
+ calls.push(call);
454
+ }
455
+ return calls;
456
+ } else {
457
+ throw new Error(`${this.getTag()}::getVesuMultiplyCall: no adapters to use for deposit: ${params.leg1DepositAmount.toString()}`);
497
458
  }
498
459
 
499
- // Cases of lever increase (within the scopr of this function)
500
- // 1. debtAmount > 0 and marginAmount > 0
501
- // 2. debtAmount > 0 and marginAmount < 0
502
-
503
- // Cases of lever decrease
504
- // 3. debtAmount < 0 and marginAmount > 0
505
- // 4. debtAmount < 0 and marginAmount < 0
506
- return this.getModifyLeverCall({
507
- marginAmount,
508
- debtAmount,
509
- lstDexPriceInUnderlying: dexPrice,
510
- isIncrease: debtAmount.greaterThan(0),
511
- maxEkuboPriceImpact
512
- });
460
+ // const existingPositions = await vesuAdapter1.getPositions(this.config);
461
+ // const collateralisation = await vesuAdapter1.getCollateralization(this.config);
462
+ // const existingCollateralInfo = existingPositions[0];
463
+ // const existingDebtInfo = existingPositions[1];
464
+ // logger.debug(`${this.getTag()}::getVesuMultiplyCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
465
+ // existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
466
+
467
+ // // - Prices as seen by Vesu contracts, ideal for HF math
468
+ // // Price 1 is ok as fallback bcz that would relatively price the
469
+ // // collateral and debt as equal.
470
+ // const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
471
+ // const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
472
+ // logger.debug(`${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
473
+
474
+ // // - Prices as seen by actual swap price
475
+ // const dexPrice = await this.getLSTDexPrice();
476
+
477
+ // // compute optimal amount of collateral and debt post addition/removal
478
+ // // target hf = collateral * collateralPrice * ltv / debt * debtPrice
479
+ // // assuming X to be the usd amount of debt borrowed or repaied (negative).
480
+ // // target hf = (((collateral + legDepositAmount) * collateralPrice + X)) * ltv / (debt * debtPrice + X)
481
+ // // => X * target hf = (((collateral + legDepositAmount) * collateralPrice + X)) * ltv - (debt * debtPrice * target hf)
482
+ // // => X * (target hf - ltv)= ((collateral + legDepositAmount) * collateralPrice * ltv) - (debt * debtPrice * target hf)
483
+ // // => X = (((collateral + legDepositAmount) * collateralPrice * ltv) - (debt * debtPrice * target hf)) / (target hf - ltv)
484
+ // const addedCollateral = params.leg1DepositAmount
485
+ // .multipliedBy(params.isDeposit ? 1 : -1)
486
+ // logger.verbose(`${this.getTag()}::getVesuMultiplyCall addedCollateral: ${addedCollateral}`);
487
+ // const numeratorPart1 = (existingCollateralInfo.amount.plus((addedCollateral))).multipliedBy(collateralPrice).multipliedBy(legLTV);
488
+ // logger.verbose(`${this.getTag()}::getVesuMultiplyCall numeratorPart1: ${numeratorPart1}`);
489
+ // const numeratorPart2 = existingDebtInfo.amount.multipliedBy(debtPrice).multipliedBy(this.metadata.additionalInfo.targetHealthFactor);
490
+ // logger.verbose(`${this.getTag()}::getVesuMultiplyCall numeratorPart2: ${numeratorPart2}`);
491
+ // const denominatorPart = this.metadata.additionalInfo.targetHealthFactor - (legLTV / dexPrice);
492
+ // logger.verbose(`${this.getTag()}::getVesuMultiplyCall denominatorPart: ${denominatorPart}`);
493
+ // const x_debt_usd = numeratorPart1.minus(numeratorPart2).dividedBy(denominatorPart);
494
+ // logger.verbose(`${this.getTag()}::getVesuMultiplyCall x_debt_usd: ${x_debt_usd}`);
495
+ // logger.debug(`${this.getTag()}::getVesuMultiplyCall numeratorPart1: ${numeratorPart1}, numeratorPart2: ${numeratorPart2}, denominatorPart: ${denominatorPart}`);
496
+
497
+ // // both in underlying
498
+ // const debtAmount = x_debt_usd.dividedBy(debtPrice);
499
+ // const marginAmount = addedCollateral;
500
+ // logger.verbose(`${this.getTag()}::getVesuMultiplyCall debtAmount: ${debtAmount}, marginAmount: ${marginAmount}`);
501
+
502
+ // // Cases of lever increase (within the scopr of this function)
503
+ // // 1. debtAmount > 0 and marginAmount > 0
504
+ // // 2. debtAmount > 0 and marginAmount < 0
505
+
506
+ // // Cases of lever decrease
507
+ // // 3. debtAmount < 0 and marginAmount > 0
508
+ // // 4. debtAmount < 0 and marginAmount < 0
509
+ // return this.getModifyLeverCall({
510
+ // marginAmount,
511
+ // debtAmount,
512
+ // lstDexPriceInUnderlying: dexPrice,
513
+ // isIncrease: debtAmount.greaterThan(0)
514
+ // });
513
515
  }
514
516
 
517
+
515
518
  getLSTUnderlyingTokenInfo() {
516
- const vesuAdapter1 = this.getVesuSameTokenAdapter();
517
- return vesuAdapter1.config.debt;
519
+ return this.metadata.additionalInfo.underlyingToken;
518
520
  }
519
521
 
520
- async getMaxBorrowableAmount(params: { isAPYComputation: boolean } = { isAPYComputation: false }) {
521
- const vesuAdapters = this.getVesuAdapters();
522
- let netMaxBorrowableAmount = Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals);
523
- const maxBorrowables: {amount: Web3Number, dexSwappableAmount: Web3Number, maxBorrowableAmount: Web3Number, borrowableAsset: TokenInfo}[] = [];
524
- for (const vesuAdapter of vesuAdapters) {
525
- maxBorrowables.push(await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, params.isAPYComputation));
526
- }
527
- maxBorrowables.sort((a, b) => b.amount.toNumber() - a.amount.toNumber());
528
- netMaxBorrowableAmount = maxBorrowables.reduce((acc, curr) => acc.plus(curr.amount), Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals));
529
- return {netMaxBorrowableAmount, maxBorrowables};
530
- }
522
+ // async getMaxBorrowableAmount(params: { isAPYComputation: boolean } = { isAPYComputation: false }) {
523
+ // const vesuAdapters = this.getVesuAdapters();
524
+ // let netMaxBorrowableAmount = Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals);
525
+ // const maxBorrowables: {amount: Web3Number, dexSwappableAmount: Web3Number, maxBorrowableAmount: Web3Number, borrowableAsset: TokenInfo}[] = [];
526
+ // for (const vesuAdapter of vesuAdapters) {
527
+ // maxBorrowables.push(await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, params.isAPYComputation));
528
+ // }
529
+ // maxBorrowables.sort((a, b) => b.amount.toNumber() - a.amount.toNumber());
530
+ // netMaxBorrowableAmount = maxBorrowables.reduce((acc, curr) => acc.plus(curr.amount), Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals));
531
+ // return {netMaxBorrowableAmount, maxBorrowables};
532
+ // }
531
533
 
532
534
  // recursively, using binary search computes max swappable.
533
535
  // @dev assumes 1 token of from == 1 token of to
534
- async getMaxSwappableWithMaxSlippage(fromToken: TokenInfo, toToken: TokenInfo, maxSlippage: number, maxAmount: Web3Number) {
535
- const output = await findMaxInputWithSlippage({
536
- apiGetOutput: async (inputAmount: number): Promise<number> => {
537
- const ekuboQuoter = new EkuboQuoter(this.config);
538
- await new Promise(resolve => setTimeout(resolve, 1000)); // artificial delay, to avoid rate limit
539
- const quote = await ekuboQuoter.getQuote(fromToken.address.address, toToken.address.address, new Web3Number(inputAmount.toFixed(9), fromToken.decimals));
540
- return Web3Number.fromWei(quote.total_calculated.toString(), toToken.decimals).toNumber();
541
- },
542
- maxInput: maxAmount.toNumber(),
543
- maxSlippagePercent: maxSlippage,
544
- tolerance: 0.001,
545
- referenceRate: 1,
546
- });
547
- return new Web3Number(output.optimalInput, fromToken.decimals);
548
- }
549
-
550
- async getMaxBorrowableAmountByVesuAdapter(vesuAdapter: VesuAdapter, isAPYComputation: boolean) {
551
- const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
552
- const maxInterestRate = lstAPY * 0.8;
553
- const maxBorrowableAmount = await vesuAdapter.getMaxBorrowableByInterestRate(this.config, vesuAdapter.config.debt, maxInterestRate);
554
- const debtCap = await vesuAdapter.getDebtCap(this.config);
555
-
556
- const maxBorrowable = maxBorrowableAmount.minimum(debtCap).multipliedBy(0.999);
557
- // Dont compute precise max swappable for APY computation
558
- if (vesuAdapter.config.debt.address.eq(this.getLSTUnderlyingTokenInfo().address) || isAPYComputation) {
559
- return {amount: maxBorrowable, dexSwappableAmount: maxBorrowable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt};
560
- }
561
- // Want < 0.02% slippage
562
- try {
563
- const maxSwappable = await this.getMaxSwappableWithMaxSlippage(vesuAdapter.config.debt, this.getLSTUnderlyingTokenInfo(), 0.0002, maxBorrowable);
564
- return {amount: maxBorrowable.minimum(maxSwappable), dexSwappableAmount: maxSwappable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt};
565
- } catch (error) {
566
- logger.warn(`${this.getTag()}: Failed to get max swappable: ${error}`);
567
- const maxSwappable = Web3Number.fromWei("0", vesuAdapter.config.debt.decimals);
568
- return {amount: maxBorrowable.minimum(maxSwappable), dexSwappableAmount: maxSwappable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt};
569
- }
570
- }
536
+ // async getMaxSwappableWithMaxSlippage(fromToken: TokenInfo, toToken: TokenInfo, maxSlippage: number, maxAmount: Web3Number) {
537
+ // const output = await findMaxInputWithSlippage({
538
+ // apiGetOutput: async (inputAmount: number): Promise<number> => {
539
+ // const ekuboQuoter = new EkuboQuoter(this.config);
540
+ // await new Promise(resolve => setTimeout(resolve, 1000)); // artificial delay, to avoid rate limit
541
+ // const quote = await ekuboQuoter.getQuote(fromToken.address.address, toToken.address.address, new Web3Number(inputAmount.toFixed(9), fromToken.decimals));
542
+ // return Web3Number.fromWei(quote.total_calculated.toString(), toToken.decimals).toNumber();
543
+ // },
544
+ // maxInput: maxAmount.toNumber(),
545
+ // maxSlippagePercent: maxSlippage,
546
+ // tolerance: 0.001,
547
+ // referenceRate: 1,
548
+ // });
549
+ // return new Web3Number(output.optimalInput, fromToken.decimals);
550
+ // }
551
+
552
+ // async getMaxBorrowableAmountByVesuAdapter(vesuAdapter: VesuAdapter, isAPYComputation: boolean) {
553
+ // const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
554
+ // const maxInterestRate = lstAPY * 0.8;
555
+ // const maxBorrowableAmount = await vesuAdapter.getMaxBorrowableByInterestRate(this.config, vesuAdapter.config.debt, maxInterestRate);
556
+ // const debtCap = await vesuAdapter.getDebtCap(this.config);
557
+
558
+ // const maxBorrowable = maxBorrowableAmount.minimum(debtCap).multipliedBy(0.999);
559
+ // // Dont compute precise max swappable for APY computation
560
+ // if (vesuAdapter.config.debt.address.eq(this.getLSTUnderlyingTokenInfo().address) || isAPYComputation) {
561
+ // return {amount: maxBorrowable, dexSwappableAmount: maxBorrowable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt};
562
+ // }
563
+ // // Want < 0.02% slippage
564
+ // try {
565
+ // const maxSwappable = await this.getMaxSwappableWithMaxSlippage(vesuAdapter.config.debt, this.getLSTUnderlyingTokenInfo(), 0.0002, maxBorrowable);
566
+ // return {amount: maxBorrowable.minimum(maxSwappable), dexSwappableAmount: maxSwappable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt};
567
+ // } catch (error) {
568
+ // logger.warn(`${this.getTag()}: Failed to get max swappable: ${error}`);
569
+ // const maxSwappable = Web3Number.fromWei("0", vesuAdapter.config.debt.decimals);
570
+ // return {amount: maxBorrowable.minimum(maxSwappable), dexSwappableAmount: maxSwappable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt};
571
+ // }
572
+ // }
571
573
 
572
574
  // todo how much to unwind to get back healthy APY zone again
573
575
  // if net APY < LST APR + 0.5%, we need to unwind to get back to LST APR + 1% atleast or 0 vesu position
574
576
  // For xSTRK, simply deposit in Vesu if looping is not viable
575
577
 
576
- /**
577
- * Gets LST APR for the strategy's underlying asset from Endur API
578
- * @returns Promise<number> The LST APR (not divided by 1e18)
579
- */
580
- async getLSTAPR(_address: ContractAddr): Promise<number> {
581
- try {
582
- const vesuAdapter1 = this.getVesuSameTokenAdapter();
583
- const apr = await LSTAPRService.getLSTAPR(vesuAdapter1.config.debt.address);
584
- if (!apr) {
585
- throw new Error('Failed to get LST APR');
586
- }
587
- return apr;
588
- } catch (error) {
589
- logger.warn(`${this.getTag()}: Failed to get LST APR: ${error}`);
590
- return 0;
591
- }
592
- }
593
-
594
- // todo undo this
595
- async netAPY(): Promise<{ net: number; splits: { apy: number; id: string; }[]; }> {
596
- const unusedBalance = await this.getUnusedBalance();
597
- const maxNewDeposits = await this.maxNewDeposits({ isAPYComputation: true });
598
- const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
599
-
600
- // if unused balance is > max servicable from loan, we are limited by the max borrowing we can do
601
- // we also allow accepting little higher deposits (1.5x) to have room for future looping when theres more liquidity or debt cap rises
602
- if (maxNewDeposits * 1.5 < unusedBalance.amount.toNumber()) {
603
- // we have excess, just use real APY
604
- logger.verbose(`${this.getTag()}::netAPY: unused balance is > max servicable from loan, lstAPY: ${lstAPY}`);
605
- const output = await super.netAPY();
606
- output.splits.push({apy: lstAPY, id: 'lst_apy'});
607
- return output;
608
- } else {
609
- // we have little bit room to accept more deposits, we use theoretical max APY
610
- logger.verbose(`${this.getTag()}::netAPY: we can take more deposits, use theoretical max APY`);
611
- const { positions, baseAPYs, rewardAPYs } = await this.getVesuAPYs();
612
- const weights = positions.map((p, index) => p.usdValue * (index % 2 == 0 ? 1 : -1));
613
- const aum = weights.reduce((acc, curr) => acc + curr, 0);
614
- const output = await this.returnNetAPY(baseAPYs, rewardAPYs, weights, new Web3Number(aum.toFixed(9), this.getLSTUnderlyingTokenInfo().decimals));
615
- output.splits.push({apy: lstAPY, id: 'lst_apy'});
616
- return output;
578
+ // /**
579
+ // * Gets LST APR for the strategy's underlying asset from Endur API
580
+ // * @returns Promise<number> The LST APR (not divided by 1e18)
581
+ // */
582
+ // async getLSTAPR(_address: ContractAddr): Promise<number> {
583
+ // try {
584
+ // const vesuAdapter1 = this.getVesuSameTokenAdapter();
585
+ // const apr = await LSTAPRService.getLSTAPR(vesuAdapter1.config.debt.address);
586
+ // if (!apr) {
587
+ // throw new Error('Failed to get LST APR');
588
+ // }
589
+ // return apr;
590
+ // } catch (error) {
591
+ // logger.warn(`${this.getTag()}: Failed to get LST APR: ${error}`);
592
+ // return 0;
593
+ // }
594
+ // }
595
+
596
+ // async maxNewDeposits(params: { isAPYComputation: boolean } = { isAPYComputation: false }) {
597
+ // const maxBorrowableAmounts = await this.getMaxBorrowableAmount(params);
598
+
599
+ // let ltv: number | undefined = undefined;
600
+ // for (let adapter of this.getVesuAdapters()) {
601
+ // const maxBorrowableAmount = maxBorrowableAmounts.maxBorrowables.find(b => b.borrowableAsset.address.eq(adapter.config.debt.address))?.amount;
602
+ // if (!maxBorrowableAmount) {
603
+ // throw new Error(`Max borrowable amount not found for adapter: ${adapter.config.debt.symbol}`);
604
+ // }
605
+ // const maxLTV = await adapter.getLTVConfig(this.config);
606
+ // if (!ltv) {
607
+ // ltv = maxLTV;
608
+ // } else if (ltv != maxLTV) {
609
+ // throw new Error(`LTV mismatch for adapter: ${adapter.config.debt.symbol}`);
610
+ // }
611
+ // }
612
+ // if (!ltv) {
613
+ // throw new Error('LTV not found');
614
+ // }
615
+ // // for simplicity, we assume 1 underlying = 1 LST
616
+ // const numerator = this.metadata.additionalInfo.targetHealthFactor * maxBorrowableAmounts.netMaxBorrowableAmount.toNumber() / (ltv)
617
+ // return numerator - maxBorrowableAmounts.netMaxBorrowableAmount.toNumber();
618
+ // }
619
+
620
+ async getAUM(): Promise<{net: SingleTokenInfo, prevAum: Web3Number, splits: PositionInfo[]}> {
621
+ const allPositions: PositionInfo[] = [];
622
+ for (let adapter of this.metadata.additionalInfo.adapters) {
623
+ const positions = await adapter.adapter.getPositions();
624
+ allPositions.push(...positions);
617
625
  }
618
- }
619
626
 
620
- async maxNewDeposits(params: { isAPYComputation: boolean } = { isAPYComputation: false }) {
621
- const maxBorrowableAmounts = await this.getMaxBorrowableAmount(params);
622
-
623
- let ltv: number | undefined = undefined;
624
- for (let adapter of this.getVesuAdapters()) {
625
- const maxBorrowableAmount = maxBorrowableAmounts.maxBorrowables.find(b => b.borrowableAsset.address.eq(adapter.config.debt.address))?.amount;
626
- if (!maxBorrowableAmount) {
627
- throw new Error(`Max borrowable amount not found for adapter: ${adapter.config.debt.symbol}`);
627
+ const assetPrice = await this.pricer.getPrice(this.asset().symbol);
628
+ let netAUM = new Web3Number(0, this.asset().decimals);
629
+ for (let position of allPositions) {
630
+ if (position.tokenInfo.address.eq(this.asset().address)) {
631
+ netAUM = netAUM.plus(position.amount);
632
+ } else {
633
+ netAUM = netAUM.plus(position.usdValue / assetPrice.price);
628
634
  }
629
- const maxLTV = await adapter.getLTVConfig(this.config);
630
- if (!ltv) {
631
- ltv = maxLTV;
632
- } else if (ltv != maxLTV) {
633
- throw new Error(`LTV mismatch for adapter: ${adapter.config.debt.symbol}`);
634
- }
635
- }
636
- if (!ltv) {
637
- throw new Error('LTV not found');
638
635
  }
639
- // for simplicity, we assume 1 underlying = 1 LST
640
- const numerator = this.metadata.additionalInfo.targetHealthFactor * maxBorrowableAmounts.netMaxBorrowableAmount.toNumber() / (ltv)
641
- return numerator - maxBorrowableAmounts.netMaxBorrowableAmount.toNumber();
642
- }
643
636
 
644
- // todo revisit cases where 0th adapters is used
645
- protected async getUnusedBalanceAPY() {
646
- const unusedBalance = await this.getUnusedBalance();
647
- const vesuAdapter = this.getVesuSameTokenAdapter();
648
- const underlying = vesuAdapter.config.debt;
649
- const lstAPY = await this.getLSTAPR(underlying.address);
650
- return {
651
- apy: lstAPY, weight: unusedBalance.usdValue
652
- }
653
- }
637
+ const prevAum = await this.getPrevAUM();
638
+ const realAUM: PositionInfo = {
639
+ tokenInfo: this.asset(),
640
+ amount: netAUM,
641
+ usdValue: netAUM.toNumber() * assetPrice.price,
642
+ apy: {apy: netAUM.toNumber() * assetPrice.price, type: APYType.BASE},
643
+ remarks: AUMTypes.FINALISED,
644
+ protocol: Protocols.NONE // just placeholder
645
+ };
654
646
 
655
- async getLSTExchangeRate() {
656
- const vesuAdapter1 = this.getVesuSameTokenAdapter();
657
- const lstTokenInfo = vesuAdapter1.config.collateral;
658
- const lstABI = new Contract({
659
- abi: ERC4626Abi,
660
- address: lstTokenInfo.address.address,
661
- providerOrAccount: this.config.provider
662
- });
647
+ const estimatedAUMDelta: PositionInfo = {
648
+ tokenInfo: this.asset(),
649
+ amount: Web3Number.fromWei('0', this.asset().decimals),
650
+ usdValue: 0,
651
+ apy: {apy: 0, type: APYType.BASE},
652
+ remarks: AUMTypes.DEFISPRING,
653
+ protocol: Protocols.NONE // just placeholder
654
+ };
663
655
 
664
- const price: any = await lstABI.call('convert_to_assets', [uint256.bnToUint256((new Web3Number(1, lstTokenInfo.decimals)).toWei())]);
665
- const exchangeRate = Number(uint256.uint256ToBN(price).toString()) / Math.pow(10, lstTokenInfo.decimals);
666
- logger.verbose(`${this.getTag()}:: LST Exchange Rate: ${exchangeRate}`);
667
- return exchangeRate;
668
- }
656
+ return {net: {
657
+ tokenInfo: this.asset(),
658
+ amount: netAUM,
659
+ usdValue: netAUM.toNumber() * assetPrice.price
660
+ }, prevAum: prevAum, splits: [realAUM, estimatedAUMDelta]};
661
+ }
669
662
 
670
663
  /**
671
664
  *
672
665
  * @param params marginAmount is in LST, debtAmount is in underlying
673
666
  */
674
- async getModifyLeverCall(params: {
675
- marginAmount: Web3Number, // >0 during deposit
676
- debtAmount: Web3Number,
677
- lstDexPriceInUnderlying: number,
678
- isIncrease: boolean,
679
- maxEkuboPriceImpact: number
680
- }): Promise<Call[]> {
681
- logger.verbose(`${this.getTag()}::getModifyLeverCall marginAmount: ${params.marginAmount}, debtAmount: ${params.debtAmount}, lstDexPriceInUnderlying: ${params.lstDexPriceInUnderlying}, isIncrease: ${params.isIncrease}`);
682
- assert(!params.marginAmount.isZero() || !params.debtAmount.isZero(), 'Deposit/debt must be non-0');
683
-
684
- const vesuAdapter1 = this.getVesuSameTokenAdapter();
685
- const lstTokenInfo = this.asset();
686
- const lstUnderlyingTokenInfo = vesuAdapter1.config.debt;
687
-
688
- // todo make it more general
689
- // 500k STRK (~75k$) or 0.5 BTC (~60k$)
690
- const maxAmounts = lstTokenInfo.symbol == 'xSTRK' ? 500000 : 0.5;
691
- if (params.marginAmount.greaterThan(maxAmounts)) {
692
- throw new Error(`Margin amount is greater than max amount: ${params.marginAmount.toNumber()} > ${maxAmounts}`);
693
- }
694
-
695
- const proofsIDs: string[] = [];
696
- const manageCalls: ManageCall[] = [];
697
-
698
- // approve token
699
- if (params.marginAmount.greaterThan(0)) {
700
- const STEP1_ID = LST_MULTIPLIER_MANAGE_IDS.MULTIPLE_APPROVE;
701
- const manage1Info = this.getProofs<ApproveCallParams>(STEP1_ID);
702
- const depositAmount = params.marginAmount;
703
- const manageCall1 = manage1Info.callConstructor({
704
- amount: depositAmount
705
- })
706
- proofsIDs.push(STEP1_ID);
707
- manageCalls.push(manageCall1);
708
- }
709
-
710
- const lstDexPriceInUnderlying = params.lstDexPriceInUnderlying;
711
- const lstTrueExchangeRate = await this.getLSTExchangeRate();
712
- const ekuboQuoter = new EkuboQuoter(this.config);
713
-
714
- // compute quotes for lever swap
715
- const MAX_SLIPPAGE = 0.002;
716
- // when increasing, debt is swapped to collateral (LST)
717
- // when decreasing, collateral is swapped to debt (underlying)
718
- // but both cases, we denominate amount in underlying. negative for decrease (exact amount out)
719
- const fromToken = params.isIncrease ? lstUnderlyingTokenInfo : lstTokenInfo;
720
- const toToken = params.isIncrease ? lstTokenInfo : lstUnderlyingTokenInfo;
721
- const leverSwapQuote = await ekuboQuoter.getQuote(
722
- fromToken.address.address,
723
- toToken.address.address,
724
- params.debtAmount // negative for exact amount out
725
- );
726
- logger.verbose(`${this.getTag()}::getModifyLeverCall leverSwapQuote: ${JSON.stringify(leverSwapQuote)}`);
727
- // Ekubo's price impact can randomly show high numbers sometimes.
728
- assert(leverSwapQuote.price_impact <= params.maxEkuboPriceImpact, 'getIncreaseLeverCall: Price impact is too high [Debt swap]');
729
- const leverSwap = ekuboQuoter.getVesuMultiplyQuote(leverSwapQuote, fromToken, toToken);
730
- logger.verbose(`${this.getTag()}::getModifyLeverCall leverSwap: ${JSON.stringify(leverSwap)}`);
731
-
732
- // todo double check this logic
733
- // is Deposit
734
- let minLSTReceived = params.debtAmount.dividedBy(lstDexPriceInUnderlying).multipliedBy(1 - MAX_SLIPPAGE); // used for increase
735
- const minLSTReceivedAsPerTruePrice = params.debtAmount.dividedBy(lstTrueExchangeRate); // execution output to be <= True LST price
736
- // if (minLSTReceived < minLSTReceivedAsPerTruePrice) {
737
- // minLSTReceived = minLSTReceivedAsPerTruePrice; // the execution shouldn't be bad than True price logi
738
- // }
739
- minLSTReceived = minLSTReceivedAsPerTruePrice; // in any case, we are ok with this, bcz the BTC LST spread shouldnt be high
740
- logger.verbose(`${this.getTag()}::getModifyLeverCall minLSTReceivedAsPerTruePrice: ${minLSTReceivedAsPerTruePrice}, minLSTReceived: ${minLSTReceived}`);
741
-
742
- // is withdraw
743
- let maxUsedCollateral = params.debtAmount.abs().dividedBy(lstDexPriceInUnderlying).multipliedBy(1 + MAX_SLIPPAGE); // +ve for exact amount out, used for decrease
744
- const maxUsedCollateralInLST = params.debtAmount.abs().dividedBy(lstTrueExchangeRate).multipliedBy(1.005); // 0.5% slippage, worst case based on true price
745
- logger.verbose(`${this.getTag()}::getModifyLeverCall maxUsedCollateralInLST: ${maxUsedCollateralInLST}, maxUsedCollateral: ${maxUsedCollateral}`);
746
- // if (maxUsedCollateralInLST > maxUsedCollateral) {
747
- // maxUsedCollateral = maxUsedCollateralInLST;
748
- // }
749
- maxUsedCollateral = maxUsedCollateralInLST; // in any case, we are ok with this, bcz the BTC LST spread shouldnt be high
750
-
751
- const STEP2_ID = LST_MULTIPLIER_MANAGE_IDS.SWITCH_DELEGATION_ON;
752
- const manage2Info = this.getProofs<VesuModifyDelegationCallParams>(STEP2_ID);
753
- const manageCall2 = manage2Info.callConstructor({
754
- delegation: true
755
- });
756
-
757
- // deposit and borrow or repay and withdraw
758
- const STEP3_ID = getVesuLegId(LST_MULTIPLIER_MANAGE_IDS.MULTIPLY_VESU, vesuAdapter1.config.debt.symbol);
759
- const manage3Info = this.getProofs<VesuMultiplyCallParams>(STEP3_ID);
760
- const multiplyParams: VesuMultiplyCallParams = params.isIncrease ? {
761
- isIncrease: true,
762
- increaseParams: {
763
- add_margin: params.marginAmount,
764
- margin_swap: [],
765
- margin_swap_limit_amount: Web3Number.fromWei(0, this.asset().decimals),
766
- lever_swap: leverSwap,
767
- lever_swap_limit_amount: minLSTReceived
768
- }
769
- } : {
770
- isIncrease: false,
771
- decreaseParams: {
772
- sub_margin: params.marginAmount.multipliedBy(-1),
773
- lever_swap: leverSwap,
774
- lever_swap_limit_amount: maxUsedCollateral,
775
- // only required for close position
776
- lever_swap_weights: [],
777
- // no need to swap collateral to anything, and any residuals return our contract anyways.
778
- withdraw_swap: [],
779
- withdraw_swap_limit_amount: Web3Number.fromWei(0, this.asset().decimals),
780
- withdraw_swap_weights: [],
781
- close_position: false
782
- }
783
- }
784
- const manageCall3 = manage3Info.callConstructor(multiplyParams);
785
-
786
- // switch delegation off
787
- const STEP4_ID = LST_MULTIPLIER_MANAGE_IDS.SWITCH_DELEGATION_OFF;
788
- const manage4Info = this.getProofs<VesuModifyDelegationCallParams>(STEP4_ID);
789
- const manageCall4 = manage4Info.callConstructor({
790
- delegation: false
791
- });
792
-
793
- proofsIDs.push(STEP2_ID, STEP3_ID, STEP4_ID);
794
- manageCalls.push(manageCall2, manageCall3, manageCall4);
795
-
796
- return [this.getManageCall(proofsIDs, manageCalls)];
797
- }
667
+ // async getModifyLeverCall(params: {
668
+ // marginAmount: Web3Number, // >0 during deposit
669
+ // debtAmount: Web3Number,
670
+ // lstDexPriceInUnderlying: number,
671
+ // isIncrease: boolean
672
+ // }): Promise<Call[]> {
673
+ // logger.verbose(`${this.getTag()}::getModifyLeverCall marginAmount: ${params.marginAmount}, debtAmount: ${params.debtAmount}, lstDexPriceInUnderlying: ${params.lstDexPriceInUnderlying}, isIncrease: ${params.isIncrease}`);
674
+
675
+ // const vesuAdapter = this.getVesuSameTokenAdapter();
676
+ // const manage0Info = vesuAdapter.
677
+ // const manageCall0 = manage0Info.callConstructor({
678
+ // amount: newDepositAmount
679
+ // });
680
+ // const manageCalls = await vesu
681
+ // return [this.getManageCall(proofsIDs, manageCalls)];
682
+ // }
798
683
  }
799
684
 
800
685
  export default function VaultDescription(
@@ -831,7 +716,7 @@ export default function VaultDescription(
831
716
  </div>
832
717
  <div style={{ backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }}>
833
718
  <p style={{ fontSize: "13px", color: "#ccc" }}>
834
- <strong>Debt limits:</strong> Pools on Vesu have debt caps that are gradually increased over time. Until caps are raised, deposited LSTs remain in the vault, generating a shared net return for all depositors. There is no additional fee taken by Troves on LST APY, its only on added gain.
719
+ <strong>Debt limits:</strong> Pools on Vesu have debt caps that are gradually increased over time. Until caps are raised, deposited Tokens remain in the vault, generating a shared net return for all depositors. There is no additional fee taken by Troves on Yield token's APY, its only on added gain.
835
720
  </p>
836
721
  </div>
837
722
  {/* <div style={{ backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }}>
@@ -879,86 +764,72 @@ function getLooperSettings(
879
764
  const lstToken = Global.getDefaultTokens().find(token => token.symbol === lstSymbol)!;
880
765
  const underlyingToken = Global.getDefaultTokens().find(token => token.symbol === underlyingSymbol)!;
881
766
 
882
- const vesuAdapterLST = new VesuAdapter({
883
- poolId: pool1,
884
- collateral: lstToken,
885
- debt: underlyingToken,
767
+ const baseAdapterConfig: BaseAdapterConfig = {
768
+ baseToken: lstToken,
769
+ supportedPositions: [{asset: lstToken, isDebt: false}],
770
+ networkConfig: getMainnetConfig(),
771
+ pricer: new PricerFromApi(getMainnetConfig(), Global.getDefaultTokens()),
886
772
  vaultAllocator: vaultSettings.vaultAllocator,
887
- id: getVesuLegId(UNIVERSAL_MANAGE_IDS.VESU_LEG1, underlyingToken.symbol)
773
+ vaultAddress: vaultSettings.vaultAddress
774
+ }
775
+ const vesuAdapterLST = new VesuSupplyOnlyAdapter({
776
+ // xWBTC vToken on re7 xBTC pool
777
+ vTokenContract: ContractAddr.from('0x062a162d0827db6f43ebb850cbef3c99fc7969e3070b83a2236c9f3713c89fd8'),
778
+ ...baseAdapterConfig,
888
779
  })
889
780
 
781
+ const vesuMultiplyAdapters = borrowableAssets.map(position => new VesuMultiplyAdapter({
782
+ poolId: pool1,
783
+ collateral: lstToken,
784
+ debt: Global.getDefaultTokens().find(token => token.symbol === position)!,
785
+ targetHealthFactor: vaultSettings.targetHealthFactor,
786
+ minHealthFactor: vaultSettings.minHealthFactor,
787
+ quoteAmountToFetchPrice: vaultSettings.quoteAmountToFetchPrice,
788
+ ...baseAdapterConfig,
789
+ supportedPositions: [{asset: lstToken, isDebt: false}, {asset: Global.getDefaultTokens().find(token => token.symbol === position)!, isDebt: true}]
790
+ }));
791
+
792
+ const unusedBalanceAdapter = new UnusedBalanceAdapter({
793
+ ...baseAdapterConfig,
794
+ });
795
+
796
+ vaultSettings.adapters.push({id: `${vesuAdapterLST.name}_${lstToken.symbol}_${underlyingToken.symbol}`, adapter: vesuAdapterLST});
797
+ vesuMultiplyAdapters.map(adapter => vaultSettings.adapters.push({id: `${adapter.name}_${lstToken.symbol}_${underlyingToken.symbol}`, adapter: adapter}));
798
+ vaultSettings.adapters.push({id: `${unusedBalanceAdapter.name}_${lstToken.symbol}`, adapter: unusedBalanceAdapter});
799
+
890
800
  const commonAdapter = new CommonAdapter({
891
- manager: vaultSettings.manager,
892
- asset: lstToken.address,
893
- id: '',
801
+ id: UNIVERSAL_MANAGE_IDS.FLASH_LOAN,
894
802
  vaultAddress: vaultSettings.vaultAddress,
895
803
  vaultAllocator: vaultSettings.vaultAllocator,
804
+ manager: vaultSettings.manager,
805
+ asset: lstToken.address
896
806
  })
897
807
 
898
- // Useful for returning adapter class objects that can compute
899
- // certain things for us (e.g. positions, hfs)
900
- vaultSettings.adapters.push(...[{
901
- id: getVesuLegId(UNIVERSAL_MANAGE_IDS.VESU_LEG1, underlyingToken.symbol),
902
- adapter: vesuAdapterLST
903
- },{
904
- id: UNIVERSAL_ADAPTERS.COMMON,
905
- adapter: commonAdapter
906
- }])
907
-
908
- // avnu multiply
909
- const { isV2, addr:poolAddr } = getVesuSingletonAddress(pool1);
910
- // vesu multiply looping
911
- const VESU_MULTIPLY = isV2 ? vesuAdapterLST.VESU_MULTIPLY : vesuAdapterLST.VESU_MULTIPLY_V1;
912
- vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, VESU_MULTIPLY, LST_MULTIPLIER_MANAGE_IDS.MULTIPLE_APPROVE).bind(commonAdapter));
913
- vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter(LST_MULTIPLIER_MANAGE_IDS.SWITCH_DELEGATION_ON).bind(vesuAdapterLST));
914
- vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter(LST_MULTIPLIER_MANAGE_IDS.SWITCH_DELEGATION_OFF).bind(vesuAdapterLST));
915
-
916
- // approve lst once to avnu
917
- vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, AVNU_EXCHANGE, LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_APPROVE_WITHDRAW).bind(commonAdapter));
918
- for (let borrowableAsset of vaultSettings.borrowable_assets) {
919
- // in-efficient avnu swap looping (but good with endur integration)
920
- const debtAsset = borrowableAsset;
921
- const approve_debt_token_id = getAvnuManageIDs(LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_APPROVE_DEPOSIT, debtAsset.symbol);
922
- const swap_debt_token_id = getAvnuManageIDs(LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_SWAP_DEPOSIT, debtAsset.symbol);
923
- const swap_lst_token_id = getAvnuManageIDs(LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_SWAP_WITHDRAW, debtAsset.symbol);
924
- vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(debtAsset.address, AVNU_EXCHANGE, approve_debt_token_id).bind(commonAdapter));
925
- vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(debtAsset.address, lstToken.address, swap_debt_token_id, false).bind(commonAdapter));
926
- vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(lstToken.address, debtAsset.address, swap_lst_token_id, false).bind(commonAdapter));
927
-
928
- // approve LST to add collateral
929
- const vesuAdapter = new VesuAdapter({
930
- poolId: pool1,
931
- collateral: lstToken,
932
- debt: debtAsset,
933
- vaultAllocator: vaultSettings.vaultAllocator,
934
- id: getVesuLegId(UNIVERSAL_MANAGE_IDS.VESU_LEG1, debtAsset.symbol)
935
- });
936
- vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, poolAddr, UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN1).bind(commonAdapter));
937
- vaultSettings.leafAdapters.push(vesuAdapter.getModifyPosition.bind(vesuAdapter));
938
-
939
- // Vesu multiply
940
- const multiplID = getVesuLegId(LST_MULTIPLIER_MANAGE_IDS.MULTIPLY_VESU, debtAsset.symbol);
941
- vaultSettings.leafAdapters.push(vesuAdapter.getMultiplyAdapter(multiplID).bind(vesuAdapter));
942
- }
808
+ // push vesu adapter to leaf adapters
809
+ vaultSettings.leafAdapters.push(() => vesuAdapterLST.getDepositLeaf());
810
+ vaultSettings.leafAdapters.push(() => vesuAdapterLST.getWithdrawLeaf());
943
811
 
812
+ // push vesu multiply adapter to leaf adapters
813
+ vesuMultiplyAdapters.map(adapter => vaultSettings.leafAdapters.push(() => adapter.getDepositLeaf()));
814
+ vesuMultiplyAdapters.map(adapter => vaultSettings.leafAdapters.push(() => adapter.getWithdrawLeaf()));
944
815
 
945
816
  // to bridge liquidity back to vault (used by bring_liquidity)
946
817
  vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, vaultSettings.vaultAddress, UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY).bind(commonAdapter));
947
818
  vaultSettings.leafAdapters.push(commonAdapter.getBringLiquidityAdapter(UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY).bind(commonAdapter));
948
819
 
949
820
  // claim rewards
950
- vaultSettings.leafAdapters.push(vesuAdapterLST.getDefispringRewardsAdapter(UNIVERSAL_MANAGE_IDS.DEFISPRING_REWARDS).bind(vesuAdapterLST));
821
+ // vaultSettings.leafAdapters.push(vesuAdapterLST.getDefispringRewardsAdapter(UNIVERSAL_MANAGE_IDS.DEFISPRING_REWARDS).bind(vesuAdapterLST));
951
822
 
952
- // avnu swap for claims rewards
953
- const STRKToken = Global.getDefaultTokens().find(token => token.symbol === 'STRK')!;
954
- vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(STRKToken.address, AVNU_EXCHANGE, UNIVERSAL_MANAGE_IDS.APPROVE_SWAP_TOKEN1).bind(commonAdapter));
955
- vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(STRKToken.address, lstToken.address, UNIVERSAL_MANAGE_IDS.AVNU_SWAP_REWARDS, false).bind(commonAdapter));
823
+ // // avnu swap for claims rewards
824
+ // const STRKToken = Global.getDefaultTokens().find(token => token.symbol === 'STRK')!;
825
+ // vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(STRKToken.address, AVNU_EXCHANGE, UNIVERSAL_MANAGE_IDS.APPROVE_SWAP_TOKEN1).bind(commonAdapter));
826
+ // vabaseAdapterConfigultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(STRKToken.address, lstToken.address, UNIVERSAL_MANAGE_IDS.AVNU_SWAP_REWARDS, false).bind(commonAdapter));
956
827
  return vaultSettings;
957
828
  }
958
829
 
959
- const AUDIT_URL = 'https://docs.troves.fi/p/security#starknet-vault-kit'
830
+ export const AUDIT_URL = 'https://docs.troves.fi/p/security#starknet-vault-kit'
960
831
 
961
- function getFAQs(lstSymbol: string, underlyingSymbol: string): FAQ[] {
832
+ export function getFAQs(lstSymbol: string, underlyingSymbol: string, isLST: boolean): FAQ[] {
962
833
  return [
963
834
  {
964
835
  question: `What is the Hyper ${lstSymbol} Vault?`,
@@ -972,10 +843,14 @@ function getFAQs(lstSymbol: string, underlyingSymbol: string): FAQ[] {
972
843
  },
973
844
  {
974
845
  question: "Which protocols/dApp are used??",
975
- answer: (
846
+ answer: isLST ? (
976
847
  <span>
977
848
  Currently, the LST is from <strong>Endur</strong> while <strong>Vesu</strong> is used to collateralize the looped position.
978
849
  </span>
850
+ ) : (
851
+ <span>
852
+ Currently, the Yield Token is from <strong>Re7 Labs (Midas)</strong> while <strong>Vesu</strong> is used to collateralize the looped position.
853
+ </span>
979
854
  ),
980
855
  },
981
856
  {
@@ -993,14 +868,14 @@ function getFAQs(lstSymbol: string, underlyingSymbol: string): FAQ[] {
993
868
  "Withdrawals may take up to 1-2 hours to process, as the vault unwinds and settles liquidity routing across integrated protocols. In case of large withdrawals, to avoid slippage, we may slowly unwind the position, which could make the withdrawals longer.",
994
869
  },
995
870
  {
996
- question: "Is the Hyper xSTRK Vault non-custodial?",
871
+ question: `Is the Hyper ${lstSymbol} Vault non-custodial?`,
997
872
  answer:
998
- "Yes. The Hyper xSTRK Vault operates entirely on-chain. Users always maintain control of their vault tokens, and the strategy is fully transparent.",
873
+ `Yes. The Hyper ${lstSymbol} Vault operates entirely on-chain. Users always maintain control of their vault tokens, and the strategy is fully transparent.`,
999
874
  },
1000
875
  {
1001
876
  question: "Is the Vault audited?",
1002
877
  answer:
1003
- "Yes. The Hyper xSTRK Vault is audited by Zellic. Look for safety icon beside the strategy name for more details.",
878
+ `Yes. The Hyper ${lstSymbol} Vault is audited by Zellic. Look for safety icon beside the strategy name for more details.`,
1004
879
  },
1005
880
  {
1006
881
  question: "Are there any fees?",
@@ -1010,7 +885,7 @@ function getFAQs(lstSymbol: string, underlyingSymbol: string): FAQ[] {
1010
885
  ];
1011
886
  }
1012
887
 
1013
- const _riskFactor: RiskFactor[] = [
888
+ export const _riskFactor: RiskFactor[] = [
1014
889
  { type: RiskType.SMART_CONTRACT_RISK, value: SmartContractRiskLevel.WELL_AUDITED, weight: 25, reason: "Audited by Zellic" },
1015
890
  { type: RiskType.LIQUIDATION_RISK, value: LiquidationRiskLevel.VERY_LOW_PROBABILITY, weight: 25, reason: "The collateral and debt are highly correlated" },
1016
891
  { type: RiskType.TECHNICAL_RISK, value: TechnicalRiskLevel.STABLE_INFRASTRUCTURE, weight: 25, reason: "Liquidation can only happen if vault is left un-monitored for weeks, which is highly unlikely. We actively monitor all services on a daily basis." },
@@ -1033,6 +908,7 @@ const hyperxSTRK: HyperLSTStrategySettings = {
1033
908
  minHealthFactor: 1.05,
1034
909
  borrowable_assets: Global.getDefaultTokens().filter(token => token.symbol === 'STRK'),
1035
910
  underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'STRK')!,
911
+ quoteAmountToFetchPrice: new Web3Number('100', Global.getDefaultTokens().find(token => token.symbol === 'STRK')!.decimals),
1036
912
  }
1037
913
 
1038
914
  const hyperxWBTC: HyperLSTStrategySettings = {
@@ -1047,6 +923,7 @@ const hyperxWBTC: HyperLSTStrategySettings = {
1047
923
  minHealthFactor: 1.05,
1048
924
  borrowable_assets: borrowableAssets.map(asset => Global.getDefaultTokens().find(token => token.symbol === asset)!),
1049
925
  underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'WBTC')!,
926
+ quoteAmountToFetchPrice: new Web3Number('0.001', Global.getDefaultTokens().find(token => token.symbol === 'WBTC')!.decimals),
1050
927
  }
1051
928
 
1052
929
  const hyperxtBTC: HyperLSTStrategySettings = {
@@ -1059,8 +936,9 @@ const hyperxtBTC: HyperLSTStrategySettings = {
1059
936
  adapters: [],
1060
937
  targetHealthFactor: 1.1,
1061
938
  minHealthFactor: 1.05,
1062
- borrowable_assets: Global.getDefaultTokens().filter(token => token.symbol === 'tBTC' || token.symbol === 'WBTC'),
939
+ borrowable_assets: borrowableAssets.map(asset => Global.getDefaultTokens().find(token => token.symbol === asset)!),
1063
940
  underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'tBTC')!,
941
+ quoteAmountToFetchPrice: new Web3Number('0.001', Global.getDefaultTokens().find(token => token.symbol === 'tBTC')!.decimals),
1064
942
  }
1065
943
 
1066
944
  const hyperxsBTC: HyperLSTStrategySettings = {
@@ -1073,8 +951,9 @@ const hyperxsBTC: HyperLSTStrategySettings = {
1073
951
  adapters: [],
1074
952
  targetHealthFactor: 1.1,
1075
953
  minHealthFactor: 1.05,
1076
- borrowable_assets: Global.getDefaultTokens().filter(token => token.symbol === 'solvBTC'),
954
+ borrowable_assets: borrowableAssets.map(asset => Global.getDefaultTokens().find(token => token.symbol === asset)!),
1077
955
  underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'solvBTC')!,
956
+ quoteAmountToFetchPrice: new Web3Number('0.001', Global.getDefaultTokens().find(token => token.symbol === 'solvBTC')!.decimals),
1078
957
  }
1079
958
 
1080
959
  const hyperxLBTC: HyperLSTStrategySettings = {
@@ -1087,21 +966,56 @@ const hyperxLBTC: HyperLSTStrategySettings = {
1087
966
  adapters: [],
1088
967
  targetHealthFactor: 1.1,
1089
968
  minHealthFactor: 1.05,
1090
- borrowable_assets: Global.getDefaultTokens().filter(token => token.symbol === 'LBTC'),
969
+ borrowable_assets: borrowableAssets.map(asset => Global.getDefaultTokens().find(token => token.symbol === asset)!),
1091
970
  underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'LBTC')!,
971
+ quoteAmountToFetchPrice: new Web3Number('0.001', Global.getDefaultTokens().find(token => token.symbol === 'LBTC')!.decimals),
1092
972
  }
1093
973
 
1094
- function getInvestmentSteps(lstSymbol: string, underlyingSymbol: string) {
974
+ const hypermRe7BTC: HyperLSTStrategySettings = {
975
+ vaultAddress: ContractAddr.from('0x6c89b75d09de82477edb86b2c2918cfc1a5dc0177cfbdea46278386b6499645'),
976
+ manager: ContractAddr.from('0x7bc2d0535e13352d3ab78ea047616a3162068294297304943d2302122a150a1'),
977
+ vaultAllocator: ContractAddr.from('0x760f9cebca9d2ee624f4224591da6da8b3ea5fd2410590735709551bd4e7570'),
978
+ redeemRequestNFT: ContractAddr.from('0x5e045ae0160f7650f8a4dd7c826f25630a89fe62434db4441e7e0075608180f'),
979
+ aumOracle: ContractAddr.from('0x3958df341b838813c24efb9183c23bddd1c57d44b1b86c0dd57f67887b89fba'),
980
+ leafAdapters: [],
981
+ adapters: [],
982
+ targetHealthFactor: 1.1,
983
+ minHealthFactor: 1.05,
984
+ borrowable_assets: borrowableAssets.map(asset => Global.getDefaultTokens().find(token => token.symbol === asset)!),
985
+ underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'WBTC')!,
986
+ quoteAmountToFetchPrice: new Web3Number('0.001', Global.getDefaultTokens().find(token => token.symbol === 'mRe7BTC')!.decimals),
987
+ }
988
+ // Contract deployed: Vault, addr: 0x42797ab4eb1f72787442e91a73d63a39e3a141c1106470a946ecc328db6896c
989
+ // Contract deployed: RedeemRequest, addr: 0x4bbb25c2568af07967342833f7db1aece1be1be2330798dab4ee585aa6c2c72
990
+ // Contract deployed: VaultAllocator, addr: 0x456c4c6afca90512aeb5c735d84405fea6e51ab06d1851ac8cdb0a235e14f15
991
+ // Contract deployed: Manager, addr: 0x435b45d40fbb406cf69ac84bb471e7b7a4ea2295d0893c05dd2db565295e77f
992
+
993
+ const hypermRe7YIELD: HyperLSTStrategySettings = {
994
+ vaultAddress: ContractAddr.from('0x42797ab4eb1f72787442e91a73d63a39e3a141c1106470a946ecc328db6896c'),
995
+ manager: ContractAddr.from('0x435b45d40fbb406cf69ac84bb471e7b7a4ea2295d0893c05dd2db565295e77f'),
996
+ vaultAllocator: ContractAddr.from('0x456c4c6afca90512aeb5c735d84405fea6e51ab06d1851ac8cdb0a235e14f15'),
997
+ redeemRequestNFT: ContractAddr.from('0x4bbb25c2568af07967342833f7db1aece1be1be2330798dab4ee585aa6c2c72'),
998
+ aumOracle: ContractAddr.from('0x3e1f2825158cafccc9b42a8165d17ceb6b8e966474d9c63587d338746888382'),
999
+ leafAdapters: [],
1000
+ adapters: [],
1001
+ targetHealthFactor: 1.1,
1002
+ minHealthFactor: 1.05,
1003
+ borrowable_assets: [Global.getDefaultTokens().find(token => token.symbol === 'USDC')!],
1004
+ underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'USDC')!,
1005
+ quoteAmountToFetchPrice: new Web3Number('0.001', Global.getDefaultTokens().find(token => token.symbol === 'mRe7BTC')!.decimals),
1006
+ }
1007
+
1008
+ export function getInvestmentSteps(lstSymbol: string, underlyingSymbol: string) {
1095
1009
  return [
1096
1010
  `Deposit ${lstSymbol} into the vault`,
1097
1011
  `The vault manager loops the ${underlyingSymbol} to buy ${lstSymbol}`,
1098
1012
  `The vault manager collateralizes the ${lstSymbol} on Vesu`,
1099
1013
  `The vault manager borrows more ${underlyingSymbol} to loop further`,
1100
- `If required, adjust leverage or re-allocate assets within LST pool on Vesu to optimize yield`
1014
+ `If required, adjust leverage or re-allocate assets within pool on Vesu to optimize yield`
1101
1015
  ]
1102
1016
  }
1103
1017
 
1104
- function getStrategySettings(lstSymbol: string, underlyingSymbol: string, addresses: HyperLSTStrategySettings, isPreview: boolean = false): IStrategyMetadata<HyperLSTStrategySettings> {
1018
+ function getStrategySettings(lstSymbol: string, underlyingSymbol: string, addresses: HyperLSTStrategySettings, isPreview: boolean = false, isLST: boolean): IStrategyMetadata<HyperLSTStrategySettings> {
1105
1019
  return {
1106
1020
  name: `Hyper ${lstSymbol}`,
1107
1021
  description: getDescription(lstSymbol, underlyingSymbol),
@@ -1121,18 +1035,37 @@ function getStrategySettings(lstSymbol: string, underlyingSymbol: string, addres
1121
1035
  protocols: [Protocols.ENDUR, Protocols.VESU],
1122
1036
  maxTVL: Web3Number.fromWei(0, 18),
1123
1037
  contractDetails: getContractDetails(addresses),
1124
- faqs: getFAQs(lstSymbol, underlyingSymbol),
1038
+ faqs: getFAQs(lstSymbol, underlyingSymbol, isLST),
1125
1039
  investmentSteps: getInvestmentSteps(lstSymbol, underlyingSymbol),
1126
1040
  isPreview: isPreview,
1127
- apyMethodology: 'Current annualized APY in terms of base asset of the LST. There is no additional fee taken by Troves on LST APY. We charge a 10% performance fee on the additional gain which is already accounted in the APY shown.'
1041
+ apyMethodology: isLST ? 'Current annualized APY in terms of base asset of the LST. There is no additional fee taken by Troves on LST APY. We charge a 10% performance fee on the additional gain which is already accounted in the APY shown.' : 'Current annualized APY in terms of base asset of the Yield Token. There is no additional fee taken by Troves on yield token APY. We charge a 10% performance fee on the additional gain which is already accounted in the APY shown.'
1128
1042
  }
1129
1043
  }
1130
1044
 
1045
+
1046
+
1047
+ // const hyperxWBTCTest: HyperLSTStrategySettings = {
1048
+ // vaultAddress: ContractAddr.from('0x5535e01a0d0438a888267ba6cd6519a40e653cdfb5dce4af475221d9cf11e63'),
1049
+ // manager: ContractAddr.from('0x3caa816a9d9b55a6621a47c1a7e6773141dd05fb3ca4ec4b774656f360b32a1'),
1050
+ // vaultAllocator: ContractAddr.from('0x3d4f82f8bfa8e5b2f0242c4d8ed87287c9ad5427be8b982a31a0393cf3075d1'),
1051
+ // redeemRequestNFT: ContractAddr.from('0x6190460d0f1fd5d142bd5378d7b3270e70253bdd652d6826175f6c0b1ad4f32'),
1052
+ // aumOracle: ContractAddr.from('0x43f5aa7c67b29b5e69ad03ab427f7613e43350d6ddede481e42e8184f49cb2f'),
1053
+ // leafAdapters: [],
1054
+ // adapters: [],
1055
+ // targetHealthFactor: 1.1,
1056
+ // minHealthFactor: 1.05,
1057
+ // borrowable_assets: borrowableAssets.map(asset => Global.getDefaultTokens().find(token => token.symbol === asset)!),
1058
+ // underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'WBTC')!,
1059
+ // quoteAmountToFetchPrice: new Web3Number('0.001', Global.getDefaultTokens().find(token => token.symbol === 'WBTC')!.decimals),
1060
+ // }
1061
+
1131
1062
  export const HyperLSTStrategies: IStrategyMetadata<HyperLSTStrategySettings>[] =
1132
1063
  [
1133
- getStrategySettings('xSTRK', 'STRK', hyperxSTRK, false),
1134
- getStrategySettings('xWBTC', 'WBTC', hyperxWBTC, false),
1135
- getStrategySettings('xtBTC', 'tBTC', hyperxtBTC, false),
1136
- getStrategySettings('xsBTC', 'solvBTC', hyperxsBTC, false),
1137
- getStrategySettings('xLBTC', 'LBTC', hyperxLBTC, false),
1064
+ getStrategySettings('xSTRK', 'STRK', hyperxSTRK, false, true),
1065
+ getStrategySettings('xWBTC', 'WBTC', hyperxWBTC, false, false),
1066
+ getStrategySettings('xtBTC', 'tBTC', hyperxtBTC, false, false),
1067
+ getStrategySettings('xsBTC', 'solvBTC', hyperxsBTC, false, false),
1068
+ getStrategySettings('xLBTC', 'LBTC', hyperxLBTC, false, false),
1069
+ getStrategySettings('mRe7BTC', 'mRe7BTC', hypermRe7BTC, false, false),
1070
+ getStrategySettings('mRe7YIELD', 'mRe7YIELD', hypermRe7YIELD, false, false),
1138
1071
  ]