2

我正在创建一个 NFT 市场。当我在 Mumbai-testnet 上部署我的合约时。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"

控制台的图像

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

区块链浏览器链接

4

3 回答 3

2

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

解决方案=>

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

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

参考

这是一个解决方法部署脚本,可以让它在孟买工作。将 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.

于 2022-01-21T01:19:55.453 回答
1

我检查了你的完整代码,它正在工作。

您继承自ERC721URIStoragewhich 继承自ERC721如果您检查transferFrom内部ERC721

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);
    }

你得到那个错误,因为require里面的陈述transferFrom不满意。

这是_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));
    }

这个函数没有返回True。为了得到True,这个

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

应该返回 True。在or操作中为了获得 True,必须有 3 个条件True

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

于 2022-01-20T01:40:07.123 回答
1

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

于 2022-01-21T01:11:16.413 回答