繁体   English   中英

IUniswapV2Router02.swapExactTokensForTokens 在智能合约中失败

[英]IUniswapV2Router02.swapExactTokensForTokens fails inside smart contract

我正在尝试通过 uniswap 路由器合约将 weth 令牌交换为 dai 令牌(均为 ERC20):

我尝试了以下两种方法:

1. 使用 truffle 控制台操作 we/dai/router 合约 这种方法工作正常。 请参阅下面的详细信息:

// Dai.sol
pragma solidity ^0.6.6;


contract Dai {
    function balanceOf(address owner) external view returns(uint) {}
    function totalSupply() external view returns (uint256){}
    function transfer(address recipient, uint256 amount) external returns (bool){}
    function allowance(address owner, address spender) external view returns (uint256){}
    function approve(address spender, uint256 amount) external returns (bool){}
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool){}
}
// Weth.sol
pragma solidity ^0.6.6;

contract Weth {
    function deposit() public payable {}
    function approve(address spender, uint amount) external {}
    function allowance(address owner, address spender) external view returns(uint) {}
    function balanceOf(address owner) external view returns(uint) {}
    function transfer(address recipient, uint256 amount) external returns (bool){}
}
// Router.sol

pragma solidity ^0.6.6;

contract Router {
    function swapExactTokensForTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts){}
    function getAmountsOut(uint amountIn, address[] memory path) public view returns (uint[] memory amounts){}
    function getAmountsIn(uint amountOut, address[] memory path)public view virtual returns (uint[] memory amounts) {}
}

松露控制台上有分步命令行:

truffle(kovan)> dai = await Dai.at("0x4f96fe3b7a6cf9725f59d353f723c1bdb64ca6aa")
truffle(kovan)> weth = await Weth.at("0xd0a1e359811322d97991e03f863a0c30c2cf029c")
truffle(kovan)> router =await Router.at("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D")

truffle(kovan)> amountIn = await router.getAmountsIn(web3.utils.toWei("1"), [weth.address, dai.address])
truffle(kovan)> amountIn = amountIn[0]
truffle(kovan)> amountOut = web3.utils.toWei("1")
truffle(kovan)> weth.approve(router.address, amountIn)
truffle(kovan)> time = Math.floor((Date.now()/1000)) + 60*120
truffle(kovan)> router.swapExactTokensForTokens(amountIn, amountOut, [weth.address, dai.address], accounts[0], time)

在这种情况下,swapExactTokensForTokens的交易已经成功完成( https://kovan.etherscan.io/tx/0x11e51ad94d90ec9b2182768bcea87ad5a15d5cf83a91a02d52f2990cbaed5c61

  1. 从 uniswapv2 导入 IUniswapV2Router02.sol 并在我的合同中操作 router.swapExactTokensForTokens。
// SwapToken.sol
pragma solidity ^0.6.6;

import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@uniswap/v2-core/contracts/interfaces/IERC20.sol";

contract SwapTokens {
    
    IUniswapV2Router02 public uniRouter = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
    
    event test (uint timestamp, uint amountIn, uint amountOut, address[] path, uint allowance, address sender);
    
    function swapper(address token1, address token2) public  {
        address[] memory path = new address[](2);
        path[0] = token1;
        path[1] = token2;
        uint amountOut = 1 ether;
        uint amountIn = uniRouter.getAmountsIn(
            amountOut,
            path
        )[0];
                
        IERC20(token1).approve(address(uniRouter), amountIn);
        
        uint allowed = IERC20(token1).allowance(msg.sender, address(uniRouter));        
        
        emit test(now+90, amountIn, amountOut, path, allowed, msg.sender);

        uniRouter.swapExactTokensForTokens(
            amountIn, 
            amountOut,
            path, 
            msg.sender, 
            now + 120
        );
    }
}

然后我运行交换器 function 如下:

sw = await SwapTokens.deployed()
sw.swapper(weth.address, dai.address)

并且交易失败并出现错误'TransferHelper:TRANSFER_FROM_FAILED'( https://kovan.etherscan.io/tx/0x3324fd65004e001163b665b79583f894e17854bc33071b89b46d

这两种方法对我来说似乎都是一样的。 我不知道我做错了哪一部分。

在我看来,您发送的 swapExactTokensForTokens 的“amountOutMin”似乎高于“amountIn”,这是不可能的。

见上面swapExactTokensForTokens的function原型:

function swapExactTokensForTokens(
 uint amountIn,
  uint amountOutMin,
  address[] calldata path,
  address to,
  uint deadline
) external returns (uint[] memory amounts);

由于滑点,amountOutMin 必须小于 amountIn。 你可以在这里找到一个例子:

JS脚本:

  const amountIn = web3.utils.toWei("1");
  const amountsOut = await uniswapv2router.getAmountsOut(amountIn, [WETH, SDT]);         
  const amountOutMin = amountsOut[1].mul(web3.utils.toBN(100 - SLIPPAGE_MAX)).div(web3.utils.toBN(100));
  const txSwap = await swapRouter.swapTokens([WETH, SDT], amountIn, amountOutMin, account);

合同:

IUniswapV2Router(UNISWAP_V2_ROUTER).swapExactTokensForTokens(_amountIn, _amountOutMin, path, _to, block.timestamp);

您应该在调用交换器 function 之前批准您的合约的代币,并且需要将代币从 msg.sender 转移到您的合约。

uniRouter.swapExactTokensForTokens(
        amountIn, 
        amountOut,
        path, 
        msg.sender, 
        now + 120
    );

此代码不会将令牌从 msg.sender 带到路由器。 这意味着通过 uniRouter 交换合约中的令牌并将结果令牌发送到 msg.sender。

暂无
暂无

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

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