Solidity
如何將 ERC721 代幣批准()到稍後購買代幣的未知地址?
我正在建立一個 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(); }