@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/utils/orca.ts CHANGED
@@ -1,8 +1,63 @@
1
- import { Address, getAddressEncoder, getProgramDerivedAddress } from '@solana/kit';
1
+ import { BN } from '@coral-xyz/anchor';
2
+ import {
3
+ address,
4
+ Address,
5
+ GetAccountInfoApi,
6
+ getAddressEncoder,
7
+ GetMultipleAccountsApi,
8
+ getProgramDerivedAddress,
9
+ Rpc,
10
+ } from '@solana/kit';
2
11
  import { ProgramDerivedAddress } from '@solana/addresses/dist/types/program-derived-address';
12
+ import { ONE_BN, U64_MAX, ZERO_BN } from '../constants';
13
+ import { Percentage } from './types';
14
+ import { DEFAULT_ADDRESS, IncreaseLiquidityQuoteParam } from '@orca-so/whirlpools';
15
+ import { TickArray, Whirlpool } from '../@codegen/whirlpools/accounts';
16
+ import {
17
+ _MAX_TICK_INDEX,
18
+ _MIN_TICK_INDEX,
19
+ getTickArrayStartTickIndex,
20
+ IncreaseLiquidityQuote,
21
+ tickIndexToPrice,
22
+ TransferFee,
23
+ } from '@orca-so/whirlpools-core';
24
+ import { increaseLiquidityQuoteA, increaseLiquidityQuoteB, increaseLiquidityQuote } from '@orca-so/whirlpools-core';
25
+ import { Whirlpool as WhirlpoolAPIResponse, WhirlpoolReward } from '../services/OrcaWhirlpoolsResponse';
26
+ import Decimal from 'decimal.js/decimal';
27
+ import { getRemoveLiquidityQuote } from './whirlpools';
28
+ import { FullBPS } from './CreationParameters';
29
+ import { fetchMaybeTickArray, getTickArrayAddress } from '@orca-so/whirlpools-client';
30
+ import { sleep } from './utils';
31
+ import { ZERO } from './math';
3
32
 
33
+ export const defaultSlippagePercentageBPS = 10;
4
34
  const addressEncoder = getAddressEncoder();
5
35
 
36
+ const TICK_ARRAY_SIZE = 88;
37
+
38
+ const SECONDS_PER_YEAR =
39
+ 60 * // SECONDS
40
+ 60 * // MINUTES
41
+ 24 * // HOURS
42
+ 365; // DAYS
43
+
44
+ function estimateRewardApr(
45
+ reward: WhirlpoolReward,
46
+ rewardTokenDecimals: number,
47
+ concentratedValue: Decimal,
48
+ tokenPrices: Map<Address, Decimal>
49
+ ) {
50
+ const { mint } = reward;
51
+ const rewardTokenPrice = tokenPrices.get(address(mint));
52
+ const emissionsPerSecond = new Decimal(reward.emissionsPerSecond).div(new Decimal(10).pow(rewardTokenDecimals));
53
+ if (emissionsPerSecond.eq(ZERO) || !rewardTokenPrice) {
54
+ return 0;
55
+ }
56
+
57
+ const res = emissionsPerSecond.mul(SECONDS_PER_YEAR).mul(rewardTokenPrice).div(concentratedValue).toNumber();
58
+ return res;
59
+ }
60
+
6
61
  export async function getTickArray(
7
62
  programId: Address,
8
63
  whirlpoolAddress: Address,
@@ -13,3 +68,324 @@ export async function getTickArray(
13
68
  programAddress: programId,
14
69
  });
15
70
  }
