<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>lilcoderman</title>
        <link>https://paragraph.com/@lilcoderman</link>
        <description>Part-time nerd, full-time turd 💩 I build stuff for the world wide web 🌎 Co-founder @rauf_tech ✨ Current exploring all things web3</description>
        <lastBuildDate>Fri, 24 Jul 2026 20:57:36 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>lilcoderman</title>
            <url>https://storage.googleapis.com/papyrus_images/3603a917a998149879cf6852a45c15f1948113a95a2bcef938e210d4583b1209.png</url>
            <link>https://paragraph.com/@lilcoderman</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[How to create a motherf*cking NFT using JavaScript]]></title>
            <link>https://paragraph.com/@lilcoderman/how-to-create-a-motherf-cking-nft-using-javascript</link>
            <guid>N2CSIoSXY95N1XlnsDID</guid>
            <pubDate>Sun, 26 Dec 2021 18:52:51 GMT</pubDate>
            <description><![CDATA[In my previous post, I explained how you can mint an NFT using Solidity. But what if you don&apos;t want to learn Solidity?Ain&apos;t nobody got time for that b*tch.You want to stick with your ol&apos; pal JavaScript. Let me tell you that there&apos;s a way to do it. I present to you thirdweb - a library of smart contracts, SDK, and UI components that developers can use in their app. How cool would it be if you could just call a mint function, give the token&apos;s metadata as an argument, an...]]></description>
            <content:encoded><![CDATA[<p>In my previous <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dev.to/abdulrauf11/how-to-create-a-motherfcking-nft-using-solidity-5b5d">post</a>, I explained how you can mint an NFT using Solidity. But what if you don&apos;t want to learn Solidity?</p><blockquote><p><em>Ain&apos;t nobody got time for that b*tch.</em></p></blockquote><p>You want to stick with your ol&apos; pal JavaScript. Let me tell you that there&apos;s a way to do it. I present to you <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thirdweb.com/portal">thirdweb</a> - a library of smart contracts, SDK, and UI components that developers can use in their app.</p><p>How cool would it be if you could just call a <code>mint</code> function, give the token&apos;s metadata as an argument, and it mints an NFT for you? All without writing a single line of Solidity code. Let&apos;s see if that&apos;s possible.</p><h2 id="h-introduction-to-thirdweb" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Introduction to thirdweb</h2><p>The first thing you need to learn about is the concept of <code>projects</code> and <code>modules</code>. 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 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thirdweb.com/portal/learn/introduction">link</a> to learn more about them.</p><h3 id="h-all-the-steps-we-need-to-take" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">All the steps we need to take</h3><p>The following are the steps we need to take to mint our NFT:</p><ol><li><p>Create a project using thirdweb</p></li><li><p>Deploy an NFT module inside our project</p></li><li><p>Mint our NFT</p></li></ol><p>All of these steps will be done using just JavaScript. I will be separating these steps into 3 different <code>.js</code> files.</p><h2 id="h-setup" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Setup</h2><p>Before we start writing the code, we need to create a <code>MetaMask</code> wallet. Since we&apos;ll be deploying our contracts on the <code>Rinkeby</code> network, we&apos;ll also need some testnet ETH to approve the transactions. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thirdweb.com/portal/guides/create-a-metamask-wallet">Here&apos;s a guide on how to create a MetaMask Wallet and get testnet ETH</a>.</p><p>Now, head over to your thirdweb dashboard and create a project. Give it a name and a description of your choice. Make sure you&apos;ve switched your network to Rinkeby.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f00346c38b819f385b080d9dd4b740cf1fbf2f86e3d397e93ceb3c83f3a0061d.png" alt="Create project - thirdweb dashboard" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Create project - thirdweb dashboard</figcaption></figure><p>We&apos;ll do everything else using code.</p><h2 id="h-the-code" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">The code</h2><p>Go ahead and create an empty project and install all the necessary packages:</p><ul><li><p><strong>@3rdweb/sdk</strong> - to use the smart contracts provided by thirdweb</p></li><li><p><strong>ethers</strong> - to connect our MetaMask wallet</p></li><li><p><strong>dotenv</strong> - to source sensitive data from a <code>.env</code> file</p></li></ul><pre data-type="codeBlock" text="npm init -y
npm install @3rdweb/sdk ethers dotenv
"><code>npm init <span class="hljs-operator">-</span>y
npm install @3rdweb<span class="hljs-operator">/</span>sdk ethers dotenv
</code></pre><p>Let&apos;s create 3 separate files to code all the steps I mentioned above.</p><pre data-type="codeBlock" text="touch 1-init-sdk.js 2-deploy-collection.js 3-mint-nft.js
"><code>touch <span class="hljs-number">1</span><span class="hljs-operator">-</span>init<span class="hljs-operator">-</span>sdk.js <span class="hljs-number">2</span><span class="hljs-operator">-</span>deploy<span class="hljs-operator">-</span>collection.js <span class="hljs-number">3</span><span class="hljs-operator">-</span>mint<span class="hljs-operator">-</span>nft.js
</code></pre><h3 id="h-1-lets-initialize-the-sdk" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1. Let&apos;s initialize the SDK</h3><p>I like to show the entire code first before explaining it. Therefore, before further ado, here&apos;s the code for the first file i.e. <code>1-init-sdk.js</code></p><pre data-type="codeBlock" text="import { ThirdwebSDK } from &apos;@3rdweb/sdk&apos;;
import ethers from &apos;ethers&apos;;

import dotenv from &apos;dotenv&apos;;
dotenv.config();

const sdk = new ThirdwebSDK(
  new ethers.Wallet(
    // Your wallet private key. ALWAYS KEEP THIS PRIVATE, DO NOT SHARE IT WITH ANYONE.
    // Add it to your .env file and do not commit that file to github!
    process.env.PRIVATE_KEY,
    // RPC URL, we&apos;ll use our Alchemy API URL from our .env file.
    ethers.getDefaultProvider(&apos;https://rinkeby-light.eth.linkpool.io/&apos;)
  )
);

(async () =&gt; {
  try {
    const apps = await sdk.getApps();
    console.log(&apos;Your app address is:&apos;, apps[0].address);
  } catch (err) {
    console.error(&apos;Failed to get apps from the sdk&apos;, err);
    process.exit(1);
  }
})();

// We are exporting the initialised thirdweb SDK so that we can use it in our other scripts
export default sdk;
"><code><span class="hljs-keyword">import</span> { <span class="hljs-title">ThirdwebSDK</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'@3rdweb/sdk'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title">ethers</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'ethers'</span>;

<span class="hljs-keyword">import</span> <span class="hljs-title">dotenv</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'dotenv'</span>;
dotenv.config();

const sdk <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> ThirdwebSDK(
  <span class="hljs-keyword">new</span> ethers.Wallet(
    <span class="hljs-comment">// Your wallet private key. ALWAYS KEEP THIS PRIVATE, DO NOT SHARE IT WITH ANYONE.</span>
    <span class="hljs-comment">// Add it to your .env file and do not commit that file to github!</span>
    process.env.PRIVATE_KEY,
    <span class="hljs-comment">// RPC URL, we'll use our Alchemy API URL from our .env file.</span>
    ethers.getDefaultProvider(<span class="hljs-string">'https://rinkeby-light.eth.linkpool.io/'</span>)
  )
);

(async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
  <span class="hljs-keyword">try</span> {
    const apps <span class="hljs-operator">=</span> await sdk.getApps();
    console.log(<span class="hljs-string">'Your app address is:'</span>, apps[<span class="hljs-number">0</span>].<span class="hljs-built_in">address</span>);
  } <span class="hljs-keyword">catch</span> (err) {
    console.error(<span class="hljs-string">'Failed to get apps from the sdk'</span>, err);
    process.exit(<span class="hljs-number">1</span>);
  }
})();

<span class="hljs-comment">// We are exporting the initialised thirdweb SDK so that we can use it in our other scripts</span>
export default sdk;
</code></pre><p>The code is really simple. We&apos;re importing thirdweb and then initializing the SDK. We&apos;re exporting it at the end so we can re-use it in the next script.</p><p>We&apos;re also running this:</p><pre data-type="codeBlock" text="(async () =&gt; {
  try {
    const apps = await sdk.getApps();
    // Get the address of the most recently created project
    console.log(&quot;Your app address is:&quot;, apps[0].address);
  } catch (err) {
    console.error(&quot;Failed to get apps from the sdk&quot;, err);
    process.exit(1);
  }
})(
"><code>(async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
  <span class="hljs-keyword">try</span> {
    const apps <span class="hljs-operator">=</span> await sdk.getApps();
    <span class="hljs-comment">// Get the address of the most recently created project</span>
    console.log(<span class="hljs-string">"Your app address is:"</span>, apps[<span class="hljs-number">0</span>].<span class="hljs-built_in">address</span>);
  } <span class="hljs-keyword">catch</span> (err) {
    console.error(<span class="hljs-string">"Failed to get apps from the sdk"</span>, err);
    process.exit(<span class="hljs-number">1</span>);
  }
})(
</code></pre><p>This code returns the address of your app or project. It&apos;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.</p><p>Go ahead and run the following command in your terminal:</p><pre data-type="codeBlock" text="node 1-init-sdk.js
"><code>node <span class="hljs-number">1</span><span class="hljs-operator">-</span>init<span class="hljs-operator">-</span>sdk.js
</code></pre><p>Here&apos;s what I get when I run the script:</p><pre data-type="codeBlock" text="lilcoderman % node scripts/1-init-sdk.js
Your app address is: 0x25320e23DCd1813D11787aD836865a64CC69897A
"><code>lilcoderman <span class="hljs-operator">%</span> node scripts<span class="hljs-operator">/</span><span class="hljs-number">1</span><span class="hljs-operator">-</span>init<span class="hljs-operator">-</span>sdk.js
Your app <span class="hljs-keyword">address</span> <span class="hljs-keyword">is</span>: <span class="hljs-number">0x25320e23DCd1813D11787aD836865a64CC69897A</span>
</code></pre><h3 id="h-2-deploying-the-nft-module" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2. Deploying the NFT module</h3><p>Now that we have our project/app, let&apos;s use the <code>deployNftModule</code> provided by thirdweb to deploy our collection. It is one of the methods available to the SDK we initialized in the first step.</p><p>We&apos;re not creating our NFT here, yet. This module will only help us create + deploy an ERC-721 collection to the Rinkeby testnet. We&apos;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.</p><p>Go ahead and copy the following code to the <code>2-deploy-collection.js</code> file:</p><pre data-type="codeBlock" text="import sdk from &apos;./1-init-sdk.js&apos;;
import { readFileSync } from &apos;fs&apos;;

import dotenv from &apos;dotenv&apos;;
dotenv.config();

const app = sdk.getAppModule(&apos;YOUR_APP_ADDRESS&apos;);

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

    console.log(
      &apos;✅ Successfully deployed nft module, address:&apos;,
      nftModule.address
    );
  } catch (error) {
    console.log(&apos;failed to deploy nft module&apos;, error);
  }
})();
"><code><span class="hljs-keyword">import</span> <span class="hljs-title">sdk</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'./1-init-sdk.js'</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">readFileSync</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'fs'</span>;

