LogoLogo
Manifold for Developers
Manifold for Developers
  • Introduction
  • Shopify Merch Bridge
    • Overview
    • Tutorial
      • Step 1: Product Gate Setup
        • 1.1: Configure the Product
        • 1.2: Install Manifold Merch Bridge
        • 1.2: Create a New Product Gate
        • 1.3: Link a Product to the Gate
        • 1.4: Add Rules
      • Step 2: Store Theme Setup
        • 2.1 The Theme Editor
        • 2.2 Product Page Setup
        • 2.3 Cart Page Setup
    • Advanced Configuration
    • FAQ / Error Help
    • Reference
      • Product and Gate Configuration
        • Shopify Products
        • Product Gates
          • Gate Products
          • Rules
      • Custom Themes
      • Updating to the Latest Version
      • UI Configuration Options
      • Advanced Usage
      • Common Issues
  • Guides
    • Getting Started
    • HTML
    • React
    • NextJS
    • Vue
    • Wix
    • Squarespace
      • Simple Squarespace Site
      • Customised Squarespace Template
  • Resources
    • Apps
      • Grant Types
    • Widgets
      • Directory
      • Manifold CSS Variables
        • Scheme Utility Classes
        • List of Manifold CSS Variables
      • Connect Widget
        • Blockchain Interaction
        • Wallet Authentication
        • Data Client
          • NFT Information Retrieval
            • getNFT
            • getNFTsOfOwner
            • ownerHasNFT
            • getCollectors
          • Data Storage and Retrieval
        • Advanced Configuration
        • Customization & Styling
        • Automatic Error Handling
      • Campaign Widget
        • Campaign Creation
          • Questionnaire
        • Campaign Progress
        • Customization & Styling
      • Curation Widget
      • Marketplace Widgets
        • Widgets
          • Data Attributes
          • Layout Widgets
          • Card Widgets
          • Listing Widgets
        • Window Events
        • Troubleshooting
        • Customization & Styling
        • Version Change Notes
          • 3.2.1 - CSS Selector Changes
          • 3.1.1 - CSS Selector Changes
      • Claim Widgets
        • Widgets
          • Data Attributes
          • Complete Claim Widget
          • Buy Button Only Widget
          • Mint Count Widget
        • Troubleshooting
        • Customization & Styling
        • Version Change Notes
          • 1.7.0, 1.7.1 - CSS Selector Changes
      • Restricted Token Widget
        • Customization & Styling
      • Wallet Identity Widget
        • Customization & Styling
      • Subscription Widget
      • 6551 Display Widget
    • Manifold Ethereum Provider
  • Tools and APIs
    • Merkle Tree Tool
    • Snapshot Tool
    • Discord Tools
    • Server-Side Session Authentication
      • Signature Grant
      • Authorization Code Grant
  • Smart Contracts
    • Manifold Creator
      • Contracts
        • Creator Core
          • Common Functions
          • ERC721 Functions
          • ERC1155 Functions
        • Extensions
          • Extensions Functions
          • Extensions Examples
          • Extensions Deployment Guide
            • Dynamic NFT Extension
            • Lazy Mint Extension ERC1155
            • Lazy Mint Extension ERC721
        • Mint Permissions
          • Mint Permissions Functions
      • Prior Versions
        • 1.0.x
          • Creator Core
            • Common Functions
            • ERC721 Functions
            • ERC1155 Functions
          • Extensions
            • Extensions Functions
            • Extensions Examples
            • Extensions Deployment Guide
              • Dynamic NFT Extension
              • Lazy Mint Extension ERC1155
              • Lazy Mint Extension ERC721
          • Mint Permissions
            • Mint Permissions Functions
        • 2.0.x
          • Creator Core
            • Common Functions
            • ERC721 Functions
            • ERC1155 Functions
          • Extensions
            • Extensions Functions
            • Extensions Examples
            • Extensions Deployment Guide
              • Dynamic NFT Extension
              • Lazy Mint Extension ERC1155
              • Lazy Mint Extension ERC721
          • Mint Permissions
            • Mint Permissions Functions
    • Marketplace
      • Identity Verifier
    • Royalty Registry
  • Contact Us
Powered by GitBook
On this page
  • Intro
  • Contract
  • How to Deploy
  • FAQ

Was this helpful?

  1. Smart Contracts
  2. Manifold Creator
  3. Prior Versions
  4. 2.0.x
  5. Extensions
  6. Extensions Deployment Guide

