paint-brush
How to Create an NFT Reveal With Solidityby@sirfedos
928 reads
928 reads

How to Create an NFT Reveal With Solidity

by Sir FedosMay 10th, 2023
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Reveal functionality stands for hiding NFT picture with some placeholder image initially. In this article we will go through the process of implementing such behavior and analyze why you’d possibly use it in your collection. NFTs are following [ERC721] standard of a non-fungible token and all of the generative collections follow it.
featured image - How to Create an NFT Reveal With Solidity
Sir Fedos HackerNoon profile picture

As the NFT area is growing every day, more new mechanics and experiments are coming to the world of priceless pixels. One of the popular approaches during NFT launches is a Reveal toggle functionality.


Reveal functionality stands for hiding the NFT picture with some placeholder image initially. In this article we will go through the process of implementing such behavior and analyze why you’d possibly use it in your collection.

Theory

Firstly, let’s dive into the theory of NFTs to define the steps needed for our Reveal. NFTs are following ERC721 standard of a non-fungible token and all of the generative collections follow ERC721Metadata interface as well.


interface ERC721Metadata {    
  function name() external view returns (string _name);
  function symbol() external view returns (string _symbol);   
  function tokenURI(uint256 _tokenId) external view returns (string);
}  


This interface allows us to specify name, symbol and tokenURI for each NFT in our collection. What we are interested here is tokenURI function that is responsible for returning item’s metadata value.


So our task for implementing Reveal is the following:

  1. Create a flag variable in Smart Contract that indicates whether NFTs are hidden/revealed
  2. Add external function for toggling (or setting to true) flag variable value, that has to be accessed only by owner
  3. Override tokenURI method to return the same single metadata file for every NFT during the Hidden phase and appropriate NFT metadata after reveal
  4. Upload Hidden phase metadata to IPFS

Updating Smart Contract

I won’t go deep with explaining the common NFT smart-contract, assuming that you have one already ;) If not, then have a look on ERC721A standard that provides gas-efficient minting, so your customers won’t pay a lot for transaction fee. I’ll be using ERC721A in this tutorial as well.

Let’s add the flag property to existing Contract class and initialize it with false:


bool public revealed = false;


Then let’s add a function for changing our revealed value and make sure it could only be called by the owner. For doing that, I’d suggest derive from the OpenZeppelin Ownable contract that will add onlyOwner modifier for us.


contract HiddenReveal is ERC721A, Ownable {
  bool public revealed = false;  
  function reveal() external onlyOwner {revealed = true;}
}


As you can see, I’m not toggling the revealed value but just set it true. In this way you won’t make your community nervous that you might hide their NFTs again after revealing 🙃 You can make it to toggle current value or set to the value passed into the function.

Now is the most interesting part: overriding tokenURI function based on our revealed flag.


function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
  if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
  string memory baseURI = _baseURI();  
  string memory metadataPointerId = !revealed ? 'unrevealed' : _toString(tokenId);  
  string memory result = string(abi.encodePacked(baseURI, metadataPointerId, '.json'));  

  return bytes(baseURI).length != 0 ? result : '';  
}


  1. Check if token with such tokenId exists and revert with Custom Error if not
  2. Take the baseURI value to concat it with tokenId and get metadata URL
  3. Check the current revealed state and if it’s false then use unrevealed string instead of tokenId, store it into metadataPointerId
  4. Concat baseURI, metadataPointerId and .json extension
  5. Return the result is baseURI is specified


Final result for revealed=false will be something like this, for every NFT:

https://www.mybaseurilink.com/folderipfshash/unrevealed.json or ipfs://folderipfshash/unrevealed.json


Here is the full Smart Contract code with Hide/Reveal functionality:


contract HiddenReveal is ERC721A, Ownable {
  string private _baseTokenURI;
  bool public revealed = false;  

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

  function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {  
    if (!_exists(tokenId)) revert URIQueryForNonexistentToken();  

    string memory baseURI = _baseURI();  
    string memory metadataPointerId = !revealed ? 'unrevealed' : _toString(tokenId);  
    string memory result = string(abi.encodePacked(baseURI, metadataPointerId, '.json'));  

    return bytes(baseURI).length != 0 ? result : '';  
  }  

  function setBaseURI(string calldata baseURI) external onlyOwner {  
    _baseTokenURI = baseURI;  
  }  

  function reveal() external onlyOwner {  
    revealed = true;  
  }
}  


Please, note that this Smart Contract is NOT production ready, as it doesn’t have mint functions lol. But you can use it as a reference to plug functionality into your solution

Setting Up IPFS

After finishing with Smart Contract part, you have to set up the storage for your Unrevealed items metadata. Generally, you will just need to store a placeholder image and unrevealed.json metadata files in a separate IPFS folder.


Then you connect your Smart Contract to the IPFS storage through calling setBaseURI on contract with the folder’s hash.


Here is an example of unrevealed.json:


{
  "name": "@sir_fedos Hide/Reveal",
  "description": "Tutorial on how to create Reveal functionality on your NFT",
  "image": "ipfs://hAshToYoUrPlAcEhoLderImAge"
}

Conclusion

All in all, Reveal functionality is a great marketing tool and a tiny mechanic that could be added to every NFT drop with ease. Moreover, you can specify multiple reveal stages, define them as an enum and add some entertainment to the post-mint phase of your project!

Follow for more tutorials!


Also published here.