@strkfarm/sdk 2.0.0-staging.23 → 2.0.0-staging.25

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.
@@ -1,12 +1,62 @@
1
- import { FAQ, getNoRiskTags, highlightTextWithLinks, IConfig, IStrategyMetadata, Protocols, RiskFactor, RiskType, StrategyTag, TokenInfo, AuditStatus, SourceCodeType, AccessControlType, InstantWithdrawalVault, StrategyLiveStatus, StrategySettings, VaultType, RedemptionInfo } from "@/interfaces";
2
- import { AUMTypes, getContractDetails, UNIVERSAL_ADAPTERS, UNIVERSAL_MANAGE_IDS, UniversalManageCall, UniversalStrategy, UniversalStrategySettings } from "./universal-strategy";
1
+ import {
2
+ FAQ,
3
+ getNoRiskTags,
4
+ highlightTextWithLinks,
5
+ IConfig,
6
+ IStrategyMetadata,
7
+ Protocols,
8
+ RiskFactor,
9
+ RiskType,
10
+ StrategyTag,
11
+ TokenInfo,
12
+ AuditStatus,
13
+ SourceCodeType,
14
+ AccessControlType,
15
+ InstantWithdrawalVault,
16
+ StrategyLiveStatus,
17
+ StrategySettings,
18
+ VaultType,
19
+ RedemptionInfo,
20
+ } from "@/interfaces";
21
+ import {
22
+ AUMTypes,
23
+ getContractDetails,
24
+ UNIVERSAL_ADAPTERS,
25
+ UNIVERSAL_MANAGE_IDS,
26
+ UniversalManageCall,
27
+ UniversalStrategy,
28
+ UniversalStrategySettings,
29
+ } from "./universal-strategy";
3
30
  import { PricerBase } from "@/modules/pricerBase";
4
31
  import { ContractAddr, Web3Number } from "@/dataTypes";
5
32
  import { Global } from "@/global";
6
- import { ApproveCallParams, AvnuSwapCallParams, CommonAdapter, getVesuSingletonAddress, ManageCall, Swap, VesuAdapter, VesuModifyDelegationCallParams, VesuModifyPositionCallParams, VesuMultiplyCallParams, VesuPools } from "./universal-adapters";
33
+ import {
34
+ ApproveCallParams,
35
+ AvnuSwapCallParams,
36
+ CommonAdapter,
37
+ getVesuSingletonAddress,
38
+ ManageCall,
39
+ Swap,
40
+ VesuAdapter,
41
+ VesuModifyDelegationCallParams,
42
+ VesuModifyPositionCallParams,
43
+ VesuMultiplyCallParams,
44
+ VesuPools,
45
+ } from "./universal-adapters";
7
46
  import { AVNU_EXCHANGE } from "./universal-adapters/adapter-utils";
8
- import { DepegRiskLevel, LiquidationRiskLevel, SmartContractRiskLevel, TechnicalRiskLevel } from "@/interfaces/risks";
9
- import { AvnuWrapper, EkuboQuoter, ERC20, LSTAPRService, PricerLST } from "@/modules";
47
+ import {
48
+ DepegRiskLevel,
49
+ LiquidationRiskLevel,
50
+ SmartContractRiskLevel,
51
+ TechnicalRiskLevel,
52
+ } from "@/interfaces/risks";
53
+ import {
54
+ AvnuWrapper,
55
+ EkuboQuoter,
56
+ ERC20,
57
+ LSTAPRService,
58
+ PricerLST,
59
+ } from "@/modules";
10
60
  import { assert, logger } from "@/utils";
11
61
  import { SingleTokenInfo } from "./base-strategy";
12
62
  import { Call, Contract, uint256 } from "starknet";
@@ -16,30 +66,40 @@ import { findMaxInputWithSlippage } from "@/utils/math-utils";
16
66
  import { LSTPriceType } from "./types";
17
67
 
18
68
  export interface HyperLSTStrategySettings extends UniversalStrategySettings {
19
- borrowable_assets: { token: TokenInfo, poolId: ContractAddr }[];
69
+ borrowable_assets: { token: TokenInfo; poolId: ContractAddr }[];
20
70
  underlyingToken: TokenInfo;
21
71
  defaultPoolId: ContractAddr;
22
72
  }
23
73
 
24
74
  export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTStrategySettings> {
25
-
26
75
  private quoteAmountToFetchPrice = new Web3Number(1, 18);
27
-
28
- constructor(config: IConfig, pricer: PricerBase, metadata: IStrategyMetadata<HyperLSTStrategySettings>) {
76
+
77
+ constructor(
78
+ config: IConfig,
79
+ pricer: PricerBase,
80
+ metadata: IStrategyMetadata<HyperLSTStrategySettings>,
81
+ ) {
29
82
  super(config, pricer, metadata);
30
83
 
31
- const STRKToken = Global.getDefaultTokens().find(token => token.symbol === 'STRK')!;
84
+ const STRKToken = Global.getDefaultTokens().find(
85
+ (token) => token.symbol === "STRK",
86
+ )!;
32
87
  const underlyingToken = this.getLSTUnderlyingTokenInfo();
33
88
  if (underlyingToken.address.eq(STRKToken.address)) {
34
89
  this.quoteAmountToFetchPrice = new Web3Number(100, 18);
35
90
  } else {
36
91
  // else this BTC
37
- this.quoteAmountToFetchPrice = new Web3Number(0.01, this.asset().decimals);
92
+ this.quoteAmountToFetchPrice = new Web3Number(
93
+ 0.01,
94
+ this.asset().decimals,
95
+ );
38
96
  }
39
97
  }
40
98
 
41
99
  asset() {
42
- return this.getVesuSameTokenAdapter(this.metadata.additionalInfo.defaultPoolId).config.collateral;
100
+ return this.getVesuSameTokenAdapter(
101
+ this.metadata.additionalInfo.defaultPoolId,
102
+ ).config.collateral;
43
103
  }
44
104
 
45
105
  getTag() {
@@ -48,7 +108,13 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
48
108
 
49
109
  // Vesu adapter with LST and base token match
50
110
  getVesuSameTokenAdapter(poolId: ContractAddr) {
51
- const baseAdapter = this.getAdapter(getVesuLegId(UNIVERSAL_MANAGE_IDS.VESU_LEG1, this.metadata.additionalInfo.underlyingToken.symbol, poolId.toString())) as VesuAdapter;
111
+ const baseAdapter = this.getAdapter(
112
+ getVesuLegId(
113
+ UNIVERSAL_MANAGE_IDS.VESU_LEG1,
114
+ this.metadata.additionalInfo.underlyingToken.symbol,
115
+ poolId.toString(),
116
+ ),
117
+ ) as VesuAdapter;
52
118
  baseAdapter.networkConfig = this.config;
53
119
  baseAdapter.pricer = this.pricer;
54
120
  return baseAdapter;
@@ -58,7 +124,8 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
58
124
  // todo support lending assets of underlying as well (like if xSTRK looping is not viable, simply supply STRK)
59
125
  getVesuAdapters() {
60
126
  const adapters: VesuAdapter[] = [];
61
- for (const borrowableInfo of this.metadata.additionalInfo.borrowable_assets) {
127
+ for (const borrowableInfo of this.metadata.additionalInfo
128
+ .borrowable_assets) {
62
129
  // do not add adapter if the pool id does not match
63
130
  const asset = borrowableInfo.token;
64
131
  const poolId = borrowableInfo.poolId;
@@ -67,8 +134,8 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
67
134
  collateral: this.asset(),
68
135
  debt: asset,
69
136
  vaultAllocator: this.metadata.additionalInfo.vaultAllocator,
70
- id: ''
71
- })
137
+ id: "",
138
+ });
72
139
  vesuAdapter1.pricer = this.pricer;
73
140
  vesuAdapter1.networkConfig = this.config;
74
141
  adapters.push(vesuAdapter1);
@@ -80,7 +147,7 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
80
147
  // No rewards on collateral or borrowing of LST assets
81
148
  protected async getRewardsAUM(prevAum: Web3Number): Promise<Web3Number> {
82
149
  const lstToken = this.asset();
83
- if (lstToken.symbol === 'xSTRK') {
150
+ if (lstToken.symbol === "xSTRK") {
84
151
  return super.getRewardsAUM(prevAum);
85
152
  }
86
153
  return Web3Number.fromWei("0", lstToken.decimals);
@@ -93,110 +160,163 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
93
160
  const quote = await ekuboQuoter.getQuote(
94
161
  lstTokenInfo.address.address,
95
162
  lstUnderlyingTokenInfo.address.address,
96
- this.quoteAmountToFetchPrice
163
+ this.quoteAmountToFetchPrice,
97
164
  );
98
165
 
99
166
  // in Underlying
100
- const outputAmount = Web3Number.fromWei(quote.total_calculated, lstUnderlyingTokenInfo.decimals);
101
- const price = outputAmount.toNumber() / this.quoteAmountToFetchPrice.toNumber();
167
+ const outputAmount = Web3Number.fromWei(
168
+ quote.total_calculated,
169
+ lstUnderlyingTokenInfo.decimals,
170
+ );
171
+ const price =
172
+ outputAmount.toNumber() / this.quoteAmountToFetchPrice.toNumber();
102
173
  logger.verbose(`${this.getTag()}:: LST Dex Price: ${price}`);
103
174
  return price;
104
175
  }
105
176
 
106
-
107
177
  async getAvnuSwapMultiplyCall(params: {
108
- isDeposit: boolean,
109
- leg1DepositAmount: Web3Number
178
+ isDeposit: boolean;
179
+ leg1DepositAmount: Web3Number;
110
180
  }) {
111
- assert(params.isDeposit, 'Only deposit is supported in getAvnuSwapMultiplyCall')
181
+ assert(
182
+ params.isDeposit,
183
+ "Only deposit is supported in getAvnuSwapMultiplyCall",
184
+ );
112
185
  // TODO use a varibale for 1.02
113
- const maxBorrowableAmounts = await this.getMaxBorrowableAmount({ isAPYComputation: false });
186
+ const maxBorrowableAmounts = await this.getMaxBorrowableAmount({
187
+ isAPYComputation: false,
188
+ });
114
189
  const allVesuAdapters = this.getVesuAdapters();
115
190
  let remainingAmount = params.leg1DepositAmount;
116
191
  const lstExRate = await this.getLSTExchangeRate();
117
- const baseAssetPrice = await this.pricer.getPrice(this.getLSTUnderlyingTokenInfo().symbol);
192
+ const baseAssetPrice = await this.pricer.getPrice(
193
+ this.getLSTUnderlyingTokenInfo().symbol,
194
+ );
118
195
  const lstPrice = baseAssetPrice.price * lstExRate;
119
196
  for (let i = 0; i < maxBorrowableAmounts.maxBorrowables.length; i++) {
120
197
  const maxBorrowable = maxBorrowableAmounts.maxBorrowables[i];
121
- const vesuAdapter = allVesuAdapters.find(adapter => adapter.config.debt.address.eq(maxBorrowable.borrowableAsset.address));
198
+ const vesuAdapter = allVesuAdapters.find((adapter) =>
199
+ adapter.config.debt.address.eq(maxBorrowable.borrowableAsset.address),
200
+ );
122
201
  if (!vesuAdapter) {
123
- throw new Error(`${this.getTag()}::getAvnuSwapMultiplyCall: vesuAdapter not found for borrowable asset: ${maxBorrowable.borrowableAsset.symbol}`);
202
+ throw new Error(
203
+ `${this.getTag()}::getAvnuSwapMultiplyCall: vesuAdapter not found for borrowable asset: ${maxBorrowable.borrowableAsset.symbol}`,
204
+ );
124
205
  }
125
206
  const maxLTV = await vesuAdapter.getLTVConfig(this.config);
126
- const debtPrice = await this.pricer.getPrice(maxBorrowable.borrowableAsset.symbol);
127
- const maxAmountToDeposit = HealthFactorMath.getMinCollateralRequiredOnLooping(
128
- maxBorrowable.amount,
129
- debtPrice.price,
130
- this.metadata.additionalInfo.targetHealthFactor,
131
- maxLTV,
132
- lstPrice,
133
- this.asset()
134
- )
207
+ const debtPrice = await this.pricer.getPrice(
208
+ maxBorrowable.borrowableAsset.symbol,
209
+ );
210
+ const maxAmountToDeposit =
211
+ HealthFactorMath.getMinCollateralRequiredOnLooping(
212
+ maxBorrowable.amount,
213
+ debtPrice.price,
214
+ this.metadata.additionalInfo.targetHealthFactor,
215
+ maxLTV,
216
+ lstPrice,
217
+ this.asset(),
218
+ );
135
219
  const amountToDeposit = remainingAmount.minimum(maxAmountToDeposit);
136
- logger.verbose(`${this.getTag()}::getAvnuSwapMultiplyCall::${vesuAdapter.config.debt.symbol}:: remainingAmount: ${remainingAmount}, amountToDeposit: ${amountToDeposit}, depositAmount: ${amountToDeposit}, maxBorrowable: ${maxBorrowable.amount}`);
220
+ logger.verbose(
221
+ `${this.getTag()}::getAvnuSwapMultiplyCall::${vesuAdapter.config.debt.symbol}:: remainingAmount: ${remainingAmount}, amountToDeposit: ${amountToDeposit}, depositAmount: ${amountToDeposit}, maxBorrowable: ${maxBorrowable.amount}`,
222
+ );
137
223
  const call = await this._getAvnuDepositSwapLegCall({
138
224
  isDeposit: params.isDeposit,
139
225
  // adjust decimals of debt asset
140
226
  leg1DepositAmount: amountToDeposit,
141
227
  minHF: 1.1, // undo
142
- vesuAdapter: vesuAdapter
228
+ vesuAdapter: vesuAdapter,
143
229
  });
144
230
  remainingAmount = remainingAmount.minus(amountToDeposit);
145
231
 
146
232
  // return the first possible call because computing all calls at a time
147
233
  // is not efficinet for swaps
148
- return {call, vesuAdapter};
234
+ return { call, vesuAdapter };
149
235
  }
150
- throw new Error(`${this.getTag()}::getAvnuSwapMultiplyCall: no calls found`);
236
+ throw new Error(
237
+ `${this.getTag()}::getAvnuSwapMultiplyCall: no calls found`,
238
+ );
151
239
  }
152
240
 
153
241
  async _getAvnuDepositSwapLegCall(params: {
154
- isDeposit: boolean,
155
- leg1DepositAmount: Web3Number,
156
- minHF: number, // e.g. 1.01
157
- vesuAdapter: VesuAdapter
242
+ isDeposit: boolean;
243
+ leg1DepositAmount: Web3Number;
244
+ minHF: number; // e.g. 1.01
245
+ vesuAdapter: VesuAdapter;
158
246
  }) {
159
247
  const { vesuAdapter } = params;
160
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall params: ${JSON.stringify(params)}`);
161
- assert(params.isDeposit, 'Only deposit is supported in _getAvnuDepositSwapLegCall')
248
+ logger.verbose(
249
+ `${this.getTag()}::_getAvnuDepositSwapLegCall params: ${JSON.stringify(params)}`,
250
+ );
251
+ assert(
252
+ params.isDeposit,
253
+ "Only deposit is supported in _getAvnuDepositSwapLegCall",
254
+ );
162
255
  // add collateral
163
256
  // borrow STRK (e.g.)
164
257
  // approve and swap strk
165
258
  // add collateral again
166
259
 
167
-
168
260
  const legLTV = await vesuAdapter.getLTVConfig(this.config);
169
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall legLTV: ${legLTV}`);
261
+ logger.verbose(
262
+ `${this.getTag()}::_getAvnuDepositSwapLegCall legLTV: ${legLTV}`,
263
+ );
170
264
  const existingPositions = await vesuAdapter.getPositions(this.config);
171
- const collateralisation = await vesuAdapter.getCollateralization(this.config);
265
+ const collateralisation = await vesuAdapter.getCollateralization(
266
+ this.config,
267
+ );
172
268
  const existingCollateralInfo = existingPositions[0];
173
269
  const existingDebtInfo = existingPositions[1];
174
270
  logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
175
271
  existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
176
272
 
177
273
  // - Prices as seen by Vesu contracts, ideal for HF math
178
- // Price 1 is ok as fallback bcz that would relatively price the
274
+ // Price 1 is ok as fallback bcz that would relatively price the
179
275
  // collateral and debt as equal.
180
- const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
181
- const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
182
- logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
183
-
276
+ const collateralPrice =
277
+ collateralisation[0].usdValue > 0
278
+ ? collateralisation[0].usdValue /
279
+ existingCollateralInfo.amount.toNumber()
280
+ : 1;
281
+ const debtPrice =
282
+ collateralisation[1].usdValue > 0
283
+ ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber()
284
+ : 1;
285
+ logger.debug(
286
+ `${this.getTag()}::_getAvnuDepositSwapLegCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`,
287
+ );
184
288
 
185
289
  const debtTokenInfo = vesuAdapter.config.debt;
186
290
  let newDepositAmount = params.leg1DepositAmount;
187
- const totalCollateral = existingCollateralInfo.amount.plus(params.leg1DepositAmount);
188
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalCollateral: ${totalCollateral}`);
291
+ const totalCollateral = existingCollateralInfo.amount.plus(
292
+ params.leg1DepositAmount,
293
+ );
294
+ logger.verbose(
295
+ `${this.getTag()}::_getAvnuDepositSwapLegCall totalCollateral: ${totalCollateral}`,
296
+ );
189
297
  const totalDebtAmount = new Web3Number(
190
- totalCollateral.multipliedBy(collateralPrice).multipliedBy(legLTV).dividedBy(debtPrice).dividedBy(params.minHF).toString(),
191
- debtTokenInfo.decimals
298
+ totalCollateral
299
+ .multipliedBy(collateralPrice)
300
+ .multipliedBy(legLTV)
301
+ .dividedBy(debtPrice)
302
+ .dividedBy(params.minHF)
303
+ .toString(),
304
+ debtTokenInfo.decimals,
192
305
  );
193
306
  let debtAmount = totalDebtAmount.minus(existingDebtInfo.amount);
194
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalDebtAmount: ${totalDebtAmount}, initial computed debt: ${debtAmount}`);
195
- const maxBorrowable = await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, false);
307
+ logger.verbose(
308
+ `${this.getTag()}::_getAvnuDepositSwapLegCall totalDebtAmount: ${totalDebtAmount}, initial computed debt: ${debtAmount}`,
309
+ );
310
+ const maxBorrowable = await this.getMaxBorrowableAmountByVesuAdapter(
311
+ vesuAdapter,
312
+ false,
313
+ );
196
314
 
197
315
  // if the debt amount is greater than 0 and the max borrowable amount is 0, skip
198
316
  if (debtAmount.gt(0) && maxBorrowable.amount.eq(0)) {
199
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall maxBorrowable is 0, skipping`);
317
+ logger.verbose(
318
+ `${this.getTag()}::_getAvnuDepositSwapLegCall maxBorrowable is 0, skipping`,
319
+ );
200
320
  return undefined;
201
321
  } else if (debtAmount.gt(0) && maxBorrowable.amount.gt(0)) {
202
322
  debtAmount = maxBorrowable.amount.minimum(debtAmount);
@@ -207,58 +327,78 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
207
327
  params.minHF,
208
328
  legLTV,
209
329
  collateralPrice,
210
- this.asset()
330
+ this.asset(),
331
+ );
332
+ newDepositAmount = totalCollateralRequired.minus(
333
+ existingCollateralInfo.amount,
211
334
  );
212
- newDepositAmount = totalCollateralRequired.minus(existingCollateralInfo.amount);
213
335
  if (newDepositAmount.lt(0)) {
214
- throw new Error(`${this.getTag()}::_getAvnuDepositSwapLegCall newDepositAmount is less than 0, newDepositAmount: ${newDepositAmount}, totalCollateralRequired: ${totalCollateralRequired}, existingCollateralInfo.amount: ${existingCollateralInfo.amount}`);
336
+ throw new Error(
337
+ `${this.getTag()}::_getAvnuDepositSwapLegCall newDepositAmount is less than 0, newDepositAmount: ${newDepositAmount}, totalCollateralRequired: ${totalCollateralRequired}, existingCollateralInfo.amount: ${existingCollateralInfo.amount}`,
338
+ );
215
339
  }
216
340
  if (newDebtUSDValue.toNumber() < 100) {
217
341
  // too less debt, skip
218
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall newDebtUSDValue is less than 100, skipping`);
342
+ logger.verbose(
343
+ `${this.getTag()}::_getAvnuDepositSwapLegCall newDebtUSDValue is less than 100, skipping`,
344
+ );
219
345
  return undefined;
220
346
  }
221
347
  }
