@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.
@@ -1937,7 +1937,6 @@ import { toHex } from "@ericnordelo/strk-merkle-tree/dist/bytes";
1937
1937
  import { processMultiProof, processProof } from "@ericnordelo/strk-merkle-tree/dist/core";
1938
1938
  import { standardLeafHash } from "@ericnordelo/strk-merkle-tree/dist/hashes";
1939
1939
  import { MerkleTreeImpl } from "@ericnordelo/strk-merkle-tree/dist/merkletree";
1940
- import { validateArgument } from "@ericnordelo/strk-merkle-tree/src/utils/errors";
1941
1940
  import { num as num2 } from "starknet";
1942
1941
 
1943
1942
  // ../node_modules/@noble/hashes/esm/_assert.js
@@ -3994,13 +3993,6 @@ var StandardMerkleTree = class _StandardMerkleTree extends MerkleTreeImpl {
3994
3993
  });
3995
3994
  return new _StandardMerkleTree(tree, indexedValues, leafEncoding);
3996
3995
  }
3997
- static load(data) {
3998
- validateArgument(data.format === "standard-v1", `Unknown format '${data.format}'`);
3999
- validateArgument(data.leafEncoding !== void 0, "Expected leaf encoding");
4000
- const tree = new _StandardMerkleTree(data.tree, data.values, data.leafEncoding);
4001
- tree.validate();
4002
- return tree;
4003
- }
4004
3996
  static verify(root, leafEncoding, leaf, proof) {
4005
3997
  return toHex(root) === processProof(standardLeafHash(leafEncoding, leaf), proof);
4006
3998
  }
@@ -5758,23 +5750,10 @@ var vesu_rebalance_abi_default = [
5758
5750
  }
5759
5751
  ];
5760
5752
 
