user19820596
user19820596

Reputation: 1

SwapExactTokensForTokensSupportingFeeOnTransferTokens gives error in smart contract

I would like to call SwapExactTokensForTokensSupportingFeeOnTransferTokens in my contract to swap tokens with a transfer fee, however, the transaction reverts with an error. I have enough balance in the contract when calling the function.

The transaction that failed, which I called from the contract: https://dashboard.tenderly.co/tx/bsc/0xe44eba37baba3705376163d94f5d1051ac7ae9b2017ab9e403bad22f6a4c0577

When I perform the following (similar) transaction on the exchange, it works as expected: https://dashboard.tenderly.co/tx/bsc/0x5ab848527c12e76c6316859bab14a454a329aeade8046418f5dd542bcf1bd691/

With the debugging mode of Tenderly, I determined that the two transactions are similar except for the fact that the transaction in the contract had one additional approval call. Also when I submitted the transaction, a gas estimation error popped up in Remix.

Below is the code snippet of my contract. The other function, SwapExactTokensForTokens, is working in the contract call as expected. In the contract, SwapFeeOnExternal and SwapExternal are called to interact with the PancakeSwap Router.

pragma solidity >=0.8.14;

interface IERC20 {
    function totalSupply() external view returns (uint);

    function balanceOf(address account) external view returns (uint);

    function transfer(address recipient, uint amount) external returns (bool);

    function allowance(address owner, address spender) external view returns (uint);

    function approve(address spender, uint amount) external returns (bool);

    function transferFrom(address sender, address recipient, uint amount) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint value);
    event Approval(address indexed owner, address indexed spender, uint value);
}

interface IUniswapV2Router {
    function getAmountsOut(uint256 amountIn, address[] memory path) external view returns (uint256[] memory amounts);

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

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline) external returns (uint256[] memory amounts);
}


contract SwapTradeExecution {
    address owner;

    constructor(){
        // Set the owner to the account that deployes the contract
        owner = msg.sender;
    }

    modifier onlyOwner() {
        // Only owner can execute some functions
        require(msg.sender == owner, "Only the owner is allowed to execute");
        _;
    }

    function swapFeeOn(address router, address _tokenIn, address _tokenOut, uint256 _amount) internal {
        // Single swap function for uniswap v2 swap.
        IERC20(_tokenIn).approve(router, _amount);
        address[] memory path;
        path = new address[](2);
        path[0] = _tokenIn;
        path[1] = _tokenOut;
        uint deadline = block.timestamp + 300;
        IUniswapV2Router(router).swapExactTokensForTokensSupportingFeeOnTransferTokens(_amount, 0, path, address(this), deadline);
    }

    function swapExternal(address router, address _tokenIn, address _tokenOut, uint256 _amount, uint256 minAmount) external onlyOwner {
        // Single swap function for uniswap v2 swap.
        IERC20(_tokenIn).approve(router, _amount);
        address[] memory path;
        path = new address[](2);
        path[0] = _tokenIn;
        path[1] = _tokenOut;
        uint deadline = block.timestamp + 300;
        IUniswapV2Router(router).swapExactTokensForTokens(_amount, minAmount, path, address(this), deadline);
    }


    function swapFeeOnExternal(address router, address _tokenIn, address _tokenOut, uint256 _amount,uint256 minAmount) external onlyOwner {
        // Single swap function for uniswap v2 swap.
        IERC20(_tokenIn).approve(router, _amount);
        address[] memory path;
        path = new address[](2);
        path[0] = _tokenIn;
        path[1] = _tokenOut;
        uint deadline = block.timestamp + 300;
        IUniswapV2Router(router).swapExactTokensForTokensSupportingFeeOnTransferTokens(_amount, minAmount, path, address(this), deadline);
    }

    function tokenBalance(address token) public view returns (uint256) {
        IERC20 token = IERC20(token);
        return token.balanceOf(address(this));
    }

    function withdrawFunds(address token) external onlyOwner {
        IERC20 token = IERC20(token);
        uint balance = token.balanceOf(address(this));
        require(balance > 0, "No avaliable fund to withdraw");
        token.transfer(msg.sender, balance);
    }
}

Upvotes: 0

Views: 3017

Answers (1)

Prodog Hard
Prodog Hard

Reputation: 11

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

replace to

function swapExactTokensForTokensSupportingFeeOnTransferTokens(uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline) external;

Upvotes: 1

Related Questions