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);
}
}
参数 truePriceTokenA
和 truePriceTokenB
字面意思似乎分别是 tokenA 和 tokenB 在外部市场的真实价格(意图在当前池子在套利完成后两种 token 的价格与这两个参数持平)。其中,函数体中的 aToB = FullMath.mulDiv(reserveA, truePriceTokenB, reserveB) < truePriceTokenA
用于比较池子内 tokenA 的价格和外部市场 tokenA 的价格,从而确认兑换方向是否为 tokenA --> tokenB 。
对于此函数,我有 2 个疑问:
FullMath.mulDiv(reserveA, truePriceTokenB, reserveB)
按逻辑来讲应该是池子内的 tokenA 的价格,对应的计算式为 reserveA * truePriceTokenB / reserveB
,相当于 “池内每个 tokenB 等于多少 tokenA” 乘以 “tokenB 在外部市场的真实价格“ 的结果,我对这个计算公式有疑问;我个人理解的计算公式应为 reserveB * truePriceTokenB / reserveA
,即 “池内每个 tokenA 等于多少 tokenB” 乘以 “tokenB 在外部市场的真实价格“,这样就得到了“池内每个 tokenA 的实际价格”。很明显,我理解的计算公式和代码给出的公式不一样,关键在于乘以 truePriceTokenB
的到底是 reserveA / reserveB
还是 reserveB / reserveA
,我怀疑是我对 truePriceTokenA
和 truePriceTokenB
这两个参数的理解有问题,请大佬们点拨一下。
以兑换方向为 tokenA --> tokenB 为例(当 aToB
为 true
时)。amountIn
= leftSide
- rightSide
,我对 leftSide
的公式有疑问,代码给出的公式为 leftSide
= (invariant
1000
) truePriceTokenA
/ (truePriceTokenB
* 997
) 。我尝试推导了一下,发现“实际推算的 leftSide
” 是 “代码中的 leftSide
”的 sqrt(1000/997) 倍。如果是我的计算错误,请大佬们指出。以下是我对 leftSide
的推导过程:
初始条件:Uniswap 池子中 tokenA 与 tokenB 的储备量分别为 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#91、issue#100、issue#103 均提出了与第 2 个疑问中相同的推导结果,似乎代码中算式的错误是存在的,但未被 Uniswap 官方解决。