I'm building an ERC20 token using OpenZeppelin's ERC20 base contract.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;

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

contract MyToken is ERC20, Ownable {
    constructor() ERC20("MyToken", "MTK") {
        _mint(msg.sender, 20 * 10 ** decimals());

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

And I deploy it using this code in nodejs:

async deployContract(account: Account, compiled: any): Promise<TransactionReceipt> {
    const contract = new this.web3.eth.Contract(compiled.contracts["contract.sol"]["MyToken"].abi);
    return contract.deploy({ data: "0x" + compiled.contracts["contract.sol"]["MyToken"].evm.bytecode.object });
    const signed = await account.signTransaction({
        from: account.address,
        data: contract.encodeABI(),
        gas: Math.floor((await contract.estimateGas()) * 1.1),
        gasPrice: await this.web3.eth.getGasPrice(),

    return this.web3.eth.sendSignedTransaction(signed.rawTransaction);

But the execution breaks at the account.signTransaction method giving the following error:

Error: Returned error: execution reverted: ERC20: mint to the zero address
    at Object.ErrorResponse (/***/node_modules/web3-core-helpers/lib/errors.js:28:19)
    at /***/node_modules/web3-core-requestmanager/lib/index.js:302:36
    at XMLHttpRequest.request.onreadystatechange (/***/node_modules/web3-providers-http/lib/index.js:98:13)

I guess msg.sender has the zero address, but I don't understand what I am doing wrong. Thanks!

  • It is missing to field in signTransaction.
    – Ismael
    Commented Sep 23, 2021 at 6:05

1 Answer 1


This can be a REALLY frustrating problem.

In my case, I was using Infura, so I thought of course the addr couldn't be zero.

What I realized is that for some reason msg.sender wasn't coming out the way it was supposed to.

Here's what I ended up doing in my contract; I passed an owner to the contract and used that as my initial _mint.

That is what solved this for me. I hope this saves someone from wasting 5 hours on this like I did.

  address public OWNER;

    string memory name,
    string memory symbol,
    uint256 initialSupply,
    address payable owner
  ) payable ERC20(name, symbol) {
    OWNER = owner;
    _mint(OWNER, initialSupply);
  • Wish you had mentioned how to pass this owner while deploying because when I tried, it didn't work
    – Neel Kamal
    Commented Apr 2 at 15:13

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.