2

i have a problem with swapExactETHForTokens(). It seems to fail everytime I change the input value to something else than Zero.

To help you to follow the path of de DATA, I show you :

  • swapExactETHForTokens() from the pancakeswap contract

     function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
          external
          virtual
          override
          payable
          ensure(deadline)
          returns (uint[] memory amounts)
      {
          require(path[0] == WETH, 'PancakeRouter: INVALID_PATH');
          amounts = PancakeLibrary.getAmountsOut(factory, msg.value, path);
          require(amounts[amounts.length - 1] >= amountOutMin, 'PancakeRouter: INSUFFICIENT_OUTPUT_AMOUNT');
          IWETH(WETH).deposit{value: amounts[0]}();
          assert(IWETH(WETH).transfer(PancakeLibrary.pairFor(factory, path[0], path[1]), amounts[0]));
          _swap(amounts, path, to);
    
  • getAmountsOut() from the same contract. That is used inside the first one.

     function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) {
     require(path.length >= 2, 'PancakeLibrary: INVALID_PATH');
     amounts = new uint[](path.length);
     amounts[0] = amountIn;
     for (uint i; i < path.length - 1; i++) {
         (uint reserveIn, uint reserveOut) = getReserves(factory, path[i], path[i + 1]);
         amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut);
     }
    
  • and getAmoutOut() called from the end of getAmountsOut():

      function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) {
      require(amountIn > 0, 'PancakeLibrary: INSUFFICIENT_INPUT_AMOUNT');
      require(reserveIn > 0 && reserveOut > 0, 'PancakeLibrary: INSUFFICIENT_LIQUIDITY');
      uint amountInWithFee = amountIn.mul(9975);
      uint numerator = amountInWithFee.mul(reserveOut);
      uint denominator = reserveIn.mul(10000).add(amountInWithFee);
      amountOut = numerator / denominator;
    

My problem and the progression, with different configurations :

1. With {value:msg.value}, {value:0} or no value.

IUniswapV2Router02(PANCAKE_ROUTER).swapExactETHForTokens(0,path,address(this),deadline)
IUniswapV2Router02(PANCAKE_ROUTER).swapExactETHForTokens{value:msg.value}(0,path,address(this),deadline)
IUniswapV2Router02(PANCAKE_ROUTER).swapExactETHForTokens{value:0}(0,path,address(this),deadline)
  • In all of these cases, I get the error message 'INSUFFICIENT_INPUT_AMOUNT'.

This message comes from getAmoutOut(), called by getAmountsOut(), called by swapExactETHForTokens(), because my input amount is not > 0. So the data seems to be well recognized.

2. With non zero value ex:{value:1000000000000000000}

IUniswapV2Router02(PANCAKE_ROUTER).swapExactETHForTokens{value:1000000000000000000}(0,path,address(this),deadline)
  • I get the error 'Error: Transaction reverted: function call failed to execute'. So it shows that the function stops somewhere.

To go forward, I have changed the path[0] = WBNB_contract to path[0] = Cake_contract. So it should display the error :'PancakeRouter: INVALID_PATH'.

3. With Non zero value, with path[0]=CAKE (instead of WBNB)

IUniswapV2Router02(PANCAKE_ROUTER).swapExactETHForTokens{value:1000000000000000000}(0,path,address(this),deadline)
  • Gives me again 'Error: Transaction reverted: function call failed to execute' for both of them. So the data doesn't seem to go inside the function.

4. With no value and path[0]=CAKE (instead of WBNB)

IUniswapV2Router02(PANCAKE_ROUTER).swapExactETHForTokens(0,path,address(this),deadline)
IUniswapV2Router02(PANCAKE_ROUTER).swapExactETHForTokens{value:0}(0,path,address(this),deadline)
IUniswapV2Router02(PANCAKE_ROUTER).swapExactETHForTokens{value:msg.value}(0,path,address(this),deadline)
  • But without a value, i get the error 'PancakeRouter: INVALID_PATH'. So the error is from the first line of the function swapExactETHForTokens().

It appears that with a non zero value, the data doesn't penetrate inside the function. i am using hardhat, and am on pragma 0.6.6. Am I doing something wrong? I have lost all my hairs after two days of research.

this is my function, called from pancakeCall():

function placeTrade(address _fromToken,address _toToken,uint256 _amountIn) payable public returns (uint256) {
    address pair = IUniswapV2Factory(PANCAKE_FACTORY).getPair(_fromToken,_toToken); 
    require(pair != address(0), "Pool does not exist (for trade)");

    // Calculate Amount Out
    address[] memory path = new address[](2);
    path[0] = _fromToken;
    path[1] = _toToken;

  
    uint256 amountRequired = IUniswapV2Router02(PANCAKE_ROUTER).getAmountsOut(_amountIn, path)[1];

    // Perform Arbitrage - Swap for another token
    uint256 amountReceived ;
    console.log('- fromToken:',path[0], "toToken:",path[1]);
    if (_fromToken == WBNB) {
         console.log('- BNB / token');

        TransferHelper.safeApprove(_fromToken, address(PANCAKE_ROUTER),_amountIn);
        amountReceived = IUniswapV2Router02(PANCAKE_ROUTER).swapExactETHForTokens{value:msg.value}(0,path,address(this),deadline)[1];

The startTrade() function is called from the pancakeswap call, right after i asked for a flashswap with the swap() function from pancakeswap. This is my pancakeCall()function

    function pancakeCall(address _sender,uint256 _amount0,uint256 _amount1,bytes calldata _data) external {


    address token0 = IUniswapV2Pair(msg.sender).token0();
    address token1 = IUniswapV2Pair(msg.sender).token1();
    address pair = IUniswapV2Factory(PANCAKE_FACTORY).getPair(token0,token1);

    require(msg.sender == pair, "The sender needs to match the pair");
    require(_sender == address(this), "Sender should match this contract");

    (address starterToken, address tokenLink1, address tokenLink2,  uint256 amount, address myAddress) = abi.decode(_data,(address, address, address, uint256, address));


    uint256 fee = ((amount * 3) / 997) + 1;
    uint256 amountToRepay = amount + fee;

    uint256 loanAmount = _amount0 > 0 ? _amount0 : _amount1;

    uint256 trade1AcquiredCoin = placeTrade(starterToken, tokenLink1, loanAmount);//with starterToken =WBNB

1 Answer 1

1

How are you calling the function? In the case where you're using value:msg.value, are you actually sending any ETH (well, BNB in your case) when calling your function? And when you're using value: 100..., Does your contract have the funds for that already?

5
  • I am calling this function from inside the pancakeCall() function, returned by pancakeswap, (I called this function placeTrade()). (I have edited my code, with the process in the end, maybe you could throw an eye?). My account is funded with bnb, i Approved the swap with safeApprove, but I just have the Bnb from the flashloan on my contract. I did not send BNB except with the swapExactETHForTokens, I thought it was enough, maybe I am doing wrong?
    – david
    Sep 20 at 1:23
  • the approve part isnt useful, you can remove it (BNB on the BSC, (and ETH on ethereum, Matic on polygon etc.., i mean the token you're paying gas with) works differently than other ERC20 tokens, and it doesnt have an approval mechanism). Apart from that your placeTrade() function looks fine to me. How are you calling it, if it's through code, can you share the code that calls it? And if it's manually through remix or bscscan can you tell me exactly what you're doing?
    – Foxxxey
    Sep 20 at 10:29
  • Thanks for the Approve(), I will remove it now. this is how i proceed : I deploy this smartcontract on the hardhat local fork, and it interacts with it from javascript : My smartcontract borrows BNB with a flashswap that works fine, then pancakeswap calls my pancakeCall() function (The pancakeCall() function is edited in my post now), with my data in bytes within. And finally my pancakeCall() function execute my placeTrade function.
    – david
    Sep 20 at 11:42
  • Well pancakeCall isnt sending any value to your contract, so msg.value is 0 here. You'd need to hardcode the amount you want to swap, i guess. Or pass it as a param
    – Foxxxey
    Sep 20 at 11:44
  • Do you have an exemple of how to do that? for the while, when I am using {value:_amount} or whatever value, my contract returns this error 'Error: Transaction reverted: function call failed to execute'
    – david
    Sep 20 at 11:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.