@strkfarm/sdk 1.0.41 → 1.0.43

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.
@@ -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
  }
@@ -3,6 +3,7 @@ import { logger } from "@/utils/logger";
3
3
  import { IConfig } from "@/interfaces";
4
4
  import { assert } from "@/utils";
5
5
  import { Contract, num } from "starknet";
6
+ import { ERC20 } from "./erc20";
6
7
 
7
8
  export interface HarvestInfo {
8
9
  rewardsContract: ContractAddr,
@@ -36,8 +37,16 @@ export class Harvests {
36
37
  const contract = new Contract(cls.abi, reward.rewardsContract.address, this.config.provider);
37
38
  const isClaimed = await contract.call('is_claimed', [reward.claim.id]);
38
39
  logger.verbose(`${Harvests.name}: isClaimed: ${isClaimed}`);
39
- if (isClaimed)
40
+ if (isClaimed) {
40
41
  return unClaimed;
42
+ }
43
+ // rewards contract must have enough balance to claim
44
+ const bal = await (new ERC20(this.config)).balanceOf(reward.token, reward.rewardsContract.address, 18);
45
+ if (bal.lessThan(reward.claim.amount)) {
46
+ logger.verbose(`${Harvests.name}: balance: ${bal.toString()}, amount: ${reward.claim.amount.toString()}`);
47
+ continue;
48
+ }
49
+
41
50
  unClaimed.unshift(reward); // to ensure older harvest is first
42
51
  }
43
52
  return unClaimed;
@@ -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,59 +1624,65 @@ 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
- ]
1577
- },
1578
- {
1579
- name: "Ekubo USDC/USDT",
1580
- description: (
1581
- <div>
1582
- <p>{_description.replace("{{POOL_NAME}}", "USDC/USDT")}</p>
1583
- <ul
1584
- style={{
1585
- marginLeft: "20px",
1586
- listStyle: "circle",
1587
- fontSize: "12px",
1588
- }}
1589
- >
1590
- <li style={{ marginTop: "10px" }}>
1591
- During withdrawal, you may receive either or both tokens depending
1592
- on market conditions and prevailing prices.
1593
- </li>
1594
- </ul>
1595
- </div>
1596
- ),
1597
- address: ContractAddr.from(
1598
- "0xd647ed735f0db52f2a5502b6e06ed21dc4284a43a36af4b60d3c80fbc56c91"
1599
- ),
1600
- launchBlock: 1385576,
1601
- type: "Other",
1602
- // must be same order as poolKey token0 and token1
1603
- depositTokens: [
1604
- Global.getDefaultTokens().find((t) => t.symbol === "USDC")!,
1605
- Global.getDefaultTokens().find((t) => t.symbol === "USDT")!,
1606
1627
  ],
1607
- protocols: [_protocol],
1608
- auditUrl: AUDIT_URL,
1609
- maxTVL: Web3Number.fromWei("0", 6),
1610
- risk: {
1611
- riskFactor: _riskFactorStable,
1612
- netRisk:
1613
- _riskFactorStable.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
1614
- _riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
1615
- notARisks: getNoRiskTags(_riskFactorStable),
1616
- },
1617
- apyMethodology:
1618
- "APY based on 7-day historical performance, including fees and rewards.",
1619
- additionalInfo: {
1620
- newBounds: {
1621
- lower: -1,
1622
- upper: 1,
1623
- },
1624
- truePrice: 1,
1625
- feeBps: 1000,
1626
- },
1627
- faqs: [
1628
- ...faqs,
1629
- ]
1630
1628
  },
1629
+ // {
1630
+ // name: "Ekubo USDC/USDT",
1631
+ // description: (
1632
+ // <div>
1633
+ // <p>{_description.replace("{{POOL_NAME}}", "USDC/USDT")}</p>
1634
+ // <ul
1635
+ // style={{
1636
+ // marginLeft: "20px",
1637
+ // listStyle: "circle",
1638
+ // fontSize: "12px",
1639
+ // }}
1640
+ // >
1641
+ // <li style={{ marginTop: "10px" }}>
1642
+ // During withdrawal, you may receive either or both tokens depending
1643
+ // on market conditions and prevailing prices.
1644
+ // </li>
1645
+ // </ul>
1646
+ // </div>
1647
+ // ),
1648
+ // address: ContractAddr.from(
1649
+ // "0xd647ed735f0db52f2a5502b6e06ed21dc4284a43a36af4b60d3c80fbc56c91"
1650
+ // ),
1651
+ // launchBlock: 1385576,
1652
+ // type: "Other",
1653
+ // // must be same order as poolKey token0 and token1
1654
+ // depositTokens: [
1655
+ // Global.getDefaultTokens().find((t) => t.symbol === "USDC")!,
1656
+ // Global.getDefaultTokens().find((t) => t.symbol === "USDT")!,
1657
+ // ],
1658
+ // protocols: [_protocol],
1659
+ // auditUrl: AUDIT_URL,
1660
+ // maxTVL: Web3Number.fromWei("0", 6),
1661
+ // risk: {
1662
+ // riskFactor: _riskFactorStable,
1663
+ // netRisk:
1664
+ // _riskFactorStable.reduce(
1665
+ // (acc, curr) => acc + curr.value * curr.weight,
1666
+ // 0
1667
+ // ) / _riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
1668
+ // notARisks: getNoRiskTags(_riskFactorStable),
1669
+ // },
1670
+ // apyMethodology:
1671
+ // "APY based on 7-day historical performance, including fees and rewards.",
1672
+ // additionalInfo: {
1673
+ // newBounds: {
1674
+ // lower: -1,
1675
+ // upper: 1,
1676
+ // },
1677
+ // truePrice: 1,
1678
+ // feeBps: 1000,
1679
+ // rebalanceConditions: {
1680
+ // customShouldRebalance: async (currentPrice: number) =>
1681
+ // currentPrice > 0.99 && currentPrice < 1.01,
1682
+ // minWaitHours: 6,
1683
+ // direction: "any",
1684
+ // },
1685
+ // },
1686
+ // faqs: [...faqs],
1687
+ // },
1631
1688
  ];
@@ -500,7 +500,7 @@ export class VesuRebalance extends BaseStrategy<
500
500
  logger.verbose(
501
501
  `VesuRebalance: Pool ${pool.id} not found in Vesu API, using hardcoded data`
502
502
  );
503
- throw new Error("pool not found [sanity check]");
503
+ throw new Error(`pool not found [sanity check]: ${pool.id}`);
504
504
  }
505
505
  }
506
506
  } catch (e) {