@strkfarm/sdk 1.1.24 → 1.1.26

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.
@@ -20191,7 +20191,7 @@ ${r2}}` : "}", l2;
20191
20191
  toHexString: () => toHexString2,
20192
20192
  toStorageKey: () => toStorageKey2
20193
20193
  });
20194
- var import_utils62 = require_utils2();
20194
+ var import_utils63 = require_utils2();
20195
20195
  function isHex3(hex) {
20196
20196
  return /^0x[0-9a-f]*$/i.test(hex);
20197
20197
  }
@@ -20264,7 +20264,7 @@ ${r2}}` : "}", l2;
20264
20264
  if (adaptedValue.length % 2 !== 0) {
20265
20265
  adaptedValue = `0${adaptedValue}`;
20266
20266
  }
20267
- return (0, import_utils62.hexToBytes)(adaptedValue);
20267
+ return (0, import_utils63.hexToBytes)(adaptedValue);
20268
20268
  }
20269
20269
  function addPercent2(number2, percent) {
20270
20270
  const bigIntNum = BigInt(number2);
@@ -28658,6 +28658,7 @@ ${r2}}` : "}", l2;
28658
28658
  HyperLSTStrategies: () => HyperLSTStrategies,
28659
28659
  ILending: () => ILending,
28660
28660
  Initializable: () => Initializable,
28661
+ LSTAPRService: () => LSTAPRService,
28661
28662
  MarginType: () => MarginType,
28662
28663
  Network: () => Network,
28663
28664
  PRICE_ROUTER: () => PRICE_ROUTER,
@@ -53881,6 +53882,107 @@ ${JSON.stringify(data, null, 2)}`;
53881
53882
  }
53882
53883
  };
53883
53884
 
53885
+ // src/modules/lst-apr.ts
53886
+ var LSTAPRService = class {
53887
+ // 5 minutes
53888
+ /**
53889
+ * Fetches LST stats from Endur API with caching
53890
+ * @returns Promise<LSTStats[]> Array of LST statistics
53891
+ */
53892
+ static async getLSTStats() {
53893
+ const now = Date.now();
53894
+ if (this.cache && now - this.cacheTimestamp < this.CACHE_DURATION) {
53895
+ logger2.verbose(`LSTAPRService: Returning cached LST stats`);
53896
+ return this.cache;
53897
+ }
53898
+ try {
53899
+ logger2.verbose(`LSTAPRService: Fetching LST stats from Endur API`);
53900
+ const response = await fetch(this.ENDUR_API_URL);
53901
+ if (!response.ok) {
53902
+ throw new Error(`Failed to fetch LST stats: ${response.status} ${response.statusText}`);
53903
+ }
53904
+ const data = await response.json();
53905
+ if (!Array.isArray(data)) {
53906
+ throw new Error("Invalid response format: expected array");
53907
+ }
53908
+ this.cache = data;
53909
+ this.cacheTimestamp = now;
53910
+ logger2.verbose(`LSTAPRService: Successfully fetched ${data.length} LST stats`);
53911
+ return data;
53912
+ } catch (error2) {
53913
+ logger2.error(`LSTAPRService: Error fetching LST stats: ${error2}`);
53914
+ if (this.cache) {
53915
+ logger2.warn(`LSTAPRService: Returning stale cached data due to API error`);
53916
+ return this.cache;
53917
+ }
53918
+ throw error2;
53919
+ }
53920
+ }
53921
+ /**
53922
+ * Gets LST APR for a specific asset address
53923
+ * @param assetAddress - The contract address of the underlying asset
53924
+ * @returns Promise<number> The LST APR (not divided by 1e18)
53925
+ */
53926
+ static async getLSTAPR(assetAddress) {
53927
+ const stats = await this.getLSTStats();
53928
+ const lstStat = stats.find(
53929
+ (stat) => ContractAddr.eqString(stat.assetAddress, assetAddress.address)
53930
+ );
53931
+ if (!lstStat) {
53932
+ logger2.warn(`LSTAPRService: No LST stats found for asset address ${assetAddress.address}`);
53933
+ return 0;
53934
+ }
53935
+ logger2.verbose(`LSTAPRService: Found LST APR for ${lstStat.asset}: ${lstStat.apy} (${lstStat.apyInPercentage})`);
53936
+ return lstStat.apy;
53937
+ }
53938
+ /**
53939
+ * Gets LST APR for multiple asset addresses
53940
+ * @param assetAddresses - Array of contract addresses
53941
+ * @returns Promise<Map<string, number>> Map of asset address to LST APR
53942
+ */
53943
+ static async getLSTAPRs(assetAddresses) {
53944
+ const stats = await this.getLSTStats();
53945
+ const result2 = /* @__PURE__ */ new Map();
53946
+ for (const assetAddress of assetAddresses) {
53947
+ const lstStat = stats.find(
53948
+ (stat) => ContractAddr.eqString(stat.assetAddress, assetAddress.address)
53949
+ );
53950
+ if (lstStat) {
53951
+ result2.set(assetAddress.address, lstStat.apy);
53952
+ logger2.verbose(`LSTAPRService: Found LST APR for ${lstStat.asset}: ${lstStat.apy}`);
53953
+ } else {
53954
+ result2.set(assetAddress.address, 0);
53955
+ logger2.warn(`LSTAPRService: No LST stats found for asset address ${assetAddress.address}`);
53956
+ }
53957
+ }
53958
+ return result2;
53959
+ }
53960
+ /**
53961
+ * Gets all available LST assets and their APRs
53962
+ * @returns Promise<Map<string, LSTStats>> Map of asset address to LST stats
53963
+ */
53964
+ static async getAllLSTStats() {
53965
+ const stats = await this.getLSTStats();
53966
+ const result2 = /* @__PURE__ */ new Map();
53967
+ for (const stat of stats) {
53968
+ result2.set(stat.assetAddress, stat);
53969
+ }
53970
+ return result2;
53971
+ }
53972
+ /**
53973
+ * Clears the cache (useful for testing or forcing refresh)
53974
+ */
53975
+ static clearCache() {
53976
+ this.cache = null;
53977
+ this.cacheTimestamp = 0;
53978
+ logger2.verbose(`LSTAPRService: Cache cleared`);
53979
+ }
53980
+ };
53981
+ LSTAPRService.ENDUR_API_URL = "https://app.endur.fi/api/lst/stats";
53982
+ LSTAPRService.cache = null;
53983
+ LSTAPRService.cacheTimestamp = 0;
53984
+ LSTAPRService.CACHE_DURATION = 5 * 60 * 1e3;
53985
+
53884
53986
  // src/interfaces/common.tsx
53885
53987
  var import_jsx_runtime = __toESM(require_jsx_runtime());
53886
53988
  var RiskType = /* @__PURE__ */ ((RiskType2) => {
@@ -80478,7 +80580,7 @@ spurious results.`);
80478
80580
  return [baseFlow, rebalanceFlow];
80479
80581
  }
80480
80582
  };
80481
- var _description2 = "Deploys your {{POOL_NAME}} into an Ekubo liquidity pool, automatically rebalancing positions around the current price to optimize yield and reduce the need for manual adjustments. Trading fees and DeFi Spring rewards are automatically compounded back into the strategy. In return, you receive an ERC-20 token representing your share of the strategy";
80583
+ var _description2 = "Deploys your {{POOL_NAME}} into an Ekubo liquidity pool, automatically rebalancing positions around the current price to optimize yield and reduce the need for manual adjustments. Trading fees and any rewards are automatically compounded back into the strategy. In return, you receive an ERC-20 token representing your share of the strategy";
80482
80584
  var _protocol2 = {
80483
80585
  name: "Ekubo",
80484
80586
  logo: "https://app.ekubo.org/favicon.ico"
@@ -80523,7 +80625,7 @@ spurious results.`);
80523
80625
  },
80524
80626
  {
80525
80627
  question: "How are trading fees and rewards handled?",
80526
- answer: "Trading fees and DeFi Spring rewards are automatically compounded back into the strategy, increasing your overall returns."
80628
+ answer: "Trading fees and any rewards are automatically compounded back into the strategy, increasing your overall returns."
80527
80629
  },
