Solidity Uniswap V2 library contract

library contract 

        在 Solidity 中,库是一种无状态合约(即它没有可变状态),它实现了一组可被其他合约使用的函数--这是库的主要目的。与合约不同,库没有状态:它们的函数通过 DELEGATECALL 在调用者的状态下执行。但与合约一样,库也必须部署后才能使用。幸运的是,Forge 支持自动链接库(我们不需要在测试中部署库),这让我们的工作变得更轻松。

library ZuniswapV2Library {

    error InsufficientAmount();

    error InsufficientLiquidity();



    function getReserves(

        address factoryAddress,

        address tokenA,

        address tokenB

    ) public returns (uint256 reserveA, uint256 reserveB) {

        (address token0, address token1) = _sortTokens(tokenA, tokenB);

        (uint256 reserve0, uint256 reserve1, ) = IZuniswapV2Pair(

            pairFor(factoryAddress, token0, token1)

        ).getReserves();

        (reserveA, reserveB) = tokenA == token0

            ? (reserve0, reserve1)

            : (reserve1, reserve0);

    }

    ...

        这是一个高级函数,它可以获取任意配对的reserve。

        函数的第一步是token地址排序--当我们想通过token地址查找pair地址时,总是要这样做。这就是我们下一步要做的事情:有了factory地址和排序过的token地址,我们就能获得pair地址--我们接下来会看看 pairFor 函数。

        请注意,在返回之前,我们已经对储备进行了排序:我们希望按照token地址指定的顺序返回它们!

        现在,让我们来看看 pairFor 函数:

function pairFor(

    address factoryAddress,

    address tokenA,

    address tokenB

) internal pure returns (address pairAddress) {

        该函数用于通过factory地址和token地址查找pair地址。最直接的方法是从factory合约中获取配对地址,例如

ZuniswapV2Factory(factoryAddress).pairs(address(token0), address(token1))

        但这样做会产生外部调用,从而使函数的运行成本增加。

        Uniswap 使用的是更先进的方法,我们可以从 CREATE2 操作码的确定性地址生成中获的启发。

(address token0, address token1) = sortTokens(tokenA, tokenB);

pairAddress = address(

    uint160(

        uint256(

            keccak256(

                abi.encodePacked(

                    hex"ff",

                    factoryAddress,

                    keccak256(abi.encodePacked(token0, token1)),

                    keccak256(type(ZuniswapV2Pair).creationCode)

                )

            )

        )

    )

);

        这段代码生成地址的方式与 CREATE2 相同。

        1、第一步是对token地址进行排序。还记得 createPair 函数吗?我们使用排序过的令牌地址作为盐。

        2、接下来,我们构建一个字节序列,其中包括:

        0xff - 第一个字节有助于避免与 CREATE 操作码发生碰撞。(更多详情请参见 EIP-1014)。

        factoryAddress - 用于部署配对的工厂。

        salt - 已排序和散列的token地址。

        一对合约字节码的哈希值 - 我们对 creationCode 进行哈希处理以获得该值。

        3、然后,对字节序列进行散列(keccak256)并转换为地址(字节->uint256->uint160->地址)。

        整个过程在 EIP-1014 中定义,并在 CREATE2 操作码中实现。我们要做的就是在 Solidity 中重新实现地址生成!

        最后,我们来到引用函数。

function quote(

  uint256 amountIn,

  uint256 reserveIn,

  uint256 reserveOut

) public pure returns (uint256 amountOut) {

  if (amountIn == 0) revert InsufficientAmount();

  if (reserveIn == 0 || reserveOut == 0) revert InsufficientLiquidity();



  return (amountIn * reserveOut) / reserveIn;

}

        如前所述,该函数根据输入量和配对储备计算输出量。这样,我们就可以知道用特定数量的token A 换取多少token B。在交换中,使用的是基于恒积公式的公式。

你可能感兴趣的:(solidity合约那点事儿,区块链,智能合约,Uniswap)