Uniswap V2 源码学习(三):手续费与交易池估值深度解析优质

6次浏览 | 2024-11-06 10:10:06 更新
来源 :互联网
最佳经验

简要回答

Uniswap可是去中心化交易所里的热门项目,很多人都在那头交易。不过,它的手续费计算方式就像是个神秘的盒子,让人摸不着头脑。不懂行的话,交易和做市的时候很容易吃哑巴亏。今天就给它来个大揭秘,好好看看这其中的门道。

Uniswap交易算法是前提

之前咱们对Uniswap的交易算法有个大概的了解。这就像是盖楼的地基,不先弄明白这个算法,手续费的计算就像是建在空中的楼一样不牢靠。交易的时候,算法决定了资产怎么流动,手续费的计算就是在这个流动过程中怎么分利的问题。那些早期研究Uniswap的交易员,把交易算法当成了研究手续费计算的第一关。只有搞清楚交易是怎么完成的,才能明白费用是哪来的。

这学问要是没掌握,就好比闯进一片新天地却没带地图,到处都是未知和危险。想要真正弄懂Uniswap的手续费计算,这节课是必须得上的。

function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock {
    ...
    { // scope for reserve{0,1}Adjusted, avoids stack too deep errors
        uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3));
        uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3));
        require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'UniswapV2: K');
    }
    ...
}

有效输入在计算中的角色

收取手续费时,实际有效输入得这样算:effectiveInput=amountIn×0.997。公式看起来挺简单,但其实背后藏着大秘密。它规定了swap交易中实际有效的资产量,这直接关系到交易结果。对那些操作交易的投资者来说,这说明了手续费对投入资产量的具体削减作用。

这个有效输入在经过swap交易处理之后,满足了A2_B2等于A1乘以B1的条件。这说明,即便是在收取手续费的情况下,交易前后的资产关系依然保持了一定的稳定性。这种稳定性,正是Uniswap交易机制的一个鲜明特点,同时也是构建手续费模型的重要基础。

做市商手续费的独特考量

做市商的手续费不必直接算。池子里的财富要是多了,LP代币的数量可不会变。这样一来,每个做市商手头的LP就能分到更多的tokenA和tokenB。就拿某些交易对来说,交易挺频繁的,池子里的财富就明显增长了。要是你想提取流动性,根据LP和LP供应量的比例,你就能拿到更多的tokenA和tokenB。

做市商面对的是一种独特的盈利模式。跟直接的手续费算法不同,这种模式是随着资金池规模扩大而间接带来收益的。正因如此,不少做市商被这种特别的设计所吸引,纷纷加入Uniswap的生态圈进行做市活动。

财富度量标准的重要性

在Uniswap里头,手续费的计算得先搞清楚池子里的财富度量标准,这可是关键。搞明白了这个,咱们才能算出财富增长的百分比,然后才能正确地mint出lp代币来当手续费。就像在商店里算利润,你得先学会怎么评估货物的价值一样。

// if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k)
function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) {
    address feeTo = IUniswapV2Factory(factory).feeTo();
    feeOn = feeTo != address(0);
    uint _kLast = kLast; // gas savings
    if (feeOn) {
        if (_kLast != 0) {
            uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1));
            uint rootKLast = Math.sqrt(_kLast);
            if (rootK > rootKLast) {
                uint numerator = totalSupply.mul(rootK.sub(rootKLast));
                uint denominator = rootK.mul(5).add(rootKLast);
                uint liquidity = numerator / denominator;
                if (liquidity > 0) _mint(feeTo, liquidity);
            }
        }
    } else if (_kLast != 0) {
        kLast = 0;
    }
}

想自己搞个类似协议或者想深入研究Uniswap金融逻辑的,得先搞懂这个概念,这直接关系到你能探索多深。要是财富度量标准搞错了,那手续费相关的计算全都会跟着出错。

从问题看手续费计算关键

假设交易池一开始是A1、B1的状态,财富值是w1,然后经过swap交易后变成了A2、B2,可A2和A1的比值不等于B2和B1的比值,那我们要怎么算出w2?这个问题可真是关键。它揭示了交易过程中,变量变动对财富所产生影响的复杂程度。在实际的交易环境中,尤其是在业务高峰期,热门交易对的资产比例这种不同步的变化是很常见的。

这个数学问题看起来简单,但其实它揭示了Uniswap手续费计算逻辑的一个具体应用。弄懂这个问题,对于我们理解协议如何根据交易结果来收取手续费,非常有帮助。

协议手续费的最终确认

Pair合约的mint()和burn()操作前后,都得先执行_mintFee()来结算手续费。别忘了,最后还得更新kLast这个关键信息。这一连串动作保证了不管交易怎么进行,手续费都能准确计算并记录下来。交易量大的时候,这些动作得频繁进行,才能确保每个环节的手续费结算都是精确无误的。

这就是Uniswap手续费计算逻辑的终极展现,把之前的各种思考和定义都转化成了实际的代码操作,让手续费体系能够完整地运转起来。

你对Uniswap的手续费计算理解得怎么样了?读完这篇文章,你有啥想法没?不吝赐教,欢迎来评论点赞,还有转发!

// this low-level function should be called from a contract which performs important safety checks
function mint(address to) external lock returns (uint liquidity) {
    ...
    /****************************************************************************
     *  流动性操作之前, 结清迄今为止产生的手续费
     ****************************************************************************/
    bool feeOn = _mintFee(_reserve0, _reserve1);
    ...
    //按照输入的 balance-reserve, mint 代币给 to(即项目方钱包)
    ...
    _update(balance0, balance1, _reserve0, _reserve1);
    /****************************************************************************
     *  流动性操作结束后, 重新记录 kLast, 使得rootK - rootKLast 始终不受增减流动性的影响
     ****************************************************************************/
    if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
    emit Mint(msg.sender, amount0, amount1);
}

本文地址:https://www.huajie.net.cn/qkl/55039.html

发布于 2024-11-06 10:10:06
收藏
分享
海报
6
上一篇:比特币‘钱包’揭秘:你真的了解它吗? 下一篇:数字货币钱包有哪些?一文带你了解

推荐阅读

0 条评论

本站已关闭游客评论,请登录或者注册后再评论吧~

忘记密码?

图形验证码