<span class="hljs-keyword">import</span> <span class="hljs-title">dotenv</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'dotenv'</span>;
dotenv.config();

const app <span class="hljs-operator">=</span> sdk.getAppModule(<span class="hljs-string">'YOUR_APP_ADDRESS'</span>);

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

    console.log(
      <span class="hljs-string">'✅ Successfully deployed nft module, address:'</span>,
      nftModule.<span class="hljs-built_in">address</span>
    );
  } <span class="hljs-keyword">catch</span> (<span class="hljs-function"><span class="hljs-keyword">error</span>) </span>{
    console.log(<span class="hljs-string">'failed to deploy nft module'</span>, <span class="hljs-function"><span class="hljs-keyword">error</span>)</span>;
  }
})();
</code></pre><p>The code is pretty self-explanatory. We&apos;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&apos;ve also provided the necessary metadata as an argument to the <code>deployNftModule</code> function.</p><p>Once you run this script, it will return the collection&apos;s address. Here&apos;s what I get:</p><pre data-type="codeBlock" text="lilcoderman % node scripts/2-deploy-collection.js
✅ Successfully deployed nft module, address: 0x1C267DC8841999de9B9C4F33D63a8d6bC81b8e2D
"><code>lilcoderman <span class="hljs-operator">%</span> node scripts<span class="hljs-operator">/</span><span class="hljs-number">2</span><span class="hljs-operator">-</span>deploy<span class="hljs-operator">-</span>collection.js
✅ Successfully deployed nft module, <span class="hljs-keyword">address</span>: <span class="hljs-number">0x1C267DC8841999de9B9C4F33D63a8d6bC81b8e2D</span>
</code></pre><h3 id="h-3-time-to-mint-our-nft" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3. Time to mint our NFT</h3><p>We&apos;re almost done now! It&apos;s time to mint our NFT, and we haven&apos;t even written a single line of Solidity. This is probably the simplest code we&apos;ve written so far. Copy the following code to the final file <code>3-mint-nft.js</code>:</p><pre data-type="codeBlock" text="import sdk from &apos;./1-init-sdk.js&apos;;
import { readFileSync } from &apos;fs&apos;;

