Polygon 区块链上 MetaMask 的内部 JSON-RPC 错误。 `ERC721:转移呼叫者不是所有者,也不是批准的。`

Internal JSON-RPC error with MetaMask on Polygon Blockchain. `ERC721: transfer caller is not owner nor approved.`

我正在做一个 NFT 市场。当我在孟买测试网上部署我的合同时。 createToken 函数可能会工作,因为它会为 Gas Fee 调出 Metamask,但在那之后,会发生关于 ONWNERSHIP 的错误。 (下方有错误图片和文字。)

我遵循的步骤

  1. npm hardhat node
  2. npm run dev
  3. 选择创建页面。
  4. 输入所有详细信息。
  5. 单击调用 createToken 函数的创建资产。

然后出现错误。

这是我的 NFT 合约

contract NFT is ERC721URIStorage {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
address contractAddress;

constructor(address marketplaceAddress) ERC721("Metaverse Tokens", "METT") {
    contractAddress = marketplaceAddress;
}

function createToken(string memory tokenURI) public returns (uint256) {
    _tokenIds.increment();
    uint256 newItemId = _tokenIds.current();

    _mint(msg.sender, newItemId);
    _setTokenURI(newItemId, tokenURI);
    setApprovalForAll(contractAddress, true);

    return newItemId;
}}

这是我的 NFTMarket 合约

contract NFTMarket is ReentrancyGuard {
using Counters for Counters.Counter;

Counters.Counter private _itemIds;
Counters.Counter private _itemSold;

address payable owner;
uint256 listingPrice = 0.025 ether; // Here ether is denoting the MATIC

constructor() {
    owner = payable(msg.sender);
}

struct MarketItem {
    uint256 itemId;
    address nftContract;
    uint256 tokenId;
    address payable seller;
    address payable owner;
    uint256 price;
    bool sold;
}

mapping(uint256 => MarketItem) private idToMarketItem;

event MarketItemCreated(
    uint256 indexed itemId,
    address indexed nftContract,
    uint256 indexed tokenId,
    address seller,
    address owner,
    uint256 price,
    bool sold
);

function getListingPrice() public view returns (uint256) {
    return listingPrice;
}

//Function to create an NFT
function createMarketItem(
    address nftContract,
    uint256 tokenId,
    uint256 price
) public payable nonReentrant {
    //Conditions for creating the Item.
    require(price > 0, "Price must be at least 1 wei");
    require(
        msg.value == listingPrice,
        "Price must be equal to listing price"
    );

    _itemIds.increment();
    uint256 itemId = _itemIds.current();

    idToMarketItem[itemId] = MarketItem(
        itemId,
        nftContract,
        tokenId,
        payable(msg.sender),
        payable(address(0)), // When new NFT is created its ownership add is set to 0.
        price,
        false
    );

    IERC721(nftContract).transferFrom(msg.sender, address(this), tokenId);

    //Trigger the Event
    emit MarketItemCreated(
        itemId,
        nftContract,
        tokenId,
        msg.sender,
        address(0),
        price,
        false
    );
}

//Function to Transfer the Ownership
function createMarketSale(address nftContract, uint256 itemId)
    public
    payable
    nonReentrant
{
    uint256 price = idToMarketItem[itemId].price;
    uint256 tokenId = idToMarketItem[itemId].tokenId;

    require(
        msg.value == price,
        "Please submit the asking value in order to Purchase"
    );

    //Will transfer the MATIC to the seller address.
    idToMarketItem[itemId].seller.transfer(msg.value);

    //Will transfer the ownership from the owner of this contract to the Buyer.
    IERC721(nftContract).transferFrom(address(this), msg.sender, tokenId);

    //Set the local value of the owner to the Buyer(msg.sender).
    idToMarketItem[itemId].owner = payable(msg.sender);

    //Set this NFT as sold.
    idToMarketItem[itemId].sold = true;
    _itemSold.increment();

    payable(owner).transfer(listingPrice);
}

//Returns number of items unsold
function fetchMarketItems() public view returns (MarketItem[] memory) {
    uint256 itemCount = _itemIds.current();
    uint256 unsoldItemCount = _itemIds.current() - _itemSold.current();
    uint256 currentIndex = 0;

    MarketItem[] memory items = new MarketItem[](unsoldItemCount);

    for (uint256 i = 0; i < itemCount; i++) {
        if (idToMarketItem[i + 1].owner == address(0)) {
            uint256 currentId = idToMarketItem[i + 1].itemId;
            MarketItem storage currentItem = idToMarketItem[currentId];
            items[currentIndex] = currentItem;
            currentIndex += 1;
        }
    }
    return items;
}

//Returns number of Own(Created or Bought) NFTs
function fetchMyNFTs() public view returns (MarketItem[] memory) {
    uint256 totalItemCount = _itemIds.current();
    uint256 itemCount = 0;
    uint256 currentIndex = 0;

    for (uint256 i = 0; i < totalItemCount; i++) {
        if (idToMarketItem[i + 1].owner == msg.sender) {
            itemCount += 1;
        }
    }

    MarketItem[] memory items = new MarketItem[](itemCount);
    for (uint256 i = 0; i < totalItemCount; i++) {
        if (idToMarketItem[i + 1].owner == msg.sender) {
            uint256 currentId = idToMarketItem[i + 1].itemId;
            MarketItem storage currentItem = idToMarketItem[currentId];
            items[currentIndex] = currentItem;
            currentIndex += 1;
        }
    }
    return items;
}

//Returns the no of NFT created
function fetchItemsCreated() public view returns (MarketItem[] memory) {
    uint256 totalItemCount = _itemIds.current();
    uint256 itemCount = 0;
    uint256 currentIndex = 0;

    for (uint256 i = 0; i < totalItemCount; i++) {
        if (idToMarketItem[i + 1].seller == msg.sender) {
            itemCount += 1;
        }
    }

    MarketItem[] memory items = new MarketItem[](itemCount);
    for (uint256 i = 0; i < totalItemCount; i++) {
        if (idToMarketItem[i + 1].seller == msg.sender) {
            uint256 currentId = idToMarketItem[i + 1].itemId;
            MarketItem storage currentItem = idToMarketItem[currentId];
            items[currentIndex] = currentItem;
            currentIndex += 1;
        }
    }
    return items;
}}

