Solidity

uniswap solidity 合約:swapExactTokensForTokens 在我自己的智能合約中失敗

  • May 5, 2021

我正在使用 sushiswap 將 weth 轉移到 dai。當我使用 web3.js 呼叫swapExactTokensForTokens目錄時,一切都很好。但是,當我嘗試將其包含swapExactTokensForTokens在 IUniswapV2Router02.sol 中時,出現了問題。這是我在 Remix 上執行的程式碼:

pragma solidity ^0.6.6;

import "https://github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/interfaces/IUniswapV2Router02.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/docs-v3.x/contracts/token/ERC20/IERC20.sol";

contract Arbitrage {
   
   IUniswapV2Router02 public sushiRouter = IUniswapV2Router02(0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506);
   
   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 = sushiRouter.getAmountsIn(
           amountOut,
           path
       )[0];
       
       
       
       IERC20(token1).approve(address(sushiRouter), amountIn);
       
       uint allowed = IERC20(token1).allowance(msg.sender, address(sushiRouter));
       
       emit test(now+90, amountIn, amountOut, path, allowed, msg.sender);

       sushiRouter.swapExactTokensForTokens(
           amountIn, 
           amountOut,
           path, 
           msg.sender, 
           now + 60
       );
   }
}

Remix 上顯示的錯誤消息是:

Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
The execution failed due to an exception. Reverted

混音中的錯誤

我還使用 truffle + ganache-cli(從主網分叉)。松露控制台上顯示的錯誤是:

Uncaught:
Error: Returned error: VM Exception while processing transaction: revert TransferHelper: TRANSFER_FROM_FAILED -- Reason given: TransferHelper: TRANSFER_FROM_FAILED.

松露錯誤

我相信“ sushiRouter.swapExactTokensForTokens()”內部出現問題,因為一旦我將其註釋掉,程式碼就會通過並成功發出事件。

如果有人可以讓我知道我在哪一部分搞砸了,將不勝感激。

—— 下面的一些更多資訊 —–

刪除交換部分後,如下所示:

...
contract Arbitrage {
   
   IUniswapV2Router02 public sushiRouter = IUniswapV2Router02(0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506);
   
   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 = sushiRouter.getAmountsIn(
           amountOut,
           path
       )[0];
       
       IERC20(token1).approve(address(sushiRouter), amountIn);
       IERC20(token2).approve(address(sushiRouter), amountOut);
       
       uint allowed = IERC20(token1).allowance(msg.sender, address(sushiRouter));
       
       
       emit test(now+90, amountIn, amountOut, path, allowed, msg.sender);
   }
}

該交易通過以下 tx 詳細資訊進行:

發送詳細資訊

—- 4/21 更新 —-

當我試圖在我的 ganache 分叉主網上研究錯誤時,我可能已經找到了一些線索。

Google表示“TRANSFER_FROM_FAILED”的原因是 sushiswap 路由器合約沒有足夠的配額來轉移令牌。所以我再次檢查“測試事件”中的津貼欄位。令人驚訝的是,即使我已經批准,它實際上是“0”。

在此處輸入圖像描述

為什麼??下面這行程式碼不生效??我錯過了什麼嗎?

IERC20(token1).approve(address(sushiRouter), amountIn);

除此之外,即使我使用 truffle 控制台手動批准 100 weth,交換仍然失敗:

truffle(development)> weth.approve(srouter.address, web3.utils.toWei("1000"))
truffle(development)> allowed = await weth.allowance(accounts[0], srouter.address)
truffle(development)> allowed.toString()
'1000000000000000000000'
truffle(development)> tx = await sw.swapper(weth.address, dai.address)
Uncaught:
Error: Returned error: VM Exception while processing transaction: revert TransferHelper: TRANSFER_FROM_FAILED -- Reason given: TransferHelper: TRANSFER_FROM_FAILED.

我很確定我的環境設置不應該是一個問題,因為我手動執行類似的過程有問題:

下面的過程:

  1. 通過 ganache-cli 分叉主網
ganache-cli --fork https://mainnet.infura.io/v3/<projectID> --unlock 0x47ac0fb4f2d84898e4d9e7b4dab3c24507a6d503 -p 7545
  1. 松露控制台和遷移
  2. 在 truffle 控制台上實現 swaptoken 沒有任何問題
truffle(development)> dai = await Dai.at("0x6b175474e89094c44da98b954eedeac495271d0f")
truffle(development)> weth = await Weth.at("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")
truffle(development)> sw = await SwapTokens.deployed()

truffle(development)> srouter =await Router.at("0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F")

truffle(development)> web3.eth.sendTransaction({from:accounts[0], to: "0x47ac0fb4f2d84898e4d9e7b4dab3c24507a6d503", value:web3.utils.toWei("20")})
truffle(development)> dai.transfer(accounts[0], web3.utils.toWei("5000"), {from: "0x47ac0fb4f2d84898e4d9e7b4dab3c24507a6d503"}
truffle(development)> weth.deposit({from:accounts[0], value:web3.utils.toWei("50")})
truffle(development)> amountIn = await srouter.getAmountsIn(web3.utils.toWei("1"), [weth.address, dai.address])
truffle(development)> amountIn = amountIn[0]
truffle(development)> weth.approve(srouter.address, amountIn)
truffle(development)> amountOut = web3.utils.toWei("1")
truffle(development)> time = Math.floor((Date.now()/1000)) + 60*300
srouter.swapExactTokensForTokens(amountIn, amountOut, [weth.address, dai.address], accounts[0], time)

一切正常,沒有問題。

但是當我在智能合約中呼叫它時它會失敗嗎?

請幫忙,我在這里卡了這麼久@@

IERC20(token1).approve(address(sushiRouter), amountIn);
IERC20(token2).approve(address(sushiRouter), amountOut);

基本上,當您approve從契約內部呼叫時,approve方法內部msg.sender就是您的契約。所以替換uint allowed = IERC20(token1).allowance(msg.sender, address(sushiRouter));uint allowed = IERC20(token1).allowance(address(this), address(sushiRouter));,你應該看到津貼並檢查你的合約是否有你想要交換的代幣餘額,或者你需要給你的合約支付津貼。

引用自:https://ethereum.stackexchange.com/questions/97570