@strkfarm/sdk 1.1.22 → 1.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -15288,6 +15288,17 @@ var erc4626_abi_default = [
15288
15288
  }
15289
15289
  ];
15290
15290
 
15291
+ // src/strategies/ekubo-cl-vault.tsx
15292
+ import { gql } from "@apollo/client";
15293
+
15294
+ // src/modules/apollo-client.ts
15295
+ import { ApolloClient, InMemoryCache } from "@apollo/client";
15296
+ var apolloClient = new ApolloClient({
15297
+ uri: "https://api.troves.fi/",
15298
+ cache: new InMemoryCache()
15299
+ });
15300
+ var apollo_client_default = apolloClient;
15301
+
15291
15302
  // src/strategies/ekubo-cl-vault.tsx
15292
15303
  import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
15293
15304
  var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
@@ -15445,11 +15456,75 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
15445
15456
  handleFeesCall() {
15446
15457
  return [this.contract.populate("handle_fees", [])];
15447
15458
  }
15448
- /**
15449
- * Calculates assets before and now in a given token of TVL per share to observe growth
15450
- * @returns {Promise<number>} The weighted average APY across all pools
15451
- */
15452
- async netAPY(blockIdentifier = "latest", sinceBlocks = 6e5) {
15459
+ async getFeeHistory(timePeriod = "24h") {
15460
+ const { data } = await apollo_client_default.query({
15461
+ query: gql`
15462
+ query ContractFeeEarnings(
15463
+ $timeframe: String!
15464
+ $contract: String!
15465
+ ) {
15466
+ contractFeeEarnings(timeframe: $timeframe, contract: $contract) {
15467
+ contract
15468
+ dailyEarnings {
15469
+ date
15470
+ tokenAddress
15471
+ amount
15472
+ }
15473
+ totalCollections
15474
+ }
15475
+ }
15476
+ `,
15477
+ variables: {
15478
+ timeframe: timePeriod,
15479
+ contract: this.address.address
15480
+ },
15481
+ fetchPolicy: "no-cache"
15482
+ });
15483
+ const poolKey = await this.getPoolKey();
15484
+ const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
15485
+ const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
15486
+ const price0 = await this.pricer.getPrice(token0Info.symbol);
15487
+ const price1 = await this.pricer.getPrice(token1Info.symbol);
15488
+ let totalToken0Amount = Web3Number.fromWei(0, token0Info.decimals);
15489
+ let totalToken1Amount = Web3Number.fromWei(0, token1Info.decimals);
15490
+ let totalToken0Usd = 0;
15491
+ let totalToken1Usd = 0;
15492
+ const parsedFeeInfo = [];
15493
+ const feeInfo = data.contractFeeEarnings.dailyEarnings;
15494
+ for (const d of feeInfo) {
15495
+ const tokenInfo = await Global.getTokenInfoFromAddr(ContractAddr.from(d.tokenAddress));
15496
+ const amount = Web3Number.fromWei(d.amount, tokenInfo.decimals);
15497
+ if (tokenInfo.address.eq(poolKey.token0)) {
15498
+ totalToken0Amount = totalToken0Amount.plus(amount);
15499
+ totalToken0Usd = totalToken0Usd + amount.multipliedBy(price0.price).toNumber();
15500
+ } else {
15501
+ totalToken1Amount = totalToken1Amount.plus(amount);
15502
+ totalToken1Usd = totalToken1Usd + amount.multipliedBy(price1.price).toNumber();
15503
+ }
15504
+ parsedFeeInfo.push({
15505
+ date: d.date,
15506
+ tokenInfo,
15507
+ amount: Web3Number.fromWei(d.amount, tokenInfo.decimals)
15508
+ });
15509
+ }
15510
+ return {
15511
+ summary: {
15512
+ usdValue: totalToken0Usd + totalToken1Usd,
15513
+ token0: {
15514
+ tokenInfo: token0Info,
15515
+ amount: totalToken0Amount,
15516
+ usdValue: totalToken0Usd
15517
+ },
15518
+ token1: {
15519
+ tokenInfo: token1Info,
15520
+ amount: totalToken1Amount,
15521
+ usdValue: totalToken1Usd
15522
+ }
15523
+ },
15524
+ history: parsedFeeInfo
15525
+ };
15526
+ }
15527
+ async netSharesBasedTrueAPY(blockIdentifier = "latest", sinceBlocks = 6e5) {
15453
15528
  const tvlNow = await this._getTVL(blockIdentifier);
15454
15529
  const supplyNow = await this.totalSupply(blockIdentifier);
15455
15530
  const priceNow = await this.getCurrentPrice(blockIdentifier);
@@ -15487,6 +15562,23 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
15487
15562
  ) / 1e4;
15488
15563
  return apyForGivenBlocks * (365 * 24 * 3600) / timeDiffSeconds;
15489
15564
  }
