@strkfarm/sdk 1.1.8 → 1.1.10

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.
@@ -0,0 +1,497 @@
1
+ import { FAQ, getNoRiskTags, IConfig, IStrategyMetadata, Protocols, RiskFactor, RiskType } from "@/interfaces";
2
+ import { AUMTypes, getContractDetails, UNIVERSAL_ADAPTERS, UNIVERSAL_MANAGE_IDS, UniversalManageCall, UniversalStrategy, UniversalStrategySettings } from "./universal-strategy";
3
+ import { PricerBase } from "@/modules/pricerBase";
4
+ import { ContractAddr, Web3Number } from "@/dataTypes";
5
+ import { Global } from "@/global";
6
+ import { ApproveCallParams, CommonAdapter, ManageCall, Swap, VesuAdapter, VesuModifyDelegationCallParams, VesuMultiplyCallParams, VesuPools } from "./universal-adapters";
7
+ import { AVNU_MIDDLEWARE } from "./universal-adapters/adapter-utils";
8
+ import { LiquidationRiskLevel, SmartContractRiskLevel, TechnicalRiskLevel } from "@/interfaces/risks";
9
+ import { EkuboQuoter, ERC20 } from "@/modules";
10
+ import { assert, logger } from "@/utils";
11
+ import { SingleTokenInfo } from "./base-strategy";
12
+ import { Call, Contract, uint256 } from "starknet";
13
+ import ERC4626Abi from "@/data/erc4626.abi.json";
14
+
15
+
16
+ export class UniversalLstMultiplierStrategy extends UniversalStrategy<UniversalStrategySettings> {
17
+
18
+ private quoteAmountToFetchPrice = new Web3Number(1, 18);
19
+
20
+ constructor(config: IConfig, pricer: PricerBase, metadata: IStrategyMetadata<UniversalStrategySettings>) {
21
+ super(config, pricer, metadata);
22
+
23
+ const STRKToken = Global.getDefaultTokens().find(token => token.symbol === 'STRK')!;
24
+ const underlyingToken = this.getLSTUnderlyingTokenInfo();
25
+ if (underlyingToken.address.eq(STRKToken.address)) {
26
+ this.quoteAmountToFetchPrice = new Web3Number(100, 18);
27
+ } else {
28
+ // else this BTC
29
+ this.quoteAmountToFetchPrice = new Web3Number(0.01, this.asset().decimals);
30
+ }
31
+ }
32
+
33
+ // only one leg is used
34
+ // todo support lending assets of underlying as well
35
+ getVesuAdapters() {
36
+ const vesuAdapter1 = this.getAdapter(UNIVERSAL_ADAPTERS.VESU_LEG1) as VesuAdapter;
37
+ vesuAdapter1.pricer = this.pricer;
38
+ vesuAdapter1.networkConfig = this.config;
39
+
40
+ return [vesuAdapter1];
41
+ }
42
+
43
+ // not applicable for this strategy
44
+ // No rewards on collateral or borrowing of LST assets
45
+ protected async getRewardsAUM(prevAum: Web3Number): Promise<Web3Number> {
46
+ return Web3Number.fromWei("0", this.asset().decimals);
47
+ }
48
+
49
+ async getLSTDexPrice() {
50
+ const ekuboQuoter = new EkuboQuoter(this.config);
51
+ const lstTokenInfo = this.asset();
52
+ const lstUnderlyingTokenInfo = this.getLSTUnderlyingTokenInfo();
53
+ const quote = await ekuboQuoter.getQuote(
54
+ lstTokenInfo.address.address,
55
+ lstUnderlyingTokenInfo.address.address,
56
+ this.quoteAmountToFetchPrice
57
+ );
58
+
59
+ // in Underlying
60
+ const outputAmount = Web3Number.fromWei(quote.total_calculated, lstUnderlyingTokenInfo.decimals);
61
+ const price = outputAmount.toNumber() / this.quoteAmountToFetchPrice.toNumber();
62
+ logger.verbose(`${this.getTag()}:: LST Dex Price: ${price}`);
63
+ return price;
64
+ }
65
+
66
+ /**
67
+ * Uses vesu's multiple call to create leverage on LST
68
+ * Deposit amount is in LST
69
+ * @param params
70
+ */
71
+ async getVesuMultiplyCall(params: {
72
+ isDeposit: boolean,
73
+ leg1DepositAmount: Web3Number
74
+ }) {
75
+ const [vesuAdapter1] = this.getVesuAdapters();
76
+ const legLTV = await vesuAdapter1.getLTVConfig(this.config);
77
+
78
+ const existingPositions = await vesuAdapter1.getPositions(this.config);
79
+ const collateralisation = await vesuAdapter1.getCollateralization(this.config);
80
+ const existingCollateralInfo = existingPositions[0];
81
+ const existingDebtInfo = existingPositions[1];
82
+ logger.debug(`${this.getTag()}::getVesuMultiplyCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
83
+ existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
84
+
85
+ // Price 1 is ok as fallback bcz that would relatively price the
86
+ // collateral and debt as equal.
87
+ const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
88
+ const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
89
+ logger.debug(`${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
90
+
91
+ // compute optimal amount of collateral and debt post addition/removal
92
+ // target hf = collateral * collateralPrice * ltv / debt * debtPrice
93
+ // assuming X to be the usd amount of debt borrowed or repaied (negative).
94
+ // target hf = (((collateral + legDepositAmount) * collateralPrice + X)) * ltv / (debt * debtPrice + X)
95
+ // => X * target hf = (((collateral + legDepositAmount) * collateralPrice + X)) * ltv - (debt * debtPrice * target hf)
96
+ // => X * (target hf - ltv)= ((collateral + legDepositAmount) * collateralPrice * ltv) - (debt * debtPrice * target hf)
97
+ // => X = (((collateral + legDepositAmount) * collateralPrice * ltv) - (debt * debtPrice * target hf)) / (target hf - ltv)
98
+ const addedCollateral = params.leg1DepositAmount
99
+ .multipliedBy(params.isDeposit ? 1 : -1)
100
+ const DEXPrice = await this.getLSTDexPrice();
101
+ logger.verbose(`${this.getTag()}::getVesuMultiplyCall addedCollateral: ${addedCollateral}`);
102
+ const numeratorPart1 = (existingCollateralInfo.amount.plus((addedCollateral))).multipliedBy(collateralPrice).multipliedBy(legLTV);
103
+ const numeratorPart2 = existingDebtInfo.amount.multipliedBy(debtPrice).multipliedBy(this.metadata.additionalInfo.targetHealthFactor);
104
+ const denominatorPart = this.metadata.additionalInfo.targetHealthFactor - (legLTV / DEXPrice);
105
+ const x_debt_usd = numeratorPart1.minus(numeratorPart2).dividedBy(denominatorPart);
106
+ logger.verbose(`${this.getTag()}::getVesuMultiplyCall x_debt_usd: ${x_debt_usd}`);
107
+ logger.debug(`${this.getTag()}::getVesuMultiplyCall numeratorPart1: ${numeratorPart1}, numeratorPart2: ${numeratorPart2}, denominatorPart: ${denominatorPart}`);
108
+
109
+ // both in underlying
110
+ const debtAmount = x_debt_usd.dividedBy(debtPrice);
111
+ const marginAmount = addedCollateral;
112
+ logger.verbose(`${this.getTag()}::getVesuMultiplyCall debtAmount: ${debtAmount}, marginAmount: ${marginAmount}`);
113
+
114
+ // Cases of lever increase (within the scopr of this function)
115
+ // 1. debtAmount > 0 and marginAmount > 0
116
+ // 2. debtAmount > 0 and marginAmount < 0
117
+
118
+ // Cases of lever decrease
119
+ // 3. debtAmount < 0 and marginAmount > 0
120
+ // 4. debtAmount < 0 and marginAmount < 0
121
+ return this.getModifyLeverCall({
122
+ marginAmount,
123
+ debtAmount,
124
+ isIncrease: debtAmount.greaterThan(0)
125
+ });
126
+ }
127
+
128
+ getLSTUnderlyingTokenInfo() {
129
+ const [vesuAdapter1] = this.getVesuAdapters();
130
+ return vesuAdapter1.config.debt;
131
+ }
132
+
133
+ async getLSTExchangeRate() {
134
+ const [vesuAdapter1] = this.getVesuAdapters();
135
+ const lstTokenInfo = vesuAdapter1.config.collateral;
136
+ const lstABI = new Contract({
137
+ abi: ERC4626Abi,
138
+ address: lstTokenInfo.address.address,
139
+ providerOrAccount: this.config.provider
140
+ });
141
+
142
+ const price: any = await lstABI.call('convert_to_assets', [uint256.bnToUint256((new Web3Number(1, lstTokenInfo.decimals)).toWei())]);
143
+ const exchangeRate = Number(uint256.uint256ToBN(price).toString()) / Math.pow(10, lstTokenInfo.decimals);
144
+ logger.verbose(`${this.getTag()}:: LST Exchange Rate: ${exchangeRate}`);
145
+ return exchangeRate;
146
+ }
147
+
148
+ /**
149
+ *
150
+ * @param params marginAmount is in LST, debtAmount is in underlying
151
+ */
152
+ async getModifyLeverCall(params: {
153
+ marginAmount: Web3Number, // >0 during deposit
154
+ debtAmount: Web3Number,
155
+ isIncrease: boolean
156
+ }): Promise<Call[]> {
157
+ assert(!params.marginAmount.isZero() || !params.debtAmount.isZero(), 'Deposit/debt must be non-0');
158
+
159
+ const [vesuAdapter1] = this.getVesuAdapters();
160
+ const lstTokenInfo = this.asset();
161
+ const lstUnderlyingTokenInfo = vesuAdapter1.config.debt;
162
+
163
+ const proofsIDs: string[] = [];
164
+ const manageCalls: ManageCall[] = [];
165
+
166
+ // approve token
167
+ if (params.marginAmount.greaterThan(0)) {
168
+ const STEP1_ID = UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN1;
169
+ const manage1Info = this.getProofs<ApproveCallParams>(STEP1_ID);
170
+ const depositAmount = params.marginAmount;
171
+ const manageCall1 = manage1Info.callConstructor({
172
+ amount: depositAmount
173
+ })
174
+ proofsIDs.push(STEP1_ID);
175
+ manageCalls.push(manageCall1);
176
+ }
177
+
178
+ const ekuboQuoter = new EkuboQuoter(this.config);
179
+
180
+ // compute quotes for margin swap
181
+ const lstPrice = await this.getLSTExchangeRate();
182
+ const marginSwap: Swap[] = [];
183
+
184
+
185
+ // compute quotes for lever swap
186
+ const MAX_SLIPPAGE = 0.01;
187
+ // when increasing, debt is swapped to collateral (LST)
188
+ // when decreasing, collateral is swapped to debt (underlying)
189
+ // but both cases, we denominate amount in underlying. negative for decrease (exact amount out)
190
+ const fromToken = params.isIncrease ? lstUnderlyingTokenInfo : lstTokenInfo;
191
+ const toToken = params.isIncrease ? lstTokenInfo : lstUnderlyingTokenInfo;
192
+ const leverSwapQuote = await ekuboQuoter.getQuote(
193
+ fromToken.address.address,
194
+ toToken.address.address,
195
+ params.debtAmount // negative for exact amount out
196
+ );
197
+ assert(leverSwapQuote.price_impact < MAX_SLIPPAGE, 'getIncreaseLeverCall: Price impact is too high [Debt swap]');
198
+ const leverSwap = ekuboQuoter.getVesuMultiplyQuote(leverSwapQuote, fromToken, toToken);
199
+ const minExpectedDebt = params.debtAmount.dividedBy(lstPrice).multipliedBy(1 - MAX_SLIPPAGE); // used for increase
200
+ const maxUsedCollateral = params.debtAmount.abs().dividedBy(lstPrice).multipliedBy(1 + MAX_SLIPPAGE); // +ve for exact amount out, used for decrease
201
+
202
+ const STEP2_ID = LST_MULTIPLIER_MANAGE_IDS.SWITCH_DELEGATION_ON;
203
+ const manage2Info = this.getProofs<VesuModifyDelegationCallParams>(STEP2_ID);
204
+ const manageCall2 = manage2Info.callConstructor({
205
+ delegation: true
206
+ });
207
+
208
+ // deposit and borrow or repay and withdraw
209
+ const STEP3_ID = LST_MULTIPLIER_MANAGE_IDS.MULTIPLY_VESU;
210
+ const manage3Info = this.getProofs<VesuMultiplyCallParams>(STEP3_ID);
211
+ const multiplyParams: VesuMultiplyCallParams = params.isIncrease ? {
212
+ isIncrease: true,
213
+ increaseParams: {
214
+ add_margin: params.marginAmount,
215
+ margin_swap: marginSwap,
216
+ margin_swap_limit_amount: Web3Number.fromWei(0, this.asset().decimals),
217
+ lever_swap: leverSwap,
218
+ lever_swap_limit_amount: minExpectedDebt
219
+ }
220
+ } : {
221
+ isIncrease: false,
222
+ decreaseParams: {
223
+ sub_margin: params.marginAmount.multipliedBy(-1),
224
+ lever_swap: leverSwap,
225
+ lever_swap_limit_amount: maxUsedCollateral,
226
+ // only required for close position
227
+ lever_swap_weights: [],
228
+ // no need to swap collateral to anything, and any residuals return our contract anyways.
229
+ withdraw_swap: [],
230
+ withdraw_swap_limit_amount: Web3Number.fromWei(0, this.asset().decimals),
231
+ withdraw_swap_weights: [],
232
+ close_position: false
233
+ }
234
+ }
235
+ const manageCall3 = manage3Info.callConstructor(multiplyParams);
236
+
237
+ // switch delegation off
238
+ const STEP4_ID = LST_MULTIPLIER_MANAGE_IDS.SWITCH_DELEGATION_OFF;
239
+ const manage4Info = this.getProofs<VesuModifyDelegationCallParams>(STEP4_ID);
240
+ const manageCall4 = manage4Info.callConstructor({
241
+ delegation: false
242
+ });
243
+
244
+ proofsIDs.push(STEP2_ID, STEP3_ID, STEP4_ID);
245
+ manageCalls.push(manageCall2, manageCall3, manageCall4);
246
+
247
+ return [this.getManageCall(proofsIDs, manageCalls)];
248
+ }
249
+ }
250
+
251
+ export default function VaultDescription() {
252
+ const containerStyle = {
253
+ maxWidth: "800px",
254
+ margin: "0 auto",
255
+ backgroundColor: "#111",
256
+ color: "#eee",
257
+ fontFamily: "Arial, sans-serif",
258
+ borderRadius: "12px",
259
+ };
260
+
261
+ return (
262
+ <div style={containerStyle}>
263
+ <h1 style={{ fontSize: "18px", marginBottom: "10px" }}>Meta Vault — Automated Yield Router</h1>
264
+ <p style={{ fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }}>
265
+ This Levered Endur LST vault is a tokenized leveraged Vault, auto-compounding strategy that continuously allocates your deposited
266
+ asset to the best available yield source in the ecosystem. Depositors receive vault shares that
267
+ represent a proportional claim on the underlying assets and accrued yield. Allocation shifts are
268
+ handled programmatically based on on-chain signals and risk filters, minimizing idle capital and
269
+ maximizing net APY.
270
+ </p>
271
+
272
+ <div style={{ backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }}>
273
+ <p style={{ fontSize: "13px", color: "#ccc" }}>
274
+ <strong>Withdrawals:</strong> Requests can take up to <strong>1-2 hours</strong> to process as the vault unwinds and settles routing.
275
+ </p>
276
+ </div>
277
+ </div>
278
+ );
279
+ }
280
+
281
+
282
+ function getDescription(tokenSymbol: string) {
283
+ return VaultDescription();
284
+ }
285
+
286
+ enum LST_MULTIPLIER_MANAGE_IDS {
287
+ MULTIPLY_VESU = 'multiply_vesu',
288
+ SWITCH_DELEGATION_ON = 'switch_delegation_on',
289
+ SWITCH_DELEGATION_OFF = 'switch_delegation_off'
290
+ }
291
+
292
+ function getLooperSettings(
293
+ lstSymbol: string,
294
+ underlyingSymbol: string,
295
+ vaultSettings: UniversalStrategySettings,
296
+ pool1: ContractAddr,
297
+ ) {
298
+ vaultSettings.leafAdapters = [];
299
+
300
+ const lstToken = Global.getDefaultTokens().find(token => token.symbol === lstSymbol)!;
301
+ const underlyingToken = Global.getDefaultTokens().find(token => token.symbol === underlyingSymbol)!;
302
+
303
+ const vesuAdapterLST = new VesuAdapter({
304
+ poolId: pool1,
305
+ collateral: lstToken,
306
+ debt: underlyingToken,
307
+ vaultAllocator: vaultSettings.vaultAllocator,
308
+ id: LST_MULTIPLIER_MANAGE_IDS.MULTIPLY_VESU
309
+ })
310
+
311
+ const commonAdapter = new CommonAdapter({
312
+ manager: vaultSettings.manager,
313
+ asset: lstToken.address,
314
+ id: '',
315
+ vaultAddress: vaultSettings.vaultAddress,
316
+ vaultAllocator: vaultSettings.vaultAllocator,
317
+ })
318
+
319
+ // vesu looping
320
+ vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, vesuAdapterLST.VESU_MULTIPLY, UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN1).bind(commonAdapter));
321
+ vaultSettings.leafAdapters.push(vesuAdapterLST.getMultiplyAdapter.bind(vesuAdapterLST));
322
+ vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter(LST_MULTIPLIER_MANAGE_IDS.SWITCH_DELEGATION_ON).bind(vesuAdapterLST));
323
+ vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter(LST_MULTIPLIER_MANAGE_IDS.SWITCH_DELEGATION_OFF).bind(vesuAdapterLST));
324
+
325
+ // Useful for returning adapter class objects that can compute
326
+ // certain things for us (e.g. positions, hfs)
327
+ vaultSettings.adapters.push(...[{
328
+ id: UNIVERSAL_ADAPTERS.VESU_LEG1,
329
+ adapter: vesuAdapterLST
330
+ },{
331
+ id: UNIVERSAL_ADAPTERS.COMMON,
332
+ adapter: commonAdapter
333
+ }])
334
+
335
+ // to bridge liquidity back to vault (used by bring_liquidity)
336
+ vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, vaultSettings.vaultAddress, UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY).bind(commonAdapter));
337
+ vaultSettings.leafAdapters.push(commonAdapter.getBringLiquidityAdapter(UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY).bind(commonAdapter));
338
+
339
+ // claim rewards
340
+ vaultSettings.leafAdapters.push(vesuAdapterLST.getDefispringRewardsAdapter(UNIVERSAL_MANAGE_IDS.DEFISPRING_REWARDS).bind(vesuAdapterLST));
341
+
342
+ // avnu swap for claims rewards
343
+ const STRKToken = Global.getDefaultTokens().find(token => token.symbol === 'STRK')!;
344
+ vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(STRKToken.address, AVNU_MIDDLEWARE, UNIVERSAL_MANAGE_IDS.APPROVE_SWAP_TOKEN1).bind(commonAdapter));
345
+ vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(STRKToken.address, lstToken.address, UNIVERSAL_MANAGE_IDS.AVNU_SWAP_REWARDS).bind(commonAdapter));
346
+ return vaultSettings;
347
+ }
348
+
349
+ function getFAQs(lstSymbol: string, underlyingSymbol: string): FAQ[] {
350
+ return [
351
+ {
352
+ question: `What is the Hyper ${lstSymbol} Vault?`,
353
+ answer:
354
+ `The Hyper ${lstSymbol} Vault is a tokenized strategy that automatically loops your ${underlyingSymbol} or ${lstSymbol} to create up to 4x leverage to hence yield in a very low risk manner.`,
355
+ },
356
+ {
357
+ question: "How does yield allocation work?",
358
+ answer:
359
+ `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.`,
360
+ },
361
+ {
362
+ question: "Which protocols/dApp are used??",
363
+ answer: (
364
+ <span>
365
+ Currently, the LST is from <strong>Endur</strong> while <strong>Vesu</strong> is used to collateralize the looped position.
366
+ </span>
367
+ ),
368
+ },
369
+ {
370
+ question: "Can I get liquidated?",
371
+ 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.",
372
+ },
373
+ {
374
+ question: "What do I receive when I deposit?",
375
+ answer:
376
+ "Depositors receive vault tokens representing their proportional share of the vault. These tokens entitle holders to both the principal and accrued yield.",
377
+ },
378
+ {
379
+ question: "How long do withdrawals take?",
380
+ answer:
381
+ "Withdrawals may take up to 1-2 hours to process, as the vault unwinds and settles liquidity routing across integrated protocols. In case of large withdrawals, to avoid slippage, we may slowly unwind the position, which could make the withdrawals longer.",
382
+ },
383
+ {
384
+ question: "Is the Hyper xSTRK Vault non-custodial?",
385
+ answer:
386
+ "Yes. The Hyper xSTRK Vault operates entirely on-chain. Users always maintain control of their vault tokens, and the strategy is fully transparent.",
387
+ },
388
+ {
389
+ question: "Is the Vault audited?",
390
+ answer:
391
+ "Yes. The Hyper xSTRK Vault is audited by Zellic. Look for safety icon beside the strategy name for more details.",
392
+ },
393
+ {
394
+ question: "Are there any fees?",
395
+ answer:
396
+ "Troves charges a performance of 10% on the yield generated. The APY shown is net of this fee. This fee is only applied to the profits earned, ensuring that users retain their initial capital.",
397
+ },
398
+ ];
399
+ }
400
+
401
+ const _riskFactor: RiskFactor[] = [
402
+ { type: RiskType.SMART_CONTRACT_RISK, value: SmartContractRiskLevel.WELL_AUDITED, weight: 25, reason: "Audited by Zellic" },
403
+ { type: RiskType.LIQUIDATION_RISK, value: LiquidationRiskLevel.VERY_LOW_PROBABILITY, weight: 50, reason: "The collateral and debt are highly correlated" },
404
+ { type: RiskType.TECHNICAL_RISK, value: TechnicalRiskLevel.STABLE_INFRASTRUCTURE, weight: 50, 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." }
405
+ ];
406
+
407
+ const hyperxSTRK: UniversalStrategySettings = {
408
+ vaultAddress: ContractAddr.from('0x46c7a54c82b1fe374353859f554a40b8bd31d3e30f742901579e7b57b1b5960'),
409
+ manager: ContractAddr.from('0x5d499cd333757f461a0bedaca3dfc4d77320c773037e0aa299f22a6dbfdc03a'),
410
+ vaultAllocator: ContractAddr.from('0x511d07953a09bc7c505970891507c5a2486d2ea22752601a14db092186d7caa'),
411
+ redeemRequestNFT: ContractAddr.from('0x51e40b839dc0c2feca923f863072673b94abfa2483345be3b30b457a90d095'),
412
+ aumOracle: ContractAddr.from('0x48cf709870a1a0d453d37de108e0c41b8b89819ef54f95abc0e2e1f98bbe937'),
413
+ leafAdapters: [],
414
+ adapters: [],
415
+ targetHealthFactor: 1.1,
416
+ minHealthFactor: 1.05
417
+ }
418
+
419
+ const hyperxWBTC: UniversalStrategySettings = {
420
+ vaultAddress: ContractAddr.from('0x2da9d0f96a46b453f55604313785dc866424240b1c6811d13bef594343db818'),
421
+ manager: ContractAddr.from('0x75866db44c81e6986f06035206ee9c7d15833ddb22d6a22c016cfb5c866a491'),
422
+ vaultAllocator: ContractAddr.from('0x57b5c1bb457b5e840a2714ae53ada87d77be2f3fd33a59b4fe709ef20c020c1'),
423
+ redeemRequestNFT: ContractAddr.from('0x7a5dc288325456f05e70e9616e16bc02ffbe448f4b89f80b47c0970b989c7c'),
424
+ aumOracle: ContractAddr.from(''),
425
+ leafAdapters: [],
426
+ adapters: [],
427
+ targetHealthFactor: 1.1,
428
+ minHealthFactor: 1.05
429
+ }
430
+
431
+ const hyperxtBTC: UniversalStrategySettings = {
432
+ vaultAddress: ContractAddr.from('0x47d5f68477e5637ce0e56436c6b5eee5a354e6828995dae106b11a48679328'),
433
+ manager: ContractAddr.from('0xc4cc3e08029a0ae076f5fdfca70575abb78d23c5cd1c49a957f7e697885401'),
434
+ vaultAllocator: ContractAddr.from('0x50bbd4fe69f841ecb13b2619fe50ebfa4e8944671b5d0ebf7868fd80c61b31e'),
435
+ redeemRequestNFT: ContractAddr.from('0xeac9032f02057779816e38a6cb9185d12d86b3aacc9949b96b36de359c1e3'),
436
+ aumOracle: ContractAddr.from(''),
437
+ leafAdapters: [],
438
+ adapters: [],
439
+ targetHealthFactor: 1.1,
440
+ minHealthFactor: 1.05
441
+ }
442
+
443
+ const hyperxsBTC: UniversalStrategySettings = {
444
+ vaultAddress: ContractAddr.from('0x437ef1e7d0f100b2e070b7a65cafec0b2be31b0290776da8b4112f5473d8d9'),
445
+ manager: ContractAddr.from('0xc9ac023090625b0be3f6532ca353f086746f9c09f939dbc1b2613f09e5f821'),
446
+ vaultAllocator: ContractAddr.from('0x60c2d856936b975459a5b4eb28b8672d91f757bd76cebb6241f8d670185dc01'),
447
+ redeemRequestNFT: ContractAddr.from('0x429e8ee8bc7ecd1ade72630d350a2e0f10f9a2507c45f188ba17fe8f2ab4cf3'),
448
+ aumOracle: ContractAddr.from(''),
449
+ leafAdapters: [],
450
+ adapters: [],
451
+ targetHealthFactor: 1.1,
452
+ minHealthFactor: 1.05
453
+ }
454
+
455
+ function getInvestmentSteps(lstSymbol: string, underlyingSymbol: string) {
456
+ return [
457
+ `Deposit ${underlyingSymbol} into the vault`,
458
+ `The vault manager loops the ${underlyingSymbol} to buy ${lstSymbol}`,
459
+ `The vault manager collateralizes the ${lstSymbol} on Vesu`,
460
+ `The vault manager borrows more ${underlyingSymbol} to loop further`,
461
+ `Claim BTCFi STRK rewards weekly to swap to ${lstSymbol} and reinvest`,
462
+ `If required, adjust leverage or re-allocate assets within LST pool on Vesu to optimize yield`
463
+ ]
464
+ }
465
+
466
+ function getStrategySettings(lstSymbol: string, underlyingSymbol: string, addresses: UniversalStrategySettings, isPreview: boolean = false): IStrategyMetadata<UniversalStrategySettings> {
467
+ return {
468
+ name: `Hyper ${lstSymbol}`,
469
+ description: getDescription(lstSymbol),
470
+ address: addresses.vaultAddress,
471
+ launchBlock: 0,
472
+ type: 'Other',
473
+ depositTokens: [Global.getDefaultTokens().find(token => token.symbol === lstSymbol)!],
474
+ additionalInfo: getLooperSettings(lstSymbol, underlyingSymbol, addresses, VesuPools.Re7xSTRK),
475
+ risk: {
476
+ riskFactor: _riskFactor,
477
+ netRisk:
478
+ _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
479
+ _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
480
+ notARisks: getNoRiskTags(_riskFactor)
481
+ },
482
+ protocols: [Protocols.ENDUR, Protocols.VESU],
483
+ maxTVL: Web3Number.fromWei(0, 18),
484
+ contractDetails: getContractDetails(addresses),
485
+ faqs: getFAQs(lstSymbol, underlyingSymbol),
486
+ investmentSteps: getInvestmentSteps(lstSymbol, underlyingSymbol),
487
+ isPreview: isPreview
488
+ }
489
+ }
490
+
491
+ export const HyperLSTStrategies: IStrategyMetadata<UniversalStrategySettings>[] =
492
+ [
493
+ getStrategySettings('xSTRK', 'STRK', hyperxSTRK, false),
494
+ getStrategySettings('xWBTC', 'WBTC', hyperxWBTC, true),
495
+ getStrategySettings('xtBTC', 'tBTC', hyperxtBTC, true),
496
+ getStrategySettings('xsBTC', 'solvBTC', hyperxsBTC, true),
497
+ ]