Внедрение примера единой подкачки Uniswap v3 API на scaffold-eth — ОШИБКА: невозможно оценить газ
Использование 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 acheive 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,
});
Все это сработало, и я могу увидеть это в консоли отладки на моем локальном scaffold-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 и т. д.
Любые мысли приветствуются!
3 ответа
У меня та же проблема, получатель это не msg.sender, это должен быть адрес (этот), также вы должны позаботиться о функциях 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 относится к основной сети Ethereum, и вы развернули его на Rinkeby. Вы должны использовать адрес контракта токена Rinkeby.
Не уверен в каких-либо других проблемах, если таковые имеются.