Solidity Uniswap V2 Router swapTokensForExactTokens

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

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

        让我们回到交换公式:

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

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

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

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

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

function getAmountIn(

    uint256 amountOut,

    uint256 reserveIn,

    uint256 reserveOut

) public pure returns (uint256) {

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

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



    uint256 numerator = reserveIn * amountOut * 1000;

    uint256 denominator = (reserveOut - amountOut) * 997;



    return (numerator / denominator) + 1;

}

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

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

function getAmountsIn(

    address factory,

    uint256 amountOut,

    address[] memory path

) public returns (uint256[] memory) {

    if (path.length < 2) revert InvalidPath();

    uint256[] memory amounts = new uint256[](path.length);

    amounts[amounts.length - 1] = amountOut;



    for (uint256 i = path.length - 1; i > 0; i--) {

        (uint256 reserve0, uint256 reserve1) = getReserves(

            factory,

            path[i - 1],

            path[i]

        );

        amounts[i - 1] = getAmountIn(amounts[i], reserve0, reserve1);

    }



    return amounts;

}

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

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

function swapTokensForExactTokens(

    uint256 amountOut,

    uint256 amountInMax,

    address[] calldata path,

    address to

) public returns (uint256[] memory amounts) {

    amounts = ZuniswapV2Library.getAmountsIn(

        address(factory),

        amountOut,

        path

    );

    if (amounts[amounts.length - 1] > amountInMax)

        revert ExcessiveInputAmount();

    _safeTransferFrom(

        path[0],

        msg.sender,

        ZuniswapV2Library.pairFor(address(factory), path[0], path[1]),

        amounts[0]

    );

    _swap(amounts, path, to);

}

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

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0xweb3q

有钱的捧个钱场,没钱的捧个人场

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值