I created an contract , source code is:

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

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract MyTestNft is ERC721URIStorage {
    uint256 private _tokensCount = 0;
    address public minter = address(0);

    event LogMint(address to, uint256 tokenId, uint256 tokensCount, address minter, address sender);

    modifier onlyMinter(){
            minter == msg.sender,
            'Invalid Minter: ...'

    constructor() ERC721("MyTestNft", "MTN") {
        minter = msg.sender;

    function mint(address to) external onlyMinter {
        uint256 tokenId = _tokensCount + 1;
        _mint(to, tokenId);
        _tokensCount = tokenId;
        emit LogMint(to, tokenId, _tokensCount, minter, msg.sender);


when published this contract via remix, and call the mint method, everything is fine.

However, if I call this contract's mint method via javascript web3.js, EVM always complaints that Invalid Minter ( minter == msg.sender )

my call.js looks like:

const Web3 = require('web3')
const fs = require('fs')

async function main(file_name_without_suffix, contract_address){
  const { abi } = JSON.parse(fs.readFileSync("build/contracts/" +file_name_without_suffix+'.json'))
  const network = process.env.ETHEREUM_NETWORK

  // step1. 初始化web3 实例,增加json rpc server
  const web3 = new Web3(
    new Web3.providers.HttpProvider(

  // step2. 创建signer
  const signer = web3.eth.accounts.privateKeyToAccount(  process.env.SIGNER_PRIVATE_KEY)

  // step3. 创建contract, abi是关键
  const contract = new web3.eth.Contract( abi, contract_address)

  let result = ''
  result = await contract.methods.minter().call()
  console.info("minter: ", result)
  result = await contract.methods.name().call()
  console.info("name: ", result)
  result = await contract.methods.symbol().call()
  console.info("symbol: ", result)

  console.info("--- signer:", signer)

  let tx = ''
  tx = await contract.methods.mint('0xc0dD5021e298dB57bEF361C735cd1C04cef2E48A')
  let from = signer.address
  // let from = (await web3.eth.getAccounts())[0]
  console.info("== now let's mine one: ,from: ", from)
  result = await tx
    .send({from: from, gas: await tx.estimateGas()})
    .once("transactionHash" , (txHash) => {
      console.info("mining transaction...", txHash)
    .on('error', (error) => {
      console.info("--- on error: ", error)
  console.info("mint result: ", result)



main(process.argv[2], process.argv[3]).then( () => process.exit(0) )

I deploy this contract to: https://goerli.etherscan.io/address/0x81ec27587694f9996a69dc26230643dd619cfaba

and when I run this script by node call.js MyTestNft 0x494B51eA8c1a6e9994274141977186c809c68fb5

it always shows the error:

minter:  0xc0dD5021e298dB57bEF361C735cd1C04cef2E48A
name:  MyTestNft
symbol:  MTN
--- signer: {
  address: '0xc0dD5021e298dB57bEF361C735cd1C04cef2E48A',
  privateKey: '0xa7d856cf836a71422df6a76837e1c67022aba9bda349b0a9e85a496cb321????',
  signTransaction: [Function: signTransaction],
  sign: [Function: sign],
  encrypt: [Function: encrypt]
== now let's mine one: ,from:  0xc0dD5021e298dB57bEF361C735cd1C04cef2E48A
        var err = new Error('Returned error: ' + message);

Error: Returned error: execution reverted: Invalid Minter: ...
    at Object.ErrorResponse (/mnt/d/workspace/test_erc_721_in_truffle/node_modules/web3-core-helpers/lib/errors.js:28:19)
    at /mnt/d/workspace/test_erc_721_in_truffle/node_modules/web3-core-requestmanager/lib/index.js:300:36
    at XMLHttpRequest.request.onreadystatechange (/mnt/d/workspace/test_erc_721_in_truffle/node_modules/web3-providers-http/lib/index.js:98:13)
    at XMLHttpRequestEventTarget.dispatchEvent (/mnt/d/workspace/test_erc_721_in_truffle/node_modules/xhr2-cookies/dist/xml-http-request-event-target.js:34:22)
    at XMLHttpRequest._setReadyState (/mnt/d/workspace/test_erc_721_in_truffle/node_modules/xhr2-cookies/dist/xml-http-request.js:208:14)
    at XMLHttpRequest._onHttpResponseEnd (/mnt/d/workspace/test_erc_721_in_truffle/node_modules/xhr2-cookies/dist/xml-http-request.js:318:14)
    at IncomingMessage.<anonymous> (/mnt/d/workspace/test_erc_721_in_truffle/node_modules/xhr2-cookies/dist/xml-http-request.js:289:61)
    at IncomingMessage.emit (node:events:539:35)
    at endReadableNT (node:internal/streams/readable:1345:12)
    at processTicksAndRejections (node:internal/process/task_queues:83:21) {
  data: '0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000013496e76616c6964204d696e7465723a202e2e2e00000000000000000000000000'

so, any ideas? thank you so much!

p.s. If I remove the modifier at the function declaration, e.g.

    function mint(address to) external {
        uint256 tokenId = _tokensCount + 1;
        _mint(to, tokenId);
        _tokensCount = tokenId;
        emit LogMint(to, tokenId, _tokensCount, minter, msg.sender);

everything looks fine! and it would give the event log, showed the minter is the same as msg.sender. e.g. ( https://goerli.etherscan.io/tx/0x4db740f0b927ffa17e50003d59487670b173b075f8c57f840d81c038b8e68511#eventlog )

enter image description here

updated 1:

I found it OK under truffle's local node, not OK in goerli + infura.

updated 2:

I found it OK under local ganache. I am thinking if goerli has bug.


2 Answers 2


OK, finally, 2 months later, I found solution: don't use web3.js, use ethers instead.

It's a bug for web3.js.


I think this is a bug or maybe the network connection problems for goerli network.

I tested the same code on truffle's local node, also on ganache, both of them are running ok.


The correct answer to the question is that the error is generated by the estimateGas function and not the send function.

Based on the documentation, you need to pass the from address await tx.estimateGas({from: '0x.....'}) which makes sense as this info is not known yet to estimate the gas.

You can easily tested (for sanity reasons) by adding a fixed gas value instead of using the estimateGas function.

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.