@strkfarm/sdk 1.1.70 → 2.0.0-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/cli.js +2 -2
  2. package/dist/cli.mjs +2 -2
  3. package/dist/index.browser.global.js +67016 -59681
  4. package/dist/index.browser.mjs +29832 -23221
  5. package/dist/index.d.ts +2006 -787
  6. package/dist/index.js +25403 -18769
  7. package/dist/index.mjs +25333 -18739
  8. package/package.json +80 -76
  9. package/src/data/extended-deposit.abi.json +3613 -0
  10. package/src/data/universal-vault.abi.json +135 -20
  11. package/src/dataTypes/address.ts +7 -0
  12. package/src/global.ts +240 -193
  13. package/src/interfaces/common.tsx +26 -2
  14. package/src/modules/ExtendedWrapperSDk/index.ts +62 -0
  15. package/src/modules/ExtendedWrapperSDk/types.ts +311 -0
  16. package/src/modules/ExtendedWrapperSDk/wrapper.ts +395 -0
  17. package/src/modules/avnu.ts +17 -4
  18. package/src/modules/ekubo-quoter.ts +99 -10
  19. package/src/modules/erc20.ts +67 -21
  20. package/src/modules/harvests.ts +16 -29
  21. package/src/modules/index.ts +5 -1
  22. package/src/modules/lst-apr.ts +36 -0
  23. package/src/modules/midas.ts +159 -0
  24. package/src/modules/pricer-from-api.ts +2 -2
  25. package/src/modules/pricer-lst.ts +1 -1
  26. package/src/modules/pricer.ts +3 -38
  27. package/src/modules/token-market-data.ts +202 -0
  28. package/src/node/deployer.ts +1 -36
  29. package/src/strategies/autoCompounderStrk.ts +1 -1
  30. package/src/strategies/base-strategy.ts +20 -3
  31. package/src/strategies/ekubo-cl-vault.tsx +123 -306
  32. package/src/strategies/index.ts +4 -1
  33. package/src/strategies/svk-strategy.ts +247 -0
  34. package/src/strategies/universal-adapters/adapter-optimizer.ts +65 -0
  35. package/src/strategies/universal-adapters/adapter-utils.ts +5 -1
  36. package/src/strategies/universal-adapters/avnu-adapter.ts +411 -0
  37. package/src/strategies/universal-adapters/baseAdapter.ts +181 -153
  38. package/src/strategies/universal-adapters/common-adapter.ts +98 -77
  39. package/src/strategies/universal-adapters/extended-adapter.ts +661 -0
  40. package/src/strategies/universal-adapters/index.ts +5 -1
  41. package/src/strategies/universal-adapters/unused-balance-adapter.ts +109 -0
  42. package/src/strategies/universal-adapters/vesu-adapter.ts +220 -218
  43. package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +924 -0
  44. package/src/strategies/universal-adapters/vesu-supply-only-adapter.ts +58 -51
  45. package/src/strategies/universal-lst-muliplier-strategy.tsx +707 -774
  46. package/src/strategies/universal-strategy.tsx +1098 -1180
  47. package/src/strategies/vesu-extended-strategy/services/operationService.ts +34 -0
  48. package/src/strategies/vesu-extended-strategy/utils/config.runtime.ts +77 -0
  49. package/src/strategies/vesu-extended-strategy/utils/constants.ts +49 -0
  50. package/src/strategies/vesu-extended-strategy/utils/helper.ts +376 -0
  51. package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +1134 -0
  52. package/src/strategies/vesu-rebalance.tsx +16 -19
  53. package/src/utils/health-factor-math.ts +11 -5
