Modifying Liquidity

Whirlpools provide two instructions - increase_liquidity and decrease_liquidity to allow users to modify their position's liquidity.

The SDK also provides quote functions (ex. increaseLiquidityQuoteByInputToken, decreaseLiquidityQuoteByLiquidity) to help estimate the tokenIn/Out from the liquidity operation.

Using Whirlpool Client

Use the Position class from the WhirlpoolClient to fetch and manage your liquidity. Read below for more on the relationship between quote and the transaction.

const position = await client.getPosition(positionAddress);
const preIncreaseData = position.getData();
const increase_quote = increaseLiquidityQuoteByInputToken(
  poolInitInfo.tokenMintB,
  new Decimal(70),
  lowerTick,
  upperTick,
  Percentage.fromFraction(1, 100),
  pool
);

await (
  await position.increaseLiquidity(increase_quote, ctx.wallet.publicKey, ctx.wallet.publicKey)
).buildAndExecute();

The Manual Way

For each instruction, calculate the following values:

  • liquidityAmount - The total amount of liquidity you would like to deposit/withdraw into your position.

  • tokenMax A, B (increase_liquidity) - The maximum amount of token X to add to the position. Note the value here is shifted by the decimal places of the token.

  • tokenMin A, B (decrease_liquidity) - The minimum amount of token X to withdraw from the position. Note the value here is shifted by the decimal places of the token.

Getting a quote

The Typescript SDK provides several quote functions to help generate an estimate based on common user input values.

Increase Liquidity quote by input token amount

Given a desired amount of input token (A or B), you can use the quote utility function increaseLiquidityQuoteByInputTokenWithParams to calculate the liquidityAmount and other tokenMax value required to deposit the desired amount of token into the position.

The quote amount will differ based on the current price (tick) and the desired tick boundaries for the position. The price environment may change from the time of quote to the actual processing of the increase_liquidity ix. Use the slippage tolerance to adjust the quote values to balance your risk of ix failure and total tokens to deposit.

const whirlpool = await fetcher.getPool(...);
const position = await fetcher.getPosition(...);
// 10 tokens of a token with 6 decimals
const depositTokenBAmount = new BN(10_000_000);

const quote = await increaseLiquidityQuoteByInputTokenWithParams({
  tokenMintA: whirlpool.tokenMintA,
  tokenMintB: whirlpool.tokenMintB,
  tickCurrentIndex: whirlpool.tickCurrentIndex,
  sqrtPrice: whirlpool.sqrtPrice,
  inputTokenMint: whirlpool.tokenMintB,
  inputTokenAmount: desiredTokenBAmount,
  tickLowerIndex: position.tickLowerIndex,
  tickUpperIndex: position.tickUpperIndex,
  slippageTolerance: Percentage.fromFraction(1, 1000),
});

Decrease Liquidity quote by liquidity amount

Given the liquidity amount, use the decreaseLiquidityQuoteByLiquidityWithParams util function to get an estimate on what's the minimum token A & B you can expect from the decrease_liquidity instruction call.

Like increase_liquidity, use the slippage tolerance to adjust the quote values to balance your risk of ix failure and total tokens to deposit.

const whirlpool = await fetcher.getPool(whirlpoolAddress);
const position = await fetcher.getPosition(positionAddress);

// Example: Withdraw 30% of the position
const totalLiquidityInPosition = position.liquidity;
const withdrawLiquidityAmount = totalLiquidityInPosition.mul(new BN(30).div(new BN(100)));
const depositQuote = decreaseLiquidityQuoteByLiquidityWithParams({
    withdrawLiquidityAmount,
    sqrtPrice: whirlpool.sqrtPrice,
    tickCurrentIndex: whirpool.tickCurrentIndex,
    tickLowerIndex: position.tickLowerIndex,
    tickUpperIndex: position.tickUpperIndex,
    slippageTolerance: Percentage.fromFraction(1, 100),
});

Decrease Liquidity quote by input token amount

This quote is in development....

Other Parameters

  • whirlpool - PublicKey of the whirlpool the position is a part of

  • position - PublicKey of the position address. Derivable from PDAUtil.getPosition.

  • positionTokenAccount - Associated token address of the position token on the user's wallet.

  • tokenOwnerAccount A, B - Associated token address of the tokenA,B on the user's wallet.

  • tokenVaults A, B - PublicKey of the token vaults for this

  • tickArrayLower, Upper - Lower & upper tick-array accounts that contains the tick indices for the lower, upper bound of the position

  • positionAuthority - The address that hosts the position token. This authority must sign the transaction.

Sample Code

Increase Liquidity example

const whirlpool = await fetcher.getPool(whirlpoolAddress);
const position = await fetcher.getPosition(positionAddress);
// 10 tokens of a token with 6 decimals
const depositTokenBAmount = new BN(10_000_000);
const depositQuote = increaseLiquidityQuoteByInputTokenWithParams({depositTokenBAmount, ...});

await toTx(ctx, WhirlpoolIx.increaseLiquidityIx(ctx.program, {
    ...depositQuote,
    whirlpool: whirlpoolAddress,
    positionAuthority: provider.wallet.publicKey,
    position: positionAddress,
    positionTokenAccount,
    tokenOwnerAccountA,
    tokenOwnerAccountB,
    tokenVaultA: whirlpool.tokenVaultA,
    tokenVaultB: whirlpool.tokenVaultB,
    tickArrayLower: position.tickArrayLower,
    tickArrayUpper: position.tickArrayUpper,
})).buildAndExecute();

Decrease Liquidity example

const whirlpool = await fetcher.getPool(whirlpoolAddress);
const position = await fetcher.getPosition(positionAddress);
const removalQuote = decreaseLiquidityQuoteByLiquidityWithParams({...});

await toTx(ctx, WhirlpoolIx.decreaseLiquidityIx(ctx.program, {
    ...removalQuote,
    whirlpool: whirlpoolAddress,
    positionAuthority: provider.wallet.publicKey,
    position: positionAddress,
    positionTokenAccount,
    tokenOwnerAccountA,
    tokenOwnerAccountB,
    tokenVaultA: whirlpool.tokenVaultA,
    tokenVaultB: whirlpool.tokenVaultB,
    tickArrayLower: position.tickArrayLower,
    tickArrayUpper: position.tickArrayUpper,
})).buildAndExecute();

Common Errors

  • LiquidityZero (0x177c) - Provided liquidity amount is zero.

  • LiquidityTooHigh (0x177d) - Provided liquidity exceeds u128::max.

  • TokenMaxExceeded (0x1781) - The required token to perform this operation exceeds the user defined amount in increase_liquidity.

  • TokenMinSubceeded (0x1782) - The required token to perform this operation subceeds the user defined amount in decrease_liquidity.

  • TickNotFound (0x1779) - The provided tick array accounts do not contain the tick specified in the position.

  • ConstraintRaw (0x7d3) - TokenVault, TokenAccount mints does not match the values in the provided whirlpool.

Last updated