15565
+ async feeBasedAPY(timeperiod = "24h") {
15566
+ const feeInfo = await this.getFeeHistory(timeperiod);
15567
+ const tvlNow = await this.getTVL("latest");
15568
+ return feeInfo.summary.usdValue * 365 / tvlNow.usdValue;
15569
+ }
15570
+ /**
15571
+ * Calculates assets before and now in a given token of TVL per share to observe growth
15572
+ * @returns {Promise<number>} The weighted average APY across all pools
15573
+ */
15574
+ async netAPY(blockIdentifier = "latest", sinceBlocks = 6e5, timeperiod = "24h") {
15575
+ const isUSDCQouteToken = this.metadata.additionalInfo.quoteAsset.symbol === "USDC";
15576
+ if (!isUSDCQouteToken) {
15577
+ return this.netSharesBasedTrueAPY(blockIdentifier, sinceBlocks);
15578
+ } else {
15579
+ return this.feeBasedAPY(timeperiod);
15580
+ }
15581
+ }
15490
15582
  async getHarvestRewardShares(fromBlock, toBlock) {
15491
15583
  const len = Number(await this.contract.call("get_total_rewards"));
15492
15584
  let shares = Web3Number.fromWei(0, 18);
@@ -16501,7 +16593,7 @@ var highRisk = {
16501
16593
  netRisk: highVolatilityPoolRiskFactors.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / highVolatilityPoolRiskFactors.reduce((acc, curr) => acc + curr.weight, 0),
16502
16594
  notARisks: getNoRiskTags(highVolatilityPoolRiskFactors)
16503
16595
  };
16504
- var AUDIT_URL2 = "https://assets.troves.fi/strkfarm/audit_report_vesu_and_ekubo_strats.pdf";
16596
+ var AUDIT_URL2 = "https://docs.troves.fi/p/security#ekubo-vault";
16505
16597
  var faqs2 = [
16506
16598
  {
16507
16599
  question: "What is the Ekubo CL Vault strategy?",
@@ -16700,7 +16792,7 @@ var ETHUSDCRe7Strategy = {
16700
16792
  Global.getDefaultTokens().find((t) => t.symbol === "ETH"),
16701
16793
  Global.getDefaultTokens().find((t) => t.symbol === "USDC")
16702
16794
  ],
16703
- apyMethodology: "APY based on 7-day historical performance, including fees and rewards.",
16795
+ apyMethodology: "Annualized fee APY, calculated as fees earned in the last 24h divided by TVL",
16704
16796
  additionalInfo: {
16705
16797
  newBounds: "Managed by Re7",
16706
16798
  truePrice: 1,
@@ -16721,6 +16813,10 @@ var ETHUSDCRe7Strategy = {
16721
16813
  /* @__PURE__ */ jsx3("a", { href: "https://www.re7labs.xyz", style: { textDecoration: "underline", marginLeft: "2px" }, target: "_blank", children: "here" }),
16722
16814
  "."
16723
16815
  ] })
16816
+ },
16817
+ {
16818
+ question: "How is the APY calculated?",
16819
+ answer: /* @__PURE__ */ jsx3("div", { children: "It's an annualized fee APY, calculated as fees earned in the last 24h divided by TVL. Factors like impermanent loss are not considered." })
16724
16820
  }
16725
16821
  ],
16726
16822
  risk: highRisk,
@@ -27328,6 +27424,7 @@ var investmentSteps = [
27328
27424
  "Vault manager reports asset under management (AUM) regularly to the vault",
27329
27425
  "Request withdrawal and vault manager processes it in 1-2 hours"
27330
27426
  ];
