SetApprovalForAll не работает, когда я пытаюсь перейти с торговой площадки

Я создал смарт-контракт NFT под названием AliveNatureERC721, а также рыночный контракт под названием AliveNatureMarketplaceV1.

Оба контракта ниже. Я использую Ремикс. у меня ошибка

Сбой с ошибкой «Только владелец NFT может передать или записать его»

на ERCNFT.transferFrom( msg.sender, address(this), _tokenId), даже когда я перешел к развернутому смарт-контракту NFT на Remix и выполнил функцию setApprovalForAll("marketplace smart contract address", true) до того, как вызвал функцию listNFT(ERC721 _nft, uint256 _tokenId, uint256 _price, address _coin).

Я также пытался вызвать функцию setApprovalForAll внутри смарт-контракта торговой площадки, но это тоже не сработало.

Вот вызов, который я делаю:

Marketplace address: 0x3f46f42900DDFE85FC03B80D934608a8C2522Dc
NFT address: 0x2CF055487A80014a10d75D4EC86de2b0Ac1C9B0e

setApprovalForAll("0x3f46f42900DDFE85FC03B80D934608a8C2522Dc", true)

после того, как я позвоню ERCNFT.transferFrom( msg.sender, address(this), _tokenId);, где address(this) находится 0x3f46f42900DDFE85FC03B80D934608a8C2522Dc

Я не знаю, что я делаю неправильно в этом случае.

Смарт-контракт торговой площадки:

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

import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";


contract AliveNatureMarketplaceV1 is Ownable, Pausable,  ReentrancyGuard  {
    IERC20 public ERC20;
    IERC721 public ERCNFT;

    using Counters for Counters.Counter;
    
    Counters.Counter private numOfListing;

    uint256  commissionPercentage = 250;

struct NFTListing {  
  ERC721 nft;
  uint tokenId;
  uint price;
  address coin;
  address seller;
  bool forSale;
}
  
  event NftBuy(address _buyer, uint256 _tokenId, uint256 _price);
  event NftList(address _seller, IERC721 _nft, uint256 _tokenId);
 
  mapping(uint256 => NFTListing) public listings;
   
   modifier onlyNftOwner(uint _Id) {
        require(msg.sender == listings[_Id].seller);
        _;
    }


    function pauseMarketplace() public onlyOwner {
        _pause();
    }

    function unpauseMarketplace() public onlyOwner {
        _unpause();
    }

  
// this function will list and sell an NFT into the marketplace
  function listNFT(ERC721 _nft, uint256 _tokenId, uint256 _price, address _coin) public  {
    ERCNFT = IERC721(_nft);
    require (ERCNFT.ownerOf(_tokenId) == msg.sender, "You are not the owner");
    require(_price > 0, "NFTMarket: price must be greater than 0");
    numOfListing.increment();
    listings[numOfListing.current()] = NFTListing(
       _nft,
       _tokenId,
       _price,
       _coin,
       payable(msg.sender), 
       false
       );
    NFTListing storage listing = listings[_tokenId];
   //ERCNFT.approve(address(this) , _tokenId);
  // listing.nft.setApprovalForAll(ERCNFT, true);
    ERCNFT.transferFrom( msg.sender, address(this), _tokenId);
    listing.forSale = true;
     emit NftList(msg.sender, ERCNFT, _tokenId);

  } 



// this function will cancel the listing. it also has checks to make sure only the owner of the listing can cancel the listing from the market place

  function cancel(uint _Id) public payable onlyNftOwner(_Id){
     NFTListing storage listing = listings[_Id];
     require(listing.seller == msg.sender);
     require(listing.forSale == true);
     listing.nft.transferFrom(address(this), msg.sender, _Id);
     listing.forSale = false;
  }



// this function will facilitate the purchasing of a listing
  function buyNFT(uint _Id) public payable whenNotPaused nonReentrant {
        NFTListing storage listing = listings[_Id];
        require(_Id > 0 && _Id <= numOfListing.current(), "item doesn't exist");
        require(msg.value >= listing.price,"not enough balance for this transaction");
        require(listing.forSale != false, "item is not for sell");
        require(listing.seller != msg.sender, "You cannot buy your own nft");

        uint256 comissionAmount = SafeMath.mul(listing.price, commissionPercentage);
        comissionAmount = SafeMath.div(comissionAmount, 10000);
        uint256 sellerAmount = SafeMath.sub(listing.price, comissionAmount);


        if (listing.coin == 0xF194afDf50B03e69Bd7D057c1Aa9e10c9954E4C9){
        require(sellerAmount <= address(this).balance, "Insufficient funds.");
        payable(address(this)).transfer(comissionAmount);
        payable(listing.seller).transfer(sellerAmount);
        } else {
          ERC20 = IERC20(listing.coin);
          require(sellerAmount <= ERC20.balanceOf(address(this)), "Insufficient funds.");
          ERC20.transfer(address(this), comissionAmount);
          ERC20.transfer(listing.seller, sellerAmount);

        }
        listing.nft.transferFrom(address(this), msg.sender, listing.tokenId);
        listing.seller = msg.sender;
        listing.forSale = false;
        emit NftBuy( msg.sender, listing.tokenId, sellerAmount);
    }

     // Function to transfer or withdraw the funds
    function transferOrWithdraw (bool _isCelo, uint _amount, address _ERC20Address) public whenNotPaused nonReentrant onlyOwner {
        require(_amount != 0, "Amount cannot be zero");
       if (_isCelo) {
            require(_amount <= address(this).balance, "Insufficient funds.");
            payable(msg.sender).transfer(_amount);
        } else {
            require(_ERC20Address != address(0), "ERC20 address cannot be zero address");
            ERC20 = IERC20(_ERC20Address);
            require(_amount <= ERC20.balanceOf(address(this)), "Insufficient funds.");
            ERC20.transfer(msg.sender , _amount);
        }
    }

// this function will get the listings in the market place
    function getNFTListing(uint _Id) public view returns (NFTListing memory) {
        return listings[_Id];
    }

    
    // get list of items
    function getListinglength() public view returns (uint) {
        return numOfListing.current();
    }   


  

}