222
348
 
223
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall debtAmount: ${debtAmount}`);
349
+ logger.verbose(
350
+ `${this.getTag()}::_getAvnuDepositSwapLegCall debtAmount: ${debtAmount}`,
351
+ );
224
352
  if (debtAmount.lt(0)) {
225
- // this is to unwind the position to optimal HF.
353
+ // this is to unwind the position to optimal HF.
226
354
  const lstDEXPrice = await this.getLSTDexPrice();
227
355
  const debtAmountInLST = debtAmount.abs().dividedBy(lstDEXPrice);
228
356
  const calls = await this.getVesuMultiplyCall({
229
357
  isDeposit: false,
230
358
  leg1DepositAmount: debtAmountInLST,
231
- poolId: vesuAdapter.config.poolId
232
- })
233
- assert(calls.length == 1, `Expected 1 call for unwind, got ${calls.length}`);
359
+ poolId: vesuAdapter.config.poolId,
360
+ });
361
+ assert(
362
+ calls.length == 1,
363
+ `Expected 1 call for unwind, got ${calls.length}`,
364
+ );
234
365
  return calls[0];
235
366
  }
236
367
  // console.log(`debtAmount`, debtAmount.toWei(), params.leg1DepositAmount.toWei());
237
368
  const STEP0 = UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN1;
238
369
  const manage0Info = this.getProofs<ApproveCallParams>(STEP0);
239
370
  const manageCall0 = manage0Info.callConstructor({
240
- amount: newDepositAmount
371
+ amount: newDepositAmount,
241
372
  });
242
- const STEP1 = getVesuLegId(UNIVERSAL_MANAGE_IDS.VESU_LEG1, vesuAdapter.config.debt.symbol, vesuAdapter.config.poolId.toString());
373
+ const STEP1 = getVesuLegId(
374
+ UNIVERSAL_MANAGE_IDS.VESU_LEG1,
375
+ vesuAdapter.config.debt.symbol,
376
+ vesuAdapter.config.poolId.toString(),
377
+ );
243
378
  const manage1Info = this.getProofs<VesuModifyPositionCallParams>(STEP1);
244
- const manageCall1 = manage1Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
379
+ const manageCall1 = manage1Info.callConstructor(
380
+ VesuAdapter.getDefaultModifyPositionCallParams({
245
381
  collateralAmount: newDepositAmount,
246
382
  isAddCollateral: params.isDeposit,
247
383
  debtAmount: debtAmount,
248
- isBorrow: params.isDeposit
249
- }));
384
+ isBorrow: params.isDeposit,
385
+ }),
386
+ );
250
387
 
251
388
  // console.log(`manageCall1`, manageCall1.call, debtAmount.toWei(), newDepositAmount.toWei());
252
-
389
+
253
390
  const proofIds: string[] = [STEP0, STEP1];
254
391
  const manageCalls: ManageCall[] = [manageCall0, manageCall1];
255
392
 
256
393
  // approve and swap to LST using avnu
257
394
  if (debtAmount.gt(0)) {
258
- const STEP2 = getAvnuManageIDs(LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_APPROVE_DEPOSIT, vesuAdapter.config.debt.symbol);
395
+ const STEP2 = getAvnuManageIDs(
396
+ LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_APPROVE_DEPOSIT,
397
+ vesuAdapter.config.debt.symbol,
398
+ );
259
399
  const manage2Info = this.getProofs<ApproveCallParams>(STEP2);
260
400
  const manageCall2 = manage2Info.callConstructor({
261
- amount: debtAmount
401
+ amount: debtAmount,
262
402
  });
263
403
 
264
404
  const debtTokenInfo = vesuAdapter.config.debt;
@@ -268,51 +408,75 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
268
408
  debtTokenInfo.address.address,
269
409
  lstTokenInfo.address.address,
270
410
  debtAmount.toWei(),
271
- this.metadata.additionalInfo.vaultAllocator.address
411
+ this.metadata.additionalInfo.vaultAllocator.address,
272
412
  );
273
413
  const minAmount = await this._getMinOutputAmountLSTBuy(debtAmount);
274
- const minAmountWei = (minAmount).toWei();
275
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall minAmount: ${minAmount}`);
414
+ const minAmountWei = minAmount.toWei();
415
+ logger.verbose(
416
+ `${this.getTag()}::_getAvnuDepositSwapLegCall minAmount: ${minAmount}`,
417
+ );
276
418
  const swapInfo = await avnuModule.getSwapInfo(
277
- quote,
278
- this.metadata.additionalInfo.vaultAllocator.address,
279
- 0,
419
+ quote,
420
+ this.metadata.additionalInfo.vaultAllocator.address,
421
+ 0,
280
422
  this.address.address,
281
- minAmountWei
423
+ minAmountWei,
424
+ );
425
+ logger.verbose(
426
+ `${this.getTag()}::_getAvnuDepositSwapLegCall swapInfo: ${JSON.stringify(swapInfo)}`,
427
+ );
428
+ const STEP3 = getAvnuManageIDs(
429
+ LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_SWAP_DEPOSIT,
430
+ vesuAdapter.config.debt.symbol,
282
431
  );
