I'm trying to send an amount of ERC20 on Contract deploy to the contract itself. I'm using Hardhat and OpenZeppelin Contracts. Contract Code:

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

import "hardhat/console.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

contract Test {
    address private owner;
    IERC20 private _token;

        IERC20 token,
        uint256 tokenAmount
    ) {
        owner = msg.sender;
        _token = token;
        uint ownerBalance = _token.balanceOf(owner);
        console.log("Amount available: ", ownerBalance);
        console.log("Amount to transfer: ", tokenAmount);
        bool success = _token.approve(owner, tokenAmount);
        console.log("Is approved: ", success);
        uint allowance = _token.allowance(owner, address(this));
        console.log("Allowance: ", allowance);
        _token.transferFrom(owner, address(this), tokenAmount);

Deployment script:

const hre = require("hardhat");
const { utils } = require("ethers");

async function main() {
  const tokenAddr = "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6"; // Contract address of deployed erc20
  const tokenAmount = "100";
  const Test = await hre.ethers.getContractFactory("Test");
  const test = await Test.deploy(
    utils.parseUnits(tokenAmount, 18)

  await test.deployed();

  console.log("Contract deployed to:", test.address);

  .then(() => process.exit(0))
  .catch((error) => {

Deployment fails with:

ProviderError: Error: VM Exception while processing transaction: reverted with reason string 'ERC20: insufficient allowance'

But from the logs you can see that approve was successful:

    Amount available:  10000000000000000000000
    Amount to transfer:  100000000000000000000
    Is approved:  true
    Allowance:  0

Something's missing. I have no idea what

2 Answers 2


You cannot use transferFrom function into constructor. The reason is this function uses approve + transfer for move tokens (in this case) from your account to smart contract. approve() function requires two fields:

  • spender: address of those who'll spent your tokens;
  • amount: how many tokens the 'spender' can spend.

For first parameter, you must to put the address about your smart contract and if you did not deploy it you cannot know its address! For this reason (in this case) you cannot call transferFrom() into smart contract constructor.

If you want to resolve this problem, you can implement a function that inside it you call transferFrom() function. For example, you can see this smart contract code:

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

import "hardhat/console.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

contract Test {
    address private owner;
    IERC20 private token;

    constructor(address _tokenAddress) {
        // NOTE: You pass the address about token to send to smart contract 
        token = IERC20(_tokenAddress);

    // NOTE: Remember to call before 'approve()' function and then this function
    function transferMyTokenToThisSmartContract(uint _amount) public {
        token.transferFrom(msg.sender, address(this), _amount);
bool success = _token.approve(owner, tokenAmount);

You are actually telling the contract to allow "owner" to spend the Contract's tokens.

While with:

_token.transferFrom(owner, address(this), tokenAmount);

You are trying to transfer tokens from "owner" to the contract, which is the other way around.

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.