用户界面
\[ \]

用户界面 #

现在,我们可以针对我们在这个 milestone 中做出的改变来更新我们的UI了。我们会增加两个新的特性:

  1. 添加流动性对话框
  2. 交易时的滑点设置

添加流动性对话框 #

Add Liquidity dialog window

这一步的改变会最终移除代码中硬编码的流动性数量,并且允许我们在任意价格区间添加流动性。

对话框就是一个带一系列输入的简单组件。我们认识可以重用之前实现的 addLiquidity 函数。然而,我们现在需要在JavaScript中将价格转换成 tick:我们希望用户输入的是价格信息,但是合约想要的参数是 tick。为了简化我们的实现,我们会使用 Uniswap V3 官方 SDK来完成这一步。

要把价格转换成 $\sqrt{P}$,我们可以使用 encodeSqrtRatioX96 函数。这个函数把两个 token 数量作为输入,计算出对应的价格。由于我们只希望把价格转换成 $\sqrt{P}$,我们给 amount0 传参数 1 即可:

const priceToSqrtP = (price) => encodeSqrtRatioX96(price, 1);

为了把价格转成 tick index,我们可以使用 TickMath.getTickAtSqrtRatio 函数。这是 Solidity 中的 TickMath 库的 JavaScript 版本:

const priceToTick = (price) => TickMath.getTickAtSqrtRatio(priceToSqrtP(price));

我们现在可以直接把用户输入的价格转换成 tick 了:

const lowerTick = priceToTick(lowerPrice);
const upperTick = priceToTick(upperPrice);

另一个我们需要添加的点就是滑点保护。为了简化起见,我们在这里把它硬编码为 0.5%。下面的代码展示了如何用滑点来计算最小数量:

const slippage = 0.5;
const amount0Desired = ethers.utils.parseEther(amount0);
const amount1Desired = ethers.utils.parseEther(amount1);
const amount0Min = amount0Desired.mul((100 - slippage) * 100).div(10000);
const amount1Min = amount1Desired.mul((100 - slippage) * 100).div(10000);

交易中的滑点保护 #

尽管我们是我们系统的唯一用户因此永远不会遇到滑点的问题,我们还是要增加一个输入项来对于交易过程进行滑点保护。

Main screen of the web app

在交易中,滑点保护是通过限制价格来实现的——我们在交易过程中不会超过或者低于这个价格。这意味着我们需要在发送交易之前就知道价格。然而我们并不需要在前端对此进行计算,因为我们已经在报价合约中实现了相关功能:

function quote(QuoteParams memory params)
    public
    returns (
        uint256 amountOut,
        uint160 sqrtPriceX96After,
        int24 tickAfter
    ) { ... }

我们调用它来获取交易数额。

因此,为了计算限制价格,我们使用 sqrtPriceX96After,并从其中减去滑点价格——就得到了我们希望在交易中不低于的某个价格。

const limitPrice = priceAfter.mul((100 - parseFloat(slippage)) * 100).div(10000);

完成了!