Dynamic NFT Extension

Last updated 2 years ago

Was this helpful?

Intro

One of the more common requests we get is "wen dynamic NFTs with Manifold". Well - probably the easiest way is with HTML NFTs as described . But using an extension to make a dynamic NFT is also possible and desirable in some cases. Here we'll write an extension that displays two different pieces of art depending on the current block timestamp when the token URI is retrieved.

Before we start deploying things, let's take a look at the contract. We'll be making an extension for an ERC721 token, but a similar process can be done for ERC1155s.

Contract

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/// @author: manifold.xyz

import "@manifoldxyz/libraries-solidity/contracts/access/AdminControl.sol";
import "@manifoldxyz/creator-core-solidity/contracts/core/IERC721CreatorCore.sol";
import "@manifoldxyz/creator-core-solidity/contracts/extensions/ICreatorExtensionTokenURI.sol";

import "@openzeppelin/contracts/utils/introspection/ERC165.sol";

contract Tutorial is AdminControl, ICreatorExtensionTokenURI{
    address private _core;
    string private _firstURI;
    string private _secondURI;

    function initialize(address core) public adminRequired {
      _core = core;
      IERC721CreatorCore(_core).mintExtension(msg.sender);
    }

    function supportsInterface(bytes4 interfaceId) public view virtual override(AdminControl, IERC165) returns (bool) {
        return interfaceId == type(ICreatorExtensionTokenURI).interfaceId || AdminControl.supportsInterface(interfaceId) || super.supportsInterface(interfaceId);
    }

    function setURIs(string memory firstURI, string memory secondURI) public adminRequired {
      _firstURI = firstURI;
      _secondURI = secondURI;
    }

    function tokenURI(address core, uint256 tokenId) external view override returns (string memory) {
        require(core == _core, "Invalid token");
        if (block.timestamp % 2 == 0) {
          return _firstURI;
        } else {
          return _secondURI;
        }
    }
}

Let's walk through the contract here before we think about deploying it.

The first function we have there is called initialize and this is where we actually mint the token. It is important to note that we're taking the assumption here that the extension will only be used for one token, or at least that every token minted on this contract has the same set of URIs. When we call this function, we're saving the address of our core contract, and calling the mintExtension function on it to mint the token.

The supportsInterface function simply tells other contracts that are calling this one what functions it supports.

The setURIs function lets us set the two different tokenURIs we want to return, depending on the block number. It also lets us update this information at any time in the future.

Finally, the tokenURI function is where the "magic" happens. We first check that the core address is the same as we expect, and then if the time of the block is even, we return the first URI, otherwise we return the second.

How to Deploy

As this tutorial is focused on actual contracts and Manifold-specific logic, I won't go too in-depth into tools. I really like Remix for this kind of thing, but use whatever you are most comfortable with! Here is the order of how I would deploy:

  1. Deploy your creator contract using Manifold Studio (in this example, you will want a 721 contract)

  2. Set the two baseURIs for your extension with write function #4. setURIs. You can do this in via remix, or via the etherscan page for the extension contract.

  3. Initialize the extension with write function #2: initialize. You can do this in via remix, or via the etherscan page for the extension contract.

You should now be able to see your token on OpenSea TestNet via: https://testnets.opensea.io/assets/<CREATOR_CONTRACT_ADDRESS>/1

There are just a couple things to note here. The first is that this is token #1 on the creator contract. Notice the OpenSea URL which has the address of the creator contract. The other thing to note is minute - but the data is cached for performance reasons on OpenSea's side, so even though this technically switches which image quite often, you may not find that to be the case on many marketplace websites. Perhaps yours switches once a month, in which case, there is no issue.

FAQ

Is this contract an ERC721 contract?

No - but it helps you mint a token on an ERC721 contract (your core contract)

Can this deployed contract be re-used?

Not in its current form. However, an extension can be written in such a way that it manages tokens for many different core contracts.

What is the gas cost for deploying an extension like this?

This particular extension cost me 1,515,346 gas to deploy. At gas prices of 40 gwei, that would be about 0.06 ETH.

Deploy the extension contract above using .

Register the extension with write as proxy function #14: registerExtension on your creator contract from step 1. You can access this function by visiting the etherscan page for your contract, then clicking contract -> write as proxy. You will want to enter the address from the extension contract from step 2 in the extension parameter, and a blank space for the baseURI parameter.

here
remix