УМНЫЙ КОНТРАКТ NFT

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

import "@openzeppelin/contracts/token/common/ERC2981.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";


contract AliveNatureERC721 is ERC721, ERC721Enumerable, ERC721URIStorage,Ownable ,ERC2981,  Pausable {
    using Counters for Counters.Counter;

    Counters.Counter private _tokenIdCounter;


    //Base URI
    string private url;
    // percentage split for commission 
    uint96 public commissionPercentage;
    // address of the commission recipient
    address public commissionRecipient;

    struct ProjectData {
        string name;
        uint256 projectTokenId;
        string methodology;
        string area;
        string region;
        string emissionType;
        string uri;
        address creator;
        uint256 timeStamp;
    }

    struct RetireData {
        uint256 retireTokenId;
        address beneficiary;
        string retirementMessage;
        uint256 timeStamp;
        uint256 amount;
    }

    mapping (uint256 => ProjectData) private _projectData;
    mapping (uint256 => RetireData) private _retireData;




    constructor( string memory _MyToken, string memory _Symbol) ERC721(_MyToken, _Symbol) {
        commissionPercentage = 100;
        commissionRecipient = 0xE3506A38C80D8bA1ef219ADF55E31E18FB88EbF4;
        _setDefaultRoyalty(commissionRecipient, commissionPercentage);
    }

    function _baseURI() internal view override returns (string memory) {
        return url;
    }

    function pause() external onlyOwner  {
        _pause();
    }

    function unpause() external onlyOwner {
        _unpause();
    }


    function safeMint(address _to, string memory _uri, string memory _name,
    string memory _methodology, string memory _area, string memory _region,  string memory _emissionType, uint256 _tokenId) public whenNotPaused onlyOwner {
        uint256 tokenId = _tokenId;
        _safeMint(_to, tokenId);
        _setTokenURI(tokenId, _uri);
        
        // Create a new ProjectData struct and store it in the contract's storage
        _projectData[tokenId] = ProjectData({
        projectTokenId : tokenId,
        uri : _uri,
        name : _name,
        methodology : _methodology,
        area : _area,
        region : _region,
        emissionType : _emissionType,
        creator : msg.sender,
        timeStamp : block.timestamp
        });
    }

    function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize)
        internal
        whenNotPaused
        override(ERC721, ERC721Enumerable)
    {
        super._beforeTokenTransfer(from, to, tokenId, batchSize);
            if (from != address(0)) {
            address owner = ownerOf(tokenId);
            require(owner == msg.sender, "Only the owner of NFT can transfer or burn it");
        }
    }

    function _burn(uint256 tokenId) internal whenNotPaused override(ERC721, ERC721URIStorage) {
        super._burn(tokenId);
    }

    function burnToken(uint256 tokenId, string memory _retirementMessage, uint256 _amount) public whenNotPaused {
        address owner = ownerOf(tokenId);
        require(owner == msg.sender, "Only the owner of NFT can burn it");
        _burn(tokenId);

        // Create a new ProjectData struct and store it in the contract's storage
        _retireData[tokenId] = RetireData({
        retireTokenId : tokenId,
        beneficiary : msg.sender,
        retirementMessage : _retirementMessage,
        timeStamp : block.timestamp,
        amount : _amount
        });
    }

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

    // The following functions are overrides required by Solidity.

    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC721, ERC2981,  ERC721Enumerable)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }



    function ownerOf(uint256 tokenId) public view virtual override(ERC721, IERC721) returns (address) {
        address owner = _ownerOf(tokenId);
        require(owner != address(0), "ERC721: invalid token ID");
        return owner;
    }

    function getProjectData(uint256 tokenId) public view returns (ProjectData memory) {
        return _projectData[tokenId];
    }

    function getRetireData(uint256 tokenId) public view returns (RetireData memory) {
        return _retireData[tokenId];
    }

    function getCommissionPercentage() public view returns (uint96) {
        return commissionPercentage;
    }

    function getCommissionRecipient() public view returns (address) {
        return commissionRecipient;
    }

}




Я пытался следовать многим примерам, которые вызывают, что мне нужно сначала выполнить setApprovalforAll, но даже это все еще не работает.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
58
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

require(owner == msg.sender, "Only the owner of NFT can transfer or burn it")

Ошибка говорит сама за себя, owner не msg.sender.

При вызове ERCNFT.transferFrommsg.sender будет адресом контракта Marketplace. Ваша логика внутри _beforeTokenTransfer ограничивает возможность передачи любого адреса, кроме владельца токена, даже если этот адрес был одобрен.

проблема в том, что вы модифицируете функцию _beforeTokenTransfer, нарушая логику утверждения

thks173 05.04.2023 09:14

Другие вопросы по теме