目录
引言
在去中心化金融(DeFi)领域,Uniswap V2 是最经典也是最具代表性的自动化做市商(AMM)协议之一。它通过极简而高效的合约设计,实现了无需许可的代币兑换和流动性池管理。
本文将详细解析 Uniswap V2 的核心架构:Factory、Pair 和 Router 三大合约之间的关系及交互流程,并通过 Solidity 合约示例,带你了解如何基于 Router 快速实现:添加流动性、移除流动性以及代币交换等核心功能。无论你是想开发自己的 DApp,还是想深入学习 Uniswap 工作原理,这都是非常值得掌握的基础。
一、项目结构 & 合约关系
Uniswap V2 项目通常拆分为两个仓库:
uniswap-v2-core:核心合约
uniswap-v2-periphery:外围设计,用户交互方便用的合约,比如 router
主要合约:

Uniswap V2 的核心合约主要有三个
UniswapV2Factory
工厂合约,用来创建和管理交易对(Pair)合约。管理所有流动性池的 “工厂”
关键点:
- 部署新交易对(如 USDC/ETH)。
- 存储所有已部署的交易对地址。
- 提供查询接口(如 getPair() 返回特定 token 对应的 Pair 地址)。
UniswapV2Pair
每个交易对都会有一个独立的 Pair 合约,用于真正存储资金、计算定价和执行 swap、add/remove liquidity。每个池子一个 Pair,所有交易都发生在 Pair 合约里。
关键点:
- 保留了 token0 和 token1 的储备量。
- 实现核心恒定乘积公式:x * y = k。
- 实现 swap()、mint()(增加流动性)、burn()(移除流动性)等方法。
UniswapV2Router02
是一个提供更友好的交互接口的合约,让用户或 DApp 更方便地:添加/移除流动性、进行 token 之间的 swap。是 DApp/前端最常直接交互的合约。
关键点:
- 内部帮你调用 Pair 的 swap/mint/burn。
- 会计算 slippage、最小金额、路径等,简化操作。
典型的流程解释:
以用户通过 Router 添加流动性为例:

解释:
用户只和 Router 交互,不直接调用 Pair 或 Factory。
Router 内部先去 Factory 查询 Pair 地址,然后去 Pair 完成交互。
如果 Pair 不存在,先调用 Factory 创建。
Pair 是实际存储 token 和发放 LP Token 的地方。
假设场景
你想在 Uniswap V2 上添加一个 USDC/ETH 的流动性池,也就是让别人可以方便地在 USDC 和 ETH 之间交易。
✅第 1 步:你发起请求
你在 DApp/前端(网页)点了「添加流动性」按钮。这个操作其实是要调用链上的一个合约方法。
✅ 第 2 步:前端调用 Router
前端帮你调用合约 UniswapV2Router02.addLiquidity(…)。Router 是 Uniswap 官方写好的合约,帮忙处理各种计算(比如最小价格、滑点、路径等),让用户不需要自己和底层合约打交道。
✅ 第 3 步:Router 去找池子(Pair 合约)
Router 想添加流动性,必须知道这个池子的合约地址在哪里。所以 Router 会先问 UniswapV2Factory.getPair(tokenA, tokenB):
“你有没有 USDC 和 ETH 的池子?”Factory 是一个工厂合约,里面只管理所有 Pair(池子)的地址。
✅ 第 4 步:如果池子还没创建
如果这是第一个想要创建 USDC/ETH 池子的人,那 Factory 会返回一个空地址(意思是没有)。Router 就需要先让用户调用 UniswapV2Factory.createPair(tokenA, tokenB),去链上创建一个新的池子(Pair 合约)。
✅ 第 5 步:拿到 Pair 地址后,Router 把用户的 token 转进去
用户想放多少 USDC 和多少 ETH,前端把这些信息告诉 Router。Router 调用 transferFrom 等方式,把这些 token 转到 Pair 合约里。
✅ 第 6 步:Router 调用 Pair 的 mint() 函数
mint() 是 Pair 合约的方法,用来给用户铸造 LP Token(流动性凭证)。LP Token 的作用:以后当你想撤回资金时,就用 LP Token 去 Pair 合约里 burn,取回原来的 token + 一部分手续费收益。
✅ 第 7 步:用户得到 LP Token
添加流动性完成,你拿到 LP Token。别人就可以在这个池子里自由交换 USDC ↔ ETH,你也能从手续费里获得收益。
来个比喻方便理解
Factory = 房地产开发商,建楼(创建池子)
Pair = 楼本身(池子),里面放钱、交易
Router = 中介公司,帮忙跑流程、算价钱、带你找楼
简单总结
Router:帮你计算、帮你调用,不存钱
Factory:只管理/创建池子
Pair:池子本体,真正存钱,负责 swap、mint、burn
二、创建合约实例
// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.0;
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";contract UniswapV2Integration {
address private constant ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
IUniswapV2Router02 public uniswapV2Router;
constructor() {
uniswapV2Router = IUniswapV2Router02(ROUTER);
}
}
三、增加流动性:成为流动性提供者
addLiquidity() 函数允许你为交易对提供流动性,并从每笔交易中赚取费用。
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
参数分解
- tokenA/tokenB:要配对的代币的合约地址
- amountADesired/amountBDesired:你期望的存款金额
- amountAMin/amountBMin:最小金额(滑点保护)
- to:接收 LP 代币的地址
- deadline:交易过期时间戳
实际实现
function addLiquidityToPool(
address tokenA,
address tokenB,
uint256 amountA,
uint256 amountB
) external {
// Approve router to spend tokens
// 授权路由器消费代币
IERC20(tokenA).approve(address(uniswapV2Router), amountA);
IERC20(tokenB).approve(address(uniswapV2Router), amountB);
// Add liquidity with 5% slippage tolerance
// 增加流动性,滑点容忍度为 5%
uniswapV2Router.addLiquidity(
tokenA,
tokenB,
amountA,
amountB,
amountA * 95 / 100, // 5% slippage protection
amountB * 95 / 100, // 5% slippage protection
msg.sender

最低0.47元/天 解锁文章
1万+

被折叠的 条评论
为什么被折叠?