80528
80630
  {
80529
80631
  question: "What happens during withdrawal?",
@@ -80900,7 +81002,7 @@ spurious results.`);
80900
81002
  s.investmentSteps = [
80901
81003
  "Supply tokens to Ekubo's pool",
80902
81004
  "Monitor and Rebalance position to optimize yield",
80903
- "Harvest and supply Defi Spring STRK rewards every week (Auto-compound)"
81005
+ "Harvest and re-invest any rewards every week (Auto-compound)"
80904
81006
  ];
80905
81007
  });
80906
81008
 
@@ -90613,12 +90715,21 @@ spurious results.`);
90613
90715
  logger2.verbose(`${this.metadata.name}::netAPY: positions: ${JSON.stringify(positions)}`);
90614
90716
  const baseAPYs = [];
90615
90717
  const rewardAPYs = [];
90718
+ const collateralAddresses = vesuAdapters.map((adapter) => adapter.config.collateral.address);
90719
+ let lstAPRs;
90720
+ try {
90721
+ lstAPRs = await LSTAPRService.getLSTAPRs(collateralAddresses);
90722
+ } catch (error2) {
90723
+ logger2.warn(`${this.metadata.name}::netAPY: Failed to fetch LST APRs from Endur API, using fallback: ${error2}`);
90724
+ lstAPRs = /* @__PURE__ */ new Map();
90725
+ }
90616
90726
  for (const [index, pool] of pools.entries()) {
90617
90727
  const vesuAdapter = vesuAdapters[index];
90618
90728
  const collateralAsset = pool.assets.find((a) => a.symbol.toLowerCase() === vesuAdapter.config.collateral.symbol.toLowerCase())?.stats;
90619
90729
  const debtAsset = pool.assets.find((a) => a.symbol.toLowerCase() === vesuAdapter.config.debt.symbol.toLowerCase())?.stats;
90620
90730
  const supplyApy = Number(collateralAsset.supplyApy.value || 0) / 1e18;
90621
- const lstAPY = Number(collateralAsset.lstApr?.value || 0) / 1e18;
90731
+ const lstAPY = lstAPRs.get(vesuAdapter.config.collateral.address.address) || 0;
90732
+ logger2.verbose(`${this.metadata.name}::netAPY: ${vesuAdapter.config.collateral.symbol} LST APR from Endur: ${lstAPY}`);
90622
90733
  baseAPYs.push(...[supplyApy + lstAPY, Number(debtAsset.borrowApr.value) / 1e18]);
90623
90734
  rewardAPYs.push(...[Number(collateralAsset.defiSpringSupplyApr?.value || "0") / 1e18, 0]);
90624
90735
  }
