@strkfarm/sdk 1.1.10 → 1.1.11

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.js CHANGED
@@ -54,6 +54,7 @@ __export(index_exports, {
54
54
  Pragma: () => Pragma,
55
55
  Pricer: () => Pricer,
56
56
  PricerFromApi: () => PricerFromApi,
57
+ PricerLST: () => PricerLST2,
57
58
  PricerRedis: () => PricerRedis,
58
59
  Protocols: () => Protocols,
59
60
  RiskType: () => RiskType,
@@ -385,6 +386,17 @@ var defaultTokens = [{
385
386
  symbol: "xtBTC",
386
387
  logo: "https://assets.strkfarm.com/integrations/tokens/xtbtc.svg",
387
388
  address: ContractAddr.from("0x43a35c1425a0125ef8c171f1a75c6f31ef8648edcc8324b55ce1917db3f9b91"),
389
+ decimals: 18,
390
+ coingeckId: void 0,
391
+ displayDecimals: 6,
392
+ priceProxySymbol: "WBTC",
393
+ priceCheckAmount: 1e-4
394
+ // 112000 * 0.0001 = $11.2
395
+ }, {
396
+ name: "xLBTC",
397
+ symbol: "xLBTC",
398
+ logo: "https://assets.strkfarm.com/integrations/tokens/xlbtc.svg",
399
+ address: ContractAddr.from("0x036834a40984312f7f7de8d31e3f6305b325389eaeea5b1c0664b2fb936461a4"),
388
400
  decimals: 8,
389
401
  coingeckId: void 0,
390
402
  displayDecimals: 6,
@@ -988,7 +1000,7 @@ var PricerFromApi = class extends PricerBase {
988
1000
  }
989
1001
  async getPriceFromMyAPI(tokenSymbol) {
990
1002
  logger.verbose(`getPrice from redis: ${tokenSymbol}`);
991
- const endpoint = "https://app.troves.fi";
1003
+ const endpoint = "https://cache-server-t2me.onrender.com";
992
1004
  const url = `${endpoint}/api/price/${tokenSymbol}`;
993
1005
  const priceInfoRes = await fetch(url);
994
1006
  const priceInfo = await priceInfoRes.json();
@@ -16687,6 +16699,29 @@ var lstStrategies = [
16687
16699
  points: [],
16688
16700
  contractDetails: [],
16689
16701
  investmentSteps: []
16702
+ },
16703
+ {
16704
+ ...xSTRKSTRK,
16705
+ name: "Ekubo xLBTC/LBTC",
16706
+ description: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, {}),
16707
+ address: ContractAddr.from(
16708
+ "0x315a614603b1f702e466aedcbcb1ad97a77eb1192b8bd077e5154d4f2ee4fab"
16709
+ ),
16710
+ launchBlock: 2344809,
16711
+ // must be same order as poolKey token0 and token1
16712
+ depositTokens: [
16713
+ Global.getDefaultTokens().find((t) => t.symbol === "LBTC"),
16714
+ Global.getDefaultTokens().find((t) => t.symbol === "xLBTC")
16715
+ ],
16716
+ additionalInfo: {
16717
+ ...xSTRKSTRK.additionalInfo,
16718
+ quoteAsset: Global.getDefaultTokens().find((t) => t.symbol === "LBTC"),
16719
+ lstContract: Global.getDefaultTokens().find((t) => t.symbol === "xLBTC").address
16720
+ },
16721
+ faqs: getLSTFAQs("xLBTC"),
16722
+ points: [],
16723
+ contractDetails: [],
16724
+ investmentSteps: []
16690
16725
  }
16691
16726
  ];
16692
16727
  var ETHUSDCRe7Strategy = {
@@ -24789,17 +24824,16 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
24789
24824
  const legAUM = await adapter.getPositions(this.config);
24790
24825
  const underlying = this.asset();
24791
24826
  let vesuAum = Web3Number.fromWei("0", underlying.decimals);
24827
+ let tokenUnderlyingPrice = await this.pricer.getPrice(this.asset().symbol);
24792
24828
  if (legAUM[0].token.address.eq(underlying.address)) {
24793
24829
  vesuAum = vesuAum.plus(legAUM[0].amount);
24794
24830
  } else {
24795
- const tokenPrice = await this.pricer.getPrice(legAUM[1].token.symbol);
24796
- vesuAum = vesuAum.plus(legAUM[1].usdValue / tokenPrice.price);
24831
+ vesuAum = vesuAum.plus(legAUM[1].usdValue / tokenUnderlyingPrice.price);
24797
24832
  }
24798
24833
  if (legAUM[1].token.address.eq(underlying.address)) {
24799
24834
  vesuAum = vesuAum.minus(legAUM[1].amount);
24800
24835
  } else {
24801
- const tokenPrice = await this.pricer.getPrice(legAUM[1].token.symbol);
24802
- vesuAum = vesuAum.minus(legAUM[1].usdValue / tokenPrice.price);
24836
+ vesuAum = vesuAum.minus(legAUM[1].usdValue / tokenUnderlyingPrice.price);
24803
24837
  }
24804
24838
  ;
24805
24839
  logger.verbose(`${this.getTag()} Vesu AUM: ${vesuAum}, legCollateral: ${legAUM[0].amount.toNumber()}, legDebt: ${legAUM[1].amount.toNumber()}`);
@@ -25556,9 +25590,9 @@ var UniversalLstMultiplierStrategy = class extends UniversalStrategy {
25556
25590
  }
25557
25591
  // not applicable for this strategy
25558
25592
  // No rewards on collateral or borrowing of LST assets
25559
- async getRewardsAUM(prevAum) {
25560
- return Web3Number.fromWei("0", this.asset().decimals);
25561
- }
25593
+ // protected async getRewardsAUM(prevAum: Web3Number): Promise<Web3Number> {
25594
+ // return Web3Number.fromWei("0", this.asset().decimals);
25595
+ // }
25562
25596
  async getLSTDexPrice() {
25563
25597
  const ekuboQuoter = new EkuboQuoter(this.config);
25564
25598
  const lstTokenInfo = this.asset();
@@ -25590,12 +25624,12 @@ var UniversalLstMultiplierStrategy = class extends UniversalStrategy {
25590
25624
  const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
25591
25625
  const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
25592
25626
  logger.debug(`${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
25627
+ const dexPrice = await this.getLSTDexPrice();
25593
25628
  const addedCollateral = params.leg1DepositAmount.multipliedBy(params.isDeposit ? 1 : -1);
25594
- const DEXPrice = await this.getLSTDexPrice();
25595
25629
  logger.verbose(`${this.getTag()}::getVesuMultiplyCall addedCollateral: ${addedCollateral}`);
25596
25630
  const numeratorPart1 = existingCollateralInfo.amount.plus(addedCollateral).multipliedBy(collateralPrice).multipliedBy(legLTV);
25597
25631
  const numeratorPart2 = existingDebtInfo.amount.multipliedBy(debtPrice).multipliedBy(this.metadata.additionalInfo.targetHealthFactor);
25598
- const denominatorPart = this.metadata.additionalInfo.targetHealthFactor - legLTV / DEXPrice;
25632
+ const denominatorPart = this.metadata.additionalInfo.targetHealthFactor - legLTV / dexPrice;
25599
25633
  const x_debt_usd = numeratorPart1.minus(numeratorPart2).dividedBy(denominatorPart);
25600
25634
  logger.verbose(`${this.getTag()}::getVesuMultiplyCall x_debt_usd: ${x_debt_usd}`);
25601
25635
  logger.debug(`${this.getTag()}::getVesuMultiplyCall numeratorPart1: ${numeratorPart1}, numeratorPart2: ${numeratorPart2}, denominatorPart: ${denominatorPart}`);
@@ -25605,6 +25639,7 @@ var UniversalLstMultiplierStrategy = class extends UniversalStrategy {
25605
25639
  return this.getModifyLeverCall({
25606
25640
  marginAmount,
25607
25641
  debtAmount,
25642
+ lstDexPriceInUnderlying: dexPrice,
25608
25643
  isIncrease: debtAmount.greaterThan(0)
25609
25644
  });
25610
25645
  }
@@ -25646,8 +25681,8 @@ var UniversalLstMultiplierStrategy = class extends UniversalStrategy {
25646
25681
  proofsIDs.push(STEP1_ID);
25647
25682
  manageCalls.push(manageCall1);
25648
25683
  }
25684
+ const lstDexPriceInUnderlying = params.lstDexPriceInUnderlying;
25649
25685
  const ekuboQuoter = new EkuboQuoter(this.config);
25650
- const lstPrice = await this.getLSTExchangeRate();
25651
25686
  const marginSwap = [];
25652
25687
  const MAX_SLIPPAGE = 0.01;
25653
25688
  const fromToken = params.isIncrease ? lstUnderlyingTokenInfo : lstTokenInfo;
@@ -25660,8 +25695,8 @@ var UniversalLstMultiplierStrategy = class extends UniversalStrategy {
25660
25695
  );
25661
25696
  assert(leverSwapQuote.price_impact < MAX_SLIPPAGE, "getIncreaseLeverCall: Price impact is too high [Debt swap]");
25662
25697
  const leverSwap = ekuboQuoter.getVesuMultiplyQuote(leverSwapQuote, fromToken, toToken);
25663
- const minExpectedDebt = params.debtAmount.dividedBy(lstPrice).multipliedBy(1 - MAX_SLIPPAGE);
25664
- const maxUsedCollateral = params.debtAmount.abs().dividedBy(lstPrice).multipliedBy(1 + MAX_SLIPPAGE);
25698
+ const minExpectedDebt = params.debtAmount.dividedBy(lstDexPriceInUnderlying).multipliedBy(1 - MAX_SLIPPAGE);
25699
+ const maxUsedCollateral = params.debtAmount.abs().dividedBy(lstDexPriceInUnderlying).multipliedBy(1 + MAX_SLIPPAGE);
25665
25700
  const STEP2_ID = "switch_delegation_on" /* SWITCH_DELEGATION_ON */;
25666
25701
  const manage2Info = this.getProofs(STEP2_ID);
25667
25702
  const manageCall2 = manage2Info.callConstructor({
@@ -25859,6 +25894,17 @@ var hyperxsBTC = {
25859
25894
  targetHealthFactor: 1.1,
25860
25895
  minHealthFactor: 1.05
25861
25896
  };
25897
+ var hyperxLBTC = {
25898
+ vaultAddress: ContractAddr.from("0x38e96a301428d204ab4553799aa386a0f14a5ef9b30a5830be1814e4fb8da1c"),
25899
+ manager: ContractAddr.from("0x18d376446d9df1f783e17aff1f21bac3d97aa3ba378e367742cdd744468ad35"),
25900
+ vaultAllocator: ContractAddr.from("0x3e98774ca0508505ba6d7f17d95ec391648f44f947b0d211241464a4f5b9b20"),
25901
+ redeemRequestNFT: ContractAddr.from("0x268017b4c8b2117ca0136d9a77e3666db44b143447566f0746ca0b1c9ab1e72"),
25902
+ aumOracle: ContractAddr.from("0x521a3f339c65e918e0d8a065b14baef1ea25676bb7fca1e0238ac47e20d7755"),
25903
+ leafAdapters: [],
25904
+ adapters: [],
25905
+ targetHealthFactor: 1.1,
25906
+ minHealthFactor: 1.05
25907
+ };
25862
25908
  function getInvestmentSteps(lstSymbol, underlyingSymbol) {
25863
25909
  return [
25864
25910
  `Deposit ${underlyingSymbol} into the vault`,
@@ -25895,9 +25941,60 @@ var HyperLSTStrategies = [
25895
25941
  getStrategySettings("xSTRK", "STRK", hyperxSTRK, false),
25896
25942
  getStrategySettings("xWBTC", "WBTC", hyperxWBTC, true),
25897
25943
  getStrategySettings("xtBTC", "tBTC", hyperxtBTC, true),
25898
- getStrategySettings("xsBTC", "solvBTC", hyperxsBTC, true)
25944
+ getStrategySettings("xsBTC", "solvBTC", hyperxsBTC, true),
25945
+ getStrategySettings("xLBTC", "LBTC", hyperxLBTC, true)
25899
25946
  ];
25900
25947
 
25948
+ // src/modules/pricer-lst.ts
25949
+ var import_axios7 = __toESM(require("axios"));
25950
+ var PricerLST2 = class extends Pricer {
25951
+ // e.g. xSTRK/STRK
25952
+ constructor(config, tokenMaps) {
25953
+ const refreshInterval = 5e3;
25954
+ const staleTime = 6e4;
25955
+ const allTokens = tokenMaps.map((map) => [map.lst, map.underlying]).flat();
25956
+ super(config, allTokens, refreshInterval, staleTime);
25957
+ this.EKUBO_API = "https://quoter-mainnet-api.ekubo.org/{{AMOUNT}}/{{TOKEN_ADDRESS}}/{{UNDERLYING_ADDRESS}}";
25958
+ this.tokenMaps = tokenMaps;
25959
+ }
25960
+ isUnderlying(token) {
25961
+ return this.tokenMaps.some((map) => map.underlying.address.eq(token.address));
25962
+ }
25963
+ getUnderlying(token) {
25964
+ return this.tokenMaps.find((map) => map.lst.address.eq(token.address)).underlying;
25965
+ }
25966
+ async _getPrice(token, defaultMethod = "all") {
25967
+ if (this.isUnderlying(token)) {
25968
+ return 1;
25969
+ }
25970
+ const methodToUse = this.methodToUse[token.symbol] || defaultMethod;
25971
+ logger.verbose(`Fetching price of ${token.symbol} using ${methodToUse}`);
25972
+ try {
25973
+ const result = await this._getPriceEkubo(token, new Web3Number(token.priceCheckAmount ? token.priceCheckAmount : 1, token.decimals));
25974
+ this.methodToUse[token.symbol] = "Ekubo";
25975
+ return result;
25976
+ } catch (error) {
25977
+ console.warn(`Ekubo: price err [${token.symbol}]: `, error.message);
25978
+ console.warn(`Ekubo: price err [${token.symbol}]: `, Object.keys(error));
25979
+ }
25980
+ throw new FatalError(`Price not found for ${token.symbol}`);
25981
+ }
25982
+ async _getPriceEkubo(token, amountIn = new Web3Number(1, token.decimals), retry = 0) {
25983
+ const underlying = this.getUnderlying(token);
25984
+ const url = this.EKUBO_API.replace("{{TOKEN_ADDRESS}}", token.address.toString()).replace("{{AMOUNT}}", amountIn.toWei()).replace("{{UNDERLYING_ADDRESS}}", underlying.address.toString());
25985
+ const result = await import_axios7.default.get(url);
25986
+ const data = result.data;
25987
+ const multiplier = 1 / amountIn.toNumber();
25988
+ const outputUnderlying = Number(Web3Number.fromWei(data.total_calculated, underlying.decimals).toFixed(6)) * multiplier;
25989
+ logger.verbose(`Ekubo: ${token.symbol} -> ${underlying.symbol}: ${outputUnderlying}, retry: ${retry}`);
25990
+ if (outputUnderlying === 0 && retry < 3) {
25991
+ const amountIn2 = new Web3Number(100, token.decimals);
25992
+ return await this._getPriceEkubo(token, amountIn2, retry + 1);
25993
+ }
25994
+ return outputUnderlying;
25995
+ }
25996
+ };
25997
+
25901
25998
  // src/notifs/telegram.ts
25902
25999
  var import_node_telegram_bot_api = __toESM(require("node-telegram-bot-api"));
25903
26000
  var TelegramNotif = class {
@@ -26345,6 +26442,7 @@ var deployer_default = Deployer;
26345
26442
  Pragma,
26346
26443
  Pricer,
26347
26444
  PricerFromApi,
26445
+ PricerLST,
26348
26446
  PricerRedis,
26349
26447
  Protocols,
26350
26448
  RiskType,
package/dist/index.mjs CHANGED
@@ -294,6 +294,17 @@ var defaultTokens = [{
294
294
  symbol: "xtBTC",
295
295
  logo: "https://assets.strkfarm.com/integrations/tokens/xtbtc.svg",
296
296
  address: ContractAddr.from("0x43a35c1425a0125ef8c171f1a75c6f31ef8648edcc8324b55ce1917db3f9b91"),
297
+ decimals: 18,
298
+ coingeckId: void 0,
299
+ displayDecimals: 6,
300
+ priceProxySymbol: "WBTC",
301
+ priceCheckAmount: 1e-4
302
+ // 112000 * 0.0001 = $11.2
303
+ }, {
304
+ name: "xLBTC",
305
+ symbol: "xLBTC",
306
+ logo: "https://assets.strkfarm.com/integrations/tokens/xlbtc.svg",
307
+ address: ContractAddr.from("0x036834a40984312f7f7de8d31e3f6305b325389eaeea5b1c0664b2fb936461a4"),
297
308
  decimals: 8,
298
309
  coingeckId: void 0,
299
310
  displayDecimals: 6,
@@ -897,7 +908,7 @@ var PricerFromApi = class extends PricerBase {
897
908
  }
898
909
  async getPriceFromMyAPI(tokenSymbol) {
899
910
  logger.verbose(`getPrice from redis: ${tokenSymbol}`);
900
- const endpoint = "https://app.troves.fi";
911
+ const endpoint = "https://cache-server-t2me.onrender.com";
901
912
  const url = `${endpoint}/api/price/${tokenSymbol}`;
902
913
  const priceInfoRes = await fetch(url);
903
914
  const priceInfo = await priceInfoRes.json();
@@ -16600,6 +16611,29 @@ var lstStrategies = [
16600
16611
  points: [],
16601
16612
  contractDetails: [],
16602
16613
  investmentSteps: []
16614
+ },
16615
+ {
16616
+ ...xSTRKSTRK,
16617
+ name: "Ekubo xLBTC/LBTC",
16618
+ description: /* @__PURE__ */ jsx3(Fragment2, {}),
16619
+ address: ContractAddr.from(
16620
+ "0x315a614603b1f702e466aedcbcb1ad97a77eb1192b8bd077e5154d4f2ee4fab"
16621
+ ),
16622
+ launchBlock: 2344809,
16623
+ // must be same order as poolKey token0 and token1
16624
+ depositTokens: [
16625
+ Global.getDefaultTokens().find((t) => t.symbol === "LBTC"),
16626
+ Global.getDefaultTokens().find((t) => t.symbol === "xLBTC")
16627
+ ],
16628
+ additionalInfo: {
16629
+ ...xSTRKSTRK.additionalInfo,
16630
+ quoteAsset: Global.getDefaultTokens().find((t) => t.symbol === "LBTC"),
16631
+ lstContract: Global.getDefaultTokens().find((t) => t.symbol === "xLBTC").address
16632
+ },
16633
+ faqs: getLSTFAQs("xLBTC"),
16634
+ points: [],
16635
+ contractDetails: [],
16636
+ investmentSteps: []
16603
16637
  }
16604
16638
  ];
16605
16639
  var ETHUSDCRe7Strategy = {
@@ -24702,17 +24736,16 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
24702
24736
  const legAUM = await adapter.getPositions(this.config);
24703
24737
  const underlying = this.asset();
24704
24738
  let vesuAum = Web3Number.fromWei("0", underlying.decimals);
24739
+ let tokenUnderlyingPrice = await this.pricer.getPrice(this.asset().symbol);
24705
24740
  if (legAUM[0].token.address.eq(underlying.address)) {
24706
24741
  vesuAum = vesuAum.plus(legAUM[0].amount);
24707
24742
  } else {
24708
- const tokenPrice = await this.pricer.getPrice(legAUM[1].token.symbol);
24709
- vesuAum = vesuAum.plus(legAUM[1].usdValue / tokenPrice.price);
24743
+ vesuAum = vesuAum.plus(legAUM[1].usdValue / tokenUnderlyingPrice.price);
24710
24744
  }
24711
24745
  if (legAUM[1].token.address.eq(underlying.address)) {
24712
24746
  vesuAum = vesuAum.minus(legAUM[1].amount);
24713
24747
  } else {
24714
- const tokenPrice = await this.pricer.getPrice(legAUM[1].token.symbol);
24715
- vesuAum = vesuAum.minus(legAUM[1].usdValue / tokenPrice.price);
24748
+ vesuAum = vesuAum.minus(legAUM[1].usdValue / tokenUnderlyingPrice.price);
24716
24749
  }
24717
24750
  ;
24718
24751
  logger.verbose(`${this.getTag()} Vesu AUM: ${vesuAum}, legCollateral: ${legAUM[0].amount.toNumber()}, legDebt: ${legAUM[1].amount.toNumber()}`);
@@ -25469,9 +25502,9 @@ var UniversalLstMultiplierStrategy = class extends UniversalStrategy {
25469
25502
  }
25470
25503
  // not applicable for this strategy
25471
25504
  // No rewards on collateral or borrowing of LST assets
25472
- async getRewardsAUM(prevAum) {
25473
- return Web3Number.fromWei("0", this.asset().decimals);
25474
- }
25505
+ // protected async getRewardsAUM(prevAum: Web3Number): Promise<Web3Number> {
25506
+ // return Web3Number.fromWei("0", this.asset().decimals);
25507
+ // }
25475
25508
  async getLSTDexPrice() {
25476
25509
  const ekuboQuoter = new EkuboQuoter(this.config);
25477
25510
  const lstTokenInfo = this.asset();
@@ -25503,12 +25536,12 @@ var UniversalLstMultiplierStrategy = class extends UniversalStrategy {
25503
25536
  const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
25504
25537
  const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
25505
25538
  logger.debug(`${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
25539
+ const dexPrice = await this.getLSTDexPrice();
25506
25540
  const addedCollateral = params.leg1DepositAmount.multipliedBy(params.isDeposit ? 1 : -1);
25507
- const DEXPrice = await this.getLSTDexPrice();
25508
25541
  logger.verbose(`${this.getTag()}::getVesuMultiplyCall addedCollateral: ${addedCollateral}`);
25509
25542
  const numeratorPart1 = existingCollateralInfo.amount.plus(addedCollateral).multipliedBy(collateralPrice).multipliedBy(legLTV);
25510
25543
  const numeratorPart2 = existingDebtInfo.amount.multipliedBy(debtPrice).multipliedBy(this.metadata.additionalInfo.targetHealthFactor);
25511
- const denominatorPart = this.metadata.additionalInfo.targetHealthFactor - legLTV / DEXPrice;
25544
+ const denominatorPart = this.metadata.additionalInfo.targetHealthFactor - legLTV / dexPrice;
25512
25545
  const x_debt_usd = numeratorPart1.minus(numeratorPart2).dividedBy(denominatorPart);
25513
25546
  logger.verbose(`${this.getTag()}::getVesuMultiplyCall x_debt_usd: ${x_debt_usd}`);
25514
25547
  logger.debug(`${this.getTag()}::getVesuMultiplyCall numeratorPart1: ${numeratorPart1}, numeratorPart2: ${numeratorPart2}, denominatorPart: ${denominatorPart}`);
@@ -25518,6 +25551,7 @@ var UniversalLstMultiplierStrategy = class extends UniversalStrategy {
25518
25551
  return this.getModifyLeverCall({
25519
25552
  marginAmount,
25520
25553
  debtAmount,
25554
+ lstDexPriceInUnderlying: dexPrice,
25521
25555
  isIncrease: debtAmount.greaterThan(0)
25522
25556
  });
25523
25557
  }
@@ -25559,8 +25593,8 @@ var UniversalLstMultiplierStrategy = class extends UniversalStrategy {
25559
25593
  proofsIDs.push(STEP1_ID);
25560
25594
  manageCalls.push(manageCall1);
25561
25595
  }
25596
+ const lstDexPriceInUnderlying = params.lstDexPriceInUnderlying;
25562
25597
  const ekuboQuoter = new EkuboQuoter(this.config);
25563
- const lstPrice = await this.getLSTExchangeRate();
25564
25598
  const marginSwap = [];
25565
25599
  const MAX_SLIPPAGE = 0.01;
25566
25600
  const fromToken = params.isIncrease ? lstUnderlyingTokenInfo : lstTokenInfo;
@@ -25573,8 +25607,8 @@ var UniversalLstMultiplierStrategy = class extends UniversalStrategy {
25573
25607
  );
25574
25608
  assert(leverSwapQuote.price_impact < MAX_SLIPPAGE, "getIncreaseLeverCall: Price impact is too high [Debt swap]");
25575
25609
  const leverSwap = ekuboQuoter.getVesuMultiplyQuote(leverSwapQuote, fromToken, toToken);
25576
- const minExpectedDebt = params.debtAmount.dividedBy(lstPrice).multipliedBy(1 - MAX_SLIPPAGE);
25577
- const maxUsedCollateral = params.debtAmount.abs().dividedBy(lstPrice).multipliedBy(1 + MAX_SLIPPAGE);
25610
+ const minExpectedDebt = params.debtAmount.dividedBy(lstDexPriceInUnderlying).multipliedBy(1 - MAX_SLIPPAGE);
25611
+ const maxUsedCollateral = params.debtAmount.abs().dividedBy(lstDexPriceInUnderlying).multipliedBy(1 + MAX_SLIPPAGE);
25578
25612
  const STEP2_ID = "switch_delegation_on" /* SWITCH_DELEGATION_ON */;
25579
25613
  const manage2Info = this.getProofs(STEP2_ID);
25580
25614
  const manageCall2 = manage2Info.callConstructor({
@@ -25772,6 +25806,17 @@ var hyperxsBTC = {
25772
25806
  targetHealthFactor: 1.1,
25773
25807
  minHealthFactor: 1.05
25774
25808
  };
25809
+ var hyperxLBTC = {
25810
+ vaultAddress: ContractAddr.from("0x38e96a301428d204ab4553799aa386a0f14a5ef9b30a5830be1814e4fb8da1c"),
25811
+ manager: ContractAddr.from("0x18d376446d9df1f783e17aff1f21bac3d97aa3ba378e367742cdd744468ad35"),
25812
+ vaultAllocator: ContractAddr.from("0x3e98774ca0508505ba6d7f17d95ec391648f44f947b0d211241464a4f5b9b20"),
25813
+ redeemRequestNFT: ContractAddr.from("0x268017b4c8b2117ca0136d9a77e3666db44b143447566f0746ca0b1c9ab1e72"),
25814
+ aumOracle: ContractAddr.from("0x521a3f339c65e918e0d8a065b14baef1ea25676bb7fca1e0238ac47e20d7755"),
25815
+ leafAdapters: [],
25816
+ adapters: [],
25817
+ targetHealthFactor: 1.1,
25818
+ minHealthFactor: 1.05
25819
+ };
25775
25820
  function getInvestmentSteps(lstSymbol, underlyingSymbol) {
25776
25821
  return [
25777
25822
  `Deposit ${underlyingSymbol} into the vault`,
@@ -25808,9 +25853,60 @@ var HyperLSTStrategies = [
25808
25853
  getStrategySettings("xSTRK", "STRK", hyperxSTRK, false),
25809
25854
  getStrategySettings("xWBTC", "WBTC", hyperxWBTC, true),
25810
25855
  getStrategySettings("xtBTC", "tBTC", hyperxtBTC, true),
25811
- getStrategySettings("xsBTC", "solvBTC", hyperxsBTC, true)
25856
+ getStrategySettings("xsBTC", "solvBTC", hyperxsBTC, true),
25857
+ getStrategySettings("xLBTC", "LBTC", hyperxLBTC, true)
25812
25858
  ];
25813
25859
 
25860
+ // src/modules/pricer-lst.ts
25861
+ import axios7 from "axios";
25862
+ var PricerLST2 = class extends Pricer {
25863
+ // e.g. xSTRK/STRK
25864
+ constructor(config, tokenMaps) {
25865
+ const refreshInterval = 5e3;
25866
+ const staleTime = 6e4;
25867
+ const allTokens = tokenMaps.map((map) => [map.lst, map.underlying]).flat();
25868
+ super(config, allTokens, refreshInterval, staleTime);
25869
+ this.EKUBO_API = "https://quoter-mainnet-api.ekubo.org/{{AMOUNT}}/{{TOKEN_ADDRESS}}/{{UNDERLYING_ADDRESS}}";
25870
+ this.tokenMaps = tokenMaps;
25871
+ }
25872
+ isUnderlying(token) {
25873
+ return this.tokenMaps.some((map) => map.underlying.address.eq(token.address));
25874
+ }
25875
+ getUnderlying(token) {
25876
+ return this.tokenMaps.find((map) => map.lst.address.eq(token.address)).underlying;
25877
+ }
25878
+ async _getPrice(token, defaultMethod = "all") {
25879
+ if (this.isUnderlying(token)) {
25880
+ return 1;
25881
+ }
25882
+ const methodToUse = this.methodToUse[token.symbol] || defaultMethod;
25883
+ logger.verbose(`Fetching price of ${token.symbol} using ${methodToUse}`);
25884
+ try {
25885
+ const result = await this._getPriceEkubo(token, new Web3Number(token.priceCheckAmount ? token.priceCheckAmount : 1, token.decimals));
25886
+ this.methodToUse[token.symbol] = "Ekubo";
25887
+ return result;
25888
+ } catch (error) {
25889
+ console.warn(`Ekubo: price err [${token.symbol}]: `, error.message);
25890
+ console.warn(`Ekubo: price err [${token.symbol}]: `, Object.keys(error));
25891
+ }
25892
+ throw new FatalError(`Price not found for ${token.symbol}`);
25893
+ }
25894
+ async _getPriceEkubo(token, amountIn = new Web3Number(1, token.decimals), retry = 0) {
25895
+ const underlying = this.getUnderlying(token);
25896
+ const url = this.EKUBO_API.replace("{{TOKEN_ADDRESS}}", token.address.toString()).replace("{{AMOUNT}}", amountIn.toWei()).replace("{{UNDERLYING_ADDRESS}}", underlying.address.toString());
25897
+ const result = await axios7.get(url);
25898
+ const data = result.data;
25899
+ const multiplier = 1 / amountIn.toNumber();
25900
+ const outputUnderlying = Number(Web3Number.fromWei(data.total_calculated, underlying.decimals).toFixed(6)) * multiplier;
25901
+ logger.verbose(`Ekubo: ${token.symbol} -> ${underlying.symbol}: ${outputUnderlying}, retry: ${retry}`);
25902
+ if (outputUnderlying === 0 && retry < 3) {
25903
+ const amountIn2 = new Web3Number(100, token.decimals);
25904
+ return await this._getPriceEkubo(token, amountIn2, retry + 1);
25905
+ }
25906
+ return outputUnderlying;
25907
+ }
25908
+ };
25909
+
25814
25910
  // src/notifs/telegram.ts
25815
25911
  import TelegramBot from "node-telegram-bot-api";
25816
25912
  var TelegramNotif = class {
@@ -26257,6 +26353,7 @@ export {
26257
26353
  Pragma,
26258
26354
  Pricer,
26259
26355
  PricerFromApi,
26356
+ PricerLST2 as PricerLST,
26260
26357
  PricerRedis,
26261
26358
  Protocols,
26262
26359
  RiskType,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strkfarm/sdk",
3
- "version": "1.1.10",
3
+ "version": "1.1.11",
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",
package/src/global.ts CHANGED
@@ -122,6 +122,16 @@ const defaultTokens: TokenInfo[] = [{
122
122
  symbol: 'xtBTC',
123
123
  logo: 'https://assets.strkfarm.com/integrations/tokens/xtbtc.svg',
124
124
  address: ContractAddr.from('0x43a35c1425a0125ef8c171f1a75c6f31ef8648edcc8324b55ce1917db3f9b91'),
125
+ decimals: 18,
126
+ coingeckId: undefined,
127
+ displayDecimals: 6,
128
+ priceProxySymbol: 'WBTC',
129
+ priceCheckAmount: 0.0001, // 112000 * 0.0001 = $11.2
130
+ }, {
131
+ name: 'xLBTC',
132
+ symbol: 'xLBTC',
133
+ logo: 'https://assets.strkfarm.com/integrations/tokens/xlbtc.svg',
134
+ address: ContractAddr.from('0x036834a40984312f7f7de8d31e3f6305b325389eaeea5b1c0664b2fb936461a4'),
125
135
  decimals: 8,
126
136
  coingeckId: undefined,
127
137
  displayDecimals: 6,
@@ -4,4 +4,5 @@ export * from './zkLend';
4
4
  export * from './pricer-from-api';
5
5
  export * from './erc20';
6
6
  export * from './avnu';
7
- export * from './ekubo-quoter';
7
+ export * from './ekubo-quoter';
8
+ export * from './pricer-lst';
@@ -42,7 +42,7 @@ export class PricerFromApi extends PricerBase {
42
42
 
43
43
  async getPriceFromMyAPI(tokenSymbol: string) {
44
44
  logger.verbose(`getPrice from redis: ${tokenSymbol}`);
45
- const endpoint = 'https://app.troves.fi'
45
+ const endpoint = 'https://cache-server-t2me.onrender.com'
46
46
  const url = `${endpoint}/api/price/${tokenSymbol}`;
47
47
  const priceInfoRes = await fetch(url);
48
48
  const priceInfo = await priceInfoRes.json();
@@ -0,0 +1,66 @@
1
+ import { FatalError, PriceInfo, Pricer, Web3Number } from "@/index.browser";
2
+ import { PricerBase } from "./pricerBase";
3
+ import { IConfig, TokenInfo } from "@/interfaces";
4
+ import { logger } from "@/utils";
5
+ import axios from "axios";
6
+
7
+ export class PricerLST extends Pricer {
8
+ private tokenMaps: {lst: TokenInfo, underlying: TokenInfo}[];
9
+ protected EKUBO_API = 'https://quoter-mainnet-api.ekubo.org/{{AMOUNT}}/{{TOKEN_ADDRESS}}/{{UNDERLYING_ADDRESS}}'; // e.g. xSTRK/STRK
10
+
11
+ constructor(config: IConfig, tokenMaps: {lst: TokenInfo, underlying: TokenInfo}[]) {
12
+ const refreshInterval = 5000;
13
+ const staleTime = 60000;
14
+ const allTokens = tokenMaps.map(map => [map.lst, map.underlying]).flat();
15
+ super(config, allTokens, refreshInterval, staleTime);
16
+ this.tokenMaps = tokenMaps;
17
+ }
18
+
19
+ isUnderlying(token: TokenInfo): boolean {
20
+ return this.tokenMaps.some(map => map.underlying.address.eq(token.address));
21
+ }
22
+
23
+ getUnderlying(token: TokenInfo): TokenInfo {
24
+ return this.tokenMaps.find(map => map.lst.address.eq(token.address))!.underlying;
25
+ }
26
+
27
+ async _getPrice(token: TokenInfo, defaultMethod = 'all'): Promise<number> {
28
+ if (this.isUnderlying(token)) {
29
+ return 1; // underlying is always 1 relative to LST
30
+ }
31
+
32
+ const methodToUse: string = this.methodToUse[token.symbol] || defaultMethod; // default start with coinbase
33
+ logger.verbose(`Fetching price of ${token.symbol} using ${methodToUse}`);
34
+ try {
35
+ const result = await this._getPriceEkubo(token, new Web3Number(token.priceCheckAmount ? token.priceCheckAmount : 1, token.decimals));
36
+ this.methodToUse[token.symbol] = 'Ekubo';
37
+ return result;
38
+ } catch (error: any) {
39
+ console.warn(`Ekubo: price err [${token.symbol}]: `, error.message);
40
+ console.warn(`Ekubo: price err [${token.symbol}]: `, Object.keys(error));
41
+ // do nothing, try next
42
+ }
43
+
44
+ throw new FatalError(`Price not found for ${token.symbol}`);
45
+ }
46
+
47
+ async _getPriceEkubo(token: TokenInfo, amountIn = new Web3Number(1, token.decimals), retry = 0): Promise<number> {
48
+ const underlying = this.getUnderlying(token);
49
+ const url = this.EKUBO_API
50
+ .replace("{{TOKEN_ADDRESS}}", token.address.toString())
51
+ .replace("{{AMOUNT}}", amountIn.toWei())
52
+ .replace("{{UNDERLYING_ADDRESS}}", underlying.address.toString());
53
+ const result = await axios.get(url);
54
+ const data: any = result.data;
55
+ const multiplier = 1 / amountIn.toNumber();
56
+ const outputUnderlying = Number(Web3Number.fromWei(data.total_calculated, underlying.decimals).toFixed(6)) * multiplier;
57
+ logger.verbose(`Ekubo: ${token.symbol} -> ${underlying.symbol}: ${outputUnderlying}, retry: ${retry}`);
58
+ if (outputUnderlying === 0 && retry < 3) {
59
+ // try again with a higher amount
60
+ const amountIn = new Web3Number(100, token.decimals); // 100 unit of token
61
+ return await this._getPriceEkubo(token, amountIn, retry + 1);
62
+ }
63
+
64
+ return outputUnderlying;
65
+ }
66
+ }
@@ -21,7 +21,7 @@ export class Pricer extends PricerBase {
21
21
 
22
22
  // code populates this map during runtime to determine which method to use for a given token
23
23
  // The method set will be the first one to try after first attempt
24
- private methodToUse: {[tokenSymbol: string]: 'Ekubo' | 'Coinbase' | 'Coinmarketcap'} = {};
24
+ protected methodToUse: {[tokenSymbol: string]: 'Ekubo' | 'Coinbase' | 'Coinmarketcap'} = {};
25
25
 
26
26
  /**
27
27
  * TOKENA and TOKENB are the two token names to get price of TokenA in terms of TokenB
@@ -1809,6 +1809,29 @@ const lstStrategies: IStrategyMetadata<CLVaultStrategySettings>[] = [
1809
1809
  contractDetails: [],
1810
1810
  investmentSteps: []
1811
1811
  },
1812
+ {
1813
+ ...xSTRKSTRK,
1814
+ name: "Ekubo xLBTC/LBTC",
1815
+ description: <></>,
1816
+ address: ContractAddr.from(
1817
+ "0x315a614603b1f702e466aedcbcb1ad97a77eb1192b8bd077e5154d4f2ee4fab"
1818
+ ),
1819
+ launchBlock: 2344809,
1820
+ // must be same order as poolKey token0 and token1
1821
+ depositTokens: [
1822
+ Global.getDefaultTokens().find((t) => t.symbol === "LBTC")!,
1823
+ Global.getDefaultTokens().find((t) => t.symbol === "xLBTC")!,
1824
+ ],
1825
+ additionalInfo: {
1826
+ ...xSTRKSTRK.additionalInfo,
1827
+ quoteAsset: Global.getDefaultTokens().find((t) => t.symbol === "LBTC")!,
1828
+ lstContract: Global.getDefaultTokens().find((t) => t.symbol === "xLBTC")!.address,
1829
+ },
1830
+ faqs: getLSTFAQs("xLBTC"),
1831
+ points: [],
1832
+ contractDetails: [],
1833
+ investmentSteps: []
1834
+ }
1812
1835
  ];
1813
1836
 
1814
1837
  const ETHUSDCRe7Strategy: IStrategyMetadata<CLVaultStrategySettings> = {