71
+
72
+ export function getTokenAFromLiquidity(liquidity: BN, sqrtPrice0X64: BN, sqrtPrice1X64: BN, roundUp: boolean) {
73
+ const [sqrtPriceLowerX64, sqrtPriceUpperX64] = orderSqrtPrice(sqrtPrice0X64, sqrtPrice1X64);
74
+
75
+ const numerator = liquidity.mul(sqrtPriceUpperX64.sub(sqrtPriceLowerX64)).shln(64);
76
+ const denominator = sqrtPriceUpperX64.mul(sqrtPriceLowerX64);
77
+ if (roundUp) {
78
+ return divRoundUp(numerator, denominator);
79
+ } else {
80
+ return numerator.div(denominator);
81
+ }
82
+ }
83
+
84
+ export function getTokenBFromLiquidity(liquidity: BN, sqrtPrice0X64: BN, sqrtPrice1X64: BN, roundUp: boolean) {
85
+ const [sqrtPriceLowerX64, sqrtPriceUpperX64] = orderSqrtPrice(sqrtPrice0X64, sqrtPrice1X64);
86
+
87
+ const result = liquidity.mul(sqrtPriceUpperX64.sub(sqrtPriceLowerX64));
88
+ if (roundUp) {
89
+ return shiftRightRoundUp(result);
90
+ } else {
91
+ return result.shrn(64);
92
+ }
93
+ }
94
+
95
+ export function getNearestValidTickIndexFromTickIndex(tickIndex: number, tickSpacing: number): number {
96
+ return tickIndex - (tickIndex % tickSpacing);
97
+ }
98
+
99
+ export function getIncreaseLiquidityQuote(
100
+ param: IncreaseLiquidityQuoteParam,
101
+ pool: Whirlpool,
102
+ tickLowerIndex: number,
103
+ tickUpperIndex: number,
104
+ slippageToleranceBps: number,
105
+ transferFeeA: TransferFee | undefined,
106
+ transferFeeB: TransferFee | undefined
107
+ ): IncreaseLiquidityQuote {
108
+ if ('liquidity' in param) {
109
+ return increaseLiquidityQuote(
110
+ param.liquidity,
111
+ slippageToleranceBps,
112
+ BigInt(pool.sqrtPrice.toString()),
113
+ tickLowerIndex,
114
+ tickUpperIndex,
115
+ transferFeeA,
116
+ transferFeeB
117
+ );
118
+ } else if ('tokenA' in param) {
119
+ return increaseLiquidityQuoteA(
120
+ param.tokenA,
121
+ slippageToleranceBps,
122
+ BigInt(pool.sqrtPrice.toString()),
123
+ tickLowerIndex,
124
+ tickUpperIndex,
125
+ transferFeeA,
126
+ transferFeeB
127
+ );
128
+ } else {
129
+ return increaseLiquidityQuoteB(
130
+ param.tokenB,
131
+ slippageToleranceBps,
132
+ BigInt(pool.sqrtPrice.toString()),
133
+ tickLowerIndex,
134
+ tickUpperIndex,
135
+ transferFeeA,
136
+ transferFeeB
137
+ );
138
+ }
139
+ }
140
+
141
+ function orderSqrtPrice(sqrtPrice0X64: BN, sqrtPrice1X64: BN): [BN, BN] {
142
+ if (sqrtPrice0X64.lt(sqrtPrice1X64)) {
143
+ return [sqrtPrice0X64, sqrtPrice1X64];
144
+ } else {
145
+ return [sqrtPrice1X64, sqrtPrice0X64];
146
+ }
147
+ }
148
+
149
+ function shiftRightRoundUp(n: BN): BN {
150
+ let result = n.shrn(64);
151
+
152
+ if (n.mod(new BN(U64_MAX)).gt(ZERO_BN)) {
153
+ result = result.add(ONE_BN);
154
+ }
155
+
156
+ return result;
157
+ }
158
+
159
+ function divRoundUp(n0: BN, n1: BN): BN {
160
+ const hasRemainder = !n0.mod(n1).eq(ZERO_BN);
161
+ if (hasRemainder) {
162
+ return n0.div(n1).add(ONE_BN);
163
+ } else {
164
+ return n0.div(n1);
165
+ }
166
+ }
167
+
168
+ export function adjustForSlippage(n: BN, { numerator, denominator }: Percentage, adjustUp: boolean): BN {
169
+ if (adjustUp) {
170
+ return n.mul(denominator.add(numerator)).div(denominator);
171
+ } else {
172
+ return n.mul(denominator).div(denominator.add(numerator));
173
+ }
174
+ }
175
+
176
+ export type EstimatedAprs = {
177
+ fee: number;
178
+ rewards: number[];
179
+ };
180
+
181
+ export const ZERO_APR = {
182
+ fee: 0,
183
+ rewards: [0, 0, 0],
184
+ };
185
+
186
+ export function estimateAprsForPriceRange(
187
+ pool: WhirlpoolAPIResponse,
188
+ tokenPrices: Map<Address, Decimal>,
189
+ fees24h: number,
190
+ tickLowerIndex: number,
191
+ tickUpperIndex: number,
192
+ rewardsDecimals: Map<Address, number>
193
+ ): EstimatedAprs {
194
+ const tokenPriceA = tokenPrices.get(address(pool.tokenMintA));
195
+ const tokenPriceB = tokenPrices.get(address(pool.tokenMintB));
196
+
197
+ if (!fees24h || !tokenPriceA || !tokenPriceB || tickLowerIndex >= tickUpperIndex) {
198
+ return ZERO_APR;
199
+ }
200
+
201
+ // Value of liquidity if the entire liquidity were concentrated between tickLower/Upper
202
+ // Since this is virtual liquidity, concentratedValue should actually be less than totalValue
203
+ const { minTokenA, minTokenB } = getRemoveLiquidityQuote({
204
+ positionAddress: DEFAULT_ADDRESS,
205
+ tickCurrentIndex: pool.tickCurrentIndex,
206
+ sqrtPrice: new BN(pool.sqrtPrice.toString()),
207
+ tickLowerIndex,
208
+ tickUpperIndex,
209
+ liquidity: new BN(pool.liquidity.toString()),
210
+ slippageTolerance: { numerator: ZERO_BN, denominator: new BN(FullBPS) },
211
+ });
212
+ const tokenValueA = getTokenValue(minTokenA, pool.tokenA.decimals, tokenPriceA);
213
+ const tokenValueB = getTokenValue(minTokenB, pool.tokenB.decimals, tokenPriceB);
214
+ const concentratedValue = tokenValueA.add(tokenValueB);
215
+
216
+ const feesPerYear = new Decimal(fees24h).mul(365).div(new Decimal(10).pow(6)); // scale from lamports of USDC to tokens
217
+ const feeApr = feesPerYear.div(concentratedValue).toNumber();
218
+
219
+ const rewards = pool.rewards.map((reward) => {
220
+ if (rewardsDecimals.has(address(reward.mint))) {
221
+ return estimateRewardApr(reward, rewardsDecimals.get(address(reward.mint))!, concentratedValue, tokenPrices);
222
+ } else {
223
+ return 0;
224
+ }
225
+ });
226
+
227
+ return { fee: feeApr, rewards };
228
+ }
229
+
230
+ function getTokenValue(tokenAmount: BN, decimals: number, tokenPrice: Decimal): Decimal {
231
+ return tokenPrice.mul(new Decimal(tokenAmount.toString()).div(new Decimal(10).pow(decimals)));
232
+ }
233
+
234
+ export async function getLowestInitializedTickArrayTickIndex(
235
+ rpc: Rpc<GetAccountInfoApi>,
236
+ whirlpoolAddress: Address,
237
+ tickSpacing: number
238
+ ): Promise<number> {
239
+ const minTick = _MIN_TICK_INDEX();
240
+ let startTickIndex = getTickArrayStartTickIndex(minTick, tickSpacing);
241
+
242
+ // eslint-disable-next-line
243
+ while (true) {
244
+ const [tickArrayAddress] = await getTickArrayAddress(whirlpoolAddress, startTickIndex);
245
+ const tickArray = await fetchMaybeTickArray(rpc, tickArrayAddress);
246
+
247
+ if (tickArray.exists) {
248
+ return startTickIndex;
249
+ }
250
+
251
+ startTickIndex += TICK_ARRAY_SIZE * tickSpacing;
252
+ await sleep(500);
253
+ }
254
+ }
255
+
256
+ export async function getHighestInitializedTickArrayTickIndex(
257
+ rpc: Rpc<GetAccountInfoApi>,
258
+ whirlpoolAddress: Address,
259
+ tickSpacing: number
260
+ ): Promise<number> {
261
+ const maxTick = _MAX_TICK_INDEX();
262
+ let startTickIndex = getTickArrayStartTickIndex(maxTick, tickSpacing);
263
+
264
+ // eslint-disable-next-line
265
+ while (true) {
266
+ const [tickArrayAddress] = await getTickArrayAddress(whirlpoolAddress, startTickIndex);
267
+ const tickArray = await fetchMaybeTickArray(rpc, tickArrayAddress);
268
+
269
+ if (tickArray.exists) {
270
+ return startTickIndex;
271
+ }
272
+
273
+ startTickIndex -= TICK_ARRAY_SIZE * tickSpacing;
274
+ await sleep(500);
275
+ }
276
+ }
277
+
278
+ export type LiquidityDataPoint = {
279
+ liquidity: Decimal;
280
+ price: Decimal;
281
+ tickIndex: number;
282
+ };
283
+ export type WhirlpoolLiquidityDistribution = {
284
+ currentPrice: Decimal;
285
+ currentTickIndex: number;
286
+ datapoints: LiquidityDataPoint[];
287
+ };
288
+
289
+ export async function getLiquidityDistribution(
290
+ rpc: Rpc<GetMultipleAccountsApi>,
291
+ poolAddress: Address,
292
+ poolData: WhirlpoolAPIResponse,
293
+ tickLower: number,
294
+ tickUpper: number,
295
+ whirlpoolProgramId: Address
296
+ ): Promise<WhirlpoolLiquidityDistribution> {
297
+ const datapoints: LiquidityDataPoint[] = [];
298
+
299
+ const tokenDecimalsA = poolData.tokenA.decimals;
300
+ const tokenDecimalsB = poolData.tokenB.decimals;
301
+
302
+ const tickArrayAddresses = await getSurroundingTickArrayAddresses(
303
+ poolAddress,
304
+ poolData,
305
+ tickLower,
306
+ tickUpper,
307
+ whirlpoolProgramId
308
+ );
309
+ const tickArrays = await TickArray.fetchMultiple(rpc, tickArrayAddresses, whirlpoolProgramId);
310
+
311
+ const currentLiquidity = new Decimal(poolData.liquidity.toString());
312
+ let relativeLiquidity = currentLiquidity;
313
+ let minLiquidity = new Decimal(0);
314
+ let liquidity = new Decimal(0);
315
+
316
+ tickArrays.forEach((tickArray) => {
317
+ if (!tickArray) {
318
+ return;
319
+ }
320
+
321
+ const startIndex = tickArray.startTickIndex;
322
+ tickArray.ticks.forEach((tick, index) => {
323
+ const tickIndex = startIndex + index * poolData.tickSpacing;
324
+ const price = tickIndexToPrice(tickIndex, tokenDecimalsA, tokenDecimalsB);
325
+ const liquidityNet = new Decimal(tick.liquidityNet.toString());
326
+ liquidity = liquidity.add(liquidityNet);
327
+ datapoints.push({ liquidity: new Decimal(liquidity), price: new Decimal(price), tickIndex });
328
+
329
+ minLiquidity = liquidity.lt(minLiquidity) ? liquidity : minLiquidity;
330
+
331
+ if (tickIndex === poolData.tickCurrentIndex) {
332
+ relativeLiquidity = relativeLiquidity.sub(liquidityNet);
333
+ }
334
+ });
335
+ });
336
+
337
+ if (!relativeLiquidity.eq(currentLiquidity)) {
338
+ minLiquidity = minLiquidity.add(relativeLiquidity);
339
+ datapoints.forEach((datapoint) => {
340
+ datapoint.liquidity = datapoint.liquidity.add(relativeLiquidity);
341
+ });
342
+ }
343
+
344
+ if (minLiquidity.lt(0)) {
345
+ datapoints.forEach((datapoint) => {
346
+ datapoint.liquidity = datapoint.liquidity.add(minLiquidity.neg());
347
+ });
348
+ }
349
+
350
+ return {
351
+ currentPrice: new Decimal(poolData.price),
352
+ currentTickIndex: poolData.tickCurrentIndex,
353
+ datapoints,
354
+ };
355
+ }
356
+
357
+ async function getSurroundingTickArrayAddresses(
358
+ poolAddress: Address,
359
+ pool: WhirlpoolAPIResponse,
360
+ tickLower: number,
361
+ tickUpper: number,
362
+ programId: Address
363
+ ): Promise<Address[]> {
364
+ const tickArrayAddresses: Address[] = [];
365
+
366
+ let startIndex = getTickArrayStartTickIndex(tickLower, pool.tickSpacing);
367
+ while (startIndex <= tickUpper) {
368
+ const [address, _bump] = await getTickArrayPda(programId, poolAddress, startIndex);
369
+ tickArrayAddresses.push(address);
370
+
371
+ try {
372
+ startIndex = getTickArrayStartTickIndex(startIndex, pool.tickSpacing);
373
+ } catch (_e) {
374
+ return tickArrayAddresses;
375
+ }
376
+ }
377
+ return tickArrayAddresses;
378
+ }
379
+
380
+ export async function getTickArrayPda(
381
+ programId: Address,
382
+ poolAddress: Address,
383
+ startIndex: number
384
+ ): Promise<[Address, number]> {
385
+ const pdaWithBump = await getProgramDerivedAddress({
386
+ seeds: [Buffer.from('tick_array'), addressEncoder.encode(poolAddress), Buffer.from(startIndex.toString())],
387
+ programAddress: programId,
388
+ });
389
+
390
+ return [pdaWithBump[0], pdaWithBump[1]];
391
+ }
@@ -1,6 +1,5 @@
1
1
  import { Address, IInstruction, address, TransactionSigner, Rpc, GetAccountInfoApi, Account } from '@solana/kit';