@@ -90842,6 +90953,18 @@ spurious results.`);
90842
90953
  getTag() {
90843
90954
  return `${_UniversalStrategy.name}:${this.metadata.name}`;
90844
90955
  }
90956
+ /**
90957
+ * Gets LST APR for the strategy's underlying asset from Endur API
90958
+ * @returns Promise<number> The LST APR (not divided by 1e18)
90959
+ */
90960
+ async getLSTAPR() {
90961
+ try {
90962
+ return await LSTAPRService.getLSTAPR(this.asset().address);
90963
+ } catch (error2) {
90964
+ logger2.warn(`${this.getTag()}: Failed to get LST APR: ${error2}`);
90965
+ return 0;
90966
+ }
90967
+ }
90845
90968
  async getVesuHealthFactors() {
90846
90969
  return await Promise.all(this.getVesuAdapters().map((v) => v.getHealthFactor()));
90847
90970
  }
@@ -2279,6 +2279,107 @@ var PricerLST = class extends Pricer {
2279
2279
  }
2280
2280
  };
2281
2281
 
2282
+ // src/modules/lst-apr.ts
2283
+ var LSTAPRService = class {
2284
+ // 5 minutes
2285
+ /**
2286
+ * Fetches LST stats from Endur API with caching
2287
+ * @returns Promise<LSTStats[]> Array of LST statistics
2288
+ */
2289
+ static async getLSTStats() {
2290
+ const now = Date.now();
2291
+ if (this.cache && now - this.cacheTimestamp < this.CACHE_DURATION) {
2292
+ logger.verbose(`LSTAPRService: Returning cached LST stats`);
2293
+ return this.cache;
2294
+ }
2295
+ try {
2296
+ logger.verbose(`LSTAPRService: Fetching LST stats from Endur API`);
2297
+ const response = await fetch(this.ENDUR_API_URL);
2298
+ if (!response.ok) {
2299
+ throw new Error(`Failed to fetch LST stats: ${response.status} ${response.statusText}`);
2300
+ }
2301
+ const data = await response.json();
2302
+ if (!Array.isArray(data)) {
2303
+ throw new Error("Invalid response format: expected array");
2304
+ }
2305
+ this.cache = data;
2306
+ this.cacheTimestamp = now;
2307
+ logger.verbose(`LSTAPRService: Successfully fetched ${data.length} LST stats`);
2308
+ return data;
2309
+ } catch (error) {
2310
+ logger.error(`LSTAPRService: Error fetching LST stats: ${error}`);
2311
+ if (this.cache) {
2312
+ logger.warn(`LSTAPRService: Returning stale cached data due to API error`);
2313
+ return this.cache;
2314
+ }
2315
+ throw error;
2316
+ }
2317
+ }
2318
+ /**
2319
+ * Gets LST APR for a specific asset address
2320
+ * @param assetAddress - The contract address of the underlying asset
2321
+ * @returns Promise<number> The LST APR (not divided by 1e18)
2322
+ */
2323
+ static async getLSTAPR(assetAddress) {
2324
+ const stats = await this.getLSTStats();
2325
+ const lstStat = stats.find(
2326
+ (stat) => ContractAddr.eqString(stat.assetAddress, assetAddress.address)
2327
+ );
2328
+ if (!lstStat) {
2329
+ logger.warn(`LSTAPRService: No LST stats found for asset address ${assetAddress.address}`);
2330
+ return 0;
2331
+ }
2332
+ logger.verbose(`LSTAPRService: Found LST APR for ${lstStat.asset}: ${lstStat.apy} (${lstStat.apyInPercentage})`);
2333
+ return lstStat.apy;
2334
+ }
2335
+ /**
2336
+ * Gets LST APR for multiple asset addresses
2337
+ * @param assetAddresses - Array of contract addresses
2338
+ * @returns Promise<Map<string, number>> Map of asset address to LST APR
2339
+ */
2340
+ static async getLSTAPRs(assetAddresses) {
2341
+ const stats = await this.getLSTStats();
2342
+ const result = /* @__PURE__ */ new Map();
2343
+ for (const assetAddress of assetAddresses) {
2344
+ const lstStat = stats.find(
2345
+ (stat) => ContractAddr.eqString(stat.assetAddress, assetAddress.address)
2346
+ );
2347
+ if (lstStat) {
2348
+ result.set(assetAddress.address, lstStat.apy);
2349
+ logger.verbose(`LSTAPRService: Found LST APR for ${lstStat.asset}: ${lstStat.apy}`);
2350
+ } else {
2351
+ result.set(assetAddress.address, 0);
2352
+ logger.warn(`LSTAPRService: No LST stats found for asset address ${assetAddress.address}`);
2353
+ }
2354
+ }
2355
+ return result;
2356
+ }
2357
+ /**
2358
+ * Gets all available LST assets and their APRs
2359
+ * @returns Promise<Map<string, LSTStats>> Map of asset address to LST stats
2360
+ */
2361
+ static async getAllLSTStats() {
2362
+ const stats = await this.getLSTStats();
2363
+ const result = /* @__PURE__ */ new Map();
2364
+ for (const stat of stats) {
2365
+ result.set(stat.assetAddress, stat);
2366
+ }
2367
+ return result;
2368
+ }
2369
+ /**
2370
+ * Clears the cache (useful for testing or forcing refresh)
2371
+ */
2372
+ static clearCache() {
2373
+ this.cache = null;
2374
+ this.cacheTimestamp = 0;
2375
+ logger.verbose(`LSTAPRService: Cache cleared`);
2376
+ }
2377
+ };
2378
+ LSTAPRService.ENDUR_API_URL = "https://app.endur.fi/api/lst/stats";
2379
+ LSTAPRService.cache = null;
2380
+ LSTAPRService.cacheTimestamp = 0;
2381
+ LSTAPRService.CACHE_DURATION = 5 * 60 * 1e3;
2382
+
2282
2383
  // src/interfaces/common.tsx
2283
2384
  import { BlockTag, RpcProvider as RpcProvider2 } from "starknet";
2284
2385
  import { Fragment, jsx } from "react/jsx-runtime";
@@ -16557,7 +16658,7 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16557
16658
  return [baseFlow, rebalanceFlow];
16558
16659
  }
16559
16660
  };
16560
- var _description2 = "Deploys your {{POOL_NAME}} into an Ekubo liquidity pool, automatically rebalancing positions around the current price to optimize yield and reduce the need for manual adjustments. Trading fees and DeFi Spring rewards are automatically compounded back into the strategy. In return, you receive an ERC-20 token representing your share of the strategy";
16661
+ var _description2 = "Deploys your {{POOL_NAME}} into an Ekubo liquidity pool, automatically rebalancing positions around the current price to optimize yield and reduce the need for manual adjustments. Trading fees and any rewards are automatically compounded back into the strategy. In return, you receive an ERC-20 token representing your share of the strategy";
16561
16662
  var _protocol2 = {
16562
16663
  name: "Ekubo",
16563
16664
  logo: "https://app.ekubo.org/favicon.ico"
@@ -16602,7 +16703,7 @@ var faqs2 = [
16602
16703
  },
16603
16704
  {
16604
16705
  question: "How are trading fees and rewards handled?",
16605
- answer: "Trading fees and DeFi Spring rewards are automatically compounded back into the strategy, increasing your overall returns."
16706
+ answer: "Trading fees and any rewards are automatically compounded back into the strategy, increasing your overall returns."
16606
16707
  },
16607
16708
  {
16608
16709
  question: "What happens during withdrawal?",
@@ -16979,7 +17080,7 @@ EkuboCLVaultStrategies.forEach((s) => {
16979
17080
  s.investmentSteps = [
16980
17081
  "Supply tokens to Ekubo's pool",
16981
17082
  "Monitor and Rebalance position to optimize yield",
16982
- "Harvest and supply Defi Spring STRK rewards every week (Auto-compound)"
17083
+ "Harvest and re-invest any rewards every week (Auto-compound)"
16983
17084
  ];
16984
17085
  });
16985
17086
 
@@ -26705,12 +26806,21 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
26705
26806
  logger.verbose(`${this.metadata.name}::netAPY: positions: ${JSON.stringify(positions)}`);
26706
26807
  const baseAPYs = [];
26707
26808
  const rewardAPYs = [];
26809
+ const collateralAddresses = vesuAdapters.map((adapter) => adapter.config.collateral.address);
26810
+ let lstAPRs;
26811
+ try {
26812
+ lstAPRs = await LSTAPRService.getLSTAPRs(collateralAddresses);
26813
+ } catch (error) {
26814
+ logger.warn(`${this.metadata.name}::netAPY: Failed to fetch LST APRs from Endur API, using fallback: ${error}`);
26815
+ lstAPRs = /* @__PURE__ */ new Map();
26816
+ }
26708
26817
  for (const [index, pool] of pools.entries()) {
26709
26818
  const vesuAdapter = vesuAdapters[index];
26710
26819
  const collateralAsset = pool.assets.find((a) => a.symbol.toLowerCase() === vesuAdapter.config.collateral.symbol.toLowerCase())?.stats;
26711
26820
  const debtAsset = pool.assets.find((a) => a.symbol.toLowerCase() === vesuAdapter.config.debt.symbol.toLowerCase())?.stats;
26712
26821
  const supplyApy = Number(collateralAsset.supplyApy.value || 0) / 1e18;
26713
- const lstAPY = Number(collateralAsset.lstApr?.value || 0) / 1e18;
26822
+ const lstAPY = lstAPRs.get(vesuAdapter.config.collateral.address.address) || 0;
26823
+ logger.verbose(`${this.metadata.name}::netAPY: ${vesuAdapter.config.collateral.symbol} LST APR from Endur: ${lstAPY}`);
26714
26824
  baseAPYs.push(...[supplyApy + lstAPY, Number(debtAsset.borrowApr.value) / 1e18]);
26715
26825
  rewardAPYs.push(...[Number(collateralAsset.defiSpringSupplyApr?.value || "0") / 1e18, 0]);
26716
26826
  }
@@ -26934,6 +27044,18 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
26934
27044
  getTag() {
26935
27045
  return `${_UniversalStrategy.name}:${this.metadata.name}`;
26936
27046
  }
27047
+ /**
27048
+ * Gets LST APR for the strategy's underlying asset from Endur API
27049
+ * @returns Promise<number> The LST APR (not divided by 1e18)
27050
+ */
27051
+ async getLSTAPR() {
27052
+ try {
27053
+ return await LSTAPRService.getLSTAPR(this.asset().address);
27054
+ } catch (error) {
27055
+ logger.warn(`${this.getTag()}: Failed to get LST APR: ${error}`);
27056
+ return 0;
27057
+ }
27058
+ }
26937
27059
  async getVesuHealthFactors() {
26938
27060
  return await Promise.all(this.getVesuAdapters().map((v) => v.getHealthFactor()));
26939
27061
  }
@@ -27982,6 +28104,7 @@ export {
27982
28104
  HyperLSTStrategies,
27983
28105
  ILending,
27984
28106
  Initializable,
28107
+ LSTAPRService,
27985
28108
  MarginType,
27986
28109
  Network,
27987
28110
  PRICE_ROUTER,
package/dist/index.d.ts CHANGED
@@ -1225,6 +1225,11 @@ declare class UniversalStrategy<S extends UniversalStrategySettings> extends Bas
1225
1225
  debtAmount: Web3Number;
1226
1226
  }): UniversalManageCall[];
1227
1227
  getTag(): string;
1228
+ /**
1229
+ * Gets LST APR for the strategy's underlying asset from Endur API
1230
+ * @returns Promise<number> The LST APR (not divided by 1e18)
1231
+ */
1232
+ getLSTAPR(): Promise<number>;
1228
1233
  getVesuHealthFactors(): Promise<number[]>;
1229
1234
  computeRebalanceConditionAndReturnCalls(): Promise<Call[]>;
1230
1235
  private getNewHealthFactor;
@@ -1385,6 +1390,50 @@ declare class PricerLST extends Pricer {
1385
1390
  _getPriceEkubo(token: TokenInfo, amountIn?: Web3Number, retry?: number): Promise<number>;
1386
1391
  }
1387
1392
 
1393
+ interface LSTStats {
1394
+ asset: string;
1395
+ assetAddress: string;
1396
+ lstAddress: string;
1397
+ tvlUsd: number;
1398
+ tvlAsset: number;
1399
+ apy: number;
1400
+ apyInPercentage: string;
1401
+ exchangeRate: number;
1402
+ preciseExchangeRate: string;
1403
+ }
1404
+ declare class LSTAPRService {
1405
+ private static readonly ENDUR_API_URL;
1406
+ private static cache;
1407
+ private static cacheTimestamp;
1408
+ private static readonly CACHE_DURATION;
1409
+ /**
1410
+ * Fetches LST stats from Endur API with caching
1411
+ * @returns Promise<LSTStats[]> Array of LST statistics
1412
+ */
1413
+ static getLSTStats(): Promise<LSTStats[]>;
1414
+ /**
1415
+ * Gets LST APR for a specific asset address
1416
+ * @param assetAddress - The contract address of the underlying asset
1417
+ * @returns Promise<number> The LST APR (not divided by 1e18)
1418
+ */
1419
+ static getLSTAPR(assetAddress: ContractAddr): Promise<number>;
1420
+ /**
1421
+ * Gets LST APR for multiple asset addresses
1422
+ * @param assetAddresses - Array of contract addresses
1423
+ * @returns Promise<Map<string, number>> Map of asset address to LST APR
1424
+ */
1425
+ static getLSTAPRs(assetAddresses: ContractAddr[]): Promise<Map<string, number>>;
1426
+ /**
1427
+ * Gets all available LST assets and their APRs
1428
+ * @returns Promise<Map<string, LSTStats>> Map of asset address to LST stats
1429
+ */
1430
+ static getAllLSTStats(): Promise<Map<string, LSTStats>>;
1431
+ /**
1432
+ * Clears the cache (useful for testing or forcing refresh)
1433
+ */
1434
+ static clearCache(): void;
1435
+ }
1436
+
1388
1437
  declare class TelegramNotif {
1389
1438
  private subscribers;
1390
1439
  readonly bot: TelegramBot;
@@ -1535,4 +1584,4 @@ declare class PasswordJsonCryptoUtil {
1535
1584
  decrypt(encryptedData: string, password: string): any;
1536
1585
  }
1537
1586
 
1538
- export { AUMTypes, AVNU_MIDDLEWARE, type AccountInfo, type AdapterLeafType, type AllAccountsStore, type ApproveCallParams, AutoCompounderSTRK, type AvnuSwapCallParams, AvnuWrapper, BaseAdapter, BaseStrategy, type CLVaultStrategySettings, CommonAdapter, type CommonAdapterConfig, ContractAddr, type DecreaseLeverParams, Deployer, type DualActionAmount, type DualTokenInfo, ERC20, type EkuboBounds, EkuboCLVault, EkuboCLVaultStrategies, type EkuboPoolKey, type EkuboQuote, EkuboQuoter, type EkuboRouteNode, type EkuboSplit, type FAQ, FatalError, type FlashloanCallParams, FlowChartColors, type GenerateCallFn, Global, HyperLSTStrategies, type IConfig, type IInvestmentFlow, ILending, type ILendingMetadata, type ILendingPosition, type IProtocol, type IStrategyMetadata, type IncreaseLeverParams, Initializable, type LeafAdapterFn, type LeafData, type LendingToken, type ManageCall, MarginType, Network, PRICE_ROUTER, PasswordJsonCryptoUtil, Pragma, type PriceInfo, Pricer, PricerFromApi, PricerLST, PricerRedis, Protocols, type RequiredFields, type RequiredKeys, type RequiredStoreConfig, type RiskFactor, RiskType, type Route, type RouteNode, SIMPLE_SANITIZER, SIMPLE_SANITIZER_V2, SIMPLE_SANITIZER_VESU_V1_DELEGATIONS, SenseiStrategies, SenseiVault, type SenseiVaultSettings, type SingleActionAmount, type SingleTokenInfo, StandardMerkleTree, type StandardMerkleTreeData, Store, type StoreConfig, type Swap, type SwapInfo, TelegramGroupNotif, TelegramNotif, type TokenAmount, type TokenInfo, UNIVERSAL_ADAPTERS, UNIVERSAL_MANAGE_IDS, UniversalLstMultiplierStrategy, type UniversalManageCall, UniversalStrategies, UniversalStrategy, type UniversalStrategySettings, VESU_SINGLETON, type VaultPosition, VesuAdapter, type VesuAdapterConfig, type VesuAmount, VesuAmountDenomination, VesuAmountType, type VesuDefiSpringRewardsCallParams, type VesuModifyDelegationCallParams, type VesuModifyPositionCallParams, type VesuMultiplyCallParams, VesuPools, VesuRebalance, type VesuRebalanceSettings, VesuRebalanceStrategies, Web3Number, ZkLend, assert, getAPIUsingHeadlessBrowser, getContractDetails, getDefaultStoreConfig, getMainnetConfig, getNoRiskTags, getRiskColor, getRiskExplaination, getTrovesEndpoint, getVesuSingletonAddress, highlightTextWithLinks, type i257, logger, toBigInt };
1587
+ export { AUMTypes, AVNU_MIDDLEWARE, type AccountInfo, type AdapterLeafType, type AllAccountsStore, type ApproveCallParams, AutoCompounderSTRK, type AvnuSwapCallParams, AvnuWrapper, BaseAdapter, BaseStrategy, type CLVaultStrategySettings, CommonAdapter, type CommonAdapterConfig, ContractAddr, type DecreaseLeverParams, Deployer, type DualActionAmount, type DualTokenInfo, ERC20, type EkuboBounds, EkuboCLVault, EkuboCLVaultStrategies, type EkuboPoolKey, type EkuboQuote, EkuboQuoter, type EkuboRouteNode, type EkuboSplit, type FAQ, FatalError, type FlashloanCallParams, FlowChartColors, type GenerateCallFn, Global, HyperLSTStrategies, type IConfig, type IInvestmentFlow, ILending, type ILendingMetadata, type ILendingPosition, type IProtocol, type IStrategyMetadata, type IncreaseLeverParams, Initializable, LSTAPRService, type LSTStats, type LeafAdapterFn, type LeafData, type LendingToken, type ManageCall, MarginType, Network, PRICE_ROUTER, PasswordJsonCryptoUtil, Pragma, type PriceInfo, Pricer, PricerFromApi, PricerLST, PricerRedis, Protocols, type RequiredFields, type RequiredKeys, type RequiredStoreConfig, type RiskFactor, RiskType, type Route, type RouteNode, SIMPLE_SANITIZER, SIMPLE_SANITIZER_V2, SIMPLE_SANITIZER_VESU_V1_DELEGATIONS, SenseiStrategies, SenseiVault, type SenseiVaultSettings, type SingleActionAmount, type SingleTokenInfo, StandardMerkleTree, type StandardMerkleTreeData, Store, type StoreConfig, type Swap, type SwapInfo, TelegramGroupNotif, TelegramNotif, type TokenAmount, type TokenInfo, UNIVERSAL_ADAPTERS, UNIVERSAL_MANAGE_IDS, UniversalLstMultiplierStrategy, type UniversalManageCall, UniversalStrategies, UniversalStrategy, type UniversalStrategySettings, VESU_SINGLETON, type VaultPosition, VesuAdapter, type VesuAdapterConfig, type VesuAmount, VesuAmountDenomination, VesuAmountType, type VesuDefiSpringRewardsCallParams, type VesuModifyDelegationCallParams, type VesuModifyPositionCallParams, type VesuMultiplyCallParams, VesuPools, VesuRebalance, type VesuRebalanceSettings, VesuRebalanceStrategies, Web3Number, ZkLend, assert, getAPIUsingHeadlessBrowser, getContractDetails, getDefaultStoreConfig, getMainnetConfig, getNoRiskTags, getRiskColor, getRiskExplaination, getTrovesEndpoint, getVesuSingletonAddress, highlightTextWithLinks, type i257, logger, toBigInt };
package/dist/index.js CHANGED
@@ -49,6 +49,7 @@ __export(index_exports, {
49
49
  HyperLSTStrategies: () => HyperLSTStrategies,
50
50
  ILending: () => ILending,
51
51
  Initializable: () => Initializable,
52
+ LSTAPRService: () => LSTAPRService,
52
53
  MarginType: () => MarginType,
53
54
  Network: () => Network,
54
55
  PRICE_ROUTER: () => PRICE_ROUTER,
@@ -16653,7 +16654,7 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16653
16654
  return [baseFlow, rebalanceFlow];
16654
16655
  }
16655
16656
  };
16656
- var _description2 = "Deploys your {{POOL_NAME}} into an Ekubo liquidity pool, automatically rebalancing positions around the current price to optimize yield and reduce the need for manual adjustments. Trading fees and DeFi Spring rewards are automatically compounded back into the strategy. In return, you receive an ERC-20 token representing your share of the strategy";
16657
+ var _description2 = "Deploys your {{POOL_NAME}} into an Ekubo liquidity pool, automatically rebalancing positions around the current price to optimize yield and reduce the need for manual adjustments. Trading fees and any rewards are automatically compounded back into the strategy. In return, you receive an ERC-20 token representing your share of the strategy";
16657
16658
  var _protocol2 = {
16658
16659
  name: "Ekubo",
16659
16660
  logo: "https://app.ekubo.org/favicon.ico"
@@ -16698,7 +16699,7 @@ var faqs2 = [
16698
16699
  },
16699
16700
  {
16700
16701
  question: "How are trading fees and rewards handled?",
16701
- answer: "Trading fees and DeFi Spring rewards are automatically compounded back into the strategy, increasing your overall returns."
16702
+ answer: "Trading fees and any rewards are automatically compounded back into the strategy, increasing your overall returns."
16702
16703
  },
16703
16704
  {
16704
16705
  question: "What happens during withdrawal?",
@@ -17075,7 +17076,7 @@ EkuboCLVaultStrategies.forEach((s) => {
17075
17076
  s.investmentSteps = [
17076
17077
  "Supply tokens to Ekubo's pool",
17077
17078
  "Monitor and Rebalance position to optimize yield",
17078
- "Harvest and supply Defi Spring STRK rewards every week (Auto-compound)"
17079
+ "Harvest and re-invest any rewards every week (Auto-compound)"
17079
17080
  ];
17080
17081
  });
17081
17082
 
@@ -26801,12 +26802,21 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
26801
26802
  logger.verbose(`${this.metadata.name}::netAPY: positions: ${JSON.stringify(positions)}`);
26802
26803
  const baseAPYs = [];
26803
26804
  const rewardAPYs = [];
26805
+ const collateralAddresses = vesuAdapters.map((adapter) => adapter.config.collateral.address);
26806
+ let lstAPRs;
26807
+ try {
26808
+ lstAPRs = await LSTAPRService.getLSTAPRs(collateralAddresses);
26809
+ } catch (error) {
26810
+ logger.warn(`${this.metadata.name}::netAPY: Failed to fetch LST APRs from Endur API, using fallback: ${error}`);
26811
+ lstAPRs = /* @__PURE__ */ new Map();
26812
+ }
26804
26813
  for (const [index, pool] of pools.entries()) {
26805
26814
  const vesuAdapter = vesuAdapters[index];
26806
26815
  const collateralAsset = pool.assets.find((a) => a.symbol.toLowerCase() === vesuAdapter.config.collateral.symbol.toLowerCase())?.stats;
26807
26816
  const debtAsset = pool.assets.find((a) => a.symbol.toLowerCase() === vesuAdapter.config.debt.symbol.toLowerCase())?.stats;
26808
26817
  const supplyApy = Number(collateralAsset.supplyApy.value || 0) / 1e18;
26809
- const lstAPY = Number(collateralAsset.lstApr?.value || 0) / 1e18;
26818
+ const lstAPY = lstAPRs.get(vesuAdapter.config.collateral.address.address) || 0;
26819
+ logger.verbose(`${this.metadata.name}::netAPY: ${vesuAdapter.config.collateral.symbol} LST APR from Endur: ${lstAPY}`);
26810
26820
  baseAPYs.push(...[supplyApy + lstAPY, Number(debtAsset.borrowApr.value) / 1e18]);
26811
26821
  rewardAPYs.push(...[Number(collateralAsset.defiSpringSupplyApr?.value || "0") / 1e18, 0]);
26812
26822
  }
@@ -27030,6 +27040,18 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
27030
27040
  getTag() {
27031
27041
  return `${_UniversalStrategy.name}:${this.metadata.name}`;
27032
27042
  }
27043
+ /**
27044
+ * Gets LST APR for the strategy's underlying asset from Endur API
27045
+ * @returns Promise<number> The LST APR (not divided by 1e18)
27046
+ */
27047
+ async getLSTAPR() {
27048
+ try {
27049
+ return await LSTAPRService.getLSTAPR(this.asset().address);
27050
+ } catch (error) {
27051
+ logger.warn(`${this.getTag()}: Failed to get LST APR: ${error}`);
27052
+ return 0;
27053
+ }
27054
+ }
27033
27055
  async getVesuHealthFactors() {
27034
27056
  return await Promise.all(this.getVesuAdapters().map((v) => v.getHealthFactor()));
27035
27057
  }
@@ -28110,6 +28132,107 @@ var PricerLST2 = class extends Pricer {
28110
28132
  }
28111
28133
  };
28112
28134
 
28135
+ // src/modules/lst-apr.ts
28136
+ var LSTAPRService = class {
28137
+ // 5 minutes
28138
+ /**
28139
+ * Fetches LST stats from Endur API with caching
28140
+ * @returns Promise<LSTStats[]> Array of LST statistics
28141
+ */
28142
+ static async getLSTStats() {
28143
+ const now = Date.now();
28144
+ if (this.cache && now - this.cacheTimestamp < this.CACHE_DURATION) {
28145
+ logger.verbose(`LSTAPRService: Returning cached LST stats`);
28146
+ return this.cache;
28147
+ }
28148
+ try {
28149
+ logger.verbose(`LSTAPRService: Fetching LST stats from Endur API`);
28150
+ const response = await fetch(this.ENDUR_API_URL);
28151
+ if (!response.ok) {
28152
+ throw new Error(`Failed to fetch LST stats: ${response.status} ${response.statusText}`);
28153
+ }
28154
+ const data = await response.json();
28155
+ if (!Array.isArray(data)) {
28156
+ throw new Error("Invalid response format: expected array");
28157
+ }
28158
+ this.cache = data;
28159
+ this.cacheTimestamp = now;
28160
+ logger.verbose(`LSTAPRService: Successfully fetched ${data.length} LST stats`);
28161
+ return data;
28162
+ } catch (error) {
28163
+ logger.error(`LSTAPRService: Error fetching LST stats: ${error}`);
28164
+ if (this.cache) {
28165
+ logger.warn(`LSTAPRService: Returning stale cached data due to API error`);
28166
+ return this.cache;
28167
+ }
28168
+ throw error;
28169
+ }
28170
+ }
28171
+ /**
28172
+ * Gets LST APR for a specific asset address
28173
+ * @param assetAddress - The contract address of the underlying asset
28174
+ * @returns Promise<number> The LST APR (not divided by 1e18)
28175
+ */
28176
+ static async getLSTAPR(assetAddress) {
28177
+ const stats = await this.getLSTStats();
28178
+ const lstStat = stats.find(
28179
+ (stat) => ContractAddr.eqString(stat.assetAddress, assetAddress.address)
28180
+ );
28181
+ if (!lstStat) {
28182
+ logger.warn(`LSTAPRService: No LST stats found for asset address ${assetAddress.address}`);
28183
+ return 0;
28184
+ }
28185
+ logger.verbose(`LSTAPRService: Found LST APR for ${lstStat.asset}: ${lstStat.apy} (${lstStat.apyInPercentage})`);
28186
+ return lstStat.apy;
28187
+ }
28188
+ /**
28189
+ * Gets LST APR for multiple asset addresses
28190
+ * @param assetAddresses - Array of contract addresses
28191
+ * @returns Promise<Map<string, number>> Map of asset address to LST APR
28192
+ */
28193
+ static async getLSTAPRs(assetAddresses) {
28194
+ const stats = await this.getLSTStats();
28195
+ const result = /* @__PURE__ */ new Map();
28196
+ for (const assetAddress of assetAddresses) {
28197
+ const lstStat = stats.find(
28198
+ (stat) => ContractAddr.eqString(stat.assetAddress, assetAddress.address)
28199
+ );
28200
+ if (lstStat) {
28201
+ result.set(assetAddress.address, lstStat.apy);
28202
+ logger.verbose(`LSTAPRService: Found LST APR for ${lstStat.asset}: ${lstStat.apy}`);
28203
+ } else {
28204
+ result.set(assetAddress.address, 0);
28205
+ logger.warn(`LSTAPRService: No LST stats found for asset address ${assetAddress.address}`);
28206
+ }
28207
+ }
28208
+ return result;
28209
+ }
28210
+ /**
28211
+ * Gets all available LST assets and their APRs
28212
+ * @returns Promise<Map<string, LSTStats>> Map of asset address to LST stats
28213
+ */
28214
+ static async getAllLSTStats() {
28215
+ const stats = await this.getLSTStats();
28216
+ const result = /* @__PURE__ */ new Map();
28217
+ for (const stat of stats) {
28218
+ result.set(stat.assetAddress, stat);
28219
+ }
28220
+ return result;
28221
+ }
28222
+ /**
28223
+ * Clears the cache (useful for testing or forcing refresh)
28224
+ */
28225
+ static clearCache() {
28226
+ this.cache = null;
28227
+ this.cacheTimestamp = 0;
28228
+ logger.verbose(`LSTAPRService: Cache cleared`);
28229
+ }
28230
+ };
28231
+ LSTAPRService.ENDUR_API_URL = "https://app.endur.fi/api/lst/stats";
28232
+ LSTAPRService.cache = null;
28233
+ LSTAPRService.cacheTimestamp = 0;
28234
+ LSTAPRService.CACHE_DURATION = 5 * 60 * 1e3;
28235
+
28113
28236
  // src/notifs/telegram.ts
28114
28237
  var import_node_telegram_bot_api = __toESM(require("node-telegram-bot-api"));
28115
28238
  var TelegramNotif = class {
@@ -28638,6 +28761,7 @@ var deployer_default = Deployer;
28638
28761
  HyperLSTStrategies,
28639
28762
  ILending,
28640
28763
  Initializable,
28764
+ LSTAPRService,
28641
28765
  MarginType,
28642
28766
  Network,
28643
28767
  PRICE_ROUTER,
package/dist/index.mjs CHANGED
@@ -16556,7 +16556,7 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16556
16556
  return [baseFlow, rebalanceFlow];
16557
16557
  }
16558
16558
  };
16559
- var _description2 = "Deploys your {{POOL_NAME}} into an Ekubo liquidity pool, automatically rebalancing positions around the current price to optimize yield and reduce the need for manual adjustments. Trading fees and DeFi Spring rewards are automatically compounded back into the strategy. In return, you receive an ERC-20 token representing your share of the strategy";
16559
+ var _description2 = "Deploys your {{POOL_NAME}} into an Ekubo liquidity pool, automatically rebalancing positions around the current price to optimize yield and reduce the need for manual adjustments. Trading fees and any rewards are automatically compounded back into the strategy. In return, you receive an ERC-20 token representing your share of the strategy";
16560
16560
  var _protocol2 = {
16561
16561
  name: "Ekubo",
16562
16562
  logo: "https://app.ekubo.org/favicon.ico"
@@ -16601,7 +16601,7 @@ var faqs2 = [
16601
16601
  },
16602
16602
  {
16603
16603
  question: "How are trading fees and rewards handled?",
16604
- answer: "Trading fees and DeFi Spring rewards are automatically compounded back into the strategy, increasing your overall returns."
16604
+ answer: "Trading fees and any rewards are automatically compounded back into the strategy, increasing your overall returns."
16605
16605
  },
16606
16606
  {
16607
16607
  question: "What happens during withdrawal?",
@@ -16978,7 +16978,7 @@ EkuboCLVaultStrategies.forEach((s) => {
16978
16978
  s.investmentSteps = [
16979
16979
  "Supply tokens to Ekubo's pool",
16980
16980
  "Monitor and Rebalance position to optimize yield",
16981
- "Harvest and supply Defi Spring STRK rewards every week (Auto-compound)"
16981
+ "Harvest and re-invest any rewards every week (Auto-compound)"
16982
16982
  ];
16983
16983
  });
16984
16984
 
@@ -26704,12 +26704,21 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
26704
26704
  logger.verbose(`${this.metadata.name}::netAPY: positions: ${JSON.stringify(positions)}`);
26705
26705
  const baseAPYs = [];
26706
26706
  const rewardAPYs = [];
26707
+ const collateralAddresses = vesuAdapters.map((adapter) => adapter.config.collateral.address);
26708
+ let lstAPRs;
26709
+ try {
26710
+ lstAPRs = await LSTAPRService.getLSTAPRs(collateralAddresses);
26711
+ } catch (error) {
26712
+ logger.warn(`${this.metadata.name}::netAPY: Failed to fetch LST APRs from Endur API, using fallback: ${error}`);
26713
+ lstAPRs = /* @__PURE__ */ new Map();
26714
+ }
26707
26715
  for (const [index, pool] of pools.entries()) {
26708
26716
  const vesuAdapter = vesuAdapters[index];
26709
26717
  const collateralAsset = pool.assets.find((a) => a.symbol.toLowerCase() === vesuAdapter.config.collateral.symbol.toLowerCase())?.stats;
26710
26718
  const debtAsset = pool.assets.find((a) => a.symbol.toLowerCase() === vesuAdapter.config.debt.symbol.toLowerCase())?.stats;
26711
26719
  const supplyApy = Number(collateralAsset.supplyApy.value || 0) / 1e18;
26712
- const lstAPY = Number(collateralAsset.lstApr?.value || 0) / 1e18;
26720
+ const lstAPY = lstAPRs.get(vesuAdapter.config.collateral.address.address) || 0;
26721
+ logger.verbose(`${this.metadata.name}::netAPY: ${vesuAdapter.config.collateral.symbol} LST APR from Endur: ${lstAPY}`);
26713
26722
  baseAPYs.push(...[supplyApy + lstAPY, Number(debtAsset.borrowApr.value) / 1e18]);
26714
26723
  rewardAPYs.push(...[Number(collateralAsset.defiSpringSupplyApr?.value || "0") / 1e18, 0]);
26715
26724
  }
@@ -26933,6 +26942,18 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
26933
26942
  getTag() {
26934
26943
  return `${_UniversalStrategy.name}:${this.metadata.name}`;
26935
26944
  }
26945
+ /**
26946
+ * Gets LST APR for the strategy's underlying asset from Endur API
26947
+ * @returns Promise<number> The LST APR (not divided by 1e18)
26948
+ */
26949
+ async getLSTAPR() {
26950
+ try {
26951
+ return await LSTAPRService.getLSTAPR(this.asset().address);
26952
+ } catch (error) {
26953
+ logger.warn(`${this.getTag()}: Failed to get LST APR: ${error}`);
26954
+ return 0;
26955
+ }
26956
+ }
26936
26957
  async getVesuHealthFactors() {
26937
26958
  return await Promise.all(this.getVesuAdapters().map((v) => v.getHealthFactor()));
26938
26959
  }
@@ -28013,6 +28034,107 @@ var PricerLST2 = class extends Pricer {
28013
28034
  }
28014
28035
  };
28015
28036
 
28037
+ // src/modules/lst-apr.ts
28038
+ var LSTAPRService = class {
28039
+ // 5 minutes
28040
+ /**
28041
+ * Fetches LST stats from Endur API with caching
28042
+ * @returns Promise<LSTStats[]> Array of LST statistics
28043
+ */
28044
+ static async getLSTStats() {
28045
+ const now = Date.now();
28046
+ if (this.cache && now - this.cacheTimestamp < this.CACHE_DURATION) {
28047
+ logger.verbose(`LSTAPRService: Returning cached LST stats`);
28048
+ return this.cache;
28049
+ }
28050
+ try {
28051
+ logger.verbose(`LSTAPRService: Fetching LST stats from Endur API`);
28052
+ const response = await fetch(this.ENDUR_API_URL);
28053
+ if (!response.ok) {
28054
+ throw new Error(`Failed to fetch LST stats: ${response.status} ${response.statusText}`);
28055
+ }
28056
+ const data = await response.json();
28057
+ if (!Array.isArray(data)) {
28058
+ throw new Error("Invalid response format: expected array");
28059
+ }
28060
+ this.cache = data;
28061
+ this.cacheTimestamp = now;
28062
+ logger.verbose(`LSTAPRService: Successfully fetched ${data.length} LST stats`);
28063
+ return data;
28064
+ } catch (error) {
28065
+ logger.error(`LSTAPRService: Error fetching LST stats: ${error}`);
28066
+ if (this.cache) {
28067
+ logger.warn(`LSTAPRService: Returning stale cached data due to API error`);
28068
+ return this.cache;
28069
+ }
28070
+ throw error;
28071
+ }
28072
+ }
28073
+ /**
28074
+ * Gets LST APR for a specific asset address
28075
+ * @param assetAddress - The contract address of the underlying asset
28076
+ * @returns Promise<number> The LST APR (not divided by 1e18)
28077
+ */
28078
+ static async getLSTAPR(assetAddress) {
28079
+ const stats = await this.getLSTStats();
28080
+ const lstStat = stats.find(
28081
+ (stat) => ContractAddr.eqString(stat.assetAddress, assetAddress.address)
28082
+ );
28083
+ if (!lstStat) {
28084
+ logger.warn(`LSTAPRService: No LST stats found for asset address ${assetAddress.address}`);
28085
+ return 0;
28086
+ }
28087
+ logger.verbose(`LSTAPRService: Found LST APR for ${lstStat.asset}: ${lstStat.apy} (${lstStat.apyInPercentage})`);
28088
+ return lstStat.apy;
28089
+ }
28090
+ /**
28091
+ * Gets LST APR for multiple asset addresses
28092
+ * @param assetAddresses - Array of contract addresses
28093
+ * @returns Promise<Map<string, number>> Map of asset address to LST APR
28094
+ */
28095
+ static async getLSTAPRs(assetAddresses) {
28096
+ const stats = await this.getLSTStats();
28097
+ const result = /* @__PURE__ */ new Map();
28098
+ for (const assetAddress of assetAddresses) {
28099
+ const lstStat = stats.find(
28100
+ (stat) => ContractAddr.eqString(stat.assetAddress, assetAddress.address)
28101
+ );
28102
+ if (lstStat) {
28103
+ result.set(assetAddress.address, lstStat.apy);
28104
+ logger.verbose(`LSTAPRService: Found LST APR for ${lstStat.asset}: ${lstStat.apy}`);
28105
+ } else {
28106
+ result.set(assetAddress.address, 0);
28107
+ logger.warn(`LSTAPRService: No LST stats found for asset address ${assetAddress.address}`);
28108
+ }
28109
+ }
28110
+ return result;
28111
+ }
28112
+ /**
28113
+ * Gets all available LST assets and their APRs
28114
+ * @returns Promise<Map<string, LSTStats>> Map of asset address to LST stats
28115
+ */
28116
+ static async getAllLSTStats() {
28117
+ const stats = await this.getLSTStats();
28118
+ const result = /* @__PURE__ */ new Map();
28119
+ for (const stat of stats) {
28120
+ result.set(stat.assetAddress, stat);
28121
+ }
28122
+ return result;
28123
+ }
28124
+ /**
28125
+ * Clears the cache (useful for testing or forcing refresh)
28126
+ */
28127
+ static clearCache() {
28128
+ this.cache = null;
28129
+ this.cacheTimestamp = 0;
28130
+ logger.verbose(`LSTAPRService: Cache cleared`);
28131
+ }
28132
+ };
28133
+ LSTAPRService.ENDUR_API_URL = "https://app.endur.fi/api/lst/stats";
28134
+ LSTAPRService.cache = null;
28135
+ LSTAPRService.cacheTimestamp = 0;
28136
+ LSTAPRService.CACHE_DURATION = 5 * 60 * 1e3;
28137
+
28016
28138
  // src/notifs/telegram.ts
28017
28139
  import TelegramBot from "node-telegram-bot-api";
28018
28140
  var TelegramNotif = class {
@@ -28540,6 +28662,7 @@ export {
28540
28662
  HyperLSTStrategies,
28541
28663
  ILending,
28542
28664
  Initializable,
28665
+ LSTAPRService,
28543
28666
  MarginType,
28544
28667
  Network,
28545
28668
  PRICE_ROUTER,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strkfarm/sdk",
3
- "version": "1.1.24",
3
+ "version": "1.1.26",
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",
@@ -5,4 +5,5 @@ export * from './pricer-from-api';
5
5
  export * from './erc20';
6
6
  export * from './avnu';
7
7
  export * from './ekubo-quoter';
8
- export * from './pricer-lst';
8
+ export * from './pricer-lst';
9
+ export * from './lst-apr';
@@ -0,0 +1,140 @@
1
+ import { ContractAddr } from "@/dataTypes";
2
+ import { logger } from "@/utils";
3
+
4
+ export interface LSTStats {
5
+ asset: string;
6
+ assetAddress: string;
7
+ lstAddress: string;
8
+ tvlUsd: number;
9
+ tvlAsset: number;
10
+ apy: number;
11
+ apyInPercentage: string;
12
+ exchangeRate: number;
13
+ preciseExchangeRate: string;
14
+ }
15
+
16
+ export class LSTAPRService {
17
+ private static readonly ENDUR_API_URL = 'https://app.endur.fi/api/lst/stats';
18
+ private static cache: LSTStats[] | null = null;
19
+ private static cacheTimestamp: number = 0;
20
+ private static readonly CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
21
+
22
+ /**
23
+ * Fetches LST stats from Endur API with caching
24
+ * @returns Promise<LSTStats[]> Array of LST statistics
25
+ */
26
+ static async getLSTStats(): Promise<LSTStats[]> {
27
+ const now = Date.now();
28
+
29
+ // Return cached data if still valid
30
+ if (this.cache && (now - this.cacheTimestamp) < this.CACHE_DURATION) {
31
+ logger.verbose(`LSTAPRService: Returning cached LST stats`);
32
+ return this.cache;
33
+ }
34
+
35
+ try {
36
+ logger.verbose(`LSTAPRService: Fetching LST stats from Endur API`);
37
+ const response = await fetch(this.ENDUR_API_URL);
38
+
39
+ if (!response.ok) {
40
+ throw new Error(`Failed to fetch LST stats: ${response.status} ${response.statusText}`);
41
+ }
42
+
43
+ const data: LSTStats[] = await response.json();
44
+
45
+ // Validate the response structure
46
+ if (!Array.isArray(data)) {
47
+ throw new Error('Invalid response format: expected array');
48
+ }
49
+
50
+ // Cache the data
51
+ this.cache = data;
52
+ this.cacheTimestamp = now;
53
+
54
+ logger.verbose(`LSTAPRService: Successfully fetched ${data.length} LST stats`);
55
+ return data;
56
+
57
+ } catch (error) {
58
+ logger.error(`LSTAPRService: Error fetching LST stats: ${error}`);
59
+
60
+ // Return cached data if available, even if expired
61
+ if (this.cache) {
62
+ logger.warn(`LSTAPRService: Returning stale cached data due to API error`);
63
+ return this.cache;
64
+ }
65
+
66
+ throw error;
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Gets LST APR for a specific asset address
72
+ * @param assetAddress - The contract address of the underlying asset
73
+ * @returns Promise<number> The LST APR (not divided by 1e18)
74
+ */
75
+ static async getLSTAPR(assetAddress: ContractAddr): Promise<number> {
76
+ const stats = await this.getLSTStats();
77
+
78
+ const lstStat = stats.find(stat =>
79
+ ContractAddr.eqString(stat.assetAddress, assetAddress.address)
80
+ );
81
+
82
+ if (!lstStat) {
83
+ logger.warn(`LSTAPRService: No LST stats found for asset address ${assetAddress.address}`);
84
+ return 0;
85
+ }
86
+
87
+ logger.verbose(`LSTAPRService: Found LST APR for ${lstStat.asset}: ${lstStat.apy} (${lstStat.apyInPercentage})`);
88
+ return lstStat.apy;
89
+ }
90
+
91
+ /**
92
+ * Gets LST APR for multiple asset addresses
93
+ * @param assetAddresses - Array of contract addresses
94
+ * @returns Promise<Map<string, number>> Map of asset address to LST APR
95
+ */
96
+ static async getLSTAPRs(assetAddresses: ContractAddr[]): Promise<Map<string, number>> {
97
+ const stats = await this.getLSTStats();
98
+ const result = new Map<string, number>();
99
+
100
+ for (const assetAddress of assetAddresses) {
101
+ const lstStat = stats.find(stat =>
102
+ ContractAddr.eqString(stat.assetAddress, assetAddress.address)
103
+ );
104
+
105
+ if (lstStat) {
106
+ result.set(assetAddress.address, lstStat.apy);
107
+ logger.verbose(`LSTAPRService: Found LST APR for ${lstStat.asset}: ${lstStat.apy}`);
108
+ } else {
109
+ result.set(assetAddress.address, 0);
110
+ logger.warn(`LSTAPRService: No LST stats found for asset address ${assetAddress.address}`);
111
+ }
112
+ }
113
+
114
+ return result;
115
+ }
116
+
117
+ /**
118
+ * Gets all available LST assets and their APRs
119
+ * @returns Promise<Map<string, LSTStats>> Map of asset address to LST stats
120
+ */
121
+ static async getAllLSTStats(): Promise<Map<string, LSTStats>> {
122
+ const stats = await this.getLSTStats();
123
+ const result = new Map<string, LSTStats>();
124
+
125
+ for (const stat of stats) {
126
+ result.set(stat.assetAddress, stat);
127
+ }
128
+
129
+ return result;
130
+ }
131
+
132
+ /**
133
+ * Clears the cache (useful for testing or forcing refresh)
134
+ */
135
+ static clearCache(): void {
136
+ this.cache = null;
137
+ this.cacheTimestamp = 0;
138
+ logger.verbose(`LSTAPRService: Cache cleared`);
139
+ }
140
+ }
@@ -1751,7 +1751,7 @@ export class EkuboCLVault extends BaseStrategy<
1751
1751
  }
1752
1752
 
1753
1753
  const _description =
1754
- "Deploys your {{POOL_NAME}} into an Ekubo liquidity pool, automatically rebalancing positions around the current price to optimize yield and reduce the need for manual adjustments. Trading fees and DeFi Spring rewards are automatically compounded back into the strategy. In return, you receive an ERC-20 token representing your share of the strategy";
1754
+ "Deploys your {{POOL_NAME}} into an Ekubo liquidity pool, automatically rebalancing positions around the current price to optimize yield and reduce the need for manual adjustments. Trading fees and any rewards are automatically compounded back into the strategy. In return, you receive an ERC-20 token representing your share of the strategy";
1755
1755
  const _protocol: IProtocol = {
1756
1756
  name: "Ekubo",
1757
1757
  logo: "https://app.ekubo.org/favicon.ico",
@@ -1812,7 +1812,7 @@ const faqs: FAQ[] = [
1812
1812
  {
1813
1813
  question: "How are trading fees and rewards handled?",
1814
1814
  answer:
1815
- "Trading fees and DeFi Spring rewards are automatically compounded back into the strategy, increasing your overall returns.",
1815
+ "Trading fees and any rewards are automatically compounded back into the strategy, increasing your overall returns.",
1816
1816
  },
1817
1817
  {
1818
1818
  question: "What happens during withdrawal?",
@@ -2217,6 +2217,6 @@ EkuboCLVaultStrategies.forEach((s) => {
2217
2217
  s.investmentSteps = [
2218
2218
  "Supply tokens to Ekubo's pool",
2219
2219
  "Monitor and Rebalance position to optimize yield",
2220
- "Harvest and supply Defi Spring STRK rewards every week (Auto-compound)",
2220
+ "Harvest and re-invest any rewards every week (Auto-compound)",
2221
2221
  ]
2222
2222
  });
@@ -9,7 +9,7 @@ import UniversalVaultAbi from '../data/universal-vault.abi.json';
9
9
  import ManagerAbi from '../data/vault-manager.abi.json';
10
10
  import { ApproveCallParams, AvnuSwapCallParams, BaseAdapter, CommonAdapter, FlashloanCallParams, GenerateCallFn, LeafAdapterFn, ManageCall, VesuAdapter, VesuDefiSpringRewardsCallParams, VesuModifyPositionCallParams, VesuPools } from "./universal-adapters";
11
11
  import { Global } from "@/global";
12
- import { AvnuWrapper, ERC20 } from "@/modules";
12
+ import { AvnuWrapper, ERC20, LSTAPRService } from "@/modules";
13
13
  import { AVNU_MIDDLEWARE, VESU_SINGLETON } from "./universal-adapters/adapter-utils";
14
14
  import { VesuHarvests } from "@/modules/harvests";
15
15
 
@@ -227,12 +227,28 @@ export class UniversalStrategy<
227
227
  logger.verbose(`${this.metadata.name}::netAPY: positions: ${JSON.stringify(positions)}`);
228
228
  const baseAPYs: number[] = [];
229
229
  const rewardAPYs: number[] = [];
230
+
231
+ // Get LST APRs for all collateral assets with fallback
232
+ const collateralAddresses = vesuAdapters.map(adapter => adapter.config.collateral.address);
233
+ let lstAPRs: Map<string, number>;
234
+ try {
235
+ lstAPRs = await LSTAPRService.getLSTAPRs(collateralAddresses);
236
+ } catch (error) {
237
+ logger.warn(`${this.metadata.name}::netAPY: Failed to fetch LST APRs from Endur API, using fallback: ${error}`);
238
+ // Fallback: create empty map (will result in 0 LST APR)
239
+ lstAPRs = new Map();
240
+ }
241
+
230
242
  for (const [index, pool] of pools.entries()) {
231
243
  const vesuAdapter = vesuAdapters[index];
232
244
  const collateralAsset = pool.assets.find((a: any) => a.symbol.toLowerCase() === vesuAdapter.config.collateral.symbol.toLowerCase())?.stats!;
233
245
  const debtAsset = pool.assets.find((a: any) => a.symbol.toLowerCase() === vesuAdapter.config.debt.symbol.toLowerCase())?.stats!;
234
246
  const supplyApy = Number(collateralAsset.supplyApy.value || 0) / 1e18;
235
- const lstAPY = Number(collateralAsset.lstApr?.value || 0) / 1e18;
247
+
248
+ // Use LST APR from Endur API instead of Vesu's lstApr
249
+ const lstAPY = lstAPRs.get(vesuAdapter.config.collateral.address.address) || 0;
250
+ logger.verbose(`${this.metadata.name}::netAPY: ${vesuAdapter.config.collateral.symbol} LST APR from Endur: ${lstAPY}`);
251
+
236
252
  baseAPYs.push(...[supplyApy + lstAPY, Number(debtAsset.borrowApr.value) / 1e18]);
237
253
  rewardAPYs.push(...[Number(collateralAsset.defiSpringSupplyApr?.value || "0") / 1e18, 0]);
238
254
  }
@@ -501,6 +517,19 @@ export class UniversalStrategy<
501
517
  return `${UniversalStrategy.name}:${this.metadata.name}`;
502
518
  }
503
519
 
520
+ /**
521
+ * Gets LST APR for the strategy's underlying asset from Endur API
522
+ * @returns Promise<number> The LST APR (not divided by 1e18)
523
+ */
524
+ async getLSTAPR(): Promise<number> {
525
+ try {
526
+ return await LSTAPRService.getLSTAPR(this.asset().address);
527
+ } catch (error) {
528
+ logger.warn(`${this.getTag()}: Failed to get LST APR: ${error}`);
529
+ return 0;
530
+ }
531
+ }
532
+
504
533
  async getVesuHealthFactors() {
505
534
  return await Promise.all(this.getVesuAdapters().map(v => v.getHealthFactor()));
506
535
  }