跳转到主要内容

提供流动性 (V2)

V2 池使用简单的恒定乘积模型。流动性提供者(LP)按当前储备比率存入两种代币,并获得代表其份额的可替换 LP 代币。

添加流动性

1. 授权代币

授权两种代币给 V2 Router:
const V2_ROUTER = '0xC7ca845B8302346e1C7227f03bb9EFb35ecD51fe'; // 主网

await tokenA.approve(V2_ROUTER, amountA);
await tokenB.approve(V2_ROUTER, amountB);

2. 调用 addLiquidity

const V2_ROUTER_ABI = [
  'function addLiquidity(address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) returns (uint256 amountA, uint256 amountB, uint256 liquidity)',
  'function addLiquidityETH(address token, uint256 amountTokenDesired, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline) payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity)'
];

const router = new ethers.Contract(V2_ROUTER, V2_ROUTER_ABI, signer);
const deadline = Math.floor(Date.now() / 1000) + 1200; // 20 分钟

// ERC-20 / ERC-20 交易对
const tx = await router.addLiquidity(
  tokenA.target,
  tokenB.target,
  amountADesired,
  amountBDesired,
  amountADesired * 99n / 100n,  // 1% 滑点
  amountBDesired * 99n / 100n,
  userAddress,
  deadline
);

3. 使用原生 KAS

使用 addLiquidityETH 并将 KAS 作为 value 发送:
const tx = await router.addLiquidityETH(
  tokenAddress,
  amountTokenDesired,
  amountTokenDesired * 99n / 100n,
  amountKASDesired * 99n / 100n,
  userAddress,
  deadline,
  { value: amountKASDesired }
);

移除流动性

1. 授权 LP 代币

const lpToken = new ethers.Contract(pairAddress, ERC20_ABI, signer);
await lpToken.approve(V2_ROUTER, lpAmount);

2. 调用 removeLiquidity

const REMOVE_ABI = [
  'function removeLiquidity(address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline) returns (uint256 amountA, uint256 amountB)',
  'function removeLiquidityETH(address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline) returns (uint256 amountToken, uint256 amountETH)'
];

const router = new ethers.Contract(V2_ROUTER, REMOVE_ABI, signer);

// ERC-20 / ERC-20 交易对
const tx = await router.removeLiquidity(
  tokenA,
  tokenB,
  lpAmount,
  0,  // amountAMin(为简化设为 0;生产环境请使用滑点保护)
  0,  // amountBMin
  userAddress,
  deadline
);

3. 使用原生 KAS

使用 removeLiquidityETH 接收 KAS 而非 WKAS:
const tx = await router.removeLiquidityETH(
  tokenAddress,
  lpAmount,
  0,
  0,
  userAddress,
  deadline
);

计算金额

要按当前价格比率添加流动性,首先查询池的储备量:
const PAIR_ABI = [
  'function getReserves() view returns (uint112, uint112, uint32)',
  'function token0() view returns (address)'
];

const pair = new ethers.Contract(pairAddress, PAIR_ABI, provider);
const [reserve0, reserve1] = await pair.getReserves();
const token0 = await pair.token0();

// 如果你想存入 amountA 的 tokenA:
const isToken0 = tokenA.toLowerCase() === token0.toLowerCase();
const amountB = isToken0
  ? (amountA * reserve1) / reserve0
  : (amountA * reserve0) / reserve1;

要点

  • 首个 LP 设定初始价格 — 按期望比率存入代币
  • 后续 LP 必须匹配当前储备比率
  • LP 代币是 ERC-20,可以转让或在其他协议中使用
  • 手续费(0.3%)自动复利进入池中 — 无需手动领取
  • 存在无常损失风险