I want to call a contract method like this:

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";
import "@openzeppelin/contracts/utils/Strings.sol";

contract MyNFT is ERC721URIStorage {

  // ... 

  modifier onlyRoot(address message_sender){
    emit SenderAddress(message_sender);
    string memory message = string.concat("caller",  Strings.toHexString(uint160(message_sender), 20) , " is not the contract root.");
    require(rootAddress == message_sender, message);

  function mint(address to, string calldata _uri) public onlyRoot(msg.sender) {
     // ... 

when I call the mint method from server ( nodejs using web3 ) , it always gives me error caller 0x00000000000000000000000000000 is not the contract root.

the nodejs code is shown as below: ( the private key belongs the root address )

const Web3 = require('web3')
const fs = require('fs')
async function main(){

  const myArgs = process.argv.slice(2);
  let rpc_server = myArgs[0]
  let contract_address = myArgs[1]
  let abi_file = myArgs[2]
  let abi = JSON.parse(fs.readFileSync(abi_file))
  let to = myArgs[3]
  let uri = myArgs[4]
  let private_key = 'c218dd579b86393d4351c2d301b99aa8ee14678247a94e64????????????????'

  const web3 = new Web3(new Web3.providers.HttpProvider(rpc_server))

  const signer = web3.eth.accounts.privateKeyToAccount(private_key)

  const contract = new web3.eth.Contract(abi, contract_address)

  let tx = contract.methods.mint(to, uri)
  tx.send({ from: signer.address, gas: await tx.estimateGas() })
    .once("transactionHash" , (txHash) => {
      console.info("mining transaction...", txHash)

  console.info("mined in block: ", result.blockNumber)
  • network: fuji

so my question is : how to get correct msg.sender ?

thanks a lot!

2 Answers 2


try like something like this

function mint(address to, string calldata _uri) public onlyRoot {
     // ... 

  modifier onlyRoot{
    emit SenderAddress(msg.sender);
    string memory message = string.concat("caller ",  Strings.toHexString(uint160(msg.sender), 20) , " is not the contract root.");
    require(rootAddress == msg.sender, message);

passing a global variable (msg.sender) into a modifier isn't necessary and would cost more gas even if you got it working.

Error messages tend to be very terse in solidity because doing things with strings is expensive. It's a good exercise, but generally you'd just use a message like not "not root" or "not authorised". Maybe one day gas will be cheap enough that we don't care


OK, I found the solution 2 months later.

use ether.js instead of web3.js, which has bugs or I used it incorrectly.

this is a script:

const { ethers } = require("ethers");
const fs = require('fs')

async function run(){

  let rpc_server = 'https://api.avax-test.network/ext/bc/C/rpc'
  let private_key = 'my private key....'
  let abi_file = './abis/template_9.abi'
  const provider = new ethers.providers.JsonRpcProvider(rpc_server, 43113);
  let signer = new ethers.Wallet(private_key, provider)

  let abi = JSON.parse(fs.readFileSync(abi_file))

  let contract_address = '0x092989875157af55fdaa7776a3f0818a78480269'
  let my_contract = new ethers.Contract(contract_address, abi, signer)

  let symbol = await my_contract.name()
  console.info("-- symbol: ", symbol)

  console.info("-- before mint: ")
  let result = await my_contract.mint('0x0b23E3588c906C3F723C58Ef4d6baEe7????', 2)
  console.info("-- after mint: ", result)



refer to: How to call a contract function/method using ethersjs

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.