<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Abdul Rauf</title>
    <description>The latest articles on DEV Community by Abdul Rauf (@lilcoderman).</description>
    <link>https://dev.to/lilcoderman</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F264971%2F8615bcef-48cc-4ae3-b816-11d6bf7d2450.jpeg</url>
      <title>DEV Community: Abdul Rauf</title>
      <link>https://dev.to/lilcoderman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lilcoderman"/>
    <language>en</language>
    <item>
      <title>Let's mint an on-chain NFT mfers!</title>
      <dc:creator>Abdul Rauf</dc:creator>
      <pubDate>Thu, 17 Feb 2022 22:16:25 +0000</pubDate>
      <link>https://dev.to/lilcoderman/lets-mint-an-on-chain-nft-mfers-2i27</link>
      <guid>https://dev.to/lilcoderman/lets-mint-an-on-chain-nft-mfers-2i27</guid>
      <description>&lt;p&gt;This guide will teach you how to deploy an ERC-721 smart contract that lets you mint on-chain SVG NFTs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are on-chain NFTs?
&lt;/h2&gt;

&lt;p&gt;On-chain NFTs are NFTs on f*cking steroids! They are the best kind of NFTs out there. If an NFT is on-chain, it means that the token's metadata + image is stored directly on the blockchain.&lt;/p&gt;

&lt;p&gt;Most of the projects out there store their metadata on a decentralized file storage system such as IPFS. It's not a bad solution at all and many big names like &lt;a href="https://boredapeyachtclub.com/" rel="noopener noreferrer"&gt;Bored Ape Yacht Club&lt;/a&gt; and &lt;a href="https://www.coolcatsnft.com/" rel="noopener noreferrer"&gt;Cool Cats&lt;/a&gt; use it. Having said that, if IPFS goes down one day, you will most probably lose your NFTs.&lt;/p&gt;

&lt;p&gt;There's an even better solution available to us i.e. storing the NFTs on-chain. Projects like &lt;a href="https://www.lootproject.com/" rel="noopener noreferrer"&gt;Loot&lt;/a&gt; and &lt;a href="https://larvalabs.com/autoglyphs" rel="noopener noreferrer"&gt;Autoglyphs&lt;/a&gt; are popular projects that are using this technique. &lt;/p&gt;

&lt;p&gt;The only downside is that it is quite costly to store data this way, and there's a limited type of formats that we can store on-chain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-requisites
&lt;/h2&gt;

&lt;p&gt;This tutorial covers how to write and deploy a smart contract on Ethereum, but does not go into how to install all of the individual dependencies. &lt;/p&gt;

&lt;p&gt;Instead, I will list the dependencies and link to the documentation for how to install them.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Node.js - I recommend installing Node using &lt;a href="https://dev.toLink"&gt;nvm&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.toLink"&gt;MetaMask&lt;/a&gt; - An Ethereum browser wallet&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.toLink"&gt;Hardhat&lt;/a&gt; - An Ethereum development environment to compile, deploy, and test our smart contracts&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.toLink"&gt;ethers.js&lt;/a&gt; - A JavaScript library to interact with our deployed smart contract&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.toLink"&gt;Alchemy&lt;/a&gt; - A blockchain API that we'll use to access the &lt;code&gt;Rinkeby&lt;/code&gt; test network&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://dev.toLink"&gt;Here's a guide&lt;/a&gt; that will help you set up your development environment. The only difference is that I will be using the &lt;code&gt;Rinkeby&lt;/code&gt; network to deploy my smart contract instead of Ropsten.&lt;/p&gt;

&lt;p&gt;You also need some test ETH for this tutorial which you can get it from &lt;a href="https://www.rinkebyfaucet.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's write our smart contract
&lt;/h2&gt;

&lt;p&gt;Create a new file in the &lt;code&gt;/contracts&lt;/code&gt; directory named &lt;strong&gt;OnChainNFT.sol&lt;/strong&gt;. Add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// contracts/onChainNFT.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

/* 
    A library that provides a function for encoding some bytes in base64
    Source: https://github.com/zlayine/epic-game-buildspace/blob/master/contracts/libraries/Base64.sol
*/
import {Base64} from "./Base64.sol";

