@kamino-finance/kliquidity-sdk 8.3.0 → 8.3.2

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.
Files changed (77) hide show
  1. package/dist/Kamino.d.ts +12 -12
  2. package/dist/Kamino.d.ts.map +1 -1
  3. package/dist/Kamino.js +103 -122
  4. package/dist/Kamino.js.map +1 -1
  5. package/dist/constants/numericalValues.d.ts +3 -0
  6. package/dist/constants/numericalValues.d.ts.map +1 -1
  7. package/dist/constants/numericalValues.js +4 -1
  8. package/dist/constants/numericalValues.js.map +1 -1
  9. package/dist/rebalance_methods/autodriftRebalance.d.ts.map +1 -1
  10. package/dist/rebalance_methods/autodriftRebalance.js +10 -10
  11. package/dist/rebalance_methods/autodriftRebalance.js.map +1 -1
  12. package/dist/rebalance_methods/driftRebalance.d.ts.map +1 -1
  13. package/dist/rebalance_methods/driftRebalance.js +10 -10
  14. package/dist/rebalance_methods/driftRebalance.js.map +1 -1
  15. package/dist/rebalance_methods/expanderRebalance.d.ts.map +1 -1
  16. package/dist/rebalance_methods/expanderRebalance.js +3 -4
  17. package/dist/rebalance_methods/expanderRebalance.js.map +1 -1
  18. package/dist/rebalance_methods/pricePercentageRebalance.d.ts.map +1 -1
  19. package/dist/rebalance_methods/pricePercentageRebalance.js +5 -6
  20. package/dist/rebalance_methods/pricePercentageRebalance.js.map +1 -1
  21. package/dist/rebalance_methods/pricePercentageWithResetRebalance.d.ts.map +1 -1
  22. package/dist/rebalance_methods/pricePercentageWithResetRebalance.js +5 -6
  23. package/dist/rebalance_methods/pricePercentageWithResetRebalance.js.map +1 -1
  24. package/dist/rebalance_methods/takeProfitRebalance.d.ts.map +1 -1
  25. package/dist/rebalance_methods/takeProfitRebalance.js +5 -5
  26. package/dist/rebalance_methods/takeProfitRebalance.js.map +1 -1
  27. package/dist/services/OrcaService.d.ts +7 -11
  28. package/dist/services/OrcaService.d.ts.map +1 -1
  29. package/dist/services/OrcaService.js +132 -100
  30. package/dist/services/OrcaService.js.map +1 -1
  31. package/dist/services/OrcaWhirlpoolsResponse.d.ts +63 -92
  32. package/dist/services/OrcaWhirlpoolsResponse.d.ts.map +1 -1
  33. package/dist/utils/farms.d.ts +1 -0
  34. package/dist/utils/farms.d.ts.map +1 -0
  35. package/dist/utils/farms.js +2 -0
  36. package/dist/utils/farms.js.map +1 -0
  37. package/dist/utils/index.d.ts +1 -0
  38. package/dist/utils/index.d.ts.map +1 -1
  39. package/dist/utils/index.js +1 -0
  40. package/dist/utils/index.js.map +1 -1
  41. package/dist/utils/orca.d.ts +37 -1
  42. package/dist/utils/orca.d.ts.map +1 -1
  43. package/dist/utils/orca.js +242 -0
  44. package/dist/utils/orca.js.map +1 -1
  45. package/dist/utils/tokenUtils.d.ts +5 -5
  46. package/dist/utils/tokenUtils.d.ts.map +1 -1
  47. package/dist/utils/tokenUtils.js +11 -7
  48. package/dist/utils/tokenUtils.js.map +1 -1
  49. package/dist/utils/types.d.ts +5 -0
  50. package/dist/utils/types.d.ts.map +1 -1
  51. package/dist/utils/types.js.map +1 -1
  52. package/dist/utils/utils.d.ts +0 -1
  53. package/dist/utils/utils.d.ts.map +1 -1
  54. package/dist/utils/utils.js +3 -4
  55. package/dist/utils/utils.js.map +1 -1
  56. package/dist/utils/whirlpools.d.ts +12 -1
  57. package/dist/utils/whirlpools.d.ts.map +1 -1
  58. package/dist/utils/whirlpools.js +30 -29
  59. package/dist/utils/whirlpools.js.map +1 -1
  60. package/package.json +4 -3
  61. package/src/Kamino.ts +256 -209
  62. package/src/constants/numericalValues.ts +5 -0
  63. package/src/rebalance_methods/autodriftRebalance.ts +30 -22
  64. package/src/rebalance_methods/driftRebalance.ts +30 -22
  65. package/src/rebalance_methods/expanderRebalance.ts +7 -4
  66. package/src/rebalance_methods/pricePercentageRebalance.ts +13 -6
  67. package/src/rebalance_methods/pricePercentageWithResetRebalance.ts +13 -6
  68. package/src/rebalance_methods/takeProfitRebalance.ts +13 -5
  69. package/src/services/OrcaService.ts +162 -125
  70. package/src/services/OrcaWhirlpoolsResponse.ts +69 -101
  71. package/src/utils/farms.ts +0 -0
  72. package/src/utils/index.ts +1 -0
  73. package/src/utils/orca.ts +377 -1
  74. package/src/utils/tokenUtils.ts +5 -5
  75. package/src/utils/types.ts +7 -0
  76. package/src/utils/utils.ts +2 -4
  77. package/src/utils/whirlpools.ts +50 -31
package/src/Kamino.ts CHANGED
@@ -30,21 +30,15 @@ import {
30
30
  InitializeTickArrayAccounts,
31
31
  InitializeTickArrayArgs,
32
32
  } from './@codegen/whirlpools/instructions';
