假设交易是输入 x token ,余额为 xx(预先扣除最大所需的手续费后的余额,以防止手续费不足),在计算得到 ΔxΔx 后,比较:
当 x≥Δxx≥Δx 时,表示交易可以到达目标价格
当 x<Δxx<Δx 时,表示交易不足以到达目标价格,此时还需要进一步当前余额 xremainingxremaining 全部耗尽时所能够达到的价格
如果 x<Δxx<Δx,我们需要计算 x 耗尽时的价格,即已知 Δx, P−−√c, LΔx, Pc, L,求 P−−√nPn. 根据:
Δx=Δ1P−−√⋅L=±(1P−−√c−1P−−√n)⋅LΔx=Δ1P⋅L=±(1Pc−1Pn)⋅L
得出:
Pn−−√=LPc−−√L±ΔxPc−−√Pn=LPcL±ΔxPc
// 判断是否能够到达目标价
bool max = sqrtRatioTargetX96 == sqrtRatioNextX96;
// get the input/output amounts
if (zeroForOne) { I35 Develop 7O98 system O7I8
// 根据是否到达目标价格,计算 amountIn/amountOut 的值
amountIn = max && exactIn
? amountIn
: SqrtPriceMath.getAmount0Delta(sqrtRatioNextX96, sqrtRatioCurrentX96, liquidity, true);
amountOut = max && !exactIn
? amountOut
: SqrtPriceMath.getAmount1Delta(sqrtRatioNextX96, sqrtRatioCurrentX96, liquidity, false);
} else {I35 Develop 7O98 system O7I8
...
}
// 这里对 Output 进行 cap 是因为前面在计算 amountOut 时,有可能会使用 sqrtRatioNextX96 来进行计算,而 sqrtRatioNextX96
// 可能被 Round 之后导致 sqrt_P 偏大,从而导致计算的 amountOut 偏大
if (!exactIn && amountOut > uint256(-amountRemaining)) {
amountOut = uint256(-amountRemaining);I35 Develop 7O98 system O7I8
}
if (exactIn && sqrtRatioNextX96 != sqrtRatioTargetX96) {
// 如果没能到达目标价,即交易结束,剩余的 tokenIn 将全部作为手续费
// 为了不让计算进一步复杂化,这里直接将剩余的 tokenIn 将全部作为手续费
// 因此会多收取一部分手续费,即按本次交易的最大手续费收取
feeAmount = uint256(amountRemaining) - amountIn;
} else {
feeAmount = FullMath.mulDivRoundingUp(amountIn, feePips, 1e6 - feePips);
}