> For the complete documentation index, see [llms.txt](https://docs.turbine.exchange/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.turbine.exchange/liquidity/liquidity-provision-for-engineers.md).

# Manage Liquidity Programmatically

Managing your liquidity on Turbine means:

1. Authenticating
2. Submitting a liquidity intent
3. Waiting for Turbine to execute the intent, or executing it directly.

We'll explore these steps below.

{% hint style="success" %}
The easiest way to interact with Turbine programmatically is the [Typescript SDK](https://github.com/propeller-heads/turbine-sdk).

We will use it throughout this guide.
{% endhint %}

{% hint style="info" %}
Learn more about liquidity provision: [Market Tracking LP](/features/market-tracking-lp.md) and [Liquidity Pools in Depth](/reference/technical/liquidity-pools-in-depth.md).
{% endhint %}

## Providing and Withdrawing Liquidity via API

{% hint style="info" %}
See [`add-liquidity.ts`](https://github.com/propeller-heads/turbine-sdk/blob/main/scripts/add-liquidity.ts) in the SDK repo for a complete example of providing liquidity.

See [`remove-liquidity.ts`](https://github.com/propeller-heads/turbine-sdk/blob/main/scripts/remove-liquidity.ts) in the SDK repo for a complete example of withdrawing liquidity.
{% endhint %}

{% stepper %}
{% step %}
**Prepare your wallet**

To submit a liquidity intent to Turbine and have it executed, the following conditions must be met:

{% tabs %}
{% tab title="Provide liquidity" %}

* You need to have enough balance of provided tokens.
* You need to approve [Permit2 contract](https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3) to spend at least the amounts you're providing (i.e. call `approve(permit2address, amount)` on the provided token contracts; you can use [`approve-token.ts`](https://github.com/propeller-heads/turbine-sdk/blob/main/scripts/approve-token.ts) script).
  {% endtab %}

{% tab title="Withdraw liquidity" %}

* You need to have enough balance of pool's LP token.
* You need to approve [Permit2 contract](https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3) to spend at least the amount of LP token you want to burn (i.e. call `approve(permit2address, amount)` on the LP token contract; you can use the [`approve-lp-token.ts`](https://github.com/propeller-heads/turbine-sdk/blob/main/scripts/approve-lp-token.ts) script).
  {% endtab %}
  {% endtabs %}
  {% endstep %}

{% step %}
**Instantiate TurbineClient**

Set environment variables for the below example to work:

* `PRIVATE_KEY` - private key of the wallet
* `RPC_URL` - URL to access Ethereum blockchain; you can use your private RPC or pick one from <https://ethereumnodes.com/>
* `TURBINE_API_URL` - URL of Turbine API instance, with `/api` suffix. E.g. `https://api.turbine.exchange/api`.

```typescript
import { createPublicClient, createWalletClient, http, Hex } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { TurbineClient, getRandomSalt } from "turbine-sdk";

const account = privateKeyToAccount(PRIVATE_KEY);
const walletClient = createWalletClient({
    account: account,
    chain: mainnet,
    transport: http(RPC_URL),
});
const publicClient = createPublicClient({
    chain: mainnet,
    transport: http(RPC_URL),
});

const turbineClient = await TurbineClient.create(
    walletClient,
    publicClient,
    TURBINE_API_URL
);
```

{% endstep %}

{% step %}
**Authenticate**

To submit liquidity intents you must be authenticated. See [Authentication](/reference/api/authentication.md) for details.

The SDK handles authentication automatically.
{% endstep %}

{% step %}
**Get available pools**

Call `getPools()` to get a list of available pools:

```typescript
const pools = await turbineClient.getPools();
```

The result looks like this:

```typescript
[
  {
    metadata: {
      token0: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
      token1: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
      fee: 3000,
      lpToken: '0xB03aC5cabFc98DB26C0D9eA232E1e900724d91F3'
    },
    state: { reserve0: 0n, reserve1: 0n, liquidity: 0n },
    stats: { weeklySellVolumeToken0: 0n, weeklySellVolumeToken1: 0n }
  },
  {
    metadata: {
      token0: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
      token1: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
      fee: 10000,
      lpToken: '0x2bcF0170103930dc12d748c8b54205a36B7351dA'
    },
    state: { reserve0: 10000000000n, reserve1: 500000000000000000n, liquidity: 250000005000000000n },
    stats: { weeklySellVolumeToken0: 0n, weeklySellVolumeToken1: 0n }
  }
]
```

The snippet above shows two USDC/WETH pools: one at 0.3% fee tier and one at 1% fee tier. The first is empty; the second holds 10,000 USDC and 0.5 WETH.

{% hint style="info" %}
Pool statistics aren't implemented yet — the `stats` fields above return placeholders.
{% endhint %}
{% endstep %}

{% step %}
**Create a liquidity intent**

{% tabs %}
{% tab title="Provide liquidity" %}
Create an intent to provide exactly 1000 USDC and 0.1 WETH to the pool at 1% fee tier.

```typescript
const liquidityIntent: AddLiquidityIntent = {
    owner: account.address,
    token0: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" as Hex,
    token1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" as Hex,
    fee: 10000,
    token0Amount: 1000000000n,
    token1Amount: 100000000000000000n,
    exact: true,
    salt: getRandomSalt(),
};
```

{% endtab %}

{% tab title="Withdraw liquidity" %}
Create an intent to withdraw 40% of liquidity from the USDC/WETH pool at 1% fee tier. 40% of total pool liquidity equals 100,000,002 × 10<sup>9</sup> units of LP token.

```typescript
const liquidityIntent: RemoveLiquidityIntent = {
    owner: account.address,
    token0: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" as Hex,
    token1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" as Hex,
    fee: 10000,
    lpToken: "0x2bcF0170103930dc12d748c8b54205a36B7351dA" as Hex,
    lpTokenAmount: 100000002000000000n,
    salt: getRandomSalt(),
};
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}
**Submit liquidity intent**

Submit the intent to Turbine:

{% tabs %}
{% tab title="Provide liquidity" %}

```typescript
const intentHash = await turbineClient.addLiquidity(liquidityIntent);
```

{% hint style="info" %}
This method calls: [Turbine](/reference/api/readme/turbine.md#post-api-add_liquidity)
{% endhint %}
{% endtab %}

{% tab title="Withdraw liquidity" %}

```typescript
const intentHash = await turbineClient.removeLiquidity(liquidityIntent);
```

{% hint style="info" %}
This method calls: [Turbine](/reference/api/readme/turbine.md#post-api-remove_liquidity)
{% endhint %}
{% endtab %}
{% endtabs %}

This call errors if Turbine rejects your intent during initial validation.

Submitting the intent does not execute it immediately. Your intent must still pass [The Speedbump](/features/the-speedbump.md).
{% endstep %}

{% step %}
**Check intent state**

To check intent state, call `getLiquidityIntents`:

```typescript
const intentState = (await turbineClient.getLiquidityIntents([intentHash]))[0];
console.log(intentState.status);
```

The intent can be in the following states:

* `Pending` - The intent is waiting to pass the speedbump.
* `Invalid` - The intent was removed due to validation errors during a settlement.
* `Expired` - The intent was removed because it expired before execution.
* `Executed` - The intent was executed.
* `PendingCancellation` - The owner has requested cancellation.
* `Canceled` - The owner canceled the intent.

{% hint style="info" %}
This method calls: [Turbine](/reference/api/readme/turbine.md#post-api-liquidity_intent_states)
{% endhint %}
{% endstep %}
{% endstepper %}

## Directly Withdrawing Liquidity Onchain

You can withdraw liquidity by submitting onchain transactions, without the Turbine backend acting as intermediary. The speedbump still applies.

Direct onchain withdrawal has two steps:

1. Submit a liquidity withdrawal intent to LiquidityRouter
2. Execute the submitted intent (after the speedbump)

Instead of authenticating to the Turbine backend, you confirm your identity by signing a transaction.

{% stepper %}
{% step %}
**Create liquidity intent**

Follow the steps in [#providing-and-withdrawing-liquidity-via-api](#providing-and-withdrawing-liquidity-via-api "mention") up through creating the liquidity intent. You can skip authentication.
{% endstep %}

{% step %}
**Submit liquidity intent onchain**

```typescript
const { txHash, intentHash } =
    await turbineClient.submitRemoveLiquidityIntentOnchain(liquidityIntent);
```

{% hint style="info" %}
This method calls [TurbineLiquidityRouter](/reference/contracts/solidity-documentation/univ4-hook/contract.turbineliquidityrouter.md#submitremoveliquidityintent)
{% endhint %}
{% endstep %}

{% step %}
**Execute the liquidity intent**

After submitting, wait at least the speedbump duration (12 seconds, or 1 Ethereum block).

Then execute the intent:

```typescript
await turbineClient.executePendingRemoveLiquidityIntentsOnchain([intentHash]);
```

{% endstep %}
{% endstepper %}

Turbine also executes liquidity removal intents submitted directly to LiquidityRouter (not only those submitted via the Turbine API).

#### See also

{% columns %}
{% column %}
{% content-ref url="/pages/IKe5swJDlfB3HKjSeAqZ" %}
[Market Tracking LP](/features/market-tracking-lp.md)
{% endcontent-ref %}
{% endcolumn %}

{% column %}
{% content-ref url="/spaces/QHptutFygga9WKVU1emZ/pages/w93B4h4yx9hA0notuTxS" %}
[Liquidity Pools in Depth](/reference/technical/liquidity-pools-in-depth.md)
{% endcontent-ref %}
{% endcolumn %}
{% endcolumns %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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.turbine.exchange/liquidity/liquidity-provision-for-engineers.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.
