> ## Documentation Index
> Fetch the complete documentation index at: https://build.flashnet.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Liquidity

`TradingClient` provides liquidity to the Uniswap V3 pools on Flashnet Execution. Mint a position, grow or shrink it, collect fees, or reposition, each as one signed intent that funds from your Spark balance and routes through the Conductor.

<Note>
  These are the Uniswap V3 pools the Conductor wraps on Execution, managed with `TradingClient`. The Spark-native AMM under [Markets](/products/flashnet-amm/overview) is a separate system with its own client.
</Note>

## Configure for liquidity

LP needs more contract addresses than swaps. On `TradingConfig`:

| Field                    | When required                              |
| ------------------------ | ------------------------------------------ |
| `positionManagerAddress` | every LP method                            |
| `wbtcAddress`            | BTC-paired pools                           |
| `permit2Address`         | funding from Spark (`useAvailableBalance`) |

`lpGasLimit` is optional.

```typescript theme={null}
const trading = new TradingClient(execClient, {
  conductorAddress: process.env.CONDUCTOR_ADDRESS,
  positionManagerAddress: process.env.POSITION_MANAGER_ADDRESS,
  wbtcAddress: process.env.WBTC_ADDRESS,        // BTC-paired pools
  permit2Address: process.env.PERMIT2_ADDRESS,  // useAvailableBalance funding
});
```

On staging, `new TradingClient(execClient, "regtest")` includes all of these, so you can skip the explicit config.

## How positions work

A position is a Uniswap V3 concentrated-liquidity NFT held by the NonfungiblePositionManager, identified by a `tokenId` and bounded by two ticks. Four conventions carry across every method:

* Pass pair tokens sorted: `token0 < token1` by lowercase address.
* The WBTC leg is denominated in wei, not sats (1 sat = 1e10 wei). Convert with `satsToWei` and `weiToSats` from `@flashnet/sdk`.
* For a BTC-paired pool, use the WBTC address as the BTC leg's token. The SDK routes to the Conductor's BTC entry point and funds `msg.value`.
* Ticks are standard Uniswap V3 ticks, where price = 1.0001^tick. `V3TickMath` from `@flashnet/sdk` converts between prices and ticks.

## Funding

LP methods fund the same two ways as [swaps](/products/execution/swaps). With `useAvailableBalance: true`, the SDK pulls each leg from your Spark balance and bundles the funding transfers with the Conductor call in one intent. Supply the Spark token id for each ERC20 leg (`token0SparkId`, `token1SparkId`); the BTC leg funds from the WBTC slot.

ERC20 legs are pulled via Permit2, so each token needs a standing Permit2 approval from your EVM address first:

```typescript theme={null}
await trading.ensurePermit2Approval(tokenAddress);  // requires permit2Address in config
```

Without `useAvailableBalance`, the methods spend balances already on the Execution side.

## Mint a position

`addLiquidity` mints a new position NFT.

```typescript theme={null}
const result = await trading.addLiquidity({
  token0: "0x...",             // sorted: token0 < token1
  token1: "0x...",
  fee: 3000,
  tickLower: -887220,          // full range for the 0.3% tier
  tickUpper: 887220,
  amount0Desired: "1000000",
  amount1Desired: "1000000",
  amount0Min: "990000",        // slippage floor
  amount1Min: "990000",
  useAvailableBalance: true,
  token0SparkId: "btkn1...",   // required for ERC20 legs funded from Spark
  token1SparkId: "btkn1...",
});
```

For a BTC-paired pool, set one leg's token to the WBTC address and its amounts in wei. That leg funds from `msg.value` and takes no Spark token id.

## Grow or shrink

`increaseLiquidity` adds to a position. `decreaseLiquidity` removes liquidity and withdraws the recovered tokens to Spark.

```typescript theme={null}
await trading.increaseLiquidity({
  tokenId: 123n,
  amount0Desired: "500000",
  amount1Desired: "500000",
  amount0Min: "495000",
  amount1Min: "495000",
  useAvailableBalance: true,
  token0SparkId: "btkn1...",
  token1SparkId: "btkn1...",
});

await trading.decreaseLiquidity({
  tokenId: 123n,
  liquidity: 1_000_000n,       // liquidity units to remove
  amount0Min: "495000",
  amount1Min: "495000",
});
```

`decreaseLiquidity` sends the recovered token0 and token1 to your Spark wallet. `sparkRecipient` defaults to your identity key.

## Collect fees

`collectFees` sweeps accrued fees to Spark without touching principal.

```typescript theme={null}
await trading.collectFees({ tokenId: 123n });
```

## Reposition

`modifyPosition` moves a position to a new tick range. It removes all liquidity from the current position, optionally adds capital, and mints a new NFT at the new range.

```typescript theme={null}
await trading.modifyPosition({
  tokenId: 123n,
  newTickLower: -443580,
  newTickUpper: 443580,
  amount0Min: "0",                      // floors on the OLD position's recovery
  amount1Min: "0",
  additionalAmount0Desired: "250000",   // optional extra capital
  additionalAmount1Desired: "250000",
  newAmount0Min: "240000",              // floors on minting the NEW position
  newAmount1Min: "240000",
});
```

## Read positions

`getPosition` and `listPositions` read straight from the NonfungiblePositionManager.

```typescript theme={null}
const position = await trading.getPosition(123n);
position.liquidity;    // bigint
position.tickLower;    // number
position.tokensOwed0;  // uncollected fees, bigint

const mine = await trading.listPositions();           // your positions
const theirs = await trading.listPositions("0x...");  // another owner's
```

`PositionInfo` mirrors the NonfungiblePositionManager's `positions()` tuple: `token0`, `token1`, `fee`, `tickLower`, `tickUpper`, `liquidity`, `tokensOwed0`/`tokensOwed1`, and the fee-growth checkpoints.

## What the result tells you

```typescript theme={null}
interface LpWriteResult {
  submissionId: string;
  intentId: string;
  status: string;
  evmTxHash: string;
  inboundSparkTransferIds?: string[];  // set on the useAvailableBalance path
}
```

The result carries submission handles and the signed-tx hash, not on-chain outputs. The minted `tokenId`, the liquidity added, amounts used, and fees collected are knowable only after the intent executes. Read them from the transaction receipt or the Conductor LP events (`LiquidityAdded`, `LiquidityIncreased`, `LiquidityDecreased`, `FeesCollected`, `PositionModified`) once the intent reaches `INCLUDED_PENDING_FINALITY`.

## Fund recovery

When an `addLiquidity`, `increaseLiquidity`, or `modifyPosition` call with `useAvailableBalance` fails after its funding transfers commit, the SDK claws the committed transfers back to your Spark balance and throws `StrandedFundingError` with a `clawbackSummary` of what was recovered. This matches the swap round-trip's behavior. `decreaseLiquidity` and `collectFees` have no inbound funding, so they carry no clawback.

## Cross-references

* [Swaps](/products/execution/swaps) trade through the same pools.
* [Conductor](/products/execution/conductor) is the contract these calls route through.
