Solidity

如何將 ERC721 代幣批准()到稍後購買代幣的未知地址?

  • February 27, 2022

我正在建立一個 NFT 市場,使用者操作如下。

  • 地址 A 上傳圖像以創建 NFT。此操作呼叫智能合約函式 createToken() 來創建 ERC721 代幣,並呼叫 listNFTItem() 來列出代幣。
  • 現在,如果地址 B 想要購買該代幣,則通過呼叫 Buy() 來執行此操作,然後在其中呼叫 transferFrom()。
  • 現在理想情況下,代幣的所有權應該從地址 A 轉移到地址 B,並且地址 B 應該能夠重新列出它。
  • 這是我面臨問題的地方。當地址 B 使用呼叫 transferFrom() 的 relistNftItem() 重新列出此令牌時,此操作失敗並出現錯誤“ ERC721:transfer caller is not owner or approved

現在,在對 stackoverflow 進行了一些研究並閱讀了 openzeppelin 契約之後,我意識到這個錯誤相當普遍,“地址 B”只需要在重新列出之前批准“收件人”地址(在這種情況下是契約地址)。但是在 relistNftItem() 函式中添加一個approve(address(this), tokenId) 會引發這個新錯誤“ ERC721:approve caller is not owner or approved for all ”。即使我在批准()中用 msg.sender 替換地址(這個),錯誤也是一樣的。

這是 createToken()

function createToken(string memory tokenURI) public returns (uint256) {
   // Token URI contains metadata like msg.sender etc
   _tokenIds.increment();
   uint256 newItemId = _tokenIds.current();

   _mint(msg.sender, newItemId);
   _setTokenURI(newItemId, tokenURI);

   // Giving approval to the contract address for transferring ownership from all nfts

   setApprovalForAll(contractAddress, true);

   return newItemId;
}

這是我在智能合約上的 listNFTItem() 函式

function listNFTItem(
   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[itemId] = 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 Buy(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 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);
}

這是 relistNFTitem() 的合約程式碼

function relistNFTitem(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 price in order to complete the purchase"
   );
   require(
       idToMarketItem[itemId].owner == msg.sender,
       "Only token owner can put up token for sell"
   );

   idToMarketItem[itemId].seller.transfer(msg.value);

   // I am approving the approve contract here. Commented it out to reproduce step by step. 

   // IERC721(nftContract).approve(address(this), tokenId);

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

我假設購買()將所有權轉移到購買()中的“地址B”。如果沒有,如何批准地址“B”重新列出。如果我的構想是錯誤的,請告訴我我錯過了什麼。請指導我如何重新列出令牌/可自由交易。

我遇到了同樣的問題。你有沒有解決過這個問題?

$$ SOLVED $$ 我必須為 NFT ERC721 合約創建第二筆交易,允許 NFT 市場合約被批准列出任何地址代幣。

async function allowListing() {
 // connect to the web3 modal and get the signer
 const web3Modal = new Web3Modal();
 const connection = await web3Modal.connect();
 const provider = new ethers.providers.Web3Provider(connection);
 const signer = provider.getSigner();

 // allow token from the NFT contract to be listed on the markeplace
 let contract = new ethers.Contract(nftAddress, NFT.abi, signer);
 let transaction = await contract.setApprovalForAll(nftMarketAddress, true);
 await transaction.wait();
}

引用自:https://ethereum.stackexchange.com/questions/118022