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

# 提供流动性 (V3)

> 创建、管理和关闭 V3 集中流动性头寸

# 提供流动性 (V3)

V3 允许 LP 将流动性集中在特定价格范围内，以获得更高的资本效率。每个头寸都是一个具有唯一参数的 NFT。

## 创建头寸

### 1. 选择池参数

* **代币对**：两种代币
* **手续费等级**：0.01%、0.05%、0.3% 或 1%（参阅 [手续费等级](/concepts/v3/fee-tiers)）
* **价格范围**：`[tickLower, tickUpper]`（参阅 [Ticks 与范围](/concepts/v3/ticks-and-ranges)）

### 2. 获取当前池状态

```typescript theme={null}
const V3_FACTORY = '0x0dfb1Bb755d872EA1fa4d95E4ad0c2E6317Ce9B9'; // 主网
const V3_POSITION_MANAGER = '0x343b244bEDF133D57C61b241557bF29AA32ea4F9';

const FACTORY_ABI = ['function getPool(address,address,uint24) view returns (address)'];
const POOL_ABI = [
  'function slot0() view returns (uint160, int24, uint16, uint16, uint16, uint8, bool)',
  'function tickSpacing() view returns (int24)'
];

const factory = new ethers.Contract(V3_FACTORY, FACTORY_ABI, provider);
const poolAddress = await factory.getPool(token0, token1, 3000);
const pool = new ethers.Contract(poolAddress, POOL_ABI, provider);

const [sqrtPriceX96, currentTick] = await pool.slot0();
const tickSpacing = await pool.tickSpacing();
```

### 3. 计算 Tick 范围

将你期望的价格范围对齐到池的 tick 间距：

```typescript theme={null}
function nearestUsableTick(tick, tickSpacing) {
  return Math.round(tick / tickSpacing) * tickSpacing;
}

// 示例：当前价格上下浮动 ±10%
const tickLower = nearestUsableTick(currentTick - 2000, tickSpacing);
const tickUpper = nearestUsableTick(currentTick + 2000, tickSpacing);
```

### 4. 授权代币

```typescript theme={null}
await token0Contract.approve(V3_POSITION_MANAGER, amount0Desired);
await token1Contract.approve(V3_POSITION_MANAGER, amount1Desired);
```

### 5. 铸造头寸

```typescript theme={null}
const PM_ABI = [
  'function mint((address,address,uint24,int24,int24,uint256,uint256,uint256,uint256,address,uint256)) payable returns (uint256,uint128,uint256,uint256)'
];

const pm = new ethers.Contract(V3_POSITION_MANAGER, PM_ABI, signer);
const deadline = Math.floor(Date.now() / 1000) + 1200;

const tx = await pm.mint({
  token0,
  token1,
  fee: 3000,
  tickLower,
  tickUpper,
  amount0Desired,
  amount1Desired,
  amount0Min: amount0Desired * 99n / 100n,
  amount1Min: amount1Desired * 99n / 100n,
  recipient: userAddress,
  deadline
});

const receipt = await tx.wait();
// 从交易回执事件中解析 tokenId
```

<Note>
  `token0` 的地址必须小于 `token1`。调用前请先排序。
</Note>

### 使用原生 KAS

如果其中一个代币是 KAS，将其作为 `value` 发送，而不是授权 WKAS：

```typescript theme={null}
const tx = await pm.mint(params, { value: kasAmount });
```

## 增加流动性

向现有头寸（相同 tick 范围）追加更多代币：

```typescript theme={null}
const tx = await pm.increaseLiquidity({
  tokenId,
  amount0Desired,
  amount1Desired,
  amount0Min: 0,
  amount1Min: 0,
  deadline
});
```

## 领取手续费

领取累积的交易手续费：

```typescript theme={null}
const tx = await pm.collect({
  tokenId,
  recipient: userAddress,
  amount0Max: ethers.MaxUint128,
  amount1Max: ethers.MaxUint128
});
```

## 移除流动性

### 1. 减少流动性

```typescript theme={null}
const tx = await pm.decreaseLiquidity({
  tokenId,
  liquidity: liquidityToRemove,  // 完全移除时使用全部流动性
  amount0Min: 0,
  amount1Min: 0,
  deadline
});
```

### 2. 提取代币

减少流动性后，代币由 Position Manager 持有。调用 `collect()` 来提取：

```typescript theme={null}
const tx = await pm.collect({
  tokenId,
  recipient: userAddress,
  amount0Max: ethers.MaxUint128,
  amount1Max: ethers.MaxUint128
});
```

### 3. 销毁 NFT（可选）

移除所有流动性并领取所有代币/手续费后：

```typescript theme={null}
const tx = await pm.burn(tokenId);
```

## 单边头寸

你可以创建完全在当前价格之上或之下的头寸：

| 范围                                | 存入       | 行为        |
| --------------------------------- | -------- | --------- |
| 高于当前价格（`tickLower > currentTick`） | 仅 Token0 | 相当于限价卖出订单 |
| 低于当前价格（`tickUpper < currentTick`） | 仅 Token1 | 相当于限价买入订单 |

```typescript theme={null}
// 限价卖出：仅提供 token0，范围在当前价格之上
const tx = await pm.mint({
  token0,
  token1,
  fee: 3000,
  tickLower: currentTick + 60,    // 高于当前价格
  tickUpper: currentTick + 600,
  amount0Desired: sellAmount,
  amount1Desired: 0,              // 不需要 token1
  amount0Min: 0,
  amount1Min: 0,
  recipient: userAddress,
  deadline
});
```

## 要点

* 每个头寸都是一个 NFT — 跟踪 `tokenId` 以进行后续操作
* 手续费必须主动领取（不会自动复利）
* 超出范围的头寸不会赚取手续费，直到价格重新进入范围
* 范围越窄 = 资本效率越高，但需要更积极的管理
* 使用 Position Manager 上的 `multicall()` 可以在一笔交易中批量执行减少流动性 + 领取
