♈
Bootcamp-2024
  • Intro
  • 1. Blockchain & Wallet Fundamentals
    • Blockchain Introduction
    • State Machines
    • Cryptography
    • Distributed Networks
    • Game Theory
    • What is Web3
    • MetaMask Wallet Installation
    • Transferring Tokens with MetaMask
  • 2. Smart Contract & Solidity Fundamentals
    • Using Remix
    • Create, compile and publish your first smart contract
    • Interact with already published smart contracts
    • Blockchain Explorer
    • Verify source code on Etherscan
  • 3. Oracles, ERC20 & Chainlink Data Feeds
    • Oracles
    • Create & Deploy ERC20
    • Data Feeds
  • 4. Cross-Chain Tokens With Chainlink CCIP
    • Setting up MetaMask
    • Getting USDC Testnet Tokens
    • Create Smart Contract In Remix
    • Compile and Deploy
    • Approve USDC
    • Send LINK to your Contract
    • Send USDC from Fuji to Sepolia
    • USDC on Sepolia
  • 5. Mentoring Session
  • 6. NFTs & Chainlink Automation
    • NFT Basics
    • Dynamic NFTs
    • Creating an NFT Smart Contract
    • Deploying Your Dynamic NFTs
  • 7. Chainlink CCIP & Cross-Chain NFT dApps
    • Create and deploy CCIP NFT Contracts
    • Mint on Source Chain
    • Fund Contract
    • Mint On Sepolia From Fuji
    • Mint from Destination 2 - Base Sepolia
  • 8. Random Numbers with Chainlink VRF
    • Introduction to Chainlink VRF
    • Hands On Game Using VRF
  • 9. Off-Chain Data with Chainlink Functions
    • Chainlink Functions Playground
    • Setting up MetaMask
    • Remix
    • Functions Subscription
    • Creating The Functions Consumer Contract
    • Sending a Request from Remix
    • City Weather and Examples
    • City Weather on Chainlink Functions
  • 10. Connecting the 🌏 with Chainlink
  • Glossary
Powered by GitBook
On this page
  1. 6. NFTs & Chainlink Automation

Deploying Your Dynamic NFTs

In this section, you will be deploying and interacting with your Dynamic NFTs

PreviousCreating an NFT Smart ContractNext7. Chainlink CCIP & Cross-Chain NFT dApps

Last updated 1 year ago

You will be creating a dynamic NFT of a flower with 3 stages: Seed, Seedling, and Bloom.

Please make sure you've done before you attempt this, as we use tools set up in that section.

Create Our DynamicNFT contract

First, open Remix and create a new workspace, then create a new file called Flowers.sol

This will open an empty file on the right side of your screen which is the IDE. Here you can paste the following code.

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import "@chainlink/contracts/src/v0.8/AutomationCompatible.sol";
import "@openzeppelin/contracts@4.6.0/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts@4.6.0/utils/Counters.sol";

contract Flower is ERC721, ERC721URIStorage, AutomationCompatibleInterface {
    using Counters for Counters.Counter;

    Counters.Counter public tokenIdCounter;
 
   // Metadata information for each stage of the NFT on IPFS.
    string[] IpfsUri = [
        "<https://ipfs.io/ipfs/QmVCZ6hVENjkdCDLMoovNCR5S6bSisUQnBKPibb8XXSJqF/seed.json>",
        "<https://ipfs.io/ipfs/QmVCZ6hVENjkdCDLMoovNCR5S6bSisUQnBKPibb8XXSJqF/purple-sprout.json>",
        "<https://ipfs.io/ipfs/QmVCZ6hVENjkdCDLMoovNCR5S6bSisUQnBKPibb8XXSJqF/purple-blooms.json>"
    ];

    uint public immutable interval;
    uint public lastTimeStamp;

    constructor(uint updateInterval) ERC721("Flower Bootcamp 2024", "FLO") {
        interval = updateInterval;
        lastTimeStamp = block.timestamp;
        safeMint(msg.sender);
    }

    function safeMint(address to) public {
        uint256 tokenId = tokenIdCounter.current();
        tokenIdCounter.increment();
        _safeMint(to, tokenId);
        _setTokenURI(tokenId, IpfsUri[0]);
    }

    // determine the stage of the flower growth
    function flowerStage(uint256 _tokenId) public view returns (uint256) {
        string memory _uri = tokenURI(_tokenId);
        // Seed
        if (compareStrings(_uri, IpfsUri[0])) {
            return 0;
        }
        // Sprout
        if (
            compareStrings(_uri, IpfsUri[1])
        ) {
            return 1;
        }
        // Must be a Bloom
        return 2;
    }

    function growFlower(uint256 _tokenId) public {
        if(flowerStage(_tokenId) >= 2){return;}
        // Get the current stage of the flower and add 1
        uint256 newVal = flowerStage(_tokenId) + 1;
        // store the new URI
        string memory newUri = IpfsUri[newVal];
        // Update the URI
        _setTokenURI(_tokenId, newUri);
    }

    // helper function to compare strings
    function compareStrings(string memory a, string memory b)
        public pure returns (bool)
    {
        return (keccak256(abi.encodePacked((a))) ==
            keccak256(abi.encodePacked((b))));
    }

    function checkUpkeep(bytes calldata /* checkData */) external view override returns (bool upkeepNeeded, bytes memory /* performData */) {
        if ((block.timestamp - lastTimeStamp) > interval ) {
            uint256 tokenId = tokenIdCounter.current() - 1;
            if (flowerStage(tokenId) < 2) {
                upkeepNeeded = true;
            }
        }
        // We don't use the checkData in this example. The checkData is defined when the Upkeep was registered.
    }

    function performUpkeep(bytes calldata /* performData */) external override {
        //We highly recommend revalidating the upkeep in the performUpkeep function
        if ((block.timestamp - lastTimeStamp) > interval ) {
            uint256 tokenId = tokenIdCounter.current() - 1;
            if (flowerStage(tokenId) < 2) {
                lastTimeStamp = block.timestamp;            
                growFlower(tokenId);
            }
        }
        // We don't use the performData in this example. The performData is generated by the Automation's call to your checkUpkeep function
    }
    
    function tokenURI(uint256 tokenId)
        public view override(ERC721, ERC721URIStorage) returns (string memory)
    {
        return super.tokenURI(tokenId);
    }

    // The following function is an override required by Solidity.
    function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage)
    {
        super._burn(tokenId);
    }

}

