Web3js Contract Deployment – Mint _msgSender() on Contract Deployment in Web3js

contract-deploymentweb3js

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
        .deploy({
            data: bytecode,
            arguments: args
        })
        .encodeABI();

        var txData = {
            data: deployData
        }

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

    });
}

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!

Best Answer

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.