我尝试更改 MetaMask 中的 RPC 和配置文件,并使用不同的帐户重新部署它多次,但仍然没有任何变化。

错误

 MetaMask - RPC Error: Internal JSON-RPC error. 
data:
code: 3
message: "execution reverted: ERC721: transfer caller is not owner nor approved"

Image of the console

如果需要任何其他信息,请评论

Link of Blockchain Explorer

我检查了你的完整代码,它正在运行。

您继承自 ERC721URIStorage,而 ERC721URIStorage 继承自 ERC721 如果您检查 ERC721 中的 transferFrom

function transferFrom(address from,address to,uint256 tokenId
        ) public virtual override {
        // *****  THIS REQUIRE IS NOT SATISFIED *****
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
        _transfer(from, to, tokenId);
    }

您收到该错误,因为 transferFrom 中的 require 语句不满足。

这是_isApprovedOrOwner

 function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
        address owner = ERC721.ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    }

此功能未 returning True。为了得到True,这个

spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender) 

应该return正确。在 or 操作中为了得到 True,条件 3 必须是 True.

在我看来,您正在尝试转移不属于您的代币。

在开发过程中,每次编译智能合约(使用hardhat compile..之类的东西)时,都必须复制在命令提示符中生成的新智能合约地址,并将其粘贴到源代码中的指定位置代码。

感谢您的努力。 我得到了解决方案(搜索了 3 天后)。

解决方案=>

孟买目前存在导致部署地址不正确的错误。这导致 NFT 合约的构造函数批准 错误的地址 用于 NFT 购买(因为它使用市场部署的地址进行批准) — 导致烦人的 "execution reverted: ERC721: approve caller is not owner nor approved for all" 错误。

尝试使用主网(是的,你必须使用真钱)但它有效!

Reference

这是一个可以在孟买运行的解决方法部署脚本。将 deploy.js 中的 main() 替换为:

const hre = require("hardhat");

async function main() {
  const [deployer] = await hre.ethers.getSigners();

  console.log(
    "Deploying contracts with the account:",
    deployer.address
  );

  let txHash, txReceipt
  const NFTMarket = await hre.ethers.getContractFactory("NFTMarket");
  const nftMarket = await NFTMarket.deploy();
  await nftMarket.deployed();

  txHash = nftMarket.deployTransaction.hash;
  txReceipt = await ethers.provider.waitForTransaction(txHash);
  let nftMarketAddress = txReceipt.contractAddress

  console.log("nftMarket deployed to:", nftMarketAddress);

  const NFT = await hre.ethers.getContractFactory("NFT");
  const nft = await NFT.deploy(nftMarketAddress);
  await nft.deployed();


  txHash = nft.deployTransaction.hash;
  // console.log(`NFT hash: ${txHash}\nWaiting for transaction to be mined...`);
  txReceipt = await ethers.provider.waitForTransaction(txHash);
  let nftAddress = txReceipt.contractAddress

  console.log("nft deployed to:", nftAddress);
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

使用此脚本重新部署合同,并更改config.js