用户界面

用户界面 #

现在,我们可以让我们的 web 应用看起来更像一个真正的 DEX 了。我们可以移除那些硬编码的数额,并且允许用户输入任意的数量。同样,我们还可以让用户在任意一个方向交易,所以我们需要一个按钮来改变交易方向。在更新之后,swap 的表单长这样:

<form className="SwapForm">
  <SwapInput
    amount={zeroForOne ? amount0 : amount1}
    disabled={!enabled || loading}
    readOnly={false}
    setAmount={setAmount_(zeroForOne ? setAmount0 : setAmount1, zeroForOne)}
    token={zeroForOne ? pair[0] : pair[1]} />
  <ChangeDirectionButton zeroForOne={zeroForOne} setZeroForOne={setZeroForOne} disabled={!enabled || loading} />
  <SwapInput
    amount={zeroForOne ? amount1 : amount0}
    disabled={!enabled || loading}
    readOnly={true}
    token={zeroForOne ? pair[1] : pair[0]} />
  <button className='swap' disabled={!enabled || loading} onClick={swap_}>Swap</button>
</form>

每个输入都根据交易方向赋值给一个变量,交易方向由 zeroForOne 这个状态来控制。下面的输入空间总是只读的,因为这部分的数字是由报价合约计算出来。

setAmount_ 函数做了两件事:更新上面输入框中的值,调用报价合约来计算下面输入框中的值

const updateAmountOut = debounce((amount) => {
  if (amount === 0 || amount === "0") {
    return;
  }

  setLoading(true);

  quoter.callStatic
    .quote({ pool: config.poolAddress, amountIn: ethers.utils.parseEther(amount), zeroForOne: zeroForOne })
    .then(({ amountOut }) => {
      zeroForOne ? setAmount1(ethers.utils.formatEther(amountOut)) : setAmount0(ethers.utils.formatEther(amountOut));
      setLoading(false);
    })
    .catch((err) => {
      zeroForOne ? setAmount1(0) : setAmount0(0);
      setLoading(false);
      console.error(err);
    })
})

const setAmount_ = (setAmountFn) => {
  return (amount) => {
    amount = amount || 0;
    setAmountFn(amount);
    updateAmountOut(amount)
  }
}

注意到,我们对 quoter 使用了 callStatic —— 这就是我们在上一小节讨论到的:我们需要强制 Ethers.js 进行 static call。如果不这样,由于 quote 不是 pure 或者 view 的,Ethers.js 会尝试发送一个交易。

这样就完成了!现在的 UI 允许任意数量和任意方向的交易了。