contract OnChainNFT is ERC721URIStorage, Ownable {
    event Minted(uint256 tokenId);

    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    constructor() ERC721("OnChainNFT", "ONC") {}

    /* Converts an SVG to Base64 string */
    function svgToImageURI(string memory svg)
        public
        pure
        returns (string memory)
    {
        string memory baseURL = "data:image/svg+xml;base64,";
        string memory svgBase64Encoded = Base64.encode(bytes(svg));
        return string(abi.encodePacked(baseURL, svgBase64Encoded));
    }

    /* Generates a tokenURI using Base64 string as the image */
    function formatTokenURI(string memory imageURI)
        public
        pure
        returns (string memory)
    {
        return
            string(
                abi.encodePacked(
                    "data:application/json;base64,",
                    Base64.encode(
                        bytes(
                            abi.encodePacked(
                                '{"name": "LCM ON-CHAINED", "description": "A simple SVG based on-chain NFT", "image":"',
                                imageURI,
                                '"}'
                            )
                        )
                    )
                )
            );
    }

    /* Mints the token */
    function mint(string memory svg) public onlyOwner {
        string memory imageURI = svgToImageURI(svg);
        string memory tokenURI = formatTokenURI(imageURI);

        _tokenIds.increment();
        uint256 newItemId = _tokenIds.current();

        _safeMint(msg.sender, newItemId);
        _setTokenURI(newItemId, tokenURI);

        emit Minted(newItemId);
    }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this contract, we are inheriting from the ERC721URIStorage standard implemented by &lt;a href="https://docs.openzeppelin.com/contracts/4.x/api/token/erc721#ERC721URIStorage" rel="noopener noreferrer"&gt;OpenZeppelin&lt;/a&gt;. If you want to use the contracts provided by Openzeppelin, you can install them using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @openzeppelin/contracts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's go through some of the difficult bits together.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Base64 encoding
&lt;/h3&gt;

&lt;p&gt;Why do we have to encode our SVG and JSON data? Base64 encoding allows you to convert your byte data into a nice string that can be transmitted easily across a network.&lt;/p&gt;

&lt;p&gt;Let's take a look at the &lt;code&gt;svgToImageURI&lt;/code&gt; function again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
function svgToImageURI(string memory svg)
    public
    pure
    returns (string memory)
{
    string memory baseURL = "data:image/svg+xml;base64,";
    string memory svgBase64Encoded = Base64.encode(bytes(svg));
    /* 
      abi.encodePacked is a function provided by Solidity which
      is used to concatenate two strings, similar to a `concat()`
      function in JavaScript.
    */
    return string(abi.encodePacked(baseURL, svgBase64Encoded));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this function, we are encoding our SVG into a Base64 string. We are also prepending our Base64 string with &lt;code&gt;data:image/svg+xml;base64&lt;/code&gt; - which simply states that we want this string to be processed as an SVG. &lt;/p&gt;

&lt;p&gt;After passing our SVG image through this function, we get something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMDI0JyBoZWlnaHQ9JzEwMjQnPgogICAgICA8ZGVmcz48Y2xpcFBhdGggaWQ9J2EnPjxwYXRoIGQ9J00wIDBoMTAyNHYxMDI0SDB6Jy8+PC9jbGlwUGF0aD48L2RlZnM+CiAgICAgIDxnIGNsaXAtcGF0aD0ndXJsKCNhKSc+CiAgICAgICAgPHBhdGggZD0nTTAgMGgxMDI0djEwMjRIMHonLz4KICAgICAgICA8cGF0aCBmaWxsPScjZmZmJyBkPSdNMCAyNDFoMTAyNHYyMEgwek0wIDUwMmgxMDI0djIwSDB6TTAgNzYzaDEwMjR2MjBIMHonLz4KICAgICAgICA8cGF0aCBmaWxsPScjZmZmJyBkPSdNMjQxIDBoMjB2MTAyNGgtMjB6Jy8+CiAgICAgIDwvZz4KICAgIDwvc3ZnPg==
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste this string in your browser and you'll see our SVG. Here's how my SVG looks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feo9yt5jvc8lnfxpuqqqq.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feo9yt5jvc8lnfxpuqqqq.jpeg" alt="SVG NFT by LCM"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So f*cking cool, am I right? 🤯 &lt;/p&gt;

&lt;h3&gt;
  
  
  2. Generate 'tokenURI'
&lt;/h3&gt;

&lt;p&gt;What is a tokenURI you ask? It is a link to your token's metadata. Basically, it is just a JSON object containing the NFTs name, description, properties, and image. Let's look at the simplified version of the &lt;code&gt;formatTokenURI&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function simplifiedFormatTokenURI(string memory imageURI)
    public
    pure
    returns (string memory)
{
    string memory baseURL = "data:application/json;base64,";
    string memory json = string(
        abi.encodePacked(
            '{"name": "LCM ON-CHAINED", "description": "A simple SVG based on-chain NFT", "image":"',
            imageURI,
            '"}'
        )
    );
    string memory jsonBase64Encoded = Base64.encode(bytes(json));
    return string(abi.encodePacked(baseURL, jsonBase64Encoded));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is similar to the &lt;code&gt;svgToImageURI&lt;/code&gt; function but instead of encoding the SVG, we're going to base64 encode our entire JSON object. After passing our previously generated imageURI through this function, this is what we get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data:application/json;base64,eyJuYW1lIjogIkxDTSBPTi1DSEFJTkVEIiwgImRlc2NyaXB0aW9uIjogIkEgc2ltcGxlIFNWRyBiYXNlZCBvbi1jaGFpbiBORlQiLCAiaW1hZ2UiOiAiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCNGJXeHVjejBuYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNuSUhkcFpIUm9QU2N4TURJMEp5Qm9aV2xuYUhROUp6RXdNalFuUGdvZ0lDQWdJQ0E4WkdWbWN6NDhZMnhwY0ZCaGRHZ2dhV1E5SjJFblBqeHdZWFJvSUdROUowMHdJREJvTVRBeU5IWXhNREkwU0RCNkp5OCtQQzlqYkdsd1VHRjBhRDQ4TDJSbFpuTStDaUFnSUNBZ0lEeG5JR05zYVhBdGNHRjBhRDBuZFhKc0tDTmhLU2MrQ2lBZ0lDQWdJQ0FnUEhCaGRHZ2daRDBuVFRBZ01HZ3hNREkwZGpFd01qUklNSG9uTHo0S0lDQWdJQ0FnSUNBOGNHRjBhQ0JtYVd4c1BTY2pabVptSnlCa1BTZE5NQ0F5TkRGb01UQXlOSFl5TUVnd2VrMHdJRFV3TW1neE1ESTBkakl3U0RCNlRUQWdOell6YURFd01qUjJNakJJTUhvbkx6NEtJQ0FnSUNBZ0lDQThjR0YwYUNCbWFXeHNQU2NqWm1abUp5QmtQU2ROTWpReElEQm9NakIyTVRBeU5HZ3RNakI2Snk4K0NpQWdJQ0FnSUR3dlp6NEtJQ0FnSUR3dmMzWm5QZz09In0=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once again copy and paste this string in your browser and you'll see the JSON object in all its glory! This is what I get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LCM ON-CHAINED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A simple SVG based on-chain NFT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMDI0JyBoZWlnaHQ9JzEwMjQnPgogICAgICA8ZGVmcz48Y2xpcFBhdGggaWQ9J2EnPjxwYXRoIGQ9J00wIDBoMTAyNHYxMDI0SDB6Jy8+PC9jbGlwUGF0aD48L2RlZnM+CiAgICAgIDxnIGNsaXAtcGF0aD0ndXJsKCNhKSc+CiAgICAgICAgPHBhdGggZD0nTTAgMGgxMDI0djEwMjRIMHonLz4KICAgICAgICA8cGF0aCBmaWxsPScjZmZmJyBkPSdNMCAyNDFoMTAyNHYyMEgwek0wIDUwMmgxMDI0djIwSDB6TTAgNzYzaDEwMjR2MjBIMHonLz4KICAgICAgICA8cGF0aCBmaWxsPScjZmZmJyBkPSdNMjQxIDBoMjB2MTAyNGgtMjB6Jy8+CiAgICAgIDwvZz4KICAgIDwvc3ZnPg=="&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perfect 👏&lt;/p&gt;

&lt;p&gt;Now let's move on to the mint function.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The f*cking 'mint' function
&lt;/h3&gt;

&lt;p&gt;This is a standard mint function and there's not much we're doing here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function mint(string memory svg) public onlyOwner {
   /* Encode the SVG to a Base64 string and then generate the tokenURI */
    string memory imageURI = svgToImageURI(svg);
    string memory tokenURI = formatTokenURI(imageURI);

    /* Increment the token id everytime we call the mint function */
    _tokenIds.increment();
    uint256 newItemId = _tokenIds.current();

    /* Mint the token id and set the token URI */
    _safeMint(msg.sender, newItemId);
    _setTokenURI(newItemId, tokenURI);

    /* Emit an event that returns the newly minted token id */
    emit Minted(newItemId);
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First of all, we are Base64 encoding our SVG using the &lt;code&gt;svgToImageURI&lt;/code&gt; function. After that, we pass the encoded string to the &lt;code&gt;formatTokenURI&lt;/code&gt; function to generate the token URI.&lt;/p&gt;

&lt;p&gt;Then, we increment the token id and mint our NFT. Lastly, we emit an event that returns the newly minted token id which will be used to generate our NFT's OpenSea link.&lt;/p&gt;

&lt;p&gt;By adding the &lt;code&gt;onlyOwner&lt;/code&gt; keyword, the mint function can only be called by the owner of the contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compile the contract
&lt;/h2&gt;

&lt;p&gt;You can compile the contract by running the following command in the root directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx hardhat compile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything goes correctly, you should see this on your screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Compiling 1 file with 0.8.4
Solidity compilation finished successfully
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Let's write the deploy script
&lt;/h2&gt;

&lt;p&gt;Create a new file in the &lt;code&gt;/scripts&lt;/code&gt; directory named &lt;strong&gt;deploy.js&lt;/strong&gt;. Add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// scripts/deploy.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Get 'OnChainNFT' contract&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nftContractFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;hre&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContractFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OnChainNFT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Deploy contract&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nftContract&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;nftContractFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deploy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;nftContract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deployed&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;✅ Contract deployed to:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nftContract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// SVG image that you want to mint&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;svg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;svg xmlns='http://www.w3.org/2000/svg' width='1024' height='1024'&amp;gt;
      &amp;lt;defs&amp;gt;&amp;lt;clipPath id='a'&amp;gt;&amp;lt;path d='M0 0h1024v1024H0z'/&amp;gt;&amp;lt;/clipPath&amp;gt;&amp;lt;/defs&amp;gt;
      &amp;lt;g clip-path='url(#a)'&amp;gt;
        &amp;lt;path d='M0 0h1024v1024H0z'/&amp;gt;
        &amp;lt;path fill='#fff' d='M0 241h1024v20H0zM0 502h1024v20H0zM0 763h1024v20H0z'/&amp;gt;
        &amp;lt;path fill='#fff' d='M241 0h20v1024h-20z'/&amp;gt;
      &amp;lt;/g&amp;gt;
    &amp;lt;/svg&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Call the mint function from our contract&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;txn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;nftContract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;txnReceipt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;txn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Get the token id of the minted NFT (using our event)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;txnReceipt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Minted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tokenId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tokenId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;🎨 Your minted NFT:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;`https://testnets.opensea.io/assets/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;nftContract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;runMain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;runMain&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've tried my best to explain what's going on through comments. It should be pretty easy to follow in my opinion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Time to mint our NFT!
&lt;/h2&gt;

&lt;p&gt;We’re finally ready to deploy the smart contract and mint our on-chain NFT. Navigate to the root of your project directory, and run the following script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx hardhat --network rinkeby run scripts/deploy.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;✅ Contract deployed to: 0x6F25096874fA386802aB30516003Df22873EeEF5
🎨 Your minted NFT: https://testnets.opensea.io/assets/0x6F25096874fA386802aB30516003Df22873EeEF5/1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The live contract can now be viewed on &lt;a href="https://rinkeby.etherscan.io/address/0x6F25096874fA386802aB30516003Df22873EeEF5" rel="noopener noreferrer"&gt;Etherscan Rinkeby Testnet Explorer&lt;/a&gt;. Also, you can look at your freshly minted NFT on &lt;a href="https://testnets.opensea.io/assets/0x6F25096874fA386802aB30516003Df22873EeEF5/1" rel="noopener noreferrer"&gt;Opensea&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;LFG 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  See the full code
&lt;/h2&gt;

&lt;p&gt;Enough chit-chat! if you want to see the full code, you can find the &lt;a href="https://github.com/abdulrauf11/lcm-onchained" rel="noopener noreferrer"&gt;Github repo here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;I plan to create a frontend react app where the users can interact with this contract. You will be able to copy-paste your SVG code and mint your on-chain NFTs 🔥&lt;/p&gt;



&lt;h2&gt;
  
  
  Don't leave me, take me with you
&lt;/h2&gt;

&lt;p&gt;Like what you read? Follow me on social media to know more about NFTs, web development, and shit-posting.&lt;/p&gt;

&lt;p&gt;Twitter: &lt;a href="https://twitter.com/lilcoderman" rel="noopener noreferrer"&gt;@lilcoderman&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instagram: &lt;a href="https://www.instagram.com/lilcoderman/" rel="noopener noreferrer"&gt;@lilcoderman&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>solidity</category>
      <category>ethereum</category>
      <category>nft</category>
    </item>
    <item>
      <title>Create a whitelist for your NFT project</title>
      <dc:creator>Abdul Rauf</dc:creator>
      <pubDate>Wed, 05 Jan 2022 18:13:32 +0000</pubDate>
      <link>https://dev.to/lilcoderman/create-a-whitelist-for-your-nft-project-1g55</link>
      <guid>https://dev.to/lilcoderman/create-a-whitelist-for-your-nft-project-1g55</guid>
      <description>&lt;p&gt;Many NFT projects have been using whitelists/allowlists to reward their most active community members. The members in this list are allowed to mint their NFTs before the rest of the public. This saves them from competing in a gas war with others.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;wen whitelist??&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well, I don't know anything about that but I can show how you can implement it in your smart contracts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;We're going to examine the smart contract of the Doodles NFT project, and see how they stored a list of their members on the blockchain. We're also going to learn about different &lt;strong&gt;function types&lt;/strong&gt;, &lt;strong&gt;modifiers&lt;/strong&gt;, and &lt;strong&gt;data locations&lt;/strong&gt; in &lt;code&gt;Solidity&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To understand this tutorial, you need to know about NFTs, crypto wallets, and the Solidity programming language. We do go through some Solidity concepts as mentioned above, but you need to know how smart contracts work in general. &lt;/p&gt;

&lt;h2&gt;
  
  
  But why Doodles?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://doodles.app/"&gt;Doodles&lt;/a&gt; is one of the best 10k NFT collectible projects out there. At the time of writing (5th Jan 2022), they've already traded around &lt;strong&gt;46.3k&lt;/strong&gt; ETH on Opensea and have a floor price of &lt;strong&gt;9.35&lt;/strong&gt; ETH. Their minting process went relatively smooth, so they are a good project to learn from.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Doodles OpenSea link&lt;/strong&gt;: &lt;a href="https://opensea.io/collection/doodles-official"&gt;https://opensea.io/collection/doodles-official&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The process
&lt;/h2&gt;

&lt;p&gt;The process is simple. We just need to store all the whitelisted addresses in a list. Doodles have gone one step ahead and stored the amount of NFTs the members can mint as well. They've used a data structure called &lt;code&gt;mapping&lt;/code&gt; to do that.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is mapping?
&lt;/h3&gt;

&lt;p&gt;Mapping in Solidity acts like a hash table or dictionary in any other language. It is used to store the data in the form of key-value pairs. Maps are created with the syntax &lt;code&gt;mapping(keyType =&amp;gt; valueType)&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keyType could be a type such as &lt;code&gt;uint&lt;/code&gt;, &lt;code&gt;address&lt;/code&gt;, or &lt;code&gt;bytes&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;valueType could be all types including another mapping or an array.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Maps are not iterable, which means you cannot loop through them. You can only access a value through its key.&lt;/p&gt;

&lt;p&gt;This is where Doodles are storing all the members and the number of NFTs they can mint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="k"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;_allowList&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can access data from a mapping similar to how you'd do it from an array. Instead of an index, you'll just give it a key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="n"&gt;_allowList&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;someAddress&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;someNumber&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding members to the whitelist
&lt;/h3&gt;

&lt;p&gt;Let's look at the &lt;code&gt;setAllowList&lt;/code&gt; function where everything happens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setAllowList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;calldata&lt;/span&gt; &lt;span class="n"&gt;addresses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint8&lt;/span&gt; &lt;span class="n"&gt;numAllowedToMint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="n"&gt;onlyOwner&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;addresses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_allowList&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;addresses&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numAllowedToMint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're passing in an array of addresses and the number of tokens to the function. Inside the function, we loop through the addresses and store them in the &lt;code&gt;_allowList&lt;/code&gt;. Pretty straightforward, eh?&lt;/p&gt;

&lt;p&gt;The most interesting keywords here are &lt;code&gt;calldata&lt;/code&gt;, &lt;code&gt;external&lt;/code&gt;, and &lt;code&gt;onlyOwner&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. The "OnlyOwner" modifier
&lt;/h4&gt;

&lt;p&gt;This keyword is imported by the &lt;a href="https://openzeppelin.com/"&gt;OpenZeppelin&lt;/a&gt; library. OpenZeppelin provides &lt;a href="https://docs.openzeppelin.com/contracts/2.x/api/ownership#Ownable"&gt;Ownable&lt;/a&gt; for implementing ownership in your contracts. By adding this modifier to your function, you're only allowing it to be called by a specific address. By default, &lt;code&gt;onlyOwner&lt;/code&gt; refers to the account that deployed the contract.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"@openzeppelin/contracts/access/Ownable.sol"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...
&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setAllowList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// anyone can call this setAllowList()
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setAllowList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="n"&gt;onlyOwner&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// only the owner can call setAllowList()!
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Different types of functions
&lt;/h4&gt;

&lt;p&gt;There are four types of Solidity functions: &lt;code&gt;external&lt;/code&gt;, &lt;code&gt;internal&lt;/code&gt;, &lt;code&gt;public&lt;/code&gt;, and &lt;code&gt;private&lt;/code&gt;. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;private&lt;/em&gt; functions can be only called from inside the contract.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;internal&lt;/em&gt; functions can be called from inside the contract as well other contracts inheriting from it.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;external&lt;/em&gt; functions can only be invoked from the outside.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;public&lt;/em&gt; functions can be called from anywhere.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why are we using an &lt;code&gt;external&lt;/code&gt; function here instead of, maybe, &lt;code&gt;public&lt;/code&gt;? Well, because external functions are sometimes more efficient when they receive large arrays of data.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The difference is because in public functions, Solidity immediately copies array arguments to memory, while external functions can read directly from calldata. Memory allocation is expensive, whereas reading from calldata is cheap.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This was taken from a &lt;a href="https://ethereum.stackexchange.com/questions/19380/external-vs-public-best-practices"&gt;StackoverExchange answer&lt;/a&gt; on this topic.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Data locations
&lt;/h4&gt;

&lt;p&gt;Variables in Solidity can be stored in three different locations: &lt;code&gt;storage&lt;/code&gt;, &lt;code&gt;memory&lt;/code&gt;, and &lt;code&gt;calldata&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;storage&lt;/em&gt; variables are stored directly on the blockchain.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;memory&lt;/em&gt; variables are stored in memory and only exist while a function is being called.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;calldata&lt;/em&gt; variables are special (more efficient) data locations that contain function arguments. They are only available for &lt;code&gt;external&lt;/code&gt; functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since our list of whitelisted members can be large, we're using &lt;code&gt;calldata&lt;/code&gt; to store our array of addresses. &lt;/p&gt;

&lt;h2&gt;
  
  
  How to mint
&lt;/h2&gt;

&lt;p&gt;Let's look at the mint function they've used for the members in the whitelist:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;mintAllowList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8&lt;/span&gt; &lt;span class="n"&gt;numberOfTokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="k"&gt;payable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;totalSupply&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isAllowListActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Allow list is not active"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numberOfTokens&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;_allowList&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s"&gt;"Exceeded max available to purchase"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;numberOfTokens&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;MAX_SUPPLY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Purchase would exceed max tokens"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PRICE_PER_TOKEN&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;numberOfTokens&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Ether value sent is not correct"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;_allowList&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;numberOfTokens&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;numberOfTokens&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_safeMint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following line is relevant for this tutorial:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numberOfTokens&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;_allowList&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s"&gt;"Exceeded max available to purchase"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;if the wallet minting the token i.e. &lt;code&gt;msg.sender&lt;/code&gt; is not available in the &lt;code&gt;_allowList&lt;/code&gt;, this line will throw an exception.&lt;/p&gt;

&lt;p&gt;You can take a look at the complete &lt;a href="https://etherscan.io/address/0x8a90cab2b38dba80c64b7734e58ee1db38b8992e#code"&gt;source code here&lt;/a&gt;.&lt;/p&gt;



&lt;h2&gt;
  
  
  Don't leave me, take me with you
&lt;/h2&gt;

&lt;p&gt;Like what you read? Follow me on social media to know more about NFTs, Web development, and shit-posting.&lt;/p&gt;

&lt;p&gt;Twitter: &lt;a href="https://twitter.com/lilcoderman"&gt;@lilcoderman&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instagram: &lt;a href="https://www.instagram.com/lilcoderman/"&gt;@lilcoderman&lt;/a&gt;&lt;/p&gt;

</description>
      <category>solidity</category>
      <category>nft</category>
      <category>blockchain</category>
      <category>ethereum</category>
    </item>
    <item>
      <title>How to create a motherf*cking NFT using JavaScript</title>
      <dc:creator>Abdul Rauf</dc:creator>
      <pubDate>Sun, 26 Dec 2021 19:40:26 +0000</pubDate>
      <link>https://dev.to/lilcoderman/how-to-create-a-motherfcking-nft-using-javascript-2foj</link>
      <guid>https://dev.to/lilcoderman/how-to-create-a-motherfcking-nft-using-javascript-2foj</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This blog post is outdated as it is based on V1. Please use thirdweb V2 for your upcoming projects.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In my previous &lt;a href="https://dev.to/abdulrauf11/how-to-create-a-motherfcking-nft-using-solidity-5b5d"&gt;post&lt;/a&gt;, I explained how you can mint an NFT using Solidity. But what if you don't want to learn Solidity? &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Ain't nobody got time for that b*tch.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You want to stick with your ol' pal JavaScript. Let me tell you that there's a way to do it. I present to you &lt;a href="https://thirdweb.com/portal" rel="noopener noreferrer"&gt;thirdweb&lt;/a&gt; - a library of smart contracts, SDK, and UI components that developers can use in their app.&lt;/p&gt;

&lt;p&gt;How cool would it be if you could just call a &lt;code&gt;mint&lt;/code&gt; function, give the token's metadata as an argument, and it mints an NFT for you? All without writing a single line of Solidity code. Let's see if that's possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to thirdweb
&lt;/h2&gt;

&lt;p&gt;The first thing you need to learn about is the concept of &lt;code&gt;projects&lt;/code&gt; and &lt;code&gt;modules&lt;/code&gt;. In short, projects are smart contracts that act as containers for your modules. On the other hand, modules are packages that contain smart contracts and other functionalities. Head over to this &lt;a href="https://thirdweb.com/portal/learn/introduction" rel="noopener noreferrer"&gt;link&lt;/a&gt; to learn more about them.&lt;/p&gt;

&lt;h3&gt;
  
  
  All the steps we need to take
&lt;/h3&gt;

&lt;p&gt;The following are the steps we need to take to mint our NFT:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a project using thirdweb&lt;/li&gt;
&lt;li&gt;Deploy an NFT module inside our project&lt;/li&gt;
&lt;li&gt;Mint our NFT&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of these steps will be done using just JavaScript. I will be separating these steps into 3 different &lt;code&gt;.js&lt;/code&gt; files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Before we start writing the code, we need to create a &lt;code&gt;MetaMask&lt;/code&gt; wallet. Since we'll be deploying our contracts on the &lt;code&gt;Rinkeby&lt;/code&gt; network, we'll also need some testnet ETH to approve the transactions. &lt;a href="https://thirdweb.com/portal/guides/create-a-metamask-wallet" rel="noopener noreferrer"&gt;Here's a guide on how to create a MetaMask Wallet and get testnet ETH&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, head over to your thirdweb dashboard and create a project. Give it a name and a description of your choice. Make sure you've switched your network to Rinkeby.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1cnx0gk0byz34q9z81nb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1cnx0gk0byz34q9z81nb.png" alt="Create project - thirdweb dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll do everything else using code.&lt;/p&gt;

&lt;h2&gt;
  
  
  The code
&lt;/h2&gt;

&lt;p&gt;Go ahead and create an empty project and install all the necessary packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;@3rdweb/sdk&lt;/strong&gt; - to use the smart contracts provided by thirdweb&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ethers&lt;/strong&gt; - to connect our MetaMask wallet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;dotenv&lt;/strong&gt; - to source sensitive data from a &lt;code&gt;.env&lt;/code&gt; file
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; @3rdweb/sdk ethers dotenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's create 3 separate files to code all the steps I mentioned above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;1-init-sdk.js 2-deploy-collection.js 3-mint-nft.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1. Let's initialize the SDK
&lt;/h3&gt;

&lt;p&gt;I like to show the entire code first before explaining it. Therefore, before further ado, here's the code for the first file i.e. &lt;code&gt;1-init-sdk.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ThirdwebSDK&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@3rdweb/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ethers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sdk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ThirdwebSDK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Wallet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;// Your wallet private key. ALWAYS KEEP THIS PRIVATE, DO NOT SHARE IT WITH ANYONE.&lt;/span&gt;
    &lt;span class="c1"&gt;// Add it to your .env file and do not commit that file to github!&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PRIVATE_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// RPC URL, we'll use our Alchemy API URL from our .env file.&lt;/span&gt;
    &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDefaultProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://rinkeby-light.eth.linkpool.io/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getApps&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Your app address is:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;apps&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to get apps from the sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;

&lt;span class="c1"&gt;// We are exporting the initialised thirdweb SDK so that we can use it in our other scripts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;sdk&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code is really simple. We're importing thirdweb and then initializing the SDK. We're exporting it at the end so we can re-use it in the next script.&lt;/p&gt;

&lt;p&gt;We're also running this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getApps&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Get the address of the most recently created project&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Your app address is:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;apps&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Failed to get apps from the sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})(&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code returns the address of your app or project. It's the address of the container that will hold all your modules. Remember, we created a project using our dashboard in the beginning? This will return its address.&lt;/p&gt;

&lt;p&gt;Go ahead and run the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node 1-init-sdk.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what I get when I run the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lilcoderman % node scripts/1-init-sdk.js
Your app address is: 0x25320e23DCd1813D11787aD836865a64CC69897A
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Deploying the NFT module
&lt;/h3&gt;

&lt;p&gt;Now that we have our project/app, let's use the &lt;code&gt;deployNftModule&lt;/code&gt; provided by thirdweb to deploy our collection. It is one of the methods available to the SDK we initialized in the first step.&lt;/p&gt;

&lt;p&gt;We're not creating our NFT here, yet. This module will only help us create + deploy an ERC-721 collection to the Rinkeby testnet. We're just setting up the metadata of the collection itself. You know stuff like the name (e.g. Bored Ape Yacht Club), description, and image associated with the entire collection.&lt;/p&gt;

&lt;p&gt;Go ahead and copy the following code to the &lt;code&gt;2-deploy-collection.js&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;sdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./1-init-sdk.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;readFileSync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAppModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_APP_ADDRESS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nftModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deployNftModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="c1"&gt;// The collection's name, ex. CryptoPunks&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;JavaScript NFTS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// A description for the collection.&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;How to mint an NFT using Javascript - a tutorial by @lilcoderman&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// The image for the collection that will show up on OpenSea.&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;assets/collection.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="c1"&gt;// The amount of royalty collected on all royalties represented as basis points. The default is 0 (no royalties).&lt;/span&gt;
      &lt;span class="c1"&gt;// 1 basis point = 0.01%&lt;/span&gt;
      &lt;span class="c1"&gt;// For example: if this value is 100, then the royalty is 1% of the total sales.&lt;/span&gt;
      &lt;span class="na"&gt;sellerFeeBasisPoints&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// The address of the royalty recipient. All royalties will be sent to this address.&lt;/span&gt;
      &lt;span class="na"&gt;feeRecipient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WALLET_ADDRESS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// The symbol for the NFT Collection&lt;/span&gt;
      &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;JS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;✅ Successfully deployed nft module, address:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;nftModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;failed to deploy nft module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code is pretty self-explanatory. We're importing our SDK from the previous file and calling one of its methods. This method will deploy an NFT module (i.e collection) for us. We've also provided the necessary metadata as an argument to the &lt;code&gt;deployNftModule&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Once you run this script, it will return the collection's address. Here's what I get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lilcoderman % node scripts/2-deploy-collection.js
✅ Successfully deployed nft module, address: 0x1C267DC8841999de9B9C4F33D63a8d6bC81b8e2D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Time to mint our NFT
&lt;/h3&gt;

&lt;p&gt;We're almost done now! It's time to mint our NFT, and we haven't even written a single line of Solidity. This is probably the simplest code we've written so far. Copy the following code to the final file &lt;code&gt;3-mint-nft.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;sdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./1-init-sdk.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;readFileSync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getNFTModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_NFT_MODULE_ADDRESS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;nft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;LCM&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Follow me on twitter @lilcoderman&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;assets/nft.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;✅ Successfully created a new NFT in the collection!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;failed to create the new NFT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just like before, we're importing the SDK from the first file. However, we are using the module &lt;code&gt;getNFTModule&lt;/code&gt; this time around. This module returns our ERC-721 contract.&lt;/p&gt;

&lt;p&gt;Then, we can call the &lt;code&gt;mint&lt;/code&gt; function from the contract to create an actual NFT! The mint function requires an object containing the metadata of the token. I've passed in the NFT's name, description, and image as arguments. You can also set its properties if you'd like.&lt;/p&gt;

&lt;p&gt;Now, let's run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lilcoderman % node scripts/3-mint-nft.js
✅ Successfully created a new NFT &lt;span class="k"&gt;in &lt;/span&gt;the collection!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now view the NFT on your thirdweb &lt;a href="https://thirdweb.com/rinkeby/" rel="noopener noreferrer"&gt;dashboard&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4radw9vks53jstm2efdu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4radw9vks53jstm2efdu.png" alt="NFT collection - thirdweb dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can also find our NFT on &lt;strong&gt;OpenSea&lt;/strong&gt; by using its address. Go to this &lt;a href="https://testnets.opensea.io/assets/0x1c267dc8841999de9b9c4f33d63a8d6bc81b8e2d/0" rel="noopener noreferrer"&gt;link&lt;/a&gt; to check mine.&lt;/p&gt;

&lt;p&gt;That's it. You've now minted an NFT using JavaScript only. Pretty f*cking cool, won't you say?&lt;/p&gt;

&lt;p&gt;Anyway, here's the Github repo with all the code: &lt;a href="https://github.com/abdulrauf11/tutorial-thirdweb-nft" rel="noopener noreferrer"&gt;https://github.com/abdulrauf11/tutorial-thirdweb-nft&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What next...
&lt;/h2&gt;

&lt;p&gt;thirdweb can do much more than just minting an NFT collection. It has modules for creating a custom token, a marketplace for NFTs, and even a DAO! In the future, they also plan to support other chains like Solana and Flow.&lt;/p&gt;

&lt;p&gt;We're using JavaScript to do all the steps, however, it is not a requirement. You can do all this manually using your dashboard. In my opinion, doing it with code just gives you more flexibility.&lt;/p&gt;

&lt;p&gt;Keep in mind, if you're going to use thirdweb in production, they will take a minor 5% cut from your royalties. I think that's fair given how they're making our lives much easier with their product.&lt;/p&gt;



&lt;h2&gt;
  
  
  Don't leave me, take me with you
&lt;/h2&gt;

&lt;p&gt;Like what you read? Follow me on social media to know more about NFTs, Web development, and shit-posting.&lt;/p&gt;

&lt;p&gt;Twitter: &lt;a href="https://twitter.com/lilcoderman" rel="noopener noreferrer"&gt;@lilcoderman&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instagram: &lt;a href="https://www.instagram.com/lilcoderman/" rel="noopener noreferrer"&gt;@lilcoderman&lt;/a&gt; &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>nft</category>
      <category>web3</category>
      <category>ethereum</category>
    </item>
    <item>
      <title>How to create a motherf*cking NFT using Solidity</title>
      <dc:creator>Abdul Rauf</dc:creator>
      <pubDate>Sat, 11 Dec 2021 14:13:15 +0000</pubDate>
      <link>https://dev.to/lilcoderman/how-to-create-a-motherfcking-nft-using-solidity-5b5d</link>
      <guid>https://dev.to/lilcoderman/how-to-create-a-motherfcking-nft-using-solidity-5b5d</guid>
      <description>&lt;p&gt;This is a simple no-bullshit guide to creating an NFT using Solidity.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Before you go any further, you need to know a little about NFTs, Crypto wallets, Solidity, and the ERC721 token standard to understand this article.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I am going to start by showing you the entire &lt;a href="https://gist.github.com/abdulrauf11/179411d79dfee19b050cddb0e1fa07a4" rel="noopener noreferrer"&gt;code&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";


contract BasicNFT is ERC721URIStorage {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    constructor() ERC721("BasicNFT", "BNFT") {}

    function mint(string memory tokenURI) public {
        _tokenIds.increment();

        uint256 newItemId = _tokenIds.current();

        _safeMint(msg.sender, newItemId);
        _setTokenURI(newItemId, tokenURI);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait…that’s it?&lt;/p&gt;

&lt;p&gt;Yes, what else did you expect you beautiful b*stard.&lt;/p&gt;

&lt;p&gt;Now let's try to understand the not-so-obvious lines of code.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenZeppelin to the rescue
&lt;/h2&gt;

&lt;p&gt;The OpenZeppelin library is there to save you from writing any shitty code. It does all the hard work for you. You import the necessary contracts from the library, and they just work. I am talking about the following imports made in the code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll discuss what exactly I am using from these contracts in the coming sections.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inheriting from 'ERC721URIStorage'
&lt;/h2&gt;

&lt;p&gt;Next, we inherit our contract from the &lt;code&gt;ERC721URIStorage&lt;/code&gt; contract - which was given to us by the OpenZeppelin library. In short, contracts that inherit from other contracts can access their (non-private) functions and variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract BasicNFT is ERC721URIStorage {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Initialising the constructor
&lt;/h2&gt;

&lt;p&gt;Since we're inheriting from &lt;code&gt;ERC721URIStorage&lt;/code&gt;, we'll initialise its constructor in the &lt;code&gt;BasicNFT&lt;/code&gt; constructor. It requires two parameters i.e. a name and a symbol.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// name: 'BasicNFT', symbol: 'BNFT'
constructor() ERC721("BasicNFT", "BNFT") {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The name and symbol are not f*cking important, so let's just move on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Assign token ids with 'Counters'
&lt;/h2&gt;

&lt;p&gt;Let's see another utility provided to us by the brilliant OpenZeppelin library i.e. &lt;code&gt;Counters&lt;/code&gt;. This gets you a simple counter that can be incremented or decremented. It will allow us to issue ids to our ERC721 tokens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// include counters
using Counters for Counters.Counter;
// declare token ids as counters
Counters.Counter private _tokenIds;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Coding the mint function
&lt;/h2&gt;

&lt;p&gt;Now comes the most important function in this contract i.e the motherf*cking &lt;code&gt;mint&lt;/code&gt; function. I've declared it as a public method so that everyone is allowed to call it.&lt;/p&gt;

&lt;p&gt;Let's go through all the steps we take inside this function. Here's the code with some comments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; function mint(string memory tokenURI) public {
     // 1. Increment the the token Ids by one
     _tokenIds.increment();
     // 2. Get the current Id (the first id will be 1)
     uint256 newItemId = _tokenIds.current();
     // 3. Call the `_safeMint` function provided by OpenZeppelin
     _safeMint(msg.sender, newItemId);
     // 4. Call the `_setTokenURI` function provided by OpenZeppelin
     _setTokenURI(newItemId, tokenURI);
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yeah, I should probably explain the last two lines of the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  _safeMint explained
&lt;/h3&gt;

&lt;p&gt;This function literally mints an ERC721 token for you. It takes in an address and a token id as arguments. I am passing in &lt;code&gt;msg.sender&lt;/code&gt; and &lt;code&gt;newItemId&lt;/code&gt; as the address and token id respectively. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;msg.sender&lt;/code&gt; is the wallet calling the mint function&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;newItemId&lt;/code&gt; is the current token id i.e. &lt;code&gt;_tokenIds.current()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once called, this function will safely mint a token and transfer it to the wallet calling the mint function.&lt;/p&gt;

&lt;h3&gt;
  
  
  _setTokenURI explained
&lt;/h3&gt;

&lt;p&gt;This is one of my favourite methods provided by OpenZeppelin. You can set the metadata for your token through this function. You know the kind of metadata you see on OpenSea - a name, description, and even an image. It takes in a token id and uri as arguments.&lt;/p&gt;

&lt;p&gt;We'll discuss how to get a &lt;code&gt;tokenURI&lt;/code&gt; soon. Basically, it's just a url that sends back a &lt;strong&gt;JSON&lt;/strong&gt; object.&lt;/p&gt;

&lt;p&gt;This is the &lt;a href="https://ipfs.io/ipfs/bafkreibsk54mbtejlffbvbl2fepyfgnee3ccdiy7ywkv5nu5ja6erxwazy" rel="noopener noreferrer"&gt;tokenURI&lt;/a&gt; I'll be using as an example. It returns the following object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Basic NFT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Basic NFT tutorial by @lilcoderman"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ipfs.io/ipfs/bafkreid5vd3sw2wwj2uagm22nomnktbhgl2qqcgksgxvu7xfwwbxtxecly"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the contract is deployed, you will be able to call the mint function with a &lt;code&gt;tokenURI&lt;/code&gt; and get a unique ERC721 token in return.&lt;/p&gt;

&lt;p&gt;WHEW! It looks like most of the work was done by the OpenZeppelin library. You ask why? Well, because you deserve to be taken care of you beautiful son of a b*tch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying to testnet
&lt;/h2&gt;

&lt;p&gt;I am going to use &lt;a href="https://remix.ethereum.org/" rel="noopener noreferrer"&gt;Remix&lt;/a&gt; to compile, deploy and interact with the contract. The contract will be deployed to the &lt;strong&gt;Rinkeby&lt;/strong&gt; testnet. If you need to learn how to do that, please go through this &lt;a href="https://forum.openzeppelin.com/t/create-an-nft-and-deploy-to-a-public-testnet-using-remix/6358" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My contract got deployed to this address: &lt;strong&gt;0x20A65d15fFf5315A4c9E79dED87273b1BfC3Fd65&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After deploying, let's call the mint function with the &lt;code&gt;tokenURI&lt;/code&gt; I mentioned above.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg12pdsd9i1ptxq3l8si0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg12pdsd9i1ptxq3l8si0.png" alt="Contract interface provided by Remix"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll wait a few minutes after it finishes minting. Now, let's take a look at our newly minted NFT on OpenSea/Rarible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OpenSea:&lt;/strong&gt; &lt;a href="https://testnets.opensea.io/assets/0x20a65d15fff5315a4c9e79ded87273b1bfc3fd65/1" rel="noopener noreferrer"&gt;https://testnets.opensea.io/assets/0x20a65d15fff5315a4c9e79ded87273b1bfc3fd65/1&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rarible:&lt;/strong&gt; &lt;a href="https://rinkeby.rarible.com/token/0x20a65d15fff5315a4c9e79ded87273b1bfc3fd65:1" rel="noopener noreferrer"&gt;https://rinkeby.rarible.com/token/0x20a65d15fff5315a4c9e79ded87273b1bfc3fd65:1&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So freaking cool, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Image and Metadata
&lt;/h2&gt;

&lt;p&gt;Throughout this article, we've assumed that we already have the &lt;code&gt;tokenURI&lt;/code&gt; i.e. the url pointing towards our metadata. But, how did I get that? Where did I upload my NFT's image and metadata?&lt;/p&gt;

&lt;p&gt;I uploaded them to an &lt;strong&gt;IPFS&lt;/strong&gt;. IPFS is a decentralised file storage system which isn't controlled by one entity, and is instead maintained by a large number of peers in the network. &lt;/p&gt;

&lt;h3&gt;
  
  
  nft.storage
&lt;/h3&gt;

&lt;p&gt;I used a free service called &lt;a href="https://nft.storage/" rel="noopener noreferrer"&gt;nft.storage&lt;/a&gt; to upload my assets to the IPFS network. You need to upload the image first and then use its link in your metadata. After doing that, you need to upload your metadata file as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F96fwgf02crybeoxa0rrf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F96fwgf02crybeoxa0rrf.png" alt="Image and metadata files as shown on nft.storage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy the &lt;a href="https://ipfs.io/ipfs/bafkreibsk54mbtejlffbvbl2fepyfgnee3ccdiy7ywkv5nu5ja6erxwazy" rel="noopener noreferrer"&gt;link&lt;/a&gt; to your metadata and pass it as an argument to the mint function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Off-chain vs. On-chain
&lt;/h2&gt;

&lt;p&gt;In this article, we've only discussed how we can create an off-chain NFT. You might have heard about an on-chain token as well. The difference between them is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;off-chain: Only the token ids are stored on the blockchain. Image and metadata are stored somewhere else e.g. IPFS.&lt;/li&gt;
&lt;li&gt;on-chain: Both the metadata and image are stored directly on the blockchain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We stored our image and metadata on IPFS, which is a pretty good second option. Many top projects have used this same approach.&lt;/p&gt;



&lt;h2&gt;
  
  
  Don't leave me, take me with you
&lt;/h2&gt;

&lt;p&gt;Like what you read? Follow me on social media to know more about NFTs, Web development, and shit-posting.&lt;/p&gt;

&lt;p&gt;Twitter: &lt;a href="https://twitter.com/lilcoderman" rel="noopener noreferrer"&gt;@lilcoderman&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instagram: &lt;a href="https://www.instagram.com/lilcoderman/" rel="noopener noreferrer"&gt;@lilcoderman&lt;/a&gt; &lt;/p&gt;

</description>
      <category>solidity</category>
      <category>web3</category>
      <category>nft</category>
      <category>ethereum</category>
    </item>
  </channel>
</rss>