const nft = sdk.getNFTModule(&apos;YOUR_NFT_MODULE_ADDRESS&apos;);

(async () =&gt; {
  try {
    await nft.mint({
      name: &apos;LCM&apos;,
      description: &apos;Follow me on twitter @lilcoderman&apos;,
      image: readFileSync(&apos;assets/nft.png&apos;),
      properties: {},
    });
    console.log(&apos;✅ Successfully created a new NFT in the collection!&apos;);
  } catch (error) {
    console.error(&apos;failed to create the new NFT&apos;, error);
  }
})();
"><code><span class="hljs-keyword">import</span> <span class="hljs-title">sdk</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'./1-init-sdk.js'</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">readFileSync</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'fs'</span>;

const nft <span class="hljs-operator">=</span> sdk.getNFTModule(<span class="hljs-string">'YOUR_NFT_MODULE_ADDRESS'</span>);

(async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
  <span class="hljs-keyword">try</span> {
    await nft.mint({
      name: <span class="hljs-string">'LCM'</span>,
      description: <span class="hljs-string">'Follow me on twitter @lilcoderman'</span>,
      image: readFileSync(<span class="hljs-string">'assets/nft.png'</span>),
      properties: {},
    });
    console.log(<span class="hljs-string">'✅ Successfully created a new NFT in the collection!'</span>);
  } <span class="hljs-keyword">catch</span> (<span class="hljs-function"><span class="hljs-keyword">error</span>) </span>{
    console.error(<span class="hljs-string">'failed to create the new NFT'</span>, <span class="hljs-function"><span class="hljs-keyword">error</span>)</span>;
  }
})();
</code></pre><p>Just like before, we&apos;re importing the SDK from the first file. However, we are using the module <code>getNFTModule</code> this time around. This module returns our ERC-721 contract.</p><p>Then, we can call the <code>mint</code> function from the contract to create an actual NFT! The mint function requires an object containing the metadata of the token. I&apos;ve passed in the NFT&apos;s name, description, and image as arguments. You can also set its properties if you&apos;d like.</p><p>Now, let&apos;s run it:</p><pre data-type="codeBlock" text="lilcoderman % node scripts/3-mint-nft.js
✅ Successfully created a new NFT in the collection!
"><code>lilcoderman <span class="hljs-operator">%</span> node scripts<span class="hljs-operator">/</span><span class="hljs-number">3</span><span class="hljs-operator">-</span>mint<span class="hljs-operator">-</span>nft.js
✅ Successfully created a <span class="hljs-keyword">new</span> NFT in the collection<span class="hljs-operator">!</span>
</code></pre><p>You can now view the NFT on your thirdweb <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thirdweb.com/rinkeby/">dashboard</a>.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/bfb057dff66d0bcb44977be8eb063914890a81221ad536f9512cd4c7fa4f17bb.png" alt="NFT collection - thirdweb dashboard" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">NFT collection - thirdweb dashboard</figcaption></figure><p>We can also find our NFT on <strong>OpenSea</strong> by using its address. Go to this <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://testnets.opensea.io/assets/0x1c267dc8841999de9b9c4f33d63a8d6bc81b8e2d/0">link</a> to check mine.</p><p>That&apos;s it. You&apos;ve now minted an NFT using JavaScript only. Pretty f*cking cool, won&apos;t you say?</p><p>Anyway, here&apos;s the Github repo with all the code: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/abdulrauf11/tutorial-thirdweb-nft">https://github.com/abdulrauf11/tutorial-thirdweb-nft</a></p><h2 id="h-what-next" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">What next...</h2><p>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.</p><p>We&apos;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.</p><p>Keep in mind, if you&apos;re going to use thirdweb in production, they will take a minor 5% cut from your royalties. I think that&apos;s fair given how they&apos;re making our lives much easier with their product.</p><hr><p>Get in touch if you want to know more about NFTs and Web dev. You can find me on Twitter <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/lilcoderman">@lilcoderman</a></p>]]></content:encoded>
            <author>lilcoderman@newsletter.paragraph.com (lilcoderman)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/8d8a607e44c35dbda37944b8b410a336553e2e25bb0d028576a1703c880813c7.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[How to create a motherf*cking NFT using Solidity]]></title>
            <link>https://paragraph.com/@lilcoderman/how-to-create-a-motherf-cking-nft-using-solidity</link>
            <guid>UQrv6dNPVlOrEIRnqikH</guid>
            <pubDate>Wed, 08 Dec 2021 20:11:16 GMT</pubDate>
            <description><![CDATA[This is a simple no-bullshit guide to creating an NFT using Solidity.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.I am going to start by showing you the entire code.// 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 ERC721URIStor...]]></description>
            <content:encoded><![CDATA[<p>This is a simple no-bullshit guide to creating an NFT using Solidity.</p><blockquote><p><em>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.</em></p></blockquote><p>I am going to start by showing you the entire <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://gist.github.com/abdulrauf11/179411d79dfee19b050cddb0e1fa07a4">code</a>.</p><pre data-type="codeBlock" text="// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

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


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

    constructor() ERC721(&quot;BasicNFT&quot;, &quot;BNFT&quot;) {}

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

        uint256 newItemId = _tokenIds.current();
        
        _safeMint(msg.sender, newItemId);
        _setTokenURI(newItemId, tokenURI);
    }
}
"><code><span class="hljs-comment">// SPDX-License-Identifier: UNLICENSED</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/utils/Counters.sol"</span>;


<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">BasicNFT</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC721URIStorage</span> </span>{
    <span class="hljs-keyword">using</span> <span class="hljs-title">Counters</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title">Counters</span>.<span class="hljs-title">Counter</span>;
    Counters.Counter <span class="hljs-keyword">private</span> _tokenIds;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) <span class="hljs-title">ERC721</span>(<span class="hljs-params"><span class="hljs-string">"BasicNFT"</span>, <span class="hljs-string">"BNFT"</span></span>) </span>{}

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mint</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> tokenURI</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        _tokenIds.increment();

        <span class="hljs-keyword">uint256</span> newItemId <span class="hljs-operator">=</span> _tokenIds.current();
        
        _safeMint(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, newItemId);
        _setTokenURI(newItemId, tokenURI);
    }
}
</code></pre><p>Wait…that’s it?</p><p>Yes, what else did you expect you beautiful b*stard?</p><p>Now let&apos;s try to understand the not-so-obvious lines of code.</p><h2 id="h-openzeppelin-to-the-rescue" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">OpenZeppelin to the rescue</h2><p>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.</p><pre data-type="codeBlock" text="import &quot;@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol&quot;;
import &quot;@openzeppelin/contracts/utils/Counters.sol&quot;;
"><code><span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/utils/Counters.sol"</span>;
</code></pre><p>We&apos;ll discuss what exactly I am using from these contracts in the coming sections.</p><h2 id="h-inheriting-from-erc721uristorage" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Inheriting from &apos;ERC721URIStorage&apos;</h2><p>Next, we inherit our contract from the <code>ERC721URIStorage</code> 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.</p><pre data-type="codeBlock" text="contract BasicNFT is ERC721URIStorage {}
"><code><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">BasicNFT</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC721URIStorage</span> </span>{}
</code></pre><h2 id="h-initializing-the-constructor" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Initializing the constructor</h2><p>Since we&apos;re inheriting from <code>ERC721URIStorage</code>, we&apos;ll initialize its constructor in the <code>BasicNFT</code> constructor. It requires two parameters i.e. a name and a symbol.</p><pre data-type="codeBlock" text="// name: &apos;BasicNFT&apos;, symbol: &apos;BNFT&apos;
constructor() ERC721(&quot;BasicNFT&quot;, &quot;BNFT&quot;) {}
"><code>// name: <span class="hljs-string">'BasicNFT'</span>, symbol: <span class="hljs-string">'BNFT'</span>
<span class="hljs-built_in">constructor</span>() <span class="hljs-built_in">ERC721</span>(<span class="hljs-string">"BasicNFT"</span>, <span class="hljs-string">"BNFT"</span>) {}
</code></pre><p>The name and symbol are not f*cking important, so let&apos;s just move on.</p><h2 id="h-assign-token-ids-with-counters" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Assign token ids with &apos;Counters&apos;</h2><p>Let&apos;s see another utility provided to us by the brilliant OpenZeppelin library i.e. <code>Counters</code>. This gets you a simple counter that can be incremented or decremented. It will allow us to issue ids to our ERC721 tokens.</p><pre data-type="codeBlock" text="// include counters
using Counters for Counters.Counter;
// declare token ids as counters
Counters.Counter private _tokenIds;
"><code><span class="hljs-comment">// include counters</span>
<span class="hljs-keyword">using</span> <span class="hljs-title">Counters</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title">Counters</span>.<span class="hljs-title">Counter</span>;
<span class="hljs-comment">// declare token ids as counters</span>
Counters.Counter <span class="hljs-keyword">private</span> _tokenIds;
</code></pre><h2 id="h-coding-the-mint-function" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Coding the mint function</h2><p>Now comes the most important function in this contract i.e the motherf*cking <code>mint</code> function. I&apos;ve declared it as a public method so that everyone is allowed to call it.</p><p>Let&apos;s go through all the steps we take inside this function. Here&apos;s the code with some comments:</p><pre data-type="codeBlock" text=" 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);
 }
