0

这是我的 NFT 市场的可靠文件。

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";


 contract NFT is ERC721URIStorage,Ownable {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;
    address payable public _owner;
    mapping(address => uint[]) public addressToTokenArray;
    mapping(uint256 => bool) public forSale;
    mapping(uint256 => uint256) public tokenIdToPrice;
    event Minting(address _owner, uint256 _tokenId, uint256 _price);
    event Purchase(address _seller, address _buyer, uint256 _price);
    event Remove(uint256 _tokenId, uint[] beforeBuy, uint[] afterBuy);

    constructor() ERC721("TeddyBear", "TEDDY") {
    }

    function mint(string memory _tokenURI, uint256 _price) public onlyOwner returns (bool)
    {
        _tokenIds.increment();
        uint256 newItemId = _tokenIds.current();
        tokenIdToPrice[newItemId] = _price;
        if(addressToTokenArray[msg.sender].length !=1){
            addressToTokenArray[msg.sender].push(newItemId);
        }else{
            addressToTokenArray[msg.sender] = [newItemId];
        }
        _mint(msg.sender, newItemId);
        _setTokenURI(newItemId, _tokenURI);
        emit Minting(msg.sender, newItemId, _price);
        return true;
    }

    // 토큰의 주인이 판매 하는 함수
    function sell(uint256 _tokenId, uint256 _price) external { 
        require(msg.sender == ownerOf(_tokenId), 'Not owner of this token');
        require(_price > 0, 'Price zero');
        tokenIdToPrice[_tokenId] = _price;
        forSale[_tokenId] = true;
    }

    // 토큰의 주인이 판매를 취하하는 함수
    function stopSell(uint256 _tokenId) external {
        require(msg.sender == ownerOf(_tokenId), 'Not owner of this token');
        forSale[_tokenId] = false;
    }

    // function remove(uint[] memory array, uint index) public pure  returns(uint[] memory) {
    //     if (index >= array.length) return array;

    //     for (uint i = index; i<array.length-1; i++){
    //         array[i] = array[i+1];
    //     }
    //     delete array[array.length-1];
    //     return array;
    // }

    function buy(uint256 _tokenId, uint256 sendAmount) external payable {
        uint256 price = tokenIdToPrice[_tokenId];
        bool isOnSale = forSale[_tokenId];
        require(isOnSale, 'This token is not for sale');
        require(sendAmount == price, 'Incorrect value');
        address seller = ownerOf(_tokenId);
        require(seller == ownerOf(_tokenId), 'Seller and Owner is not same');
        // uint[] memory beforeBuy = addressToTokenArray[seller];
        // // for(uint i=0;i<addressToTokenArray[seller].length;i++){
        // //     if(_tokenId == addressToTokenArray[seller][i]){
        // //         remove(addressToTokenArray[seller],i);
        // //     }
        // // }
        // uint[] memory afterBuy = addressToTokenArray[seller];
        // emit Remove(_tokenId, beforeBuy, afterBuy);
        addressToTokenArray[msg.sender] = [_tokenId];
        safeTransferFrom(seller, msg.sender, _tokenId);
        forSale[_tokenId] = true;
        payable(seller).transfer(sendAmount); // send the ETH to the seller
        emit Purchase(seller, msg.sender, sendAmount);
    }

    function getPrice(uint256 _tokenId) public view returns (uint256){
        uint256 price = tokenIdToPrice[_tokenId];
        return price;
    }

    function isSale(uint256 _tokenId) public view returns (bool){
        bool isOnSale = forSale[_tokenId];
        return isOnSale;
    }

    
    function getMyTokenId() public view returns (uint[] memory){
        uint[] memory myTokens = addressToTokenArray[msg.sender];
        return myTokens;
    }
}

在上面的函数中,当我编译 .sol 文件时,buy 函数不会发出错误,但是在我部署这个合约并为“buy”函数发送交易之后,它会一直出现这个错误。 在此处输入图像描述

我只是想知道我应该在哪里修复它,如果对其他功能有更好的想法,请随时让我知道...非常感谢

4

1 回答 1

0

很可能在这里失败:

 safeTransferFrom(seller, msg.sender, _tokenId);

如果你检查 ERC721 合约,safeTransferFrom最终调用这个:

function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {
        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId);

        // ******  HERE IS THE ISSUE *****
        _approve(address(0), tokenId);

        _balances[from] -= 1;
        _balances[to] += 1;
        _owners[tokenId] = to;    
        emit Transfer(from, to, tokenId);    
        _afterTokenTransfer(from, to, tokenId);
    }

如果您的合约要代表所有者转移代币,则必须先由所有者批准。

所以从卖方的合同中,这应该被称为:

function _approve(address to, uint256 tokenId) internal virtual {
        _tokenApprovals[tokenId] = to;
        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
    }

tokenApprovals是一个跟踪哪些令牌可以转移的映射。

调试

为了测试哪个函数调用导致错误,请将这个需求语句require(sendAmount == price, 'Incorrect value');放在函数之前。并传递一个不正确的值,你会得到一个错误:'不正确的值'

然后把那个require语句放在函数后面,并传递一个错误的值,如果这个require确实给你发送了错误,你可以确定是函数导致了错误

于 2022-02-10T11:07:21.563 回答