Swap function not working while using Uniswap Router v2 contract

I am able to execute function getAmountsOut successfully
image

but when I trying to swap using TokenIn and TokenOut contract addresses deployed on Rinkeby
TokenIn: 0xa11f4607d159511ee2c3e30713f19dcbad65601f
TokenOut: 0x2F69f11adCac9713B6a311eF9285ba0f97F01e5e

image

Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
execution reverted: ERC20: transfer amount exceeds allowance { "originalError": { "code": 3, "data":

image

:1234: Code to reproduce

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

import "./Uniswap.sol";

contract TestUniswap {
    address private constant UNISWAP_V2_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
    address private constant WETH = 0x2F69f11adCac9713B6a311eF9285ba0f97F01e5e;
    function swap(
        address _tokenIn,
        address _tokenOut,
        uint _amountIn,
        uint _amountOutMin,
        address _to
    ) external {
        IERC20(_tokenIn).transferFrom(msg.sender, address(this), _amountIn);
        IERC20(_tokenIn).approve(UNISWAP_V2_ROUTER, _amountIn);

        address[] memory path;
        if (_tokenIn == WETH || _tokenOut == WETH) {
            path = new address[](2);
            path[0] = _tokenIn;
            path[1] = _tokenOut;
        } else {
            path = new address[](3);
            path[0] = _tokenIn;
            path[1] = WETH;
            path[2] = _tokenOut;
        }

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

    function getAmountOutMin(
        address _tokenIn,
        address _tokenOut,
        uint _amountIn
    ) external view returns (uint) {
        address[] memory path;
        if (_tokenIn == WETH || _tokenOut == WETH) {
            path = new address[](2);
            path[0] = _tokenIn;
            path[1] = _tokenOut;
        } else {
            path = new address[](3);
            path[0] = _tokenIn;
            path[1] = WETH;
            path[2] = _tokenOut;
        }

        // same length as path
        uint[] memory amountOutMins = IUniswapV2Router(UNISWAP_V2_ROUTER).getAmountsOut(
            _amountIn,
            path
        );

        return amountOutMins[path.length - 1];
    }
}

:computer: Environment

REMIX IDE & and RINKEBY Network

this is the problem: transfer amount exceeds allowance
you need to call approve on the token (_tokenIn) contract with the correct amount and the router address before attempting the swap

I tried with approve function with tokenIn but this giving same error as shared before.

        IERC20(_tokenIn).approve(msg.sender, _amountIn);
        IERC20(_tokenIn).transferFrom(msg.sender, address(this), _amountIn);
        IERC20(_tokenIn).approve(UNISWAP_V2_ROUTER, _amountIn);

Didn't notice the approve after the transferFrom. You also need to approve the address of your contract the same (from the msg.sender). No changes needed to the contract. just use remix to call approve before using your contract to allow it to use the tokens owned by msg.sender

I have tried with new contracts ( Token MKT and USDT ) with 100% allowance.
image

I have reproduce TestUniswap.sol smart contract code

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

import "./Uniswap.sol";

contract TestUniswap {
    address private constant UNISWAP_V2_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
    address private constant WETH = 0xe4e40D07bfCf2cb09234E23F86602bb0538F3068;
    
    function getBalance(address _tokenIn, address _address) external view returns(uint){
        uint balanceof = IERC20(_tokenIn).balanceOf(_address);
        return balanceof;
    } 
    
    function getAllowance(address _tokenIn, address _address) external view returns(uint){
        uint allowance = IERC20(_tokenIn).allowance(msg.sender,_address);
        return allowance;
    } 
    
    function swap(
        address _tokenIn,
        uint _amountIn
    ) external {
        //IERC20(_tokenIn).approve(msg.sender, _amountIn);
        IERC20(_tokenIn).approve(msg.sender, _amountIn);
        //IERC20(_tokenIn).increaseAllowance(address(this), _amountIn);
        IERC20(_tokenIn).transferFrom(msg.sender, address(this), _amountIn);
    }
    /*function swap(
        address _tokenIn,
        address _tokenOut,
        uint _amountIn,
        uint _amountOutMin,
        address _to
    ) external {
        IERC20(_tokenIn).approve(msg.sender, _amountIn);
        IERC20(_tokenIn).transferFrom(msg.sender, address(this), _amountIn);
        IERC20(_tokenIn).approve(UNISWAP_V2_ROUTER, _amountIn);

        address[] memory path;
        if (_tokenIn == WETH || _tokenOut == WETH) {
            path = new address[](2);
            path[0] = _tokenIn;
            path[1] = _tokenOut;
        } else {
            path = new address[](3);
            path[0] = _tokenIn;
            path[1] = WETH;
            path[2] = _tokenOut;
        }

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

    function getAmountOutMin(
        address _tokenIn,
        address _tokenOut,
        uint _amountIn
    ) external view returns (uint) {
        address[] memory path;
        if (_tokenIn == WETH || _tokenOut == WETH) {
            path = new address[](2);
            path[0] = _tokenIn;
            path[1] = _tokenOut;
        } else {
            path = new address[](3);
            path[0] = _tokenIn;
            path[1] = WETH;
            path[2] = _tokenOut;
        }

        // same length as path
        uint[] memory amountOutMins = IUniswapV2Router(UNISWAP_V2_ROUTER).getAmountsOut(
            _amountIn,
            path
        );

        return amountOutMins[path.length - 1];
    }
}

still facing the same error as

image

this IERC20(_tokenIn).approve(msg.sender, _amountIn); is approving the account you have used (msg.sender) to transfer tokens from the contract address. not necessary.

you need to call IERC20(_tokenIn).approve(YOUR_CONTRACT_ADDRESS, _amountIn); before. there must be a call to approve missing or with a smaller value than _ amountIn

if there is a misunderstanding on how approve/transferFrom work together. you can find an explanation here https://docs.openzeppelin.com/contracts/2.x/api/token/erc20

also which addresses are you passing to getAllowance your spender should be address(this) to check the contract allowance. are you passing the correct address (_address) when checking the allowance?

calling require(getAllowance(_tokenIn, address(this)) >= _amountIn) before the transferFrom should pass