Welcome to the world of dynamic NFTs! In this guide, you’ll build a smart contract and learn how to create a dynamic NFT that changes in real time by connecting your smart contract to an oracle using Chainlink Automation! For a deeper understanding of dynamic NFTs and why they matter, check out our previous guide.
Be sure you understand how NFT works and how to upload files to IPFS. If you don’t, you can check out this article here.
How to Create a Dynamic NFT
In this tutorial, you’ll learn how to:
Deploy a dynamic NFT smart contract.
Connect to Chainlink Keepers.
View the dynamic NFT on Opensea.
Without further ado, let’s get started!
Estimated time to follow along 15 - 25 mins.
Step 1: Creating the starter project
Launch the Remix IDE on the Remix website here. Next, on the Remix interface in the top left corner, click on the file and create a new file.
Step 2: Implementing our dynamic NFT
Before we start coding, we’ll need to do a few imports, as we don’t need to build everything from scratch. In your dynamicNft.sol file, import ERC721Uristorage, and counters.sol.
Here is what the import does:
ERC721URIStorage.sol: This extends the standard ERC721 token contract with the ability to store and manage token URIs. Token URIs are used to associate external metadata, such as images or descriptions, with each NFT.
Counters.sol: This provides a utility for creating and managing counters, which are often used for generating unique token IDs in ERC721. It helps to keep track of the number of tokens and ensure that each token has a unique identifier within a contract.
Step 3: Coding the functionalities
Having imported the necessary imports, let’s implement our functions next.
Let’s go through each of the code snippets:
contract CovNft is ERC721, ERC721URIStorage inherits its functionalities from the contracts we imported.
Counters for Token Tracking
using Counters for Counters.Counter: This line introduces the
Counterslibrary to the contract, specifically the
Countertype. It sets up a mechanism for tracking the number of unique ERC721 tokens created.
Counters.Counter private _tokenIdCounter: This declares a private variable
Counters.Counter. It is used to keep track of the unique token IDs generated by the contract.
IPFS Links For Images
This initializes an array named
IpfsUri that holds URLs to three different images stored on the InterPlanetary File System (IPFS). These images are associated with the NFTs created by our contract.
uint256 lastTimeStamp: This line declares a variable
lastTimeStampof type uint256. It's used to keep track of the last timestamp when an event occurred.
uint256 interval: This line declares a variable
intervalof type uint256. It's used to store the time interval between Chainlink upkeeps.
constructor(uint _interval) ERC721("Cov_dNft", "CDN") defines the
constructor function for the contract. It takes an input parameter
_interval, which represents the time interval between Chainlink upkeeps. We then initialize the contract with the name Cov_dNft and the symbol CDN, as required by the ERC721 standard. We also set the
lastTimeStamp variables with the provided
_interval value and the current
safeMint function allows for minting a new NFT. It takes an address
to as an argument, which represents the recipient of the newly minted NFT.
Inside the function:
It retrieves the current value of
_tokenIdCounterto determine the unique ID for the new NFT.
_tokenIdCounterto ensure each newly minted NFT has a unique ID.
Mints the NFT and assigns ownership to the provided address.
And sets the metadata URI for the NFT, which points to additional information about the NFT (e.g., image, description). In this case, it uses the IPFS link stored in the
IpfsUriarray at index
dynamicNft function allows for dynamically updating the metadata of an existing NFT, allowing it to change. It takes a uint256 argument
_tokenId, which identifies the NFT to be updated.
Inside the function:
It determines the current stage of the NFT by calling the
nextStagefor the NFT, looping back to the first stage if the current stage is at its maximum (2 or greater).
Fetches the metadata URI for the next stage from the
Updates the metadata URI of the NFT associated with the provided
newUri. This effectively changes the NFT's appearance or attributes based on its current stage.
NftStage function is used to set the stage of an existing NFT based on its metadata URI. It takes a uint256 argument
_tokenId, which identifies the NFT for which you want to determine the stage. It first retrieves the metadata URI of the NFT with the provided
_tokenId using the
tokenURI function. It then compares this metadata URI to the URIs stored in the
IpfsUri array to identify which stage the NFT corresponds to and checks if the metadata URI matches the URI at index 0 of the
IpfsURI array. It returns 0 and does the same for index 1 and index 2.
This function is responsible for comparing two strings, “a” and “b,” to check if they are equal, which serves as a helper function in the
NftStage function. We utilized the
keccak256 hash function to compute the cryptographic hash of both strings and compared the resulting hash values. Hence, if the hash values match, it returns true, indicating that the two strings are equal; otherwise, it returns false.
tokenURI function is used to retrieve the metadata URI associated with a specific token ID. It takes a
tokenId as input and returns a string representing the URI where the metadata for that token is stored.
Step 4: Make the contract keepers compatible
To make our contract keepers compatible, we need to add two functions:
performUpkeep. You can read more about them here. Let’s implement the two functions.
checkUpkeep function is used to determine whether upkeep is needed for our smart contract. It calculates if the upkeep is needed by comparing the current time
block.timestamp with the
lastTimeStamp and checking if it exceeds the specified interval. If the time difference is greater than the interval, it sets
upkeepNeeded to true, indicating that changes are required.
This checks if
block.timestamp - lastTimeStamp is greater than the specified interval. If this condition is met, it updates the NFT. In response, it updates the
lastTimeStamp to the current
block.timestamp to reset the upkeep timer. After updating the timestamp, it calls the
dynamicNft function with the argument
0, which contains the actions required to update the NFT.
Step 5: Compiling and deploying the smart contract
To compile our contract, simply navigate to the compiler tab on the left and click on compile as shown.
After you’ve successfully compiled the contract, click on the deploy tab to deploy our contract. Choose Injected Provider-Metamask from the lists of environments, set the constructor value to any value (for this guide, we used 1) and deploy your contract.
You should see something similar to this:
Step 6: Minting an NFT
To mint the newly deployed NFT, click on the deployed contract, then click on safeMint, and paste your wallet address (which you can copy from your MetaMask). After minting the NFT, you can then view it on OpenSea.
You can view the minted NFT by copying the contract address and viewing it on OpenSea here.
We just minted a static NFT; our goal is to make our NFT dynamic -i.e. to keep changing to different NFTs in real time. Let’s see how we can achieve this using Chainlink.
Step 7: Verifying our NFTs
To automate our NFTs, we’ll need to utilize Chainlink keepers. We won’t be able to cover the intricacies of what it’s all about in this guide, but you can read more here. Before we can automate our NFT, let’s verify it. Simply go to the plugins icon in Remix and search for Contract Verification - Etherscan.
Click the Activate button to activate the plugin. Obtain your Etherscan API key by creating an account on Etherscan here. Get the API key and set it on Remix.
Now, navigate to Etherscan's Contract Verification section, select the contract you wish to verify, and click the Verify button.
Step 8: Automating our NFT
We can now automate our NFT using Chainlink keepers. To do that, click here to go to the Chainlink page for you to register your contract.
Once you are on the Chainlink keepers page, click on Register new Upkeep, register the deployed contract, and choose Time-based upkeep as shown.
On the next page, enter the contract address and select dynamicNft as the target function and 0 as the _tokenId, which represents the deployed NFT.
Specify the timeframe for your NFT to undergo continuous changes. In this article, we use 1 minute as the example timeframe.
Now, fund the upkeep by getting a LINK token from this faucet and click on Register Upkeep.
Step 9: Checking the NFT on OpenSea
Once the keeper has been deployed for the contract successfully, you can then go to Opensea and see how the initial minted NFT keeps changing to a different NFT when we refresh, as shown.
And there, you can observe the dynamic NFT you’ve created!
That’s it! By utilizing the power of smart contracts and Chainlink Automation, we've showcased how to bridge the gap between static and dynamic digital assets. This guide has covered each step of creating, deploying, and automating our dynamic NFT, right from setting up our smart contract to witnessing the NFT's transformation on OpenSea in real time. Congratulations, you’ve made it to the end of this tutorial and now understand how to create dynamic NFTs. Check out our other guides for more step-by-step Web3 tutorials!