I'm extending OpenZeppelins ERC20 to create a Token that I use for testing in another smart contract. Here's how it looks:

//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract TestERC20Token is ERC20 {
    constructor(uint256 initialSupply) ERC20("Test Coin", "TEST") {
        _mint(msg.sender, initialSupply * (10 ** 18));

And here's how I'm using it another contract:

function deposit(uint256 amount)
        checkTokenBalance(msg.sender, amount)
        if (!_isClosedForDeposit()) {
            _token.transferFrom(msg.sender, address(this), amount);
            deposits[msg.sender] += amount;
            totalDeposits += amount;
        } else {
            revert DepositPeriodExpired("Depost period has expired");

The _token is instantiated in the constructor:

IERC20 private _token;
constructor(address token, uint256 duration) {
        owner = msg.sender;
        deployedAt = block.timestamp;
        _token = IERC20(token);

So I pass the address of the token contract when deploying the contract I'm using the token in.

But, when I run this js test code using hardhat:

    await deployTokenContract();

    await deployOtherContract(5);

    const amount = utils.parseUnits("5", 18);
    const token = await initTokenContract(accounts.one.privateKey);
    const approveTx = await token.approve(contractAddress, amount);
    const res = await approveTx.wait(1);
    const allowance = await token.allowance(accounts.one.address, contractAddress);

    const otherContract = await initOtherContract(accounts.one.privateKey);
    const depositTx = await otherContract.deposit(amount, {
        gasLimit: 25000
    await depositTx.wait(1);

I get the following error:

 Error: Transaction reverted: function selector was not recognized and there's no fallback function
    at TestERC20Token.<unrecognized-selector> (contracts/TestERC20Token.sol:6)

It seems to me that when transferFrom is called in my other contract, that this function is not found in TestERC20Token contract, but it should be inherited from ERC20. Not sure why it fails

  • Can you show your IERC20 interface code?
    – helias
    Commented May 6, 2022 at 11:41
  • IERC20 is also from openzeppelin, i just import it: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; Commented May 6, 2022 at 12:03
  • That's the reason. SafeERC20.sol does not have a function transferFrom. Instead, it uses safeTransferFrom. That's why the selector was not recognized. P.S. selector is formed by a keccak('functionName(argtype0, argtype1, ...').
    – helias
    Commented May 6, 2022 at 12:08

1 Answer 1


So in the two deployContract functions I was attaching hardcoded addresses to contract instance, like:

const Contract = await ethers.getContractFactory("TestERC20Token");
const contract = await Contract.deploy(initialMintAmount);
await contract.deployed();

After removing this and getting the addresses after deployment, the above issue disappeared

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.