Factory
合约是Uniswap V2
中核心合约代码,所有的Pair
合约都是通过Factory
合约进行部署。从代码量上以及代码复杂难度上来说,Factory
合约的理解难度应该是Uniswap V2
合约中比较简单的。
与平台手续费相关有两个变量,均是address
,其中address(feeTo)
表示平台手续费收取的地址,address(feeToSetter)
则表示可设置平台手续费收取地址的地址。
address public feeTo;
address public feeToSetter;
Pair
合约相关与Pair
合约相关有两个变量,其中变量getPair
的类型是map
,存放Pair
合约两个token
与Pair
合约的地址,格式为address => (address => address)
。变量allPairs
存放所有Pair
合约的地址。
mapping(address => mapping(address => address)) public getPair;
address[] public allPairs;
当Pair
合约被创建之后,会触发该事件。
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
Factory
合约的构造函数需要传入权限控制人的address
。
constructor(address _feeToSetter) public {
feeToSetter = _feeToSetter;
}
Pair
数组长度方法function allPairsLength() external view returns (uint) {
return allPairs.length;
}
Pair
方法creatPair
方法的功能是创建一组新的交易对,传入的参数是两个token
的address,需要注意的是,部署Pair
合约使用的是create2
方法,使用该方法部署合约可以固定这个合约的地址,使这个合约的地址可预测,这样便于Router
合约不进行任何调用,就可以计算得到Pair
合约的地址。
function createPair(address tokenA, address tokenB) external returns (address pair) {
require(tokenA != tokenB, 'UniswapV2: IDENTICAL_ADDRESSES');
// 对tokenA和tokenB进行大小排序,确保tokenA小于tokenB
(address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
// 确认token0不等于0地址
require(token0 != address(0), 'UniswapV2: ZERO_ADDRESS');
// 确认配对映射中不存在token0=>token1的映射
require(getPair[token0][token1] == address(0), 'UniswapV2: PAIR_EXISTS'); // single check is sufficient
// 初始化UniswapV2Pair的字节码变量
// bytecode 合约经过编译之后的源代码
bytes memory bytecode = type(UniswapV2Pair).creationCode;
// 将token0和token1打包后创建哈希
bytes32 salt = keccak256(abi.encodePacked(token0, token1));
// 内联汇编
assembly {
// 通过create2方法布置合约,并且加salt,返回合约的地址是固定的,可预测的
pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
}
// 调用pair地址的合约的`initialine`方法,传入变量token0和token1
IUniswapV2Pair(pair).initialize(token0, token1);
// 配对映射中设置token0=>token1 = pair
getPair[token0][token1] = pair;
// 配对映射中设置token1=>token0 = 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;
}
原来的权限控制人,可以指派一个新的address
作为新的权限控制人。
function setFeeToSetter(address _feeToSetter) external {
require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
feeToSetter = _feeToSetter;
}
相比核心合约里面的Pair
和ERC20
合约,Factory
合约比较简单。后续会继续解析Uniswap V2
中的Router
相关合约,Router
合约是Uniswap V2
运行的关键,前端大部分的操作,都是在与Router
合约进行交互。