错误:处理交易时VM异常:用理由字符串恢复' erc721:转移呼叫者不是所有者,也不批准'

发布于 2025-01-25 15:44:58 字数 14327 浏览 5 评论 0原文

我尝试编写NFT市场,并且在用户从所有者和新的第三个用户购买商品的用户转售商品有问题。 我使用next.js + openzeppelin + hardhat + infura和metamask。 创建和购买NFT是成功的,卖出eTem.js页面上的所有参数都正确。

这是我在nftmarket.sol中的功能:

function resellToken(address nftContract, uint256 tokenId, uint256 price) public payable {
      require(idToMarketItem[tokenId].owner == msg.sender, "Only item owner can perform this operation");
      require(msg.value == listingPrice, "Price must be equal to listing price");
      idToMarketItem[tokenId].sold = false;
      idToMarketItem[tokenId].price = price;
      idToMarketItem[tokenId].seller = payable(msg.sender);
      idToMarketItem[tokenId].owner = payable(address(this));
      _itemsSold.decrement();

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

这是我的网页:

import { useEffect, useState } from 'react'
import { ethers } from 'ethers'
import { useRouter } from 'next/router'
import axios from 'axios'
import Web3Modal from 'web3modal'

import {
    nftaddress, nftmarketaddress
} from '../config'

// import NFT from '../artifacts/contracts/NFT.sol/NFT.json'
import NFTMarket from '../artifacts/contracts/NFTMarket.sol/NFTMarket.json'

export default function ResellNFT() {
  const [formInput, updateFormInput] = useState({ price: '', image: '' })
  const router = useRouter()
  const { id, tokenUri } = router.query
  const { image, price } = formInput

  useEffect(() => {
    fetchNFT()
  }, [id])

  async function fetchNFT() {
    if (!tokenUri) return
    const meta = await axios.get(tokenUri)
    updateFormInput(state => ({ ...state, image: meta.data.image }))
  }

  async function listNFTForSale() {
    if (!price) return
    const web3Modal = new Web3Modal()
    const connection = await web3Modal.connect()
    const provider = new ethers.providers.Web3Provider(connection)
    const signer = provider.getSigner()

    const priceFormatted = ethers.utils.parseUnits(formInput.price, 'ether')
    const marketContract = new ethers.Contract(nftmarketaddress, NFTMarket.abi, signer)
    //const tokenContract = new ethers.Contract(nftaddress, NFT.abi, provider)
    let listingPrice = await marketContract.getListingPrice()    

    listingPrice = listingPrice.toString()
    let transaction = await marketContract.resellToken(nftaddress, id, priceFormatted, { value: listingPrice })
    await transaction.wait()
   
    router.push('/')
    
  }

  return (
    <div className="flex justify-center">
      <div className="w-1/2 flex flex-col pb-12">
        <input
          placeholder="Asset Price in Eth"
          className="mt-2 border rounded p-4"
          onChange={e => updateFormInput({ ...formInput, price: e.target.value })}
        />
        {
          image && (
            <img className="rounded mt-4" width="350" src={image} />
          )
        }
        <button onClick={listNFTForSale} className="font-bold mt-4 bg-pink-500 text-white rounded p-4 shadow-lg">
          List NFT
        </button>
      </div>
    </div>
  )
}

错误代码:

    eth_estimateGas
  Contract call:       NFTMarket#resellToken
  From:                0x1cbd3b2770909d4e10f157cabc84c7264073c9ec
  To:                  0x5fbdb2315678afecb367f032d93f642f64180aa3
  Value:               0.025 ETH

  Error: VM Exception while processing transaction: reverted with reason string 'ERC721: transfer caller is not owner nor approved'
      at NFT.transferFrom (@openzeppelin/contracts/token/ERC721/ERC721.sol:156)
      at NFTMarket.resellToken (contracts/NFTMarket.sol:89)
      at EthModule._estimateGasAction (E:\маркетплейс\polygon-ethereum\node_modules\hardhat\src\internal\hardhat-network\provider\modules\eth.ts:425:7)
      at HardhatNetworkProvider._sendWithLogging (E:\маркетплейс\polygon-ethereum\node_modules\hardhat\src\internal\hardhat-network\provider\provider.ts:139:22)
      at HardhatNetworkProvider.request (E:\маркетплейс\polygon-ethereum\node_modules\hardhat\src\internal\hardhat-network\provider\provider.ts:116:18)
      at JsonRpcHandler._handleRequest (E:\маркетплейс\polygon-ethereum\node_modules\hardhat\src\internal\hardhat-network\jsonrpc\handler.ts:188:20) 
      at JsonRpcHandler._handleSingleRequest (E:\маркетплейс\polygon-ethereum\node_modules\hardhat\src\internal\hardhat-network\jsonrpc\handler.ts:167:17)
      at Server.JsonRpcHandler.handleHttp (E:\маркетплейс\polygon-ethereum\node_modules\hardhat\src\internal\hardhat-network\jsonrpc\handler.ts:52:21)

更新: 这是我在市场上的智能合同,

// SPDX-License-Identifier: MIT
pragma solidity 0.8.2;

import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract NFTMarket is ReentrancyGuard {
  using Counters for Counters.Counter;
  Counters.Counter private _itemIds;
  Counters.Counter private _itemsSold;

  address payable owner;
  uint256 listingPrice = 0.025 ether;

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

  struct MarketItem {
    uint256 itemId;
    address nftContract;
    uint 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 createMarketItem(
    address nftContract,
    uint256 tokenId,
    uint256 price
  ) public payable nonReentrant {
    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[tokenId] = MarketItem(
      itemId,
      nftContract,
      tokenId,
      payable(msg.sender),
      payable(address(0)),
      price,
      false
    );

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

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

  function resellToken(address nftContract, uint256 tokenId, uint256 price) public payable {
      require(idToMarketItem[tokenId].owner == msg.sender, "Only item owner can perform this operation");
      require(msg.value == listingPrice, "Price must be equal to listing price");
      idToMarketItem[tokenId].sold = false;
      idToMarketItem[tokenId].price = price;
      idToMarketItem[tokenId].seller = payable(msg.sender);
      idToMarketItem[tokenId].owner = payable(address(this));
      _itemsSold.decrement();

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

  function createMarketSale(
    address nftContract,
    uint256 itemId
    ) public payable nonReentrant {
    uint price = idToMarketItem[itemId].price;
    uint tokenId = idToMarketItem[itemId].tokenId;
    require(msg.value == price, "Please sumbit the asking price in order to complete the purchase");

    idToMarketItem[itemId].seller.transfer(msg.value);
    IERC721 (nftContract).transferFrom(address(this), msg.sender, tokenId);
    idToMarketItem[itemId].owner = payable(msg.sender);
    idToMarketItem[itemId].sold = true;
    _itemsSold.increment();
    payable(owner).transfer(listingPrice);
  }

  function fetchMarketItems() public view returns (MarketItem[] memory) {
    uint ItemCount = _itemIds.current();
    uint unsoldItemCount = _itemIds.current() - _itemsSold.current();
    uint currentIndex = 0;

    MarketItem[] memory items = new MarketItem[](unsoldItemCount);
    for (uint i = 0; i < ItemCount; i++) {
      if (idToMarketItem[i + 1].owner == address(0)) {
        uint currentId = idToMarketItem[i + 1].itemId;
        MarketItem storage currentItem = idToMarketItem[currentId];
        items[currentIndex] = currentItem;
        currentIndex += 1;
      }
    }
    return items;
  }

   function fetchMyNFTs() public view returns (MarketItem[] memory) {
    uint totalItemCount = _itemIds.current();
    uint itemCount = 0;
    uint currentIndex = 0;

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

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

  function fetchItemsCreated() public view returns (MarketItem[] memory) {
    uint totalItemCount = _itemIds.current();
    uint itemCount = 0;
    uint currentIndex = 0;

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

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

这是NFC创建代码

import { useState } from 'react'
import { ethers } from 'ethers'
import { create as ipfsHttpClient } from 'ipfs-http-client'
import { useRouter } from 'next/router'
import Web3Modal from 'web3modal'
import {MPLayout} from '../../components/MPLayout'

const client = ipfsHttpClient('https://ipfs.infura.io:5001/api/v0')

import {
    nftaddress, nftmarketaddress
} from '../../config'

import NFT from '../../artifacts/contracts/NFT.sol/NFT.json'
import NFTMarket from '../../artifacts/contracts/NFTMarket.sol/NFTMarket.json'

export default function CreateItem () {
    const [fileUrl, setFileUrl] = useState(null)
    const [formInput, updateFormInput] = useState({ price: '', name: '', description: '' })
    const router = useRouter()

    async function onChange(e) {
        const file = e.target.files[0] 
        try {
            const added = await client.add(
                file,
                {
                    progress: (prog) => console.log('received: ${prog}')
                }
            )
            const url = `https://ipfs.infura.io/ipfs/${added.path}`
            setFileUrl(url)
        }   catch (e) {
            console.log(e)
        }
    }

    async function createItem() {
        const { name, description, price } = formInput
        if (!name || !description || !price || !fileUrl) return
        const data = JSON.stringify({
            name, description, image: fileUrl
        })

        try {
            const added = await client.add(data)
            const url = `https://ipfs.infura.io/ipfs/${added.path}`
            /* after file is uploaded to IPFS, return the URL to use it in the transaction */
            createSale(url)
        }   catch (error) {
            console.log('Error uploading file: ', error)
        }
    }

    async function createSale(url) {
        const web3Modal = new Web3Modal()
        const connection = await web3Modal.connect()
        const provider = new ethers.providers.Web3Provider(connection)
        const signer = provider.getSigner()

        let contract = new ethers.Contract(nftaddress, NFT.abi, signer)
        let transaction = await contract.createToken(url)
        let tx = await transaction.wait()

        let event = tx.events [0]
        let value = event.args[2]
        let tokenId = value.toNumber()

        const price = ethers.utils.parseUnits(formInput.price, 'ether')

        contract = new ethers.Contract(nftmarketaddress, NFTMarket.abi, signer)
        let listingPrice = await contract.getListingPrice()
        listingPrice = listingPrice.toString()

        transaction = await contract.createMarketItem(nftaddress, tokenId, price, { value: listingPrice})
        await transaction.wait()
        router.push('/')
    }

    return (
            <MPLayout title={'Create Item'}>
                <div className="flex justify-center">
                    <div className="w-1/2 flex flex-col pb-12">
                    <input 
                        placeholder="Asset Name"
                        className="mt-8 border rounded p-4"
                        onChange={e => updateFormInput({ ...formInput, name: e.target.value })}
                    />
                    <textarea
                        placeholder="Asset Description"
                        className="mt-2 border rounded p-4"
                        onChange={e => updateFormInput({ ...formInput, description: e.target.value })}
                        />
                        <input
                        placeholder="Asset Price in Eth"
                        className="mt-2 border rounded p-4"
                        onChange={e => updateFormInput({ ...formInput, price: e.target.value })}
                        />
                        <input
                        type="file"
                        name="Asset"
                        className="my-4"
                        onChange={onChange}
                        />
                        {
                            fileUrl && (
                                <img className="rounded mt-4" width="350" src={fileUrl} />
                            )
                        }
                        <button 
                            onClick={createItem} 
                            className="font-bold mt-4 bg-pink-500 text-white rounded p-4 shadow-lg"
                        >
                            Create Digital Asset 
                        </button>
                    </div>
                </div>
            </MPLayout>
    )
    
}

i try to write NFT marketplace and i have problem with reselling items from user that buy item from owner and new, third user.
I use next.js + openzeppelin + hardhat + infura and metamask.
Creating and buying NFT is successful, all params on sell-item.js page getting correctly.

This is my function in NFTMarket.sol:

function resellToken(address nftContract, uint256 tokenId, uint256 price) public payable {
      require(idToMarketItem[tokenId].owner == msg.sender, "Only item owner can perform this operation");
      require(msg.value == listingPrice, "Price must be equal to listing price");
      idToMarketItem[tokenId].sold = false;
      idToMarketItem[tokenId].price = price;
      idToMarketItem[tokenId].seller = payable(msg.sender);
      idToMarketItem[tokenId].owner = payable(address(this));
      _itemsSold.decrement();

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

This is my web page:

import { useEffect, useState } from 'react'
import { ethers } from 'ethers'
import { useRouter } from 'next/router'
import axios from 'axios'
import Web3Modal from 'web3modal'

import {
    nftaddress, nftmarketaddress
} from '../config'

// import NFT from '../artifacts/contracts/NFT.sol/NFT.json'
import NFTMarket from '../artifacts/contracts/NFTMarket.sol/NFTMarket.json'

export default function ResellNFT() {
  const [formInput, updateFormInput] = useState({ price: '', image: '' })
  const router = useRouter()
  const { id, tokenUri } = router.query
  const { image, price } = formInput

  useEffect(() => {
    fetchNFT()
  }, [id])

  async function fetchNFT() {
    if (!tokenUri) return
    const meta = await axios.get(tokenUri)
    updateFormInput(state => ({ ...state, image: meta.data.image }))
  }

  async function listNFTForSale() {
    if (!price) return
    const web3Modal = new Web3Modal()
    const connection = await web3Modal.connect()
    const provider = new ethers.providers.Web3Provider(connection)
    const signer = provider.getSigner()

    const priceFormatted = ethers.utils.parseUnits(formInput.price, 'ether')
    const marketContract = new ethers.Contract(nftmarketaddress, NFTMarket.abi, signer)
    //const tokenContract = new ethers.Contract(nftaddress, NFT.abi, provider)
    let listingPrice = await marketContract.getListingPrice()    

    listingPrice = listingPrice.toString()
    let transaction = await marketContract.resellToken(nftaddress, id, priceFormatted, { value: listingPrice })
    await transaction.wait()
   
    router.push('/')
    
  }

  return (
    <div className="flex justify-center">
      <div className="w-1/2 flex flex-col pb-12">
        <input
          placeholder="Asset Price in Eth"
          className="mt-2 border rounded p-4"
          onChange={e => updateFormInput({ ...formInput, price: e.target.value })}
        />
        {
          image && (
            <img className="rounded mt-4" width="350" src={image} />
          )
        }
        <button onClick={listNFTForSale} className="font-bold mt-4 bg-pink-500 text-white rounded p-4 shadow-lg">
          List NFT
        </button>
      </div>
    </div>
  )
}

Error code:

    eth_estimateGas
  Contract call:       NFTMarket#resellToken
  From:                0x1cbd3b2770909d4e10f157cabc84c7264073c9ec
  To:                  0x5fbdb2315678afecb367f032d93f642f64180aa3
  Value:               0.025 ETH

  Error: VM Exception while processing transaction: reverted with reason string 'ERC721: transfer caller is not owner nor approved'
      at NFT.transferFrom (@openzeppelin/contracts/token/ERC721/ERC721.sol:156)
      at NFTMarket.resellToken (contracts/NFTMarket.sol:89)
      at EthModule._estimateGasAction (E:\маркетплейс\polygon-ethereum\node_modules\hardhat\src\internal\hardhat-network\provider\modules\eth.ts:425:7)
      at HardhatNetworkProvider._sendWithLogging (E:\маркетплейс\polygon-ethereum\node_modules\hardhat\src\internal\hardhat-network\provider\provider.ts:139:22)
      at HardhatNetworkProvider.request (E:\маркетплейс\polygon-ethereum\node_modules\hardhat\src\internal\hardhat-network\provider\provider.ts:116:18)
      at JsonRpcHandler._handleRequest (E:\маркетплейс\polygon-ethereum\node_modules\hardhat\src\internal\hardhat-network\jsonrpc\handler.ts:188:20) 
      at JsonRpcHandler._handleSingleRequest (E:\маркетплейс\polygon-ethereum\node_modules\hardhat\src\internal\hardhat-network\jsonrpc\handler.ts:167:17)
      at Server.JsonRpcHandler.handleHttp (E:\маркетплейс\polygon-ethereum\node_modules\hardhat\src\internal\hardhat-network\jsonrpc\handler.ts:52:21)

UPDATE:
This is my smart contract of the marketplace

// SPDX-License-Identifier: MIT
pragma solidity 0.8.2;

import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract NFTMarket is ReentrancyGuard {
  using Counters for Counters.Counter;
  Counters.Counter private _itemIds;
  Counters.Counter private _itemsSold;

  address payable owner;
  uint256 listingPrice = 0.025 ether;

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

  struct MarketItem {
    uint256 itemId;
    address nftContract;
    uint 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 createMarketItem(
    address nftContract,
    uint256 tokenId,
    uint256 price
  ) public payable nonReentrant {
    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[tokenId] = MarketItem(
      itemId,
      nftContract,
      tokenId,
      payable(msg.sender),
      payable(address(0)),
      price,
      false
    );

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

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

  function resellToken(address nftContract, uint256 tokenId, uint256 price) public payable {
      require(idToMarketItem[tokenId].owner == msg.sender, "Only item owner can perform this operation");
      require(msg.value == listingPrice, "Price must be equal to listing price");
      idToMarketItem[tokenId].sold = false;
      idToMarketItem[tokenId].price = price;
      idToMarketItem[tokenId].seller = payable(msg.sender);
      idToMarketItem[tokenId].owner = payable(address(this));
      _itemsSold.decrement();

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

  function createMarketSale(
    address nftContract,
    uint256 itemId
    ) public payable nonReentrant {
    uint price = idToMarketItem[itemId].price;
    uint tokenId = idToMarketItem[itemId].tokenId;
    require(msg.value == price, "Please sumbit the asking price in order to complete the purchase");

    idToMarketItem[itemId].seller.transfer(msg.value);
    IERC721 (nftContract).transferFrom(address(this), msg.sender, tokenId);
    idToMarketItem[itemId].owner = payable(msg.sender);
    idToMarketItem[itemId].sold = true;
    _itemsSold.increment();
    payable(owner).transfer(listingPrice);
  }

  function fetchMarketItems() public view returns (MarketItem[] memory) {
    uint ItemCount = _itemIds.current();
    uint unsoldItemCount = _itemIds.current() - _itemsSold.current();
    uint currentIndex = 0;

    MarketItem[] memory items = new MarketItem[](unsoldItemCount);
    for (uint i = 0; i < ItemCount; i++) {
      if (idToMarketItem[i + 1].owner == address(0)) {
        uint currentId = idToMarketItem[i + 1].itemId;
        MarketItem storage currentItem = idToMarketItem[currentId];
        items[currentIndex] = currentItem;
        currentIndex += 1;
      }
    }
    return items;
  }

   function fetchMyNFTs() public view returns (MarketItem[] memory) {
    uint totalItemCount = _itemIds.current();
    uint itemCount = 0;
    uint currentIndex = 0;

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

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

  function fetchItemsCreated() public view returns (MarketItem[] memory) {
    uint totalItemCount = _itemIds.current();
    uint itemCount = 0;
    uint currentIndex = 0;

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

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

This is the nfc creation code

import { useState } from 'react'
import { ethers } from 'ethers'
import { create as ipfsHttpClient } from 'ipfs-http-client'
import { useRouter } from 'next/router'
import Web3Modal from 'web3modal'
import {MPLayout} from '../../components/MPLayout'

const client = ipfsHttpClient('https://ipfs.infura.io:5001/api/v0')

import {
    nftaddress, nftmarketaddress
} from '../../config'

import NFT from '../../artifacts/contracts/NFT.sol/NFT.json'
import NFTMarket from '../../artifacts/contracts/NFTMarket.sol/NFTMarket.json'

export default function CreateItem () {
    const [fileUrl, setFileUrl] = useState(null)
    const [formInput, updateFormInput] = useState({ price: '', name: '', description: '' })
    const router = useRouter()

    async function onChange(e) {
        const file = e.target.files[0] 
        try {
            const added = await client.add(
                file,
                {
                    progress: (prog) => console.log('received: ${prog}')
                }
            )
            const url = `https://ipfs.infura.io/ipfs/${added.path}`
            setFileUrl(url)
        }   catch (e) {
            console.log(e)
        }
    }

    async function createItem() {
        const { name, description, price } = formInput
        if (!name || !description || !price || !fileUrl) return
        const data = JSON.stringify({
            name, description, image: fileUrl
        })

        try {
            const added = await client.add(data)
            const url = `https://ipfs.infura.io/ipfs/${added.path}`
            /* after file is uploaded to IPFS, return the URL to use it in the transaction */
            createSale(url)
        }   catch (error) {
            console.log('Error uploading file: ', error)
        }
    }

    async function createSale(url) {
        const web3Modal = new Web3Modal()
        const connection = await web3Modal.connect()
        const provider = new ethers.providers.Web3Provider(connection)
        const signer = provider.getSigner()

        let contract = new ethers.Contract(nftaddress, NFT.abi, signer)
        let transaction = await contract.createToken(url)
        let tx = await transaction.wait()

        let event = tx.events [0]
        let value = event.args[2]
        let tokenId = value.toNumber()

        const price = ethers.utils.parseUnits(formInput.price, 'ether')

        contract = new ethers.Contract(nftmarketaddress, NFTMarket.abi, signer)
        let listingPrice = await contract.getListingPrice()
        listingPrice = listingPrice.toString()

        transaction = await contract.createMarketItem(nftaddress, tokenId, price, { value: listingPrice})
        await transaction.wait()
        router.push('/')
    }

    return (
            <MPLayout title={'Create Item'}>
                <div className="flex justify-center">
                    <div className="w-1/2 flex flex-col pb-12">
                    <input 
                        placeholder="Asset Name"
                        className="mt-8 border rounded p-4"
                        onChange={e => updateFormInput({ ...formInput, name: e.target.value })}
                    />
                    <textarea
                        placeholder="Asset Description"
                        className="mt-2 border rounded p-4"
                        onChange={e => updateFormInput({ ...formInput, description: e.target.value })}
                        />
                        <input
                        placeholder="Asset Price in Eth"
                        className="mt-2 border rounded p-4"
                        onChange={e => updateFormInput({ ...formInput, price: e.target.value })}
                        />
                        <input
                        type="file"
                        name="Asset"
                        className="my-4"
                        onChange={onChange}
                        />
                        {
                            fileUrl && (
                                <img className="rounded mt-4" width="350" src={fileUrl} />
                            )
                        }
                        <button 
                            onClick={createItem} 
                            className="font-bold mt-4 bg-pink-500 text-white rounded p-4 shadow-lg"
                        >
                            Create Digital Asset 
                        </button>
                    </div>
                </div>
            </MPLayout>
    )
    
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

公布 2025-02-01 15:44:58

看来最初创建NFT后代码中的其他某个地方,NFT实际上并非由iDtomarketItem [Tokenid]。所有者 _mint(...)创建NFT,则您的第一个参数可能是错误的。如果这无济于事,您可以共享创建NFT的代码以及最初设置idtomarketItem [Tokenid] .owner的代码吗?

It seems that somewhere else in your code after initially creating the nft, the nft is not actually owned by idToMarketItem[tokenId].owner but by someone else. If you're creating the nft with _mint(...), your first parameter to _mint is probably wrong. If this doesn't help, can you share the code where you create the nft and also the code where you initially set idToMarketItem[tokenId].owner?

情未る 2025-02-01 15:44:58

如果您查看erc721.sol有此功能,

function transferFrom(address from, address to, uint256 tokenId
      ) public virtual override {

        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");  
        _transfer(from, to, tokenId);
    }

您正在调用此功能,但您不满意requiend require stamtst:

require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");

在智能合约中,如果您是从另一个地址转移的,您必须被授权这样做。您不能只从任何帐户转移某些内容。因此,在调用转换之前,您必须先调用此

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 || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
    }

If you look at ERC721.sol you have this function

function transferFrom(address from, address to, uint256 tokenId
      ) public virtual override {

        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");  
        _transfer(from, to, tokenId);
    }

You are calling this function but you are not satisfying the require stament:

require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");

In smart contracts, if you are transfering from another address, you have to be authorized to do it. You cannot just go transfer something from any account. So before you call transferFrom, you have to call this first

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 || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
    }
淡莣 2025-02-01 15:44:58

正如此线程,所有者必须重新签订NFT市场合同,以代表他改变所有权。在您的NFT合同中添加下面的代码,并在调用您的Reselltoken()和Voila之前从FE调用它!

    function giveResaleApproval(uint256 tokenId) public {
        require(
            ownerOf(tokenId) == msg.sender,
            "You must own this NFT in order to resell it"
        );
        setApprovalForAll(contractAddress, true);
        return;
    }

As explained in this thread, the owner has to re-approve the NFT-market contract to change the ownership on his behalf. Add the code below in your NFT contract and call it from your FE before calling your resellToken() and voila !

    function giveResaleApproval(uint256 tokenId) public {
        require(
            ownerOf(tokenId) == msg.sender,
            "You must own this NFT in order to resell it"
        );
        setApprovalForAll(contractAddress, true);
        return;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文