制定NFT合同并接收外部交易

发布于 2025-01-21 16:02:41 字数 5058 浏览 0 评论 0原文

我正在开发用于NFT合同的简单应用程序。

被困在接收外部交易上。

合同:

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

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
//import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract RonteNft is ERC721, ERC721URIStorage, ERC721Burnable, Ownable {
    // IERC721Receiver //IERC721Enumerable
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIdCounter;
    Counters.Counter private _soldTokenIdCounter;

    uint256 public constant BASE_PRICE = 0.001 ether;

    struct TokenList {
        uint256 tokenId;
        string tokenUri;
        address tokenOwner;
        bool sold;
    }

    TokenList[] public tokenList;
    //mapping(bool => TokenList) existingTokenList;

    address[] public addressList;
    mapping(address => bool) public WhiteList;

    constructor() ERC721("RonteNft", "RtNFT") {
        WhiteList[0x9ACdCfb9385810E0270afB5bFA5000d6Be0891ea] = true;
        WhiteList[0x2A5e5cc1dA717B1F076Ce04E0c7A814320C0Dc6A] = true;
        WhiteList[0xEdc64A63ae9dc338052CdF92fA4c80154e4559AE] = true;
        WhiteList[0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266] = true;
        WhiteList[0x70997970C51812dc3A010C7d01b50e0d17dc79C8] = true;
    }

    function totalSupply() external view returns (uint256){
        return _soldTokenIdCounter.current();
    }

    function safeMint(address to, string memory nftTokenURI) public onlyOwner {
        _safeMint(to, _tokenIdCounter.current());
        _setTokenURI(_tokenIdCounter.current(), nftTokenURI);
        tokenList.push(
            TokenList(_tokenIdCounter.current(), nftTokenURI, to, false)
        );

        _tokenIdCounter.increment();
    }

    // The following functions are overrides required by Solidity.
    function _burn(uint256 tokenId)
    internal
    override(ERC721, ERC721URIStorage)
    {
        super._burn(tokenId);
    }

    function tokenURI(uint256 tokenId)
    public
    view
    override(ERC721, ERC721URIStorage)
    returns (string memory)
    {
        return super.tokenURI(tokenId);
    }

    function currentCounter() public view returns (uint256) {
        return _tokenIdCounter.current();
    }

    function freeMint(address to, string memory nftTokenURI) public {
        _safeMint(to, _tokenIdCounter.current());
        _setTokenURI(_tokenIdCounter.current(), nftTokenURI);
        tokenList.push(
            TokenList(_tokenIdCounter.current(), nftTokenURI, to, false)
        );

        _tokenIdCounter.increment();
    }

    function getTokenList() public view returns (TokenList[] memory) {
        return tokenList;
    }

    function sellToken(address buyer) public {
        //require(msg.value == BASE_PRICE, "Incoming amount is wrong!");
        require(WhiteList[buyer] == true, "You are not in a white list!");

        uint256 tokenId = tokenList[_soldTokenIdCounter.current()].tokenId;
        transferFrom(owner(), buyer, tokenId);
        _soldTokenIdCounter.increment();
        tokenList[_soldTokenIdCounter.current()].sold = true;
    }

    function getError() public {
        require(1 == 2, "TEST ERROR");
    }

    function deposit() public payable {
        require(1 == 2, "DEPOSIT ERROR");
    }

    receive() external payable {
        require(msg.value == BASE_PRICE, "Incoming amount is wrong!");
        require(WhiteList[msg.sender] == true, "You are not in a white list!");

        uint256 tokenId = tokenList[_soldTokenIdCounter.current()].tokenId;
        approve(msg.sender,tokenId);
        transferFrom(owner(), msg.sender, tokenId);
        _soldTokenIdCounter.increment();
        tokenList[_soldTokenIdCounter.current()].sold = true;
    }

    function checkWhiteList(address _wallet) public returns (bool) {
        return WhiteList[_wallet];
    }
 
}

将铸造和铸造到当地的硬汉节点(正常工作),然后尝试从另一个钱包发送交易。 收到错误:

      eth_sendRawTransaction
  Contract call:       RonteNft#<unrecognized-selector>
  Transaction:         0x5406175da512d812761b0e557ae67240987834294d51f39aa13371ff64453e57
  From:                0x70997970c51812dc3a010c7d01b50e0d17dc79c8
  To:                  0x5fbdb2315678afecb367f032d93f642f64180aa3
  Value:               0.001 ETH
  Gas used:            34976 of 91000
  Block #6:            0x12bef472185ef527d650454bb88dd69ad540cc2b5a6dbf3e33c5f928b3472867

  Error: VM Exception while processing transaction: reverted with reason string 'ERC721: approve caller is not owner nor approved for all'
      at RonteNft.approve (@openzeppelin/contracts/token/ERC721/ERC721.sol:116)
      at RonteNft.<receive> (contracts/RonteNft.sol:112)

这是因为交易的发件人不是合同的所有者,我明白了这一点,但是您如何接受付款和转让令牌? 如果从合同所有者可以调用

I'm developing simple app for nft contracts.

Got stucked at receving external transactions.

