DEV Community: Aayush Gupta The latest articles on DEV Community by Aayush Gupta (@aayushguptacoder). https://dev.to/aayushguptacoder 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%2F842584%2Fade3bd9e-36bf-41ae-94a1-af3ef42df269.jpg DEV Community: Aayush Gupta https://dev.to/aayushguptacoder en How to Build an NFT Gallery Using QuickNode's GraphQL NFT API Aayush Gupta Fri, 17 Mar 2023 11:10:17 +0000 https://dev.to/aayushguptacoder/how-to-build-an-nft-gallery-using-quicknodes-graphql-nft-api-l82 https://dev.to/aayushguptacoder/how-to-build-an-nft-gallery-using-quicknodes-graphql-nft-api-l82 <p><strong>A step-by-step tutorial on building an interactive NFT Gallery using QuickNode's GraphQL NFT API, icy.tools, JavaScript, Next.js, and Tailwind CSS</strong></p> <h2> <strong>What Are We Building</strong> </h2> <p>In this tutorial, we will be building an NFT Gallery using QuickNode's GraphQL NFT API, Icy.tools, React, JavaScript, Next.js, Vercel, and TailwindCSS. The React web app will provide a user interface that displays a grid view of all the NFTs held by any given Ethereum Name Service (ENS). NFT data was fetched using icy-nft-tools.</p> <p><a href="proxy.php?url=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%2Feg4qgfc9ckapjrbdut2e.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Feg4qgfc9ckapjrbdut2e.png" alt="NFT Gallery"></a></p> <h2> <strong>What is QuickNode?</strong> </h2> <p>QuickNode is a blockchain platform that provides infrastructure for developers to build and scale decentralized applications (DApps). It offers a suite of tools and services, including a developer API, to make it easier for developers to build, test, and deploy DApps on multiple blockchain networks. QuickNode aims to simplify the building process on blockchain and make it more accessible for developers while also providing high-performance infrastructure to support the growing demand for decentralized applications.</p> <h3> <strong>What is QuickNode's GraphQL NFT API?</strong> </h3> <p><a href="proxy.php?url=https://developers.icy.tools/?utm_source=developerdao&amp;utm_campaign=dd&amp;utm_content=ddgraphql" rel="noopener noreferrer"><strong>Sign up for the free GraphQL NFT API!</strong></a></p> <p>The GraphQL NFT API is a set of tools and services that allow developers to interact with NFT platforms using the GraphQL query language. This API provides a convenient way for developers to discover, track, and analyze NFTs with real-time floor and volume data, historical charts and trend data, NFT portfolio values on any wallet, and more. This service also allows fetching the NFTs owned by a specified address. In this tutorial, we will explore how to use this feature.</p> <h3> <strong>Explore QuickNode Marketplace!</strong> </h3> <p>Besides its GraphQL NFT API, QuickNode offers many more tools and solutions for Web3 developers in its <a href="proxy.php?url=https://www.quicknode.com/marketplace" rel="noopener noreferrer"><strong>marketplace</strong></a>. This includes a gas price estimator, crossmint NFT API, GoPlus anti-fraud API, and a massive library of expert-crafted guides, tutorials, documentation, and other developer resources.</p> <blockquote> <p><em>Note: QuickNode recently acquired</em> <a href="proxy.php?url=http://Icy.tools" rel="noopener noreferrer"><em>Icy.tools</em></a> <em>and we will use the</em> <code>icy-nft-hooks</code> <em>library to access GraphQL NFT API.</em></p> </blockquote> <p><strong>By the end of this tutorial, you will be able to:</strong></p> <ul> <li><p>Install, set up, and initialize the icy-nft-hooks.</p></li> <li><p>Create a new Next.js project and learn how to use the icy-nft-hooks to interact with QuickNode GraphQl NFT APIs for data retrieval.</p></li> <li><p>Fetch and store NFT data retrieved for a wallet address into a state variable and display the results to the user interface.</p></li> </ul> <h3> <strong>The Functionalities</strong> </h3> <ul> <li><p>Users will be able to input Ethereum Name Service (ENS) into the "Ethereum Name Service" field.</p></li> <li><p>The app will interact with the provider API endpoints and fetch the NFT data using <a href="proxy.php?url=https://developers.icy.tools/?utm_source=quicknode&amp;utm_campaign=quicknode-header" rel="noopener noreferrer">Icy.tools</a>.</p></li> <li><p>The app returns a gallery grid view of all the NFTs held by the wallet address to the user interface.</p></li> </ul> <h2> <strong>The Tech Stack</strong> </h2> <ul> <li><p>CSS Framework: <a href="proxy.php?url=https://tailwindcss.com/" rel="noopener noreferrer"><strong>TailwindCSS</strong></a></p></li> <li><p>RPC Provider: <a href="proxy.php?url=https://developers.icy.tools/?utm_source=quicknode&amp;utm_campaign=quicknode-header" rel="noopener noreferrer">QuickNode</a></p></li> <li><p>JavaScript Libraries: <strong>Icy-nft-hooks</strong>, <a href="proxy.php?url=https://reactjs.org/tutorial/tutorial.html" rel="noopener noreferrer"><strong>React</strong></a></p></li> <li><p>Frontend/Framework: <a href="proxy.php?url=https://www.javascript.com/" rel="noopener noreferrer"><strong>JavaScript</strong></a>, <a href="proxy.php?url=https://nextjs.org/" rel="noopener noreferrer"><strong>Next.js</strong></a></p></li> </ul> <h1> Let's BUIDL </h1> <p><strong>The Prerequisites</strong></p> <ul> <li><p>Have <a href="proxy.php?url=https://git-scm.com/downloads" rel="noopener noreferrer"><strong>Git</strong></a>, <a href="proxy.php?url=https://yarnpkg.com/" rel="noopener noreferrer"><strong>Yarn</strong></a>, <a href="proxy.php?url=https://tailwindcss.com/docs/guides/nextjs" rel="noopener noreferrer"><strong>TailwindCSS</strong></a>, and <a href="proxy.php?url=https://nodejs.org/en/download/" rel="noopener noreferrer"><strong>Node.js</strong></a> installed on your machine</p></li> <li><p>Basic understanding of <a href="proxy.php?url=https://www.codecademy.com/learn/introduction-to-javascript" rel="noopener noreferrer"><strong>JavaScript</strong></a>, <a href="proxy.php?url=https://reactjs.org/tutorial/tutorial.html" rel="noopener noreferrer"><strong>React</strong></a>, and <a href="proxy.php?url=https://tailwindcss.com/" rel="noopener noreferrer"><strong>TailwindCSS</strong></a></p></li> </ul> <h2> <strong>Step 1: Create Next.js Project</strong> </h2> <p>We will set up our environment and install the necessary dependencies. Open a terminal on your machine and navigate to the directory location where you would like to store your Next.js project. Then, run the following command:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code>yarn create next-app <span class="nb">.</span> </code></pre> </div> <p>This command creates a new Next.js starter project in the directory specified. Now, start the local development server by running the following command:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code>yarn dev </code></pre> </div> <p>The above command sets up your local development environment. Copy and paste <a href="proxy.php?url=http://localhost:3000" rel="noopener noreferrer"><code>http://localhost:3000</code></a> into your web browser to launch the Next.js starter project. Here's what your web browser should look like:</p> <p><a href="proxy.php?url=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%2Fpw8shxo1vu5o6lw89fhz.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fpw8shxo1vu5o6lw89fhz.png" alt="Next.js"></a></p> <p>The current app only contains the starter code provided by Next.js, which we will modify throughout this tutorial to create the custom frontend UI for our NFT market dashboard.</p> <p>Now, let's install Tailwind CSS and its necessary dependencies using npm by running the following command in the terminal:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code>npm <span class="nb">install</span> <span class="nt">-D</span> tailwindcss postcss autoprefixer </code></pre> </div> <p>Run the <code>init</code> command to generate both <code>tailwind.config.js</code> and <code>postcss.config.js</code> files:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight javascript"><code><span class="nx">npx</span> <span class="nx">tailwindcss</span> <span class="nx">init</span> <span class="o">-</span><span class="nx">p</span> </code></pre> </div> <p>In your <code>tailwind.config.js</code> file, add the paths to all your template files by updating the code with the following:</p> <p><strong>File</strong> <code>./tailwind.config.js</code><br> </p> <div class="highlight js-code-highlight"> <pre class="highlight javascript"><code><span class="cm">/** @type {import('tailwindcss').Config} */</span> <span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="p">{</span> <span class="na">content</span><span class="p">:</span> <span class="p">[</span> <span class="dl">"</span><span class="s2">./pages/**/*.{js,ts,jsx,tsx}</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">./components/**/*.{js,ts,jsx,tsx}</span><span class="dl">"</span><span class="p">,</span> <span class="p">],</span> <span class="na">theme</span><span class="p">:</span> <span class="p">{</span> <span class="na">extend</span><span class="p">:</span> <span class="p">{},</span> <span class="p">},</span> <span class="na">plugins</span><span class="p">:</span> <span class="p">[],</span> <span class="p">}</span> </code></pre> </div> <p>Now add the <code>@tailwind</code> directives for each of Tailwind's layers to your <code>globals.css</code> file. The top of your <code>globals.css</code> file should look like this:</p> <p><strong>File</strong> <code>./styles/globals.css</code><br> </p> <div class="highlight js-code-highlight"> <pre class="highlight css"><code><span class="k">@tailwind</span> <span class="n">base</span><span class="p">;</span> <span class="k">@tailwind</span> <span class="n">components</span><span class="p">;</span> <span class="k">@tailwind</span> <span class="n">utilities</span><span class="p">;</span> <span class="o">...</span> </code></pre> </div> <h2> <strong>Step 02: Installing the icy-nft-hooks Library</strong> </h2> <p>For creating the NFT market dashboard, we need real-time data, and we will fetch this data using the GraphQL NFT API. We will install and set up <code>icy-nft-hooks</code>a React hook library that acts as a wrapper for the <a href="proxy.php?url=http://icy.tools" rel="noopener noreferrer"><strong>icy.tools</strong></a> GraphQL API. This library enables us to fetch real-time NFT market data, such as the floor price, sales, average price, volume, market cap, etc.</p> <p>Install the <code>icy-nft-hooks</code> with the following command:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code>yarn add @quicknode/icy-nft-hooks yarn add @apollo/client graphql </code></pre> </div> <p>In the <code>pages</code> directory, navigate to the <code>_app.js</code> file. Copy and paste the following code into <code>_app.js</code> file.<br><br> File: <code>./pages/_app.js</code><br> </p> <div class="highlight js-code-highlight"> <pre class="highlight javascript"><code><span class="k">import</span> <span class="dl">"</span><span class="s2">../styles/globals.css</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">IcyProvider</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">@quicknode/icy-nft-hooks</span><span class="dl">"</span><span class="p">;</span> <span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nf">App</span><span class="p">({</span> <span class="nx">Component</span><span class="p">,</span> <span class="nx">pageProps</span> <span class="p">})</span> <span class="p">{</span> <span class="k">return </span><span class="p">(</span> <span class="o">&lt;</span><span class="nx">IcyProvider</span> <span class="nx">apiKey</span><span class="o">=</span><span class="p">{</span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">QUICKNODE_NFT_API_KEY</span><span class="p">}</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">Component</span> <span class="p">{...</span><span class="nx">pageProps</span><span class="p">}</span> <span class="sr">/</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="sr">/IcyProvider</span><span class="err">&gt; </span> <span class="p">);</span> <span class="p">}</span> </code></pre> </div> <p>We are importing the <code>IcyProvider</code> hook from the <code>icy-nft-hooks</code> package and wrapping the entire web app with the <code>IcyProvider</code> hook.</p> <h2> <strong>Step 03: Getting an NFT API Key</strong> </h2> <p>As you can see in the above code, we will need an API key to fetch real-time NFT market data. To get the API key, follow these steps:</p> <p>Open <a href="proxy.php?url=https://developers.icy.tools/" rel="noopener noreferrer"><strong>Icy tools</strong></a> link and click on the "Sign Up" button.</p> <p><a href="proxy.php?url=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%2F2jxbathd5f0xh9kchbm6.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2F2jxbathd5f0xh9kchbm6.png" alt="Icy.tools"></a></p> <p>Enter the details and click on the "Sign Up" button</p> <p><a href="proxy.php?url=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%2Fqah8pqx2bsurlwwmkrsd.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fqah8pqx2bsurlwwmkrsd.png" alt="Sign Up"></a></p> <p>You'll land on the "Explore" page of <a href="proxy.php?url=http://icy.tools" rel="noopener noreferrer"><strong>icy.tools</strong></a>, where you will see something like this:</p> <p><a href="proxy.php?url=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%2Fa0ip0ueu47h9cuqd3uab.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fa0ip0ueu47h9cuqd3uab.png" alt="Icy.tools page"></a></p> <p>Click on the "Settings" button on the left side. You will see the API key.</p> <p><a href="proxy.php?url=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%2Fc88pz4fxbgu8ngqq7osa.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fc88pz4fxbgu8ngqq7osa.png" alt="Settings"></a></p> <h2> <strong>Step 04: Installing the dotenv Package</strong> </h2> <p>I recommend storing sensitive information, such as API keys, in environment variables instead of hardcoding them in the code. We will use <code>dotenv</code> package for storing sensitive information. Run the following command to install the dotenv package:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code>yarn add <span class="nt">--dev</span> dotenv </code></pre> </div> <p>Create a <code>.env</code> file in the root folder. Add environment variable<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code>QUICKNODE_NFT_API_KEY <span class="o">=</span> <span class="s2">"c34kndhiflmln-API-KEY"</span> </code></pre> </div> <h2> <strong>Step 05: Fetching the NFT</strong> </h2> <p>In this section, we'll create the <code>WalletNFTs</code> function that accepts the ENS as the user input and returns the collection of NFTs owned by the input address. @quicknode/icy-nft-hook library provides us with the <code>getNFTsByOwner</code> method that we will implement and utilize inside of our <code>WalletNFTs</code> function. The NFT Gallery dapp will accept input for Ethereum wallet addresses.</p> <p>Create a new file <code>WalletNFTs.js</code> and Copy the below code.</p> <p>File: <code>./pages/WalletNFTs.js</code><br> </p> <div class="highlight js-code-highlight"> <pre class="highlight javascript"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">useWalletNFTs</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">@quicknode/icy-nft-hooks</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">useState</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react</span><span class="dl">"</span><span class="p">;</span> <span class="kd">function</span> <span class="nf">WalletNFTs</span><span class="p">()</span> <span class="p">{</span> <span class="kd">const</span> <span class="p">[</span><span class="nx">ensName</span><span class="p">,</span> <span class="nx">setEnsName</span><span class="p">]</span> <span class="o">=</span> <span class="nf">useState</span><span class="p">(</span><span class="dl">"</span><span class="s2">vitalik.eth</span><span class="dl">"</span><span class="p">);</span> <span class="c1">//vitalik.eth</span> <span class="kd">const</span> <span class="p">[</span><span class="nx">cursor</span><span class="p">,</span> <span class="nx">setCursor</span><span class="p">]</span> <span class="o">=</span> <span class="nf">useState</span><span class="p">(</span><span class="dl">""</span><span class="p">);</span> <span class="kd">const</span> <span class="p">{</span> <span class="nx">nfts</span><span class="p">,</span> <span class="nx">isSearchValid</span><span class="p">,</span> <span class="nx">pageInfo</span> <span class="p">}</span> <span class="o">=</span> <span class="nf">useWalletNFTs</span><span class="p">({</span> <span class="nx">ensName</span><span class="p">,</span> <span class="na">first</span><span class="p">:</span> <span class="mi">12</span><span class="p">,</span> <span class="na">after</span><span class="p">:</span> <span class="nx">cursor</span><span class="p">,</span> <span class="p">});</span> <span class="k">return </span><span class="p">(</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">p-10 flex flex-col items-center</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">w-full h-full flex flex-col justify-start gap-5 items-center</span><span class="dl">"</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">h1</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">text-7xl font-bold</span><span class="dl">"</span><span class="o">&gt;</span><span class="nx">NFT</span> <span class="nx">Gallery</span><span class="o">&lt;</span><span class="sr">/h1</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">h3</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">text-xl font-semibold</span><span class="dl">"</span><span class="o">&gt;</span> <span class="nx">Powered</span> <span class="nx">by</span><span class="p">{</span><span class="dl">"</span><span class="s2"> </span><span class="dl">"</span><span class="p">}</span> <span class="o">&lt;</span><span class="nx">a</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">underline</span><span class="dl">"</span> <span class="nx">href</span><span class="o">=</span><span class="dl">"</span><span class="s2">https://developers.icy.tools/?utm_source=quicknode&amp;utm_campaign=quicknode-header</span><span class="dl">"</span> <span class="o">&gt;</span> <span class="nx">QuickNode</span><span class="dl">'</span><span class="s1">s GraphQL NFT API &lt;/a&gt; &lt;/h3&gt; &lt;/div&gt; &lt;div className="flex-left flex-col mt-4"&gt; &lt;label className="text-white text-2xl font-extrabold pb-2" htmlFor="wallet-address" &gt; &amp;nbsp; Ethereum Name Service &amp;nbsp; &lt;/label&gt; &lt;div className="search"&gt; &lt;input className="px-3 py-2 rounded-md" type="text" value={ensName} onChange={(e) =&gt; setEnsName(e.target.value)} style={{ outlineColor: !isSearchValid &amp;&amp; ensName.length &gt; 0 ? "red" : undefined, }} /&gt; &lt;/div&gt; &lt;/div&gt; &lt;div className="grid grid-cols-4 mt-8 gap-4"&gt; {console.log(nfts)} {nfts.map((nft) =&gt; { const contract = nft.contract; console.log(contract); const imageUrl = nft.images.find((i) =&gt; !!i.url)?.url; return ( &lt;div className="flex flex-col rounded border p-4" key={`${nft.tokenId}${nft.contract.address}`} &gt; &lt;div className="w-full h-full rounded shadow flex justify-center items-center"&gt; &lt;img className="w-full h-full" src={imageUrl ?? "/web3.png"} alt="awesome nft" /&gt; &lt;/div&gt; &lt;div&gt; &lt;h1 className="font-bold"&gt;{contract.name}&lt;/h1&gt; &lt;h2 className="truncate"&gt; {contract.symbol}#{nft.tokenId} &lt;/h2&gt; &lt;/div&gt; &lt;/div&gt; ); })} &lt;/div&gt; {pageInfo?.hasNextPage &amp;&amp; ( &lt;div style={{ alignItems: "flex-end", width: "100%", justifyContent: "flex-end", display: "flex", }} &gt; &lt;button onClick={() =&gt; { setCursor(pageInfo.endCursor ?? undefined); }} &gt; Next &lt;/button&gt; &lt;/div&gt; )} &lt;/div&gt; ); } export default WalletNFTs; </span></code></pre> </div> <p>Interestingly, some NFTs do not have images associated with them. To address this, a default image has been added to the grid as a placeholder in case an NFT does not have its own image.</p> <p>You can find the image <a href="proxy.php?url=https://github.com/AAYUSH-GUPTA-coder/nft-gallery-quicknode/blob/main/public/web3.png" rel="noopener noreferrer">here</a>.</p> <h2> <strong>Step 06: Display NFT Gallery</strong> </h2> <p>We're almost done with our NFT Gallery. In this step, we will import the <code>WalletNFTs</code> component from the <code>WalletNFTs.js</code> file and use it in <code>index.js</code> file.</p> <p><strong>file:</strong> <code>./pages/index.js</code><br> </p> <div class="highlight js-code-highlight"> <pre class="highlight javascript"><code><span class="k">import</span> <span class="nx">Head</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">next/head</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="nx">WalletNFTs</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./WalletNFTs</span><span class="dl">"</span><span class="p">;</span> <span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nf">Home</span><span class="p">()</span> <span class="p">{</span> <span class="k">return </span><span class="p">(</span> <span class="o">&lt;&gt;</span> <span class="o">&lt;</span><span class="nx">Head</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="nx">title</span><span class="o">&gt;</span> <span class="nx">Quicknode</span> <span class="nx">NFT</span> <span class="nx">Gallery</span> <span class="o">&lt;</span><span class="sr">/title</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">meta</span> <span class="nx">name</span><span class="o">=</span><span class="dl">"</span><span class="s2">description</span><span class="dl">"</span> <span class="nx">content</span><span class="o">=</span><span class="dl">"</span><span class="s2">Generated by create next app</span><span class="dl">"</span> <span class="o">/&gt;</span> <span class="o">&lt;</span><span class="nx">meta</span> <span class="nx">name</span><span class="o">=</span><span class="dl">"</span><span class="s2">viewport</span><span class="dl">"</span> <span class="nx">content</span><span class="o">=</span><span class="dl">"</span><span class="s2">width=device-width, initial-scale=1</span><span class="dl">"</span> <span class="o">/&gt;</span> <span class="o">&lt;</span><span class="nx">link</span> <span class="nx">rel</span><span class="o">=</span><span class="dl">"</span><span class="s2">icon</span><span class="dl">"</span> <span class="nx">href</span><span class="o">=</span><span class="dl">"</span><span class="s2">/favicon.ico</span><span class="dl">"</span> <span class="o">/&gt;</span> <span class="o">&lt;</span><span class="sr">/Head</span><span class="err">&gt; </span> <span class="o">&lt;</span><span class="nx">WalletNFTs</span> <span class="o">/&gt;</span> <span class="o">&lt;</span><span class="sr">/</span><span class="err">&gt; </span> <span class="p">);</span> <span class="p">}</span> </code></pre> </div> <p>Now open the <a href="proxy.php?url=http://localhost:3000" rel="noopener noreferrer"><code>http://localhost:3000</code></a> in your browser. You have created an interactive NFT Gallery.</p> <h2> <strong>Step 07: Deploy NFT Gallery</strong> </h2> <p>Now let's deploy our Next.js app with Vercel by following the steps below:</p> <ol> <li><p>Go to <a href="proxy.php?url=https://vercel.com/dashboard" rel="noopener noreferrer"><strong>Vercel</strong></a> and sign in with your GitHub account.</p></li> <li><p>Click the <code>New Project</code> button and select your project repo.</p></li> <li><p>Select the Framework as <code>Next.js</code>.</p></li> <li><p>Enter the environment variables, with the name set to 'QUICKNODE_NFT_API_KEY' and the value set to your API Key.</p></li> <li><p>Click <code>Deploy</code> and now your <a href="proxy.php?url=https://nft-gallery-quicknode-tutorial.vercel.app/" rel="noopener noreferrer"><strong>NFT Gallery</strong></a> is live!</p></li> </ol> <p>Congrats on successfully completing this tutorial! Give yourself a pat on the back. You should now see a gallery grid view of all the NFTs owned by the input wallet address returned to the user interface.</p> <h2> <strong>Full Code Base</strong> </h2> <p>GitHub repository of the complete project: <a href="proxy.php?url=https://github.com/AAYUSH-GUPTA-coder/nft-gallery-quicknode-tutorial" rel="noopener noreferrer"><strong>NFT Gallery</strong></a></p> <p>Website Link: <a href="proxy.php?url=https://nft-gallery-quicknode-tutorial.vercel.app/" rel="noopener noreferrer">NFT Gallery Website</a></p> <p><a href="proxy.php?url=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%2Flzi0cvtr2yufw019gien.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Flzi0cvtr2yufw019gien.png" alt="NFT Gallery"></a></p> <h2> <strong>Additional Resources</strong> </h2> <p><a href="proxy.php?url=https://blog.developerdao.com/how-to-build-an-nft-market-dashboard-using-quicknodes-graphql-nft-api" rel="noopener noreferrer">https://blog.developerdao.com/how-to-build-an-nft-market-dashboard-using-quicknodes-graphql-nft-api</a></p> <p><a href="proxy.php?url=https://github.com/AAYUSH-GUPTA-coder/nft-gallery-quicknode-tutorial" rel="noopener noreferrer">https://github.com/AAYUSH-GUPTA-coder/nft-gallery-quicknode-tutorial</a></p> <p><a href="proxy.php?url=https://docs.icy.tools/developer-api/api-reference" rel="noopener noreferrer">https://docs.icy.tools/developer-api/api-reference</a></p> <h1> <strong>🎉BOOM 🎉</strong> </h1> <p>You have completed the whole tutorial. Give yourself a big pat on the back. You have learned about the following:</p> <ul> <li><p>QuickNode Node Provider</p></li> <li><p>Setting up a Next.js app and integrating Tailwind CSS</p></li> <li><p>Icy.tools NFT Hooks: <code>icy-nft-hooks</code></p></li> <li><p>Getting icy.tools API</p></li> <li><p>Setting and using dotenv package</p></li> <li><p>Fetching and displaying NFTs owned by the address</p></li> </ul> <p>I hope you learned something new or solved a problem. Thanks for reading. Have fun!</p> <p>You can follow me on <a href="proxy.php?url=https://twitter.com/Aayush_gupta_ji" rel="noopener noreferrer">Twitter</a>, <a href="proxy.php?url=https://github.com/AAYUSH-GUPTA-coder" rel="noopener noreferrer">GitHub</a>, and <a href="proxy.php?url=https://www.linkedin.com/in/aayush-gupta-20023b183/" rel="noopener noreferrer">Linkedin</a>. Keep your suggestions and comments coming!</p> web3 blockchain icytools nft What is RPC Node? Navigating the World of RPC Nodes and Node Providers Aayush Gupta Fri, 17 Mar 2023 10:54:19 +0000 https://dev.to/aayushguptacoder/what-is-rpc-node-navigating-the-world-of-rpc-nodes-and-node-providers-4h91 https://dev.to/aayushguptacoder/what-is-rpc-node-navigating-the-world-of-rpc-nodes-and-node-providers-4h91 <p>If you're new to blockchain development, one question always arises: what is an RPC node? It is sometimes referred to as a Blockchain Node, Blockchain API Key, RPC URL, or Blockchain Endpoint. You may already know that RPCs are essential tools used by blockchain developers to build decentralized apps. But what exactly are they, and why are they so important in blockchain technology? In the following article, we will learn about this in detail. It will be a long article, but I assure you that if you stay with it, you will learn all you need to know about RPC nodes and node providers to get started as a web3 developer.</p> <h2> <strong>What is an RPC node in blockchain?</strong> </h2> <p>To begin, let's cover the fundamentals. An RPC node is a program that runs on a computer and facilitates connectivity with the broader blockchain network. It communicates with other nodes, exchanging information and verifying the validity of transactions between parties. Additionally, it stores crucial data regarding the current state of the blockchain.</p> <p>RPC (Remote Procedure Call) is a type of API (Application Programming Interface) that enables developers to execute code on servers remotely. When developers build dApps that utilize RPC, the dApp can link user requests to information from blockchains. For instance, when users access an NFT collection, play a P2E game, or initiate transactions with MetaMask, the dApp leverages an RPC to connect them with nodes that hold blockchain data.</p> <p>Finally, It's worth emphasizing that information on a blockchain can only be accessed via a node; there's simply no other way to do it. In many respects, an RPC node can be thought of as a browser for the blockchain, acting as a gateway between the user and the decentralized network of nodes that uphold the blockchain's integrity.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--TN6vPGBQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1662464259679/qo58XBTZT.png%3Fauto%3Dcompress%2Cformat%26format%3Dwebp%2520align%3D%2522left%2522" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--TN6vPGBQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1662464259679/qo58XBTZT.png%3Fauto%3Dcompress%2Cformat%26format%3Dwebp%2520align%3D%2522left%2522" alt="" width="880" height="753"></a></p> <h2> <strong>Use Cases For RPCs</strong> </h2> <h3> <strong>1.</strong> Creating Decentralized Applications </h3> <p>RPC is widely used for developing dApps that can interact with one or multiple blockchains. Developers use RPC nodes to test and deploy smart contracts on networks. Decentralized applications are powered by smart contracts that enable functionalities like the automatic execution of crypto trades. They also offer user interfaces that make them accessible to a wide audience. The inclusion of an RPC layer in dApps allows these distinct software applications to communicate seamlessly with one another.</p> <h3> <strong>2.</strong> Simplifying the Process of Building Dapps </h3> <p>The RPC layer provides developers with a simplified approach to building decentralized applications. For example, if you were developing a DeFi liquidity farming site and wanted users to view their external wallet's crypto balance, you wouldn't need to create a wallet from scratch. Instead, you could build an API that can communicate with the external wallet to retrieve user holdings. Furthermore, the wallet software can include API-enabling code that facilitates interoperability with various other DeFi protocols.</p> <h3> <strong>3. Querying blockchain data</strong> </h3> <p>When building, developers also need access to a variety of information like block numbers, node connections, transactions, and historical blockchain data. They can make “requests” to their desired blockchain in JSON (JavaScript Object Notation) and receive replies with the info they need.</p> <h3> <strong>4. Run calls</strong> to retrieve vast amounts of data. </h3> <p>Developers can use RPC to execute tasks like encrypting wallets, creating multi-signature addresses, finding the current block size, producing human-readable JSON objects, and much more. These tasks provide critical information that builders need to create their blockchain platforms and services. With free, readily available, and reliable RPC access, developers can build faster and create more efficient applications.</p> <h3> <strong>5.</strong> Developing WebSockets for Real-Time Transaction Data Viewing </h3> <p>WebSockets are programming interfaces that enable continuous information exchange between a client and a server. By maintaining open and persistent communication, there is no need to establish a new connection for every message sent. They are particularly valuable for high-volume applications that require the transmission of substantial amounts of data, such as those found in Internet of Things (IoT) systems.</p> <p>Now that you understand what RPC Node is and why we need it in Blockchain development. Let’s discuss how we can actually use or get RPC Node. We (Web3 developers) have two choices for accessing the node infrastructure necessary for building and operating dApps.</p> <ol> <li><p><strong>Running our own Node</strong>: Set up a node ourselves and take on the DevOps responsibility of equipment maintenance and server problem-solving, which is a very difficult task.</p></li> <li><p><strong>RPC Node Providers:</strong> Use services from RPC Node Providers like <a href="proxy.php?url=https://www.quicknode.com/"><strong>QuickNode</strong></a> via an RPC layer.</p></li> </ol> <h2> <strong>Why is running a node difficult?</strong> </h2> <p>There are a few things that make developing on your own node connected to the network particularly annoying. Let's discuss some reasons:</p> <h3> Setting up nodes can take a long time, sometimes up to weeks! </h3> <p>Developers often find it frustrating to spend significant time setting up a tool that does not directly add value to what they are trying to create and setting up nodes can be especially time-consuming and tedious.</p> <p>There are typically two major categories of nodes</p> <ol> <li><p><strong>Light Nodes</strong>: sync just the block headers and requests from full nodes for many queries.</p></li> <li><p><strong>Full Nodes</strong>: Full nodes keep the entire state of a blockchain - every transaction that's ever been created</p></li> </ol> <p>Although most queries can be handled by light nodes, full nodes are essential for serving most information and are the backbone of the blockchain. While light nodes have become relatively simpler in the past, they still require the installation of the node program, setting configuration variables, downloading block headers, and checking ports and health to ensure they're running correctly.</p> <p>Full nodes are even worse as they require downloading every block from 0 to the latest one from scratch, and manually replaying every block and transaction ever submitted. For Ethereum mainnet, this amounts to over 10 million blocks and billions of transactions, which can take weeks to sync.</p> <h3> <strong>Nodes have to be managed - by you!</strong> </h3> <p>The biggest challenge to running your own node is that you have to manage it yourself, which can be a daunting DevOps project. Here's a quick summary of what's involved:</p> <ul> <li><p>Nodes need to be upgraded regularly, typically every few weeks, and sometimes even rebuilt from scratch due to hard forks or node client upgrades.</p></li> <li><p>Since most nodes were not designed with reliability in mind, certain queries (such as eth_getLogs) may require processing millions of blocks and transactions, often resulting in timeouts or node crashes.</p></li> <li><p>Individual nodes can fall behind the network due to various issues, such as peering and connection problems, being stranded on outdated branches, or internal state problems. If your node falls behind, your users may be served stale data without realizing it, leading to a poor user experience. There are many other reasons why running your node can be time-consuming and unpleasant.</p></li> </ul> <p>To save ourselves from all this unnecessary hard work, we can simply use RPC node providers. I understand that this article is lengthy, but please bear with me. You have already learned all about RPC nodes to get started. Now, let's learn about NODE PROVIDER.</p> <h2> <strong>What is a Node Provider?</strong> </h2> <p>In an ideal world, everyone would run their own node. Unfortunately, we don't live in an ideal world, which is why we have node providers. Node providers are essentially teams or companies (like QuickNode) that offer a way to access information on a blockchain without having to run your own node! Instead of sending your requests to a local node, you can send them over the internet to a provider offering an identical API that is running fully synced, up-to-date nodes available 24/7. A solid node provider will offer, at the very minimum:</p> <ul> <li><p>Access to light and full nodes with regularly updated nodes and alerts so that you don't have to worry about forks or network changes.</p></li> <li><p>Access to archive nodes for historical transaction data.</p></li> <li><p>Scalability and reliability: nodes should be available whenever you want them and as much as you want them.</p></li> <li><p>Consistency: Node Providers handle tricky edge cases.</p></li> </ul> <p>In summary, you can access all the capabilities of an RPC node without any hassle by using node providers, but you will need to pay a fee for their services. By now, you have also understood the reasons why using node providers is preferable to running your own node.</p> <h2> Why you should use QuickNode as a Node Provider </h2> <p><a href="proxy.php?url=https://www.quicknode.com/signup?utm_source=blog&amp;utm_medium=post&amp;utm_content=response-time-comparison">QuickNode</a> is an affordable, globally-distributed, multi-chain, multi-client, premium Web3 infrastructure provider. QuickNode powers industry leaders like Coinbase, 1inch, MagicEden, Exodus, and Nansen, to name a few and serves around 7 billion API requests per day (at the time of writing this article). Here's <a href="proxy.php?url=https://blog.quicknode.com/why-businesses-choose-quicknode-for-web3-infrastructure/">why businesses choose QuickNode for Web3 infrastructure</a>!</p> <p>Also, QuickNode is not only a node provider but an ecosystem in itself with a full suite of blockchain APIs — Core API, Token API, NFT API, Icy GraphQL NFT API — and the first of its kind, blockchain API <a href="proxy.php?url=https://www.quicknode.com/marketplace">Marketplace</a>.</p> <p>For Web3 to gain mass adoption, the UX needs to be pushed to the next level. And that could only happen with highly-performant applications powered by the finest infrastructure and service — nothing short of the best!</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--n9QdfrJi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/97eiwv5cagjlgy3j4074.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--n9QdfrJi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/97eiwv5cagjlgy3j4074.png" alt="QuickNode comparison" width="880" height="453"></a></p> <p>As evidenced by the data, we can conclude that QuickNode is the fastest and most stable node provider. QuickNode's motto is "do your stuff — build — and let us take care of the rest!" Here's <a href="proxy.php?url=https://blog.quicknode.com/justifying-quick-in-quicknode-response-time-comparison-of-various-blockchain-node-providers/">Justifying Quick in QuickNode: A Response Time Comparison of Blockchain Node Providers</a>! You can read this article to fully understand why QuickNode is the fastest.</p> <h2> <strong>🎉BOOM 🎉</strong> </h2> <p>You have completed the whole tutorial. Give yourself a big pat on the back. You have learned about:</p> <ul> <li><p>What is RPC Node</p></li> <li><p>Uses cases of RPC Node</p></li> <li><p>Difficulties with running your own Node</p></li> <li><p>Node Providers</p></li> <li><p>Why you should use QuickNode</p></li> </ul> <p>I hope you learned something new. Thanks for reading. Have fun!</p> <p>You can follow me on <a href="proxy.php?url=https://twitter.com/Aayush_gupta_ji">Twitter</a>, <a href="proxy.php?url=https://github.com/AAYUSH-GUPTA-coder">GitHub</a>, and <a href="proxy.php?url=https://www.linkedin.com/in/aayush-gupta-20023b183/">LinkedIn</a>. Keep your suggestions and comments coming!</p> rpc quicknode nodeprovider web3 How to build your first DataDAO Factory on FVM Aayush Gupta Fri, 23 Dec 2022 09:08:03 +0000 https://dev.to/aayushguptacoder/how-to-build-your-first-datadao-factory-on-fvm-4c1o https://dev.to/aayushguptacoder/how-to-build-your-first-datadao-factory-on-fvm-4c1o <p>This tutorial will enable you to program the Filecoin deal market and create multiple FVM Data DAOs.</p> <p><a href="proxy.php?url=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%2Fxc1n1ehezj0ra0k184pf.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fxc1n1ehezj0ra0k184pf.png" alt="FVM"></a></p> <h2> What is FVM </h2> <p>Let's start by understanding what is FVM. FVM stands for Filecoin Virtual machine. As a web3 developer, you may already know that filecoin is a decentralized storage provider in most layman's terms (or a peer-to-peer network that stores files, with built-in economic incentives to ensure files are stored reliably over time, to be exact). Now think of adding a computational layer on the top of filecoin, that <strong>FVM</strong> for you.</p> <p>The FVM unlocks boundless possibilities, ranging from <strong>programmable storage primitives</strong> (such as storage bounties, auctions, and more), to <strong>cross-chain interoperability bridges</strong> (e.g. trustlessly connecting Filecoin with Ethereum, Solana, NEAR, and more), to <strong>data-centric Decentralized Autonomous Organizations (DAOs)</strong>, to <strong>Layer 2 solutions</strong> (such as reputation systems, data availability sampling, computation fabrics, and incentive-aligned Content Delivery Networks), and more.</p> <h2> What is Storage Deal </h2> <p>Before moving ahead, let us get a quick insight into how the cycle between storage provider, storage, client, and marketplace revolves.</p> <p>Storage deals refer to the stored data that is picked up by a Storage Provider in the Filecoin network. A deal is initiated with the Storage Client to store the data. The deal’s details and metadata of the stored data are then uploaded onto the Filecoin blockchain. FVM/FEVM allows interaction with this metadata, effectively computing over the state.</p> <h1> <strong>Building Data DAO contract</strong> </h1> <p><a href="proxy.php?url=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%2Fcw829s44cns8ieqtfwcy.jpg" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fcw829s44cns8ieqtfwcy.jpg" alt="meme"></a></p> <p>This tutorial would be based on this <a href="proxy.php?url=https://github.com/Open-Sorcerer/CrewS/blob/main/contracts" rel="noopener noreferrer">repo</a>.</p> <p>Now, let's write smart contracts and understand the logic inside them.</p> <h3> DataDAO.sol </h3> <p>This contract enables the storage provider to add the CID to store data with the Filecoin built-in deal market. The process of adding the CID has to go through a policy check where the CID needs to be approved by DAO members via a voting mechanism.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; // import {StdStorage} from "../lib/forge-std/src/Components.sol"; import {specific_authenticate_message_params_parse, specific_deal_proposal_cbor_parse} from "./CBORParse.sol"; contract MockMarket { DataDAO client; constructor(address _client) { client = DataDAO(_client); } function publish_deal(bytes calldata raw_auth_params, uint256 proposalID) public { // calls standard filecoin receiver on message authentication api method number client.handle_filecoin_method(0, 2643134072, raw_auth_params, proposalID); } } contract DataDAO { uint64 constant public AUTHORIZE_MESSAGE_METHOD_NUM = 2643134072; // number of proposals currently in DAO uint256 public proposalCount; // mapping to check whether the cid is set for voting mapping(bytes =&gt; bool) public cidSet; // storing the size of the cid mapping(bytes =&gt; uint) public cidSizes; mapping(bytes =&gt; mapping(bytes =&gt; bool)) public cidProviders; // address of the owner of DataDAO address public immutable owner; struct Proposal { uint256 proposalID; address storageProvider; bytes cidraw; uint size; uint256 upVoteCount; uint256 downVoteCount; uint256 proposedAt; uint256 proposalExpireAt; } // mapping to keep track of proposals mapping(uint256 =&gt; Proposal) public proposals; // mapping array to track whether the user has voted for the proposal mapping(address =&gt; mapping(uint256 =&gt; bool)) public hasVotedForProposal; /** * @dev constructor: to set the owner address */ constructor(address _owner) { require(_owner != address(0), "invalid owner!"); owner = _owner; } /*** * @dev function to create new proposal */ function createCIDProposal(bytes calldata cidraw, uint size) public { proposalCount++; Proposal memory proposal = Proposal(proposalCount, msg.sender, cidraw, size, 0, 0, block.timestamp, block.timestamp + 1 hours); proposals[proposalCount] = proposal; cidSet[cidraw] = true; cidSizes[cidraw] = size; } /** * @dev function to vote in favour of proposal */ function upvoteCIDProposal(uint256 proposalID) public { require(!isCallerSP(proposalID), "Storage Provider cannot vote his own proposal"); require(!hasVotedForProposal[msg.sender][proposalID], "Already Voted"); require(isVotingOn(proposalID), "Voting Period Finished"); proposals[proposalID].upVoteCount = proposals[proposalID].upVoteCount + 1; hasVotedForProposal[msg.sender][proposalID] = true; } /** * @dev function to vote in favour of proposal */ function downvoteCIDProposal(uint256 proposalID) public { require(!isCallerSP(proposalID), "Storage Provider cannot vote his own proposal"); require(!hasVotedForProposal[msg.sender][proposalID], "Already Voted"); require(isVotingOn(proposalID), "Voting Period Finished"); proposals[proposalID].downVoteCount = proposals[proposalID].downVoteCount + 1; hasVotedForProposal[msg.sender][proposalID] = true; } /** * @dev function to check whether the policy is accepted or not */ function policyOK(uint256 proposalID) public view returns (bool) { require(proposals[proposalID].proposalExpireAt &gt; block.timestamp, "Voting in On"); return proposals[proposalID].upVoteCount &gt; proposals[proposalID].downVoteCount; } /** * @dev function to authorizedata and store on filecoin */ function authorizeData(uint256 proposalID, bytes calldata cidraw, bytes calldata provider, uint size) public { require(cidSet[cidraw], "CID must be added before authorizing"); require(cidSizes[cidraw] == size, "Data size must match expected"); require(policyOK(proposalID), "Deal failed policy check: Was the CID proposal Passed?"); cidProviders[cidraw][provider] = true; } /** * @dev function to handle filecoin */ function handle_filecoin_method(uint64, uint64 method, bytes calldata params, uint256 proposalID) public { // dispatch methods if (method == AUTHORIZE_MESSAGE_METHOD_NUM) { bytes calldata deal_proposal_cbor_bytes = specific_authenticate_message_params_parse(params); (bytes calldata cidraw, bytes calldata provider, uint size) = specific_deal_proposal_cbor_parse(deal_proposal_cbor_bytes); cidraw = bytes(bytes(cidraw)); authorizeData(proposalID, cidraw, provider, size); } else { revert("The Filecoin method that was called is not handled"); } } // getter function also used in require statement /** * @dev function to get the storage provider address */ function getSP(uint256 proposalID) view public returns(address) { return proposals[proposalID].storageProvider; } /** * @dev function to check whether the function caller is the storage provider */ function isCallerSP(uint256 proposalID) view public returns(bool) { return getSP(proposalID) == msg.sender; } /** * @dev function to check whether users can start voting on the proposal */ function isVotingOn(uint256 proposalID) view public returns(bool) { return proposals[proposalID].proposalExpireAt &gt; block.timestamp; } /** * @dev get the address of this contract */ function getAddressOfContract() public view returns (address) { return address(this); } } </code></pre> </div> <p>Let’s now go step by step. The storage provider can create a proposal to add his CID using <strong>createCIDProposal</strong> function.</p> <p>As FEVM is pre-launch to Filecoin’s mainnet, FEVM actors as of today, cannot yet interact easily with storage deals on the Filecoin network.</p> <p>To simulate this for the hack, we have sample CID-related data. These deals are built into the Wallaby test network and your actor can interact with them.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code>Sample Test Data testCID <span class="o">=</span> <span class="s2">"0x000181E2039220206B86B273FF34FCE19D6B804EFF5A3F5747ADA4EAA22F1D49C01E52DDB7875B4B"</span><span class="p">;</span> testSize <span class="o">=</span> 2048 testProvider <span class="o">=</span> <span class="s2">"0x0066"</span><span class="p">;</span> testmessageAuthParams <span class="o">=</span> <span class="s2">"0x8240584c8bd82a5828000181e2039220206b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b190800f4420068420066656c6162656c0a1a0008ca0a42000a42000a42000a"</span><span class="p">;</span> </code></pre> </div> <h2> <strong>DataDaoFactory.sol</strong> </h2> <p>Now let's write the Factory contract to interact with this DataDAO smart contract and create multiple versions of it according to our needs.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9; import "./DataDAO.sol"; contract DataDoaFactory{ // factory contract owner address public immutable dataDaoFactoryOwner; // number of DataDAO created uint256 public numOfDataDao; // struct to store all the data of dataDao and dataDaoFactory contract struct dataDaoFactoryStruct { address dataDaoOwner; address dataDaoFactoryOwner; } // searching the struct data of DataDao and DataDoaFactory using owner address mapping(address =&gt; dataDaoFactoryStruct) public allDataDaos; // owner address will be used check which address own/create a new dataDAO // mapping(ownerAddress =&gt; smart contract address) mapping(address =&gt; address) public searchByAddress; /** * @dev constructor to get the owner address of this contract factory */ constructor(address _dataDaoFactoryOwner) { dataDaoFactoryOwner = _dataDaoFactoryOwner; } /** * @dev function to create the contract DATADAO */ function createDataDao(address _dataDaoOwner) public { DataDAO dataDao = new DataDAO( _dataDaoOwner ); // Increment the number of DataDao numOfDataDao++; // Add the new DataDAO to the mapping allDataDaos[_dataDaoOwner] = ( dataDaoFactoryStruct( _dataDaoOwner, // address of dataDAO owner address(this) ) ); // search the profile by using owner address searchByAddress[_dataDaoOwner].push(address(dataDao)); } // get the balance of the contract function getContractBalance() public view returns (uint256) { return address(this).balance; } // get the address of this contract function getAddressOfContract() public view returns (address) { return address(this); } // function to withdraw the fund from contract factory function withdraw(uint256 amount) external payable { require(msg.sender == dataDaoFactoryOwner, "ONLY_ONWER_CAN_CALL_FUNCTION"); // sending money to contract owner require(address(this).balance &gt;= amount, "not_enough_funds"); (bool success, ) = dataDaoFactoryOwner.call{value: amount}(""); require(success, "TRANSFER_FAILED"); } // get the address of DataDaoFactory contract owner function getAddressOfDataDaoFactoryOwner() public view returns (address) { return dataDaoFactoryOwner; } // receive function is used to receive Ether when msg.data is empty receive() external payable {} // Fallback function is used to receive Ether when msg.data is NOT empty fallback() external payable {} } </code></pre> </div> <p>Now compile the <strong>DataDaoFactory</strong> smart contract and deploy it on <a href="proxy.php?url=https://wallaby.network/" rel="noopener noreferrer">Wallaby- Testnet for Filecoin</a>.</p> <p><a href="proxy.php?url=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%2Fm9ixdtvufbtr4y8tkf20.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fm9ixdtvufbtr4y8tkf20.png" alt="Deploy DataDAO Factory"></a></p> <p>Now let's create a new Data DAO using our <strong>DataDaoFactory</strong> contract.</p> <p><a href="proxy.php?url=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%2Fuuvb8t5ddn62ep7hkh6a.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fuuvb8t5ddn62ep7hkh6a.png" alt="Create Data DAO"></a></p> <p>Let us create an add CID proposal, using the above test data.</p> <p><a href="proxy.php?url=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%2Fong2z7xch4hdvvvlaqi5.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fong2z7xch4hdvvvlaqi5.png" alt="Create CID Proposal"></a></p> <p>Once you have created the proposal, you would be able to see all the basic data related to that proposal</p> <p><a href="proxy.php?url=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%2Fsmv5zf687knl30s24hy5.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fsmv5zf687knl30s24hy5.png" alt="Proposal Details"></a></p> <p>Now, it's time for the DAO members to vote on that proposal before the voting period ends. If the total count of upvotes is greater than the total count of downvotes then the proposal would be passed else it would be considered <strong>rejected</strong>. This contract uses a simple DAO mechanism, you can frame and implement your own rules and make it more interesting and secure.</p> <p><em>Note: Only members apart from the storage provider would be able to cast a vote and each member can vote only once.</em></p> <p>Enough said. It’s time to vote! To keep it simple, I would be upvoting and passing this proposal. You can always play around with this.</p> <p>If you go back and check the details of the proposal the count of upvotes would have been incremented to 1 whereas the downvotes would be still zero.</p> <p><em>Note: This voting process should be completed within 1 hour from the creation of the proposal. You can make changes to the contract and increase or decrease the timer accordingly.</em></p> <p>Okay. All done with the voting part !!</p> <p>Now that we have passed the proposal, now it's time to publish our deal. In case the DAO failed the proposal, the storage provider won’t be able to publish his deal.</p> <p>We have a mock marketplace contract, let's deploy that first. This contract takes the contract address of our DAO contract i.e the client contract inside its constructor.</p> <p><a href="proxy.php?url=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%2F2l90oncpo2btw233m25x.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2F2l90oncpo2btw233m25x.png" alt="MockContract"></a></p> <p>Let us publish the deal, this function takes two inputs the message auth param which you can get from the test data, and the respective proposal ID.</p> <p><a href="proxy.php?url=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%2Fqh4echn1700efjqq4o2h.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fqh4echn1700efjqq4o2h.png" alt="Publish Deals"></a></p> <p>If the proposal was passed, this function would get executed successfully else, it would fail.</p> <p>That’s it! This was a quick guide as to how you can play around with the <a href="proxy.php?url=https://github.com/lotus-web3/client-contract/blob/main/src/DealClient.sol" rel="noopener noreferrer">basic client contract</a>.</p> <p>This project is made by an amazing team of <a href="proxy.php?url=https://twitter.com/0xharsh1001" rel="noopener noreferrer">Harsh Ghodkar</a>, <a href="proxy.php?url=https://twitter.com/SuvraneelB" rel="noopener noreferrer">Suvraneel Bhuin</a> and <a href="proxy.php?url=https://twitter.com/Aayush_gupta_ji" rel="noopener noreferrer">Aayush Gupta</a></p> <h3> Reference </h3> <p><a href="proxy.php?url=https://medium.com/@rvk_rishikesh/build-your-first-datadao-on-fvm-6ed38b940103" rel="noopener noreferrer">https://medium.com/@rvk_rishikesh/build-your-first-datadao-on-fvm-6ed38b940103</a></p> <h1> <strong>🎉BOOM 🎉</strong> </h1> <p>You have completed the whole tutorial. Give yourself a pat on the back. You have learned about:</p> <ul> <li><p>Filecoin Virtual Machine (FVM)</p></li> <li><p>Build your own <strong>DataDAO</strong> smart contract</p></li> <li><p>Build <strong>DataDaoFactory</strong> contract to build multiple versions of DataDAO.</p></li> <li><p>Publish a deal using <strong>MockMarket</strong> Contract</p></li> </ul> <p>💥 Simply WOW 💥</p> <p>If you learn and enjoy this article. Please share this article with your friends. I hope you learned something new or maybe even solved a problem. Thanks for reading, and have fun!</p> <p>You can follow me on <a href="proxy.php?url=https://twitter.com/Aayush_gupta_ji" rel="noopener noreferrer"><strong>Twitter</strong></a>, <a href="proxy.php?url=https://github.com/AAYUSH-GUPTA-coder" rel="noopener noreferrer"><strong>GitHub</strong></a><strong>,</strong> and <a href="proxy.php?url=https://www.linkedin.com/in/aayush-gupta-20023b183/" rel="noopener noreferrer"><strong>LinkedIn</strong></a>. Keep your suggestions/comments coming!</p> <p>WAGMI 🚀🚀</p> fvm tutorial filecoin datadao Create NFT Smart Contract with thirdweb and Chainlink Aayush Gupta Fri, 16 Dec 2022 06:36:21 +0000 https://dev.to/aayushguptacoder/create-nft-smart-contract-with-thirdweb-and-chainlink-49ng https://dev.to/aayushguptacoder/create-nft-smart-contract-with-thirdweb-and-chainlink-49ng <p>In this Tutorial, we will build a custom ERC-721 NFT Collection using <code>Thirdweb</code> and <code>Chainlink</code>. <code>Thirdweb ContractKit</code> is used for the ERC-721 token standard, <code>thirdweb deploy</code> is used to deploy our smart contract to mumbai testnetwork, and <code>Chainlink Data Feeds</code> is used to fetch the real-time price of Matic, to set the base price for minting NFT. Basically, we will build and deploy a smart contract that allows users to mint NFT. The user has to pay at least $1 in Matic to mint the NFT. We get the real price conversion using Chainlink Data Feeds.</p> <h2> Overview </h2> <p>ERC-721 is the common standard for creating NFTs. Every major marketplace lists new tokens as an ERC-1155 standard. We will use Thirdweb ContractKit to build our smart contract along with some custom logic. We allow users to mint as many NFTs as they wanted to mint with only one condition that they have to pay a minimum of $1 to mint the NFT. We get the real price conversion using Chainlink Data Feeds.</p> <h2> Why Use ContractKit? </h2> <p>Each feature you implement in your smart contracts unlocks functionality in both the thirdweb dashboard and SDK to help you build applications on top of them.</p> <p>For example, if you implement the ERC721Base contract, you'll unlock the mint button in the dashboard and can use the mint function in the SDK; which automatically uploads and pins your metadata to IPFS!</p> <h2> What is ERC-721? </h2> <p>ERC-721 is a free, open standard that describes how to build non-fungible or unique tokens on the Ethereum blockchain. While most tokens are fungible (every token is the same as every other token), ERC-721 tokens are all unique.</p> <p>The ERC-721 introduces a standard for NFT, in other words, this type of Token is unique and can have a different value than another Token from the same Smart Contract, maybe due to its age, rarity, or even something else like its visual. Wait, visual?</p> <p>Yes! All NFTs have a uint256 variable called <code>tokenId</code>, so for any ERC-721 Contract, the pair contract address, uint256 <code>tokenId</code> must be globally unique. That said, a dapp can have a "converter" that uses the <code>tokenId</code> as input and outputs an image of something cool, like zombies, weapons, skills, or amazing kitties!</p> <h2> What is Chainlink Data Feeds ? </h2> <p>Chainlink is a decentralized network of oracles that enables smart contracts to securely interact with real-world data and services that exist outside of blockchain networks. With Chainlink, the traditional systems that currently power modern economies can connect to the emerging blockchain industry to generate more security, efficiency, and transparency in business and social processes.</p> <p>Chainlink Data Feeds are the quickest way to connect your smart contracts to the real-world data such as asset prices, reserve balances, and L2 sequencer health.</p> <h2> Setting up the environment </h2> <p>First of all, we will setup our environment and install dependencies. To get started, run the command below to create a new project by opening the terminal of your preferred IDE.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code>npx thirdweb create <span class="nt">--contract</span> </code></pre> </div> <p>You will get something like this:</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--9Aj_gqNf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l8x9hw5398hn1st613zi.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--9Aj_gqNf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l8x9hw5398hn1st613zi.png" alt="1-setup.png" width="880" height="519"></a></p> <p>Now enter your preferred details.</p> <p>After completion, navigate and open the new directory by running the following command.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>cd dapp-name code . </code></pre> </div> <p>You will see this type of file structure.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--2OkUP_Bh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/31tu086nbe5t55q5l3ui.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--2OkUP_Bh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/31tu086nbe5t55q5l3ui.png" alt="1-initail-setup.png" width="880" height="458"></a></p> <h2> Let's BUIDL </h2> <p>Now open the contracts directory and select the <code>contract.sol</code> file. You will see the demo code. Now copy the below smart contract code and replace it with the demo code.</p> <h3> Contract.sol (thirdweb contractKit) </h3> <div class="highlight js-code-highlight"> <pre class="highlight solidity"><code><span class="c1">// SPDX-License-Identifier: MIT </span><span class="cm">/** * @author Aayush Gupta Github:AAYUSH-GUPTA-coder Twitter:Aayush_gupta_ji * * Smart conntract to allow users to mint as many NFTs as they wanted to mint with only one condition that they have to pay a minimum of $1 to mint the NFT. * Using `Thirdweb` contractKit and deploy tool. Get real time price conversion using `Chainlink Data Feeds` */</span> <span class="k">pragma</span> <span class="n">solidity</span> <span class="o">^</span><span class="mf">0.8</span><span class="p">.</span><span class="mi">0</span><span class="p">;</span> <span class="c1">// thirdweb contract for ERC-721 token standard </span><span class="k">import</span> <span class="s">"@thirdweb-dev/contracts/base/ERC721Base.sol"</span><span class="p">;</span> <span class="c1">// thirdweb contract for counters </span><span class="k">import</span> <span class="s">"@thirdweb-dev/contracts/openzeppelin-presets/utils/Counters.sol"</span><span class="p">;</span> <span class="c1">// chainlink data feed </span><span class="k">import</span> <span class="s">"./PriceConverter.sol"</span><span class="p">;</span> <span class="k">contract</span> <span class="n">Contract</span> <span class="k">is</span> <span class="n">ERC721Base</span> <span class="p">{</span> <span class="k">using</span> <span class="n">PriceConverter</span> <span class="k">for</span> <span class="kt">uint256</span><span class="p">;</span> <span class="k">using</span> <span class="n">Counters</span> <span class="k">for</span> <span class="n">Counters</span><span class="p">.</span><span class="n">Counter</span><span class="p">;</span> <span class="n">Counters</span><span class="p">.</span><span class="n">Counter</span> <span class="k">private</span> <span class="n">_tokenIdCounter</span><span class="p">;</span> <span class="c1">// Minimum price of NFT $1 in MATIC </span> <span class="kt">uint256</span> <span class="k">public</span> <span class="k">constant</span> <span class="n">MINIMUM_USD</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">*</span> <span class="mi">10</span> <span class="o">**</span> <span class="mi">18</span><span class="p">;</span> <span class="cm">/** * @dev ERC721Base library's constructor takes four Parameters * _name of the NFT, _symbol of the NFT, * _royaltyRecipient (address) who will get a royalty on secondary sale, _royaltyBps (royality percentage) * we don't need to set Royality for the purpose of our smart contract. setting _royaltyBps to Zero * @param _name: name of the whole NFT bundle Collection * @param _symbol: symbol of the whole NFT bundle Collection */</span> <span class="k">constructor</span><span class="p">(</span> <span class="kt">string</span> <span class="k">memory</span> <span class="n">_name</span><span class="p">,</span> <span class="kt">string</span> <span class="k">memory</span> <span class="n">_symbol</span><span class="p">,</span> <span class="kt">address</span> <span class="n">_royaltyRecipient</span><span class="p">,</span> <span class="kt">uint128</span> <span class="n">_royaltyBps</span> <span class="p">)</span> <span class="n">ERC721Base</span><span class="p">(</span> <span class="n">_name</span><span class="p">,</span> <span class="n">_symbol</span><span class="p">,</span> <span class="n">_royaltyRecipient</span><span class="p">,</span> <span class="n">_royaltyBps</span> <span class="p">)</span> <span class="p">{}</span> <span class="cm">/** * @dev createToken mint the ERC721 Token / NFT with the check that the user have paid $1 to mint the NFT */</span> <span class="k">function</span> <span class="n">createToken</span><span class="p">()</span> <span class="k">public</span> <span class="k">payable</span> <span class="p">{</span> <span class="c1">// require statement to check the user have paid $1 to mint the NFT </span> <span class="nb">require</span><span class="p">(</span><span class="n">msg</span><span class="p">.</span><span class="n">value</span><span class="p">.</span><span class="n">getConversionRate</span><span class="p">()</span> <span class="o">&gt;=</span> <span class="n">MINIMUM_USD</span><span class="p">,</span> <span class="s">"SEND_MORE_MATIC"</span><span class="p">);</span> <span class="c1">// Increment it so next time it's correct when we call .current() </span> <span class="n">_tokenIdCounter</span><span class="p">.</span><span class="n">increment</span><span class="p">();</span> <span class="c1">// Current counter value will be the minted token's token ID. </span> <span class="kt">uint256</span> <span class="n">newTokenId</span> <span class="o">=</span> <span class="n">_tokenIdCounter</span><span class="p">.</span><span class="n">current</span><span class="p">();</span> <span class="c1">// Mint the token </span> <span class="n">_mint</span><span class="p">(</span><span class="n">msg</span><span class="p">.</span><span class="n">sender</span><span class="p">,</span> <span class="n">newTokenId</span><span class="p">);</span> <span class="c1">// Default token Metadata on token minting </span> <span class="kt">string</span> <span class="k">memory</span> <span class="n">tokenURI</span> <span class="o">=</span> <span class="s">"https://ipfs.io/ipfs/QmVAUVEmr6pxqZq2KtLtjs52d2c91q5sKKhDZweQeqaH7Z"</span><span class="p">;</span> <span class="c1">// setting default token Metadata </span> <span class="n">_setTokenURI</span><span class="p">(</span><span class="n">newTokenId</span><span class="p">,</span> <span class="n">tokenURI</span><span class="p">);</span> <span class="p">}</span> <span class="cm">/** * @dev function to withdraw funds present in contract address to owner address. In this case, the address that deploy this smart contract */</span> <span class="k">function</span> <span class="n">withdraw</span><span class="p">()</span> <span class="k">public</span> <span class="n">onlyOwner</span><span class="p">(){</span> <span class="p">(</span><span class="kt">bool</span> <span class="n">callSuccess</span><span class="p">,</span> <span class="p">)</span> <span class="o">=</span> <span class="k">payable</span><span class="p">(</span><span class="n">msg</span><span class="p">.</span><span class="n">sender</span><span class="p">).</span><span class="nb">call</span><span class="p">{</span><span class="n">value</span><span class="o">:</span> <span class="kt">address</span><span class="p">(</span><span class="nb">this</span><span class="p">).</span><span class="nb">balance</span><span class="p">}(</span><span class="s">""</span><span class="p">);</span> <span class="nb">require</span><span class="p">(</span><span class="n">callSuccess</span><span class="p">,</span><span class="s">"TRANSFER_FUND_FAIL"</span><span class="p">);</span> <span class="p">}</span> <span class="cm">/** * @dev view / Getter function to get the balance of the smart contract */</span> <span class="k">function</span> <span class="n">getContractBalance</span><span class="p">()</span> <span class="k">public</span> <span class="k">view</span> <span class="k">returns</span><span class="p">(</span><span class="kt">uint</span><span class="p">){</span> <span class="k">return</span> <span class="kt">address</span><span class="p">(</span><span class="nb">this</span><span class="p">).</span><span class="nb">balance</span><span class="p">;</span> <span class="p">}</span> <span class="c1">// A contract receiving Ether must have at least one of the functions </span> <span class="c1">// receive() is called if msg.data have value </span> <span class="k">fallback</span><span class="p">()</span> <span class="k">external</span> <span class="k">payable</span> <span class="p">{}</span> <span class="c1">// receive() is called if msg.data is empty </span> <span class="k">receive</span><span class="p">()</span> <span class="k">external</span> <span class="k">payable</span> <span class="p">{}</span> <span class="p">}</span> </code></pre> </div> <p>I will explain the code below but before seeing the explanation. I request you to try to understand smart contracts on your own by reading the code and comments.</p> <h2> Let's move to the explanation </h2> <p>Line 1: Specifying SPDX license type, which is added after Solidity version ^0.6.8. Whenever the source code of a smart contract is made available to the public, these licenses can help resolve/avoid copyright issues. If you do not wish to specify any license type, you can use a special value UNLICENSED or skip the whole comment (it will not result in an error, just a warning).</p> <p>Line 8: Declaring the Solidity version.</p> <p>Line 11: Importing the thirdweb <code>ERC721Base</code> contract.</p> <p>Line 13: Importing the thirdweb <code>Counters</code> contract. We will use it to increment and keep track of <code>tokenID</code> of NFTs.</p> <p>Line 15: importing <code>./PriceConverter.sol</code>. We will use it to get the real-time price conversion of MATIC/USD.</p> <p>Line 17: Inheriting the <code>ERC721Base</code> contract in our <code>Contract</code> smart contract. In order to use all the functionalities of <code>ERC721Base</code> contract.</p> <p>Line 18: Using <code>PriceConverter</code> as <code>uint256</code> data type.</p> <p>Line 20: Using <code>Counters</code> as <code>Counters.Counter</code> datatype.</p> <p>Line 21: Setting up the minimum price of NFT in terms of USD. In our case it will be $1. Also due to the lack of testnet funds.</p> <p>Line 34: <code>constructor</code>: <code>ERC721Base</code> library's constructor takes four Parameters</p> <p><code>_name</code>: name of the NFT</p> <p><code>_symbol</code>: symbol of the NFT</p> <p><code>_royaltyRecipient</code>: (address) who will get a royalty on a secondary sale</p> <p><code>_royaltyBps</code>: royalty percentage on secondary sale. <code>100</code> is <code>1%</code> here.</p> <p>Line 51: <code>function createToken()</code>: Allow the user to mint the ERC721 Token / NFT with the check that the user has paid $1 to mint the NFT.</p> <p>Line 54: <code>require</code> to check that the user sends more than $1 in Matic value.</p> <p>Line 57: <code>_tokenIdCounter.increment()</code> to increment the TokenID. so next time it's correct when we call .current().</p> <p>Line 60: Current counter value will be the minted token's token ID.</p> <p>Line 63: <code>_mint</code> Mint the NFT</p> <p>Line 66: Giving a default NFT Metadata. In our case, we have hardcoded the IPFS link.</p> <p>Line 69: <code>_setTokenURI</code> function to set URI/Metadata of NFT.</p> <p>Line 75: <code>function withdraw</code>: function to withdraw funds present in contract address to owner address. In this case, owner is the address that deploy this smart contract.</p> <p>Line 83: View / Getter function to get the balance of the smart contract.</p> <p>Line 90: A contract receiving Ether must have at least one of the functions. <code>fallback</code> is called if msg.data have value.</p> <p>Line 93: <code>receive</code> is called if msg.data is empty.</p> <p>Woah... That's a long explanation. Now, before moving to deploy our smart contract using <code>thirdweb deploy</code> tool. We have to write <code>PriceConverter.sol</code> contract to get the realtime value of MATIC in USD. We will use <code>Chainlink Data Feeds</code> to get the realtime value. Using <code>chainlink</code> services is extremelly easy. You can refer to official chainlink docs to learn about data feeds in depth <a href="proxy.php?url=https://docs.chain.link/docs/data-feeds/">Chainlink Docs</a>.</p> <p>Create a new <code>.sol</code> file in the <code>contracts</code> directory name <code>PriceConverter.sol</code> and copy the below smart contract code.</p> <h3> PriceConverter.sol (Chainlink Data Feeds) </h3> <p><code>PriceConverter</code> is a smart contract to get real-time price of MATIC / USD using <code>Chainlink Data feeds</code>. We use <code>PriceConverter</code> as a library because we are not sending any Matic to the smart contract. We are only using it to get the value.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight solidity"><code><span class="c1">// SPDX-License-Identifier: MIT </span> <span class="cm">/** * @author Aayush Gupta Github:AAYUSH-GUPTA-coder Twitter:Aayush_gupta_ji * smart contract to get real time price of MATIC / USD using `Chainlink Data feeds` */</span> <span class="k">pragma</span> <span class="n">solidity</span> <span class="o">^</span><span class="mf">0.8</span><span class="p">.</span><span class="mi">8</span><span class="p">;</span> <span class="k">import</span> <span class="s">"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"</span><span class="p">;</span> <span class="cm">/** * Network: Mumbai * Aggregator: MATIC / USD * Address: 0xd0D5e3DB44DE05E9F294BB0a3bEEaF030DE24Ada */</span> <span class="k">library</span> <span class="n">PriceConverter</span> <span class="p">{</span> <span class="cm">/** * @dev function to get the Price of MATIC / USD. * The problem with this we get value with 8 float point while Matic/ETH have 18 float point. * Therefore we raise the power of our answer with 10 floating point. */</span> <span class="k">function</span> <span class="n">getPrice</span><span class="p">()</span> <span class="k">internal</span> <span class="k">view</span> <span class="k">returns</span> <span class="p">(</span><span class="kt">uint256</span><span class="p">)</span> <span class="p">{</span> <span class="n">AggregatorV3Interface</span> <span class="n">priceFeed</span> <span class="o">=</span> <span class="n">AggregatorV3Interface</span><span class="p">(</span> <span class="mh">0xd0D5e3DB44DE05E9F294BB0a3bEEaF030DE24Ada</span> <span class="p">);</span> <span class="p">(,</span> <span class="kt">int256</span> <span class="n">answer</span><span class="p">,</span> <span class="p">,</span> <span class="p">,</span> <span class="p">)</span> <span class="o">=</span> <span class="n">priceFeed</span><span class="p">.</span><span class="n">latestRoundData</span><span class="p">();</span> <span class="k">return</span> <span class="kt">uint256</span><span class="p">(</span><span class="n">answer</span> <span class="o">*</span> <span class="mi">1e10</span><span class="p">);</span> <span class="c1">// 1* 10 ** 10 == 10000000000 </span> <span class="p">}</span> <span class="cm">/** * @dev function to get eth(matic) in USD. * Will get the actual ETH/USD conversion rate, after adjusting the extra 0s. */</span> <span class="k">function</span> <span class="n">getConversionRate</span><span class="p">(</span><span class="kt">uint256</span> <span class="n">ethAmount</span><span class="p">)</span> <span class="k">internal</span> <span class="k">view</span> <span class="k">returns</span> <span class="p">(</span><span class="kt">uint256</span><span class="p">)</span> <span class="p">{</span> <span class="kt">uint256</span> <span class="n">ethPrice</span> <span class="o">=</span> <span class="n">getPrice</span><span class="p">();</span> <span class="kt">uint256</span> <span class="n">ethAmountInUsd</span> <span class="o">=</span> <span class="p">(</span><span class="n">ethPrice</span> <span class="o">*</span> <span class="n">ethAmount</span><span class="p">)</span> <span class="o">/</span> <span class="mi">1e18</span><span class="p">;</span> <span class="c1">// 1 * 10 ** 18 == 1000000000000000000 </span> <span class="c1">// the actual ETH/USD conversion rate, after adjusting the extra 0s. </span> <span class="k">return</span> <span class="n">ethAmountInUsd</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> </code></pre> </div> <p>Again I will explain the code below but before seeing the explanation. I request you to try to understand smart contracts on your own by reading the code and comments.</p> <h3> Let's move to the explanation </h3> <p>Line 1: Specifying SPDX license type.</p> <p>Line 8: Declaring the Solidity version.</p> <p>Line 10: Importing the chainlink <code>AggregatorV3Interface.sol</code> contract.</p> <p>Line 25: <code>function getPrice()</code> function to get the Price of MATIC / USD. The problem with this we get a value with 8 float points while Matic/ETH has 18 float points (i.e 1 ether == 1 ^ 18 wei). Therefore, we raise the power of our answer with 10 floating points.</p> <p>Line 37: <code>function getConversionRate</code> function to get eth(Matic) in USD. Will get the actual ETH/USD conversion rate, after adjusting the extra 0s.</p> <p><strong>BOOM</strong> You have created our smart contract with custom logic using thirdweb ContractKit and Chainlink Data Feeds.</p> <h2> Deploy our smart contract using thirdweb deploy </h2> <p>Use the CLI to ship our contract directly to any of thirdweb supported networks using their dashboard.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code>npx thirdweb deploy </code></pre> </div> <p>Running this command will:</p> <ul> <li><p>Compile all the contracts in the current directory.</p></li> <li><p>Allow you to select which contract(s) you want to deploy.</p></li> <li><p>Upload your contract source code (ABI) to IPFS.</p></li> <li><p>Open the deploy flow in the dashboard for you to select one of ThirdWeb supported networks to deploy to.</p></li> <li><p>You don't need to write your deploy script. Meaning you don't need your <code>Private Key</code> to deploy your smart contract, which saves you and eliminates any chance to expose your Private Key.</p></li> </ul> <p>After running the above command, you will get something like this:</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--FtrrXnwI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/za2f6s3p85go2ljkm01z.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--FtrrXnwI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/za2f6s3p85go2ljkm01z.png" alt="1-deploy" width="880" height="415"></a></p> <p>Now click on the link. You will open the Deploy dashboard. Enter the details (Name of the NFT, symbol of the NFT, address of Royalty Recipient, percentage of Royalty and network you want to deploy your smart contract) and click on the <code>Deploy Now</code> button.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--CBeo8gs6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2q4pk4uuybfsgkaktilg.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--CBeo8gs6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2q4pk4uuybfsgkaktilg.png" alt="2-deploy-dashboard.png" width="880" height="533"></a></p> <p>Congratulations! You have deployed your smart contract on desired testnetwork.</p> <h2> Mint the NFT </h2> <p>Go to Explorer section of your NFT collection Dashboard. You will be seeing all the functions you can perform. For now, let's just focus on our custom <code>createToken</code> function.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--kZZx_pyj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/71igoqgcgbhulgbjk79m.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--kZZx_pyj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/71igoqgcgbhulgbjk79m.png" alt="createToken-button.png" width="880" height="553"></a></p> <p>Now let's mint the NFT by sending Matic valuing more than $1. Just to keep things simple we will set the value to 2.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--SYTmL306--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qlerxz1lv88ionqj61ow.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--SYTmL306--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qlerxz1lv88ionqj61ow.png" alt="nft-created.png" width="880" height="541"></a></p> <p>Copy your contract address and paste the address on Testnet Opensea to view your NFT with metadata.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--4xX8xeCk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kvj707env4c4ti492l3f.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--4xX8xeCk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kvj707env4c4ti492l3f.png" alt="opensea-NFT.png" width="880" height="422"></a></p> <p>You have successfully minted the NFT and viewed it on opensea. You can share link of opensea and brag about NFTs like all web3 native people do 😎.</p> <h2> Check Custom Errors </h2> <p>Enter the <code>Native Token Value</code> to mint the NFT. Now to check whether our code is working, we will try to mint NFT without paying any matic.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--N2M49iyB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5cl1swnt364esii7buyk.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--N2M49iyB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5cl1swnt364esii7buyk.png" alt="send-more-matic.png" width="880" height="558"></a></p> <p>As you can see it reverts the transaction with the <code>SEND_MORE_MATIC</code> meaning our custom logic is working.</p> <h2> Getter Function </h2> <p>We have already seen how we can access and use the setter function in thirdWeb. Now we will interact with the getter function. You can access the getter function by scrolling down on the <code>explorer</code> page and clicking on your custom <code>MINIMUM_USD</code> public Variable.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--GWqPgzAp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/usyqkvey176b6ur19w1y.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--GWqPgzAp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/usyqkvey176b6ur19w1y.png" alt="minimun-usd.png" width="880" height="543"></a></p> <p>Now let's try to get the smart contract balance by checking the <code>getContractBalance</code> Function.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--ktPfFWaU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xybnfp0xcm7v3yg4s8kq.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--ktPfFWaU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xybnfp0xcm7v3yg4s8kq.png" alt="balance.png" width="880" height="550"></a></p> <p>You can see you are getting the right result.</p> <h2> 🎉BOOM 🎉 </h2> <p>You have completed the whole tutorial. Give yourself a pat on the back. You have learned about:</p> <p>ERC-721 token standard</p> <ul> <li><p>Build your own custom smart contract using <code>thirdweb contractkit</code></p></li> <li><p>Fetch the real-time price of Matic in USD by using <code>Chainlink Data Feeds</code></p></li> <li><p>Deploy your smart contract using <code>thirdweb deploy</code></p></li> <li><p>Mint your NFT and interact with your smart contract using the Explorer section of <code>thirdweb dashboard</code></p></li> </ul> <p>💥 Simply WOW 💥</p> <p>If you learn and enjoy this article. Please share this article with your friends. I hope you learned something new or maybe even solved a problem. Thanks for reading, and have fun!</p> <p>You can follow me on <a href="proxy.php?url=https://twitter.com/Aayush_gupta_ji">Twitter</a>, <a href="proxy.php?url=https://github.com/AAYUSH-GUPTA-coder">GitHub</a> and <a href="proxy.php?url=https://www.linkedin.com/in/aayush-gupta-20023b183/">LinkedIn</a>. Keep your suggestions/comments coming!</p> <p>WAGMI 🚀🚀</p> thirdweb chainlink tutorial nft How to verify Smart Contract with libraries and Constructor Parameters on Polygonscan using Hardhat. Aayush Gupta Wed, 07 Dec 2022 10:53:50 +0000 https://dev.to/aayushguptacoder/how-to-verify-smart-contract-with-libraries-and-constructor-parameters-on-polygonscan-using-hardhat-43e1 https://dev.to/aayushguptacoder/how-to-verify-smart-contract-with-libraries-and-constructor-parameters-on-polygonscan-using-hardhat-43e1 <p>When you deploy code to the public, open, global censorship-resistant Ethereum Blockchain, you expect participants will use the functions and services that your Smart Contract provides all over the world. Therefore, it is important to be a good steward of the blockchain community and help the users of your contract be able to trust that the code will do what you claim it will do.</p> <h2> Why Verify? </h2> <ul> <li>Verifying contracts is important because it ensures that the code is exactly what was deployed onto the blockchain</li> <li>It also allows the public to read and audit your smart contract code</li> <li>Contracts that are verified are considered to be more trustworthy than the ones which are not</li> <li>It also gives you an UI interface to interact with the contracts</li> </ul> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--0mDc9zak--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wwgmfr2nfkmja926t1a0.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--0mDc9zak--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wwgmfr2nfkmja926t1a0.png" alt="UI interface to interact with the contract.png" width="880" height="450"></a></p> <h2> Build </h2> <p>In this tutorial, we will Verify Smart contract that is already deployed on Polygon Mumbai Test network.</p> <p>We will also Verify the contract if it has constructor parameters.</p> <p>Let's now learn how we can leverage HARDHAT for verifying smart contracts with only some lines of code.</p> <p>Let's goo 🚀🚀🚀</p> <ul> <li>We need to install <code>hardhat-etherscan</code> npm package</li> </ul> <p><code>npm install --save-dev @nomiclabs/hardhat-etherscan</code></p> <ul> <li><p><code>hardhat-etherscan</code> npm package is the package from hardhat which will help us with etherscan verification.</p></li> <li><p>We will install <code>dotenv</code> package to import the <code>.env</code> file and use it in our config. Open up a terminal and execute this command.</p></li> </ul> <p><code>npm install dotenv</code></p> <ul> <li>Now create a .env file in the folder and add the following lines, use the instructions in the comments to get your <code>ALCHEMY_API_KEY_URL</code>, <code>MUMBAI_PRIVATE_KEY</code> and <code>POLYGONSCAN_KEY</code> .If you don't have Mumbai on MetaMask, you can follow this to add it to your MetaMask, make sure that the account from which you get your mumbai private key is funded with mumbai test matic, you can get some from here. </li> </ul> <div class="highlight js-code-highlight"> <pre class="highlight javascript"><code> <span class="c1">// Go to https://www.alchemyapi.io, sign up, create</span> <span class="c1">// a new App in its dashboard and select the network as Mumbai, </span> <span class="nx">and</span> <span class="nx">replace</span> <span class="dl">"</span><span class="s2">add-the-alchemy-key-url-here</span><span class="dl">"</span> <span class="kd">with</span> <span class="nx">its</span> <span class="nx">key</span> <span class="nx">url</span> <span class="nx">ALCHEMY_API_KEY_URL</span><span class="o">=</span><span class="dl">"</span><span class="s2">add-the-alchemy-key-url-here</span><span class="dl">"</span> <span class="c1">// Replace this private key with your Mumbai account private key</span> <span class="c1">// To export your private key from Metamask, open Metamask and</span> <span class="c1">// go to Account Details &gt; Export Private Key</span> <span class="c1">// Be aware of NEVER putting real Ether into testing accounts</span> <span class="nx">MUMBAI_PRIVATE_KEY</span><span class="o">=</span><span class="dl">"</span><span class="s2">add-the-mumbai-private-key-here</span><span class="dl">"</span> <span class="c1">// Go to https://polygonscan.com/, sign up, on your account </span> <span class="c1">// overview page,</span> <span class="c1">// click on `API Keys`, add a new API key and copy the</span> <span class="c1">// `API Key Token`</span> <span class="nx">POLYGONSCAN_KEY</span><span class="o">=</span><span class="dl">"</span><span class="s2">add-the-polygonscan-api-token-here</span><span class="dl">"</span> </code></pre> </div> <ul> <li><p>If you deployed your dapp using Hardhat, you will already have <code>MUMBAI_PRIVATE_KEY</code> and <code>ALCHEMY_API_KEY_URL</code> Then you just need to add POLYGONSCAN_KEY in <code>.env</code>.</p></li> <li><p>Create a new file named <code>verify.js</code> under the <code>scripts</code> folder. Notice how we are using code to verify the contract.<br> </p></li> </ul> <div class="highlight js-code-highlight"> <pre class="highlight javascript"><code><span class="kd">const</span> <span class="p">{</span> <span class="nx">ethers</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">"</span><span class="s2">hardhat</span><span class="dl">"</span><span class="p">);</span> <span class="nx">require</span><span class="p">(</span><span class="dl">"</span><span class="s2">dotenv</span><span class="dl">"</span><span class="p">).</span><span class="nx">config</span><span class="p">({</span> <span class="na">path</span><span class="p">:</span> <span class="dl">"</span><span class="s2">.env</span><span class="dl">"</span> <span class="p">});</span> <span class="nx">require</span><span class="p">(</span><span class="dl">"</span><span class="s2">@nomiclabs/hardhat-etherscan</span><span class="dl">"</span><span class="p">);</span> <span class="k">async</span> <span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span> <span class="c1">// Verify the contract after deploying</span> <span class="k">await</span> <span class="nx">hre</span><span class="p">.</span><span class="nx">run</span><span class="p">(</span><span class="dl">"</span><span class="s2">verify:verify</span><span class="dl">"</span><span class="p">,</span> <span class="p">{</span> <span class="na">address</span><span class="p">:</span> <span class="dl">"</span><span class="s2">address-of-your-smart-contract</span><span class="dl">"</span><span class="p">,</span> <span class="na">constructorArguments</span><span class="p">:</span> <span class="p">[],</span> <span class="p">});</span> <span class="p">}</span> <span class="c1">// Call the main function and catch if there is any error</span> <span class="nx">main</span><span class="p">()</span> <span class="p">.</span><span class="nx">then</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="nx">process</span><span class="p">.</span><span class="nx">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span> <span class="p">.</span><span class="k">catch</span><span class="p">((</span><span class="nx">error</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">error</span><span class="p">);</span> <span class="nx">process</span><span class="p">.</span><span class="nx">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="p">});</span> </code></pre> </div> <ul> <li>Now if the constructor of the contract has Parameters, then you need to put the value of that parameter in constructorArguments . </li> </ul> <div class="highlight js-code-highlight"> <pre class="highlight javascript"><code><span class="kd">const</span> <span class="p">{</span> <span class="nx">ethers</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">"</span><span class="s2">hardhat</span><span class="dl">"</span><span class="p">);</span> <span class="nx">require</span><span class="p">(</span><span class="dl">"</span><span class="s2">dotenv</span><span class="dl">"</span><span class="p">).</span><span class="nx">config</span><span class="p">({</span> <span class="na">path</span><span class="p">:</span> <span class="dl">"</span><span class="s2">.env</span><span class="dl">"</span> <span class="p">});</span> <span class="nx">require</span><span class="p">(</span><span class="dl">"</span><span class="s2">@nomiclabs/hardhat-etherscan</span><span class="dl">"</span><span class="p">);</span> <span class="k">async</span> <span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span> <span class="c1">// Verify the contract after deploying</span> <span class="k">await</span> <span class="nx">hre</span><span class="p">.</span><span class="nx">run</span><span class="p">(</span><span class="dl">"</span><span class="s2">verify:verify</span><span class="dl">"</span><span class="p">,</span> <span class="p">{</span> <span class="na">address</span><span class="p">:</span> <span class="dl">"</span><span class="s2">address-of-your-smart-contract</span><span class="dl">"</span><span class="p">,</span> <span class="na">constructorArguments</span><span class="p">:</span> <span class="p">[</span><span class="dl">"</span><span class="s2">parameter1</span><span class="dl">"</span><span class="p">,</span><span class="dl">"</span><span class="s2">parameter2</span><span class="dl">"</span><span class="p">],</span> <span class="c1">// for example, if your constructor argument took an address, do something like constructorArguments: ["0xABCDEF..."],</span> <span class="p">});</span> <span class="p">}</span> <span class="c1">// Call the main function and catch if there is any error</span> <span class="nx">main</span><span class="p">()</span> <span class="p">.</span><span class="nx">then</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="nx">process</span><span class="p">.</span><span class="nx">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span> <span class="p">.</span><span class="k">catch</span><span class="p">((</span><span class="nx">error</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">error</span><span class="p">);</span> <span class="nx">process</span><span class="p">.</span><span class="nx">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="p">});</span> </code></pre> </div> <ul> <li>To verify, open up a terminal and execute this command.</li> </ul> <p><code>npx hardhat run scripts/verify.js --network mumbai</code></p> <ul> <li>It should have printed a link to Mumbai polygonscan, your contract is now verified. Click on polygonscan link and interact with your contract there 🚀🚀🚀</li> </ul> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--V3S2OSOV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1g59l03fgzpyks7drgfw.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--V3S2OSOV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1g59l03fgzpyks7drgfw.png" alt="Polygonscan Contract page after verification.png" width="880" height="452"></a></p> <h2> Reference </h2> <p>This tutorial is highly inspired by the <a href="proxy.php?url=https://learnweb3.io/">LearnWeb3DAO</a> tutorial on <a href="proxy.php?url=https://learnweb3.io/courses/6394ea7c-0ad6-4a4a-879f-7f9756bc5976/lessons/2012a201-58e1-4d36-9a9b-aafd76caedf4">Hardhat Etherscan Verification</a>.</p> <p>You can follow me on <a href="proxy.php?url=https://twitter.com/Aayush_gupta_ji">Twitter</a>, <a href="proxy.php?url=https://github.com/AAYUSH-GUPTA-coder">GitHub</a>, and <a href="proxy.php?url=https://www.linkedin.com/in/aayush-gupta-20023b183/">Linkedin</a>. Keep your suggestions and comments coming!</p> verify hardhat blockchain tutorial How to Build custom ERC-1155 NFT Collection using thirdweb Aayush Gupta Mon, 07 Nov 2022 05:51:32 +0000 https://dev.to/aayushguptacoder/how-to-build-custom-erc-1155-nft-collection-using-thirdweb-2eh6 https://dev.to/aayushguptacoder/how-to-build-custom-erc-1155-nft-collection-using-thirdweb-2eh6 <p>In this Tutorial, we will build a custom ERC-1155 NFT Bundle Collection using Thirdweb ContractKit and Deploy tool. Instead of Minting all the NFTs in one go. We allow users to mint NFT from any NFT bundle Collection one by one. We also set a maximum supply of NFTs; one user can mint only one NFT.</p> <h2> Overview </h2> <p>ERC-1155 has emerged as a gold standard for creating NFTs; every major marketplace lists new tokens as an ERC-1155 standard. We will use Thirdweb ContractKit to build our smart contract along with some custom logic. We allow users to mint only one NFT per NFT Bundle collection. </p> <h2> Why Use ContractKit? </h2> <p>Each feature you implement in your smart contracts unlocks functionality in both the thirdweb dashboard and SDK to help you build applications on top of them.</p> <p>For example, if you implement the ERC721Base contract, you'll unlock the mint button in the dashboard and can use the mint function in the SDK; which automatically uploads and pins your metadata to IPFS!</p> <h2> What is ERC-1155? </h2> <p>ERC1155 is a multi-token standard that allows the creation of fungible, non-fungible, and semi-fungible tokens all in one contract. Before ERC-1155, if a use case needed both ERC-20 (fungible) and ERC-721 (non-fungible) tokens, you would need to create separate contracts to achieve this. ERC1155 also allows for multiple NFT collections to be launched in just one smart contract instead of creating a different contract for each collection; this increases efficiency in smart contract construction and minimizes the transaction count, which is very important as it consumes less blockchain space. With ERC-1155, batch transfer of tokens is possible instead of transferring a token to a single address in previous standards.</p> <p>A prevalent example of the ERC-1155 application is blockchain-based decentralized games, which need coins and collectibles, so ERC-1155 has become a standard there. ERC1155 has also become a standard in the NFT space.</p> <p>The previous ERC-721 had a one-to-one mapping of the token id with the address. ERC-1155 has a rather complex mapping where the address in a combination of token ID is mapped to the balance of the token.</p> <h2> Setting up the environment. </h2> <p>First of all, we will setup our environment and install dependencies. To get started, run the command below to create a new project by opening the terminal of your preferred IDE.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>npx thirdweb create --contract </code></pre> </div> <p>You will get something like this:</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--Qfuxw3NR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k70vv2340ug0ejcyptuh.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--Qfuxw3NR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k70vv2340ug0ejcyptuh.png" alt="1.png" width="880" height="519"></a></p> <p>Now enter your preferred details. For this tutorial, I have selected the below setting</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--lTx3B4VE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h4l4i1fnfpvb9gnw3mcq.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--lTx3B4VE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h4l4i1fnfpvb9gnw3mcq.png" alt="enter details.png" width="880" height="482"></a></p> <p>After completion, navigate and open the new directory by running the following command.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>cd dapp-name code . </code></pre> </div> <p>You will see this type of file structure.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--5EZk4gJB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8kh2ufy08lid1ar71tpb.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--5EZk4gJB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8kh2ufy08lid1ar71tpb.png" alt="after dowload.png" width="880" height="399"></a></p> <p>Now open the <code>contracts</code> directory and select the <code>contract.sol</code> file. You will see the demo code. Now copy the below smart contract code and replace it with the demo code.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight solidity"><code><span class="c1">// SPDX-License-Identifier: MIT </span> <span class="cm">/** @author Aayush gupta * `TravelQuest` is a POV (Proof-of-visit) dapp that allow user to mint 1 NFT per collection * using `ERC1155LazyMint` library of `ThirdWeb`. */</span> <span class="k">pragma</span> <span class="n">solidity</span> <span class="o">^</span><span class="mf">0.8</span><span class="p">.</span><span class="mi">0</span><span class="p">;</span> <span class="cm">/** * Importing `ERC1155LazyMint` library of `ThirdWeb`. */</span> <span class="k">import</span> <span class="s">"@thirdweb-dev/contracts/base/ERC1155LazyMint.sol"</span><span class="p">;</span> <span class="cm">/** * @title TravelQuest * @dev inherite and using `ERC1155LazyMint` in the our smart contract * */</span> <span class="k">contract</span> <span class="n">TravelQuest</span> <span class="k">is</span> <span class="n">ERC1155LazyMint</span><span class="p">{</span> <span class="c1">// Total number of NFTs per Bundle Collection </span> <span class="kt">uint256</span><span class="p">[]</span> <span class="k">private</span> <span class="n">supplies</span> <span class="o">=</span> <span class="p">[</span><span class="mi">50</span><span class="p">,</span><span class="mi">50</span><span class="p">];</span> <span class="c1">// Total number of NFTs minted </span> <span class="kt">uint256</span><span class="p">[]</span> <span class="k">private</span> <span class="n">minted</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">];</span> <span class="c1">// nested mapping to check user can mint only one NFT per NFT Collection </span> <span class="k">mapping</span><span class="p">(</span><span class="kt">uint256</span> <span class="o">=&gt;</span> <span class="k">mapping</span><span class="p">(</span><span class="kt">address</span> <span class="o">=&gt;</span> <span class="kt">bool</span><span class="p">))</span> <span class="k">public</span> <span class="n">member</span><span class="p">;</span> <span class="cm">/** * @dev ERC1155LazyMint library's constructor takes four Parameters * _name of the NFT, _symbol of the NFT, * _royaltyRecipient (address) who will get a royalty on secondary sale, _royaltyBps (royality percentage) * we don't need to set Royality for the purpose of our smart contract. setting _royaltyBps to Zero * @param _name: name of the whole NFT bundle Collection * @param _symbol: symbol of the whole NFT bundle Collection */</span> <span class="k">constructor</span><span class="p">(</span> <span class="kt">string</span> <span class="k">memory</span> <span class="n">_name</span><span class="p">,</span> <span class="kt">string</span> <span class="k">memory</span> <span class="n">_symbol</span> <span class="p">)</span> <span class="n">ERC1155LazyMint</span> <span class="p">(</span><span class="n">_name</span><span class="p">,</span> <span class="n">_symbol</span><span class="p">,</span> <span class="n">msg</span><span class="p">.</span><span class="n">sender</span><span class="p">,</span> <span class="mi">0</span><span class="p">){}</span> <span class="cm">/** * @dev Mint NFT and also check various conditions * 1. One user can mint only one NFT per Bundle Collection * 2. Give error if _tokenId is wrong * 3. Check and give error if all the NFTs are Minted * * @param _tokenId: tokenId of the NFT Bundle collection */</span> <span class="k">function</span> <span class="n">mintNFT</span><span class="p">(</span><span class="kt">uint256</span> <span class="n">_tokenId</span><span class="p">)</span> <span class="k">external</span> <span class="p">{</span> <span class="nb">require</span><span class="p">(</span> <span class="o">!</span><span class="n">member</span><span class="p">[</span><span class="n">_tokenId</span><span class="p">][</span><span class="n">msg</span><span class="p">.</span><span class="n">sender</span><span class="p">],</span> <span class="s">"You have already claimed this NFT."</span> <span class="p">);</span> <span class="nb">require</span><span class="p">(</span><span class="n">_tokenId</span> <span class="o">&lt;=</span> <span class="n">supplies</span><span class="p">.</span><span class="n">length</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="s">"NFT does not exist"</span><span class="p">);</span> <span class="kt">uint256</span> <span class="n">index</span> <span class="o">=</span> <span class="n">_tokenId</span><span class="p">;</span> <span class="nb">require</span> <span class="p">(</span><span class="n">minted</span><span class="p">[</span><span class="n">index</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">&lt;=</span> <span class="n">supplies</span><span class="p">[</span><span class="n">index</span><span class="p">],</span> <span class="s">"All the NFT have been minted"</span><span class="p">);</span> <span class="n">_mint</span><span class="p">(</span><span class="n">msg</span><span class="p">.</span><span class="n">sender</span><span class="p">,</span> <span class="n">_tokenId</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="s">""</span><span class="p">);</span> <span class="c1">// "" is data which is set empty </span> <span class="n">minted</span><span class="p">[</span><span class="n">index</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">member</span><span class="p">[</span><span class="n">_tokenId</span><span class="p">][</span><span class="n">msg</span><span class="p">.</span><span class="n">sender</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span> <span class="p">}</span> <span class="cm">/** * @dev Give the total number of NFTs minted per NFT Bundle Collection * @param _tokenId: tokenId of the NFT Bundle collection */</span> <span class="k">function</span> <span class="n">totalNftMinted</span><span class="p">(</span><span class="kt">uint256</span> <span class="n">_tokenId</span><span class="p">)</span> <span class="k">public</span> <span class="k">view</span> <span class="k">returns</span><span class="p">(</span><span class="kt">uint256</span><span class="p">){</span> <span class="k">return</span> <span class="n">minted</span><span class="p">[</span><span class="n">_tokenId</span><span class="p">];</span> <span class="p">}</span> <span class="p">}</span> </code></pre> </div> <p>I will explain the code below but before seeing the explanation. I request you to try to understand smart contracts on your own by reading the code and comments.</p> <h3> Let's move to the explanation </h3> <p>Line 1: Specifying SPDX license type, which is added after Solidity version ^0.6.8. Whenever the source code of a smart contract is made available to the public, these licenses can help resolve/avoid copyright issues. If you do not wish to specify any license type, you can use a special value UNLICENSED or skip the whole comment (it will not result in an error, just a warning).</p> <p>Line 7: Declaring the Solidity version.</p> <p>Line 13: Importing the <code>thirdweb ERC1155LazyMint</code> contract.</p> <p>Line 20: Inheriting the <code>ERC1155LazyMint</code> contract in our <code>TravelQuest</code> smart contract. In order to use all the functionalities of ERC1155LazyMint contract.</p> <p>Line 22: <code>supplies</code> is an array that keeps track of the Maximum number of NFT available to mint.</p> <p>Line 24: <code>minted</code> is an array that keeps track of how many NFTs are already minted.</p> <p>Line 27: <code>member</code> is a nested mapping to check user can mint only one NFT per NFT Collection</p> <p>Line 37: <code>constructor</code>: ERC1155LazyMint library's constructor takes four Parameters</p> <p><code>_name</code>: name of the NFT</p> <p><code>_symbol</code>: symbol of the NFT </p> <p><code>_royaltyRecipient</code> (address) who will get a royalty on a secondary sale</p> <p><code>_royaltyBps</code> (royalty percentage). </p> <p>we don't need to set royalties for the purpose of our smart contract. setting <code>_royaltyBps</code> to Zero.</p> <p>Line 38: <code>string memory _name</code>: name of the whole NFT bundle collection</p> <p>Line 39: <code>string memory _symbol</code>: symbol of the whole NFT bundle collection</p> <p>Line 51: <code>function mintNFT</code> : to allow users to mint NFT from our NFT Bundle Collection. One user can only mint 1 NFT of each NFT collection. Also, check various condition</p> <ul> <li> One user can mint only one NFT per Bundle Collection</li> <li> Give error if <code>_tokenId</code> is wrong</li> <li> Check and give an error if all the NFTs are Minted <code>_tokenId</code>: tokenId of the NFT Bundle collection </li> </ul> <p>Line 72: <code>function totalNftMinted</code>: is a getter function. Give the total number of NFTs minted per NFT Bundle Collection. <code>_tokenId</code> is the tokenId of the NFT Bundle collection</p> <p><strong>BOOM</strong> You have created our smart contract with custom logic and thirdweb ContractKit. </p> <h2> Deploy our smart contract using thirdweb deploy </h2> <p>Use the CLI to ship our contract directly to any of thirdweb supported networks using their dashboard.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>npx thirdweb deploy </code></pre> </div> <p>Running this command will:</p> <ul> <li>Compile all the contracts in the current directory.</li> <li>Allow you to select which contract(s) you want to deploy.</li> <li>Upload your contract source code (ABI) to IPFS.</li> <li>Open the deploy flow in the dashboard for you to select one of ThirdWeb supported networks to deploy to.</li> <li>You don't need to write your deploy script. Meaning you don't need your <code>Private Key</code> to deploy your smart contract, which saves you and eliminates any chance to expose your Private Key.</li> </ul> <p>After running the above command, you will get something like this:</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--NlURRILJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6op9r4net4op1cloyvll.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--NlURRILJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6op9r4net4op1cloyvll.png" alt="link of deploy.png" width="880" height="517"></a></p> <p>Now click on the link. You will open the Deploy dashboard. Enter the details (Name of the NFT, symbol of the NFT, and network you want to deploy your smart contract) and Click on the <code>Deploy Now</code> button.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--vtUdrF6X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cb7ncbqp24um7ilj5car.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--vtUdrF6X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cb7ncbqp24um7ilj5car.png" alt="deploy dashboard.png" width="880" height="603"></a></p> <p>After the deployment of your smart contract. You will be navigated to your NFT Collection Dashboard. </p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--FwFUyPfV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i6vm46ipaddhrs7v0e8o.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--FwFUyPfV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i6vm46ipaddhrs7v0e8o.png" alt="dashboard.png" width="880" height="422"></a></p> <p>Click on the <code>Single Upload</code> to upload the metadata of our NFT. You can also use <code>Batch Upload</code>, but for this tutorial. Let's stick to the Single Upload.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--_bGjoJIk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/voycfdl30gmrsmamlaym.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--_bGjoJIk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/voycfdl30gmrsmamlaym.png" alt="add details.png" width="880" height="802"></a></p> <p>Add the details as shown above and click on <code>Lazy Mint NFT</code> button. </p> <p>Similarly, let's add metadata for another NFT. </p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--9Bx5jXWy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ieqvl6g4ykj6g17mpmbc.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--9Bx5jXWy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ieqvl6g4ykj6g17mpmbc.png" alt="gate add details.png" width="797" height="931"></a><br> After the addition of Metadata, your NFTs section on the dashboard will look like this.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--yLBDt6_N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hnletxrozfawggzey85y.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--yLBDt6_N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hnletxrozfawggzey85y.png" alt="nft-dashboard.png" width="880" height="533"></a></p> <p>Now that we have our NFT collection along with Metadata on order. Let's mint some NFTs.</p> <h2> Mint the NFT </h2> <p>Go to <code>Explorer</code> section of your NFT collection Dashboard. You will be seeing all the functions you can perform. For now, let's just focus on our custom <code>mintNFT</code> function.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--6Zh0F4CY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mpokf4ta7385pkle0d60.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--6Zh0F4CY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mpokf4ta7385pkle0d60.png" alt="explorer.png" width="880" height="589"></a></p> <p>Enter the <code>_tokenId</code> (either 0 or 1) and click on <code>Mint</code> button. You will mint the NFT and the dashboard will show all the transaction details.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s---rkSWHlo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g0t45fdg32q887solzcp.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s---rkSWHlo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g0t45fdg32q887solzcp.png" alt="succesful-minting.png" width="880" height="610"></a></p> <p>Copy your contract address and paste the address on Testnet Opensea to view your NFT with metadata. </p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--ph0P90L4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d765sidmie7lo5pxnvd1.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--ph0P90L4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d765sidmie7lo5pxnvd1.png" alt="opensea .png" width="880" height="416"></a></p> <p>You have successfully minted the NFT and viewed it on opensea. You can share link of opensea and brag about NFTs like all web3 native people do 😎.</p> <h2> Check Custom Errors </h2> <p>You can have successfully minted the NFT. Now let's check the custom errors we added in our smart contract.</p> <h3> Wrong TokenID </h3> <p>Enter any wrong <code>_tokenId</code> in <code>mintNFT</code> function.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--ZoW8Hdym--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jkwxnhp7wzijam2a26dt.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--ZoW8Hdym--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jkwxnhp7wzijam2a26dt.png" alt="exceed-tokenId.png" width="880" height="611"></a></p> <p>You will see this well-defined custom error with all details.</p> <h3> Already Claimed </h3> <p>Try to mint the same NFT with the same wallet address.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--IExZJIWf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cegvzvm0i6ba10lbp5ig.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--IExZJIWf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cegvzvm0i6ba10lbp5ig.png" alt="already-minted.png" width="880" height="624"></a></p> <p>Again, you will see this well-defined custom error with all details.</p> <h2> Getter Function </h2> <p>We have already seen how we can access and use the setter function in ThirdWeb. Now we will interact with the getter function. You can access the getter function by scrolling down on the <code>explorer</code> page and clicking on your custom <code>totalSupply</code> function.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--tVj_A3BZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zgumw51jparba7czs6rh.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--tVj_A3BZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zgumw51jparba7czs6rh.png" alt="totalSupply.png" width="880" height="612"></a></p> <p>You see you are getting the right result.</p> <h2> <strong>🎉BOOM 🎉</strong> </h2> <p>You have completed the whole tutorial. Give yourself a pat on the back.<br> You have learned about:</p> <ul> <li>ERC-1155 token standard</li> <li>Build your own custom smart contract using <code>thirdweb contractkit</code> </li> <li>Deploy your smart contract using <code>thirdweb deploy</code> </li> <li>Store your NFTs metadata in IPFS using <code>thirdweb dashboard</code> </li> <li>Mint your NFT and interact with your smart contract using the <code>Explorer</code> section of <code>thirdweb dashboard</code> </li> </ul> <p>Simply WOW </p> <p>If you learn and enjoy this article. Please share this article with your friends. I hope you learned something new or maybe even solved a problem. Thanks for reading, and have fun!</p> <p>You can follow me on <a href="proxy.php?url=https://twitter.com/Aayush_gupta_ji">Twitter</a> and <a href="proxy.php?url=https://www.linkedin.com/in/aayush-gupta-20023b183/">LinkedIn</a>. Keep your suggestions/comments coming!</p> <p>WAGMI 🚀🚀</p> thirdweb solidity erc115 tutorial What is RPC Node? Why we should use Decentralized Node Providers? Aayush Gupta Mon, 07 Nov 2022 05:50:43 +0000 https://dev.to/aayushguptacoder/what-is-rpc-node-why-we-should-use-decentralized-node-providers-2ojp https://dev.to/aayushguptacoder/what-is-rpc-node-why-we-should-use-decentralized-node-providers-2ojp <p>If you're new to blockchain development, the one question always arises: what is an RPC node?, sometimes refer as Blockchain Node, Blockchain API Key, or Blockchain Endpoint . You may know that RPCs are essential tools that blockchain developers used to build decentralized apps. But what exactly are they? And why are they so important in blockchain technology? We will learn about that in the following article. It will be a long article but I ensure you that if you stay with this article you will learn all you need to know about RPC nodes and node providers.</p> <h2> What is an RPC node in blockchain? </h2> <p>Let's start from the basics! An RPC node is essentially a program running on a single computer that allows you to connect with the rest of the blockchain network. It connects with other nodes to send information back and forth, checks that transactions sent between people are valid, and stores important information about the state of the blockchain.</p> <p>RPC (Remote Procedure Call) could be classified as a type of API (application programming interface) that allows developers to run code that can be executed on servers remotely. And when developers build dApps with RPC capabilities, the dapp will connect users’ requests to information from blockchains. For instance, when users access an NFT Collection, play P2E Game or use MetaMask to make transactions, their requests go through an RPC to connect them with the nodes that hold the data from blockchains.</p> <p>Finally, it's important to note that <em>there's no way to access the information on a blockchain without using a node</em>. Can't be done. Think of it like the browser for the blockchain.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--Chx0J0jM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ghsvxfexcuvqpet9nan.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--Chx0J0jM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ghsvxfexcuvqpet9nan.png" alt="Node" width="880" height="753"></a></p> <h2> Use Cases For RPCs </h2> <h3> 1. Creating decentralized applications </h3> <p>One of the major use cases for RPC is building dApps that have the capability to interact with one or more blockchains. Decentralized applications are based on smart contracts that enable features like minting NFTs, automatic execution of a crypto trade, and Raffle Game. They also have a user interface that makes it usable for everyone.</p> <h3> 2. Querying blockchain data without access to your own node </h3> <p>When building, developers also need access to a variety of information like block numbers, node connections, transactions, and historical blockchain data. They can make “requests” to their desired blockchain in JSON (JavaScript Object Notation) and receive replies with the info they need.</p> <h3> 3. Simplifying the building process </h3> <p>The RPC layer is also useful when building applications because it simplifies the job of developers. For instance, if you wanted users to view their external wallet’s crypto balance within your new DeFi dApp, you wouldn’t need to build a wallet from scratch — you would just need to build an API that can ask to communicate with the wallet to find what the user holds. At the same time, the software that forms the crypto wallet can contain API-enabling code that allows interoperability with many other DeFi protocols.</p> <h3> 4. Creating WebSockets to view real-time transactions data </h3> <p>WebSockets are APIs that allow for a constant exchange of information between a client and a server. Since it keeps the communication open and flowing, there is no need to establish a connection every time a message is sent. These are extremely useful for high-throughput applications, such as Internet of Things (IoT) capabilities that need to send and receive large amounts of data.</p> <h3> 5. Run calls to access a massive amount of information. </h3> <p>Developers can run calls to execute tasks like encrypting wallets, producing a human-readable JSON object, finding current block size, creating multi-signature addresses, and much more. These are critical pieces of information that builders need to create their own blockchain platforms and services. With access to a free, readily available, and reliable RPC, developers will be able to build faster and make more efficient applications.</p> <p><strong>Now</strong> that you understand what RPC Node is and why we need it in Blockchain development. Let’s discuss how we can actually use RPC Node. We (Web3 developers) have two choices for accessing the node infrastructure necessary for building and operating dApps.</p> <ol> <li> <strong>Running our own Node</strong>: Set up a node ourselves and take on the DevOps of equipment maintenance and solving server problems, which is a very difficult task.</li> <li> <strong>RPC Node Providers:</strong> Use services from RPC Node Providers like <strong><a href="proxy.php?url=https://www.ankr.com/">Ankr</a></strong>, <strong><a href="proxy.php?url=https://www.alchemy.com/">Alchemy</a></strong>, <strong><a href="proxy.php?url=https://infura.io/">Infura</a></strong> via an RPC layer.</li> </ol> <h2> Why is running a node difficult? </h2> <p>There are a few things that make developing on your own node connected to the network particularly annoying. Let's cover some reasons:</p> <h3> Nodes take a long time to set up - up to weeks! </h3> <p>The bane of any developer is spending a lot of time setting up a tool that doesn't directly contribute to what they're trying to build, and nodes are among the worst offenders.</p> <p>There are typically two major categories of nodes</p> <ol> <li> <strong>Light Nodes</strong>: sync just the block headers and requests from full nodes for many queries.</li> <li> <strong>Full Nodes</strong>: Full nodes keep the entire state of a blockchain - every transaction that's ever been created</li> </ol> <p>Most queries work with light nodes, but full nodes are the backbone of the blockchain - they’re necessary to serve most information.<br> Light nodes have gotten relatively more simple in the past, but still require installing the node program, setting configuration variables, downloading block headers, and checking ports and health to ensure they're running properly</p> <p>Full nodes are even worse: the biggest issue is that full nodes need to download every block from 0 to latest from scratch, and manually replay every block and transaction ever submitted by anybody ever. For Ethereum mainnet, that's over 10 million blocks and on the order of billions of transactions. That can literally take weeks of syncing.</p> <h2> Nodes have to be managed - by you! </h2> <p>The biggest Obstacle to running your own node is Nodes have to be managed by You. Get ready for the devOps project from hell. Just a quick overview:</p> <ul> <li><p>Nodes regularly need to be upgraded every few weeks, and occasionally rebuilt from scratch in the case of hard forks and node client upgrades.</p></li> <li><p>Because most nodes weren't designed with reliability in mind, certain queries (such as eth_getLogs) can involve running through millions of blocks and transactions, and often time out or crash a node</p></li> <li><p>Individual nodes can fall behind the network for various reasons like peering and connection issues, getting stranded on outdated branches, issues with internal state. If they’re behind, your users will get served stale data but not realize it, which can be a dangerously terrible experience.<br> There are various others reasons why running your node is time consuming and hideous.</p></li> </ul> <p>To save ourselves from all this necessary Hardwork. We can simply use RPC Node Providers. I understand this article is lengthy but bear with me. You already learn all about RPC Nodes to get started. Now let’s learn about NODE PROVIDERS.</p> <h2> What is a Node Provider? </h2> <p>Node providers are essentially teams, companies (like <a href="proxy.php?url=https://www.ankr.com/">ANKR</a>, Alchemy) that offer a way to access the information on a blockchain without having to run your own node! Instead of sending your requests to a local node, you can send them over the internet to a provider offering an identical API that is running fully synced, up-to-date nodes available 24/7.<br> A solid node provider will offer, at the very minimum:</p> <ul> <li>Access to light and full nodes with regularly updated nodes and alerts, so you don't have to worry about forks or network changes.</li> <li>Access to archive nodes for historical transaction data.</li> <li>Scalability and Reliability: nodes should be available whenever you want, as much as you want them.</li> <li>Consistency: providers should handle tricky edge-cases. This is oftentimes an issue when using Infura or other providers.</li> </ul> <p>All and all you get all the capabilities of RPC Node without any hassle but you need to pay some fees for using their services.</p> <p>You have also understood why should we use Node providers instead of running our own node.</p> <p>Now let's explore the hidden treasure of Blockchain, Decentralized RPC Node Provider and why should we use them.</p> <h2> Why should we use Decentralized RPC Node Providers? </h2> <p>Now that we know, that a majority of Web3 users do not run their own full node to interact with blockchains, but trust RPC Node Providers. Currently, most of the RPC Node Providers like Alchemy, and Infura are centralized. Now you must be thinking why we are using centralized RPC Node Providers when we building Dapp which literally stands for Decentralized Application. ANKR node provider exactly solving this problem. <a href="proxy.php?url=https://www.ankr.com/">ANKR</a> is a Decentralized RPC Node Provider that has all the capabilities of the centralized node provider plus is censorship-free. To understand decentralized RPC providers better, we will learn about the benefits of Decentralized RPC Node:</p> <h3> 1. Censorship Resistance </h3> <p>Decentralized RPC Provider is censorship-free. Meaning no center authority, not even RPC Provider (like ANKR) can remove or block the RPC request of any dApp like Tornado Cash. We come to see the ill-effect of Centralized RPC Node Providers when the Tornado cash controversy breaks out. Under the Pressure of US Government, they are blocking the RPC Request for Tornado Cash.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--kitrpE7B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r8qdufsbjbb2mxrpo4a8.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--kitrpE7B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r8qdufsbjbb2mxrpo4a8.png" alt="Infura and Alchemy" width="880" height="1011"></a></p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--gSEt5ye2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u7leq0jp8m633wzarn16.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--gSEt5ye2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u7leq0jp8m633wzarn16.png" alt="Pokt" width="880" height="1001"></a><br> With Centralized RPC Node Providers now engaging in censorship, this issue is more clear than ever. We need Decentralized RPC Provider that keeps up our dapps and remains censorship free.</p> <h3> 2. Avoid single points of failure </h3> <p>Centralized Web3 providers use AWS data centers only to house their nodes. This limits the global distribution of nodes leading to higher latency and creating a big problem if AWS goes down — all the dApps that depend on these nodes to communicate with the blockchain go down with it.</p> <p>But the bottom line is that the foundation for Web3 needs to be decentralized. Otherwise, we are just building Web 2.1 — a centralized web with extra steps.</p> <h3> 3. The Concentration of Power </h3> <p>Suppose a centralized provider or providers ended up gaining a majority of infrastructure control over a blockchain (or multiple chains) because of the number of nodes they operate. In that case, that could spell disaster for the security and continuity of decentralized systems. Additionally, if services like AWS don’t like a particular dApp, they could effectively shut it down, as they have been doing with Web2 platforms.</p> <h3> 4. Gatekeeping and Overpricing </h3> <p>We all want Web3 to be as accessible as possible, so we want fewer paywalls and barriers to entry when it comes to interfacing with node infrastructure. Centralized providers don’t price their services for the communities — they do it to secure as much profit as they can. And for VC-backed providers, prices will more than likely increase every time they seek another round of equity.</p> <h2> Decentralized RPC Node Providers are Better </h2> <p>The necessary evils of Web2 (like centralized mega-providers) are no longer necessary and should be removed at earliest. ANKR is focused on solving this exact problem. By using Decentralized RPC Node Provider (like <a href="proxy.php?url=https://www.ankr.com/">ANKR</a>), You not only make your dapp truly decentralized but also making help in creating crypto economy. Massive Servers will not run nodes but self-funded DAO’s and Communities will, not VC-backed startups and companies whose sole purpose is to make money. We will have a censor-free environment, Government will not control us. We have a once-in-a-lifetime opportunity to build a new layer of the web that provides autonomy, privacy, censorship resistance, and self-governance without a need for profiteers capitalizing on its use. Decentralized infrastructure is the missing puzzle piece that allows us to build, transact, communicate, and earn rewards on the future web independently.</p> <p>If you are still with me, I can assure you that you have learned all you need to know about RPC nodes and node providers.</p> <p>References:<br> <a href="proxy.php?url=https://medium.com/ankr-network/why-are-rpcs-so-important-in-blockchain-development-5-use-cases-60a16a02c143">https://medium.com/ankr-network/why-are-rpcs-so-important-in-blockchain-development-5-use-cases-60a16a02c143</a></p> <p><a href="proxy.php?url=https://medium.com/ankr-network/centralized-vs-decentralized-web3-infrastructure-what-should-developers-choose-1a1d5f0715c7">https://medium.com/ankr-network/centralized-vs-decentralized-web3-infrastructure-what-should-developers-choose-1a1d5f0715c7</a></p> <p>I hope you learned something new and solved the problem. Thanks for reading. Have fun!</p> <p>You can follow me on <a href="proxy.php?url=https://twitter.com/Aayush_gupta_ji">Twitter</a>, <a href="proxy.php?url=https://github.com/AAYUSH-GUPTA-coder">GitHub</a> and <a href="proxy.php?url=https://www.linkedin.com/in/aayush-gupta-20023b183/">Linkedin</a>. Keep your suggestions and comments coming!</p> rpc blockchain learning ethereum How To Migrate Dapp from Rinkeby to Mumbai Aayush Gupta Sun, 04 Sep 2022 05:30:51 +0000 https://dev.to/aayushguptacoder/how-to-migrate-dapp-from-rinkeby-to-mumbai-460j https://dev.to/aayushguptacoder/how-to-migrate-dapp-from-rinkeby-to-mumbai-460j <p>We Web3 Developers are facing, once in a lifetime tragedy. Tragedy, none of us think we will ever face. Saying Good Bye to our favorite and most popular Testnetwork <strong><em>Rinkeby</em></strong>. During this period of Grief. We have to handle, one more humongous task of Migrating our dApps from rinkeby to another testnet. This article will not take away your sorrows of losing Rinkeby but will help you migrate your dApp.</p> <h2> Steps Involve in Migrating </h2> <ol> <li>Update the RPC Node</li> <li>Re-Deploy the Smart Contract </li> <li>Make adjustments in frontend</li> </ol> <h2> 1. Update the RPC Node </h2> <p>The first task for migrating your dapp is to get RPC Node of the new Testnetwork, for our example, we will be using <em>Mumbai</em> Testnetwork. You can use any Node Provider to get Mumbai testnetwork RPC Node. I will use <a href="proxy.php?url=https://www.ankr.com/">Ankr</a>.</p> <p>Go to their RPC Service section by clicking on this <a href="proxy.php?url=https://www.ankr.com/rpc/">link</a>.</p> <p>Now Search for Polygon Network in Ankr Endpoint. Click on the "More" Button to view Polygon Mainnet and Polygon Mumbai Testnetwork.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--gAK4fKL9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/664k6940ymbg1m6u5q5r.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--gAK4fKL9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/664k6940ymbg1m6u5q5r.png" alt="Ankr Endpoint Page" width="880" height="433"></a></p> <p>Select Testnet on the network section and Copy the Public RPC Key.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--byTJmGuR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nv0wgrrorjz7bta34m60.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--byTJmGuR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nv0wgrrorjz7bta34m60.png" alt="Ankr Testnet Section" width="880" height="358"></a></p> <p>That's it. You get the RPC node. Now that we have RPC Node, we will replace our new Mumbai RPC Node key with old Rinkeby RPC in our dapp. Let's Go.</p> <p>I am assuming you are using "Hardhat" as a Solidity Development Framework. Most probably if you are following any quality tutorial or documentation. You probably store your RPC Key in <code>.env</code> file. You need to replace it with a new Mumbai RPC node.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--ZlTML_Ia--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nutvwpykjpxl47f51scz.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--ZlTML_Ia--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nutvwpykjpxl47f51scz.png" alt="Ankr RPC Node in .env" width="775" height="251"></a></p> <p>As we are using Public RPC Node. You can also simply put your RPC key in your <code>hardhat.config.js</code>.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--B5LSMq2B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ae9oxyl95olq9xw5tlsj.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--B5LSMq2B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ae9oxyl95olq9xw5tlsj.png" alt="RPC Key in Public" width="880" height="778"></a></p> <p>You can also use this preferred method of storing all your keys like Private Key, PolygonScan key, and RPC key in the <code>.env</code> file and importing them in the <code>hardhat.config.js</code> file. Now in your <code>hardhat.config.js</code> file. Replace <code>rinkeby</code> with <code>mumbai</code> inside the <code>networks</code> section.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--vx7uopv2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ysijhw9yakas6mq61mot.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--vx7uopv2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ysijhw9yakas6mq61mot.png" alt="Replacing Rinkeby To Mumbai" width="781" height="790"></a></p> <h2> 2. Re-Deploy the Contract </h2> <p>First, make sure you have some test Matic in our wallet, which you are using for deploying the smart contract. You can use this Mumbai Faucet to get some test Matic. <a href="proxy.php?url=https://mumbaifaucet.com/">Mumbai Faucet</a></p> <p>Run this command to deploy your smart contract.<br> <code>npx hardhat run scripts/deploy.js --network mumbai</code> <br> or<br> <code>npx hardhat run &lt;location of your deploy script&gt; --network mumbai</code></p> <p>If everything works according to plan, you will get an updated "Contract Address". If you added <code>console.log</code> in your deploy script, which you should. You will get output like this.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--phX4Um_F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xl9afc1blnxz0ak8f9cc.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--phX4Um_F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xl9afc1blnxz0ak8f9cc.png" alt="Contract Address" width="835" height="143"></a></p> <h2> 3. Make adjustments in frontend </h2> <p>Update your smart contract address in your Frontend folder or index file.</p> <p>Set chainId to 80001 like <code>chainId == 80001</code> and replace the word 'Rinkeby' with 'Mumbai'.</p> <p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--S7V6bEtu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ysptr1pkwcz7iyxlmqg.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--S7V6bEtu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ysptr1pkwcz7iyxlmqg.png" alt="chainID= 80001" width="880" height="172"></a></p> <blockquote> <p>Rinkeby will always be remembered in our hearts and in the stories, we will tell to our future generation.</p> </blockquote> <p>Don't forget to push your code to GitHub so all the world can see your amazing work.</p> <p>I hope you learned something new and solved the problem. Thanks for reading. Have fun!</p> <p>You can follow me on <a href="proxy.php?url=https://twitter.com/Aayush_gupta_ji">Twitter</a>, <a href="proxy.php?url=https://github.com/AAYUSH-GUPTA-coder">GitHub</a> and <a href="proxy.php?url=https://www.linkedin.com/in/aayush-gupta-20023b183/">Linkedin</a>. Keep your suggestions and comments coming!</p> blockchain rinkeby rpc ethereum How to Create and Deploy an ERC-1155 NFT Bundle Collection Aayush Gupta Wed, 06 Apr 2022 05:28:51 +0000 https://dev.to/aayushguptacoder/how-to-create-and-deploy-an-erc-1155-nft-bundle-collection-489i https://dev.to/aayushguptacoder/how-to-create-and-deploy-an-erc-1155-nft-bundle-collection-489i <p>In this Tutorial, we will build NFT Bundle Collection using <a href="proxy.php?url=https://ethereum.org/en/developers/docs/standards/tokens/erc-1155/" rel="noopener noreferrer">ERC-1155</a>. Instead of Minting all the NFTs in one go. We allow users to mint NFT from any NFT bundle Collection one by one. We also set a maximum supply of NFTs; one user can mint only one NFT.</p> <h2> Overview </h2> <p>ERC-1155 has emerged as a gold standard for creating NFTs; every major marketplace lists new tokens as an ERC-1155 standard. In this guide, we will learn about the ERC-1155 token standard and how to create an ERC-1155 NFT Bundle Collection.</p> <h2> Steps </h2> <ol> <li>Create 7 NFT collections</li> <li>Create and deploy an ERC-1155 contract</li> <li>Update the contract to be compatible with OpenSea</li> <li>Deploy our NFT collections</li> </ol> <h2> Requirements </h2> <ul> <li>Image assets to create NFTs</li> <li>Metadata of NFTs</li> <li>MetaMask and some Mumbai test MATIC</li> <li>Knowledge of <a href="proxy.php?url=https://ethereum.org/en/developers/docs/standards/tokens/erc-20/" rel="noopener noreferrer">the ERC-20</a> and <a href="proxy.php?url=https://ethereum.org/en/developers/docs/standards/tokens/erc-721/" rel="noopener noreferrer">ERC-721</a> token standards</li> </ul> <h2> What is ERC-1155? </h2> <p>ERC1155 is a multi-token standard that allows the creation of fungible, non-fungible, and semi-fungible tokens all in one contract. Before ERC-1155, if a use case needed both ERC-20 (fungible) and ERC-721 (non-fungible) tokens, you would need to create separate contracts to achieve this. ERC1155 also allows for multiple NFT collections to be launched in just one smart contract instead of creating a different contract for each collection; this increases efficiency in smart contract construction and minimizes the transaction count, which is very important as it consumes less blockchain space. With ERC-1155, batch transfer of tokens is possible instead of transferring a token to a single address in previous standards.</p> <p>A prevalent example of the ERC-1155 application is blockchain-based decentralized games, which need coins and collectibles, so ERC-1155 has become a standard there. ERC1155 has also become a standard in the NFT space.</p> <p>The previous ERC-721 had a one-to-one mapping of token id with the address. ERC-1155 has a rather complex mapping where the address in a combination of token ID is mapped to the balance of the token.</p> <h2> Creating Metadata URI </h2> <p>We will create 7 NFT Bundle collections (Agra, Delhi, Goa, and so on) with a single NFT. We will store the Metadata of NFT to the decentralized storage IPFS because we are building decentralized applications (DApp). We will upload them through <a href="proxy.php?url=https://www.pinata.cloud/" rel="noopener noreferrer">PINATA</a>. You can choose some other decentralized storage IPFS of your choice.</p> <p>Sign in to Pinata and upload your image files for Agra, Delhi, Goa, etc. You should see something like this once you have uploaded them successfully:</p> <p><a href="proxy.php?url=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%2Fj1pakalk91ymusx0s3ak.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fj1pakalk91ymusx0s3ak.png" alt="Image description"></a></p> <p>Copy the IPFS URL of the image; we will need it for the metadata of each collection.</p> <p><a href="proxy.php?url=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%2Fqx65etp29aag5pjezsz3.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fqx65etp29aag5pjezsz3.png" alt="Image description"></a></p> <p>We will create three JSON metadata files to store information about our NFT collections.</p> <ul> <li> <code>0.json</code>: Agra collection</li> <li> <code>1.json</code>: Delhi collection</li> <li> <code>2.json</code>: Goa collection</li> </ul> <p>Our 0.json file will look something like this:</p> <p><a href="proxy.php?url=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%2F250sd38hjzszzgwwq1k6.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2F250sd38hjzszzgwwq1k6.png" alt="Image description"></a></p> <p><strong>name</strong>: Has the name of the NFT.</p> <p><strong>description</strong>: Has the description of the NFT.</p> <p><strong>image</strong>: Has the link to the image we got earlier (IPFS URL).</p> <p><strong>properties</strong>: Has the various properties of NFT</p> <p>Create the remaining JSON files, <code>1.json</code> and <code>2.json</code>, for Delhi and Goa collections, respectively, and so on.</p> <p>Now Similarly, we will upload our metadata folder in Pinata. Once successfully uploaded, It will look like this:</p> <p><a href="proxy.php?url=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%2F6bp4ox0tpwrqnekscs06.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2F6bp4ox0tpwrqnekscs06.png" alt="Image description"></a></p> <p>You should be able to access JSON files by just entering the file name at the end of the URL, for example:</p> <p><a href="proxy.php?url=https://ipfs.io/ipfs/QmSCFe5vvoPsSpyHZpGAW78GJ4bAuDcySCV9UnMm7B69iS/0.json" rel="noopener noreferrer">https://ipfs.io/ipfs/QmSCFe5vvoPsSpyHZpGAW78GJ4bAuDcySCV9UnMm7B69iS/0.json</a></p> <p><a href="proxy.php?url=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%2Fqv0h9cw5dq0nv85gwrzz.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fqv0h9cw5dq0nv85gwrzz.png" alt="5"></a></p> <h2> Creating &amp; Deploying the ERC1155 Contract </h2> <p>We will use the <a href="proxy.php?url=https://www.openzeppelin.com/contracts" rel="noopener noreferrer">OpenZeppelin</a> contracts library to create our ERC1155 contract and deploy it using Ethereum <a href="proxy.php?url=https://remix.ethereum.org/#optimize=false&amp;runs=200&amp;evmVersion=null&amp;version=soljson-v0.8.7+commit.e28d00a7.js" rel="noopener noreferrer">Remix IDE</a> on the Mumbai testnet. Make sure you have some Mumbai test MATIC which you can also get from MUMBAI Faucet.</p> <p>Please create a new file, <code>traveler.sol</code>, in REMIX and paste the following code:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; contract TravelQuest is ERC1155, Ownable { uint256[] public supplies = [50,50,50,50,50,50,150]; uint256[] public minted = [0,0,0,0,0,0,0]; mapping(uint256 =&gt; mapping(address =&gt; bool)) public member; constructor() ERC1155("ipfs://QmSCFe5vvoPsSpyHZpGAW78GJ4bAuDcySCV9UnMm7B69iS/{id}.json") { } // to Put NFT to Opensea function uri(uint256 _tokenId) override public view returns (string memory) { require(_tokenId &lt;= supplies.length-1,"NFT does not exist"); return string( abi.encodePacked( "ipfs://QmSCFe5vvoPsSpyHZpGAW78GJ4bAuDcySCV9UnMm7B69iS/", Strings.toString(_tokenId), ".json" ) ); } function mint(uint256 _tokenId) public { require( !member[_tokenId][msg.sender], "You have already claimed this NFT." ); require(_tokenId &lt;= supplies.length-1,"NFT does not exist"); uint256 index = _tokenId; require (minted[index] + 1 &lt;= supplies[index], "All the NFT have been minted"); _mint(msg.sender, _tokenId, 1, ""); // "" is data which is set empty minted[index] += 1; member[_tokenId][msg.sender] = true; } function totalNftMinted(uint256 _tokenId) public view returns(uint256){ return minted[_tokenId]; } } </code></pre> </div> <p>Line 1: Specifying SPDX license type, which is added after Solidity version ^0.6.8. Whenever the source code of a smart contract is made available to the public, these licenses can help resolve/avoid copyright issues. If you do not wish to specify any license type, you can use a special value UNLICENSED or skip the whole comment (it will not result in an error, just a warning).</p> <p>Line 2: Declaring the Solidity version.</p> <p>Line 4: Importing the OpenZeppelin ERC-1155 contract.</p> <p>Line 10: <code>supplies</code> is an array that keeps track of the Maximum number of NFT available to mint.</p> <p>Line 11: <code>minted</code> is an array that keeps track of how many NFT<br> already been minted.</p> <p>Line 21: <code>function URI</code> to put metadata of NFT to Opensea. We use metadata stored in IPFS.</p> <p>Line 32: <code>function mint</code> to allow users to mint NFT from our NFT<br> Bundle Collection. One user can only mint 1 NFT of each NFT collection.</p> <p>Line 49: <code>function totalNftMinted</code> gives the total number of NFTs minted from each NFT Collection.</p> <ul> <li>Address on which tokens will be minted to, <code>msg.sender</code> here means the deployer of the contract.</li> <li>Token id, we have already assigned names to token id, so using names here.</li> <li>Quantity of each token.</li> </ul> <h2> Compiling the Smart Contract </h2> <p>Compile the contract, go to the third tab on the left menu, select Injected Web3 as environment and deploy it by choosing the correct contract name:</p> <p><a href="proxy.php?url=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%2F1lej705woab6qjyrzx4r.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2F1lej705woab6qjyrzx4r.png" alt="6.png"></a></p> <p>Approve the transaction from MetaMask. Once the transaction is complete, it will deploy your contract.</p> <p>Now you can perform functions like mint NFT by entering token id. We can also retrieve the URI of the token by entering the token id.</p> <p><a href="proxy.php?url=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%2Fa5qinp2g0hlxtvfj9bgz.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fa5qinp2g0hlxtvfj9bgz.png" alt="7.png"></a></p> <p>When you query the contract for URI, it will return a format supported by OpenSea.</p> <p><a href="proxy.php?url=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%2Fb9ygyi78akj2zjqo0in7.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fb9ygyi78akj2zjqo0in7.png" alt="8.png"></a></p> <h2> Minting an NFT </h2> <p>Enter the token ID of the NFT Bundle Collection you want to mint.</p> <p><a href="proxy.php?url=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%2Fx0gzpt4aqfmjute6yed3.png" class="article-body-image-wrapper"><img src="proxy.php?url=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%2Fx0gzpt4aqfmjute6yed3.png" alt="9.png"></a></p> <p>After some time of minting, you can see the NFT on <a href="proxy.php?url=https://testnets.opensea.io/collection/unidentified-contract-yuo4oyd8oz" rel="noopener noreferrer">OpenSea</a>.</p> <p>You will also see the metadata of the NFT.</p> <h2> Conclusion </h2> <p>Congratulations on deploying your ERC-1155 tokens. If you made it here now, you know about the ERC-1155 multi-token standard and how to create and deploy the ERC1155 bundle NFT Collection.</p> <p>I hope you learned something new or maybe even solved a problem. Thanks for reading, and have fun!</p> <p>You can follow me on <a href="proxy.php?url=https://twitter.com/Aayush_gupta_ji" rel="noopener noreferrer">Twitter</a> and <a href="proxy.php?url=https://www.linkedin.com/in/aayush-gupta-20023b183/" rel="noopener noreferrer">LinkedIn</a>. Keep your suggestions/comments coming!</p> blockchain web3 erc1155 nftbundlecollection