@strkfarm/sdk 1.0.45 → 1.0.47

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.
@@ -57,7 +57,7 @@ export interface CLVaultStrategySettings {
57
57
  newBounds: {
58
58
  lower: number;
59
59
  upper: number;
60
- };
60
+ } | string; // if no bounds are set, can say `Managed by Re7`
61
61
  // to get true price
62
62
  lstContract?: ContractAddr;
63
63
  truePrice?: number; // useful for pools where price is known (e.g. USDC/USDT as 1)
@@ -589,7 +589,9 @@ export class EkuboCLVault extends BaseStrategy<
589
589
  console.log(
590
590
  `EkuboCLVault: getCurrentPrice: blockIdentifier: ${blockIdentifier}, sqrtRatio: ${sqrtRatio}, ${priceInfo.sqrt_ratio.toString()}`
591
591
  );
592
- const price = sqrtRatio * sqrtRatio;
592
+ const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
593
+ const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
594
+ const price = sqrtRatio * sqrtRatio * (10 ** token0Info.decimals) / ( 10 ** token1Info.decimals);
593
595
  const tick = EkuboCLVault.priceToTick(
594
596
  price,
595
597
  true,
@@ -619,7 +621,7 @@ export class EkuboCLVault extends BaseStrategy<
619
621
 
620
622
  static div2Power128(num: BigInt): number {
621
623
  return (
622
- Number((BigInt(num.toString()) * 1000000n) / BigInt(2 ** 128)) / 1000000
624
+ Number((BigInt(num.toString()) * BigInt(1e18)) / BigInt(2 ** 128)) / 1e18
623
625
  );
624
626
  }
625
627
 
@@ -647,12 +649,6 @@ export class EkuboCLVault extends BaseStrategy<
647
649
  tick_spacing: result.pool_key.tick_spacing.toString(),
648
650
  extension: result.pool_key.extension.toString(),
649
651
  };
650
- const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
651
- const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
652
- assert(
653
- token0Info.decimals == token1Info.decimals,
654
- "Tested only for equal decimals"
655
- );
656
652
  this.poolKey = poolKey;
657
653
  return poolKey;
658
654
  }
@@ -661,6 +657,10 @@ export class EkuboCLVault extends BaseStrategy<
661
657
  const poolKey = await this.getPoolKey();
662
658
  const currentPrice = await this._getCurrentPrice(poolKey);
663
659
 
660
+ if (typeof this.metadata.additionalInfo.newBounds === "string") {
661
+ throw new Error(`New bounds are managed known, to be set manually/externally`);
662
+ }
663
+
664
664
  const newLower =
665
665
  currentPrice.tick +
666
666
  Number(this.metadata.additionalInfo.newBounds.lower) *
@@ -684,12 +684,12 @@ export class EkuboCLVault extends BaseStrategy<
684
684
  * @returns {amount0, amount1}
685
685
  */
686
686
  private async _getExpectedAmountsForLiquidity(
687
- amount0: Web3Number,
688
- amount1: Web3Number,
687
+ inputAmount0: Web3Number,
688
+ inputAmount1: Web3Number,
689
689
  bounds: EkuboBounds,
690
690
  justUseInputAmount = true
691
691
  ) {
692
- assert(amount0.greaterThan(0) || amount1.greaterThan(0), "Amount is 0");
692
+ assert(inputAmount0.greaterThan(0) || inputAmount1.greaterThan(0), "Amount is 0");
693
693
 
694
694
  // get amount ratio for 1e18 liquidity
695
695
  const sampleLiq = 1e20;
@@ -713,47 +713,45 @@ export class EkuboCLVault extends BaseStrategy<
713
713
  );
714
714
  // Account for edge cases
715
715
  // i.e. when liquidity is out of range
