# 锁定流动性

使用 Burn & Earn program 永久锁定一个 CLMM 仓位，并通过 lock NFT 从锁定的仓位中收取交易手续费。

***

### 工作原理

当你锁定一个 CLMM 仓位时：

1. 你的仓位 NFT 会被转移到 Burn & Earn 锁仓 program —— 它无法被取回。
2. 你会收到一个 **lock NFT** ，它代表你的已锁定仓位。
3. lock NFT 赋予你领取在底层仓位上累积的交易手续费的权利。

只要流动性池当前价格仍在其 tick 区间内，已锁定仓位就会持续赚取手续费。锁定后，你无法修改该仓位的流动性或价格区间。

***

### 锁定仓位

使用 `raydium.clmm.lockPosition()` 以永久锁定一个 CLMM 仓位。

```typescript
import {
  ApiV3PoolInfoConcentratedItem,
  CLMM_PROGRAM_ID,
  DEVNET_PROGRAM_ID,
  PositionInfoLayout,
  getPdaPersonalPositionAddress,
} from '@raydium-io/raydium-sdk-v2'
import { PublicKey } from '@solana/web3.js'
import { initSdk, txVersion } from '../config'

const lockPosition = async () => {
  const raydium = await initSdk()

  const positionNftMint = new PublicKey('your position nft mint')
  const positionPubKey = getPdaPersonalPositionAddress(
    CLMM_PROGRAM_ID, // devnet: DEVNET_PROGRAM_ID.CLMM
    positionNftMint
  ).publicKey
  const pos = await raydium.connection.getAccountInfo(positionPubKey)
  const position = PositionInfoLayout.decode(pos!.data)

  let poolInfo: ApiV3PoolInfoConcentratedItem
  if (raydium.cluster === 'mainnet') {
    poolInfo = (
      await raydium.api.fetchPoolById({ ids: position.poolId.toBase58() })
    )[0] as ApiV3PoolInfoConcentratedItem
  } else {
    const data = await raydium.clmm.getPoolInfoFromRpc(position.poolId.toBase58())
    poolInfo = data.poolInfo
  }

  if (!poolInfo) throw new Error(`clmm pool ${position.poolId.toBase58()} not found`)

  const { execute } = await raydium.clmm.lockPosition({
    // devnet: programId: DEVNET_PROGRAM_ID.CLMM_LOCK_PROGRAM_ID
    // devnet: authProgramId: DEVNET_PROGRAM_ID.CLMM_LOCK_AUTH_ID
    // devnet: poolProgramId: new PublicKey(poolInfo.programId)
    ownerPosition: position,
    txVersion,
    // 可选：在此设置优先手续费
    // computeBudgetConfig: {
    //   units: 600000,
    //   microLamports: 46591500,
    // },
  })

  const { txId } = await execute({})
  console.log('position locked:', { txId: `https://explorer.solana.com/tx/${txId}` })
}

lockPosition()
```

#### 锁定参数

| 参数              | 类型        | 描述                                                                             |
| --------------- | --------- | ------------------------------------------------------------------------------ |
| `ownerPosition` | object    | 从以下内容解码的仓位信息 `PositionInfoLayout.decode()`.                                    |
| `programId`     | PublicKey | Lock program。Mainnet 默认会自动解析。Devnet： `DEVNET_PROGRAM_ID.CLMM_LOCK_PROGRAM_ID`. |
| `authProgramId` | PublicKey | Lock auth program。Devnet： `DEVNET_PROGRAM_ID.CLMM_LOCK_AUTH_ID`.               |
| `poolProgramId` | PublicKey | CLMM program ID。Devnet：传入 `new PublicKey(poolInfo.programId)`.                 |
| `txVersion`     | TxVersion | 交易版本。                                                                          |

{% hint style="warning" %}
锁定是永久性的。一旦锁定，仓位无法解锁或修改。只有已累积的交易手续费可以通过 lock NFT 领取。
{% endhint %}

***

### 从已锁定仓位中收取手续费

使用 `raydium.clmm.harvestLockPosition()` 使用 lock NFT mint 地址，从已锁定仓位中领取累积的交易手续费。

```typescript
import {
  CLMM_LOCK_PROGRAM_ID,
  DEVNET_PROGRAM_ID,
  LockClPositionLayoutV2,
  getPdaLockClPositionIdV2,
} from '@raydium-io/raydium-sdk-v2'
import { PublicKey } from '@solana/web3.js'
import { initSdk, txVersion } from '../config'

const harvestLockedPosition = async () => {
  const raydium = await initSdk({ loadToken: true })

  const lockNftMint = new PublicKey('your locked position nft mint')
  const lockPositionId = getPdaLockClPositionIdV2(CLMM_LOCK_PROGRAM_ID, lockNftMint).publicKey
  const res = await raydium.connection.getAccountInfo(lockPositionId)
  const lockData = LockClPositionLayoutV2.decode(res!.data)

  const { execute } = await raydium.clmm.harvestLockPosition({
    // devnet: programId: DEVNET_PROGRAM_ID.CLMM_LOCK_PROGRAM_ID
    // devnet: authProgramId: DEVNET_PROGRAM_ID.CLMM_LOCK_AUTH_ID
    // devnet: clmmProgram: DEVNET_PROGRAM_ID.CLMM_PROGRAM_ID
    lockData,
    txVersion,
    // 可选：在此设置优先手续费
    // computeBudgetConfig: {
    //   units: 600000,
    //   microLamports: 100000,
    // },
  })

  const { txId } = await execute({})
  console.log('harvested locked position:', { txId: `https://explorer.solana.com/tx/${txId}` })
}

harvestLockedPosition()
```

#### 收取参数

| 参数              | 类型        | 描述                                                               |
| --------------- | --------- | ---------------------------------------------------------------- |
| `lockData`      | object    | 从以下内容解码的锁定仓位数据 `LockClPositionLayoutV2.decode()`.                |
| `programId`     | PublicKey | Lock program。Devnet： `DEVNET_PROGRAM_ID.CLMM_LOCK_PROGRAM_ID`.   |
| `authProgramId` | PublicKey | Lock auth program。Devnet： `DEVNET_PROGRAM_ID.CLMM_LOCK_AUTH_ID`. |
| `clmmProgram`   | PublicKey | CLMM program。Devnet： `DEVNET_PROGRAM_ID.CLMM_PROGRAM_ID`.        |
| `txVersion`     | TxVersion | 交易版本。                                                            |
