# Remove Liquidity

### Quick Start

```typescript
const tx = await sdk.Position.removeLiquidityTransactionPayload({
  pool_id: '0x...',
  pos_id: '0x...',
  coinTypeA: '0x2::sui::SUI',
  coinTypeB: '0x...::usdc::USDC',
  delta_liquidity: '500000',
  min_amount_a: '490000000',
  min_amount_b: '490000'
  collect_fee: true
  rewarder_coin_types: [],
})
```

### Parameters

| Parameter             | Type      | Description                                           |
| --------------------- | --------- | ----------------------------------------------------- |
| `pool_id`             | string    | The object id about which pool you want to operation. |
| `pos_id`              | string    | Position object ID                                    |
| `coinTypeA`           | string    | First token type                                      |
| `coinTypeB`           | string    | Second token type                                     |
| `delta_liquidity`     | string    | Liquidity amount to remove                            |
| `min_amount_a`        | string    | Minimum token A to receive                            |
| `min_amount_b`        | string    | Minimum token B to receive                            |
| `collect_fee`         | boolean   | Indicates whether to collect fees during the removal. |
| `rewarder_coin_types` | string\[] | Coin types associated with rewarder contracts.        |

### Calculate Token Amounts

```typescript
async function estimateRemovePosition(
  pool,
  position,
  amountABigint,
  amountBBigint
) {
  const slippage = new Percentage(new BN(5), new BN(1000));
  const { curSqrtPrice, lowerSqrtPrice, upperSqrtPrice } = getCoinsRate(
    pool,
    position
  );

  const tokenAmounts = adjustForCoinSlippage(
    {
      coinA: new BN(amountABigint.toFixed(0)),
      coinB: new BN(amountBBigint.toFixed(0)),
    },
    slippage,
    false
  );
  const liquidity = ClmmPoolUtil.estimateLiquidityFromcoinAmounts(
    curSqrtPrice,
    Number(position.tick_lower_index),
    Number(position.tick_upper_index),
    {
      coinA: new BN(Math.ceil(amountABigint)),
      coinB: new BN(Math.ceil(amountBBigint)),
    }
  );
  return {
    tokenMaxA: tokenAmounts.tokenMaxA,
    tokenMaxB: tokenAmounts.tokenMaxB,
    lowerTick: lowerSqrtPrice,
    upperTick: upperSqrtPrice,
    curSqrtPrice,
    liquidity,
  };
}

function getCoinsRate(pool, position) {
  const curSqrtPrice = new BN(pool.current_sqrt_price);

  const lowerSqrtPrice = TickMath.tickIndexToSqrtPriceX64(
    position.tick_lower_index
  );

  const upperSqrtPrice = TickMath.tickIndexToSqrtPriceX64(
    position.tick_upper_index
  );

  const amounts = ClmmPoolUtil.getCoinAmountFromLiquidity(
    new BN(position.liquidity),
    curSqrtPrice,
    lowerSqrtPrice,
    upperSqrtPrice,
    false
  );

  const coinAValue = fromDecimalsAmount(
    amounts.coinA.toNumber(),
    pool.coinA?.decimals ?? 1
  );

  const coinBValue = fromDecimalsAmount(
    amounts.coinB.toNumber(),
    pool.coinB?.decimals ?? 1
  );

  const total = coinAValue + coinBValue;
  const percent = {
    ratioA: coinAValue / total,
    ratioB: coinBValue / total,
  };

  return {
    percent,
    curSqrtPrice,
    lowerSqrtPrice,
    upperSqrtPrice,
  };
}

```

### Complete Example

```typescript
const position = await sdk.Position.getPositionById(positionId)
const pool = await sdk.Pool.getPool(position.pool)
const amountA = 100000000
const amountB = 2000000000
const percent = 0.2 
const { tokenMaxA, tokenMaxB, liquidity } = await estimateRemovePosition(poolOnchain, position, amountA, amountB);
const rewards = await ferraSDK.Rewarder.fetchPositionRewarders(
        poolOnchain,
        position.pos_object_id
      );
const rewardCoinTypes = rewards
        .filter((item) => Number(item.amount_owed) > 0)
        .map((item) => item.coin_address);
const removeLiquidityPayloadParams: RemoveLiquidityParams = {
        coinTypeA: poolOnchain.coinTypeA,
        coinTypeB: poolOnchain.coinTypeB,
        pool_id: poolOnchain.poolAddress,
        min_amount_a: tokenMaxA.toString(),
        min_amount_b: tokenMaxB.toString(),
        collect_fee: true,
        rewarder_coin_types: rewardCoinTypes,
        pos_id: position.pos_object_id,
        delta_liquidity: new BN(position.liquidity).lte(new BN(liquidity))
          ? position.liquidity.toString()
          : liquidity.toString(),
      };
const tx = await sdk.Position.removeLiquidityTransactionPayload(removeLiquidityPayloadParams);  
const result = await sdk.fullClient.signAndExecuteTransaction({
  transaction: tx,
  signer: keypair
})
```

### Error Handling

```typescript
try {
  const tx = await sdk.Position.removeLiquidityTransactionPayload(params)
} catch (error) {
  if (error.message.includes('Slippage exceeded')) {
    console.log('Price moved too much, increase slippage')
  }
  if (error.message.includes('Insufficient liquidity')) {
    console.log('Not enough liquidity in position')
  }
}
```

### Important Notes

* SDK automatically collects fees before removing liquidity
* Tokens are sent directly to sender address
* Cannot remove more liquidity than position contains
* Position NFT remains after removing all liqui


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.ferra.ag/integration/clmm/typescript-sdk/remove-liquidity.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
