UniswapV2Factory-源码解读

  • Louis
  • 发布于 2024-09-03 16:58
  • 阅读 1117

这一篇文章,从源码角度梳理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;
}

变量:

  1. feeTo:收取手续费的地址。
  2. feeToSetter:控制 feeTo 地址的权限地址。
  3. getPair:一个映射,用于存储两个代币之间的配对合约地址。
  4. allPairs:一个数组,存储所有创建的配对合约地址。
  5. 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...

剩余50%的内容订阅专栏后可查看

点赞 1
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Louis
Louis
web3 developer,技术交流或者有工作机会可加VX: magicalLouis