Ethereum 即使所有者也无法调用实现“public onlyOwner”的Solidity函数

Ethereum 即使所有者也无法调用实现“public onlyOwner”的Solidity函数,ethereum,solidity,ether,Ethereum,Solidity,Ether,我将按照以下文档进行操作:。并有一个智能合同的形式: pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; co

我将按照以下文档进行操作:。并有一个智能合同的形式:

pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

  contract NFTA is ERC721, Ownable {

     using Counters for Counters.Counter;
     Counters.Counter public _tokenIds;
     mapping (uint256 => string) public _tokenURIs;
     mapping(string => uint8) public hashes;

     constructor() public ERC721("NFTA", "NFT") {}

     function mintNFT(address recipient, string memory tokenURI)
          public onlyOwner
          returns (uint256)
      {
          _tokenIds.increment();

          uint256 newItemId = _tokenIds.current();
          _mint(recipient, newItemId);
          _setTokenURI(newItemId, tokenURI);

          return newItemId;
     }

     /**
      * @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
      *
      * Requirements:
      *
      * - `tokenId` must exist.
      */
     function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
        require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
        _tokenURIs[tokenId] = _tokenURI;
     }    

  }
当我试图用以下方法估算
造币的天然气成本时:

    const MY_PUBLIC_KEY  = '..'
    const MY_PRIVATE_KEY = '..'

    const ALCHEMY = {
        http: '',
        websocket:'',
    }

    const { createAlchemyWeb3 } = require("@alch/alchemy-web3");
    const web3 = createAlchemyWeb3(ALCHEMY.http);

    const NFTA = require("../artifacts/contracts/OpenSea.sol/NFTA.json");
    const address_a   = '0x...';
    const nft_A = new web3.eth.Contract(NFTA.abi, address_a);


    async function mint({ tokenURI, run }){

        const nonce = await web3.eth.getTransactionCount(MY_PUBLIC_KEY, 'latest'); 
        const fn  = nft_A.methods.mintNFT(MY_PUBLIC_KEY, '')

        console.log( 'fn: ', fn.estimateGas() )
    }

    mint({ tokenURI: '', run: true })
我收到错误消息:

(node:29262) UnhandledPromiseRejectionWarning: Error: Returned error: execution reverted: Ownable: caller is not the owner
大概是因为
mintNFT
public only所有者
。但是,当我检查Etherscan时,
From
字段与
MY\u PUBLIC\u KEY
相同,我不确定从
MY\u PUBLIC\u KEY
还可以做些什么来签署交易。解决此问题的简单方法是从
函数mintNFT
中删除
onlyOwner
,然后一切按预期运行。但是,假设我们只想保留
所有者
,那么在上面已经写过的内容之外,我如何签署交易

注意,我正在使用
hardHat
编译合同并部署它们。即: npx安全帽编译 npx hardhat运行脚本/deploy.js

=============================================

附录

炼金术给出的部署铸币厂的确切代码是:

async function mintNFT(tokenURI) {
  const nonce = await web3.eth.getTransactionCount(PUBLIC_KEY, 'latest'); //get latest nonce

  //the transaction
  const tx = {
    'from': PUBLIC_KEY,
    'to': contractAddress,
    'nonce': nonce,
    'gas': 500000,
    'data': nftContract.methods.mintNFT(PUBLIC_KEY, tokenURI).encodeABI()
  };
注意:在事务处理中,来自
字段是
公钥
,与部署合同的
公钥
相同,在这种情况下,
nftContract
指定了
仅公开所有者
。这正是我所做的。那么从概念上讲,谁拥有这个NFT代码呢?在etherscan上,它是
地址(合同地址),还是
地址,这是我的公钥,部署合同的地址,以及调用mint的地址,现在调用方失败,这不是所有者错误

搜索互联网,我发现其他人在这里遇到了这个问题:,对于
Truffle
,您可以使用额外字段指定调用者:

 await nft.transferFrom(accounts[0], accounts[1], 1, { from: accounts[1] })
额外的参数在这里不是一个选项,因为我使用的是hardhat。

OpenZeppelin将默认的
owner
值定义为合同部署者。您可以稍后通过调用
transferOwnership()
对其进行更改,或通过调用
renoconownership()
放弃所有者(即设置为
0x0

如果事务不是由当前
所有者发送的,则
onlyOwner
修饰符将还原该事务()

因此,您需要从部署契约的同一地址调用
mintNFT()
函数,因为这是当前的
所有者。或者,您可以通过调用
transferOwnership()
(从当前
所有者
地址)首先更改
所有者


mintNFT()
函数中删除
onlyOwner
修饰符将允许任何人调用该函数。

我终于找到了答案,契约不会初始化我部署它的方式。因此,您必须在部署后对其进行初始化。

我猜当您调用
方法时,您需要通过测试帐户发件人地址。mintNFT
@mikkoohtama我该怎么做?测试帐户发件人地址是否与我的metamask钱包公钥相同?这是一个问题,我只有一个公钥,这不应该是部署合同的地址吗?@xiaolingxiao(1/2)从您的屏幕截图中,我可以看到合同是通过地址
0xd2590…
,部署的,有效地使此地址成为
所有者
。执行
mintNFT()
函数的这个地址。(2/2)您的
MY\u PUBLIC\u KEY
的值似乎不是
0xd2590…
-它会恢复发送,只有
所有者才能执行它。还要注意
MY_PUBLIC_KEY
的值,它可能与第二个代码片段中的
PUBLIC_KEY
不同。但我无法验证它,因为你的问题没有显示值。“我删除了唯一的所有者”,我没有注意到-我的坏。。。但是现在,我没有主意了。希望有人能够更好地帮助您。他们必须使用与
所有者
公钥配对的私钥对事务进行签名。