Contract:

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

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
//import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract RonteNft is ERC721, ERC721URIStorage, ERC721Burnable, Ownable {
    // IERC721Receiver //IERC721Enumerable
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIdCounter;
    Counters.Counter private _soldTokenIdCounter;

    uint256 public constant BASE_PRICE = 0.001 ether;

    struct TokenList {
        uint256 tokenId;
        string tokenUri;
        address tokenOwner;
        bool sold;
    }

    TokenList[] public tokenList;
    //mapping(bool => TokenList) existingTokenList;

    address[] public addressList;
    mapping(address => bool) public WhiteList;

    constructor() ERC721("RonteNft", "RtNFT") {
        WhiteList[0x9ACdCfb9385810E0270afB5bFA5000d6Be0891ea] = true;
        WhiteList[0x2A5e5cc1dA717B1F076Ce04E0c7A814320C0Dc6A] = true;
        WhiteList[0xEdc64A63ae9dc338052CdF92fA4c80154e4559AE] = true;
        WhiteList[0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266] = true;
        WhiteList[0x70997970C51812dc3A010C7d01b50e0d17dc79C8] = true;
    }

    function totalSupply() external view returns (uint256){
        return _soldTokenIdCounter.current();
    }

    function safeMint(address to, string memory nftTokenURI) public onlyOwner {
        _safeMint(to, _tokenIdCounter.current());
        _setTokenURI(_tokenIdCounter.current(), nftTokenURI);
        tokenList.push(
            TokenList(_tokenIdCounter.current(), nftTokenURI, to, false)
        );

        _tokenIdCounter.increment();
    }

    // The following functions are overrides required by Solidity.
    function _burn(uint256 tokenId)
    internal
    override(ERC721, ERC721URIStorage)
    {
        super._burn(tokenId);
    }

    function tokenURI(uint256 tokenId)
    public
    view
    override(ERC721, ERC721URIStorage)
    returns (string memory)
    {
        return super.tokenURI(tokenId);
    }

    function currentCounter() public view returns (uint256) {
        return _tokenIdCounter.current();
    }

    function freeMint(address to, string memory nftTokenURI) public {
        _safeMint(to, _tokenIdCounter.current());
        _setTokenURI(_tokenIdCounter.current(), nftTokenURI);
        tokenList.push(
            TokenList(_tokenIdCounter.current(), nftTokenURI, to, false)
        );

        _tokenIdCounter.increment();
    }

    function getTokenList() public view returns (TokenList[] memory) {
        return tokenList;
    }

    function sellToken(address buyer) public {
        //require(msg.value == BASE_PRICE, "Incoming amount is wrong!");
        require(WhiteList[buyer] == true, "You are not in a white list!");

        uint256 tokenId = tokenList[_soldTokenIdCounter.current()].tokenId;
        transferFrom(owner(), buyer, tokenId);
        _soldTokenIdCounter.increment();
        tokenList[_soldTokenIdCounter.current()].sold = true;
    }

    function getError() public {
        require(1 == 2, "TEST ERROR");
    }

    function deposit() public payable {
        require(1 == 2, "DEPOSIT ERROR");
    }

    receive() external payable {
        require(msg.value == BASE_PRICE, "Incoming amount is wrong!");
        require(WhiteList[msg.sender] == true, "You are not in a white list!");

        uint256 tokenId = tokenList[_soldTokenIdCounter.current()].tokenId;
        approve(msg.sender,tokenId);
        transferFrom(owner(), msg.sender, tokenId);
        _soldTokenIdCounter.increment();
        tokenList[_soldTokenIdCounter.current()].sold = true;
    }

    function checkWhiteList(address _wallet) public returns (bool) {
        return WhiteList[_wallet];
    }
 
}

Compiling and minting to a local hardhat node(working fine) and then trying to send transaction from another wallet.
Receiving error:

      eth_sendRawTransaction
  Contract call:       RonteNft#<unrecognized-selector>
  Transaction:         0x5406175da512d812761b0e557ae67240987834294d51f39aa13371ff64453e57
  From:                0x70997970c51812dc3a010c7d01b50e0d17dc79c8
  To:                  0x5fbdb2315678afecb367f032d93f642f64180aa3
  Value:               0.001 ETH
  Gas used:            34976 of 91000
  Block #6:            0x12bef472185ef527d650454bb88dd69ad540cc2b5a6dbf3e33c5f928b3472867

  Error: VM Exception while processing transaction: reverted with reason string 'ERC721: approve caller is not owner nor approved for all'
      at RonteNft.approve (@openzeppelin/contracts/token/ERC721/ERC721.sol:116)
      at RonteNft.<receive> (contracts/RonteNft.sol:112)

It's happenging because the sender of transaction is not an owner of a contract, I understand that, but how you can accept payments and transfere token then?
If transferFrom can be called only by the owner of the contract?

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

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

发布评论

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

评论(1

茶色山野 2025-01-28 16:02:41

ERC721上有两种方法可以实现这一目标。

您可以使用批准方法;

approve(address to, uint256 tokenId)

批准另一个地址传输给定令牌ID零地址表示没有批准的地址。在给定时间,每个令牌只能有一个批准的地址。只能由令牌所有者或批准的运营商来调用。

...或者您可以使用setAppRovalForall方法;

setApprovalForAll(address to, bool approved)

这将设定或安排给定操作员的批准,允许操作员代表其转移所有发件人的代币。

您可以在此处查看详细信息: openzeppelin

There are two methods on ERC721 to achieve this.

You can use approve method;

approve(address to, uint256 tokenId)

that approves another address to transfer the given token ID The zero address indicates there is no approved address. There can only be one approved address per token at a given time. Can only be called by the token owner or an approved operator.

... or you can use setApprovalForAll method;

setApprovalForAll(address to, bool approved)

that sets or unsets the approval of a given operator An operator is allowed to transfer all tokens of the sender on their behalf.

You can check the details in here: OpenZeppelin

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文