Error called ERC721InsufficientApproval

Hello everyone, I want to list NFTs for sale in the NFT Marketplace but I got the following error:

ERC721InsufficientApproval
Parameters:
{
 "operator": {
  "value": "0xd9145CCE52D386f254917e481eB44e9943F39138",
  "documentation": "Address that may be allowed to operate on tokens without being their owner."
 },
 "tokenId": {
  "value": "0",
  "documentation": "Identifier number of a token."
 }
}

While calling the createMarketItem function.
Could you please check the below code:

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

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";

contract NFT is ERC721{
        uint256 private _tokenIdCounter;
        address marketlaceAddress;
      constructor(string memory _name, string memory _symbol, address _marketplaceAddress)
        ERC721(_name, _symbol)
    {
        marketlaceAddress = _marketplaceAddress;
    }
  

   function safeMint (address to) public returns (uint256) {
        uint256 tokenId = _tokenIdCounter;
           _safeMint(to, tokenId);    
            setApprovalForAll(marketlaceAddress, true);
          _tokenIdCounter++;
          return tokenId;
    }
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

import './NFT.sol';

contract Marketplace is Ownable(msg.sender), ReentrancyGuard{ 

    mapping (address => address[]) private tokens;
    mapping (address => uint256[] ) contractTokenIds;
    mapping (address => uint256) collectionsOfTokenId;
    mapping (uint256 => MarketItem) public marketItems;

    address[] public CollectionAddresses;
    
    uint public getNFTCount; 
    uint256 private _ItemIdsCounter;
    event TokenCreated(address, address);

     struct MarketItem {
        uint256 itemId;
        address nftContract;
        uint256 tokenId;
        address payable seller;
        address payable owner;
        uint256 price;
        bool sold;
    }

    event MarketItemCreated(
        uint256 indexed itemId,
        address indexed nftContract,
        uint256 indexed tokenId,
        address seller,
        address owner,
        uint256 price
    );

      event Bought(
        uint256 itemId,
        address indexed nft,
        uint256 tokenId,
        uint256 price,
        address indexed seller,
        address indexed buyer
    );

    function createToken(string memory name, string memory symbol) public {
       address _address = address(new NFT(name, symbol, address(this)));   
        uint256 count = 0;
       tokens[msg.sender].push(_address);
       CollectionAddresses.push(_address);
       count++;       
        emit TokenCreated(msg.sender, _address);
    }
   
   function bulkMintERC721(
    address tokenAddress,
    uint256 start,
    uint256 end
) public {
    uint256 count = 0;
    for (uint256 i = start; i < end; i++) {
        uint256 tokenId = NFT(tokenAddress).safeMint(msg.sender);
        contractTokenIds[tokenAddress].push(tokenId);
        collectionsOfTokenId[tokenAddress] = tokenId;
        count++;
    }
    getNFTCount = count;
}
 function createMarketItem(
    address nftContractAddress,
    uint256 tokenId,
    uint256 price
) public  nonReentrant{
    uint256 itemId = _ItemIdsCounter;
    marketItems[itemId] = MarketItem(
        itemId,
        nftContractAddress,
        tokenId,
        payable(msg.sender),
        payable(address(0)),
        price,
        false
    );
     _ItemIdsCounter++;
    IERC721(nftContractAddress).transferFrom(msg.sender, address(this), tokenId);
    emit MarketItemCreated(
        itemId,
        nftContractAddress,
        tokenId,
        msg.sender,
        address(0),
        price
    );
}
}

Thank you

This is pretty much the only line of code in the specified function which could revert the transaction with the specified error-message.

And what this error-message probably tells you, is that the contract which executed that line of code, did not receive permission from msg.sender to transfer tokenId.

In other words, before executing this using some wallet:

yourContract.createMarketItem(nftContract.address, tokenId, ...)

You should execute this using the same wallet:

nftContract.approve(yourContract.address, tokenId)
1 Like

Do you mean in frontend?

It worked, thank you so much:)

1 Like

It doesn't matter where, as long as you:

  • Execute them chronologically - 1 before 2
  • Execute them using the same account

This account can be an externally-owned account (aka wallet), and it can be a smart-contract account (aka contract), but it has to be the same account which executes the two transactions, where "execute" means slightly different things if done from a wallet and if done from a contract:

  • If done from a wallet, it means - sign each transaction and send it to the node
  • If done from a contract, it means - call each contract function

Okay, got it. I have executed it in fronted after mint fuction

1 Like