@kamino-finance/kliquidity-sdk 8.5.3 → 8.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kamino-finance/kliquidity-sdk",
3
- "version": "8.5.3",
3
+ "version": "8.5.4",
4
4
  "description": "Typescript SDK for interacting with the Kamino Liquidity (kliquidity) protocol",
5
5
  "repository": {
6
6
  "type": "git",
package/src/Kamino.ts CHANGED
@@ -1387,10 +1387,11 @@ export class Kamino {
1387
1387
  };
1388
1388
 
1389
1389
  /**
1390
- * Batch fetch share data for all or a filtered list of strategies
1390
+ * Used only for testing
1391
1391
  * @param strategyFilters strategy filters or a list of strategy public keys
1392
+ * @deprecated use getStrategiesShareData instead
1392
1393
  */
1393
- getStrategiesShareData = async (
1394
+ legacyGetStrategiesShareData = async (
1394
1395
  strategyFilters: StrategiesFilters | Address[],
1395
1396
  stratsWithAddresses?: StrategyWithAddress[],
1396
1397
  collateralInfos?: CollateralInfo[],
@@ -1523,6 +1524,169 @@ export class Kamino {
1523
1524
  return result;
1524
1525
  };
1525
1526
 
1527
+ /**
1528
+ * Batch fetch share data for all or a filtered list of strategies
1529
+ * @param strategyFilters strategy filters or a list of strategy public keys
1530
+ */
1531
+ getStrategiesShareData = async (
1532
+ strategyFilters: StrategiesFilters | Address[],
1533
+ stratsWithAddresses?: StrategyWithAddress[],
1534
+ collateralInfos?: CollateralInfo[],
1535
+ disabledTokensPrices?: Map<Address, Decimal>
1536
+ ): Promise<Array<ShareDataWithAddress>> => {
1537
+ const result: Array<ShareDataWithAddress> = [];
1538
+ const strategiesWithAddresses = stratsWithAddresses
1539
+ ? stratsWithAddresses
1540
+ : Array.isArray(strategyFilters)
1541
+ ? await this.getStrategiesWithAddresses(strategyFilters)
1542
+ : await this.getAllStrategiesWithFilters(strategyFilters);
1543
+ const fetchBalances: Promise<StrategyBalanceWithAddress>[] = [];
1544
+ const allScopePrices = strategiesWithAddresses.map((x) => x.strategy.scopePrices);
1545
+ const scopePrices = await this._scope.getMultipleOraclePrices(allScopePrices);
1546
+ const scopePricesMap: Record<Address, OraclePrices> = scopePrices.reduce(
1547
+ (map: Record<Address, OraclePrices>, [address, price]) => {
1548
+ map[address] = price;
1549
+ return map;
1550
+ },
1551
+ {}
1552
+ );
1553
+
1554
+ const activeStrategies = strategiesWithAddresses.filter(
1555
+ (x) => x.strategy.position !== DEFAULT_PUBLIC_KEY
1556
+ );
1557
+
1558
+ const poolsAndPositions = await batchFetch([...activeStrategies.map((x) => x.strategy.pool), ...activeStrategies.map((x) => x.strategy.position)], chunk => fetchEncodedAccounts(this._rpc, chunk));
1559
+ const pools = poolsAndPositions.slice(0, activeStrategies.length);
1560
+ const positions = poolsAndPositions.slice(activeStrategies.length);
1561
+
1562
+ const raydiumStrategies: StrategyWithAddress[] = [];
1563
+ const orcaStrategies: StrategyWithAddress[] = [];
1564
+ const meteoraStrategies: StrategyWithAddress[] = [];
1565
+
1566
+ const raydiumPools: Map<Address, PoolState> = new Map();
1567
+ const orcaPools: Map<Address, Whirlpool> = new Map();
1568
+ const meteoraPools: Map<Address, LbPair> = new Map();
1569
+
1570
+ const raydiumPositions: PersonalPositionState[] = [];
1571
+ const orcaPositions: OrcaPosition[] = [];
1572
+ const meteoraPositions: PositionV2[] = [];
1573
+
1574
+ for (let i = 0; i < activeStrategies.length; i++) {
1575
+ const pool = pools[i];
1576
+ const position = positions[i];
1577
+ const strategy = activeStrategies[i];
1578
+ if (!pool.exists || !position.exists) {
1579
+ console.error(`Pool or position does not exist for strategy ${strategy.address.toString()}, skipping`);
1580
+ continue;
1581
+ }
1582
+ const positionBuffer = Buffer.from(position.data);
1583
+ const poolBuffer = Buffer.from(pool.data);
1584
+
1585
+ switch (strategy.strategy.strategyDex.toNumber()) {
1586
+ case dexToNumber('RAYDIUM'):
1587
+ raydiumPools.set(strategy.strategy.pool, PoolState.decode(poolBuffer));
1588
+ raydiumPositions.push(PersonalPositionState.decode(positionBuffer));
1589
+ raydiumStrategies.push(strategy);
1590
+ break;
1591
+ case dexToNumber('ORCA'):
1592
+ orcaPools.set(strategy.strategy.pool, Whirlpool.decode(poolBuffer));
1593
+ orcaPositions.push(OrcaPosition.decode(positionBuffer));
1594
+ orcaStrategies.push(strategy);
1595
+ break;
1596
+ case dexToNumber('METEORA'):
1597
+ meteoraPools.set(strategy.strategy.pool, LbPair.decode(poolBuffer));
1598
+ meteoraPositions.push(PositionV2.decode(positionBuffer));
1599
+ meteoraStrategies.push(strategy);
1600
+ break;
1601
+ default:
1602
+ throw new Error(`Dex ${strategy.strategy.strategyDex.toNumber()} is not supported`);
1603
+ }
1604
+ }
1605
+
1606
+ const inactiveStrategies = strategiesWithAddresses.filter((x) => x.strategy.position === DEFAULT_PUBLIC_KEY);
1607
+ const collInfos = collateralInfos ? collateralInfos : await this.getCollateralInfos();
1608
+ const disabledPrices = disabledTokensPrices ? disabledTokensPrices : await this.getDisabledTokensPrices(collInfos);
1609
+ for (const { strategy, address } of inactiveStrategies) {
1610
+ const strategyPrices = await this.getStrategyPrices(
1611
+ strategy,
1612
+ collInfos,
1613
+ scopePricesMap[strategy.scopePrices],
1614
+ disabledPrices
1615
+ );
1616
+ result.push({
1617
+ address,
1618
+ strategy,
1619
+ shareData: getEmptyShareData({
1620
+ ...strategyPrices,
1621
+ poolPrice: ZERO,
1622
+ upperPrice: ZERO,
1623
+ lowerPrice: ZERO,
1624
+ twapPrice: ZERO,
1625
+ lowerResetPrice: ZERO,
1626
+ upperResetPrice: ZERO,
1627
+ }),
1628
+ });
1629
+ }
1630
+
1631
+ fetchBalances.push(
1632
+ ...this.getBalance<PoolState, PersonalPositionState>(
1633
+ raydiumStrategies,
1634
+ raydiumPools,
1635
+ raydiumPositions,
1636
+ this.getRaydiumBalances,
1637
+ collInfos,
1638
+ scopePricesMap,
1639
+ disabledPrices
1640
+ )
1641
+ );
1642
+
1643
+ fetchBalances.push(
1644
+ ...this.getBalance<Whirlpool, OrcaPosition>(
1645
+ orcaStrategies,
1646
+ orcaPools,
1647
+ orcaPositions,
1648
+ this.getOrcaBalances,
1649
+ collInfos,
1650
+ scopePricesMap,
1651
+ disabledPrices
1652
+ )
1653
+ );
1654
+
1655
+ fetchBalances.push(
1656
+ ...this.getBalance<LbPair, PositionV2>(
1657
+ meteoraStrategies,
1658
+ meteoraPools,
1659
+ meteoraPositions,
1660
+ this.getMeteoraBalances,
1661
+ collInfos,
1662
+ scopePricesMap,
1663
+ disabledPrices
1664
+ )
1665
+ );
1666
+
1667
+ const strategyBalances = await Promise.all(fetchBalances);
1668
+
1669
+ for (const { balance, strategyWithAddress } of strategyBalances) {
1670
+ const sharesFactor = Decimal.pow(10, strategyWithAddress.strategy.sharesMintDecimals.toString());
1671
+ const sharesIssued = new Decimal(strategyWithAddress.strategy.sharesIssued.toString());
1672
+ if (sharesIssued.isZero()) {
1673
+ result.push({
1674
+ address: strategyWithAddress.address,
1675
+ strategy: strategyWithAddress.strategy,
1676
+ shareData: { price: new Decimal(1), balance },
1677
+ });
1678
+ } else {
1679
+ result.push({
1680
+ address: strategyWithAddress.address,
1681
+ strategy: strategyWithAddress.strategy,
1682
+ shareData: { price: balance.computedHoldings.totalSum.div(sharesIssued).mul(sharesFactor), balance },
1683
+ });
1684
+ }
1685
+ }
1686
+
1687
+ return result;
1688
+ };
1689
+
1526
1690
  private getBalance = <PoolT, PositionT>(
1527
1691
  strategies: StrategyWithAddress[],
1528
1692
  pools: Map<Address, PoolT | null>,
@@ -1652,7 +1816,7 @@ export class Kamino {
1652
1816
  ): Promise<StrategyBalances> => {
1653
1817
  const strategyPricesPromise = this.getStrategyPrices(strategy, collateralInfos, prices, disabledTokensPrices);
1654
1818
  const rebalanceKind = numberToRebalanceType(strategy.rebalanceType);
1655
- const tokenHoldingsPromise = this.getMeteoraTokensBalances(strategy);
1819
+ const tokenHoldingsPromise = this.getMeteoraTokensBalances(strategy, pool, position);
1656
1820
  const [strategyPrices, tokenHoldings] = await Promise.all([strategyPricesPromise, tokenHoldingsPromise]);
1657
1821
 
1658
1822
  const computedHoldings: Holdings = this.getStrategyHoldingsUsd(
@@ -1749,11 +1913,11 @@ export class Kamino {
1749
1913
  return holdings;
1750
1914
  };
1751
1915
 
1752
- private getMeteoraTokensBalances = async (strategy: WhirlpoolStrategy): Promise<TokenHoldings> => {
1916
+ private getMeteoraTokensBalances = async (strategy: WhirlpoolStrategy, pool?: LbPair, position?: PositionV2): Promise<TokenHoldings> => {
1753
1917
  let aInvested = ZERO;
1754
1918
  let bInvested = ZERO;
1755
1919
  try {
1756
- const userPosition = await this.readMeteoraPosition(strategy.pool, strategy.position);
1920
+ const userPosition = await this.readMeteoraPosition(strategy.pool, strategy.position, pool, position);
1757
1921
 
1758
1922
  if (!userPosition?.amountX.isNaN() && !userPosition?.amountY.isNaN()) {
1759
1923
  aInvested = userPosition.amountX;
@@ -4557,9 +4721,9 @@ export class Kamino {
4557
4721
  };
4558
4722
  };
4559
4723
 
4560
- private readMeteoraPosition = async (poolPk: Address, positionPk: Address): Promise<MeteoraPosition> => {
4561
- const pool = await LbPair.fetch(this._rpc, poolPk, this._meteoraService.getMeteoraProgramId());
4562
- const position = await PositionV2.fetch(this._rpc, positionPk, this._meteoraService.getMeteoraProgramId());
4724
+ private readMeteoraPosition = async (poolPk: Address, positionPk: Address, pool?: LbPair | null, position?: PositionV2 | null): Promise<MeteoraPosition> => {
4725
+ pool = pool ?? await LbPair.fetch(this._rpc, poolPk, this._meteoraService.getMeteoraProgramId());
4726
+ position = position ?? await PositionV2.fetch(this._rpc, positionPk, this._meteoraService.getMeteoraProgramId());
4563
4727
  if (!pool || !position) {
4564
4728
  return {
4565
4729
  Address: positionPk,
@@ -4572,16 +4736,15 @@ export class Kamino {
4572
4736
  poolPk,
4573
4737
  position.lowerBinId
4574
4738
  );
4575
- const lowerBinArray = await BinArray.fetch(this._rpc, lowerTickPk, this._meteoraService.getMeteoraProgramId());
4576
- const upperBinArray = await BinArray.fetch(this._rpc, upperTickPk, this._meteoraService.getMeteoraProgramId());
4577
- if (!lowerBinArray || !upperBinArray) {
4739
+ const binArray = await BinArray.fetchMultiple(this._rpc, [lowerTickPk, upperTickPk], this._meteoraService.getMeteoraProgramId());
4740
+ if (!binArray || !binArray[0] || !binArray[1]) {
4578
4741
  return {
4579
4742
  Address: positionPk,
4580
4743
  amountX: new Decimal(0),
4581
4744
  amountY: new Decimal(0),
4582
4745
  };
4583
4746
  }
4584
- const binArrays = [lowerBinArray, upperBinArray];
4747
+ const binArrays = [binArray[0], binArray[1]];
4585
4748
  let totalAmountX = new Decimal(0);
4586
4749
  let totalAmountY = new Decimal(0);
4587
4750
  for (let idx = position.lowerBinId; idx <= position.upperBinId; idx++) {