Skip to content

Commit 3dd9201

Browse files
authored
increaseLiquidity.ts enhancements (#512)
* Uniform naming. Fix return types. Fix rent calculation. Add tickindex ordering. * Extend types * Format --------- Co-authored-by: calintje <[email protected]>
1 parent 3ba9c08 commit 3dd9201

File tree

4 files changed

+75
-76
lines changed

4 files changed

+75
-76
lines changed

docs/whirlpool/docs/03-Whirlpools SDKs/03-Whirlpools/03-Whirlpool Management/01-Create Pool.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ Splash Pools are the easiest way to get started:
3838
```tsx
3939
import { createSplashPoolInstructions } from '@orca-so/whirlpools'
4040

41-
const { poolAddress, instructions, estInitializationCost } = await createSplashPoolInstructions(
41+
const { poolAddress, instructions, initializationCost } = await createSplashPoolInstructions(
4242
rpc,
4343
tokenMintOne,
4444
tokenMintTwo,
@@ -60,7 +60,7 @@ Concentrated Liquidity Pools offer more flexibility:
6060
```tsx
6161
import { createConcentratedLiquidityPool } from '@orca-so/whirlpools'
6262

63-
const { poolAddress, instructions, estInitializationCost } = await createConcentratedLiquidityPool(
63+
const { poolAddress, instructions, initializationCost } = await createConcentratedLiquidityPool(
6464
rpc,
6565
tokenMintOne,
6666
tokenMintTwo,

ts-sdk/whirlpool/src/createPool.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export type CreatePoolInstructions = {
4444
instructions: IInstruction[];
4545

4646
/** The estimated rent exemption cost for initializing the pool, in lamports. */
47-
estInitializationCost: Lamports;
47+
initializationCost: Lamports;
4848

4949
/** The address of the newly created pool. */
5050
poolAddress: Address;
@@ -74,7 +74,7 @@ export type CreatePoolInstructions = {
7474
* const tokenMintTwo = "TOKEN_MINT_ADDRESS_2";
7575
* const initialPrice = 0.01;
7676
*
77-
* const { poolAddress, instructions, estInitializationCost } = await createSplashPoolInstructions(
77+
* const { poolAddress, instructions, initializationCost } = await createSplashPoolInstructions(
7878
* devnetRpc,
7979
* tokenMintOne,
8080
* tokenMintTwo,
@@ -125,7 +125,7 @@ export function createSplashPoolInstructions(
125125
* const tickSpacing = 64;
126126
* const initialPrice = 0.01;
127127
*
128-
* const { poolAddress, instructions, estInitializationCost } = await createConcentratedLiquidityPoolInstructions(
128+
* const { poolAddress, instructions, initializationCost } = await createConcentratedLiquidityPoolInstructions(
129129
* devnetRpc,
130130
* tokenMintOne,
131131
* tokenMintTwo,
@@ -264,6 +264,6 @@ export async function createConcentratedLiquidityPoolInstructions(
264264
return {
265265
instructions,
266266
poolAddress,
267-
estInitializationCost: lamports(nonRefundableRent),
267+
initializationCost: lamports(nonRefundableRent),
268268
};
269269
}

ts-sdk/whirlpool/src/increaseLiquidity.ts

Lines changed: 53 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
} from "@orca-so/whirlpools-client";
1313
import type {
1414
IncreaseLiquidityQuote,
15-
TickRange,
1615
TransferFee,
1716
} from "@orca-so/whirlpools-core";
1817
import {
@@ -40,6 +39,7 @@ import type {
4039
TransactionSigner,
4140
} from "@solana/web3.js";
4241
import { address, generateKeyPairSigner, lamports } from "@solana/web3.js";
42+
import { fetchSysvarRent } from "@solana/sysvars";
4343
import {
4444
DEFAULT_ADDRESS,
4545
FUNDER,
@@ -61,6 +61,7 @@ import {
6161
} from "@solana-program/token-2022";
6262
import { MEMO_PROGRAM_ADDRESS } from "@solana-program/memo";
6363
import assert from "assert";
64+
import { calculateMinimumBalanceForRentExemption } from "./sysvar";
6465

6566
// TODO: allow specify number as well as bigint
6667
// TODO: transfer hook
@@ -91,20 +92,15 @@ export type IncreaseLiquidityInstructions = {
9192
/** The quote object with details about the increase in liquidity, including the liquidity delta, estimated tokens, and maximum token amounts based on slippage tolerance. */
9293
quote: IncreaseLiquidityQuote;
9394

94-
/** The initialization cost for liquidity in lamports. */
95-
initializationCost: Lamports;
96-
97-
/** The mint address of the position NFT. */
98-
positionMint: Address;
99-
10095
/** List of Solana transaction instructions to execute. */
10196
instructions: IInstruction[];
10297
};
10398

10499
function getIncreaseLiquidityQuote(
105100
param: IncreaseLiquidityQuoteParam,
106101
pool: Whirlpool,
107-
tickRange: TickRange,
102+
tickLowerIndex: number,
103+
tickUpperIndex: number,
108104
slippageToleranceBps: number,
109105
transferFeeA: TransferFee | undefined,
110106
transferFeeB: TransferFee | undefined,
@@ -114,8 +110,8 @@ function getIncreaseLiquidityQuote(
114110
param.liquidity,
115111
slippageToleranceBps,
116112
pool.sqrtPrice,
117-
tickRange.tickLowerIndex,
118-
tickRange.tickUpperIndex,
113+
tickLowerIndex,
114+
tickUpperIndex,
119115
transferFeeA,
120116
transferFeeB,
121117
);
@@ -124,8 +120,8 @@ function getIncreaseLiquidityQuote(
124120
param.tokenA,
125121
slippageToleranceBps,
126122
pool.sqrtPrice,
127-
tickRange.tickLowerIndex,
128-
tickRange.tickUpperIndex,
123+
tickLowerIndex,
124+
tickUpperIndex,
129125
transferFeeA,
130126
transferFeeB,
131127
);
@@ -134,8 +130,8 @@ function getIncreaseLiquidityQuote(
134130
param.tokenB,
135131
slippageToleranceBps,
136132
pool.sqrtPrice,
137-
tickRange.tickLowerIndex,
138-
tickRange.tickUpperIndex,
133+
tickLowerIndex,
134+
tickUpperIndex,
139135
transferFeeA,
140136
transferFeeB,
141137
);
@@ -206,7 +202,8 @@ export async function increaseLiquidityInstructions(
206202
const quote = getIncreaseLiquidityQuote(
207203
param,
208204
whirlpool.data,
209-
position.data,
205+
position.data.tickLowerIndex,
206+
position.data.tickUpperIndex,
210207
slippageToleranceBps,
211208
transferFeeA,
212209
transferFeeB,
@@ -276,11 +273,21 @@ export async function increaseLiquidityInstructions(
276273
return {
277274
quote,
278275
instructions,
279-
positionMint: positionMintAddress,
280-
initializationCost: lamports(0n),
281276
};
282277
}
283278

279+
/**
280+
* Represents the instructions and quote for opening a position.
281+
* Extends IncreaseLiquidityInstructions with additional fields for position initialization.
282+
*/
283+
export type OpenPositionInstructions = IncreaseLiquidityInstructions & {
284+
/** The initialization cost for opening the position in lamports. */
285+
initializationCost: Lamports;
286+
287+
/** The mint address of the position NFT. */
288+
positionMint: Address;
289+
};
290+
284291
async function internalOpenPositionInstructions(
285292
rpc: Rpc<
286293
GetAccountInfoApi &
@@ -296,28 +303,28 @@ async function internalOpenPositionInstructions(
296303
mintB: Account<Mint>,
297304
slippageToleranceBps: number = SLIPPAGE_TOLERANCE_BPS,
298305
funder: TransactionSigner = FUNDER,
299-
): Promise<IncreaseLiquidityInstructions> {
306+
): Promise<OpenPositionInstructions> {
300307
assert(
301308
funder.address !== DEFAULT_ADDRESS,
302309
"Either supply a funder or set the default funder",
303310
);
304311
const instructions: IInstruction[] = [];
305-
let nonReclaimableStateSpace = 0;
312+
313+
const rent = await fetchSysvarRent(rpc);
314+
let nonRefundableRent: bigint = 0n;
315+
316+
const tickRange = orderTickIndexes(lowerTickIndex, upperTickIndex);
306317

307318
const initializableLowerTickIndex = getInitializableTickIndex(
308-
lowerTickIndex,
319+
tickRange.tickLowerIndex,
309320
whirlpool.data.tickSpacing,
310321
false,
311322
);
312323
const initializableUpperTickIndex = getInitializableTickIndex(
313-
upperTickIndex,
324+
tickRange.tickUpperIndex,
314325
whirlpool.data.tickSpacing,
315326
true,
316327
);
317-
const tickRange = orderTickIndexes(
318-
initializableLowerTickIndex,
319-
initializableUpperTickIndex,
320-
);
321328

322329
const currentEpoch = await rpc.getEpochInfo().send();
323330
const transferFeeA = getCurrentTransferFee(mintA, currentEpoch.epoch);
@@ -326,7 +333,8 @@ async function internalOpenPositionInstructions(
326333
const quote = getIncreaseLiquidityQuote(
327334
param,
328335
whirlpool.data,
329-
tickRange,
336+
initializableLowerTickIndex,
337+
initializableUpperTickIndex,
330338
slippageToleranceBps,
331339
transferFeeA,
332340
transferFeeB,
@@ -335,11 +343,11 @@ async function internalOpenPositionInstructions(
335343
const positionMint = await generateKeyPairSigner();
336344

337345
const lowerTickArrayIndex = getTickArrayStartTickIndex(
338-
tickRange.tickLowerIndex,
346+
initializableLowerTickIndex,
339347
whirlpool.data.tickSpacing,
340348
);
341349
const upperTickArrayIndex = getTickArrayStartTickIndex(
342-
tickRange.tickUpperIndex,
350+
initializableUpperTickIndex,
343351
whirlpool.data.tickSpacing,
344352
);
345353

@@ -385,7 +393,10 @@ async function internalOpenPositionInstructions(
385393
startTickIndex: lowerTickIndex,
386394
}),
387395
);
388-
nonReclaimableStateSpace += getTickArraySize();
396+
nonRefundableRent += calculateMinimumBalanceForRentExemption(
397+
rent,
398+
getTickArraySize(),
399+
);
389400
}
390401

391402
if (!upperTickArray.exists && lowerTickArrayIndex !== upperTickArrayIndex) {
@@ -397,7 +408,10 @@ async function internalOpenPositionInstructions(
397408
startTickIndex: upperTickIndex,
398409
}),
399410
);
400-
nonReclaimableStateSpace += getTickArraySize();
411+
nonRefundableRent += calculateMinimumBalanceForRentExemption(
412+
rent,
413+
getTickArraySize(),
414+
);
401415
}
402416

403417
instructions.push(
@@ -409,8 +423,8 @@ async function internalOpenPositionInstructions(
409423
positionTokenAccount,
410424
whirlpool: whirlpool.address,
411425
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
412-
tickLowerIndex: tickRange.tickLowerIndex,
413-
tickUpperIndex: tickRange.tickUpperIndex,
426+
tickLowerIndex: initializableLowerTickIndex,
427+
tickUpperIndex: initializableUpperTickIndex,
414428
token2022Program: TOKEN_2022_PROGRAM_ADDRESS,
415429
metadataUpdateAuth: address(
416430
"3axbTs2z5GBy6usVbNVoqEgZMng3vZvMnAoX29BFfwhr",
@@ -445,18 +459,11 @@ async function internalOpenPositionInstructions(
445459

446460
instructions.push(...cleanupInstructions);
447461

448-
let nonRefundableRent = lamports(0n);
449-
if (nonReclaimableStateSpace > 0) {
450-
nonRefundableRent = await rpc
451-
.getMinimumBalanceForRentExemption(BigInt(nonReclaimableStateSpace))
452-
.send();
453-
}
454-
455462
return {
456463
instructions,
457464
quote,
458465
positionMint: positionMint.address,
459-
initializationCost: nonRefundableRent,
466+
initializationCost: lamports(nonRefundableRent),
460467
};
461468
}
462469

@@ -468,7 +475,7 @@ async function internalOpenPositionInstructions(
468475
* @param {IncreaseLiquidityQuoteParam} param - The parameters for adding liquidity, where one of `liquidity`, `tokenA`, or `tokenB` must be specified. The SDK will compute the others.
469476
* @param {number} [slippageToleranceBps=SLIPPAGE_TOLERANCE_BPS] - The maximum acceptable slippage, in basis points (BPS).
470477
* @param {TransactionSigner} [funder=FUNDER] - The account funding the transaction.
471-
* @returns {Promise<IncreaseLiquidityInstructions>} A promise that resolves to an object containing the instructions, quote, position mint address, and initialization costs for increasing liquidity.
478+
* @returns {Promise<OpenPositionInstructions>} A promise that resolves to an object containing the instructions, quote, position mint address, and initialization costs for increasing liquidity.
472479
*
473480
* @example
474481
* import { openFullRangePositionInstructions } from '@orca-so/whirlpools';
@@ -502,7 +509,7 @@ export async function openFullRangePositionInstructions(
502509
param: IncreaseLiquidityQuoteParam,
503510
slippageToleranceBps: number = SLIPPAGE_TOLERANCE_BPS,
504511
funder: TransactionSigner = FUNDER,
505-
): Promise<IncreaseLiquidityInstructions> {
512+
): Promise<OpenPositionInstructions> {
506513
const whirlpool = await fetchWhirlpool(rpc, poolAddress);
507514
const tickRange = getFullRangeTickIndexes(whirlpool.data.tickSpacing);
508515
const [mintA, mintB] = await fetchAllMint(rpc, [
@@ -536,7 +543,7 @@ export async function openFullRangePositionInstructions(
536543
* @param {number} [slippageToleranceBps=SLIPPAGE_TOLERANCE_BPS] - The slippage tolerance for adding liquidity, in basis points (BPS).
537544
* @param {TransactionSigner} [funder=FUNDER] - The account funding the transaction.
538545
*
539-
* @returns {Promise<IncreaseLiquidityInstructions>} A promise that resolves to an object containing instructions, quote, position mint address, and initialization costs for increasing liquidity.
546+
* @returns {Promise<OpenPositionInstructions>} A promise that resolves to an object containing instructions, quote, position mint address, and initialization costs for increasing liquidity.
540547
*
541548
* @example
542549
* import { openPositionInstructions } from '@orca-so/whirlpools';
@@ -575,7 +582,7 @@ export async function openPositionInstructions(
575582
upperPrice: number,
576583
slippageToleranceBps: number = SLIPPAGE_TOLERANCE_BPS,
577584
funder: TransactionSigner = FUNDER,
578-
): Promise<IncreaseLiquidityInstructions> {
585+
): Promise<OpenPositionInstructions> {
579586
const whirlpool = await fetchWhirlpool(rpc, poolAddress);
580587
assert(
581588
whirlpool.data.tickSpacing !== SPLASH_POOL_TICK_SPACING,
@@ -588,21 +595,13 @@ export async function openPositionInstructions(
588595
const decimalsA = mintA.data.decimals;
589596
const decimalsB = mintB.data.decimals;
590597
const lowerTickIndex = priceToTickIndex(lowerPrice, decimalsA, decimalsB);
591-
const lowerInitializableTickIndex = getInitializableTickIndex(
592-
lowerTickIndex,
593-
whirlpool.data.tickSpacing,
594-
);
595598
const upperTickIndex = priceToTickIndex(upperPrice, decimalsA, decimalsB);
596-
const upperInitializableTickIndex = getInitializableTickIndex(
597-
upperTickIndex,
598-
whirlpool.data.tickSpacing,
599-
);
600599
return internalOpenPositionInstructions(
601600
rpc,
602601
whirlpool,
603602
param,
604-
lowerInitializableTickIndex,
605-
upperInitializableTickIndex,
603+
lowerTickIndex,
604+
upperTickIndex,
606605
mintA,
607606
mintB,
608607
slippageToleranceBps,

0 commit comments

Comments
 (0)