@kamino-finance/kliquidity-sdk 8.3.1 → 8.4.0

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 (91) hide show
  1. package/dist/Kamino.d.ts +16 -14
  2. package/dist/Kamino.d.ts.map +1 -1
  3. package/dist/Kamino.js +114 -125
  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/JupService.d.ts.map +1 -1
  28. package/dist/services/MeteoraService.d.ts.map +1 -1
  29. package/dist/services/MeteoraService.js +4 -1
  30. package/dist/services/MeteoraService.js.map +1 -1
  31. package/dist/services/OrcaService.d.ts +7 -11
  32. package/dist/services/OrcaService.d.ts.map +1 -1
  33. package/dist/services/OrcaService.js +133 -101
  34. package/dist/services/OrcaService.js.map +1 -1
  35. package/dist/services/OrcaWhirlpoolsResponse.d.ts +63 -92
  36. package/dist/services/OrcaWhirlpoolsResponse.d.ts.map +1 -1
  37. package/dist/services/RaydiumService.d.ts.map +1 -1
  38. package/dist/services/RaydiumService.js +7 -1
  39. package/dist/services/RaydiumService.js.map +1 -1
  40. package/dist/utils/farms.d.ts +1 -0
  41. package/dist/utils/farms.d.ts.map +1 -0
  42. package/dist/utils/farms.js +2 -0
  43. package/dist/utils/farms.js.map +1 -0
  44. package/dist/utils/index.d.ts +1 -0
  45. package/dist/utils/index.d.ts.map +1 -1
  46. package/dist/utils/index.js +1 -0
  47. package/dist/utils/index.js.map +1 -1
  48. package/dist/utils/lookupTable.d.ts.map +1 -1
  49. package/dist/utils/lookupTable.js +1 -1
  50. package/dist/utils/lookupTable.js.map +1 -1
  51. package/dist/utils/orca.d.ts +37 -1
  52. package/dist/utils/orca.d.ts.map +1 -1
  53. package/dist/utils/orca.js +242 -0
  54. package/dist/utils/orca.js.map +1 -1
  55. package/dist/utils/tokenUtils.d.ts +5 -5
  56. package/dist/utils/tokenUtils.d.ts.map +1 -1
  57. package/dist/utils/tokenUtils.js +11 -7
  58. package/dist/utils/tokenUtils.js.map +1 -1
  59. package/dist/utils/transactions.d.ts.map +1 -1
  60. package/dist/utils/types.d.ts +5 -0
  61. package/dist/utils/types.d.ts.map +1 -1
  62. package/dist/utils/types.js.map +1 -1
  63. package/dist/utils/utils.d.ts +0 -1
  64. package/dist/utils/utils.d.ts.map +1 -1
  65. package/dist/utils/utils.js +3 -4
  66. package/dist/utils/utils.js.map +1 -1
  67. package/dist/utils/whirlpools.d.ts +12 -1
  68. package/dist/utils/whirlpools.d.ts.map +1 -1
  69. package/dist/utils/whirlpools.js +30 -29
  70. package/dist/utils/whirlpools.js.map +1 -1
  71. package/package.json +10 -9
  72. package/src/Kamino.ts +271 -215
  73. package/src/constants/numericalValues.ts +5 -0
  74. package/src/rebalance_methods/autodriftRebalance.ts +30 -22
  75. package/src/rebalance_methods/driftRebalance.ts +30 -22
  76. package/src/rebalance_methods/expanderRebalance.ts +7 -4
  77. package/src/rebalance_methods/pricePercentageRebalance.ts +13 -6
  78. package/src/rebalance_methods/pricePercentageWithResetRebalance.ts +13 -6
  79. package/src/rebalance_methods/takeProfitRebalance.ts +13 -5
  80. package/src/services/MeteoraService.ts +5 -2
  81. package/src/services/OrcaService.ts +163 -126
  82. package/src/services/OrcaWhirlpoolsResponse.ts +69 -101
  83. package/src/services/RaydiumService.ts +8 -2
  84. package/src/utils/farms.ts +0 -0
  85. package/src/utils/index.ts +1 -0
  86. package/src/utils/lookupTable.ts +2 -2
  87. package/src/utils/orca.ts +377 -1
  88. package/src/utils/tokenUtils.ts +5 -5
  89. package/src/utils/types.ts +7 -0
  90. package/src/utils/utils.ts +2 -4
  91. package/src/utils/whirlpools.ts +50 -31
