@strkfarm/sdk 1.0.41 → 1.0.42

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.
@@ -38168,6 +38168,19 @@ var strkfarm_risk_engine = (() => {
38168
38168
  };
38169
38169
  return swapInfo;
38170
38170
  }
38171
+ static buildZeroSwap(tokenToSell, address) {
38172
+ return {
38173
+ token_from_address: tokenToSell.address,
38174
+ token_from_amount: uint256_exports.bnToUint256(0),
38175
+ token_to_address: tokenToSell.address,
38176
+ token_to_amount: uint256_exports.bnToUint256(0),
38177
+ token_to_min_amount: uint256_exports.bnToUint256(0),
38178
+ beneficiary: address,
38179
+ integrator_fee_amount_bps: 0,
38180
+ integrator_fee_recipient: address,
38181
+ routes: []
38182
+ };
38183
+ }
38171
38184
  };
38172
38185
 
38173
38186
  // src/interfaces/common.ts
@@ -54789,7 +54802,10 @@ var strkfarm_risk_engine = (() => {
54789
54802
  const priceNow = await this.getCurrentPrice(blockIdentifier);
54790
54803
  let blockNow = typeof blockIdentifier == "number" ? blockIdentifier : (await this.config.provider.getBlockLatestAccepted()).block_number;
54791
54804
  const blockNowTime = typeof blockIdentifier == "number" ? (await this.config.provider.getBlockWithTxs(blockIdentifier)).timestamp : (/* @__PURE__ */ new Date()).getTime() / 1e3;
54792
- const blockBefore = Math.max(blockNow - sinceBlocks, this.metadata.launchBlock);
54805
+ const blockBefore = Math.max(
54806
+ blockNow - sinceBlocks,
54807
+ this.metadata.launchBlock
54808
+ );
54793
54809
  const adjustedSupplyNow = supplyNow.minus(
54794
54810
  await this.getHarvestRewardShares(blockBefore, blockNow)
54795
54811
  );
@@ -55285,41 +55301,41 @@ var strkfarm_risk_engine = (() => {
55285
55301
  );
55286
55302
  let retry = 0;
55287
55303
  const maxRetry = 10;
55288
- while (retry < maxRetry) {
55289
- retry++;
55290
- if (expectedAmounts.amount0.lessThan(token0Bal) && expectedAmounts.amount1.lessThan(token1Bal)) {
55304
+ function assertValidAmounts(expectedAmounts2, token0Bal2, token1Bal2) {
55305
+ if (expectedAmounts2.amount0.lessThan(token0Bal2) && expectedAmounts2.amount1.lessThan(token1Bal2)) {
55291
55306
  throw new Error("Both tokens are decreased, something is wrong");
55292
55307
  }
55293
- if (expectedAmounts.amount0.greaterThan(token0Bal) && expectedAmounts.amount1.greaterThan(token1Bal)) {
55308
+ if (expectedAmounts2.amount0.greaterThan(token0Bal2) && expectedAmounts2.amount1.greaterThan(token1Bal2)) {
55294
55309
  throw new Error("Both tokens are increased, something is wrong");
55295
55310
  }
55296
- const tokenToSell = expectedAmounts.amount0.lessThan(token0Bal) ? poolKey.token0 : poolKey.token1;
55297
- const tokenToBuy = tokenToSell == poolKey.token0 ? poolKey.token1 : poolKey.token0;
55298
- let amountToSell = tokenToSell == poolKey.token0 ? token0Bal.minus(expectedAmounts.amount0) : token1Bal.minus(expectedAmounts.amount1);
55299
- const remainingSellAmount = tokenToSell == poolKey.token0 ? expectedAmounts.amount0 : expectedAmounts.amount1;
55300
- const tokenToBuyInfo = await Global.getTokenInfoFromAddr(tokenToBuy);
55301
- const expectedRatio = expectedAmounts.ratio;
55302
- logger.verbose(
55303
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => tokenToSell: ${tokenToSell.address}, tokenToBuy: ${tokenToBuy.address}, amountToSell: ${amountToSell.toWei()}`
55304
- );
55311
+ }
55312
+ function getSwapParams(expectedAmounts2, poolKey2, token0Bal2, token1Bal2) {
55313
+ const tokenToSell = expectedAmounts2.amount0.lessThan(token0Bal2) ? poolKey2.token0 : poolKey2.token1;
55314
+ const tokenToBuy = tokenToSell == poolKey2.token0 ? poolKey2.token1 : poolKey2.token0;
55315
+ const amountToSell = tokenToSell == poolKey2.token0 ? token0Bal2.minus(expectedAmounts2.amount0) : token1Bal2.minus(expectedAmounts2.amount1);
55316
+ const remainingSellAmount = tokenToSell == poolKey2.token0 ? expectedAmounts2.amount0 : expectedAmounts2.amount1;
55317
+ return { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount };
55318
+ }
55319
+ while (retry < maxRetry) {
55320
+ retry++;
55305
55321
  logger.verbose(
55306
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => remainingSellAmount: ${remainingSellAmount.toString()}`
55322
+ `getSwapInfoGivenAmounts::Retry attempt: ${retry}/${maxRetry}`
55307
55323
  );
55324
+ assertValidAmounts(expectedAmounts, token0Bal, token1Bal);
55325
+ const { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount } = getSwapParams(expectedAmounts, poolKey, token0Bal, token1Bal);
55326
+ const tokenToBuyInfo = await Global.getTokenInfoFromAddr(tokenToBuy);
55327
+ const expectedRatio = expectedAmounts.ratio;
55308
55328
  logger.verbose(
55309
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => expectedRatio: ${expectedRatio}`
55329
+ `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => iteration info: ${JSON.stringify({
55330
+ tokenToSell: tokenToSell.address,
55331
+ tokenToBuy: tokenToBuy.address,
55332
+ amountToSell: amountToSell.toString(),
55333
+ remainingSellAmount: remainingSellAmount.toString(),
55334
+ expectedRatio
55335
+ })}`
55310
55336
  );
55311
55337
  if (amountToSell.eq(0)) {
55312
- return {
55313
- token_from_address: tokenToSell.address,
55314
- token_from_amount: uint256_exports.bnToUint256(0),
55315
- token_to_address: tokenToSell.address,
55316
- token_to_amount: uint256_exports.bnToUint256(0),
55317
- token_to_min_amount: uint256_exports.bnToUint256(0),
55318
- beneficiary: this.address.address,
55319
- integrator_fee_amount_bps: 0,
55320
- integrator_fee_recipient: this.address.address,
55321
- routes: []
55322
- };
55338
+ return AvnuWrapper.buildZeroSwap(tokenToSell, this.address.address);
55323
55339
  }
55324
55340
  const quote = await this.avnu.getQuotes(
55325
55341
  tokenToSell.address,
@@ -55347,15 +55363,14 @@ var strkfarm_risk_engine = (() => {
55347
55363
  const swapPrice = tokenToSell == poolKey.token0 ? amountOut.dividedBy(amountToSell) : amountToSell.dividedBy(amountOut);
55348
55364
  const newRatio = tokenToSell == poolKey.token0 ? remainingSellAmount.dividedBy(token1Bal.plus(amountOut)) : token0Bal.plus(amountOut).dividedBy(remainingSellAmount);
55349
55365
  logger.verbose(
55350
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => amountOut: ${amountOut.toString()}`
55351
- );
55352
- logger.verbose(
55353
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => swapPrice: ${swapPrice.toString()}`
55354
- );
55355
- logger.verbose(
55356
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => newRatio: ${newRatio.toString()}`
55366
+ `${_EkuboCLVault.name} getSwapInfoToHandleUnused => iter post calc: ${JSON.stringify({
55367
+ amountOut: amountOut.toString(),
55368
+ swapPrice: swapPrice.toString(),
55369
+ newRatio: newRatio.toString()
55370
+ })}`
55357
55371
  );
55358
- if (Number(newRatio.toString()) > expectedRatio * 1.0000001 || Number(newRatio.toString()) < expectedRatio * 0.9999999) {
55372
+ const expectedPrecision = Math.min(7, tokenToBuyInfo.decimals - 2);
55373
+ if (Number(newRatio.toString()) > expectedRatio * (1 + 1 / 10 ** expectedPrecision) || Number(newRatio.toString()) < expectedRatio * (1 - 1 / 10 ** expectedPrecision)) {
55359
55374
  expectedAmounts = await this._solveExpectedAmountsEq(
55360
55375
  token0Bal,
55361
55376
  token1Bal,
@@ -55554,7 +55569,9 @@ var strkfarm_risk_engine = (() => {
55554
55569
  const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
55555
55570
  const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
55556
55571
  const bounds = await this.getCurrentBounds();
55557
- logger.verbose(`${_EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`);
55572
+ logger.verbose(
55573
+ `${_EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`
55574
+ );
55558
55575
  const calls = [];
55559
55576
  for (let claim of unClaimedRewards) {
55560
55577
  const fee = claim.claim.amount.multipliedBy(this.metadata.additionalInfo.feeBps).dividedBy(1e4);
@@ -55712,8 +55729,16 @@ var strkfarm_risk_engine = (() => {
55712
55729
  {
55713
55730
  question: "Is the strategy audited?",
55714
55731
  answer: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
55715
- "Yes, the strategy has been audited. You can review the audit report in our docs ",
55716
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("a", { href: "https://docs.strkfarm.com/p/ekubo-cl-vaults#technical-details", style: { textDecoration: "underline", marginLeft: "5px" }, children: "Here" }),
55732
+ "Yes, the strategy has been audited. You can review the audit report in our docs",
55733
+ " ",
55734
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
55735
+ "a",
55736
+ {
55737
+ href: "https://docs.strkfarm.com/p/ekubo-cl-vaults#technical-details",
55738
+ style: { textDecoration: "underline", marginLeft: "5px" },
55739
+ children: "Here"
55740
+ }
55741
+ ),
55717
55742
  "."
55718
55743
  ] })
55719
55744
  }
@@ -55765,7 +55790,12 @@ var strkfarm_risk_engine = (() => {
55765
55790
  lstContract: ContractAddr.from(
55766
55791
  "0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a"
55767
55792
  ),
55768
- feeBps: 1e3
55793
+ feeBps: 1e3,
55794
+ rebalanceConditions: {
55795
+ customShouldRebalance: async (currentPrice) => true,
55796
+ minWaitHours: 24,
55797
+ direction: "uponly"
55798
+ }
55769
55799
  },
55770
55800
  faqs: [
55771
55801
  ...faqs2,
@@ -55806,7 +55836,10 @@ var strkfarm_risk_engine = (() => {
55806
55836
  maxTVL: Web3Number.fromWei("0", 6),
55807
55837
  risk: {
55808
55838
  riskFactor: _riskFactorStable,
55809
- netRisk: _riskFactorStable.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
55839
+ netRisk: _riskFactorStable.reduce(
55840
+ (acc, curr) => acc + curr.value * curr.weight,
55841
+ 0
55842
+ ) / _riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
55810
55843
  notARisks: getNoRiskTags(_riskFactorStable)
55811
55844
  },
55812
55845
  apyMethodology: "APY based on 7-day historical performance, including fees and rewards.",
@@ -55816,11 +55849,14 @@ var strkfarm_risk_engine = (() => {
55816
55849
  upper: 1
55817
55850
  },
55818
55851
  truePrice: 1,
55819
- feeBps: 1e3
55852
+ feeBps: 1e3,
55853
+ rebalanceConditions: {
55854
+ customShouldRebalance: async (currentPrice) => currentPrice > 0.99 && currentPrice < 1.01,
55855
+ minWaitHours: 6,
55856
+ direction: "any"
55857
+ }
55820
55858
  },
55821
- faqs: [
55822
- ...faqs2
55823
- ]
55859
+ faqs: [...faqs2]
55824
55860
  }
55825
55861
  ];
55826
55862
  return __toCommonJS(index_browser_exports);
@@ -1948,6 +1948,19 @@ var AvnuWrapper = class _AvnuWrapper {
1948
1948
  };
1949
1949
  return swapInfo;
1950
1950
  }
1951
+ static buildZeroSwap(tokenToSell, address) {
1952
+ return {
1953
+ token_from_address: tokenToSell.address,
1954
+ token_from_amount: uint256.bnToUint256(0),
1955
+ token_to_address: tokenToSell.address,
1956
+ token_to_amount: uint256.bnToUint256(0),
1957
+ token_to_min_amount: uint256.bnToUint256(0),
1958
+ beneficiary: address,
1959
+ integrator_fee_amount_bps: 0,
1960
+ integrator_fee_recipient: address,
1961
+ routes: []
1962
+ };
1963
+ }
1951
1964
  };
1952
1965
 
1953
1966
  // src/interfaces/common.ts
@@ -18583,7 +18596,10 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
18583
18596
  const priceNow = await this.getCurrentPrice(blockIdentifier);
18584
18597
  let blockNow = typeof blockIdentifier == "number" ? blockIdentifier : (await this.config.provider.getBlockLatestAccepted()).block_number;
18585
18598
  const blockNowTime = typeof blockIdentifier == "number" ? (await this.config.provider.getBlockWithTxs(blockIdentifier)).timestamp : (/* @__PURE__ */ new Date()).getTime() / 1e3;
18586
- const blockBefore = Math.max(blockNow - sinceBlocks, this.metadata.launchBlock);
18599
+ const blockBefore = Math.max(
18600
+ blockNow - sinceBlocks,
18601
+ this.metadata.launchBlock
18602
+ );
18587
18603
  const adjustedSupplyNow = supplyNow.minus(
18588
18604
  await this.getHarvestRewardShares(blockBefore, blockNow)
18589
18605
  );
@@ -19079,41 +19095,41 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
19079
19095
  );
19080
19096
  let retry = 0;
19081
19097
  const maxRetry = 10;
19082
- while (retry < maxRetry) {
19083
- retry++;
19084
- if (expectedAmounts.amount0.lessThan(token0Bal) && expectedAmounts.amount1.lessThan(token1Bal)) {
19098
+ function assertValidAmounts(expectedAmounts2, token0Bal2, token1Bal2) {
19099
+ if (expectedAmounts2.amount0.lessThan(token0Bal2) && expectedAmounts2.amount1.lessThan(token1Bal2)) {
19085
19100
  throw new Error("Both tokens are decreased, something is wrong");
19086
19101
  }
19087
- if (expectedAmounts.amount0.greaterThan(token0Bal) && expectedAmounts.amount1.greaterThan(token1Bal)) {
19102
+ if (expectedAmounts2.amount0.greaterThan(token0Bal2) && expectedAmounts2.amount1.greaterThan(token1Bal2)) {
19088
19103
  throw new Error("Both tokens are increased, something is wrong");
19089
19104
  }
19090
- const tokenToSell = expectedAmounts.amount0.lessThan(token0Bal) ? poolKey.token0 : poolKey.token1;
19091
- const tokenToBuy = tokenToSell == poolKey.token0 ? poolKey.token1 : poolKey.token0;
19092
- let amountToSell = tokenToSell == poolKey.token0 ? token0Bal.minus(expectedAmounts.amount0) : token1Bal.minus(expectedAmounts.amount1);
19093
- const remainingSellAmount = tokenToSell == poolKey.token0 ? expectedAmounts.amount0 : expectedAmounts.amount1;
19094
- const tokenToBuyInfo = await Global.getTokenInfoFromAddr(tokenToBuy);
19095
- const expectedRatio = expectedAmounts.ratio;
19096
- logger.verbose(
19097
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => tokenToSell: ${tokenToSell.address}, tokenToBuy: ${tokenToBuy.address}, amountToSell: ${amountToSell.toWei()}`
19098
- );
19105
+ }
19106
+ function getSwapParams(expectedAmounts2, poolKey2, token0Bal2, token1Bal2) {
19107
+ const tokenToSell = expectedAmounts2.amount0.lessThan(token0Bal2) ? poolKey2.token0 : poolKey2.token1;
19108
+ const tokenToBuy = tokenToSell == poolKey2.token0 ? poolKey2.token1 : poolKey2.token0;
19109
+ const amountToSell = tokenToSell == poolKey2.token0 ? token0Bal2.minus(expectedAmounts2.amount0) : token1Bal2.minus(expectedAmounts2.amount1);
19110
+ const remainingSellAmount = tokenToSell == poolKey2.token0 ? expectedAmounts2.amount0 : expectedAmounts2.amount1;
19111
+ return { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount };
19112
+ }
19113
+ while (retry < maxRetry) {
19114
+ retry++;
19099
19115
  logger.verbose(
19100
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => remainingSellAmount: ${remainingSellAmount.toString()}`
19116
+ `getSwapInfoGivenAmounts::Retry attempt: ${retry}/${maxRetry}`
19101
19117
  );
19118
+ assertValidAmounts(expectedAmounts, token0Bal, token1Bal);
19119
+ const { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount } = getSwapParams(expectedAmounts, poolKey, token0Bal, token1Bal);
19120
+ const tokenToBuyInfo = await Global.getTokenInfoFromAddr(tokenToBuy);
19121
+ const expectedRatio = expectedAmounts.ratio;
19102
19122
  logger.verbose(
19103
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => expectedRatio: ${expectedRatio}`
19123
+ `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => iteration info: ${JSON.stringify({
19124
+ tokenToSell: tokenToSell.address,
19125
+ tokenToBuy: tokenToBuy.address,
19126
+ amountToSell: amountToSell.toString(),
19127
+ remainingSellAmount: remainingSellAmount.toString(),
19128
+ expectedRatio
19129
+ })}`
19104
19130
  );
19105
19131
  if (amountToSell.eq(0)) {
19106
- return {
19107
- token_from_address: tokenToSell.address,
19108
- token_from_amount: uint2564.bnToUint256(0),
19109
- token_to_address: tokenToSell.address,
19110
- token_to_amount: uint2564.bnToUint256(0),
19111
- token_to_min_amount: uint2564.bnToUint256(0),
19112
- beneficiary: this.address.address,
19113
- integrator_fee_amount_bps: 0,
19114
- integrator_fee_recipient: this.address.address,
19115
- routes: []
19116
- };
19132
+ return AvnuWrapper.buildZeroSwap(tokenToSell, this.address.address);
19117
19133
  }
19118
19134
  const quote = await this.avnu.getQuotes(
19119
19135
  tokenToSell.address,
@@ -19141,15 +19157,14 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
19141
19157
  const swapPrice = tokenToSell == poolKey.token0 ? amountOut.dividedBy(amountToSell) : amountToSell.dividedBy(amountOut);
19142
19158
  const newRatio = tokenToSell == poolKey.token0 ? remainingSellAmount.dividedBy(token1Bal.plus(amountOut)) : token0Bal.plus(amountOut).dividedBy(remainingSellAmount);
19143
19159
  logger.verbose(
19144
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => amountOut: ${amountOut.toString()}`
19145
- );
19146
- logger.verbose(
19147
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => swapPrice: ${swapPrice.toString()}`
19148
- );
19149
- logger.verbose(
19150
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => newRatio: ${newRatio.toString()}`
19160
+ `${_EkuboCLVault.name} getSwapInfoToHandleUnused => iter post calc: ${JSON.stringify({
19161
+ amountOut: amountOut.toString(),
19162
+ swapPrice: swapPrice.toString(),
19163
+ newRatio: newRatio.toString()
19164
+ })}`
19151
19165
  );
19152
- if (Number(newRatio.toString()) > expectedRatio * 1.0000001 || Number(newRatio.toString()) < expectedRatio * 0.9999999) {
19166
+ const expectedPrecision = Math.min(7, tokenToBuyInfo.decimals - 2);
19167
+ if (Number(newRatio.toString()) > expectedRatio * (1 + 1 / 10 ** expectedPrecision) || Number(newRatio.toString()) < expectedRatio * (1 - 1 / 10 ** expectedPrecision)) {
19153
19168
  expectedAmounts = await this._solveExpectedAmountsEq(
19154
19169
  token0Bal,
19155
19170
  token1Bal,
@@ -19348,7 +19363,9 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
19348
19363
  const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
19349
19364
  const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
19350
19365
  const bounds = await this.getCurrentBounds();
19351
- logger.verbose(`${_EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`);
19366
+ logger.verbose(
19367
+ `${_EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`
19368
+ );
19352
19369
  const calls = [];
19353
19370
  for (let claim of unClaimedRewards) {
19354
19371
  const fee = claim.claim.amount.multipliedBy(this.metadata.additionalInfo.feeBps).dividedBy(1e4);
@@ -19506,8 +19523,16 @@ var faqs2 = [
19506
19523
  {
19507
19524
  question: "Is the strategy audited?",
19508
19525
  answer: /* @__PURE__ */ jsxs2("div", { children: [
19509
- "Yes, the strategy has been audited. You can review the audit report in our docs ",
19510
- /* @__PURE__ */ jsx2("a", { href: "https://docs.strkfarm.com/p/ekubo-cl-vaults#technical-details", style: { textDecoration: "underline", marginLeft: "5px" }, children: "Here" }),
19526
+ "Yes, the strategy has been audited. You can review the audit report in our docs",
19527
+ " ",
19528
+ /* @__PURE__ */ jsx2(
19529
+ "a",
19530
+ {
19531
+ href: "https://docs.strkfarm.com/p/ekubo-cl-vaults#technical-details",
19532
+ style: { textDecoration: "underline", marginLeft: "5px" },
19533
+ children: "Here"
19534
+ }
19535
+ ),
19511
19536
  "."
19512
19537
  ] })
19513
19538
  }
@@ -19559,7 +19584,12 @@ var EkuboCLVaultStrategies = [
19559
19584
  lstContract: ContractAddr.from(
19560
19585
  "0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a"
19561
19586
  ),
19562
- feeBps: 1e3
19587
+ feeBps: 1e3,
19588
+ rebalanceConditions: {
19589
+ customShouldRebalance: async (currentPrice) => true,
19590
+ minWaitHours: 24,
19591
+ direction: "uponly"
19592
+ }
19563
19593
  },
19564
19594
  faqs: [
19565
19595
  ...faqs2,
@@ -19600,7 +19630,10 @@ var EkuboCLVaultStrategies = [
19600
19630
  maxTVL: Web3Number.fromWei("0", 6),
19601
19631
  risk: {
19602
19632
  riskFactor: _riskFactorStable,
19603
- netRisk: _riskFactorStable.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
19633
+ netRisk: _riskFactorStable.reduce(
19634
+ (acc, curr) => acc + curr.value * curr.weight,
19635
+ 0
19636
+ ) / _riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
19604
19637
  notARisks: getNoRiskTags(_riskFactorStable)
19605
19638
  },
19606
19639
  apyMethodology: "APY based on 7-day historical performance, including fees and rewards.",
@@ -19610,11 +19643,14 @@ var EkuboCLVaultStrategies = [
19610
19643
  upper: 1
19611
19644
  },
19612
19645
  truePrice: 1,
19613
- feeBps: 1e3
19646
+ feeBps: 1e3,
19647
+ rebalanceConditions: {
19648
+ customShouldRebalance: async (currentPrice) => currentPrice > 0.99 && currentPrice < 1.01,
19649
+ minWaitHours: 6,
19650
+ direction: "any"
19651
+ }
19614
19652
  },
19615
- faqs: [
19616
- ...faqs2
19617
- ]
19653
+ faqs: [...faqs2]
19618
19654
  }
19619
19655
  ];
19620
19656
  export {
package/dist/index.d.ts CHANGED
@@ -289,6 +289,7 @@ interface SwapInfo {
289
289
  declare class AvnuWrapper {
290
290
  getQuotes(fromToken: string, toToken: string, amountWei: string, taker: string, retry?: number): Promise<Quote>;
291
291
  getSwapInfo(quote: Quote, taker: string, integratorFeeBps: number, integratorFeeRecipient: string, minAmount?: string): Promise<SwapInfo>;
292
+ static buildZeroSwap(tokenToSell: ContractAddr, address: string): SwapInfo;
292
293
  }
293
294
 
294
295
  declare class FatalError extends Error {
@@ -598,6 +599,11 @@ interface CLVaultStrategySettings {
598
599
  lstContract?: ContractAddr;
599
600
  truePrice?: number;
600
601
  feeBps: number;
602
+ rebalanceConditions: {
603
+ minWaitHours: number;
604
+ direction: "any" | "uponly";
605
+ customShouldRebalance: (currentPoolPrice: number) => Promise<boolean>;
606
+ };
601
607
  }
602
608
  declare class EkuboCLVault extends BaseStrategy<DualTokenInfo, DualActionAmount> {
603
609
  /** Contract address of the strategy */
package/dist/index.js CHANGED
@@ -2066,6 +2066,19 @@ var AvnuWrapper = class _AvnuWrapper {
2066
2066
  };
2067
2067
  return swapInfo;
2068
2068
  }
2069
+ static buildZeroSwap(tokenToSell, address) {
2070
+ return {
2071
+ token_from_address: tokenToSell.address,
2072
+ token_from_amount: import_starknet4.uint256.bnToUint256(0),
2073
+ token_to_address: tokenToSell.address,
2074
+ token_to_amount: import_starknet4.uint256.bnToUint256(0),
2075
+ token_to_min_amount: import_starknet4.uint256.bnToUint256(0),
2076
+ beneficiary: address,
2077
+ integrator_fee_amount_bps: 0,
2078
+ integrator_fee_recipient: address,
2079
+ routes: []
2080
+ };
2081
+ }
2069
2082
  };
2070
2083
 
2071
2084
  // src/interfaces/common.ts
@@ -18697,7 +18710,10 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
18697
18710
  const priceNow = await this.getCurrentPrice(blockIdentifier);
18698
18711
  let blockNow = typeof blockIdentifier == "number" ? blockIdentifier : (await this.config.provider.getBlockLatestAccepted()).block_number;
18699
18712
  const blockNowTime = typeof blockIdentifier == "number" ? (await this.config.provider.getBlockWithTxs(blockIdentifier)).timestamp : (/* @__PURE__ */ new Date()).getTime() / 1e3;
18700
- const blockBefore = Math.max(blockNow - sinceBlocks, this.metadata.launchBlock);
18713
+ const blockBefore = Math.max(
18714
+ blockNow - sinceBlocks,
18715
+ this.metadata.launchBlock
18716
+ );
18701
18717
  const adjustedSupplyNow = supplyNow.minus(
18702
18718
  await this.getHarvestRewardShares(blockBefore, blockNow)
18703
18719
  );
@@ -19193,41 +19209,41 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
19193
19209
  );
19194
19210
  let retry = 0;
19195
19211
  const maxRetry = 10;
19196
- while (retry < maxRetry) {
19197
- retry++;
19198
- if (expectedAmounts.amount0.lessThan(token0Bal) && expectedAmounts.amount1.lessThan(token1Bal)) {
19212
+ function assertValidAmounts(expectedAmounts2, token0Bal2, token1Bal2) {
19213
+ if (expectedAmounts2.amount0.lessThan(token0Bal2) && expectedAmounts2.amount1.lessThan(token1Bal2)) {
19199
19214
  throw new Error("Both tokens are decreased, something is wrong");
19200
19215
  }
19201
- if (expectedAmounts.amount0.greaterThan(token0Bal) && expectedAmounts.amount1.greaterThan(token1Bal)) {
19216
+ if (expectedAmounts2.amount0.greaterThan(token0Bal2) && expectedAmounts2.amount1.greaterThan(token1Bal2)) {
19202
19217
  throw new Error("Both tokens are increased, something is wrong");
19203
19218
  }
19204
- const tokenToSell = expectedAmounts.amount0.lessThan(token0Bal) ? poolKey.token0 : poolKey.token1;
19205
- const tokenToBuy = tokenToSell == poolKey.token0 ? poolKey.token1 : poolKey.token0;
19206
- let amountToSell = tokenToSell == poolKey.token0 ? token0Bal.minus(expectedAmounts.amount0) : token1Bal.minus(expectedAmounts.amount1);
19207
- const remainingSellAmount = tokenToSell == poolKey.token0 ? expectedAmounts.amount0 : expectedAmounts.amount1;
19208
- const tokenToBuyInfo = await Global.getTokenInfoFromAddr(tokenToBuy);
19209
- const expectedRatio = expectedAmounts.ratio;
19210
- logger.verbose(
19211
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => tokenToSell: ${tokenToSell.address}, tokenToBuy: ${tokenToBuy.address}, amountToSell: ${amountToSell.toWei()}`
19212
- );
19219
+ }
19220
+ function getSwapParams(expectedAmounts2, poolKey2, token0Bal2, token1Bal2) {
19221
+ const tokenToSell = expectedAmounts2.amount0.lessThan(token0Bal2) ? poolKey2.token0 : poolKey2.token1;
19222
+ const tokenToBuy = tokenToSell == poolKey2.token0 ? poolKey2.token1 : poolKey2.token0;
19223
+ const amountToSell = tokenToSell == poolKey2.token0 ? token0Bal2.minus(expectedAmounts2.amount0) : token1Bal2.minus(expectedAmounts2.amount1);
19224
+ const remainingSellAmount = tokenToSell == poolKey2.token0 ? expectedAmounts2.amount0 : expectedAmounts2.amount1;
19225
+ return { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount };
19226
+ }
19227
+ while (retry < maxRetry) {
19228
+ retry++;
19213
19229
  logger.verbose(
19214
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => remainingSellAmount: ${remainingSellAmount.toString()}`
19230
+ `getSwapInfoGivenAmounts::Retry attempt: ${retry}/${maxRetry}`
19215
19231
  );
19232
+ assertValidAmounts(expectedAmounts, token0Bal, token1Bal);
19233
+ const { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount } = getSwapParams(expectedAmounts, poolKey, token0Bal, token1Bal);
19234
+ const tokenToBuyInfo = await Global.getTokenInfoFromAddr(tokenToBuy);
19235
+ const expectedRatio = expectedAmounts.ratio;
19216
19236
  logger.verbose(
19217
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => expectedRatio: ${expectedRatio}`
19237
+ `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => iteration info: ${JSON.stringify({
19238
+ tokenToSell: tokenToSell.address,
19239
+ tokenToBuy: tokenToBuy.address,
19240
+ amountToSell: amountToSell.toString(),
19241
+ remainingSellAmount: remainingSellAmount.toString(),
19242
+ expectedRatio
19243
+ })}`
19218
19244
  );
19219
19245
  if (amountToSell.eq(0)) {
19220
- return {
19221
- token_from_address: tokenToSell.address,
19222
- token_from_amount: import_starknet9.uint256.bnToUint256(0),
19223
- token_to_address: tokenToSell.address,
19224
- token_to_amount: import_starknet9.uint256.bnToUint256(0),
19225
- token_to_min_amount: import_starknet9.uint256.bnToUint256(0),
19226
- beneficiary: this.address.address,
19227
- integrator_fee_amount_bps: 0,
19228
- integrator_fee_recipient: this.address.address,
19229
- routes: []
19230
- };
19246
+ return AvnuWrapper.buildZeroSwap(tokenToSell, this.address.address);
19231
19247
  }
19232
19248
  const quote = await this.avnu.getQuotes(
19233
19249
  tokenToSell.address,
@@ -19255,15 +19271,14 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
19255
19271
  const swapPrice = tokenToSell == poolKey.token0 ? amountOut.dividedBy(amountToSell) : amountToSell.dividedBy(amountOut);
19256
19272
  const newRatio = tokenToSell == poolKey.token0 ? remainingSellAmount.dividedBy(token1Bal.plus(amountOut)) : token0Bal.plus(amountOut).dividedBy(remainingSellAmount);
19257
19273
  logger.verbose(
19258
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => amountOut: ${amountOut.toString()}`
19259
- );
19260
- logger.verbose(
19261
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => swapPrice: ${swapPrice.toString()}`
19262
- );
19263
- logger.verbose(
19264
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => newRatio: ${newRatio.toString()}`
19274
+ `${_EkuboCLVault.name} getSwapInfoToHandleUnused => iter post calc: ${JSON.stringify({
19275
+ amountOut: amountOut.toString(),
19276
+ swapPrice: swapPrice.toString(),
19277
+ newRatio: newRatio.toString()
19278
+ })}`
19265
19279
  );
19266
- if (Number(newRatio.toString()) > expectedRatio * 1.0000001 || Number(newRatio.toString()) < expectedRatio * 0.9999999) {
19280
+ const expectedPrecision = Math.min(7, tokenToBuyInfo.decimals - 2);
19281
+ if (Number(newRatio.toString()) > expectedRatio * (1 + 1 / 10 ** expectedPrecision) || Number(newRatio.toString()) < expectedRatio * (1 - 1 / 10 ** expectedPrecision)) {
19267
19282
  expectedAmounts = await this._solveExpectedAmountsEq(
19268
19283
  token0Bal,
19269
19284
  token1Bal,
@@ -19462,7 +19477,9 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
19462
19477
  const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
19463
19478
  const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
19464
19479
  const bounds = await this.getCurrentBounds();
19465
- logger.verbose(`${_EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`);
19480
+ logger.verbose(
19481
+ `${_EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`
19482
+ );
19466
19483
  const calls = [];
19467
19484
  for (let claim of unClaimedRewards) {
19468
19485
  const fee = claim.claim.amount.multipliedBy(this.metadata.additionalInfo.feeBps).dividedBy(1e4);
@@ -19620,8 +19637,16 @@ var faqs2 = [
19620
19637
  {
19621
19638
  question: "Is the strategy audited?",
19622
19639
  answer: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
19623
- "Yes, the strategy has been audited. You can review the audit report in our docs ",
19624
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("a", { href: "https://docs.strkfarm.com/p/ekubo-cl-vaults#technical-details", style: { textDecoration: "underline", marginLeft: "5px" }, children: "Here" }),
19640
+ "Yes, the strategy has been audited. You can review the audit report in our docs",
19641
+ " ",
19642
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
19643
+ "a",
19644
+ {
19645
+ href: "https://docs.strkfarm.com/p/ekubo-cl-vaults#technical-details",
19646
+ style: { textDecoration: "underline", marginLeft: "5px" },
19647
+ children: "Here"
19648
+ }
19649
+ ),
19625
19650
  "."
19626
19651
  ] })
19627
19652
  }
@@ -19673,7 +19698,12 @@ var EkuboCLVaultStrategies = [
19673
19698
  lstContract: ContractAddr.from(
19674
19699
  "0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a"
19675
19700
  ),
19676
- feeBps: 1e3
19701
+ feeBps: 1e3,
19702
+ rebalanceConditions: {
19703
+ customShouldRebalance: async (currentPrice) => true,
19704
+ minWaitHours: 24,
19705
+ direction: "uponly"
19706
+ }
19677
19707
  },
19678
19708
  faqs: [
19679
19709
  ...faqs2,
@@ -19714,7 +19744,10 @@ var EkuboCLVaultStrategies = [
19714
19744
  maxTVL: Web3Number.fromWei("0", 6),
19715
19745
  risk: {
19716
19746
  riskFactor: _riskFactorStable,
19717
- netRisk: _riskFactorStable.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
19747
+ netRisk: _riskFactorStable.reduce(
19748
+ (acc, curr) => acc + curr.value * curr.weight,
19749
+ 0
19750
+ ) / _riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
19718
19751
  notARisks: getNoRiskTags(_riskFactorStable)
19719
19752
  },
19720
19753
  apyMethodology: "APY based on 7-day historical performance, including fees and rewards.",
@@ -19724,11 +19757,14 @@ var EkuboCLVaultStrategies = [
19724
19757
  upper: 1
19725
19758
  },
19726
19759
  truePrice: 1,
19727
- feeBps: 1e3
19760
+ feeBps: 1e3,
19761
+ rebalanceConditions: {
19762
+ customShouldRebalance: async (currentPrice) => currentPrice > 0.99 && currentPrice < 1.01,
19763
+ minWaitHours: 6,
19764
+ direction: "any"
19765
+ }
19728
19766
  },
19729
- faqs: [
19730
- ...faqs2
19731
- ]
19767
+ faqs: [...faqs2]
19732
19768
  }
19733
19769
  ];
19734
19770
 
package/dist/index.mjs CHANGED
@@ -1997,6 +1997,19 @@ var AvnuWrapper = class _AvnuWrapper {
1997
1997
  };
1998
1998
  return swapInfo;
1999
1999
  }
2000
+ static buildZeroSwap(tokenToSell, address) {
2001
+ return {
2002
+ token_from_address: tokenToSell.address,
2003
+ token_from_amount: uint256.bnToUint256(0),
2004
+ token_to_address: tokenToSell.address,
2005
+ token_to_amount: uint256.bnToUint256(0),
2006
+ token_to_min_amount: uint256.bnToUint256(0),
2007
+ beneficiary: address,
2008
+ integrator_fee_amount_bps: 0,
2009
+ integrator_fee_recipient: address,
2010
+ routes: []
2011
+ };
2012
+ }
2000
2013
  };
2001
2014
 
2002
2015
  // src/interfaces/common.ts
@@ -18632,7 +18645,10 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
18632
18645
  const priceNow = await this.getCurrentPrice(blockIdentifier);
18633
18646
  let blockNow = typeof blockIdentifier == "number" ? blockIdentifier : (await this.config.provider.getBlockLatestAccepted()).block_number;
18634
18647
  const blockNowTime = typeof blockIdentifier == "number" ? (await this.config.provider.getBlockWithTxs(blockIdentifier)).timestamp : (/* @__PURE__ */ new Date()).getTime() / 1e3;
18635
- const blockBefore = Math.max(blockNow - sinceBlocks, this.metadata.launchBlock);
18648
+ const blockBefore = Math.max(
18649
+ blockNow - sinceBlocks,
18650
+ this.metadata.launchBlock
18651
+ );
18636
18652
  const adjustedSupplyNow = supplyNow.minus(
18637
18653
  await this.getHarvestRewardShares(blockBefore, blockNow)
18638
18654
  );
@@ -19128,41 +19144,41 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
19128
19144
  );
19129
19145
  let retry = 0;
19130
19146
  const maxRetry = 10;
19131
- while (retry < maxRetry) {
19132
- retry++;
19133
- if (expectedAmounts.amount0.lessThan(token0Bal) && expectedAmounts.amount1.lessThan(token1Bal)) {
19147
+ function assertValidAmounts(expectedAmounts2, token0Bal2, token1Bal2) {
19148
+ if (expectedAmounts2.amount0.lessThan(token0Bal2) && expectedAmounts2.amount1.lessThan(token1Bal2)) {
19134
19149
  throw new Error("Both tokens are decreased, something is wrong");
19135
19150
  }
19136
- if (expectedAmounts.amount0.greaterThan(token0Bal) && expectedAmounts.amount1.greaterThan(token1Bal)) {
19151
+ if (expectedAmounts2.amount0.greaterThan(token0Bal2) && expectedAmounts2.amount1.greaterThan(token1Bal2)) {
19137
19152
  throw new Error("Both tokens are increased, something is wrong");
19138
19153
  }
19139
- const tokenToSell = expectedAmounts.amount0.lessThan(token0Bal) ? poolKey.token0 : poolKey.token1;
19140
- const tokenToBuy = tokenToSell == poolKey.token0 ? poolKey.token1 : poolKey.token0;
19141
- let amountToSell = tokenToSell == poolKey.token0 ? token0Bal.minus(expectedAmounts.amount0) : token1Bal.minus(expectedAmounts.amount1);
19142
- const remainingSellAmount = tokenToSell == poolKey.token0 ? expectedAmounts.amount0 : expectedAmounts.amount1;
19143
- const tokenToBuyInfo = await Global.getTokenInfoFromAddr(tokenToBuy);
19144
- const expectedRatio = expectedAmounts.ratio;
19145
- logger.verbose(
19146
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => tokenToSell: ${tokenToSell.address}, tokenToBuy: ${tokenToBuy.address}, amountToSell: ${amountToSell.toWei()}`
19147
- );
19154
+ }
19155
+ function getSwapParams(expectedAmounts2, poolKey2, token0Bal2, token1Bal2) {
19156
+ const tokenToSell = expectedAmounts2.amount0.lessThan(token0Bal2) ? poolKey2.token0 : poolKey2.token1;
19157
+ const tokenToBuy = tokenToSell == poolKey2.token0 ? poolKey2.token1 : poolKey2.token0;
19158
+ const amountToSell = tokenToSell == poolKey2.token0 ? token0Bal2.minus(expectedAmounts2.amount0) : token1Bal2.minus(expectedAmounts2.amount1);
19159
+ const remainingSellAmount = tokenToSell == poolKey2.token0 ? expectedAmounts2.amount0 : expectedAmounts2.amount1;
19160
+ return { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount };
19161
+ }
19162
+ while (retry < maxRetry) {
19163
+ retry++;
19148
19164
  logger.verbose(
19149
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => remainingSellAmount: ${remainingSellAmount.toString()}`
19165
+ `getSwapInfoGivenAmounts::Retry attempt: ${retry}/${maxRetry}`
19150
19166
  );
19167
+ assertValidAmounts(expectedAmounts, token0Bal, token1Bal);
19168
+ const { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount } = getSwapParams(expectedAmounts, poolKey, token0Bal, token1Bal);
19169
+ const tokenToBuyInfo = await Global.getTokenInfoFromAddr(tokenToBuy);
19170
+ const expectedRatio = expectedAmounts.ratio;
19151
19171
  logger.verbose(
19152
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => expectedRatio: ${expectedRatio}`
19172
+ `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => iteration info: ${JSON.stringify({
19173
+ tokenToSell: tokenToSell.address,
19174
+ tokenToBuy: tokenToBuy.address,
19175
+ amountToSell: amountToSell.toString(),
19176
+ remainingSellAmount: remainingSellAmount.toString(),
19177
+ expectedRatio
19178
+ })}`
19153
19179
  );
19154
19180
  if (amountToSell.eq(0)) {
19155
- return {
19156
- token_from_address: tokenToSell.address,
19157
- token_from_amount: uint2564.bnToUint256(0),
19158
- token_to_address: tokenToSell.address,
19159
- token_to_amount: uint2564.bnToUint256(0),
19160
- token_to_min_amount: uint2564.bnToUint256(0),
19161
- beneficiary: this.address.address,
19162
- integrator_fee_amount_bps: 0,
19163
- integrator_fee_recipient: this.address.address,
19164
- routes: []
19165
- };
19181
+ return AvnuWrapper.buildZeroSwap(tokenToSell, this.address.address);
19166
19182
  }
19167
19183
  const quote = await this.avnu.getQuotes(
19168
19184
  tokenToSell.address,
@@ -19190,15 +19206,14 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
19190
19206
  const swapPrice = tokenToSell == poolKey.token0 ? amountOut.dividedBy(amountToSell) : amountToSell.dividedBy(amountOut);
19191
19207
  const newRatio = tokenToSell == poolKey.token0 ? remainingSellAmount.dividedBy(token1Bal.plus(amountOut)) : token0Bal.plus(amountOut).dividedBy(remainingSellAmount);
19192
19208
  logger.verbose(
19193
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => amountOut: ${amountOut.toString()}`
19194
- );
19195
- logger.verbose(
19196
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => swapPrice: ${swapPrice.toString()}`
19197
- );
19198
- logger.verbose(
19199
- `${_EkuboCLVault.name}: getSwapInfoToHandleUnused => newRatio: ${newRatio.toString()}`
19209
+ `${_EkuboCLVault.name} getSwapInfoToHandleUnused => iter post calc: ${JSON.stringify({
19210
+ amountOut: amountOut.toString(),
19211
+ swapPrice: swapPrice.toString(),
19212
+ newRatio: newRatio.toString()
19213
+ })}`
19200
19214
  );
19201
- if (Number(newRatio.toString()) > expectedRatio * 1.0000001 || Number(newRatio.toString()) < expectedRatio * 0.9999999) {
19215
+ const expectedPrecision = Math.min(7, tokenToBuyInfo.decimals - 2);
19216
+ if (Number(newRatio.toString()) > expectedRatio * (1 + 1 / 10 ** expectedPrecision) || Number(newRatio.toString()) < expectedRatio * (1 - 1 / 10 ** expectedPrecision)) {
19202
19217
  expectedAmounts = await this._solveExpectedAmountsEq(
19203
19218
  token0Bal,
19204
19219
  token1Bal,
@@ -19397,7 +19412,9 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
19397
19412
  const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
19398
19413
  const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
19399
19414
  const bounds = await this.getCurrentBounds();
19400
- logger.verbose(`${_EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`);
19415
+ logger.verbose(
19416
+ `${_EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`
19417
+ );
19401
19418
  const calls = [];
19402
19419
  for (let claim of unClaimedRewards) {
19403
19420
  const fee = claim.claim.amount.multipliedBy(this.metadata.additionalInfo.feeBps).dividedBy(1e4);
@@ -19555,8 +19572,16 @@ var faqs2 = [
19555
19572
  {
19556
19573
  question: "Is the strategy audited?",
19557
19574
  answer: /* @__PURE__ */ jsxs2("div", { children: [
19558
- "Yes, the strategy has been audited. You can review the audit report in our docs ",
19559
- /* @__PURE__ */ jsx2("a", { href: "https://docs.strkfarm.com/p/ekubo-cl-vaults#technical-details", style: { textDecoration: "underline", marginLeft: "5px" }, children: "Here" }),
19575
+ "Yes, the strategy has been audited. You can review the audit report in our docs",
19576
+ " ",
19577
+ /* @__PURE__ */ jsx2(
19578
+ "a",
19579
+ {
19580
+ href: "https://docs.strkfarm.com/p/ekubo-cl-vaults#technical-details",
19581
+ style: { textDecoration: "underline", marginLeft: "5px" },
19582
+ children: "Here"
19583
+ }
19584
+ ),
19560
19585
  "."
19561
19586
  ] })
19562
19587
  }
@@ -19608,7 +19633,12 @@ var EkuboCLVaultStrategies = [
19608
19633
  lstContract: ContractAddr.from(
19609
19634
  "0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a"
19610
19635
  ),
19611
- feeBps: 1e3
19636
+ feeBps: 1e3,
19637
+ rebalanceConditions: {
19638
+ customShouldRebalance: async (currentPrice) => true,
19639
+ minWaitHours: 24,
19640
+ direction: "uponly"
19641
+ }
19612
19642
  },
19613
19643
  faqs: [
19614
19644
  ...faqs2,
@@ -19649,7 +19679,10 @@ var EkuboCLVaultStrategies = [
19649
19679
  maxTVL: Web3Number.fromWei("0", 6),
19650
19680
  risk: {
19651
19681
  riskFactor: _riskFactorStable,
19652
- netRisk: _riskFactorStable.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
19682
+ netRisk: _riskFactorStable.reduce(
19683
+ (acc, curr) => acc + curr.value * curr.weight,
19684
+ 0
19685
+ ) / _riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
19653
19686
  notARisks: getNoRiskTags(_riskFactorStable)
19654
19687
  },
19655
19688
  apyMethodology: "APY based on 7-day historical performance, including fees and rewards.",
@@ -19659,11 +19692,14 @@ var EkuboCLVaultStrategies = [
19659
19692
  upper: 1
19660
19693
  },
19661
19694
  truePrice: 1,
19662
- feeBps: 1e3
19695
+ feeBps: 1e3,
19696
+ rebalanceConditions: {
19697
+ customShouldRebalance: async (currentPrice) => currentPrice > 0.99 && currentPrice < 1.01,
19698
+ minWaitHours: 6,
19699
+ direction: "any"
19700
+ }
19663
19701
  },
19664
- faqs: [
19665
- ...faqs2
19666
- ]
19702
+ faqs: [...faqs2]
19667
19703
  }
19668
19704
  ];
19669
19705
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strkfarm/sdk",
3
- "version": "1.0.41",
3
+ "version": "1.0.42",
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",
@@ -4,6 +4,7 @@ import { Call, Uint256 } from "starknet";
4
4
  import { fetchBuildExecuteTransaction, fetchQuotes, Quote } from "@avnu/avnu-sdk";
5
5
  import { assert } from "../utils";
6
6
  import { logger } from "@/utils/logger";
7
+ import { ContractAddr } from "@/dataTypes";
7
8
 
8
9
  export interface Route {
9
10
  token_from: string,
@@ -109,4 +110,21 @@ export class AvnuWrapper {
109
110
 
110
111
  return swapInfo;
111
112
  }
113
+
114
+ static buildZeroSwap(
115
+ tokenToSell: ContractAddr,
116
+ address: string
117
+ ): SwapInfo {
118
+ return {
119
+ token_from_address: tokenToSell.address,
120
+ token_from_amount: uint256.bnToUint256(0),
121
+ token_to_address: tokenToSell.address,
122
+ token_to_amount: uint256.bnToUint256(0),
123
+ token_to_min_amount: uint256.bnToUint256(0),
124
+ beneficiary: address,
125
+ integrator_fee_amount_bps: 0,
126
+ integrator_fee_recipient: address,
127
+ routes: [],
128
+ };
129
+ }
112
130
  }
@@ -62,6 +62,11 @@ export interface CLVaultStrategySettings {
62
62
  lstContract?: ContractAddr;
63
63
  truePrice?: number; // useful for pools where price is known (e.g. USDC/USDT as 1)
64
64
  feeBps: number;
65
+ rebalanceConditions: {
66
+ minWaitHours: number; // number of hours out of range to rebalance
67
+ direction: "any" | "uponly"; // any for pools like USDC/USDT, uponly for pools like xSTRK/STRK
68
+ customShouldRebalance: (currentPoolPrice: number) => Promise<boolean>; // any additional logic for deciding factor to rebalance or not based on pools
69
+ };
65
70
  }
66
71
 
67
72
  export class EkuboCLVault extends BaseStrategy<
@@ -297,7 +302,10 @@ export class EkuboCLVault extends BaseStrategy<
297
302
  ? (await this.config.provider.getBlockWithTxs(blockIdentifier))
298
303
  .timestamp
299
304
  : new Date().getTime() / 1000;
300
- const blockBefore = Math.max(blockNow - sinceBlocks, this.metadata.launchBlock);
305
+ const blockBefore = Math.max(
306
+ blockNow - sinceBlocks,
307
+ this.metadata.launchBlock
308
+ );
301
309
  const adjustedSupplyNow = supplyNow.minus(
302
310
  await this.getHarvestRewardShares(blockBefore, blockNow)
303
311
  );
@@ -369,7 +377,7 @@ export class EkuboCLVault extends BaseStrategy<
369
377
  blockIdentifier: BlockIdentifier = "pending"
370
378
  ): Promise<Web3Number> {
371
379
  let bal = await this.contract.call("balance_of", [user.address], {
372
- blockIdentifier
380
+ blockIdentifier,
373
381
  });
374
382
  return Web3Number.fromWei(bal.toString(), 18);
375
383
  }
@@ -795,7 +803,6 @@ export class EkuboCLVault extends BaseStrategy<
795
803
  ratio: Web3Number,
796
804
  price: number
797
805
  ) {
798
-
799
806
  // (amount0 + x) / (amount1 - y) = ratio
800
807
  // x = y * Py / Px ---- (1)
801
808
  // => (amount0 + y * Py / Px) / (amount1 - y) = ratio
@@ -809,7 +816,9 @@ export class EkuboCLVault extends BaseStrategy<
809
816
  .dividedBy(ratio.plus(1 / price));
810
817
  const x = y.dividedBy(price);
811
818
  logger.verbose(
812
- `${EkuboCLVault.name}: _solveExpectedAmountsEq => x: ${x.toString()}, y: ${y.toString()}, amount0: ${availableAmount0.toString()}, amount1: ${availableAmount1.toString()}`
819
+ `${
820
+ EkuboCLVault.name
821
+ }: _solveExpectedAmountsEq => x: ${x.toString()}, y: ${y.toString()}, amount0: ${availableAmount0.toString()}, amount1: ${availableAmount1.toString()}`
813
822
  );
814
823
 
815
824
  if (ratio.eq(0)) {
@@ -864,7 +873,7 @@ export class EkuboCLVault extends BaseStrategy<
864
873
  tokenInfo: token1Info,
865
874
  usdValue: token1PriceUsd,
866
875
  },
867
- }
876
+ };
868
877
  }
869
878
 
870
879
  async getSwapInfoToHandleUnused(considerRebalance: boolean = true) {
@@ -872,8 +881,10 @@ export class EkuboCLVault extends BaseStrategy<
872
881
 
873
882
  // fetch current unused balances of vault
874
883
  const unusedBalances = await this.unusedBalances(poolKey);
875
- const { amount: token0Bal1, usdValue: token0PriceUsd} = unusedBalances.token0;
876
- const { amount: token1Bal1, usdValue: token1PriceUsd} = unusedBalances.token1;
884
+ const { amount: token0Bal1, usdValue: token0PriceUsd } =
885
+ unusedBalances.token0;
886
+ const { amount: token1Bal1, usdValue: token1PriceUsd } =
887
+ unusedBalances.token1;
877
888
 
878
889
  // if (token0PriceUsd > 1 && token1PriceUsd > 1) {
879
890
  // // the swap is designed to handle one token only.
@@ -934,8 +945,12 @@ export class EkuboCLVault extends BaseStrategy<
934
945
  bounds: EkuboBounds
935
946
  ): Promise<SwapInfo> {
936
947
  logger.verbose(
937
- `${EkuboCLVault.name}: getSwapInfoGivenAmounts::pre => token0Bal: ${token0Bal.toString()}, token1Bal: ${token1Bal.toString()}`
948
+ `${
949
+ EkuboCLVault.name
950
+ }: getSwapInfoGivenAmounts::pre => token0Bal: ${token0Bal.toString()}, token1Bal: ${token1Bal.toString()}`
938
951
  );
952
+
953
+ // Compute the expected amounts of token0 and token1 for the given liquidity bounds
939
954
  let expectedAmounts = await this._getExpectedAmountsForLiquidity(
940
955
  token0Bal,
941
956
  token1Bal,
@@ -947,14 +962,16 @@ export class EkuboCLVault extends BaseStrategy<
947
962
  }: getSwapInfoToHandleUnused => expectedAmounts2: ${expectedAmounts.amount0.toString()}, ${expectedAmounts.amount1.toString()}`
948
963
  );
949
964
 
950
- // get swap info
951
- // fetch avnu routes to ensure expected amounts
952
965
  let retry = 0;
953
966
  const maxRetry = 10;
954
- while (retry < maxRetry) {
955
- retry++;
956
- // assert one token is increased and other is decreased
957
967
 
968
+ // Helper to check for invalid states:
969
+ // Throws if both tokens are decreased or both are increased, which is not expected
970
+ function assertValidAmounts(
971
+ expectedAmounts: any,
972
+ token0Bal: Web3Number,
973
+ token1Bal: Web3Number
974
+ ) {
958
975
  if (
959
976
  expectedAmounts.amount0.lessThan(token0Bal) &&
960
977
  expectedAmounts.amount1.lessThan(token1Bal)
@@ -967,58 +984,75 @@ export class EkuboCLVault extends BaseStrategy<
967
984
  ) {
968
985
  throw new Error("Both tokens are increased, something is wrong");
969
986
  }
987
+ }
970
988
 
989
+ // Helper to determine which token to sell, which to buy, and the amounts to use
990
+ function getSwapParams(
991
+ expectedAmounts: any,
992
+ poolKey: EkuboPoolKey,
993
+ token0Bal: Web3Number,
994
+ token1Bal: Web3Number
995
+ ) {
996
+ // Decide which token to sell based on which expected amount is less than the balance
971
997
  const tokenToSell = expectedAmounts.amount0.lessThan(token0Bal)
972
998
  ? poolKey.token0
973
999
  : poolKey.token1;
1000
+ // The other token is the one to buy
974
1001
  const tokenToBuy =
975
1002
  tokenToSell == poolKey.token0 ? poolKey.token1 : poolKey.token0;
976
- let amountToSell =
1003
+ // Calculate how much to sell
1004
+ const amountToSell =
977
1005
  tokenToSell == poolKey.token0
978
1006
  ? token0Bal.minus(expectedAmounts.amount0)
979
1007
  : token1Bal.minus(expectedAmounts.amount1);
1008
+ // The remaining amount of the sold token after swap
980
1009
  const remainingSellAmount =
981
1010
  tokenToSell == poolKey.token0
982
1011
  ? expectedAmounts.amount0
983
1012
  : expectedAmounts.amount1;
984
- const tokenToBuyInfo = await Global.getTokenInfoFromAddr(tokenToBuy);
985
- const expectedRatio = expectedAmounts.ratio;
1013
+ return { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount };
1014
+ }
986
1015
 
1016
+ // Main retry loop: attempts to find a swap that matches the expected ratio within tolerance
1017
+ while (retry < maxRetry) {
1018
+ retry++;
987
1019
  logger.verbose(
988
- `${EkuboCLVault.name}: getSwapInfoToHandleUnused => tokenToSell: ${
989
- tokenToSell.address
990
- }, tokenToBuy: ${
991
- tokenToBuy.address
992
- }, amountToSell: ${amountToSell.toWei()}`
993
- );
994
- logger.verbose(
995
- `${
996
- EkuboCLVault.name
997
- }: getSwapInfoToHandleUnused => remainingSellAmount: ${remainingSellAmount.toString()}`
998
- );
999
- logger.verbose(
1000
- `${EkuboCLVault.name}: getSwapInfoToHandleUnused => expectedRatio: ${expectedRatio}`
1020
+ `getSwapInfoGivenAmounts::Retry attempt: ${retry}/${maxRetry}`
1001
1021
  );
1002
1022
 
1023
+ // Ensure the expected amounts are valid for swap logic
1024
+ assertValidAmounts(expectedAmounts, token0Bal, token1Bal);
1025
+
1026
+ // Get swap parameters for this iteration
1027
+ const { tokenToSell, tokenToBuy, amountToSell, remainingSellAmount } =
1028
+ getSwapParams(expectedAmounts, poolKey, token0Bal, token1Bal);
1029
+
1030
+ const tokenToBuyInfo = await Global.getTokenInfoFromAddr(tokenToBuy);
1031
+ const expectedRatio = expectedAmounts.ratio;
1032
+
1033
+ logger.verbose(
1034
+ `${EkuboCLVault.name}: getSwapInfoToHandleUnused => iteration info: ${JSON.stringify({
1035
+ tokenToSell: tokenToSell.address,
1036
+ tokenToBuy: tokenToBuy.address,
1037
+ amountToSell: amountToSell.toString(),
1038
+ remainingSellAmount: remainingSellAmount.toString(),
1039
+ expectedRatio: expectedRatio
1040
+ })}`);
1041
+
1042
+ // If nothing to sell, return a zero swap
1003
1043
  if (amountToSell.eq(0)) {
1004
- return {
1005
- token_from_address: tokenToSell.address,
1006
- token_from_amount: uint256.bnToUint256(0),
1007
- token_to_address: tokenToSell.address,
1008
- token_to_amount: uint256.bnToUint256(0),
1009
- token_to_min_amount: uint256.bnToUint256(0),
1010
- beneficiary: this.address.address,
1011
- integrator_fee_amount_bps: 0,
1012
- integrator_fee_recipient: this.address.address,
1013
- routes: [],
1014
- };
1044
+ return AvnuWrapper.buildZeroSwap(tokenToSell, this.address.address);
1015
1045
  }
1046
+
1047
+ // Get a quote for swapping the calculated amount
1016
1048
  const quote = await this.avnu.getQuotes(
1017
1049
  tokenToSell.address,
1018
1050
  tokenToBuy.address,
1019
1051
  amountToSell.toWei(),
1020
1052
  this.address.address
1021
1053
  );
1054
+
1055
+ // If all of the token is to be swapped, return the swap info directly
1022
1056
  if (remainingSellAmount.eq(0)) {
1023
1057
  const minAmountOut = Web3Number.fromWei(
1024
1058
  quote.buyAmount.toString(),
@@ -1033,36 +1067,34 @@ export class EkuboCLVault extends BaseStrategy<
1033
1067
  );
1034
1068
  }
1035
1069
 
1070
+ // Calculate the actual output and price from the quote
1036
1071
  const amountOut = Web3Number.fromWei(
1037
1072
  quote.buyAmount.toString(),
1038
1073
  tokenToBuyInfo.decimals
1039
1074
  );
1075
+ // Calculate the swap price depending on which token is being sold
1040
1076
  const swapPrice =
1041
1077
  tokenToSell == poolKey.token0
1042
1078
  ? amountOut.dividedBy(amountToSell)
1043
1079
  : amountToSell.dividedBy(amountOut);
1080
+ // Calculate the new ratio after the swap
1044
1081
  const newRatio =
1045
1082
  tokenToSell == poolKey.token0
1046
1083
  ? remainingSellAmount.dividedBy(token1Bal.plus(amountOut))
1047
1084
  : token0Bal.plus(amountOut).dividedBy(remainingSellAmount);
1048
- logger.verbose(
1049
- `${
1050
- EkuboCLVault.name
1051
- }: getSwapInfoToHandleUnused => amountOut: ${amountOut.toString()}`
1052
- );
1053
- logger.verbose(
1054
- `${
1055
- EkuboCLVault.name
1056
- }: getSwapInfoToHandleUnused => swapPrice: ${swapPrice.toString()}`
1057
- );
1058
- logger.verbose(
1059
- `${
1060
- EkuboCLVault.name
1061
- }: getSwapInfoToHandleUnused => newRatio: ${newRatio.toString()}`
1085
+
1086
+ logger.verbose(`${EkuboCLVault.name} getSwapInfoToHandleUnused => iter post calc: ${JSON.stringify({
1087
+ amountOut: amountOut.toString(),
1088
+ swapPrice: swapPrice.toString(),
1089
+ newRatio: newRatio.toString(),
1090
+ })}`
1062
1091
  );
1092
+
1093
+ // If the new ratio is not within tolerance, adjust expected amounts and retry
1094
+ const expectedPrecision = Math.min(7, tokenToBuyInfo.decimals - 2);
1063
1095
  if (
1064
- Number(newRatio.toString()) > expectedRatio * 1.0000001 ||
1065
- Number(newRatio.toString()) < expectedRatio * 0.9999999
1096
+ Number(newRatio.toString()) > expectedRatio * (1 + 1 / 10 ** expectedPrecision) ||
1097
+ Number(newRatio.toString()) < expectedRatio * (1 - 1 / 10 ** expectedPrecision)
1066
1098
  ) {
1067
1099
  expectedAmounts = await this._solveExpectedAmountsEq(
1068
1100
  token0Bal,
@@ -1076,6 +1108,7 @@ export class EkuboCLVault extends BaseStrategy<
1076
1108
  }: getSwapInfoToHandleUnused => expectedAmounts: ${expectedAmounts.amount0.toString()}, ${expectedAmounts.amount1.toString()}`
1077
1109
  );
1078
1110
  } else {
1111
+ // Otherwise, return the swap info with a slippage buffer
1079
1112
  const minAmountOut = Web3Number.fromWei(
1080
1113
  quote.buyAmount.toString(),
1081
1114
  tokenToBuyInfo.decimals
@@ -1088,10 +1121,10 @@ export class EkuboCLVault extends BaseStrategy<
1088
1121
  minAmountOut.toWei()
1089
1122
  );
1090
1123
  }
1091
-
1092
1124
  retry++;
1093
1125
  }
1094
1126
 
1127
+ // If no suitable swap found after max retries, throw error
1095
1128
  throw new Error("Failed to get swap info");
1096
1129
  }
1097
1130
 
@@ -1308,7 +1341,9 @@ export class EkuboCLVault extends BaseStrategy<
1308
1341
  const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
1309
1342
  const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
1310
1343
  const bounds = await this.getCurrentBounds();
1311
- logger.verbose(`${EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`);
1344
+ logger.verbose(
1345
+ `${EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`
1346
+ );
1312
1347
  const calls: Call[] = [];
1313
1348
  for (let claim of unClaimedRewards) {
1314
1349
  const fee = claim.claim.amount
@@ -1353,7 +1388,7 @@ export class EkuboCLVault extends BaseStrategy<
1353
1388
  const harvestEstimateCall = async (swapInfo1: SwapInfo) => {
1354
1389
  const swap1Amount = Web3Number.fromWei(
1355
1390
  uint256.uint256ToBN(swapInfo1.token_from_amount).toString(),
1356
- 18, // cause its always STRK?
1391
+ 18 // cause its always STRK?
1357
1392
  );
1358
1393
  logger.verbose(
1359
1394
  `${EkuboCLVault.name}: harvest => swap1Amount: ${swap1Amount}`
@@ -1371,12 +1406,12 @@ export class EkuboCLVault extends BaseStrategy<
1371
1406
  `${EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
1372
1407
  swapInfo
1373
1408
  )}`
1374
- );
1409
+ );
1375
1410
  logger.verbose(
1376
1411
  `${EkuboCLVault.name}: harvest => swapInfo2: ${JSON.stringify(
1377
1412
  swapInfo2
1378
1413
  )}`
1379
- );
1414
+ );
1380
1415
  const calldata = [
1381
1416
  claim.rewardsContract.address,
1382
1417
  {
@@ -1501,9 +1536,20 @@ const faqs: FAQ[] = [
1501
1536
  },
1502
1537
  {
1503
1538
  question: "Is the strategy audited?",
1504
- answer:
1505
- <div>Yes, the strategy has been audited. You can review the audit report in our docs <a href="https://docs.strkfarm.com/p/ekubo-cl-vaults#technical-details" style={{textDecoration: 'underline', marginLeft: '5px'}}>Here</a>.</div>
1506
- }
1539
+ answer: (
1540
+ <div>
1541
+ Yes, the strategy has been audited. You can review the audit report in
1542
+ our docs{" "}
1543
+ <a
1544
+ href="https://docs.strkfarm.com/p/ekubo-cl-vaults#technical-details"
1545
+ style={{ textDecoration: "underline", marginLeft: "5px" }}
1546
+ >
1547
+ Here
1548
+ </a>
1549
+ .
1550
+ </div>
1551
+ ),
1552
+ },
1507
1553
  ];
1508
1554
  /**
1509
1555
  * Represents the Vesu Rebalance Strategies.
@@ -1565,6 +1611,11 @@ export const EkuboCLVaultStrategies: IStrategyMetadata<CLVaultStrategySettings>[
1565
1611
  "0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a"
1566
1612
  ),
1567
1613
  feeBps: 1000,
1614
+ rebalanceConditions: {
1615
+ customShouldRebalance: async (currentPrice: number) => true,
1616
+ minWaitHours: 24,
1617
+ direction: "uponly",
1618
+ },
1568
1619
  },
1569
1620
  faqs: [
1570
1621
  ...faqs,
@@ -1573,7 +1624,7 @@ export const EkuboCLVaultStrategies: IStrategyMetadata<CLVaultStrategySettings>[
1573
1624
  answer:
1574
1625
  "A negative APY can occur when xSTRK's price drops on DEXes. This is usually temporary and tends to recover within a few days or a week.",
1575
1626
  },
1576
- ]
1627
+ ],
1577
1628
  },
1578
1629
  {
1579
1630
  name: "Ekubo USDC/USDT",
@@ -1610,8 +1661,10 @@ export const EkuboCLVaultStrategies: IStrategyMetadata<CLVaultStrategySettings>[
1610
1661
  risk: {
1611
1662
  riskFactor: _riskFactorStable,
1612
1663
  netRisk:
1613
- _riskFactorStable.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
1614
- _riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
1664
+ _riskFactorStable.reduce(
1665
+ (acc, curr) => acc + curr.value * curr.weight,
1666
+ 0
1667
+ ) / _riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
1615
1668
  notARisks: getNoRiskTags(_riskFactorStable),
1616
1669
  },
1617
1670
  apyMethodology:
@@ -1623,9 +1676,13 @@ export const EkuboCLVaultStrategies: IStrategyMetadata<CLVaultStrategySettings>[
1623
1676
  },
1624
1677
  truePrice: 1,
1625
1678
  feeBps: 1000,
1679
+ rebalanceConditions: {
1680
+ customShouldRebalance: async (currentPrice: number) =>
1681
+ currentPrice > 0.99 && currentPrice < 1.01,
1682
+ minWaitHours: 6,
1683
+ direction: "any",
1684
+ },
1626
1685
  },
1627
- faqs: [
1628
- ...faqs,
1629
- ]
1686
+ faqs: [...faqs],
1630
1687
  },
1631
1688
  ];