@strkfarm/sdk 1.0.56 → 1.0.57

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
@@ -1986,7 +1986,6 @@ import { toHex } from "@ericnordelo/strk-merkle-tree/dist/bytes";
1986
1986
  import { processMultiProof, processProof } from "@ericnordelo/strk-merkle-tree/dist/core";
1987
1987
  import { standardLeafHash } from "@ericnordelo/strk-merkle-tree/dist/hashes";
1988
1988
  import { MerkleTreeImpl } from "@ericnordelo/strk-merkle-tree/dist/merkletree";
1989
- import { validateArgument } from "@ericnordelo/strk-merkle-tree/src/utils/errors";
1990
1989
  import { num as num2 } from "starknet";
1991
1990
 
1992
1991
  // ../node_modules/@noble/hashes/esm/_assert.js
@@ -4044,13 +4043,6 @@ var StandardMerkleTree = class _StandardMerkleTree extends MerkleTreeImpl {
4044
4043
  });
4045
4044
  return new _StandardMerkleTree(tree, indexedValues, leafEncoding);
4046
4045
  }
4047
- static load(data) {
4048
- validateArgument(data.format === "standard-v1", `Unknown format '${data.format}'`);
4049
- validateArgument(data.leafEncoding !== void 0, "Expected leaf encoding");
4050
- const tree = new _StandardMerkleTree(data.tree, data.values, data.leafEncoding);
4051
- tree.validate();
4052
- return tree;
4053
- }
4054
4046
  static verify(root, leafEncoding, leaf, proof) {
4055
4047
  return toHex(root) === processProof(standardLeafHash(leafEncoding, leaf), proof);
4056
4048
  }
@@ -5808,23 +5800,10 @@ var vesu_rebalance_abi_default = [
5808
5800
  }
5809
5801
  ];
5810
5802
 