Compile

Next we want to make sure that the contract has compiled with the correct version, so head to the Solidity Compiler tab on the left side of remix. Here we will ensure Auto compile is checked.

Deploy & Run Transaction

Next we navigate to the Deploy & Run Transactions tab and select our enviroment to Injected Provider - Metamask. We must ensure that we are connected to Sepolia test network.

Then, in the updateInterval field we want to input 120. This represents the interval between each attempt by Chainlink Automation to "trigger" the contract to update the NFT's metadata from seed stage to flower stage . More on Chainlink Automation's operations later in this page.

After that we want to deploy the contract by clicking the orange transact button and confirming the Metamask transaction.

In our constructor, we are minting an NFT to the deployer (your wallet address), so once the contract is deployed you should see that the balanceOf for your address will be 1.

Before we use Chainlink Automation, let's manually call the growFlower function in our smart contract on remix, passing in the _tokenId of 0 which is the NFT we have just minted (since it's the first NFT minted!). This will cause our seed to change into a seedling.

Then we will go back to Opensea to view our NFT and click the 3 dots in the top right corner, and select refresh metadata. This will tell Opensea to refresh the image of our NFT.

We can also force refresh by doing the following in our browser: Right Click → Inspect → Application → Storage → Clear Site Data

Once you’ve done both of these steps you should now be able to refresh the Opensea page and see that your seed has now changed into a seedling.

Next, we will integrate Chainlink Automation to automatically do this process for us, so we don’t have to manually call growFlower.

First, we will go to remix and call safeMint passing in your wallet address, this will mint you a new NFT. In Opensea you will now see that you have 2 NFTs, and your newly minted NFT (token id 1, since its the second minted NFT) will be a seed.

We will use Custom Logic for this example, so select that option and click next.

In Target contract address put the address of your deployed NFT contract from Remix, and click next.

Lastly you want to click Register Upkeep at the bottom of the page and confirm the transactions. You will see a pop-up like this appear.

After a few seconds, it will update once it’s been finalised and the button will appear with View Upkeep which you should click.

When we deployed our smart contract, we'd put 120 seconds as the updateInterval. So every 2 minutes, Chainlink Automation will call checkUpkeep() in our smart contract to run the custom logic we have written there. So after a couple of minutes, if you head back to Opensea and look at your minted NFT select refresh metadata and reset your cache as we did before. You will then see that your NFT has started changing and eventually, it will be fully bloomed.

You can view this NFT on by copying your contract address, and pasting it in the Opensea searchbar

Then we will head to . Make sure you're Metamask is still connected to Ethereum Sepolia, and select Register new Upkeep

This will then bring you to the Upkeep Details page, where you can give your upkeep a name. Also, ensure that your Admin Address is the wallet you are currently using in Metamask. You will also need to fund your upkeep with at least 3 LINK. If you don’t have any LINK you can obtain some from the .

Opensea
https://automation.chain.link/
Chainlink Faucet
Section 2 Smart Contract fundamentals
Dynamic NFT with 3 Stages: Seed, Seedling, Bloom
Select Create to generate a new workspace
Create a new file named 'Flowers.sol'
Select 'Auto Compile'
Select Injected Provider and ensure you are on Sepolia Test Network
Set updateInterval paramter to 120 then click transact
You now have 1 minted NFT to your wallet
Paste your contract address in the Opensea search bar
Your minted NFT on Opensea
Call growFlower passing in '0' as a paramater
Select 'Refresh Metadata'
Select 'Clear Site Data'
Refresh the page to see your Seedling
Pass your wallet address as a parameter to 'safeMint' and click transact
Select 'Register new Upkeep'
Select 'Custom Logic'
Paste your contract address here
Fill in Upkeep Details
Wait for transaction to be confirmed
Your new NFT will have started blooming automatically using Chainlink Automation