Cloned Rinkeby test network on local and trying to add liquidity to DAI-BAT pool after creation of the pool. Here is the addLiquidity function for reference:

pragma solidity >0.7.0;

//import the ERC20 interface

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);

//import the uniswap router
//the contract needs to use swapExactTokensForTokens
//this will allow us to import swapExactTokensForTokens into our contract

interface IUniswapV2Router {
  function getAmountsOut(uint256 amountIn, address[] memory path)
    returns (uint256[] memory amounts);
  function swapExactTokensForTokens(
    //amount of tokens we are sending in
    uint256 amountIn,
    //the minimum amount of tokens we want out of the trade
    uint256 amountOutMin,
    //list of token addresses we are going to trade in.  this is necessary to calculate amounts
    address[] calldata path,
    //this is the address we are going to send the output tokens to
    address to,
    //the last time that the trade is valid for
    uint256 deadline
  ) external returns (uint256[] memory amounts);
  function factory() external pure returns (address);

function addLiquidity(
  address tokenA,
  address tokenB,
  uint amountADesired,
  uint amountBDesired,
  uint amountAMin,
  uint amountBMin,
  address to,
  uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);}

interface IUniswapV2Pair {
  function token0() external view returns (address);
  function token1() external view returns (address);
  function swap(
    uint256 amount0Out,
    uint256 amount1Out,
    address to,
    bytes calldata data
  ) external;
  function kLast() external view returns (uint);
  function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);

interface IUniswapV2Factory {
  function getPair(address token0, address token1) external returns (address);
  function createPair(address tokenA, address tokenB) external returns (address pair);

contract TokenSwap {
    address private constant UNISWAP_V2_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
    address private  UniswapFactory;
    address private UniswapPair;
      address private constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

    function setFactoryAddress() external returns(address){

        require(UNISWAP_V2_ROUTER!=address(0), "Set Router address first");
        UniswapFactory = IUniswapV2Router(UNISWAP_V2_ROUTER).factory();
        return UniswapFactory;

    function getPairAddress(address _tokenA, address _tokenB) external returns(address) {

        UniswapPair = IUniswapV2Factory(UniswapFactory).getPair(_tokenA, _tokenB);
        if(UniswapPair == address(0)) {
            UniswapPair = IUniswapV2Factory(UniswapFactory).createPair(_tokenA, _tokenB);

        return UniswapPair;
function addLiquidity(address _tokenA, address _tokenB, uint256 _amountA, uint256 _amountB) external {

        IERC20(_tokenA).transferFrom(msg.sender, address(this), _amountA);
        IERC20(_tokenB).transferFrom(msg.sender, address(this), _amountB);

        IERC20(_tokenA).approve(UNISWAP_V2_ROUTER, _amountA);
        IERC20(_tokenB).approve(UNISWAP_V2_ROUTER, _amountB);

        IUniswapV2Router(UNISWAP_V2_ROUTER).addLiquidity(_tokenA, _tokenB, _amountA, _amountB, 1, 1, address(this), block.timestamp);

But the code reverts when transferFrom() is called. Could the reason be that this contract is not approved to transfer tokens? If so then do we directly call the approve() function in ERC20 from the user wallet?

  • Can you add all your smart contract code? Apr 6, 2022 at 18:24
  • Added the necessary codes with all the state variables and other functions.
    – Rohan
    Apr 6, 2022 at 18:30
  • you need to approve using the address of your smart contract before calling transferFrom
    – Adam Boudj
    Apr 6, 2022 at 18:36
  • Yeah that was the second part of my question. How do I approve my smart contract to execute transferFrom on Rinkeby directly?
    – Rohan
    Apr 7, 2022 at 5:09

1 Answer 1


In order to work your the addLiquidity the message sender must have granted allowance to use his funds. In other words from the msg.sender address must originate this two calls:

IERC20(_tokenA).approve(address(this), _amountA);
IERC20(_tokenB).approve(address(this), _amountB);

The above two lines can't be in your smart contract, the user should make transactions to them using the _tokenA, _tokenB smart contracts.

Your Answer

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

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