33
- import { Position, TickArray, Whirlpool } from './@codegen/whirlpools/accounts';
33
+ import { Position as OrcaPosition, TickArray, Whirlpool } from './@codegen/whirlpools/accounts';
34
34
  import {
35
- AddLiquidityQuote,
36
- AddLiquidityQuoteParam,
37
- defaultSlippagePercentage,
38
- getNearestValidTickIndexFromTickIndex,
39
- getNextValidTickIndex,
40
- getStartTickIndex,
41
- Percentage,
42
- priceToTickIndex,
43
- sqrtPriceX64ToPrice,
44
- tickIndexToPrice,
45
- } from '@orca-so/whirlpool-sdk';
46
- import { OrcaDAL } from '@orca-so/whirlpool-sdk/dist/dal/orca-dal';
47
- import { OrcaPosition } from '@orca-so/whirlpool-sdk/dist/position/orca-position';
35
+ sqrtPriceToPrice as orcaSqrtPriceToPrice,
36
+ getTickArrayStartTickIndex as orcaGetTickArrayStartTickIndex,
37
+ priceToTickIndex as orcaPriceToTickIndex,
38
+ IncreaseLiquidityQuote,
39
+ sqrtPriceToPrice,
40
+ tickIndexToPrice as orcaTickIndexToPrice,
41
+ } from '@orca-so/whirlpools-core';
48
42
  import {
49
43
  getEmptyShareData,
50
44
  Holdings,
@@ -119,7 +113,9 @@ import {
119
113
  WithdrawAllAndCloseIxns,
120
114
  WithdrawShares,
121
115
  ZERO,
122
- ZERO_BN,
116
+ getNearestValidTickIndexFromTickIndex as orcaGetNearestValidTickIndexFromTickIndex,
117
+ getIncreaseLiquidityQuote,
118
+ defaultSlippagePercentageBPS,
123
119
  } from './utils';
124
120
  import {
125
121
  checkExpectedVaultsBalances,
@@ -165,7 +161,7 @@ import {
165
161
  import BN from 'bn.js';
166
162
  import StrategyWithAddress from './models/StrategyWithAddress';
167
163
  import { Rebalancing, Uninitialized } from './@codegen/kliquidity/types/StrategyStatus';
168
- import { FRONTEND_KAMINO_STRATEGY_URL, METADATA_PROGRAM_ID, U64_MAX } from './constants';
164
+ import { FRONTEND_KAMINO_STRATEGY_URL, METADATA_PROGRAM_ID, U64_MAX, ZERO_BN } from './constants';
169
165
  import {
170
166
  CollateralInfo,
171
167
  ExecutiveWithdrawActionKind,
@@ -177,12 +173,7 @@ import {
177
173
  } from './@codegen/kliquidity/types';
178
174
  import { AmmConfig, PersonalPositionState, PoolState } from './@codegen/raydium/accounts';
179
175
 
180
- import { OrcaService, RaydiumService, Whirlpool as OrcaPool, WhirlpoolAprApy } from './services';
181
- import {
182
- getAddLiquidityQuote,
183
- InternalAddLiquidityQuote,
184
- InternalAddLiquidityQuoteParam,
185
- } from '@orca-so/whirlpool-sdk/dist/position/quotes/add-liquidity';
176
+ import { OrcaService, RaydiumService, Whirlpool as WhirlpoolAPIResponse, WhirlpoolAprApy } from './services';
186
177
  import { Pool } from './services/RaydiumPoolsResponse';
187
178
  import {
188
179
  UpdateCollectFeesFee,
@@ -327,10 +318,10 @@ import {
327
318
  import {
328
319
  getPdaProtocolPositionAddress,
329
320
  i32ToBytes,
330
- LiquidityMath,
331
- SqrtPriceMath,
332
- TickMath,
333
- TickUtils,
321
+ LiquidityMath as RaydiumLiquidityMath,
322
+ SqrtPriceMath as RaydiumSqrtPriceMath,
323
+ TickMath as RaydiumTickMath,
324
+ TickUtils as RaydiumTickUtils,
334
325
  } from '@raydium-io/raydium-sdk-v2/lib';
335
326
  import {
336
327
  ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
@@ -355,6 +346,7 @@ import { fetchMultipleLookupTableAccounts } from './utils/lookupTable';
355
346
  import type { AccountInfoBase, AccountInfoWithJsonData, AccountInfoWithPubkey } from '@solana/rpc-types';
356
347
  import { Connection } from '@solana/web3.js';
357
348
  import { toLegacyPublicKey } from './utils/compat';
349
+ import { IncreaseLiquidityQuoteParam } from '@orca-so/whirlpools';
358
350
 
359
351
  const addressEncoder = getAddressEncoder();
360
352
 
@@ -408,7 +400,7 @@ export class Kamino {
408
400
  }
409
401
 
410
402
  this._scope = new Scope(cluster, rpc);
411
- this._orcaService = new OrcaService(rpc, legacyConnection, cluster, whirlpoolProgramId);
403
+ this._orcaService = new OrcaService(rpc, legacyConnection, whirlpoolProgramId);
412
404
  this._raydiumService = new RaydiumService(rpc, legacyConnection, raydiumProgramId);
413
405
  this._meteoraService = new MeteoraService(rpc, meteoraProgramId);
414
406
 
@@ -419,6 +411,8 @@ export class Kamino {
419
411
 
420
412
  getConnection = () => this._rpc;
421
413
 
414
+ getLegacyConnection = () => this._legacyConnection;
415
+
422
416
  getProgramID = () => this._kliquidityProgramId;
423
417
 
424
418
  setGlobalConfig = (globalConfig: Address) => {
@@ -962,7 +956,7 @@ export class Kamino {
962
956
  if (pools.length === 0) {
963
957
  throw new Error(`No pool found for ${poolTokenA.toString()} and ${poolTokenB.toString()}`);
964
958
  }
965
- return pools[0].price;
959
+ return Number(pools[0].price);
966
960
  } else if (dex === 'RAYDIUM') {
967
961
  const pools = await this.getRaydiumPoolsForTokens(poolTokenA, poolTokenB);
968
962
  if (pools.length === 0) {
@@ -1033,7 +1027,7 @@ export class Kamino {
1033
1027
  let pool: Address = DEFAULT_PUBLIC_KEY;
1034
1028
  const orcaPools = await this.getOrcaPoolsForTokens(poolTokenA, poolTokenB);
1035
1029
  orcaPools.forEach((element) => {
1036
- if (element.lpFeeRate * FullBPS === feeBPS.toNumber()) {
1030
+ if (element.feeRate * FullBPS === feeBPS.toNumber()) {
1037
1031
  pool = address(element.address);
1038
1032
  }
1039
1033
  });
@@ -1080,22 +1074,24 @@ export class Kamino {
1080
1074
  if (dex === 'ORCA') {
1081
1075
  const pools = await this.getOrcaPoolsForTokens(tokenMintA, tokenMintB);
1082
1076
  const genericPoolInfos: GenericPoolInfo[] = await Promise.all(
1083
- pools.map(async (pool: OrcaPool) => {
1077
+ pools.map(async (pool: WhirlpoolAPIResponse) => {
1084
1078
  const positionsCount = new Decimal(await this.getPositionsCountForPool(dex, address(pool.address)));
1085
1079
  // read price from pool
1086
- const poolData = await this._orcaService.getPool(address(pool.address));
1080
+ const poolData = await this._orcaService.getOrcaWhirlpool(address(pool.address));
1087
1081
  if (!poolData) {
1088
1082
  throw new Error(`Pool ${pool.address} not found`);
1089
1083
  }
1090
1084
  const poolInfo: GenericPoolInfo = {
1091
1085
  dex,
1092
1086
  address: address(pool.address),
1093
- price: sqrtPriceX64ToPrice(poolData.sqrtPrice, pool.tokenA.decimals, pool.tokenB.decimals),
1094
- tokenMintA: address(pool.tokenA.mint),
1095
- tokenMintB: address(pool.tokenB.mint),
1096
- tvl: pool.tvl ? new Decimal(pool.tvl) : undefined,
1097
- feeRate: new Decimal(pool.lpFeeRate).mul(FullBPS),
1098
- volumeOnLast7d: pool.volume ? new Decimal(pool.volume.week) : undefined,
1087
+ price: new Decimal(
1088
+ orcaSqrtPriceToPrice(BigInt(poolData.sqrtPrice), pool.tokenA.decimals, pool.tokenB.decimals)
1089
+ ),
1090
+ tokenMintA: address(pool.tokenMintA),
1091
+ tokenMintB: address(pool.tokenMintB),
1092
+ tvl: pool.tvlUsdc ? new Decimal(pool.tvlUsdc) : undefined,
1093
+ feeRate: new Decimal(pool.feeRate).mul(FullBPS),
1094
+ volumeOnLast7d: pool.stats['7d'] ? new Decimal(pool.stats['7d'].volume) : undefined,
1099
1095
  tickSpacing: new Decimal(pool.tickSpacing),
1100
1096
  positions: positionsCount,
1101
1097
  };
@@ -1157,15 +1153,15 @@ export class Kamino {
1157
1153
  }
1158
1154
  }
1159
1155
 
1160
- getOrcaPoolsForTokens = async (poolTokenA: Address, poolTokenB: Address): Promise<OrcaPool[]> => {
1161
- const pools: OrcaPool[] = [];
1156
+ getOrcaPoolsForTokens = async (poolTokenA: Address, poolTokenB: Address): Promise<WhirlpoolAPIResponse[]> => {
1157
+ const pools: WhirlpoolAPIResponse[] = [];
1162
1158
  const poolTokenAString = poolTokenA.toString();
1163
1159
  const poolTokenBString = poolTokenB.toString();
1164
1160
  const whirlpools = await this._orcaService.getOrcaWhirlpools();
1165
- whirlpools.whirlpools.forEach((element) => {
1161
+ whirlpools.forEach((element) => {
1166
1162
  if (
1167
- (element.tokenA.mint === poolTokenAString && element.tokenB.mint === poolTokenBString) ||
1168
- (element.tokenA.mint === poolTokenBString && element.tokenB.mint === poolTokenAString)
1163
+ (element.tokenMintA === poolTokenAString && element.tokenMintB === poolTokenBString) ||
1164
+ (element.tokenMintA === poolTokenBString && element.tokenMintB === poolTokenAString)
1169
1165
  )
1170
1166
  pools.push(element);
1171
1167
  });
@@ -1484,7 +1480,7 @@ export class Kamino {
1484
1480
  );
1485
1481
 
1486
1482
  fetchBalances.push(
1487
- ...this.getBalance<Whirlpool, Position>(
1483
+ ...this.getBalance<Whirlpool, OrcaPosition>(
1488
1484
  orcaStrategies,
1489
1485
  orcaPools,
1490
1486
  orcaPositions,
@@ -1602,18 +1598,18 @@ export class Kamino {
1602
1598
  const decimalsA = strategy.tokenAMintDecimals.toNumber();
1603
1599
  const decimalsB = strategy.tokenBMintDecimals.toNumber();
1604
1600
 
1605
- const poolPrice = SqrtPriceMath.sqrtPriceX64ToPrice(pool.sqrtPriceX64, decimalsA, decimalsB);
1601
+ const poolPrice = RaydiumSqrtPriceMath.sqrtPriceX64ToPrice(pool.sqrtPriceX64, decimalsA, decimalsB);
1606
1602
  const twapPrice =
1607
1603
  strategyPrices.aTwapPrice !== null && strategyPrices.bTwapPrice !== null
1608
1604
  ? strategyPrices.aTwapPrice.div(strategyPrices.bTwapPrice)
1609
1605
  : null;
1610
- const upperPrice = SqrtPriceMath.sqrtPriceX64ToPrice(
1611
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
1606
+ const upperPrice = RaydiumSqrtPriceMath.sqrtPriceX64ToPrice(
1607
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
1612
1608
  decimalsA,
1613
1609
  decimalsB
1614
1610
  );
1615
- const lowerPrice = SqrtPriceMath.sqrtPriceX64ToPrice(
1616
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
1611
+ const lowerPrice = RaydiumSqrtPriceMath.sqrtPriceX64ToPrice(
1612
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
1617
1613
  decimalsA,
1618
1614
  decimalsB
1619
1615
  );
@@ -1726,10 +1722,10 @@ export class Kamino {
1726
1722
  position: PersonalPositionState,
1727
1723
  mode: 'DEPOSIT' | 'WITHDRAW' = 'WITHDRAW'
1728
1724
  ): TokenHoldings => {
1729
- const lowerSqrtPriceX64 = SqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex);
1730
- const upperSqrtPriceX64 = SqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex);
1725
+ const lowerSqrtPriceX64 = RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex);
1726
+ const upperSqrtPriceX64 = RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex);
1731
1727
 
1732
- const { amountA, amountB } = LiquidityMath.getAmountsFromLiquidity(
1728
+ const { amountA, amountB } = RaydiumLiquidityMath.getAmountsFromLiquidity(
1733
1729
  pool.sqrtPriceX64,
1734
1730
  new BN(lowerSqrtPriceX64),
1735
1731
  new BN(upperSqrtPriceX64),
@@ -1790,7 +1786,7 @@ export class Kamino {
1790
1786
  private getOrcaBalances = async (
1791
1787
  strategy: WhirlpoolStrategy,
1792
1788
  pool: Whirlpool,
1793
- position: Position,
1789
+ position: OrcaPosition,
1794
1790
  collateralInfos: CollateralInfo[],
1795
1791
  prices?: OraclePrices,
1796
1792
  disabledTokensPrices?: Map<Address, Decimal>,
@@ -1814,13 +1810,13 @@ export class Kamino {
1814
1810
  const decimalsA = strategy.tokenAMintDecimals.toNumber();
1815
1811
  const decimalsB = strategy.tokenBMintDecimals.toNumber();
1816
1812
 
1817
- const poolPrice = sqrtPriceX64ToPrice(pool.sqrtPrice, decimalsA, decimalsB);
1813
+ const poolPrice = new Decimal(orcaSqrtPriceToPrice(BigInt(pool.sqrtPrice.toString()), decimalsA, decimalsB));
1818
1814
  const twapPrice =
1819
1815
  strategyPrices.aTwapPrice !== null && strategyPrices.bTwapPrice !== null
1820
1816
  ? strategyPrices.aTwapPrice.div(strategyPrices.bTwapPrice)
1821
1817
  : null;
1822
- const upperPrice = tickIndexToPrice(position.tickUpperIndex, decimalsA, decimalsB);
1823
- const lowerPrice = tickIndexToPrice(position.tickLowerIndex, decimalsA, decimalsB);
1818
+ const upperPrice = new Decimal(orcaTickIndexToPrice(position.tickUpperIndex, decimalsA, decimalsB));
1819
+ const lowerPrice = new Decimal(orcaTickIndexToPrice(position.tickLowerIndex, decimalsA, decimalsB));
1824
1820
  let lowerResetPrice: Decimal | null = null;
1825
1821
  let upperResetPrice: Decimal | null = null;
1826
1822
  const dex = numberToDex(strategy.strategyDex.toNumber());
@@ -1856,14 +1852,14 @@ export class Kamino {
1856
1852
  private getOrcaTokensBalances = (
1857
1853
  strategy: WhirlpoolStrategy,
1858
1854
  pool: Whirlpool,
1859
- position: Position,
1855
+ position: OrcaPosition,
1860
1856
  mode: 'DEPOSIT' | 'WITHDRAW' = 'WITHDRAW'
1861
1857
  ): TokenHoldings => {
1862
1858
  const quote = getRemoveLiquidityQuote(
1863
1859
  {
1864
1860
  positionAddress: strategy.position,
1865
1861
  liquidity: position.liquidity,
1866
- slippageTolerance: Percentage.fromFraction(0, 1000),
1862
+ slippageTolerance: { numerator: ZERO_BN, denominator: new BN(1000) },
1867
1863
  sqrtPrice: pool.sqrtPrice,
1868
1864
  tickLowerIndex: position.tickLowerIndex,
1869
1865
  tickUpperIndex: position.tickUpperIndex,
@@ -1975,7 +1971,7 @@ export class Kamino {
1975
1971
  throw Error(`Could not fetch Orca whirlpool position state with pubkey ${strategy.position.toString()}`);
1976
1972
  }
1977
1973
  const whirlpool = Whirlpool.decode(Buffer.from(whirlpoolAcc.data[0], 'base64'));
1978
- const position = Position.decode(Buffer.from(positionAcc.data[0], 'base64'));
1974
+ const position = OrcaPosition.decode(Buffer.from(positionAcc.data[0], 'base64'));
1979
1975
  return this.getOrcaTokensBalances(strategy, whirlpool, position, mode);
1980
1976
  } else if (strategy.strategyDex.toNumber() === dexToNumber('RAYDIUM')) {
1981
1977
  const [poolStateAcc, positionAcc] = (
@@ -2049,7 +2045,7 @@ export class Kamino {
2049
2045
  throw Error(`Could not fetch Orca whirlpool position state with pubkey ${strategy.position.toString()}`);
2050
2046
  }
2051
2047
  const whirlpool = Whirlpool.decode(Buffer.from(whirlpoolAcc.data[0], 'base64'));
2052
- const position = Position.decode(Buffer.from(positionAcc.data[0], 'base64'));
2048
+ const position = OrcaPosition.decode(Buffer.from(positionAcc.data[0], 'base64'));
2053
2049
 
2054
2050
  return this.getOrcaBalances(
2055
2051
  strategy,
@@ -2437,12 +2433,12 @@ export class Kamino {
2437
2433
  if (positionPk === DEFAULT_PUBLIC_KEY) {
2438
2434
  return { lowerPrice: ZERO, upperPrice: ZERO };
2439
2435
  }
2440
- const position = await Position.fetch(this._rpc, positionPk, this._orcaService.getWhirlpoolProgramId());
2436
+ const position = await OrcaPosition.fetch(this._rpc, positionPk, this._orcaService.getWhirlpoolProgramId());
2441
2437
  if (!position) {
2442
2438
  return { lowerPrice: ZERO, upperPrice: ZERO };
2443
2439
  }
2444
- const lowerPrice = tickIndexToPrice(position.tickLowerIndex, decimalsA, decimalsB);
2445
- const upperPrice = tickIndexToPrice(position.tickUpperIndex, decimalsA, decimalsB);
2440
+ const lowerPrice = new Decimal(orcaTickIndexToPrice(position.tickLowerIndex, decimalsA, decimalsB));
2441
+ const upperPrice = new Decimal(orcaTickIndexToPrice(position.tickUpperIndex, decimalsA, decimalsB));
2446
2442
 
2447
2443
  const positionRange: PositionRange = { lowerPrice, upperPrice };
2448
2444
 
@@ -2465,14 +2461,14 @@ export class Kamino {
2465
2461
  if (!position) {
2466
2462
  return { lowerPrice: ZERO, upperPrice: ZERO };
2467
2463
  }
2468
- const lowerPrice = sqrtPriceX64ToPrice(
2469
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
2464
+ const lowerPrice = RaydiumSqrtPriceMath.sqrtPriceX64ToPrice(
2465
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
2470
2466
  decimalsA,
2471
2467
  decimalsB
2472
2468
  );
2473
2469
 
2474
- const upperPrice = sqrtPriceX64ToPrice(
2475
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
2470
+ const upperPrice = RaydiumSqrtPriceMath.sqrtPriceX64ToPrice(
2471
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
2476
2472
  decimalsA,
2477
2473
  decimalsB
2478
2474
  );
@@ -2554,17 +2550,21 @@ export class Kamino {
2554
2550
  return whirlpoolMap;
2555
2551
  };
2556
2552
 
2553
+ getAllWhirlpoolsFromAPI = async (tokens: Address[] = []): Promise<WhirlpoolAPIResponse[]> => {
2554
+ return (await this._orcaService.getOrcaWhirlpools(tokens));
2555
+ };
2556
+
2557
2557
  /**
2558
2558
  * Get a list of Orca positions from public keys
2559
2559
  * @param positions
2560
2560
  */
2561
- getOrcaPositions = async (positions: Address[]): Promise<(Position | null)[]> => {
2561
+ getOrcaPositions = async (positions: Address[]): Promise<(OrcaPosition | null)[]> => {
2562
2562
  const nonDefaults = positions.filter((value) => value !== DEFAULT_PUBLIC_KEY);
2563
2563
  const fetched = await batchFetch(nonDefaults, (chunk) =>
2564
- Position.fetchMultiple(this._rpc, chunk, this._orcaService.getWhirlpoolProgramId())
2564
+ OrcaPosition.fetchMultiple(this._rpc, chunk, this._orcaService.getWhirlpoolProgramId())
2565
2565
  );
2566
- const fetchedMap: Record<string, Position | null> = fetched.reduce(
2567
- (map: Record<Address, Position | null>, position, i) => {
2566
+ const fetchedMap: Record<string, OrcaPosition | null> = fetched.reduce(
2567
+ (map: Record<Address, OrcaPosition | null>, position, i) => {
2568
2568
  map[nonDefaults[i]] = position;
2569
2569
  return map;
2570
2570
  },
@@ -2972,8 +2972,8 @@ export class Kamino {
2972
2972
  private getWhirlpoolStateIfNotFetched = async (
2973
2973
  whirlpool: Address | WhirlpoolWithAddress
2974
2974
  ): Promise<WhirlpoolWithAddress> => {
2975
- const hasWhirlpoolBeenFetched = (object: Address | WhirlpoolWithAddress): object is WhirlpoolWithAddress => {
2976
- return 'whirlpool' in object;
2975
+ const hasWhirlpoolBeenFetched = (object: Address | WhirlpoolWithAddress) => {
2976
+ return typeof object !== 'string' && 'whirlpool' in object;
2977
2977
  };
2978
2978
 
2979
2979
  if (hasWhirlpoolBeenFetched(whirlpool)) {
@@ -2988,8 +2988,8 @@ export class Kamino {
2988
2988
  };
2989
2989
 
2990
2990
  private getMeteoraStateIfNotFetched = async (lbPair: Address | LbPairWithAddress): Promise<LbPairWithAddress> => {
2991
- const hasLbPairBeenFetched = (object: Address | LbPairWithAddress): object is LbPairWithAddress => {
2992
- return 'lbPair' in object;
2991
+ const hasLbPairBeenFetched = (object: Address | LbPairWithAddress) => {
2992
+ return typeof object !== 'string' && 'pool' in object;
2993
2993
  };
2994
2994
 
2995
2995
  if (hasLbPairBeenFetched(lbPair)) {
@@ -4501,8 +4501,8 @@ export class Kamino {
4501
4501
  tickLowerIndex: number,
4502
4502
  tickUpperIndex: number
4503
4503
  ): Promise<LowerAndUpperTickPubkeys> => {
4504
- const startTickIndex = getStartTickIndex(tickLowerIndex, whirlpoolState.tickSpacing, 0);
4505
- const endTickIndex = getStartTickIndex(tickUpperIndex, whirlpoolState.tickSpacing, 0);
4504
+ const startTickIndex = orcaGetTickArrayStartTickIndex(tickLowerIndex, whirlpoolState.tickSpacing);
4505
+ const endTickIndex = orcaGetTickArrayStartTickIndex(tickUpperIndex, whirlpoolState.tickSpacing);
4506
4506
 
4507
4507
  const [lowerTickPubkey, lowerTickBump] = await getProgramDerivedAddress({
4508
4508
  seeds: [Buffer.from('tick_array'), addressEncoder.encode(whirlpool), Buffer.from(startTickIndex.toString())],
@@ -4526,8 +4526,8 @@ export class Kamino {
4526
4526
  tickLowerIndex: number,
4527
4527
  tickUpperIndex: number
4528
4528
  ): Promise<LowerAndUpperTickPubkeys> => {
4529
- const startTickIndex = TickUtils.getTickArrayStartIndexByTick(tickLowerIndex, poolState.tickSpacing);
4530
- const endTickIndex = TickUtils.getTickArrayStartIndexByTick(tickUpperIndex, poolState.tickSpacing);
4529
+ const startTickIndex = RaydiumTickUtils.getTickArrayStartIndexByTick(tickLowerIndex, poolState.tickSpacing);
4530
+ const endTickIndex = RaydiumTickUtils.getTickArrayStartIndexByTick(tickUpperIndex, poolState.tickSpacing);
4531
4531
 
4532
4532
  const [lowerTickPubkey, lowerTickBump] = await getProgramDerivedAddress({
4533
4533
  seeds: [Buffer.from('tick_array'), addressEncoder.encode(pool), i32ToBytes(startTickIndex)],
@@ -4767,12 +4767,12 @@ export class Kamino {
4767
4767
  const decimalsA = await getMintDecimals(this._rpc, whirlpool.tokenMintA);
4768
4768
  const decimalsB = await getMintDecimals(this._rpc, whirlpool.tokenMintB);
4769
4769
 
4770
- const tickLowerIndex = getNextValidTickIndex(
4771
- priceToTickIndex(priceLower, decimalsA, decimalsB),
4770
+ const tickLowerIndex = orcaGetTickArrayStartTickIndex(
4771
+ orcaPriceToTickIndex(priceLower.toNumber(), decimalsA, decimalsB),
4772
4772
  whirlpool.tickSpacing
4773
4773
  );
4774
- const tickUpperIndex = getNextValidTickIndex(
4775
- priceToTickIndex(priceUpper, decimalsA, decimalsB),
4774
+ const tickUpperIndex = orcaGetTickArrayStartTickIndex(
4775
+ orcaPriceToTickIndex(priceUpper.toNumber(), decimalsA, decimalsB),
4776
4776
  whirlpool.tickSpacing
4777
4777
  );
4778
4778
 
@@ -4898,15 +4898,15 @@ export class Kamino {
4898
4898
  const decimalsA = await getMintDecimals(this._rpc, poolState.tokenMint0);
4899
4899
  const decimalsB = await getMintDecimals(this._rpc, poolState.tokenMint1);
4900
4900
 
4901
- const tickLowerIndex = TickMath.getTickWithPriceAndTickspacing(
4902
- TickMath.roundPriceWithTickspacing(priceLower, poolState.tickSpacing, decimalsA, decimalsB),
4901
+ const tickLowerIndex = RaydiumTickMath.getTickWithPriceAndTickspacing(
4902
+ RaydiumTickMath.roundPriceWithTickspacing(priceLower, poolState.tickSpacing, decimalsA, decimalsB),
4903
4903
  poolState.tickSpacing,
4904
4904
  decimalsA,
4905
4905
  decimalsB
4906
4906
  );
4907
4907
 
4908
- const tickUpperIndex = TickMath.getTickWithPriceAndTickspacing(
4909
- TickMath.roundPriceWithTickspacing(priceUpper, poolState.tickSpacing, decimalsA, decimalsB),
4908
+ const tickUpperIndex = RaydiumTickMath.getTickWithPriceAndTickspacing(
4909
+ RaydiumTickMath.roundPriceWithTickspacing(priceUpper, poolState.tickSpacing, decimalsA, decimalsB),
4910
4910
  poolState.tickSpacing,
4911
4911
  decimalsA,
4912
4912
  decimalsB
@@ -5461,7 +5461,7 @@ export class Kamino {
5461
5461
  const { whirlpool: whilrpoolState } = await this.getWhirlpoolStateIfNotFetched(pool);
5462
5462
  if (rebalanceTypeKind.kind === RebalanceType.Drift.kind) {
5463
5463
  processedRebalanceParams[0] = new Decimal(
5464
- getNearestValidTickIndexFromTickIndex(rebalanceParams[0].toNumber(), whilrpoolState.tickSpacing)
5464
+ orcaGetNearestValidTickIndexFromTickIndex(rebalanceParams[0].toNumber(), whilrpoolState.tickSpacing)
5465
5465
  );
5466
5466
  }
5467
5467
  }
@@ -5830,7 +5830,7 @@ export class Kamino {
5830
5830
  return getPositionRangeFromExpanderParams(price, rebalanceParams[0], rebalanceParams[1]);
5831
5831
 
5832
5832
  case RebalanceType.Autodrift.kind:
5833
- const currentTickIndex = priceToTickIndex(price, tokenADecimals, tokenBDecimals);
5833
+ const currentTickIndex = orcaPriceToTickIndex(price.toNumber(), tokenADecimals, tokenBDecimals);
5834
5834
  const startMidTick = new Decimal(currentTickIndex);
5835
5835
  return getPositionRangeFromAutodriftParams(
5836
5836
  dex,
@@ -5852,12 +5852,22 @@ export class Kamino {
5852
5852
  const pool = strategyWithAddress.strategy.pool;
5853
5853
  const dex = numberToDex(strategyWithAddress.strategy.strategyDex.toNumber());
5854
5854
 
5855
- return this.getCurrentPriceFromPool(dex, pool);
5855
+ return this.getCurrentPriceFromPool(
5856
+ dex,
5857
+ pool,
5858
+ strategyWithAddress.strategy.tokenAMintDecimals.toNumber(),
5859
+ strategyWithAddress.strategy.tokenBMintDecimals.toNumber()
5860
+ );
5856
5861
  }
5857
5862
 
5858
- async getCurrentPriceFromPool(dex: Dex, pool: Address): Promise<Decimal> {
5863
+ async getCurrentPriceFromPool(
5864
+ dex: Dex,
5865
+ pool: Address,
5866
+ tokenADecimals?: number,
5867
+ tokenBDecimals?: number
5868
+ ): Promise<Decimal> {
5859
5869
  if (dex === 'ORCA') {
5860
- return this.getOrcaPoolPrice(pool);
5870
+ return this.getOrcaPoolPrice(pool, tokenADecimals, tokenBDecimals);
5861
5871
  } else if (dex === 'RAYDIUM') {
5862
5872
  return this.getRaydiumPoolPrice(pool);
5863
5873
  } else if (dex === 'METEORA') {
@@ -6234,9 +6244,9 @@ export class Kamino {
6234
6244
  /**
6235
6245
  * Read the pool price for a specific dex and pool
6236
6246
  */
6237
- async getPoolPrice(dex: Dex, pool: Address): Promise<Decimal> {
6247
+ async getPoolPrice(dex: Dex, pool: Address, tokenADecimals: number, tokenBDecimals: number): Promise<Decimal> {
6238
6248
  if (dex === 'ORCA') {
6239
- return this.getOrcaPoolPrice(pool);
6249
+ return this.getOrcaPoolPrice(pool, tokenADecimals, tokenBDecimals);
6240
6250
  } else if (dex === 'RAYDIUM') {
6241
6251
  return this.getRaydiumPoolPrice(pool);
6242
6252
  } else if (dex === 'METEORA') {
@@ -6246,12 +6256,25 @@ export class Kamino {
6246
6256
  }
6247
6257
  }
6248
6258
 
6249
- async getOrcaPoolPrice(pool: Address): Promise<Decimal> {
6250
- const poolData = await this._orcaService.getPool(pool);
6251
- if (!poolData) {
6252
- throw Error(`Could not fetch Whirlpool data for ${pool.toString()}`);
6259
+ async getOrcaPoolPrice(pool: Address, tokenADecimals?: number, tokenBDecimals?: number): Promise<Decimal> {
6260
+ // if the decimals are provided read from API, otherwise use RPC
6261
+ if (tokenADecimals && tokenBDecimals) {
6262
+ const whirlpool = await Whirlpool.fetch(this._rpc, pool, this._orcaService.getWhirlpoolProgramId());
6263
+ if (!whirlpool) {
6264
+ throw Error(`Could not fetch Whirlpool data for ${pool.toString()}`);
6265
+ }
6266
+
6267
+ return new Decimal(sqrtPriceToPrice(BigInt(whirlpool.sqrtPrice.toString()), tokenADecimals, tokenBDecimals));
6268
+ } else {
6269
+ const whirlpool = await this._orcaService.getOrcaWhirlpool(pool);
6270
+ if (!whirlpool) {
6271
+ throw Error(`Could not fetch Whirlpool data for ${pool.toString()}`);
6272
+ }
6273
+
6274
+ return new Decimal(
6275
+ sqrtPriceToPrice(BigInt(whirlpool.sqrtPrice.toString()), whirlpool.tokenA.decimals, whirlpool.tokenB.decimals)
6276
+ );
6253
6277
  }
6254
- return poolData.price;
6255
6278
  }
6256
6279
 
6257
6280
  async getRaydiumPoolPrice(pool: Address): Promise<Decimal> {
@@ -6260,7 +6283,7 @@ export class Kamino {
6260
6283
  throw new Error(`Raydium poolState ${pool.toString()} is not found`);
6261
6284
  }
6262
6285
 
6263
- const price = SqrtPriceMath.sqrtPriceX64ToPrice(
6286
+ const price = RaydiumSqrtPriceMath.sqrtPriceX64ToPrice(
6264
6287
  poolState.sqrtPriceX64,
6265
6288
  poolState.mintDecimals0,
6266
6289
  poolState.mintDecimals1
@@ -6692,7 +6715,7 @@ export class Kamino {
6692
6715
  */
6693
6716
  getStrategyAprApy = async (
6694
6717
  strategy: Address | StrategyWithAddress,
6695
- orcaPools?: OrcaPool[],
6718
+ orcaPools?: WhirlpoolAPIResponse[],
6696
6719
  raydiumPools?: Pool[]
6697
6720
  ): Promise<WhirlpoolAprApy> => {
6698
6721
  const { strategy: strategyState } = await this.getStrategyStateIfNotFetched(strategy);
@@ -6717,7 +6740,7 @@ export class Kamino {
6717
6740
  if (isOrca) {
6718
6741
  const prices = await this.getAllPrices();
6719
6742
  const collateralInfos = await this.getCollateralInfos();
6720
- return this._orcaService.getStrategyWhirlpoolPoolAprApy(strategyState, collateralInfos, prices, orcaPools);
6743
+ return this._orcaService.getStrategyWhirlpoolPoolAprApy(strategyState, collateralInfos, prices);
6721
6744
  }
6722
6745
  if (isRaydium) {
6723
6746
  return this._raydiumService.getStrategyWhirlpoolPoolAprApy(strategyState, raydiumPools);
@@ -6951,10 +6974,10 @@ export class Kamino {
6951
6974
  const decimalsA = poolState.mintDecimals0;
6952
6975
  const decimalsB = poolState.mintDecimals1;
6953
6976
 
6954
- const { amountA, amountB } = LiquidityMath.getAmountsFromLiquidity(
6977
+ const { amountA, amountB } = RaydiumLiquidityMath.getAmountsFromLiquidity(
6955
6978
  poolState.sqrtPriceX64,
6956
- SqrtPriceMath.priceToSqrtPriceX64(lowerPrice, decimalsA, decimalsB),
6957
- SqrtPriceMath.priceToSqrtPriceX64(upperPrice, decimalsA, decimalsB),
6979
+ RaydiumSqrtPriceMath.priceToSqrtPriceX64(lowerPrice, decimalsA, decimalsB),
6980
+ RaydiumSqrtPriceMath.priceToSqrtPriceX64(upperPrice, decimalsA, decimalsB),
6958
6981
  new BN(100_000_000),
6959
6982
  true
6960
6983
  );
@@ -6972,31 +6995,31 @@ export class Kamino {
6972
6995
  const decimalsA = await getMintDecimals(this._rpc, tokenMintA);
6973
6996
  const decimalsB = await getMintDecimals(this._rpc, tokenMintB);
6974
6997
 
6975
- const tickLowerIndex = getNearestValidTickIndexFromTickIndex(
6976
- priceToTickIndex(lowerPrice, decimalsA, decimalsB),
6998
+ const tickLowerIndex = orcaGetNearestValidTickIndexFromTickIndex(
6999
+ orcaPriceToTickIndex(lowerPrice.toNumber(), decimalsA, decimalsB),
6977
7000
  whirlpoolState.tickSpacing
6978
7001
  );
6979
- const tickUpperIndex = getNearestValidTickIndexFromTickIndex(
6980
- priceToTickIndex(upperPrice, decimalsA, decimalsB),
7002
+ const tickUpperIndex = orcaGetNearestValidTickIndexFromTickIndex(
7003
+ orcaPriceToTickIndex(upperPrice.toNumber(), decimalsA, decimalsB),
6981
7004
  whirlpoolState.tickSpacing
6982
7005
  );
6983
7006
 
6984
- const params: InternalAddLiquidityQuoteParam = {
6985
- tokenMintA: toLegacyPublicKey(tokenMintA),
6986
- tokenMintB: toLegacyPublicKey(tokenMintB),
6987
- tickCurrentIndex: whirlpoolState.tickCurrentIndex,
6988
- sqrtPrice: whirlpoolState.sqrtPrice,
6989
- inputTokenMint: toLegacyPublicKey(tokenMintA),
6990
- inputTokenAmount: new BN(collToLamportsDecimal(tokenAAmountToDeposit, decimalsA).toString()),
6991
- tickLowerIndex,
6992
- tickUpperIndex,
6993
- slippageTolerance: defaultSlippagePercentage,
7007
+ const param: IncreaseLiquidityQuoteParam = {
7008
+ tokenA: BigInt(collToLamportsDecimal(tokenAAmountToDeposit, decimalsA).toString()),
6994
7009
  };
6995
7010
 
6996
- const addLiqResult: InternalAddLiquidityQuote = getAddLiquidityQuote(params);
7011
+ const addLiqResult: IncreaseLiquidityQuote = getIncreaseLiquidityQuote(
7012
+ param,
7013
+ whirlpoolState,
7014
+ tickLowerIndex,
7015
+ tickUpperIndex,
7016
+ defaultSlippagePercentageBPS,
7017
+ undefined,
7018
+ undefined
7019
+ );
6997
7020
  return [
6998
- lamportsToNumberDecimal(addLiqResult.estTokenA.toNumber(), decimalsA),
6999
- lamportsToNumberDecimal(addLiqResult.estTokenB.toNumber(), decimalsB),
7021
+ lamportsToNumberDecimal(new Decimal(addLiqResult.tokenEstA.toString()), decimalsA),
7022
+ lamportsToNumberDecimal(new Decimal(addLiqResult.tokenEstB.toString()), decimalsB),
7000
7023
  ];
7001
7024
  } else if (dex === 'METEORA') {
7002
7025
  const poolState = await LbPair.fetch(this._rpc, pool, this._meteoraService.getMeteoraProgramId());
@@ -7118,9 +7141,7 @@ export class Kamino {
7118
7141
  }
7119
7142
 
7120
7143
  return this.calculateAmountsOrca({
7121
- whirlpoolConfig: whirlpool.whirlpoolsConfig,
7122
- tokenAMint: strategyState.tokenAMint,
7123
- tokenBMint: strategyState.tokenBMint,
7144
+ whirlpoolState: whirlpool,
7124
7145
  positionAddress: strategyState.position,
7125
7146
  tokenAAmount,
7126
7147
  tokenBAmount,
@@ -7135,16 +7156,12 @@ export class Kamino {
7135
7156
  };
7136
7157
 
7137
7158
  calculateAmountsOrca = async ({
7138
- whirlpoolConfig,
7139
- tokenAMint,
7140
- tokenBMint,
7159
+ whirlpoolState,
7141
7160
  positionAddress,
7142
7161
  tokenAAmount,
7143
7162
  tokenBAmount,
7144
7163
  }: {
7145
- whirlpoolConfig: Address;
7146
- tokenAMint: Address;
7147
- tokenBMint: Address;
7164
+ whirlpoolState: Whirlpool;
7148
7165
  positionAddress: Address;
7149
7166
  tokenAAmount?: Decimal;
7150
7167
  tokenBAmount?: Decimal;
@@ -7152,47 +7169,61 @@ export class Kamino {
7152
7169
  if (!tokenAAmount && !tokenBAmount) {
7153
7170
  return [new Decimal(0), new Decimal(0)];
7154
7171
  }
7172
+
7155
7173
  // Given A in ATA, calc how much A and B
7156
- const accessor = new OrcaDAL(whirlpoolConfig, this._orcaService.getWhirlpoolProgramId(), this._legacyConnection);
7157
- const orcaPosition = new OrcaPosition(accessor);
7158
- const defaultSlippagePercentage = Percentage.fromFraction(1, 1000); // 0.1%
7174
+ const defaultSlippagePercentageBPS = 10;
7175
+ const positionState = await OrcaPosition.fetch(
7176
+ this._rpc,
7177
+ positionAddress,
7178
+ this._orcaService.getWhirlpoolProgramId()
7179
+ );
7180
+ if (!positionState) {
7181
+ throw new Error(`Unable to get Orca position for pubkey ${positionAddress}`);
7182
+ }
7159
7183
 
7160
- const primaryTokenAmount = tokenAAmount || tokenBAmount;
7161
- const primaryTokenMint = tokenAAmount ? tokenAMint : tokenBMint;
7162
- const secondaryTokenAmount = tokenAAmount ? tokenBAmount : tokenAAmount;
7163
- const secondaryTokenMint = tokenAAmount ? tokenBMint : tokenAMint;
7184
+ let computedAmounts: [Decimal, Decimal] = [new Decimal(0), new Decimal(0)];
7164
7185
 
7165
- let params: AddLiquidityQuoteParam = {
7166
- positionAddress,
7167
- tokenMint: primaryTokenMint,
7168
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
7169
- tokenAmount: new BN(primaryTokenAmount!.toString()), // safe to use ! here because we check in the beginning that at least one of the amounts are not undefined;
7170
- refresh: true,
7171
- slippageTolerance: defaultSlippagePercentage,
7172
- };
7173
- const estimatedGivenPrimary: AddLiquidityQuote = await orcaPosition.getAddLiquidityQuote(params);
7186
+ if (tokenAAmount) {
7187
+ const tokenAForQuote = BigInt(tokenAAmount.toString());
7188
+ const params: IncreaseLiquidityQuoteParam = {
7189
+ tokenA: tokenAForQuote,
7190
+ };
7191
+ const estimatedGivenA: IncreaseLiquidityQuote = getIncreaseLiquidityQuote(
7192
+ params,
7193
+ whirlpoolState,
7194
+ positionState.tickLowerIndex,
7195
+ positionState.tickUpperIndex,
7196
+ defaultSlippagePercentageBPS,
7197
+ undefined, // todo: use new Wirlpool state and read transfer fees
7198
+ undefined
7199
+ );
7200
+ computedAmounts = [
7201
+ new Decimal(estimatedGivenA.tokenEstA.toString()),
7202
+ new Decimal(estimatedGivenA.tokenEstB.toString()),
7203
+ ];
7204
+ }
7174
7205
 
7175
- if (
7176
- secondaryTokenAmount &&
7177
- new Decimal(estimatedGivenPrimary.estTokenB.toString()) > new Decimal(secondaryTokenAmount.toString())
7178
- ) {
7179
- params = {
7180
- positionAddress,
7181
- tokenMint: secondaryTokenMint,
7182
- tokenAmount: new BN(secondaryTokenAmount.toString()),
7183
- refresh: true,
7184
- slippageTolerance: defaultSlippagePercentage,
7206
+ if (tokenBAmount && computedAmounts[1] > tokenBAmount) {
7207
+ const tokenBForQuote = BigInt(tokenBAmount.toString());
7208
+ const params: IncreaseLiquidityQuoteParam = {
7209
+ tokenB: tokenBForQuote,
7185
7210
  };
7186
- const estimatedGivenSecondary: AddLiquidityQuote = await orcaPosition.getAddLiquidityQuote(params);
7187
- return [
7188
- new Decimal(estimatedGivenSecondary.estTokenA.toString()),
7189
- new Decimal(estimatedGivenSecondary.estTokenB.toString()),
7211
+ const estimatedGivenB: IncreaseLiquidityQuote = getIncreaseLiquidityQuote(
7212
+ params,
7213
+ whirlpoolState,
7214
+ positionState.tickLowerIndex,
7215
+ positionState.tickUpperIndex,
7216
+ defaultSlippagePercentageBPS,
7217
+ undefined, // todo: use new Wirlpool state and read transfer fees
7218
+ undefined
7219
+ );
7220
+ computedAmounts = [
7221
+ new Decimal(estimatedGivenB.tokenEstA.toString()),
7222
+ new Decimal(estimatedGivenB.tokenEstB.toString()),
7190
7223
  ];
7191
7224
  }
7192
- return [
7193
- new Decimal(estimatedGivenPrimary.estTokenA.toString()),
7194
- new Decimal(estimatedGivenPrimary.estTokenB.toString()),
7195
- ];
7225
+
7226
+ return computedAmounts;
7196
7227
  };
7197
7228
 
7198
7229
  calculateAmountsRaydium = async ({
@@ -7224,18 +7255,18 @@ export class Kamino {
7224
7255
  }
7225
7256
 
7226
7257
  if (tokenAAmount && tokenBAmount && tokenAAmount.gt(0) && tokenBAmount.gt(0)) {
7227
- const liquidity = LiquidityMath.getLiquidityFromTokenAmounts(
7258
+ const liquidity = RaydiumLiquidityMath.getLiquidityFromTokenAmounts(
7228
7259
  poolState.sqrtPriceX64,
7229
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
7230
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
7260
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
7261
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
7231
7262
  new BN(tokenAAmount.toString()),
7232
7263
  new BN(tokenBAmount.toString())
7233
7264
  );
7234
7265
 
7235
- const { amountA, amountB } = LiquidityMath.getAmountsFromLiquidity(
7266
+ const { amountA, amountB } = RaydiumLiquidityMath.getAmountsFromLiquidity(
7236
7267
  poolState.sqrtPriceX64,
7237
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
7238
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
7268
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
7269
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
7239
7270
  liquidity,
7240
7271
  true
7241
7272
  );
@@ -7245,10 +7276,10 @@ export class Kamino {
7245
7276
  const primaryTokenAmount = tokenAAmount || tokenBAmount;
7246
7277
  const secondaryTokenAmount = tokenAAmount ? tokenBAmount : tokenAAmount;
7247
7278
 
7248
- const { amountA, amountB } = LiquidityMath.getAmountsFromLiquidity(
7279
+ const { amountA, amountB } = RaydiumLiquidityMath.getAmountsFromLiquidity(
7249
7280
  poolState.sqrtPriceX64,
7250
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
7251
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
7281
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
7282
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
7252
7283
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
7253
7284
  new BN(primaryTokenAmount!.plus(secondaryTokenAmount || 0)!.toString()), // safe to use ! here because we check in the beginning that at least one of the amounts are not undefined;
7254
7285
  true
@@ -7447,26 +7478,30 @@ export class Kamino {
7447
7478
  throw Error(`Could not fetch whirlpool state with pubkey ${strategyState.pool.toString()}`);
7448
7479
  }
7449
7480
 
7450
- const position = await Position.fetch(this._rpc, strategyState.position, this._orcaService.getWhirlpoolProgramId());
7481
+ const position = await OrcaPosition.fetch(
7482
+ this._rpc,
7483
+ strategyState.position,
7484
+ this._orcaService.getWhirlpoolProgramId()
7485
+ );
7451
7486
  if (!position) {
7452
7487
  throw new Error(`Whirlpool position ${strategyState.position} does not exist`);
7453
7488
  }
7454
7489
 
7455
- const params: InternalAddLiquidityQuoteParam = {
7456
- tokenMintA: toLegacyPublicKey(strategyState.tokenAMint),
7457
- tokenMintB: toLegacyPublicKey(strategyState.tokenBMint),
7458
- tickCurrentIndex: whirlpool.tickCurrentIndex,
7459
- sqrtPrice: whirlpool.sqrtPrice,
7460
- inputTokenMint: toLegacyPublicKey(strategyState.tokenAMint),
7461
- inputTokenAmount: amountA,
7462
- tickLowerIndex: position.tickLowerIndex,
7463
- tickUpperIndex: position.tickUpperIndex,
7464
- slippageTolerance: defaultSlippagePercentage,
7490
+ const params: IncreaseLiquidityQuoteParam = {
7491
+ tokenA: BigInt(amountA.toString()),
7465
7492
  };
7466
7493
 
7467
- const quote: InternalAddLiquidityQuote = getAddLiquidityQuote(params);
7494
+ const quote: IncreaseLiquidityQuote = getIncreaseLiquidityQuote(
7495
+ params,
7496
+ whirlpool,
7497
+ position.tickLowerIndex,
7498
+ position.tickUpperIndex,
7499
+ defaultSlippagePercentageBPS,
7500
+ undefined,
7501
+ undefined
7502
+ );
7468
7503
 
7469
- return { amountSlippageA: quote.estTokenA, amountSlippageB: quote.estTokenB };
7504
+ return { amountSlippageA: new BN(quote.tokenEstA.toString()), amountSlippageB: new BN(quote.tokenEstB.toString()) };
7470
7505
  }
7471
7506
 
7472
7507
  private async getDepositRatioFromAMeteora(
@@ -7517,26 +7552,30 @@ export class Kamino {
7517
7552
  throw Error(`Could not fetch whirlpool state with pubkey ${strategyState.pool.toString()}`);
7518
7553
  }
7519
7554
 
7520
- const position = await Position.fetch(this._rpc, strategyState.position, this._orcaService.getWhirlpoolProgramId());
7555
+ const position = await OrcaPosition.fetch(
7556
+ this._rpc,
7557
+ strategyState.position,
7558
+ this._orcaService.getWhirlpoolProgramId()
7559
+ );
7521
7560
  if (!position) {
7522
7561
  throw new Error(`Whirlpool position ${strategyState.position} does not exist`);
7523
7562
  }
7524
7563
 
7525
- const params: InternalAddLiquidityQuoteParam = {
7526
- tokenMintA: toLegacyPublicKey(strategyState.tokenAMint),
7527
- tokenMintB: toLegacyPublicKey(strategyState.tokenBMint),
7528
- tickCurrentIndex: whirlpool.tickCurrentIndex,
7529
- sqrtPrice: whirlpool.sqrtPrice,
7530
- inputTokenMint: toLegacyPublicKey(strategyState.tokenBMint),
7531
- inputTokenAmount: amountB,
7532
- tickLowerIndex: position.tickLowerIndex,
7533
- tickUpperIndex: position.tickUpperIndex,
7534
- slippageTolerance: defaultSlippagePercentage,
7564
+ const param: IncreaseLiquidityQuoteParam = {
7565
+ tokenB: BigInt(amountB.toString()),
7535
7566
  };
7536
7567
 
7537
- const quote: InternalAddLiquidityQuote = getAddLiquidityQuote(params);
7568
+ const quote: IncreaseLiquidityQuote = getIncreaseLiquidityQuote(
7569
+ param,
7570
+ whirlpool,
7571
+ position.tickLowerIndex,
7572
+ position.tickUpperIndex,
7573
+ defaultSlippagePercentageBPS,
7574
+ undefined,
7575
+ undefined
7576
+ );
7538
7577
 
7539
- return { amountSlippageA: quote.estTokenA, amountSlippageB: quote.estTokenB };
7578
+ return { amountSlippageA: new BN(quote.tokenEstA.toString()), amountSlippageB: new BN(quote.tokenEstB.toString()) };
7540
7579
  };
7541
7580
 
7542
7581
  private getDepositRatioFromARaydium = async (
@@ -7559,11 +7598,16 @@ export class Kamino {
7559
7598
  throw new Error(`Raydium pool ${strategyState.pool.toString()} could not be found.`);
7560
7599
  }
7561
7600
 
7562
- const lowerSqrtPriceX64 = SqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickLowerIndex);
7563
- const upperSqrtPriceX64 = SqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickUpperIndex);
7601
+ const lowerSqrtPriceX64 = RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickLowerIndex);
7602
+ const upperSqrtPriceX64 = RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickUpperIndex);
7564
7603
 
7565
- const liqudity = LiquidityMath.getLiquidityFromTokenAmountA(lowerSqrtPriceX64, upperSqrtPriceX64, amountA, false);
7566
- const amountsSlippage = LiquidityMath.getAmountsFromLiquidityWithSlippage(
7604
+ const liqudity = RaydiumLiquidityMath.getLiquidityFromTokenAmountA(
7605
+ lowerSqrtPriceX64,
7606
+ upperSqrtPriceX64,
7607
+ amountA,
7608
+ false
7609
+ );
7610
+ const amountsSlippage = RaydiumLiquidityMath.getAmountsFromLiquidityWithSlippage(
7567
7611
  poolState.sqrtPriceX64,
7568
7612
  lowerSqrtPriceX64,
7569
7613
  upperSqrtPriceX64,
@@ -7596,11 +7640,11 @@ export class Kamino {
7596
7640
  throw new Error(`Raydium pool ${strategyState.pool.toString()} could not be found.`);
7597
7641
  }
7598
7642
 
7599
- const lowerSqrtPriceX64 = SqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickLowerIndex);
7600
- const upperSqrtPriceX64 = SqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickUpperIndex);
7643
+ const lowerSqrtPriceX64 = RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickLowerIndex);
7644
+ const upperSqrtPriceX64 = RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickUpperIndex);
7601
7645
 
7602
- const liqudity = LiquidityMath.getLiquidityFromTokenAmountB(lowerSqrtPriceX64, upperSqrtPriceX64, amountB);
7603
- const amountsSlippage = LiquidityMath.getAmountsFromLiquidityWithSlippage(
7646
+ const liqudity = RaydiumLiquidityMath.getLiquidityFromTokenAmountB(lowerSqrtPriceX64, upperSqrtPriceX64, amountB);
7647
+ const amountsSlippage = RaydiumLiquidityMath.getAmountsFromLiquidityWithSlippage(
7604
7648
  poolState.sqrtPriceX64,
7605
7649
  lowerSqrtPriceX64,
7606
7650
  upperSqrtPriceX64,
@@ -7869,8 +7913,11 @@ export class Kamino {
7869
7913
 
7870
7914
  const decimalsA = await getMintDecimals(this._rpc, whilrpoolState.tokenMintA);
7871
7915
  const decimalsB = await getMintDecimals(this._rpc, whilrpoolState.tokenMintB);
7872
- const tickIndex = getNextValidTickIndex(priceToTickIndex(price, decimalsA, decimalsB), whilrpoolState.tickSpacing);
7873
- const startTickIndex = getStartTickIndex(tickIndex, whilrpoolState.tickSpacing);
7916
+ const tickIndex = orcaGetTickArrayStartTickIndex(
7917
+ orcaPriceToTickIndex(price.toNumber(), decimalsA, decimalsB),
7918
+ whilrpoolState.tickSpacing
7919
+ );
7920
+ const startTickIndex = orcaGetTickArrayStartTickIndex(tickIndex, whilrpoolState.tickSpacing);
7874
7921
 
7875
7922
  const [startTickIndexPk, _startTickIndexBump] = await getTickArray(
7876
7923
  this._orcaService.getWhirlpoolProgramId(),