2021-11-26Uniswap v3 详解(六):闪电贷

本文copy自https://liaoph.com/uniswap-v3-6/

Flash swap

1637903779(1).png

Uniswap v3 的 flash swap

Uniswap v3 版本中,和 v2 一样也有两种闪电贷的方式,但是是通过不同的函数接口来完成的。

第一种是普通的闪电贷,即借入 token 和还贷 token 相同,通过 UniswapV3Pool.flash() 完成
第二种是类似 v2 的 flash swap,即借入 token 和还贷 token 不同,这个是通过 UniswapV3Pool.swap() 来完成的。

flash

普通闪电贷的接口为交易池合约的 UniswapV3Pool.flash() 函数,它的实现也比较简单:

function flash(
    address recipient,   // 借贷方地址,用于调用回调函数
    uint256 amount0,     // 借贷的 token0 的数量
    uint256 amount1,     // 借贷的 token1 的数量
    bytes calldata data  // 回调函数的参数
) external override lock noDelegateCall {
    uint128 _liquidity = liquidity;
    require(_liquidity > 0, 'L');

    // 计算借贷所需要扣除的手续费
    uint256 fee0 = FullMath.mulDivRoundingUp(amount0, fee, 1e6);
    uint256 fee1 = FullMath.mulDivRoundingUp(amount1, fee, 1e6);
    // 记录下当前的余额
    uint256 balance0Before = balance0();
    uint256 balance1Before = balance1();

    // 将所需 token 发送给借贷方
    if (amount0 > 0) TransferHelper.safeTransfer(token0, recipient, amount0);
    if (amount1 > 0) TransferHelper.safeTransfer(token1, recipient, amount1);

    // 调用借贷方地址的回调函数,将函数用户传入的 data 参数传给这个回调函数
    IUniswapV3FlashCallback(msg.sender).uniswapV3FlashCallback(fee0, fee1, data);

    // 记录调用完成后的余额
    uint256 balance0After = balance0();
    uint256 balance1After = balance1();

    // 比对借出代币前和回调函数调用完成后余额的数量,对于每个 token,余额只能多不能少
    require(balance0Before.add(fee0) <= balance0After, 'F0');
    require(balance1Before.add(fee1) <= balance1After, 'F1');

    // 手续费相关的计算
    uint256 paid0 = balance0After - balance0Before;
    uint256 paid1 = balance1After - balance1Before;

    if (paid0 > 0) {
        uint8 feeProtocol0 = slot0.feeProtocol % 16;
        uint256 fees0 = feeProtocol0 == 0 ? 0 : paid0 / feeProtocol0;
        if (uint128(fees0) > 0) protocolFees.token0 += uint128(fees0);
        feeGrowthGlobal0X128 += FullMath.mulDiv(paid0 - fees0, FixedPoint128.Q128, _liquidity);
    }
    if (paid1 > 0) {
        uint8 feeProtocol1 = slot0.feeProtocol >> 4;
        uint256 fees1 = feeProtocol1 == 0 ? 0 : paid1 / feeProtocol1;
        if (uint128(fees1) > 0) protocolFees.token1 += uint128(fees1);
        feeGrowthGlobal1X128 += FullMath.mulDiv(paid1 - fees1, FixedPoint128.Q128, _liquidity);
    }

    emit Flash(msg.sender, recipient, amount0, amount1, paid0, paid1);
}

flash swap

通过 UniswapV3Pool.swap() 函数,可以完成 flashswap 的功能,这个函数在Uniswap v3 详解(三):交易过程已经有过详细的描述。

在使用 flashswap 时,需要实现其 IUniswapV3SwapCallback 接口,完成闪电贷的还贷即可,这里不再赘述具体实现。

理解闪电贷

理解闪电贷,你才能理解 DeFi. 虽然 DeFi 领域一直有着大大小小的创新,号称颠覆传统金融。但是在我看来,只有闪电贷才是真正的颠覆者,它是 DeFi 的精髓。它区块链和智能合约的特性发挥到了极致,使得借贷资金的使用效率在短时间内提升到了前所未有的高度。引用 DODO 文档里一段话:

Once you have a deep understanding of flash swap, you will realize the superiority of the DeFi world over the centralized world. The composability of smart contracts has elevated the fund utilization of DeFi to an unprecedented level. Thanks to trustlessness, the cost of credit in DeFi is incredibly low. Once this financial system is integrated into the real world, its potential for improving our society and productivity will be truly boundless. The DODO team hopes that flash swap serves as a primer for DeFi builders and beginners alike to gain an appreciation for the power of DeFi.

至此,关于 Uniswap v3 的所有内容就介绍完毕了。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容