"><code> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mint</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> tokenURI</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
     <span class="hljs-comment">// 1. Increment the the token Ids by one</span>
     _tokenIds.increment();
     <span class="hljs-comment">// 2. Get the current Id (the first id will be 1)</span>
     <span class="hljs-keyword">uint256</span> newItemId <span class="hljs-operator">=</span> _tokenIds.current();
     <span class="hljs-comment">// 3. Call the `_safeMint` function provided by OpenZeppelin</span>
     _safeMint(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, newItemId);
     <span class="hljs-comment">// 4. Call the `_setTokenURI` function provided by OpenZeppelin</span>
     _setTokenURI(newItemId, tokenURI);
 }
</code></pre><p>Yeah, I should probably explain the last two lines of the code.</p><h3 id="h-safemint-explained" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">_safeMint explained</h3><p>This function literally mints an ERC721 token for you. It takes in an address and a token id as arguments. I am passing in <code>msg.sender</code> and <code>newItemId</code> as the address and token id respectively.</p><ul><li><p><code>msg.sender</code> is the wallet calling the mint function</p></li><li><p><code>newItemId</code> is the current token id i.e. <code>_tokenIds.current()</code></p></li></ul><p>Once called, this function will safely mint a token and transfer it to the wallet calling the mint function.</p><h3 id="h-settokenuri-explained" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">_setTokenURI explained</h3><p>This is one of my favorite 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.</p><p>We&apos;ll discuss how to get a <code>tokenURI</code> soon. Basically, it&apos;s just a URL that sends back a <strong>JSON</strong> object.</p><p>This is the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ipfs.io/ipfs/bafkreibsk54mbtejlffbvbl2fepyfgnee3ccdiy7ywkv5nu5ja6erxwazy">tokenURI</a> I&apos;ll be using as an example. It returns the following object:</p><pre data-type="codeBlock" text="{
  &quot;name&quot;: &quot;Basic NFT&quot;,
  &quot;description&quot;: &quot;Basic NFT tutorial by @lilcoderman&quot;,
  &quot;image&quot;: &quot;https://ipfs.io/ipfs/bafkreid5vd3sw2wwj2uagm22nomnktbhgl2qqcgksgxvu7xfwwbxtxecly&quot;
}
"><code>{
  <span class="hljs-string">"name"</span>: <span class="hljs-string">"Basic NFT"</span>,
  <span class="hljs-string">"description"</span>: <span class="hljs-string">"Basic NFT tutorial by @lilcoderman"</span>,
  <span class="hljs-string">"image"</span>: <span class="hljs-string">"https://ipfs.io/ipfs/bafkreid5vd3sw2wwj2uagm22nomnktbhgl2qqcgksgxvu7xfwwbxtxecly"</span>
}
</code></pre><p>After the contract is deployed, you will be able to call the mint function with a <code>tokenURI</code> and get a unique ERC721 token in return.</p><p>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.</p><h2 id="h-deploying-to-testnet" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Deploying to testnet</h2><p>I am going to use <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://remix.ethereum.org/">Remix</a> to compile, deploy and interact with the contract. The contract will be deployed to the <strong>Rinkeby</strong> testnet. If you need to learn how to do that, please go through this <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://forum.openzeppelin.com/t/create-an-nft-and-deploy-to-a-public-testnet-using-remix/6358">link</a>.</p><p>My contract got deployed to this address: <strong>0x20A65d15fFf5315A4c9E79dED87273b1BfC3Fd65</strong></p><p>After deploying, let&apos;s call the mint function with the <code>tokenURI</code> I mentioned above.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/566e47bf4a9372f1e433f778ec29814bb8d0153947e8936c1bdd9b5d7bf9b780.png" alt="Contract interface provided by Remix" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Contract interface provided by Remix</figcaption></figure><p>We&apos;ll wait a few minutes after it finishes minting. Now, let&apos;s take a look at our newly minted NFT on OpenSea/Rarible:</p><ul><li><p><strong>OpenSea:</strong> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://testnets.opensea.io/assets/0x20a65d15fff5315a4c9e79ded87273b1bfc3fd65/1">https://testnets.opensea.io/assets/0x20a65d15fff5315a4c9e79ded87273b1bfc3fd65/1</a></p></li><li><p><strong>Rarible:</strong> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://rinkeby.rarible.com/token/0x20a65d15fff5315a4c9e79ded87273b1bfc3fd65:1">https://rinkeby.rarible.com/token/0x20a65d15fff5315a4c9e79ded87273b1bfc3fd65:1</a></p></li></ul><p>So freaking cool, right?</p><h2 id="h-image-and-metadata" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Image and Metadata</h2><p>Throughout this article, we&apos;ve assumed that we already have the <code>tokenURI</code> i.e. the URL pointing towards our metadata. But, how did I get that? Where did I upload my NFT&apos;s image and metadata?</p><p>I uploaded them to an <strong>IPFS</strong>. IPFS is a decentralized file storage system that isn&apos;t controlled by one entity and is instead maintained by a large number of peers in the network.</p><h3 id="h-nftstorage" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">nft.storage</h3><p>I used a free service called <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://nft.storage/">nft.storage</a> 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.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7c7119aea8505906ad3fa953410ea9acef029c95a03e4b7d35d7694973ffdc0c.png" alt="Image and metadata files as shown on nft.storage" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Image and metadata files as shown on nft.storage</figcaption></figure><p>Copy the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ipfs.io/ipfs/bafkreibsk54mbtejlffbvbl2fepyfgnee3ccdiy7ywkv5nu5ja6erxwazy">link</a> to your metadata and pass it as an argument to the mint function.</p><h2 id="h-off-chain-vs-on-chain" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Off-chain vs. On-chain</h2><p>In this article, we&apos;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:</p><ul><li><p>off-chain: Only the token ids are stored on the blockchain. Image and metadata are stored somewhere else e.g. IPFS.</p></li><li><p>on-chain: Both the metadata and image are stored directly on the blockchain.</p></li></ul><p>We stored our image and metadata on IPFS, which is a pretty good second option. Many top projects have used this same approach.</p><p>Get in touch if you want to know more about NFTs and Web dev. You can find me on Twitter <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/lilcoderman">@lilcoderman</a></p>]]></content:encoded>
            <author>lilcoderman@newsletter.paragraph.com (lilcoderman)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/889fb5a1fb62e4b8341c7ad85354f26930c132c965511cc359e1b6de96374eb4.png" length="0" type="image/png"/>
        </item>
    </channel>
</rss>