283
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall swapInfo: ${JSON.stringify(swapInfo)}`);
284
- const STEP3 = getAvnuManageIDs(LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_SWAP_DEPOSIT, vesuAdapter.config.debt.symbol);
285
432
  const manage3Info = this.getProofs<AvnuSwapCallParams>(STEP3);
286
433
  const manageCall3 = manage3Info.callConstructor({
287
- props: swapInfo
434
+ props: swapInfo,
288
435
  });
289
436
  proofIds.push(STEP2);
290
437
  proofIds.push(STEP3);
291
438
  manageCalls.push(manageCall2, manageCall3);
292
439
 
293
-
294
440
  // if the created debt, when added is collateral will put the total HF above min, but below (target + 0.05),
295
- // then lets close the looping cycle by adding this as collateral.
441
+ // then lets close the looping cycle by adding this as collateral.
296
442
  const newCollateral = minAmount.plus(totalCollateral);
297
- const newHF = newCollateral.multipliedBy(collateralPrice).multipliedBy(legLTV).dividedBy(totalDebtAmount).dividedBy(debtPrice).toNumber();
298
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall newHF: ${newHF}`);
299
- if (newHF > this.metadata.additionalInfo.minHealthFactor && newHF < this.metadata.additionalInfo.targetHealthFactor + 0.05) {
300
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall newHF is above min and below target + 0.05, adding collateral on vesu`);
443
+ const newHF = newCollateral
444
+ .multipliedBy(collateralPrice)
445
+ .multipliedBy(legLTV)
446
+ .dividedBy(totalDebtAmount)
447
+ .dividedBy(debtPrice)
448
+ .toNumber();
449
+ logger.verbose(
450
+ `${this.getTag()}::_getAvnuDepositSwapLegCall newHF: ${newHF}`,
451
+ );
452
+ if (
453
+ newHF > this.metadata.additionalInfo.minHealthFactor &&
454
+ newHF < this.metadata.additionalInfo.targetHealthFactor + 0.05
455
+ ) {
456
+ logger.verbose(
457
+ `${this.getTag()}::_getAvnuDepositSwapLegCall newHF is above min and below target + 0.05, adding collateral on vesu`,
458
+ );
301
459
  // approve and add collateral on vesu (modify position)
302
460
  const STEP4 = UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN1;
303
461
  const manage4Info = this.getProofs<ApproveCallParams>(STEP4);
304
462
  const manageCall4 = manage4Info.callConstructor({
305
- amount: minAmount
463
+ amount: minAmount,
306
464
  });
307
-
308
- const STEP5 = getVesuLegId(UNIVERSAL_MANAGE_IDS.VESU_LEG1, vesuAdapter.config.debt.symbol, vesuAdapter.config.poolId.toString());
465
+
466
+ const STEP5 = getVesuLegId(
467
+ UNIVERSAL_MANAGE_IDS.VESU_LEG1,
468
+ vesuAdapter.config.debt.symbol,
469
+ vesuAdapter.config.poolId.toString(),
470
+ );
309
471
  const manage5Info = this.getProofs<VesuModifyPositionCallParams>(STEP5);
310
- const manageCall5 = manage5Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
311
- collateralAmount: minAmount,
312
- isAddCollateral: true,
313
- debtAmount: Web3Number.fromWei('0', this.asset().decimals),
314
- isBorrow: params.isDeposit
315
- }));
472
+ const manageCall5 = manage5Info.callConstructor(
473
+ VesuAdapter.getDefaultModifyPositionCallParams({
474
+ collateralAmount: minAmount,
475
+ isAddCollateral: true,
476
+ debtAmount: Web3Number.fromWei("0", this.asset().decimals),
477
+ isBorrow: params.isDeposit,
478
+ }),
479
+ );
316
480
  proofIds.push(STEP4, STEP5);
317
481
  manageCalls.push(manageCall4, manageCall5);
318
482
  }
@@ -322,53 +486,78 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
322
486
  return manageCall;
323
487
  }
324
488
 
325
- // todo unwind or not deposit when the yield is bad.
489
+ // todo unwind or not deposit when the yield is bad.
326
490
 
327
- async getLSTMultiplierRebalanceCall(): Promise<{ shouldRebalance: boolean, manageCalls: {vesuAdapter: VesuAdapter, manageCall: Call}[] }> {
491
+ async getLSTMultiplierRebalanceCall(): Promise<{
492
+ shouldRebalance: boolean;
493
+ manageCalls: { vesuAdapter: VesuAdapter; manageCall: Call }[];
494
+ }> {
328
495
  let shouldRebalance = false;
329
- const calls: {vesuAdapter: VesuAdapter, manageCall: Call}[] = [];
496
+ const calls: { vesuAdapter: VesuAdapter; manageCall: Call }[] = [];
330
497
  // todo undo
331
- const allVesuAdapters = this.getVesuAdapters().filter(vesuAdapter => vesuAdapter.config.debt.symbol === 'LBTC');
498
+ const allVesuAdapters = this.getVesuAdapters().filter(
499
+ (vesuAdapter) => vesuAdapter.config.debt.symbol === "LBTC",
500
+ );
332
501
  for (const vesuAdapter of allVesuAdapters) {
333
502
  const call = await this._getLSTMultiplierRebalanceCall(vesuAdapter);
334
503
  if (call.shouldRebalance && call.manageCall) {
335
504
  shouldRebalance = true;
336
- calls.push({vesuAdapter, manageCall: call.manageCall});
505
+ calls.push({ vesuAdapter, manageCall: call.manageCall });
337
506
  }
338
507
  }
339
508
  return { shouldRebalance, manageCalls: calls };
340
509
  }
341
510
 
342
- async _getLSTMultiplierRebalanceCall(vesuAdapter: VesuAdapter): Promise<{ shouldRebalance: boolean, manageCall: Call | undefined }> {
511
+ async _getLSTMultiplierRebalanceCall(
512
+ vesuAdapter: VesuAdapter,
513
+ ): Promise<{ shouldRebalance: boolean; manageCall: Call | undefined }> {
343
514
  const positions = await vesuAdapter.getPositions(this.config);
344
- assert(positions.length == 2, 'Rebalance call is only supported for 2 positions');
515
+ assert(
516
+ positions.length == 2,
517
+ "Rebalance call is only supported for 2 positions",
518
+ );
345
519
  const existingCollateralInfo = positions[0];
346
520
  const existingDebtInfo = positions[1];
347
521
  const unusedBalance = await this.getUnusedBalance();
348
522
  const healthFactor = await vesuAdapter.getHealthFactor();
349
523
 
350
- const collateralisation = await vesuAdapter.getCollateralization(this.config);
524
+ const collateralisation = await vesuAdapter.getCollateralization(
525
+ this.config,
526
+ );
351
527
  logger.debug(`${this.getTag()}::getVesuMultiplyCall::${vesuAdapter.config.debt.symbol} existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
352
528
  existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
353
529
 
354
530
  // - Prices as seen by Vesu contracts, ideal for HF math
355
- // Price 1 is ok as fallback bcz that would relatively price the
531
+ // Price 1 is ok as fallback bcz that would relatively price the
356
532
  // collateral and debt as equal.
357
- const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
358
- const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
359
- logger.debug(`${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
360
- logger.debug(`${this.getTag()}::getVesuMultiplyCall healthFactor: ${healthFactor}`);
533
+ const collateralPrice =
534
+ collateralisation[0].usdValue > 0
535
+ ? collateralisation[0].usdValue /
536
+ existingCollateralInfo.amount.toNumber()
537
+ : 1;
538
+ const debtPrice =
539
+ collateralisation[1].usdValue > 0
540
+ ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber()
541
+ : 1;
542
+ logger.debug(
543
+ `${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`,
544
+ );
545
+ logger.debug(
546
+ `${this.getTag()}::getVesuMultiplyCall healthFactor: ${healthFactor}`,
547
+ );
361
548
 
362
- const isHFTooLow = healthFactor < this.metadata.additionalInfo.minHealthFactor;
363
- const isHFTooHigh = healthFactor > this.metadata.additionalInfo.targetHealthFactor + 0.05;
549
+ const isHFTooLow =
550
+ healthFactor < this.metadata.additionalInfo.minHealthFactor;
551
+ const isHFTooHigh =
552
+ healthFactor > this.metadata.additionalInfo.targetHealthFactor + 0.05;
364
553
  if (isHFTooLow || isHFTooHigh || 1) {
365
- // use unused collateral to target more.
554
+ // use unused collateral to target more.
366
555
  const manageCall = await this._getAvnuDepositSwapLegCall({
367
556
  isDeposit: true,
368
557
  leg1DepositAmount: unusedBalance.amount,
369
- minHF: 1.02, // todo, shouldnt use this 1.02 HF, if there isn;t more looping left.
370
- vesuAdapter
371
- })
558
+ minHF: 1.02, // todo, shouldnt use this 1.02 HF, if there isn;t more looping left.
559
+ vesuAdapter,
560
+ });
372
561
  return { shouldRebalance: true, manageCall };
373
562
  } else {
374
563
  // do nothing
@@ -376,42 +565,61 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
376
565
  }
377
566
  }
378
567
 
379
- protected async getVesuAUM(adapter: VesuAdapter, priceType: LSTPriceType = LSTPriceType.AVNU_PRICE) {
568
+ protected async getVesuAUM(
569
+ adapter: VesuAdapter,
570
+ priceType: LSTPriceType = LSTPriceType.AVNU_PRICE,
571
+ ) {
380
572
  const legAUM = await adapter.getPositions(this.config);
381
573
  const underlying = this.asset();
382
574
  // assert its an LST of Endur
383
- assert(underlying.symbol.startsWith('x'), 'Underlying is not an LST of Endur');
575
+ assert(
576
+ underlying.symbol.startsWith("x"),
577
+ "Underlying is not an LST of Endur",
578
+ );
384
579
 
385
580
  let vesuAum = Web3Number.fromWei("0", underlying.decimals);
386
-
581
+
387
582
  // Get the price based on the price type
388
583
  let tokenUnderlyingPrice: number;
389
584
  if (priceType === LSTPriceType.ENDUR_PRICE) {
390
585
  tokenUnderlyingPrice = await this.getLSTExchangeRate();
391
586
  if (tokenUnderlyingPrice === 0) {
392
- throw new Error(`${this.getTag()}::getVesuAUM: tokenUnderlyingPrice (Endur) is 0`);
587
+ throw new Error(
588
+ `${this.getTag()}::getVesuAUM: tokenUnderlyingPrice (Endur) is 0`,
589
+ );
393
590
  }
394
591
 
395
592
  // For Endur price, also check against Avnu rate to ensure they're within 2%
396
593
  const avnuRate = await this.getLSTAvnuRate();
397
594
  if (avnuRate === 0) {
398
- throw new Error(`${this.getTag()}::getVesuAUM: tokenUnderlyingPrice (Avnu) is 0`);
595
+ throw new Error(
596
+ `${this.getTag()}::getVesuAUM: tokenUnderlyingPrice (Avnu) is 0`,
597
+ );
399
598
  }
400
599
 
401
- const diff = Math.abs(tokenUnderlyingPrice - avnuRate) / tokenUnderlyingPrice;
600
+ const diff =
601
+ Math.abs(tokenUnderlyingPrice - avnuRate) / tokenUnderlyingPrice;
402
602
  if (diff > 0.02) {
403
- throw new Error(`${this.getTag()}::getVesuAUM: Endur and Avnu prices differ by more than 2% (Endur: ${tokenUnderlyingPrice}, Avnu: ${avnuRate})`);
603
+ throw new Error(
604
+ `${this.getTag()}::getVesuAUM: Endur and Avnu prices differ by more than 2% (Endur: ${tokenUnderlyingPrice}, Avnu: ${avnuRate})`,
605
+ );
404
606
  }
405
607
 
406
- logger.verbose(`${this.getTag()} tokenUnderlyingPrice (Endur): ${tokenUnderlyingPrice}, avnuRate: ${avnuRate}, diff: ${diff}`);
608
+ logger.verbose(
609
+ `${this.getTag()} tokenUnderlyingPrice (Endur): ${tokenUnderlyingPrice}, avnuRate: ${avnuRate}, diff: ${diff}`,
610
+ );
407
611
  } else {
408
612
  tokenUnderlyingPrice = await this.getLSTAvnuRate();
409
613
  if (tokenUnderlyingPrice === 0) {
410
- throw new Error(`${this.getTag()}::getVesuAUM: tokenUnderlyingPrice (Avnu) is 0`);
614
+ throw new Error(
615
+ `${this.getTag()}::getVesuAUM: tokenUnderlyingPrice (Avnu) is 0`,
616
+ );
411
617
  }
412
- logger.verbose(`${this.getTag()} tokenUnderlyingPrice (Avnu): ${tokenUnderlyingPrice}`);
618
+ logger.verbose(
619
+ `${this.getTag()} tokenUnderlyingPrice (Avnu): ${tokenUnderlyingPrice}`,
620
+ );
413
621
  }
414
-
622
+
415
623
  // handle collateral
416
624
  if (legAUM[0].token.address.eq(underlying.address)) {
417
625
  vesuAum = vesuAum.plus(legAUM[0].amount);
@@ -424,71 +632,82 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
424
632
  vesuAum = vesuAum.minus(legAUM[1].amount);
425
633
  } else {
426
634
  vesuAum = vesuAum.minus(legAUM[1].amount.dividedBy(tokenUnderlyingPrice));
427
- };
635
+ }
428
636
 
429
- const priceTypeLabel = priceType === LSTPriceType.ENDUR_PRICE ? 'Endur Price' : 'Avnu Price';
430
- logger.verbose(`${this.getTag()} Vesu AUM (${priceTypeLabel}): ${vesuAum}, legCollateral: ${legAUM[0].amount.toNumber()}, legDebt: ${legAUM[1].amount.toNumber()}`);
637
+ const priceTypeLabel =
638
+ priceType === LSTPriceType.ENDUR_PRICE ? "Endur Price" : "Avnu Price";
639
+ logger.verbose(
640
+ `${this.getTag()} Vesu AUM (${priceTypeLabel}): ${vesuAum}, legCollateral: ${legAUM[0].amount.toNumber()}, legDebt: ${legAUM[1].amount.toNumber()}`,
641
+ );
431
642
  return vesuAum;
432
643
  }
433
644
 
434
- async getTVLUnrealized(): Promise<{net: SingleTokenInfo, prevAum: Web3Number, splits: {id: string, aum: Web3Number}[]}> {
645
+ async getTVLUnrealized(): Promise<{
646
+ net: SingleTokenInfo;
647
+ prevAum: Web3Number;
648
+ splits: { id: string; aum: Web3Number }[];
649
+ }> {
435
650
  return await this.getAUM(true);
436
651
  }
437
652
 
438
653
  async getUserUnrealizedGains(user: ContractAddr) {
439
654
  // Get total TVL (realized)
440
655
  const tvl = await this.getTVL();
441
-
656
+
442
657
  // Get unrealized TVL (using Endur prices)
443
658
  const unrealizedTVL = await this.getTVLUnrealized();
444
-
659
+
445
660
  // Calculate the difference between unrealized and realized TVL
446
661
  const unrealizedDiff = unrealizedTVL.net.amount.minus(tvl.amount);
447
-
662
+
448
663
  // Get user's TVL
449
664
  const userTVL = await this.getUserTVL(user);
450
-
665
+
451
666
  // Calculate user's share of the total TVL
452
667
  const userShare = userTVL.amount.dividedBy(tvl.amount);
453
-
668
+
454
669
  // Calculate user's unrealized gains (in token amount)
455
670
  const unrealizedGains = unrealizedDiff.multipliedBy(userShare);
456
-
671
+
457
672
  return {
458
673
  unrealizedGains,
459
674
  userShare: userShare.toNumber(),
460
- tokenInfo: this.asset()
675
+ tokenInfo: this.asset(),
461
676
  };
462
677
  }
463
678
 
464
679
  //
465
680
  private async _getMinOutputAmountLSTBuy(amountInUnderlying: Web3Number) {
466
681
  const lstTruePrice = await this.getLSTExchangeRate();
467
- // during buy, the purchase should always be <= true LST price.
468
- const minOutputAmount = amountInUnderlying.dividedBy(lstTruePrice).multipliedBy(0.99979); // minus 0.021% to account for avnu fees
682
+ // during buy, the purchase should always be <= true LST price.
683
+ const minOutputAmount = amountInUnderlying
684
+ .dividedBy(lstTruePrice)
685
+ .multipliedBy(0.99979); // minus 0.021% to account for avnu fees
469
686
  return new Web3Number(minOutputAmount.toString(), this.asset().decimals);
470
687
  }
471
688
 
472
689
  private async _getMinOutputAmountLSTSell(amountInLST: Web3Number) {
473
690
  const lstTruePrice = await this.getLSTExchangeRate();
474
- // during sell, the purchase should always be > 0.995 * true LST price.
475
- const minOutputAmount = amountInLST.multipliedBy(lstTruePrice).multipliedBy(0.995);
691
+ // during sell, the purchase should always be > 0.995 * true LST price.
692
+ const minOutputAmount = amountInLST
693
+ .multipliedBy(lstTruePrice)
694
+ .multipliedBy(0.995);
476
695
  return minOutputAmount;
477
696
  }
478
697
 
479
698
  // todo add a function to findout max borrowable amount without fucking yield
480
- // if the current net yield < LST yield, add a function to calculate how much to unwind.
699
+ // if the current net yield < LST yield, add a function to calculate how much to unwind.
481
700
 
482
701
  /**
483
702
  * Uses vesu's multiple call to create leverage on LST
484
703
  * Deposit amount is in LST
485
- * @param params
704
+ * @param params
486
705
  */
487
706
  async getVesuMultiplyCall(params: {
488
- isDeposit: boolean,
489
- leg1DepositAmount: Web3Number,
490
- maxEkuboPriceImpact?: number,
491
- poolId: ContractAddr
707
+ isDeposit: boolean;
708
+ leg1DepositAmount: Web3Number;
709
+ maxEkuboPriceImpact?: number;
710
+ poolId: ContractAddr;
492
711
  }) {
493
712
  const maxEkuboPriceImpact = params.maxEkuboPriceImpact || 0.01;
494
713
  const vesuAdapter1 = this.getVesuSameTokenAdapter(params.poolId);
@@ -496,10 +715,12 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
496
715
  logger.verbose(`${this.getTag()}::getVesuMultiplyCall legLTV: ${legLTV}`);
497
716
 
498
717
  if (!params.isDeposit) {
499
- // try using unused balance to unwind.
500
- // no need to unwind.
718
+ // try using unused balance to unwind.
719
+ // no need to unwind.
501
720
  const unusedBalance = await this.getUnusedBalance();
502
- logger.verbose(`${this.getTag()}::getVesuMultiplyCall unusedBalance: ${unusedBalance.amount.toString()}, required: ${params.leg1DepositAmount.toString()}`);
721
+ logger.verbose(
722
+ `${this.getTag()}::getVesuMultiplyCall unusedBalance: ${unusedBalance.amount.toString()}, required: ${params.leg1DepositAmount.toString()}`,
723
+ );
503
724
  // undo
504
725
  // if (unusedBalance.amount.gte(params.leg1DepositAmount)) {
505
726
  // return [];
@@ -508,51 +729,85 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
508
729
  }
509
730
 
510
731
  const existingPositions = await vesuAdapter1.getPositions(this.config);
511
- const collateralisation = await vesuAdapter1.getCollateralization(this.config);
732
+ const collateralisation = await vesuAdapter1.getCollateralization(
733
+ this.config,
734
+ );
512
735
  const existingCollateralInfo = existingPositions[0];
513
736
  const existingDebtInfo = existingPositions[1];
514
737
  logger.debug(`${this.getTag()}::getVesuMultiplyCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
515
738
  existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
516
739
 
517
740
  // - Prices as seen by Vesu contracts, ideal for HF math
518
- // Price 1 is ok as fallback bcz that would relatively price the
741
+ // Price 1 is ok as fallback bcz that would relatively price the
519
742
  // collateral and debt as equal.
520
- const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
521
- const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
522
- logger.debug(`${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
743
+ const collateralPrice =
744
+ collateralisation[0].usdValue > 0
745
+ ? collateralisation[0].usdValue /
746
+ existingCollateralInfo.amount.toNumber()
747
+ : 1;
748
+ const debtPrice =
749
+ collateralisation[1].usdValue > 0
750
+ ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber()
751
+ : 1;
752
+ logger.debug(
753
+ `${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`,
754
+ );
523
755
 
524
756
  // - Prices as seen by actual swap price
525
757
  const dexPrice = await this.getLSTDexPrice();
526
758
 
527
759
  // compute optimal amount of collateral and debt post addition/removal
528
760
  // target hf = collateral * collateralPrice * ltv / debt * debtPrice
529
- // assuming X to be the usd amount of debt borrowed or repaied (negative).
761
+ // assuming X to be the usd amount of debt borrowed or repaied (negative).
530
762
  // target hf = (((collateral + legDepositAmount) * collateralPrice + X)) * ltv / (debt * debtPrice + X)
531
763
  // => X * target hf = (((collateral + legDepositAmount) * collateralPrice + X)) * ltv - (debt * debtPrice * target hf)
532
764
  // => X * (target hf - ltv)= ((collateral + legDepositAmount) * collateralPrice * ltv) - (debt * debtPrice * target hf)
533
765
  // => X = (((collateral + legDepositAmount) * collateralPrice * ltv) - (debt * debtPrice * target hf)) / (target hf - ltv)
534
- const addedCollateral = params.leg1DepositAmount
535
- .multipliedBy(params.isDeposit ? 1 : -1)
536
- logger.verbose(`${this.getTag()}::getVesuMultiplyCall addedCollateral: ${addedCollateral}`);
537
- const numeratorPart1 = (existingCollateralInfo.amount.plus((addedCollateral))).multipliedBy(collateralPrice).multipliedBy(legLTV);
538
- logger.verbose(`${this.getTag()}::getVesuMultiplyCall numeratorPart1: ${numeratorPart1}`);
539
- const numeratorPart2 = existingDebtInfo.amount.multipliedBy(debtPrice).multipliedBy(this.metadata.additionalInfo.targetHealthFactor);
540
- logger.verbose(`${this.getTag()}::getVesuMultiplyCall numeratorPart2: ${numeratorPart2}`);
541
- const denominatorPart = this.metadata.additionalInfo.targetHealthFactor - (legLTV / dexPrice);
542
- logger.verbose(`${this.getTag()}::getVesuMultiplyCall denominatorPart: ${denominatorPart}`);
543
- const x_debt_usd = numeratorPart1.minus(numeratorPart2).dividedBy(denominatorPart);
544
- logger.verbose(`${this.getTag()}::getVesuMultiplyCall x_debt_usd: ${x_debt_usd}`);
545
- logger.debug(`${this.getTag()}::getVesuMultiplyCall numeratorPart1: ${numeratorPart1}, numeratorPart2: ${numeratorPart2}, denominatorPart: ${denominatorPart}`);
766
+ const addedCollateral = params.leg1DepositAmount.multipliedBy(
767
+ params.isDeposit ? 1 : -1,
768
+ );
769
+ logger.verbose(
770
+ `${this.getTag()}::getVesuMultiplyCall addedCollateral: ${addedCollateral}`,
771
+ );
772
+ const numeratorPart1 = existingCollateralInfo.amount
773
+ .plus(addedCollateral)
774
+ .multipliedBy(collateralPrice)
775
+ .multipliedBy(legLTV);
776
+ logger.verbose(
777
+ `${this.getTag()}::getVesuMultiplyCall numeratorPart1: ${numeratorPart1}`,
778
+ );
779
+ const numeratorPart2 = existingDebtInfo.amount
780
+ .multipliedBy(debtPrice)
781
+ .multipliedBy(this.metadata.additionalInfo.targetHealthFactor);
782
+ logger.verbose(
783
+ `${this.getTag()}::getVesuMultiplyCall numeratorPart2: ${numeratorPart2}`,
784
+ );
785
+ const denominatorPart =
786
+ this.metadata.additionalInfo.targetHealthFactor - legLTV / dexPrice;
787
+ logger.verbose(
788
+ `${this.getTag()}::getVesuMultiplyCall denominatorPart: ${denominatorPart}`,
789
+ );
790
+ const x_debt_usd = numeratorPart1
791
+ .minus(numeratorPart2)
792
+ .dividedBy(denominatorPart);
793
+ logger.verbose(
794
+ `${this.getTag()}::getVesuMultiplyCall x_debt_usd: ${x_debt_usd}`,
795
+ );
796
+ logger.debug(
797
+ `${this.getTag()}::getVesuMultiplyCall numeratorPart1: ${numeratorPart1}, numeratorPart2: ${numeratorPart2}, denominatorPart: ${denominatorPart}`,
798
+ );
546
799
 
547
800
  // both in underlying
548
801
  let debtAmount = x_debt_usd.dividedBy(debtPrice);
549
802
  const marginAmount = addedCollateral;
550
- logger.verbose(`${this.getTag()}::getVesuMultiplyCall debtAmount: ${debtAmount}, marginAmount: ${marginAmount}`);
803
+ logger.verbose(
804
+ `${this.getTag()}::getVesuMultiplyCall debtAmount: ${debtAmount}, marginAmount: ${marginAmount}`,
805
+ );
551
806
 
552
807
  if (marginAmount.lt(0) && debtAmount.gt(0)) {
553
808
  // if we want to withdraw, but debt can go high, its conflicting between
554
- // increasing and reducing lever. and in this case, the HF will go high,
555
- // which is ok.
809
+ // increasing and reducing lever. and in this case, the HF will go high,
810
+ // which is ok.
556
811
  debtAmount = Web3Number.fromWei(0, this.asset().decimals);
557
812
  }
558
813
 
@@ -569,38 +824,69 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
569
824
  lstDexPriceInUnderlying: dexPrice,
570
825
  isIncrease: debtAmount.greaterThan(0),
571
826
  maxEkuboPriceImpact,
572
- poolId: params.poolId
827
+ poolId: params.poolId,
573
828
  });
574
829
  }
575
830
 
576
831
  getLSTUnderlyingTokenInfo() {
577
- const vesuAdapter1 = this.getVesuSameTokenAdapter(this.metadata.additionalInfo.defaultPoolId);
832
+ const vesuAdapter1 = this.getVesuSameTokenAdapter(
833
+ this.metadata.additionalInfo.defaultPoolId,
834
+ );
578
835
  return vesuAdapter1.config.debt;
579
836
  }
580
837
 
581
- async getMaxBorrowableAmount(params: { isAPYComputation: boolean } = { isAPYComputation: false }) {
838
+ async getMaxBorrowableAmount(
839
+ params: { isAPYComputation: boolean } = { isAPYComputation: false },
840
+ ) {
582
841
  const vesuAdapters = this.getVesuAdapters();
583
- let netMaxBorrowableAmount = Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals);
584
- const maxBorrowables: {amount: Web3Number, dexSwappableAmount: Web3Number, maxBorrowableAmount: Web3Number, borrowableAsset: TokenInfo, ltv: number}[] = [];
842
+ let netMaxBorrowableAmount = Web3Number.fromWei(
843
+ "0",
844
+ this.getLSTUnderlyingTokenInfo().decimals,
845
+ );
846
+ const maxBorrowables: {
847
+ amount: Web3Number;
848
+ dexSwappableAmount: Web3Number;
849
+ maxBorrowableAmount: Web3Number;
850
+ borrowableAsset: TokenInfo;
851
+ ltv: number;
852
+ }[] = [];
585
853
  for (const vesuAdapter of vesuAdapters) {
586
- const output = await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, params.isAPYComputation);
854
+ const output = await this.getMaxBorrowableAmountByVesuAdapter(
855
+ vesuAdapter,
856
+ params.isAPYComputation,
857
+ );
587
858
  const ltv = await vesuAdapter.getLTVConfig(this.config);
588
- maxBorrowables.push({...output, ltv});
859
+ maxBorrowables.push({ ...output, ltv });
589
860
  }
590
861
  maxBorrowables.sort((a, b) => b.amount.toNumber() - a.amount.toNumber());
591
- netMaxBorrowableAmount = maxBorrowables.reduce((acc, curr) => acc.plus(curr.amount), Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals));
592
- return {netMaxBorrowableAmount, maxBorrowables};
862
+ netMaxBorrowableAmount = maxBorrowables.reduce(
863
+ (acc, curr) => acc.plus(curr.amount),
864
+ Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals),
865
+ );
866
+ return { netMaxBorrowableAmount, maxBorrowables };
593
867
  }
594
868
 
595
- // recursively, using binary search computes max swappable.
869
+ // recursively, using binary search computes max swappable.
596
870
  // @dev assumes 1 token of from == 1 token of to
597
- async getMaxSwappableWithMaxSlippage(fromToken: TokenInfo, toToken: TokenInfo, maxSlippage: number, maxAmount: Web3Number) {
871
+ async getMaxSwappableWithMaxSlippage(
872
+ fromToken: TokenInfo,
873
+ toToken: TokenInfo,
874
+ maxSlippage: number,
875
+ maxAmount: Web3Number,
876
+ ) {
598
877
  const output = await findMaxInputWithSlippage({
599
878
  apiGetOutput: async (inputAmount: number): Promise<number> => {
600
879
  const ekuboQuoter = new EkuboQuoter(this.config);
601
- await new Promise(resolve => setTimeout(resolve, 1000)); // artificial delay, to avoid rate limit
602
- const quote = await ekuboQuoter.getQuote(fromToken.address.address, toToken.address.address, new Web3Number(inputAmount.toFixed(9), fromToken.decimals));
603
- return Web3Number.fromWei(quote.total_calculated.toString(), toToken.decimals).toNumber();
880
+ await new Promise((resolve) => setTimeout(resolve, 1000)); // artificial delay, to avoid rate limit
881
+ const quote = await ekuboQuoter.getQuote(
882
+ fromToken.address.address,
883
+ toToken.address.address,
884
+ new Web3Number(inputAmount.toFixed(9), fromToken.decimals),
885
+ );
886
+ return Web3Number.fromWei(
887
+ quote.total_calculated.toString(),
888
+ toToken.decimals,
889
+ ).toNumber();
604
890
  },
605
891
  maxInput: maxAmount.toNumber(),
606
892
  maxSlippagePercent: maxSlippage,
@@ -610,48 +896,103 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
610
896
  return new Web3Number(output.optimalInput, fromToken.decimals);
611
897
  }
612
898
 
613
- async getMaxBorrowableAmountByVesuAdapter(vesuAdapter: VesuAdapter, isAPYComputation: boolean) {
614
- const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
899
+ async getMaxBorrowableAmountByVesuAdapter(
900
+ vesuAdapter: VesuAdapter,
901
+ isAPYComputation: boolean,
902
+ ) {
903
+ const lstAPY = await this.getLSTAPR(
904
+ this.getLSTUnderlyingTokenInfo().address,
905
+ );
615
906
  const maxInterestRate = lstAPY * 0.8;
616
- const {maxDebtToHave: maxBorrowableAmount, currentDebt} = await vesuAdapter.getMaxBorrowableByInterestRate(this.config, vesuAdapter.config.debt, maxInterestRate);
907
+ const { maxDebtToHave: maxBorrowableAmount, currentDebt } =
908
+ await vesuAdapter.getMaxBorrowableByInterestRate(
909
+ this.config,
910
+ vesuAdapter.config.debt,
911
+ maxInterestRate,
912
+ );
617
913
  const debtCap = await vesuAdapter.getDebtCap(this.config);
618
914
 
619
915
  if (currentDebt.gte(debtCap)) {
620
- return {amount: Web3Number.fromWei("0", vesuAdapter.config.debt.decimals), dexSwappableAmount: Web3Number.fromWei("0", vesuAdapter.config.debt.decimals), maxBorrowableAmount: Web3Number.fromWei("0", vesuAdapter.config.debt.decimals), borrowableAsset: vesuAdapter.config.debt};
916
+ return {
917
+ amount: Web3Number.fromWei("0", vesuAdapter.config.debt.decimals),
918
+ dexSwappableAmount: Web3Number.fromWei(
919
+ "0",
920
+ vesuAdapter.config.debt.decimals,
921
+ ),
922
+ maxBorrowableAmount: Web3Number.fromWei(
923
+ "0",
924
+ vesuAdapter.config.debt.decimals,
925
+ ),
926
+ borrowableAsset: vesuAdapter.config.debt,
927
+ };
621
928
  }
622
929
 
623
930
  const availableToBorrow = debtCap.minus(currentDebt);
624
931
 
625
- const maxBorrowable = maxBorrowableAmount.minimum(availableToBorrow).multipliedBy(0.999);
932
+ const maxBorrowable = maxBorrowableAmount
933
+ .minimum(availableToBorrow)
934
+ .multipliedBy(0.999);
626
935
  // Dont compute precise max swappable for APY computation
627
- if (vesuAdapter.config.debt.address.eq(this.getLSTUnderlyingTokenInfo().address) || isAPYComputation) {
628
- return {amount: maxBorrowable, dexSwappableAmount: maxBorrowable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt};
936
+ if (
937
+ vesuAdapter.config.debt.address.eq(
938
+ this.getLSTUnderlyingTokenInfo().address,
939
+ ) ||
940
+ isAPYComputation
941
+ ) {
942
+ return {
943
+ amount: maxBorrowable,
944
+ dexSwappableAmount: maxBorrowable,
945
+ maxBorrowableAmount: maxBorrowable,
946
+ borrowableAsset: vesuAdapter.config.debt,
947
+ };
629
948
  }
630
949
  // Want < 0.02% slippage
631
950
  try {
632
- const maxSwappable = await this.getMaxSwappableWithMaxSlippage(vesuAdapter.config.debt, this.getLSTUnderlyingTokenInfo(), 0.0002, maxBorrowable);
633
- return {amount: maxBorrowable.minimum(maxSwappable), dexSwappableAmount: maxSwappable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt};
951
+ const maxSwappable = await this.getMaxSwappableWithMaxSlippage(
952
+ vesuAdapter.config.debt,
953
+ this.getLSTUnderlyingTokenInfo(),
954
+ 0.0002,
955
+ maxBorrowable,
956
+ );
957
+ return {
958
+ amount: maxBorrowable.minimum(maxSwappable),
959
+ dexSwappableAmount: maxSwappable,
960
+ maxBorrowableAmount: maxBorrowable,
961
+ borrowableAsset: vesuAdapter.config.debt,
962
+ };
634
963
  } catch (error) {
635
964
  logger.warn(`${this.getTag()}: Failed to get max swappable: ${error}`);
636
- const maxSwappable = Web3Number.fromWei("0", vesuAdapter.config.debt.decimals);
637
- return {amount: maxBorrowable.minimum(maxSwappable), dexSwappableAmount: maxSwappable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt};
638
- }
965
+ const maxSwappable = Web3Number.fromWei(
966
+ "0",
967
+ vesuAdapter.config.debt.decimals,
968
+ );
969
+ return {
970
+ amount: maxBorrowable.minimum(maxSwappable),
971
+ dexSwappableAmount: maxSwappable,
972
+ maxBorrowableAmount: maxBorrowable,
973
+ borrowableAsset: vesuAdapter.config.debt,
974
+ };
975
+ }
639
976
  }
640
977
 
641
978
  // todo how much to unwind to get back healthy APY zone again
642
979
  // if net APY < LST APR + 0.5%, we need to unwind to get back to LST APR + 1% atleast or 0 vesu position
643
- // For xSTRK, simply deposit in Vesu if looping is not viable
644
-
980
+ // For xSTRK, simply deposit in Vesu if looping is not viable
981
+
645
982
  /**
646
983
  * Gets LST APR for the strategy's underlying asset from Endur API
647
984
  * @returns Promise<number> The LST APR (not divided by 1e18)
648
985
  */
649
986
  async getLSTAPR(_address: ContractAddr): Promise<number> {
650
987
  try {
651
- const vesuAdapter1 = this.getVesuSameTokenAdapter(this.metadata.additionalInfo.defaultPoolId);
652
- const apr = await LSTAPRService.getLSTAPR(vesuAdapter1.config.debt.address);
988
+ const vesuAdapter1 = this.getVesuSameTokenAdapter(
989
+ this.metadata.additionalInfo.defaultPoolId,
990
+ );
991
+ const apr = await LSTAPRService.getLSTAPR(
992
+ vesuAdapter1.config.debt.address,
993
+ );
653
994
  if (!apr) {
654
- throw new Error('Failed to get LST APR');
995
+ throw new Error("Failed to get LST APR");
655
996
  }
656
997
  return apr;
657
998
  } catch (error) {
@@ -661,119 +1002,170 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
661
1002
  }
662
1003
 
663
1004
  // todo undo this
664
- async netAPY(): Promise<{ net: number; splits: { apy: number; id: string; }[]; }> {
1005
+ async netAPY(): Promise<{
1006
+ net: number;
1007
+ splits: { apy: number; id: string }[];
1008
+ }> {
665
1009
  const unusedBalance = await this.getUnusedBalance();
666
- const maxNewDeposits = await this.maxNewDeposits({ isAPYComputation: true });
667
- const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
1010
+ const maxNewDeposits = await this.maxNewDeposits({
1011
+ isAPYComputation: true,
1012
+ });
1013
+ const lstAPY = await this.getLSTAPR(
1014
+ this.getLSTUnderlyingTokenInfo().address,
1015
+ );
668
1016
 
669
1017
  // if unused balance is > max servicable from loan, we are limited by the max borrowing we can do
670
1018
  // we also allow accepting little higher deposits (1.5x) to have room for future looping when theres more liquidity or debt cap rises
671
1019
  if (maxNewDeposits * 1.5 < unusedBalance.amount.toNumber()) {
672
1020
  // we have excess, just use real APY
673
- logger.verbose(`${this.getTag()}::netAPY: unused balance is > max servicable from loan, lstAPY: ${lstAPY}`);
1021
+ logger.verbose(
1022
+ `${this.getTag()}::netAPY: unused balance is > max servicable from loan, lstAPY: ${lstAPY}`,
1023
+ );
674
1024
  const output = await super.netAPY();
675
- output.splits.push({apy: lstAPY, id: 'lst_apy'});
1025
+ output.splits.push({ apy: lstAPY, id: "lst_apy" });
676
1026
  return output;
677
1027
  } else {
678
1028
  // we have little bit room to accept more deposits, we use theoretical max APY
679
- logger.verbose(`${this.getTag()}::netAPY: we can take more deposits, use theoretical max APY`);
1029
+ logger.verbose(
1030
+ `${this.getTag()}::netAPY: we can take more deposits, use theoretical max APY`,
1031
+ );
680
1032
  const { positions, baseAPYs, rewardAPYs } = await this.getVesuAPYs();
681
- const weights = positions.map((p, index) => p.usdValue * (index % 2 == 0 ? 1 : -1));
1033
+ const weights = positions.map(
1034
+ (p, index) => p.usdValue * (index % 2 == 0 ? 1 : -1),
1035
+ );
682
1036
  const aum = weights.reduce((acc, curr) => acc + curr, 0);
683
- const output = await this.returnNetAPY(baseAPYs, rewardAPYs, weights, new Web3Number(aum.toFixed(9), this.getLSTUnderlyingTokenInfo().decimals));
684
- output.splits.push({apy: lstAPY, id: 'lst_apy'});
1037
+ const output = await this.returnNetAPY(
1038
+ baseAPYs,
1039
+ rewardAPYs,
1040
+ weights,
1041
+ new Web3Number(
1042
+ aum.toFixed(9),
1043
+ this.getLSTUnderlyingTokenInfo().decimals,
1044
+ ),
1045
+ );
1046
+ output.splits.push({ apy: lstAPY, id: "lst_apy" });
685
1047
  return output;
686
1048
  }
687
1049
  }
688
1050
 
689
- async maxNewDeposits(params: { isAPYComputation: boolean } = { isAPYComputation: false }) {
1051
+ async maxNewDeposits(
1052
+ params: { isAPYComputation: boolean } = { isAPYComputation: false },
1053
+ ) {
690
1054
  const maxBorrowableAmounts = await this.getMaxBorrowableAmount(params);
691
1055
  let numerator = 0;
692
1056
 
693
1057
  let ltv: number | undefined = undefined;
694
1058
  for (let adapter of this.getVesuAdapters()) {
695
- const maxBorrowableAmountInfo = maxBorrowableAmounts.maxBorrowables.find(b => b.borrowableAsset.address.eq(adapter.config.debt.address));
1059
+ const maxBorrowableAmountInfo = maxBorrowableAmounts.maxBorrowables.find(
1060
+ (b) => b.borrowableAsset.address.eq(adapter.config.debt.address),
1061
+ );
696
1062
  if (!maxBorrowableAmountInfo || !maxBorrowableAmountInfo?.amount) {
697
- throw new Error(`Max borrowable amount not found for adapter: ${adapter.config.debt.symbol}`);
1063
+ throw new Error(
1064
+ `Max borrowable amount not found for adapter: ${adapter.config.debt.symbol}`,
1065
+ );
698
1066
  }
699
1067
 
700
- numerator += this.metadata.additionalInfo.targetHealthFactor * maxBorrowableAmountInfo.amount.toNumber() / maxBorrowableAmountInfo.ltv;
1068
+ numerator +=
1069
+ (this.metadata.additionalInfo.targetHealthFactor *
1070
+ maxBorrowableAmountInfo.amount.toNumber()) /
1071
+ maxBorrowableAmountInfo.ltv;
701
1072
  }
702
1073
 
703
- return numerator - maxBorrowableAmounts.netMaxBorrowableAmount.toNumber();
1074
+ return numerator - maxBorrowableAmounts.netMaxBorrowableAmount.toNumber();
704
1075
  }
705
1076
 
706
1077
  // todo revisit cases where 0th adapters is used
707
1078
  protected async getUnusedBalanceAPY() {
708
1079
  const unusedBalance = await this.getUnusedBalance();
709
- const vesuAdapter = this.getVesuSameTokenAdapter(this.metadata.additionalInfo.defaultPoolId);
1080
+ const vesuAdapter = this.getVesuSameTokenAdapter(
1081
+ this.metadata.additionalInfo.defaultPoolId,
1082
+ );
710
1083
  const underlying = vesuAdapter.config.debt;
711
1084
  const lstAPY = await this.getLSTAPR(underlying.address);
712
1085
  return {
713
- apy: lstAPY, weight: unusedBalance.usdValue
714
- }
1086
+ apy: lstAPY,
1087
+ weight: unusedBalance.usdValue,
1088
+ };
715
1089
  }
716
1090
 
717
1091
  async getLSTAvnuRate() {
718
- const vesuAdapter1 = this.getVesuSameTokenAdapter(this.metadata.additionalInfo.defaultPoolId);
1092
+ const vesuAdapter1 = this.getVesuSameTokenAdapter(
1093
+ this.metadata.additionalInfo.defaultPoolId,
1094
+ );
719
1095
  const lstTokenInfo = vesuAdapter1.config.collateral;
720
1096
  const underlyingTokenInfo = vesuAdapter1.config.debt;
721
1097
 
722
1098
  const avnuModule = new AvnuWrapper();
723
1099
 
724
- const sellAmount = lstTokenInfo.priceCheckAmount
725
- ? new Web3Number(lstTokenInfo.priceCheckAmount,underlyingTokenInfo.decimals)
726
- : new Web3Number(1,underlyingTokenInfo.decimals)
1100
+ const sellAmount = lstTokenInfo.priceCheckAmount
1101
+ ? new Web3Number(
1102
+ lstTokenInfo.priceCheckAmount,
1103
+ underlyingTokenInfo.decimals,
1104
+ )
1105
+ : new Web3Number(1, underlyingTokenInfo.decimals);
727
1106
 
728
1107
  const quote = await avnuModule.getQuotes(
729
1108
  underlyingTokenInfo.address.address,
730
1109
  lstTokenInfo.address.address,
731
1110
  sellAmount.toWei(),
732
- this.metadata.additionalInfo.vaultAllocator.address
1111
+ this.metadata.additionalInfo.vaultAllocator.address,
733
1112
  );
734
1113
 
735
1114
  const underlyingAmountNumber = sellAmount.toNumber();
736
1115
  const lstAmountNumber = Web3Number.fromWei(
737
1116
  quote.buyAmount.toString(),
738
- lstTokenInfo.decimals
1117
+ lstTokenInfo.decimals,
739
1118
  ).toNumber();
740
1119
 
741
- assert(lstAmountNumber > 0, 'Avnu LST amount is zero');
1120
+ assert(lstAmountNumber > 0, "Avnu LST amount is zero");
742
1121
 
743
1122
  const exchangeRate = underlyingAmountNumber / lstAmountNumber;
744
- logger.verbose(`${this.getTag()}:: LST Avnu Exchange Rate: ${exchangeRate}`);
1123
+ logger.verbose(
1124
+ `${this.getTag()}:: LST Avnu Exchange Rate: ${exchangeRate}`,
1125
+ );
745
1126
  return exchangeRate;
746
1127
  }
747
1128
 
748
1129
  async getLSTExchangeRate() {
749
- const vesuAdapter1 = this.getVesuSameTokenAdapter(this.metadata.additionalInfo.defaultPoolId);
1130
+ const vesuAdapter1 = this.getVesuSameTokenAdapter(
1131
+ this.metadata.additionalInfo.defaultPoolId,
1132
+ );
750
1133
  const lstTokenInfo = vesuAdapter1.config.collateral;
751
1134
  const lstABI = new Contract({
752
1135
  abi: ERC4626Abi,
753
1136
  address: lstTokenInfo.address.address,
754
- providerOrAccount: this.config.provider
1137
+ providerOrAccount: this.config.provider,
755
1138
  });
756
1139
 
757
- const price: any = await lstABI.call('convert_to_assets', [uint256.bnToUint256((new Web3Number(1, lstTokenInfo.decimals)).toWei())]);
758
- const exchangeRate = Number(uint256.uint256ToBN(price).toString()) / Math.pow(10, lstTokenInfo.decimals);
1140
+ const price: any = await lstABI.call("convert_to_assets", [
1141
+ uint256.bnToUint256(new Web3Number(1, lstTokenInfo.decimals).toWei()),
1142
+ ]);
1143
+ const exchangeRate =
1144
+ Number(uint256.uint256ToBN(price).toString()) /
1145
+ Math.pow(10, lstTokenInfo.decimals);
759
1146
  logger.verbose(`${this.getTag()}:: LST Exchange Rate: ${exchangeRate}`);
760
1147
  return exchangeRate;
761
- }
1148
+ }
762
1149
 
763
1150
  /**
764
- *
1151
+ *
765
1152
  * @param params marginAmount is in LST, debtAmount is in underlying
766
1153
  */
767
1154
  async getModifyLeverCall(params: {
768
- marginAmount: Web3Number, // >0 during deposit
769
- debtAmount: Web3Number,
770
- lstDexPriceInUnderlying: number,
771
- isIncrease: boolean,
772
- maxEkuboPriceImpact: number,
773
- poolId: ContractAddr
1155
+ marginAmount: Web3Number; // >0 during deposit
1156
+ debtAmount: Web3Number;
1157
+ lstDexPriceInUnderlying: number;
1158
+ isIncrease: boolean;
1159
+ maxEkuboPriceImpact: number;
1160
+ poolId: ContractAddr;
774
1161
  }): Promise<Call[]> {
775
- logger.verbose(`${this.getTag()}::getModifyLeverCall marginAmount: ${params.marginAmount}, debtAmount: ${params.debtAmount}, lstDexPriceInUnderlying: ${params.lstDexPriceInUnderlying}, isIncrease: ${params.isIncrease}`);
776
- assert(!params.marginAmount.isZero() || !params.debtAmount.isZero(), 'Deposit/debt must be non-0');
1162
+ logger.verbose(
1163
+ `${this.getTag()}::getModifyLeverCall marginAmount: ${params.marginAmount}, debtAmount: ${params.debtAmount}, lstDexPriceInUnderlying: ${params.lstDexPriceInUnderlying}, isIncrease: ${params.isIncrease}`,
1164
+ );
1165
+ assert(
1166
+ !params.marginAmount.isZero() || !params.debtAmount.isZero(),
1167
+ "Deposit/debt must be non-0",
1168
+ );
777
1169
 
778
1170
  const vesuAdapter1 = this.getVesuSameTokenAdapter(params.poolId);
779
1171
  const lstTokenInfo = this.asset();
@@ -781,9 +1173,11 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
781
1173
 
782
1174
  // todo make it more general
783
1175
  // 500k STRK (~75k$) or 0.5 BTC (~60k$)
784
- const maxAmounts = lstTokenInfo.symbol == 'xSTRK' ? 500000 : 0.5;
1176
+ const maxAmounts = lstTokenInfo.symbol == "xSTRK" ? 500000 : 0.5;
785
1177
  if (params.marginAmount.greaterThan(maxAmounts)) {
786
- throw new Error(`Margin amount is greater than max amount: ${params.marginAmount.toNumber()} > ${maxAmounts}`);
1178
+ throw new Error(
1179
+ `Margin amount is greater than max amount: ${params.marginAmount.toNumber()} > ${maxAmounts}`,
1180
+ );
787
1181
  }
788
1182
 
789
1183
  const proofsIDs: string[] = [];
@@ -791,12 +1185,15 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
791
1185
 
792
1186
  // approve token
793
1187
  if (params.marginAmount.greaterThan(0)) {
794
- const STEP1_ID = getVesuGenericLegId(params.poolId.toString(), LST_MULTIPLIER_MANAGE_IDS.MULTIPLE_APPROVE);
1188
+ const STEP1_ID = getVesuGenericLegId(
1189
+ params.poolId.toString(),
1190
+ LST_MULTIPLIER_MANAGE_IDS.MULTIPLE_APPROVE,
1191
+ );
795
1192
  const manage1Info = this.getProofs<ApproveCallParams>(STEP1_ID);
796
1193
  const depositAmount = params.marginAmount;
797
1194
  const manageCall1 = manage1Info.callConstructor({
798
- amount: depositAmount
799
- })
1195
+ amount: depositAmount,
1196
+ });
800
1197
  proofsIDs.push(STEP1_ID);
801
1198
  manageCalls.push(manageCall1);
802
1199
  }
@@ -813,75 +1210,119 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
813
1210
  const fromToken = params.isIncrease ? lstUnderlyingTokenInfo : lstTokenInfo;
814
1211
  const toToken = params.isIncrease ? lstTokenInfo : lstUnderlyingTokenInfo;
815
1212
  const leverSwapQuote = await ekuboQuoter.getQuote(
816
- fromToken.address.address,
817
- toToken.address.address,
818
- params.debtAmount // negative for exact amount out
1213
+ fromToken.address.address,
1214
+ toToken.address.address,
1215
+ params.debtAmount, // negative for exact amount out
1216
+ );
1217
+ logger.verbose(
1218
+ `${this.getTag()}::getModifyLeverCall leverSwapQuote: ${JSON.stringify(leverSwapQuote)}`,
1219
+ );
1220
+ // Ekubo's price impact can randomly show high numbers sometimes.
1221
+ assert(
1222
+ leverSwapQuote.price_impact <= params.maxEkuboPriceImpact,
1223
+ "getIncreaseLeverCall: Price impact is too high [Debt swap]",
1224
+ );
1225
+ const leverSwap = ekuboQuoter.getVesuMultiplyQuote(
1226
+ leverSwapQuote,
1227
+ fromToken,
1228
+ toToken,
1229
+ );
1230
+ logger.verbose(
1231
+ `${this.getTag()}::getModifyLeverCall leverSwap: ${JSON.stringify(leverSwap)}`,
819
1232
  );
820
- logger.verbose(`${this.getTag()}::getModifyLeverCall leverSwapQuote: ${JSON.stringify(leverSwapQuote)}`);
821
- // Ekubo's price impact can randomly show high numbers sometimes.
822
- assert(leverSwapQuote.price_impact <= params.maxEkuboPriceImpact, 'getIncreaseLeverCall: Price impact is too high [Debt swap]');
823
- const leverSwap = ekuboQuoter.getVesuMultiplyQuote(leverSwapQuote, fromToken, toToken);
824
- logger.verbose(`${this.getTag()}::getModifyLeverCall leverSwap: ${JSON.stringify(leverSwap)}`);
825
1233
 
826
1234
  // todo double check this logic
827
1235
  // is Deposit
828
- let minLSTReceived = params.debtAmount.dividedBy(lstDexPriceInUnderlying).multipliedBy(1 - MAX_SLIPPAGE); // used for increase
829
- const minLSTReceivedAsPerTruePrice = params.debtAmount.dividedBy(lstTrueExchangeRate); // execution output to be <= True LST price
1236
+ let minLSTReceived = params.debtAmount
1237
+ .dividedBy(lstDexPriceInUnderlying)
1238
+ .multipliedBy(1 - MAX_SLIPPAGE); // used for increase
1239
+ const minLSTReceivedAsPerTruePrice =
1240
+ params.debtAmount.dividedBy(lstTrueExchangeRate); // execution output to be <= True LST price
830
1241
  // if (minLSTReceived < minLSTReceivedAsPerTruePrice) {
831
1242
  // minLSTReceived = minLSTReceivedAsPerTruePrice; // the execution shouldn't be bad than True price logi
832
1243
  // }
833
1244
  minLSTReceived = minLSTReceivedAsPerTruePrice; // in any case, we are ok with this, bcz the BTC LST spread shouldnt be high
834
- logger.verbose(`${this.getTag()}::getModifyLeverCall minLSTReceivedAsPerTruePrice: ${minLSTReceivedAsPerTruePrice}, minLSTReceived: ${minLSTReceived}`);
1245
+ logger.verbose(
1246
+ `${this.getTag()}::getModifyLeverCall minLSTReceivedAsPerTruePrice: ${minLSTReceivedAsPerTruePrice}, minLSTReceived: ${minLSTReceived}`,
1247
+ );
835
1248
 
836
1249
  // is withdraw
837
- let maxUsedCollateral = params.debtAmount.abs().dividedBy(lstDexPriceInUnderlying).multipliedBy(1 + MAX_SLIPPAGE); // +ve for exact amount out, used for decrease
838
- const maxUsedCollateralInLST = params.debtAmount.abs().dividedBy(lstTrueExchangeRate).multipliedBy(1.005); // 0.5% slippage, worst case based on true price
839
- logger.verbose(`${this.getTag()}::getModifyLeverCall maxUsedCollateralInLST: ${maxUsedCollateralInLST}, maxUsedCollateral: ${maxUsedCollateral}`);
1250
+ let maxUsedCollateral = params.debtAmount
1251
+ .abs()
1252
+ .dividedBy(lstDexPriceInUnderlying)
1253
+ .multipliedBy(1 + MAX_SLIPPAGE); // +ve for exact amount out, used for decrease
1254
+ const maxUsedCollateralInLST = params.debtAmount
1255
+ .abs()
1256
+ .dividedBy(lstTrueExchangeRate)
1257
+ .multipliedBy(1.005); // 0.5% slippage, worst case based on true price
1258
+ logger.verbose(
1259
+ `${this.getTag()}::getModifyLeverCall maxUsedCollateralInLST: ${maxUsedCollateralInLST}, maxUsedCollateral: ${maxUsedCollateral}`,
1260
+ );
840
1261
  // if (maxUsedCollateralInLST > maxUsedCollateral) {
841
1262
  // maxUsedCollateral = maxUsedCollateralInLST;
842
1263
  // }
843
1264
  maxUsedCollateral = maxUsedCollateralInLST; // in any case, we are ok with this, bcz the BTC LST spread shouldnt be high
844
1265
 
845
- const STEP2_ID = getVesuGenericLegId(params.poolId.toString(), LST_MULTIPLIER_MANAGE_IDS.SWITCH_DELEGATION_ON);
846
- const manage2Info = this.getProofs<VesuModifyDelegationCallParams>(STEP2_ID);
1266
+ const STEP2_ID = getVesuGenericLegId(
1267
+ params.poolId.toString(),
1268
+ LST_MULTIPLIER_MANAGE_IDS.SWITCH_DELEGATION_ON,
1269
+ );
1270
+ const manage2Info =
1271
+ this.getProofs<VesuModifyDelegationCallParams>(STEP2_ID);
847
1272
  const manageCall2 = manage2Info.callConstructor({
848
1273
  delegation: true,
849
1274
  });
850
1275
 
851
1276
  // deposit and borrow or repay and withdraw
852
- const STEP3_ID = getVesuLegId(LST_MULTIPLIER_MANAGE_IDS.MULTIPLY_VESU, vesuAdapter1.config.debt.symbol, vesuAdapter1.config.poolId.toString());
1277
+ const STEP3_ID = getVesuLegId(
1278
+ LST_MULTIPLIER_MANAGE_IDS.MULTIPLY_VESU,
1279
+ vesuAdapter1.config.debt.symbol,
1280
+ vesuAdapter1.config.poolId.toString(),
1281
+ );
853
1282
  const manage3Info = this.getProofs<VesuMultiplyCallParams>(STEP3_ID);
854
- const multiplyParams: VesuMultiplyCallParams = params.isIncrease ? {
855
- isIncrease: true,
856
- increaseParams: {
857
- add_margin: params.marginAmount,
858
- margin_swap: [],
859
- margin_swap_limit_amount: Web3Number.fromWei(0, this.asset().decimals),
860
- lever_swap: leverSwap,
861
- lever_swap_limit_amount: minLSTReceived
862
- }
863
- } : {
864
- isIncrease: false,
865
- decreaseParams: {
866
- sub_margin: params.marginAmount.multipliedBy(-1),
867
- lever_swap: leverSwap,
868
- lever_swap_limit_amount: maxUsedCollateral,
869
- // only required for close position
870
- lever_swap_weights: [],
871
- // no need to swap collateral to anything, and any residuals return our contract anyways.
872
- withdraw_swap: [],
873
- withdraw_swap_limit_amount: Web3Number.fromWei(0, this.asset().decimals),
874
- withdraw_swap_weights: [],
875
- close_position: false
876
- }
877
- }
1283
+ const multiplyParams: VesuMultiplyCallParams = params.isIncrease
1284
+ ? {
1285
+ isIncrease: true,
1286
+ increaseParams: {
1287
+ add_margin: params.marginAmount,
1288
+ margin_swap: [],
1289
+ margin_swap_limit_amount: Web3Number.fromWei(
1290
+ 0,
1291
+ this.asset().decimals,
1292
+ ),
1293
+ lever_swap: leverSwap,
1294
+ lever_swap_limit_amount: minLSTReceived,
1295
+ },
1296
+ }
1297
+ : {
1298
+ isIncrease: false,
1299
+ decreaseParams: {
1300
+ sub_margin: params.marginAmount.multipliedBy(-1),
1301
+ lever_swap: leverSwap,
1302
+ lever_swap_limit_amount: maxUsedCollateral,
1303
+ // only required for close position
1304
+ lever_swap_weights: [],
1305
+ // no need to swap collateral to anything, and any residuals return our contract anyways.
1306
+ withdraw_swap: [],
1307
+ withdraw_swap_limit_amount: Web3Number.fromWei(
1308
+ 0,
1309
+ this.asset().decimals,
1310
+ ),
1311
+ withdraw_swap_weights: [],
1312
+ close_position: false,
1313
+ },
1314
+ };
878
1315
  const manageCall3 = manage3Info.callConstructor(multiplyParams);
879
1316
 
880
1317
  // switch delegation off
881
- const STEP4_ID = getVesuGenericLegId(params.poolId.toString(), LST_MULTIPLIER_MANAGE_IDS.SWITCH_DELEGATION_OFF);
882
- const manage4Info = this.getProofs<VesuModifyDelegationCallParams>(STEP4_ID);
1318
+ const STEP4_ID = getVesuGenericLegId(
1319
+ params.poolId.toString(),
1320
+ LST_MULTIPLIER_MANAGE_IDS.SWITCH_DELEGATION_OFF,
1321
+ );
1322
+ const manage4Info =
1323
+ this.getProofs<VesuModifyDelegationCallParams>(STEP4_ID);
883
1324
  const manageCall4 = manage4Info.callConstructor({
884
- delegation: false
1325
+ delegation: false,
885
1326
  });
886
1327
 
887
1328
  proofsIDs.push(STEP2_ID, STEP3_ID, STEP4_ID);
@@ -893,12 +1334,11 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<HyperLSTSt
893
1334
 
894
1335
  export default function VaultDescription(
895
1336
  lstSymbol: string,
896
- underlyingSymbol: string
1337
+ underlyingSymbol: string,
897
1338
  ) {
898
1339
  const containerStyle = {
899
1340
  maxWidth: "800px",
900
1341
  margin: "0 auto",
901
- backgroundColor: "#111",
902
1342
  color: "#eee",
903
1343
  fontFamily: "Arial, sans-serif",
904
1344
  borderRadius: "12px",
@@ -906,26 +1346,64 @@ export default function VaultDescription(
906
1346
 
907
1347
  return (
908
1348
  <div style={containerStyle}>
909
- <h1 style={{ fontSize: "18px", marginBottom: "10px" }}>Liquidation risk managed leverged {lstSymbol} Vault</h1>
1349
+ <h1 style={{ fontSize: "18px", marginBottom: "10px" }}>
1350
+ Liquidation risk managed leverged {lstSymbol} Vault
1351
+ </h1>
910
1352
  <p style={{ fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }}>
911
- This Levered Endur {lstSymbol} vault is a tokenized leveraged Vault, auto-compounding strategy that takes upto 5x leverage on {lstSymbol} by borrow {underlyingSymbol}. Borrowed amount
912
- is swapped to {lstSymbol} to create leverage. Depositors receive vault shares that
913
- represent a proportional claim on the underlying assets and accrued yield.
1353
+ This Levered Endur {lstSymbol} vault is a tokenized leveraged Vault,
1354
+ auto-compounding strategy that takes upto 5x leverage on {lstSymbol} by
1355
+ borrow {underlyingSymbol}. Borrowed amount is swapped to {lstSymbol} to
1356
+ create leverage. Depositors receive vault shares that represent a
1357
+ proportional claim on the underlying assets and accrued yield.
914
1358
  </p>
915
1359
 
916
1360
  <p style={{ fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }}>
917
- This vault uses Vesu for lending and borrowing. The oracle used by this pool is a {highlightTextWithLinks("conversion rate oracle", [{highlight: "conversion rate oracle", link: "https://docs.pragma.build/starknet/development#conversion-rate"}])}
918
- {" "}which is resilient to liquidity issues and price volatility, hence reducing the risk of liquidation. However, overtime, if left un-monitored, debt can increase enough to trigger a liquidation. But no worries, our continuous monitoring systems look for situations with reduced health factor and balance collateral/debt to bring it back to safe levels. With Troves, you can have a peaceful sleep.
1361
+ This vault uses Vesu for lending and borrowing. The oracle used by this
1362
+ pool is a{" "}
1363
+ {highlightTextWithLinks("conversion rate oracle", [
1364
+ {
1365
+ highlight: "conversion rate oracle",
1366
+ link: "https://docs.pragma.build/starknet/development#conversion-rate",
1367
+ },
1368
+ ])}{" "}
1369
+ which is resilient to liquidity issues and price volatility, hence
1370
+ reducing the risk of liquidation. However, overtime, if left
1371
+ un-monitored, debt can increase enough to trigger a liquidation. But no
1372
+ worries, our continuous monitoring systems look for situations with
1373
+ reduced health factor and balance collateral/debt to bring it back to
1374
+ safe levels. With Troves, you can have a peaceful sleep.
919
1375
  </p>
920
1376
 
921
- <div style={{ backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }}>
1377
+ <div
1378
+ style={{
1379
+ backgroundColor: "#222",
1380
+ padding: "10px",
1381
+ borderRadius: "8px",
1382
+ marginBottom: "20px",
1383
+ border: "1px solid #444",
1384
+ }}
1385
+ >
922
1386
  <p style={{ fontSize: "13px", color: "#ccc" }}>
923
- <strong>Withdrawals:</strong> Requests can take up to <strong>1-2 hours</strong> to process as the vault unwinds and settles routing.
1387
+ <strong>Withdrawals:</strong> Requests can take up to{" "}
1388
+ <strong>1-2 hours</strong> to process as the vault unwinds and settles
1389
+ routing.
924
1390
  </p>
925
1391
  </div>
926
- <div style={{ backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }}>
1392
+ <div
1393
+ style={{
1394
+ backgroundColor: "#222",
1395
+ padding: "10px",
1396
+ borderRadius: "8px",
1397
+ marginBottom: "20px",
1398
+ border: "1px solid #444",
1399
+ }}
1400
+ >
927
1401
  <p style={{ fontSize: "13px", color: "#ccc" }}>
928
- <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.
1402
+ <strong>Debt limits:</strong> Pools on Vesu have debt caps that are
1403
+ gradually increased over time. Until caps are raised, deposited LSTs
1404
+ remain in the vault, generating a shared net return for all
1405
+ depositors. There is no additional fee taken by Troves on LST APY, its
1406
+ only on added gain.
929
1407
  </p>
930
1408
  </div>
931
1409
  {/* <div style={{ backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }}>
@@ -937,24 +1415,25 @@ export default function VaultDescription(
937
1415
  );
938
1416
  }
939
1417
 
940
-
941
1418
  function getDescription(tokenSymbol: string, underlyingSymbol: string) {
942
1419
  return VaultDescription(tokenSymbol, underlyingSymbol);
943
1420
  }
944
1421
 
945
-
946
- enum LST_MULTIPLIER_MANAGE_IDS {
947
- MULTIPLE_APPROVE = 'multiple_approve',
948
- MULTIPLY_VESU = 'multiply_vesu',
949
- SWITCH_DELEGATION_ON = 'switch_delegation_on',
950
- SWITCH_DELEGATION_OFF = 'switch_delegation_off',
951
- AVNU_MULTIPLY_APPROVE_DEPOSIT = 'avnu_mul_approve_dep',
952
- AVNU_MULTIPLY_SWAP_DEPOSIT = 'avnu_mul_swap_dep',
953
- AVNU_MULTIPLY_APPROVE_WITHDRAW = 'avnu_mul_approve_withdr',
954
- AVNU_MULTIPLY_SWAP_WITHDRAW = 'avnu_mul_swap_withdr',
1422
+ enum LST_MULTIPLIER_MANAGE_IDS {
1423
+ MULTIPLE_APPROVE = "multiple_approve",
1424
+ MULTIPLY_VESU = "multiply_vesu",
1425
+ SWITCH_DELEGATION_ON = "switch_delegation_on",
1426
+ SWITCH_DELEGATION_OFF = "switch_delegation_off",
1427
+ AVNU_MULTIPLY_APPROVE_DEPOSIT = "avnu_mul_approve_dep",
1428
+ AVNU_MULTIPLY_SWAP_DEPOSIT = "avnu_mul_swap_dep",
1429
+ AVNU_MULTIPLY_APPROVE_WITHDRAW = "avnu_mul_approve_withdr",
1430
+ AVNU_MULTIPLY_SWAP_WITHDRAW = "avnu_mul_swap_withdr",
955
1431
  }
956
1432
 
957
- function getAvnuManageIDs(baseID: LST_MULTIPLIER_MANAGE_IDS, debtTokenSymbol: string) {
1433
+ function getAvnuManageIDs(
1434
+ baseID: LST_MULTIPLIER_MANAGE_IDS,
1435
+ debtTokenSymbol: string,
1436
+ ) {
958
1437
  return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
959
1438
  }
960
1439
 
@@ -973,45 +1452,100 @@ function addVesuLeaves(
973
1452
  vaultSettings: HyperLSTStrategySettings,
974
1453
  commonAdapter: CommonAdapter,
975
1454
  ) {
976
- const lstToken = Global.getDefaultTokens().find(token => token.symbol === lstSymbol)!;
977
- const underlyingToken = Global.getDefaultTokens().find(token => token.symbol === underlyingSymbol)!;
1455
+ const lstToken = Global.getDefaultTokens().find(
1456
+ (token) => token.symbol === lstSymbol,
1457
+ )!;
1458
+ const underlyingToken = Global.getDefaultTokens().find(
1459
+ (token) => token.symbol === underlyingSymbol,
1460
+ )!;
978
1461
 
979
1462
  const vesuAdapterLST = new VesuAdapter({
980
1463
  poolId: poolId,
981
1464
  collateral: lstToken,
982
1465
  debt: underlyingToken,
983
1466
  vaultAllocator: vaultSettings.vaultAllocator,
984
- id: getVesuLegId(UNIVERSAL_MANAGE_IDS.VESU_LEG1, underlyingToken.symbol, poolId.toString())
1467
+ id: getVesuLegId(
1468
+ UNIVERSAL_MANAGE_IDS.VESU_LEG1,
1469
+ underlyingToken.symbol,
1470
+ poolId.toString(),
1471
+ ),
985
1472
  });
986
1473
 
987
1474
  // Useful for returning adapter class objects that can compute
988
1475
  // certain things for us (e.g. positions, hfs)
989
- vaultSettings.adapters.push(...[{
990
- id: getVesuLegId(UNIVERSAL_MANAGE_IDS.VESU_LEG1, underlyingToken.symbol, poolId.toString()),
991
- adapter: vesuAdapterLST
992
- }]);
1476
+ vaultSettings.adapters.push(
1477
+ ...[
1478
+ {
1479
+ id: getVesuLegId(
1480
+ UNIVERSAL_MANAGE_IDS.VESU_LEG1,
1481
+ underlyingToken.symbol,
1482
+ poolId.toString(),
1483
+ ),
1484
+ adapter: vesuAdapterLST,
1485
+ },
1486
+ ],
1487
+ );
993
1488
 
994
1489
  // avnu multiply
995
1490
  const { isV2, addr: poolAddr } = getVesuSingletonAddress(poolId);
996
1491
 
997
1492
  // vesu multiply looping
998
- const VESU_MULTIPLY = isV2 ? vesuAdapterLST.VESU_MULTIPLY : vesuAdapterLST.VESU_MULTIPLY_V1;
999
-
1000
- const leafIdApprove = getVesuGenericLegId(poolId.toString(), LST_MULTIPLIER_MANAGE_IDS.MULTIPLE_APPROVE);
1001
- vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, VESU_MULTIPLY, leafIdApprove).bind(commonAdapter));
1002
-
1003
- const leafIdDelegationOn = getVesuGenericLegId(poolId.toString(), LST_MULTIPLIER_MANAGE_IDS.SWITCH_DELEGATION_ON);
1004
- vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter(leafIdDelegationOn, VESU_MULTIPLY).bind(vesuAdapterLST));
1005
-
1006
- const leafIdDelegationOff = getVesuGenericLegId(poolId.toString(), LST_MULTIPLIER_MANAGE_IDS.SWITCH_DELEGATION_OFF);
1007
- vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter(leafIdDelegationOff, VESU_MULTIPLY).bind(vesuAdapterLST));
1008
-
1009
- const multiplID = getVesuLegId(LST_MULTIPLIER_MANAGE_IDS.MULTIPLY_VESU, underlyingToken.symbol, poolId.toString());
1010
- vaultSettings.leafAdapters.push(vesuAdapterLST.getMultiplyAdapter(multiplID).bind(vesuAdapterLST));
1011
-
1493
+ const VESU_MULTIPLY = isV2
1494
+ ? vesuAdapterLST.VESU_MULTIPLY
1495
+ : vesuAdapterLST.VESU_MULTIPLY_V1;
1496
+
1497
+ const leafIdApprove = getVesuGenericLegId(
1498
+ poolId.toString(),
1499
+ LST_MULTIPLIER_MANAGE_IDS.MULTIPLE_APPROVE,
1500
+ );
1501
+ vaultSettings.leafAdapters.push(
1502
+ commonAdapter
1503
+ .getApproveAdapter(lstToken.address, VESU_MULTIPLY, leafIdApprove)
1504
+ .bind(commonAdapter),
1505
+ );
1506
+
1507
+ const leafIdDelegationOn = getVesuGenericLegId(
1508
+ poolId.toString(),
1509
+ LST_MULTIPLIER_MANAGE_IDS.SWITCH_DELEGATION_ON,
1510
+ );
1511
+ vaultSettings.leafAdapters.push(
1512
+ vesuAdapterLST
1513
+ .getVesuModifyDelegationAdapter(leafIdDelegationOn, VESU_MULTIPLY)
1514
+ .bind(vesuAdapterLST),
1515
+ );
1516
+
1517
+ const leafIdDelegationOff = getVesuGenericLegId(
1518
+ poolId.toString(),
1519
+ LST_MULTIPLIER_MANAGE_IDS.SWITCH_DELEGATION_OFF,
1520
+ );
1521
+ vaultSettings.leafAdapters.push(
1522
+ vesuAdapterLST
1523
+ .getVesuModifyDelegationAdapter(leafIdDelegationOff, VESU_MULTIPLY)
1524
+ .bind(vesuAdapterLST),
1525
+ );
1526
+
1527
+ const multiplID = getVesuLegId(
1528
+ LST_MULTIPLIER_MANAGE_IDS.MULTIPLY_VESU,
1529
+ underlyingToken.symbol,
1530
+ poolId.toString(),
1531
+ );
1532
+ vaultSettings.leafAdapters.push(
1533
+ vesuAdapterLST.getMultiplyAdapter(multiplID).bind(vesuAdapterLST),
1534
+ );
1535
+
1012
1536
  // direct modify position stuff
1013
- vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, poolAddr, UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN1).bind(commonAdapter));
1014
- vaultSettings.leafAdapters.push(vesuAdapterLST.getModifyPosition.bind(vesuAdapterLST));
1537
+ vaultSettings.leafAdapters.push(
1538
+ commonAdapter
1539
+ .getApproveAdapter(
1540
+ lstToken.address,
1541
+ poolAddr,
1542
+ UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN1,
1543
+ )
1544
+ .bind(commonAdapter),
1545
+ );
1546
+ vaultSettings.leafAdapters.push(
1547
+ vesuAdapterLST.getModifyPosition.bind(vesuAdapterLST),
1548
+ );
1015
1549
 
1016
1550
  return vesuAdapterLST;
1017
1551
  }
@@ -1020,7 +1554,7 @@ function getLooperSettings(
1020
1554
  lstSymbol: string,
1021
1555
  underlyingSymbol: string,
1022
1556
  vaultSettings: HyperLSTStrategySettings,
1023
- defaultPoolId: ContractAddr
1557
+ defaultPoolId: ContractAddr,
1024
1558
  ) {
1025
1559
  vaultSettings.leafAdapters = [];
1026
1560
  const pool1 = vaultSettings.defaultPoolId;
@@ -1028,82 +1562,179 @@ function getLooperSettings(
1028
1562
  throw new Error(`Dont include default pool id in supported pool ids`);
1029
1563
  }
1030
1564
 
1031
- const lstToken = Global.getDefaultTokens().find(token => token.symbol === lstSymbol)!;
1032
- const underlyingToken = Global.getDefaultTokens().find(token => token.symbol === underlyingSymbol)!;
1565
+ const lstToken = Global.getDefaultTokens().find(
1566
+ (token) => token.symbol === lstSymbol,
1567
+ )!;
1568
+ const underlyingToken = Global.getDefaultTokens().find(
1569
+ (token) => token.symbol === underlyingSymbol,
1570
+ )!;
1033
1571
 
1034
1572
  const commonAdapter = new CommonAdapter({
1035
1573
  manager: vaultSettings.manager,
1036
1574
  asset: lstToken.address,
1037
- id: '',
1575
+ id: "",
1038
1576
  vaultAddress: vaultSettings.vaultAddress,
1039
1577
  vaultAllocator: vaultSettings.vaultAllocator,
1040
1578
  });
1041
1579
 
1042
1580
  // add common adapter to adapters
1043
- vaultSettings.adapters.push(...[{
1044
- id: UNIVERSAL_ADAPTERS.COMMON,
1045
- adapter: commonAdapter
1046
- }]);
1581
+ vaultSettings.adapters.push(
1582
+ ...[
1583
+ {
1584
+ id: UNIVERSAL_ADAPTERS.COMMON,
1585
+ adapter: commonAdapter,
1586
+ },
1587
+ ],
1588
+ );
1047
1589
 
1048
1590
  // add vesu leaves for all supported pool ids
1049
- vaultSettings.borrowable_assets.map(borrowableAsset => addVesuLeaves(borrowableAsset.poolId, lstSymbol, underlyingSymbol, vaultSettings, commonAdapter));
1050
-
1591
+ vaultSettings.borrowable_assets.map((borrowableAsset) =>
1592
+ addVesuLeaves(
1593
+ borrowableAsset.poolId,
1594
+ lstSymbol,
1595
+ underlyingSymbol,
1596
+ vaultSettings,
1597
+ commonAdapter,
1598
+ ),
1599
+ );
1600
+
1051
1601
  // approve lst once to avnu
1052
- vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, AVNU_EXCHANGE, LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_APPROVE_WITHDRAW).bind(commonAdapter));
1053
-
1054
- const uniqueBorrowableAssets = [...new Set(vaultSettings.borrowable_assets.map(borrowableAsset => borrowableAsset.token.symbol))];
1602
+ vaultSettings.leafAdapters.push(
1603
+ commonAdapter
1604
+ .getApproveAdapter(
1605
+ lstToken.address,
1606
+ AVNU_EXCHANGE,
1607
+ LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_APPROVE_WITHDRAW,
1608
+ )
1609
+ .bind(commonAdapter),
1610
+ );
1611
+
1612
+ const uniqueBorrowableAssets = [
1613
+ ...new Set(
1614
+ vaultSettings.borrowable_assets.map(
1615
+ (borrowableAsset) => borrowableAsset.token.symbol,
1616
+ ),
1617
+ ),
1618
+ ];
1055
1619
  for (let borrowableAssetSymbol of uniqueBorrowableAssets) {
1056
- const borrowableAsset = Global.getDefaultTokens().find(token => token.symbol === borrowableAssetSymbol)!;
1620
+ const borrowableAsset = Global.getDefaultTokens().find(
1621
+ (token) => token.symbol === borrowableAssetSymbol,
1622
+ )!;
1057
1623
  // in-efficient avnu swap looping (but good with endur integration)
1058
1624
  const debtAsset = borrowableAsset;
1059
- const approve_debt_token_id = getAvnuManageIDs(LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_APPROVE_DEPOSIT, debtAsset.symbol);
1060
- const swap_debt_token_id = getAvnuManageIDs(LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_SWAP_DEPOSIT, debtAsset.symbol);
1061
- const swap_lst_token_id = getAvnuManageIDs(LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_SWAP_WITHDRAW, debtAsset.symbol);
1062
- vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(debtAsset.address, AVNU_EXCHANGE, approve_debt_token_id).bind(commonAdapter));
1063
- vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(debtAsset.address, lstToken.address, swap_debt_token_id, false).bind(commonAdapter));
1064
- vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(lstToken.address, debtAsset.address, swap_lst_token_id, false).bind(commonAdapter));
1625
+ const approve_debt_token_id = getAvnuManageIDs(
1626
+ LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_APPROVE_DEPOSIT,
1627
+ debtAsset.symbol,
1628
+ );
1629
+ const swap_debt_token_id = getAvnuManageIDs(
1630
+ LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_SWAP_DEPOSIT,
1631
+ debtAsset.symbol,
1632
+ );
1633
+ const swap_lst_token_id = getAvnuManageIDs(
1634
+ LST_MULTIPLIER_MANAGE_IDS.AVNU_MULTIPLY_SWAP_WITHDRAW,
1635
+ debtAsset.symbol,
1636
+ );
1637
+ vaultSettings.leafAdapters.push(
1638
+ commonAdapter
1639
+ .getApproveAdapter(
1640
+ debtAsset.address,
1641
+ AVNU_EXCHANGE,
1642
+ approve_debt_token_id,
1643
+ )
1644
+ .bind(commonAdapter),
1645
+ );
1646
+ vaultSettings.leafAdapters.push(
1647
+ commonAdapter
1648
+ .getAvnuAdapter(
1649
+ debtAsset.address,
1650
+ lstToken.address,
1651
+ swap_debt_token_id,
1652
+ false,
1653
+ )
1654
+ .bind(commonAdapter),
1655
+ );
1656
+ vaultSettings.leafAdapters.push(
1657
+ commonAdapter
1658
+ .getAvnuAdapter(
1659
+ lstToken.address,
1660
+ debtAsset.address,
1661
+ swap_lst_token_id,
1662
+ false,
1663
+ )
1664
+ .bind(commonAdapter),
1665
+ );
1065
1666
  }
1066
1667
 
1067
-
1068
1668
  // to bridge liquidity back to vault (used by bring_liquidity)
1069
- vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, vaultSettings.vaultAddress, UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY).bind(commonAdapter));
1070
- vaultSettings.leafAdapters.push(commonAdapter.getBringLiquidityAdapter(UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY).bind(commonAdapter));
1071
-
1669
+ vaultSettings.leafAdapters.push(
1670
+ commonAdapter
1671
+ .getApproveAdapter(
1672
+ lstToken.address,
1673
+ vaultSettings.vaultAddress,
1674
+ UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY,
1675
+ )
1676
+ .bind(commonAdapter),
1677
+ );
1678
+ vaultSettings.leafAdapters.push(
1679
+ commonAdapter
1680
+ .getBringLiquidityAdapter(UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY)
1681
+ .bind(commonAdapter),
1682
+ );
1683
+
1072
1684
  // claim rewards (defi spring ended)
1073
1685
  // vaultSettings.leafAdapters.push(vesuAdapterLST.getDefispringRewardsAdapter(UNIVERSAL_MANAGE_IDS.DEFISPRING_REWARDS).bind(vesuAdapterLST));
1074
1686
 
1075
1687
  // avnu swap for claims rewards
1076
- const STRKToken = Global.getDefaultTokens().find(token => token.symbol === 'STRK')!;
1077
- vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(STRKToken.address, AVNU_EXCHANGE, UNIVERSAL_MANAGE_IDS.APPROVE_SWAP_TOKEN1).bind(commonAdapter));
1078
- vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(STRKToken.address, lstToken.address, UNIVERSAL_MANAGE_IDS.AVNU_SWAP_REWARDS, false).bind(commonAdapter));
1688
+ const STRKToken = Global.getDefaultTokens().find(
1689
+ (token) => token.symbol === "STRK",
1690
+ )!;
1691
+ vaultSettings.leafAdapters.push(
1692
+ commonAdapter
1693
+ .getApproveAdapter(
1694
+ STRKToken.address,
1695
+ AVNU_EXCHANGE,
1696
+ UNIVERSAL_MANAGE_IDS.APPROVE_SWAP_TOKEN1,
1697
+ )
1698
+ .bind(commonAdapter),
1699
+ );
1700
+ vaultSettings.leafAdapters.push(
1701
+ commonAdapter
1702
+ .getAvnuAdapter(
1703
+ STRKToken.address,
1704
+ lstToken.address,
1705
+ UNIVERSAL_MANAGE_IDS.AVNU_SWAP_REWARDS,
1706
+ false,
1707
+ )
1708
+ .bind(commonAdapter),
1709
+ );
1079
1710
  return vaultSettings;
1080
1711
  }
1081
1712
 
1082
- const AUDIT_URL = 'https://docs.troves.fi/p/security#starknet-vault-kit'
1713
+ const AUDIT_URL = "https://docs.troves.fi/p/security#starknet-vault-kit";
1083
1714
 
1084
1715
  function getFAQs(lstSymbol: string, underlyingSymbol: string): FAQ[] {
1085
1716
  return [
1086
1717
  {
1087
1718
  question: `What is the Hyper ${lstSymbol} Vault?`,
1088
- answer:
1089
- `The Hyper ${lstSymbol} Vault is a tokenized strategy that automatically loops your ${lstSymbol} to create up to 5x leverage to hence yield in a very low risk manner.`,
1719
+ answer: `The Hyper ${lstSymbol} Vault is a tokenized strategy that automatically loops your ${lstSymbol} to create up to 5x leverage to hence yield in a very low risk manner.`,
1090
1720
  },
1091
1721
  {
1092
1722
  question: "How does yield allocation work?",
1093
- answer:
1094
- `The strategy uses deposited ${lstSymbol} to collateralize it on Vesu, borrow more ${underlyingSymbol} to loop further. Instead of manually doing this, using flash loan, this leverage is created in a single gas efficient step. Our continuous monitoring systems gauge current yield and available liquidity in real time to make sure yield is optimal. For instance, if the looping becomes in-efficient in future, the strategy will rebalance to reduce leverage or simply hold ${lstSymbol} to continue earning yield.`,
1723
+ answer: `The strategy uses deposited ${lstSymbol} to collateralize it on Vesu, borrow more ${underlyingSymbol} to loop further. Instead of manually doing this, using flash loan, this leverage is created in a single gas efficient step. Our continuous monitoring systems gauge current yield and available liquidity in real time to make sure yield is optimal. For instance, if the looping becomes in-efficient in future, the strategy will rebalance to reduce leverage or simply hold ${lstSymbol} to continue earning yield.`,
1095
1724
  },
1096
1725
  {
1097
1726
  question: "Which protocols/dApp are used??",
1098
1727
  answer: (
1099
1728
  <span>
1100
- Currently, the LST is from <strong>Endur</strong> while <strong>Vesu</strong> is used to collateralize the looped position.
1729
+ Currently, the LST is from <strong>Endur</strong> while{" "}
1730
+ <strong>Vesu</strong> is used to collateralize the looped position.
1101
1731
  </span>
1102
1732
  ),
1103
1733
  },
1104
1734
  {
1105
1735
  question: "Can I get liquidated?",
1106
- answer: "The strategy uses highly correlated assets which drastically reduces the risk of liquidation. However, overtime, if left un-monitored, debt can increase enough to trigger a liquidation. But no worries, our continuous monitoring systems look for situations with reduced health factor and balance collateral/debt to bring it back to safe levels. With Troves, you can have a peaceful sleep.",
1736
+ answer:
1737
+ "The strategy uses highly correlated assets which drastically reduces the risk of liquidation. However, overtime, if left un-monitored, debt can increase enough to trigger a liquidation. But no worries, our continuous monitoring systems look for situations with reduced health factor and balance collateral/debt to bring it back to safe levels. With Troves, you can have a peaceful sleep.",
1107
1738
  },
1108
1739
  {
1109
1740
  question: "What do I receive when I deposit?",
@@ -1134,107 +1765,209 @@ function getFAQs(lstSymbol: string, underlyingSymbol: string): FAQ[] {
1134
1765
  }
1135
1766
 
1136
1767
  const _riskFactor: RiskFactor[] = [
1137
- { type: RiskType.SMART_CONTRACT_RISK, value: SmartContractRiskLevel.WELL_AUDITED, weight: 25, reason: "Audited by Zellic" },
1138
- { type: RiskType.LIQUIDATION_RISK, value: LiquidationRiskLevel.VERY_LOW_PROBABILITY, weight: 25, reason: "The collateral and debt are highly correlated" },
1139
- { 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." },
1140
- {type: RiskType.DEPEG_RISK, value: DepegRiskLevel.GENERALLY_STABLE, weight: 25, reason: "Generally stable pegged assets" },
1768
+ {
1769
+ type: RiskType.SMART_CONTRACT_RISK,
1770
+ value: SmartContractRiskLevel.WELL_AUDITED,
1771
+ weight: 25,
1772
+ reason: "Audited by Zellic",
1773
+ },
1774
+ {
1775
+ type: RiskType.LIQUIDATION_RISK,
1776
+ value: LiquidationRiskLevel.VERY_LOW_PROBABILITY,
1777
+ weight: 25,
1778
+ reason: "The collateral and debt are highly correlated",
1779
+ },
1780
+ {
1781
+ type: RiskType.TECHNICAL_RISK,
1782
+ value: TechnicalRiskLevel.STABLE_INFRASTRUCTURE,
1783
+ weight: 25,
1784
+ reason:
1785
+ "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.",
1786
+ },
1787
+ {
1788
+ type: RiskType.DEPEG_RISK,
1789
+ value: DepegRiskLevel.GENERALLY_STABLE,
1790
+ weight: 25,
1791
+ reason: "Generally stable pegged assets",
1792
+ },
1141
1793
  ];
1142
1794
 
1143
- const btcBorrowableAssets = [
1144
- 'WBTC', 'tBTC', 'LBTC', 'solvBTC'
1145
- ]
1795
+ const btcBorrowableAssets = ["WBTC", "tBTC", "LBTC", "solvBTC"];
1146
1796
 
1147
1797
  const hyperxSTRK: HyperLSTStrategySettings = {
1148
- vaultAddress: ContractAddr.from('0x46c7a54c82b1fe374353859f554a40b8bd31d3e30f742901579e7b57b1b5960'),
1149
- manager: ContractAddr.from('0x5d499cd333757f461a0bedaca3dfc4d77320c773037e0aa299f22a6dbfdc03a'),
1150
- vaultAllocator: ContractAddr.from('0x511d07953a09bc7c505970891507c5a2486d2ea22752601a14db092186d7caa'),
1151
- redeemRequestNFT: ContractAddr.from('0x51e40b839dc0c2feca923f863072673b94abfa2483345be3b30b457a90d095'),
1152
- aumOracle: ContractAddr.from('0x48cf709870a1a0d453d37de108e0c41b8b89819ef54f95abc0e2e1f98bbe937'),
1798
+ vaultAddress: ContractAddr.from(
1799
+ "0x46c7a54c82b1fe374353859f554a40b8bd31d3e30f742901579e7b57b1b5960",
1800
+ ),
1801
+ manager: ContractAddr.from(
1802
+ "0x5d499cd333757f461a0bedaca3dfc4d77320c773037e0aa299f22a6dbfdc03a",
1803
+ ),
1804
+ vaultAllocator: ContractAddr.from(
1805
+ "0x511d07953a09bc7c505970891507c5a2486d2ea22752601a14db092186d7caa",
1806
+ ),
1807
+ redeemRequestNFT: ContractAddr.from(
1808
+ "0x51e40b839dc0c2feca923f863072673b94abfa2483345be3b30b457a90d095",
1809
+ ),
1810
+ aumOracle: ContractAddr.from(
1811
+ "0x48cf709870a1a0d453d37de108e0c41b8b89819ef54f95abc0e2e1f98bbe937",
1812
+ ),
1153
1813
  leafAdapters: [],
1154
1814
  adapters: [],
1155
1815
  targetHealthFactor: 1.1,
1156
1816
  minHealthFactor: 1.05,
1157
1817
  borrowable_assets: [
1158
- ...Global.getDefaultTokens().filter(token => token.symbol === 'STRK').map(token => ({ token, poolId: VesuPools.Re7xSTRK })),
1159
- ...Global.getDefaultTokens().filter(token => token.symbol === 'STRK').map(token => ({ token, poolId: VesuPools.Prime })),
1160
- ...Global.getDefaultTokens().filter(token => token.symbol === 'STRK').map(token => ({ token, poolId: VesuPools.Re7STRK })), // v2, new alt for Re7xSTRK
1818
+ ...Global.getDefaultTokens()
1819
+ .filter((token) => token.symbol === "STRK")
1820
+ .map((token) => ({ token, poolId: VesuPools.Re7xSTRK })),
1821
+ ...Global.getDefaultTokens()
1822
+ .filter((token) => token.symbol === "STRK")
1823
+ .map((token) => ({ token, poolId: VesuPools.Prime })),
1824
+ ...Global.getDefaultTokens()
1825
+ .filter((token) => token.symbol === "STRK")
1826
+ .map((token) => ({ token, poolId: VesuPools.Re7STRK })), // v2, new alt for Re7xSTRK
1161
1827
  ],
1162
- underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'STRK')!,
1828
+ underlyingToken: Global.getDefaultTokens().find(
1829
+ (token) => token.symbol === "STRK",
1830
+ )!,
1163
1831
  defaultPoolId: VesuPools.Re7xSTRK,
1164
- }
1832
+ };
1165
1833
 
1166
1834
  const hyperxWBTC: HyperLSTStrategySettings = {
1167
- vaultAddress: ContractAddr.from('0x2da9d0f96a46b453f55604313785dc866424240b1c6811d13bef594343db818'),
1168
- manager: ContractAddr.from('0x75866db44c81e6986f06035206ee9c7d15833ddb22d6a22c016cfb5c866a491'),
1169
- vaultAllocator: ContractAddr.from('0x57b5c1bb457b5e840a2714ae53ada87d77be2f3fd33a59b4fe709ef20c020c1'),
1170
- redeemRequestNFT: ContractAddr.from('0x7a5dc288325456f05e70e9616e16bc02ffbe448f4b89f80b47c0970b989c7c'),
1171
- aumOracle: ContractAddr.from('0x258f8a0ca0d21f542e48ad89d00e92dc4d9db4999084f50ef9c22dfb1e83023'),
1835
+ vaultAddress: ContractAddr.from(
1836
+ "0x2da9d0f96a46b453f55604313785dc866424240b1c6811d13bef594343db818",
1837
+ ),
1838
+ manager: ContractAddr.from(
1839
+ "0x75866db44c81e6986f06035206ee9c7d15833ddb22d6a22c016cfb5c866a491",
1840
+ ),
1841
+ vaultAllocator: ContractAddr.from(
1842
+ "0x57b5c1bb457b5e840a2714ae53ada87d77be2f3fd33a59b4fe709ef20c020c1",
1843
+ ),
1844
+ redeemRequestNFT: ContractAddr.from(
1845
+ "0x7a5dc288325456f05e70e9616e16bc02ffbe448f4b89f80b47c0970b989c7c",
1846
+ ),
1847
+ aumOracle: ContractAddr.from(
1848
+ "0x258f8a0ca0d21f542e48ad89d00e92dc4d9db4999084f50ef9c22dfb1e83023",
1849
+ ),
1172
1850
  leafAdapters: [],
1173
1851
  adapters: [],
1174
1852
  targetHealthFactor: 1.1,
1175
1853
  minHealthFactor: 1.05,
1176
1854
  borrowable_assets: [
1177
1855
  // allow all BTC flavours borrowing on Re7xBTC pool
1178
- ...btcBorrowableAssets.map(asset => Global.getDefaultTokens().find(token => token.symbol === asset)!).map(token => ({ token, poolId: VesuPools.Re7xBTC })),
1856
+ ...btcBorrowableAssets
1857
+ .map(
1858
+ (asset) =>
1859
+ Global.getDefaultTokens().find((token) => token.symbol === asset)!,
1860
+ )
1861
+ .map((token) => ({ token, poolId: VesuPools.Re7xBTC })),
1179
1862
  // allow only WBTC borrowing on Prime pool
1180
- ...Global.getDefaultTokens().filter(token => token.symbol === 'WBTC').map(token => ({ token, poolId: VesuPools.Prime })),
1863
+ ...Global.getDefaultTokens()
1864
+ .filter((token) => token.symbol === "WBTC")
1865
+ .map((token) => ({ token, poolId: VesuPools.Prime })),
1181
1866
  ],
1182
- underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'WBTC')!,
1867
+ underlyingToken: Global.getDefaultTokens().find(
1868
+ (token) => token.symbol === "WBTC",
1869
+ )!,
1183
1870
  defaultPoolId: VesuPools.Re7xBTC,
1184
- redemptionRouter: ContractAddr.from('0x6ea649f402898f69baf775c1afdd08522c071c640b9c4460192070ec2b96417')
1185
- }
1871
+ redemptionRouter: ContractAddr.from(
1872
+ "0x6ea649f402898f69baf775c1afdd08522c071c640b9c4460192070ec2b96417",
1873
+ ),
1874
+ };
1186
1875
 
1187
1876
  const hyperxtBTC: HyperLSTStrategySettings = {
1188
- vaultAddress: ContractAddr.from('0x47d5f68477e5637ce0e56436c6b5eee5a354e6828995dae106b11a48679328'),
1189
- manager: ContractAddr.from('0xc4cc3e08029a0ae076f5fdfca70575abb78d23c5cd1c49a957f7e697885401'),
1190
- vaultAllocator: ContractAddr.from('0x50bbd4fe69f841ecb13b2619fe50ebfa4e8944671b5d0ebf7868fd80c61b31e'),
1191
- redeemRequestNFT: ContractAddr.from('0xeac9032f02057779816e38a6cb9185d12d86b3aacc9949b96b36de359c1e3'),
1192
- aumOracle: ContractAddr.from('0x7e0d05cb7ba3f7db77a36c21c21583b5a524c2e685c08c24b3554911fb4a039'),
1877
+ vaultAddress: ContractAddr.from(
1878
+ "0x47d5f68477e5637ce0e56436c6b5eee5a354e6828995dae106b11a48679328",
1879
+ ),
1880
+ manager: ContractAddr.from(
1881
+ "0xc4cc3e08029a0ae076f5fdfca70575abb78d23c5cd1c49a957f7e697885401",
1882
+ ),
1883
+ vaultAllocator: ContractAddr.from(
1884
+ "0x50bbd4fe69f841ecb13b2619fe50ebfa4e8944671b5d0ebf7868fd80c61b31e",
1885
+ ),
1886
+ redeemRequestNFT: ContractAddr.from(
1887
+ "0xeac9032f02057779816e38a6cb9185d12d86b3aacc9949b96b36de359c1e3",
1888
+ ),
1889
+ aumOracle: ContractAddr.from(
1890
+ "0x7e0d05cb7ba3f7db77a36c21c21583b5a524c2e685c08c24b3554911fb4a039",
1891
+ ),
1193
1892
  leafAdapters: [],
1194
1893
  adapters: [],
1195
1894
  targetHealthFactor: 1.1,
1196
1895
  minHealthFactor: 1.05,
1197
1896
  borrowable_assets: [
1198
- ...Global.getDefaultTokens().filter(token => token.symbol === 'tBTC' || token.symbol === 'WBTC').map(token => ({ token, poolId: VesuPools.Re7xBTC })),
1897
+ ...Global.getDefaultTokens()
1898
+ .filter((token) => token.symbol === "tBTC" || token.symbol === "WBTC")
1899
+ .map((token) => ({ token, poolId: VesuPools.Re7xBTC })),
1199
1900
  ],
1200
- underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'tBTC')!,
1901
+ underlyingToken: Global.getDefaultTokens().find(
1902
+ (token) => token.symbol === "tBTC",
1903
+ )!,
1201
1904
  defaultPoolId: VesuPools.Re7xBTC,
1202
- redemptionRouter: ContractAddr.from('0x3de9c409d1e357e25778fb7a3e2e2393666956846a5c2caa607296fa8e76b5d')
1203
- }
1905
+ redemptionRouter: ContractAddr.from(
1906
+ "0x3de9c409d1e357e25778fb7a3e2e2393666956846a5c2caa607296fa8e76b5d",
1907
+ ),
1908
+ };
1204
1909
 
1205
1910
  const hyperxsBTC: HyperLSTStrategySettings = {
1206
- vaultAddress: ContractAddr.from('0x437ef1e7d0f100b2e070b7a65cafec0b2be31b0290776da8b4112f5473d8d9'),
1207
- manager: ContractAddr.from('0xc9ac023090625b0be3f6532ca353f086746f9c09f939dbc1b2613f09e5f821'),
1208
- vaultAllocator: ContractAddr.from('0x60c2d856936b975459a5b4eb28b8672d91f757bd76cebb6241f8d670185dc01'),
1209
- redeemRequestNFT: ContractAddr.from('0x429e8ee8bc7ecd1ade72630d350a2e0f10f9a2507c45f188ba17fe8f2ab4cf3'),
1210
- aumOracle: ContractAddr.from('0x149298ade3e79ec6cbdac6cfad289c57504eaf54e590939136ed1ceca60c345'),
1911
+ vaultAddress: ContractAddr.from(
1912
+ "0x437ef1e7d0f100b2e070b7a65cafec0b2be31b0290776da8b4112f5473d8d9",
1913
+ ),
1914
+ manager: ContractAddr.from(
1915
+ "0xc9ac023090625b0be3f6532ca353f086746f9c09f939dbc1b2613f09e5f821",
1916
+ ),
1917
+ vaultAllocator: ContractAddr.from(
1918
+ "0x60c2d856936b975459a5b4eb28b8672d91f757bd76cebb6241f8d670185dc01",
1919
+ ),
1920
+ redeemRequestNFT: ContractAddr.from(
1921
+ "0x429e8ee8bc7ecd1ade72630d350a2e0f10f9a2507c45f188ba17fe8f2ab4cf3",
1922
+ ),
1923
+ aumOracle: ContractAddr.from(
1924
+ "0x149298ade3e79ec6cbdac6cfad289c57504eaf54e590939136ed1ceca60c345",
1925
+ ),
1211
1926
  leafAdapters: [],
1212
1927
  adapters: [],
1213
1928
  targetHealthFactor: 1.1,
1214
1929
  minHealthFactor: 1.05,
1215
1930
  borrowable_assets: [
1216
- ...Global.getDefaultTokens().filter(token => token.symbol === 'solvBTC').map(token => ({ token, poolId: VesuPools.Re7xBTC })),
1931
+ ...Global.getDefaultTokens()
1932
+ .filter((token) => token.symbol === "solvBTC")
1933
+ .map((token) => ({ token, poolId: VesuPools.Re7xBTC })),
1217
1934
  ],
1218
- underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'solvBTC')!,
1935
+ underlyingToken: Global.getDefaultTokens().find(
1936
+ (token) => token.symbol === "solvBTC",
1937
+ )!,
1219
1938
  defaultPoolId: VesuPools.Re7xBTC,
1220
- }
1939
+ };
1221
1940
 
1222
1941
  const hyperxLBTC: HyperLSTStrategySettings = {
1223
- vaultAddress: ContractAddr.from('0x64cf24d4883fe569926419a0569ab34497c6956a1a308fa883257f7486d7030'),
1224
- manager: ContractAddr.from('0x203530a4022a99b8f4b406aaf33b0849d43ad7422c1d5cc14ff8c667abec6c0'),
1225
- vaultAllocator: ContractAddr.from('0x7dbc8ccd4eabce6ea6c19e0e5c9ccca3a93bd510303b9e071cbe25fc508546e'),
1226
- redeemRequestNFT: ContractAddr.from('0x5ee66a39af9aef3d0d48982b4a63e8bd2a5bad021916bd87fb0eae3a26800b8'),
1227
- aumOracle: ContractAddr.from('0x23d69e4391fa72d10e625e7575d8bddbb4aff96f04503f83fdde23123bf41d0'),
1942
+ vaultAddress: ContractAddr.from(
1943
+ "0x64cf24d4883fe569926419a0569ab34497c6956a1a308fa883257f7486d7030",
1944
+ ),
1945
+ manager: ContractAddr.from(
1946
+ "0x203530a4022a99b8f4b406aaf33b0849d43ad7422c1d5cc14ff8c667abec6c0",
1947
+ ),
1948
+ vaultAllocator: ContractAddr.from(
1949
+ "0x7dbc8ccd4eabce6ea6c19e0e5c9ccca3a93bd510303b9e071cbe25fc508546e",
1950
+ ),
1951
+ redeemRequestNFT: ContractAddr.from(
1952
+ "0x5ee66a39af9aef3d0d48982b4a63e8bd2a5bad021916bd87fb0eae3a26800b8",
1953
+ ),
1954
+ aumOracle: ContractAddr.from(
1955
+ "0x23d69e4391fa72d10e625e7575d8bddbb4aff96f04503f83fdde23123bf41d0",
1956
+ ),
1228
1957
  leafAdapters: [],
1229
1958
  adapters: [],
1230
1959
  targetHealthFactor: 1.1,
1231
1960
  minHealthFactor: 1.05,
1232
1961
  borrowable_assets: [
1233
- ...Global.getDefaultTokens().filter(token => token.symbol === 'LBTC').map(token => ({ token, poolId: VesuPools.Re7xBTC })),
1962
+ ...Global.getDefaultTokens()
1963
+ .filter((token) => token.symbol === "LBTC")
1964
+ .map((token) => ({ token, poolId: VesuPools.Re7xBTC })),
1234
1965
  ],
1235
- underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'LBTC')!,
1966
+ underlyingToken: Global.getDefaultTokens().find(
1967
+ (token) => token.symbol === "LBTC",
1968
+ )!,
1236
1969
  defaultPoolId: VesuPools.Re7xBTC,
1237
- }
1970
+ };
1238
1971
 
1239
1972
  function getInvestmentSteps(lstSymbol: string, underlyingSymbol: string) {
1240
1973
  return [
@@ -1242,172 +1975,180 @@ function getInvestmentSteps(lstSymbol: string, underlyingSymbol: string) {
1242
1975
  `The vault manager loops the ${underlyingSymbol} to buy ${lstSymbol}`,
1243
1976
  `The vault manager collateralizes the ${lstSymbol} on Vesu`,
1244
1977
  `The vault manager borrows more ${underlyingSymbol} to loop further`,
1245
- `If required, adjust leverage or re-allocate assets within LST pool on Vesu to optimize yield`
1246
- ]
1978
+ `If required, adjust leverage or re-allocate assets within LST pool on Vesu to optimize yield`,
1979
+ ];
1247
1980
  }
1248
1981
 
1249
1982
  // Helper to get maxTVL based on LST symbol (matching client values)
1250
1983
  function getMaxTVL(lstSymbol: string): Web3Number {
1251
- const lstMaxTVLs: Record<string, number> = {
1252
- xWBTC: 5,
1253
- xLBTC: 5,
1254
- xtBTC: 5,
1255
- xsBTC: 5,
1256
- xSTRK: 550000
1257
- };
1984
+ const lstMaxTVLs: Record<string, number> = {
1985
+ xWBTC: 5,
1986
+ xLBTC: 5,
1987
+ xtBTC: 5,
1988
+ xsBTC: 5,
1989
+ xSTRK: 7000000,
1990
+ };
1258
1991
 
1259
- const maxTVLValue = lstMaxTVLs[lstSymbol] || 0;
1260
- const token = Global.getDefaultTokens().find(
1261
- (token) => token.symbol === lstSymbol
1262
- );
1263
- if (!token) {
1264
- return Web3Number.fromWei(0, 18);
1265
- }
1266
- return Web3Number.fromWei(maxTVLValue, token.decimals);
1992
+ const maxTVLValue = lstMaxTVLs[lstSymbol] || 0;
1993
+ const token = Global.getDefaultTokens().find(
1994
+ (token) => token.symbol === lstSymbol,
1995
+ );
1996
+ if (!token) {
1997
+ return Web3Number.fromWei(0, 18);
1998
+ }
1999
+ return Web3Number.fromWei(maxTVLValue, token.decimals);
1267
2000
  }
1268
2001
 
1269
2002
  // Helper to create Hyper LST strategy settings
1270
2003
  function createHyperLSTSettings(
1271
- lstSymbol: string,
1272
- underlyingSymbol: string
2004
+ lstSymbol: string,
2005
+ underlyingSymbol: string,
1273
2006
  ): StrategySettings {
1274
- const depositToken = Global.getDefaultTokens().find(
1275
- (token) => token.symbol === lstSymbol
1276
- )!;
1277
- return {
1278
- maxTVL: getMaxTVL(lstSymbol),
1279
- isPaused: false,
1280
- liveStatus: StrategyLiveStatus.HOT,
1281
- isAudited: true,
1282
- isInstantWithdrawal: false,
1283
- hideHarvestInfo: true,
1284
- quoteToken: depositToken,
1285
- showWithdrawalWarningModal: false,
1286
- alerts: [
1287
- {
1288
- tab: "withdraw" as const,
1289
- text: "On withdrawal, you will receive an NFT representing your withdrawal request. The funds will be automatically sent to your wallet (NFT owner) in 24 hours (In this initial phase of Launch). You can monitor the status in transactions tab.",
1290
- type: "info" as const
1291
- },
1292
- {
1293
- tab: "deposit" as const,
1294
- text: (
1295
- <>
1296
- To acquire the LST, please visit{" "}
1297
- <a
1298
- href="https://app.endur.fi"
1299
- target="_blank"
1300
- rel="noopener noreferrer"
1301
- >
1302
- endur.fi
1303
- </a>
1304
- </>
1305
- ),
1306
- type: "info" as const
1307
- },
1308
- {
1309
- tab: "deposit" as const,
1310
- text: "It may take up to one week for your deposit to appreciate in value. This delay occurs because the LST price is sourced from DEXes and liquidity is usually rebased once a week.",
1311
- type: "info" as const
1312
- }
1313
- ]
1314
- };
2007
+ const depositToken = Global.getDefaultTokens().find(
2008
+ (token) => token.symbol === lstSymbol,
2009
+ )!;
2010
+ return {
2011
+ maxTVL: getMaxTVL(lstSymbol),
2012
+ isPaused: false,
2013
+ liveStatus: StrategyLiveStatus.HOT,
2014
+ isAudited: true,
2015
+ isInstantWithdrawal: false,
2016
+ hideHarvestInfo: true,
2017
+ quoteToken: depositToken,
2018
+ showWithdrawalWarningModal: false,
2019
+ alerts: [
2020
+ {
2021
+ tab: "withdraw" as const,
2022
+ text: "On withdrawal, you will receive an NFT representing your withdrawal request. The funds will be automatically sent to your wallet (NFT owner) in 24 hours (In this initial phase of Launch). You can monitor the status in transactions tab.",
2023
+ type: "info" as const,
2024
+ },
2025
+ {
2026
+ tab: "deposit" as const,
2027
+ text: (
2028
+ <>
2029
+ To acquire the LST, please visit{" "}
2030
+ <a
2031
+ href="https://app.endur.fi"
2032
+ target="_blank"
2033
+ rel="noopener noreferrer"
2034
+ >
2035
+ endur.fi
2036
+ </a>
2037
+ </>
2038
+ ),
2039
+ type: "info" as const,
2040
+ },
2041
+ {
2042
+ tab: "deposit" as const,
2043
+ text: "It may take up to one week for your deposit to appreciate in value. This delay occurs because the LST price is sourced from DEXes and liquidity is usually rebased once a week.",
2044
+ type: "info" as const,
2045
+ },
2046
+ ],
2047
+ };
1315
2048
  }
1316
2049
 
1317
2050
  const HYPER_LST_SECURITY = {
1318
- auditStatus: AuditStatus.AUDITED,
1319
- sourceCode: {
1320
- type: SourceCodeType.CLOSED_SOURCE,
1321
- contractLink: "https://github.com/trovesfi/troves-contracts"
1322
- },
1323
- accessControl: {
1324
- type: AccessControlType.STANDARD_ACCOUNT,
1325
- addresses: [ContractAddr.from("0x0")],
1326
- timeLock: "2 Days"
1327
- }
2051
+ auditStatus: AuditStatus.AUDITED,
2052
+ sourceCode: {
2053
+ type: SourceCodeType.CLOSED_SOURCE,
2054
+ contractLink: "https://github.com/trovesfi/troves-contracts",
2055
+ },
2056
+ accessControl: {
2057
+ type: AccessControlType.STANDARD_ACCOUNT,
2058
+ addresses: [ContractAddr.from("0x0")],
2059
+ timeLock: "2 Days",
2060
+ },
1328
2061
  };
1329
2062
 
1330
2063
  const HYPER_LST_REDEMPTION_INFO: RedemptionInfo = {
1331
- instantWithdrawalVault: InstantWithdrawalVault.NO,
1332
- redemptionsInfo: [{
1333
- title: "Typical Duration",
1334
- description: "1-2 hours"
1335
- }],
1336
- alerts: [{
1337
- type: 'info',
1338
- text: 'In cases of low liquidity, high slippages, the redemptions can take longer time. Redemption times are estimates and may vary based on network conditions and liquidity requirements.',
1339
- tab: 'withdraw'
1340
- }]
2064
+ instantWithdrawalVault: InstantWithdrawalVault.NO,
2065
+ redemptionsInfo: [
2066
+ {
2067
+ title: "Typical Duration",
2068
+ description: "1-2 hours",
2069
+ },
2070
+ ],
2071
+ alerts: [
2072
+ {
2073
+ type: "info",
2074
+ text: "In cases of low liquidity, high slippages, the redemptions can take longer time. Redemption times are estimates and may vary based on network conditions and liquidity requirements.",
2075
+ tab: "withdraw",
2076
+ },
2077
+ ],
1341
2078
  };
1342
2079
 
1343
2080
  function getStrategySettings(
1344
- lstSymbol: string,
1345
- underlyingSymbol: string,
1346
- settings: HyperLSTStrategySettings,
1347
- isPreview: boolean = false
2081
+ lstSymbol: string,
2082
+ underlyingSymbol: string,
2083
+ settings: HyperLSTStrategySettings,
2084
+ isPreview: boolean = false,
1348
2085
  ): IStrategyMetadata<HyperLSTStrategySettings> {
1349
- return {
1350
- id: `hyper_${lstSymbol.toLowerCase()}`,
1351
- name: `Hyper ${lstSymbol}`,
1352
- description: getDescription(lstSymbol, underlyingSymbol),
1353
- address: settings.vaultAddress,
1354
- launchBlock: 0,
1355
- type: "Other",
1356
- vaultType: {
1357
- type: VaultType.LOOPING,
1358
- description: `Creates leveraged looping position on ${lstSymbol} by borrowing ${underlyingSymbol} to increase yield`
1359
- },
1360
- depositTokens: [
1361
- Global.getDefaultTokens().find(
1362
- (token) => token.symbol === lstSymbol
1363
- )!
1364
- ],
1365
- additionalInfo: getLooperSettings(
1366
- lstSymbol,
1367
- underlyingSymbol,
1368
- settings,
1369
- lstSymbol === "xSTRK" ? VesuPools.Re7xSTRK : VesuPools.Re7xBTC,
1370
- ),
1371
- risk: {
1372
- riskFactor: _riskFactor,
1373
- netRisk:
1374
- _riskFactor.reduce(
1375
- (acc, curr) => acc + curr.value * curr.weight,
1376
- 0
1377
- ) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
1378
- notARisks: getNoRiskTags(_riskFactor)
1379
- },
1380
- auditUrl: AUDIT_URL,
1381
- protocols: [Protocols.ENDUR, Protocols.VESU],
1382
- curator: {
1383
- name: "Unwrap Labs",
1384
- logo: "https://assets.troves.fi/integrations/unwraplabs/white.png"
1385
- },
1386
- settings: createHyperLSTSettings(lstSymbol, underlyingSymbol),
1387
- contractDetails: getContractDetails(settings),
1388
- faqs: getFAQs(lstSymbol, underlyingSymbol),
1389
- investmentSteps: getInvestmentSteps(lstSymbol, underlyingSymbol),
1390
- isPreview: isPreview,
1391
- apyMethodology:
1392
- "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.",
1393
- tags: lstSymbol.includes('BTC') ? [StrategyTag.BTC, StrategyTag.LEVERED] : [StrategyTag.LEVERED],
1394
- security: HYPER_LST_SECURITY,
1395
- redemptionInfo: HYPER_LST_REDEMPTION_INFO,
1396
- usualTimeToEarnings: "2 weeks",
1397
- usualTimeToEarningsDescription: "Strategy returns depend on LST price on DEXes. Even though the true price of LST on Endur increases continuously, the DEX price may lag sometimes, and historically is seen to rebase at least once every 2 hours. This is when you realise your earnings.",
1398
- points: [{
1399
- multiplier: 4,
1400
- logo: 'https://endur.fi/favicon.ico',
1401
- toolTip: "This strategy holds xSTRK. Earn 3-4x Endur points on your xSTRK due to the leverage. Points can be found on endur.fi.",
1402
- }]
1403
- };
2086
+ return {
2087
+ id: `hyper_${lstSymbol.toLowerCase()}`,
2088
+ name: `Hyper ${lstSymbol}`,
2089
+ description: getDescription(lstSymbol, underlyingSymbol),
2090
+ address: settings.vaultAddress,
2091
+ launchBlock: 0,
2092
+ type: "Other",
2093
+ vaultType: {
2094
+ type: VaultType.LOOPING,
2095
+ description: `Creates leveraged looping position on ${lstSymbol} by borrowing ${underlyingSymbol} to increase yield`,
2096
+ },
2097
+ depositTokens: [
2098
+ Global.getDefaultTokens().find((token) => token.symbol === lstSymbol)!,
2099
+ ],
2100
+ additionalInfo: getLooperSettings(
2101
+ lstSymbol,
2102
+ underlyingSymbol,
2103
+ settings,
2104
+ lstSymbol === "xSTRK" ? VesuPools.Re7xSTRK : VesuPools.Re7xBTC,
2105
+ ),
2106
+ risk: {
2107
+ riskFactor: _riskFactor,
2108
+ netRisk:
2109
+ _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
2110
+ _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
2111
+ notARisks: getNoRiskTags(_riskFactor),
2112
+ },
2113
+ auditUrl: AUDIT_URL,
2114
+ protocols: [Protocols.ENDUR, Protocols.VESU],
2115
+ curator: {
2116
+ name: "Unwrap Labs",
2117
+ logo: "https://assets.troves.fi/integrations/unwraplabs/white.png",
2118
+ },
2119
+ settings: createHyperLSTSettings(lstSymbol, underlyingSymbol),
2120
+ contractDetails: getContractDetails(settings),
2121
+ faqs: getFAQs(lstSymbol, underlyingSymbol),
2122
+ investmentSteps: getInvestmentSteps(lstSymbol, underlyingSymbol),
2123
+ isPreview: isPreview,
2124
+ apyMethodology:
2125
+ "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.",
2126
+ realizedAPYMethodology:
2127
+ "The realizedAPY is based on past 14 days performance by the vault",
2128
+ tags: lstSymbol.includes("BTC")
2129
+ ? [StrategyTag.BTC, StrategyTag.LEVERED]
2130
+ : [StrategyTag.LEVERED],
2131
+ security: HYPER_LST_SECURITY,
2132
+ redemptionInfo: HYPER_LST_REDEMPTION_INFO,
2133
+ usualTimeToEarnings: "2 weeks",
2134
+ usualTimeToEarningsDescription:
2135
+ "Strategy returns depend on LST price on DEXes. Even though the true price of LST on Endur increases continuously, the DEX price may lag sometimes, and historically is seen to rebase at least once every 2 hours. This is when you realise your earnings.",
2136
+ points: [
2137
+ {
2138
+ multiplier: 4,
2139
+ logo: "https://endur.fi/favicon.ico",
2140
+ toolTip:
2141
+ "This strategy holds xSTRK. Earn 3-4x Endur points on your xSTRK due to the leverage. Points can be found on endur.fi.",
2142
+ },
2143
+ ],
2144
+ };
1404
2145
  }
1405
2146
 
1406
2147
  export const HyperLSTStrategies: IStrategyMetadata<HyperLSTStrategySettings>[] =
1407
2148
  [
1408
- getStrategySettings('xSTRK', 'STRK', hyperxSTRK, false),
1409
- getStrategySettings('xWBTC', 'WBTC', hyperxWBTC, false),
1410
- getStrategySettings('xtBTC', 'tBTC', hyperxtBTC, false),
1411
- getStrategySettings('xsBTC', 'solvBTC', hyperxsBTC, false),
1412
- getStrategySettings('xLBTC', 'LBTC', hyperxLBTC, false),
1413
- ]
2149
+ getStrategySettings("xSTRK", "STRK", hyperxSTRK, false),
2150
+ getStrategySettings("xWBTC", "WBTC", hyperxWBTC, false),
2151
+ getStrategySettings("xtBTC", "tBTC", hyperxtBTC, false),
2152
+ getStrategySettings("xsBTC", "solvBTC", hyperxsBTC, false),
2153
+ getStrategySettings("xLBTC", "LBTC", hyperxLBTC, false),
2154
+ ];