1

I'm struggling with taxing upon swapping a token back for ETH. I can't figure out what I'm doing wrong here. I'm using Hardhat testnet forking Goerli to work with the Uniswap contracts. Also made quite excessive use of Hardhats Console Log functionality to figure out what's wrong. But I don't.

So, upon a transfer, I check if it's a sell of token for ETH. Here is the full console log. I replaced the addresses with Caps values for better readability.

BTW I use swapExactTokensForETHSupportingFeeOnTransferTokens in my Test script

    Transfer from: ADDRESS_1 to: UNISWAP_PAIR amount: 10000000000000000000000000
    Message sender: UNISWAP_ROUTER
    **************************************************
    SELL
    **************************************************
    Amount: 10000000000000000000000000
    Tax Share: 2000000000000000000000000, Sell Fee is: 20%
    Transfer Amount remaining: 8000000000000000000000000
    Current CONTRACT_ADDRESS Balance 66595677821594337933353168

So now the swap function is called. Here is it's solidity code:

  function swapTokensForEth(uint256 tokenAmount) private {
    console.log("Swap and Pay Taxes %s", tokenAmount);

    address[] memory path = new address[](2);
    path[0] = address(this);
    path[1] = uniswapV2Router.WETH();

    _approve(address(this), address(uniswapV2Router), tokenAmount);
    console.log(
      "Approved %s to spend %s of %s",
      address(uniswapV2Router),
      tokenAmount,
      address(this)
    );

    console.log("**** SWAPPING START ****");

    uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
      tokenAmount,
      0,
      path,
      address(this),
      block.timestamp
    );

    console.log("**** SWAPPING END ****");
  }

And here is the console log. You see that after the SWAPPING START, the transfer function of the contract is called again.

    Swap and pay taxes with 2000000000000000000000000
    Approved UNISWAP_ROUTER to spend 2000000000000000000000000 of CONTRACT_ADDRESS
    **** SWAPPING START ****
    Transfer from: CONTRACT_ADDRESS to: UNISWAP_ROUTER amount: 2000000000000000000000000
    Message sender: UNISWAP_ROUTER
    CONTRACT_ADDRESS Balance 66595677821594337933353168
    SUPER Transfer from CONTRACT_ADDRESS to UNISWAP_PAIR share of 2000000000000000000000000 Token
    CONTRACT_ADDRESS Balance 64595677821594337933353168
    
    Error: VM Exception while processing transaction: reverted with reason string 'TransferHelper: TRANSFER_FROM_FAILED'
      at <UnrecognizedContract>.<unknown> (UNISWAP_ROUTER)  

But it fails at within the swap. As you can see, it never comes back to the Swap Method, as it's not consoling out the "SWAPPING_END"

EDIT HERE IS THE SOLUTION IF SOMEONE IS EVER STRUGGLING WITH THE SAME
My contract was simply missing the ability to receive ETH. I needed to declare a receive function:

receive() external payable {}

Make sure you also create withdrawals though :-)

1 Answer 1

1

Just a glampse for you of how it should work:


    function swapTokensForEth(uint256 tokenAmount) private {
    console.log("Swap and Pay Taxes %s", tokenAmount);

    uint fee = tokenAmount * (20 / 1000);
    uint taxedAmount = tokenAmount - fee;
    address[] memory path = new address[](2);
    path[0] = address(this);
    path[1] = uniswapV2Router.WETH();

    _approve(address(this), address(uniswapV2Router), tokenAmount);
    console.log(
      "Approved %s to spend %s of %s",
      address(uniswapV2Router),
      taxedAmount,
      address(this)
    );

    console.log("**** SWAPPING START ****");

    uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
      taxedAmount,
      0,
      path,
      address(this),
      block.timestamp
    );

    token.transfer(projectWallet, fee);

    console.log("**** SWAPPING END ****");
  }
}

Don't remember if this: uint fee = tokenAmount * (20 / 1000); will work.

Another issue, TransferHelper: TRANSFER_FROM_FAILED is an error for allowance. You are not transfering the tokens from the user to the contract so insteed of address(this) try msg.sender as the first param of _approve.

By the way, inmo this should be IERC20(tokenAddress).approve(address(uniswapV2Router), tokenAmount).

1
  • Thanks, your answer was a useful help. But the issues was something else: For anybody who is ever struggling with the same: Make sure your contract is able to receive ETH if you want to use it as a receiver of a swap to ETH function :-) All my contract was missing was this line receive() external payable {} Mar 7 at 22:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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