5811
- // src/strategies/base-strategy.ts
5812
- var BaseStrategy = class {
5813
- constructor(config) {
5803
+ // src/utils/cacheClass.ts
5804
+ var CacheClass = class {
5805
+ constructor() {
5814
5806
  this.cache = /* @__PURE__ */ new Map();
5815
- this.config = config;
5816
- }
5817
- async getUserTVL(user) {
5818
- throw new Error("Not implemented");
5819
- }
5820
- async getTVL() {
5821
- throw new Error("Not implemented");
5822
- }
5823
- async depositCall(amountInfo, receiver) {
5824
- throw new Error("Not implemented");
5825
- }
5826
- async withdrawCall(amountInfo, receiver, owner) {
5827
- throw new Error("Not implemented");
5828
5807
  }
5829
5808
  setCache(key, data, ttl = 6e4) {
5830
5809
  const timestamp = Date.now();
@@ -5845,6 +5824,27 @@ var BaseStrategy = class {
5845
5824
  }
5846
5825
  };
5847
5826
 
5827
+ // src/strategies/base-strategy.ts
5828
+ var BaseStrategy = class extends CacheClass {
5829
+ constructor(config) {
5830
+ super();
5831
+ this.cache = /* @__PURE__ */ new Map();
5832
+ this.config = config;
5833
+ }
5834
+ async getUserTVL(user) {
5835
+ throw new Error("Not implemented");
5836
+ }
5837
+ async getTVL() {
5838
+ throw new Error("Not implemented");
5839
+ }
5840
+ async depositCall(amountInfo, receiver) {
5841
+ throw new Error("Not implemented");
5842
+ }
5843
+ async withdrawCall(amountInfo, receiver, owner) {
5844
+ throw new Error("Not implemented");
5845
+ }
5846
+ };
5847
+
5848
5848
  // src/node/headless.browser.ts
5849
5849
  import axios5 from "axios";
5850
5850
  async function getAPIUsingHeadlessBrowser(url) {
@@ -20318,9 +20318,8 @@ var SenseiVault = class extends BaseStrategy {
20318
20318
  }
20319
20319
  async getPositionInfo() {
20320
20320
  const CACHE_KEY = "positionInfo";
20321
- if (this.isCacheValid(CACHE_KEY)) {
20322
- return this.getCache(CACHE_KEY);
20323
- }
20321
+ const existingCacheData = this.getCache(CACHE_KEY);
20322
+ if (existingCacheData) return existingCacheData;
20324
20323
  const resp = await fetch(
20325
20324
  `${getTrovesEndpoint()}/vesu/positions?walletAddress=${this.address.address}`
20326
20325
  );
@@ -20364,9 +20363,8 @@ var SenseiVault = class extends BaseStrategy {
20364
20363
  }
20365
20364
  async getSecondaryTokenPriceRelativeToMain(retry = 0) {
20366
20365
  const CACHE_KEY = "xSTRKPrice";
20367
- if (this.isCacheValid(CACHE_KEY)) {
20368
- return this.getCache(CACHE_KEY);
20369
- }
20366
+ const existingCacheData = this.getCache(CACHE_KEY);
20367
+ if (existingCacheData) return existingCacheData;
20370
20368
  const params = {
20371
20369
  sellTokenAddress: this.metadata.additionalInfo.secondaryToken.address.address,
20372
20370
  buyTokenAddress: this.metadata.additionalInfo.mainToken.address.address,
@@ -20520,7 +20518,7 @@ function toBigInt(value) {
20520
20518
  }
20521
20519
 
20522
20520
  // src/strategies/universal-adapters/baseAdapter.ts
20523
- var BaseAdapter = class {
20521
+ var BaseAdapter = class extends CacheClass {
20524
20522
  constructSimpleLeafData(params) {
20525
20523
  const { id, target, method, packedArguments } = params;
20526
20524
  return {
@@ -22895,7 +22893,6 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
22895
22893
  constructor(config) {
22896
22894
  super();
22897
22895
  this.VESU_SINGLETON = ContractAddr.from("0x000d8d6dfec4d33bfb6895de9f3852143a17c6f92fd2a21da3d6924d34870160");
22898
- this.cache = {};
22899
22896
  this.getModifyPosition = () => {
22900
22897
  const positionData = [0n];
22901
22898
  const packedArguments = [
@@ -22924,17 +22921,19 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
22924
22921
  denomination: this.formatAmountDenominationEnum(params.collateralAmount.denomination),
22925
22922
  value: {
22926
22923
  abs: uint2567.bnToUint256(params.collateralAmount.value.abs.toWei()),
22927
- is_negative: params.collateralAmount.value.is_negative
22924
+ is_negative: params.collateralAmount.value.abs.isZero() ? false : params.collateralAmount.value.is_negative
22928
22925
  }
22929
22926
  };
22927
+ logger.verbose(`VesuAdapter::ConstructingModify::Collateral::${JSON.stringify(_collateral)}`);
22930
22928
  const _debt = {
22931
22929
  amount_type: this.formatAmountTypeEnum(params.debtAmount.amount_type),
22932
22930
  denomination: this.formatAmountDenominationEnum(params.debtAmount.denomination),
22933
22931
  value: {
22934
22932
  abs: uint2567.bnToUint256(params.debtAmount.value.abs.toWei()),
22935
- is_negative: params.debtAmount.value.is_negative
22933
+ is_negative: params.debtAmount.value.abs.isZero() ? false : params.debtAmount.value.is_negative
22936
22934
  }
22937
22935
  };
22936
+ logger.verbose(`VesuAdapter::ConstructingModify::Debt::${JSON.stringify(_debt)}`);
22938
22937
  const singletonContract = new Contract8(vesu_singleton_abi_default, this.VESU_SINGLETON.toString(), new RpcProvider4({ nodeUrl: "" }));
22939
22938
  const call = singletonContract.populate("modify_position", {
22940
22939
  params: {
@@ -23003,20 +23002,22 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
23003
23002
  }
23004
23003
  async getLTVConfig(config) {
23005
23004
  const CACHE_KEY = "ltv_config";
23006
- if (this.cache[CACHE_KEY]) {
23007
- return this.cache[CACHE_KEY];
23005
+ const cacheData = this.getCache(CACHE_KEY);
23006
+ if (cacheData) {
23007
+ return cacheData;
23008
23008
  }
23009
23009
  const output2 = await this.getVesuSingletonContract(config).call("ltv_config", [this.config.poolId.address, this.config.collateral.address.address, this.config.debt.address.address]);
23010
- this.cache[CACHE_KEY] = Number(output2.max_ltv) / 1e18;
23011
- return this.cache[CACHE_KEY];
23010
+ this.setCache(CACHE_KEY, Number(output2.max_ltv) / 1e18, 3e5);
23011
+ return this.getCache(CACHE_KEY);
23012
23012
  }
23013
23013
  async getPositions(config) {
23014
23014
  if (!this.pricer) {
23015
23015
  throw new Error("Pricer is not initialized");
23016
23016
  }
23017
23017
  const CACHE_KEY = "positions";
23018
- if (this.cache[CACHE_KEY]) {
23019
- return this.cache[CACHE_KEY];
23018
+ const cacheData = this.getCache(CACHE_KEY);
23019
+ if (cacheData) {
23020
+ return cacheData;
23020
23021
  }
23021
23022
  const output2 = await this.getVesuSingletonContract(config).call("position_unsafe", [
23022
23023
  this.config.poolId.address,
@@ -23039,9 +23040,65 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
23039
23040
  usdValue: debtAmount.multipliedBy(token2Price.price).toNumber(),
23040
23041
  remarks: "Debt"
23041
23042
  }];
23042
- this.cache[CACHE_KEY] = value;
23043
+ this.setCache(CACHE_KEY, value, 6e4);
23044
+ return value;
23045
+ }
23046
+ async getCollateralization(config) {
23047
+ if (!this.pricer) {
23048
+ throw new Error("Pricer is not initialized");
23049
+ }
23050
+ const CACHE_KEY = "collateralization";
23051
+ const cacheData = this.getCache(CACHE_KEY);
23052
+ if (cacheData) {
23053
+ return cacheData;
23054
+ }
23055
+ const output2 = await this.getVesuSingletonContract(config).call("check_collateralization_unsafe", [
23056
+ this.config.poolId.address,
23057
+ this.config.collateral.address.address,
23058
+ this.config.debt.address.address,
23059
+ this.config.vaultAllocator.address
23060
+ ]);
23061
+ const collateralAmount = Web3Number.fromWei(output2["1"].toString(), 18);
23062
+ const debtAmount = Web3Number.fromWei(output2["2"].toString(), 18);
23063
+ const value = [{
23064
+ token: this.config.collateral,
23065
+ usdValue: collateralAmount.toNumber(),
23066
+ remarks: "Collateral"
23067
+ }, {
23068
+ token: this.config.debt,
23069
+ usdValue: debtAmount.toNumber(),
23070
+ remarks: "Debt"
23071
+ }];
23072
+ this.setCache(CACHE_KEY, value, 6e4);
23043
23073
  return value;
23044
23074
  }
23075
+ async getAssetPrices() {
23076
+ const collateralizationProm = this.getCollateralization(this.networkConfig);
23077
+ const positionsProm = this.getPositions(this.networkConfig);
23078
+ const ltvProm = this.getLTVConfig(this.networkConfig);
23079
+ const output2 = await Promise.all([collateralizationProm, positionsProm, ltvProm]);
23080
+ const [collateralization, positions, ltv] = output2;
23081
+ const collateralTokenAmount = positions[0].amount;
23082
+ const collateralUSDAmount = collateralization[0].usdValue;
23083
+ const collateralPrice = collateralUSDAmount / collateralTokenAmount.toNumber();
23084
+ const debtTokenAmount = positions[1].amount;
23085
+ const debtUSDAmount = collateralization[1].usdValue;
23086
+ const debtPrice = debtUSDAmount / debtTokenAmount.toNumber();
23087
+ return {
23088
+ collateralTokenAmount,
23089
+ collateralUSDAmount,
23090
+ collateralPrice,
23091
+ debtTokenAmount,
23092
+ debtUSDAmount,
23093
+ debtPrice,
23094
+ ltv
23095
+ };
23096
+ }
23097
+ async getHealthFactor() {
23098
+ const ltv = await this.getLTVConfig(this.networkConfig);
23099
+ const collateralisation = await this.getCollateralization(this.networkConfig);
23100
+ return collateralisation[0].usdValue * ltv / collateralisation[1].usdValue;
23101
+ }
23045
23102
  static async getVesuPools(retry = 0) {
23046
23103
  const CACHE_KEY = "VESU_POOLS";
23047
23104
  const cacheValue = Global.getGlobalCache(CACHE_KEY);
@@ -25413,19 +25470,32 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
25413
25470
  const debtAsset1 = pool1.assets.find((a) => a.symbol === vesuAdapter1.config.debt.symbol)?.stats;
25414
25471
  const collateralAsset2 = pool2.assets.find((a) => a.symbol === vesuAdapter2.config.collateral.symbol)?.stats;
25415
25472
  const debtAsset2 = pool2.assets.find((a) => a.symbol === vesuAdapter2.config.debt.symbol)?.stats;
25416
- const collateral1APY = Number(collateralAsset1.supplyApy.value) / 1e18 + Number(collateralAsset1.defiSpringSupplyApr.value) / 1e18;
25473
+ const collateral1APY = Number(collateralAsset1.supplyApy.value) / 1e18;
25417
25474
  const debt1APY = Number(debtAsset1.borrowApr.value) / 1e18;
25418
- const collateral2APY = Number(collateralAsset2.supplyApy.value) / 1e18 + Number(collateralAsset2.defiSpringSupplyApr.value) / 1e18;
25475
+ const collateral2APY = Number(collateralAsset2.supplyApy.value) / 1e18;
25419
25476
  const debt2APY = Number(debtAsset2.borrowApr.value) / 1e18;
25420
- const apys = [collateral1APY, debt1APY, collateral2APY, debt2APY];
25421
25477
  const positions = await this.getVaultPositions();
25422
- assert(positions.length == apys.length, "Positions and APYs length mismatch");
25423
- const weightedAPYs = positions.map((pos, i) => {
25424
- return pos.usdValue * apys[i] * (i % 2 == 0 ? 1 : -1);
25425
- });
25426
- const netPosition = positions.reduce((acc, val, index) => acc + val.usdValue * (index % 2 == 0 ? 1 : -1), 0);
25427
- const apy = weightedAPYs.reduce((acc, val) => acc + val, 0) / netPosition;
25428
- return apy;
25478
+ const weights = positions.map((p, index) => p.usdValue * (index % 2 == 0 ? 1 : -1));
25479
+ const baseAPYs = [collateral1APY, debt1APY, collateral2APY, debt2APY];
25480
+ assert(positions.length == baseAPYs.length, "Positions and APYs length mismatch");
25481
+ const rewardAPYs = [Number(collateralAsset1.defiSpringSupplyApr.value) / 1e18, 0, Number(collateralAsset2.defiSpringSupplyApr.value) / 1e18, 0];
25482
+ const baseAPY = this.computeAPY(baseAPYs, weights);
25483
+ const rewardAPY = this.computeAPY(rewardAPYs, weights);
25484
+ const apys = [...baseAPYs, ...rewardAPYs];
25485
+ const netAPY = baseAPY + rewardAPY;
25486
+ return { net: netAPY, splits: [{
25487
+ apy: baseAPY,
25488
+ id: "base"
25489
+ }, {
25490
+ apy: rewardAPY,
25491
+ id: "defispring"
25492
+ }] };
25493
+ }
25494
+ computeAPY(apys, weights) {
25495
+ assert(apys.length === weights.length, "APYs and weights length mismatch");
25496
+ const weightedSum = apys.reduce((acc, apy, i) => acc + apy * weights[i], 0);
25497
+ const totalWeight = weights.reduce((acc, weight) => acc + weight, 0);
25498
+ return weightedSum / totalWeight;
25429
25499
  }
25430
25500
  /**
25431
25501
  * Calculates the total TVL of the strategy.
@@ -25448,22 +25518,48 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
25448
25518
  };
25449
25519
  }
25450
25520
  async getAUM() {
25521
+ const currentAUM = await this.contract.call("aum", []);
25522
+ const lastReportTime = await this.contract.call("last_report_timestamp", []);
25523
+ const token1Price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
25451
25524
  const [vesuAdapter1, vesuAdapter2] = this.getVesuAdapters();
25452
25525
  const leg1AUM = await vesuAdapter1.getPositions(this.config);
25453
25526
  const leg2AUM = await vesuAdapter2.getPositions(this.config);
25454
- const token1Price = await this.pricer.getPrice(vesuAdapter1.config.collateral.symbol);
25455
25527
  const aumToken = leg1AUM[0].amount.plus(leg2AUM[0].usdValue / token1Price.price).minus(leg1AUM[1].usdValue / token1Price.price).minus(leg2AUM[1].amount);
25456
- return {
25528
+ logger.verbose(`${this.getTag()} Actual AUM: ${aumToken}`);
25529
+ const netAPY = await this.netAPY();
25530
+ const defispringAPY = netAPY.splits.find((s) => s.id === "defispring")?.apy || 0;
25531
+ if (!defispringAPY) throw new Error("DefiSpring APY not found");
25532
+ const timeDiff = Math.round(Date.now() / 1e3) - Number(lastReportTime);
25533
+ const growthRate = timeDiff * defispringAPY / (365 * 24 * 60 * 60);
25534
+ const prevAum = Web3Number.fromWei(currentAUM.toString(), this.asset().decimals);
25535
+ const rewardAssets = prevAum.multipliedBy(growthRate);
25536
+ logger.verbose(`${this.getTag()} DefiSpring AUM time difference: ${timeDiff}`);
25537
+ logger.verbose(`${this.getTag()} Current AUM: ${currentAUM}`);
25538
+ logger.verbose(`${this.getTag()} Net APY: ${JSON.stringify(netAPY)}`);
25539
+ logger.verbose(`${this.getTag()} rewards AUM: ${rewardAssets}`);
25540
+ const newAUM = aumToken.plus(rewardAssets);
25541
+ logger.verbose(`${this.getTag()} New AUM: ${newAUM}`);
25542
+ const net = {
25457
25543
  tokenInfo: this.asset(),
25458
- amount: aumToken,
25459
- usdValue: aumToken.multipliedBy(token1Price.price).toNumber()
25544
+ amount: newAUM,
25545
+ usdValue: newAUM.multipliedBy(token1Price.price).toNumber()
25460
25546
  };
25547
+ const splits = [{
25548
+ id: "finalised",
25549
+ aum: aumToken
25550
+ }, {
25551
+ id: "defispring",
25552
+ aum: rewardAssets
25553
+ }];
25554
+ return { net, splits, prevAum };
25461
25555
  }
25462
25556
  getVesuAdapters() {
25463
25557
  const vesuAdapter1 = this.getAdapter("vesu_leg1_adapter" /* VESU_LEG1 */);
25464
25558
  const vesuAdapter2 = this.getAdapter("vesu_leg2_adapter" /* VESU_LEG2 */);
25465
25559
  vesuAdapter1.pricer = this.pricer;
25466
25560
  vesuAdapter2.pricer = this.pricer;
25561
+ vesuAdapter1.networkConfig = this.config;
25562
+ vesuAdapter2.networkConfig = this.config;
25467
25563
  return [vesuAdapter1, vesuAdapter2];
25468
25564
  }
25469
25565
  async getVaultPositions() {
@@ -25505,12 +25601,14 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
25505
25601
  }));
25506
25602
  const output2 = [{
25507
25603
  proofs: manage5Info.proofs,
25508
- manageCall: manageCall5
25604
+ manageCall: manageCall5,
25605
+ step: STEP2_ID
25509
25606
  }];
25510
25607
  if (approveAmount.gt(0)) {
25511
25608
  output2.unshift({
25512
25609
  proofs: manage4Info.proofs,
25513
- manageCall: manageCall4
25610
+ manageCall: manageCall4,
25611
+ step: STEP1_ID
25514
25612
  });
25515
25613
  }
25516
25614
  return output2;
@@ -25518,9 +25616,96 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
25518
25616
  getTag() {
25519
25617
  return `${_UniversalStrategy.name}:${this.metadata.name}`;
25520
25618
  }
25619
+ async getVesuHealthFactors() {
25620
+ return await Promise.all(this.getVesuAdapters().map((v) => v.getHealthFactor()));
25621
+ }
25622
+ async computeRebalanceConditionAndReturnCalls() {
25623
+ const vesuAdapters = this.getVesuAdapters();
25624
+ const healthFactors = await this.getVesuHealthFactors();
25625
+ const leg1HealthFactor = healthFactors[0];
25626
+ const leg2HealthFactor = healthFactors[1];
25627
+ logger.verbose(`${this.getTag()}: HealthFactorLeg1: ${leg1HealthFactor}`);
25628
+ logger.verbose(`${this.getTag()}: HealthFactorLeg2: ${leg2HealthFactor}`);
25629
+ const minHf = this.metadata.additionalInfo.minHealthFactor;
25630
+ const isRebalanceNeeded1 = leg1HealthFactor < minHf;
25631
+ const isRebalanceNeeded2 = leg2HealthFactor < minHf;
25632
+ if (!isRebalanceNeeded1 && !isRebalanceNeeded2) {
25633
+ return [];
25634
+ }
25635
+ if (isRebalanceNeeded1) {
25636
+ const amount = await this.getLegRebalanceAmount(vesuAdapters[0], leg1HealthFactor, false);
25637
+ const leg2HF = await this.getNewHealthFactor(vesuAdapters[1], amount, true);
25638
+ assert(leg2HF > minHf, `Rebalance Leg1 failed: Leg2 HF after rebalance would be too low: ${leg2HF}`);
25639
+ return [await this.getRebalanceCall({
25640
+ isLeg1toLeg2: false,
25641
+ amount
25642
+ })];
25643
+ } else {
25644
+ const amount = await this.getLegRebalanceAmount(vesuAdapters[1], leg2HealthFactor, true);
25645
+ const leg1HF = await this.getNewHealthFactor(vesuAdapters[0], amount, false);
25646
+ assert(leg1HF > minHf, `Rebalance Leg2 failed: Leg1 HF after rebalance would be too low: ${leg1HF}`);
25647
+ return [await this.getRebalanceCall({
25648
+ isLeg1toLeg2: true,
25649
+ amount
25650
+ })];
25651
+ }
25652
+ }
25653
+ async getNewHealthFactor(vesuAdapter, newAmount, isWithdraw) {
25654
+ const {
25655
+ collateralTokenAmount,
25656
+ collateralUSDAmount,
25657
+ collateralPrice,
25658
+ debtTokenAmount,
25659
+ debtUSDAmount,
25660
+ debtPrice,
25661
+ ltv
25662
+ } = await vesuAdapter.getAssetPrices();
25663
+ if (isWithdraw) {
25664
+ const newHF = (collateralTokenAmount.toNumber() - newAmount.toNumber()) * collateralPrice * ltv / debtUSDAmount;
25665
+ logger.verbose(`getNewHealthFactor:: HF: ${newHF}, amoutn: ${newAmount.toNumber()}, isDeposit`);
25666
+ return newHF;
25667
+ } else {
25668
+ const newHF = collateralUSDAmount * ltv / ((debtTokenAmount.toNumber() + newAmount.toNumber()) * debtPrice);
25669
+ logger.verbose(`getNewHealthFactor:: HF: ${newHF}, amoutn: ${newAmount.toNumber()}, isRepay`);
25670
+ return newHF;
25671
+ }
25672
+ }
25673
+ /**
25674
+ *
25675
+ * @param vesuAdapter
25676
+ * @param currentHf
25677
+ * @param isDeposit if true, attempt by adding collateral, else by repaying
25678
+ * @returns
25679
+ */
25680
+ async getLegRebalanceAmount(vesuAdapter, currentHf, isDeposit) {
25681
+ const {
25682
+ collateralTokenAmount,
25683
+ collateralUSDAmount,
25684
+ collateralPrice,
25685
+ debtTokenAmount,
25686
+ debtUSDAmount,
25687
+ debtPrice,
25688
+ ltv
25689
+ } = await vesuAdapter.getAssetPrices();
25690
+ if (debtTokenAmount.isZero()) {
25691
+ return Web3Number.fromWei(0, 0);
25692
+ }
25693
+ assert(collateralPrice > 0 && debtPrice > 0, "getRebalanceAmount: Invalid price");
25694
+ const targetHF = this.metadata.additionalInfo.targetHealthFactor;
25695
+ if (currentHf > targetHF - 0.01)
25696
+ throw new Error("getLegRebalanceAmount: Current health factor is healthy");
25697
+ if (isDeposit) {
25698
+ const newAmount = targetHF * debtUSDAmount / (collateralPrice * ltv) - collateralTokenAmount.toNumber();
25699
+ logger.verbose(`${this.getTag()}:: getLegRebalanceAmount: addCollateral, currentHf: ${currentHf}, targetHF: ${targetHF}, collAmount: ${collateralTokenAmount.toString()}, collUSD: ${collateralUSDAmount}, collPrice: ${collateralPrice}, debtAmount: ${debtTokenAmount.toString()}, debtUSD: ${debtUSDAmount}, debtPrice: ${debtPrice}, ltv: ${ltv}, newAmount: ${newAmount}`);
25700
+ return new Web3Number(newAmount.toFixed(8), collateralTokenAmount.decimals);
25701
+ } else {
25702
+ const newAmount = debtTokenAmount.toNumber() - collateralUSDAmount * ltv / (targetHF * debtPrice);
25703
+ logger.verbose(`${this.getTag()}:: getLegRebalanceAmount: repayDebt, currentHf: ${currentHf}, targetHF: ${targetHF}, collAmount: ${collateralTokenAmount.toString()}, collUSD: ${collateralUSDAmount}, collPrice: ${collateralPrice}, debtAmount: ${debtTokenAmount.toString()}, debtUSD: ${debtUSDAmount}, debtPrice: ${debtPrice}, ltv: ${ltv}, newAmount: ${newAmount}`);
25704
+ return new Web3Number(newAmount.toFixed(8), debtTokenAmount.decimals);
25705
+ }
25706
+ }
25521
25707
  async getVesuMultiplyCall(params) {
25522
- const vesuAdapter1 = this.getAdapter("vesu_leg1_adapter" /* VESU_LEG1 */);
25523
- const vesuAdapter2 = this.getAdapter("vesu_leg2_adapter" /* VESU_LEG2 */);
25708
+ const [vesuAdapter1, vesuAdapter2] = this.getVesuAdapters();
25524
25709
  const leg1LTV = await vesuAdapter1.getLTVConfig(this.config);
25525
25710
  const leg2LTV = await vesuAdapter2.getLTVConfig(this.config);
25526
25711
  logger.verbose(`${this.getTag()}: LTVLeg1: ${leg1LTV}`);
@@ -25529,7 +25714,7 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
25529
25714
  const token2Price = await this.pricer.getPrice(vesuAdapter2.config.collateral.symbol);
25530
25715
  logger.verbose(`${this.getTag()}: Price${vesuAdapter1.config.collateral.symbol}: ${token1Price.price}`);
25531
25716
  logger.verbose(`${this.getTag()}: Price${vesuAdapter2.config.collateral.symbol}: ${token2Price.price}`);
25532
- const TARGET_HF = 1.3;
25717
+ const TARGET_HF = this.metadata.additionalInfo.targetHealthFactor;
25533
25718
  const k1 = token1Price.price * leg1LTV / token2Price.price / TARGET_HF;
25534
25719
  const k2 = token1Price.price * TARGET_HF / token2Price.price / leg2LTV;
25535
25720
  const borrow2Amount = new Web3Number(
@@ -25587,14 +25772,14 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
25587
25772
  });
25588
25773
  if (params.isLeg1toLeg2) {
25589
25774
  const manageCall = this.getManageCall([
25590
- "vesu_leg1" /* VESU_LEG1 */,
25591
- "vesu_leg2" /* VESU_LEG2 */
25775
+ ...callSet1.map((i) => i.step),
25776
+ ...callSet2.map((i) => i.step)
25592
25777
  ], [...callSet1.map((i) => i.manageCall), ...callSet2.map((i) => i.manageCall)]);
25593
25778
  return manageCall;
25594
25779
  } else {
25595
25780
  const manageCall = this.getManageCall([
25596
- "vesu_leg2" /* VESU_LEG2 */,
25597
- "vesu_leg1" /* VESU_LEG1 */
25781
+ ...callSet2.map((i) => i.step),
25782
+ ...callSet1.map((i) => i.step)
25598
25783
  ], [...callSet2.map((i) => i.manageCall), ...callSet1.map((i) => i.manageCall)]);
25599
25784
  return manageCall;
25600
25785
  }
@@ -25662,14 +25847,18 @@ var usdcVaultSettings = {
25662
25847
  vaultAllocator: ContractAddr.from("0x228cca1005d3f2b55cbaba27cb291dacf1b9a92d1d6b1638195fbd3d0c1e3ba"),
25663
25848
  redeemRequestNFT: ContractAddr.from("0x906d03590010868cbf7590ad47043959d7af8e782089a605d9b22567b64fda"),
25664
25849
  leafAdapters: [],
25665
- adapters: []
25850
+ adapters: [],
25851
+ targetHealthFactor: 1.3,
25852
+ minHealthFactor: 1.25
25666
25853
  };
25667
25854
  var wbtcVaultSettings = {
25668
25855
  manager: ContractAddr.from("0xef8a664ffcfe46a6af550766d27c28937bf1b77fb4ab54d8553e92bca5ba34"),
25669
25856
  vaultAllocator: ContractAddr.from("0x1e01c25f0d9494570226ad28a7fa856c0640505e809c366a9fab4903320e735"),
25670
25857
  redeemRequestNFT: ContractAddr.from("0x4fec59a12f8424281c1e65a80b5de51b4e754625c60cddfcd00d46941ec37b2"),
25671
25858
  leafAdapters: [],
25672
- adapters: []
25859
+ adapters: [],
25860
+ targetHealthFactor: 1.3,
25861
+ minHealthFactor: 1.25
25673
25862
  };
25674
25863
  var UniversalStrategies = [
25675
25864
  {
@@ -25719,13 +25908,10 @@ var TelegramNotif = class {
25719
25908
  this.subscribers = [
25720
25909
  // '6820228303',
25721
25910
  "1505578076",
25722
- // '5434736198', // maaza
25723
25911
  "1356705582",
25724
25912
  // langs
25725
25913
  "1388729514",
25726
25914
  // hwashere
25727
- "6020162572",
25728
- //minato
25729
25915
  "985902592"
25730
25916
  ];
25731
25917
  this.bot = new TelegramBot(token, { polling: shouldPoll });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strkfarm/sdk",
3
- "version": "1.0.56",
3
+ "version": "1.0.57",
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,10 +5,8 @@ export class TelegramNotif {
5
5
  private subscribers: string[] = [
6
6
  // '6820228303',
7
7
  '1505578076',
8
- // '5434736198', // maaza
9
8
  '1356705582', // langs
10
9
  '1388729514', // hwashere
11
- '6020162572', //minato
12
10
  '985902592'
13
11
  ];
14
12
  readonly bot: TelegramBot;
@@ -1,5 +1,6 @@
1
1
  import { ContractAddr, Web3Number } from "@/dataTypes";
2
2
  import { IConfig, TokenInfo } from "@/interfaces";
3
+ import { CacheClass } from "@/utils/cacheClass";
3
4
  import { Call } from "starknet";
4
5
 
5
6
  export interface SingleActionAmount {
@@ -26,11 +27,12 @@ interface CacheData {
26
27
  ttl: number;
27
28
  data: any;
28
29
  }
29
- export class BaseStrategy<TVLInfo, ActionInfo> {
30
+ export class BaseStrategy<TVLInfo, ActionInfo> extends CacheClass {
30
31
  readonly config: IConfig;
31
32
  readonly cache: Map<string, CacheData> = new Map();
32
33
 
33
34
  constructor(config: IConfig) {
35
+ super();
34
36
  this.config = config;
35
37
  }
36
38
 
@@ -49,26 +51,4 @@ export class BaseStrategy<TVLInfo, ActionInfo> {
49
51
  async withdrawCall(amountInfo: ActionInfo, receiver: ContractAddr, owner: ContractAddr): Promise<Call[]> {
50
52
  throw new Error("Not implemented");
51
53
  }
52
-
53
- setCache(key: string, data: any, ttl: number = 60000): void {
54
- const timestamp = Date.now();
55
- this.cache.set(key, { timestamp, ttl, data });
56
- }
57
-
58
- getCache(key: string): any | null {
59
- const cachedData = this.cache.get(key);
60
- if (!cachedData || !this.isCacheValid(key)) {
61
- return null;
62
- }
63
- return cachedData.data;
64
- }
65
-
66
- isCacheValid(key: string): boolean {
67
- const cachedData = this.cache.get(key);
68
- if (!cachedData) return false;
69
-
70
- const { timestamp, ttl } = cachedData;
71
- return Date.now() - timestamp <= ttl;
72
- }
73
-
74
54
  }
@@ -126,9 +126,16 @@ export class SenseiVault extends BaseStrategy<
126
126
  collateralInSTRK: number;
127
127
  }> {
128
128
  const CACHE_KEY = 'positionInfo';
129
- if (this.isCacheValid(CACHE_KEY)) {
130
- return this.getCache(CACHE_KEY);
131
- }
129
+ const existingCacheData = this.getCache<{
130
+ collateralXSTRK: Web3Number;
131
+ collateralUSDValue: Web3Number;
132
+ debtSTRK: Web3Number;
133
+ debtUSDValue: Web3Number;
134
+ xSTRKPrice: number;
135
+ collateralInSTRK: number;
136
+ }>(CACHE_KEY);
137
+ if (existingCacheData) return existingCacheData;
138
+
132
139
  const resp = await fetch(
133
140
  `${getTrovesEndpoint()}/vesu/positions?walletAddress=${this.address.address}`,
134
141
  );
@@ -179,9 +186,9 @@ export class SenseiVault extends BaseStrategy<
179
186
 
180
187
  async getSecondaryTokenPriceRelativeToMain(retry = 0): Promise<number> {
181
188
  const CACHE_KEY = 'xSTRKPrice';
182
- if (this.isCacheValid(CACHE_KEY)) {
183
- return this.getCache(CACHE_KEY);
184
- }
189
+ const existingCacheData = this.getCache<number>(CACHE_KEY);
190
+ if (existingCacheData) return existingCacheData;
191
+
185
192
  const params: QuoteRequest = {
186
193
  sellTokenAddress: this.metadata.additionalInfo.secondaryToken.address.address,
187
194
  buyTokenAddress: this.metadata.additionalInfo.mainToken.address.address,
@@ -2,6 +2,7 @@ import { Call, hash, num, shortString } from "starknet";
2
2
  import { SIMPLE_SANITIZER, toBigInt } from "./adapter-utils";
3
3
  import { ContractAddr } from "@/dataTypes";
4
4
  import { LeafData } from "@/utils";
5
+ import { CacheClass } from "@/utils/cacheClass";
5
6
 
6
7
  export interface ManageCall {
7
8
  sanitizer: ContractAddr,
@@ -16,7 +17,7 @@ export type GenerateCallFn<T> = (params: T) => ManageCall;
16
17
  export type AdapterLeafType<T> = {leaf: LeafData, callConstructor: GenerateCallFn<T>}
17
18
  export type LeafAdapterFn<T> = () => AdapterLeafType<T>;
18
19
 
19
- export class BaseAdapter {
20
+ export class BaseAdapter extends CacheClass {
20
21
 
21
22
  protected constructSimpleLeafData(params: {
22
23
  id: string,