@@ -0,0 +1,1134 @@
1
+ import {
2
+ getMainnetConfig,
3
+ IConfig,
4
+ IStrategyMetadata,
5
+ TokenInfo,
6
+ } from "@/interfaces";
7
+ import {
8
+ UNIVERSAL_MANAGE_IDS,
9
+ UniversalStrategySettings,
10
+ } from "../universal-strategy";
11
+ import { calculateExtendedLevergae } from "./utils/helper";
12
+ import { logger } from "@/utils";
13
+ import { AUDIT_URL } from "../universal-lst-muliplier-strategy";
14
+ import { getNoRiskTags } from "@/interfaces";
15
+ import { _riskFactor } from "../universal-lst-muliplier-strategy";
16
+ import { BUFFER_USDC_IN_WITHDRAWAL, EXTENDED_QTY_PRECISION, LIMIT_BALANCE, MAX_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED, MIN_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED, MINIMUM_EXTENDED_POSITION_SIZE, USDC_TOKEN_DECIMALS, WALLET_ADDRESS, WBTC_TOKEN_DECIMALS } from "./utils/constants";
17
+ import { PricerBase } from "@/modules/pricerBase";
18
+ import { ContractAddr, Web3Number } from "@/dataTypes";
19
+ import { Global } from "@/global";
20
+ import { ERC20 } from "@/modules";
21
+ import { Balance, OrderSide } from "@/modules/ExtendedWrapperSDk";
22
+ import { Protocols } from "@/interfaces";
23
+ import { MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP } from "./utils/constants";
24
+ import { getInvestmentSteps, getFAQs } from "../universal-lst-muliplier-strategy";
25
+ import { getContractDetails } from "../universal-strategy";
26
+ import { highlightTextWithLinks } from "@/interfaces";
27
+ import { PositionInfo } from "../universal-adapters";
28
+ import { APYType } from "../universal-adapters";
29
+ import { AUMTypes } from "../universal-strategy";
30
+ import { VesuPools } from "../universal-adapters";
31
+ import {
32
+ BaseAdapterConfig,
33
+ CommonAdapter,
34
+ UnusedBalanceAdapter,
35
+ VesuMultiplyAdapter,
36
+ } from "../universal-adapters";
37
+ import { Operations } from "./services/operationService";
38
+ import {
39
+ AVNU_EXCHANGE,
40
+ AVNU_QUOTE_URL,
41
+ AVNU_MIDDLEWARE,
42
+ EXTENDED_CONTRACT,
43
+ } from "../universal-adapters/adapter-utils";
44
+ import { PricerFromApi } from "@/modules";
45
+ import { ExtendedAdapter } from "../universal-adapters/extended-adapter";
46
+ import { SVKStrategy } from "../svk-strategy";
47
+ import { AvnuAdapter } from "../universal-adapters/avnu-adapter";
48
+ import {
49
+ calculateAmountDistribution,
50
+ calculateAmountDistributionForWithdrawal,
51
+ calculateVesuLeverage,
52
+ calculateVesUPositionSizeGivenExtended
53
+ } from "./utils/helper";
54
+ import { SingleTokenInfo } from "../base-strategy";
55
+ import { Call } from "starknet";
56
+
57
+
58
+ export interface VesuExtendedStrategySettings
59
+ extends UniversalStrategySettings {
60
+ underlyingToken: TokenInfo;
61
+ borrowable_assets: TokenInfo[];
62
+ targetHealthFactor: number;
63
+ quoteAmountToFetchPrice: Web3Number;
64
+ minHealthFactor: number;
65
+ aumOracle: ContractAddr;
66
+ minimumWBTCDifferenceForAvnuSwap: number;
67
+ }
68
+
69
+ export class VesuExtendedMultiplierStrategy<
70
+ S extends VesuExtendedStrategySettings
71
+ >
72
+ extends SVKStrategy<S>
73
+ implements Operations {
74
+
75
+ constructor(
76
+ config: IConfig,
77
+ pricer: PricerBase,
78
+ metadata: IStrategyMetadata<S>
79
+ ) {
80
+ super(config, pricer, metadata);
81
+ this.metadata.additionalInfo.adapters.forEach((adapter) => {
82
+ adapter.adapter.config.networkConfig = this.config;
83
+ adapter.adapter.config.pricer = this.pricer;
84
+ if ((adapter.adapter as VesuMultiplyAdapter).vesuAdapter) {
85
+ (adapter.adapter as VesuMultiplyAdapter).vesuAdapter.networkConfig =
86
+ this.config;
87
+ (adapter.adapter as VesuMultiplyAdapter).vesuAdapter.pricer =
88
+ this.pricer;
89
+ }
90
+ });
91
+ }
92
+
93
+ getTag() {
94
+ return `${VesuExtendedMultiplierStrategy.name}:${this.metadata.name}`;
95
+ }
96
+
97
+ async getAssetPrices() {
98
+ const wbtcToken = Global.getDefaultTokens().find(
99
+ (token) => token.symbol === "WBTC"
100
+ )!;
101
+ const usdcToken = Global.getDefaultTokens().find(
102
+ (token) => token.symbol === "USDC"
103
+ )!;
104
+ const collateralPrice = await this.pricer.getPrice(wbtcToken.symbol);
105
+ const debtPrice = await this.pricer.getPrice(usdcToken.symbol);
106
+ return {
107
+ collateralPrice,
108
+ debtPrice,
109
+ };
110
+ }
111
+
112
+ async getUnusedBalanceUSDCE(): Promise<SingleTokenInfo> {
113
+ const usdceToken = Global.getDefaultTokens().find(
114
+ (token) => token.symbol === "USDCe"
115
+ )!;
116
+ const balance = await new ERC20(this.config).balanceOf(
117
+ usdceToken.address,
118
+ WALLET_ADDRESS,
119
+ usdceToken.decimals
120
+ );
121
+ const price = await this.pricer.getPrice(usdceToken.symbol);
122
+ const usdValue =
123
+ Number(balance.toFixed(usdceToken.decimals)) * price.price;
124
+ return {
125
+ tokenInfo: usdceToken,
126
+ amount: balance,
127
+ usdValue,
128
+ };
129
+ }
130
+
131
+
132
+ async getUnusedBalanceWBTC(): Promise<SingleTokenInfo> {
133
+ const collateralToken = this.metadata.additionalInfo.borrowable_assets[0]!;
134
+ const balance = await new ERC20(this.config).balanceOf(
135
+ collateralToken.address,
136
+ this.metadata.additionalInfo.vaultAllocator,
137
+ collateralToken.decimals
138
+ );
139
+ const price = await this.pricer.getPrice(collateralToken.symbol);
140
+ const usdValue =
141
+ Number(balance.toFixed(collateralToken.decimals)) * price.price;
142
+ return {
143
+ tokenInfo: collateralToken,
144
+ amount: balance,
145
+ usdValue,
146
+ };
147
+ }
148
+
149
+ async getVesuAdapter(): Promise<VesuMultiplyAdapter | null> {
150
+ const vesuAdapter = this.metadata.additionalInfo.adapters.find(
151
+ (adapter) => adapter.adapter.name === VesuMultiplyAdapter.name
152
+ );
153
+ if (!vesuAdapter) {
154
+ logger.error("vesu adapter not found");
155
+ return null;
156
+ }
157
+ return vesuAdapter.adapter as VesuMultiplyAdapter;
158
+ }
159
+
160
+ async getAvnuAdapter(): Promise<AvnuAdapter | null> {
161
+ const avnuAdapter = this.metadata.additionalInfo.adapters.find(
162
+ (adapter) => adapter.adapter.name === AvnuAdapter.name
163
+ );
164
+ if (!avnuAdapter) {
165
+ logger.error("avnu adapter not found");
166
+ return null;
167
+ }
168
+ return avnuAdapter.adapter as AvnuAdapter;
169
+ }
170
+
171
+ async getExtendedAdapter(): Promise<ExtendedAdapter | null> {
172
+ const extendedAdapter = this.metadata.additionalInfo.adapters.find(
173
+ (adapter) => adapter.adapter.name === ExtendedAdapter.name
174
+ );
175
+ if (!extendedAdapter) {
176
+ logger.error("extended adapter not found");
177
+ return null;
178
+ }
179
+ return extendedAdapter.adapter as ExtendedAdapter;
180
+ }
181
+
182
+ async moveAssetsToVaultAllocator(amount: Web3Number, extendedAdapter: ExtendedAdapter): Promise<Call[]> {
183
+ try {
184
+ const usdceToken = Global.getDefaultTokens().find(
185
+ (token) => token.symbol === "USDCe"
186
+ )!;
187
+ const approveCall = new ERC20(this.config).approve(
188
+ usdceToken.address,
189
+ this.metadata.additionalInfo.vaultAllocator,
190
+ amount
191
+ );
192
+ const transferCall = new ERC20(this.config).transfer(
193
+ usdceToken.address,
194
+ this.metadata.additionalInfo.vaultAllocator,
195
+ amount
196
+ );
197
+ const proofsInfo = extendedAdapter.getProofsForFromLegacySwap(
198
+ this.getMerkleTree()
199
+ );
200
+ const proofGroups = proofsInfo.proofs;
201
+ const call = this.getManageCall(
202
+ proofGroups,
203
+ await proofsInfo.callConstructor({ amount: amount })
204
+ );
205
+ return [approveCall, transferCall, call];
206
+ } catch (err) {
207
+ logger.error(`error moving assets to vault allocator: ${err}`);
208
+ return [];
209
+ }
210
+ }
211
+
212
+ async shouldInvest(): Promise<{
213
+ shouldInvest: boolean;
214
+ vesuAmount: Web3Number;
215
+ extendedAmount: Web3Number;
216
+ extendedLeverage: number;
217
+ collateralPrice: number;
218
+ debtPrice: number;
219
+ vesuLeverage: number;
220
+ }> {
221
+ try {
222
+ const vesuAdapter = await this.getVesuAdapter();
223
+ const extendedAdapter = await this.getExtendedAdapter();
224
+ if (!vesuAdapter || !extendedAdapter || !extendedAdapter.client) {
225
+ logger.error(
226
+ `vesu or extended adapter not found: vesuAdapter=${vesuAdapter}, extendedAdapter=${extendedAdapter}`
227
+ );
228
+ return {
229
+ shouldInvest: false,
230
+ vesuAmount: new Web3Number(0, 0),
231
+ extendedAmount: new Web3Number(0, 0),
232
+ extendedLeverage: 0,
233
+ collateralPrice: 0,
234
+ debtPrice: 0,
235
+ vesuLeverage: 0,
236
+ };
237
+ }
238
+ const balance = await this.getUnusedBalance();
239
+ const usdcBalanceOnExtended = await extendedAdapter.getExtendedDepositAmount();
240
+ /** The LIMIT_BALANCE is the bffer amount to keep in the investing Cycle */
241
+ const amountToInvest = balance.amount.plus(usdcBalanceOnExtended?.availableForWithdrawal ?? 0).minus(LIMIT_BALANCE);
242
+
243
+ if (amountToInvest.lessThan(0)) {
244
+ return {
245
+ shouldInvest: false,
246
+ vesuAmount: new Web3Number(0, 0),
247
+ extendedAmount: new Web3Number(0, 0),
248
+ extendedLeverage: 0,
249
+ collateralPrice: 0,
250
+ debtPrice: 0,
251
+ vesuLeverage: 0,
252
+ };
253
+ }
254
+
255
+ const extendedPositon = await extendedAdapter.getAllOpenPositions();
256
+ if (!extendedPositon) {
257
+ logger.error("error getting extended position to decide move assets");
258
+ return {
259
+ shouldInvest: false,
260
+ vesuAmount: new Web3Number(0, 0),
261
+ extendedAmount: new Web3Number(0, 0),
262
+ extendedLeverage: 0,
263
+ collateralPrice: 0,
264
+ debtPrice: 0,
265
+ vesuLeverage: 0,
266
+ };
267
+ }
268
+ const { collateralTokenAmount } =
269
+ await vesuAdapter.vesuAdapter.getAssetPrices();
270
+
271
+ const {
272
+ collateralPrice,
273
+ debtPrice
274
+ } = await this.getAssetPrices();
275
+ const { vesu_amount, extended_amount, extended_leverage, vesu_leverage } =
276
+ await calculateAmountDistribution(
277
+ amountToInvest.toNumber(),
278
+ extendedAdapter.client,
279
+ extendedAdapter.config.extendedMarketName,
280
+ collateralPrice.price,
281
+ debtPrice.price,
282
+ collateralTokenAmount,
283
+ extendedPositon
284
+ );
285
+ if (
286
+ !vesu_amount ||
287
+ !extended_amount ||
288
+ !extended_leverage ||
289
+ !vesu_leverage
290
+ ) {
291
+ logger.error(
292
+ `Not enough amount to invest: vesu_amount=${vesu_amount}, extended_amount=${extended_amount}`
293
+ );
294
+ return {
295
+ shouldInvest: false,
296
+ vesuAmount: new Web3Number(0, 0),
297
+ extendedAmount: new Web3Number(0, 0),
298
+ extendedLeverage: 0,
299
+ collateralPrice: 0,
300
+ debtPrice: 0,
301
+ vesuLeverage: 0,
302
+ };
303
+ }
304
+ return {
305
+ shouldInvest: true,
306
+ vesuAmount: vesu_amount,
307
+ extendedAmount: extended_amount,
308
+ extendedLeverage: extended_leverage,
309
+ vesuLeverage: vesu_leverage,
310
+ collateralPrice: collateralPrice.price,
311
+ debtPrice: debtPrice.price,
312
+ };
313
+ } catch (err) {
314
+ logger.error(`error deciding invest: ${err}`);
315
+ return {
316
+ shouldInvest: false,
317
+ vesuAmount: new Web3Number(0, 0),
318
+ extendedAmount: new Web3Number(0, 0),
319
+ extendedLeverage: 0,
320
+ collateralPrice: 0,
321
+ debtPrice: 0,
322
+ vesuLeverage: 0,
323
+ };
324
+ }
325
+ }
326
+
327
+ async shouldMoveAssets(extendedAmount: Web3Number, vesuAmount: Web3Number): Promise<Call[]> {
328
+ try {
329
+ const vesuAdapter = await this.getVesuAdapter();
330
+ const extendedAdapter = await this.getExtendedAdapter();
331
+ let calls: Call[] = [];
332
+ if (!vesuAdapter || !extendedAdapter || !extendedAdapter.client) {
333
+ logger.error(
334
+ `vesu or extended adapter not found: vesuAdapter=${vesuAdapter}, extendedAdapter=${extendedAdapter}`
335
+ );
336
+ return calls;
337
+ }
338
+ if (extendedAmount.lessThan(0)) {
339
+ try {
340
+ const {calls: extendedCalls, status: extendedStatus} = await this.moveAssets(
341
+ {
342
+ to: Protocols.VAULT.name,
343
+ from: Protocols.EXTENDED.name,
344
+ amount: extendedAmount.abs(),
345
+ },
346
+ extendedAdapter,
347
+ vesuAdapter
348
+ );
349
+ //If withdrawal succesfull, then do further
350
+ if(extendedStatus){
351
+ calls.push(...extendedCalls);
352
+ }else{
353
+ return [];
354
+ }
355
+ } catch (err) {
356
+ logger.error(`Failed moving assets to vault: ${err}`);
357
+ }
358
+ }
359
+
360
+ if (vesuAmount.lessThan(0)) {
361
+ try {
362
+ const {calls: vesuCalls, status: vesuStatus} = await this.moveAssets(
363
+ {
364
+ to: Protocols.EXTENDED.name,
365
+ from: Protocols.VESU.name,
366
+ amount: vesuAmount.abs(),
367
+ },
368
+ extendedAdapter,
369
+ vesuAdapter
370
+ );
371
+ calls.push(...vesuCalls);
372
+ if(!vesuStatus){
373
+ return [];
374
+ }
375
+ } catch (err) {
376
+ logger.error(`Failed moving assets to vault: ${err}`);
377
+ }
378
+ }
379
+
380
+ const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
381
+ if (!extendedHoldings) {
382
+ logger.error(`error getting extended holdings: ${extendedHoldings}`);
383
+ return calls;
384
+ }
385
+ const usdcAmountInWallet = (await this.getUnusedBalance()).amount;
386
+ const usdcAmountOnExtended = parseFloat(
387
+ extendedHoldings.availableForWithdrawal
388
+ );
389
+ if (extendedAmount.minus(usdcAmountOnExtended).greaterThan(0)) {
390
+ //move assets to extended
391
+ try {
392
+ const {calls: extendedCalls} = await this.moveAssets(
393
+ {
394
+ to: Protocols.EXTENDED.name,
395
+ from: Protocols.VAULT.name,
396
+ amount: extendedAmount.minus(usdcAmountOnExtended),
397
+ },
398
+ extendedAdapter,
399
+ vesuAdapter
400
+ );
401
+ calls.push(...extendedCalls);
402
+ } catch (err) {
403
+ logger.error(`Failed moving assets to extended: ${err}`);
404
+ }
405
+ }
406
+ if (vesuAmount.minus(usdcAmountInWallet).greaterThan(0)) {
407
+ //move assets to vesu
408
+ try {
409
+ const {calls: vesuCalls, status: vesuStatus} = await this.moveAssets(
410
+ {
411
+ to: Protocols.VAULT.name,
412
+ from: Protocols.EXTENDED.name,
413
+ amount: vesuAmount.minus(usdcAmountInWallet),
414
+ },
415
+ extendedAdapter,
416
+ vesuAdapter
417
+ );
418
+ if(!vesuStatus){
419
+ return [];
420
+ }
421
+ calls.push(...vesuCalls);
422
+ } catch (err) {
423
+ logger.error(`Failed moving assets to vault: ${err}`);
424
+ }
425
+ }
426
+ return calls;
427
+ } catch (err) {
428
+ logger.error(`Failed moving assets to vesu: ${err}`);
429
+ return [];
430
+ }
431
+ }
432
+
433
+ async moveAssets(
434
+ params: {
435
+ amount: Web3Number;
436
+ from: string;
437
+ to: string;
438
+ },
439
+ extendedAdapter: ExtendedAdapter,
440
+ vesuAdapter: VesuMultiplyAdapter
441
+ ): Promise<{
442
+ calls: Call[];
443
+ status: boolean;
444
+ }> {
445
+ try {
446
+ const avnuAdapter = await this.getAvnuAdapter();
447
+ if (!avnuAdapter) {
448
+ logger.error(`avnu adapter not found: ${avnuAdapter}`);
449
+ return {
450
+ calls: [],
451
+ status: false
452
+ };
453
+ }
454
+ logger.info(`moveAssets params, ${JSON.stringify(params)}`);
455
+ const collateralToken = vesuAdapter.config.supportedPositions[0].asset;
456
+ const {
457
+ collateralPrice,
458
+ } = await this.getAssetPrices();
459
+
460
+ if (params.to === Protocols.EXTENDED.name && params.from === Protocols.VAULT.name) {
461
+ const proofsInfo = extendedAdapter.getProofs(
462
+ true,
463
+ this.getMerkleTree()
464
+ );
465
+ const calls = [];
466
+ const proofGroups = proofsInfo.proofs;
467
+ const call = this.getManageCall(
468
+ proofGroups,
469
+ await proofsInfo.callConstructor({ amount: params.amount })
470
+ );
471
+ calls.push(call);
472
+ return {
473
+ calls: [call],
474
+ status: true
475
+ };
476
+ } else if (params.to === Protocols.VAULT.name && params.from === Protocols.EXTENDED.name) {
477
+ const extendedLeverage = calculateExtendedLevergae();
478
+ const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
479
+ if (!extendedHoldings) {
480
+ logger.error(`error getting extended holdings: ${extendedHoldings}`);
481
+ return {
482
+ calls: [],
483
+ status: false
484
+ };
485
+ }
486
+ const extendedHoldingAmount = new Web3Number(
487
+ extendedHoldings.availableForWithdrawal,
488
+ USDC_TOKEN_DECIMALS
489
+ );
490
+
491
+ const leftAmountAfterWithdrawalAmountInAccount = params.amount.minus(extendedHoldingAmount);
492
+ const btcAmount = leftAmountAfterWithdrawalAmountInAccount.dividedBy(collateralPrice.price);
493
+ const openLongPosition = await extendedAdapter.createOrder(
494
+ extendedLeverage.toString(),
495
+ btcAmount.toNumber(),
496
+ OrderSide.BUY
497
+ )
498
+ if (!openLongPosition) {
499
+ logger.error(`error opening long position: ${openLongPosition}`);
500
+ return {
501
+ calls: [],
502
+ status: false
503
+ };
504
+ }
505
+ await new Promise(resolve => setTimeout(resolve, 5000));
506
+ const withdrawalFromExtended =
507
+ await extendedAdapter.withdrawFromExtended(params.amount);
508
+ if (withdrawalFromExtended) {
509
+ /**
510
+ * We need to move assets from my wallet back to vault contract
511
+ */
512
+ const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
513
+ logger.info(`extendedHoldings after withdrawal ${extendedHoldings}`);
514
+ await new Promise(resolve => setTimeout(resolve, 10000));
515
+ const calls = await this.moveAssetsToVaultAllocator(params.amount, extendedAdapter);
516
+ if (calls.length > 0) {
517
+ return {
518
+ calls: calls,
519
+ status: true
520
+ };
521
+ }
522
+ } else {
523
+ logger.error("withdrawal from extended failed");
524
+ return {
525
+ calls: [],
526
+ status: false
527
+ };
528
+ }
529
+ } else if (params.to === Protocols.VAULT.name && params.from === Protocols.VESU.name) {
530
+ //withdraw from vesu
531
+ const vesuAmountInBTC = new Web3Number(
532
+ params.amount.dividedBy(collateralPrice.price).toNumber(),
533
+ collateralToken.decimals
534
+ );
535
+ const proofsInfo = vesuAdapter.getProofs(false, this.getMerkleTree());
536
+ const calls = [];
537
+ const proofGroups = proofsInfo.proofs;
538
+ const call = this.getManageCall(
539
+ proofGroups,
540
+ await proofsInfo.callConstructor({ amount: vesuAmountInBTC })
541
+ );
542
+ calls.push(call);
543
+ const swapProofsInfo = avnuAdapter.getProofs(false, this.getMerkleTree());
544
+ const swapProofGroups = swapProofsInfo.proofs;
545
+ const swapCall = this.getManageCall(
546
+ swapProofGroups,
547
+ await swapProofsInfo.callConstructor({ amount: vesuAmountInBTC })
548
+ );
549
+ calls.push(swapCall);
550
+ return {
551
+ calls: calls,
552
+ status: true
553
+ };
554
+ } else if (params.to === Protocols.EXTENDED.name && params.from === Protocols.VESU.name) {
555
+ const vesuAmountInBTC = new Web3Number(
556
+ params.amount.dividedBy(collateralPrice.price).toNumber(),
557
+ collateralToken.decimals
558
+ );
559
+ const proofsInfo = vesuAdapter.getProofs(false, this.getMerkleTree());
560
+ const calls = [];
561
+ const proofGroups = proofsInfo.proofs;
562
+ const call = this.getManageCall(
563
+ proofGroups,
564
+ await proofsInfo.callConstructor({ amount: vesuAmountInBTC })
565
+ );
566
+ calls.push(call);
567
+ const swapProofsInfo = avnuAdapter.getProofs(false, this.getMerkleTree());
568
+ const swapProofGroups = swapProofsInfo.proofs;
569
+ const swapCall = this.getManageCall(
570
+ swapProofGroups,
571
+ await swapProofsInfo.callConstructor({ amount: vesuAmountInBTC })
572
+ );
573
+ calls.push(swapCall);
574
+ const proofsInfoDeposit = extendedAdapter.getProofs(
575
+ true,
576
+ this.getMerkleTree()
577
+ );
578
+ //Deposit Amount would still be in usdc
579
+ const proofGroupsDeposit = proofsInfoDeposit.proofs;
580
+ const callDeposit = this.getManageCall(
581
+ proofGroupsDeposit,
582
+ await proofsInfoDeposit.callConstructor({ amount: params.amount })
583
+ );
584
+ calls.push(callDeposit);
585
+ return {
586
+ calls: calls,
587
+ status: true
588
+ };
589
+ }
590
+ return {
591
+ calls: [],
592
+ status: false
593
+ };
594
+ } catch (err) {
595
+ logger.error(`error moving assets: ${err}`);
596
+ return {
597
+ calls: [],
598
+ status: false
599
+ };
600
+ }
601
+ }
602
+
603
+ async handleDeposit(): Promise<{
604
+ extendedAmountInBTC: Web3Number,
605
+ calls: Call[]
606
+ }> {
607
+ try {
608
+ const vesuAdapter = await this.getVesuAdapter();
609
+ const extendedAdapter = await this.getExtendedAdapter();
610
+ const avnuAdapter = await this.getAvnuAdapter();
611
+ if (
612
+ !vesuAdapter ||
613
+ !extendedAdapter ||
614
+ !extendedAdapter.client ||
615
+ !avnuAdapter
616
+ ) {
617
+ logger.error(
618
+ "vesu or extended adapter not found",
619
+ vesuAdapter,
620
+ extendedAdapter
621
+ );
622
+ return {
623
+ extendedAmountInBTC: new Web3Number(0, 0),
624
+ calls: [],
625
+ };
626
+ }
627
+ const extendedLeverage = calculateExtendedLevergae();
628
+ const isPriceDifferenceBetweenAvnuAndExtended = await this.checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter, vesuAdapter, avnuAdapter);
629
+ if (!isPriceDifferenceBetweenAvnuAndExtended) {
630
+ logger.error("price difference between avnu and extended doesn't fit the range");
631
+ return {
632
+ extendedAmountInBTC: new Web3Number(0, 0),
633
+ calls: [],
634
+ };
635
+ }
636
+ const position = await extendedAdapter.getAllOpenPositions();
637
+ if (!position) {
638
+ logger.error("error getting extended position", position);
639
+ return {
640
+ extendedAmountInBTC: new Web3Number(0, 0),
641
+ calls: [],
642
+ };
643
+ }
644
+ const extendedPositionValue = position.length > 0 ? parseFloat(position[0].value) : 0;
645
+ const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
646
+ if (!extendedHoldings) {
647
+ logger.error(`error getting extended holdings: ${extendedHoldings}`);
648
+ return {
649
+ extendedAmountInBTC: new Web3Number(0, 0),
650
+ calls: [],
651
+ };
652
+ }
653
+ const extendedHoldingAmount = new Web3Number(
654
+ extendedHoldings.availableForWithdrawal,
655
+ USDC_TOKEN_DECIMALS
656
+ );
657
+ const {
658
+ collateralTokenAmount,
659
+ } = await vesuAdapter.vesuAdapter.getAssetPrices();
660
+ const { collateralPrice } = await this.getAssetPrices();
661
+ const { vesuAmountInBTC, extendedAmountInBTC } = calculateVesUPositionSizeGivenExtended(
662
+ extendedPositionValue,
663
+ extendedHoldingAmount,
664
+ collateralTokenAmount,
665
+ collateralPrice.price
666
+ );
667
+ logger.info(`vesuAmountInBTC ${vesuAmountInBTC}, extendedAmountInBTC ${extendedAmountInBTC}`);
668
+
669
+ let calls: Call[] = [];
670
+ if (vesuAmountInBTC.greaterThan(MINIMUM_EXTENDED_POSITION_SIZE)) {
671
+ const proofsInfo = vesuAdapter.getProofs(true, this.getMerkleTree());
672
+ const proofGroups = proofsInfo.proofs;
673
+ const call = this.getManageCall(
674
+ proofGroups,
675
+ await proofsInfo.callConstructor({
676
+ amount: vesuAmountInBTC,
677
+ })
678
+ );
679
+ const { amount: wbtcAmountInVaultAllocator } = await this.getUnusedBalanceWBTC();
680
+ if (wbtcAmountInVaultAllocator.lessThan(vesuAmountInBTC)) {
681
+ logger.info(`WBTC amount in vault allocator is less than vesu amount required in WBTC thus swapping, wbtcAmountInVaultAllocator: ${wbtcAmountInVaultAllocator}, vesuAmountInBTC: ${vesuAmountInBTC}`);
682
+ const swapProofsInfo = avnuAdapter.getProofs(true, this.getMerkleTree());
683
+ const swapProofGroups = swapProofsInfo.proofs;
684
+ const swapCall = this.getManageCall(
685
+ swapProofGroups,
686
+ await swapProofsInfo.callConstructor({
687
+ amount: vesuAmountInBTC,
688
+ })
689
+ );
690
+ calls.push(swapCall);
691
+ }
692
+ calls.push(call);
693
+ }
694
+
695
+ const shortPosition = extendedAmountInBTC.multipliedBy(3).abs().greaterThan(MINIMUM_EXTENDED_POSITION_SIZE) ? await extendedAdapter.createOrder(
696
+ extendedLeverage.toString(),
697
+ extendedAmountInBTC.toNumber(),
698
+ OrderSide.SELL
699
+ ) : null;
700
+ if (!shortPosition && extendedAmountInBTC.multipliedBy(3).abs().greaterThan(MINIMUM_EXTENDED_POSITION_SIZE)) {
701
+ logger.error(`error creating short position thus no position to be opened on vesu: ${shortPosition}`);
702
+ return {
703
+ extendedAmountInBTC: new Web3Number(0, 0),
704
+ calls: [],
705
+ };
706
+ }
707
+ return {
708
+ extendedAmountInBTC: extendedAmountInBTC,
709
+ calls: calls,
710
+ };
711
+ } catch (err) {
712
+ logger.error(`error handling deposit: ${err}`);
713
+ return {
714
+ extendedAmountInBTC: new Web3Number(0, 0),
715
+ calls: [],
716
+ };;
717
+ }
718
+ }
719
+
720
+ async checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter: ExtendedAdapter, vesuAdapter: VesuMultiplyAdapter, avnuAdapter: AvnuAdapter): Promise<boolean> {
721
+ const {
722
+ ask, bid
723
+ } = await extendedAdapter.fetchOrderBookBTCUSDC();
724
+ const price = ask.plus(bid).dividedBy(2);
725
+ const btcToken = vesuAdapter.config.supportedPositions[0].asset;
726
+ const btcPriceAvnu = await avnuAdapter.getPriceOfToken(btcToken.address.toString());
727
+ if (!btcPriceAvnu) {
728
+ logger.error(`error getting btc price avnu: ${btcPriceAvnu}`);
729
+ return false;
730
+ }
731
+ const priceDifference = price.minus(btcPriceAvnu).toNumber();
732
+ if (priceDifference < MAX_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED && priceDifference > MIN_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED) {
733
+ return true;
734
+ }
735
+ logger.error(`price difference between avnu and extended doesn't fit the range, priceDifference: ${priceDifference}`);
736
+ return false;
737
+ }
738
+
739
+ async handleWithdraw(amount: Web3Number): Promise<{calls: Call[], status: boolean}> {
740
+ try {
741
+ const usdcBalanceVaultAllocator = await this.getUnusedBalance()
742
+ const usdcBalanceDifference = amount.plus(BUFFER_USDC_IN_WITHDRAWAL).minus(usdcBalanceVaultAllocator.usdValue);
743
+ logger.info(`usdcBalanceDifference, ${usdcBalanceDifference.toNumber()}`);
744
+ let calls: Call[] = [];
745
+ let status: boolean = true;
746
+ if (usdcBalanceDifference.lessThan(0)) {
747
+ const withdrawCall = await this.getBringLiquidityCall({
748
+ amount: usdcBalanceVaultAllocator.amount
749
+ })
750
+ logger.info("withdraw call", withdrawCall);
751
+ calls.push(withdrawCall);
752
+ return {
753
+ calls:calls,
754
+ status:true
755
+ };
756
+ }
757
+ const vesuAdapter = await this.getVesuAdapter();
758
+ const extendedAdapter = await this.getExtendedAdapter();
759
+ if (!vesuAdapter || !extendedAdapter || !extendedAdapter.client) {
760
+ status = false;
761
+ logger.error(
762
+ `vesu or extended adapter not found: vesuAdapter=${vesuAdapter}, extendedAdapter=${extendedAdapter}`
763
+ );
764
+ return {
765
+ calls:calls,
766
+ status:status
767
+ };
768
+ }
769
+ const { collateralTokenAmount } =
770
+ await vesuAdapter.vesuAdapter.getAssetPrices();
771
+ const {
772
+ collateralPrice
773
+ } = await this.getAssetPrices();
774
+ const extendedPositon = await extendedAdapter.getAllOpenPositions();
775
+ if(!extendedPositon) {
776
+ status = false;
777
+ logger.error("error getting extended position", extendedPositon);
778
+ return {
779
+ calls:calls,
780
+ status:status
781
+ }
782
+ }
783
+ const amountDistributionForWithdrawal =
784
+ await calculateAmountDistributionForWithdrawal(
785
+ usdcBalanceDifference,
786
+ collateralPrice.price,
787
+ collateralTokenAmount,
788
+ extendedPositon
789
+ );
790
+ if (!amountDistributionForWithdrawal) {
791
+ status = false;
792
+ logger.error(
793
+ `error calculating amount distribution for withdrawal: ${amountDistributionForWithdrawal}`
794
+ );
795
+ return {
796
+ calls:calls,
797
+ status:status
798
+ };
799
+ }
800
+ const { vesu_amount, extended_amount } = amountDistributionForWithdrawal;
801
+
802
+ if (status && vesu_amount.greaterThan(0)) {
803
+ const {calls: vesuCalls, status: vesuStatus} = await this.moveAssets(
804
+ {
805
+ amount: vesu_amount,
806
+ from: Protocols.VESU.name,
807
+ to: Protocols.VAULT.name,
808
+ },
809
+ extendedAdapter,
810
+ vesuAdapter
811
+ );
812
+ status = vesuStatus;
813
+ calls.push(...vesuCalls);
814
+ }
815
+ if (status && extended_amount.greaterThan(0)) {
816
+ const {calls: extendedCalls, status: extendedStatus} = await this.moveAssets(
817
+ {
818
+ amount: extended_amount,
819
+ from: Protocols.EXTENDED.name,
820
+ to: Protocols.VAULT.name,
821
+ },
822
+ extendedAdapter,
823
+ vesuAdapter
824
+ );
825
+ status = extendedStatus;
826
+ if(status) {
827
+ calls.push(...extendedCalls);
828
+ }else{
829
+ logger.error("error moving assets to vault: extendedStatus: ${extendedStatus}");
830
+ return {
831
+ calls: [],
832
+ status: status
833
+ };
834
+ }
835
+ }
836
+ const withdrawCall = await this.getBringLiquidityCall({
837
+ amount: amount
838
+ })
839
+ logger.info("withdraw call", withdrawCall);
840
+ calls.push(withdrawCall);
841
+ return {
842
+ calls: calls,
843
+ status: status
844
+ };
845
+ } catch (err) {
846
+ logger.error(`error handling withdrawal: ${err}`);
847
+ return {
848
+ calls: [],
849
+ status: false
850
+ };
851
+ }
852
+ }
853
+
854
+ async getAUM(): Promise<{ net: SingleTokenInfo, prevAum: Web3Number, splits: PositionInfo[] }> {
855
+ const allPositions: PositionInfo[] = [];
856
+ for (let adapter of this.metadata.additionalInfo.adapters) {
857
+ const positions = await adapter.adapter.getPositions();
858
+ allPositions.push(...positions);
859
+ }
860
+
861
+ const assetPrice = await this.pricer.getPrice(this.asset().symbol);
862
+ let netAUM = new Web3Number(0, this.asset().decimals);
863
+ for (let position of allPositions) {
864
+ if (position.tokenInfo.address.eq(this.asset().address)) {
865
+ netAUM = netAUM.plus(position.amount);
866
+ } else {
867
+ netAUM = netAUM.plus(position.usdValue / assetPrice.price);
868
+ }
869
+ }
870
+
871
+ const prevAum = await this.getPrevAUM();
872
+ const realAUM: PositionInfo = {
873
+ tokenInfo: this.asset(),
874
+ amount: netAUM,
875
+ usdValue: netAUM.toNumber() * assetPrice.price,
876
+ apy: { apy: netAUM.toNumber() * assetPrice.price, type: APYType.BASE },
877
+ remarks: AUMTypes.FINALISED,
878
+ protocol: Protocols.NONE // just placeholder
879
+ };
880
+
881
+ const estimatedAUMDelta: PositionInfo = {
882
+ tokenInfo: this.asset(),
883
+ amount: Web3Number.fromWei('0', this.asset().decimals),
884
+ usdValue: 0,
885
+ apy: { apy: 0, type: APYType.BASE },
886
+ remarks: AUMTypes.DEFISPRING,
887
+ protocol: Protocols.NONE // just placeholder
888
+ };
889
+
890
+ return {
891
+ net: {
892
+ tokenInfo: this.asset(),
893
+ amount: netAUM,
894
+ usdValue: netAUM.toNumber() * assetPrice.price
895
+ }, prevAum: prevAum, splits: [realAUM, estimatedAUMDelta]
896
+ };
897
+ }
898
+
899
+ }
900
+
901
+ function getLooperSettings(
902
+ lstSymbol: string,
903
+ underlyingSymbol: string,
904
+ vaultSettings: VesuExtendedStrategySettings,
905
+ pool1: ContractAddr,
906
+ extendedBackendUrl: string,
907
+ extendedApiKey: string,
908
+ vaultIdExtended: number,
909
+ ) {
910
+ vaultSettings.leafAdapters = [];
911
+
912
+ const wbtcToken = Global.getDefaultTokens().find(
913
+ (token) => token.symbol === lstSymbol
914
+ )!;
915
+ const usdcToken = Global.getDefaultTokens().find(
916
+ (token) => token.symbol === underlyingSymbol
917
+ )!;
918
+
919
+ const baseAdapterConfig: BaseAdapterConfig = {
920
+ baseToken: wbtcToken,
921
+ supportedPositions: [
922
+ { asset: usdcToken, isDebt: true },
923
+ { asset: wbtcToken, isDebt: false },
924
+ ],
925
+ //Since we open 2 positions, we need to add both positions, one is debt another is collateral
926
+ networkConfig: getMainnetConfig(),
927
+ pricer: new PricerFromApi(getMainnetConfig(), Global.getDefaultTokens()),
928
+ vaultAllocator: vaultSettings.vaultAllocator,
929
+ vaultAddress: vaultSettings.vaultAddress,
930
+ };
931
+
932
+ const avnuAdapter = new AvnuAdapter({
933
+ ...baseAdapterConfig,
934
+ avnuContract: AVNU_MIDDLEWARE,
935
+ slippage: 0.01,
936
+ baseUrl: AVNU_QUOTE_URL,
937
+ });
938
+
939
+ const extendedAdapter = new ExtendedAdapter({
940
+ ...baseAdapterConfig,
941
+ supportedPositions: [
942
+ { asset: usdcToken, isDebt: true },
943
+ ],
944
+ vaultIdExtended: vaultIdExtended,
945
+ extendedContract: EXTENDED_CONTRACT,
946
+ extendedBackendUrl: extendedBackendUrl,
947
+ extendedApiKey: extendedApiKey,
948
+ extendedTimeout: 30000,
949
+ extendedRetries: 3,
950
+ extendedBaseUrl: "https://api.starknet.extended.exchange",
951
+ extendedMarketName: "BTC-USD",
952
+ extendedPrecision: 5,
953
+ avnuAdapter: avnuAdapter,
954
+ });
955
+
956
+ const vesuMultiplyAdapter = new VesuMultiplyAdapter({
957
+ poolId: pool1,
958
+ collateral: wbtcToken,
959
+ debt: usdcToken,
960
+ targetHealthFactor: vaultSettings.targetHealthFactor,
961
+ minHealthFactor: vaultSettings.minHealthFactor,
962
+ quoteAmountToFetchPrice: vaultSettings.quoteAmountToFetchPrice,
963
+ ...baseAdapterConfig,
964
+ supportedPositions: [
965
+ { asset: wbtcToken, isDebt: false },
966
+ { asset: usdcToken, isDebt: true },
967
+ ],
968
+ });
969
+
970
+ const unusedBalanceAdapter = new UnusedBalanceAdapter({
971
+ ...baseAdapterConfig,
972
+ });
973
+
974
+ vaultSettings.adapters.push({
975
+ id: `${vesuMultiplyAdapter.name}_${wbtcToken.symbol}_${usdcToken.symbol}`,
976
+ adapter: vesuMultiplyAdapter,
977
+ });
978
+
979
+ vaultSettings.adapters.push({
980
+ id: `${unusedBalanceAdapter.name}_${wbtcToken.symbol}`,
981
+ adapter: unusedBalanceAdapter,
982
+ });
983
+
984
+ vaultSettings.adapters.push({
985
+ id: `${extendedAdapter.name}_${wbtcToken.symbol}`,
986
+ adapter: extendedAdapter,
987
+ });
988
+
989
+ vaultSettings.adapters.push({
990
+ id: `${avnuAdapter.name}_${wbtcToken.symbol}`,
991
+ adapter: avnuAdapter,
992
+ });
993
+
994
+ const commonAdapter = new CommonAdapter({
995
+ id: UNIVERSAL_MANAGE_IDS.FLASH_LOAN,
996
+ vaultAddress: vaultSettings.vaultAddress,
997
+ vaultAllocator: vaultSettings.vaultAllocator,
998
+ manager: vaultSettings.manager,
999
+ asset: wbtcToken.address,
1000
+ });
1001
+
1002
+ vaultSettings.leafAdapters.push(() => vesuMultiplyAdapter.getDepositLeaf());
1003
+ vaultSettings.leafAdapters.push(() =>
1004
+ vesuMultiplyAdapter.getWithdrawLeaf()
1005
+ );
1006
+ vaultSettings.leafAdapters.push(() => extendedAdapter.getDepositLeaf());
1007
+ vaultSettings.leafAdapters.push(() => extendedAdapter.getSwapFromLegacyLeaf());
1008
+ vaultSettings.leafAdapters.push(() => avnuAdapter.getDepositLeaf());
1009
+ vaultSettings.leafAdapters.push(() => avnuAdapter.getWithdrawLeaf());
1010
+ // Doubt here, should this be usdcToken.address, or wbtcToken.address?
1011
+ vaultSettings.leafAdapters.push(
1012
+ commonAdapter
1013
+ .getApproveAdapter(
1014
+ usdcToken.address,
1015
+ vaultSettings.vaultAddress,
1016
+ UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY
1017
+ )
1018
+ .bind(commonAdapter)
1019
+ );
1020
+
1021
+ vaultSettings.leafAdapters.push(
1022
+ commonAdapter
1023
+ .getBringLiquidityAdapter(UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY)
1024
+ .bind(commonAdapter)
1025
+ );
1026
+ return vaultSettings;
1027
+ }
1028
+
1029
+
1030
+ function getDescription(tokenSymbol: string, underlyingSymbol: string) {
1031
+ return VaultDescription(tokenSymbol, underlyingSymbol);
1032
+ }
1033
+
1034
+ export default function VaultDescription(
1035
+ lstSymbol: string,
1036
+ underlyingSymbol: string
1037
+ ) {
1038
+ const containerStyle = {
1039
+ maxWidth: "800px",
1040
+ margin: "0 auto",
1041
+ backgroundColor: "#111",
1042
+ color: "#eee",
1043
+ fontFamily: "Arial, sans-serif",
1044
+ borderRadius: "12px",
1045
+ };
1046
+
1047
+ return (
1048
+ <div style={containerStyle}>
1049
+ <h1 style={{ fontSize: "18px", marginBottom: "10px" }}>Liquidation risk managed leverged {lstSymbol} Vault</h1>
1050
+ <p style={{ fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }}>
1051
+ 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
1052
+ is swapped to {lstSymbol} to create leverage. Depositors receive vault shares that
1053
+ represent a proportional claim on the underlying assets and accrued yield.
1054
+ </p>
1055
+
1056
+ <p style={{ fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }}>
1057
+ 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" }])}
1058
+ {" "}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.
1059
+ </p>
1060
+
1061
+ <div style={{ backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }}>
1062
+ <p style={{ fontSize: "13px", color: "#ccc" }}>
1063
+ <strong>Withdrawals:</strong> Requests can take up to <strong>1-2 hours</strong> to process as the vault unwinds and settles routing.
1064
+ </p>
1065
+ </div>
1066
+ <div style={{ backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }}>
1067
+ <p style={{ fontSize: "13px", color: "#ccc" }}>
1068
+ <strong>Debt limits:</strong> Pools on Vesu have debt caps that are gradually increased over time. Until caps are raised, deposited Tokens remain in the vault, generating a shared net return for all depositors. There is no additional fee taken by Troves on Yield token's APY, its only on added gain.
1069
+ </p>
1070
+ </div>
1071
+ {/* <div style={{ backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }}>
1072
+ <p style={{ fontSize: "13px", color: "#ccc" }}>
1073
+ <strong>APY assumptions:</strong> APY shown is the max possible value given current LST and borrowing rates. True APY will be subject to the actual leverage, based on above point. More insights on exact APY will be added soon.
1074
+ </p>
1075
+ </div> */}
1076
+ </div>
1077
+ );
1078
+ }
1079
+
1080
+ const re7UsdcPrimeDevansh: VesuExtendedStrategySettings = {
1081
+ vaultAddress: ContractAddr.from("0x520a2e945dd0762e5284fc1b012f62ca04e238e105eb362d5e0ce208928729d"),
1082
+ manager: ContractAddr.from("0x6abe24d31cbc16d7c4acb2421a826f96273e225b4a2d168d91e65123da0bfb9"),
1083
+ vaultAllocator: ContractAddr.from("0x6e4f716e22efb164ee4a831233e513f45396ad3be4cff3c07386be0226febed"),
1084
+ redeemRequestNFT: ContractAddr.from("0x66060e1874e05506b18e6029188ec49bf231a411ad57642311bbdf3cb22e5f"),
1085
+ aumOracle: ContractAddr.from("0x301d883b9b45c76132638e39326b3f464c492599623263d405ec0df991e27ab"),
1086
+ leafAdapters: [],
1087
+ adapters: [],
1088
+ targetHealthFactor: 1.4,
1089
+ minHealthFactor: 1.05,
1090
+ underlyingToken: Global.getDefaultTokens().find(
1091
+ (token) => token.symbol === "USDC"
1092
+ )!,
1093
+ quoteAmountToFetchPrice: new Web3Number(
1094
+ "0.001",
1095
+ Global.getDefaultTokens().find((token) => token.symbol === "WBTC")!.decimals
1096
+ ),
1097
+ borrowable_assets: [Global.getDefaultTokens().find(token => token.symbol === "WBTC")!],
1098
+ minimumWBTCDifferenceForAvnuSwap: MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP,
1099
+ }
1100
+
1101
+ export const VesuExtendedTestStrategies = (extendedBackendUrl: string, extendedApiKey: string, vaultIdExtended: number): IStrategyMetadata<VesuExtendedStrategySettings>[] => {
1102
+ return [
1103
+ getStrategySettingsVesuExtended('WBTC', 'USDC', re7UsdcPrimeDevansh, false, false, extendedBackendUrl, extendedApiKey, vaultIdExtended),
1104
+ ]
1105
+ }
1106
+
1107
+
1108
+
1109
+ function getStrategySettingsVesuExtended(lstSymbol: string, underlyingSymbol: string, addresses: VesuExtendedStrategySettings, isPreview: boolean = false, isLST: boolean, extendedBackendUrl: string, extendedApiKey: string, vaultIdExtended: number): IStrategyMetadata<VesuExtendedStrategySettings> {
1110
+ return {
1111
+ name: `Extended Test ${underlyingSymbol}`,
1112
+ description: getDescription(lstSymbol, underlyingSymbol),
1113
+ address: addresses.vaultAddress,
1114
+ launchBlock: 0,
1115
+ type: 'Other',
1116
+ depositTokens: [Global.getDefaultTokens().find(token => token.symbol === underlyingSymbol)!],
1117
+ additionalInfo: getLooperSettings(lstSymbol, underlyingSymbol, addresses, VesuPools.Re7USDCPrime, extendedBackendUrl, extendedApiKey, vaultIdExtended),
1118
+ risk: {
1119
+ riskFactor: _riskFactor,
1120
+ netRisk:
1121
+ _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
1122
+ _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
1123
+ notARisks: getNoRiskTags(_riskFactor)
1124
+ },
1125
+ auditUrl: AUDIT_URL,
1126
+ protocols: [Protocols.ENDUR, Protocols.VESU],
1127
+ maxTVL: Web3Number.fromWei(0, 18),
1128
+ contractDetails: getContractDetails(addresses),
1129
+ faqs: getFAQs(lstSymbol, underlyingSymbol, isLST),
1130
+ investmentSteps: getInvestmentSteps(lstSymbol, underlyingSymbol),
1131
+ isPreview: isPreview,
1132
+ apyMethodology: isLST ? 'Current annualized APY in terms of base asset of the LST. There is no additional fee taken by Troves on LST APY. We charge a 10% performance fee on the additional gain which is already accounted in the APY shown.' : 'Current annualized APY in terms of base asset of the Yield Token. There is no additional fee taken by Troves on yield token APY. We charge a 10% performance fee on the additional gain which is already accounted in the APY shown.'
1133
+ }
1134
+ }