I'm starting up with solidity and I'm deploying my smart contracts using web3 with the following function:

    deployContract(args) {
    var web3 = <MY-WEB3-PROVIDER>;
    var privateKey = <MY-PRIVATE-KEY>;

    return new Promise(function (resolve, reject) {

        const file = fs.readFileSync('./contracts/Dummy.json').toString();
        var output = JSON.parse(file);
        var ABI = output.abi;
        var bytecode = output.bytecode;
        const contract = new web3.eth.Contract(ABI);

        var deployData = contract
            data: bytecode,
            arguments: args

        var txData = {
            data: deployData

        var estimatedGas = contract
            data: bytecode,
            arguments: args
        .then(function(gas) {
            txData.gas = web3.utils.toHex(3000000);
            web3.eth.accounts.signTransaction(txData, privateKey)
            .then((signed) => {
                .on("receipt", (receipt) => {


It works well so far until I'm trying to deploy an ERC20 token contract which is supposed to mint the initial supply of tokens to the message sender, for some reason it sees zero address as the message sender and thus the transaction fails.

This is the contract:

//SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;

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

contract GoldToken is ERC20, Ownable, Whitelist {
  string public TOKEN_NAME = "Gold Token";
  string public TOKEN_SYMBOL = "GLD";

  uint256 private constant TOTAL_SUPPLY = 50000;

  constructor()ERC20(TOKEN_NAME, TOKEN_SYMBOL) {
    _mint(_msgSender(), TOTAL_SUPPLY);

  function mint(address to, uint256 amount) public onlyOwner {
    _mint(to, amount);

Funny thing is the deployment of this contract works perfectly on Remix (either with the Remix VM or using Injected Provider to use Metamask and deploy the contract to the very same testnet I'm using from nodejs) which leds me to think I'm missing something on the deployment process

I'm almost out of ideas here, I'll appreciate if someone can give me an idea of what could be causing this or a workaround. Thanks in advance guys!

1 Answer 1


Yes, tokens are technically created out of thin air. On mainnet it is seen as coming from the zero address.

What you need to do in this case is rather add an input paramater to the constructor for example:

 constructor()ERC20(TOKEN_NAME, TOKEN_SYMBOL, address payable _initialPayWallet) {
    _mint(_initialPayWallet, TOTAL_SUPPLY);

That should work.

  • Thanks a lot man, that is in fact a viable solution and it is what I ended up doing. However I'm not quite grasping the concept of why can't you mint ERC20 tokens in constructor, see here docs.openzeppelin.com/contracts/2.x/erc20-supply
    – Chrishow
    Commented Aug 1, 2022 at 16:40
  • What happends if you use msg.sender instead of _msgSender() Commented Aug 3, 2022 at 9:22
  • Already tried it, exactly the same thing.
    – Chrishow
    Commented Aug 3, 2022 at 11:27

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.