80 关于 UniswapV2 官方库 UniswapV2LiquidityMathLibrary 的函数 {computeProfitMaximizingTrade} 的疑问

UniswapV2 官方给出的 库 UniswapV2LiquidityMathLibrary 的函数 {computeProfitMaximizingTrade} 如下所示:

pragma solidity >=0.5.0;

import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol';
import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol';
import '@uniswap/lib/contracts/libraries/Babylonian.sol';
import '@uniswap/lib/contracts/libraries/FullMath.sol';

import './SafeMath.sol';
import './UniswapV2Library.sol';

// library containing some math for dealing with the liquidity shares of a pair, e.g. computing their exact value
// in terms of the underlying tokens
library UniswapV2LiquidityMathLibrary {
    using SafeMath for uint256;

    // computes the direction and magnitude of the profit-maximizing trade
    function computeProfitMaximizingTrade(
        uint256 truePriceTokenA,
        uint256 truePriceTokenB,
        uint256 reserveA,
        uint256 reserveB
    ) pure internal returns (bool aToB, uint256 amountIn) {
        aToB = FullMath.mulDiv(reserveA, truePriceTokenB, reserveB) < truePriceTokenA;

        uint256 invariant = reserveA.mul(reserveB);

        uint256 leftSide = Babylonian.sqrt(
            FullMath.mulDiv(
                invariant.mul(1000),
                aToB ? truePriceTokenA : truePriceTokenB,
                (aToB ? truePriceTokenB : truePriceTokenA).mul(997)
            )
        );
        uint256 rightSide = (aToB ? reserveA.mul(1000) : reserveB.mul(1000)) / 997;

        if (leftSide < rightSide) return (false, 0);

        // compute the amount that must be sent to move the price to the profit-maximizing price
        amountIn = leftSide.sub(rightSide);
    }
}

参数 truePriceTokenAtruePriceTokenB 字面意思似乎分别是 tokenAtokenB 在外部市场的真实价格(意图在当前池子在套利完成后两种 token 的价格与这两个参数持平)。其中,函数体中的 aToB = FullMath.mulDiv(reserveA, truePriceTokenB, reserveB) < truePriceTokenA 用于比较池子内 tokenA 的价格和外部市场 tokenA 的价格,从而确认兑换方向是否为 tokenA --> tokenB

对于此函数,我有 2 个疑问:

  1. FullMath.mulDiv(reserveA, truePriceTokenB, reserveB) 按逻辑来讲应该是池子内的 tokenA 的价格,对应的计算式为 reserveA * truePriceTokenB / reserveB,相当于 “池内每个 tokenB 等于多少 tokenA” 乘以 “tokenB 在外部市场的真实价格“ 的结果,我对这个计算公式有疑问;我个人理解的计算公式应为 reserveB * truePriceTokenB / reserveA,即 “池内每个 tokenA 等于多少 tokenB” 乘以 “tokenB 在外部市场的真实价格“,这样就得到了“池内每个 tokenA 的实际价格”。很明显,我理解的计算公式代码给出的公式不一样,关键在于乘以 truePriceTokenB 的到底是 reserveA / reserveB 还是 reserveB / reserveA,我怀疑是我对 truePriceTokenAtruePriceTokenB 这两个参数的理解有问题,请大佬们点拨一下。

  2. 以兑换方向为 tokenA --> tokenB 为例(当 aToBtrue时)。amountIn = leftSide - rightSide,我对 leftSide 的公式有疑问,代码给出的公式为 leftSide = (invariant 1000) truePriceTokenA / (truePriceTokenB * 997) 。我尝试推导了一下,发现“实际推算的 leftSide” 是 “代码中的 leftSide”的 sqrt(1000/997) 倍。如果是我的计算错误,请大佬们指出。以下是我对 leftSide 的推导过程:

    初始条件:Uniswap 池子中 tokenAtokenB 的储备量分别为 r<sub>A</sub> 和 r<sub>B</sub>,两者的真实价格分别为 S<sub>A</sub> 和 S<sub>B</sub>,兑换方向为 tokenA -> tokenB,实际投入兑换的 tokenA 的数量(已扣除手续费)为 x,兑出的 tokenB 的数量为 y 。 数学计算过程: <img src="https://img.learnblockchain.cn/attachments/2025/01/H4d9pUJE677f586d37483.jpg" alt="Q1" style="width:75%; height=auto;">

<img src="https://img.learnblockchain.cn/attachments/2025/01/Q85iG1s1677e9ebca8c5c.jpg" alt="Q2" style="width: 75%; height: auto;">


【2025.01.09 更新】目前在 Uniswap 的 v2-periphery 代码库的 issue#91issue#100issue#103 均提出了与第 2 个疑问相同的推导结果,似乎代码中算式的错误是存在的,但未被 Uniswap 官方解决。

请先 登录 后评论
  • 1 关注
  • 0 收藏,686 浏览
  • Garen Woo 提出于 2025-01-08 23:58