UniswapV2-创建 UniswapV2Pair


图片来源

Uniswap 通过能够孵化出其它合约的超级合约,建立 ERC20 协议上的合约工厂。
孵化出来的合约,定义了用户交易/分红/流动性管理的具体规则。所以,它也扮演了一个去中心化交易所的角色。

本文,基于 Uniswap V2 版本的 UniswapV2Factory 源码,分析 UniswapV2Pair 的创建过程。

UniswapV2-创建 UniswapV2Pair
UniswapV2-添加流动性
UniswapV2-移除流动性
UniswapV2-兑换(swap)
UniswapV2-公式分析

概述

Uniswap 本质上,实际上是一组 ERC20 合约。
它的职责,主要是根据用户操作,将其它 ERC20 Token 对 进行绑定,并将这种绑定结果,定义在其生成的合约内,即创建 Uniswap Pair。这个过程,也可以说是 用合约创建合约

绑定完成之后,任何人都可以来 SWAP,即通过输入 ERC20 Token 对 中的一种 token 以兑换另外以一种 token;任何人也都可以通过提供注入流动性的方式,成为做市商。
整个过程,都由合约自动完成,这就是去中心化的根本。

基于 Uniswap V2 版本,计划做一个系列,介绍 createPair/swap/addLiquidity/removeLiquidity/分红/无常损失等。本文是第一篇。

创建 UniswapV2Pair

创建过程比较简单,主要是通过 create2 操作符,完成合约的生成。通过源码我们可知:

  1. 任意两个 token 对(非零) ,都可以生成一个 pair。这两个 token 地址非零即可,UniswapV2Factory 甚至不会去检查这两个 token 是否真的存在。
  2. 协议费(Protocol Fees)发给谁,由谁来管理发给谁,这些是在 UniswapV2Factory 中控制的。UniswapV2Factory 在构造的时候,确定了 feeSetter; 而是否收取协议费,是通过 feeTo 是否是零地址判断的(这一点后文中 mint 环节将介绍,目前 feeTo 还是零地址,即平台的协议费还没有还是收取)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
//https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Factory.sol#L6
contract UniswapV2Factory is IUniswapV2Factory {
// 收费地址
address public feeTo;
// 拥有权限设置收费地址的 setter
address public feeToSetter;
// getPair[token0][token1] = pair;
// getPair[token1][token0] = pair;
mapping(address => mapping(address => address)) public getPair;

address[] public allPairs;

event PairCreated(address indexed token0, address indexed token1, address pair, uint);

constructor(address _feeToSetter) public {
feeToSetter = _feeToSetter;
}

function allPairsLength() external view returns (uint) {
return allPairs.length;
}

function createPair(address tokenA, address tokenB) external returns (address pair) {
require(tokenA != tokenB, 'UniswapV2: IDENTICAL_ADDRESSES');
(address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
// token0 和 token1 address 不能为 0
require(token0 != address(0), 'UniswapV2: ZERO_ADDRESS');
// 该 pair 并不存在于本 factory 中
require(getPair[token0][token1] == address(0), 'UniswapV2: PAIR_EXISTS'); // single check is sufficient
// 获取包含 UniswapV2Pair 合约创建的字节码(数组),即创建代码,用以创建合约。
// 创建代码中,包含了合约本身/构造函数以及构造函数的参数。
// https://docs.soliditylang.org/en/v0.5.3/units-and-global-variables.html#type-information
bytes memory bytecode = type(UniswapV2Pair).creationCode;
bytes32 salt = keccak256(abi.encodePacked(token0, token1));
assembly {
// CREATE2 操作符 部署合约
pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
}
// 将 pair 邦迪在 token0 和 token1 上。
IUniswapV2Pair(pair).initialize(token0, token1);
// 如此这番,可以通过 (token0/token1) or (token1/token0) 的形式都可以找到这个 token pair
getPair[token0][token1] = pair;
getPair[token1][token0] = pair; // populate mapping in the reverse direction
// 将这个 pair 放入到数组中存储,方便索引
allPairs.push(pair);
// 发射日志
emit PairCreated(token0, token1, pair, allPairs.length);
}

function setFeeTo(address _feeTo) external {
require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
feeTo = _feeTo;
}

function setFeeToSetter(address _feeToSetter) external {
require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
feeToSetter = _feeToSetter;
}
}

参考链接

Uniswap v2 Core
UniswapV2Factory
Deploying Smart Contracts Using CREATE2

© 2024 YueGS