Uniswap-v2 Factory合约分析

原文发布在 https://github.com/33357/smartcontract-apps这是一个面向中文社区,分析市面上智能合约应用的架构与实现的仓库。欢迎关注开源知识项目!

Uniswap-v2 Factory合约分析

Factory 合约是 Uniswap-v2 用来创建资金池的合约,通过分析它可以深入了解 Uniswap-v2 的运行逻辑。

演示代码仓库:https://github.com/33357/uniswap-v2-contract

合约初始化

  • 公共函数(合约内外部都可以调用)
    • constructor
      • 代码速浏览

        constructor(address _feeToSetter) public {
            feeToSetter = _feeToSetter;
        }
        
      • 参数分析

        函数 constructor 的入参有1个,出参有0个,对应的解释如下:

        constructor(
            address _feeToSetter // 手续费管理员地址
        ) public {
            ...
        }
        

        在合约初始化时,需要在函数 constructor 中传入 _feeToSetter,该参数设置了手续费管理员地址。

      • 实现分析

        ...
        {
            // 设置手续费管理员地址
            feeToSetter = _feeToSetter;
        }
        
      • 总结

        Factory 合约初始化时,需要传入手续费管理员地址。

资金池

  • 外部函数(仅合约外部可以调用)
    • allPairsLength
      • 代码速浏览

        function allPairsLength() external view returns (uint) {
            return allPairs.length;
        }
        
      • 参数分析

        函数 allPairsLength 的入参有0个,出参有1个,对应的解释如下:

        function allPairsLength() external view returns (
            uint // 资金池的数量
        ) {
            ...
        }
        

        函数 allPairsLength 返回了 allPairs 的长度,也就是当前资金池的数量。

      • 实现分析

        ...
        {
            // 返回资金池数组的长度
            return allPairs.length;
        }
        
      • 总结

        获取 allPairs 需要输入 index,因此需要获取资金池数组。

    • createPair
      • 代码速浏览

        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);
            require(token0 != address(0), 'UniswapV2: ZERO_ADDRESS');
            require(getPair[token0][token1] == address(0), 'UniswapV2: PAIR_EXISTS');
            bytes memory bytecode = type(UniswapV2Pair).creationCode;
            bytes32 salt = keccak256(abi.encodePacked(token0, token1));
            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);
        }
        
      • 参数分析

        函数 createPair 的入参有2个,出参有1个,对应的解释如下:

        function createPair(
            address tokenA, // tokenA 的地址
            address tokenB // tokenB 的地址
        ) external returns (
            address pair // 资金池地址
        ) {
            ...
        }
        

        函数 createPair 可以创建新的资金池合约,需要传入 tokenAtokenB,返回资金池地址 pair

      • 实现分析

        ...
        {
            // 需要 tokenA 不等于 tokenB
            require(tokenA != tokenB, 'UniswapV2: IDENTICAL_ADDRESSES');
            // 计算 tokenA 和 tokenB 中谁是 token0 和 token1
            (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');
            // 获取 UniswapV2Pair 合约的字节码
            bytes memory bytecode = type(UniswapV2Pair).creationCode;
            // 使用参数 token0, token1 计算 salt
            bytes32 salt = keccak256(abi.encodePacked(token0, token1));
            // 使用 create2 部署 Pair 合约
            assembly {
                pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
            }
            // Pair 合约初始化
            IUniswapV2Pair(pair).initialize(token0, token1);
            // 记录 token0,token1 创建的资金池地址是 pair
            getPair[token0][token1] = pair;
            getPair[token1][token0] = pair;
            // pair 加入资金池数组
            allPairs.push(pair);
            // 触发资金池创建事件
            emit PairCreated(token0, token1, pair, allPairs.length);
        }
        
      • 总结

        create2(0, add(bytecode, 32), mload(bytecode), salt)中的四个参数意思分别是:创建合约发送的 ETH 数量、bytecode 起始位置、bytecode 长度、生成合约地址的随机盐值。

手续费

  • 外部函数(仅合约外部可以调用)
    • setFeeTo
      • 代码速浏览

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

        函数 setFeeTo 的入参有1个,出参有0个,对应的解释如下:

        function setFeeTo(
            address _feeTo // 手续费接收地址
        ) external {
            ...
        }
        

        函数 setFeeTo 可以设置手续费接收地址,但需要手续费管理员调用才能成功。

      • 实现分析

        ...
        {
            // 检查调用者是否是手续费管理员
            require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
            // 设置手续费接收地址
            feeTo = _feeTo;
        }
        
      • 总结

        只有手续费管理员才能设置手续费接收地址。

    • setFeeToSetter
      • 代码速浏览

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

        函数 setFeeToSetter 的入参有1个,出参有0个,对应的解释如下:

        function setFeeToSetter(
           address _feeToSetter // 手续费管理员地址
        ) external {
            ...
        }
        

        函数 setFeeToSetter 可以设置手续费管理员地址,但需要手续费管理员调用才能成功。

      • 实现分析

        ...
        {
            // 检查调用者是否是手续费管理员
            require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
             // 设置手续费管理员地址
            feeToSetter = _feeToSetter;
        }
        
      • 总结

        只有手续费管理员才能设置手续费管理员地址。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值