2
2
  import { WhirlpoolStrategy } from '../@codegen/kliquidity/accounts';
3
- import { tickIndexToPrice } from '@orca-so/whirlpool-sdk';
4
3
  import Decimal from 'decimal.js';
5
4
  import { CollateralInfo } from '../@codegen/kliquidity/types';
6
5
  import { getPriceOfBinByBinIdWithDecimals } from './meteora';
@@ -15,6 +14,7 @@ import {
15
14
  } from '@solana-program/token-2022';
16
15
  import { SYSTEM_PROGRAM_ADDRESS } from '@solana-program/system';
17
16
  import { getSetComputeUnitLimitInstruction } from '@solana-program/compute-budget';
17
+ import { tickIndexToPrice } from '@orca-so/whirlpools-core';
18
18
 
19
19
  export const SOL_MINTS = [
20
20
  address('So11111111111111111111111111111111111111111'),
@@ -52,7 +52,7 @@ export async function getAssociatedTokenAddress(
52
52
 
53
53
  export function createAssociatedTokenAccountInstruction(
54
54
  payer: TransactionSigner,
55
- associatedToken: Address,
55
+ associatedTokenAddress: Address,
56
56
  owner: Address,
57
57
  mint: Address,
58
58
  programId: Address = TOKEN_PROGRAM_ADDRESS,
@@ -62,7 +62,7 @@ export function createAssociatedTokenAccountInstruction(
62
62
  {
63
63
  mint,
64
64
  owner,
65
- ata: associatedToken,
65
+ ata: associatedTokenAddress,
66
66
  payer: payer,
67
67
  tokenProgram: programId,
68
68
  systemProgram: SYSTEM_PROGRAM_ADDRESS,
@@ -99,9 +99,9 @@ export function getStrategyPriceRangeRaydium(
99
99
  tokenBDecimals: number
100
100
  ) {
101
101
  const { priceLower, priceUpper } = getPriceLowerUpper(tickLowerIndex, tickUpperIndex, tokenADecimals, tokenBDecimals);
102
- const poolPrice = tickIndexToPrice(tickCurrent, tokenADecimals, tokenBDecimals);
102
+ const poolPrice = new Decimal(tickIndexToPrice(tickCurrent, tokenADecimals, tokenBDecimals));
103
103
  const strategyOutOfRange = poolPrice.lt(priceLower) || poolPrice.gt(priceUpper);
104
- return { priceLower, poolPrice, priceUpper, strategyOutOfRange };
104
+ return { priceLower: new Decimal(priceLower), poolPrice, priceUpper: new Decimal(priceUpper), strategyOutOfRange };
105
105
  }
106
106
 
107
107
  export function getStrategyPriceRangeMeteora(
@@ -1,3 +1,5 @@
1
+ import { BN } from '@coral-xyz/anchor';
2
+
1
3
  import { address, Address, IInstruction, TransactionMessage, TransactionSigner } from '@solana/kit';
2
4
  import { WhirlpoolStrategy } from '../@codegen/kliquidity/accounts';
3
5
  import { Dex, collToLamportsDecimal } from './utils';
@@ -310,3 +312,8 @@ export interface InitPoolTickIfNeeded {
310
312
  tick: Address;
311
313
  initTickIx: IInstruction | undefined;
312
314
  }
315
+
316
+ export type Percentage = {
317
+ numerator: BN;
318
+ denominator: BN;
319
+ };
@@ -19,19 +19,17 @@ import {
19
19
  import { RebalanceFieldInfo, RebalanceFieldsDict } from './types';
20
20
  import BN from 'bn.js';
21
21
  import { PoolPriceReferenceType, TwapPriceReferenceType } from './priceReferenceTypes';
22
- import { sqrtPriceX64ToPrice } from '@orca-so/whirlpool-sdk';
23
22
  import { U64_MAX } from '../constants/numericalValues';
24
23
  import { SqrtPriceMath } from '@raydium-io/raydium-sdk-v2/lib/raydium/clmm/utils/math';
25
24
  import { DEFAULT_PUBLIC_KEY } from '../constants/pubkeys';
26
25
  import { SYSTEM_PROGRAM_ADDRESS } from '@solana-program/system';
26
+ import { sqrtPriceToPrice as orcaSqrtPriceToPrice } from '@orca-so/whirlpools-core';
27
27
 
28
28
  export const DollarBasedMintingMethod = new Decimal(0);
29
29
  export const ProportionalMintingMethod = new Decimal(1);
30
30
 
31
31
  export const RebalanceParamOffset = new Decimal(256);
32
32
 
33
- export const ZERO_BN = new BN(0);
34
-
35
33
  export function sleep(ms: number) {
36
34
  return new Promise((resolve) => setTimeout(resolve, ms));
37
35
  }
@@ -272,7 +270,7 @@ export function isVaultInitialized(vault: Address, decimals: BN): boolean {
272
270
  export function sqrtPriceToPrice(sqrtPrice: BN, dexNo: number, decimalsA: number, decimalsB: number): Decimal {
273
271
  const dex = numberToDex(dexNo);
274
272
  if (dex == 'ORCA') {
275
- return sqrtPriceX64ToPrice(sqrtPrice, decimalsA, decimalsB);
273
+ return new Decimal(orcaSqrtPriceToPrice(BigInt(sqrtPrice.toString()), decimalsA, decimalsB));
276
274
  }
277
275
  if (dex == 'RAYDIUM') {
278
276
  return SqrtPriceMath.sqrtPriceX64ToPrice(sqrtPrice, decimalsA, decimalsB);
@@ -2,19 +2,13 @@
2
2
  /**
3
3
  * Added roundUp flag to accurately estimate token holdings for deposits
4
4
  */
5
- import { tickIndexToSqrtPriceX64 } from '@orca-so/whirlpool-client-sdk';
5
+
6
6
  import { BN } from '@coral-xyz/anchor';
7
7
  import { Address } from '@solana/kit';
8
- import {
9
- adjustForSlippage,
10
- getTokenAFromLiquidity,
11
- getTokenBFromLiquidity,
12
- Percentage,
13
- PositionStatus,
14
- PositionUtil,
15
- RemoveLiquidityQuote,
16
- } from '@orca-so/whirlpool-sdk';
17
- import { ZERO_BN } from './utils';
8
+ import { positionStatus, tickIndexToSqrtPrice } from '@orca-so/whirlpools-core';
9
+ import { ZERO_BN } from '../constants/numericalValues';
10
+ import { adjustForSlippage, getTokenAFromLiquidity, getTokenBFromLiquidity } from './orca';
11
+ import { Percentage } from './types';
18
12
 
19
13
  export type InternalRemoveLiquidityQuoteParam = {
20
14
  positionAddress: Address;
@@ -30,21 +24,17 @@ export function getRemoveLiquidityQuote(
30
24
  param: InternalRemoveLiquidityQuoteParam,
31
25
  roundUp: boolean = false
32
26
  ): RemoveLiquidityQuote {
33
- const positionStatus = PositionUtil.getPositionStatus(
34
- param.tickCurrentIndex,
35
- param.tickLowerIndex,
36
- param.tickUpperIndex
37
- );
27
+ const posStatus = positionStatus(BigInt(param.sqrtPrice.toString()), param.tickLowerIndex, param.tickUpperIndex);
38
28
 
39
- switch (positionStatus) {
40
- case PositionStatus.BelowRange:
29
+ switch (posStatus) {
30
+ case 'priceBelowRange':
41
31
  return getRemoveLiquidityQuoteWhenPositionIsBelowRange(param, roundUp);
42
- case PositionStatus.InRange:
32
+ case 'priceInRange':
43
33
  return getRemoveLiquidityQuoteWhenPositionIsInRange(param, roundUp);
44
- case PositionStatus.AboveRange:
34
+ case 'priceAboveRange':
45
35
  return getRemoveLiquidityQuoteWhenPositionIsAboveRange(param, roundUp);
46
36
  default:
47
- throw new Error(`type ${positionStatus} is an unknown PositionStatus`);
37
+ throw new Error(`type ${posStatus} is an unknown PositionStatus`);
48
38
  }
49
39
  }
50
40
 
@@ -54,10 +44,15 @@ function getRemoveLiquidityQuoteWhenPositionIsBelowRange(
54
44
  ): RemoveLiquidityQuote {
55
45
  const { positionAddress, tickLowerIndex, tickUpperIndex, liquidity, slippageTolerance } = param;
56
46
 
57
- const sqrtPriceLowerX64 = tickIndexToSqrtPriceX64(tickLowerIndex);
58
- const sqrtPriceUpperX64 = tickIndexToSqrtPriceX64(tickUpperIndex);
47
+ const sqrtPriceLowerX64 = tickIndexToSqrtPrice(tickLowerIndex);
48
+ const sqrtPriceUpperX64 = tickIndexToSqrtPrice(tickUpperIndex);
59
49
 
60
- const estTokenA = getTokenAFromLiquidity(liquidity, sqrtPriceLowerX64, sqrtPriceUpperX64, roundUp);
50
+ const estTokenA = getTokenAFromLiquidity(
51
+ liquidity,
52
+ new BN(sqrtPriceLowerX64.toString()),
53
+ new BN(sqrtPriceUpperX64.toString()),
54
+ roundUp
55
+ );
61
56
  const minTokenA = adjustForSlippage(estTokenA, slippageTolerance, roundUp);
62
57
 
63
58
  return {
@@ -77,13 +72,23 @@ function getRemoveLiquidityQuoteWhenPositionIsInRange(
77
72
  const { positionAddress, sqrtPrice, tickLowerIndex, tickUpperIndex, liquidity, slippageTolerance } = param;
78
73
 
79
74
  const sqrtPriceX64 = sqrtPrice;
80
- const sqrtPriceLowerX64 = tickIndexToSqrtPriceX64(tickLowerIndex);
81
- const sqrtPriceUpperX64 = tickIndexToSqrtPriceX64(tickUpperIndex);
75
+ const sqrtPriceLowerX64 = tickIndexToSqrtPrice(tickLowerIndex);
76
+ const sqrtPriceUpperX64 = tickIndexToSqrtPrice(tickUpperIndex);
82
77
 
83
- const estTokenA = getTokenAFromLiquidity(liquidity, sqrtPriceX64, sqrtPriceUpperX64, roundUp);
78
+ const estTokenA = getTokenAFromLiquidity(
79
+ liquidity,
80
+ new BN(sqrtPriceX64.toString()),
81
+ new BN(sqrtPriceUpperX64.toString()),
82
+ roundUp
83
+ );
84
84
  const minTokenA = adjustForSlippage(estTokenA, slippageTolerance, roundUp);
85
85
 
86
- const estTokenB = getTokenBFromLiquidity(liquidity, sqrtPriceLowerX64, sqrtPriceX64, roundUp);
86
+ const estTokenB = getTokenBFromLiquidity(
87
+ liquidity,
88
+ new BN(sqrtPriceLowerX64.toString()),
89
+ new BN(sqrtPriceX64.toString()),
90
+ roundUp
91
+ );
87
92
  const minTokenB = adjustForSlippage(estTokenB, slippageTolerance, roundUp);
88
93
 
89
94
  return {
@@ -102,10 +107,15 @@ function getRemoveLiquidityQuoteWhenPositionIsAboveRange(
102
107
  ): RemoveLiquidityQuote {
103
108
  const { positionAddress, tickLowerIndex, tickUpperIndex, liquidity, slippageTolerance: slippageTolerance } = param;
104
109
 
105
- const sqrtPriceLowerX64 = tickIndexToSqrtPriceX64(tickLowerIndex);
106
- const sqrtPriceUpperX64 = tickIndexToSqrtPriceX64(tickUpperIndex);
110
+ const sqrtPriceLowerX64 = tickIndexToSqrtPrice(tickLowerIndex);
111
+ const sqrtPriceUpperX64 = tickIndexToSqrtPrice(tickUpperIndex);
107
112
 
108
- const estTokenB = getTokenBFromLiquidity(liquidity, sqrtPriceLowerX64, sqrtPriceUpperX64, roundUp);
113
+ const estTokenB = getTokenBFromLiquidity(
114
+ liquidity,
115
+ new BN(sqrtPriceLowerX64.toString()),
116
+ new BN(sqrtPriceUpperX64.toString()),
117
+ roundUp
118
+ );
109
119
  const minTokenB = adjustForSlippage(estTokenB, slippageTolerance, roundUp);
110
120
 
111
121
  return {
@@ -117,3 +127,12 @@ function getRemoveLiquidityQuoteWhenPositionIsAboveRange(
117
127
  liquidity,
118
128
  };
119
129
  }
130
+
131
+ export type RemoveLiquidityQuote = {
132
+ positionAddress: Address;
133
+ minTokenA: BN;
134
+ minTokenB: BN;
135
+ estTokenA: BN;
136
+ estTokenB: BN;
137
+ liquidity: BN;
138
+ };