1

使用scaffold-eth来实现uniswap 文档中的这个单一交换示例 - https://docs.uniswap.org/protocol/guides/swaps/single-swaps

几乎只是复制并粘贴了代码,并且能够成功地将其部署到 rinkeby:

//SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
pragma abicoder v2;

import "hardhat/console.sol";
import '@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol';
import '@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol';

contract YourContract {
  // For the scope of these swap examples,
  // we will detail the design considerations when using
  // `exactInput`, `exactInputSingle`, `exactOutput`, and  `exactOutputSingle`.

  // It should be noted that for the sake of these examples, we purposefully pass in the swap router instead of inherit the swap router for simplicity.
  // More advanced example contracts will detail how to inherit the swap router safely.

  ISwapRouter public immutable swapRouter;

  // This example swaps DAI/WETH9 for single path swaps and DAI/USDC/WETH9 for multi path swaps.

  address public constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
  address public constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
  address public constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;

  // For this example, we will set the pool fee to 0.3%.
  uint24 public constant poolFee = 3000;

  constructor(ISwapRouter _swapRouter) {
      swapRouter = _swapRouter;
  }

  /// @notice swapExactInputSingle swaps a fixed amount of DAI for a maximum possible amount of WETH9
  /// using the DAI/WETH9 0.3% pool by calling `exactInputSingle` in the swap router.
  /// @dev The calling address must approve this contract to spend at least `amountIn` worth of its DAI for this function to succeed.
  /// @param amountIn The exact amount of DAI that will be swapped for WETH9.
  /// @return amountOut The amount of WETH9 received.
  function swapExactInputSingle(uint256 amountIn) external returns (uint256 amountOut) {
      // msg.sender must approve this contract

      // Transfer the specified amount of DAI to this contract.
      TransferHelper.safeTransferFrom(DAI, msg.sender, address(this), amountIn);

      // Approve the router to spend DAI.
      TransferHelper.safeApprove(DAI, address(swapRouter), amountIn);

      // Naively set amountOutMinimum to 0. In production, use an oracle or other data source to choose a safer value for amountOutMinimum.
      // We also set the sqrtPriceLimitx96 to be 0 to ensure we swap our exact input amount.
      ISwapRouter.ExactInputSingleParams memory params =
          ISwapRouter.ExactInputSingleParams({
              tokenIn: DAI,
              tokenOut: WETH9,
              fee: poolFee,
              recipient: msg.sender,
              deadline: block.timestamp,
              amountIn: amountIn,
              amountOutMinimum: 0,
              sqrtPriceLimitX96: 0
          });

      // The call to `exactInputSingle` executes the swap.
      amountOut = swapRouter.exactInputSingle(params);
  }

  /// @notice swapExactOutputSingle swaps a minimum possible amount of DAI for a fixed amount of WETH.
  /// @dev The calling address must approve this contract to spend its DAI for this function to succeed. As the amount of input DAI is variable,
  /// the calling address will need to approve for a slightly higher amount, anticipating some variance.
  /// @param amountOut The exact amount of WETH9 to receive from the swap.
  /// @param amountInMaximum The amount of DAI we are willing to spend to receive the specified amount of WETH9.
  /// @return amountIn The amount of DAI actually spent in the swap.
  function swapExactOutputSingle(uint256 amountOut, uint256 amountInMaximum) external returns (uint256 amountIn) {
      // Transfer the specified amount of DAI to this contract.
      TransferHelper.safeTransferFrom(DAI, msg.sender, address(this), amountInMaximum);

      // Approve the router to spend the specifed `amountInMaximum` of DAI.
      // In production, you should choose the maximum amount to spend based on oracles or other data sources to achieve a better swap.
      TransferHelper.safeApprove(DAI, address(swapRouter), amountInMaximum);

      ISwapRouter.ExactOutputSingleParams memory params =
          ISwapRouter.ExactOutputSingleParams({
              tokenIn: DAI,
              tokenOut: WETH9,
              fee: poolFee,
              recipient: msg.sender,
              deadline: block.timestamp,
              amountOut: amountOut,
              amountInMaximum: amountInMaximum,
              sqrtPriceLimitX96: 0
          });

      // Executes the swap returning the amountIn needed to spend to receive the desired amountOut.
      amountIn = swapRouter.exactOutputSingle(params);

      // For exact output swaps, the amountInMaximum may not have all been spent.
      // If the actual amount spent (amountIn) is less than the specified maximum amount, we must refund the msg.sender and approve the swapRouter to spend 0.
      if (amountIn < amountInMaximum) {
          TransferHelper.safeApprove(DAI, address(swapRouter), 0);
          TransferHelper.safeTransfer(DAI, msg.sender, amountInMaximum - amountIn);
      }
  }
}

还学会了编辑我的部署程序以添加构造函数的参数,并确保从此处传递 SwapRouter 地址:

await deploy("YourContract", {
    // Learn more about args here: https://www.npmjs.com/package/hardhat-deploy#deploymentsdeploy
    from: deployer,
    args: [ '0xE592427A0AEce92De3Edee1F18E0157C05861564' ],
    log: true,
    waitConfirmations: 5,
  });

这一切都奏效了,我可以在我的本地脚手架-eth 上的调试控制台中看到这一点,在 rinkeby 上运行:

在此处输入图像描述

我还确保我的钱包中有足够的资金用于加油等:

在此处输入图像描述

当我尝试在 swapExactInputSingle 函数中为任意数量的 DAI 发送时,每次都会收到以下错误:

{
   "reason":"cannot estimate gas; transaction may fail or may require manual gas limit",
   "code":"UNPREDICTABLE_GAS_LIMIT",
   "error":{
      "code":-32000,
      "message":"execution reverted"
   },
   "method":"estimateGas",
   "transaction":{
      "from":"0xF59FBfd44C9e495542D46109F81416bd3fC38Ed7",
      "to":"0xcFc57b48365133105F6877a02126673B7b906a55",
      "data":"0x73bd43ad000000000000000000000000000000000000000000000000000000000000000a",
      "accessList":null
   }
}

我一点击发送就收到此错误,并且从未提示我批准我的 DAI 或其他任何内容。其他简单的合约也有效,我能够在 Rinkeby 上正确发送交易,所以假设这是由于使用 Uniswap API 等增加了复杂性。

任何想法表示赞赏!

4

1 回答 1

0

I'm having the same issue, the recipient it is not msg.sender, it should be address(this), also you have to take care of the functions TransferHelper, who is going to receive, who is going to send

于 2022-03-01T02:14:35.460 回答