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
不同。但我无法验证它,因为你的问题没有显示值。“我删除了唯一的所有者”,我没有注意到-我的坏。。。但是现在,我没有主意了。希望有人能够更好地帮助您。他们必须使用与所有者
公钥配对的私钥对事务进行签名。