pragma solidity =0.5.16; import './interfaces/IUniswapV2Factory.sol'; import './UniswapV2Pair.sol'; /** * @title UniswapV2Factory 工厂合约 * @notice Uniswap V2协议的工厂合约,负责创建和管理所有交易对 * @dev 使用CREATE2确定性部署,可预测交易对地址 */ contract UniswapV2Factory is IUniswapV2Factory { // 协议手续费接收地址 address public feeTo; // 有权设置feeTo的地址 address public feeToSetter; // 双重映射:token地址 => token地址 => 交易对地址 mapping(address => mapping(address => address)) public getPair; // 所有交易对地址的数组 address[] public allPairs; // 创建交易对时触发的事件 event PairCreated(address indexed token0, address indexed token1, address pair, uint); /** * @dev 构造函数 * @param _feeToSetter 初始的手续费设置者地址 */ constructor(address _feeToSetter) public { feeToSetter = _feeToSetter; } /** * @notice 获取所有交易对的数量 * @return 交易对总数 */ function allPairsLength() external view returns (uint) { return allPairs.length; } /** * @notice 创建交易对 * @dev 使用CREATE2确定性部署,任何人都可以调用 * @param tokenA 第一个代币地址 * @param tokenB 第二个代币地址 * @return pair 新创建的交易对地址 */ function createPair(address tokenA, address tokenB) external returns (address pair) { require(tokenA != tokenB, 'UniswapV2: IDENTICAL_ADDRESSES'); // 按字典顺序排序代币地址,确保token0 < token1 (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0), 'UniswapV2: ZERO_ADDRESS'); require(getPair[token0][token1] == address(0), 'UniswapV2: PAIR_EXISTS'); // 获取UniswapV2Pair合约的字节码 bytes memory bytecode = type(UniswapV2Pair).creationCode; // 使用两个代币地址生成salt bytes32 salt = keccak256(abi.encodePacked(token0, token1)); // 使用CREATE2部署合约,地址可预测 assembly { pair := create2(0, add(bytecode, 32), mload(bytecode), salt) } // 初始化交易对 IUniswapV2Pair(pair).initialize(token0, token1); // 在映射中记录交易对(双向) getPair[token0][token1] = pair; getPair[token1][token0] = pair; // 添加到数组中 allPairs.push(pair); // 触发创建事件 emit PairCreated(token0, token1, pair, allPairs.length); } /** * @notice 设置协议手续费接收地址 * @dev 只有feeToSetter可以调用 * @param _feeTo 新的手续费接收地址 */ function setFeeTo(address _feeTo) external { require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN'); feeTo = _feeTo; } /** * @notice 设置有权修改feeTo的地址 * @dev 只有当前feeToSetter可以调用 * @param _feeToSetter 新的手续费设置者地址 */ function setFeeToSetter(address _feeToSetter) external { require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN'); feeToSetter = _feeToSetter; } }