A Developer Guide to Creating a Dynamic NFT

Posted By : Saurabh

Mar 13, 2023

Understanding Dynamic NFTs

 

Dynamic NFTs differ from static NFTs due to the dynamic nature of their metadata. In this article, we look at how to create d-NFT smart contract that can be minted manually. Also, we introduce Chainlink Automation (for automatic minting), a smart-contract automatic service that triggers changes based on predefined conditions, and explain how it can be combined with Chainlink Data Feeds or any API to build autonomous and decentralized dynamic NFT.

 

Prerequisites:

 

  • Knowledge of NFTs
  • An NFT marketplace
  • Set up a crypto wallet
  • Cryptocurrency for paying gas to mint NFTs
  • An Integrated Development Environment for setting up a contract

 

dNFT Development:

 

We have understood dNFTs. Now, let's create one. An important factor in the creation of a dNFT is how to include the information and functions necessary to build a secured NFT. Let's see how this works.

 

Step 1 - Setting up the Contract:

 

First, we need to create a Solidity smart contract for a (DNFT) that inherits from the ERC721 and Ownable contracts. The contract imports functionality from other contracts & creates a private variable to track the next token ID to be minted. The contract's constructor calls the constructor of the ERC721 contract. This sets up the metadata for the NFTs that will be created using this contract.

 

pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
 
contract DynamicNFT is ERC721,Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
constructor() ERC721("Dynamic NFT", "DNFT") {}
}

 

Step 2 - Creating an NFTMetadata structure & mapping: 

 

Next, we define a structure for NFTMetadata containing five fields: name, description, imageURI, createdAt, and lastUpdated. Then we do a mapping of  _tokenMetadata that maps a uint256 token ID to its corresponding NFTMetadata struct. The mapping is made private, so it can only be accessed and modified within the contract. This mapping is used to store metadata information for each token ID in the contract.

 

struct NFTMetadata {
string name;
string description;
string imageURI;
uint256 createdAt;
uint256 lastUpdated;
}
 
mapping(uint256 => NFTMetadata) private _tokenMetadata;
 

 

Step 3 - Necessary functionalities for updating and handling metadata change:

 

A. updateTokenMetadata ->

 

This function allows the owner of the contract to update the metadata of a token with the specified tokenId. It checks whether the token with the given ID exists using the _exists function and whether the owner of the token is the same as the person calling the function. If correct, the function calls the _setTokenMetadata.

 

function updateTokenMetadata(uint256 tokenId, string memory name, string memory description, string memory imageURI) public onlyOwner {
require(_exists(tokenId), "Token does not exist");
require(ownerOf(tokenId) == msg.sender, "Only token owner can update metadata");
_setTokenMetadata(tokenId, name, description, imageURI);
}

 

B. setTokenMetadata ->

 

The next function is used to update the metadata of the token with the given tokenId.
It is a private function that takes in the tokenId, name, description, and imageURI parameters and updates the NFTMetadata struct for the given tokenId. It sets the name, description, and imageURI fields to the values provided, and also sets the lastUpdated field to the current block timestamp. If the createdAt field is 0 (meaning it hasn't been set before), it sets it to the current block timestamp. The function then emits a MetadataUpdated event with the updated metadata.

 

function _setTokenMetadata(uint256 tokenId, string memory name, string memory description, string memory imageURI) private {
NFTMetadata storage metadata = _tokenMetadata[tokenId];
metadata.name = name;
metadata.description = description;
metadata.imageURI = imageURI;
metadata.lastUpdated = block.timestamp;
 
if (metadata.createdAt == 0) {
metadata.createdAt = block.timestamp;
emit MetadataUpdated(tokenId, name, description, imageURI);
}

                            
C. getTokenMetadata ->

 

This function is a public view function that is used to return the NFTMetadata struct for a given tokenId. It first checks whether the token with the given tokenId exists using the _exists function, and then returns the metadata associated with that token using the _tokenMetadata mapping. It is view-only as it doesn't modify the contract state.

function getTokenMetadata(uint256 tokenId) public view returns (NFTMetadata memory) {
require(_exists(tokenId), "Token does not exist");
return _tokenMetadata[tokenId];
}
Step:4 Minting the NFT & updating contract : -
Finally we create a public mint function that mints a new DNFT token to the contract owner's address. 
It takes in name, description, and imageURI parameters and sets the metadata of the new token using the _setTokenMetadata function. 
It will return the ID of the new token that was minted.
  
  
function mint(string memory name, string memory description, string memory imageURI) public onlyOwner returns (uint256) {
_tokenIdCounter.increment();
uint256 tokenId = _tokenIdCounter.current();
_safeMint(msg.sender, tokenId);
_setTokenMetadata(tokenId, name, description, imageURI);
return tokenId;
}
event MetadataUpdated(uint256 indexed tokenId, string name, string description, string imageURI);

 

dNFT metadata changes are triggered by both on and off-chain events taking place in the real world. Blockchains are inherently unable to work upon the off-chain data, 
thus we need some other technology if we wish to automate the minting process. Chainlink Data Feeds is an off-chain data delivery service that can securely use any real-world data and with the help of this, we can manipulate the meta-data of our NFT.
Below is a brief explanation for achieving this. 

 

Step A - Getting Off-Chain Data:

 

To get off-chain data for NFT smart contracts, use Chainlink oracles in three steps:

 

Chainlink price feeds: retrieves asset prices in smart contracts.
Chainlink VRF: consumes randomness in smart contracts.
Chainlink contract library: request and receive API data.

 

Step B - Querying the Data Feed and Modifying NFT:

 

Once the data is on-chain, query the data feed from your smart contracts. Depending on the values provided by Chainlink ,  modification in  the NFT assets can be made  and thus we can proceed with the minting of NFT.

 

Step C - Minting NFT:

 

Once all necessary changes are made, the metadata of the NFT will change by the function written on the smart contract. The NFT is ready to be sold in the marketplace.

 

Conclusion:

 

To create dNFTs, one can use Chainlink. It is a secure smart-contract automatic service that triggers dynamic NFT changes when certain set rules or predefined conditions are met.
Combined with Chainlink Data Feeds and Any API, it provides a simple way to build autonomous and decentralized NFTs and ensure d-NFTs will perform exactly as programmed to meet certain defined thresholds & conditions. 

If you have a project in mind that you want to discuss and want to make a reality, please connect with our skilled blockchain and NFT developers for more information. 

Leave a

Comment

Name is required

Invalid Name

Comment is required

Recaptcha is required.

blog-detail

September 8, 2024 at 02:24 am

Your comment is awaiting moderation.

By using this site, you allow our use of cookies. For more information on the cookies we use and how to delete or block them, please read our cookie notice.

Chat with Us
Telegram Button
Youtube Button
Contact Us

Oodles | Blockchain Development Company

Name is required

Please enter a valid Name

Please enter a valid Phone Number

Please remove URL from text