繁体   English   中英

在scaffold-eth上实施Uniswap v3 API单交换示例-错误:无法估计气体

[英]Implementing Uniswap v3 API single swap example on scaffold-eth - ERROR: cannot estimate gas

使用scaffold-eth来实现uniswap 文档中的这个单一交换示例。

几乎只是复制并粘贴了代码,并且能够成功地将其部署到 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 function 中发送任意数量的 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 等增加了复杂性。

收件人不是 msg.sender,应该是 address(this)。 您还必须处理 TransferHelper 功能,谁将接收,谁将发送。

尝试将您的配置设置为如下所示。 我相信您遇到的问题是由metamask不正确地估计气体引起的

networks: {
  hardhat: {
   
   forking: {
      url: `https://eth-mainnet.alchemyapi.io/v2/YOUR_KEY_HERE`,
      // url: `https://mainnet.infura.io/v3/${process.env.INFURA_KEY}`,
      // url: 'http://localhost:8545',
    },
    gasPrice: 0,
    initialBaseFeePerGas: 0,

  }

DAI、WETH9、USDC 的代币地址属于以太坊主网,您已将其部署在 Rinkeby 上。 您必须使用 Rinkeby 的代币合约地址。

不确定是否存在任何其他问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM