Empty string tokenURI with proper record of baseURI and tokenURIs minted

I have made an NFTs contract with all Openzeppelin standards.

I have minted a token but the return function of the concatenated structure for use on platforms like OpenSea does not return anything:

Check the corresponding getters and their correct reading:
para_mandar

The Tokenuri function is in two standards. In the ERC721 and in the ERC721URIStorage that I also inherit

ERC721

  /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        string memory baseURI = _baseURI();
        return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
    }

ERC721URIStorage

   /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721URIStorage: URI query for nonexistent token");

        string memory _tokenURI = _tokenURIs[tokenId];
        string memory base = _baseURI();

        // If there is no base URI, return the token URI.
        if (bytes(base).length == 0) {
            return _tokenURI;
        }
        // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
        if (bytes(_tokenURI).length > 0) {
            return string(abi.encodePacked(base, _tokenURI));
        }

        return super.tokenURI(tokenId);
    }

Why does it return an empty string if the registration was successful?

The contract was very dirty with multiple unnecessary inheritances in my opinion.
I think the problem was that there were two different arrays to hold the IDs.
I have cleared the contract and now it returns the metadata correctly

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

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract GothicStars is ERC721Enumerable, Ownable  
{

    string public baseURI;
    mapping(uint256 => string) private _tokenURIs;
    
    constructor(string memory name, string memory symbol) 
    ERC721(name, symbol) 
    {
        setBaseURI("https://ipfs.io/ipfs/");

    }

         /**
     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
     * by default, can be overriden in child contracts.
     */
    function _baseURI() internal view virtual override returns (string memory) 
    {
        return baseURI;
    }

    function mintToken(address to, string memory metadata) public onlyOwner 
    {

    uint256 supply = totalSupply();
    _safeMint(to, supply + 1);
    _setTokenURI(supply + 1, metadata);

    }
     

     function multipleMInt(address to, string[] memory hashes) public onlyOwner 
     {

        uint256 supply = totalSupply();

        for (uint256 i = 0; i < hashes.length; i++) {
            _safeMint(to, supply + 1);
            _setTokenURI(supply + 1, hashes[i]);
            supply++;
        }
    }

    function tokensOfOwner(address _owner) public view returns (uint256[] memory)
    {
        uint256 ownerTokenCount = balanceOf(_owner);
        uint256[] memory tokenIds = new uint256[](ownerTokenCount);

        for (uint256 i; i < ownerTokenCount; i++) {
            tokenIds[i] = tokenOfOwnerByIndex(_owner, i);
        }
        return tokenIds;
    }

    function setBaseURI(string memory _newBaseURI) public onlyOwner 
    {
        baseURI = _newBaseURI;
    }

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view override returns (string memory) 
    {
        require(_exists(tokenId), "ERC721URIStorage: URI query for nonexistent token");

        string memory _tokenURI = _tokenURIs[tokenId];
        string memory base = _baseURI();

        // If there is no base URI, return the token URI.
        if (bytes(base).length == 0) {
            return _tokenURI;
        }
        // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
        if (bytes(_tokenURI).length > 0) {
            return string(abi.encodePacked(base, _tokenURI));
        }

        return super.tokenURI(tokenId);
    }

    /**
     * @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _setTokenURI(uint256 tokenId, string memory _tokenURI) public 
    {
        require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
        _tokenURIs[tokenId] = _tokenURI;
    }

    
}
2 Likes

Be extremely careful when inheriting contracts. Here's a good article of how inheritance might be abused if done incorrectly.

2 Likes

You are absolutely right.

Apart from being an unnecessary expense of storage. But many times it is thought that "having everything" is much better.
Knowing what is needed, and what it is needed for, is enough.

2 Likes