27427
+ var AUDIT_URL3 = "https://docs.troves.fi/p/security#starknet-vault-kit";
27331
27428
  var UniversalStrategies = [
27332
27429
  {
27333
27430
  name: "USDC Evergreen",
@@ -27342,6 +27439,7 @@ var UniversalStrategies = [
27342
27439
  netRisk: _riskFactor3.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor3.reduce((acc, curr) => acc + curr.weight, 0),
27343
27440
  notARisks: getNoRiskTags(_riskFactor3)
27344
27441
  },
27442
+ auditUrl: AUDIT_URL3,
27345
27443
  protocols: [Protocols.VESU],
27346
27444
  maxTVL: Web3Number.fromWei(0, 6),
27347
27445
  contractDetails: getContractDetails(usdcVaultSettings),
@@ -27365,7 +27463,8 @@ var UniversalStrategies = [
27365
27463
  maxTVL: Web3Number.fromWei(0, 8),
27366
27464
  contractDetails: getContractDetails(wbtcVaultSettings),
27367
27465
  faqs: getFAQs(),
27368
- investmentSteps
27466
+ investmentSteps,
27467
+ auditUrl: AUDIT_URL3
27369
27468
  },
27370
27469
  {
27371
27470
  name: "ETH Evergreen",
@@ -27384,7 +27483,8 @@ var UniversalStrategies = [
27384
27483
  maxTVL: Web3Number.fromWei(0, 18),
27385
27484
  contractDetails: getContractDetails(ethVaultSettings),
27386
27485
  faqs: getFAQs(),
27387
- investmentSteps
27486
+ investmentSteps,
27487
+ auditUrl: AUDIT_URL3
27388
27488
  },
27389
27489
  {
27390
27490
  name: "STRK Evergreen",
@@ -27403,7 +27503,8 @@ var UniversalStrategies = [
27403
27503
  maxTVL: Web3Number.fromWei(0, 18),
27404
27504
  contractDetails: getContractDetails(strkVaultSettings),
27405
27505
  faqs: getFAQs(),
27406
- investmentSteps
27506
+ investmentSteps,
27507
+ auditUrl: AUDIT_URL3
27407
27508
  },
27408
27509
  {
27409
27510
  name: "USDT Evergreen",
@@ -27422,7 +27523,8 @@ var UniversalStrategies = [
27422
27523
  maxTVL: Web3Number.fromWei(0, 6),
27423
27524
  contractDetails: getContractDetails(usdtVaultSettings),
27424
27525
  faqs: getFAQs(),
27425
- investmentSteps
27526
+ investmentSteps,
27527
+ auditUrl: AUDIT_URL3
27426
27528
  }
27427
27529
  ];
27428
27530
 
@@ -27632,7 +27734,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
27632
27734
  return [this.getManageCall(proofsIDs, manageCalls)];
27633
27735
  }
27634
27736
  };
27635
- function VaultDescription() {
27737
+ function VaultDescription(lstSymbol, underlyingSymbol) {
27636
27738
  const containerStyle = {
27637
27739
  maxWidth: "800px",
27638
27740
  margin: "0 auto",
@@ -27642,8 +27744,27 @@ function VaultDescription() {
27642
27744
  borderRadius: "12px"
27643
27745
  };
27644
27746
  return /* @__PURE__ */ jsxs4("div", { style: containerStyle, children: [
27645
- /* @__PURE__ */ jsx5("h1", { style: { fontSize: "18px", marginBottom: "10px" }, children: "Meta Vault \u2014 Automated Yield Router" }),
27646
- /* @__PURE__ */ jsx5("p", { style: { fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }, children: "This Levered Endur LST vault is a tokenized leveraged Vault, auto-compounding strategy that continuously allocates your deposited asset to the best available yield source in the ecosystem. Depositors receive vault shares that represent a proportional claim on the underlying assets and accrued yield. Allocation shifts are handled programmatically based on on-chain signals and risk filters, minimizing idle capital and maximizing net APY." }),
27747
+ /* @__PURE__ */ jsxs4("h1", { style: { fontSize: "18px", marginBottom: "10px" }, children: [
27748
+ "Liquidation risk managed leverged ",
27749
+ lstSymbol,
27750
+ " Vault"
27751
+ ] }),
27752
+ /* @__PURE__ */ jsxs4("p", { style: { fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }, children: [
27753
+ "This Levered Endur ",
27754
+ lstSymbol,
27755
+ " vault is a tokenized leveraged Vault, auto-compounding strategy that takes upto 5x leverage on ",
27756
+ lstSymbol,
27757
+ " by borrow ",
27758
+ underlyingSymbol,
27759
+ ". Borrowed amount is swapped to ",
27760
+ lstSymbol,
27761
+ " to create leverage. Depositors receive vault shares that represent a proportional claim on the underlying assets and accrued yield."
27762
+ ] }),
27763
+ /* @__PURE__ */ jsxs4("p", { style: { fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }, children: [
27764
+ "This vault uses Vesu for lending and borrowing. The oracle used by this pool is a ",
27765
+ highlightTextWithLinks("conversion rate oracle", [{ highlight: "conversion rate oracle", link: "https://docs.pragma.build/starknet/development#conversion-rate" }]),
27766
+ "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."
27767
+ ] }),
27647
27768
  /* @__PURE__ */ jsx5("div", { style: { backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }, children: /* @__PURE__ */ jsxs4("p", { style: { fontSize: "13px", color: "#ccc" }, children: [
27648
27769
  /* @__PURE__ */ jsx5("strong", { children: "Withdrawals:" }),
27649
27770
  " Requests can take up to ",
@@ -27652,8 +27773,8 @@ function VaultDescription() {
27652
27773
  ] }) })
27653
27774
  ] });
27654
27775
  }
27655
- function getDescription2(tokenSymbol) {
27656
- return VaultDescription();
27776
+ function getDescription2(tokenSymbol, underlyingSymbol) {
27777
+ return VaultDescription(tokenSymbol, underlyingSymbol);
27657
27778
  }
27658
27779
  function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
27659
27780
  vaultSettings.leafAdapters = [];
@@ -27694,11 +27815,12 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
27694
27815
  vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(STRKToken.address, lstToken.address, "avnu_swap_rewards" /* AVNU_SWAP_REWARDS */).bind(commonAdapter));
27695
27816
  return vaultSettings;
27696
27817
  }
27818
+ var AUDIT_URL4 = "https://docs.troves.fi/p/security#starknet-vault-kit";
27697
27819
  function getFAQs2(lstSymbol, underlyingSymbol) {
27698
27820
  return [
27699
27821
  {
27700
27822
  question: `What is the Hyper ${lstSymbol} Vault?`,
27701
- answer: `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.`
27823
+ 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.`
27702
27824
  },
27703
27825
  {
27704
27826
  question: "How does yield allocation work?",
@@ -27742,8 +27864,9 @@ function getFAQs2(lstSymbol, underlyingSymbol) {
27742
27864
  }
27743
27865
  var _riskFactor4 = [
27744
27866
  { type: "Smart Contract Risk" /* SMART_CONTRACT_RISK */, value: 2 /* WELL_AUDITED */, weight: 25, reason: "Audited by Zellic" },
27745
- { type: "Liquidation Risk" /* LIQUIDATION_RISK */, value: 1 /* VERY_LOW_PROBABILITY */, weight: 50, reason: "The collateral and debt are highly correlated" },
27746
- { type: "Technical Risk" /* TECHNICAL_RISK */, value: 1 /* 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." }
27867
+ { type: "Liquidation Risk" /* LIQUIDATION_RISK */, value: 1 /* VERY_LOW_PROBABILITY */, weight: 25, reason: "The collateral and debt are highly correlated" },
27868
+ { type: "Technical Risk" /* TECHNICAL_RISK */, value: 1 /* 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." },
27869
+ { type: "Depeg Risk" /* DEPEG_RISK */, value: 2 /* GENERALLY_STABLE */, weight: 25, reason: "Generally stable pegged assets" }
27747
27870
  ];
27748
27871
  var hyperxSTRK = {
27749
27872
  vaultAddress: ContractAddr.from("0x46c7a54c82b1fe374353859f554a40b8bd31d3e30f742901579e7b57b1b5960"),
@@ -27806,14 +27929,13 @@ function getInvestmentSteps(lstSymbol, underlyingSymbol) {
27806
27929
  `The vault manager loops the ${underlyingSymbol} to buy ${lstSymbol}`,
27807
27930
  `The vault manager collateralizes the ${lstSymbol} on Vesu`,
27808
27931
  `The vault manager borrows more ${underlyingSymbol} to loop further`,
27809
- `Claim BTCFi STRK rewards weekly to swap to ${lstSymbol} and reinvest`,
27810
27932
  `If required, adjust leverage or re-allocate assets within LST pool on Vesu to optimize yield`
27811
27933
  ];
27812
27934
  }
27813
27935
  function getStrategySettings(lstSymbol, underlyingSymbol, addresses, isPreview = false) {
27814
27936
  return {
27815
27937
  name: `Hyper ${lstSymbol}`,
27816
- description: getDescription2(lstSymbol),
27938
+ description: getDescription2(lstSymbol, underlyingSymbol),
27817
27939
  address: addresses.vaultAddress,
27818
27940
  launchBlock: 0,
27819
27941
  type: "Other",
@@ -27824,6 +27946,7 @@ function getStrategySettings(lstSymbol, underlyingSymbol, addresses, isPreview =
27824
27946
  netRisk: _riskFactor4.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor4.reduce((acc, curr) => acc + curr.weight, 0),
27825
27947
  notARisks: getNoRiskTags(_riskFactor4)
27826
27948
  },
27949
+ auditUrl: AUDIT_URL4,
27827
27950
  protocols: [Protocols.ENDUR, Protocols.VESU],
27828
27951
  maxTVL: Web3Number.fromWei(0, 18),
27829
27952
  contractDetails: getContractDetails(addresses),
@@ -27936,7 +28059,7 @@ var TelegramNotif = class {
27936
28059
  import TelegramBot2 from "node-telegram-bot-api";
27937
28060
  var TelegramGroupNotif = class {
27938
28061
  constructor(token, groupId, topicId) {
27939
- this.bot = new TelegramBot2(token, { polling: true });
28062
+ this.bot = new TelegramBot2(token, { polling: false });
27940
28063
  this.groupId = groupId;
27941
28064
  this.topicId = topicId;
27942
28065
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strkfarm/sdk",
3
- "version": "1.1.22",
3
+ "version": "1.1.24",
4
4
  "description": "STRKFarm TS SDK (Meant for our internal use, but feel free to use it)",
5
5
  "typings": "dist/index.d.ts",
6
6
  "types": "dist/index.d.ts",
@@ -57,6 +57,7 @@
57
57
  "starknet": "8.5.2"
58
58
  },
59
59
  "dependencies": {
60
+ "@apollo/client": "3.11.8",
60
61
  "@avnu/avnu-sdk": "3.0.2",
61
62
  "@ericnordelo/strk-merkle-tree": "^1.0.0",
62
63
  "@noble/curves": "^1.0.0",
@@ -68,6 +69,7 @@
68
69
  "chalk": "^4.1.2",
69
70
  "commander": "^12.1.0",
70
71
  "ethers": "^6.13.5",
72
+ "graphql": "16.9.0",
71
73
  "inquirer": "^10.1.2",
72
74
  "node-telegram-bot-api": "^0.66.0",
73
75
  "proxy-from-env": "^1.1.0",
@@ -0,0 +1,8 @@
1
+ import { ApolloClient, InMemoryCache } from '@apollo/client';
2
+
3
+ const apolloClient = new ApolloClient({
4
+ uri: 'https://api.troves.fi/',
5
+ cache: new InMemoryCache(),
6
+ });
7
+
8
+ export default apolloClient;
@@ -7,7 +7,7 @@ export class TelegramGroupNotif {
7
7
  private topicId?: number;
8
8
 
9
9
  constructor(token: string, groupId: string, topicId?: number) {
10
- this.bot = new TelegramBot(token, { polling: true });
10
+ this.bot = new TelegramBot(token, { polling: false });
11
11
  this.groupId = groupId;
12
12
  this.topicId = topicId;
13
13
  }
@@ -37,6 +37,8 @@ import { EkuboHarvests } from "@/modules/harvests";
37
37
  import { logger } from "@/utils/logger";
38
38
  import { COMMON_CONTRACTS } from "./constants";
39
39
  import { DepegRiskLevel, ImpermanentLossLevel, MarketRiskLevel, SmartContractRiskLevel } from "@/interfaces/risks";
40
+ import { gql } from "@apollo/client";
41
+ import apolloClient from "@/modules/apollo-client";
40
42
 
41
43
  export interface EkuboPoolKey {
42
44
  token0: ContractAddr;
@@ -51,6 +53,12 @@ export interface EkuboBounds {
51
53
  upperTick: bigint;
52
54
  }
53
55
 
56
+ interface FeeHistory {
57
+ date: string;
58
+ tokenInfo: TokenInfo;
59
+ amount: Web3Number;
60
+ }
61
+
54
62
  /**
55
63
  * Settings for the CLVaultStrategy
56
64
  *
@@ -285,11 +293,97 @@ export class EkuboCLVault extends BaseStrategy<
285
293
  return [this.contract.populate("handle_fees", [])];
286
294
  }
287
295
 
288
- /**
289
- * Calculates assets before and now in a given token of TVL per share to observe growth
290
- * @returns {Promise<number>} The weighted average APY across all pools
291
- */
292
- async netAPY(
296
+ async getFeeHistory(timePeriod: '24h' | '30d' | '3m' = '24h'): Promise<{
297
+ summary: DualTokenInfo,
298
+ history: FeeHistory[]
299
+ }> {
300
+ const { data } = await apolloClient.query({
301
+ query: gql`
302
+ query ContractFeeEarnings(
303
+ $timeframe: String!
304
+ $contract: String!
305
+ ) {
306
+ contractFeeEarnings(timeframe: $timeframe, contract: $contract) {
307
+ contract
308
+ dailyEarnings {
309
+ date
310
+ tokenAddress
311
+ amount
312
+ }
313
+ totalCollections
314
+ }
315
+ }
316
+ `,
317
+ variables: {
318
+ timeframe: timePeriod,
319
+ contract: this.address.address
320
+ },
321
+ fetchPolicy: 'no-cache',
322
+ });
323
+
324
+ // Sample response type:
325
+ // {
326
+ // contractFeeEarnings: {
327
+ // contract: '0x2bcaef2eb7706875a5fdc6853dd961a0590f850bc3a031c59887189b5e84ba1',
328
+ // dailyEarnings: [ [Object], [Object], [Object], [Object] ],
329
+ // totalCollections: 3,
330
+ // __typename: 'FeeSummary'
331
+ // }
332
+ // }
333
+ // dailyEarnings: {
334
+ // date: '2025-09-27',
335
+ // tokenAddress: '0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac',
336
+ // amount: '15404',
337
+ // __typename: 'DailyFeeEarnings'
338
+ // }[]
339
+
340
+ // get pool key and token info
341
+ const poolKey = await this.getPoolKey();
342
+ const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
343
+ const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
344
+ const price0 = await this.pricer.getPrice(token0Info.symbol);
345
+ const price1 = await this.pricer.getPrice(token1Info.symbol);
346
+ let totalToken0Amount = Web3Number.fromWei(0, token0Info.decimals);
347
+ let totalToken1Amount = Web3Number.fromWei(0, token1Info.decimals);
348
+ let totalToken0Usd = 0;
349
+ let totalToken1Usd = 0;
350
+ const parsedFeeInfo: FeeHistory[] = [];
351
+ const feeInfo = data.contractFeeEarnings.dailyEarnings;
352
+ for (const d of feeInfo) {
353
+ const tokenInfo = await Global.getTokenInfoFromAddr(ContractAddr.from(d.tokenAddress));
354
+ const amount = Web3Number.fromWei(d.amount, tokenInfo.decimals);
355
+ if (tokenInfo.address.eq(poolKey.token0)) {
356
+ totalToken0Amount = totalToken0Amount.plus(amount);
357
+ totalToken0Usd = totalToken0Usd + amount.multipliedBy(price0.price).toNumber();
358
+ } else {
359
+ totalToken1Amount = totalToken1Amount.plus(amount);
360
+ totalToken1Usd = totalToken1Usd + amount.multipliedBy(price1.price).toNumber();
361
+ }
362
+ parsedFeeInfo.push({
363
+ date: d.date,
364
+ tokenInfo,
365
+ amount: Web3Number.fromWei(d.amount, tokenInfo.decimals)
366
+ });
367
+ }
368
+ return {
369
+ summary: {
370
+ usdValue: totalToken0Usd + totalToken1Usd,
371
+ token0: {
372
+ tokenInfo: token0Info,
373
+ amount: totalToken0Amount,
374
+ usdValue: totalToken0Usd
375
+ },
376
+ token1: {
377
+ tokenInfo: token1Info,
378
+ amount: totalToken1Amount,
379
+ usdValue: totalToken1Usd
380
+ }
381
+ },
382
+ history: parsedFeeInfo
383
+ }
384
+ }
385
+
386
+ async netSharesBasedTrueAPY(
293
387
  blockIdentifier: BlockIdentifier = "latest",
294
388
  sinceBlocks = 600000
295
389
  ): Promise<number> {
@@ -354,6 +448,33 @@ export class EkuboCLVault extends BaseStrategy<
354
448
  return (apyForGivenBlocks * (365 * 24 * 3600)) / timeDiffSeconds;
355
449
  }
356
450
 
451
+ async feeBasedAPY(
452
+ timeperiod: '24h' | '30d' | '3m' = '24h'
453
+ ): Promise<number> {
454
+ const feeInfo = await this.getFeeHistory(timeperiod);
455
+ const tvlNow = await this.getTVL('latest');
456
+ return feeInfo.summary.usdValue * 365 / tvlNow.usdValue;
457
+ }
458
+
459
+ /**
460
+ * Calculates assets before and now in a given token of TVL per share to observe growth
461
+ * @returns {Promise<number>} The weighted average APY across all pools
462
+ */
463
+ async netAPY(
464
+ blockIdentifier: BlockIdentifier = "latest",
465
+ sinceBlocks = 600000,
466
+ timeperiod: '24h' | '30d' | '3m' = '24h' // temp thing for fee based APY
467
+ ): Promise<number> {
468
+ const isUSDCQouteToken = this.metadata.additionalInfo.quoteAsset.symbol === "USDC";
469
+ if (!isUSDCQouteToken) {
470
+ // good for LSTs and stables
471
+ return this.netSharesBasedTrueAPY(blockIdentifier, sinceBlocks);
472
+ } else {
473
+ // good for non-stables
474
+ return this.feeBasedAPY(timeperiod);
475
+ }
476
+ }
477
+
357
478
  async getHarvestRewardShares(fromBlock: number, toBlock: number) {
358
479
  const len = Number(await this.contract.call("get_total_rewards"));
359
480
  let shares = Web3Number.fromWei(0, 18);
@@ -1680,7 +1801,7 @@ const highRisk = {
1680
1801
 
1681
1802
 
1682
1803
  const AUDIT_URL =
1683
- "https://assets.troves.fi/strkfarm/audit_report_vesu_and_ekubo_strats.pdf";
1804
+ "https://docs.troves.fi/p/security#ekubo-vault";
1684
1805
 
1685
1806
  const faqs: FAQ[] = [
1686
1807
  {
@@ -1893,7 +2014,7 @@ const ETHUSDCRe7Strategy: IStrategyMetadata<CLVaultStrategySettings> = {
1893
2014
  Global.getDefaultTokens().find((t) => t.symbol === "USDC")!
1894
2015
  ],
1895
2016
  apyMethodology:
1896
- "APY based on 7-day historical performance, including fees and rewards.",
2017
+ "Annualized fee APY, calculated as fees earned in the last 24h divided by TVL",
1897
2018
  additionalInfo: {
1898
2019
  newBounds: "Managed by Re7",
1899
2020
  truePrice: 1,
@@ -1913,6 +2034,11 @@ const ETHUSDCRe7Strategy: IStrategyMetadata<CLVaultStrategySettings> = {
1913
2034
  answer:
1914
2035
  <div>Re7 Labs is the curator of this strategy. Re7 Labs is a well-known Web3 asset management firm. This strategy is completely managed by them, including ownership of the vault. Troves is developer of the smart contracts and maintains infrastructure to help users access these strategies. You can find more information about them on their website <a href='https://www.re7labs.xyz' style={{textDecoration: "underline", marginLeft: "2px"}} target="_blank">here</a>.</div>
1915
2036
  },
2037
+ {
2038
+ question: "How is the APY calculated?",
2039
+ answer:
2040
+ <div>It's an annualized fee APY, calculated as fees earned in the last 24h divided by TVL. Factors like impermanent loss are not considered.</div>
2041
+ },
1916
2042
  ],
1917
2043
  risk: highRisk,
1918
2044
  points: [],
@@ -1,11 +1,11 @@
1
- import { FAQ, getNoRiskTags, IConfig, IStrategyMetadata, Protocols, RiskFactor, RiskType } from "@/interfaces";
1
+ import { FAQ, getNoRiskTags, highlightTextWithLinks, IConfig, IStrategyMetadata, Protocols, RiskFactor, RiskType } from "@/interfaces";
2
2
  import { AUMTypes, getContractDetails, UNIVERSAL_ADAPTERS, UNIVERSAL_MANAGE_IDS, UniversalManageCall, UniversalStrategy, UniversalStrategySettings } from "./universal-strategy";
3
3
  import { PricerBase } from "@/modules/pricerBase";
4
4
  import { ContractAddr, Web3Number } from "@/dataTypes";
5
5
  import { Global } from "@/global";
6
6
  import { ApproveCallParams, CommonAdapter, getVesuSingletonAddress, ManageCall, Swap, VesuAdapter, VesuModifyDelegationCallParams, VesuMultiplyCallParams, VesuPools } from "./universal-adapters";
7
7
  import { AVNU_MIDDLEWARE } from "./universal-adapters/adapter-utils";
8
- import { LiquidationRiskLevel, SmartContractRiskLevel, TechnicalRiskLevel } from "@/interfaces/risks";
8
+ import { DepegRiskLevel, LiquidationRiskLevel, SmartContractRiskLevel, TechnicalRiskLevel } from "@/interfaces/risks";
9
9
  import { EkuboQuoter, ERC20, PricerLST } from "@/modules";
10
10
  import { assert, logger } from "@/utils";
11
11
  import { SingleTokenInfo } from "./base-strategy";
@@ -293,7 +293,10 @@ export class UniversalLstMultiplierStrategy extends UniversalStrategy<UniversalS
293
293
  }
294
294
  }
295
295
 
296
- export default function VaultDescription() {
296
+ export default function VaultDescription(
297
+ lstSymbol: string,
298
+ underlyingSymbol: string
299
+ ) {
297
300
  const containerStyle = {
298
301
  maxWidth: "800px",
299
302
  margin: "0 auto",
@@ -305,13 +308,16 @@ export default function VaultDescription() {
305
308
 
306
309
  return (
307
310
  <div style={containerStyle}>
308
- <h1 style={{ fontSize: "18px", marginBottom: "10px" }}>Meta Vault Automated Yield Router</h1>
311
+ <h1 style={{ fontSize: "18px", marginBottom: "10px" }}>Liquidation risk managed leverged {lstSymbol} Vault</h1>
312
+ <p style={{ fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }}>
313
+ 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
314
+ is swapped to {lstSymbol} to create leverage. Depositors receive vault shares that
315
+ represent a proportional claim on the underlying assets and accrued yield.
316
+ </p>
317
+
309
318
  <p style={{ fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }}>
310
- This Levered Endur LST vault is a tokenized leveraged Vault, auto-compounding strategy that continuously allocates your deposited
311
- asset to the best available yield source in the ecosystem. Depositors receive vault shares that
312
- represent a proportional claim on the underlying assets and accrued yield. Allocation shifts are
313
- handled programmatically based on on-chain signals and risk filters, minimizing idle capital and
314
- maximizing net APY.
319
+ 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"}])}
320
+ 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.
315
321
  </p>
316
322
 
317
323
  <div style={{ backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }}>
@@ -324,8 +330,8 @@ export default function VaultDescription() {
324
330
  }
325
331
 
326
332
 
327
- function getDescription(tokenSymbol: string) {
328
- return VaultDescription();
333
+ function getDescription(tokenSymbol: string, underlyingSymbol: string) {
334
+ return VaultDescription(tokenSymbol, underlyingSymbol);
329
335
  }
330
336
 
331
337
  enum LST_MULTIPLIER_MANAGE_IDS {
@@ -393,12 +399,14 @@ function getLooperSettings(
393
399
  return vaultSettings;
394
400
  }
395
401
 
402
+ const AUDIT_URL = 'https://docs.troves.fi/p/security#starknet-vault-kit'
403
+
396
404
  function getFAQs(lstSymbol: string, underlyingSymbol: string): FAQ[] {
397
405
  return [
398
406
  {
399
407
  question: `What is the Hyper ${lstSymbol} Vault?`,
400
408
  answer:
401
- `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.`,
409
+ `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.`,
402
410
  },
403
411
  {
404
412
  question: "How does yield allocation work?",
@@ -447,8 +455,9 @@ function getFAQs(lstSymbol: string, underlyingSymbol: string): FAQ[] {
447
455
 
448
456
  const _riskFactor: RiskFactor[] = [
449
457
  { type: RiskType.SMART_CONTRACT_RISK, value: SmartContractRiskLevel.WELL_AUDITED, weight: 25, reason: "Audited by Zellic" },
450
- { type: RiskType.LIQUIDATION_RISK, value: LiquidationRiskLevel.VERY_LOW_PROBABILITY, weight: 50, reason: "The collateral and debt are highly correlated" },
451
- { 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." }
458
+ { type: RiskType.LIQUIDATION_RISK, value: LiquidationRiskLevel.VERY_LOW_PROBABILITY, weight: 25, reason: "The collateral and debt are highly correlated" },
459
+ { 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." },
460
+ {type: RiskType.DEPEG_RISK, value: DepegRiskLevel.GENERALLY_STABLE, weight: 25, reason: "Generally stable pegged assets" },
452
461
  ];
453
462
 
454
463
  const hyperxSTRK: UniversalStrategySettings = {
@@ -517,7 +526,6 @@ function getInvestmentSteps(lstSymbol: string, underlyingSymbol: string) {
517
526
  `The vault manager loops the ${underlyingSymbol} to buy ${lstSymbol}`,
518
527
  `The vault manager collateralizes the ${lstSymbol} on Vesu`,
519
528
  `The vault manager borrows more ${underlyingSymbol} to loop further`,
520
- `Claim BTCFi STRK rewards weekly to swap to ${lstSymbol} and reinvest`,
521
529
  `If required, adjust leverage or re-allocate assets within LST pool on Vesu to optimize yield`
522
530
  ]
523
531
  }
@@ -525,7 +533,7 @@ function getInvestmentSteps(lstSymbol: string, underlyingSymbol: string) {
525
533
  function getStrategySettings(lstSymbol: string, underlyingSymbol: string, addresses: UniversalStrategySettings, isPreview: boolean = false): IStrategyMetadata<UniversalStrategySettings> {
526
534
  return {
527
535
  name: `Hyper ${lstSymbol}`,
528
- description: getDescription(lstSymbol),
536
+ description: getDescription(lstSymbol, underlyingSymbol),
529
537
  address: addresses.vaultAddress,
530
538
  launchBlock: 0,
531
539
  type: 'Other',
@@ -538,6 +546,7 @@ function getStrategySettings(lstSymbol: string, underlyingSymbol: string, addres
538
546
  _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
539
547
  notARisks: getNoRiskTags(_riskFactor)
540
548
  },
549
+ auditUrl: AUDIT_URL,
541
550
  protocols: [Protocols.ENDUR, Protocols.VESU],
542
551
  maxTVL: Web3Number.fromWei(0, 18),
543
552
  contractDetails: getContractDetails(addresses),