Erc20 transferFrom

Hi im using an instance of a pool contract where you can call the function "addliquidity" from. But when i call the "addliquidity" function which has a transferfrom, i get "ERC20: insufficient allowance", even though i have approved the contract with the token amount from the owner before calling it. Maybe its not possible to approve a child contract?

Contract A "Dex" ->

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "./Pool.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract DexV3 {
    Pool public  pool;

    event poolAddress (address indexed _pooladdress);
    event userAddress (address indexed _useraddress);

    event userNumber (uint256 indexed _userNumber);

    event userMessage (string indexed _message);
    mapping (uint256 => Pool) public PoolMapping;
    uint256 public counter;

    function createPool(address liquidityToken, address tokenA) public payable {
        pool = new Pool(liquidityToken, tokenA);
        PoolMapping[counter] = pool;
        emit poolAddress(address(pool));
        counter += 1;
    }
    
    function _addLiquidity(uint256 _pool, uint256 _amount) public payable  {
        pool =  Pool(address(PoolMapping[_pool]));
        // tokenA.transferFrom(msg.sender, address(this), _amount);
        emit userAddress(address(pool));
        pool.addLiquidity(_amount, msg.sender);
        // pool.addLiquidity(_amount).send({from: msg.sender});
    }

    function _removeLiquidity(uint256 _pool, uint256 _amount) public payable{
        pool = PoolMapping[_pool];
        pool.removeLiquidity(_amount);
    }
}

Contract B "Pool" ->

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "./LiquidityToken.sol";

contract Pool is IERC20, LiquidityToken {
    LiquidityToken public lpToken;
    address public lpTokenAddress;
    address public erc20TokenAddress;
    mapping(address => uint256) WethMapping;
    event tokenSwap(address indexed token, address indexed swapper, string indexed swap);
    event liquidityPool( uint256 indexed amount, address indexed provider);
    event liquidityWidthdraw( uint256 indexed _amount, address indexed _to);
    event addressBalance(address indexed token, uint256 indexed _amount, address indexed _address);
    event balanceCall( uint256 indexed _amount);
    event userInPoolAddress(address indexed _caller);

    constructor(address _lpToken, address _erc20TokenAddress) {
        require(_lpToken != address(0));
        lpTokenAddress = _lpToken;
        erc20TokenAddress = _erc20TokenAddress;
    }

    function getReserve() public payable returns(uint256) {
        uint256 balaceGet = IERC20(erc20TokenAddress).balanceOf(address(this));
        emit balanceCall(balaceGet);
        return balaceGet;
    }

     function getEthReserve() public payable returns(uint256) {
        uint256 balaceGet = address(this).balance;
        emit balanceCall(balaceGet);
        return address(this).balance;
    }
 
    function addLiquidity (uint _amount, address _sender) public payable{
        uint256 daiReserve = getReserve();
        uint256 ethReserve = address(this).balance;
        emit userInPoolAddress(msg.sender);
        if(daiReserve == 0){
            IERC20(erc20TokenAddress).transferFrom(_sender, address(this), _amount);
            _mint(_sender, ethReserve);
            emit liquidityPool( _amount, _sender);
        }else{
        uint256 _ethReserve = address(this).balance - msg.value;
        uint256 acceptedLiquidityAmount = (_amount * daiReserve) / (_ethReserve);
        require(_amount >= acceptedLiquidityAmount, "not accepted liquidity less then the minimum amount accepted");
        IERC20(erc20TokenAddress).transferFrom(msg.sender, address(this), acceptedLiquidityAmount);

        uint256 mintokens = (IERC20(erc20TokenAddress).totalSupply() * msg.value) / (_ethReserve);
        _mint(msg.sender, mintokens);
        emit liquidityPool( _amount, msg.sender);
        }
    }
 
    
}


Can you share the approve tx please
Did you approve the Pool contract or Dex?

It looks like you are calling the addLiquidity function of the Pool contract from the DexV3 contract. In order for this to work, the msg.sender (the DexV3 contract in this case) must have approved the Pool contract to transfer tokens on its behalf.

To do this, you can use the approve function of the ERC20 token contract, which grants an allowance to another contract to transfer a certain amount of tokens on your behalf. This must be done before calling the addLiquidity function, like this:

// Before calling addLiquidity, call approve on the ERC20 token contract to grant the
// Pool contract an allowance to transfer tokens on your behalf
IERC20(erc20TokenAddress).approve(address(pool), _amount, {from: msg.sender});

After calling approve, you can then call the addLiquidity function on the Pool contract and it should succeed.

It is also important to note that in your addLiquidity function, you are calling transferFrom on the ERC20 token contract without checking the allowance first. You should check the allowance using the allowance function before calling transferFrom to ensure that the caller has the required allowance.

function addLiquidity (uint _amount, address _sender) public payable {
    // Check the allowance first using the allowance function
    require(IERC20(erc20TokenAddress).allowance(_sender, address(this)) >= _amount, "Insufficient allowance");

    // Now call transferFrom
    IERC20(erc20TokenAddress).transferFrom(_sender, address(this), _amount);
    // Rest of the function...
}

I hope this helps! Let me know if you have any other questions.

1 Like

Yeah i approved the pool contract via hardhat i got the issue " Transaction reverted: function call to a non-contract account" but when i tried in remix with ganache node it worked!