716
- if (amount1.eq(0) && amount0.greaterThan(0)) {
716
+ if (inputAmount1.eq(0) && inputAmount0.greaterThan(0)) {
717
717
  if (sampleAmount1.eq(0)) {
718
718
  return {
719
- amount0: amount0,
720
- amount1: Web3Number.fromWei("0", amount1.decimals),
719
+ amount0: inputAmount0,
720
+ amount1: Web3Number.fromWei("0", inputAmount1.decimals),
721
721
  ratio: Infinity,
722
722
  };
723
723
  } else if (sampleAmount0.eq(0)) {
724
724
  // swap all to token1
725
725
  return {
726
- amount0: Web3Number.fromWei("0", amount0.decimals),
727
- amount1: amount0.multipliedBy(price),
726
+ amount0: Web3Number.fromWei("0", inputAmount0.decimals),
727
+ // to ensure decimal consistency, we start with 0
728
+ amount1: Web3Number.fromWei("0", inputAmount1.decimals).plus(inputAmount0.toString()).multipliedBy(price),
728
729
  ratio: 0,
729
730
  };
730
731
  }
731
- } else if (amount0.eq(0) && amount1.greaterThan(0)) {
732
+ } else if (inputAmount0.eq(0) && inputAmount1.greaterThan(0)) {
732
733
  if (sampleAmount0.eq(0)) {
733
734
  return {
734
- amount0: Web3Number.fromWei("0", amount0.decimals),
735
- amount1: amount1,
735
+ amount0: Web3Number.fromWei("0", inputAmount0.decimals),
736
+ amount1: inputAmount1,
736
737
  ratio: 0,
737
738
  };
738
739
  } else if (sampleAmount1.eq(0)) {
739
740
  // swap all to token0
740
741
  return {
741
- amount0: amount1.dividedBy(price),
742
- amount1: Web3Number.fromWei("0", amount1.decimals),
742
+ // to ensure decimal consistency, we start with 0
743
+ amount0: Web3Number.fromWei("0", inputAmount0.decimals).plus(inputAmount1.toString()).dividedBy(price),
744
+ amount1: Web3Number.fromWei("0", inputAmount1.decimals),
743
745
  ratio: Infinity,
744
746
  };
745
747
  }
746
748
  }
747
749
 
748
- // must make it general later
749
- assert(
750
- sampleAmount0.decimals == sampleAmount1.decimals,
751
- "Sample amounts have different decimals"
752
- );
753
750
  const ratioWeb3Number = sampleAmount0
754
751
  .multipliedBy(1e18)
755
752
  .dividedBy(sampleAmount1.toString())
756
753
  .dividedBy(1e18);
754
+
757
755
  const ratio: number = Number(ratioWeb3Number.toFixed(18));
758
756
  logger.verbose(
759
757
  `${EkuboCLVault.name}: ${
@@ -763,8 +761,8 @@ export class EkuboCLVault extends BaseStrategy<
763
761
 
764
762
  if (justUseInputAmount)
765
763
  return this._solveExpectedAmountsEq(
766
- amount0,
767
- amount1,
764
+ inputAmount0,
765
+ inputAmount1,
768
766
  ratioWeb3Number,
769
767
  price
770
768
  );
@@ -772,20 +770,20 @@ export class EkuboCLVault extends BaseStrategy<
772
770
  // we are at liberty to propose amounts outside the propsed amount
773
771
  // assuming amount0 and amount1 as independent values, compute other amounts
774
772
  // Also, if code came till here, it means both sample amounts are non-zero
775
- if (amount1.eq(0) && amount0.greaterThan(0)) {
773
+ if (inputAmount1.eq(0) && inputAmount0.greaterThan(0)) {
776
774
  // use amount0 as base and compute amount1 using ratio
777
- const _amount1 = amount0.dividedBy(ratioWeb3Number);
775
+ const _amount1 = new Web3Number(inputAmount0.toString(), inputAmount1.decimals).dividedBy(ratioWeb3Number);
778
776
  return {
779
- amount0: amount0,
777
+ amount0: inputAmount0,
780
778
  amount1: _amount1,
781
779
  ratio,
782
780
  };
783
- } else if (amount0.eq(0) && amount1.greaterThan(0)) {
781
+ } else if (inputAmount0.eq(0) && inputAmount1.greaterThan(0)) {
784
782
  // use amount1 as base and compute amount0 using ratio
785
- const _amount0 = amount1.multipliedBy(ratio);
783
+ const _amount0 = new Web3Number(inputAmount1.toString(), inputAmount0.decimals).multipliedBy(ratio);
786
784
  return {
787
785
  amount0: _amount0,
788
- amount1: amount1,
786
+ amount1: inputAmount1,
789
787
  ratio,
790
788
  };
791
789
  } else {
@@ -876,7 +874,7 @@ export class EkuboCLVault extends BaseStrategy<
876
874
  };
877
875
  }
878
876
 
879
- async getSwapInfoToHandleUnused(considerRebalance: boolean = true) {
877
+ async getSwapInfoToHandleUnused(considerRebalance: boolean = true, newBounds: EkuboBounds | null = null): Promise<SwapInfo> {
880
878
  const poolKey = await this.getPoolKey();
881
879
 
882
880
  // fetch current unused balances of vault
@@ -921,7 +919,9 @@ export class EkuboCLVault extends BaseStrategy<
921
919
 
922
920
  // get expected amounts for liquidity
923
921
  let ekuboBounds: EkuboBounds;
924
- if (considerRebalance) {
922
+ if (newBounds) {
923
+ ekuboBounds = newBounds;
924
+ } else if (considerRebalance) {
925
925
  ekuboBounds = await this.getNewBounds();
926
926
  } else {
927
927
  ekuboBounds = await this.getCurrentBounds();
@@ -1269,7 +1269,11 @@ export class EkuboCLVault extends BaseStrategy<
1269
1269
  );
1270
1270
  }
1271
1271
 
1272
- static i129ToNumber(i129: { mag: bigint; sign: number }) {
1272
+ static i129ToNumber(i129: { mag: bigint; sign: 0 | 1 | "true" | "false" }): bigint {
1273
+ if (i129.sign == 0 || i129.sign == 1) {
1274
+ return EkuboCLVault.i129ToNumber({mag: i129.mag, sign: i129.sign == 1 ? "true" : "false"});
1275
+ }
1276
+ assert(i129.sign.toString() == 'false' || i129.sign.toString() == 'true', "Invalid sign value");
1273
1277
  return i129.mag * (i129.sign.toString() == "false" ? 1n : -1n);
1274
1278
  }
1275
1279
 
@@ -1483,7 +1487,9 @@ export class EkuboCLVault extends BaseStrategy<
1483
1487
  subItems: [
1484
1488
  {
1485
1489
  key: "Range selection",
1486
- value: `${
1490
+ value: (typeof this.metadata.additionalInfo.newBounds == 'string') ?
1491
+ this.metadata.additionalInfo.newBounds :
1492
+ `${
1487
1493
  this.metadata.additionalInfo.newBounds.lower *
1488
1494
  Number(poolKey.tick_spacing)
1489
1495
  } to ${
@@ -1551,86 +1557,89 @@ const faqs: FAQ[] = [
1551
1557
  ),
1552
1558
  },
1553
1559
  ];
1560
+
1561
+ const xSTRKSTRK: IStrategyMetadata<CLVaultStrategySettings> = {
1562
+ name: "Ekubo xSTRK/STRK",
1563
+ description: (
1564
+ <div>
1565
+ <p>{_description.replace("{{POOL_NAME}}", "xSTRK/STRK")}</p>
1566
+ <ul
1567
+ style={{
1568
+ marginLeft: "20px",
1569
+ listStyle: "circle",
1570
+ fontSize: "12px",
1571
+ }}
1572
+ >
1573
+ <li style={{ marginTop: "10px" }}>
1574
+ During withdrawal, you may receive either or both tokens depending
1575
+ on market conditions and prevailing prices.
1576
+ </li>
1577
+ <li style={{ marginTop: "10px" }}>
1578
+ Sometimes you might see a negative APY — this is usually not a big
1579
+ deal. It happens when xSTRK's price drops on DEXes, but things
1580
+ typically bounce back within a few days or a week.
1581
+ </li>
1582
+ </ul>
1583
+ </div>
1584
+ ),
1585
+ address: ContractAddr.from(
1586
+ "0x01f083b98674bc21effee29ef443a00c7b9a500fd92cf30341a3da12c73f2324"
1587
+ ),
1588
+ launchBlock: 1209881,
1589
+ type: "Other",
1590
+ // must be same order as poolKey token0 and token1
1591
+ depositTokens: [
1592
+ Global.getDefaultTokens().find((t) => t.symbol === "xSTRK")!,
1593
+ Global.getDefaultTokens().find((t) => t.symbol === "STRK")!,
1594
+ ],
1595
+ protocols: [_protocol],
1596
+ auditUrl: AUDIT_URL,
1597
+ maxTVL: Web3Number.fromWei("0", 18),
1598
+ risk: {
1599
+ riskFactor: _riskFactor,
1600
+ netRisk:
1601
+ _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
1602
+ _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
1603
+ notARisks: getNoRiskTags(_riskFactor),
1604
+ },
1605
+ apyMethodology:
1606
+ "APY based on 7-day historical performance, including fees and rewards.",
1607
+ additionalInfo: {
1608
+ newBounds: {
1609
+ lower: -1,
1610
+ upper: 1,
1611
+ },
1612
+ lstContract: ContractAddr.from(
1613
+ "0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a"
1614
+ ),
1615
+ feeBps: 1000,
1616
+ rebalanceConditions: {
1617
+ customShouldRebalance: async (currentPrice: number) => true,
1618
+ minWaitHours: 24,
1619
+ direction: "uponly",
1620
+ },
1621
+ },
1622
+ faqs: [
1623
+ ...faqs,
1624
+ {
1625
+ question: "Why might I see a negative APY?",
1626
+ answer:
1627
+ "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.",
1628
+ },
1629
+ ],
1630
+ points: [{
1631
+ multiplier: 1,
1632
+ logo: 'https://endur.fi/favicon.ico',
1633
+ toolTip: "This strategy holds xSTRK and STRK tokens. Earn 1x Endur points on your xSTRK portion of Liquidity. STRK portion will earn Endur's DEX Bonus points. Points can be found on endur.fi.",
1634
+ }]
1635
+ };
1636
+
1554
1637
  /**
1555
1638
  * Represents the Vesu Rebalance Strategies.
1556
1639
  */
1557
1640
  export const EkuboCLVaultStrategies: IStrategyMetadata<CLVaultStrategySettings>[] =
1558
1641
  [
1559
- {
1560
- name: "Ekubo xSTRK/STRK",
1561
- description: (
1562
- <div>
1563
- <p>{_description.replace("{{POOL_NAME}}", "xSTRK/STRK")}</p>
1564
- <ul
1565
- style={{
1566
- marginLeft: "20px",
1567
- listStyle: "circle",
1568
- fontSize: "12px",
1569
- }}
1570
- >
1571
- <li style={{ marginTop: "10px" }}>
1572
- During withdrawal, you may receive either or both tokens depending
1573
- on market conditions and prevailing prices.
1574
- </li>
1575
- <li style={{ marginTop: "10px" }}>
1576
- Sometimes you might see a negative APY — this is usually not a big
1577
- deal. It happens when xSTRK's price drops on DEXes, but things
1578
- typically bounce back within a few days or a week.
1579
- </li>
1580
- </ul>
1581
- </div>
1582
- ),
1583
- address: ContractAddr.from(
1584
- "0x01f083b98674bc21effee29ef443a00c7b9a500fd92cf30341a3da12c73f2324"
1585
- ),
1586
- launchBlock: 1209881,
1587
- type: "Other",
1588
- // must be same order as poolKey token0 and token1
1589
- depositTokens: [
1590
- Global.getDefaultTokens().find((t) => t.symbol === "xSTRK")!,
1591
- Global.getDefaultTokens().find((t) => t.symbol === "STRK")!,
1592
- ],
1593
- protocols: [_protocol],
1594
- auditUrl: AUDIT_URL,
1595
- maxTVL: Web3Number.fromWei("0", 18),
1596
- risk: {
1597
- riskFactor: _riskFactor,
1598
- netRisk:
1599
- _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
1600
- _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
1601
- notARisks: getNoRiskTags(_riskFactor),
1602
- },
1603
- apyMethodology:
1604
- "APY based on 7-day historical performance, including fees and rewards.",
1605
- additionalInfo: {
1606
- newBounds: {
1607
- lower: -1,
1608
- upper: 1,
1609
- },
1610
- lstContract: ContractAddr.from(
1611
- "0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a"
1612
- ),
1613
- feeBps: 1000,
1614
- rebalanceConditions: {
1615
- customShouldRebalance: async (currentPrice: number) => true,
1616
- minWaitHours: 24,
1617
- direction: "uponly",
1618
- },
1619
- },
1620
- faqs: [
1621
- ...faqs,
1622
- {
1623
- question: "Why might I see a negative APY?",
1624
- answer:
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.",
1626
- },
1627
- ],
1628
- points: [{
1629
- multiplier: 1,
1630
- logo: 'https://endur.fi/favicon.ico',
1631
- toolTip: "This strategy holds xSTRK and STRK tokens. Earn 1x Endur points on your xSTRK portion of Liquidity. STRK portion will earn Endur's DEX Bonus points. Points can be found on endur.fi.",
1632
- }]
1633
- },
1642
+ xSTRKSTRK,
1634
1643
  {
1635
1644
  name: "Ekubo USDC/USDT",
1636
1645
  description: (
@@ -1690,4 +1699,46 @@ export const EkuboCLVaultStrategies: IStrategyMetadata<CLVaultStrategySettings>[
1690
1699
  },
1691
1700
  faqs: [...faqs],
1692
1701
  },
1693
- ];
1702
+ // {
1703
+ // ...xSTRKSTRK,
1704
+ // name: "Ekubo STRK/USDC",
1705
+ // description: (
1706
+ // <div>
1707
+ // <p>{_description.replace("{{POOL_NAME}}", "STRK/USDC")}</p>
1708
+ // <ul
1709
+ // style={{
1710
+ // marginLeft: "20px",
1711
+ // listStyle: "circle",
1712
+ // fontSize: "12px",
1713
+ // }}
1714
+ // >
1715
+ // <li style={{ marginTop: "10px" }}>
1716
+ // During withdrawal, you may receive either or both tokens depending
1717
+ // on market conditions and prevailing prices.
1718
+ // </li>
1719
+ // </ul>
1720
+ // </div>
1721
+ // ),
1722
+ // address: ContractAddr.from(
1723
+ // "0xb7bd37121041261446d8eedec618955a4490641034942da688e8cbddea7b23"
1724
+ // ),
1725
+ // launchBlock: 1492136,
1726
+ // // must be same order as poolKey token0 and token1
1727
+ // depositTokens: [
1728
+ // Global.getDefaultTokens().find((t) => t.symbol === "STRK")!,
1729
+ // Global.getDefaultTokens().find((t) => t.symbol === "USDC")!,
1730
+ // ],
1731
+ // maxTVL: Web3Number.fromWei("0", 6),
1732
+ // additionalInfo: {
1733
+ // newBounds: "Managed by Re7",
1734
+ // feeBps: 1000,
1735
+ // rebalanceConditions: {
1736
+ // customShouldRebalance: async (currentPrice: number) =>
1737
+ // true,
1738
+ // minWaitHours: 6,
1739
+ // direction: "any",
1740
+ // },
1741
+ // },
1742
+ // },
1743
+ ];
1744
+