这一篇文章,从源码角度梳理UniswapV2Factory的实现
pragma solidity =0.5.16;
import './interfaces/IUniswapV2Factory.sol';
import './UniswapV2Pair.sol';
//uniswap工厂
contract UniswapV2Factory is IUniswapV2Factory {
address public feeTo; //收税地址
address public feeToSetter; //收税权限控制地址
//配对映射, 地址 => (地址 => 地址)
mapping(address => mapping(address => address)) public getPair;
//所有配对数组
address[] public allPairs;
//配对合约的Bytecode的hash
bytes32 public constant INIT_CODE_PAIR_HASH = keccak256(abi.encodePacked(type(UniswapV2Pair).creationCode));
//事件:配对被创建
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
/**
* @dev 构造函数
* @param _feeToSetter 收税开关权限控制
*/
constructor(address _feeToSetter) public {
feeToSetter = _feeToSetter;
}
/**
* @dev 查询配对数组长度方法
*/
function allPairsLength() external view returns (uint) {
return allPairs.length;
}
/**
*
* @param tokenA TokenA
* @param tokenB TokenB
* @return pair 配对地址
* @dev 创建配对
*/
function createPair(address tokenA, address tokenB) external returns (address pair) {
//确认tokenA不等于tokenB
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
//给bytecode变量赋值"UniswapV2Pair"合约的创建字节码
bytes memory bytecode = type(UniswapV2Pair).creationCode;
//将token0和token1打包后创建哈希
bytes32 salt = keccak256(abi.encodePacked(token0, token1));
//内联汇编
//solium-disable-next-line
assembly {
//通过create2方法布署合约,并且加盐,返回地址到pair变量
pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
}
//调用pair地址的合约中的"initialize"方法,传入变量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);
}
/**
* @dev 设置收税地址
* @param _feeTo 收税地址
*/
function setFeeTo(address _feeTo) external {
require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
feeTo = _feeTo;
}
/**
* @dev 收税权限控制
* @param _feeToSetter 收税权限控制
*/
function setFeeToSetter(address _feeToSetter) external {
require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
feeToSetter = _feeToSetter;
}
}
这是 Uniswap V2 中的工厂合约 (UniswapV2Factory
) 的 Solidity 代码。这个合约负责创建和管理代币对(pair
),并且包含了一些关键的功能。
编译器已经被锁死了,使用的是0.5.16版本,这个版本中的solidity还会有溢出问题。这是相关技术背景。
UniswapV2Factory
仅仅继承了接口合约,继承接口合约的目的是为了保证要实现内部的所有方法,如果不实现其中的方法就会报错,接口相当于一种约束。
pragma solidity ^0.5.6;
interface IUniswapV2Factory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function createPair(address tokenA, address tokenB) external returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;
}
feeTo
:收取手续费的地址。feeToSetter
:控制 feeTo
地址的权限地址。getPair
:一个映射,用于存储两个代币之间的配对合约地址。allPairs
:一个数组,存储所有创建的配对合约地址。INIT_CODE_PAIR_HASH
:配对合约的字节码哈希值,用于通过 create2
函数部署合约。PairCreated
:每当一个新的代币对被创建时触发,记录了代币对的两个代币地址及其配对合约地址。constructor(address _feeToSetter) public {
feeToSetter = _feeToSetter;
}
构造函数接受一个 _feeToSetter
地址,用于初始化 feeToSetter
变量。可以在部署工厂合约的时候,传入一个初始化的部署参数,这个参数是一个地址类型,也就是_feeToSetter,然后_feeToSetter 被设置为管理员之后,可以设置feeTo
的地址,最终的手续费会被打到这个feeTo
地址上面。
allPairsLength
方法:
/**
* @dev 查询配对数组长度方法
*/
function allPairsLength() external view returns (uint) {
return allPairs.length;
}
这是一个view函数,返回 `al...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!