You did not set the TokenURI for NFT, so when NFT gets the URI, BaseURI + TokenID is used.Look at the source code.
/**
* @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 _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));
}
// If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.
return string(abi.encodePacked(base, tokenId.toString()));
}
It returns the URI: https://gateway.pinata.cloud/ipfs/0
This, of course, is not ideal, the ideal URI should be: https://gateway.pinata.cloud/ipfs/Qmf43nycxRXdwdq3GqT7SKU3MvRyBvbpjzufzZR8ASkMGb
I think you see the reason for the problem here.
The next thing you need to do is call _setTokenUri to store the CID from IPFS so that you can get the correct IPFS link when reading the NFT.
/**
* @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
_tokenURIs[tokenId] = _tokenURI;
}
This function is an internal function, and you should provide an external function to use it, but security must be taken care of, or anyone can modify it!
It's possible to publish folders to IPFS.
So you'll put metadata files for all the NFTs into that folder and receive an IPFS hash. To access individual file use this: folderIPFSHash/fileName
In the ERC-721 contract, add the folderIPFSHash
into _baseURI
variable, and for each tokenId
a unique metadata path can be generated by concatenating strings to form: _baseURI/tokenId.json
as output for the tokenURI
function.
Best Answer
You need to declare an empty variable at the beginning of your smart contract:
Then you need to create a function to control the URI, this function takes a variable called _newURI as a parameter, this is the CID of pinata.
As you can see the _baseURI( ) function returns the URI of the files, and the setURI( ) function is the one that will override the newURI variable (which is the one that _baseURI returns)
When you deploy your smart contract you will need to set the CID of pinata with the placeholder images, and whenever you want to reveal them you just need to call setURI( ) with the updated CID.