package/src/Kamino.ts CHANGED
@@ -4,6 +4,7 @@ import {
4
4
  AccountRole,
5
5
  address,
6
6
  Address,
7
+ Base58EncodedBytes,
7
8
  fetchEncodedAccounts,
8
9
  generateKeyPairSigner,
9
10
  getAddressEncoder,
@@ -30,21 +31,15 @@ import {
30
31
  InitializeTickArrayAccounts,
31
32
  InitializeTickArrayArgs,
32
33
  } from './@codegen/whirlpools/instructions';
33
- import { Position, TickArray, Whirlpool } from './@codegen/whirlpools/accounts';
34
+ import { Position as OrcaPosition, TickArray, Whirlpool } from './@codegen/whirlpools/accounts';
34
35
  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';
36
+ sqrtPriceToPrice as orcaSqrtPriceToPrice,
37
+ getTickArrayStartTickIndex as orcaGetTickArrayStartTickIndex,
38
+ priceToTickIndex as orcaPriceToTickIndex,
39
+ IncreaseLiquidityQuote,
40
+ sqrtPriceToPrice,
41
+ tickIndexToPrice as orcaTickIndexToPrice,
42
+ } from '@orca-so/whirlpools-core';
48
43
  import {
49
44
  getEmptyShareData,
50
45
  Holdings,
@@ -119,7 +114,9 @@ import {
119
114
  WithdrawAllAndCloseIxns,
120
115
  WithdrawShares,
121
116
  ZERO,
122
- ZERO_BN,
117
+ getNearestValidTickIndexFromTickIndex as orcaGetNearestValidTickIndexFromTickIndex,
118
+ getIncreaseLiquidityQuote,
119
+ defaultSlippagePercentageBPS,
123
120
  } from './utils';
124
121
  import {
125
122
  checkExpectedVaultsBalances,
@@ -165,7 +162,7 @@ import {
165
162
  import BN from 'bn.js';
166
163
  import StrategyWithAddress from './models/StrategyWithAddress';
167
164
  import { Rebalancing, Uninitialized } from './@codegen/kliquidity/types/StrategyStatus';
168
- import { FRONTEND_KAMINO_STRATEGY_URL, METADATA_PROGRAM_ID, U64_MAX } from './constants';
165
+ import { FRONTEND_KAMINO_STRATEGY_URL, METADATA_PROGRAM_ID, U64_MAX, ZERO_BN } from './constants';
169
166
  import {
170
167
  CollateralInfo,
171
168
  ExecutiveWithdrawActionKind,
@@ -177,12 +174,7 @@ import {
177
174
  } from './@codegen/kliquidity/types';
178
175
  import { AmmConfig, PersonalPositionState, PoolState } from './@codegen/raydium/accounts';
179
176
 
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';
177
+ import { OrcaService, RaydiumService, Whirlpool as WhirlpoolAPIResponse, WhirlpoolAprApy } from './services';
186
178
  import { Pool } from './services/RaydiumPoolsResponse';
187
179
  import {
188
180
  UpdateCollectFeesFee,
@@ -327,10 +319,10 @@ import {
327
319
  import {
328
320
  getPdaProtocolPositionAddress,
329
321
  i32ToBytes,
330
- LiquidityMath,
331
- SqrtPriceMath,
332
- TickMath,
333
- TickUtils,
322
+ LiquidityMath as RaydiumLiquidityMath,
323
+ SqrtPriceMath as RaydiumSqrtPriceMath,
324
+ TickMath as RaydiumTickMath,
325
+ TickUtils as RaydiumTickUtils,
334
326
  } from '@raydium-io/raydium-sdk-v2/lib';
335
327
  import {
336
328
  ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
@@ -355,6 +347,7 @@ import { fetchMultipleLookupTableAccounts } from './utils/lookupTable';
355
347
  import type { AccountInfoBase, AccountInfoWithJsonData, AccountInfoWithPubkey } from '@solana/rpc-types';
356
348
  import { Connection } from '@solana/web3.js';
357
349
  import { toLegacyPublicKey } from './utils/compat';
350
+ import { IncreaseLiquidityQuoteParam } from '@orca-so/whirlpools';
358
351
 
359
352
  const addressEncoder = getAddressEncoder();
360
353
 
@@ -408,7 +401,7 @@ export class Kamino {
408
401
  }
409
402
 
410
403
  this._scope = new Scope(cluster, rpc);
411
- this._orcaService = new OrcaService(rpc, legacyConnection, cluster, whirlpoolProgramId);
404
+ this._orcaService = new OrcaService(rpc, legacyConnection, whirlpoolProgramId);
412
405
  this._raydiumService = new RaydiumService(rpc, legacyConnection, raydiumProgramId);
413
406
  this._meteoraService = new MeteoraService(rpc, meteoraProgramId);
414
407
 
@@ -419,6 +412,8 @@ export class Kamino {
419
412
 
420
413
  getConnection = () => this._rpc;
421
414
 
415
+ getLegacyConnection = () => this._legacyConnection;
416
+
422
417
  getProgramID = () => this._kliquidityProgramId;
423
418
 
424
419
  setGlobalConfig = (globalConfig: Address) => {
@@ -962,7 +957,7 @@ export class Kamino {
962
957
  if (pools.length === 0) {
963
958
  throw new Error(`No pool found for ${poolTokenA.toString()} and ${poolTokenB.toString()}`);
964
959
  }
965
- return pools[0].price;
960
+ return Number(pools[0].price);
966
961
  } else if (dex === 'RAYDIUM') {
967
962
  const pools = await this.getRaydiumPoolsForTokens(poolTokenA, poolTokenB);
968
963
  if (pools.length === 0) {
@@ -1033,7 +1028,7 @@ export class Kamino {
1033
1028
  let pool: Address = DEFAULT_PUBLIC_KEY;
1034
1029
  const orcaPools = await this.getOrcaPoolsForTokens(poolTokenA, poolTokenB);
1035
1030
  orcaPools.forEach((element) => {
1036
- if (element.lpFeeRate * FullBPS === feeBPS.toNumber()) {
1031
+ if (element.feeRate * FullBPS === feeBPS.toNumber()) {
1037
1032
  pool = address(element.address);
1038
1033
  }
1039
1034
  });
@@ -1080,22 +1075,24 @@ export class Kamino {
1080
1075
  if (dex === 'ORCA') {
1081
1076
  const pools = await this.getOrcaPoolsForTokens(tokenMintA, tokenMintB);
1082
1077
  const genericPoolInfos: GenericPoolInfo[] = await Promise.all(
1083
- pools.map(async (pool: OrcaPool) => {
1078
+ pools.map(async (pool: WhirlpoolAPIResponse) => {
1084
1079
  const positionsCount = new Decimal(await this.getPositionsCountForPool(dex, address(pool.address)));
1085
1080
  // read price from pool
1086
- const poolData = await this._orcaService.getPool(address(pool.address));
1081
+ const poolData = await this._orcaService.getOrcaWhirlpool(address(pool.address));
1087
1082
  if (!poolData) {
1088
1083
  throw new Error(`Pool ${pool.address} not found`);
1089
1084
  }
1090
1085
  const poolInfo: GenericPoolInfo = {
1091
1086
  dex,
1092
1087
  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,
1088
+ price: new Decimal(
1089
+ orcaSqrtPriceToPrice(BigInt(poolData.sqrtPrice), pool.tokenA.decimals, pool.tokenB.decimals)
1090
+ ),
1091
+ tokenMintA: address(pool.tokenMintA),
1092
+ tokenMintB: address(pool.tokenMintB),
1093
+ tvl: pool.tvlUsdc ? new Decimal(pool.tvlUsdc) : undefined,
1094
+ feeRate: new Decimal(pool.feeRate).mul(FullBPS),
1095
+ volumeOnLast7d: pool.stats['7d'] ? new Decimal(pool.stats['7d'].volume) : undefined,
1099
1096
  tickSpacing: new Decimal(pool.tickSpacing),
1100
1097
  positions: positionsCount,
1101
1098
  };
@@ -1157,15 +1154,15 @@ export class Kamino {
1157
1154
  }
1158
1155
  }
1159
1156
 
1160
- getOrcaPoolsForTokens = async (poolTokenA: Address, poolTokenB: Address): Promise<OrcaPool[]> => {
1161
- const pools: OrcaPool[] = [];
1157
+ getOrcaPoolsForTokens = async (poolTokenA: Address, poolTokenB: Address): Promise<WhirlpoolAPIResponse[]> => {
1158
+ const pools: WhirlpoolAPIResponse[] = [];
1162
1159
  const poolTokenAString = poolTokenA.toString();
1163
1160
  const poolTokenBString = poolTokenB.toString();
1164
1161
  const whirlpools = await this._orcaService.getOrcaWhirlpools();
1165
- whirlpools.whirlpools.forEach((element) => {
1162
+ whirlpools.forEach((element) => {
1166
1163
  if (
1167
- (element.tokenA.mint === poolTokenAString && element.tokenB.mint === poolTokenBString) ||
1168
- (element.tokenA.mint === poolTokenBString && element.tokenB.mint === poolTokenAString)
1164
+ (element.tokenMintA === poolTokenAString && element.tokenMintB === poolTokenBString) ||
1165
+ (element.tokenMintA === poolTokenBString && element.tokenMintB === poolTokenAString)
1169
1166
  )
1170
1167
  pools.push(element);
1171
1168
  });
@@ -1244,7 +1241,7 @@ export class Kamino {
1244
1241
  filters.push({
1245
1242
  memcmp: {
1246
1243
  offset: 0n,
1247
- bytes: bs58.encode(WhirlpoolStrategy.discriminator),
1244
+ bytes: bs58.encode(WhirlpoolStrategy.discriminator) as Base58EncodedBytes,
1248
1245
  encoding: 'base58',
1249
1246
  },
1250
1247
  });
@@ -1253,7 +1250,7 @@ export class Kamino {
1253
1250
  filters.push({
1254
1251
  memcmp: {
1255
1252
  offset: 8n,
1256
- bytes: strategyFilters.owner,
1253
+ bytes: strategyFilters.owner.toString() as Base58EncodedBytes,
1257
1254
  encoding: 'base58',
1258
1255
  },
1259
1256
  });
@@ -1263,7 +1260,7 @@ export class Kamino {
1263
1260
  filters.push({
1264
1261
  memcmp: {
1265
1262
  offset: 1625n,
1266
- bytes: strategyCreationStatusToBase58(strategyFilters.strategyCreationStatus),
1263
+ bytes: strategyCreationStatusToBase58(strategyFilters.strategyCreationStatus) as Base58EncodedBytes,
1267
1264
  encoding: 'base58',
1268
1265
  },
1269
1266
  });
@@ -1272,7 +1269,7 @@ export class Kamino {
1272
1269
  filters.push({
1273
1270
  memcmp: {
1274
1271
  offset: 1120n,
1275
- bytes: strategyTypeToBase58(strategyFilters.strategyType).toString(),
1272
+ bytes: strategyTypeToBase58(strategyFilters.strategyType).toString() as Base58EncodedBytes,
1276
1273
  encoding: 'base58',
1277
1274
  },
1278
1275
  });
@@ -1283,7 +1280,7 @@ export class Kamino {
1283
1280
  filters.push({
1284
1281
  memcmp: {
1285
1282
  offset: 1664n,
1286
- bytes: value,
1283
+ bytes: value as Base58EncodedBytes,
1287
1284
  encoding: 'base58',
1288
1285
  },
1289
1286
  });
@@ -1323,13 +1320,13 @@ export class Kamino {
1323
1320
  {
1324
1321
  memcmp: {
1325
1322
  offset: 0n,
1326
- bytes: bs58.encode(WhirlpoolStrategy.discriminator),
1323
+ bytes: bs58.encode(WhirlpoolStrategy.discriminator) as Base58EncodedBytes,
1327
1324
  encoding: 'base58',
1328
1325
  },
1329
1326
  },
1330
1327
  {
1331
1328
  memcmp: {
1332
- bytes: kTokenMint,
1329
+ bytes: kTokenMint.toString() as Base58EncodedBytes,
1333
1330
  offset: 720n,
1334
1331
  encoding: 'base58',
1335
1332
  },
@@ -1484,7 +1481,7 @@ export class Kamino {
1484
1481
  );
1485
1482
 
1486
1483
  fetchBalances.push(
1487
- ...this.getBalance<Whirlpool, Position>(
1484
+ ...this.getBalance<Whirlpool, OrcaPosition>(
1488
1485
  orcaStrategies,
1489
1486
  orcaPools,
1490
1487
  orcaPositions,
@@ -1602,18 +1599,18 @@ export class Kamino {
1602
1599
  const decimalsA = strategy.tokenAMintDecimals.toNumber();
1603
1600
  const decimalsB = strategy.tokenBMintDecimals.toNumber();
1604
1601
 
1605
- const poolPrice = SqrtPriceMath.sqrtPriceX64ToPrice(pool.sqrtPriceX64, decimalsA, decimalsB);
1602
+ const poolPrice = RaydiumSqrtPriceMath.sqrtPriceX64ToPrice(pool.sqrtPriceX64, decimalsA, decimalsB);
1606
1603
  const twapPrice =
1607
1604
  strategyPrices.aTwapPrice !== null && strategyPrices.bTwapPrice !== null
1608
1605
  ? strategyPrices.aTwapPrice.div(strategyPrices.bTwapPrice)
1609
1606
  : null;
1610
- const upperPrice = SqrtPriceMath.sqrtPriceX64ToPrice(
1611
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
1607
+ const upperPrice = RaydiumSqrtPriceMath.sqrtPriceX64ToPrice(
1608
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
1612
1609
  decimalsA,
1613
1610
  decimalsB
1614
1611
  );
1615
- const lowerPrice = SqrtPriceMath.sqrtPriceX64ToPrice(
1616
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
1612
+ const lowerPrice = RaydiumSqrtPriceMath.sqrtPriceX64ToPrice(
1613
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
1617
1614
  decimalsA,
1618
1615
  decimalsB
1619
1616
  );
@@ -1726,10 +1723,10 @@ export class Kamino {
1726
1723
  position: PersonalPositionState,
1727
1724
  mode: 'DEPOSIT' | 'WITHDRAW' = 'WITHDRAW'
1728
1725
  ): TokenHoldings => {
1729
- const lowerSqrtPriceX64 = SqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex);
1730
- const upperSqrtPriceX64 = SqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex);
1726
+ const lowerSqrtPriceX64 = RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex);
1727
+ const upperSqrtPriceX64 = RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex);
1731
1728
 
1732
- const { amountA, amountB } = LiquidityMath.getAmountsFromLiquidity(
1729
+ const { amountA, amountB } = RaydiumLiquidityMath.getAmountsFromLiquidity(
1733
1730
  pool.sqrtPriceX64,
1734
1731
  new BN(lowerSqrtPriceX64),
1735
1732
  new BN(upperSqrtPriceX64),
@@ -1790,7 +1787,7 @@ export class Kamino {
1790
1787
  private getOrcaBalances = async (
1791
1788
  strategy: WhirlpoolStrategy,
1792
1789
  pool: Whirlpool,
1793
- position: Position,
1790
+ position: OrcaPosition,
1794
1791
  collateralInfos: CollateralInfo[],
1795
1792
  prices?: OraclePrices,
1796
1793
  disabledTokensPrices?: Map<Address, Decimal>,
@@ -1814,13 +1811,13 @@ export class Kamino {
1814
1811
  const decimalsA = strategy.tokenAMintDecimals.toNumber();
1815
1812
  const decimalsB = strategy.tokenBMintDecimals.toNumber();
1816
1813
 
1817
- const poolPrice = sqrtPriceX64ToPrice(pool.sqrtPrice, decimalsA, decimalsB);
1814
+ const poolPrice = new Decimal(orcaSqrtPriceToPrice(BigInt(pool.sqrtPrice.toString()), decimalsA, decimalsB));
1818
1815
  const twapPrice =
1819
1816
  strategyPrices.aTwapPrice !== null && strategyPrices.bTwapPrice !== null
1820
1817
  ? strategyPrices.aTwapPrice.div(strategyPrices.bTwapPrice)
1821
1818
  : null;
1822
- const upperPrice = tickIndexToPrice(position.tickUpperIndex, decimalsA, decimalsB);
1823
- const lowerPrice = tickIndexToPrice(position.tickLowerIndex, decimalsA, decimalsB);
1819
+ const upperPrice = new Decimal(orcaTickIndexToPrice(position.tickUpperIndex, decimalsA, decimalsB));
1820
+ const lowerPrice = new Decimal(orcaTickIndexToPrice(position.tickLowerIndex, decimalsA, decimalsB));
1824
1821
  let lowerResetPrice: Decimal | null = null;
1825
1822
  let upperResetPrice: Decimal | null = null;
1826
1823
  const dex = numberToDex(strategy.strategyDex.toNumber());
@@ -1856,14 +1853,14 @@ export class Kamino {
1856
1853
  private getOrcaTokensBalances = (
1857
1854
  strategy: WhirlpoolStrategy,
1858
1855
  pool: Whirlpool,
1859
- position: Position,
1856
+ position: OrcaPosition,
1860
1857
  mode: 'DEPOSIT' | 'WITHDRAW' = 'WITHDRAW'
1861
1858
  ): TokenHoldings => {
1862
1859
  const quote = getRemoveLiquidityQuote(
1863
1860
  {
1864
1861
  positionAddress: strategy.position,
1865
1862
  liquidity: position.liquidity,
1866
- slippageTolerance: Percentage.fromFraction(0, 1000),
1863
+ slippageTolerance: { numerator: ZERO_BN, denominator: new BN(1000) },
1867
1864
  sqrtPrice: pool.sqrtPrice,
1868
1865
  tickLowerIndex: position.tickLowerIndex,
1869
1866
  tickUpperIndex: position.tickUpperIndex,
@@ -1975,7 +1972,7 @@ export class Kamino {
1975
1972
  throw Error(`Could not fetch Orca whirlpool position state with pubkey ${strategy.position.toString()}`);
1976
1973
  }
1977
1974
  const whirlpool = Whirlpool.decode(Buffer.from(whirlpoolAcc.data[0], 'base64'));
1978
- const position = Position.decode(Buffer.from(positionAcc.data[0], 'base64'));
1975
+ const position = OrcaPosition.decode(Buffer.from(positionAcc.data[0], 'base64'));
1979
1976
  return this.getOrcaTokensBalances(strategy, whirlpool, position, mode);
1980
1977
  } else if (strategy.strategyDex.toNumber() === dexToNumber('RAYDIUM')) {
1981
1978
  const [poolStateAcc, positionAcc] = (
@@ -2049,7 +2046,7 @@ export class Kamino {
2049
2046
  throw Error(`Could not fetch Orca whirlpool position state with pubkey ${strategy.position.toString()}`);
2050
2047
  }
2051
2048
  const whirlpool = Whirlpool.decode(Buffer.from(whirlpoolAcc.data[0], 'base64'));
2052
- const position = Position.decode(Buffer.from(positionAcc.data[0], 'base64'));
2049
+ const position = OrcaPosition.decode(Buffer.from(positionAcc.data[0], 'base64'));
2053
2050
 
2054
2051
  return this.getOrcaBalances(
2055
2052
  strategy,
@@ -2328,7 +2325,10 @@ export class Kamino {
2328
2325
  //datasize:165 filter selects all token accounts, memcmp filter selects based on the mint address withing each token account
2329
2326
  return this._rpc
2330
2327
  .getProgramAccounts(TOKEN_PROGRAM_ADDRESS, {
2331
- filters: [{ dataSize: 165n }, { memcmp: { offset: 0n, bytes: shareMint, encoding: 'base58' } }],
2328
+ filters: [
2329
+ { dataSize: 165n },
2330
+ { memcmp: { offset: 0n, bytes: shareMint.toString() as Base58EncodedBytes, encoding: 'base58' } },
2331
+ ],
2332
2332
  encoding: 'jsonParsed',
2333
2333
  })
2334
2334
  .send();
@@ -2343,7 +2343,10 @@ export class Kamino {
2343
2343
  //how to get all token accounts for specific wallet: https://spl.solana.com/token#finding-all-token-accounts-for-a-wallet
2344
2344
  return this._rpc
2345
2345
  .getProgramAccounts(TOKEN_PROGRAM_ADDRESS, {
2346
- filters: [{ dataSize: 165n }, { memcmp: { offset: 32n, bytes: wallet, encoding: 'base58' } }],
2346
+ filters: [
2347
+ { dataSize: 165n },
2348
+ { memcmp: { offset: 32n, bytes: wallet.toString() as Base58EncodedBytes, encoding: 'base58' } },
2349
+ ],
2347
2350
  encoding: 'jsonParsed',
2348
2351
  })
2349
2352
  .send();
@@ -2437,12 +2440,12 @@ export class Kamino {
2437
2440
  if (positionPk === DEFAULT_PUBLIC_KEY) {
2438
2441
  return { lowerPrice: ZERO, upperPrice: ZERO };
2439
2442
  }
2440
- const position = await Position.fetch(this._rpc, positionPk, this._orcaService.getWhirlpoolProgramId());
2443
+ const position = await OrcaPosition.fetch(this._rpc, positionPk, this._orcaService.getWhirlpoolProgramId());
2441
2444
  if (!position) {
2442
2445
  return { lowerPrice: ZERO, upperPrice: ZERO };
2443
2446
  }
2444
- const lowerPrice = tickIndexToPrice(position.tickLowerIndex, decimalsA, decimalsB);
2445
- const upperPrice = tickIndexToPrice(position.tickUpperIndex, decimalsA, decimalsB);
2447
+ const lowerPrice = new Decimal(orcaTickIndexToPrice(position.tickLowerIndex, decimalsA, decimalsB));
2448
+ const upperPrice = new Decimal(orcaTickIndexToPrice(position.tickUpperIndex, decimalsA, decimalsB));
2446
2449
 
2447
2450
  const positionRange: PositionRange = { lowerPrice, upperPrice };
2448
2451
 
@@ -2465,14 +2468,14 @@ export class Kamino {
2465
2468
  if (!position) {
2466
2469
  return { lowerPrice: ZERO, upperPrice: ZERO };
2467
2470
  }
2468
- const lowerPrice = sqrtPriceX64ToPrice(
2469
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
2471
+ const lowerPrice = RaydiumSqrtPriceMath.sqrtPriceX64ToPrice(
2472
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
2470
2473
  decimalsA,
2471
2474
  decimalsB
2472
2475
  );
2473
2476
 
2474
- const upperPrice = sqrtPriceX64ToPrice(
2475
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
2477
+ const upperPrice = RaydiumSqrtPriceMath.sqrtPriceX64ToPrice(
2478
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
2476
2479
  decimalsA,
2477
2480
  decimalsB
2478
2481
  );
@@ -2554,17 +2557,21 @@ export class Kamino {
2554
2557
  return whirlpoolMap;
2555
2558
  };
2556
2559
 
2560
+ getAllWhirlpoolsFromAPI = async (tokens: Address[] = []): Promise<WhirlpoolAPIResponse[]> => {
2561
+ return await this._orcaService.getOrcaWhirlpools(tokens);
2562
+ };
2563
+
2557
2564
  /**
2558
2565
  * Get a list of Orca positions from public keys
2559
2566
  * @param positions
2560
2567
  */
2561
- getOrcaPositions = async (positions: Address[]): Promise<(Position | null)[]> => {
2568
+ getOrcaPositions = async (positions: Address[]): Promise<(OrcaPosition | null)[]> => {
2562
2569
  const nonDefaults = positions.filter((value) => value !== DEFAULT_PUBLIC_KEY);
2563
2570
  const fetched = await batchFetch(nonDefaults, (chunk) =>
2564
- Position.fetchMultiple(this._rpc, chunk, this._orcaService.getWhirlpoolProgramId())
2571
+ OrcaPosition.fetchMultiple(this._rpc, chunk, this._orcaService.getWhirlpoolProgramId())
2565
2572
  );
2566
- const fetchedMap: Record<string, Position | null> = fetched.reduce(
2567
- (map: Record<Address, Position | null>, position, i) => {
2573
+ const fetchedMap: Record<string, OrcaPosition | null> = fetched.reduce(
2574
+ (map: Record<Address, OrcaPosition | null>, position, i) => {
2568
2575
  map[nonDefaults[i]] = position;
2569
2576
  return map;
2570
2577
  },
@@ -4501,8 +4508,8 @@ export class Kamino {
4501
4508
  tickLowerIndex: number,
4502
4509
  tickUpperIndex: number
4503
4510
  ): Promise<LowerAndUpperTickPubkeys> => {
4504
- const startTickIndex = getStartTickIndex(tickLowerIndex, whirlpoolState.tickSpacing, 0);
4505
- const endTickIndex = getStartTickIndex(tickUpperIndex, whirlpoolState.tickSpacing, 0);
4511
+ const startTickIndex = orcaGetTickArrayStartTickIndex(tickLowerIndex, whirlpoolState.tickSpacing);
4512
+ const endTickIndex = orcaGetTickArrayStartTickIndex(tickUpperIndex, whirlpoolState.tickSpacing);
4506
4513
 
4507
4514
  const [lowerTickPubkey, lowerTickBump] = await getProgramDerivedAddress({
4508
4515
  seeds: [Buffer.from('tick_array'), addressEncoder.encode(whirlpool), Buffer.from(startTickIndex.toString())],
@@ -4526,8 +4533,8 @@ export class Kamino {
4526
4533
  tickLowerIndex: number,
4527
4534
  tickUpperIndex: number
4528
4535
  ): Promise<LowerAndUpperTickPubkeys> => {
4529
- const startTickIndex = TickUtils.getTickArrayStartIndexByTick(tickLowerIndex, poolState.tickSpacing);
4530
- const endTickIndex = TickUtils.getTickArrayStartIndexByTick(tickUpperIndex, poolState.tickSpacing);
4536
+ const startTickIndex = RaydiumTickUtils.getTickArrayStartIndexByTick(tickLowerIndex, poolState.tickSpacing);
4537
+ const endTickIndex = RaydiumTickUtils.getTickArrayStartIndexByTick(tickUpperIndex, poolState.tickSpacing);
4531
4538
 
4532
4539
  const [lowerTickPubkey, lowerTickBump] = await getProgramDerivedAddress({
4533
4540
  seeds: [Buffer.from('tick_array'), addressEncoder.encode(pool), i32ToBytes(startTickIndex)],
@@ -4767,12 +4774,12 @@ export class Kamino {
4767
4774
  const decimalsA = await getMintDecimals(this._rpc, whirlpool.tokenMintA);
4768
4775
  const decimalsB = await getMintDecimals(this._rpc, whirlpool.tokenMintB);
4769
4776
 
4770
- const tickLowerIndex = getNextValidTickIndex(
4771
- priceToTickIndex(priceLower, decimalsA, decimalsB),
4777
+ const tickLowerIndex = orcaGetTickArrayStartTickIndex(
4778
+ orcaPriceToTickIndex(priceLower.toNumber(), decimalsA, decimalsB),
4772
4779
  whirlpool.tickSpacing
4773
4780
  );
4774
- const tickUpperIndex = getNextValidTickIndex(
4775
- priceToTickIndex(priceUpper, decimalsA, decimalsB),
4781
+ const tickUpperIndex = orcaGetTickArrayStartTickIndex(
4782
+ orcaPriceToTickIndex(priceUpper.toNumber(), decimalsA, decimalsB),
4776
4783
  whirlpool.tickSpacing
4777
4784
  );
4778
4785
 
@@ -4898,15 +4905,15 @@ export class Kamino {
4898
4905
  const decimalsA = await getMintDecimals(this._rpc, poolState.tokenMint0);
4899
4906
  const decimalsB = await getMintDecimals(this._rpc, poolState.tokenMint1);
4900
4907
 
4901
- const tickLowerIndex = TickMath.getTickWithPriceAndTickspacing(
4902
- TickMath.roundPriceWithTickspacing(priceLower, poolState.tickSpacing, decimalsA, decimalsB),
4908
+ const tickLowerIndex = RaydiumTickMath.getTickWithPriceAndTickspacing(
4909
+ RaydiumTickMath.roundPriceWithTickspacing(priceLower, poolState.tickSpacing, decimalsA, decimalsB),
4903
4910
  poolState.tickSpacing,
4904
4911
  decimalsA,
4905
4912
  decimalsB
4906
4913
  );
4907
4914
 
4908
- const tickUpperIndex = TickMath.getTickWithPriceAndTickspacing(
4909
- TickMath.roundPriceWithTickspacing(priceUpper, poolState.tickSpacing, decimalsA, decimalsB),
4915
+ const tickUpperIndex = RaydiumTickMath.getTickWithPriceAndTickspacing(
4916
+ RaydiumTickMath.roundPriceWithTickspacing(priceUpper, poolState.tickSpacing, decimalsA, decimalsB),
4910
4917
  poolState.tickSpacing,
4911
4918
  decimalsA,
4912
4919
  decimalsB
@@ -5461,7 +5468,7 @@ export class Kamino {
5461
5468
  const { whirlpool: whilrpoolState } = await this.getWhirlpoolStateIfNotFetched(pool);
5462
5469
  if (rebalanceTypeKind.kind === RebalanceType.Drift.kind) {
5463
5470
  processedRebalanceParams[0] = new Decimal(
5464
- getNearestValidTickIndexFromTickIndex(rebalanceParams[0].toNumber(), whilrpoolState.tickSpacing)
5471
+ orcaGetNearestValidTickIndexFromTickIndex(rebalanceParams[0].toNumber(), whilrpoolState.tickSpacing)
5465
5472
  );
5466
5473
  }
5467
5474
  }
@@ -5830,7 +5837,7 @@ export class Kamino {
5830
5837
  return getPositionRangeFromExpanderParams(price, rebalanceParams[0], rebalanceParams[1]);
5831
5838
 
5832
5839
  case RebalanceType.Autodrift.kind:
5833
- const currentTickIndex = priceToTickIndex(price, tokenADecimals, tokenBDecimals);
5840
+ const currentTickIndex = orcaPriceToTickIndex(price.toNumber(), tokenADecimals, tokenBDecimals);
5834
5841
  const startMidTick = new Decimal(currentTickIndex);
5835
5842
  return getPositionRangeFromAutodriftParams(
5836
5843
  dex,
@@ -5852,12 +5859,22 @@ export class Kamino {
5852
5859
  const pool = strategyWithAddress.strategy.pool;
5853
5860
  const dex = numberToDex(strategyWithAddress.strategy.strategyDex.toNumber());
5854
5861
 
5855
- return this.getCurrentPriceFromPool(dex, pool);
5862
+ return this.getCurrentPriceFromPool(
5863
+ dex,
5864
+ pool,
5865
+ strategyWithAddress.strategy.tokenAMintDecimals.toNumber(),
5866
+ strategyWithAddress.strategy.tokenBMintDecimals.toNumber()
5867
+ );
5856
5868
  }
5857
5869
 
5858
- async getCurrentPriceFromPool(dex: Dex, pool: Address): Promise<Decimal> {
5870
+ async getCurrentPriceFromPool(
5871
+ dex: Dex,
5872
+ pool: Address,
5873
+ tokenADecimals?: number,
5874
+ tokenBDecimals?: number
5875
+ ): Promise<Decimal> {
5859
5876
  if (dex === 'ORCA') {
5860
- return this.getOrcaPoolPrice(pool);
5877
+ return this.getOrcaPoolPrice(pool, tokenADecimals, tokenBDecimals);
5861
5878
  } else if (dex === 'RAYDIUM') {
5862
5879
  return this.getRaydiumPoolPrice(pool);
5863
5880
  } else if (dex === 'METEORA') {
@@ -6234,9 +6251,9 @@ export class Kamino {
6234
6251
  /**
6235
6252
  * Read the pool price for a specific dex and pool
6236
6253
  */
6237
- async getPoolPrice(dex: Dex, pool: Address): Promise<Decimal> {
6254
+ async getPoolPrice(dex: Dex, pool: Address, tokenADecimals: number, tokenBDecimals: number): Promise<Decimal> {
6238
6255
  if (dex === 'ORCA') {
6239
- return this.getOrcaPoolPrice(pool);
6256
+ return this.getOrcaPoolPrice(pool, tokenADecimals, tokenBDecimals);
6240
6257
  } else if (dex === 'RAYDIUM') {
6241
6258
  return this.getRaydiumPoolPrice(pool);
6242
6259
  } else if (dex === 'METEORA') {
@@ -6246,12 +6263,25 @@ export class Kamino {
6246
6263
  }
6247
6264
  }
6248
6265
 
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()}`);
6266
+ async getOrcaPoolPrice(pool: Address, tokenADecimals?: number, tokenBDecimals?: number): Promise<Decimal> {
6267
+ // if the decimals are provided read from API, otherwise use RPC
6268
+ if (tokenADecimals && tokenBDecimals) {
6269
+ const whirlpool = await Whirlpool.fetch(this._rpc, pool, this._orcaService.getWhirlpoolProgramId());
6270
+ if (!whirlpool) {
6271
+ throw Error(`Could not fetch Whirlpool data for ${pool.toString()}`);
6272
+ }
6273
+
6274
+ return new Decimal(sqrtPriceToPrice(BigInt(whirlpool.sqrtPrice.toString()), tokenADecimals, tokenBDecimals));
6275
+ } else {
6276
+ const whirlpool = await this._orcaService.getOrcaWhirlpool(pool);
6277
+ if (!whirlpool) {
6278
+ throw Error(`Could not fetch Whirlpool data for ${pool.toString()}`);
6279
+ }
6280
+
6281
+ return new Decimal(
6282
+ sqrtPriceToPrice(BigInt(whirlpool.sqrtPrice.toString()), whirlpool.tokenA.decimals, whirlpool.tokenB.decimals)
6283
+ );
6253
6284
  }
6254
- return poolData.price;
6255
6285
  }
6256
6286
 
6257
6287
  async getRaydiumPoolPrice(pool: Address): Promise<Decimal> {
@@ -6260,7 +6290,7 @@ export class Kamino {
6260
6290
  throw new Error(`Raydium poolState ${pool.toString()} is not found`);
6261
6291
  }
6262
6292
 
6263
- const price = SqrtPriceMath.sqrtPriceX64ToPrice(
6293
+ const price = RaydiumSqrtPriceMath.sqrtPriceX64ToPrice(
6264
6294
  poolState.sqrtPriceX64,
6265
6295
  poolState.mintDecimals0,
6266
6296
  poolState.mintDecimals1
@@ -6329,7 +6359,9 @@ export class Kamino {
6329
6359
  ) {
6330
6360
  return await this._rpc
6331
6361
  .getProgramAccounts(ADDRESS_LOOKUP_TABLE_PROGRAM_ADDRESS, {
6332
- filters: [{ memcmp: { offset: 22n, bytes: LUT_OWNER_KEY, encoding: 'base58' } }],
6362
+ filters: [
6363
+ { memcmp: { offset: 22n, bytes: LUT_OWNER_KEY.toString() as Base58EncodedBytes, encoding: 'base58' } },
6364
+ ],
6333
6365
  dataSlice: { length: 0, offset: 0 },
6334
6366
  })
6335
6367
  .send()
@@ -6692,7 +6724,7 @@ export class Kamino {
6692
6724
  */
6693
6725
  getStrategyAprApy = async (
6694
6726
  strategy: Address | StrategyWithAddress,
6695
- orcaPools?: OrcaPool[],
6727
+ orcaPools?: WhirlpoolAPIResponse[],
6696
6728
  raydiumPools?: Pool[]
6697
6729
  ): Promise<WhirlpoolAprApy> => {
6698
6730
  const { strategy: strategyState } = await this.getStrategyStateIfNotFetched(strategy);
@@ -6717,7 +6749,7 @@ export class Kamino {
6717
6749
  if (isOrca) {
6718
6750
  const prices = await this.getAllPrices();
6719
6751
  const collateralInfos = await this.getCollateralInfos();
6720
- return this._orcaService.getStrategyWhirlpoolPoolAprApy(strategyState, collateralInfos, prices, orcaPools);
6752
+ return this._orcaService.getStrategyWhirlpoolPoolAprApy(strategyState, collateralInfos, prices);
6721
6753
  }
6722
6754
  if (isRaydium) {
6723
6755
  return this._raydiumService.getStrategyWhirlpoolPoolAprApy(strategyState, raydiumPools);
@@ -6951,10 +6983,10 @@ export class Kamino {
6951
6983
  const decimalsA = poolState.mintDecimals0;
6952
6984
  const decimalsB = poolState.mintDecimals1;
6953
6985
 
6954
- const { amountA, amountB } = LiquidityMath.getAmountsFromLiquidity(
6986
+ const { amountA, amountB } = RaydiumLiquidityMath.getAmountsFromLiquidity(
6955
6987
  poolState.sqrtPriceX64,
6956
- SqrtPriceMath.priceToSqrtPriceX64(lowerPrice, decimalsA, decimalsB),
6957
- SqrtPriceMath.priceToSqrtPriceX64(upperPrice, decimalsA, decimalsB),
6988
+ RaydiumSqrtPriceMath.priceToSqrtPriceX64(lowerPrice, decimalsA, decimalsB),
6989
+ RaydiumSqrtPriceMath.priceToSqrtPriceX64(upperPrice, decimalsA, decimalsB),
6958
6990
  new BN(100_000_000),
6959
6991
  true
6960
6992
  );
@@ -6972,31 +7004,31 @@ export class Kamino {
6972
7004
  const decimalsA = await getMintDecimals(this._rpc, tokenMintA);
6973
7005
  const decimalsB = await getMintDecimals(this._rpc, tokenMintB);
6974
7006
 
6975
- const tickLowerIndex = getNearestValidTickIndexFromTickIndex(
6976
- priceToTickIndex(lowerPrice, decimalsA, decimalsB),
7007
+ const tickLowerIndex = orcaGetNearestValidTickIndexFromTickIndex(
7008
+ orcaPriceToTickIndex(lowerPrice.toNumber(), decimalsA, decimalsB),
6977
7009
  whirlpoolState.tickSpacing
6978
7010
  );
6979
- const tickUpperIndex = getNearestValidTickIndexFromTickIndex(
6980
- priceToTickIndex(upperPrice, decimalsA, decimalsB),
7011
+ const tickUpperIndex = orcaGetNearestValidTickIndexFromTickIndex(
7012
+ orcaPriceToTickIndex(upperPrice.toNumber(), decimalsA, decimalsB),
6981
7013
  whirlpoolState.tickSpacing
6982
7014
  );
6983
7015
 
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,
7016
+ const param: IncreaseLiquidityQuoteParam = {
7017
+ tokenA: BigInt(collToLamportsDecimal(tokenAAmountToDeposit, decimalsA).toString()),
6994
7018
  };
6995
7019
 
6996
- const addLiqResult: InternalAddLiquidityQuote = getAddLiquidityQuote(params);
7020
+ const addLiqResult: IncreaseLiquidityQuote = getIncreaseLiquidityQuote(
7021
+ param,
7022
+ whirlpoolState,
7023
+ tickLowerIndex,
7024
+ tickUpperIndex,
7025
+ defaultSlippagePercentageBPS,
7026
+ undefined,
7027
+ undefined
7028
+ );
6997
7029
  return [
6998
- lamportsToNumberDecimal(addLiqResult.estTokenA.toNumber(), decimalsA),
6999
- lamportsToNumberDecimal(addLiqResult.estTokenB.toNumber(), decimalsB),
7030
+ lamportsToNumberDecimal(new Decimal(addLiqResult.tokenEstA.toString()), decimalsA),
7031
+ lamportsToNumberDecimal(new Decimal(addLiqResult.tokenEstB.toString()), decimalsB),
7000
7032
  ];
7001
7033
  } else if (dex === 'METEORA') {
7002
7034
  const poolState = await LbPair.fetch(this._rpc, pool, this._meteoraService.getMeteoraProgramId());
@@ -7118,9 +7150,7 @@ export class Kamino {
7118
7150
  }
7119
7151
 
7120
7152
  return this.calculateAmountsOrca({
7121
- whirlpoolConfig: whirlpool.whirlpoolsConfig,
7122
- tokenAMint: strategyState.tokenAMint,
7123
- tokenBMint: strategyState.tokenBMint,
7153
+ whirlpoolState: whirlpool,
7124
7154
  positionAddress: strategyState.position,
7125
7155
  tokenAAmount,
7126
7156
  tokenBAmount,
@@ -7135,16 +7165,12 @@ export class Kamino {
7135
7165
  };
7136
7166
 
7137
7167
  calculateAmountsOrca = async ({
7138
- whirlpoolConfig,
7139
- tokenAMint,
7140
- tokenBMint,
7168
+ whirlpoolState,
7141
7169
  positionAddress,
7142
7170
  tokenAAmount,
7143
7171
  tokenBAmount,
7144
7172
  }: {
7145
- whirlpoolConfig: Address;
7146
- tokenAMint: Address;
7147
- tokenBMint: Address;
7173
+ whirlpoolState: Whirlpool;
7148
7174
  positionAddress: Address;
7149
7175
  tokenAAmount?: Decimal;
7150
7176
  tokenBAmount?: Decimal;
@@ -7152,47 +7178,61 @@ export class Kamino {
7152
7178
  if (!tokenAAmount && !tokenBAmount) {
7153
7179
  return [new Decimal(0), new Decimal(0)];
7154
7180
  }
7181
+
7155
7182
  // 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%
7183
+ const defaultSlippagePercentageBPS = 10;
7184
+ const positionState = await OrcaPosition.fetch(
7185
+ this._rpc,
7186
+ positionAddress,
7187
+ this._orcaService.getWhirlpoolProgramId()
7188
+ );
7189
+ if (!positionState) {
7190
+ throw new Error(`Unable to get Orca position for pubkey ${positionAddress}`);
7191
+ }
7159
7192
 
7160
- const primaryTokenAmount = tokenAAmount || tokenBAmount;
7161
- const primaryTokenMint = tokenAAmount ? tokenAMint : tokenBMint;
7162
- const secondaryTokenAmount = tokenAAmount ? tokenBAmount : tokenAAmount;
7163
- const secondaryTokenMint = tokenAAmount ? tokenBMint : tokenAMint;
7193
+ let computedAmounts: [Decimal, Decimal] = [new Decimal(0), new Decimal(0)];
7164
7194
 
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);
7195
+ if (tokenAAmount) {
7196
+ const tokenAForQuote = BigInt(tokenAAmount.toString());
7197
+ const params: IncreaseLiquidityQuoteParam = {
7198
+ tokenA: tokenAForQuote,
7199
+ };
7200
+ const estimatedGivenA: IncreaseLiquidityQuote = getIncreaseLiquidityQuote(
7201
+ params,
7202
+ whirlpoolState,
7203
+ positionState.tickLowerIndex,
7204
+ positionState.tickUpperIndex,
7205
+ defaultSlippagePercentageBPS,
7206
+ undefined, // todo: use new Wirlpool state and read transfer fees
7207
+ undefined
7208
+ );
7209
+ computedAmounts = [
7210
+ new Decimal(estimatedGivenA.tokenEstA.toString()),
7211
+ new Decimal(estimatedGivenA.tokenEstB.toString()),
7212
+ ];
7213
+ }
7174
7214
 
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,
7215
+ if (tokenBAmount && computedAmounts[1] > tokenBAmount) {
7216
+ const tokenBForQuote = BigInt(tokenBAmount.toString());
7217
+ const params: IncreaseLiquidityQuoteParam = {
7218
+ tokenB: tokenBForQuote,
7185
7219
  };
7186
- const estimatedGivenSecondary: AddLiquidityQuote = await orcaPosition.getAddLiquidityQuote(params);
7187
- return [
7188
- new Decimal(estimatedGivenSecondary.estTokenA.toString()),
7189
- new Decimal(estimatedGivenSecondary.estTokenB.toString()),
7220
+ const estimatedGivenB: IncreaseLiquidityQuote = getIncreaseLiquidityQuote(
7221
+ params,
7222
+ whirlpoolState,
7223
+ positionState.tickLowerIndex,
7224
+ positionState.tickUpperIndex,
7225
+ defaultSlippagePercentageBPS,
7226
+ undefined, // todo: use new Wirlpool state and read transfer fees
7227
+ undefined
7228
+ );
7229
+ computedAmounts = [
7230
+ new Decimal(estimatedGivenB.tokenEstA.toString()),
7231
+ new Decimal(estimatedGivenB.tokenEstB.toString()),
7190
7232
  ];
7191
7233
  }
7192
- return [
7193
- new Decimal(estimatedGivenPrimary.estTokenA.toString()),
7194
- new Decimal(estimatedGivenPrimary.estTokenB.toString()),
7195
- ];
7234
+
7235
+ return computedAmounts;
7196
7236
  };
7197
7237
 
7198
7238
  calculateAmountsRaydium = async ({
@@ -7224,18 +7264,18 @@ export class Kamino {
7224
7264
  }
7225
7265
 
7226
7266
  if (tokenAAmount && tokenBAmount && tokenAAmount.gt(0) && tokenBAmount.gt(0)) {
7227
- const liquidity = LiquidityMath.getLiquidityFromTokenAmounts(
7267
+ const liquidity = RaydiumLiquidityMath.getLiquidityFromTokenAmounts(
7228
7268
  poolState.sqrtPriceX64,
7229
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
7230
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
7269
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
7270
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
7231
7271
  new BN(tokenAAmount.toString()),
7232
7272
  new BN(tokenBAmount.toString())
7233
7273
  );
7234
7274
 
7235
- const { amountA, amountB } = LiquidityMath.getAmountsFromLiquidity(
7275
+ const { amountA, amountB } = RaydiumLiquidityMath.getAmountsFromLiquidity(
7236
7276
  poolState.sqrtPriceX64,
7237
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
7238
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
7277
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
7278
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
7239
7279
  liquidity,
7240
7280
  true
7241
7281
  );
@@ -7245,10 +7285,10 @@ export class Kamino {
7245
7285
  const primaryTokenAmount = tokenAAmount || tokenBAmount;
7246
7286
  const secondaryTokenAmount = tokenAAmount ? tokenBAmount : tokenAAmount;
7247
7287
 
7248
- const { amountA, amountB } = LiquidityMath.getAmountsFromLiquidity(
7288
+ const { amountA, amountB } = RaydiumLiquidityMath.getAmountsFromLiquidity(
7249
7289
  poolState.sqrtPriceX64,
7250
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
7251
- SqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
7290
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickLowerIndex),
7291
+ RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(position.tickUpperIndex),
7252
7292
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
7253
7293
  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
7294
  true
@@ -7447,26 +7487,30 @@ export class Kamino {
7447
7487
  throw Error(`Could not fetch whirlpool state with pubkey ${strategyState.pool.toString()}`);
7448
7488
  }
7449
7489
 
7450
- const position = await Position.fetch(this._rpc, strategyState.position, this._orcaService.getWhirlpoolProgramId());
7490
+ const position = await OrcaPosition.fetch(
7491
+ this._rpc,
7492
+ strategyState.position,
7493
+ this._orcaService.getWhirlpoolProgramId()
7494
+ );
7451
7495
  if (!position) {
7452
7496
  throw new Error(`Whirlpool position ${strategyState.position} does not exist`);
7453
7497
  }
7454
7498
 
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,
7499
+ const params: IncreaseLiquidityQuoteParam = {
7500
+ tokenA: BigInt(amountA.toString()),
7465
7501
  };
7466
7502
 
7467
- const quote: InternalAddLiquidityQuote = getAddLiquidityQuote(params);
7503
+ const quote: IncreaseLiquidityQuote = getIncreaseLiquidityQuote(
7504
+ params,
7505
+ whirlpool,
7506
+ position.tickLowerIndex,
7507
+ position.tickUpperIndex,
7508
+ defaultSlippagePercentageBPS,
7509
+ undefined,
7510
+ undefined
7511
+ );
7468
7512
 
7469
- return { amountSlippageA: quote.estTokenA, amountSlippageB: quote.estTokenB };
7513
+ return { amountSlippageA: new BN(quote.tokenEstA.toString()), amountSlippageB: new BN(quote.tokenEstB.toString()) };
7470
7514
  }
7471
7515
 
7472
7516
  private async getDepositRatioFromAMeteora(
@@ -7517,26 +7561,30 @@ export class Kamino {
7517
7561
  throw Error(`Could not fetch whirlpool state with pubkey ${strategyState.pool.toString()}`);
7518
7562
  }
7519
7563
 
7520
- const position = await Position.fetch(this._rpc, strategyState.position, this._orcaService.getWhirlpoolProgramId());
7564
+ const position = await OrcaPosition.fetch(
7565
+ this._rpc,
7566
+ strategyState.position,
7567
+ this._orcaService.getWhirlpoolProgramId()
7568
+ );
7521
7569
  if (!position) {
7522
7570
  throw new Error(`Whirlpool position ${strategyState.position} does not exist`);
7523
7571
  }
7524
7572
 
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,
7573
+ const param: IncreaseLiquidityQuoteParam = {
7574
+ tokenB: BigInt(amountB.toString()),
7535
7575
  };
7536
7576
 
7537
- const quote: InternalAddLiquidityQuote = getAddLiquidityQuote(params);
7577
+ const quote: IncreaseLiquidityQuote = getIncreaseLiquidityQuote(
7578
+ param,
7579
+ whirlpool,
7580
+ position.tickLowerIndex,
7581
+ position.tickUpperIndex,
7582
+ defaultSlippagePercentageBPS,
7583
+ undefined,
7584
+ undefined
7585
+ );
7538
7586
 
7539
- return { amountSlippageA: quote.estTokenA, amountSlippageB: quote.estTokenB };
7587
+ return { amountSlippageA: new BN(quote.tokenEstA.toString()), amountSlippageB: new BN(quote.tokenEstB.toString()) };
7540
7588
  };
7541
7589
 
7542
7590
  private getDepositRatioFromARaydium = async (
@@ -7559,11 +7607,16 @@ export class Kamino {
7559
7607
  throw new Error(`Raydium pool ${strategyState.pool.toString()} could not be found.`);
7560
7608
  }
7561
7609
 
7562
- const lowerSqrtPriceX64 = SqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickLowerIndex);
7563
- const upperSqrtPriceX64 = SqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickUpperIndex);
7610
+ const lowerSqrtPriceX64 = RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickLowerIndex);
7611
+ const upperSqrtPriceX64 = RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickUpperIndex);
7564
7612
 
7565
- const liqudity = LiquidityMath.getLiquidityFromTokenAmountA(lowerSqrtPriceX64, upperSqrtPriceX64, amountA, false);
7566
- const amountsSlippage = LiquidityMath.getAmountsFromLiquidityWithSlippage(
7613
+ const liqudity = RaydiumLiquidityMath.getLiquidityFromTokenAmountA(
7614
+ lowerSqrtPriceX64,
7615
+ upperSqrtPriceX64,
7616
+ amountA,
7617
+ false
7618
+ );
7619
+ const amountsSlippage = RaydiumLiquidityMath.getAmountsFromLiquidityWithSlippage(
7567
7620
  poolState.sqrtPriceX64,
7568
7621
  lowerSqrtPriceX64,
7569
7622
  upperSqrtPriceX64,
@@ -7596,11 +7649,11 @@ export class Kamino {
7596
7649
  throw new Error(`Raydium pool ${strategyState.pool.toString()} could not be found.`);
7597
7650
  }
7598
7651
 
7599
- const lowerSqrtPriceX64 = SqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickLowerIndex);
7600
- const upperSqrtPriceX64 = SqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickUpperIndex);
7652
+ const lowerSqrtPriceX64 = RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickLowerIndex);
7653
+ const upperSqrtPriceX64 = RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(positionState.tickUpperIndex);
7601
7654
 
7602
- const liqudity = LiquidityMath.getLiquidityFromTokenAmountB(lowerSqrtPriceX64, upperSqrtPriceX64, amountB);
7603
- const amountsSlippage = LiquidityMath.getAmountsFromLiquidityWithSlippage(
7655
+ const liqudity = RaydiumLiquidityMath.getLiquidityFromTokenAmountB(lowerSqrtPriceX64, upperSqrtPriceX64, amountB);
7656
+ const amountsSlippage = RaydiumLiquidityMath.getAmountsFromLiquidityWithSlippage(
7604
7657
  poolState.sqrtPriceX64,
7605
7658
  lowerSqrtPriceX64,
7606
7659
  upperSqrtPriceX64,
@@ -7869,8 +7922,11 @@ export class Kamino {
7869
7922
 
7870
7923
  const decimalsA = await getMintDecimals(this._rpc, whilrpoolState.tokenMintA);
7871
7924
  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);
7925
+ const tickIndex = orcaGetTickArrayStartTickIndex(
7926
+ orcaPriceToTickIndex(price.toNumber(), decimalsA, decimalsB),
7927
+ whilrpoolState.tickSpacing
7928
+ );
7929
+ const startTickIndex = orcaGetTickArrayStartTickIndex(tickIndex, whilrpoolState.tickSpacing);
7874
7930
 
7875
7931
  const [startTickIndexPk, _startTickIndexBump] = await getTickArray(
7876
7932
  this._orcaService.getWhirlpoolProgramId(),