当前位置:   article > 正文

Solidity Uniswap V2 Router swapTokensForExactTokens_uniswap v2 swapexacttokensfortokens

uniswap v2 swapexacttokensfortokens

        最初的router合约实现了许多不同的交换方式。我们不会实现所有的方式,但我想向大家展示如何实现倒置交换:用未知量的输入Token交换精确量的输出代币。这是一个有趣的用例,可能并不常用,但仍有可能实现。

GitHub - XuHugo/solidityproject: DApp go go go !!!

        让我们回到交换公式:

        (x+rΔx)(y−Δy)=xy

        现在,我们要找到的不是 Δy,而是 Δx:我们知道想要得到的输出Token的确切数量,但不知道需要提供多少输入Token。

        同样,在应用基本的代数运算后,我们可以得到

        同样,这是一个考虑到产出量(Δy)和费用 r 的储备金(x/y)关系式。

        现在我们就可以实现这一公式:

  1. function getAmountIn(
  2.     uint256 amountOut,
  3.     uint256 reserveIn,
  4.     uint256 reserveOut
  5. ) public pure returns (uint256) {
  6.     if (amountOut == 0) revert InsufficientAmount();
  7.     if (reserveIn == 0 || reserveOut == 0) revert InsufficientLiquidity();
  8.     uint256 numerator = reserveIn * amountOut * 1000;
  9.     uint256 denominator = (reserveOut - amountOut) * 997;
  10.     return (numerator / denominator) + 1;
  11. }

        一切都很清楚,除了最后的结果多了一个 1 ,为什么会这样?原因在于,Solidity 中的除法(即整除)会将结果向下舍入,这意味着结果会被截断。在计算输入金额时,我们希望保证计算出的金额能达到要求的输出金额。如果结果被截断,输出的金额就会稍小。

        接下来,我们需要 getAmountsIn 函数:

  1. function getAmountsIn(
  2.     address factory,
  3.     uint256 amountOut,
  4.     address[] memory path
  5. ) public returns (uint256[] memory) {
  6.     if (path.length < 2) revert InvalidPath();
  7.     uint256[] memory amounts = new uint256[](path.length);
  8.     amounts[amounts.length - 1] = amountOut;
  9.     for (uint256 i = path.length - 1; i > 0; i--) {
  10.         (uint256 reserve0, uint256 reserve1) = getReserves(
  11.             factory,
  12.             path[i - 1],
  13.             path[i]
  14.         );
  15.         amounts[i - 1] = getAmountIn(amounts[i], reserve0, reserve1);
  16.     }
  17.     return amounts;
  18. }

        它复制了 getAmountsOut,但有一个显著的变化:遍历路径的顺序颠倒了。由于我们知道输出金额,并希望找到输入金额,因此我们从路径的末尾开始,以相反的顺序将输入金额填入金额数组。

        高级交换函数看起来也很熟悉:

  1. function swapTokensForExactTokens(
  2.     uint256 amountOut,
  3.     uint256 amountInMax,
  4.     address[] calldata path,
  5.     address to
  6. ) public returns (uint256[] memory amounts) {
  7.     amounts = ZuniswapV2Library.getAmountsIn(
  8.         address(factory),
  9.         amountOut,
  10.         path
  11.     );
  12.     if (amounts[amounts.length - 1] > amountInMax)
  13.         revert ExcessiveInputAmount();
  14.     _safeTransferFrom(
  15.         path[0],
  16.         msg.sender,
  17.         ZuniswapV2Library.pairFor(address(factory), path[0], path[1]),
  18.         amounts[0]
  19.     );
  20.     _swap(amounts, path, to);
  21. }

        它与我们之前实现的 swap 函数几乎完全相同,但它调用的是 getAmountsIn。同样有趣的是,即使金额是输入的,我们也可以使用相同的 _swap 函数。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/900124
推荐阅读
  

闽ICP备14008679号