Execution reverted: Ownable: caller is not the owner when trying to estimate gas

I've resumed a project I worked on 7 months ago and I've issue minting NFT on the Goerli network.
Since my old tests were on Rinkeby I had to re-publish the contract but this time I got errors I haven't got last time.

I got Error: Returned error: execution reverted: Ownable: caller is not the owner at Object.ErrorRe… … but what I don't understand is that the signer of the contract is the same that signs the NFT.

Here's my contract code (generated with openzeppelin wizard)

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

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

contract MyToken is ERC721, ERC721Enumerable, ERC721URIStorage, Ownable {
    using Counters for Counters.Counter;

    Counters.Counter private _tokenIdCounter;

    constructor() ERC721("myNFT", "myNFT") {}

    function safeMint(address to, string memory uri) public onlyOwner {
        uint256 tokenId = _tokenIdCounter.current();
        _safeMint(to, tokenId);
        _setTokenURI(tokenId, uri);

    // The following functions are overrides required by Solidity.

    function _beforeTokenTransfer(address from, address to, uint256 tokenId)
        override(ERC721, ERC721Enumerable)
        super._beforeTokenTransfer(from, to, tokenId);

    function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {

    function tokenURI(uint256 tokenId)
        override(ERC721, ERC721URIStorage)
        returns (string memory)
        return super.tokenURI(tokenId);

    function supportsInterface(bytes4 interfaceId)
        override(ERC721, ERC721Enumerable)
        returns (bool)
        return super.supportsInterface(interfaceId);

After this I've done npx hardhat compile and I got Compiled 14 Solidity files successfully

Then I deployed the contract via npx hardhat run scripts/deploy.js --network goerli

This is the deploy script I used

    const MyNFT = await ethers.getContractFactory("myNft")
    // Start deployment, returning a promise that resolves to a contract object
    const myNFT = await MyNFT.deploy()
    await myNFT.deployed()
    console.log("Contract deployed to address:", myNFT.address)
    .then(() => process.exit(0))
    .catch((error) => {

The contract has the following address on the blockchain

Contract deployed to address: 0x8FB28B7cF48534D4f1A19f47997752dc59B79b13

This is the code I use to mint the NFT (and where you see the ** is where it throws the exception)

const secretManager = require("./secretManager");
const apiUrl = process.env.API_URL;
const publicKey = process.env.PUBLIC_KEY;
const privateKey = process.env.PRIVATE_KEY;
const gasLimitOffset = process.env.GAS_LIMIT_OFFSET;
const waitTimeout = process.env.WAIT_TIMEOUT;
const { createAlchemyWeb3 } = require("@alch/alchemy-web3");
const web3 = createAlchemyWeb3(apiUrl);
const aws = require('aws-sdk');

exports.mintNFT = async (event) => {

  var contractAddress = await secretManager.handler("Blockchain_Contract_Address");
  var blockChainAddress = contractAddress.secrets.BlockChainAddress;

  try {
    console.log("BlockChainAddress", blockChainAddress);

    //  var key=  web3.eth.accounts.create();

    var balance = await web3.eth.getBalance(blockChainAddress);

    console.log("Balance", balance);

    const nonce = await web3.eth.getTransactionCount("0x294262758f44Df35e856AEb7a2dA9b3830232A12", "latest"); //get latest nonce
    console.log("nonce", nonce);
    const noncePending = await web3.eth.getTransactionCount("0x294262758f44Df35e856AEb7a2dA9b3830232A12", "pending"); //get latest nonce
    console.log("noncePending", noncePending);
    var nonceToUse = Math.max(nonce, noncePending);

    var metadataUri = event.AssetUri;
    var userToken = event.UserToken;
    var token = event.Token;

    aws.config.region = process.env.AWS_REGION;
    //make metadata

    let s3 = new aws.S3({ region: process.env.AWS_REGION });

    var params = { Bucket: process.env.BUCKET, Key: process.env.KEY };


    const fileContent = (await (s3.getObject(params).promise())).Body.toString('utf-8')

    var contract = JSON.parse(fileContent);
    var nftContract = new web3.eth.Contract(contract.abi, "0x8FB28B7cF48534D4f1A19f47997752dc59B79b13");
    var gasEstimate = await nftContract.methods.safeMint(publicKey, metadataUri).estimateGas();


    //  console.log("ci passo");
    //var g = await gasEstimate.estimateGas();
    //var gasValue = getGasValueWithOffset(gasEstimate);
 //   console.log("gasEstimate", gasEstimate);
    var contractData = nftContract.methods.safeMint(publicKey, metadataUri).encodeABI();
    //the transaction
    const tx = {
      from: publicKey,
      to: "0x294262758f44Df35e856AEb7a2dA9b3830232A12",
      nonce: nonceToUse,
      gas: 30000,
      data: contractData

    try {
      var signPromise = await web3.eth.accounts.signTransaction(tx, privateKey);

      await web3.eth.sendSignedTransaction(

      console.info("updating Token: " + token);
      await updateMintInfomation(token, signPromise.transactionHash, nonceToUse, 'IN_PROGRESS', userToken);

      await sleep(waitTimeout); //This is used to wait that the promise has been sent

      console.info("The mint function has completed. Waiting for Blockchain response");

    } catch (err) {
      throw err;
  catch (errMain) {

getGasValueWithOffset = (gasEstimate)=>
  if (gasLimitOffset == null || gasLimitOffset == 0) gasLimitOffset = 1;

  var offset = (gasEstimate / 100) * gasLimitOffset;

  return Math.round(gasEstimate + offset);

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));

getCurrentMaxNonCeFromDynamoDB = async () => {

  var docClient = new aws.DynamoDB.DocumentClient();
  var params = {
    "TableName": process.env.NFT_MINTING_TABLE_NAME,
    "IndexName": "Nonce-index",
    "ScanIndexForward": false,
    "FilterExpression": "#s = :s",
    ExpressionAttributeNames: {
      "#s": "Status"
    ExpressionAttributeValues: {
      ":s": "IN_PROGRESS"

  try {
    var res = await docClient.scan(params).promise();

    var item = res.Items[0];

    if (item == null || item.Nonce == null) return 0;

    return item.Nonce + 1;

  } catch (error) {
    return 0;

updateMintInfomation = async (token, hash, nonce, status, userToken) => {

  var docClient = new aws.DynamoDB.DocumentClient();
  try {
    //I update the main table
    var timestampUpdate = new Date().toISOString();

    var params = {
      "TableName": process.env.NFT_MINTING_TABLE_NAME,
      Key: { Token: token },
      UpdateExpression: "set #s = :status, #ts_up = :update_timestamp, #th= :transaction_hash, Nonce = :nonce",
      ExpressionAttributeValues: {
        ":status": status,
        ":update_timestamp": timestampUpdate,
        ":transaction_hash": hash,
        ":token": token,
        ":nonce": nonce
      ExpressionAttributeNames: {
        "#s": "Status",
        "#ts_up": "UpdateTimestamp",
        "#th": "TransactionHash",
        "#t": "Token"
      ConditionExpression: "#t = :token"

    await docClient.update(params).promise();
    console.info("Token " + token + "Inserted with hash " + hash + " with nonce " + nonce + "for the user" + userToken);
    //I update the mapping table
  } catch (error) {
    throw new Error("Error in dynamoDB: " + JSON.stringify(error));

Do you see any particular issue?


Are you sure you are signign the tx with the corrent address?

To be 100% console.log() the signer address and compare it to contract owner

Hello, but the estimates happens before signing the transaction, is there a way I can pass my public key?

Just console log the signer