5761
- // src/strategies/base-strategy.ts
5762
- var BaseStrategy = class {
5763
- constructor(config) {
5753
+ // src/utils/cacheClass.ts
5754
+ var CacheClass = class {
5755
+ constructor() {
5764
5756
  this.cache = /* @__PURE__ */ new Map();
5765
- this.config = config;
5766
- }
5767
- async getUserTVL(user) {
5768
- throw new Error("Not implemented");
5769
- }
5770
- async getTVL() {
5771
- throw new Error("Not implemented");
5772
- }
5773
- async depositCall(amountInfo, receiver) {
5774
- throw new Error("Not implemented");
5775
- }
5776
- async withdrawCall(amountInfo, receiver, owner) {
5777
- throw new Error("Not implemented");
5778
5757
  }
5779
5758
  setCache(key, data, ttl = 6e4) {
5780
5759
  const timestamp = Date.now();
@@ -5795,6 +5774,27 @@ var BaseStrategy = class {
5795
5774
  }
5796
5775
  };
5797
5776
 
5777
+ // src/strategies/base-strategy.ts
5778
+ var BaseStrategy = class extends CacheClass {
5779
+ constructor(config) {
5780
+ super();
5781
+ this.cache = /* @__PURE__ */ new Map();
5782
+ this.config = config;
5783
+ }
5784
+ async getUserTVL(user) {
5785
+ throw new Error("Not implemented");
5786
+ }
5787
+ async getTVL() {
5788
+ throw new Error("Not implemented");
5789
+ }
5790
+ async depositCall(amountInfo, receiver) {
5791
+ throw new Error("Not implemented");
5792
+ }
5793
+ async withdrawCall(amountInfo, receiver, owner) {
5794
+ throw new Error("Not implemented");
5795
+ }
5796
+ };
5797
+
5798
5798
  // src/node/headless.browser.ts
5799
5799
  import axios5 from "axios";
5800
5800
  async function getAPIUsingHeadlessBrowser(url) {
@@ -20268,9 +20268,8 @@ var SenseiVault = class extends BaseStrategy {
20268
20268
  }
20269
20269
  async getPositionInfo() {
20270
20270
  const CACHE_KEY = "positionInfo";
20271
- if (this.isCacheValid(CACHE_KEY)) {
20272
- return this.getCache(CACHE_KEY);
20273
- }
20271
+ const existingCacheData = this.getCache(CACHE_KEY);
20272
+ if (existingCacheData) return existingCacheData;
20274
20273
  const resp = await fetch(
20275
20274
  `${getTrovesEndpoint()}/vesu/positions?walletAddress=${this.address.address}`
20276
20275
  );
@@ -20314,9 +20313,8 @@ var SenseiVault = class extends BaseStrategy {
20314
20313
  }
20315
20314
  async getSecondaryTokenPriceRelativeToMain(retry = 0) {
20316
20315
  const CACHE_KEY = "xSTRKPrice";
20317
- if (this.isCacheValid(CACHE_KEY)) {
20318
- return this.getCache(CACHE_KEY);
20319
- }
20316
+ const existingCacheData = this.getCache(CACHE_KEY);
20317
+ if (existingCacheData) return existingCacheData;
20320
20318
  const params = {
20321
20319
  sellTokenAddress: this.metadata.additionalInfo.secondaryToken.address.address,
20322
20320
  buyTokenAddress: this.metadata.additionalInfo.mainToken.address.address,
@@ -20470,7 +20468,7 @@ function toBigInt(value) {
20470
20468
  }
20471
20469
 
20472
20470
  // src/strategies/universal-adapters/baseAdapter.ts
20473
- var BaseAdapter = class {
20471
+ var BaseAdapter = class extends CacheClass {
20474
20472
  constructSimpleLeafData(params) {
20475
20473
  const { id, target, method, packedArguments } = params;
20476
20474
  return {
@@ -22845,7 +22843,6 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
22845
22843
  constructor(config) {
22846
22844
  super();
22847
22845
  this.VESU_SINGLETON = ContractAddr.from("0x000d8d6dfec4d33bfb6895de9f3852143a17c6f92fd2a21da3d6924d34870160");
22848
- this.cache = {};
22849
22846
  this.getModifyPosition = () => {
22850
22847
  const positionData = [0n];
22851
22848
  const packedArguments = [
@@ -22874,17 +22871,19 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
22874
22871
  denomination: this.formatAmountDenominationEnum(params.collateralAmount.denomination),
22875
22872
  value: {
22876
22873
  abs: uint2567.bnToUint256(params.collateralAmount.value.abs.toWei()),
22877
- is_negative: params.collateralAmount.value.is_negative
22874
+ is_negative: params.collateralAmount.value.abs.isZero() ? false : params.collateralAmount.value.is_negative
22878
22875
  }
22879
22876
  };
22877
+ logger.verbose(`VesuAdapter::ConstructingModify::Collateral::${JSON.stringify(_collateral)}`);
22880
22878
  const _debt = {
22881
22879
  amount_type: this.formatAmountTypeEnum(params.debtAmount.amount_type),
22882
22880
  denomination: this.formatAmountDenominationEnum(params.debtAmount.denomination),
22883
22881
  value: {
22884
22882
  abs: uint2567.bnToUint256(params.debtAmount.value.abs.toWei()),
22885
- is_negative: params.debtAmount.value.is_negative
22883
+ is_negative: params.debtAmount.value.abs.isZero() ? false : params.debtAmount.value.is_negative
22886
22884
  }
22887
22885
  };
22886
+ logger.verbose(`VesuAdapter::ConstructingModify::Debt::${JSON.stringify(_debt)}`);
22888
22887
  const singletonContract = new Contract8(vesu_singleton_abi_default, this.VESU_SINGLETON.toString(), new RpcProvider4({ nodeUrl: "" }));
22889
22888
  const call = singletonContract.populate("modify_position", {
22890
22889
  params: {
@@ -22953,20 +22952,22 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
22953
22952
  }
22954
22953
  async getLTVConfig(config) {
22955
22954
  const CACHE_KEY = "ltv_config";
22956
- if (this.cache[CACHE_KEY]) {
22957
- return this.cache[CACHE_KEY];
22955
+ const cacheData = this.getCache(CACHE_KEY);
22956
+ if (cacheData) {
22957
+ return cacheData;
22958
22958
  }
22959
22959
  const output2 = await this.getVesuSingletonContract(config).call("ltv_config", [this.config.poolId.address, this.config.collateral.address.address, this.config.debt.address.address]);
22960
- this.cache[CACHE_KEY] = Number(output2.max_ltv) / 1e18;
22961
- return this.cache[CACHE_KEY];
22960
+ this.setCache(CACHE_KEY, Number(output2.max_ltv) / 1e18, 3e5);
22961
+ return this.getCache(CACHE_KEY);
22962
22962
  }
22963
22963
  async getPositions(config) {
22964
22964
  if (!this.pricer) {
22965
22965
  throw new Error("Pricer is not initialized");
22966
22966
  }
22967
22967
  const CACHE_KEY = "positions";
22968
- if (this.cache[CACHE_KEY]) {
22969
- return this.cache[CACHE_KEY];
22968
+ const cacheData = this.getCache(CACHE_KEY);
22969
+ if (cacheData) {
22970
+ return cacheData;
22970
22971
  }
22971
22972
  const output2 = await this.getVesuSingletonContract(config).call("position_unsafe", [
22972
22973
  this.config.poolId.address,
@@ -22989,9 +22990,65 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
22989
22990
  usdValue: debtAmount.multipliedBy(token2Price.price).toNumber(),
22990
22991
  remarks: "Debt"
22991
22992
  }];
22992
- this.cache[CACHE_KEY] = value;
22993
+ this.setCache(CACHE_KEY, value, 6e4);
22994
+ return value;
22995
+ }
22996
+ async getCollateralization(config) {
22997
+ if (!this.pricer) {
22998
+ throw new Error("Pricer is not initialized");
22999
+ }
23000
+ const CACHE_KEY = "collateralization";
23001
+ const cacheData = this.getCache(CACHE_KEY);
23002
+ if (cacheData) {
23003
+ return cacheData;
23004
+ }
23005
+ const output2 = await this.getVesuSingletonContract(config).call("check_collateralization_unsafe", [
23006
+ this.config.poolId.address,
23007
+ this.config.collateral.address.address,
23008
+ this.config.debt.address.address,
23009
+ this.config.vaultAllocator.address
23010
+ ]);
23011
+ const collateralAmount = Web3Number.fromWei(output2["1"].toString(), 18);
23012
+ const debtAmount = Web3Number.fromWei(output2["2"].toString(), 18);
23013
+ const value = [{
23014
+ token: this.config.collateral,
23015
+ usdValue: collateralAmount.toNumber(),
23016
+ remarks: "Collateral"
23017
+ }, {
23018
+ token: this.config.debt,
23019
+ usdValue: debtAmount.toNumber(),
23020
+ remarks: "Debt"
23021
+ }];
23022
+ this.setCache(CACHE_KEY, value, 6e4);
22993
23023
  return value;
22994
23024
  }
23025
+ async getAssetPrices() {
23026
+ const collateralizationProm = this.getCollateralization(this.networkConfig);
23027
+ const positionsProm = this.getPositions(this.networkConfig);
23028
+ const ltvProm = this.getLTVConfig(this.networkConfig);
23029
+ const output2 = await Promise.all([collateralizationProm, positionsProm, ltvProm]);
23030
+ const [collateralization, positions, ltv] = output2;
23031
+ const collateralTokenAmount = positions[0].amount;
23032
+ const collateralUSDAmount = collateralization[0].usdValue;
23033
+ const collateralPrice = collateralUSDAmount / collateralTokenAmount.toNumber();
23034
+ const debtTokenAmount = positions[1].amount;
23035
+ const debtUSDAmount = collateralization[1].usdValue;
23036
+ const debtPrice = debtUSDAmount / debtTokenAmount.toNumber();
23037
+ return {
23038
+ collateralTokenAmount,
23039
+ collateralUSDAmount,
23040
+ collateralPrice,
23041
+ debtTokenAmount,
23042
+ debtUSDAmount,
23043
+ debtPrice,
23044
+ ltv
23045
+ };
23046
+ }
23047
+ async getHealthFactor() {
23048
+ const ltv = await this.getLTVConfig(this.networkConfig);
23049
+ const collateralisation = await this.getCollateralization(this.networkConfig);
23050
+ return collateralisation[0].usdValue * ltv / collateralisation[1].usdValue;
23051
+ }
22995
23052
  static async getVesuPools(retry = 0) {
22996
23053
  const CACHE_KEY = "VESU_POOLS";
22997
23054
  const cacheValue = Global.getGlobalCache(CACHE_KEY);
@@ -25363,19 +25420,32 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
25363
25420
  const debtAsset1 = pool1.assets.find((a) => a.symbol === vesuAdapter1.config.debt.symbol)?.stats;
25364
25421
  const collateralAsset2 = pool2.assets.find((a) => a.symbol === vesuAdapter2.config.collateral.symbol)?.stats;
25365
25422
  const debtAsset2 = pool2.assets.find((a) => a.symbol === vesuAdapter2.config.debt.symbol)?.stats;
25366
- const collateral1APY = Number(collateralAsset1.supplyApy.value) / 1e18 + Number(collateralAsset1.defiSpringSupplyApr.value) / 1e18;
25423
+ const collateral1APY = Number(collateralAsset1.supplyApy.value) / 1e18;
25367
25424
  const debt1APY = Number(debtAsset1.borrowApr.value) / 1e18;
25368
- const collateral2APY = Number(collateralAsset2.supplyApy.value) / 1e18 + Number(collateralAsset2.defiSpringSupplyApr.value) / 1e18;
25425
+ const collateral2APY = Number(collateralAsset2.supplyApy.value) / 1e18;
25369
25426
  const debt2APY = Number(debtAsset2.borrowApr.value) / 1e18;
25370
- const apys = [collateral1APY, debt1APY, collateral2APY, debt2APY];
25371
25427
  const positions = await this.getVaultPositions();
25372
- assert(positions.length == apys.length, "Positions and APYs length mismatch");
25373
- const weightedAPYs = positions.map((pos, i) => {
25374
- return pos.usdValue * apys[i] * (i % 2 == 0 ? 1 : -1);
25375
- });
25376
- const netPosition = positions.reduce((acc, val, index) => acc + val.usdValue * (index % 2 == 0 ? 1 : -1), 0);
25377
- const apy = weightedAPYs.reduce((acc, val) => acc + val, 0) / netPosition;
25378
- return apy;
25428
+ const weights = positions.map((p, index) => p.usdValue * (index % 2 == 0 ? 1 : -1));
25429
+ const baseAPYs = [collateral1APY, debt1APY, collateral2APY, debt2APY];
25430
+ assert(positions.length == baseAPYs.length, "Positions and APYs length mismatch");
25431
+ const rewardAPYs = [Number(collateralAsset1.defiSpringSupplyApr.value) / 1e18, 0, Number(collateralAsset2.defiSpringSupplyApr.value) / 1e18, 0];
25432
+ const baseAPY = this.computeAPY(baseAPYs, weights);
25433
+ const rewardAPY = this.computeAPY(rewardAPYs, weights);
25434
+ const apys = [...baseAPYs, ...rewardAPYs];
25435
+ const netAPY = baseAPY + rewardAPY;
25436
+ return { net: netAPY, splits: [{
25437
+ apy: baseAPY,
25438
+ id: "base"
25439
+ }, {
25440
+ apy: rewardAPY,
25441
+ id: "defispring"
25442
+ }] };
25443
+ }
25444
+ computeAPY(apys, weights) {
25445
+ assert(apys.length === weights.length, "APYs and weights length mismatch");
25446
+ const weightedSum = apys.reduce((acc, apy, i) => acc + apy * weights[i], 0);
25447
+ const totalWeight = weights.reduce((acc, weight) => acc + weight, 0);
25448
+ return weightedSum / totalWeight;
25379
25449
  }
25380
25450
  /**
25381
25451
  * Calculates the total TVL of the strategy.
@@ -25398,22 +25468,48 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
25398
25468
  };
25399
25469
  }
25400
25470
  async getAUM() {
25471
+ const currentAUM = await this.contract.call("aum", []);
25472
+ const lastReportTime = await this.contract.call("last_report_timestamp", []);
25473
+ const token1Price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
25401
25474
  const [vesuAdapter1, vesuAdapter2] = this.getVesuAdapters();
25402
25475
  const leg1AUM = await vesuAdapter1.getPositions(this.config);
25403
25476
  const leg2AUM = await vesuAdapter2.getPositions(this.config);
25404
- const token1Price = await this.pricer.getPrice(vesuAdapter1.config.collateral.symbol);
25405
25477
  const aumToken = leg1AUM[0].amount.plus(leg2AUM[0].usdValue / token1Price.price).minus(leg1AUM[1].usdValue / token1Price.price).minus(leg2AUM[1].amount);
25406
- return {
25478
+ logger.verbose(`${this.getTag()} Actual AUM: ${aumToken}`);
25479
+ const netAPY = await this.netAPY();
25480
+ const defispringAPY = netAPY.splits.find((s) => s.id === "defispring")?.apy || 0;
25481
+ if (!defispringAPY) throw new Error("DefiSpring APY not found");
25482
+ const timeDiff = Math.round(Date.now() / 1e3) - Number(lastReportTime);
25483
+ const growthRate = timeDiff * defispringAPY / (365 * 24 * 60 * 60);
25484
+ const prevAum = Web3Number.fromWei(currentAUM.toString(), this.asset().decimals);
25485
+ const rewardAssets = prevAum.multipliedBy(growthRate);
25486
+ logger.verbose(`${this.getTag()} DefiSpring AUM time difference: ${timeDiff}`);
25487
+ logger.verbose(`${this.getTag()} Current AUM: ${currentAUM}`);
25488
+ logger.verbose(`${this.getTag()} Net APY: ${JSON.stringify(netAPY)}`);
25489
+ logger.verbose(`${this.getTag()} rewards AUM: ${rewardAssets}`);
25490
+ const newAUM = aumToken.plus(rewardAssets);
25491
+ logger.verbose(`${this.getTag()} New AUM: ${newAUM}`);
25492
+ const net = {
25407
25493
  tokenInfo: this.asset(),
25408
- amount: aumToken,
25409
- usdValue: aumToken.multipliedBy(token1Price.price).toNumber()
25494
+ amount: newAUM,
25495
+ usdValue: newAUM.multipliedBy(token1Price.price).toNumber()
25410
25496
  };
25497
+ const splits = [{
25498
+ id: "finalised",
25499
+ aum: aumToken
25500
+ }, {
25501
+ id: "defispring",
25502
+ aum: rewardAssets
25503
+ }];
25504
+ return { net, splits, prevAum };
25411
25505
  }
25412
25506
  getVesuAdapters() {
25413
25507
  const vesuAdapter1 = this.getAdapter("vesu_leg1_adapter" /* VESU_LEG1 */);
25414
25508
  const vesuAdapter2 = this.getAdapter("vesu_leg2_adapter" /* VESU_LEG2 */);
25415
25509
  vesuAdapter1.pricer = this.pricer;
25416
25510
  vesuAdapter2.pricer = this.pricer;
25511
+ vesuAdapter1.networkConfig = this.config;
25512
+ vesuAdapter2.networkConfig = this.config;
25417
25513
  return [vesuAdapter1, vesuAdapter2];
25418
25514
  }
25419
25515
  async getVaultPositions() {
@@ -25455,12 +25551,14 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
25455
25551
  }));
25456
25552
  const output2 = [{
25457
25553
  proofs: manage5Info.proofs,
25458
- manageCall: manageCall5
25554
+ manageCall: manageCall5,
25555
+ step: STEP2_ID
25459
25556
  }];
25460
25557
  if (approveAmount.gt(0)) {
25461
25558
  output2.unshift({
25462
25559
  proofs: manage4Info.proofs,
25463
- manageCall: manageCall4
25560
+ manageCall: manageCall4,
25561
+ step: STEP1_ID
25464
25562
  });
25465
25563
  }
25466
25564
  return output2;
@@ -25468,9 +25566,96 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
25468
25566
  getTag() {
25469
25567
  return `${_UniversalStrategy.name}:${this.metadata.name}`;
25470
25568
  }
25569
+ async getVesuHealthFactors() {
25570
+ return await Promise.all(this.getVesuAdapters().map((v) => v.getHealthFactor()));
25571
+ }
25572
+ async computeRebalanceConditionAndReturnCalls() {
25573
+ const vesuAdapters = this.getVesuAdapters();
25574
+ const healthFactors = await this.getVesuHealthFactors();
25575
+ const leg1HealthFactor = healthFactors[0];
25576
+ const leg2HealthFactor = healthFactors[1];
25577
+ logger.verbose(`${this.getTag()}: HealthFactorLeg1: ${leg1HealthFactor}`);
25578
+ logger.verbose(`${this.getTag()}: HealthFactorLeg2: ${leg2HealthFactor}`);
25579
+ const minHf = this.metadata.additionalInfo.minHealthFactor;
25580
+ const isRebalanceNeeded1 = leg1HealthFactor < minHf;
25581
+ const isRebalanceNeeded2 = leg2HealthFactor < minHf;
25582
+ if (!isRebalanceNeeded1 && !isRebalanceNeeded2) {
25583
+ return [];
25584
+ }
25585
+ if (isRebalanceNeeded1) {
25586
+ const amount = await this.getLegRebalanceAmount(vesuAdapters[0], leg1HealthFactor, false);
25587
+ const leg2HF = await this.getNewHealthFactor(vesuAdapters[1], amount, true);
25588
+ assert(leg2HF > minHf, `Rebalance Leg1 failed: Leg2 HF after rebalance would be too low: ${leg2HF}`);
25589
+ return [await this.getRebalanceCall({
25590
+ isLeg1toLeg2: false,
25591
+ amount
25592
+ })];
25593
+ } else {
25594
+ const amount = await this.getLegRebalanceAmount(vesuAdapters[1], leg2HealthFactor, true);
25595
+ const leg1HF = await this.getNewHealthFactor(vesuAdapters[0], amount, false);
25596
+ assert(leg1HF > minHf, `Rebalance Leg2 failed: Leg1 HF after rebalance would be too low: ${leg1HF}`);
25597
+ return [await this.getRebalanceCall({
25598
+ isLeg1toLeg2: true,
25599
+ amount
25600
+ })];
25601
+ }
25602
+ }
25603
+ async getNewHealthFactor(vesuAdapter, newAmount, isWithdraw) {
25604
+ const {
25605
+ collateralTokenAmount,
25606
+ collateralUSDAmount,
25607
+ collateralPrice,
25608
+ debtTokenAmount,
25609
+ debtUSDAmount,
25610
+ debtPrice,
25611
+ ltv
25612
+ } = await vesuAdapter.getAssetPrices();
25613
+ if (isWithdraw) {
25614
+ const newHF = (collateralTokenAmount.toNumber() - newAmount.toNumber()) * collateralPrice * ltv / debtUSDAmount;
25615
+ logger.verbose(`getNewHealthFactor:: HF: ${newHF}, amoutn: ${newAmount.toNumber()}, isDeposit`);
25616
+ return newHF;
25617
+ } else {
25618
+ const newHF = collateralUSDAmount * ltv / ((debtTokenAmount.toNumber() + newAmount.toNumber()) * debtPrice);
25619
+ logger.verbose(`getNewHealthFactor:: HF: ${newHF}, amoutn: ${newAmount.toNumber()}, isRepay`);
25620
+ return newHF;
25621
+ }
25622
+ }
25623
+ /**
25624
+ *
25625
+ * @param vesuAdapter
25626
+ * @param currentHf
25627
+ * @param isDeposit if true, attempt by adding collateral, else by repaying
25628
+ * @returns
25629
+ */
25630
+ async getLegRebalanceAmount(vesuAdapter, currentHf, isDeposit) {
25631
+ const {
25632
+ collateralTokenAmount,
25633
+ collateralUSDAmount,
25634
+ collateralPrice,
25635
+ debtTokenAmount,
25636
+ debtUSDAmount,
25637
+ debtPrice,
25638
+ ltv
25639
+ } = await vesuAdapter.getAssetPrices();
25640
+ if (debtTokenAmount.isZero()) {
25641
+ return Web3Number.fromWei(0, 0);
25642
+ }
25643
+ assert(collateralPrice > 0 && debtPrice > 0, "getRebalanceAmount: Invalid price");
25644
+ const targetHF = this.metadata.additionalInfo.targetHealthFactor;
25645
+ if (currentHf > targetHF - 0.01)
25646
+ throw new Error("getLegRebalanceAmount: Current health factor is healthy");
25647
+ if (isDeposit) {
25648
+ const newAmount = targetHF * debtUSDAmount / (collateralPrice * ltv) - collateralTokenAmount.toNumber();
25649
+ 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}`);
25650
+ return new Web3Number(newAmount.toFixed(8), collateralTokenAmount.decimals);
25651
+ } else {
25652
+ const newAmount = debtTokenAmount.toNumber() - collateralUSDAmount * ltv / (targetHF * debtPrice);
25653
+ 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}`);
25654
+ return new Web3Number(newAmount.toFixed(8), debtTokenAmount.decimals);
25655
+ }
25656
+ }
25471
25657
  async getVesuMultiplyCall(params) {
25472
- const vesuAdapter1 = this.getAdapter("vesu_leg1_adapter" /* VESU_LEG1 */);
25473
- const vesuAdapter2 = this.getAdapter("vesu_leg2_adapter" /* VESU_LEG2 */);
25658
+ const [vesuAdapter1, vesuAdapter2] = this.getVesuAdapters();
25474
25659
  const leg1LTV = await vesuAdapter1.getLTVConfig(this.config);
25475
25660
  const leg2LTV = await vesuAdapter2.getLTVConfig(this.config);
25476
25661
  logger.verbose(`${this.getTag()}: LTVLeg1: ${leg1LTV}`);
@@ -25479,7 +25664,7 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
25479
25664
  const token2Price = await this.pricer.getPrice(vesuAdapter2.config.collateral.symbol);
25480
25665
  logger.verbose(`${this.getTag()}: Price${vesuAdapter1.config.collateral.symbol}: ${token1Price.price}`);
25481
25666
  logger.verbose(`${this.getTag()}: Price${vesuAdapter2.config.collateral.symbol}: ${token2Price.price}`);
25482
- const TARGET_HF = 1.3;
25667
+ const TARGET_HF = this.metadata.additionalInfo.targetHealthFactor;
25483
25668
  const k1 = token1Price.price * leg1LTV / token2Price.price / TARGET_HF;
25484
25669
  const k2 = token1Price.price * TARGET_HF / token2Price.price / leg2LTV;
25485
25670
  const borrow2Amount = new Web3Number(
@@ -25537,14 +25722,14 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
25537
25722
  });
25538
25723
  if (params.isLeg1toLeg2) {
25539
25724
  const manageCall = this.getManageCall([
25540
- "vesu_leg1" /* VESU_LEG1 */,
25541
- "vesu_leg2" /* VESU_LEG2 */
25725
+ ...callSet1.map((i) => i.step),
25726
+ ...callSet2.map((i) => i.step)
25542
25727
  ], [...callSet1.map((i) => i.manageCall), ...callSet2.map((i) => i.manageCall)]);
25543
25728
  return manageCall;
25544
25729
  } else {
25545
25730
  const manageCall = this.getManageCall([
25546
- "vesu_leg2" /* VESU_LEG2 */,
25547
- "vesu_leg1" /* VESU_LEG1 */
25731
+ ...callSet2.map((i) => i.step),
25732
+ ...callSet1.map((i) => i.step)
25548
25733
  ], [...callSet2.map((i) => i.manageCall), ...callSet1.map((i) => i.manageCall)]);
25549
25734
  return manageCall;
25550
25735
  }
@@ -25612,14 +25797,18 @@ var usdcVaultSettings = {
25612
25797
  vaultAllocator: ContractAddr.from("0x228cca1005d3f2b55cbaba27cb291dacf1b9a92d1d6b1638195fbd3d0c1e3ba"),
25613
25798
  redeemRequestNFT: ContractAddr.from("0x906d03590010868cbf7590ad47043959d7af8e782089a605d9b22567b64fda"),
25614
25799
  leafAdapters: [],
25615
- adapters: []
25800
+ adapters: [],
25801
+ targetHealthFactor: 1.3,
25802
+ minHealthFactor: 1.25
25616
25803
  };
25617
25804
  var wbtcVaultSettings = {
25618
25805
  manager: ContractAddr.from("0xef8a664ffcfe46a6af550766d27c28937bf1b77fb4ab54d8553e92bca5ba34"),
25619
25806
  vaultAllocator: ContractAddr.from("0x1e01c25f0d9494570226ad28a7fa856c0640505e809c366a9fab4903320e735"),
25620
25807
  redeemRequestNFT: ContractAddr.from("0x4fec59a12f8424281c1e65a80b5de51b4e754625c60cddfcd00d46941ec37b2"),
25621
25808
  leafAdapters: [],
25622
- adapters: []
25809
+ adapters: [],
25810
+ targetHealthFactor: 1.3,
25811
+ minHealthFactor: 1.25
25623
25812
  };
25624
25813
  var UniversalStrategies = [
25625
25814
  {
package/dist/index.d.ts CHANGED
@@ -380,6 +380,18 @@ declare class AutoCompounderSTRK {
380
380
  }>;
381
381
  }
382
382
 
383
+ interface CacheData$1 {
384
+ timestamp: number;
385
+ ttl: number;
386
+ data: any;
387
+ }
388
+ declare class CacheClass {
389
+ readonly cache: Map<string, CacheData$1>;
390
+ setCache(key: string, data: any, ttl?: number): void;
391
+ getCache<T>(key: string): T | null;
392
+ isCacheValid(key: string): boolean;
393
+ }
394
+
383
395
  interface SingleActionAmount {
384
396
  tokenInfo: TokenInfo;
385
397
  amount: Web3Number;
@@ -401,7 +413,7 @@ interface CacheData {
401
413
  ttl: number;
402
414
  data: any;
403
415
  }
404
- declare class BaseStrategy<TVLInfo, ActionInfo> {
416
+ declare class BaseStrategy<TVLInfo, ActionInfo> extends CacheClass {
405
417
  readonly config: IConfig;
406
418
  readonly cache: Map<string, CacheData>;
407
419
  constructor(config: IConfig);
@@ -409,9 +421,6 @@ declare class BaseStrategy<TVLInfo, ActionInfo> {
409
421
  getTVL(): Promise<TVLInfo>;
410
422
  depositCall(amountInfo: ActionInfo, receiver: ContractAddr): Promise<Call[]>;
411
423
  withdrawCall(amountInfo: ActionInfo, receiver: ContractAddr, owner: ContractAddr): Promise<Call[]>;
412
- setCache(key: string, data: any, ttl?: number): void;
413
- getCache(key: string): any | null;
414
- isCacheValid(key: string): boolean;
415
424
  }
416
425
 
417
426
  interface PoolProps {
@@ -866,7 +875,6 @@ declare class StandardMerkleTree extends MerkleTreeImpl<LeafData> {
866
875
  protected readonly leafEncoding: ValueType[];
867
876
  protected constructor(tree: HexString[], values: StandardMerkleTreeData<LeafData>['values'], leafEncoding: ValueType[]);
868
877
  static of(values: LeafData[], leafEncoding?: ValueType[], options?: MerkleTreeOptions): StandardMerkleTree;
869
- static load(data: StandardMerkleTreeData<LeafData>): StandardMerkleTree;
870
878
  static verify<T extends any[]>(root: BytesLike, leafEncoding: ValueType[], leaf: T, proof: BytesLike[]): boolean;
871
879
  static verifyMultiProof<T extends any[]>(root: BytesLike, leafEncoding: ValueType[], multiproof: MultiProof<BytesLike, T>): boolean;
872
880
  dump(): StandardMerkleTreeData<LeafData>;
@@ -895,7 +903,7 @@ type AdapterLeafType<T> = {
895
903
  callConstructor: GenerateCallFn<T>;
896
904
  };
897
905
  type LeafAdapterFn<T> = () => AdapterLeafType<T>;
898
- declare class BaseAdapter {
906
+ declare class BaseAdapter extends CacheClass {
899
907
  protected constructSimpleLeafData(params: {
900
908
  id: string;
901
909
  target: ContractAddr;
@@ -972,7 +980,6 @@ declare class VesuAdapter extends BaseAdapter {
972
980
  config: VesuAdapterConfig;
973
981
  networkConfig: IConfig | undefined;
974
982
  pricer: PricerBase | undefined;
975
- cache: Record<string, any>;
976
983
  constructor(config: VesuAdapterConfig);
977
984
  getModifyPosition: () => AdapterLeafType<VesuModifyPositionCallParams>;
978
985
  static getDefaultModifyPositionCallParams(params: {
@@ -1004,6 +1011,17 @@ declare class VesuAdapter extends BaseAdapter {
1004
1011
  getVesuSingletonContract(config: IConfig): Contract;
1005
1012
  getLTVConfig(config: IConfig): Promise<number>;
1006
1013
  getPositions(config: IConfig): Promise<VaultPosition[]>;
1014
+ getCollateralization(config: IConfig): Promise<Omit<VaultPosition, 'amount'>[]>;
1015
+ getAssetPrices(): Promise<{
1016
+ collateralTokenAmount: Web3Number;
1017
+ collateralUSDAmount: number;
1018
+ collateralPrice: number;
1019
+ debtTokenAmount: Web3Number;
1020
+ debtUSDAmount: number;
1021
+ debtPrice: number;
1022
+ ltv: number;
1023
+ }>;
1024
+ getHealthFactor(): Promise<number>;
1007
1025
  static getVesuPools(retry?: number): Promise<VesuPoolsInfo>;
1008
1026
  }
1009
1027
 
@@ -1016,6 +1034,8 @@ interface UniversalStrategySettings {
1016
1034
  id: string;
1017
1035
  adapter: BaseAdapter;
1018
1036
  }[];
1037
+ targetHealthFactor: number;
1038
+ minHealthFactor: number;
1019
1039
  }
1020
1040
  declare class UniversalStrategy<S extends UniversalStrategySettings> extends BaseStrategy<SingleTokenInfo, SingleActionAmount> {
1021
1041
  /** Contract address of the strategy */
@@ -1052,7 +1072,14 @@ declare class UniversalStrategy<S extends UniversalStrategySettings> extends Bas
1052
1072
  * Calculates the weighted average APY across all pools based on USD value.
1053
1073
  * @returns {Promise<number>} The weighted average APY across all pools
1054
1074
  */
1055
- netAPY(): Promise<number>;
1075
+ netAPY(): Promise<{
1076
+ net: number;
1077
+ splits: {
1078
+ apy: number;
1079
+ id: string;
1080
+ }[];
1081
+ }>;
1082
+ private computeAPY;
1056
1083
  /**
1057
1084
  * Calculates the total TVL of the strategy.
1058
1085
  * @returns Object containing the total amount in token units and USD value
@@ -1062,7 +1089,14 @@ declare class UniversalStrategy<S extends UniversalStrategySettings> extends Bas
1062
1089
  amount: Web3Number;
1063
1090
  usdValue: number;
1064
1091
  }>;
1065
- getAUM(): Promise<SingleTokenInfo>;
1092
+ getAUM(): Promise<{
1093
+ net: SingleTokenInfo;
1094
+ prevAum: Web3Number;
1095
+ splits: {
1096
+ id: string;
1097
+ aum: Web3Number;
1098
+ }[];
1099
+ }>;
1066
1100
  getVesuAdapters(): VesuAdapter[];
1067
1101
  getVaultPositions(): Promise<VaultPosition[]>;
1068
1102
  getSetManagerCall(strategist: ContractAddr, root?: string): Call;
@@ -1075,8 +1109,20 @@ declare class UniversalStrategy<S extends UniversalStrategySettings> extends Bas
1075
1109
  }): {
1076
1110
  proofs: string[];
1077
1111
  manageCall: ManageCall;
1112
+ step: UNIVERSAL_MANAGE_IDS;
1078
1113
  }[];
1079
1114
  getTag(): string;
1115
+ getVesuHealthFactors(): Promise<number[]>;
1116
+ computeRebalanceConditionAndReturnCalls(): Promise<Call[]>;
1117
+ private getNewHealthFactor;
1118
+ /**
1119
+ *
1120
+ * @param vesuAdapter
1121
+ * @param currentHf
1122
+ * @param isDeposit if true, attempt by adding collateral, else by repaying
1123
+ * @returns
1124
+ */
1125
+ private getLegRebalanceAmount;
1080
1126
  getVesuMultiplyCall(params: {
1081
1127
  isDeposit: boolean;
1082
1128
  leg1DepositAmount: Web3Number;