<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Ankr - Web3.0 Developer Tutorials]]></title><description><![CDATA[Explore web3 tools, platforms, protocols, tutorials, guides, and more!]]></description><link>https://ankr.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1662476830903/fghff19pS.png</url><title>Ankr - Web3.0 Developer Tutorials</title><link>https://ankr.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Mon, 22 Jun 2026 16:58:17 GMT</lastBuildDate><atom:link href="https://ankr.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Web3 Data Challenges and the State of APIs]]></title><description><![CDATA[An odyssey of data and frustration of a developer
Ah, the joys of querying Web3. It's like going on a grand adventure, where you're not quite sure what you're looking for or where you're going to find it. You might start out with a simple query, some...]]></description><link>https://ankr.hashnode.dev/web3-data-challenges-and-the-state-of-apis</link><guid isPermaLink="true">https://ankr.hashnode.dev/web3-data-challenges-and-the-state-of-apis</guid><category><![CDATA[Web3 Data Challenges]]></category><category><![CDATA[Ankr]]></category><category><![CDATA[ankrjs]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Blockchain]]></category><dc:creator><![CDATA[Krinza Momin]]></dc:creator><pubDate>Sat, 24 Dec 2022 06:54:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671864574952/81b0973b-00eb-42ef-a174-107d43890044.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-an-odyssey-of-data-and-frustration-of-a-developer">An odyssey of data and frustration of a developer</h2>
<p>Ah, the joys of querying Web3. It's like going on a grand adventure, where you're not quite sure what you're looking for or where you're going to find it. You might start out with a simple query, something like "How many transactions were processed on the Ethereum network yesterday?" But before you know it, you're down the rabbit hole of complex data structures, arcane technical jargon, and seemingly endless frustration.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=gzVcZRDZe9Y">https://www.youtube.com/watch?v=gzVcZRDZe9Y</a></div>
<p> </p>
<p>The first challenge you'll face is figuring out how to actually query the data you're looking for. Once you've finally figured out which method to use, you'll need to start dealing with all of the technical details. You'll need to figure out which Ethereum node to connect to, what the correct block number or transaction hash is, and how to format your query in a way that the node will understand.</p>
<p>And even then, there's no guarantee that you'll get the data you're looking for. The Ethereum network is notoriously unreliable, and you might find yourself getting error messages or incomplete results.</p>
<p>But even if you manage to get your query working, you're not out of the woods yet. Just because you have the data doesn’t mean it’s usable yet. It's like trying to solve a puzzle with only half the pieces.</p>
<h2 id="heading-the-challenges-of-web3-data-querying">The challenges of Web3 data querying</h2>
<p>Web3 data querying is a hot topic among developers, with many of them struggling to find the best way to access the vast amounts of data on the decentralized web. This has led to a rise in the use of APIs, which provide a simple and effective way for developers to query data on the blockchain.</p>
<p>One of the biggest challenges faced by developers when it comes to querying is the sheer amount of data that is available. With millions of transactions and blocks being added to the blockchain every day, it can be difficult for developers to know where to start when it comes to accessing this data.</p>
<p>Another challenge is the complexity of the data structures. Unlike traditional databases, which are organized in a simple, hierarchical manner, adding cross-chain functionality can be a complex task, as data does not flow easily between different blockchain networks. This added layer of complexity can make it more challenging to integrate and utilize multiple blockchains in a single system</p>
<h2 id="heading-the-state-of-api-development">The state of API development</h2>
<p>In response to these challenges, many developers have turned to APIs, or application programming interfaces, to help them access data on the decentralized web. APIs provide a way for different software systems to communicate with each other and share data and functionality, making it easier for developers to build complex interconnected applications.</p>
<p>There are several different types of APIs available, each designed to serve a specific purpose. Some APIs allow developers to query data directly from the blockchain, while others provide access to third-party data sources, such as exchanges or other decentralized applications.</p>
<h2 id="heading-the-data-layer-for-web3-dapps">The Data Layer for Web3 dapps</h2>
<p>Web3 dapps are applications built on top of the blockchain and use smart contracts and other decentralized technologies to provide a wide range of services and functionality.</p>
<p>However, building and running a Web3 dapp is not as simple as building a traditional web application. Unlike traditional web apps, which can easily access data from centralized databases, Web3 dapps must rely on the blockchain for their data needs.</p>
<p>That's where APIs come in. APIs provide a simple and standardized way for Web3 dapps to access data on the blockchain, allowing developers to query data and interact with smart contracts in a consistent and predictable way. In this sense, APIs can be thought of as the data layer for Web3 dapps, providing a common interface that can be used by any dapp, regardless of its specific requirements or underlying technology.</p>
<h2 id="heading-build-with-ankr-advanced-apis">Build with Ankr Advanced APIs</h2>
<p>Ankr offers advanced APIs that make it easy for developers to build and ship powerful dapps. These APIs provide a wide range of tools and features, including support for NFTs, tokens, and data querying. This allows developers to build complex and feature-rich dapps, without the toiling of setting up complex RPC calls, that provide value to users and take advantage of the full potential of the web3 data.</p>
<h3 id="heading-nft-api">NFT API</h3>
<p>One of the most popular Ankr APIs is the NFT API, which allows developers to access and query data related to non-fungible tokens, or NFTs. NFTs are unique digital assets, such as artwork or collectibles, that are built on top of the blockchain. They are often used in Web3 dapps to represent virtual items or assets and can be traded and exchanged on decentralized exchanges.</p>
<p><img src="https://strapi-no-cache.ankr.com/uploads/Untitled_c5de8a2d9b.png" alt="Untitled.png" /></p>
<p>The NFT API offered by Ankr provides developers with a simple and standardized way to access and query data related to NFTs. With the NFT API, developers can easily retrieve information about specific NFTs, such as their metadata, ownership, and transaction history. They can also use the API to display and manage NFTs within their NFT galleries, wallets and marketplace dapps, providing their users with a seamless and secure way to interact with these unique digital assets.</p>
<h3 id="heading-token-api">Token API</h3>
<p>Another important API offered by Ankr is the Token API, which provides developers with access to data related to tokens. Tokens are digital assets that can be traded and exchanged on the blockchain and are often used to represent a variety of different assets, such as cryptocurrencies, utility tokens, and stablecoins. The Token API allows developers to query data related to tokens, such as their token holders, prices, and account balances.</p>
<p><img src="https://strapi-no-cache.ankr.com/uploads/73f520e7_10c4_4ec7_b196_b2d778bbfb5b_0473217688.png" alt="73f520e7-10c4-4ec7-b196-b2d778bbfb5b.png" /></p>
<h3 id="heading-query-api">Query API</h3>
<p>With the Query API, developers can easily retrieve information about transactions, blocks, and logs, making it easier to build applications that rely on this data. Additionally, Query API offers developers a simple and standardized way to access data from multiple blockchains, without having to worry about the complexities and differences of each individual chain.</p>
<p><img src="https://strapi-no-cache.ankr.com/uploads/dfa3f0a2_c9c8_482a_a5b3_02b2c106045a_daf7b7f6fe.png" alt="dfa3f0a2-c9c8-482a-a5b3-02b2c106045a.png" /></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>With ANKR's advanced APIs, developers can take advantage of a range of features and capabilities, including no-node maintenance and cross-chain interoperability. These APIs are designed to be easy to use and integrate, making it possible for developers of all skill levels to get started building with blockchain.</p>
<p>From real-time data feeds to advanced analytics and reporting, Ankr's APIs provide a comprehensive suite of tools for building next-generation blockchain-based applications.</p>
<p>Start building now with <a target="_blank" href="https://www.ankr.com/advanced-api/">Ankr Advanced APIs</a>.</p>
]]></content:encoded></item><item><title><![CDATA[How to build an NFT minting site with RainbowKit + Next.js + thirdweb + Ankr]]></title><description><![CDATA[Launching your NFT project has never been easier! Looking to put your own NFT collection on the blockchain? You’re in the right place!
What are we building?
In this tutorial, we will be building an ERC-1155 (Edition) minting page. This will be a full...]]></description><link>https://ankr.hashnode.dev/how-to-build-an-nft-minting-site-with-rainbowkit-nextjs-thirdweb-ankr</link><guid isPermaLink="true">https://ankr.hashnode.dev/how-to-build-an-nft-minting-site-with-rainbowkit-nextjs-thirdweb-ankr</guid><category><![CDATA[Ankr]]></category><category><![CDATA[NFT]]></category><category><![CDATA[Mint]]></category><category><![CDATA[thirdweb]]></category><dc:creator><![CDATA[joshcs.eth ᵍᵐ]]></dc:creator><pubDate>Thu, 15 Dec 2022 12:21:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671106984881/gXJjqo3-5.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Launching your NFT project has never been easier! Looking to put your own NFT collection on the blockchain? You’re in the right place!</p>
<h2 id="heading-what-are-we-building"><strong>What are we building?</strong></h2>
<p>In this tutorial, we will be building an ERC-1155 (Edition) minting page. This will be a full-stack dApp made with Next.js, RainbowKit, thirdweb, and Ankr.</p>
<h3 id="heading-tech-stack">Tech Stack</h3>
<ul>
<li><p>RPC provider: <a target="_blank" href="https://www.ankr.com/protocol/">Ankr</a></p>
</li>
<li><p>Wallet Connect: <a target="_blank" href="https://www.rainbowkit.com/">Rainbowkit</a></p>
</li>
<li><p>User Interface: <a target="_blank" href="https://chakra-ui.com/">Chakra UI</a></p>
</li>
<li><p>Smart Contract: <a target="_blank" href="http://thirdweb.com/">Thirdweb</a></p>
</li>
</ul>
<p><strong>Prerequisite:</strong> To successfully finish this guide, you'll need Node.js and Yarn installed on your machine.</p>
<h2 id="heading-step-01-development-setup">Step 01: Development <strong>Setup</strong></h2>
<h3 id="heading-create-nextjs-app"><strong>Create Next.js app</strong></h3>
<p>First, open your terminal and run the following command to start your Next.js app:</p>
<pre><code class="lang-bash">npx create-next-app@latest --ts
</code></pre>
<p>We have named the directory <code>thirdweb-rainbowkit</code>, you can change directories to your Next app by running:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> thirdweb-rainbowkit
</code></pre>
<h3 id="heading-add-chakra-ui"><strong>Add Chakra UI</strong></h3>
<p>Next, add Chakra UI by running this command:</p>
<pre><code class="lang-bash">npm i @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^6
</code></pre>
<p>We’re not going to be using the <code>api</code> directory, so you can delete it.</p>
<p>Start up your instance of the Next App on <a target="_blank" href="http://localhost"><strong>localhost</strong></a> by running:</p>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>Now, head to <code>pages/index.tsx</code>and remove the <code>&lt;div&gt; ... &lt;/div&gt;</code> and <code>&lt;p&gt; ... &lt;/p&gt;</code> in <code>&lt;main&gt;</code> to clean up our minting page. This is also a good time to change the title from the boilerplate text, it should look something like the screenshot below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671105372937/mJTMujbtq.png" alt class="image--center mx-auto" /></p>
<p>Import the <code>ChakraProvider</code>, <code>ColorModeScript</code>, and <code>extendTheme</code> from <code>@chakra-ui/react</code> at the top of your <code>_app.tsx</code> file:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { ChakraProvider, ColorModeScript, extendTheme } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;
</code></pre>
<p>Add the Chakra Provider to <code>MyApp</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyApp</span>(<span class="hljs-params">{ Component, pageProps }: AppProps</span>) </span>{
<span class="hljs-keyword">return</span> (
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ChakraProvider</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">Component</span> {<span class="hljs-attr">...pageProps</span>} /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ChakraProvider</span>&gt;</span></span>
);
}
</code></pre>
<p>Below our imports, declare your <code>initialColorMode</code>, <code>useSystemColorMode</code>, <code>fonts</code>, and <code>theme</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> config = {
<span class="hljs-attr">initialColorMode</span>: <span class="hljs-string">"dark"</span>,
<span class="hljs-attr">useSystemColorMode</span>: <span class="hljs-literal">true</span>,
};
<span class="hljs-keyword">const</span> fonts = {
<span class="hljs-attr">heading</span>: <span class="hljs-string">"Inter"</span>, sans-serif,
<span class="hljs-attr">body</span>: <span class="hljs-string">"Inter"</span>, sans-serif,
};
<span class="hljs-keyword">const</span> theme = extendTheme({ config, fonts });
</code></pre>
<p>Add <code>ColorModeScript</code> to your <code>MyApp</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyApp</span>(<span class="hljs-params">{ Component, pageProps }: AppProps</span>) </span>{
<span class="hljs-keyword">return</span> (
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ChakraProvider</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">ColorModeScript</span> <span class="hljs-attr">initialColorMode</span>=<span class="hljs-string">{theme.config.initialColorMode}</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">Component</span> {<span class="hljs-attr">...pageProps</span>} /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ChakraProvider</span>&gt;</span></span>
);
}
</code></pre>
<h3 id="heading-install-rainbowkit"><strong>Install RainbowKit</strong></h3>
<p>Now we’ll add our connect wallet button using RainbowKit:</p>
<pre><code class="lang-bash">npm install @rainbow-me/rainbowkit wagmi ethers
</code></pre>
<p>Import the required packages into the top of <code>_app.tsx</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> {
  chain,
  configureChains,
  createClient,
  WagmiConfig,
  useSigner,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"wagmi"</span>;
<span class="hljs-keyword">import</span> { publicProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"wagmi/providers/public"</span>;
<span class="hljs-keyword">import</span> { jsonRpcProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"wagmi/providers/jsonRpc"</span>;
<span class="hljs-keyword">import</span> {
  connectorsForWallets,
  wallet,
  RainbowKitProvider,
  midnightTheme,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@rainbow-me/rainbowkit"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@rainbow-me/rainbowkit/styles.css"</span>;
</code></pre>
<p>Configure <code>chains</code>, <code>provider</code>, <code>connectorsForWallets</code>, and <code>wagmiClient</code> underneath of your <code>config</code>, <code>fonts</code>, and <code>theme</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> { chains, provider } = configureChains(
  [chain.goerli],
  [
    jsonRpcProvider({
      <span class="hljs-attr">rpc</span>: <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">return</span> {
          <span class="hljs-attr">http</span>: <span class="hljs-string">"&lt;https://rpc.ankr.com/eth_goerli&gt;"</span>,
        };
      },
    }),
    publicProvider(),
  ]
);

<span class="hljs-keyword">const</span> connectors = connectorsForWallets([
  {
    <span class="hljs-attr">groupName</span>: <span class="hljs-string">"Recommended"</span>,
    <span class="hljs-attr">wallets</span>: [
      wallet.metaMask({ chains, <span class="hljs-attr">shimDisconnect</span>: <span class="hljs-literal">true</span> }),
      wallet.walletConnect({ chains }),
      wallet.coinbase({ <span class="hljs-attr">appName</span>: <span class="hljs-string">"probably nothing"</span>, chains }),
      wallet.rainbow({ chains }),
    ],
  },
  {
    <span class="hljs-attr">groupName</span>: <span class="hljs-string">"Others"</span>,
    <span class="hljs-attr">wallets</span>: [
      wallet.argent({ chains }),
      wallet.brave({
        chains,
        <span class="hljs-attr">shimDisconnect</span>: <span class="hljs-literal">true</span>,
      }),
      wallet.imToken({ chains }),
      wallet.injected({
        chains,
        <span class="hljs-attr">shimDisconnect</span>: <span class="hljs-literal">true</span>,
      }),
      wallet.ledger({
        chains,
      }),
      wallet.steak({ chains }),
      wallet.trust({ chains, <span class="hljs-attr">shimDisconnect</span>: <span class="hljs-literal">true</span> }),
    ],
  },
]);

<span class="hljs-keyword">const</span> wagmiClient = createClient({
  <span class="hljs-attr">autoConnect</span>: <span class="hljs-literal">false</span>,
  connectors,
  provider,
});
</code></pre>
<p>Wrap your <code>MyApp</code> in <code>WagmiConfig</code> and <code>RainbowKitProvider</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyApp</span>(<span class="hljs-params">{ Component, pageProps }: AppProps</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ChakraProvider</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">WagmiConfig</span> <span class="hljs-attr">client</span>=<span class="hljs-string">{wagmiClient}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">RainbowKitProvider</span> <span class="hljs-attr">chains</span>=<span class="hljs-string">{chains}</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{midnightTheme()}</span> <span class="hljs-attr">coolMode</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ColorModeScript</span> <span class="hljs-attr">initialColorMode</span>=<span class="hljs-string">{theme.config.initialColorMode}</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Component</span> {<span class="hljs-attr">...pageProps</span>} /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">RainbowKitProvider</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">WagmiConfig</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ChakraProvider</span>&gt;</span></span>
  );
}
</code></pre>
<h3 id="heading-add-thirdweb-provider"><strong>Add thirdweb provider</strong></h3>
<p>Now we’re ready to set up our <code>ThirdwebSDKProvider</code>  and declare the <code>ChainId</code>. First, add the package with NPM:</p>
<pre><code class="lang-bash">npm install @thirdweb-dev/react@2.6.0-1
</code></pre>
<p>Import the <code>ThirdwebSDKProvider</code>:</p>
<pre><code class="lang-bash">import { ThirdwebSDKProvider, ChainId } from <span class="hljs-string">"@thirdweb-dev/react"</span>;
</code></pre>
<p>Add the <code>activeChainId</code> in your constants:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> activeChainId = ChainId.Goerli;
</code></pre>
<p>Declare your <code>ThirdwebProvider</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ThirdwebProvider</span>(<span class="hljs-params">{ wagmiClient, children }: any</span>) </span>{
<span class="hljs-keyword">const</span> { <span class="hljs-attr">data</span>: signer } = useSigner();
<span class="hljs-keyword">return</span> (
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ThirdwebSDKProvider</span>
<span class="hljs-attr">desiredChainId</span>=<span class="hljs-string">{activeChainId}</span>
<span class="hljs-attr">signer</span>=<span class="hljs-string">{signer</span> <span class="hljs-attr">as</span> <span class="hljs-attr">any</span>}
<span class="hljs-attr">provider</span>=<span class="hljs-string">{wagmiClient.provider}</span>
<span class="hljs-attr">queryClient</span>=<span class="hljs-string">{wagmiClient.queryClient</span> <span class="hljs-attr">as</span> <span class="hljs-attr">any</span>}
&gt;</span>
{children}
<span class="hljs-tag">&lt;/<span class="hljs-name">ThirdwebSDKProvider</span>&gt;</span></span>
);
}
</code></pre>
<p>Wrap your <code>MyApp</code> in the <code>ThirdwebProvider</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyApp</span>(<span class="hljs-params">{ Component, pageProps }: AppProps</span>) </span>{
<span class="hljs-keyword">return</span> (
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ChakraProvider</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">WagmiConfig</span> <span class="hljs-attr">client</span>=<span class="hljs-string">{wagmiClient}</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">RainbowKitProvider</span> <span class="hljs-attr">chains</span>=<span class="hljs-string">{chains}</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{midnightTheme()}</span> <span class="hljs-attr">coolMode</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">ThirdwebProvider</span> <span class="hljs-attr">wagmiClient</span>=<span class="hljs-string">{wagmiClient}</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">ColorModeScript</span> <span class="hljs-attr">initialColorMode</span>=<span class="hljs-string">{theme.config.initialColorMode}</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">Component</span> {<span class="hljs-attr">...pageProps</span>} /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ThirdwebProvider</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">RainbowKitProvider</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">WagmiConfig</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ChakraProvider</span>&gt;</span></span>
);
}
</code></pre>
<h3 id="heading-apptsx-review"><code>_app.tsx</code> Review</h3>
<p>Your <code>_app.tsx</code> file should look very similar to this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> <span class="hljs-string">"../styles/globals.css"</span>;
<span class="hljs-keyword">import</span> type { AppProps } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/app"</span>;
<span class="hljs-keyword">import</span> { ChakraProvider, ColorModeScript, extendTheme } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;
<span class="hljs-keyword">import</span> {
  chain,
  configureChains,
  createClient,
  WagmiConfig,
  useSigner,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"wagmi"</span>;
<span class="hljs-keyword">import</span> { publicProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"wagmi/providers/public"</span>;
<span class="hljs-keyword">import</span> { jsonRpcProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"wagmi/providers/jsonRpc"</span>;
<span class="hljs-keyword">import</span> {
  connectorsForWallets,
  wallet,
  RainbowKitProvider,
  midnightTheme,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@rainbow-me/rainbowkit"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@rainbow-me/rainbowkit/styles.css"</span>;
<span class="hljs-keyword">import</span> { ThirdwebSDKProvider, ChainId } <span class="hljs-keyword">from</span> <span class="hljs-string">"@thirdweb-dev/react"</span>;

<span class="hljs-keyword">const</span> config = {
  <span class="hljs-attr">initialColorMode</span>: <span class="hljs-string">"dark"</span>,
  <span class="hljs-attr">useSystemColorMode</span>: <span class="hljs-literal">true</span>,
};
<span class="hljs-keyword">const</span> fonts = {
  <span class="hljs-attr">heading</span>: <span class="hljs-string">`"Inter", sans-serif`</span>,
  <span class="hljs-attr">body</span>: <span class="hljs-string">`"Inter", sans-serif`</span>,
};

<span class="hljs-keyword">const</span> theme = extendTheme({ config, fonts });

<span class="hljs-keyword">const</span> { chains, provider } = configureChains(
  [chain.goerli],
  [
    jsonRpcProvider({
      <span class="hljs-attr">rpc</span>: <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">return</span> {
          <span class="hljs-attr">http</span>: <span class="hljs-string">"&lt;https://rpc.ankr.com/eth_goerli&gt;"</span>,
        };
      },
    }),
    publicProvider(),
  ]
);

<span class="hljs-keyword">const</span> connectors = connectorsForWallets([
  {
    <span class="hljs-attr">groupName</span>: <span class="hljs-string">"Recommended"</span>,
    <span class="hljs-attr">wallets</span>: [
      wallet.metaMask({ chains, <span class="hljs-attr">shimDisconnect</span>: <span class="hljs-literal">true</span> }),
      wallet.walletConnect({ chains }),
      wallet.coinbase({ <span class="hljs-attr">appName</span>: <span class="hljs-string">"probably nothing"</span>, chains }),
      wallet.rainbow({ chains }),
    ],
  },
  {
    <span class="hljs-attr">groupName</span>: <span class="hljs-string">"Others"</span>,
    <span class="hljs-attr">wallets</span>: [
      wallet.argent({ chains }),
      wallet.brave({
        chains,
        <span class="hljs-attr">shimDisconnect</span>: <span class="hljs-literal">true</span>,
      }),
      wallet.imToken({ chains }),
      wallet.injected({
        chains,
        <span class="hljs-attr">shimDisconnect</span>: <span class="hljs-literal">true</span>,
      }),
      wallet.ledger({
        chains,
      }),
      wallet.steak({ chains }),
      wallet.trust({ chains, <span class="hljs-attr">shimDisconnect</span>: <span class="hljs-literal">true</span> }),
    ],
  },
]);

<span class="hljs-keyword">const</span> wagmiClient = createClient({
  <span class="hljs-attr">autoConnect</span>: <span class="hljs-literal">false</span>,
  connectors,
  provider,
});

<span class="hljs-keyword">const</span> activeChainId = ChainId.Goerli;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ThirdwebProvider</span>(<span class="hljs-params">{ wagmiClient, children }: any</span>) </span>{
  <span class="hljs-keyword">const</span> { <span class="hljs-attr">data</span>: signer } = useSigner();
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ThirdwebSDKProvider</span>
      <span class="hljs-attr">desiredChainId</span>=<span class="hljs-string">{activeChainId}</span>
      <span class="hljs-attr">signer</span>=<span class="hljs-string">{signer</span> <span class="hljs-attr">as</span> <span class="hljs-attr">any</span>}
      <span class="hljs-attr">provider</span>=<span class="hljs-string">{wagmiClient.provider}</span>
      <span class="hljs-attr">queryClient</span>=<span class="hljs-string">{wagmiClient.queryClient</span> <span class="hljs-attr">as</span> <span class="hljs-attr">any</span>}
    &gt;</span>
      {children}
    <span class="hljs-tag">&lt;/<span class="hljs-name">ThirdwebSDKProvider</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyApp</span>(<span class="hljs-params">{ Component, pageProps }: AppProps</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ChakraProvider</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">WagmiConfig</span> <span class="hljs-attr">client</span>=<span class="hljs-string">{wagmiClient}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">RainbowKitProvider</span> <span class="hljs-attr">chains</span>=<span class="hljs-string">{chains}</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{midnightTheme()}</span> <span class="hljs-attr">coolMode</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ThirdwebProvider</span> <span class="hljs-attr">wagmiClient</span>=<span class="hljs-string">{wagmiClient}</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ColorModeScript</span> <span class="hljs-attr">initialColorMode</span>=<span class="hljs-string">{theme.config.initialColorMode}</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Component</span> {<span class="hljs-attr">...pageProps</span>} /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">ThirdwebProvider</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">RainbowKitProvider</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">WagmiConfig</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ChakraProvider</span>&gt;</span></span>
  );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> MyApp;
</code></pre>
<h3 id="heading-add-connect-wallet-button"><strong>Add connect wallet button</strong></h3>
<p>Head over to the <code>index.tsx</code> file and import the <code>ConnectButton</code> from RainbowKit:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { ConnectButton } <span class="hljs-keyword">from</span> <span class="hljs-string">"@rainbow-me/rainbowkit"</span>;
</code></pre>
<p>Add <code>&lt;ConnectButton /&gt;</code> in the <code>&lt;main&gt; ... &lt;/main&gt;</code> tag:</p>
<pre><code class="lang-jsx">&lt;main className={styles.main}&gt;
   <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.title}</span>&gt;</span>gm<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>
   <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ConnectButton</span> /&gt;</span></span>
&lt;/main&gt;
</code></pre>
<p>Congratulations 🎉 Your connect wallet button from RainbowKit should now show on <a target="_blank" href="http://localhost:3000"><strong>localhost:3000</strong></a>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671105472310/ufGz2dItH.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-writing-and-deploying-our-contract-on-thirdweb"><strong>Writing and deploying our contract on thirdweb</strong></h3>
<p>Thirdweb is a great way to get started deploying your own contracts while also maintaining security of your private keys and ownership of your contracts. Head to <a target="_blank" href="http://thirdweb.com"><strong>thirdweb.com</strong></a> and click <code>Start building</code> to begin deploying your first contract.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671105495022/mkDtBhp7J.png" alt class="image--center mx-auto" /></p>
<p>Before going further, you’ll need some Goerli ETH. Make sure to head over to any goerli faucet to request some test ether.</p>
<p>First, connect your wallet at <a target="_blank" href="https://thirdweb.com/dashboard"><strong>https://thirdweb.com/dashboard</strong></a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671105515294/g3w1o5X6F.png" alt class="image--center mx-auto" /></p>
<p>Next, select <code>Pre-built contracts</code>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671105566884/tbr5dWhBJ.png" alt class="image--center mx-auto" /></p>
<p>Then <code>Release a drop</code>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671105594656/bN5mvGKlo.png" alt class="image--center mx-auto" /></p>
<p>And then <code>Edition Drop</code> - this is an ERC-1155 Audited Smart Contract:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671105617588/scsqwhOXP.png" alt class="image--center mx-auto" /></p>
<p>Add the contract metadata that describes what your contract is about. Here’s what we have put:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671105652827/jQKURxcZT.png" alt class="image--center mx-auto" /></p>
<p>Click <code>Deploy Now</code> to deploy your contract. You’ll be prompted to confirm a transaction in your wallet.</p>
<p>Now, you’re ready to add your first edition drop! Click <code>+ Create</code> to get started:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671105675055/eN5ungBNC.png" alt class="image--center mx-auto" /></p>
<p>Upload your image for the ERC-1155 NFT, metadata, and click <code>Create Edition Drop</code>. You’ll be prompted to sign a transaction in MetaMask, confirm it. Once the transaction confirms we are ready to set the Claim Phase for this token. Your dashboard should look like this, click <code>⚙️ Claim Phases</code> then + <code>Add Initial Claim Phase</code>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671105737879/IJNJMRLtL.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671105743485/SsnLI0FOK.png" alt class="image--center mx-auto" /></p>
<p>We’ve set 1 NFT per transaction, start date of the current time, unlimited NFTs on the drop, and only 1 NFT per wallet. Click <code>Save Claim Phases</code> and you will be prompted to confirm another transaction. Copy the contract address under the title of your Edition at the top of the page. For us, it is <code>0xc321cB91524f3C7fcD9e9333D71b644957852Fd2</code>.</p>
<p>Now, we’re ready to head back to our Next.js app to continue building the minting functionality. We will be using the ThirdwebProvider and ThirdwebSDKProvider that we have already imported into our <code>_app.tsx</code>.</p>
<p>We’ll be starting in the <code>index.tsx</code> file. First we will clean up the heading and add padding before our connect wallet button. Add an import for the Chakra UI heading.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// imports</span>
<span class="hljs-keyword">import</span> { Heading } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;

<span class="hljs-comment">// constants</span>

<span class="hljs-keyword">return</span> (
...
&lt;main className={styles.main}&gt;
   <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Heading</span> <span class="hljs-attr">size</span>=<span class="hljs-string">"xl"</span> <span class="hljs-attr">textAlign</span>=<span class="hljs-string">"center"</span> <span class="hljs-attr">pb</span>=<span class="hljs-string">"3"</span>&gt;</span>gm<span class="hljs-tag">&lt;/<span class="hljs-name">Heading</span>&gt;</span></span>
   <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ConnectButton</span> /&gt;</span></span>
&lt;/main&gt;
</code></pre>
<h3 id="heading-add-minting-to-your-dapp"><strong>Add minting to your dApp</strong></h3>
<p>Nice, now it’s time to add some minting functionality from the thirdweb SDK. Add the following imports to allow use of <code>useEditionDrop</code> and <code>useClaimNFT</code> and wagmi:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { useEditionDrop, useClaimNFT } <span class="hljs-keyword">from</span> <span class="hljs-string">"@thirdweb-dev/react"</span>;
<span class="hljs-keyword">import</span> { useAccount } <span class="hljs-keyword">from</span> <span class="hljs-string">"wagmi"</span>;
</code></pre>
<p>Now, add constants. Be sure to replace the  <code>CONTRACT_ADDRESS</code> with your contract address from thirdweb:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Home: NextPage = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// new constants</span>
  <span class="hljs-keyword">const</span> { address } = useAccount();
  <span class="hljs-keyword">const</span> editionDrop = useEditionDrop(
    <span class="hljs-string">"CONTRACT_ADDRESS"</span>
  );
  <span class="hljs-keyword">const</span> { <span class="hljs-attr">mutate</span>: claimNft, isLoading, error } = useClaimNFT(editionDrop);
  <span class="hljs-keyword">if</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"failed to claim nft"</span>, error);
  }
  <span class="hljs-comment">// your frontend</span>
  <span class="hljs-keyword">return</span> (
</code></pre>
<p>Add <code>Button</code> and **<code>Image</code>**to your import with Chakra UI at the top of <code>index.tsx</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Heading, Button, Image } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;
</code></pre>
<p>The next step will add logic to detect a connected wallet from RainbowKit and render the UI accordingly using a ternary statement. You’ll need to add an image in place of <code>probablynothing.png</code> and also add your  <code>&lt;CONTRACT_ADDRESS&gt;</code> and <code>&lt;TOKEN_ID&gt;</code> for the OpenSea URL. Add and modify this code underneath of your <code>&lt;ConnectButton /&gt;</code>:</p>
<pre><code class="lang-jsx">{address ? (
  &lt;&gt;
    &lt;Image
      src="./probablynothing.png"
      rounded="2xl"
      width="42%"
      maxW="300px"
      mt="5"
      mb="3"
      alt="probably nothing"
    /&gt;
    {isLoading ? (
      &lt;Button
        colorScheme="purple"
        disabled={isLoading}
        isLoading
        loadingText="minting..."
        spinnerPlacement="start"
        _hover={{ transform: "scale(1.1)" }}
        size="lg"
        my="3"
      /&gt;
    ) : (
      &lt;Button
        colorScheme="purple"
        disabled={isLoading}
        onClick={() =&gt;
          claimNft({ to: address as any, tokenId: &lt;TOKEN_ID&gt;, quantity: 1 })
        }
        _hover={{ transform: "scale(1.1)" }}
        size="lg"
        my="3"
      &gt;
        claim probably nothing!
      &lt;/Button&gt;
    )}
    &lt;Button
      colorScheme="blue"
      rightIcon={&lt;GiSailboat /&gt;}
      onClick={() =&gt;
        window.open(
          "&lt;https://testnets.opensea.io/assets/goerli/&gt;&lt;CONTRACT_ADDRESS&gt;/&lt;TOKEN_ID&gt;",
          "_blank"
        )
      }
    &gt;
      view on opensea
    &lt;/Button&gt;
  &lt;/&gt;
) : null}
</code></pre>
<p>Between your <code>&lt;Heading&gt; … &lt;/Heading&gt;</code> and <code>&lt;ConnectButton /&gt;</code>, add this code to conditionally render the image of the NFT to be minted if a wallet is not connected, and hide it if there is a connection:</p>
<pre><code class="lang-jsx">{!address ? (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Image</span>
    <span class="hljs-attr">src</span>=<span class="hljs-string">"./probablynothing.png"</span>
    <span class="hljs-attr">rounded</span>=<span class="hljs-string">"full"</span>
    <span class="hljs-attr">width</span>=<span class="hljs-string">"42%"</span>
    <span class="hljs-attr">mt</span>=<span class="hljs-string">"5"</span>
    <span class="hljs-attr">maxW</span>=<span class="hljs-string">"300px"</span>
    <span class="hljs-attr">alt</span>=<span class="hljs-string">"probably nothing"</span>
  /&gt;</span></span>
) : <span class="hljs-literal">null</span>}
&lt;br /&gt;
</code></pre>
<h3 id="heading-indextsx-review"><code>index.tsx</code> review</h3>
<p>Your <code>index.tsx</code> should now look very similar like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> type { NextPage } <span class="hljs-keyword">from</span> <span class="hljs-string">"next"</span>;
<span class="hljs-keyword">import</span> Head <span class="hljs-keyword">from</span> <span class="hljs-string">"next/head"</span>;
<span class="hljs-keyword">import</span> styles <span class="hljs-keyword">from</span> <span class="hljs-string">"../styles/Home.module.css"</span>;
<span class="hljs-keyword">import</span> { ConnectButton } <span class="hljs-keyword">from</span> <span class="hljs-string">"@rainbow-me/rainbowkit"</span>;
<span class="hljs-keyword">import</span> { Heading, Button, Image } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;
<span class="hljs-keyword">import</span> { useEditionDrop, useClaimNFT } <span class="hljs-keyword">from</span> <span class="hljs-string">"@thirdweb-dev/react"</span>;
<span class="hljs-keyword">import</span> { useAccount } <span class="hljs-keyword">from</span> <span class="hljs-string">"wagmi"</span>;

<span class="hljs-keyword">const</span> Home: NextPage = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { address } = useAccount();
  <span class="hljs-keyword">const</span> editionDrop = useEditionDrop(
    <span class="hljs-string">"0xc321cB91524f3C7fcD9e9333D71b644957852Fd2"</span>
  );
  <span class="hljs-keyword">const</span> { <span class="hljs-attr">mutate</span>: claimNft, isLoading, error } = useClaimNFT(editionDrop);
  <span class="hljs-keyword">if</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"failed to claim nft"</span>, error);
  }
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.container}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>thirdweb + RainbowKit + Ankr Edition Drop<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Generated by create next app"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/favicon.ico"</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Head</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.main}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Heading</span> <span class="hljs-attr">size</span>=<span class="hljs-string">"xl"</span> <span class="hljs-attr">textAlign</span>=<span class="hljs-string">"center"</span> <span class="hljs-attr">pb</span>=<span class="hljs-string">"3"</span>&gt;</span>
          gm
        <span class="hljs-tag">&lt;/<span class="hljs-name">Heading</span>&gt;</span>
        {!address ? (
          <span class="hljs-tag">&lt;<span class="hljs-name">Image</span>
            <span class="hljs-attr">src</span>=<span class="hljs-string">"./probablynothing.png"</span>
            <span class="hljs-attr">rounded</span>=<span class="hljs-string">"full"</span>
            <span class="hljs-attr">width</span>=<span class="hljs-string">"42%"</span>
            <span class="hljs-attr">mt</span>=<span class="hljs-string">"5"</span>
            <span class="hljs-attr">maxW</span>=<span class="hljs-string">"300px"</span>
            <span class="hljs-attr">alt</span>=<span class="hljs-string">"probably nothing"</span>
          /&gt;</span>
        ) : null}
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ConnectButton</span> /&gt;</span>
        {address ? (
          <span class="hljs-tag">&lt;&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Image</span>
              <span class="hljs-attr">src</span>=<span class="hljs-string">"./probablynothing.png"</span>
              <span class="hljs-attr">rounded</span>=<span class="hljs-string">"2xl"</span>
              <span class="hljs-attr">width</span>=<span class="hljs-string">"42%"</span>
              <span class="hljs-attr">maxW</span>=<span class="hljs-string">"300px"</span>
              <span class="hljs-attr">mt</span>=<span class="hljs-string">"5"</span>
              <span class="hljs-attr">mb</span>=<span class="hljs-string">"3"</span>
              <span class="hljs-attr">alt</span>=<span class="hljs-string">"probably nothing"</span>
            /&gt;</span>
            {/* <span class="hljs-tag">&lt;<span class="hljs-name">Text</span>&gt;</span>0 out of ∞ Minted<span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span> */}
            {isLoading ? (
              <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
                <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"purple"</span>
                <span class="hljs-attr">disabled</span>=<span class="hljs-string">{isLoading}</span>
                <span class="hljs-attr">isLoading</span>
                <span class="hljs-attr">loadingText</span>=<span class="hljs-string">"minting..."</span>
                <span class="hljs-attr">spinnerPlacement</span>=<span class="hljs-string">"start"</span>
                <span class="hljs-attr">_hover</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">transform:</span> "<span class="hljs-attr">scale</span>(<span class="hljs-attr">1.1</span>)" }}
                <span class="hljs-attr">size</span>=<span class="hljs-string">"lg"</span>
                <span class="hljs-attr">my</span>=<span class="hljs-string">"3"</span>
              /&gt;</span>
            ) : (
              <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
                <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"purple"</span>
                <span class="hljs-attr">disabled</span>=<span class="hljs-string">{isLoading}</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                  claimNft({ to: address as any, tokenId: 0, quantity: 1 })
                }
                _hover={{ transform: "scale(1.1)" }}
                size="lg"
                my="3"
              &gt;
                claim probably nothing!
              <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
            )}
            <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
              <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"blue"</span>
              <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                window.open(
                  "<span class="hljs-tag">&lt;<span class="hljs-name">https:</span>//<span class="hljs-attr">testnets.opensea.io</span>/<span class="hljs-attr">assets</span>/<span class="hljs-attr">goerli</span>/<span class="hljs-attr">0xc321cB91524f3C7fcD9e9333D71b644957852Fd2</span>/<span class="hljs-attr">0</span>&gt;</span>",
                  "_blank"
                )
              }
            &gt;
              view on opensea
            <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
          <span class="hljs-tag">&lt;/&gt;</span>
        ) : null}
      <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">footer</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.footer}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span>
          <span class="hljs-attr">href</span>=<span class="hljs-string">"&lt;https://vercel.com?utm_source=create-next-app&amp;utm_medium=default-template&amp;utm_campaign=create-next-app&gt;"</span>
          <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>
          <span class="hljs-attr">rel</span>=<span class="hljs-string">"noopener noreferrer"</span>
        &gt;</span>
          Powered by Vercel
        <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>Beautiful!</p>
<p>Here, you can go and test out the mint functionality and play around the code to add more functionalities.</p>
]]></content:encoded></item><item><title><![CDATA[Fetch the list of cryptocurrencies launched on a particular Blockchain using Ankr’s Token API]]></title><description><![CDATA[In this tutorial, we’ll be fetching the list of cryptocurrencies launched on a particular Blockchain using Ankr's Advanced Multichain Token API↗.
Refresher on Ankr Advanced APIs
Ankr's Advanced Multichain APIs are the collection of RPC methods create...]]></description><link>https://ankr.hashnode.dev/fetch-the-list-of-cryptocurrencies-launched-on-a-particular-blockchain-using-ankrs-token-api</link><guid isPermaLink="true">https://ankr.hashnode.dev/fetch-the-list-of-cryptocurrencies-launched-on-a-particular-blockchain-using-ankrs-token-api</guid><category><![CDATA[Ankr]]></category><category><![CDATA[ankrjs]]></category><category><![CDATA[token]]></category><dc:creator><![CDATA[Krinza Momin]]></dc:creator><pubDate>Mon, 28 Nov 2022 10:21:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1669631827916/2o9Z5uFZH.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this tutorial, we’ll be fetching the list of cryptocurrencies launched on a particular Blockchain using <a target="_blank" href="https://www.ankr.com/advanced-api/">Ankr's Advanced Multichain Token API</a>↗.</p>
<h2 id="heading-refresher-on-ankr-advanced-apis">Refresher on Ankr Advanced APIs</h2>
<p>Ankr's Advanced Multichain APIs are the collection of RPC methods created to simplify querying blockchain data. These APIs do all the heavy lifting for us so that we can query on-chain data in a matter of seconds.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661806349664/xo9fUHHO_.avif" alt="1xRkkFGFz.avif" /></p>
<p>Currently, it supports eight EVM-compatible chains: Ethereum, Fantom, Binance Smart Chain, Polygon, Avalanche, Arbitrum, with more EVM and non-EVM chains coming soon. To interact with Ankr's Advanced APIs, we are going to use a JavaScript library named <a target="_blank" href="https://www.npmjs.com/package/@ankr.com/ankr.js">Ankr.js</a>↗.</p>
<hr />
<h2 id="heading-getting-started">Getting Started</h2>
<p><strong>Prerequisite:</strong> To successfully finish this guide, you'll need <a target="_blank" href="https://nodejs.org/en/">Node.js</a>↗ and <a target="_blank" href="https://yarnpkg.com/">Yarn</a>↗ installed on your machine.</p>
<h3 id="heading-step-1-setting-up-nextjs-starter-application">Step 1: Setting Up Next.js Starter Application</h3>
<p>First up, navigate into the directory of your choice where you want to initiate this project and run the following command in your terminal to set up a new Next.js starter page:</p>
<pre><code>yarn create next-app --ts ankrjs-cryptolist
</code></pre><p>You'll be able to see a couple of files and folders being created for you. Let's dive into the newly created directory and start the development server on localhost:3000.</p>
<pre><code>cd ankrjs-cryptolist
</code></pre><pre><code>yarn dev
</code></pre><p>Visit localhost:3000 to view the starter application and it will resemble the screen attached below: </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661070917881/oogwlMj1X.png" alt="screely-1661070904826.png" /></p>
<hr />
<h3 id="heading-step-2-installing-and-setting-up-ankrjs">Step 2: Installing and Setting Up Ankr.js</h3>
<p>In this section, we will install and set up Ankr.js for querying crypto tokens by blockchain.</p>
<p>We will start by installing the ankr.js package from npm:</p>
<pre><code>yarn add @ankr.com/ankr.js
</code></pre><p>Now that we have installed the Ankr.js library, let's set up Ankr.js by <strong>creating a new file</strong> named <code>apis.ts</code> at the root of your project directory. We will initialize Ankr.js in this file.</p>
<p><strong>File:</strong> <code>./apis.ts</code></p>
<pre><code><span class="hljs-keyword">import</span> AnkrscanProvider <span class="hljs-keyword">from</span> <span class="hljs-string">'@ankr.com/ankr.js'</span>;
<span class="hljs-keyword">import</span> type { Blockchain } <span class="hljs-keyword">from</span> <span class="hljs-string">'@ankr.com/ankr.js/dist/types'</span>;

<span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> AnkrscanProvider(<span class="hljs-string">''</span>);
</code></pre><p>To interact with Ankr's Advanced APIs, we have created a provider instance that will serve as an interface to the APIs required to fetch data.</p>
<hr />
<h3 id="heading-step-3-create-function-to-fetch-cryptocurrencies">Step 3: Create Function to Fetch Cryptocurrencies</h3>
<p>In this step, we will first create a <code>getCurrencies</code> function in the <code>./apis.ts</code> file, which will accept the <code>blockchain</code>, and return us the list of cryptocurrencies and the respective details about each token. Here we are going to use the <a target="_blank" href="https://documenter.getpostman.com/view/19024547/UVsEVUGQ#a19d176a-a87f-4bac-a406-e424758515ee">getCurrencies</a>↗ method provided by Ankr.js. </p>
<p>File: <code>./apis.ts</code></p>
<pre><code><span class="hljs-keyword">import</span> AnkrscanProvider <span class="hljs-keyword">from</span> <span class="hljs-string">'@ankr.com/ankr.js'</span>;
<span class="hljs-keyword">import</span> type { Blockchain } <span class="hljs-keyword">from</span> <span class="hljs-string">'@ankr.com/ankr.js/dist/types'</span>;

<span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> AnkrscanProvider(<span class="hljs-string">''</span>);

<span class="hljs-comment">//defining the list of supported blockchains</span>
<span class="hljs-keyword">const</span> listOfChains: Blockchain[] = [<span class="hljs-string">'eth'</span>, <span class="hljs-string">'arbitrum'</span>, <span class="hljs-string">'avalanche'</span>, 
<span class="hljs-string">'bsc'</span>, <span class="hljs-string">'fantom'</span>, <span class="hljs-string">'polygon'</span>, <span class="hljs-string">'syscoin'</span>, <span class="hljs-string">'optimism'</span>,];

<span class="hljs-comment">//key-value pair mapping of chains to their native symbols</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> chainsToNativeSymbols: { [key <span class="hljs-keyword">in</span> Blockchain]: string } = {
  <span class="hljs-attr">eth</span>: <span class="hljs-string">'ETH'</span>,
  <span class="hljs-attr">arbitrum</span>: <span class="hljs-string">'ETH'</span>,
  <span class="hljs-attr">avalanche</span>: <span class="hljs-string">'AVAX'</span>,
  <span class="hljs-attr">bsc</span>: <span class="hljs-string">'BNB'</span>,
  <span class="hljs-attr">fantom</span>: <span class="hljs-string">'FTM'</span>,
  <span class="hljs-attr">polygon</span>: <span class="hljs-string">'MATIC'</span>,
  <span class="hljs-attr">syscoin</span>: <span class="hljs-string">'SYS'</span>,
  <span class="hljs-attr">optimism</span>: <span class="hljs-string">'Opt'</span>,
};

<span class="hljs-comment">//getCurrencies function</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getCurrencies = <span class="hljs-keyword">async</span> (

  blockchain: Blockchain
) =&gt; {
  <span class="hljs-keyword">return</span> provider.getCurrencies({

    blockchain,
  });
};
</code></pre><p>Let's call this function on our page i.e. <code>./pages/index.tsx</code> to check the list. To do so, clear the code from the <strong>index.tsx</strong> file and replace it with the one given below:</p>
<p><strong>File:</strong> <code>./pages/index.tsx</code></p>
<pre><code><span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">import</span> {
  getCurrencies,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'../apis'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{

  useEffect(<span class="hljs-function">() =&gt;</span> {
    (<span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">const</span>  total  = <span class="hljs-keyword">await</span> getCurrencies(
        <span class="hljs-string">"eth"</span>
      );
      <span class="hljs-built_in">console</span>.log({ total });
    })();
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'p-10 flex flex-col items-center'</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'text-3xl font-bold'</span>&gt;</span>Cryptolist<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre><p>Now, let's see the fetched list of cryptocurrencies of an inputted blockchain in the developer console of a browser. </p>
<ul>
<li>Head over to your localhost and use <code>Option + ⌘ + J</code> (on macOS), or <code>Shift + CTRL + J</code> (on Windows/Linux). </li>
</ul>
<p>You should be able to see the list of cryptocurrencies with their contract addresses, name, symbol and thumbnail. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669636835380/6IsuHN9F8.png" alt="screely-1669636801142.png" /></p>
<h2 id="heading-github-repo">Github Repo</h2>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/kaymomin/ankrjs-cryptolist">https://github.com/kaymomin/ankrjs-cryptolist</a></div>
]]></content:encoded></item><item><title><![CDATA[How to check your Account Balance across Multiple Blockchains using Ankrjs]]></title><description><![CDATA[In this tutorial, we’ll be fetching the account balances from multiple blockchains such as Ethereum, Polygon, and Fantom, to name a few, using Ankr's Advanced Multichain APIs↗.

Refresher on Ankr Advanced APIs
Ankr's Advanced Multichain APIs are the ...]]></description><link>https://ankr.hashnode.dev/how-to-check-your-account-balance-across-multiple-blockchains-using-ankrjs</link><guid isPermaLink="true">https://ankr.hashnode.dev/how-to-check-your-account-balance-across-multiple-blockchains-using-ankrjs</guid><category><![CDATA[Ankr]]></category><category><![CDATA[ankrjs]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[APIs]]></category><dc:creator><![CDATA[Krinza Momin]]></dc:creator><pubDate>Tue, 30 Aug 2022 10:44:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1661853389484/2UIVgKkfo.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this tutorial, we’ll be fetching the account balances from multiple blockchains such as Ethereum, Polygon, and Fantom, to name a few, using <a target="_blank" href="https://www.ankr.com/advanced-api/">Ankr's Advanced Multichain APIs</a>↗.</p>
<p></p><details><p></p>
<p><summary>Refresher on Ankr Advanced APIs</summary>
Ankr's Advanced Multichain APIs are the collection of RPC methods created to simplify querying blockchain data. These APIs do all the heavy lifting for us so that we can query on-chain data in a matter of seconds.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661806349664/xo9fUHHO_.avif" alt="1xRkkFGFz.avif" /></p>
<p>Currently, it supports six EVM compatible chains: Ethereum, Fantom, Binance Smart Chain, Polygon, Avalanche, Arbitrum, with more EVM and non-EVM chains coming soon. To interact with Ankr's Advanced APIs, we are going to use a JavaScript library named <a target="_blank" href="https://www.npmjs.com/package/@ankr.com/ankr.js">Ankr.js</a>↗.
</p></details>
<br /><p></p>
<h2 id="heading-getting-started">Getting Started</h2>
<p><strong>Prerequisite:</strong> To successfully finish this guide, you'll need <a target="_blank" href="https://nodejs.org/en/">Node.js</a>↗ and <a target="_blank" href="https://yarnpkg.com/">Yarn</a>↗ installed on your machine.</p>
<h3 id="heading-step-1-setting-up-nextjs-starter-application">Step 1: Setting Up Next.js Starter Application</h3>
<p>First up, navigate into the directory of your choice where you want to initiate this project and run the following command in your terminal to set up a new Next.js starter page:</p>
<pre><code>yarn create next<span class="hljs-operator">-</span>app <span class="hljs-operator">-</span><span class="hljs-operator">-</span>ts ankrjs<span class="hljs-operator">-</span>account<span class="hljs-operator">-</span>balance
</code></pre><p>You'll be able to see a couple of files and folders being created for you. Let's dive into the newly created directory and start the development server on localhost:3000.</p>
<pre><code>cd ankrjs<span class="hljs-operator">-</span>account<span class="hljs-operator">-</span>balance
</code></pre><pre><code><span class="hljs-attribute">yarn</span> dev
</code></pre><p>Visit localhost:3000 to view the starter application and it will resemble the screen attached below: </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661070917881/oogwlMj1X.png" alt="screely-1661070904826.png" /></p>
<hr />
<h3 id="heading-step-2-installing-and-setting-up-ankrjs">Step 2: Installing and Setting Up Ankr.js</h3>
<p>In this section, we will install and set up Ankr.js for querying account balances across multichains.</p>
<p>We will start by installing the ankr.js package from npm:</p>
<pre><code><span class="hljs-attribute">yarn</span> add <span class="hljs-variable">@ankr</span>.com/ankr.js
</code></pre><p>Now that we have installed the Ankr.js library, let's set up Ankr.js by <strong>creating a new file</strong> named <code>apis.ts</code> at the root of your project directory. We will initialize Ankr.js in this file.</p>
<p><strong>File:</strong> <code>./apis.ts</code></p>
<pre><code><span class="hljs-keyword">import</span> <span class="hljs-title">AnkrscanProvider</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'@ankr.com/ankr.js'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title"><span class="hljs-keyword">type</span></span> { <span class="hljs-title">Blockchain</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'@ankr.com/ankr.js/dist/types'</span>;

const provider <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> AnkrscanProvider(<span class="hljs-string">''</span>);
</code></pre><p>To interact with Ankr's Advanced APIs, we have created a provider instance that will serve as an interface to the APIs required to fetch data.</p>
<hr />
<h3 id="heading-step-3-create-function-to-fetch-total-balance">Step 3: Create Function to Fetch Total Balance</h3>
<p>In this step, we will first create a <code>getAccountBalance</code> function in the <code>./apis.ts</code> file, which will accept a <code>walletAddress</code>, and return the coin and the respective token balance. Here we are going to utilize the <a target="_blank" href="https://documenter.getpostman.com/view/19024547/UVsEVUGQ#74b5cc68-fba2-415c-a53b-28c08818f970">getAccountBalance</a>↗ method provided by Ankr.js. </p>
<p>File: <code>./apis.ts</code></p>
<pre><code><span class="hljs-keyword">import</span> <span class="hljs-title">AnkrscanProvider</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'@ankr.com/ankr.js'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title"><span class="hljs-keyword">type</span></span> { <span class="hljs-title">Blockchain</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'@ankr.com/ankr.js/dist/types'</span>;

const provider <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> AnkrscanProvider(<span class="hljs-string">''</span>);

<span class="hljs-comment">//defining the list of supported blockchains</span>
const listOfChains: Blockchain[] <span class="hljs-operator">=</span> [<span class="hljs-string">'eth'</span>, <span class="hljs-string">'arbitrum'</span>, <span class="hljs-string">'avalanche'</span>, 
<span class="hljs-string">'bsc'</span>, <span class="hljs-string">'fantom'</span>, <span class="hljs-string">'polygon'</span>, ];

<span class="hljs-comment">//key-value pair mapping of chains to their native symbols</span>
export const chainsToNativeSymbols: { [key in Blockchain]: <span class="hljs-keyword">string</span> } <span class="hljs-operator">=</span> {
  eth: <span class="hljs-string">'ETH'</span>,
  arbitrum: <span class="hljs-string">'ETH'</span>,
  avalanche: <span class="hljs-string">'AVAX'</span>,
  bsc: <span class="hljs-string">'BNB'</span>,
  fantom: <span class="hljs-string">'FTM'</span>,
  polygon: <span class="hljs-string">'MATIC'</span>,
};

<span class="hljs-comment">//getAccountBalance function to fetch coins and their respective token balances</span>
export const getAccountBalance <span class="hljs-operator">=</span> async (walletAddress: <span class="hljs-keyword">string</span>) <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> {
  <span class="hljs-keyword">return</span> provider.getAccountBalance({
    walletAddress,
  });
};
</code></pre><p>Let's call this function on our page i.e. <code>./pages/index.tsx</code> to check the account balances. To do so, clear the code from the <strong>index.tsx</strong> file and replace it with the one given below:</p>
<p><strong>File:</strong> <code>./pages/index.tsx</code></p>
<pre><code><span class="hljs-keyword">import</span> { <span class="hljs-title">useEffect</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">import</span> {
  <span class="hljs-title">getAccountBalance</span>,
} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'../apis'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{

  useEffect(() <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> {
    (async () <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> {
      const  total  <span class="hljs-operator">=</span> await getAccountBalance(
        <span class="hljs-string">"0xd8da6bf26964af9d7eed9e03e53415d37aa96045"</span>,
      );
      console.log({ total });
    })();
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">'p-10 flex flex-col items-center'</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>h1 className<span class="hljs-operator">=</span><span class="hljs-string">'text-3xl font-bold'</span><span class="hljs-operator">&gt;</span>Account Balance<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>h1<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
  );
}

export default App;
</code></pre><p>Now, let's see the Account Balances of an inputted wallet address in the developer console of a browser. </p>
<ul>
<li>Head over to your localhost and use <code>Option + ⌘ + J</code> (on macOS), or <code>Shift + CTRL + J</code> (on Windows/Linux). </li>
</ul>
<p>You should be able to see the list of chains with their respective tokens and account balances. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661851200487/CwOyNGqN6.png" alt="screely-1661851076829.png" /></p>
<hr />
<h3 id="heading-optional-calculating-the-net-worth">[Optional]: Calculating the Net Worth</h3>
<p>To calculate the sum of balances (net worth) across the chains we will create a new function in the <code>apis.ts</code> file and let's call it <strong>getTotalMultichainBalance</strong>.</p>
<p>File: <code>./apis.ts</code></p>
<pre><code><span class="hljs-keyword">import</span> <span class="hljs-title">AnkrscanProvider</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'@ankr.com/ankr.js'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title"><span class="hljs-keyword">type</span></span> { <span class="hljs-title">Blockchain</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'@ankr.com/ankr.js/dist/types'</span>;

const provider <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> AnkrscanProvider(<span class="hljs-string">''</span>);

<span class="hljs-comment">//defining the list of supported blockchains</span>
const listOfChains: Blockchain[] <span class="hljs-operator">=</span> [<span class="hljs-string">'eth'</span>, <span class="hljs-string">'arbitrum'</span>, <span class="hljs-string">'avalanche'</span>, 
<span class="hljs-string">'bsc'</span>, <span class="hljs-string">'fantom'</span>, <span class="hljs-string">'polygon'</span>, ];

<span class="hljs-comment">//key-value pair mapping of chains to their native symbols</span>
export const chainsToNativeSymbols: { [key in Blockchain]: <span class="hljs-keyword">string</span> } <span class="hljs-operator">=</span> {
  eth: <span class="hljs-string">'ETH'</span>,
  arbitrum: <span class="hljs-string">'ETH'</span>,
  avalanche: <span class="hljs-string">'AVAX'</span>,
  bsc: <span class="hljs-string">'BNB'</span>,
  fantom: <span class="hljs-string">'FTM'</span>,
  polygon: <span class="hljs-string">'MATIC'</span>,
};

<span class="hljs-comment">//getAccountBalance function to fetch coins and their respective token balances</span>
export const getAccountBalance <span class="hljs-operator">=</span> async (
  walletAddress: <span class="hljs-keyword">string</span>,
  blockchain: Blockchain
) <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> {
  <span class="hljs-keyword">return</span> provider.getAccountBalance({
    walletAddress,
    blockchain,
  });
};

<span class="hljs-comment">//use getAccountBalance to sum total balance across chains</span>
export const getTotalMultichainBalance <span class="hljs-operator">=</span> async (walletAddress: <span class="hljs-keyword">string</span>) <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> {
  let total <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
  <span class="hljs-keyword">for</span> await (const chain of listOfChains) {
    const { totalBalanceUsd, assets } <span class="hljs-operator">=</span> await getAccountBalance(
      walletAddress,
      chain
    );
    total <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-operator">+</span>totalBalanceUsd;
  }
  <span class="hljs-keyword">return</span> total;
};
</code></pre><p>Let's call this function on our page to check the total account balance. </p>
<p><strong>File:</strong> <code>./pages/index.tsx</code></p>
<pre><code><span class="hljs-keyword">import</span> { <span class="hljs-title">useEffect</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">import</span> {
  <span class="hljs-title">getTotalMultichainBalance</span>,
} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'../apis'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{

  useEffect(() <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> {
    (async () <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> {
      const  total  <span class="hljs-operator">=</span> await getTotalMultichainBalance(
        <span class="hljs-string">"0xd8da6bf26964af9d7eed9e03e53415d37aa96045"</span>
      );
      console.log({ total });
    })();
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">'p-10 flex flex-col items-center'</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>h1 className<span class="hljs-operator">=</span><span class="hljs-string">'text-3xl font-bold'</span><span class="hljs-operator">&gt;</span>Net Worth<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>h1<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
  );
}

export default App;
</code></pre><p>Let's see the net worth of an inputted wallet address in the developer console of a browser.</p>
<p>Head over to your localhost and use Option + ⌘ + J (on macOS), or Shift + CTRL + J (on Windows/Linux).</p>
<p>You should be able to see the net worth.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661851640868/Rk0tBZCxs.png" alt="screely-1661851609629.png" /></p>
<hr />
<h3 id="heading-github-repo">GitHub Repo</h3>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/kaymomin/ankrjs-account-balance">https://github.com/kaymomin/ankrjs-account-balance</a></div>
<p>You can also extend what you just learned here into building a <a target="_blank" href="https://ankr.hashnode.dev/create-a-whats-in-your-wallet-dapp-using-ankrs-multichain-advanced-apis">Multichain DeFi Board.</a>↗</p>
]]></content:encoded></item><item><title><![CDATA[How to fetch all NFTs owned by a particular Wallet Address using Ankrjs]]></title><description><![CDATA[In this tutorial, we’ll be fetching all the NFTs owned by a particular wallet or owner across multiple blockchains such as Ethereum, Polygon, and Fantom, to name a few, using Ankr's Advanced Multichain APIs↗.
Ankr Advanced APIs
Ankr's Advanced Multic...]]></description><link>https://ankr.hashnode.dev/how-to-fetch-all-nfts-owned-by-a-particular-wallet-address-using-ankrjs</link><guid isPermaLink="true">https://ankr.hashnode.dev/how-to-fetch-all-nfts-owned-by-a-particular-wallet-address-using-ankrjs</guid><category><![CDATA[Ankr]]></category><category><![CDATA[ankrjs]]></category><category><![CDATA[Web3]]></category><category><![CDATA[APIs]]></category><category><![CDATA[Blockchain]]></category><dc:creator><![CDATA[Krinza Momin]]></dc:creator><pubDate>Mon, 29 Aug 2022 09:53:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1661799187895/HYg8ZA2rP.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this tutorial, we’ll be fetching all the NFTs owned by a particular wallet or owner across multiple blockchains such as Ethereum, Polygon, and Fantom, to name a few, using <a target="_blank" href="https://www.ankr.com/advanced-api/">Ankr's Advanced Multichain APIs</a>↗.</p>
<h3 id="heading-ankr-advanced-apis">Ankr Advanced APIs</h3>
<p>Ankr's Advanced Multichain APIs are the collection of RPC methods created to simplify querying blockchain data. These APIs do all the heavy lifting for us so that we can query on-chain data in a matter of seconds. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660735043632/1xRkkFGFz.png" alt="image.png" /></p>
<p>Currently, it supports six EVM compatible chains: Ethereum, Fantom, Binance Smart Chain, Polygon, Avalanche, Arbitrum, with more EVM and non-EVM chains coming soon. To interact with Ankr's Advanced APIs, we are going to use a JavaScript library named <a target="_blank" href="https://www.npmjs.com/package/@ankr.com/ankr.js">Ankr.js</a>↗.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1660735100094/EKMDJ0uOr.png" alt="image.png" /></p>
<hr />
<h2 id="heading-getting-started">Getting Started</h2>
<p><strong>Prerequisite:</strong> To successfully finish this guide, you'll need <a target="_blank" href="https://nodejs.org/en/">Node.js</a>↗ and <a target="_blank" href="https://yarnpkg.com/">Yarn</a>↗ installed on your machine.</p>
<h3 id="heading-step-1-setting-up-nextjs-starter-application">Step 1: Setting Up Next.js Starter Application</h3>
<p>First up, navigate into the directory of your choice where you want to initiate this project and run the following command in your terminal to set up a new Next.js starter page:</p>
<pre><code>yarn create next<span class="hljs-operator">-</span>app <span class="hljs-operator">-</span><span class="hljs-operator">-</span>ts ankrjs<span class="hljs-operator">-</span>fetch<span class="hljs-operator">-</span>nfts
</code></pre><p>You'll be able to see a couple of files and folders being created for you. Let's dive into the newly created directory and start the development server on localhost:3000.</p>
<pre><code>cd ankrjs<span class="hljs-operator">-</span>fetch<span class="hljs-operator">-</span>nfts
</code></pre><pre><code><span class="hljs-attribute">yarn</span> dev
</code></pre><p>Visit localhost:3000 to view the starter application and it will resemble the screen attached below: </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661070917881/oogwlMj1X.png" alt="screely-1661070904826.png" /></p>
<hr />
<h3 id="heading-step-2-installing-and-setting-up-ankrjs">Step 2: Installing and Setting Up Ankr.js</h3>
<p>In this section, we will install and set up Ankr.js for querying NFT data from the blockchain for a given wallet address.</p>
<p>We will start by installing the ankr.js package from npm:</p>
<pre><code><span class="hljs-attribute">yarn</span> add <span class="hljs-variable">@ankr</span>.com/ankr.js
</code></pre><p>Now that we have installed the Ankr.js library, let's set up Ankr.js by <strong>creating a new file</strong> named <code>apis.ts</code> at the root of your project directory. We will initialize Ankr.js in this file.</p>
<p><strong>File:</strong> <code>./apis.ts</code></p>
<pre><code><span class="hljs-keyword">import</span> <span class="hljs-title">AnkrscanProvider</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'@ankr.com/ankr.js'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title"><span class="hljs-keyword">type</span></span> { <span class="hljs-title">Blockchain</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'@ankr.com/ankr.js/dist/types'</span>;

const provider <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> AnkrscanProvider(<span class="hljs-string">''</span>);
</code></pre><p>To interact with Ankr's Advanced APIs, we have created a provider instance that will serve as an interface to the APIs required to fetch data.</p>
<hr />
<h3 id="heading-step-3-create-getnfts-function">Step 3: Create getNFTs Function</h3>
<p>In this step, you will create a <code>getNfts</code> function that accepts a <code>walletAddress</code> and returns a list of NFTs owned by that address.</p>
<p>Here, we are going to utilize the <code>getNFTsByOwner</code> function provided by Ankr.js for this.</p>
<p>File: <code>./apis.ts</code></p>
<pre><code><span class="hljs-keyword">import</span> <span class="hljs-title">AnkrscanProvider</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'@ankr.com/ankr.js'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title"><span class="hljs-keyword">type</span></span> { <span class="hljs-title">Blockchain</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'@ankr.com/ankr.js/dist/types'</span>;

const provider <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> AnkrscanProvider(<span class="hljs-string">''</span>);

export const getNfts <span class="hljs-operator">=</span> async (<span class="hljs-keyword">address</span>: <span class="hljs-keyword">string</span>) <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> {
  const { assets } <span class="hljs-operator">=</span> await provider.getNFTsByOwner({
    walletAddress: <span class="hljs-keyword">address</span>,
    blockchain: <span class="hljs-string">'eth'</span>,
  });
  <span class="hljs-keyword">return</span> {
    nfts: assets,
  };
};
</code></pre><p>And that's it. </p>
<p>Let's call this function on our page i.e. <code>./pages/index.tsx</code> to see the fetched NFTs by the owner's wallet address and log the output. To do so, clear the code from the <strong>index.tsx</strong> file and replace it with the one given below:</p>
<p><strong>File:</strong> <code>./pages/index.tsx</code></p>
<pre><code><span class="hljs-keyword">import</span> <span class="hljs-title"><span class="hljs-keyword">type</span></span> { <span class="hljs-title">NextPage</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'next'</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">useEffect</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">getNfts</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'../apis'</span>;

const Home: NextPage <span class="hljs-operator">=</span> () <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> {
  useEffect(() <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> {
    (async () <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> {
      const { nfts } <span class="hljs-operator">=</span> await getNfts(
        <span class="hljs-string">'0xd8da6bf26964af9d7eed9e03e53415d37aa96045'</span>
      );
      console.log({ nfts });
    })();
  }, []);

  <span class="hljs-keyword">return</span> (
  <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">'p-10 flex flex-col items-center'</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>h1 className<span class="hljs-operator">=</span><span class="hljs-string">'text-3xl font-bold'</span><span class="hljs-operator">&gt;</span>NFTs<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>h1<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
  );
};

export default Home;
</code></pre><p>Now, let's see the NFT logs of an inputted wallet address in the developer console of a browser. </p>
<ul>
<li>Head over to your localhost and use <code>Option + ⌘ + J</code> (on macOS), or <code>Shift + CTRL + J</code> (on Windows/Linux). </li>
</ul>
<p>You should be able to see the list of NFTs owned by a particular address. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661078471145/Y_QwhWNmD.png" alt="screely-1661078460144.png" /></p>
<p>You can also extend the toggle to dive into the details of the NFTs held by the owner. Details include: <code>blockchain</code>, <code>collectionName</code>, <code>contractAddress</code>, <code>contractType</code>, <code>imageUrl</code>, <code>name</code>, <code>symbol</code>, <code>tokenId</code> and <code>tokenUrl</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1661078864873/0SAmvt0JN.png" alt="screely-1661078840436.png" /></p>
<h3 id="heading-github-repo">GitHub Repo</h3>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/kaymomin/ankrjs-fetch-nfts">https://github.com/kaymomin/ankrjs-fetch-nfts</a></div>
<p>You can also extend what you just learned here into building a <a target="_blank" href="https://ankr.hashnode.dev/ankrjs-advanced-apis-react-quickstart-guide">Multichain NFT Viewer.</a>↗</p>
]]></content:encoded></item><item><title><![CDATA[Ankr.js (Advanced APIs) Node.js Quickstart Guide]]></title><description><![CDATA[Ankr.js is a JavaScript library that lets you interact with Ankr's Advanced APIs. In this guide, you'll learn how to create a Node.js script that logs out a list of all the NFTs owned by an account and a given account's ERC20 token balances.

Node.js...]]></description><link>https://ankr.hashnode.dev/ankrjs-advanced-apis-nodejs-quickstart-guide</link><guid isPermaLink="true">https://ankr.hashnode.dev/ankrjs-advanced-apis-nodejs-quickstart-guide</guid><category><![CDATA[Web3]]></category><category><![CDATA[APIs]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[NFT]]></category><dc:creator><![CDATA[Dhaiwat Pandya]]></dc:creator><pubDate>Tue, 09 Aug 2022 14:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1660011276197/uAHkT3r0b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://github.com/ankr-network/ankr.js">Ankr.js</a> is a JavaScript library that lets you interact with <a target="_blank" href="https://ankr.com/advanced-api">Ankr's Advanced APIs</a>. In this guide, you'll learn how to create a Node.js script that logs out a list of all the NFTs owned by an account and a given account's ERC20 token balances.</p>
<ul>
<li><a target="_blank" href="https://nodejs.org/">Node.js</a> as our script runner</li>
<li><a target="_blank" href="https://github.com/ankr-network/ankr.js">Ankr.js</a> to interact with <a target="_blank" href="https://ankr.com/advanced-api">Ankr's Advanced APIs</a></li>
<li><a target="_blank" href="https://ankr.com/advanced-api">Ankr's Advanced APIs</a> as the data source</li>
</ul>
<p><img src="https://i.imgur.com/aBo1kI1.gif" alt="https://i.imgur.com/aBo1kI1.gif" /></p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To successfully finish this guide, you'll only need <a target="_blank" href="https://nodejs.org/">Node.js</a> and <a target="_blank" href="https://yarnpkg.com/">Yarn</a> installed on your machine.</p>
<h2 id="heading-step-1-set-up-your-nodejs-project">Step 1: Set Up Your Node.js Project</h2>
<p>Navigate into a directory of your choice and run the following commands in your terminal to set up a new Node.js project:</p>
<pre><code class="lang-bash">mkdir ankrjs-node-followalong &amp;&amp; <span class="hljs-built_in">cd</span> ankrjs-node-followalong; <span class="hljs-comment"># create and cd into our project directory</span>
mkdir src; <span class="hljs-comment"># where our source code will live</span>
yarn init -y; <span class="hljs-comment"># generates our package.json and yarn.lock files</span>
git init;
<span class="hljs-built_in">echo</span> <span class="hljs-string">"node_modules\\n.env\\nbuild\\n*.log"</span> &gt; .gitignore;
yarn add -D typescript ts-node @types/node;
yarn add prompts; <span class="hljs-comment"># library to help us accept inputs from the terminal</span>
./node_modules/.bin/tsc --init; <span class="hljs-comment"># generates our tsconfig.json file</span>
</code></pre>
<p>Now, create a new file named <code>app.ts</code> inside of your <code>src</code> folder.</p>
<p><strong>File:</strong> <code>./src/app.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> main = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// this function contains the code that be executed when you run your script</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Hello world!'</span>);
};

main();
</code></pre>
<p>Next, go into your <code>package.json</code> file and add a <code>dev</code> script that will let you run your code.</p>
<p><strong>File:</strong> <code>./package.json</code></p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"ankrjs-node-tutorial"</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
  <span class="hljs-attr">"main"</span>: <span class="hljs-string">"index.js"</span>,
  <span class="hljs-attr">"author"</span>: <span class="hljs-string">"Dhaiwat Pandya"</span>,
  <span class="hljs-attr">"license"</span>: <span class="hljs-string">"MIT"</span>,
  <span class="hljs-attr">"dependencies"</span>: {
    <span class="hljs-attr">"prompts"</span>: <span class="hljs-string">"^2.4.2"</span>
  },
  <span class="hljs-attr">"devDependencies"</span>: {
    <span class="hljs-attr">"@types/node"</span>: <span class="hljs-string">"^18.0.3"</span>,
    <span class="hljs-attr">"ts-node"</span>: <span class="hljs-string">"^10.8.2"</span>,
    <span class="hljs-attr">"typescript"</span>: <span class="hljs-string">"^4.7.4"</span>
  },
+  <span class="hljs-attr">"scripts"</span>: {
+    <span class="hljs-attr">"dev"</span>: <span class="hljs-string">"ts-node src/app.ts"</span>
+  }
}
</code></pre>
<p>You can now run your script from the root of your project:</p>
<pre><code class="lang-bash">yarn dev
</code></pre>
<p><img src="https://i.imgur.com/zlQ06TW.png" alt="https://i.imgur.com/zlQ06TW.png" /></p>
<h2 id="heading-step-2-install-and-set-up-ankrjs">Step 2: Install And Set Up Ankr.js</h2>
<p>Next, you will install and set up Ankr.js so that you can use it to fetch all the NFTs and tokens for a given wallet address later on.</p>
<p>Start by installing the <code>ankr.js</code> package from npm:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># /ankrjs-node-followalong</span>
yarn add @ankr.com/ankr.js
</code></pre>
<p><img src="https://i.imgur.com/hZVlpII.jpg" alt="https://i.imgur.com/hZVlpII.jpg" /></p>
<p>Next, create a new file named <code>utils.ts</code> inside the <code>src</code> directory. You will initialize Ankr.js in this file.</p>
<p><strong>File:</strong> <code>./src/utils.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> AnkrscanProvider <span class="hljs-keyword">from</span> <span class="hljs-string">'@ankr.com/ankr.js'</span>;

<span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> AnkrscanProvider(<span class="hljs-string">''</span>);
</code></pre>
<p>Your <code>provider</code> instance will be your interface to the Ankr Advanced APIs whenever you want to fetch some data from them.</p>
<h2 id="heading-step-3-create-the-getnfts-function">Step 3: Create The <code>getNFTs</code> Function</h2>
<p>In this step, you will create a <code>getNFTs</code> function that accepts a <code>walletAddress</code> and returns a list of NFTs owned by that address.</p>
<p>You can utilize the <code>getNFTsByOwner</code> function provided by Ankr.js for this.</p>
<p><strong>File:</strong> <code>./src/utils.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> AnkrscanProvider <span class="hljs-keyword">from</span> <span class="hljs-string">'@ankr.com/ankr.js'</span>;

<span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> AnkrscanProvider(<span class="hljs-string">''</span>);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getNFTs = <span class="hljs-keyword">async</span> (walletAddress: <span class="hljs-built_in">string</span>) =&gt; {
  <span class="hljs-keyword">return</span> provider.getNFTsByOwner({
    walletAddress,
  });
};
</code></pre>
<p>Just to see if things are working, let's call this function from our main script i.e. <code>./src/app.ts</code> and log out the output.</p>
<p><strong>File:</strong> <code>./src/app.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { getNFTs } <span class="hljs-keyword">from</span> <span class="hljs-string">'./utils'</span>;

<span class="hljs-keyword">const</span> main = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-comment">// this function contains the code that be executed when you run your script</span>
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'NFTS ================='</span>);
  <span class="hljs-keyword">const</span> nfts = <span class="hljs-keyword">await</span> getNFTs(<span class="hljs-string">'0x0ED6Cec17F860fb54E21D154b49DAEFd9Ca04106'</span>);
  <span class="hljs-built_in">console</span>.log(nfts);
};

main();
</code></pre>
<p>You can now re-run your script using <code>yarn dev</code> and see a list of NFTs being logged out.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># /ankrjs-node-followalong</span>
yarn dev
</code></pre>
<p><img src="https://i.imgur.com/vCdcxcp.jpg" alt="https://i.imgur.com/vCdcxcp.jpg" /></p>
<h2 id="heading-step-4-accept-the-address-as-an-input">Step 4: Accept the address as an input</h2>
<p>At the moment, we are passing in a hard-coded address to the <code>getNFTs</code> function. You will now let the user pass in any address from their keyboard instead.</p>
<p>To achieve this, you can make use of the <code>prompts</code> package.</p>
<p><strong>File:</strong> <code>./src/app.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { getNFTs } <span class="hljs-keyword">from</span> <span class="hljs-string">'./utils'</span>;
<span class="hljs-keyword">const</span> prompts = <span class="hljs-built_in">require</span>(<span class="hljs-string">'prompts'</span>);

<span class="hljs-keyword">const</span> main = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-comment">// this function contains the code that be executed when you run your script</span>
  <span class="hljs-keyword">const</span> addressToQueryNFTsFor = <span class="hljs-keyword">await</span> prompts({
    <span class="hljs-keyword">type</span>: <span class="hljs-string">'text'</span>,
    name: <span class="hljs-string">'address'</span>,
    message: <span class="hljs-string">'Enter an address to query NFTs for'</span>,
  });
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'NFTS ================='</span>);
  <span class="hljs-keyword">const</span> nfts = <span class="hljs-keyword">await</span> getNFTs(addressToQueryNFTsFor.address);
  <span class="hljs-built_in">console</span>.log(nfts);
};

main();
</code></pre>
<p>Re-run your script by running <code>yarn dev</code>. You should now be able to type in any address of your choice and see all the NFTs owned by that address being logged out.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># /ankrjs-node-followalong</span>
yarn dev
</code></pre>
<p><img src="https://i.imgur.com/IwX1KQn.png" alt="https://i.imgur.com/IwX1KQn.png" /></p>
<h2 id="heading-step-5-create-the-getaccountbalance-function">Step 5: Create the <code>getAccountBalance</code> function</h2>
<p>In this step, you will create a <code>getAccountBalance</code> function that accepts a <code>walletAddress</code> and returns a list of ERC20 tokens owned by that address and their balances.</p>
<p>You can use the <code>getNFTsByOwner</code> function provided by Ankr.js for this.</p>
<p><strong>File:</strong> <code>./src/utils.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> AnkrscanProvider <span class="hljs-keyword">from</span> <span class="hljs-string">'@ankr.com/ankr.js'</span>;

<span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> AnkrscanProvider(<span class="hljs-string">''</span>);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getNFTs = <span class="hljs-keyword">async</span> (walletAddress: <span class="hljs-built_in">string</span>) =&gt; {
  <span class="hljs-keyword">return</span> provider.getNFTsByOwner({
    walletAddress,
  });
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getAccountBalance = <span class="hljs-keyword">async</span> (walletAddress: <span class="hljs-built_in">string</span>) =&gt; {
  <span class="hljs-keyword">return</span> provider.getAccountBalance({
    walletAddress,
    blockchain: [<span class="hljs-string">'eth'</span>], <span class="hljs-comment">// you can fetch ERC20 tokens on other chains by passing in more chain names to this array eg. ['eth', 'polygon']</span>
  });
};
</code></pre>
<h2 id="heading-step-6-use-getaccountbalance-in-your-script">Step 6: Use <code>getAccountBalance</code> in your script</h2>
<p>In this step, you will accept an address as input and pass it into <code>getAccountBalance</code> to display results for the given address just like you did with <code>getNFTs</code>.</p>
<p><strong>File:</strong> <code>./src/app.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { getAccountBalance, getNFTs } <span class="hljs-keyword">from</span> <span class="hljs-string">'./utils'</span>;
<span class="hljs-keyword">const</span> prompts = <span class="hljs-built_in">require</span>(<span class="hljs-string">'prompts'</span>);

<span class="hljs-keyword">const</span> main = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-comment">// this function contains the code that be executed when you run your script</span>
  <span class="hljs-keyword">const</span> addressToQueryNFTsFor = <span class="hljs-keyword">await</span> prompts({
    <span class="hljs-keyword">type</span>: <span class="hljs-string">'text'</span>,
    name: <span class="hljs-string">'address'</span>,
    message: <span class="hljs-string">'Enter an address to query NFTs for'</span>,
  });
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'NFTS ================='</span>);
  <span class="hljs-keyword">const</span> nfts = <span class="hljs-keyword">await</span> getNFTs(addressToQueryNFTsFor.address);
  <span class="hljs-built_in">console</span>.log(nfts);

  <span class="hljs-keyword">const</span> addressToQueryBalancesFor = <span class="hljs-keyword">await</span> prompts({
    <span class="hljs-keyword">type</span>: <span class="hljs-string">'text'</span>,
    name: <span class="hljs-string">'address'</span>,
    message: <span class="hljs-string">'Enter an address to query token balances for'</span>,
  });
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'TOKEN BALANCES ================='</span>);
  <span class="hljs-keyword">const</span> balances = <span class="hljs-keyword">await</span> getAccountBalance(addressToQueryBalancesFor.address);
  <span class="hljs-built_in">console</span>.log(balances);
};

main();
</code></pre>
<p>Run your script again and everything should work as expected!</p>
<pre><code class="lang-bash"><span class="hljs-comment"># /ankrjs-node-followalong</span>
yarn dev
</code></pre>
<p><img src="https://i.imgur.com/AQkb6VZ.jpg" alt="https://i.imgur.com/AQkb6VZ.jpg" /></p>
<p>You can find the final code for reference here: <a target="_blank" href="https://github.com/Dhaiwat10/ankrjs-node-quickstart">https://github.com/Dhaiwat10/ankrjs-node-quickstart</a></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this guide, you learned how to get up and running with Ankr.js in a Node.js project. If you ran into an issue or have any questions about this guide, feel free to let us know in <a target="_blank" href="https://discord.gg/BgA5QAnjat">our Discord server</a>.</p>
<h2 id="heading-next-steps">Next Steps</h2>
<p>Ankr.js and Ankr Advanced APIs have so much more to offer than what we covered in this quickstart guide. Ankr.js gives you access to all sorts of data from <em>seven</em> different chains. Learn more here: <a target="_blank" href="https://github.com/ankr-network/ankr.js#%EF%B8%8F-ankrjs">https://github.com/ankr-network/ankr.js#️-ankrjs</a></p>
<h2 id="heading-other-articles-to-read">Other Articles To Read</h2>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://ankr.hashnode.dev/ankrjs-advanced-apis-react-quickstart-guide">https://ankr.hashnode.dev/ankrjs-advanced-apis-react-quickstart-guide</a></div>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://ankr.hashnode.dev/create-a-whats-in-your-wallet-dapp-using-ankrs-multichain-advanced-apis">https://ankr.hashnode.dev/create-a-whats-in-your-wallet-dapp-using-ankrs-multichain-advanced-apis</a></div>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://ankr.hashnode.dev/build-and-deploy-a-rentable-nft-smart-contract-on-optimism">https://ankr.hashnode.dev/build-and-deploy-a-rentable-nft-smart-contract-on-optimism</a></div>
]]></content:encoded></item><item><title><![CDATA[How to build an End-to-End Donation-Based Crowdfunding dApp on Polygon]]></title><description><![CDATA[In this tutorial, we’ll be building a donation-based crowdfunding dApp on Polygon where users can start a fundraising project for anyone to contribute and support the campaign by pledging the amount of their wish. 
By the end of this tutorial, you'll...]]></description><link>https://ankr.hashnode.dev/how-to-build-an-end-to-end-donation-based-crowdfunding-dapp-on-polygon</link><guid isPermaLink="true">https://ankr.hashnode.dev/how-to-build-an-end-to-end-donation-based-crowdfunding-dapp-on-polygon</guid><category><![CDATA[Web3]]></category><category><![CDATA[dapps]]></category><category><![CDATA[Polygon]]></category><category><![CDATA[crowdfunding]]></category><category><![CDATA[development]]></category><dc:creator><![CDATA[Krinza Momin]]></dc:creator><pubDate>Sun, 31 Jul 2022 14:01:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1659211779957/_Ka4DeVAy.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this tutorial, we’ll be building a donation-based crowdfunding dApp on Polygon where users can start a fundraising project for anyone to contribute and support the campaign by pledging the amount of their wish. </p>
<p>By the end of this tutorial, you'll be able to:</p>
<ul>
<li>deploy crowdfunding smart contract on polygon</li>
<li>and create a full-fledged frontend for your dApp </li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659124374214/-EFHTGxf6.png" alt="Screenshot 2022-07-29 at 5.39.36 AM (1).png" /></p>
<h2 id="heading-the-functionalities">The Functionalities</h2>
<ol>
<li><strong>Start New Campaign</strong>  — users will be able to start a new crowdfunding project by inputting some details about the campaign like title, story and goal amount to be raised.</li>
<li><strong>View Projects</strong> — users can see all the existing projects and campaign details on the homepage </li>
<li><strong>Make Donation</strong> — anyone can fund to the project they want to support in Matic tokens</li>
</ol>
<h2 id="heading-the-tech-stack">The Tech Stack</h2>
<ul>
<li>Smart Contract Language: Solidity</li>
<li>Smart Contract Deploy and Verify Scripts: Javascript</li>
<li>Smart Contract Development Environment: <a target="_blank" href="https://hardhat.org/">Hardhat</a>↗</li>
<li>Frontend Language: React - TypeScript</li>
<li>Wallet Connect: <a target="_blank" href="https://www.rainbowkit.com/">Rainbowkit</a>↗</li>
<li>Interacting with Contract through Frontend: <a target="_blank" href="https://wagmi.sh/">Wagmi</a>↗</li>
<li>User Interface: <a target="_blank" href="https://tailwindcss.com/">TailwindCSS</a>↗</li>
<li>RPC provider: <a target="_blank" href="https://www.ankr.com/protocol/">Ankr</a>↗</li>
</ul>
<hr />
<h1 id="heading-getting-started">Getting Started</h1>
<p><strong>Prerequisite:</strong> To successfully finish this guide, you'll need Node.js and Yarn installed on your machine.</p>
<p>We will begin the project by forking this <a target="_blank" href="https://github.com/kaymomin/Starterkit-Crowdfunding-dApp">Crowdfunding-dApp🌈 Starter Repository</a>↗ that I have prepared which includes basic configurations, wallet connect with rainbowkit and complete structure of empty files and folders to get us started with our dApp. To clone the repo, click the <strong>fork</strong> button at the top-right of the linked GitHub page. </p>
<blockquote>
<p>Note in the code block below, make sure you paste the repo URL of your own cloned repository.</p>
</blockquote>
<p>Once the repository has been forked, clone it locally to get building on top of it by following the steps below:</p>
<ul>
<li><p>Navigate into a directory of your choice and run the following command in your terminal to set up a local clone of the starterkit</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/kaymomin/Starterkit-Crowdfunding-dApp.git
</code></pre>
</li>
<li><p>Now, let's navigate into the cloned directory and set up the development environment</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> starterkit-crowdfunding-dapp
</code></pre>
<pre><code class="lang-bash">yarn
</code></pre>
</li>
<li><p>To launch the starter kit, run the following command in the VSCode terminal</p>
<pre><code class="lang-bash">yarn dev
</code></pre>
<p>and you will be able to see the starter-kit webpage. Here's what the site will look like at this point: </p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1658737064172/wztwdf729.png" alt="Untitled design (12).png" /></p>
<h2 id="heading-step-1-setup-hardhat-configs">Step 1: Setup Hardhat Configs</h2>
<p>Navigate back to the project and find the <code>hardhat.config.js</code> file in root directory and the following code: </p>
<p><strong>File:</strong> <code>hardhat.config.js</code></p>
<pre><code><span class="hljs-comment">/**
 * @type import('hardhat/config').HardhatUserConfig
 */</span>
 <span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config();
 <span class="hljs-built_in">require</span>(<span class="hljs-string">"@nomiclabs/hardhat-ethers"</span>);
 <span class="hljs-built_in">require</span>(<span class="hljs-string">"@nomiclabs/hardhat-etherscan"</span>);

 module.exports <span class="hljs-operator">=</span> {
   solidity: <span class="hljs-string">"0.8.15"</span>,
   defaultNetwork: <span class="hljs-string">"mumbai"</span>,
   networks: {
     hardhat: {},
     mumbai: {
       <span class="hljs-comment">//ankr's free public rpc</span>
       url: <span class="hljs-string">"https://rpc.ankr.com/polygon_mumbai"</span>,
       accounts: [`0x${process.env.PRIVATE_KEY}`],
     },
   },
   etherscan: {
     apiKey: {
       polygon: process.env.POLYGONSCAN_API_KEY <span class="hljs-operator">|</span><span class="hljs-operator">|</span> <span class="hljs-string">""</span>,
       polygonMumbai: process.env.POLYGONSCAN_API_KEY <span class="hljs-operator">|</span><span class="hljs-operator">|</span> <span class="hljs-string">""</span>,
     },
   },
 };
</code></pre><p>In this file, we have configured the solidity version, network details and plugged <a target="_blank" href="https://www.ankr.com/protocol/public/polygon/">Ankr's free public RPC</a>↗ for Polygon Mumbai Testnet.</p>
<p>Did you notice how we are sourcing the PRIVATE_KEY and POLYGONSCAN_API_KEY variable in this file? We are loading them up from <code>process.env</code> using the dotenv library. So before we move ahead to next steps, let's add these variables in our <code>.env</code> file. </p>
<ul>
<li>Head over to the <code>.env</code> file and create these two environment variables: </li>
</ul>
<p><strong>File:</strong> <code>.env</code></p>
<pre><code class="lang-bash">PRIVATE_KEY=ADD_YOUR_WALLET_PRIVATE_KEY
POLYGONSCAN_API_KEY=ADD_YOUR_POLYGONSCAN_API_KEY
</code></pre>
<p>Here, you need to set your wallet's <a target="_blank" href="https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-export-an-account-s-private-key">private key</a>↗ and API key from <a target="_blank" href="https://polygonscan.com/">Polygonscan</a>↗. You can follow their <a target="_blank" href="https://docs.polygonscan.com/getting-started/viewing-api-usage-statistics">tutorial</a>↗ if you aren't familiar with how to get one. </p>
<hr />
<h2 id="heading-step-2-write-crowdfunding-smart-contract">Step 2: Write Crowdfunding Smart Contract</h2>
<p>Now that we have everything setup, we are all ready to write the smart contract for the donation based crowdfund platform. For that, navigate to <code>contracts</code> directory and you'll find <code>crowdfunding.sol</code> file. Add the following code in that file:</p>
<p><strong>File:</strong> <code>contracts/crowdfunding.sol</code></p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: Unlicensed</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.15;</span>

<span class="hljs-comment">//contract to record all crowdfunding projects</span>
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">CrowdFactory</span> </span>{
    <span class="hljs-keyword">address</span>[] <span class="hljs-keyword">public</span> publishedProjs;

    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">Projectcreated</span>(<span class="hljs-params">
        <span class="hljs-keyword">string</span> projTitle,
        <span class="hljs-keyword">uint256</span> goalAmount,
        <span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> ownerWallet,
        <span class="hljs-keyword">address</span> projAddress,
        <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">indexed</span> timestamp
    </span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">totalPublishedProjs</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
        <span class="hljs-keyword">return</span> publishedProjs.<span class="hljs-built_in">length</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createProject</span>(<span class="hljs-params">
        <span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> projectTitle,
        <span class="hljs-keyword">uint256</span> projgoalAmount,
        <span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> projDescript,
        <span class="hljs-keyword">address</span> ownerWallet
    </span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-comment">//initializing CrowdfundingProject contract</span>
        CrowdfundingProject newproj <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> CrowdfundingProject(
            <span class="hljs-comment">//passing arguments from constructor function</span>
            projectTitle,
            projgoalAmount,
            projDescript,
            ownerWallet
        );

        <span class="hljs-comment">//pushing project address</span>
        publishedProjs.<span class="hljs-built_in">push</span>(<span class="hljs-keyword">address</span>(newproj));

        <span class="hljs-comment">//calling Projectcreated (event above)</span>
        <span class="hljs-keyword">emit</span> Projectcreated(
            projectTitle,
            projgoalAmount,
            <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>,
            <span class="hljs-keyword">address</span>(newproj),
            <span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>
        );
    }
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">CrowdfundingProject</span> </span>{
    <span class="hljs-comment">//defining state variables</span>
    <span class="hljs-keyword">string</span> <span class="hljs-keyword">public</span> projTitle;
    <span class="hljs-keyword">string</span> <span class="hljs-keyword">public</span> projDescription;
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> goalAmount;
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> raisedAmount;
    <span class="hljs-keyword">address</span> ownerWallet; <span class="hljs-comment">//address where amount to be transfered</span>

    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">Funded</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> donar,
        <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">indexed</span> amount,
        <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">indexed</span> timestamp
    </span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params">
        <span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> projectTitle,
        <span class="hljs-keyword">uint256</span> projgoalAmount,
        <span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> projDescript,
        <span class="hljs-keyword">address</span> ownerWallet_
    </span>) </span>{
        <span class="hljs-comment">//mapping values</span>
        projTitle <span class="hljs-operator">=</span> projectTitle;
        goalAmount <span class="hljs-operator">=</span> projgoalAmount;
        projDescription <span class="hljs-operator">=</span> projDescript;
        ownerWallet <span class="hljs-operator">=</span> ownerWallet_;
    }

    <span class="hljs-comment">//donation function</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">makeDonation</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-comment">//if goal amount is achieved, close the proj</span>
        <span class="hljs-built_in">require</span>(goalAmount <span class="hljs-operator">&gt;</span> raisedAmount, <span class="hljs-string">"GOAL ACHIEVED"</span>);

        <span class="hljs-comment">//record walletaddress of donor</span>
        (<span class="hljs-keyword">bool</span> success, ) <span class="hljs-operator">=</span> <span class="hljs-keyword">payable</span>(ownerWallet).<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>}(<span class="hljs-string">""</span>);
        <span class="hljs-built_in">require</span>(success, <span class="hljs-string">"VALUE NOT TRANSFERRED"</span>);

        <span class="hljs-comment">//calculate total amount raised</span>
        raisedAmount <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;

        <span class="hljs-keyword">emit</span> Funded(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>, <span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>);
    }
}
</code></pre>
<p>You'll see we have initiated two contracts:</p>
<ol>
<li><strong>CrowdfundingProject</strong> - deals with a single project or campaign being create. It includes the <code>makeDonation()</code> function which calculates the amount raised and checks if the <code>goalAmount</code> is achieved or not while recording the wallet address of the donor.</li>
<li><strong>CrowdFactory</strong> - records for all the crowdfunding projects being created and launched. </li>
</ol>
<p>Now, let's compile hardhat to see if everything's good to go!</p>
<pre><code class="lang-Bash">yarn hardhat compile

<span class="hljs-comment"># output</span>
<span class="hljs-comment"># Compiled n Solidity file successfully</span>
</code></pre>
<hr />
<h2 id="heading-step-3-write-the-deploy-scripts">Step 3: Write the Deploy Script(s)</h2>
<p>Now that we've got our contract set up, let's create the deployment scripts. There will be two scripts, one for deploying the <strong>CrowdFactory</strong> contract and second for a dummy campaign creation with some dummy project info. </p>
<ul>
<li>For the first script, navigate to the <code>scripts</code> folder and add the following code in <code>deploy.js</code> file</li>
</ul>
<p><strong>File:</strong> <code>scripts/deploy.js</code></p>
<pre><code>const { ethers } <span class="hljs-operator">=</span> <span class="hljs-built_in">require</span>(<span class="hljs-string">"hardhat"</span>);

async <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Grab the contract factory</span>
  const CrowdFactory <span class="hljs-operator">=</span> await ethers.getContractFactory(<span class="hljs-string">"CrowdFactory"</span>);

  <span class="hljs-comment">// Start deployment, returning a promise that resolves to a contract object</span>
  const crowd <span class="hljs-operator">=</span> await CrowdFactory.deploy(); <span class="hljs-comment">// Instance of the contract</span>
  await crowd.deployed();
  console.log(<span class="hljs-string">"Contract deployed to address:"</span>, crowd.<span class="hljs-built_in">address</span>);
}

main()
  .then(() <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> process.exit(<span class="hljs-number">0</span>))
  .catch((<span class="hljs-function"><span class="hljs-keyword">error</span>) =&gt; </span>{
    console.error(<span class="hljs-function"><span class="hljs-keyword">error</span>)</span>;
    process.exit(<span class="hljs-number">1</span>);
  });
</code></pre><ul>
<li>Save this file and run the following command to deploy the <strong>CrowdFactory</strong> contract</li>
</ul>
<pre><code class="lang-Bash">yarn hardhat run scripts/deploy.js --network mumbai
</code></pre>
<p>Running this command will prompt you with the address of the deployed contract. Here's the contract I <a target="_blank" href="https://mumbai.polygonscan.com/address/0xA6A30bCc591107d932CA12a50FC616BAb5E58cdA">deployed</a>.↗</p>
<p><strong><em>Note your contract address as you will need it in your next deployment script.</em></strong></p>
<hr />
<p>Before we go on deploying another contract, let's save this contract address in a file named <strong>constants.tx</strong> under <strong>src</strong> directory.</p>
<p><strong>File:</strong> <code>src/constants.tx</code></p>
<pre><code><span class="hljs-comment">//add your contract's address here</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> FACTORY_CONTRACT_ADDRESS = <span class="hljs-string">"0xA6A30bCc591107d932CA12a50FC616BAb5E58cdA"</span>;

<span class="hljs-comment">//just for testing purpose</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> DEBUG = <span class="hljs-literal">false</span>;
</code></pre><hr />
<p>Now let's deploy another contract with a sudo campaign details for us to get started. For this, we are going to use <strong>createCampaigns.js</strong> file under <code>scripts</code> directory. Navigate to that file and save the following code.</p>
<blockquote>
<p>Note: In this file you need to edit two things. First the contract address we got in the above step. Replace your contract address with the address mentioned already in the script (check line 6). Second, on line 13, replace my wallet address with yours. </p>
</blockquote>
<p><strong>File:</strong> <code>scripts/createCampaigns.js</code></p>
<pre><code>const { ethers } <span class="hljs-operator">=</span> <span class="hljs-built_in">require</span>(<span class="hljs-string">"hardhat"</span>);

async <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
const <span class="hljs-class"><span class="hljs-keyword">contract</span> = <span class="hljs-title">await</span> <span class="hljs-title">ethers</span>.<span class="hljs-title">getContractAt</span>(<span class="hljs-params"><span class="hljs-string">"CrowdFactory"</span>,
<span class="hljs-comment">//add the contract address that you just deployed in the last step</span>
<span class="hljs-string">"0xA6A30bCc591107d932CA12a50FC616BAb5E58cdA"</span></span>) <span class="hljs-comment">//line 6</span>

<span class="hljs-title">await</span> <span class="hljs-title"><span class="hljs-keyword">contract</span></span>.<span class="hljs-title">createProject</span>(<span class="hljs-params">
<span class="hljs-string">"first title"</span>, 
ethers.utils.parseUnits(<span class="hljs-params"><span class="hljs-string">"0.1"</span>, <span class="hljs-number">18</span></span>), 
<span class="hljs-string">"description"</span>, 
<span class="hljs-comment">//insert your wallet's public key</span>
<span class="hljs-string">"0x81AE60AC85F0b81Cc00e2B294d83A03f40d1deF5"</span></span>) <span class="hljs-comment">//line 13</span>
}

<span class="hljs-title">main</span>(<span class="hljs-params"></span>)
  .<span class="hljs-title">then</span>(<span class="hljs-params">(<span class="hljs-params"></span>) =&gt; process.exit(<span class="hljs-params"><span class="hljs-number">0</span></span>)</span>)
  .<span class="hljs-title"><span class="hljs-keyword">catch</span></span>(<span class="hljs-params">(<span class="hljs-params"><span class="hljs-keyword">error</span></span>) =&gt; {
    console.<span class="hljs-keyword">error</span>(<span class="hljs-params"><span class="hljs-keyword">error</span></span>);
    process.exit(<span class="hljs-params"><span class="hljs-number">1</span></span>);
  }</span>);</span>
</code></pre><p>Once done, run the following command to deploy this script as well:</p>
<pre><code>yarn hardhat run scripts<span class="hljs-operator">/</span>createCampaigns.js <span class="hljs-operator">-</span><span class="hljs-operator">-</span>network mumbai
</code></pre><h2 id="heading-step-4-get-contract-abi-for-verified-codes">Step 4: Get Contract ABI for Verified Codes</h2>
<p>In this step, we are going to do two things:</p>
<ol>
<li>we will verify our smart contracts on <a target="_blank" href="https://mumbai.polygonscan.com/">Polygonscan</a>↗</li>
<li>get contract ABIs for verified contract source codes</li>
</ol>
<p><strong>Verifying Smart Contracts</strong></p>
<ul>
<li>Go to <code>verify-factory.js</code> file under scripts folder and add the following verify script: </li>
</ul>
<blockquote>
<p>Note: In this file you need to edit one thing. The <strong>contractAddress</strong>  you see on line number 5 needs to be replaced by your contract's address. </p>
</blockquote>
<p><strong>File:</strong> <code>scripts/verify-factory.js</code></p>
<pre><code><span class="hljs-keyword">const</span> { run } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"hardhat"</span>);

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
<span class="hljs-comment">//add the contract address that you deployed in the prev steps</span>
  <span class="hljs-keyword">const</span> contractAddress = <span class="hljs-string">"0xA6A30bCc591107d932CA12a50FC616BAb5E58cdA"</span>; <span class="hljs-comment">//line 5</span>

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">await</span> run(<span class="hljs-string">"verify:verify"</span>, {
      <span class="hljs-attr">address</span>: contractAddress,
      <span class="hljs-attr">constructorArguments</span>: [],
      <span class="hljs-attr">contract</span>: <span class="hljs-string">"contracts/crowdfunding.sol:CrowdFactory"</span>,
    });
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">if</span> (error.message.toLowerCase().includes(<span class="hljs-string">"already verified"</span>)) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Already verified!"</span>);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">console</span>.log(error);
    }
  }
}

main()
  .then(<span class="hljs-function">() =&gt;</span> process.exit(<span class="hljs-number">0</span>))
  .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.error(error);
    process.exit(<span class="hljs-number">1</span>);
  });
</code></pre><ul>
<li>Now in the terminal, run this command to verify the <strong>CrowdFactory</strong> smart contract on polygonscan:</li>
</ul>
<pre><code>yarn hardhat run scripts<span class="hljs-operator">/</span>verify<span class="hljs-operator">-</span>factory.js <span class="hljs-operator">-</span><span class="hljs-operator">-</span>network mumbai
</code></pre><p><strong>Output of this command:</strong></p>
<p><code>Successfully verified contract CrowdFactory on Etherscan.</code>
<code>https://mumbai.polygonscan.com/address/0xA6A30bCc591107d932CA12a50FC616BAb5E58cdA#code</code></p>
<ul>
<li><p>Head over to the Mumbai Polygonscan link you get as the output after running the command and it will land you to the verified contract's page</p>
</li>
<li><p>Scroll down and you'll find <strong>Contract ABI</strong> section</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1658908647862/28NCzlMn3.png" alt="image.png" /></p>
<ul>
<li><p>Copy the ABI and paste it in the <code>crowdfactory.json</code> file under <code>src/abis</code> directory</p>
</li>
<li><p>Go back to the same polygonscan link, click on the <strong>Read Contract </strong>button and query "0" from the <strong>publishedProjs</strong>. </p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1658916647034/bkH4QKaI9.gif" alt="Untitled design.gif" /></p>
<blockquote>
<p>Copy and save the address it outputs, we will need it in <em>line 5</em> of the next file.</p>
</blockquote>
<p>Now, we are going to follow the similar steps to first verify our dummy crowdfunding project and get the contract's ABI.</p>
<ul>
<li>Navigate to <code>verify-crowdfundingproject.js</code> file under <strong>scripts</strong> folder and insert the following code in the file:</li>
</ul>
<blockquote>
<p>Replace contractAddress in the file with the one we saved above querying the 0th publishedProj and also insert your wallet address on line 9</p>
</blockquote>
<p><strong>File:</strong> <code>scripts/verify-crowdfundingproject.js</code></p>
<pre><code><span class="hljs-keyword">const</span> { run, ethers } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"hardhat"</span>);

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">//replace contractAddress with the one we saved above querying the 0th publishedProj</span>
  <span class="hljs-keyword">const</span> contractAddress = <span class="hljs-string">"0xcf092E8bDCDC1FA8B15Ebeb9D97453D498067Df1"</span>; <span class="hljs-comment">//line5</span>
  <span class="hljs-keyword">const</span> args = [
    <span class="hljs-string">"first title"</span>, ethers.utils.parseUnits(<span class="hljs-string">"0.1"</span>, <span class="hljs-number">18</span>), <span class="hljs-string">"description"</span>,
<span class="hljs-comment">//Insert you wallet's public address here</span>
<span class="hljs-string">"YOUR_WALLET_PUBLIC_ADDRESS"</span>,  <span class="hljs-comment">//line 9</span>

  ];

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">await</span> run(<span class="hljs-string">"verify:verify"</span>, {
      <span class="hljs-attr">address</span>: contractAddress,
      <span class="hljs-attr">constructorArguments</span>: args,
      <span class="hljs-attr">contract</span>: <span class="hljs-string">"contracts/crowdfunding.sol:CrowdfundingProject"</span>,
    });
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">if</span> (error.message.toLowerCase().includes(<span class="hljs-string">"already verified"</span>)) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Already verified!"</span>);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">console</span>.log(error);
    }
  }
}

main()
  .then(<span class="hljs-function">() =&gt;</span> process.exit(<span class="hljs-number">0</span>))
  .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.error(error);
    process.exit(<span class="hljs-number">1</span>);
  });
</code></pre><ul>
<li>Once you save the above file, run this command to verify it on polygonscan:</li>
</ul>
<pre><code>yarn hardhat run scripts<span class="hljs-operator">/</span>verify<span class="hljs-operator">-</span>crowdfundingproject.js <span class="hljs-operator">-</span><span class="hljs-operator">-</span>network mumbai
</code></pre><p><strong>Output of this command:</strong></p>
<p><code>Successfully verified contract CrowdfundingProject on Etherscan.</code> <code>https://mumbai.polygonscan.com/address/0xcf092E8bDCDC1FA8B15Ebeb9D97453D498067Df1#code</code></p>
<ul>
<li><p>Head over to the Mumbai Polygonscan link you get as the output after running the command and it will land you to the verified contract's page</p>
</li>
<li><p>Scroll down, find <strong>Contract ABI</strong> section and copy-paste ABI in the <code>crowdfundingproject.json</code> file under <code>src/abis</code> directory</p>
</li>
</ul>
<p>Once this is done, run the following command in the terminal:</p>
<pre><code><span class="hljs-attribute">yarn</span> typechain
</code></pre><p>TypeChain is a typescript binding and code generator used to create smart contracts that features static typing and IDE support.</p>
<hr />
<h2 id="heading-step-5-write-hooks-utils-and-read">Step 5: Write Hooks, Utils and Read</h2>
<p>As the heading suggests, this section will be no less than a lot of code. We will begin by updating the <code>hooks.ts</code> under <code>src</code> directory. In this file, we will be creating generic hooks to access the write and read functions of both "crowdfactory" and "CrowdfundingProject" contracts.</p>
<p><strong>File:</strong> <code>src/hooks.ts</code></p>
<pre><code><span class="hljs-keyword">import</span> { useContract, useContractRead, useContractWrite } <span class="hljs-keyword">from</span> <span class="hljs-string">"wagmi"</span>;

<span class="hljs-keyword">import</span> CROWDFACTORY_ABI <span class="hljs-keyword">from</span> <span class="hljs-string">"./abis/crowdfactory.json"</span>;
<span class="hljs-keyword">import</span> CROWNFUNDINGPROJECT_ABI <span class="hljs-keyword">from</span> <span class="hljs-string">"./abis/crowdfundingproject.json"</span>;
<span class="hljs-keyword">import</span> { FACTORY_CONTRACT_ADDRESS } <span class="hljs-keyword">from</span> <span class="hljs-string">"./constants"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { Crowdfactory } <span class="hljs-keyword">from</span> <span class="hljs-string">"./contract-types/Crowdfactory"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { Crowdfundingproject } <span class="hljs-keyword">from</span> <span class="hljs-string">"./contract-types/Crowdfundingproject"</span>;

<span class="hljs-comment">/*//////////////////////////////////////////////////////////////
                              CROWD FACTORY
//////////////////////////////////////////////////////////////*/</span>

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useCrowdFactoryContract</span>(<span class="hljs-params"></span>): <span class="hljs-title">Crowdfactory</span> </span>{
  <span class="hljs-keyword">const</span> contract = useContract({
    addressOrName: FACTORY_CONTRACT_ADDRESS,
    contractInterface: CROWDFACTORY_ABI,
  });

  <span class="hljs-keyword">return</span> contract <span class="hljs-keyword">as</span> Crowdfactory;
}

<span class="hljs-comment">// create a generic hook to access write functions of contract</span>
<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useCrowdFactoryFunctionWriter</span>(<span class="hljs-params">
  functionName: <span class="hljs-built_in">string</span>
</span>): <span class="hljs-title">ReturnType</span>&lt;<span class="hljs-title">typeof</span> <span class="hljs-title">useContractWrite</span>&gt; </span>{
  <span class="hljs-keyword">const</span> contractWrite = useContractWrite({
    addressOrName: FACTORY_CONTRACT_ADDRESS,
    contractInterface: CROWDFACTORY_ABI,
    functionName: functionName,
  });

  <span class="hljs-keyword">return</span> contractWrite;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> UseCrowdFactoryFunctionReaderProps {
  functionName: <span class="hljs-built_in">string</span>;
  args?: <span class="hljs-built_in">any</span>[];
}
<span class="hljs-comment">// create a generic hook to access read functions of contract</span>
<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useCrowdFactoryFunctionReader</span>(<span class="hljs-params">{
  functionName,
  args,
}: UseCrowdFactoryFunctionReaderProps</span>): <span class="hljs-title">ReturnType</span>&lt;<span class="hljs-title">typeof</span> <span class="hljs-title">useContractRead</span>&gt; </span>{
  <span class="hljs-keyword">const</span> contractRead = useContractRead({
    addressOrName: FACTORY_CONTRACT_ADDRESS,
    contractInterface: CROWDFACTORY_ABI,
    functionName: functionName,
    args: args,
    watch: <span class="hljs-literal">true</span>,
  });

  <span class="hljs-keyword">return</span> contractRead;
}

<span class="hljs-comment">/*//////////////////////////////////////////////////////////////
                          CROWD FUNDING PROJECT
//////////////////////////////////////////////////////////////*/</span>

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useCrowdfundingProjectContract</span>(<span class="hljs-params">
  contractAddress: <span class="hljs-built_in">string</span>
</span>): <span class="hljs-title">Crowdfundingproject</span> </span>{
  <span class="hljs-keyword">const</span> contract = useContract({
    addressOrName: contractAddress,
    contractInterface: CROWNFUNDINGPROJECT_ABI,
  });

  <span class="hljs-keyword">return</span> contract <span class="hljs-keyword">as</span> Crowdfundingproject;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> UseCrowdfundingProjectFunctionWriterProps {
  contractAddress: <span class="hljs-built_in">string</span>;
  functionName: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useCrowdfundingProjectFunctionWriter</span>(<span class="hljs-params">{
  contractAddress,
  functionName,
}: UseCrowdfundingProjectFunctionWriterProps</span>): <span class="hljs-title">ReturnType</span>&lt;
  <span class="hljs-title">typeof</span> <span class="hljs-title">useContractWrite</span>
&gt; </span>{
  <span class="hljs-keyword">const</span> contractWrite = useContractWrite({
    addressOrName: contractAddress,
    contractInterface: CROWNFUNDINGPROJECT_ABI,
    functionName: functionName,
  });

  <span class="hljs-keyword">return</span> contractWrite;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> UseCrowdfundingProjectFunctionReaderProps {
  contractAddress: <span class="hljs-built_in">string</span>;
  functionName: <span class="hljs-built_in">string</span>;
  args?: <span class="hljs-built_in">any</span>[];
}

<span class="hljs-comment">// create a generic hook to access read functions of contract</span>
<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useCrowdfundingProjectFunctionReader</span>(<span class="hljs-params">{
  contractAddress,
  functionName,
  args,
}: UseCrowdfundingProjectFunctionReaderProps</span>): <span class="hljs-title">ReturnType</span>&lt;
  <span class="hljs-title">typeof</span> <span class="hljs-title">useContractRead</span>
&gt; </span>{
  <span class="hljs-keyword">const</span> contractRead = useContractRead({
    addressOrName: contractAddress,
    contractInterface: CROWNFUNDINGPROJECT_ABI,
    functionName: functionName,
    args: args,
    watch: <span class="hljs-literal">true</span>,
  });

  <span class="hljs-keyword">return</span> contractRead;
}
</code></pre><p>Now, let's move to the other file named "<strong>utils.ts</strong>". In this file we are creating helper functions to convert wei into matic.</p>
<p><strong>File:</strong> <code>src/utils.ts</code></p>
<pre><code><span class="hljs-comment">//helper functions to convert wei into matic</span>

<span class="hljs-keyword">import</span> <span class="hljs-title"><span class="hljs-keyword">type</span></span> { <span class="hljs-title">BigNumberish</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"ethers"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">BigNumber</span>, <span class="hljs-title">utils</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"ethers"</span>;

<span class="hljs-comment">/**
 * Return the `value` converted to BigNumber.
 *
 * @param value string value preferred.
 * @return BigNumber value
 */</span>
export <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toBN</span>(<span class="hljs-params">value: BigNumberish</span>): <span class="hljs-title">BigNumber</span> </span>{
  <span class="hljs-keyword">return</span> BigNumber.from(value);
}

<span class="hljs-comment">/**
 * Return the `gasPrice` converted to gwei.
 * formatUnits(value: BigNumberish, unitName?: BigNumberish | undefined): string
 * BigNumberish -&gt; string, BigNumber, number, BytesLike or BigInt.`https://docs.ethers.io/v5/api/utils/bignumber/#BigNumberish`
 *
 * @param gasPrice BigNumberish value to be converted, preferred is BigNumber.
 * @return string value
 */</span>
export <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toGwei</span>(<span class="hljs-params">gasPrice: BigNumberish</span>): <span class="hljs-title"><span class="hljs-keyword">string</span></span> </span>{
  <span class="hljs-keyword">return</span> utils.formatUnits(gasPrice, <span class="hljs-string">"gwei"</span>);
}

<span class="hljs-comment">/**
 * Return the `value` converted to BigNumber wei.
 * parseUnits(value: string, unitName?: BigNumberish | undefined): BigNumber
 * BigNumberish -&gt; string, BytesLike, BigNumber, number or BigInt.`https://docs.ethers.io/v5/api/utils/bignumber/#BigNumberish`
 *
 * @param value the string value to be converted.
 * @param decimals decimal value or BigNumberish.
 * @return BigNumber value or undefined.
 */</span>
export <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toWei</span>(<span class="hljs-params">value: <span class="hljs-keyword">string</span>, decimals: number = <span class="hljs-number">18</span></span>): <span class="hljs-title">BigNumber</span> </span>{
  <span class="hljs-keyword">return</span> utils.parseUnits(value, decimals);
}
<span class="hljs-comment">/**
 * Return the `value` converted to string from wei.
 * formatUnits(value: BigNumberish, unitName?: BigNumberish | undefined): string
 * BigNumberish -&gt; string, BigNumber, number, BytesLike or BigInt.`https://docs.ethers.io/v5/api/utils/bignumber/#BigNumberish`
 *
 * @param value BigNumberish value to be converted, preferred is BigNumber.
 * @param decimals decimal value or BigNumberish.
 * @return string value.
 */</span>
export <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fromWei</span>(<span class="hljs-params">value: BigNumberish, decimals: number = <span class="hljs-number">18</span></span>): <span class="hljs-title"><span class="hljs-keyword">string</span></span> </span>{
  <span class="hljs-keyword">return</span> utils.formatUnits(value, decimals);
}

<span class="hljs-comment">/**
 * Returns true if the string value is zero in hex
 * @param hexNumberString
 */</span>
export default <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isZero</span>(<span class="hljs-params">hexNumberString: <span class="hljs-keyword">string</span></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-operator">/</span><span class="hljs-operator">^</span><span class="hljs-number">0x0</span><span class="hljs-operator">*</span>$<span class="hljs-operator">/</span>.test(hexNumberString);
}
</code></pre><p>And last but not at all the least, "<strong>read.ts</strong>" under the <strong>src</strong> directory which will contain <a target="_blank" href="https://www.geeksforgeeks.org/solidity-view-and-pure-functions/">view and pure functions</a>.↗</p>
<p><strong>File:</strong> <code>src/read.ts</code></p>
<pre><code><span class="hljs-comment">//read function</span>
<span class="hljs-comment">//view and pure functions (Smartcontract)</span>

<span class="hljs-keyword">import</span> <span class="hljs-title"><span class="hljs-keyword">type</span></span> { <span class="hljs-title">BigNumber</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"ethers"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title"><span class="hljs-keyword">type</span></span> { <span class="hljs-title">Result</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"ethers/lib/utils"</span>;

<span class="hljs-keyword">import</span> { <span class="hljs-title">DEBUG</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"./constants"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title"><span class="hljs-keyword">type</span></span> { <span class="hljs-title">Crowdfactory</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"./contract-types/Crowdfactory"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title"><span class="hljs-keyword">type</span></span> { <span class="hljs-title">Crowdfundingproject</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"./contract-types/Crowdfundingproject"</span>;
<span class="hljs-keyword">import</span> {
  <span class="hljs-title">useCrowdFactoryFunctionReader</span>,
  <span class="hljs-title">useCrowdfundingProjectFunctionReader</span>,
} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"./hooks"</span>;

<span class="hljs-comment">/*//////////////////////////////////////////////////////////////
                              CROWD FACTORY
//////////////////////////////////////////////////////////////*/</span>

export <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useTotalPublishedProjs</span>(<span class="hljs-params"></span>): <span class="hljs-title">number</span> | <span class="hljs-title">undefined</span> </span>{
  const totalPublishedProjsReader <span class="hljs-operator">=</span> useCrowdFactoryFunctionReader({
    functionName: <span class="hljs-string">"totalPublishedProjs"</span>,
  });
  const totalPublishedProjs:
    <span class="hljs-operator">|</span> Awaited<span class="hljs-operator">&lt;</span>ReturnType<span class="hljs-operator">&lt;</span>Crowdfactory[<span class="hljs-string">"totalPublishedProjs"</span>]<span class="hljs-operator">&gt;</span><span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">|</span> Result
    <span class="hljs-operator">|</span> undefined <span class="hljs-operator">=</span> totalPublishedProjsReader.data;

  DEBUG <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span>
    console.log(<span class="hljs-string">"totalPublishedProjs: "</span>, totalPublishedProjs?.toString());

  <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>totalPublishedProjs) <span class="hljs-keyword">return</span> undefined;

  <span class="hljs-keyword">return</span> parseInt(totalPublishedProjs.toString()) <span class="hljs-keyword">as</span> number;
}

export <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">usePublishedProjs</span>(<span class="hljs-params">index: number</span>): <span class="hljs-title"><span class="hljs-keyword">string</span></span> | <span class="hljs-title">undefined</span> </span>{
  const publishedProjsReader <span class="hljs-operator">=</span> useCrowdFactoryFunctionReader({
    functionName: <span class="hljs-string">"publishedProjs"</span>,
    args: [index],
  });
  const publishedProjs:
    <span class="hljs-operator">|</span> Awaited<span class="hljs-operator">&lt;</span>ReturnType<span class="hljs-operator">&lt;</span>Crowdfactory[<span class="hljs-string">"publishedProjs"</span>]<span class="hljs-operator">&gt;</span><span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">|</span> Result
    <span class="hljs-operator">|</span> undefined <span class="hljs-operator">=</span> publishedProjsReader.data;

  DEBUG <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> console.log(<span class="hljs-string">"publishedProjs: "</span>, publishedProjs);

  <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>publishedProjs) <span class="hljs-keyword">return</span> undefined;

  <span class="hljs-keyword">return</span> publishedProjs <span class="hljs-keyword">as</span> unknown <span class="hljs-keyword">as</span> <span class="hljs-keyword">string</span>;
}

<span class="hljs-comment">/*//////////////////////////////////////////////////////////////
                          CROWD FUNDING PROJECT
//////////////////////////////////////////////////////////////*/</span>

export <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useProjTitle</span>(<span class="hljs-params">contractAddress: <span class="hljs-keyword">string</span></span>): <span class="hljs-title"><span class="hljs-keyword">string</span></span> | <span class="hljs-title">undefined</span> </span>{
  const projTitleReader <span class="hljs-operator">=</span> useCrowdfundingProjectFunctionReader({
    contractAddress: contractAddress,
    functionName: <span class="hljs-string">"projTitle"</span>,
  });

  const projTitle:
    <span class="hljs-operator">|</span> Awaited<span class="hljs-operator">&lt;</span>ReturnType<span class="hljs-operator">&lt;</span>Crowdfundingproject[<span class="hljs-string">"projTitle"</span>]<span class="hljs-operator">&gt;</span><span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">|</span> Result
    <span class="hljs-operator">|</span> undefined <span class="hljs-operator">=</span> projTitleReader.data;

  DEBUG <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> console.log(<span class="hljs-string">"projTitle: "</span>, projTitle);

  <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>projTitle) <span class="hljs-keyword">return</span> undefined;

  <span class="hljs-keyword">return</span> projTitle <span class="hljs-keyword">as</span> unknown <span class="hljs-keyword">as</span> <span class="hljs-keyword">string</span>;
}

export <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useProjDescription</span>(<span class="hljs-params">
  contractAddress: <span class="hljs-keyword">string</span>
</span>): <span class="hljs-title"><span class="hljs-keyword">string</span></span> | <span class="hljs-title">undefined</span> </span>{
  const projDescriptionReader <span class="hljs-operator">=</span> useCrowdfundingProjectFunctionReader({
    contractAddress: contractAddress,
    functionName: <span class="hljs-string">"projDescription"</span>,
  });

  const projDescription:
    <span class="hljs-operator">|</span> Awaited<span class="hljs-operator">&lt;</span>ReturnType<span class="hljs-operator">&lt;</span>Crowdfundingproject[<span class="hljs-string">"projDescription"</span>]<span class="hljs-operator">&gt;</span><span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">|</span> Result
    <span class="hljs-operator">|</span> undefined <span class="hljs-operator">=</span> projDescriptionReader.data;

  DEBUG <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> console.log(<span class="hljs-string">"projDescription: "</span>, projDescription);

  <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>projDescription) <span class="hljs-keyword">return</span> undefined;

  <span class="hljs-keyword">return</span> projDescription <span class="hljs-keyword">as</span> unknown <span class="hljs-keyword">as</span> <span class="hljs-keyword">string</span>;
}

export <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useGoalAmount</span>(<span class="hljs-params">contractAddress: <span class="hljs-keyword">string</span></span>): <span class="hljs-title">BigNumber</span> | <span class="hljs-title">undefined</span> </span>{
  const goalAmountReader <span class="hljs-operator">=</span> useCrowdfundingProjectFunctionReader({
    contractAddress: contractAddress,
    functionName: <span class="hljs-string">"goalAmount"</span>,
  });

  const goalAmount:
    <span class="hljs-operator">|</span> Awaited<span class="hljs-operator">&lt;</span>ReturnType<span class="hljs-operator">&lt;</span>Crowdfundingproject[<span class="hljs-string">"goalAmount"</span>]<span class="hljs-operator">&gt;</span><span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">|</span> Result
    <span class="hljs-operator">|</span> undefined <span class="hljs-operator">=</span> goalAmountReader.data;

  DEBUG <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> console.log(<span class="hljs-string">"goalAmount: "</span>, goalAmount);

  <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>goalAmount) <span class="hljs-keyword">return</span> undefined;

  <span class="hljs-keyword">return</span> goalAmount <span class="hljs-keyword">as</span> unknown <span class="hljs-keyword">as</span> BigNumber;
}

export <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useRaisedAmount</span>(<span class="hljs-params">
  contractAddress: <span class="hljs-keyword">string</span>
</span>): <span class="hljs-title">BigNumber</span> | <span class="hljs-title">undefined</span> </span>{
  const raisedAmountReader <span class="hljs-operator">=</span> useCrowdfundingProjectFunctionReader({
    contractAddress: contractAddress,
    functionName: <span class="hljs-string">"raisedAmount"</span>,
  });

  const raisedAmount:
    <span class="hljs-operator">|</span> Awaited<span class="hljs-operator">&lt;</span>ReturnType<span class="hljs-operator">&lt;</span>Crowdfundingproject[<span class="hljs-string">"raisedAmount"</span>]<span class="hljs-operator">&gt;</span><span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">|</span> Result
    <span class="hljs-operator">|</span> undefined <span class="hljs-operator">=</span> raisedAmountReader.data;

  DEBUG <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> console.log(<span class="hljs-string">"raisedAmount: "</span>, raisedAmount);

  <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>raisedAmount) <span class="hljs-keyword">return</span> undefined;

  <span class="hljs-keyword">return</span> raisedAmount <span class="hljs-keyword">as</span> unknown <span class="hljs-keyword">as</span> BigNumber;
}
</code></pre><hr />
<h2 id="heading-step-6-create-components">Step 6: Create Components</h2>
<p>In this step, we are going to head over to <code>components</code> folder under <code>src</code> directory. First up, navigate to "<strong>CreateCampaign.tsx</strong>" file and insert the following code. In this file, we will be using custom hook we made in hooks.ts for writing functions along with the coding the UI. </p>
<p><strong>File:</strong> <code>src/components/CreateCampaign.tsx</code></p>
<pre><code><span class="hljs-keyword">import</span> { <span class="hljs-title">DEBUG</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../constants"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title"><span class="hljs-keyword">type</span></span> { <span class="hljs-title">Crowdfactory</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../contract-types/Crowdfactory"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">useCrowdFactoryFunctionWriter</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../hooks"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">toWei</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../utils"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">useAddRecentTransaction</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@rainbow-me/rainbowkit"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title"><span class="hljs-keyword">type</span></span> { <span class="hljs-title">ChangeEvent</span>, <span class="hljs-title">FormEvent</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">useState</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">useAccount</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"wagmi"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">CreateCampaign</span>(<span class="hljs-params"></span>) </span>{
  const [title, setTitle] <span class="hljs-operator">=</span> useState<span class="hljs-operator">&lt;</span><span class="hljs-keyword">string</span><span class="hljs-operator">&gt;</span>(<span class="hljs-string">""</span>);
  const [amount, setAmount] <span class="hljs-operator">=</span> useState<span class="hljs-operator">&lt;</span><span class="hljs-keyword">string</span><span class="hljs-operator">&gt;</span>(<span class="hljs-string">""</span>);
  const [story, setStory] <span class="hljs-operator">=</span> useState<span class="hljs-operator">&lt;</span><span class="hljs-keyword">string</span><span class="hljs-operator">&gt;</span>(<span class="hljs-string">""</span>);

  const { <span class="hljs-keyword">address</span> } <span class="hljs-operator">=</span> useAccount();

  <span class="hljs-comment">// custom hook we made in hooks.ts for writing functions</span>
  const { writeAsync, isError } <span class="hljs-operator">=</span>
    useCrowdFactoryFunctionWriter(<span class="hljs-string">"createProject"</span>);

  <span class="hljs-comment">// rainbow kit txn handler</span>
  const addRecentTransaction <span class="hljs-operator">=</span> useAddRecentTransaction();

  <span class="hljs-comment">// onChange handler for title</span>
  const handleTitle <span class="hljs-operator">=</span> (e: ChangeEvent<span class="hljs-operator">&lt;</span>HTMLInputElement<span class="hljs-operator">&gt;</span>) <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> {
    e.preventDefault();

    const value <span class="hljs-operator">=</span> e.target.<span class="hljs-built_in">value</span>;
    DEBUG <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> console.log(<span class="hljs-string">"title: "</span>, value);

    <span class="hljs-comment">// set title</span>
    setTitle(value);
  };

  <span class="hljs-comment">// onChange handler for amount</span>
  const handleAmount <span class="hljs-operator">=</span> (e: ChangeEvent<span class="hljs-operator">&lt;</span>HTMLInputElement<span class="hljs-operator">&gt;</span>) <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> {
    e.preventDefault();

    const value <span class="hljs-operator">=</span> e.target.<span class="hljs-built_in">value</span>;
    DEBUG <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> console.log(<span class="hljs-string">"amount: "</span>, value);

    <span class="hljs-comment">// set amount</span>
    setAmount(value);
  };

  <span class="hljs-comment">// onChange handler for story</span>
  const handleStory <span class="hljs-operator">=</span> (e: ChangeEvent<span class="hljs-operator">&lt;</span>HTMLTextAreaElement<span class="hljs-operator">&gt;</span>) <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> {
    e.preventDefault();

    const value <span class="hljs-operator">=</span> e.target.<span class="hljs-built_in">value</span>;
    DEBUG <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> console.log(<span class="hljs-string">"story: "</span>, value);

    <span class="hljs-comment">// set story</span>
    setStory(value);
  };

  const handleSubmit <span class="hljs-operator">=</span> async (e: FormEvent<span class="hljs-operator">&lt;</span>HTMLFormElement<span class="hljs-operator">&gt;</span>) <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> {
    <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>title <span class="hljs-operator">|</span><span class="hljs-operator">|</span> <span class="hljs-operator">!</span>amount <span class="hljs-operator">|</span><span class="hljs-operator">|</span> <span class="hljs-operator">!</span>story <span class="hljs-operator">|</span><span class="hljs-operator">|</span> <span class="hljs-operator">!</span><span class="hljs-keyword">address</span>) {
      <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-keyword">try</span> {
      e.preventDefault();

      console.log(<span class="hljs-string">"submit!"</span>);

      DEBUG <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> console.log({ title, amount, story });

      const amountToWei <span class="hljs-operator">=</span> toWei(amount);
      DEBUG <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> console.log(<span class="hljs-string">"amountToWei: "</span>, amountToWei);

      const functionArgs: Parameters<span class="hljs-operator">&lt;</span>Crowdfactory[<span class="hljs-string">"createProject"</span>]<span class="hljs-operator">&gt;</span> <span class="hljs-operator">=</span> [
        title,
        amountToWei,
        story,
        <span class="hljs-keyword">address</span>,
      ];
      const <span class="hljs-built_in">tx</span> <span class="hljs-operator">=</span> await writeAsync({
        args: functionArgs,
      });
      console.log(<span class="hljs-string">"tx &gt;&gt;&gt; "</span>, <span class="hljs-built_in">tx</span>);

      addRecentTransaction({
        hash: <span class="hljs-built_in">tx</span>.hash,
        description: <span class="hljs-string">"Create Project Transaction"</span>,
      });
    } <span class="hljs-keyword">catch</span> (<span class="hljs-function"><span class="hljs-keyword">error</span>) </span>{
      console.log(<span class="hljs-string">"errror &gt;&gt;&gt; "</span>, <span class="hljs-function"><span class="hljs-keyword">error</span>)</span>;
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"text-center font-bold text-xl mb-2"</span><span class="hljs-operator">&gt;</span>
        Create Crowdfunding Project
      <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>

      <span class="hljs-operator">&lt;</span>form
        className<span class="hljs-operator">=</span><span class="hljs-string">"bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4"</span>
        onSubmit<span class="hljs-operator">=</span>{handleSubmit}
      <span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"flex flex-wrap -mx-3 mb-6"</span><span class="hljs-operator">&gt;</span>
          <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"w-full md:w-1/2 px-3 mb-6 md:mb-0"</span><span class="hljs-operator">&gt;</span>
            <span class="hljs-operator">&lt;</span>label className<span class="hljs-operator">=</span><span class="hljs-string">"block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"</span><span class="hljs-operator">&gt;</span>
              Campaign Title
            <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>label<span class="hljs-operator">&gt;</span>
            <span class="hljs-operator">&lt;</span>input
              className<span class="hljs-operator">=</span><span class="hljs-string">"appearance-none block w-full bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white"</span>
              <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"text"</span>
              placeholder<span class="hljs-operator">=</span><span class="hljs-string">"Campaign Title"</span>
              onChange<span class="hljs-operator">=</span>{handleTitle}
              required
            <span class="hljs-operator">/</span><span class="hljs-operator">&gt;</span>
          <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>

          <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"w-full md:w-1/2 px-3"</span><span class="hljs-operator">&gt;</span>
            <span class="hljs-operator">&lt;</span>label
              className<span class="hljs-operator">=</span><span class="hljs-string">"block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"</span>
              htmlFor<span class="hljs-operator">=</span><span class="hljs-string">"grid-password"</span>
            <span class="hljs-operator">&gt;</span>
              Required Amount
            <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>label<span class="hljs-operator">&gt;</span>
            <span class="hljs-operator">&lt;</span>input
              className<span class="hljs-operator">=</span><span class="hljs-string">"appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white focus:border-gray-500"</span>
              <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"number"</span>
              min<span class="hljs-operator">=</span>{<span class="hljs-number">0</span>}
              step<span class="hljs-operator">=</span><span class="hljs-string">"0.01"</span>
              placeholder<span class="hljs-operator">=</span><span class="hljs-string">"0.00"</span>
              onChange<span class="hljs-operator">=</span>{handleAmount}
              required
            <span class="hljs-operator">/</span><span class="hljs-operator">&gt;</span>
          <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>

        <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"flex flex-wrap -mx-3 mb-6"</span><span class="hljs-operator">&gt;</span>
          <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"w-full px-3"</span><span class="hljs-operator">&gt;</span>
            <span class="hljs-operator">&lt;</span>label className<span class="hljs-operator">=</span><span class="hljs-string">"block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"</span><span class="hljs-operator">&gt;</span>
              Story
            <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>label<span class="hljs-operator">&gt;</span>
            <span class="hljs-operator">&lt;</span>textarea
              className<span class="hljs-operator">=</span><span class="hljs-string">"appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500"</span>
              placeholder<span class="hljs-operator">=</span><span class="hljs-string">"Story"</span>
              onChange<span class="hljs-operator">=</span>{handleStory}
              required
            <span class="hljs-operator">/</span><span class="hljs-operator">&gt;</span>
          <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>

        <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"md:flex md:items-center"</span><span class="hljs-operator">&gt;</span>
          <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"md:w-1/3"</span><span class="hljs-operator">&gt;</span><span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
          <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"md:w-2/3"</span><span class="hljs-operator">&gt;</span>
            <span class="hljs-operator">&lt;</span>button
              className<span class="hljs-operator">=</span><span class="hljs-string">"shadow bg-purple-500 hover:bg-purple-400 focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded"</span>
              <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"submit"</span>
            <span class="hljs-operator">&gt;</span>
              Create Campaign
            <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>button<span class="hljs-operator">&gt;</span>
          <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>

          {<span class="hljs-comment">/* if error occures display text to try again */</span>}
          {isError <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> (
            <span class="hljs-operator">&lt;</span>p className<span class="hljs-operator">=</span><span class="hljs-string">"text-red-500 text-xs italic"</span><span class="hljs-operator">&gt;</span>
              <span class="hljs-built_in">Error</span> occured<span class="hljs-operator">!</span> Please <span class="hljs-keyword">try</span> again<span class="hljs-operator">!</span>.
            &lt;<span class="hljs-operator">/</span>p<span class="hljs-operator">&gt;</span>
          )}
        <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>form<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span><span class="hljs-operator">&gt;</span>
  );
}

export default CreateCampaign;
</code></pre><p>Now, navigate to "<strong>Campaign.tsx</strong>" file and the edit the following code. Again in this file, we will use custom hook we made in hooks.ts for writing functions along with the UI. This component deals with the details of a single campaign. </p>
<p><strong>File:</strong> <code>src/components/Campaign.tsx</code></p>
<pre><code><span class="hljs-keyword">import</span> { <span class="hljs-title">DEBUG</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../constants"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">useCrowdfundingProjectFunctionWriter</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../hooks"</span>;
<span class="hljs-keyword">import</span> {
  <span class="hljs-title">useGoalAmount</span>,
  <span class="hljs-title">useProjDescription</span>,
  <span class="hljs-title">useProjTitle</span>,
  <span class="hljs-title">usePublishedProjs</span>,
  <span class="hljs-title">useRaisedAmount</span>,
} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../read"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">fromWei</span>, <span class="hljs-title">toWei</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../utils"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">useAddRecentTransaction</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@rainbow-me/rainbowkit"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title"><span class="hljs-keyword">type</span></span> { <span class="hljs-title">ChangeEvent</span>, <span class="hljs-title">MouseEvent</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">useState</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"react"</span>;

export <span class="hljs-keyword">type</span> CampaignProps <span class="hljs-operator">=</span> { projectNumber: number };

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Campaign</span>(<span class="hljs-params">{ projectNumber }: CampaignProps</span>) </span>{
  DEBUG <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> console.log(<span class="hljs-string">"projectNumber: "</span>, projectNumber);

  const [value, setValue] <span class="hljs-operator">=</span> useState<span class="hljs-operator">&lt;</span><span class="hljs-keyword">string</span><span class="hljs-operator">&gt;</span>(<span class="hljs-string">""</span>);

  const publishedProjsAddress <span class="hljs-operator">=</span> usePublishedProjs(projectNumber);

  const projTitle <span class="hljs-operator">=</span> useProjTitle(publishedProjsAddress <span class="hljs-operator">|</span><span class="hljs-operator">|</span> <span class="hljs-string">""</span>);
  const projDescription <span class="hljs-operator">=</span> useProjDescription(publishedProjsAddress <span class="hljs-operator">|</span><span class="hljs-operator">|</span> <span class="hljs-string">""</span>);
  const goalAmount <span class="hljs-operator">=</span> useGoalAmount(publishedProjsAddress <span class="hljs-operator">|</span><span class="hljs-operator">|</span> <span class="hljs-string">""</span>);
  const raisedAmount <span class="hljs-operator">=</span> useRaisedAmount(publishedProjsAddress <span class="hljs-operator">|</span><span class="hljs-operator">|</span> <span class="hljs-string">""</span>);

  DEBUG <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span>
    console.log({
      publishedProjsAddress,
      projTitle,
      projDescription,
      goalAmount,
      raisedAmount,
    });

  <span class="hljs-comment">// rainbow kit txn handler</span>
  const addRecentTransaction <span class="hljs-operator">=</span> useAddRecentTransaction();

  <span class="hljs-comment">// custom hook we made in hooks.ts for writing functions</span>
  const { writeAsync, isError } <span class="hljs-operator">=</span> useCrowdfundingProjectFunctionWriter({
    contractAddress: publishedProjsAddress <span class="hljs-operator">|</span><span class="hljs-operator">|</span> <span class="hljs-string">""</span>,
    functionName: <span class="hljs-string">"makeDonation"</span>,
  });

  const handleValue <span class="hljs-operator">=</span> (e: ChangeEvent<span class="hljs-operator">&lt;</span>HTMLInputElement<span class="hljs-operator">&gt;</span>) <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> {
    e.preventDefault();

    const inputValue <span class="hljs-operator">=</span> e.target.<span class="hljs-built_in">value</span>;
    DEBUG <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> console.log(<span class="hljs-string">"value: "</span>, inputValue);

    <span class="hljs-comment">// set value</span>
    setValue(inputValue);
  };

  const handleDonate <span class="hljs-operator">=</span> async (e: MouseEvent<span class="hljs-operator">&lt;</span>HTMLButtonElement<span class="hljs-operator">&gt;</span>) <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> {
    <span class="hljs-keyword">try</span> {
      e.preventDefault();

      const valueToWei <span class="hljs-operator">=</span> toWei(value);
      DEBUG <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> console.log(<span class="hljs-string">"valueToWei: "</span>, valueToWei);

      const <span class="hljs-built_in">tx</span> <span class="hljs-operator">=</span> await writeAsync({
        overrides: {
          <span class="hljs-built_in">value</span>: valueToWei,
        },
      });
      console.log(<span class="hljs-string">"tx &gt;&gt;&gt; "</span>, <span class="hljs-built_in">tx</span>);

      addRecentTransaction({
        hash: <span class="hljs-built_in">tx</span>.hash,
        description: `Donate ${value} MATIC`,
      });
    } <span class="hljs-keyword">catch</span> (<span class="hljs-function"><span class="hljs-keyword">error</span>) </span>{
      console.log(<span class="hljs-string">"errror &gt;&gt;&gt; "</span>, <span class="hljs-function"><span class="hljs-keyword">error</span>)</span>;
    }
  };

  <span class="hljs-keyword">if</span> (
    <span class="hljs-operator">!</span>publishedProjsAddress <span class="hljs-operator">|</span><span class="hljs-operator">|</span>
    <span class="hljs-operator">!</span>projTitle <span class="hljs-operator">|</span><span class="hljs-operator">|</span>
    <span class="hljs-operator">!</span>projDescription <span class="hljs-operator">|</span><span class="hljs-operator">|</span>
    <span class="hljs-operator">!</span>goalAmount <span class="hljs-operator">|</span><span class="hljs-operator">|</span>
    <span class="hljs-operator">!</span>raisedAmount
  ) {
    <span class="hljs-keyword">return</span> null;
  }

  <span class="hljs-keyword">return</span> (
    <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"max-w-sm rounded overflow-hidden shadow-lg"</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"px-6 py-4"</span><span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"font-bold text-xl mb-2"</span><span class="hljs-operator">&gt;</span>{projTitle}<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span>p className<span class="hljs-operator">=</span><span class="hljs-string">"text-gray-700 text-base"</span><span class="hljs-operator">&gt;</span>{projDescription}<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>p<span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"px-6 pt-4 pb-2"</span><span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span>span className<span class="hljs-operator">=</span><span class="hljs-string">"inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2"</span><span class="hljs-operator">&gt;</span>
          Goal Amount:
          <span class="hljs-operator">&lt;</span>span className<span class="hljs-operator">=</span><span class="hljs-string">"text-purple-700"</span><span class="hljs-operator">&gt;</span>{fromWei(goalAmount)} MATIC<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>span<span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>span<span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span>span className<span class="hljs-operator">=</span><span class="hljs-string">"inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2"</span><span class="hljs-operator">&gt;</span>
          Raised Amount:
          <span class="hljs-operator">&lt;</span>span className<span class="hljs-operator">=</span><span class="hljs-string">"text-purple-700"</span><span class="hljs-operator">&gt;</span>{fromWei(raisedAmount)} MATIC<span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>span<span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>span<span class="hljs-operator">&gt;</span>

        <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"flex items-center py-2"</span><span class="hljs-operator">&gt;</span>
          <span class="hljs-operator">&lt;</span>input
            className<span class="hljs-operator">=</span><span class="hljs-string">"appearance-none bg-transparent border-none w-full text-gray-700 mr-3 py-1 px-2 leading-tight focus:outline-none"</span>
            <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"number"</span>
            placeholder<span class="hljs-operator">=</span><span class="hljs-string">"0.000"</span>
            min<span class="hljs-operator">=</span>{<span class="hljs-number">0</span>}
            step<span class="hljs-operator">=</span><span class="hljs-string">"0.001"</span>
            required
            onChange<span class="hljs-operator">=</span>{handleValue}
          <span class="hljs-operator">/</span><span class="hljs-operator">&gt;</span>
          <span class="hljs-operator">&lt;</span>button
            className<span class="hljs-operator">=</span><span class="hljs-string">"flex-shrink-0 bg-purple-500 hover:bg-purple-400 border-purple-500 hover:border-purple-400 text-sm border-4 text-white py-1 px-2 rounded"</span>
            <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"button"</span>
            onClick<span class="hljs-operator">=</span>{handleDonate}
          <span class="hljs-operator">&gt;</span>
            Donate
          <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>button<span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>

        {<span class="hljs-comment">/* if error occures display text to try again */</span>}
        {isError <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> (
          <span class="hljs-operator">&lt;</span>p className<span class="hljs-operator">=</span><span class="hljs-string">"text-red-500 text-xs italic"</span><span class="hljs-operator">&gt;</span>
            <span class="hljs-built_in">Error</span> occured<span class="hljs-operator">!</span> Please <span class="hljs-keyword">try</span> again<span class="hljs-operator">!</span>.
          &lt;<span class="hljs-operator">/</span>p<span class="hljs-operator">&gt;</span>
        )}
      <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
  );
}

export default Campaign;
</code></pre><p>Last, let's edit the "<strong>Campaigns.tsx</strong>" file and for that, navigate to <code>Campaigns.tsx</code> and add the following code:</p>
<p><strong>File:</strong> <code>src/components/Campaigns.tsx</code></p>
<pre><code><span class="hljs-keyword">import</span> { <span class="hljs-title">DEBUG</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../constants"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">useTotalPublishedProjs</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../read"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title">Campaign</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"./Campaign"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Campaigns</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// for testing no projects yet</span>
  <span class="hljs-comment">// const totalPublishedProjs = 0;</span>

  const totalPublishedProjs <span class="hljs-operator">=</span> useTotalPublishedProjs();
  DEBUG <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span>
    console.log(<span class="hljs-string">"totalPublishedProjs: "</span>, totalPublishedProjs?.toString());

  <span class="hljs-comment">// if totalPublishedProjs not present return nothing</span>
  <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>totalPublishedProjs) {
    <span class="hljs-keyword">return</span> <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"font-bold text-xl mb-2"</span><span class="hljs-operator">&gt;</span>No Projects yet<span class="hljs-operator">!</span><span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>;
  }

  <span class="hljs-keyword">return</span> (
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"text-center font-bold text-xl mb-2"</span><span class="hljs-operator">&gt;</span>
        Crowdfunding Projects
      <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"p-10 grid grid-cols-1 sm:grid-cols-1 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-3 gap-5"</span><span class="hljs-operator">&gt;</span>
        {<span class="hljs-comment">/* create an array starting from 0 index  */</span>}
        {Array.from(Array(totalPublishedProjs).keys()).map(
          (projectNumber: number, i) <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> {
            <span class="hljs-keyword">return</span> (
              <span class="hljs-operator">&lt;</span>div key<span class="hljs-operator">=</span>{i}<span class="hljs-operator">&gt;</span>
                <span class="hljs-operator">&lt;</span>Campaign projectNumber<span class="hljs-operator">=</span>{projectNumber} <span class="hljs-operator">/</span><span class="hljs-operator">&gt;</span>
              <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
            );
          }
        )}
      <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span><span class="hljs-operator">&gt;</span>
  );
}

export default Campaigns;
</code></pre><hr />
<h2 id="heading-step-7-displaying-the-ui">Step 7: Displaying the UI</h2>
<p>Now comes the moment of truth we have been waiting for. All the code, all these functions, contract, and frontend will come together in a form of a single-page application. </p>
<p>In this section, we will edit our "App.tsx" file which will display everything we have been building so far. So let's go and edit the existing code in the file and replace it with this one:</p>
<p><strong>File:</strong> <code>src/App.tsx</code></p>
<pre><code><span class="hljs-keyword">import</span> <span class="hljs-title">Campaigns</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"./components/Campaigns"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title">CreateCampaign</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"./components/CreateCampaign"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">ConnectButton</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@rainbow-me/rainbowkit"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">useAccount</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"wagmi"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  const { isConnected } <span class="hljs-operator">=</span> useAccount();

  <span class="hljs-keyword">return</span> (
    <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"flex flex-col items-center py-8"</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span>h1 className<span class="hljs-operator">=</span><span class="hljs-string">"flex justify-center text-sm sm:text-base md:text-3xl lg:text-4xl pb-10"</span><span class="hljs-operator">&gt;</span>
        Crowdfunding 💜 Show love to your fav project<span class="hljs-operator">!</span>
      <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>h1<span class="hljs-operator">&gt;</span>

      <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"flex justify-center"</span><span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span>ConnectButton
          showBalance<span class="hljs-operator">=</span>{<span class="hljs-literal">false</span>}
          accountStatus<span class="hljs-operator">=</span>{{
            smallScreen: <span class="hljs-string">"avatar"</span>,
            largeScreen: <span class="hljs-string">"full"</span>,
          }}
        <span class="hljs-operator">/</span><span class="hljs-operator">&gt;</span>
      <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>

      {<span class="hljs-operator">!</span>isConnected ? (
        <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"text-center font-bold text-xl m-8"</span><span class="hljs-operator">&gt;</span>
          Please connect to wallet
        <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
      ) : (
        <span class="hljs-operator">&lt;</span><span class="hljs-operator">&gt;</span>
          <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"flex gap-6 mt-8"</span><span class="hljs-operator">&gt;</span>
            <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"flex flex-col"</span><span class="hljs-operator">&gt;</span>
              <span class="hljs-operator">&lt;</span>CreateCampaign <span class="hljs-operator">/</span><span class="hljs-operator">&gt;</span>
            <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
          <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>

          <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"flex gap-6 mt-8"</span><span class="hljs-operator">&gt;</span>
            <span class="hljs-operator">&lt;</span>div className<span class="hljs-operator">=</span><span class="hljs-string">"flex flex-col"</span><span class="hljs-operator">&gt;</span>
              <span class="hljs-operator">&lt;</span>Campaigns <span class="hljs-operator">/</span><span class="hljs-operator">&gt;</span>
            <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
          <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span><span class="hljs-operator">&gt;</span>
      )}
    <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">&gt;</span>
  );
}

export default App;
</code></pre><p>Woah, that was a lot of code that we wrote! Now comes the crunch as we run our dApp in the local dev environment.</p>
<pre><code><span class="hljs-attribute">yarn</span> dev
</code></pre><p>And, here's what you should be able to see! </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1659124425763/IWNzpiSWV.png" alt="Screenshot 2022-07-29 at 5.39.36 AM (2).png" /></p>
<hr />
<h3 id="heading-check-the-github-repo">Check the GitHub Repo</h3>
<p>If you want to take a look at the full source code, find the repo below.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/kaymomin/Crowdfunding-dApp">https://github.com/kaymomin/Crowdfunding-dApp</a></div>
<hr />
<h3 id="heading-next-steps">Next Steps</h3>
<p>If you are up for a fun challenge, extend this project into a full-fleshed platform with additional functionalities in the smart contract and improved UI. </p>
<p>Also, feel free to share your learnings and reach out to me on Twitter @kayprasla if you've any doubts or questions for me.</p>
<p>Happy building! 🛠️</p>
<hr />
]]></content:encoded></item><item><title><![CDATA[Build An NFT Minting Page With RainbowKit & Wagmi]]></title><description><![CDATA[In this tutorial, we will be building a minting page for an NFT collection deployed on the Ethereum Goerli testnet. It will be a Single-Page Application built using modern web3 frontend tools like RainbowKit and wagmi that lets users connect their wa...]]></description><link>https://ankr.hashnode.dev/build-an-nft-minting-page-with-rainbowkit-wagmi</link><guid isPermaLink="true">https://ankr.hashnode.dev/build-an-nft-minting-page-with-rainbowkit-wagmi</guid><category><![CDATA[rainbowkit]]></category><category><![CDATA[#wagmi]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Dhaiwat Pandya]]></dc:creator><pubDate>Thu, 28 Jul 2022 14:57:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1658992482229/vvccFNVC1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this tutorial, we will be building a minting page for an NFT collection deployed on the Ethereum Goerli testnet. It will be a Single-Page Application built using modern web3 frontend tools like <a target="_blank" href="https://rainbowkit.com">RainbowKit</a> and <a target="_blank" href="https://wagmi.sh">wagmi</a> that lets users connect their wallets and mint an NFT. This is what the end result looks like:</p>
<p><img src="https://i.imgur.com/9uAyRIz.gif" alt="https://i.imgur.com/9uAyRIz.gif" /></p>
<p>You can try it out yourself <a target="_blank" href="https://rainbowkit-nft-mint-vite.vercel.app/">here</a>.</p>
<blockquote>
<p>ℹ️ <strong>Note:</strong> The content of this tutorial was prepared with <code>wagmi 0.5.8</code> and <code>rainbowkit 0.4.1</code>. These libraries get updated often and sometimes introduce breaking changes, so please keep that in mind!</p>
</blockquote>
<h2 id="heading-tech-stack">Tech Stack</h2>
<ul>
<li><strong><a target="_blank" href="https://rainbowkit.com">RainbowKit</a> for wallet connections.:</strong> It is made by the same team behind the popular <a target="_blank" href="https://rainbow.me/">Rainbow wallet</a>. It lets developers add a beautiful connect wallet button to their app with just a few lines of code.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1658992167049/Qh1H1mmAR.png" alt="Screen Shot 2022-07-15 at 11.56.13 AM.png" /></p>
<ul>
<li><strong><a target="_blank" href="https://wagmi.sh">wagmi</a> to interact with our smart contract.:</strong> It is a set of React hooks for building frontends for Ethereum &amp; EVM-based dApps. The <a target="_blank" href="https://github.com/tmm/wagmi">wagmi Github repository</a> has over 2,000 stars on GitHub and is quickly becoming the go-to library for React devs.</li>
<li><strong><a target="_blank" href="https://reactjs.org">React</a> and <a target="_blank" href="https://vitejs.dev/">Vite</a> to build our frontend.</strong></li>
<li><strong><a target="_blank" href="https://www.typescriptlang.org/">TypeScript</a> as our programming language.</strong></li>
</ul>
<h2 id="heading-project-setup">Project Setup</h2>
<p>Let's start off by initializing a new Vite project from our terminal. Make sure you have <a target="_blank" href="https://nodejs.org/en/">Node.js</a> installed.</p>
<pre><code class="lang-bash">yarn create vite
</code></pre>
<p><img src="https://i.imgur.com/cpU2ki0.png" alt="https://i.imgur.com/cpU2ki0.png" /></p>
<p>Next, let's <code>cd</code> into our project directory and install the dependencies.</p>
<p><img src="https://i.imgur.com/HW5CjAe.png" alt="https://i.imgur.com/HW5CjAe.png" /></p>
<p>Once those dependencies have been installed, we can run our app locally by running <code>yarn dev</code>.</p>
<p><img src="https://i.imgur.com/lkPz3C8.png" alt="https://i.imgur.com/lkPz3C8.png" /></p>
<p>If you open <a target="_blank" href="http://localhost:3000/">http://localhost:3000</a> in your browser, you should see our app running:</p>
<p><img src="https://i.imgur.com/XkHYMWj.png" alt="https://i.imgur.com/XkHYMWj.png" /></p>
<h2 id="heading-setting-up-rainbowkit-and-wagmi">Setting Up Rainbowkit And wagmi</h2>
<p>We are mostly going to follow the instructions on the <a target="_blank" href="https://www.rainbowkit.com/docs/installation">Rainbowkit installation page</a>.</p>
<p>We'll start by installing some dependencies. On top of the dependencies required by Rainbowkit, let's also install some dependencies for <a target="_blank" href="https://chakra-ui.com/">Chakra UI</a>. We will be using Chakra to help us with some styling.</p>
<p>Run <code>yarn add @rainbow-me/rainbowkit wagmi ethers @chakra-ui/react @emotion/react @emotion/styled framer-motion</code> in your terminal.</p>
<p><img src="https://i.imgur.com/aPtwWEs.png" alt="https://i.imgur.com/aPtwWEs.png" /></p>
<p>Once that's done, let's setup the different providers and clients.</p>
<p><strong>File:</strong> <code>./src/main.tsx</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom/client'</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'@rainbow-me/rainbowkit/styles.css'</span>;
<span class="hljs-keyword">import</span> { getDefaultWallets, RainbowKitProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">'@rainbow-me/rainbowkit'</span>;
<span class="hljs-keyword">import</span> { chain, configureChains, createClient, WagmiConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">'wagmi'</span>;
<span class="hljs-keyword">import</span> { jsonRpcProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">'wagmi/providers/jsonRpc'</span>;
<span class="hljs-keyword">import</span> { publicProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">'wagmi/providers/public'</span>;
<span class="hljs-keyword">import</span> { ChakraProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">'@chakra-ui/react'</span>;

<span class="hljs-keyword">const</span> { chains, provider } = configureChains(
  [chain.goerli], <span class="hljs-comment">// you can add more chains here like chain.mainnet, chain.optimism etc.</span>
  [
    jsonRpcProvider({
      rpc: <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">return</span> {
          http: <span class="hljs-string">'https://rpc.ankr.com/eth_goerli'</span>, <span class="hljs-comment">// go to https://www.ankr.com/protocol/ to get a free RPC for your network</span>
        };
      },
    }),
    publicProvider(),
  ]
);

<span class="hljs-keyword">const</span> { connectors } = getDefaultWallets({
  appName: <span class="hljs-string">'NFT minting dApp'</span>,
  chains,
});

<span class="hljs-keyword">const</span> wagmiClient = createClient({
  autoConnect: <span class="hljs-literal">false</span>,
  connectors,
  provider,
});

ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>)!).render(
  &lt;React.StrictMode&gt;
    &lt;ChakraProvider&gt;
      &lt;WagmiConfig client={wagmiClient}&gt;
        &lt;RainbowKitProvider chains={chains}&gt;
          &lt;App /&gt;
        &lt;/RainbowKitProvider&gt;
      &lt;/WagmiConfig&gt;
    &lt;/ChakraProvider&gt;
  &lt;/React.StrictMode&gt;
);
</code></pre>
<p>That's all the configuration work out of the way.</p>
<h2 id="heading-adding-the-connect-wallet-button">Adding The Connect Wallet Button</h2>
<p>Like I mentioned earlier, Rainbowkit makes it extremely easy for you to add a connect wallet button to your app. This is all you need:</p>
<p><strong>File:</strong> <code>./src/App.tsx</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Container } <span class="hljs-keyword">from</span> <span class="hljs-string">'@chakra-ui/react'</span>;
<span class="hljs-keyword">import</span> { ConnectButton } <span class="hljs-keyword">from</span> <span class="hljs-string">'@rainbow-me/rainbowkit'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;Container paddingY=<span class="hljs-string">'10'</span>&gt;
      &lt;ConnectButton /&gt;
    &lt;/Container&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>You should now see a fully-functional connect wallet button in your app! It's that easy.</p>
<p><img src="https://i.imgur.com/TYMqrdr.png" alt="https://i.imgur.com/TYMqrdr.png" /></p>
<p><img src="https://i.imgur.com/zlGWMpv.jpg" alt="https://i.imgur.com/zlGWMpv.jpg" /></p>
<h2 id="heading-loading-up-the-smart-contract">Loading Up The Smart Contract</h2>
<p>We will be minting NFTs from a smart contract that has already been deployed at <a target="_blank" href="https://goerli.etherscan.io/address/0xaa3906f986e0cd86e64c1e30ce500c1de1ef46ad">0xaa3906f986e0cd86e64c1e30ce500c1de1ef46ad</a> on the Goerli testnet. I have verified the contract so you can view the source code on Etherscan too if you are curious.</p>
<blockquote>
<p>💡 If you want to learn how to write and deploy your own ERC721 NFT smart contract, I highly recommend checking out this tutorial: <a target="_blank" href="https://ankr.hashnode.dev/deploy-and-mint-a-cryptokitties-like-nft-with-erc-721-smart-contract">https://ankr.hashnode.dev/deploy-and-mint-a-cryptokitties-like-nft-with-erc-721-smart-contract</a></p>
</blockquote>
<p><img src="https://i.imgur.com/WvVZxbS.jpg" alt="https://i.imgur.com/WvVZxbS.jpg" /></p>
<p>On top of the address of the contract, we'll also need its ABI (<a target="_blank" href="https://ernestognw.medium.com/what-is-a-smart-contracts-abi-anyways-a-guide-to-understand-client-blockchain-communication-7b68fb6ae466">What's an ABI?</a>). Create a new file named <code>abiFile.json</code> inside the <code>src</code> directory.</p>
<p>Copy and paste the contents of <a target="_blank" href="https://github.com/Dhaiwat10/rainbowkit-nft-mint-vite/blob/main/src/abiFile.json">this file</a> into your <code>abiFile.json</code> file.</p>
<h2 id="heading-displaying-the-image-of-the-nft">Displaying The Image Of The NFT</h2>
<p>For convenience's sake, the smart contract we are using for this tutorial uses the same image for all the NFTs it mints. It has a variable named <code>commonTokenURI</code> which holds a link to the metadata of our NFT.</p>
<p>We will have to call a function with the same name in order to get the URI for our NFT's image. We'll be using the <code>useContractRead</code> hook from our wagmi node package to do this.</p>
<p><strong>File:</strong> <code>./src/App.tsx</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Container } <span class="hljs-keyword">from</span> <span class="hljs-string">'@chakra-ui/react'</span>;
<span class="hljs-keyword">import</span> { ConnectButton } <span class="hljs-keyword">from</span> <span class="hljs-string">'@rainbow-me/rainbowkit'</span>;
<span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { useContractRead } <span class="hljs-keyword">from</span> <span class="hljs-string">'wagmi'</span>;
<span class="hljs-keyword">import</span> abiFile <span class="hljs-keyword">from</span> <span class="hljs-string">'./abiFile.json'</span>;

<span class="hljs-keyword">const</span> CONTRACT_ADDRESS = <span class="hljs-string">'0xaa3906f986e0cd86e64c1e30ce500c1de1ef46ad'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> contractConfig = {
    addressOrName: CONTRACT_ADDRESS,
    contractInterface: abiFile.abi,
  };

  <span class="hljs-keyword">const</span> { data: tokenURI } = useContractRead({
    ...contractConfig,
    functionName: <span class="hljs-string">'commonTokenURI'</span>,
  }); <span class="hljs-comment">// calling the 'commonTokenURI' function in our contract</span>

    <span class="hljs-comment">// Log the fetched tokenURI to the console</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log({ tokenURI });
  }, [tokenURI]);

  <span class="hljs-keyword">return</span> (
    &lt;Container paddingY=<span class="hljs-string">'10'</span>&gt;
      &lt;ConnectButton /&gt;
    &lt;/Container&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Go back to your app and open the console in your browser. You should see the token URI being logged.</p>
<p><img src="https://i.imgur.com/YBOq1P1.png" alt="https://i.imgur.com/YBOq1P1.png" /></p>
<p>Let's open this link. As you can see, it's just a JSON file hosted on IPFS: <a target="_blank" href="https://gateway.pinata.cloud/ipfs/QmPf2x91DoemnhXSZhGDP8TX9Co8AScpvFzTuFt9BGAoBY">https://gateway.pinata.cloud/ipfs/QmPf2x91DoemnhXSZhGDP8TX9Co8AScpvFzTuFt9BGAoBY</a>.</p>
<p><img src="https://i.imgur.com/hSjokNr.jpg" alt="https://i.imgur.com/hSjokNr.jpg" /></p>
<p>If you open the link associated with the <code>image</code> field in that file, you should see this:</p>
<p><img src="https://i.imgur.com/oL6ug5k.jpg" alt="https://i.imgur.com/oL6ug5k.jpg" /></p>
<p>This is the image for our NFTs. A good ol' blue Ankr logo!</p>
<p>Since we want to display this image in our app, let's go about grabbing a link to it from the <code>tokenURI</code> we fetched from the <code>commonTokenURI</code> function on our contract.</p>
<p><strong>File:</strong> <code>./src/App.tsx</code></p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> contractConfig = {
    addressOrName: CONTRACT_ADDRESS,
    contractInterface: abiFile.abi,
  };

  <span class="hljs-keyword">const</span> { data: tokenURI } = useContractRead({
    ...contractConfig,
    functionName: <span class="hljs-string">'commonTokenURI'</span>,
  });
  <span class="hljs-keyword">const</span> [imgURL, setImgURL] = useState(<span class="hljs-string">''</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    (<span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">if</span> (tokenURI) {
        <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> (<span class="hljs-keyword">await</span> fetch(tokenURI <span class="hljs-keyword">as</span> unknown <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>)).json();
        setImgURL(res.image);
      }
    })();
  }, [tokenURI]);

  <span class="hljs-keyword">return</span> (
    &lt;Container paddingY=<span class="hljs-string">'10'</span>&gt;
      &lt;ConnectButton /&gt;
      &lt;Image src={imgURL} width=<span class="hljs-string">'200px'</span> /&gt;
    &lt;/Container&gt;
  );
}
</code></pre>
<p>You should now see the image showing up in your app. Nice!</p>
<p><img src="https://i.imgur.com/kgK1YM7.png" alt="https://i.imgur.com/kgK1YM7.png" /></p>
<p>Let's tidy up our page a little bit and add a loading indicator for the image before we move on.</p>
<p><strong>File:</strong> <code>./src/App.tsx</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Box, Container, Image, Skeleton, Text } <span class="hljs-keyword">from</span> <span class="hljs-string">'@chakra-ui/react'</span>;
<span class="hljs-keyword">import</span> { ConnectButton } <span class="hljs-keyword">from</span> <span class="hljs-string">'@rainbow-me/rainbowkit'</span>;
<span class="hljs-keyword">import</span> { motion } <span class="hljs-keyword">from</span> <span class="hljs-string">'framer-motion'</span>;
<span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { useContractRead } <span class="hljs-keyword">from</span> <span class="hljs-string">'wagmi'</span>;
<span class="hljs-keyword">import</span> abiFile <span class="hljs-keyword">from</span> <span class="hljs-string">'./abiFile.json'</span>;

<span class="hljs-keyword">const</span> CONTRACT_ADDRESS = <span class="hljs-string">'0xaa3906f986e0cd86e64c1e30ce500c1de1ef46ad'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> contractConfig = {
    addressOrName: CONTRACT_ADDRESS,
    contractInterface: abiFile.abi,
  };

  <span class="hljs-keyword">const</span> { data: tokenURI } = useContractRead({
    ...contractConfig,
    functionName: <span class="hljs-string">'commonTokenURI'</span>,
  });
  <span class="hljs-keyword">const</span> [imgURL, setImgURL] = useState(<span class="hljs-string">''</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    (<span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">if</span> (tokenURI) {
        <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> (<span class="hljs-keyword">await</span> fetch(tokenURI <span class="hljs-keyword">as</span> unknown <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>)).json();
        setImgURL(res.image);
      }
    })();
  }, [tokenURI]);

  <span class="hljs-keyword">return</span> (
    &lt;Container paddingY=<span class="hljs-string">'10'</span>&gt;
      &lt;ConnectButton /&gt;
      &lt;Text marginTop=<span class="hljs-string">'4'</span>&gt;This is the NFT we will be minting!&lt;/Text&gt;

      {imgURL ? (
        &lt;Box
          <span class="hljs-keyword">as</span>={motion.div}
          borderColor=<span class="hljs-string">'gray.200'</span>
          borderWidth=<span class="hljs-string">'1px'</span>
          width=<span class="hljs-string">'fit-content'</span>
          marginTop=<span class="hljs-string">'4'</span>
          padding=<span class="hljs-string">'6'</span>
          shadow=<span class="hljs-string">'md'</span>
          rounded=<span class="hljs-string">'lg'</span>
          whileHover={{ scale: <span class="hljs-number">1.05</span> }}
          whileTap={{ scale: <span class="hljs-number">0.95</span> }}
        &gt;
          &lt;Image src={imgURL} width=<span class="hljs-string">'200px'</span> /&gt;
        &lt;/Box&gt;
      ) : (
        &lt;Skeleton marginTop=<span class="hljs-string">'4'</span> width=<span class="hljs-string">'250px'</span> height=<span class="hljs-string">'250px'</span> rounded=<span class="hljs-string">'lg'</span> /&gt;
      )}
    &lt;/Container&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Our app looks much better now.</p>
<p><img src="https://i.imgur.com/hFqKEpu.jpg" alt="https://i.imgur.com/hFqKEpu.jpg" /></p>
<h2 id="heading-adding-the-mint-functionality">Adding the mint functionality</h2>
<p>It's now time to add the logic that will let people mint NFTs! We're gonna start by placing a nice button on our page. We'll also call a function named <code>onMintClick</code> when someone clicks this button.</p>
<p>To mint an NFT, we will be calling the <code>mint</code> function on our smart contract. We'll be using the <code>useContractWrite</code> hook from our wagmi node package for this.</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">const</span> { address } = useAccount();
  <span class="hljs-keyword">const</span> { writeAsync: mint, error: mintError } = useContractWrite({
    ...contractConfig,
    functionName: <span class="hljs-string">'mint'</span>,
  });
  <span class="hljs-keyword">const</span> [mintLoading, setMintLoading] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> onMintClick = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> tx = <span class="hljs-keyword">await</span> mint({
        args: [
          address,
          {
            value: ethers.utils.parseEther(<span class="hljs-string">'0.001'</span>),
          },
        ],
      });
      <span class="hljs-keyword">const</span> receipt = <span class="hljs-keyword">await</span> tx.wait();
      <span class="hljs-built_in">console</span>.log({ receipt });
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(error);
    } <span class="hljs-keyword">finally</span> {
      setMintLoading(<span class="hljs-literal">false</span>);
    }
  };
</code></pre>
<p>Before proceeding, make sure you have some Goerli ETH in your account. You can grab some from <a target="_blank" href="https://faucet.paradigm.xyz/">this generous faucet by Paradigm</a>.</p>
<p>Once you have some test ETH, you can finally click that mint button and see what happens. Confirm the transaction request in your wallet and you should see something like this being logged out in your console:</p>
<p><img src="https://i.imgur.com/21sVskX.png" alt="https://i.imgur.com/21sVskX.png" /></p>
<p>That's the transaction receipt of an NFT you just successfully minted! Cool. Our code is working.</p>
<p>Next we’re going to clean up the UI a bit and add one or two additional pieces of functionality. Once the user successfully mints an NFT, we'll show them a link to their NFT on <a target="_blank" href="https://opensea.io/">Opensea</a>.</p>
<p>We will also handle errors if there are any because that's what good devs do.</p>
<p><strong>File:</strong> <code>./src/App.tsx</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> {
  Button,
  Container,
  Text,
  Image,
  Box,
  Link,
  Skeleton,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'@chakra-ui/react'</span>;
<span class="hljs-keyword">import</span> { ConnectButton } <span class="hljs-keyword">from</span> <span class="hljs-string">'@rainbow-me/rainbowkit'</span>;
<span class="hljs-keyword">import</span> { ethers } <span class="hljs-keyword">from</span> <span class="hljs-string">'ethers'</span>;
<span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { useAccount, useContractRead, useContractWrite } <span class="hljs-keyword">from</span> <span class="hljs-string">'wagmi'</span>;
<span class="hljs-keyword">import</span> abiFile <span class="hljs-keyword">from</span> <span class="hljs-string">'./abiFile.json'</span>;
<span class="hljs-keyword">import</span> { motion } <span class="hljs-keyword">from</span> <span class="hljs-string">'framer-motion'</span>;

<span class="hljs-keyword">const</span> CONTRACT_ADDRESS = <span class="hljs-string">'0xaa3906f986e0cd86e64c1e30ce500c1de1ef46ad'</span>;

<span class="hljs-keyword">const</span> getOpenSeaURL = <span class="hljs-function">(<span class="hljs-params">tokenId: <span class="hljs-built_in">string</span> | <span class="hljs-built_in">number</span></span>) =&gt;</span>
  <span class="hljs-string">`https://testnets.opensea.io/assets/goerli/<span class="hljs-subst">${CONTRACT_ADDRESS}</span>/<span class="hljs-subst">${tokenId}</span>`</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> contractConfig = {
    addressOrName: CONTRACT_ADDRESS,
    contractInterface: abiFile.abi,
  };
  <span class="hljs-keyword">const</span> { data: tokenURI } = useContractRead({
    ...contractConfig,
    functionName: <span class="hljs-string">'commonTokenURI'</span>,
  });
  <span class="hljs-keyword">const</span> [imgURL, setImgURL] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> { writeAsync: mint, error: mintError } = useContractWrite({
    ...contractConfig,
    functionName: <span class="hljs-string">'mint'</span>,
  });
  <span class="hljs-keyword">const</span> [mintLoading, setMintLoading] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> { address } = useAccount();
  <span class="hljs-keyword">const</span> isConnected = !!address;
  <span class="hljs-keyword">const</span> [mintedTokenId, setMintedTokenId] = useState&lt;<span class="hljs-built_in">number</span>&gt;();

  <span class="hljs-keyword">const</span> onMintClick = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      setMintLoading(<span class="hljs-literal">true</span>);
      <span class="hljs-keyword">const</span> tx = <span class="hljs-keyword">await</span> mint({
        args: [address, { value: ethers.utils.parseEther(<span class="hljs-string">'0.001'</span>) }],
      });
      <span class="hljs-keyword">const</span> receipt = <span class="hljs-keyword">await</span> tx.wait();
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'TX receipt'</span>, receipt);
      <span class="hljs-comment">// @ts-ignore</span>
      <span class="hljs-keyword">const</span> mintedTokenId = <span class="hljs-keyword">await</span> receipt.events[<span class="hljs-number">0</span>].args[<span class="hljs-number">2</span>].toString();
      setMintedTokenId(mintedTokenId);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(error);
    } <span class="hljs-keyword">finally</span> {
      setMintLoading(<span class="hljs-literal">false</span>);
    }
  };

  useEffect(<span class="hljs-function">() =&gt;</span> {
    (<span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">if</span> (tokenURI) {
        <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> (<span class="hljs-keyword">await</span> fetch(tokenURI <span class="hljs-keyword">as</span> unknown <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>)).json();
        setImgURL(res.image);
      }
    })();
  }, [tokenURI]);

  <span class="hljs-keyword">return</span> (
    &lt;Container paddingY=<span class="hljs-string">'10'</span>&gt;
      &lt;ConnectButton /&gt;

      &lt;Text marginTop=<span class="hljs-string">'4'</span>&gt;This is the NFT we will be minting!&lt;/Text&gt;

      {imgURL ? (
        &lt;Box
          <span class="hljs-keyword">as</span>={motion.div}
          borderColor=<span class="hljs-string">'gray.200'</span>
          borderWidth=<span class="hljs-string">'1px'</span>
          width=<span class="hljs-string">'fit-content'</span>
          marginTop=<span class="hljs-string">'4'</span>
          padding=<span class="hljs-string">'6'</span>
          shadow=<span class="hljs-string">'md'</span>
          rounded=<span class="hljs-string">'lg'</span>
          whileHover={{ scale: <span class="hljs-number">1.05</span> }}
          whileTap={{ scale: <span class="hljs-number">0.95</span> }}
        &gt;
          &lt;Image src={imgURL} width=<span class="hljs-string">'200px'</span> /&gt;
        &lt;/Box&gt;
      ) : (
        &lt;Skeleton marginTop=<span class="hljs-string">'4'</span> width=<span class="hljs-string">'250px'</span> height=<span class="hljs-string">'250px'</span> rounded=<span class="hljs-string">'lg'</span> /&gt;
      )}

      &lt;Button
        disabled={!isConnected || mintLoading}
        marginTop=<span class="hljs-string">'6'</span>
        onClick={onMintClick}
        textColor=<span class="hljs-string">'white'</span>
        bg=<span class="hljs-string">'blue.500'</span>
        _hover={{
          bg: <span class="hljs-string">'blue.700'</span>,
        }}
      &gt;
        {isConnected ? <span class="hljs-string">'🎉 Mint'</span> : <span class="hljs-string">'🎉 Mint (Connect Wallet)'</span>}
      &lt;/Button&gt;

      {mintError &amp;&amp; (
        &lt;Text marginTop=<span class="hljs-string">'4'</span>&gt;⛔️ Mint unsuccessful! <span class="hljs-built_in">Error</span> message:&lt;/Text&gt;
      )}

      {mintError &amp;&amp; (
        &lt;pre style={{ marginTop: <span class="hljs-string">'8px'</span>, color: <span class="hljs-string">'red'</span> }}&gt;
          &lt;code&gt;{<span class="hljs-built_in">JSON</span>.stringify(mintError, <span class="hljs-literal">null</span>, <span class="hljs-string">' '</span>)}&lt;/code&gt;
        &lt;/pre&gt;
      )}
      {mintLoading &amp;&amp; &lt;Text marginTop=<span class="hljs-string">'2'</span>&gt;Minting... please wait&lt;/Text&gt;}

      {mintedTokenId &amp;&amp; (
        &lt;Text marginTop=<span class="hljs-string">'2'</span>&gt;
          🥳 Mint successful! You can view your NFT{<span class="hljs-string">' '</span>}
          &lt;Link
            isExternal
            href={getOpenSeaURL(mintedTokenId)}
            color=<span class="hljs-string">'blue'</span>
            textDecoration=<span class="hljs-string">'underline'</span>
          &gt;
            here!
          &lt;/Link&gt;
        &lt;/Text&gt;
      )}
    &lt;/Container&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>That's all! Our NFT minting page is ready now. Go ahead and mint as many NFTs as you want. :)</p>
<p><img src="https://i.imgur.com/9uAyRIz.gif" alt="https://i.imgur.com/9uAyRIz.gif" /></p>
<h2 id="heading-final-code">Final Code</h2>
<p>You can find the final code for this project here: https://github.com/Dhaiwat10/rainbowkit-nft-mint-vite</p>
<h2 id="heading-next-steps">Next Steps</h2>
<ul>
<li>Follow me on Twitter at <a target="_blank" href="https://twitter.com/dhaiwat10">@dhaiwat10</a> 👻</li>
<li>Now that you know how to interact with an NFT smart contract and mint an NFT, you can try something bigger by building out a UI for an NFT marketplace. If you don't want to write an NFT marketplace contract, you can just build a UI for an existing marketplace like <a target="_blank" href="https://docs.zora.co/docs/v3-overview">Zora</a>.</li>
</ul>
<h2 id="heading-other-articles-to-read">Other Articles To Read</h2>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://mirror.xyz/dhaiwat.eth/O5CK6Tjfv8uhl6FPbjT0yZ8LUwViDPWGYHdu9khRWpM">https://mirror.xyz/dhaiwat.eth/O5CK6Tjfv8uhl6FPbjT0yZ8LUwViDPWGYHdu9khRWpM</a></div>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://ankr.hashnode.dev/deploy-a-dapp-with-rainbowkit-ankr-react-and-chakra-ui">https://ankr.hashnode.dev/deploy-a-dapp-with-rainbowkit-ankr-react-and-chakra-ui</a></div>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://ankr.hashnode.dev/deploy-and-mint-a-cryptokitties-like-nft-with-erc-721-smart-contract">https://ankr.hashnode.dev/deploy-and-mint-a-cryptokitties-like-nft-with-erc-721-smart-contract</a></div>
]]></content:encoded></item><item><title><![CDATA[Create a “What’s in Your Wallet?” dApp using Ankr’s Multichain Advanced APIs]]></title><description><![CDATA[In this tutorial, we’ll be building a "What's in Your Wallet?" dApp where users can check their net worth, credits in native balance by chain, and NFTs they hold on multiple blockchains such as Ethereum, Polygon and Fantom (to name a few) using Ankr'...]]></description><link>https://ankr.hashnode.dev/create-a-whats-in-your-wallet-dapp-using-ankrs-multichain-advanced-apis</link><guid isPermaLink="true">https://ankr.hashnode.dev/create-a-whats-in-your-wallet-dapp-using-ankrs-multichain-advanced-apis</guid><category><![CDATA[Ankr]]></category><category><![CDATA[ankrjs]]></category><category><![CDATA[dapps]]></category><category><![CDATA[Web3]]></category><category><![CDATA[wallet]]></category><dc:creator><![CDATA[Krinza Momin]]></dc:creator><pubDate>Wed, 20 Jul 2022 14:01:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1663847054364/T2f_ZZPBO.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this tutorial, we’ll be building a "What's in Your Wallet?" dApp where users can check their net worth, credits in native balance by chain, and NFTs they hold on multiple blockchains such as Ethereum, Polygon and Fantom (to name a few) using <a target="_blank" href="https://www.ankr.com/advanced-api/">Ankr's Advanced Multichain APIs</a>↗.</p>
<h3 id="heading-ankr-advanced-apis">Ankr Advanced APIs</h3>
<p>Ankr's Advanced Multichain APIs are the collection of RPC methods created to simplify querying blockchain data. These APIs does all the heavy lifting for us so that we can query on-chain data in a matter of seconds.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657871478431/qiFtPI3FG.jpg" alt="FTTcMTLX0AIfYIF.jpg" /></p>
<p>Currently, it support eight EVM compatible chains: Ethereum, Fantom, Binance Smart Chain, Polygon, Avalanche, Arbitrum, with more EVM and non-EVM chains coming soon.</p>
<p>To interact with Ankr's Advanced APIs, we are going to use a JavaScript library named <a target="_blank" href="https://www.npmjs.com/package/@ankr.com/ankr.js">Ankr.js</a>↗. Here's the tech stack for this guide:</p>
<ul>
<li><p>Vite.js</p>
</li>
<li><p><a target="_blank" href="https://tailwindcss.com/docs/guides/vite">TailwindCSS</a>↗ as CSS framework (follow their official guide to set it up)</p>
</li>
<li><p>Ankr's Advanced APIs for querying blockchain data</p>
</li>
</ul>
<p>Here's what you'll be able to build by the end of this tutorial:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657793282262/h0GR1HWPh.png" alt="screely-1657793270241.png" /></p>
<p>Now that we have a basic understanding of what we are building and the tools we will be using to achieve the outcome, we can start building our dApp!</p>
<hr />
<h2 id="heading-getting-started">Getting Started</h2>
<p><strong>Prerequisite</strong>: To successfully finish this guide, you'll only need <a target="_blank" href="https://nodejs.org/">Node.js</a> and <a target="_blank" href="https://yarnpkg.com/">Yarn</a> installed on your machine.</p>
<p>We will begin the project by forking this Vite + Tailwind CSS + RainbowKit 🌈 <a target="_blank" href="https://github.com/kaymomin/StarterKit-DefiDashboard">starter repository</a>↗. We can do so by clicking the 'fork' button at the top-right of the linked GitHub page. It has some basic configurations and setup to get us started with our dApp.</p>
<blockquote>
<p>Note in the code block below, make sure you paste the repo URL of your own cloned repository.</p>
</blockquote>
<p>Once the repository has been forked, we will clone it locally to get building on top of it by following the steps below:</p>
<ul>
<li>Navigate into a directory of your choice and run the following command in your terminal to set up a local clone of the starter-kit</li>
</ul>
<pre><code class="lang-plaintext">git clone https://github.com/kaymomin/StarterKit-DefiDashboard
</code></pre>
<ul>
<li>Now, let's navigate into the cloned directory and install the dependencies in the following section</li>
</ul>
<pre><code class="lang-plaintext">cd starterkit-defidashboard
</code></pre>
<pre><code class="lang-plaintext">yarn
</code></pre>
<hr />
<h3 id="heading-installing-ankrjs">Installing Ankr.js</h3>
<p>In this section, we will install and set up Ankr.js for querying NFTs and Tokens related data from the blockchain for a given wallet address.</p>
<p>We will start by installing the <code>ankr.js</code> package from npm:</p>
<pre><code class="lang-plaintext">yarn add @ankr.com/ankr.js
</code></pre>
<p>Now that we have installed the Ankr.js library, let's head to the VSCode and open the <code>starterkit-defidashboard</code> folder in our code editor.</p>
<p>To launch the starter kit, run the following command in the VSCode terminal: <code>yarn dev</code> and you will be able to see the start-kit webpage. Here's the <a target="_blank" href="https://defidashboard-starterkit.vercel.app/">live demo</a>↗ of what the site will look like at this point.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1658325413444/i_Rb881pe.png" alt="Screen Shot 2022-07-18 at 5.26.26 AM.png" /></p>
<hr />
<h3 id="heading-setting-up-ankrjs">Setting Up Ankr.js</h3>
<ul>
<li>Now to set up Ankr.js, create a new file named <code>api.ts</code> under the <code>src</code> directory. We will initialize Ankr.js in this file.</li>
</ul>
<p><strong>File:</strong> <code>src/api.ts</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> AnkrscanProvider <span class="hljs-keyword">from</span> <span class="hljs-string">'@ankr.com/ankr.js'</span>;
<span class="hljs-keyword">import</span> type { Blockchain } <span class="hljs-keyword">from</span> <span class="hljs-string">'@ankr.com/ankr.js/dist/types'</span>;

<span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> AnkrscanProvider(<span class="hljs-string">''</span>);
</code></pre>
<p>To interact with Ankr's Advanced APIs, we have created a provider instance which will serve as an interface to the APIs required to fetch data.</p>
<hr />
<h3 id="heading-creating-function-to-fetch-total-balance">Creating Function to Fetch Total Balance</h3>
<p>In this step, we will first create a <code>getAccountBalance</code> function in the <code>src/api.ts</code> file, which will accept a <code>walletAddress</code>, and return the coin and the respective token balances. Here we are going to utilize the <a target="_blank" href="https://documenter.getpostman.com/view/19024547/UVsEVUGQ#74b5cc68-fba2-415c-a53b-28c08818f970">getAccountBalance</a>↗ method provided by Ankr.js to calculate the sum of balance (net worth) across the chains in the <code>getTotalMultichainBalance</code> function.</p>
<p><strong>File:</strong> <code>src/api.ts</code></p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">import</span> AnkrscanProvider <span class="hljs-keyword">from</span> <span class="hljs-string">'@ankr.com/ankr.js'</span>; <span class="hljs-keyword">import</span> type { Blockchain } <span class="hljs-keyword">from</span> <span class="hljs-string">'@ankr.com/ankr.js/dist/types'</span>;

<span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> AnkrscanProvider(<span class="hljs-string">''</span>);

<span class="hljs-comment">//defining the list of supported blockchains </span>

<span class="hljs-keyword">const</span> listOfChains: Blockchain[] = [<span class="hljs-string">'eth'</span>, <span class="hljs-string">'arbitrum'</span>, <span class="hljs-string">'avalanche'</span>, <span class="hljs-string">'bsc'</span>, <span class="hljs-string">'fantom'</span>, <span class="hljs-string">'polygon'</span>, ];

<span class="hljs-comment">//key-value pair mapping of chains to their native symbols </span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> chainsToNativeSymbols: { [key <span class="hljs-keyword">in</span> Blockchain]: string } = { <span class="hljs-attr">eth</span>: <span class="hljs-string">'ETH'</span>, <span class="hljs-attr">arbitrum</span>: <span class="hljs-string">'ETH'</span>, <span class="hljs-attr">avalanche</span>: <span class="hljs-string">'AVAX'</span>, <span class="hljs-attr">bsc</span>: <span class="hljs-string">'BNB'</span>, <span class="hljs-attr">fantom</span>: <span class="hljs-string">'FTM'</span>, <span class="hljs-attr">polygon</span>: <span class="hljs-string">'MATIC'</span>, };

<span class="hljs-comment">//getAccountBalance function to fetch coins and their respective token balances</span>

 <span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getAccountBalance = <span class="hljs-keyword">async</span> ( walletAddress: string, <span class="hljs-attr">blockchain</span>: Blockchain ) =&gt; { <span class="hljs-keyword">return</span> provider.getAccountBalance({ walletAddress, blockchain, }); };

<span class="hljs-comment">//use getAccountBalance to sum total balance across chains </span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getTotalMultichainBalance = <span class="hljs-keyword">async</span> (walletAddress: string) =&gt; { <span class="hljs-keyword">let</span> total = <span class="hljs-number">0</span>; 

<span class="hljs-keyword">for</span> <span class="hljs-keyword">await</span> (<span class="hljs-keyword">const</span> chain <span class="hljs-keyword">of</span> listOfChains) { 

<span class="hljs-keyword">const</span> { totalBalanceUsd, assets } = <span class="hljs-keyword">await</span> getAccountBalance( walletAddress, chain ); 

total += +totalBalanceUsd; } <span class="hljs-keyword">return</span> total; 

};
</code></pre>
<p>Just to see if things are working, let's call this function on our app i.e. <code>./src/App.tsx</code> and log out the output.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { ConnectButton } <span class="hljs-keyword">from</span> <span class="hljs-string">"@rainbow-me/rainbowkit"</span>;
<span class="hljs-keyword">import</span> { useEffect} <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> {
  getTotalMultichainBalance,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'./api'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{

  useEffect(<span class="hljs-function">() =&gt;</span> {
    (<span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">const</span>  total  = <span class="hljs-keyword">await</span> getTotalMultichainBalance(
        <span class="hljs-comment">//add your wallet address</span>
        <span class="hljs-string">'0xdC4EfDac43475F434482e61805E0df96D2dC1DF4'</span>
      );
      <span class="hljs-built_in">console</span>.log({ total });
    })();
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center py-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-center text-sm sm:text-base md:text-3xl 
lg:text-4xl pb-10"</span>&gt;</span>DefiDashboard 🪙 What's in your Wallet?<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-center"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ConnectButton</span> <span class="hljs-attr">showBalance</span>=<span class="hljs-string">{false}/</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-6 mt-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'flex flex-col'</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>You should be able to see the net-worth or total balance in your browser's console.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657821605390/rMNyZA2BX.png" alt="screely-1657821568622.png" /></p>
<p>You can now revert back the changes we made in the <code>App.tsx</code> file as we will work on it once we create all our functions in <code>api.ts</code> file.</p>
<h3 id="heading-creating-more-functions">Creating More Functions</h3>
<p>Now that we have created a function to get total balance, in this section we will write three more functions as follow:</p>
<ul>
<li><p><strong>getNativeCurrencyBalance:</strong> This function will fetch account balance for a particular chain.</p>
</li>
<li><p><strong>getAllNativeCurrencyBalances:</strong> This function will serve as a loop to get all the native currency balance from the list of blockchains we declared in the above section.</p>
</li>
<li><p><strong>getNfts:</strong> Will returns the list of NFTs owned by the particular address.</p>
</li>
</ul>
<p><strong>File:</strong><code>src/api.ts</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getNativeCurrencyBalance = <span class="hljs-keyword">async</span> ( 
walletAddress: string, 
<span class="hljs-attr">chain</span>: Blockchain 
) =&gt; { 
<span class="hljs-keyword">const</span> { assets } = <span class="hljs-keyword">await</span> getAccountBalance(walletAddress, chain);

<span class="hljs-keyword">const</span> nativeCurrencySymbol = chainsToNativeSymbols[chain]; 
<span class="hljs-keyword">const</span> nativeCurrencyBalance = assets.find( <span class="hljs-function">(<span class="hljs-params">asset</span>) =&gt;</span> asset.tokenSymbol === nativeCurrencySymbol ); 

<span class="hljs-keyword">return</span> nativeCurrencyBalance ? +nativeCurrencyBalance.balance : <span class="hljs-number">0</span>; };

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getAllNativeCurrencyBalances = <span class="hljs-keyword">async</span> (walletAddress: string) =&gt; { <span class="hljs-keyword">const</span> balances: {
 [key <span class="hljs-keyword">in</span> Blockchain]?: number } = {}; 
<span class="hljs-keyword">for</span> <span class="hljs-keyword">await</span> (<span class="hljs-keyword">const</span> chain <span class="hljs-keyword">of</span> listOfChains) { 
<span class="hljs-keyword">const</span> nativeCurrencyBalance = <span class="hljs-keyword">await</span> getNativeCurrencyBalance( walletAddress, chain ); 

balances[chain] = nativeCurrencyBalance; 
} 

<span class="hljs-keyword">return</span> balances; };

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getNfts = <span class="hljs-keyword">async</span> (walletAddress: string) =&gt; { <span class="hljs-keyword">const</span> { assets } = <span class="hljs-keyword">await</span> provider.getNFTsByOwner({ walletAddress, 
<span class="hljs-comment">// blockchain: 'eth', </span>
}
); 
<span class="hljs-keyword">return</span> assets; };
</code></pre>
<p>And with that, we have our <code>api.ts</code> file all ready where we created methods for getting account balance, calculation net worth, fetching balances by native tokens and getting NFTs by owner. You can also find the complete code for this file below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> AnkrscanProvider <span class="hljs-keyword">from</span> <span class="hljs-string">'@ankr.com/ankr.js'</span>;
<span class="hljs-keyword">import</span> type { Blockchain } <span class="hljs-keyword">from</span> <span class="hljs-string">'@ankr.com/ankr.js/dist/types'</span>;

<span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> AnkrscanProvider(<span class="hljs-string">''</span>);

<span class="hljs-keyword">const</span> listOfChains: Blockchain[] = [
  <span class="hljs-string">'eth'</span>,
  <span class="hljs-string">'arbitrum'</span>,
  <span class="hljs-string">'avalanche'</span>,
  <span class="hljs-string">'bsc'</span>,
  <span class="hljs-string">'fantom'</span>,
  <span class="hljs-string">'polygon'</span>,
];

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> chainsToNativeSymbols: { [key <span class="hljs-keyword">in</span> Blockchain]: string } = {
  <span class="hljs-attr">eth</span>: <span class="hljs-string">'ETH'</span>,
  <span class="hljs-attr">arbitrum</span>: <span class="hljs-string">'ETH'</span>,
  <span class="hljs-attr">avalanche</span>: <span class="hljs-string">'AVAX'</span>,
  <span class="hljs-attr">bsc</span>: <span class="hljs-string">'BNB'</span>,
  <span class="hljs-attr">fantom</span>: <span class="hljs-string">'FTM'</span>,
  <span class="hljs-attr">polygon</span>: <span class="hljs-string">'MATIC'</span>,
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getAccountBalance = <span class="hljs-keyword">async</span> (
  walletAddress: string,
  <span class="hljs-attr">blockchain</span>: Blockchain
) =&gt; {
  <span class="hljs-keyword">return</span> provider.getAccountBalance({
    walletAddress,
    blockchain,
  });
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getTotalMultichainBalance = <span class="hljs-keyword">async</span> (walletAddress: string) =&gt; {
  <span class="hljs-keyword">let</span> total = <span class="hljs-number">0</span>;
  <span class="hljs-keyword">for</span> <span class="hljs-keyword">await</span> (<span class="hljs-keyword">const</span> chain <span class="hljs-keyword">of</span> listOfChains) {
    <span class="hljs-keyword">const</span> { totalBalanceUsd, assets } = <span class="hljs-keyword">await</span> getAccountBalance(
      walletAddress,
      chain
    );
    total += +totalBalanceUsd;
  }
  <span class="hljs-keyword">return</span> total;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getNativeCurrencyBalance = <span class="hljs-keyword">async</span> (
  walletAddress: string,
  <span class="hljs-attr">chain</span>: Blockchain
) =&gt; {
  <span class="hljs-keyword">const</span> { assets } = <span class="hljs-keyword">await</span> getAccountBalance(walletAddress, chain);
  <span class="hljs-keyword">const</span> nativeCurrencySymbol = chainsToNativeSymbols[chain];
  <span class="hljs-keyword">const</span> nativeCurrencyBalance = assets.find(
    <span class="hljs-function">(<span class="hljs-params">asset</span>) =&gt;</span> asset.tokenSymbol === nativeCurrencySymbol
  );
  <span class="hljs-keyword">return</span> nativeCurrencyBalance ? +nativeCurrencyBalance.balance : <span class="hljs-number">0</span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getAllNativeCurrencyBalances = <span class="hljs-keyword">async</span> (walletAddress: string) =&gt; {
  <span class="hljs-keyword">const</span> balances: { [key <span class="hljs-keyword">in</span> Blockchain]?: number } = {};
  <span class="hljs-keyword">for</span> <span class="hljs-keyword">await</span> (<span class="hljs-keyword">const</span> chain <span class="hljs-keyword">of</span> listOfChains) {
    <span class="hljs-keyword">const</span> nativeCurrencyBalance = <span class="hljs-keyword">await</span> getNativeCurrencyBalance(
      walletAddress,
      chain
    );
    balances[chain] = nativeCurrencyBalance;
  }
  <span class="hljs-keyword">return</span> balances;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getNfts = <span class="hljs-keyword">async</span> (walletAddress: string) =&gt; {
  <span class="hljs-keyword">const</span> { assets } = <span class="hljs-keyword">await</span> provider.getNFTsByOwner({
    walletAddress,
    <span class="hljs-comment">// blockchain: 'eth',</span>
  });
  <span class="hljs-keyword">return</span> assets;
};
</code></pre>
<h3 id="heading-creating-components-and-frontend">Creating Components and Frontend</h3>
<p>In this section, we will work on <code>App.tsx</code> file where we will create some components that will interact with our functions in <code>api.ts</code> file and build frontend to display the results on our webpage. Here's the code for the <code>App.tsx</code> file:</p>
<p><strong>File:</strong> <code>src/App.tsx</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { ConnectButton } <span class="hljs-keyword">from</span> <span class="hljs-string">"@rainbow-me/rainbowkit"</span>;
<span class="hljs-keyword">import</span> type { Blockchain, Nft } <span class="hljs-keyword">from</span> <span class="hljs-string">'@ankr.com/ankr.js/dist/types'</span>;
<span class="hljs-keyword">import</span> { useEffect, useMemo, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { useAccount } <span class="hljs-keyword">from</span> <span class="hljs-string">'wagmi'</span>;
<span class="hljs-keyword">import</span> {
  chainsToNativeSymbols,
  getAllNativeCurrencyBalances,
  getNfts,
  getTotalMultichainBalance,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'./api'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [totalBalance, setTotalBalance] = useState&lt;number&gt;();
  <span class="hljs-keyword">const</span> [allNativeBalances, setAllNativeBalances] = useState&lt;{
    [key <span class="hljs-keyword">in</span> Blockchain]?: number;
  }&gt;({});
  <span class="hljs-keyword">const</span> [nfts, setNfts] = useState&lt;Nft[]&gt;([]);

  <span class="hljs-keyword">const</span> nativeBalancesSorted = useMemo(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// sort allNativeBalances by value, descending and convert it back to an object</span>
    <span class="hljs-keyword">const</span> res = <span class="hljs-built_in">Object</span>.entries(allNativeBalances).sort(<span class="hljs-function">(<span class="hljs-params">[, a], [, b]</span>) =&gt;</span> b - a);
    <span class="hljs-keyword">return</span> res;
  }, [allNativeBalances]);

  <span class="hljs-keyword">const</span> { address } = useAccount();

  <span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">false</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    (<span class="hljs-keyword">async</span> () =&gt; {
      setLoading(<span class="hljs-literal">true</span>);
      <span class="hljs-keyword">if</span> (!address) {
        <span class="hljs-keyword">return</span>;
      }
      <span class="hljs-keyword">const</span> totalBal = <span class="hljs-keyword">await</span> getTotalMultichainBalance(address);
      <span class="hljs-keyword">const</span> nativeBalances = <span class="hljs-keyword">await</span> getAllNativeCurrencyBalances(address);
      <span class="hljs-keyword">const</span> nfts = <span class="hljs-keyword">await</span> getNfts(address);
      setAllNativeBalances(nativeBalances);
      setTotalBalance(<span class="hljs-built_in">Math</span>.round(totalBal));
      setNfts(nfts);
      setLoading(<span class="hljs-literal">false</span>);
    })();
  }, [address]);



  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center py-8"</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-center text-sm sm:text-base md:text-3xl lg:text-4xl pb-10"</span>&gt;</span>
          DefiDashboard 🪙 What's in your Wallet?
        <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-center"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ConnectButton</span> <span class="hljs-attr">showBalance</span>=<span class="hljs-string">{false}/</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-6 mt-8"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'flex flex-col'</span>&gt;</span>
          {/* Net worth */}
          {totalBalance &amp;&amp; (
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'bg-[#f1f5f9] py-4 px-8 rounded flex flex-col w-[300px] items-center mt-20'</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'text-blue-800 font-bold'</span>&gt;</span>Net Worth<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'text-3xl '</span>&gt;</span>${totalBalance}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          )}

          {/* Native currency balances */}
          {nativeBalancesSorted.length &gt; 0 &amp;&amp; (
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'bg-[#f1f5f9] py-4 px-8 rounded flex flex-col mt-4 w-[300px] items-center'</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'text-blue-800 font-bold'</span>&gt;</span>Wallet<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'mt-4 flex flex-col gap-2'</span>&gt;</span>
                {nativeBalancesSorted.map(([chain, bal], idx) =&gt; (
                  <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{chain</span> + <span class="hljs-attr">idx</span>} <span class="hljs-attr">className</span>=<span class="hljs-string">'capitalize flex flex-col'</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{chain}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'font-bold text-2xl'</span>&gt;</span>
                      {/* @ts-expect-error */}
                      {bal.toFixed(2)} {chainsToNativeSymbols[chain]}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                ))}
              <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          )}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        {/* NFTs section */}
        {nfts.length &gt; 0 &amp;&amp; (
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'mt-8'</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'font-bold text-3xl text-blue-800 text-center'</span>&gt;</span>
              NFTs
            <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'grid grid-cols-3 gap-6'</span>&gt;</span>
              {nfts.map((nft) =&gt; {
                const id = `${nft.contractAddress}/${nft.tokenId}`;

                return (
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
                    <span class="hljs-attr">key</span>=<span class="hljs-string">{id}</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">'bg-[#f1f5f9] py-4 px-8 rounded flex flex-col mt-4 w-[200px] items-center'</span>
                  &gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{nft.imageUrl}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'w-32 h-32 rounded-lg'</span> /&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'text-blue-800 font-bold mt-2'</span>&gt;</span>{nft.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                );
              })}
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        )}

      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Woah, that's a lot of code that we wrote! Now comes the crunch as we run our dApp in the local dev environment.</p>
<pre><code class="lang-bash">yarn dev
</code></pre>
<p>You should now be able to view your net-worth, balances by chain and their native token and ofc the NFTs!!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657871016766/2-e_fGfdP.png" alt="Untitled design (13).png" /></p>
<hr />
<h3 id="heading-check-the-github-repo">Check the GitHub Repo</h3>
<p>If you want to take a look at the full source code, find the repo below.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/kaymomin/multichain-defi-board-dapp">https://github.com/kaymomin/multichain-defi-board-dapp</a></div>
<p> </p>
<hr />
<h3 id="heading-next-steps">Next Steps</h3>
<p>If you are up for a fun challenge, extend this project into a full fleshed defi-dashboard with graphs and improvements in the UI itself. Or you can build a full-stack multichain NFT gallery using <a target="_blank" href="https://www.ankr.com/advanced-api/">Ankr Advanced APIs</a>↗.</p>
<p>Also, feel free to share your learnings and reach out to me on Twitter <a target="_blank" href="https://twitter.com/kayprasla">@kayprasla</a> if you've any doubts or questions for me.</p>
<hr />
<h3 id="heading-explore-more-such-tutorials">Explore More Such Tutorials</h3>
<p>%[https://ankr.hashnode.dev/how-to-build-a-dao-with-zero-lines-of-code-and-yes-there-are-tokens] %[https://ankr.hashnode.dev/nft-20-creating-a-soulbound-token] %[https://ankr.hashnode.dev/deploy-and-mint-a-cryptokitties-like-nft-with-erc-721-smart-contract]</p>
]]></content:encoded></item><item><title><![CDATA[Getting Started With Lens Protocol As A Frontend Developer]]></title><description><![CDATA[It is safe to say that Lens Protocol has been the talk of the town for these past few months in web3. It is the closest thing we have to a decentralized and composable social graph.
The Lens team has conveniently made available an API that indexes al...]]></description><link>https://ankr.hashnode.dev/getting-started-with-lens-protocol-as-a-frontend-developer</link><guid isPermaLink="true">https://ankr.hashnode.dev/getting-started-with-lens-protocol-as-a-frontend-developer</guid><category><![CDATA[lensprotocol]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[React]]></category><category><![CDATA[lens]]></category><dc:creator><![CDATA[Dhaiwat Pandya]]></dc:creator><pubDate>Tue, 19 Jul 2022 21:09:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1658258392022/i4RKE1cLB.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It is safe to say that Lens Protocol has been the talk of the town for these past few months in web3. It is the closest thing we have to a decentralized and composable <a target="_blank" href="https://en.wikipedia.org/wiki/Social_graph">social graph</a>.</p>
<p>The Lens team has conveniently made available an <a target="_blank" href="https://docs.lens.xyz/docs/introduction">API</a> that indexes all of the contracts on the protocol and gives developers, especially frontend devs ease of access to the protocol's data. This API relies on JWT tokens to authenticate users. Our focus for this article will be on learning about how these tokens are used by Lens Protocol to authenticate users and how you can set up a simple user authentication flow on your frontend.</p>
<h2 id="heading-building-an-authenticated-lens-protocol-feed">Building An Authenticated Lens Protocol Feed</h2>
<p>We’ll be building a Next.js app that lets people connect their wallets and then logs into Lens Protocol. As a bonus, we will also show them a timeline of some recommended posts coming straight from the Lens API!</p>
<p><img src="https://i.imgur.com/X1rt7ta.jpg" alt="https://i.imgur.com/X1rt7ta.jpg" /></p>
<h2 id="heading-project-setup-walkthrough">Project Setup Walkthrough</h2>
<p>Let's start by setting up a Next.js project locally. To save us some time, we are going to use a <a target="_blank" href="https://github.com/Dhaiwat10/next-chakra-rainbowkit-wagmi-starter">Next RainbowKit wagmi template</a> I made as a base. It comes along with <a target="_blank" href="https://rainbowkit.com/">Rainbowkit</a>, <a target="_blank" href="https://wagmi.sh/">wagmi</a> and <a target="_blank" href="https://chakra-ui.com/">Chakra UI</a> pre-configured.</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/Dhaiwat10/next-chakra-rainbowkit-wagmi-starter lens-frontend;
</code></pre>
<p>Let's install the dependencies now.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> lens-frontend;

yarn;
</code></pre>
<p>We also need to install two additional dependencies. We will be needing these to fetch data from the <a target="_blank" href="https://docs.lens.xyz/docs/introduction">Lens API</a>.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># ./lens-frontend</span>

yarn add @apollo/client graphql
</code></pre>
<p>Now, let’s look at what we’re working with by running <code>yarn dev</code> and opening our site on <a target="_blank" href="http://localhost:3000/">http://localhost:3000</a>.</p>
<p><img src="https://i.imgur.com/LwW0BFm.png" alt="https://i.imgur.com/LwW0BFm.png" /></p>
<h2 id="heading-api-client-setup">API Client Setup</h2>
<p>Let's get to business! As discussed earlier, we will be using <a target="_blank" href="https://www.apollographql.com/docs/react/">Apollo Client</a> to interact with the Lens API.</p>
<p>Create a new file called <code>utils.js</code> at the root of your project. We'll start by setting up an <a target="_blank" href="https://www.apollographql.com/docs/react/api/link/apollo-link-http/"><code>HttpLink</code></a> to fetch data and an <a target="_blank" href="https://www.apollographql.com/docs/react/api/link/introduction/"><code>ApolloLink</code></a> to take care of authentication. In the end, we are just creating an <a target="_blank" href="https://www.apollographql.com/docs/react/api/core/ApolloClient"><code>ApolloClient</code></a> and passing in both the <code>httpLink</code> and <code>authLink</code>.</p>
<p><strong>File:</strong> <code>./utils.js</code></p>
<pre><code class="lang-jsx"><span class="hljs-comment">// utils.js</span>
<span class="hljs-keyword">import</span> {
  ApolloClient,
  ApolloLink,
  HttpLink,
  InMemoryCache,
  gql
} <span class="hljs-keyword">from</span> <span class="hljs-string">'@apollo/client'</span>;

<span class="hljs-keyword">const</span> API_URL = <span class="hljs-string">'&lt;https://api.lens.dev/&gt;'</span>;

<span class="hljs-comment">// `httpLink` our gateway to the Lens GraphQL API. It lets us request for data from the API and passes it forward</span>
<span class="hljs-keyword">const</span> httpLink = <span class="hljs-keyword">new</span> HttpLink({ <span class="hljs-attr">uri</span>: API_URL });

<span class="hljs-comment">/* `authLink` takes care of passing on the access token along with all of our requests. We will be using session storage to store our access token. 

The reason why we have to account for an access token is that that's what the Lens API uses to authenticate users. This is the token you'll get back when someone successfully signs in. We need to pass this token along with all the requests we made to the API that *need* authentication.
*/</span>
<span class="hljs-keyword">const</span> authLink = <span class="hljs-keyword">new</span> ApolloLink(<span class="hljs-function">(<span class="hljs-params">operation, forward</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> token = sessionStorage.getItem(<span class="hljs-string">'accessToken'</span>);

    operation.setContext({
        <span class="hljs-attr">headers</span>: {
            <span class="hljs-string">'x-access-token'</span>: token ? <span class="hljs-string">`Bearer <span class="hljs-subst">${token}</span>`</span> : <span class="hljs-string">''</span>,
        },
    });

    <span class="hljs-keyword">return</span> forward(operation);
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> apolloClient = <span class="hljs-keyword">new</span> ApolloClient({
    <span class="hljs-attr">link</span>: authLink.concat(httpLink),
    <span class="hljs-attr">cache</span>: <span class="hljs-keyword">new</span> InMemoryCache(),
});
</code></pre>
<h2 id="heading-sign-in-with-lens-setup">Sign-In With Lens Setup</h2>
<p>The next step is to get a brief idea of the general flow of how authentication with the Lens API works.</p>
<p><img src="https://i.imgur.com/mg6snvy.png" alt="https://i.imgur.com/mg6snvy.png" /></p>
<h3 id="heading-1-request-for-a-challenge-text">1. Request For A “Challenge” Text</h3>
<p>To verify the authenticity of requests coming in, the Lens API asks clients to request for a “challenge” text (or prompt) that they must get signed by the user's wallet. This challenge text is nothing but a piece of text containing a timestamp and a random request id (nonce) generated by the API. This is what a challenge text looks like:</p>
<p><img src="https://i.imgur.com/Wq03fIq.png" alt="https://i.imgur.com/Wq03fIq.png" /></p>
<p>Before prompting the user to sign this message with their wallet, we have to retrieve it from the Lens API. Let's set up a <a target="_blank" href="https://www.apollographql.com/docs/react/data/queries/">query</a> for that. Add this to the bottom of your <code>utils.js</code> file.</p>
<p><strong>File:</strong> <code>./utils.js</code></p>
<pre><code class="lang-jsx"><span class="hljs-comment">// ...</span>

<span class="hljs-keyword">const</span> GET_CHALLENGE = <span class="hljs-string">`
    query($request: ChallengeRequest!) {
        challenge(request: $request) { text }
    }
`</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> generateChallenge = <span class="hljs-keyword">async</span> (address) =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> apolloClient.query({
        <span class="hljs-attr">query</span>: gql(GET_CHALLENGE),
        <span class="hljs-attr">variables</span>: {
            <span class="hljs-attr">request</span>: {
                address,
            }
        }
    });
    <span class="hljs-keyword">return</span> res.data.challenge.text;
}
</code></pre>
<p>The <code>generateChallenge</code> function lets us ask the Lens API for a challenge text for the user to sign. Let's now add an actual sign in button to our UI. Go to the <code>pages/index.js</code> file and add this to the markup:</p>
<p><strong>File:</strong> <code>./pages/index.js</code></p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Container</span> <span class="hljs-attr">paddingY</span>=<span class="hljs-string">'10'</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ConnectButton</span> /&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">marginTop</span>=<span class="hljs-string">'2'</span>&gt;</span>Login with Lens<span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span></span>
  );
}
</code></pre>
<p>Next, we are going to create a <code>signIn</code> function and execute it whenever someone clicks the Login button.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Button, Container } <span class="hljs-keyword">from</span> <span class="hljs-string">'@chakra-ui/react'</span>;
<span class="hljs-keyword">import</span> { ConnectButton } <span class="hljs-keyword">from</span> <span class="hljs-string">'@rainbow-me/rainbowkit'</span>;
<span class="hljs-keyword">import</span> { useAccount } <span class="hljs-keyword">from</span> <span class="hljs-string">'wagmi'</span>;
<span class="hljs-keyword">import</span> { generateChallenge } <span class="hljs-keyword">from</span> <span class="hljs-string">'../utils'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { data } = useAccount();
  <span class="hljs-keyword">const</span> address = data?.address;
  <span class="hljs-keyword">const</span> connected = !!data?.address;

  <span class="hljs-keyword">const</span> signIn = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">if</span> (!connected) {
        <span class="hljs-keyword">return</span> alert(<span class="hljs-string">'Please connect your wallet first'</span>);
      }
      <span class="hljs-keyword">const</span> challenge = <span class="hljs-keyword">await</span> generateChallenge(address);
      <span class="hljs-built_in">console</span>.log({ challenge });
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(error);
      alert(<span class="hljs-string">'Error signing in'</span>);
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Container</span> <span class="hljs-attr">paddingY</span>=<span class="hljs-string">'10'</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ConnectButton</span> /&gt;</span>

     <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{signIn}</span> <span class="hljs-attr">marginTop</span>=<span class="hljs-string">'2'</span>&gt;</span>
       Login with Lens
     <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">marginTop</span>=<span class="hljs-string">'2'</span>&gt;</span>Login with Lens<span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span></span>
  );
}
</code></pre>
<p>You should now be able to click on the Login button and see a challenge text being logged in the console.</p>
<p><img src="https://i.imgur.com/pgTLNmu.gif" alt="https://i.imgur.com/pgTLNmu.gif" /></p>
<h3 id="heading-2-ask-the-user-to-sign-the-challenge-text">2. Ask The User To Sign The Challenge Text</h3>
<p>We will use the <code>useSignMessage</code> hook from <a target="_blank" href="https://wagmi.sh/">wagmi</a> to do this. All we need to do is to pass in the <code>challenge</code> to the <code>signMessageAsync</code> function and retrieve the signature.</p>
<p><strong>File:</strong> <code>./pages/index.js</code></p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { useAccount, useSignMessage } <span class="hljs-keyword">from</span> <span class="hljs-string">'wagmi'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { data } = useAccount();
  <span class="hljs-keyword">const</span> address = data?.address;
  <span class="hljs-keyword">const</span> connected = !!data?.address;

    <span class="hljs-comment">// `signMessageAsync` lets us programatically request a message signature from the user's wallet</span>
 <span class="hljs-keyword">const</span> { signMessageAsync } = useSignMessage();

  <span class="hljs-keyword">const</span> signIn = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">if</span> (!connected) {
        <span class="hljs-keyword">return</span> alert(<span class="hljs-string">'Please connect your wallet first'</span>);
      }
      <span class="hljs-keyword">const</span> challenge = <span class="hljs-keyword">await</span> generateChallenge(address);
      <span class="hljs-keyword">const</span> signature = <span class="hljs-keyword">await</span> signMessageAsync({ <span class="hljs-attr">message</span>: challenge });
      <span class="hljs-built_in">console</span>.log({ signature });
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(error);
      alert(<span class="hljs-string">'Error signing in'</span>);
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Container</span> <span class="hljs-attr">paddingY</span>=<span class="hljs-string">'10'</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ConnectButton</span> /&gt;</span>

     <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{signIn}</span> <span class="hljs-attr">marginTop</span>=<span class="hljs-string">'2'</span>&gt;</span>
       Login with Lens
     <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">marginTop</span>=<span class="hljs-string">'2'</span>&gt;</span>Login with Lens<span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span></span>
  );
}
</code></pre>
<p>You should now see a Metamask popup asking you to sign a message and the signed message being logged in the console.</p>
<p><img src="https://i.imgur.com/FiGaS5p.gif" alt="https://i.imgur.com/FiGaS5p.gif" /></p>
<h3 id="heading-3-retrieve-access-token-with-signed-message">3. Retrieve Access Token With Signed Message</h3>
<p>Now that we have a signature, let's send it over to the Lens API for verification. In return, we can expect to get back an access token if the signature is legit.</p>
<p>Go to your <code>utils.js</code> file and add this piece of code to the bottom of your file.</p>
<p><strong>File:</strong> <code>./utils.js</code></p>
<pre><code class="lang-jsx"><span class="hljs-comment">// ...</span>

<span class="hljs-keyword">const</span> AUTHENTICATION = <span class="hljs-string">`
  mutation($request: SignedAuthChallenge!) {
    authenticate(request: $request) {
      accessToken
      refreshToken
    }
 }
`</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> authenticate = <span class="hljs-keyword">async</span> (address, signature) =&gt; {
  <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> apolloClient.mutate({
    <span class="hljs-attr">mutation</span>: gql(AUTHENTICATION),
    <span class="hljs-attr">variables</span>: {
      <span class="hljs-attr">request</span>: {
        address,
        signature,
      },
    },
  });
  <span class="hljs-keyword">return</span> data.authenticate.accessToken;
};
</code></pre>
<p>The <code>authenticate</code> function here is taking in the user's address and the signed message, sending it to the Lens API to get it verified and returning an access token if there is one. We will now make use of this function inside of the <code>signIn</code> function for our UI in our <code>pages/index.js</code> file.</p>
<p><strong>File:</strong> <code>./pages/index.js</code></p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { authenticate, generateChallenge } <span class="hljs-keyword">from</span> <span class="hljs-string">'../utils'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { data } = useAccount();
  <span class="hljs-keyword">const</span> address = data?.address;
  <span class="hljs-keyword">const</span> connected = !!data?.address;
  <span class="hljs-keyword">const</span> { signMessageAsync } = useSignMessage();

  <span class="hljs-keyword">const</span> signIn = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">if</span> (!connected) {
        <span class="hljs-keyword">return</span> alert(<span class="hljs-string">'Please connect your wallet first'</span>);
      }
      <span class="hljs-keyword">const</span> challenge = <span class="hljs-keyword">await</span> generateChallenge(address);
      <span class="hljs-keyword">const</span> signature = <span class="hljs-keyword">await</span> signMessageAsync({ <span class="hljs-attr">message</span>: challenge });
      <span class="hljs-keyword">const</span> accessToken = <span class="hljs-keyword">await</span> authenticate(address, signature);
      <span class="hljs-built_in">console</span>.log({ accessToken });
      <span class="hljs-built_in">window</span>.sessionStorage.setItem(<span class="hljs-string">'accessToken'</span>, accessToken);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(error);
      alert(<span class="hljs-string">'Error signing in'</span>);
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Container</span> <span class="hljs-attr">paddingY</span>=<span class="hljs-string">'10'</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ConnectButton</span> /&gt;</span>

     <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{signIn}</span> <span class="hljs-attr">marginTop</span>=<span class="hljs-string">'2'</span>&gt;</span>
       Login with Lens
     <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">marginTop</span>=<span class="hljs-string">'2'</span>&gt;</span>Login with Lens<span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span></span>
  );
}
</code></pre>
<p>You will also notice that we are calling <code>window.sessionStorage.setItem</code> to store the access token to the browser's session storage. Let me explain why - if you go back to the <code>utils.js</code> file and have a look, you will notice that we are looking for the access token inside the browser's session storage to then pass it along with any further requests.</p>
<p><strong>File:</strong> <code>./utils.js</code></p>
<pre><code class="lang-jsx">
<span class="hljs-comment">// ...</span>

<span class="hljs-keyword">const</span> authLink = <span class="hljs-keyword">new</span> ApolloLink(<span class="hljs-function">(<span class="hljs-params">operation, forward</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> token = sessionStorage.getItem(<span class="hljs-string">'accessToken'</span>);

  operation.setContext({
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">'x-access-token'</span>: token ? <span class="hljs-string">`Bearer <span class="hljs-subst">${token}</span>`</span> : <span class="hljs-string">''</span>,
    },
  });

  <span class="hljs-keyword">return</span> forward(operation);
});
</code></pre>
<p>Let's now go to our browser and try this out. You should now see the access token being stored in the browser's session storage successfully.</p>
<p><img src="https://i.imgur.com/z3CdmmH.gif" alt="https://i.imgur.com/z3CdmmH.gif" /></p>
<p>That's it! That's all you need to do to integrate Login with Lens in your React app. With the setup that we have in place, you don't need to do any additional work in order to make use of the access token in your future API requests. (You may need to tackle <a target="_blank" href="https://docs.lens.xyz/docs/refresh-jwt">refresh tokens</a> if you want to create a production app)</p>
<blockquote>
<p>ℹ️ <strong>Note:</strong> Lens API currently has restricted access to the write endpoints/mutations. You might need to get your domain allowlisted.</p>
</blockquote>
<h2 id="heading-bonus-timeline">Bonus: Timeline</h2>
<p>As a bonus, we will add a simple timeline showing the current top posts on Lens Protocol.</p>
<p>To get started, let's setup a <code>getPublications</code> function in our <code>utils.js</code> file. Add this piece of code to the bottom of it:</p>
<p><strong>File:</strong> <code>./utils.js</code></p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> GET_PUBLICATIONS_QUERY = <span class="hljs-string">`
query {
  explorePublications(request: {
    sortCriteria: TOP_COMMENTED,
    publicationTypes: [POST],
    limit: 20
  }) {
    items {
      __typename
      ... on Post {
        ...PostFields
      }
    }
  }
}

fragment ProfileFields on Profile {
  id
  name
  metadata
  handle
  picture {
    ... on NftImage {
      uri
    }
    ... on MediaSet {
      original {
        ...MediaFields
      }
    }
  }
  stats {
    totalComments
    totalMirrors
    totalCollects
  }
}

fragment MediaFields on Media {
  url
}

fragment PublicationStatsFields on PublicationStats {
  totalAmountOfMirrors
  totalAmountOfCollects
  totalAmountOfComments
}

fragment MetadataOutputFields on MetadataOutput {
    content
  media {
    original {
      ...MediaFields
    }
  }
}

fragment PostFields on Post {
  id
  profile {
    ...ProfileFields
  }
  stats {
    ...PublicationStatsFields
  }
  metadata {
    ...MetadataOutputFields
  }
}
  `</span>;

<span class="hljs-comment">// publications = posts in Lens lingo</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getPublications = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> apolloClient.query({
    <span class="hljs-attr">query</span>: gql(GET_PUBLICATIONS_QUERY),
  });
  <span class="hljs-keyword">return</span> data.explorePublications.items;
};
</code></pre>
<p>It's quite a long GraphQL query I know! This is because we are fetching data about a lot of different fields. Let's now use this <code>getPublications</code> function to show some posts in our UI.</p>
<p>In our <code>pages/index.js</code> file, we want to fetch a list of posts using <code>getPublications</code> and display them in our UI nicely.</p>
<p>Add the following piece of code to your <code>pages/index.js</code> file in order to make this happen.</p>
<p><strong>File:</strong> <code>./pages/index.js</code></p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { authenticate, generateChallenge, getPublications } <span class="hljs-keyword">from</span> <span class="hljs-string">'../utils'</span>;
<span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { data } = useAccount();
  <span class="hljs-keyword">const</span> address = data?.address;
  <span class="hljs-keyword">const</span> connected = !!data?.address;
  <span class="hljs-keyword">const</span> { signMessageAsync } = useSignMessage();

  <span class="hljs-keyword">const</span> [posts, setPosts] = useState([]);

  <span class="hljs-keyword">const</span> signIn = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">if</span> (!connected) {
        <span class="hljs-keyword">return</span> alert(<span class="hljs-string">'Please connect your wallet first'</span>);
      }
      <span class="hljs-keyword">const</span> challenge = <span class="hljs-keyword">await</span> generateChallenge(address);
      <span class="hljs-keyword">const</span> signature = <span class="hljs-keyword">await</span> signMessageAsync({ <span class="hljs-attr">message</span>: challenge });
      <span class="hljs-keyword">const</span> accessToken = <span class="hljs-keyword">await</span> authenticate(address, signature);
      <span class="hljs-built_in">console</span>.log({ accessToken });
      <span class="hljs-built_in">window</span>.sessionStorage.setItem(<span class="hljs-string">'accessToken'</span>, accessToken);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(error);
      alert(<span class="hljs-string">'Error signing in'</span>);
    }
  };

    useEffect(<span class="hljs-function">() =&gt;</span> {
    getPublications().then(setPosts);
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Container</span> <span class="hljs-attr">paddingY</span>=<span class="hljs-string">'10'</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ConnectButton</span> /&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{signIn}</span> <span class="hljs-attr">marginTop</span>=<span class="hljs-string">'2'</span>&gt;</span>
        Login with Lens
      <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">VStack</span> <span class="hljs-attr">spacing</span>=<span class="hljs-string">{4}</span> <span class="hljs-attr">marginY</span>=<span class="hljs-string">'10'</span>&gt;</span>
        {posts
          .filter((post) =&gt; post.__typename === 'Post') // we need to filter the list to make sure we are not rendering anything other than Posts, like comments and other formats.
          .map((post) =&gt; {
            return (
              <span class="hljs-tag">&lt;<span class="hljs-name">VStack</span>
                <span class="hljs-attr">key</span>=<span class="hljs-string">{post.id}</span>
                <span class="hljs-attr">borderWidth</span>=<span class="hljs-string">'0.7px'</span>
                <span class="hljs-attr">paddingX</span>=<span class="hljs-string">'4'</span>
                <span class="hljs-attr">paddingY</span>=<span class="hljs-string">'2'</span>
                <span class="hljs-attr">rounded</span>=<span class="hljs-string">'md'</span>
                <span class="hljs-attr">width</span>=<span class="hljs-string">'full'</span>
                <span class="hljs-attr">alignItems</span>=<span class="hljs-string">'left'</span>
                <span class="hljs-attr">as</span>=<span class="hljs-string">'a'</span>
                <span class="hljs-attr">href</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">https:</span>//<span class="hljs-attr">lenster.xyz</span>/<span class="hljs-attr">posts</span>/${<span class="hljs-attr">post.id</span>}`}
                <span class="hljs-attr">target</span>=<span class="hljs-string">'_blank'</span>
                <span class="hljs-attr">transition</span>=<span class="hljs-string">'all 0.2s'</span>
                <span class="hljs-attr">_hover</span>=<span class="hljs-string">{{</span>
                  <span class="hljs-attr">shadow:</span> '<span class="hljs-attr">md</span>',
                }}
              &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">HStack</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">Avatar</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{post.profile.picture.original.url}</span> /&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">Text</span> <span class="hljs-attr">fontWeight</span>=<span class="hljs-string">'bold'</span> <span class="hljs-attr">justifyContent</span>=<span class="hljs-string">'left'</span>&gt;</span>
                    {post.profile?.handle || post.profile?.id}
                  <span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">HStack</span>&gt;</span>
                 <span class="hljs-tag">&lt;<span class="hljs-name">Text</span>&gt;</span>{post.metadata?.content}<span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">HStack</span> <span class="hljs-attr">textColor</span>=<span class="hljs-string">'gray.400'</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">Text</span>&gt;</span>
                    {post.stats?.totalAmountOfComments} comments,
                  <span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">Text</span>&gt;</span>
                    {post.stats?.totalAmountOfMirrors} mirrors,
                  <span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">Text</span>&gt;</span>
                    {post.stats?.totalAmountOfCollects} collects
                  <span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">HStack</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">VStack</span>&gt;</span>
            );
          })}
      <span class="hljs-tag">&lt;/<span class="hljs-name">VStack</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span></span>
  );
}
</code></pre>
<p>You should now be seeing a nice list of posts showing up on your timeline. Cool!</p>
<p><img src="https://i.imgur.com/t1Yt8V9.jpg" alt="https://i.imgur.com/t1Yt8V9.jpg" /></p>
<p>To add some last few finishing touches, we are going to show some skeletons when the posts are still loading and we are going to hide the login button once someone has signed in.</p>
<p>To add the skeletons, add the following piece of code to your <code>pages/index.js</code> file.(I have omitted the parts of the file which are unaffected)</p>
<p><strong>File:</strong> <code>./pages/index.js</code></p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Skeleton } <span class="hljs-keyword">from</span> <span class="hljs-string">'@chakra-ui/react'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Container</span> <span class="hljs-attr">paddingY</span>=<span class="hljs-string">'10'</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ConnectButton</span> /&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{signIn}</span> <span class="hljs-attr">marginTop</span>=<span class="hljs-string">'2'</span>&gt;</span>
        Login with Lens
      <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">VStack</span> <span class="hljs-attr">spacing</span>=<span class="hljs-string">{4}</span> <span class="hljs-attr">marginY</span>=<span class="hljs-string">'10'</span>&gt;</span>
        {posts
          .filter((post) =&gt; post.__typename === 'Post')
          .map((post) =&gt; {
            return (
              ...
            );
          })}

        {/* Skeletons */}
        {posts.length === 0 || !posts ? (
          <span class="hljs-tag">&lt;<span class="hljs-name">VStack</span>&gt;</span>
            {[...Array(10)].map((_, idx) =&gt; {
              return <span class="hljs-tag">&lt;<span class="hljs-name">Skeleton</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{idx}</span> <span class="hljs-attr">height</span>=<span class="hljs-string">'32'</span> <span class="hljs-attr">width</span>=<span class="hljs-string">'xl'</span> <span class="hljs-attr">rounded</span>=<span class="hljs-string">'md'</span> /&gt;</span>;
            })}
          <span class="hljs-tag">&lt;/<span class="hljs-name">VStack</span>&gt;</span>
        ) : null}
      <span class="hljs-tag">&lt;/<span class="hljs-name">VStack</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span></span>
    );
}
</code></pre>
<p>To hide the Login button when someone is already signed in, we are going to make use of a simple hack. We are going to create a state variable called <code>signedIn</code> and use that variable to show the button conditionally. Let's add the following piece of code to make this happen:</p>
<p><strong>File:</strong> <code>./pages/index.js</code></p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [signedIn, setSignedIn] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> signIn = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">if</span> (!connected) {
        <span class="hljs-keyword">return</span> alert(<span class="hljs-string">'Please connect your wallet first'</span>);
      }
      <span class="hljs-keyword">const</span> challenge = <span class="hljs-keyword">await</span> generateChallenge(data?.address <span class="hljs-keyword">as</span> string);
      <span class="hljs-keyword">const</span> signature = <span class="hljs-keyword">await</span> signMessageAsync({ <span class="hljs-attr">message</span>: challenge });
      <span class="hljs-keyword">const</span> accessToken = <span class="hljs-keyword">await</span> authenticate(address <span class="hljs-keyword">as</span> string, signature);
      <span class="hljs-built_in">window</span>.sessionStorage.setItem(<span class="hljs-string">'accessToken'</span>, accessToken);

      setSignedIn(<span class="hljs-literal">true</span>);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(error);
      alert(<span class="hljs-string">'Error signing in'</span>);
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Container</span> <span class="hljs-attr">paddingY</span>=<span class="hljs-string">'10'</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ConnectButton</span> <span class="hljs-attr">showBalance</span>=<span class="hljs-string">{false}</span> /&gt;</span>
       {!signedIn &amp;&amp; (
        <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{signIn}</span> <span class="hljs-attr">marginTop</span>=<span class="hljs-string">'2'</span>&gt;</span>
          Login with Lens
        <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
       )}
            ...</span>
</code></pre>
<p>There we have it! We now have a nice-looking, simple React frontend built on top of Lens Protocol in front of us.</p>
<p><img src="https://i.imgur.com/xY230ew.gif" alt="https://i.imgur.com/xY230ew.gif" /></p>
<h2 id="heading-full-code-repository">Full Code Repository</h2>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/Dhaiwat10/lens-frontend">https://github.com/Dhaiwat10/lens-frontend</a></div>
<h2 id="heading-whats-next">What’s Next?</h2>
<p>Now that you know how to authenticate users using the Lens API, the possibilities for you are endless. I highly suggest browsing through the <a target="_blank" href="https://docs.lens.xyz/docs/introduction">Lens API docs</a> and the <a target="_blank" href="https://lens.xyz/#apps">Lens Showcase</a> for some inspiration. You can build anything from a Hackernews clone to a decentralized YouTube clone. You have the world at your feet!</p>
<h2 id="heading-other-articles-to-read">Other Articles To Read</h2>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://eda.hashnode.dev/web3-social-and-building-withlens-protocol">https://eda.hashnode.dev/web3-social-and-building-withlens-protocol</a></div>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://ankr.hashnode.dev/build-and-deploy-a-rentable-nft-smart-contract-on-optimism">https://ankr.hashnode.dev/build-and-deploy-a-rentable-nft-smart-contract-on-optimism</a></div>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://ankr.hashnode.dev/ankrjs-advanced-apis-react-quickstart-guide">https://ankr.hashnode.dev/ankrjs-advanced-apis-react-quickstart-guide</a></div>
]]></content:encoded></item><item><title><![CDATA[How to Build a DAO with Zero Lines of Code (And yes, there are tokens!)]]></title><description><![CDATA[I'm writing this article thinking about two things. First, why is the web3 community obsessed with three-letter words - think ICOs, NFTs, and now DAO? Second, will the no-code revolution really dismantle the mentality that building cool stuff is only...]]></description><link>https://ankr.hashnode.dev/how-to-build-a-dao-with-zero-lines-of-code-and-yes-there-are-tokens</link><guid isPermaLink="true">https://ankr.hashnode.dev/how-to-build-a-dao-with-zero-lines-of-code-and-yes-there-are-tokens</guid><category><![CDATA[No Code]]></category><category><![CDATA[Ethereum]]></category><category><![CDATA[Smart Contracts]]></category><category><![CDATA[DAO]]></category><category><![CDATA[Aragon]]></category><dc:creator><![CDATA[Krinza Momin]]></dc:creator><pubDate>Tue, 19 Jul 2022 19:00:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1669116178567/lFngtPVH5.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I'm writing this article thinking about two things. First, why is the web3 community obsessed with three-letter words - think ICOs, NFTs, and now DAO? Second, will the no-code revolution really dismantle the mentality that building cool stuff is only reserved for very serious developers?! </p>
<p>I mean, I'm no Naval Ravikant, so I won’t say that the next big thing in code is no-code but I'll rather let Chris echo that on my behalf:</p>
<blockquote>
<p>"The future of coding is no coding at all." - Chris Wanstrath, CEO at GitHub.</p>
</blockquote>
<p>Anyway, getting back to the topic, the DAO; a new-ish type of organizational structure and another hot acronym on the block. For those of you who aren't familiar with what DAO is, toggle the tweet. For the rest of you, enter the playground! </p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://twitter.com/themetav3rse/status/1456337864342466561?s=20&amp;t=wzXj7B8cqaclAlYDFi2MXw">https://twitter.com/themetav3rse/status/1456337864342466561?s=20&amp;t=wzXj7B8cqaclAlYDFi2MXw</a></div>
<hr />
<h3 id="heading-so-what-are-we-building-today">So, what are we building today?</h3>
<p>A DAO.<br /><em>haha, I already read the title … tell me more!</em></p>
<p>Um, without writing a single line of code.<br /><em>what do you think why I clicked on this article, huh?</em></p>
<p>Let me just show you instead. Also, was that just me talking to myself or what? </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1658257496670/reXHIQX1T.png" alt="screely-1658257484452.png" /></p>
<p>TL;DR: We will build a DAO on <a target="_blank" href="https://client.aragon.org/#/">Aragon Client</a>↗ and deploy it on the Ethereum Rinkeby Testnet. By the end of this tutorial, you’ll be able to:</p>
<ul>
<li>deploy a DAO</li>
<li>declare the name and symbol for your token</li>
<li>allocate tokens to the members of the DAO</li>
<li>create the first proposal question </li>
<li>begin the voting process</li>
<li>and enter your first vote in favor/against the proposal</li>
</ul>
<h2 id="heading-wait-whats-aragon-though">Wait, what’s Aragon though?</h2>
<p>Aragon is a DAO maker tool for beginners and developers to create their first of many DAOs in a couple of clicks. This tool will help you with managing your DAO members, their votes, and proposals, and will let you admin your funds directly on the blockchain without writing a single line of code. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657877982295/h9Fg7K8Dh.png" alt="screely-1657877962734.png" /></p>
<hr />
<h2 id="heading-getting-started">Getting Started</h2>
<p>Before we get started deploying our very first DAO, make sure your Metamask wallet is connected with the Rinkeby Testnet. Next, we will need some test ethers to make transactions. So, head over to the <a target="_blank" href="https://faucets.chain.link/rinkeby">Rinkeby Faucet</a>↗, follow through the instructions, and get yourself some test ETH. You'll at least need 0.2 test ETH. </p>
<h3 id="heading-setting-up-a-dao">Setting up a DAO</h3>
<p>Head over to <a target="_blank" href="https://client.aragon.org/#/">Aragon Client</a>↗ and follow these steps:</p>
<ul>
<li><p>Click on the "Connect Account" button and select "Metamask", approve the request from MetaMask, and connect with the ‘Ethereum Rinkeby Testnet.</p>
</li>
<li><p>Navigate to the "Create an organization" option and click on that.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657878158971/M9ZL-fipA.png" alt="screely-1657878032066.png" /></p>
<p>Once you select the "Create an Organization" button, you'll land to this page where you'll be given a few options as pre-configured templates for your DAO, with the details given already. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657878243591/2hCqeOQGP.png" alt="screely-1657878202637.png" /></p>
<p>For this project, we will opt for the "Company" template where the tokens are transferable and decisions are based on the weighted voting system. </p>
<blockquote>
<p>In a weighted voting system, all votes are valid but not equally counted. Each voter's voting power is based on the size of their stake; their individual level of status or expertise; or according to pre-defined organizational rules.</p>
</blockquote>
<ul>
<li>Next up, we will set up the DAO's name. The name you choose will be mapped to the organization's address and cannot be changed after you launch it.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657878373849/lgcDc4BRP.png" alt="screely-1657878305182.png" /></p>
<ul>
<li>Once you set up the name from the DAO, click "Next: Configure template".</li>
</ul>
<h3 id="heading-configure-voting">Configure Voting</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657878434720/gglyCR3CN.png" alt="screely-1657878421747.png" /></p>
<p>Now, in the above screenshot, you see a couple of different options which we will be exploring below: </p>
<ul>
<li><p><strong>Support %</strong> is the relative percentage of tokens that are required to vote “Yes” for a proposal to be approved. For example, if “Support” is set to 50%, then more than 50% of the tokens used to vote on a proposal must vote “Yes” for it to pass.</p>
</li>
<li><p><strong>Minimum Approval %</strong> is the percentage of the total token supply that is required to vote “Yes” on a proposal before it can be approved. For example, if the “Minimum Approval” is set to 20%, then more than 20% of the outstanding token supply must vote “Yes” on a proposal for it to pass.</p>
</li>
<li><p><strong>Vote Duration</strong> is the length of time that the vote will be open for participation. For example, if the Vote Duration is set to 24 hours, then token holders have 24 hours to participate in the vote.</p>
</li>
</ul>
<p>You can set the settings which might suit best for your DAO, for the sake of this project, let's go with the default configs. </p>
<h3 id="heading-set-tokens">Set Tokens!</h3>
<p>Now that we have configured the voting mechanism for the DAO, you can now set a desired name and symbol for your token. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657878541367/tk-syH5ds.png" alt="screely-1657878528202.png" /></p>
<ul>
<li>Enter the token name and symbol </li>
<li>Enter the addresses of the DAO members or holders and allocate tokens to them. </li>
<li>Review the information and hit ‘Launch your organization’.</li>
</ul>
<p>After you launch your organization, the Metamask window will pop up for transaction approval. Confirm the transaction and make sure you don't select the speed-up option in MetaMask. Also, do not refresh the window.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657878669747/g0JSY-t1w.png" alt="screely-1657878614186.png" /></p>
<p>With that, you should be presented with a screen similar to this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657878728005/C-QwyWtIR.png" alt="screely-1657878708181.png" /></p>
<h3 id="heading-first-proposal-first-vote">First Proposal, First Vote</h3>
<p>Click on get started, and let us create our very first proposal to begin the voting process.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657878836812/v9DCmgk0W.png" alt="screely-1657878819178.png" /></p>
<ul>
<li><p>Click on ‘Vote’ from the options shown or find 'Voting' from the left menu and click on ‘Create a New Vote’. </p>
</li>
<li><p>Add in the proposal question and open it for voting. </p>
</li>
</ul>
<p>This action will require you to sign a transaction for the proposal to go live.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657878908695/CTxYhHkWB.png" alt="screely-1657878872314.png" /></p>
<p>Once the proposal is live, members can vote "yes" or "no" based on their decision in favor or against the question asked. The voting window will be open for the time duration set in the earlier steps. In our case, it is 24 hours only. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657878923527/3uIf2XTyL.png" alt="screely-1657878890001.png" /></p>
<p>Now that you have successfully published the first proposal, you can finally register your first vote!</p>
<hr />
<h2 id="heading-next-steps">Next Steps</h2>
<p>If you're leaving under a rock, here is some news for you - Ethereum Rinkeby Testnet will be deprecated soon. Don't fret, we're good for now and I'll update these tutorials as the testnet landscape changes. But for now, here's a task for y'all:</p>
<ul>
<li>Create an exclusive club for your friends online (aka DAO) and deploy it on the Polygon network instead (here's me saving you from dollars worth of deployment cost). </li>
</ul>
<p>PS: Feel free to plug your DAO's ENS in the comments below. I'm all eyes and ears, really. You can also drop me a "👋" on Twitter <a target="_blank" href="https://twitter.com/kayprasla">@kayprasla</a> or find me in the Developer DAO discord!</p>
<hr />
<h2 id="heading-other-articles-to-explore">Other Articles to Explore</h2>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://ankr.hashnode.dev/nft-20-creating-a-soulbound-token">https://ankr.hashnode.dev/nft-20-creating-a-soulbound-token</a></div>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://ankr.hashnode.dev/how-to-deploy-your-own-erc-20-token-with-ankr-and-hardhat-on-eth-goerli-testnet">https://ankr.hashnode.dev/how-to-deploy-your-own-erc-20-token-with-ankr-and-hardhat-on-eth-goerli-testnet</a></div>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://ankr.hashnode.dev/deploy-and-mint-a-cryptokitties-like-nft-with-erc-721-smart-contract">https://ankr.hashnode.dev/deploy-and-mint-a-cryptokitties-like-nft-with-erc-721-smart-contract</a></div>
]]></content:encoded></item><item><title><![CDATA[Ankr.js (Advanced APIs) React Quickstart Guide]]></title><description><![CDATA[Ankr.js is a JavaScript library that lets you interact with Ankr's Advanced APIs. In this guide, you'll learn how to create an NFT viewer app using the following technologies:

Next.js as the React/frontend framework
TailwindCSS as the CSS framework
...]]></description><link>https://ankr.hashnode.dev/ankrjs-advanced-apis-react-quickstart-guide</link><guid isPermaLink="true">https://ankr.hashnode.dev/ankrjs-advanced-apis-react-quickstart-guide</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Web3]]></category><category><![CDATA[React]]></category><category><![CDATA[NFT]]></category><category><![CDATA[ankrjs]]></category><dc:creator><![CDATA[Dhaiwat Pandya]]></dc:creator><pubDate>Mon, 18 Jul 2022 15:49:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1658156014228/hOh8bdh8l.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://github.com/ankr-network/ankr.js">Ankr.js</a> is a JavaScript library that lets you interact with <a target="_blank" href="https://ankr.com/advanced-api">Ankr's Advanced APIs</a>. In this guide, you'll learn how to create an NFT viewer app using the following technologies:</p>
<ul>
<li><a target="_blank" href="https://nextjs.org/">Next.js</a> as the React/frontend framework</li>
<li><a target="_blank" href="https://tailwindcss.com/">TailwindCSS</a> as the CSS framework</li>
<li><a target="_blank" href="https://github.com/ankr-network/ankr.js">Ankr.js</a> to interact with <a target="_blank" href="https://ankr.com/advanced-api">Ankr's Advanced APIs</a></li>
<li><a target="_blank" href="https://ankr.com/advanced-api">Ankr's Advanced APIs</a> as the data source</li>
</ul>
<p><img src="https://i.imgur.com/Cnaoed4.png" alt="https://i.imgur.com/Cnaoed4.png" /></p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To successfully finish this guide, you'll only need <a target="_blank" href="https://nodejs.org/">Node.js</a> and <a target="_blank" href="https://yarnpkg.com/">Yarn</a> installed on your machine.</p>
<h2 id="heading-step-1-set-up-your-nextjs-starter-project">Step 1: Set Up Your Next.js Starter Project</h2>
<p>Navigate into a directory of your choice and run the following command in your terminal to set up a new Next.js project:</p>
<pre><code class="lang-bash">yarn create next-app --ts ankrjs-tutorial
</code></pre>
<p>You can now navigate into the directory and launch the app:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> ankrjs-tutorial &amp;&amp; yarn dev
</code></pre>
<p>Here's what it looks like at the moment:</p>
<p><img src="https://i.imgur.com/DtagqBA.jpg" alt="https://i.imgur.com/DtagqBA.jpg" /></p>
<p>The app currently only contains the boilerplate code provided by Next.js. Over the course of the next few sections, you'll set up Ankr.js and use it to create a gallery of NFTs for any given wallet address.</p>
<p>Before we proceed to step 2, feel free to set up TailwindCSS by following their official guide for Next.js: <a target="_blank" href="https://tailwindcss.com/docs/guides/nextjs">https://tailwindcss.com/docs/guides/nextjs</a></p>
<h2 id="heading-step-2-install-and-set-up-ankrjs">Step 2: Install And Set Up Ankr.js</h2>
<p>Next, you will install and set up Ankr.js so that you can use it to fetch all the NFTs for a given wallet address later on.</p>
<p>Start by installing the <code>ankr.js</code> package from npm:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># ./ankrjs-tutorial</span>

yarn add @ankr.com/ankr.js
</code></pre>
<p>Next, create a new file named <code>utils.ts</code> at the root of your project directory. You will initialize Ankr.js in this file.</p>
<p><strong>File:</strong> <code>./utils.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> AnkrscanProvider <span class="hljs-keyword">from</span> <span class="hljs-string">'@ankr.com/ankr.js'</span>;

<span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> AnkrscanProvider(<span class="hljs-string">''</span>);
</code></pre>
<p>Your <code>provider</code> instance will be your interface to the Ankr Advanced APIs whenever you want to fetch some data from them.</p>
<h2 id="heading-step-3-create-nft-retrieval-function">Step 3: Create NFT Retrieval Function</h2>
<p>In this step, you will create a <code>getNfts</code> function that accepts a <code>walletAddress</code> and returns a list of NFTs owned by that address.</p>
<p>You can utilize the <code>getNFTsByOwner</code> function provided by Ankr.js for this.</p>
<p><strong>File:</strong> <code>./utils.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> AnkrscanProvider <span class="hljs-keyword">from</span> <span class="hljs-string">'@ankr.com/ankr.js'</span>;

<span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> AnkrscanProvider(<span class="hljs-string">''</span>);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getNfts = <span class="hljs-keyword">async</span> (address: <span class="hljs-built_in">string</span>) =&gt; {
  <span class="hljs-keyword">const</span> { assets } = <span class="hljs-keyword">await</span> provider.getNFTsByOwner({
    walletAddress: address,
    blockchain: <span class="hljs-string">'eth'</span>,
  });
  <span class="hljs-keyword">return</span> {
    nfts: assets,
  };
};
</code></pre>
<p>Just to see if things are working, let's call this function on our page i.e. <code>./pages/index.tsx</code> and log out the output.</p>
<p><strong>File:</strong> <code>./pages/index.tsx</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { NextPage } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>;
<span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { getNfts } <span class="hljs-keyword">from</span> <span class="hljs-string">'../utils'</span>;

<span class="hljs-keyword">const</span> Home: NextPage = <span class="hljs-function">() =&gt;</span> {
  useEffect(<span class="hljs-function">() =&gt;</span> {
    (<span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">const</span> { nfts } = <span class="hljs-keyword">await</span> getNfts(
        <span class="hljs-string">'0xB2Ebc9b3a788aFB1E942eD65B59E9E49A1eE500D'</span>
      );
      <span class="hljs-built_in">console</span>.log({ nfts });
    })();
  }, []);

  <span class="hljs-keyword">return</span> (
    &lt;div className=<span class="hljs-string">'p-10 flex flex-col items-center'</span>&gt;
      &lt;h1 className=<span class="hljs-string">'text-3xl font-bold'</span>&gt;NFT viewer&lt;/h1&gt;
    &lt;/div&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>You should see a list of <code>nfts</code> being logged out in your browser's console.</p>
<p><img src="https://i.imgur.com/qxAxaoa.jpg" alt="https://i.imgur.com/qxAxaoa.jpg" /></p>
<h2 id="heading-step-4-create-wallet-address-input">Step 4: Create Wallet Address Input</h2>
<p>You will now add an input to the UI that lets the user input any wallet address they want and pass it to the <code>getNfts</code> function.</p>
<p>You can keep track of the wallet address input in a state variable named <code>walletAddress</code>, hook it up to the input element in the UI, and then pass <code>walletAddress</code> to the <code>getNfts</code> function.</p>
<p><strong>File:</strong> <code>./pages/index.tsx</code></p>
<pre><code class="lang-typescript"><span class="hljs-comment">/* eslint-disable @next/next/no-img-element */</span>
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { NextPage } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>;
<span class="hljs-keyword">import</span> Link <span class="hljs-keyword">from</span> <span class="hljs-string">'next/link'</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { useNfts } <span class="hljs-keyword">from</span> <span class="hljs-string">'../hooks'</span>;

<span class="hljs-keyword">const</span> Home: NextPage = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [walletAddress, setWalletAddress] = useState(
    <span class="hljs-string">'0xB2Ebc9b3a788aFB1E942eD65B59E9E49A1eE500D'</span>
  );

  useEffect(<span class="hljs-function">() =&gt;</span> {
    (<span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">const</span> { nfts } = <span class="hljs-keyword">await</span> getNfts(walletAddress);
      <span class="hljs-built_in">console</span>.log({ nfts });
    })();
  }, [walletAddress]);

  <span class="hljs-keyword">return</span> (
    &lt;div className=<span class="hljs-string">'p-10 flex flex-col items-center'</span>&gt;
      &lt;h1 className=<span class="hljs-string">'text-3xl font-bold'</span>&gt;NFT viewer&lt;/h1&gt;

      &lt;div className=<span class="hljs-string">'flex flex-col mt-4'</span>&gt;
        &lt;label className=<span class="hljs-string">'text-zinc-700'</span> htmlFor=<span class="hljs-string">'wallet-address'</span>&gt;
          Wallet address
        &lt;/label&gt;
        &lt;input
          id=<span class="hljs-string">'wallet-address'</span>
          <span class="hljs-keyword">type</span>=<span class="hljs-string">'text'</span>
          value={walletAddress}
          onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setWalletAddress(e.target.value)}
          className=<span class="hljs-string">'rounded p-2 w-[400px] border'</span>
          placeholder=<span class="hljs-string">'Enter a wallet address here'</span>
        /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>You should see a different list of <code>nfts</code> being logged out in the console when you change the wallet address in the input now. Congrats! You are now able to fetch the list of NFTs owned by any given address.</p>
<p><img src="https://i.imgur.com/7tmuhJ8.png" alt="https://i.imgur.com/7tmuhJ8.png" /></p>
<h2 id="heading-step-5-display-nfts-in-your-ui">Step 5: Display NFTs In Your UI</h2>
<p>You can start off by storing the list of NFTs you fetch in a state variable named <code>nfts</code>. You can then loop through <code>nfts</code> and display all the NFTs in a grid.</p>
<p><strong>File:</strong> <code>./pages/index.tsx</code></p>
<pre><code class="lang-typescript"><span class="hljs-comment">/* eslint-disable @next/next/no-img-element */</span>
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { NextPage } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>;
<span class="hljs-keyword">import</span> Link <span class="hljs-keyword">from</span> <span class="hljs-string">'next/link'</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { useNfts } <span class="hljs-keyword">from</span> <span class="hljs-string">'../hooks'</span>;

<span class="hljs-keyword">const</span> Home: NextPage = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [walletAddress, setWalletAddress] = useState(
    <span class="hljs-string">'0xB2Ebc9b3a788aFB1E942eD65B59E9E49A1eE500D'</span>
  );
  <span class="hljs-keyword">const</span> [nfts, setNfts] = useState&lt;Nft[]&gt;([]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    (<span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">const</span> { nfts } = <span class="hljs-keyword">await</span> getNfts(walletAddress);
      <span class="hljs-built_in">console</span>.log({ nfts });
      setNfts(nfts);
    })();
  }, [walletAddress]);

  <span class="hljs-keyword">return</span> (
    &lt;div className=<span class="hljs-string">'p-10 flex flex-col items-center'</span>&gt;
      ...

      &lt;div className=<span class="hljs-string">'grid grid-cols-3 mt-8 gap-4'</span>&gt;
        {nfts.map(<span class="hljs-function">(<span class="hljs-params">nft</span>) =&gt;</span> {
          <span class="hljs-keyword">return</span> (
            &lt;div
              key={<span class="hljs-string">`<span class="hljs-subst">${nft.contractAddress}</span>/<span class="hljs-subst">${nft.tokenId}</span>`</span>}
              className=<span class="hljs-string">'flex flex-col rounded border p-4'</span>
            &gt;
              &lt;img
                className=<span class="hljs-string">'w-[200px] rounded shadow'</span>
                src={nft.imageUrl}
                alt={nft.name}
              /&gt;
              &lt;span className=<span class="hljs-string">'font-bold mt-4'</span>&gt;{nft.name}&lt;/span&gt;
              &lt;span&gt;{nft.collectionName}&lt;/span&gt;
            &lt;/div&gt;
          );
        })}
      &lt;/div&gt;
    &lt;/div&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>You should now see a gallery of all the NFTs owned by the given wallet address of your choice. LFG!</p>
<p><img src="https://i.imgur.com/ObnZ1eq.jpg" alt="https://i.imgur.com/ObnZ1eq.jpg" /></p>
<h2 id="heading-full-code-repository">Full Code Repository</h2>
<p>You can find the final code for reference here:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/Dhaiwat10/ankrjs-react-quickstart">https://github.com/Dhaiwat10/ankrjs-react-quickstart</a></div>
<h2 id="heading-conclusion-andamp-next-steps">Conclusion &amp; Next Steps</h2>
<p>Ankr.js and Ankr Advanced APIs have so much more to offer than what we covered in this quick-start guide. Ankr.js gives you access to all sorts of data from <em>seven</em> different chains. Learn more here: <a target="_blank" href="https://github.com/ankr-network/ankr.js#%EF%B8%8F-ankrjs">https://github.com/ankr-network/ankr.js#️-ankrjs</a></p>
<p>Apart from that, you can make some UX improvements to the app we built in the guide. We did not handle the loading or the error state for our app. You can try fixing that on your own! If you want to go the fancy route, you can create a <code>useNfts</code> hook on top of the <code>getNfts</code> function to do this. If you need help, I have included this in the final code for the guide that you can find here: <a target="_blank" href="https://github.com/Dhaiwat10/ankrjs-react-quickstart">https://github.com/Dhaiwat10/ankrjs-react-quickstart</a>. Good luck!</p>
<p>If you run into an issue or have any questions about this guide, feel free to let us know in <a target="_blank" href="https://discord.gg/ankr">our Discord server</a>.</p>
<h2 id="heading-other-articles-to-read">Other Articles To Read</h2>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://ankr.hashnode.dev/build-and-deploy-a-rentable-nft-smart-contract-on-optimism">https://ankr.hashnode.dev/build-and-deploy-a-rentable-nft-smart-contract-on-optimism</a></div>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://ankr.hashnode.dev/nft-20-creating-a-soulbound-token">https://ankr.hashnode.dev/nft-20-creating-a-soulbound-token</a></div>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://ankr.hashnode.dev/build-and-deploy-your-own-erc20-token-on-optimism">https://ankr.hashnode.dev/build-and-deploy-your-own-erc20-token-on-optimism</a></div>
]]></content:encoded></item><item><title><![CDATA[NFT 2.0: Creating a Soulbound Token]]></title><description><![CDATA[We laud NFTs for their transferability but Vitalik's extended idea in a blog post titled "Soulbound"↗, over the long haul is showing up in literally every conversation happening around identity, reputation, and individuation in web3. If you haven't c...]]></description><link>https://ankr.hashnode.dev/nft-20-creating-a-soulbound-token</link><guid isPermaLink="true">https://ankr.hashnode.dev/nft-20-creating-a-soulbound-token</guid><category><![CDATA[Smart Contracts]]></category><category><![CDATA[Ethereum]]></category><category><![CDATA[sbt]]></category><category><![CDATA[Soulbound NFT]]></category><category><![CDATA[Non-transferable Token]]></category><dc:creator><![CDATA[Krinza Momin]]></dc:creator><pubDate>Mon, 18 Jul 2022 13:21:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1669116065660/mX9DD4x1Z.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We laud NFTs for their transferability but Vitalik's extended idea in a blog post titled "<a target="_blank" href="https://vitalik.ca/general/2022/01/26/soulbound.html">Soulbound</a>"↗, over the long haul is showing up in literally every conversation happening around identity, reputation, and individuation in web3. If you haven't checked it out yet, go give it a read. If you've already and need a refresher, here's a TLDR:</p>
<blockquote>
<p>Soulbound Tokens (SBT) are just non-fungible tokens (NFTs) that, "once picked up, cannot be transferred or sold to anyone else."</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657625736542/hadENgq59.jpg" alt="o.jpg" /></p>
<p>Provoking name and the Kardashian clan's shenanigans aside, there are (IRL) some things you just cannot sell. Think of your driver’s license, university degree, and formal identification. What if all of it could be encoded on the blockchain and verified by the token, coined as soulbound?</p>
<p>Sounds interesting? Let’s SHIPPPPP one!</p>
<hr />
<h2 id="heading-building-a-soulbound-nft">Building a Soulbound NFT</h2>
<p>In this tutorial, we will learn how to:</p>
<ol>
<li><p>Create a non-transferable NFT smart contract on Solidity</p>
</li>
<li><p>Deploy it on Ethereum Rinkeby Testnet</p>
</li>
<li><p>and display the minted Soulbound token on Opensea</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657621606643/fyK0VSngk.png" alt="screely-1657621556883.png" /></p>
<p>If you followed along the tutorial I published about building an <a target="_blank" href="https://www.youtube.com/watch?v=-kcrQKA-ZLk">ERC721 Smart Contract</a>↗, then you already know most of the code necessary to build them. If not, you can always refer to that video to explore more. So, let's get building!</p>
<h3 id="heading-step-1-writing-nft-smart-contract">Step 1: Writing NFT Smart Contract</h3>
<p>Before we implement the non-transferring logic in our smart contract, we would need a base ERC-721 code for NFTs. To start, we’ll navigate to the <a target="_blank" href="https://docs.openzeppelin.com/contracts/4.x/wizard">OpenZeppelin Wizard</a>↗, select “ERC721” as our contract type and opt for a few features like "Mintable", "Auto-increment IDs" and "Base URI" from the sidebar as shown.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657577285958/AaAryD3sk.png" alt="screely-1657577275934.png" /></p>
<h3 id="heading-step-2-customizing-code-to-make-it-soulbound">Step 2: Customizing Code to Make it Soulbound</h3>
<p>Now that we have the base code ready, let's head over to <a target="_blank" href="https://remix.ethereum.org/?#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC40OwoKaW1wb3J0ICJAb3BlbnplcHBlbGluL2NvbnRyYWN0c0A0LjcuMC90b2tlbi9FUkM3MjEvRVJDNzIxLnNvbCI7CmltcG9ydCAiQG9wZW56ZXBwZWxpbi9jb250cmFjdHNANC43LjAvdG9rZW4vRVJDNzIxL2V4dGVuc2lvbnMvRVJDNzIxVVJJU3RvcmFnZS5zb2wiOwppbXBvcnQgIkBvcGVuemVwcGVsaW4vY29udHJhY3RzQDQuNy4wL2FjY2Vzcy9Pd25hYmxlLnNvbCI7CmltcG9ydCAiQG9wZW56ZXBwZWxpbi9jb250cmFjdHNANC43LjAvdXRpbHMvQ291bnRlcnMuc29sIjsKCmNvbnRyYWN0IFNvdWxCb3VuZFRlc3QgaXMgRVJDNzIxLCBFUkM3MjFVUklTdG9yYWdlLCBPd25hYmxlIHsKICAgIHVzaW5nIENvdW50ZXJzIGZvciBDb3VudGVycy5Db3VudGVyOwoKICAgIENvdW50ZXJzLkNvdW50ZXIgcHJpdmF0ZSBfdG9rZW5JZENvdW50ZXI7CgogICAgY29uc3RydWN0b3IoKSBFUkM3MjEoIlNvdWxCb3VuZFRlc3QiLCAiU0JUIikge30KCiAgICBmdW5jdGlvbiBzYWZlTWludChhZGRyZXNzIHRvLCBzdHJpbmcgbWVtb3J5IHVyaSkgcHVibGljIG9ubHlPd25lciB7CiAgICAgICAgdWludDI1NiB0b2tlbklkID0gX3Rva2VuSWRDb3VudGVyLmN1cnJlbnQoKTsKICAgICAgICBfdG9rZW5JZENvdW50ZXIuaW5jcmVtZW50KCk7CiAgICAgICAgX3NhZmVNaW50KHRvLCB0b2tlbklkKTsKICAgICAgICBfc2V0VG9rZW5VUkkodG9rZW5JZCwgdXJpKTsKICAgIH0KCiAgICAvLyBUaGUgZm9sbG93aW5nIGZ1bmN0aW9ucyBhcmUgb3ZlcnJpZGVzIHJlcXVpcmVkIGJ5IFNvbGlkaXR5LgoKICAgIGZ1bmN0aW9uIF9idXJuKHVpbnQyNTYgdG9rZW5JZCkgaW50ZXJuYWwgb3ZlcnJpZGUoRVJDNzIxLCBFUkM3MjFVUklTdG9yYWdlKSB7CiAgICAgICAgc3VwZXIuX2J1cm4odG9rZW5JZCk7CiAgICB9CgogICAgZnVuY3Rpb24gdG9rZW5VUkkodWludDI1NiB0b2tlbklkKQogICAgICAgIHB1YmxpYwogICAgICAgIHZpZXcKICAgICAgICBvdmVycmlkZShFUkM3MjEsIEVSQzcyMVVSSVN0b3JhZ2UpCiAgICAgICAgcmV0dXJucyAoc3RyaW5nIG1lbW9yeSkKICAgIHsKICAgICAgICByZXR1cm4gc3VwZXIudG9rZW5VUkkodG9rZW5JZCk7CiAgICB9Cn0K&amp;optimize=false&amp;runs=200&amp;evmVersion=null&amp;version=soljson-v0.8.7+commit.e28d00a7.js">Remix Solidity Compiler</a>↗ by clicking, "Open in Remix".</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657610361152/MEA5nVkYb.png" alt="screely-1657610347231.png" /></p>
<p>Once we're on Remix, you should be able to see the following code:</p>
<pre><code class="lang-plaintext">// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

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

contract SoulBoundTest is ERC721, ERC721URIStorage, Ownable {
    using Counters for Counters.Counter;

    Counters.Counter private _tokenIdCounter;

    constructor() ERC721("SoulBoundTest", "SBT") {}

    function safeMint(address to, string memory uri) public onlyOwner {
        uint256 tokenId = _tokenIdCounter.current();
        _tokenIdCounter.increment();
        _safeMint(to, tokenId);
        _setTokenURI(tokenId, uri);
    }

    // The following functions are overrides required by Solidity.

    function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
        super._burn(tokenId);
    }

    function tokenURI(uint256 tokenId)
        public
        view
        override(ERC721, ERC721URIStorage)
        returns (string memory)
    {
        return super.tokenURI(tokenId);
    }
}
</code></pre>
<p>Now let's go ahead and add a new code snippet to the existing smart contract in order for us to block the transfer of NFT and eventually making it "Soulbound." There already exist an API in the OpenZeppelin's ERC721 Contract, using which we can actually control the transferability of our tokens.</p>
<p>If you navigate to the OpenZeppelin API Docs, you will find the following functions:</p>
<ul>
<li><strong>_beforeTokenTransfer</strong>(<strong>address</strong> from, <strong>address</strong> to, <strong>uint256</strong> tokenId)</li>
</ul>
<p>To block token transfers, add the following to your code:</p>
<p><strong>File:</strong> <code>openzeppelin-contracts/contracts/token/ERC721/ERC721.sol</code> <code>function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal override virtual { require(from == address(0), "Err: token transfer is BLOCKED"); super._beforeTokenTransfer(from, to, tokenId); }</code></p>
<p>Now let's understand the logic behind this <a target="_blank" href="https://gist.github.com/kaymomin/7daf2175496bdaefcd3924c3d7657e14">code</a>↗.</p>
<p>Every time this code will run, the require statement will check: if the <code>from address</code> parameter in the function is set to zero. If yes, it will allow the action to happen and block all the other transfers to make it a non-transferable token.</p>
<blockquote>
<p>ℹ️ <strong>Note:</strong> When the <code>address from == 0</code>, it means the token is being issued or minted and not transferred.</p>
</blockquote>
<h3 id="heading-step-3-deploying-the-soulbound-nft-smart-contract">Step 3: Deploying The Soulbound NFT Smart Contract</h3>
<p>To deploy the smart contract directly from remix, head over to side bar and select "<strong>Deploy and Run Transaction</strong>" from the tab. Set Environment to <strong>Injected Web3</strong>, select the Soulbound smart contract we just created from contracts dropdown and click <strong>Deploy</strong>.</p>
<ul>
<li><strong>Injected Provider - Provider Name</strong>: For connecting Remix to an injected web3 provider. The most common injected provider is Metamask.</li>
</ul>
<p>Make sure your MetaMask is connected to the Ethereum Rinkeby Testnet and you've some test ether to make transactions happen.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657616471296/nM2GqFGvI.png" alt="screely-1657616462343.png" /></p>
<h3 id="heading-step-4-adding-nft-asset-to-ipfs-via-pinata">Step 4: Adding NFT Asset To IPFS Via Pinata</h3>
<p>Once the contract is successfully <a target="_blank" href="https://rinkeby.etherscan.io/tx/0xd601de5af7afd11df07059edc19207cfd0b26df9832c272b312ea693aed8922c">deployed</a>↗, the next thing we will need to do is minting a Soulbound NFT. To do so, we are going to first set the NFT asset and metadata using Pinata.</p>
<p>If you don’t have a Pinata account, sign up for a free account here and complete the steps to verify your email.</p>
<ul>
<li><p>Once you have verified your account on the Pinata, navigate to the "<strong>My Files</strong>" page and click the "<strong>Upload</strong>" button</p>
</li>
<li><p>Upload your NFT art and you'll see your image asset file under the <strong>Files</strong> page along with the CID column</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657619569693/2WXWn0USm.png" alt="screely-1657619551837.png" /></p>
<p>Copy the CID by clicking the copy button next to it and use it as a postfix to this URL "<strong>gateway.pinata.cloud/ipfs</strong>" to view your NFT art.</p>
<p>Here's the <a target="_blank" href="https://gateway.pinata.cloud/ipfs/QmTY1jMAqabHUZFCj91ckwnCu3CPtJChpg345jdkxzj3ac">image</a>↗ that I used.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1658149224339/ByZpnqPBq.png" alt="download (1).png" /></p>
<p>Now, we’re going to upload one more document to Pinata - JSON metadata. To do that, create a JSON file and add the following code.</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"attributes"</span> : [ {
      <span class="hljs-attr">"trait_type"</span> : <span class="hljs-string">"NFT"</span>,
      <span class="hljs-attr">"value"</span> : <span class="hljs-string">"Soulbound"</span>
    }, {
      <span class="hljs-attr">"trait_type"</span> : <span class="hljs-string">"Asset"</span>,
      <span class="hljs-attr">"value"</span> : <span class="hljs-string">"Non-transferable Badge"</span>
    }, {
        <span class="hljs-attr">"trait_type"</span> : <span class="hljs-string">"Badge"</span>,
        <span class="hljs-attr">"value"</span> : <span class="hljs-string">"Minting First Soulbound Token"</span>
      }, {
        <span class="hljs-attr">"trait_type"</span> : <span class="hljs-string">"Type"</span>,
        <span class="hljs-attr">"value"</span> : <span class="hljs-string">"Demo"</span>
      }   ],
    <span class="hljs-attr">"description"</span> : <span class="hljs-string">"This is a demo soulbound token mint"</span>,
    <span class="hljs-attr">"image"</span> : <span class="hljs-string">"https://gateway.pinata.cloud/ipfs/QmTY1jMAqabHUZFCj91ckwnCu3CPtJChpg345jdkxzj3ac"</span>,
    <span class="hljs-attr">"name"</span> : <span class="hljs-string">"Soulbound Token"</span>
}
</code></pre>
<p>Feel free to add or remove the attributes. Also, make sure you are providing your own IPFS image URL!</p>
<p>Once you’re done editing the JSON file, save it and upload it to Pinata, following the same steps we followed for uploading the image and copy the CID for the JSON file (we will need that in the next step).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657619937405/lB3UWGT9s.png" alt="screely-1657619929495.png" /></p>
<h3 id="heading-step-5-minting-the-soulbound-nft">Step 5: Minting The Soulbound NFT</h3>
<p>In this step, we are finally going to mint the NFT and display it on Opensea. To mint the NFT, head back to Remix IDE, find "<strong>Deployed Contracts</strong>" button, and click on the "<strong>SafeMint</strong>" function.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657620396624/VZypDRZVv.png" alt="screely-1657620320333.png" /></p>
<p>Under SafeMint, input your wallet address in <strong>to</strong> and set the JSON file's URL in URI, following the format as "<strong>gateway.pinata.cloud/ipfs/{CID_of_JSON_file}</strong>". Here's the IPFS <a target="_blank" href="https://gateway.pinata.cloud/ipfs/QmUcCgfVb1wc8ngLY6LJ9rT85hyWkFe4SABfxX18VyAYmF">link</a>↗ to the Metadata I uploaded to the Pinata.</p>
<p>Once the configurations is set, hit <strong>transact</strong>, confirm the transaction and wait a few seconds for the NFT to be minted.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657621039306/Nu0XfiFTd.png" alt="screely-1657621006676.png" /></p>
<p>Now, we are going to head to <a target="_blank" href="https://testnets.opensea.io/">Opensea</a>↗ (Testnet) to view the minted <a target="_blank" href="https://testnets.opensea.io/assets/rinkeby/0x9ebc13c372384356c9686c541364e04c54ccd32d/0">Soulbound NFT</a>↗.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657621368740/XyBErfxZc.png" alt="screely-1657621356982.png" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657621568161/D7S-2j_bU.png" alt="screely-1657621556883.png" /></p>
<p>Since we have blocked all the transfer action, if you try to send this NFT to some other wallet it will prompt you an error. This way, we can confirm that the NFT we just minted is now bounded to our souls (realistically, to our wallet address) and can never be transferred or sold to anyone else.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657621926628/5sXF46iDn.png" alt="screely-1657621920315.png" /></p>
<hr />
<h3 id="heading-full-code-repository">Full Code Repository</h3>
<p>Wohoo! We’ve finally deployed our very first Soulbound NFT on Rinkeyby Testnet. If you want to take a look at the full source code, find the repo below.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/kaymomin/soulbound-nft-token-smart-contract/blob/main/soulbound.sol">https://github.com/kaymomin/soulbound-nft-token-smart-contract/blob/main/soulbound.sol</a></div>
<p> </p>
<hr />
<h3 id="heading-whats-next">What’s Next?</h3>
<p>A fun project would be to create a platform that lets course creators issue a Soulbound NFT as a credential for students who complete the course.</p>
<p>PS: If you work on this idea, feel free to comment your creation in the comment section below.</p>
<p>You can also drop me a "👋" on Twitter <a target="_blank" href="https://twitter.com/kayprasla">@kayprasla</a> or find me in the Developer DAO discord!</p>
<hr />
<h3 id="heading-other-articles-ive-written">Other Articles I’ve Written</h3>
<p>%[https://ankr.hashnode.dev/how-to-deploy-your-own-erc-20-token-with-ankr-and-hardhat-on-eth-goerli-testnet] %[https://ankr.hashnode.dev/deploy-and-mint-a-cryptokitties-like-nft-with-erc-721-smart-contract]</p>
]]></content:encoded></item><item><title><![CDATA[Create A Backend NodeJS IPFS File Uploader With Filebase]]></title><description><![CDATA[IPFS & Filebase
If you’d like to understand IPFS a bit better, check out the another article written called Easily Understand & Upload Files To IPFS With Filebase. In short, this tutorial will focus on creating a Node Backend API that allows for uplo...]]></description><link>https://ankr.hashnode.dev/create-a-backend-nodejs-ipfs-file-uploader-with-filebase</link><guid isPermaLink="true">https://ankr.hashnode.dev/create-a-backend-nodejs-ipfs-file-uploader-with-filebase</guid><category><![CDATA[ipfs]]></category><category><![CDATA[filebase]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Express.js]]></category><dc:creator><![CDATA[Manny]]></dc:creator><pubDate>Sat, 09 Jul 2022 17:11:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1657384456321/_cJgn92NX.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-ipfs-andamp-filebase">IPFS &amp; Filebase</h1>
<p>If you’d like to understand IPFS a bit better, check out the another article written called <a target="_blank" href="https://ankr.hashnode.dev/easily-understand-and-upload-files-to-ipfs-with-filebase">Easily Understand &amp; Upload Files To IPFS With Filebase</a>. In short, this tutorial will focus on creating a Node Backend API that allows for uploading to IPFS with Filebase.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657384538099/MveELFFR0.png" alt="Filebase Uploader" /></p>
<h1 id="heading-requirements">Requirements</h1>
<p>Before we start, we need to make sure that you have the following installed locally on your computer.</p>
<ul>
<li><a target="_blank" href="https://github.com/nvm-sh/nvm">NVM</a> or <a target="_blank" href="https://nodejs.org">Node v16.15.1</a></li>
<li><a target="_blank" href="https://yarnpkg.com">Yarn</a></li>
<li><a target="_blank" href="https://www.postman.com">Postman</a> <em>(Optional - will also show with curl)</em></li>
</ul>
<h1 id="heading-node-project-setup">Node Project Setup</h1>
<p>The first step is to setup our project from scratch with Express &amp; Typescript.</p>
<pre><code class="lang-bash">mkdir node-filebase-ipfs-uploader;
<span class="hljs-built_in">cd</span> node-filebase-ipfs-uploader;
mkdir bucket; <span class="hljs-comment"># Folder we'll be using for local testing</span>
touch bucket/.gitkeep; <span class="hljs-comment"># To make sure we keep the folder and not its file</span>
mkdir src; <span class="hljs-comment"># Where our code will live</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"16.15.1"</span> &gt; .nvmrc;
nvm install; <span class="hljs-comment"># ignore if you already have Node 16.15.1 installed</span>
yarn init -y;
git init;
<span class="hljs-built_in">echo</span> <span class="hljs-string">"node_modules\n.env\nbucket/*\n\!bucket/.gitkeep\nbuild\n*.log"</span> &gt; .gitignore;
yarn add aws-sdk cors express dotenv multer multer-s3 typescript @aws-sdk/client-s3 @types/cors @types/express @types/multer-s3 @types/node;
yarn add -D nodemon ts-node;
./node_modules/.bin/tsc --init; <span class="hljs-comment"># generates our tsconfig.json file</span>
</code></pre>
<p>Now that we have our project setup, let’s make a modification to our TypeScript config file to adjust for the output folder to be set to <code>./build</code>.</p>
<p><strong>File:</strong> <code>./tsconfig.json</code></p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"compilerOptions"</span>: {
    <span class="hljs-comment">/* Visit https://aka.ms/tsconfig to read more about this file */</span>

    <span class="hljs-comment">/* Projects */</span>
    <span class="hljs-comment">// "incremental": true,                              /* Save .tsbuildinfo files to allow for incremental compilation of projects. */</span>
    <span class="hljs-comment">// "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */</span>
    <span class="hljs-comment">// "tsBuildInfoFile": "./.tsbuildinfo",              /* Specify the path to .tsbuildinfo incremental compilation file. */</span>
    <span class="hljs-comment">// "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects. */</span>
    <span class="hljs-comment">// "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */</span>
    <span class="hljs-comment">// "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */</span>

    <span class="hljs-comment">/* Language and Environment */</span>
    <span class="hljs-attr">"target"</span>: <span class="hljs-string">"es2016"</span> <span class="hljs-comment">/* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */</span>,
    <span class="hljs-comment">// "lib": [],                                        /* Specify a set of bundled library declaration files that describe the target runtime environment. */</span>
    <span class="hljs-comment">// "jsx": "preserve",                                /* Specify what JSX code is generated. */</span>
    <span class="hljs-comment">// "experimentalDecorators": true,                   /* Enable experimental support for TC39 stage 2 draft decorators. */</span>
    <span class="hljs-comment">// "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */</span>
    <span class="hljs-comment">// "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */</span>
    <span class="hljs-comment">// "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */</span>
    <span class="hljs-comment">// "jsxImportSource": "",                            /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */</span>
    <span class="hljs-comment">// "reactNamespace": "",                             /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */</span>
    <span class="hljs-comment">// "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */</span>
    <span class="hljs-comment">// "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */</span>
    <span class="hljs-comment">// "moduleDetection": "auto",                        /* Control what method is used to detect module-format JS files. */</span>

    <span class="hljs-comment">/* Modules */</span>
    <span class="hljs-attr">"module"</span>: <span class="hljs-string">"commonjs"</span> <span class="hljs-comment">/* Specify what module code is generated. */</span>,
    <span class="hljs-comment">// "rootDir": "./",                                  /* Specify the root folder within your source files. */</span>
    <span class="hljs-attr">"moduleResolution"</span>: <span class="hljs-string">"node"</span> <span class="hljs-comment">/* Specify how TypeScript looks up a file from a given module specifier. */</span>,
    <span class="hljs-comment">// "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */</span>
    <span class="hljs-comment">// "paths": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */</span>
    <span class="hljs-comment">// "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */</span>
    <span class="hljs-comment">// "typeRoots": [],                                  /* Specify multiple folders that act like './node_modules/@types'. */</span>
    <span class="hljs-comment">// "types": [],                                      /* Specify type package names to be included without being referenced in a source file. */</span>
    <span class="hljs-comment">// "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */</span>
    <span class="hljs-comment">// "moduleSuffixes": [],                             /* List of file name suffixes to search when resolving a module. */</span>
    <span class="hljs-comment">// "resolveJsonModule": true,                        /* Enable importing .json files. */</span>
    <span class="hljs-comment">// "noResolve": true,                                /* Disallow 'import's, 'require's or '&lt;reference&gt;'s from expanding the number of files TypeScript should add to a project. */</span>

    <span class="hljs-comment">/* JavaScript Support */</span>
    <span class="hljs-comment">// "allowJs": true,                                  /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */</span>
    <span class="hljs-comment">// "checkJs": true,                                  /* Enable error reporting in type-checked JavaScript files. */</span>
    <span class="hljs-comment">// "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */</span>

    <span class="hljs-comment">/* Emit */</span>
    <span class="hljs-comment">// "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */</span>
    <span class="hljs-comment">// "declarationMap": true,                           /* Create sourcemaps for d.ts files. */</span>
    <span class="hljs-comment">// "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */</span>
    <span class="hljs-attr">"sourceMap"</span>: <span class="hljs-literal">true</span> <span class="hljs-comment">/* Create source map files for emitted JavaScript files. */</span>,
    <span class="hljs-comment">// "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */</span>
    <span class="hljs-attr">"outDir"</span>: <span class="hljs-string">"./build"</span> <span class="hljs-comment">/* Specify an output folder for all emitted files. */</span>,
    <span class="hljs-comment">// "removeComments": true,                           /* Disable emitting comments. */</span>
    <span class="hljs-comment">// "noEmit": true,                                   /* Disable emitting files from a compilation. */</span>
    <span class="hljs-comment">// "importHelpers": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */</span>
    <span class="hljs-comment">// "importsNotUsedAsValues": "remove",               /* Specify emit/checking behavior for imports that are only used for types. */</span>
    <span class="hljs-comment">// "downlevelIteration": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */</span>
    <span class="hljs-comment">// "sourceRoot": "",                                 /* Specify the root path for debuggers to find the reference source code. */</span>
    <span class="hljs-comment">// "mapRoot": "",                                    /* Specify the location where debugger should locate map files instead of generated locations. */</span>
    <span class="hljs-comment">// "inlineSourceMap": true,                          /* Include sourcemap files inside the emitted JavaScript. */</span>
    <span class="hljs-comment">// "inlineSources": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */</span>
    <span class="hljs-comment">// "emitBOM": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */</span>
    <span class="hljs-comment">// "newLine": "crlf",                                /* Set the newline character for emitting files. */</span>
    <span class="hljs-comment">// "stripInternal": true,                            /* Disable emitting declarations that have '@internal' in their JSDoc comments. */</span>
    <span class="hljs-comment">// "noEmitHelpers": true,                            /* Disable generating custom helper functions like '__extends' in compiled output. */</span>
    <span class="hljs-comment">// "noEmitOnError": true,                            /* Disable emitting files if any type checking errors are reported. */</span>
    <span class="hljs-comment">// "preserveConstEnums": true,                       /* Disable erasing 'const enum' declarations in generated code. */</span>
    <span class="hljs-comment">// "declarationDir": "./",                           /* Specify the output directory for generated declaration files. */</span>
    <span class="hljs-comment">// "preserveValueImports": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */</span>

    <span class="hljs-comment">/* Interop Constraints */</span>
    <span class="hljs-comment">// "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */</span>
    <span class="hljs-comment">// "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */</span>
    <span class="hljs-attr">"esModuleInterop"</span>: <span class="hljs-literal">true</span> <span class="hljs-comment">/* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */</span>,
    <span class="hljs-comment">// "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */</span>
    <span class="hljs-attr">"forceConsistentCasingInFileNames"</span>: <span class="hljs-literal">true</span> <span class="hljs-comment">/* Ensure that casing is correct in imports. */</span>,

    <span class="hljs-comment">/* Type Checking */</span>
    <span class="hljs-attr">"strict"</span>: <span class="hljs-literal">true</span> <span class="hljs-comment">/* Enable all strict type-checking options. */</span>,
    <span class="hljs-comment">// "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied 'any' type. */</span>
    <span class="hljs-comment">// "strictNullChecks": true,                         /* When type checking, take into account 'null' and 'undefined'. */</span>
    <span class="hljs-comment">// "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */</span>
    <span class="hljs-comment">// "strictBindCallApply": true,                      /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */</span>
    <span class="hljs-comment">// "strictPropertyInitialization": true,             /* Check for class properties that are declared but not set in the constructor. */</span>
    <span class="hljs-comment">// "noImplicitThis": true,                           /* Enable error reporting when 'this' is given the type 'any'. */</span>
    <span class="hljs-comment">// "useUnknownInCatchVariables": true,               /* Default catch clause variables as 'unknown' instead of 'any'. */</span>
    <span class="hljs-comment">// "alwaysStrict": true,                             /* Ensure 'use strict' is always emitted. */</span>
    <span class="hljs-comment">// "noUnusedLocals": true,                           /* Enable error reporting when local variables aren't read. */</span>
    <span class="hljs-comment">// "noUnusedParameters": true,                       /* Raise an error when a function parameter isn't read. */</span>
    <span class="hljs-comment">// "exactOptionalPropertyTypes": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */</span>
    <span class="hljs-comment">// "noImplicitReturns": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */</span>
    <span class="hljs-comment">// "noFallthroughCasesInSwitch": true,               /* Enable error reporting for fallthrough cases in switch statements. */</span>
    <span class="hljs-comment">// "noUncheckedIndexedAccess": true,                 /* Add 'undefined' to a type when accessed using an index. */</span>
    <span class="hljs-comment">// "noImplicitOverride": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */</span>
    <span class="hljs-comment">// "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type. */</span>
    <span class="hljs-comment">// "allowUnusedLabels": true,                        /* Disable error reporting for unused labels. */</span>
    <span class="hljs-comment">// "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */</span>

    <span class="hljs-comment">/* Completeness */</span>
    <span class="hljs-comment">// "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */</span>
    <span class="hljs-attr">"skipLibCheck"</span>: <span class="hljs-literal">true</span> <span class="hljs-comment">/* Skip type checking all .d.ts files. */</span>
  }
}
</code></pre>
<h1 id="heading-creating-initial-server-endpoints">Creating Initial Server Endpoints</h1>
<p>Now that we have our initial project configuration and files setup, we’re going to create two new files that host both the endpoints and the server respectively.</p>
<p>The first file is the endpoints and our initial Express server configurations with a single get endpoint on the root to verify that the server is working.</p>
<p><strong>File:</strong> <code>./src/app.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Imports</span>
<span class="hljs-comment">// ========================================================</span>
<span class="hljs-keyword">import</span> { config } <span class="hljs-keyword">from</span> <span class="hljs-string">"dotenv"</span>;
<span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">"express"</span>;
<span class="hljs-keyword">import</span> cors <span class="hljs-keyword">from</span> <span class="hljs-string">"cors"</span>;

<span class="hljs-comment">// ENV VARS</span>
<span class="hljs-comment">// ========================================================</span>
config();

<span class="hljs-keyword">const</span> NODE_ENV: <span class="hljs-built_in">string</span> = process.env.NODE_ENV || <span class="hljs-string">"development"</span>;

<span class="hljs-comment">// Init</span>
<span class="hljs-comment">// ========================================================</span>
<span class="hljs-comment">/**
 * Initial ExpressJS
 */</span>
<span class="hljs-keyword">const</span> app = express();

<span class="hljs-comment">// Middlewares</span>
<span class="hljs-comment">// ========================================================</span>
<span class="hljs-comment">/**
 * Allows for requests from other servers
 */</span>
app.use(cors());

<span class="hljs-comment">// Endpoints / Routes</span>
<span class="hljs-comment">// ========================================================</span>
<span class="hljs-comment">/**
 * Main endpoint to verify that things are working and what environment mode it's running in
 */</span>
app.get(<span class="hljs-string">"/"</span>, <span class="hljs-function">(<span class="hljs-params">_req, res</span>) =&gt;</span> res.send({ environment: NODE_ENV }));

<span class="hljs-comment">// Exports</span>
<span class="hljs-comment">// ========================================================</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> app;
</code></pre>
<p>Our second file imports the endpoints and runs them on a specific server. Typically you might have seen both of these in the same files, but for testing (covered in another article), it’s typically easier to run unit and integration tests without the server running to separate concerns.</p>
<p><strong>File:</strong> <code>./src/server.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Imports</span>
<span class="hljs-comment">// ========================================================</span>
<span class="hljs-keyword">import</span> app <span class="hljs-keyword">from</span> <span class="hljs-string">"./app"</span>;
<span class="hljs-keyword">import</span> { config } <span class="hljs-keyword">from</span> <span class="hljs-string">"dotenv"</span>;

<span class="hljs-comment">// ENV VARS</span>
<span class="hljs-comment">// ========================================================</span>
config();
<span class="hljs-keyword">const</span> NODE_ENV: <span class="hljs-built_in">string</span> = process.env.NODE_ENV || <span class="hljs-string">"development"</span>;
<span class="hljs-keyword">const</span> PORT: <span class="hljs-built_in">number</span> =
  NODE_ENV === <span class="hljs-string">"production"</span> ? <span class="hljs-number">8080</span> : <span class="hljs-built_in">parseInt</span>(process.env.PORT || <span class="hljs-string">"5001"</span>, <span class="hljs-number">10</span>);

<span class="hljs-comment">// Server</span>
<span class="hljs-comment">// ========================================================</span>
app.listen(PORT, <span class="hljs-function">() =&gt;</span>
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Listening on PORT <span class="hljs-subst">${PORT}</span>\nEnvironment: <span class="hljs-subst">${NODE_ENV}</span>`</span>)
);
</code></pre>
<p>Next, let’s make it easier for ourselves by adding a script command to our <code>package.json</code> file, so we can run <code>yarn dev</code>.</p>
<p><strong>File:</strong> <code>./package.json</code></p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"node-filebase-ipfs-uploader"</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
  <span class="hljs-attr">"main"</span>: <span class="hljs-string">"index.js"</span>,
  <span class="hljs-attr">"license"</span>: <span class="hljs-string">"MIT"</span>,
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"dev"</span>: <span class="hljs-string">"nodemon src/server.ts"</span>
  },
  <span class="hljs-attr">"dependencies"</span>: {
    <span class="hljs-attr">"@aws-sdk/client-s3"</span>: <span class="hljs-string">"^3.113.0"</span>,
    <span class="hljs-attr">"@types/cors"</span>: <span class="hljs-string">"^2.8.12"</span>,
    <span class="hljs-attr">"@types/express"</span>: <span class="hljs-string">"^4.17.13"</span>,
    <span class="hljs-attr">"@types/multer-s3"</span>: <span class="hljs-string">"^3.0.0"</span>,
    <span class="hljs-attr">"@types/node"</span>: <span class="hljs-string">"^18.0.0"</span>,
    <span class="hljs-attr">"aws-sdk"</span>: <span class="hljs-string">"^2.1157.0"</span>,
    <span class="hljs-attr">"cors"</span>: <span class="hljs-string">"^2.8.5"</span>,
    <span class="hljs-attr">"dotenv"</span>: <span class="hljs-string">"^16.0.1"</span>,
    <span class="hljs-attr">"express"</span>: <span class="hljs-string">"^4.18.1"</span>,
    <span class="hljs-attr">"multer"</span>: <span class="hljs-string">"^1.4.5-lts.1"</span>,
    <span class="hljs-attr">"multer-s3"</span>: <span class="hljs-string">"^3.0.1"</span>,
    <span class="hljs-attr">"typescript"</span>: <span class="hljs-string">"^4.7.4"</span>
  },
  <span class="hljs-attr">"devDependencies"</span>: {
    <span class="hljs-attr">"nodemon"</span>: <span class="hljs-string">"^2.0.16"</span>,
    <span class="hljs-attr">"ts-node"</span>: <span class="hljs-string">"^10.8.1"</span>
  }
}
</code></pre>
<p>Now if we run <code>yarn dev</code> and open up our browser to <code>http://localhost:5001</code> we should see our server running.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># /node-filebase-ipfs-uploader</span>
yarn dev;

<span class="hljs-comment"># Expected Output</span>
<span class="hljs-comment"># $ nodemon src/server.ts</span>
<span class="hljs-comment"># [nodemon] 2.0.16</span>
<span class="hljs-comment"># [nodemon] to restart at any time, enter `rs`</span>
<span class="hljs-comment"># [nodemon] watching path(s): *.*</span>
<span class="hljs-comment"># [nodemon] watching extensions: ts,json</span>
<span class="hljs-comment"># [nodemon] starting `ts-node src/server.ts`</span>
<span class="hljs-comment"># Listening on PORT 5001</span>
<span class="hljs-comment"># Environment: development</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657384721094/Qo5s5dNzh.png" alt="IPFS File Uploader NodeJS" /></p>
<p>Our server is now working, now we need to add upload functionality.</p>
<h1 id="heading-adding-local-file-upload">Adding Local File Upload</h1>
<p>In order to get a file uploader code setup, we’re going to take advantage of an npm package called <a target="_blank" href="https://www.npmjs.com/package/multer">multer</a>. Multer is a middleware that makes developer’s lives easier when handling files. It is originally done for just local development, but there are additional extensions that support AWS S3, which we’ll be using for Filebase.</p>
<p>We’re going to modify our original endpoints file to include a new POST upload endpoint that utilizes multer.</p>
<p><strong>File:</strong> <code>./src/app.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Imports</span>
<span class="hljs-comment">// ========================================================</span>
<span class="hljs-keyword">import</span> { config } <span class="hljs-keyword">from</span> <span class="hljs-string">"dotenv"</span>;
<span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">"express"</span>;
<span class="hljs-keyword">import</span> cors <span class="hljs-keyword">from</span> <span class="hljs-string">"cors"</span>;
<span class="hljs-keyword">import</span> multer <span class="hljs-keyword">from</span> <span class="hljs-string">"multer"</span>;

<span class="hljs-comment">// ENV VARS</span>
<span class="hljs-comment">// ========================================================</span>
config();
<span class="hljs-keyword">const</span> NODE_ENV: <span class="hljs-built_in">string</span> = process.env.NODE_ENV || <span class="hljs-string">"development"</span>;
<span class="hljs-keyword">const</span> FILE_DEST: <span class="hljs-built_in">string</span> = process.env.FILE_DEST || <span class="hljs-string">"bucket"</span>;
<span class="hljs-keyword">const</span> FILE_SERVER_URL: <span class="hljs-built_in">string</span> =
  process.env.FILE_SERVER_URL || <span class="hljs-string">"http://localhost:5002"</span>;

<span class="hljs-comment">// Init</span>
<span class="hljs-comment">// ========================================================</span>
<span class="hljs-comment">/**
 * Initial ExpressJS
 */</span>
<span class="hljs-keyword">const</span> app = express();

<span class="hljs-comment">// Middlewares</span>
<span class="hljs-comment">// ========================================================</span>
<span class="hljs-comment">/**
 * Allows for requests from other servers
 */</span>
app.use(cors());

<span class="hljs-comment">/**
 * Main uploader middleware that configures the final `destination` of the file and how the `filename` would be set once saved
 */</span>
<span class="hljs-keyword">const</span> upload = multer({
  storage: multer.diskStorage({
    destination: <span class="hljs-function">(<span class="hljs-params">_req, file, callback</span>) =&gt;</span> {
      callback(<span class="hljs-literal">null</span>, FILE_DEST);
    },
    filename: <span class="hljs-function">(<span class="hljs-params">_req, file, callback</span>) =&gt;</span> {
      callback(<span class="hljs-literal">null</span>, file.originalname);
    },
  }),
});

<span class="hljs-comment">// Endpoints / Routes</span>
<span class="hljs-comment">// ========================================================</span>
<span class="hljs-comment">/**
 * Main endpoint to verify that things are working and what environment mode it's running in
 */</span>
app.get(<span class="hljs-string">"/"</span>, <span class="hljs-function">(<span class="hljs-params">_req, res</span>) =&gt;</span> res.send({ environment: NODE_ENV }));

<span class="hljs-comment">/**
 * Upload endpoint that accepts an input file field of `file`
 */</span>
app.post(<span class="hljs-string">"/upload"</span>, upload.single(<span class="hljs-string">"file"</span>), <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> responseData = {
    file: req.file?.originalname,
    url: <span class="hljs-string">`<span class="hljs-subst">${FILE_SERVER_URL}</span>/<span class="hljs-subst">${req.file?.originalname}</span>`</span>,
  };

  <span class="hljs-keyword">return</span> res.json({ data: responseData });
});

<span class="hljs-comment">// Exports</span>
<span class="hljs-comment">// ========================================================</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> app;
</code></pre>
<p>While the server is running, let’s make an upload.</p>
<p><strong>Curl:</strong></p>
<pre><code class="lang-bash"><span class="hljs-comment"># /node-filebase-ipfs-uploader</span>

curl --location --request POST <span class="hljs-string">'http://localhost:5001/upload'</span> \
--form <span class="hljs-string">'file=@"/full/path/to/node-filebase-ipfs-uploader/test/test-forever.jpg"'</span>;

<span class="hljs-comment"># Expected Output</span>
<span class="hljs-comment"># {"data":{"file":"test-forever.jpg","url":"http://localhost:5002/test-forever.jpg"}}</span>
</code></pre>
<p><strong>Postman:</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657384820413/Cg5WwbDMc.png" alt="Postman IPFS File Uploader" /></p>
<p>To confirm that the file has also been uploaded, we can check our <code>bucket</code> folder to see a new  <code>test-forever.jpg</code> created. We can also create a server on port 5002 to see that our file is uploaded by running the following:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># /node-filebase-ipfs-uploader</span>
npx http-server -p 5002 bucket;

<span class="hljs-comment"># Expected Output</span>
<span class="hljs-comment"># npx: installed 39 in 3.094s</span>
<span class="hljs-comment"># Starting up http-server, serving bucket</span>
<span class="hljs-comment"># </span>
<span class="hljs-comment"># http-server version: 14.1.1</span>
<span class="hljs-comment"># </span>
<span class="hljs-comment"># http-server settings: </span>
<span class="hljs-comment"># CORS: disabled</span>
<span class="hljs-comment"># Cache: 3600 seconds</span>
<span class="hljs-comment"># Connection Timeout: 120 seconds</span>
<span class="hljs-comment"># Directory Listings: visible</span>
<span class="hljs-comment"># AutoIndex: visible</span>
<span class="hljs-comment"># Serve GZIP Files: false</span>
<span class="hljs-comment"># Serve Brotli Files: false</span>
<span class="hljs-comment"># Default File Extension: none</span>
<span class="hljs-comment"># </span>
<span class="hljs-comment"># Available on:</span>
<span class="hljs-comment">#   http://127.0.0.1:5002</span>
<span class="hljs-comment">#   http://10.0.0.6:5002</span>
<span class="hljs-comment"># Hit CTRL-C to stop the server</span>
</code></pre>
<p>If we open up <code>http://localhost:5002/test-forever.jpg</code> we can see in our browser that image is there.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657384890912/p78VYLBkA.png" alt="IPFS File Uploader HTTP Server" /></p>
<p>Now that we have the base setup for our local uploads, we’re going to leverage <a target="_blank" href="https://www.npmjs.com/package/multer-s3">multer-s3</a> to utilize Filebase’s AWS S3 Client compatibility.</p>
<h1 id="heading-adding-filebase-ipfs-support">Adding Filebase IPFS Support</h1>
<p>Before we can add the code, we’ll need to create a new account at <a target="_blank" href="http://Filebase.com">Filebase.com</a>. Once an account has been created, we’ll need to create a new <strong>bucket</strong>, with the <strong>Storage Network</strong> set to <strong>IPFS (All data is public)</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657384983684/87I8a0I6c.png" alt="Filebase Create New Bucket" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657385172187/d6iMavMsz.png" alt="Filebase Create New Bucket Name" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657385208494/LDdr7Em57.png" alt="Filebase New Bucket" /></p>
<p>Once we have our newly created bucket, we’re going to take note of the name so that we can use it later, and then get our <strong>Access Keys</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657385271120/tztTKjLNw.png" alt="Filebase access Keys" /></p>
<p>Now that we have the values, we’re going to create a dot environment file <code>.env</code>, but we’ll create a template (<code>.env.example</code>) for it because we should never save our <code>.env</code> to our git repository.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># /node-filebase-ipfs-uploader</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"PORT=5001\nNODE_ENV=development\nFILEBASE_ACCESS_KEY=key\nFILEBASE_SECRET_KEY=secret\nFILEBASE_BUCKET=bucket\nFILEBASE_REGION=us-east-1\nFILE_SERVER_URL=http://localhost:5002"</span> &gt; .env.example;
cp .env.example .env;
</code></pre>
<p>In our copied <code>.env</code> we’ll need to fill it out with the values we just got from Filebase.</p>
<p><strong>File:</strong> <code>./.env</code></p>
<pre><code class="lang-bash">PORT=5001
NODE_ENV=development
FILEBASE_ACCESS_KEY=&lt;YOUR-FILEBASE-ACCESS-KEY&gt;
FILEBASE_SECRET_KEY=&lt;YOUR-FILEBASE-SECRET-KEY&gt;
FILEBASE_BUCKET=&lt;YOUR-FILEBASE-BUCKET-NAME&gt;
FILEBASE_REGION=us-east-1
FILE_SERVER_URL=http://localhost:5002
</code></pre>
<p>What we want to do is create a way so that when we’re running in <code>development</code> mode that the files upload to our local <code>bucket</code> folder, but when we’re in production mode, the files upload to IPFS with Filebase. To do this, we’re going to take advantage of our <code>NODE_ENV</code> and modify our <code>upload</code> middleware to use a different <code>multer</code> configuration when the <code>NODE_ENV</code> is set to <code>production</code>. More specifically, we’ll be using an extension of <code>multer</code> called <code>multer-s3</code> that handles requests regularly to AWS S3 but because Filebase is an AWS S3 compatible service, we’ll just configure it to point to Filebase.</p>
<p><strong>File:</strong> <code>./src/app.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Imports</span>
<span class="hljs-comment">// ========================================================</span>
<span class="hljs-keyword">import</span> { config } <span class="hljs-keyword">from</span> <span class="hljs-string">"dotenv"</span>;
<span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">"express"</span>;
<span class="hljs-keyword">import</span> cors <span class="hljs-keyword">from</span> <span class="hljs-string">"cors"</span>;
<span class="hljs-keyword">import</span> multer <span class="hljs-keyword">from</span> <span class="hljs-string">"multer"</span>;
<span class="hljs-keyword">import</span> multerS3 <span class="hljs-keyword">from</span> <span class="hljs-string">"multer-s3"</span>;
<span class="hljs-keyword">import</span> { S3Client, GetObjectCommand } <span class="hljs-keyword">from</span> <span class="hljs-string">"@aws-sdk/client-s3"</span>;

<span class="hljs-comment">// ENV VARS</span>
<span class="hljs-comment">// ========================================================</span>
config();
<span class="hljs-keyword">const</span> NODE_ENV: <span class="hljs-built_in">string</span> = process.env.NODE_ENV || <span class="hljs-string">"development"</span>;
<span class="hljs-keyword">const</span> FILE_DEST: <span class="hljs-built_in">string</span> = process.env.FILE_DEST || <span class="hljs-string">"bucket"</span>;
<span class="hljs-keyword">const</span> FILE_SERVER_URL: <span class="hljs-built_in">string</span> =
  process.env.FILE_SERVER_URL || <span class="hljs-string">"http://localhost:5002"</span>;
<span class="hljs-keyword">const</span> FILEBASE_BUCKET = process.env.FILEBASE_BUCKET || <span class="hljs-string">""</span>;
<span class="hljs-comment">// Configured AWS S3 Client For Filebase</span>
<span class="hljs-keyword">const</span> s3 = <span class="hljs-keyword">new</span> S3Client({
  endpoint: <span class="hljs-string">"https://s3.filebase.com"</span>,
  region: process.env.FILEBASE_REGION || <span class="hljs-string">""</span>,
  credentials: {
    accessKeyId: process.env.FILEBASE_ACCESS_KEY || <span class="hljs-string">""</span>,
    secretAccessKey: process.env.FILEBASE_SECRET_KEY || <span class="hljs-string">""</span>,
  },
});

<span class="hljs-comment">// Init</span>
<span class="hljs-comment">// ========================================================</span>
<span class="hljs-comment">/**
 * Initial ExpressJS
 */</span>
<span class="hljs-keyword">const</span> app = express();

<span class="hljs-comment">// Middlewares</span>
<span class="hljs-comment">// ========================================================</span>
<span class="hljs-comment">/**
 * Allows for requests from other servers
 */</span>
app.use(cors());

<span class="hljs-comment">/**
 * Main uploader middleware that configures the final `destination` of the file and how the `filename` would be set once saved
 */</span>
<span class="hljs-keyword">const</span> upload =
  <span class="hljs-comment">// If production use the s3 client</span>
  NODE_ENV === <span class="hljs-string">"production"</span>
    ? multer({
        storage: multerS3({
          s3: s3,
          bucket: FILEBASE_BUCKET,
          metadata: <span class="hljs-function">(<span class="hljs-params">_req, file, cb</span>) =&gt;</span> {
            cb(<span class="hljs-literal">null</span>, { fieldName: file.fieldname });
          },
          key: <span class="hljs-function">(<span class="hljs-params">_req, file, cb</span>) =&gt;</span> {
            cb(<span class="hljs-literal">null</span>, file.originalname);
          },
        }),
      })
    : multer({
        storage: multer.diskStorage({
          destination: <span class="hljs-function">(<span class="hljs-params">_req, file, callback</span>) =&gt;</span> {
            callback(<span class="hljs-literal">null</span>, FILE_DEST);
          },
          filename: <span class="hljs-function">(<span class="hljs-params">_req, file, callback</span>) =&gt;</span> {
            callback(<span class="hljs-literal">null</span>, file.originalname);
          },
        }),
      });

<span class="hljs-comment">// Endpoints / Routes</span>
<span class="hljs-comment">// ========================================================</span>
<span class="hljs-comment">/**
 * Main endpoint to verify that things are working and what environment mode it's running in
 */</span>
app.get(<span class="hljs-string">"/"</span>, <span class="hljs-function">(<span class="hljs-params">_req, res</span>) =&gt;</span> res.send({ environment: NODE_ENV }));

<span class="hljs-comment">/**
 * Upload endpoint that accepts an input file field of `file`
 */</span>
app.post(<span class="hljs-string">"/upload"</span>, upload.single(<span class="hljs-string">"file"</span>), <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> responseData = {
    file: req.file?.originalname,
    url: <span class="hljs-string">`<span class="hljs-subst">${FILE_SERVER_URL}</span>/<span class="hljs-subst">${req.file?.originalname}</span>`</span>,
  };

  <span class="hljs-comment">// If production retrieve file data to get the ipfs CID</span>
  <span class="hljs-keyword">if</span> (NODE_ENV === <span class="hljs-string">"production"</span>) {
    <span class="hljs-keyword">const</span> commandGetObject = <span class="hljs-keyword">new</span> GetObjectCommand({
      Bucket: FILEBASE_BUCKET,
      Key: req.file?.originalname,
    });
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> s3.send(commandGetObject);
    responseData.url = <span class="hljs-string">`ipfs://<span class="hljs-subst">${response.Metadata?.cid}</span>`</span>;
  }

  <span class="hljs-keyword">return</span> res.json({ data: responseData });
});

<span class="hljs-comment">// Exports</span>
<span class="hljs-comment">// ========================================================</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> app;
</code></pre>
<p>Now, in order to test it, we just need to create a different start script that passes a new <code>NODE_ENV</code>. To do this, we’ll need to modify our <code>package.json</code></p>
<p><strong>File:</strong> <code>./package.json</code></p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"node-filebase-ipfs-uploader"</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
  <span class="hljs-attr">"main"</span>: <span class="hljs-string">"index.js"</span>,
  <span class="hljs-attr">"license"</span>: <span class="hljs-string">"MIT"</span>,
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"dev"</span>: <span class="hljs-string">"nodemon src/server.ts"</span>,
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"export NODE_ENV=production &amp;&amp; tsc &amp;&amp; node build/server.js"</span>
  },
  <span class="hljs-attr">"dependencies"</span>: {
    <span class="hljs-attr">"@aws-sdk/client-s3"</span>: <span class="hljs-string">"^3.113.0"</span>,
    <span class="hljs-attr">"@types/cors"</span>: <span class="hljs-string">"^2.8.12"</span>,
    <span class="hljs-attr">"@types/express"</span>: <span class="hljs-string">"^4.17.13"</span>,
    <span class="hljs-attr">"@types/multer-s3"</span>: <span class="hljs-string">"^3.0.0"</span>,
    <span class="hljs-attr">"@types/node"</span>: <span class="hljs-string">"^18.0.0"</span>,
    <span class="hljs-attr">"aws-sdk"</span>: <span class="hljs-string">"^2.1157.0"</span>,
    <span class="hljs-attr">"cors"</span>: <span class="hljs-string">"^2.8.5"</span>,
    <span class="hljs-attr">"dotenv"</span>: <span class="hljs-string">"^16.0.1"</span>,
    <span class="hljs-attr">"express"</span>: <span class="hljs-string">"^4.18.1"</span>,
    <span class="hljs-attr">"multer"</span>: <span class="hljs-string">"^1.4.5-lts.1"</span>,
    <span class="hljs-attr">"multer-s3"</span>: <span class="hljs-string">"^3.0.1"</span>,
    <span class="hljs-attr">"typescript"</span>: <span class="hljs-string">"^4.7.4"</span>
  },
  <span class="hljs-attr">"devDependencies"</span>: {
    <span class="hljs-attr">"nodemon"</span>: <span class="hljs-string">"^2.0.16"</span>,
    <span class="hljs-attr">"ts-node"</span>: <span class="hljs-string">"^10.8.1"</span>
  }
}
</code></pre>
<p>Now when we run the following we should see our server running on port 8080.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># /node-filebase-ipfs-uploader</span>

yarn start;

<span class="hljs-comment"># Expected Output</span>
<span class="hljs-comment"># yarn run v1.22.18</span>
<span class="hljs-comment"># $ export NODE_ENV=production &amp;&amp; tsc &amp;&amp; node build/server.js</span>
<span class="hljs-comment"># Listening on PORT 8080</span>
<span class="hljs-comment"># Environment: production</span>
</code></pre>
<p>If we try uploading our file again with <strong>curl</strong> or <strong>Postman</strong> with the new address, we should get a different result.</p>
<p><strong>Curl:</strong></p>
<pre><code class="lang-bash"><span class="hljs-comment"># /node-filebase-ipfs-uploader</span>

curl --location --request POST <span class="hljs-string">'http://localhost:8080/upload'</span> \
--form <span class="hljs-string">'file=@"/full/path/to/node-filebase-ipfs-uploader/test/test-forever.jpg"'</span>;

<span class="hljs-comment"># Expected Output</span>
<span class="hljs-comment"># {"data":{"file":"test-forever.jpg","url":"ipfs://QmY8UXb7Nka5VWkXXRAMC1DQtamc1s8xzcjoQY6GaEbTdn"}}</span>
</code></pre>
<p><strong>Postman:</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657385508717/r6aSKMx5Y.png" alt="Filebase Uploader" /></p>
<p>Seeing that IPFS url, we can go to it directly and see that it’s actually persisted on the decentralized storage.</p>
<pre><code class="lang-bash">https://ipfs.filebase.io/ipfs/bafybeierozrtdlir5ywdguah573ga25a7tzzhqeh7kvlvfx2y2wqymdj7u
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657385545827/szBXMwLpv.png" alt="IPFS Image" /></p>
<p>There you have it, we built a Backend IPFS File Uploader with Filebase.</p>
<h1 id="heading-code-repository">Code Repository</h1>
<p>If you’d like to check out the full code, check out the following GitHub repository.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/codingwithmanny/node-filebase-ipfs-uploader">https://github.com/codingwithmanny/node-filebase-ipfs-uploader</a></div>
<h1 id="heading-whats-next">What’s Next?</h1>
<p>Now that you have the backend, the next step is to build a frontend that communicates with the backend, which is another article I should be working on shortly.</p>
<p>Another aspect that could be worked on is the deployment of the backend to either a service like Digital Ocean with Docker, or Netlify with Edge Functions.</p>
<p>If you got value from this, please like it, heart it, fire it, all of the emojis, and please also follow me on twitter (where I’m quite active) <a target="_blank" href="https://twitter.com/codingwithmant">@codingwithmanny</a> and on Discord as codingwithmanny :).</p>
<h1 id="heading-other-articles-to-read">Other Articles To Read</h1>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://ankr.hashnode.dev/easily-understand-and-upload-files-to-ipfs-with-filebase">https://ankr.hashnode.dev/easily-understand-and-upload-files-to-ipfs-with-filebase</a></div>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://ankr.hashnode.dev/build-and-deploy-your-own-erc20-token-on-optimism">https://ankr.hashnode.dev/build-and-deploy-your-own-erc20-token-on-optimism</a></div>
]]></content:encoded></item><item><title><![CDATA[Build and Deploy A Rentable NFT Smart Contract On Optimism]]></title><description><![CDATA[NFTs are one of the most interesting things to have happened around digital ownership and the creator economy. They have opened a whole new world of possibilities for artists and developers alike.
NFTs are also expensive, though. Most people cannot a...]]></description><link>https://ankr.hashnode.dev/build-and-deploy-a-rentable-nft-smart-contract-on-optimism</link><guid isPermaLink="true">https://ankr.hashnode.dev/build-and-deploy-a-rentable-nft-smart-contract-on-optimism</guid><category><![CDATA[Web3]]></category><category><![CDATA[NFT]]></category><category><![CDATA[Smart Contracts]]></category><category><![CDATA[Ethereum]]></category><category><![CDATA[optimism]]></category><dc:creator><![CDATA[Dhaiwat Pandya]]></dc:creator><pubDate>Sat, 09 Jul 2022 01:37:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1657196549109/Yb7GC45_B.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>NFTs are one of the most interesting things to have happened around digital ownership and the creator economy. They have opened a whole new world of possibilities for artists and developers alike.</p>
<p>NFTs are also expensive, though. Most people cannot afford to buy an NFT just to get access to a certain community or just to use it as a profile picture on Twitter.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://twitter.com/GargEtisha/status/1517193418358763520?s=20&amp;t=B6coHLh2jrcEKKO5objmhQ">https://twitter.com/GargEtisha/status/1517193418358763520?s=20&amp;t=B6coHLh2jrcEKKO5objmhQ</a></div>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://twitter.com/KinjalPipaliya/status/1509050788056018951?s=20&amp;t=B6coHLh2jrcEKKO5objmhQ">https://twitter.com/KinjalPipaliya/status/1509050788056018951?s=20&amp;t=B6coHLh2jrcEKKO5objmhQ</a></div>
<p>If buying them is out of the question, what if you could rent them? What if you could only pay a fraction of the price and still be able to “use” the NFT everywhere in web3? That's exactly what we are going to talk about and build in this article!</p>
<h2 id="heading-building-a-rentable-nft">Building A Rentable NFT</h2>
<p>We are going to be building a rentable NFT collection. By <strong><em>“rentable”</em></strong>, we mean that any NFT from this collection can be rented out to someone else by its owner for a certain time period. During this rental period, the account renting the NFT can <strong><em>“use”</em></strong> it but cannot sell it or perform any destructive actions, like transfer or burn.</p>
<p>To test out our rentable NFTs, we will be using a gated frontend that gives you access to some content depending on whether you have rented a given NFT or not.</p>
<p><img src="https://i.imgur.com/Tkwmg4J.gif" alt="https://i.imgur.com/Tkwmg4J.gif" /></p>
<p>To make these NFTs even more accessible, we will be deploying them to the <a target="_blank" href="https://www.optimism.io/">Optimism</a>’s Kovan Testnet. Optimism is an extremely powerful Layer-2 scaling solution for Ethereum, and if you’d like to read more about them check <a target="_blank" href="https://community.optimism.io/">Optimism’s Website</a>.</p>
<p>Before we get into writing the smart contract, let's first discuss a standard for rentable NFTs that already exists - <a target="_blank" href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4907.md">EIP-4907</a>. We will be building our NFT collection on top of this standard.</p>
<h2 id="heading-eip-4907-the-rental-nft-standard">EIP-4907: The Rental NFT Standard</h2>
<p><a target="_blank" href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4907.md">Ethereum Improvement Proposal (EIP) 4907</a> discusses a new standard called <a target="_blank" href="https://eips.ethereum.org/EIPS/eip-4907">ERC4907</a> which is an extension of the <a target="_blank" href="https://docs.openzeppelin.com/contracts/3.x/erc721">ERC721 standard</a>. For some context, the ERC721 standard is the most commonly used standard for Non-Fungible Tokens (NFTs).</p>
<blockquote>
<p>ERC4907 proposes an additional role called (user) which can be granted to addresses, and a time where the role is automatically revoked. The user role represents permission to 'use' the NFT, but not the ability to transfer it or set users.</p>
<p><em>– From the official EIP-4907 doc - (</em><a target="_blank" href="https://eips.ethereum.org/EIPS/eip-4907">https://eips.ethereum.org/EIPS/eip-4907</a>)</p>
</blockquote>
<p>In other words, the ERC4907 NFT standard makes it possible for you to <strong><em>“rent out”</em></strong> the utilities unlocked by your NFT to another address. This is made possible by adding a new role to the NFT.</p>
<p><img src="https://i.imgur.com/93uxHCp.png" alt="https://i.imgur.com/93uxHCp.png" /></p>
<p>For example, as mentioned in the <a target="_blank" href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4907.md">EIP</a> itself, rentable NFTs can be leveraged heavily in projects where NFTs are used to manage the ownership of virtual real estate or “virtual land”.</p>
<p>Think of a Metaverse project like <a target="_blank" href="https://www.cryptovoxels.com/">Voxels</a> where in order to purchase land in the virtual world, you need to purchase a corresponding NFT. Owning the NFT makes you the owner of that piece of land.</p>
<p>Just like <a target="_blank" href="https://www.urbandictionary.com/define.php?term=irl">IRL</a> real estate, the <a target="_blank" href="https://github.com/ethereum/EIPs/blob/master/assets/eip-4907/contracts/ERC4907.sol">ERC4907 NFT standard</a> would let land owners rent out their land. This lets land owners create some passive revenue from their virtual assets and makes virtual land more accessible by lowering the barrier in terms of the money required. It's a win-win situation!</p>
<p>Now that we have got a gist of the ERC4907 standard, let's start building!</p>
<h2 id="heading-project-setup">Project Setup</h2>
<p>We will be using <a target="_blank" href="https://hardhat.org/">Hardhat</a> to bootstrap our local development environment. Make sure you have <a target="_blank" href="https://nodejs.org/en/">NodeJS</a> installed!</p>
<p>Let's first create an empty folder for our project.</p>
<pre><code class="lang-bash">mkdir optimism-rentable-nfts &amp;&amp; <span class="hljs-built_in">cd</span> optimism-rentable-nfts;
</code></pre>
<h3 id="heading-initialize-project-using-hardhat">Initialize Project Using Hardhat</h3>
<p>We'll now use the super convenient scaffolding CLI tool provided by Hardhat to set up some boilerplate for our project. Run this in your terminal:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># /optimism-rentable-nfts</span>
npx hardhat;
</code></pre>
<p>Select <code>Create a Javascript project</code> when asked and say yes to all the remaining questions. The CLI tool will now set up the boilerplate and install dependencies for us.</p>
<p>Once that's done, we need to install one last dependency.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># /optimism-rentable-nfts</span>
npm install @openzeppelin/contracts;
</code></pre>
<p><a target="_blank" href="https://www.npmjs.com/package/@openzeppelin/contracts">OpenZeppelin</a> is an extremely handy library containing implementations of some common standards like ERC20 and ERC721. We will need these contracts later on.</p>
<h2 id="heading-writing-the-smart-contract">Writing The Smart Contract</h2>
<p>First, open your project in a code editor of your choice and create three new, empty files inside of the <code>contracts</code> folder.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657329852926/J1HASEhYT.png" alt="ss1.png" /></p>
<p>Let's go over each of these files and what their purpose is.</p>
<h3 id="heading-ierc4907sol">IERC4907.sol</h3>
<p>The <code>IERC4907.sol</code> file will contain the Solidity interface for the ERC4907 standard including Natspec &amp; OpenZeppelin interfaces. This means that this file will contain the skeleton or blueprint of the ERC4907 implementation.</p>
<p>Copy the entire contents of <a target="_blank" href="https://github.com/ethereum/EIPs/blob/master/assets/eip-4907/contracts/IERC4907.sol">this file</a> and paste it in your <code>IERC4907.sol</code> file. We don't need to touch this file again.</p>
<p><strong>File:</strong> <code>./contracts/IERC4907.sol</code></p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: CC0-1.0</span>

<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IERC4907</span> </span>{
    <span class="hljs-comment">// Logged when the user of a token assigns a new user or updates expires</span>
    <span class="hljs-comment">/// @notice Emitted when the `user` of an NFT or the `expires` of the `user` is changed</span>
    <span class="hljs-comment">/// The zero address for user indicates that there is no user address</span>
    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">UpdateUser</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> <span class="hljs-keyword">indexed</span> tokenId, <span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> user, <span class="hljs-keyword">uint64</span> expires</span>)</span>;

    <span class="hljs-comment">/// @notice set the user and expires of a NFT</span>
    <span class="hljs-comment">/// @dev The zero address indicates there is no user </span>
    <span class="hljs-comment">/// Throws if `tokenId` is not valid NFT</span>
    <span class="hljs-comment">/// @param user  The new user of the NFT</span>
    <span class="hljs-comment">/// @param expires  UNIX timestamp, The new user could use the NFT before expires</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setUser</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> tokenId, <span class="hljs-keyword">address</span> user, <span class="hljs-keyword">uint64</span> expires</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>;

    <span class="hljs-comment">/// @notice Get the user address of an NFT</span>
    <span class="hljs-comment">/// @dev The zero address indicates that there is no user or the user is expired</span>
    <span class="hljs-comment">/// @param tokenId The NFT to get the user address for</span>
    <span class="hljs-comment">/// @return The user address for this NFT</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">userOf</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> tokenId</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span>(<span class="hljs-params"><span class="hljs-keyword">address</span></span>)</span>;

    <span class="hljs-comment">/// @notice Get the user expires of an NFT</span>
    <span class="hljs-comment">/// @dev The zero value indicates that there is no user </span>
    <span class="hljs-comment">/// @param tokenId The NFT to get the user expires for</span>
    <span class="hljs-comment">/// @return The user expires for this NFT</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">userExpires</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> tokenId</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>)</span>;
}
</code></pre>
<h3 id="heading-erc4907sol">ERC4907.sol</h3>
<p>The <code>ERC4907.sol</code> file will contain the full implementation of the ERC4907 standard. We need this file because we will be 'extending' our actual NFT collection contract off of the ERC4907 standard.</p>
<p>Copy the entire contents of <a target="_blank" href="https://github.com/Dhaiwat10/optimism-rentable-nfts/blob/main/contracts/ERC4907.sol">this file</a> and paste it in your <code>ERC4907.sol</code> file. You may notice that you are copying the source code from my repo instead of directly from the EIP like we did with <code>IERC4907.sol</code>. This is because we have to make some adjustments to the original <code>ERC4907.sol</code> file in order to compile it and use it in our project. Specifically, I had to add the <code>override</code> keyword to some functions to make them work. You can see the original unmodified source code here: <a target="_blank" href="https://github.com/ethereum/EIPs/blob/master/assets/eip-4907/contracts/ERC4907.sol">https://github.com/ethereum/EIPs/blob/master/assets/eip-4907/contracts/ERC4907.sol</a></p>
<p>We have to do this manually because EIP-4907 has not been accepted yet as a standard and isn't a part of any libraries like OpenZeppelin.</p>
<p>Let's briefly go through some of the important parts of the ERC4907 source code.</p>
<p>The functions we want to be paying attention to are <code>setUser</code> and <code>userOf</code>.</p>
<h3 id="heading-setuser">setUser</h3>
<p><strong>File:</strong> <code>./contracts/ERC4907.sol</code></p>
<pre><code class="lang-solidity"><span class="hljs-comment">/// @notice set the user and expires of a NFT</span>
<span class="hljs-comment">/// @dev The zero address indicates there is no user</span>
<span class="hljs-comment">/// Throws if `tokenId` is not valid NFT</span>
<span class="hljs-comment">/// @param user The new user of the NFT</span>
<span class="hljs-comment">/// @param expires UNIX timestamp, The new user could use the NFT before expires</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setUser</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> tokenId, <span class="hljs-keyword">address</span> user, <span class="hljs-keyword">uint64</span> expires</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span></span>{
    <span class="hljs-built_in">require</span>(_isApprovedOrOwner(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, tokenId),<span class="hljs-string">"ERC721: transfer caller is not owner nor approved"</span>);
    UserInfo <span class="hljs-keyword">storage</span> info <span class="hljs-operator">=</span>  _users[tokenId];
    info.user <span class="hljs-operator">=</span> user;
    info.expires <span class="hljs-operator">=</span> expires;
    <span class="hljs-keyword">emit</span> UpdateUser(tokenId,user,expires);
}
</code></pre>
<p>As discussed earlier, the ERC4907 token standard extends the ERC721 standard and manages two roles for each token</p>
<ol>
<li>The owner (rentee) of the token</li>
<li>The user (renter) of the token</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657329943591/0LwWE_8cU.png" alt="ss2.png" /></p>
<p>Just to recap, accounts with the <strong><em>user</em></strong> role can <em>use</em> the token but cannot perform any destructive actions like transfer or burn.</p>
<p>The <code>setUser</code> function lets owners rent out their NFT to another account. It can only be called by token owners (or “<em>approved”</em> accounts).</p>
<p>The function then sets the <code>info</code> struct in the contract with the newly set <code>user</code> and <code>expires</code> values - <code>user</code> being the address we want to rent out the NFT to and <code>expires</code> being the block timestamp when we want the renting period to end. I definitely recommend reading up on <a target="_blank" href="https://originstamp.com/blog/how-accurate-and-reliable-is-the-block-timestamp-in-ethereum/">Ethereum Block Timestamps</a>.</p>
<p>A key detail that we don't want to miss is that the <code>setUser</code> does <em>not</em> require a payment in the form of ETH or any other tokens in order to run. This is because it can only be called by the owner and, well, you are not going to be the one paying if you are renting your NFT out!</p>
<p>It should be the user who should have to pay a fee. This is why if you want to use the ERC4907 token standard then you would have to use the <code>setUser</code> function as a base and build your own payment functionality on top of it.</p>
<p>Let's move on to the <code>userOf</code> function for now.</p>
<h3 id="heading-userof">userOf</h3>
<p>Let's say you have rented out an NFT to a person named Bob.</p>
<p>Now, how does Bob actually use your NFT? How does Bob get access to, for example, the token gated communities or content your NFT gives access to?</p>
<p>To answer that, we need to understand how most token gated communities define the criteria for access. The community is going to take advantage of the <code>balanceOf</code> function, that comes built into the ERC721 our contract extends, which allows it to verify a specific wallet owns a certain amount.</p>
<p>With ERC4907, these gating tools will still be able to correctly grant access to the <em>original owner</em>. If we look back the <code>ERC4907.sol</code> file we can see that it extends the ERC721 standard, which brings with it all of its default functionality. This is why it has the exact same <code>balanceOf</code> functionality that comes with ERC721.</p>
<p>This token gating functionality won’t work out of the box for users (renters) of the NFT because:</p>
<ol>
<li>The <code>balanceOf</code> function only works for owners</li>
<li>There is no counterpart of <code>balanceOf</code> for users</li>
</ol>
<p>This is where the <code>userOf</code> function comes in.</p>
<p><strong>File:</strong> <code>./contracts/ERC4907.sol</code></p>
<pre><code class="lang-solidity"><span class="hljs-comment">/// @notice Get the user address of an NFT</span>
<span class="hljs-comment">/// @dev The zero address indicates that there is no user or the user is expired</span>
<span class="hljs-comment">/// @param tokenId The NFT to get the user address for</span>
<span class="hljs-comment">/// @return The user address for this NFT</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">userOf</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> tokenId</span>)<span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span>(<span class="hljs-params"><span class="hljs-keyword">address</span></span>)</span>{
    <span class="hljs-keyword">if</span>( <span class="hljs-keyword">uint256</span>(_users[tokenId].expires) <span class="hljs-operator">&gt;</span><span class="hljs-operator">=</span>  <span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>){
        <span class="hljs-keyword">return</span>  _users[tokenId].user;
    }
    <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>);
    }
}
</code></pre>
<p>When we send a <code>tokenId</code> to <code>userOf</code> it returns the wallet address of its renter.</p>
<p>Because of this <code>userOf</code> function, token gating tools can also support accounts who have rented NFTs! All they would have to do is also call the <code>userOf</code> function and check if the account trying to get access has rented an NFT.</p>
<p>The only weird quirk here is that you need to pass in a <code>tokenId</code> to <code>userOf</code>.</p>
<p>Now that we have a pretty decent understanding of the inner workings of the ERC4907 token standard, let's move on to writing the source code for our rentable NFT collection!</p>
<h3 id="heading-rentablenftsol">RentableNFT.sol</h3>
<p>This file will contain the source code for our NFT collection's smart contract. This is everything we’ll need to get our ERC4907 NFT collection up and running:</p>
<p><strong>File:</strong> <code>./contracts/RentableNFT.sol</code></p>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"./ERC4907.sol"</span>;

<span class="hljs-comment">// We are extending our contract from ERC4907. It lets us make our NFTs rentable and gives us access to functions like setUser and userOf.</span>
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">RentableNFT</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC4907</span> </span>{
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">uint256</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> <span class="hljs-keyword">string</span>) <span class="hljs-keyword">public</span> tokenURIs;

    <span class="hljs-comment">// We are accepting the collection's name and its symbol in our constructor. 1:1 copy of how it's done in an ERC721 contract.</span>
        <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> _name, <span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> _symbol</span>)
        <span class="hljs-title">ERC4907</span>(<span class="hljs-params">_name, _symbol</span>)
    </span>{}

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mint</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> _tokenId, <span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> _tokenURI</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        _mint(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, _tokenId);
        tokenURIs[_tokenId] <span class="hljs-operator">=</span> _tokenURI;
    }

        <span class="hljs-comment">// This is where the ✨ magic ✨ happens. This function will let any owners rent out their NFTs. It internally calls the setUser function from the ERC4907 standard</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">rentOut</span>(<span class="hljs-params">
        <span class="hljs-keyword">uint256</span> _tokenId,
        <span class="hljs-keyword">address</span> _user,
        <span class="hljs-keyword">uint64</span> _expires
    </span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">onlyOwner</span>(<span class="hljs-params">_tokenId</span>) </span>{
        setUser(_tokenId, _user, _expires);
    }

        <span class="hljs-comment">// Returns the tokenURI for a given _tokenId</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">tokenURI</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> _tokenId</span>)
        <span class="hljs-title"><span class="hljs-keyword">public</span></span>
        <span class="hljs-title"><span class="hljs-keyword">view</span></span>
        <span class="hljs-title"><span class="hljs-keyword">override</span></span>
        <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span></span>)
    </span>{
        <span class="hljs-keyword">return</span> tokenURIs[_tokenId];
    }

        <span class="hljs-comment">// Checks if the account calling the function actually owns the given token.</span>
    <span class="hljs-function"><span class="hljs-keyword">modifier</span> <span class="hljs-title">onlyOwner</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> _tokenId</span>) </span>{
        <span class="hljs-built_in">require</span>(
            _isApprovedOrOwner(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, _tokenId),
            <span class="hljs-string">"caller is not owner nor approved"</span>
        );
        <span class="hljs-keyword">_</span>;
    }
}
</code></pre>
<p>You might have noticed that the only way an NFT can be rented out right now is if the owner goes and calls this <code>rentOut</code> function. There is no way for a person looking to rent an NFT to pay a certain fee and get an NFT on rent without the owner having to intervene. We’ll go over this functionality near the end of the article.</p>
<p>That is all for the source code of our contract. Let's now write an automated test suite that tests the entire renting flow from start to finish so that we know that our new shiny rentable NFT collection actually does something!</p>
<h2 id="heading-writing-tests-for-erc4907">Writing Tests For ERC4907</h2>
<p>Tests! Who doesn't like writing some tests?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657330030265/BzoETI-gl.png" alt="meme.png" /></p>
<p>Delete the <code>sample-test.js</code> file in your <code>tests</code> directory and create a new file called <code>tests.js</code>.</p>
<p>Let's start by writing two utility functions that will come in handy.</p>
<p><strong>File:</strong> <code>./test/tests.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { expect } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"chai"</span>);
<span class="hljs-keyword">const</span> { ethers, network } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"hardhat"</span>);

<span class="hljs-comment">// this function will deploy our NFT collection's contract and return an instance of the contract for us to interact with</span>
<span class="hljs-keyword">const</span> setupContract = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> RentableNFT = <span class="hljs-keyword">await</span> ethers.getContractFactory(<span class="hljs-string">"RentableNFT"</span>);
  <span class="hljs-keyword">const</span> rentableNFT = <span class="hljs-keyword">await</span> RentableNFT.deploy(<span class="hljs-string">"RentableNFT"</span>, <span class="hljs-string">"RNFT"</span>);
  <span class="hljs-keyword">await</span> rentableNFT.deployed();
  <span class="hljs-keyword">return</span> rentableNFT;
};

<span class="hljs-comment">// this function will simply give us *full* access to two accounts a.k.a *'signers'*. Using these two accounts, we will be able to simulate two different accounts interacting with our contract in any way we want</span>
<span class="hljs-keyword">const</span> setupAccounts = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> accounts = <span class="hljs-keyword">await</span> ethers.getSigners();
  <span class="hljs-keyword">return</span> [accounts[<span class="hljs-number">0</span>], accounts[<span class="hljs-number">1</span>]];
};
</code></pre>
<p>With this base, we can now structure what we want to test for different scenarios.</p>
<p><img src="https://i.imgur.com/DyW7Xgk.png" alt="https://i.imgur.com/DyW7Xgk.png" /></p>
<p>Let’s write the code for our test suite now.</p>
<p><strong>File:</strong> <code>./test/tests.js</code></p>
<pre><code class="lang-javascript">it(<span class="hljs-string">"Rent flow "</span>, <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> rentableNFT = <span class="hljs-keyword">await</span> setupContract();
  <span class="hljs-keyword">const</span> [owner, renter] = <span class="hljs-keyword">await</span> setupAccounts();

  <span class="hljs-comment">// mint tokenId 0 to owner. The .connect function lets us interact with the contract instance explicitly from an account of our choice. In this case, that account is owner.</span>
    <span class="hljs-keyword">const</span> tx = <span class="hljs-keyword">await</span> rentableNFT.connect(owner).mint(<span class="hljs-number">0</span>, <span class="hljs-string">"QmPf2x91DoemnhXSZhGDP8TX9Co8AScpvFzTuFt9BGAoBY"</span>);
    <span class="hljs-keyword">await</span> tx.wait();

  <span class="hljs-comment">// check owner of tokenId 0</span>
    <span class="hljs-keyword">const</span> ownerOf = <span class="hljs-keyword">await</span> rentableNFT.ownerOf(<span class="hljs-number">0</span>);
    expect(ownerOf).to.equal(owner.address);

  <span class="hljs-comment">// rent the nft to renter for 1 hour</span>
    <span class="hljs-keyword">const</span> expiryTimestamp = <span class="hljs-built_in">Math</span>.round(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime() / <span class="hljs-number">1000</span>) + <span class="hljs-number">3600</span>;
    <span class="hljs-keyword">const</span> tx2 = <span class="hljs-keyword">await</span> rentableNFT
      .connect(owner)
      .rentOut(<span class="hljs-number">0</span>, renter.address, expiryTimestamp);
    <span class="hljs-keyword">await</span> tx2.wait();

  <span class="hljs-comment">// check 'renter i.e. 'user' of tokenId 0</span>
    <span class="hljs-keyword">const</span> renterOf = <span class="hljs-keyword">await</span> rentableNFT.userOf(<span class="hljs-number">0</span>);
  expect(renterOf).to.equal(renter.address);

  <span class="hljs-comment">// fast forward the chain to 2 hours later and check if the nft is still rented</span>
    <span class="hljs-keyword">await</span> network.provider.send(<span class="hljs-string">"evm_increaseTime"</span>, [<span class="hljs-number">3601</span>]); <span class="hljs-comment">// 3601 -&gt; 3600 seconds = 1 hour + 1 seconds</span>
    <span class="hljs-keyword">await</span> network.provider.send(<span class="hljs-string">"evm_mine"</span>);

  <span class="hljs-comment">// check renter i.e. 'user' of tokenId 0</span>
    <span class="hljs-keyword">const</span> renterOf2 = <span class="hljs-keyword">await</span> rentableNFT.userOf(<span class="hljs-number">0</span>);
    expect(renterOf2).to.not.equal(renter.address);
    expect(renterOf2).to.equal(<span class="hljs-string">"0x0000000000000000000000000000000000000000"</span>);
});
</code></pre>
<p>We'll now run <code>npx hardhat test</code> and check if our entire flow works as intended.</p>
<blockquote>
<p>The test might not pass in the first run. Just run it again. Sometimes it doesn’t manage to fast forward the chain successfully on the first go.</p>
</blockquote>
<pre><code class="lang-bash"><span class="hljs-comment"># /optimism-rentable-nfts</span>
npx hardhat <span class="hljs-built_in">test</span>

  ✔ Rent flow (85ms)

  1 passing (618ms)
</code></pre>
<p>And...of course, it does! We just tested the entire lifecycle of an ERC4907 rentable NFT. Woohoo! 🎉</p>
<p>Let's now try deploying our smart contract to a Tesnet!</p>
<h2 id="heading-deploying-to-testnet">Deploying To Testnet</h2>
<p>We will be deploying our contract to the Optimism Kovan Testnet.</p>
<p>The great thing about Optimism is that even deploying something to the Optimism Mainnet is extremely cheap (a couple of dollars <em>at most</em>).</p>
<p>But we are going to do the right thing and not clog up the Mainnet with our temporary test contracts. That's what Testnets are for.</p>
<p>Instead of using Hardhat for the deployment, we are going to use <a target="_blank" href="https://portal.thirdweb.com/thirdweb-deploy">Thirdweb Deploy</a>. It is a tool that lets us deploy smart contracts without needing to deal with bare private keys. You can learn more about the tool here: <a target="_blank" href="https://portal.thirdweb.com/thirdweb-deploy">https://portal.thirdweb.com/thirdweb-deploy</a></p>
<p>Let's get started by running <code>npx thirdweb deploy</code> in your terminal. Make sure you run this command from the root of your project.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># /optimism-rentable-nfts</span>
npx thirdweb deploy
</code></pre>
<p><img src="https://i.imgur.com/yxqNdmc.png" alt="https://i.imgur.com/yxqNdmc.png" /></p>
<p>Select only the <code>RentableNFT</code> contract when prompted. We don't need to deploy the <code>ERC4907</code> contract separately. If all goes well, you should see something like this show up in your browser:</p>
<p><img src="https://i.imgur.com/MvlfbmT.png" alt="https://i.imgur.com/MvlfbmT.png" /></p>
<p>Fill in the contract's constructor parameters, select the Optimism Testnet from the Network dropdown and then click <strong>Deploy Now</strong>. You will see two transaction confirmation requests show up.</p>
<p>The first popup will be for the actual contract deployment. Make sure you confirm this one.</p>
<p><img src="https://i.imgur.com/MTYuQoc.png" alt="https://i.imgur.com/MTYuQoc.png" /></p>
<p>The second transaction is optional. This transaction will add your contract to Thirdweb's proxy so that you can access it from your Thirdweb dashboard later on. This does <em>not</em> give away any ownership of your contract to Thirdweb.</p>
<p><img src="https://i.imgur.com/p7sZQMX.png" alt="https://i.imgur.com/p7sZQMX.png" /></p>
<p>Once your contract gets deployed you should be redirected to the Contract Explorer which allows you to interact with the contract functions.</p>
<p><img src="https://i.imgur.com/AJevJA3.png" alt="https://i.imgur.com/AJevJA3.png" /></p>
<p>Make sure you copy your contract's address from the top. You will need it later on.</p>
<p>LFG! We just successfully deployed a rentable NFT collection to the Optimism Kovan Testnet!</p>
<p>You can go see your contract on <a target="_blank" href="https://kovan-optimistic.etherscan.io/">Optimism's Testnet block explorer</a> too.</p>
<h2 id="heading-interacting-with-our-deployed-contract">Interacting With Our Deployed Contract</h2>
<p>We are going to use the Thirdweb UI to interact with our contract and go through the entire renting flow we touched upon when we wrote all those tests.</p>
<p>Let’s start by minting an NFT by selecting the <strong>mint</strong> function from the left sidebar, specifying a <code>_tokenId</code> and <code>_tokenURI</code> (our IPFS URL), and then clicking <strong>Execute</strong>.</p>
<p><img src="https://i.imgur.com/6hOp28F.png" alt="https://i.imgur.com/6hOp28F.png" /></p>
<p>Next, we are going to rent this NFT out to an account. Make sure you have access to this account though! We will use this account to interact with that gated frontend we talked about at the beginning.</p>
<p>Let’s rent out the NFT by selecting the <strong>rentOut</strong> function from the left sidebar, specifying a <code>_tokenId</code>, a <code>_user</code> and an <code>_expires</code> timestamp.</p>
<p>You can run this piece of code in your browser’s console to get a timestamp for 1 hour from now.</p>
<pre><code class="lang-jsx"><span class="hljs-built_in">Math</span>.round(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime() / <span class="hljs-number">1000</span>) + <span class="hljs-number">3600</span>
</code></pre>
<p>Additionally, you can use Node as well.</p>
<pre><code class="lang-bash">node;
&gt; Math.round(new Date().getTime() / 1000) + 3600
&gt; 1657242017
</code></pre>
<p><img src="https://i.imgur.com/MwS58Kl.png" alt="https://i.imgur.com/MwS58Kl.png" /></p>
<p>Check if the NFT was successfully rented out by calling <code>userOf</code> function for the token with token ID 1.</p>
<p><img src="https://i.imgur.com/O7mbSIT.png" alt="https://i.imgur.com/O7mbSIT.png" /></p>
<p>You can also go see your NFT on <a target="_blank" href="https://testnet.quixotic.io/">Quixotic</a>, which is an NFT marketplace for Optimism. Insert your contract address and token ID in this link to view yours:</p>
<pre><code class="lang-bash">https://testnet.quixotic.io/asset/CONTRACT_ADDRESS/TOKEN_ID
</code></pre>
<p>Here’s an NFT that was already deployed and minted.</p>
<p><a target="_blank" href="https://testnet.quixotic.io/asset/0x1d269Cf95A2732ce98fAaF909642D756b59Af0aF/2">https://testnet.quixotic.io/asset/0x1d269Cf95A2732ce98fAaF909642D756b59Af0aF/2</a></p>
<p><img src="https://i.imgur.com/VfdFwjU.png" alt="https://i.imgur.com/VfdFwjU.png" /></p>
<h2 id="heading-seeing-the-rentable-nfts-in-action">Seeing The Rentable NFTs In Action</h2>
<p>We will now use the NFT we just rented for access to a gated frontend. It is a website that gives you access to some content if and only if you have rented an NFT from a certain ERC4907 NFT collection. This website will help you get a feel of a practical use case of the Rentable NFTs we just built.</p>
<p>To save you some time and efforts, I have already created this website for you. You can go clone this <a target="_blank" href="https://github.com/Dhaiwat10/rentable-nft-gated-frontend">rentable nft gated frontend repo</a> and follow the instructions in the <strong>README.md</strong> to get yourself up and running.</p>
<p><a target="_blank" href="https://github.com/Dhaiwat10/rentable-nft-gated-frontend">GitHub - Dhaiwat10/rentable-nft-gated-frontend</a></p>
<p>Connect with the wallet you rented your NFT to and you should be able to view the gated content!</p>
<p><img src="https://i.imgur.com/Tkwmg4J.gif" alt="https://i.imgur.com/Tkwmg4J.gif" /></p>
<blockquote>
<p>ℹ️ <strong>NOTE:</strong> Try this again after a hour and you will notice that your rented NFT has now expired. It won't let you get to the gated content anymore.</p>
</blockquote>
<h2 id="heading-final-code">Final Code</h2>
<p>You can find the repo containing the full code for this project here:</p>
<p><a target="_blank" href="https://github.com/Dhaiwat10/optimism-rentable-nfts">GitHub - Dhaiwat10/optimism-rentable-nfts: Rentable NFTs on Optimism 🔴</a></p>
<h2 id="heading-next-steps">Next Steps</h2>
<p>A good next step after building this project would be to build a marketplace for these rentable NFTs. If you recall, the smart contract we wrote for our NFT collection doesn't let anyone get an NFT on rent on-demand. It requires the owner of the NFT to call a function that rents out the NFT.</p>
<p>Ideally, anyone looking to get an NFT on rent should be able to pay a certain fee and get it on rent without waiting on anyone else. This is why you need a marketplace smart contract that acts as a bridge between NFT owners and people looking to rent them. This is something you can work on or wait for my next article. 😉</p>
<p>Have questions, comments, or words of appreciation? Find me on Twitter at <a target="_blank" href="https://twitter.com/dhaiwat10">@dhaiwat10</a> where I’m super-active!</p>
]]></content:encoded></item><item><title><![CDATA[Easily Understand & Upload Files To IPFS With Filebase]]></title><description><![CDATA[IPFS & Filebase
If you’re just getting started with web3 or just haven’t touched decentralized storage before, then Filebase is a good way to bridge the gap between traditional storage and Interplanetary File System (IPFS).

If you read that last lin...]]></description><link>https://ankr.hashnode.dev/easily-understand-and-upload-files-to-ipfs-with-filebase</link><guid isPermaLink="true">https://ankr.hashnode.dev/easily-understand-and-upload-files-to-ipfs-with-filebase</guid><category><![CDATA[ipfs]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[File Upload]]></category><category><![CDATA[filebase]]></category><dc:creator><![CDATA[Manny]]></dc:creator><pubDate>Fri, 08 Jul 2022 23:47:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1657322844117/dQvLz9qFB.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-ipfs-andamp-filebase">IPFS &amp; Filebase</h1>
<p>If you’re just getting started with web3 or just haven’t touched decentralized storage before, then Filebase is a good way to bridge the gap between traditional storage and <a target="_blank" href="https://docs.filebase.com/storage-networks/ipfs">Interplanetary File System (IPFS)</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657322912529/PUk--7_--.png" alt="Filecoin" /></p>
<p>If you read that last line and asked yourself “What the heck is IPFS”, then let’s break it down in simple terms, it’s a decentralized storage system that lives forever. In other words, make sure you know what you’re uploading before hand.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657322952404/tXL0oyKbn.png" alt="This Live Forever" /></p>
<h1 id="heading-why-would-you-want-forever-storage">Why Would You Want Forever Storage?</h1>
<p>One of the main reasons for storing a file forever is to either give value to its permanence or keep a full record of data that is immutable (can never be modified), which adds to its validity of authenticity. One of main uses for this currently are <a target="_blank" href="https://ethereum.org/en/developers/docs/standards/tokens/erc-721/">Non-Fungible Tokens (NFTs)</a>.</p>
<p>If you get past the highly priced JPGs then there is value in authentic data. In the offline world, authentic data comes in the form government issued identification, supply chain logs, wills, deeds, contracts, and basically anything that could potentially be forged.</p>
<p>Web3 is still young, and IPFS is still being adopted by major browsers, but decentralized storage definitely has a use, alongside traditional web2 storage.</p>
<h1 id="heading-getting-started-with-filebase">Getting Started With Filebase</h1>
<p>Web3 is growing and until it has a mass adoption there will still be a need for web2 solutions that bridge the gap. Filebase is the bridge to web3 decentralized storage on IPFS. The good news is that Filebase is currently 5GB of storage without any credit card, so take advantage and upload that entire collection of Gilmore Girls* to IPFS. Just create an account at <a target="_blank" href="https://console.filebase.com/signup">Filebase.com</a>.</p>
<p>*(Don’t listen to me. This is probably a bad idea)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657323085386/rqFOAsu6-.png" alt="Filebase.com Pricing" /></p>
<h1 id="heading-uploading-your-first-file">Uploading Your First File</h1>
<p>The first step will be to create a bucket, by going to the <a target="_blank" href="https://console.filebase.com/buckets">Buckets</a> section and click <strong>Create Bucket</strong>. If you’re familiar with <a target="_blank" href="https://aws.amazon.com/s3/">AWS S3</a>, then buckets are another way of saying folders. Why they chose the names buckets, I have no idea, but my guess is that instead of trying to organize things into folders, they just dumped everything into a bucket and ignore trying to organize anything.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657323158233/FmrYcQ1KI.png" alt="Filebase.com Create Bucket" /></p>
<p>Give your Bucket a name, to try and organize things, and select the <strong>IPFS (All data is public)</strong> as the <strong>Storage Network</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657323211821/z-k747X7o.png" alt="Filebase.com Create New Bucket" /></p>
<p>Click on your newly created bucket to open it up and take a look at its emptiness that screams “I need some files!”</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657323249048/v2gZibaxS.png" alt="Filebase.com Bucket Details" /></p>
<p>In your new bucket, click upload and File, to be prompted with file to upload, and select an image to start with to make things easier.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657323299952/3b49AEyLe.png" alt="Filebase.com Upload File" /></p>
<p>Tada! You have uploaded a file to IPFS. Click on the new file to see its details.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657323335880/VpUyfE1TI.png" alt="Filebase.com Test JPG" /></p>
<p>In the details, Right-Click the link in a new tab and wait for it to load.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657323371979/lhLrDhGgU.png" alt="Filebase.com Test JPG Details" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657323401937/EQtlYe9MH.png" alt="IPFS Test JPG" /></p>
<p>You should also be able to access the file from this public gateways URL</p>
<pre><code class="lang-bash">https://ipfs.filebase.io/ipfs/bafybeiblmwzu3evblahlvasdbs2a7p4qk6n6yaihcznvyqpp7mabfadkd4
</code></pre>
<h1 id="heading-deleting-your-files">Deleting Your Files</h1>
<p>Wait, how can you delete a file that lives forever and is immutable?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657323480879/21QwOziDq.png" alt="Filebase.com Deleting Files" /></p>
<p>The answer is you can’t, the file lives forever. What you’re really deleting is just the reference to it in Filebase. A good way to test this theory is to use other <a target="_blank" href="https://docs.filebase.com/storage-networks/ipfs/ipfs-gateway">IPFS Gateways</a> to access the file. Depending on the Gateway, the request to load the file may differ.</p>
<p>We can access the file natively through the Opera Web Browser at:</p>
<pre><code class="lang-bash">ipfs://bafybeiblmwzu3evblahlvasdbs2a7p4qk6n6yaihcznvyqpp7mabfadkd4
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657323537233/l1arxsyKr.png" alt="IPFS URL" /></p>
<p>We can use Cloudfare’s IPFS Gateway to also access the file through a browser that doesn’t natively support IPFS.</p>
<pre><code class="lang-bash">https://cloudflare-ipfs.com/ipfs/QmRG4BgEVcD3MuNaL3SxmZJcCEEYkRomw6PFEaha1Gagi2
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657323584056/m0pZCd9ya.png" alt="Cloudflare IPFS URL" /></p>
<p>We can also still access our file through Filebase’s IPFS Gateway, even after we’ve deleted it in Filebase.</p>
<pre><code class="lang-bash">https://ipfs.filebase.io/ipfs/bafybeiblmwzu3evblahlvasdbs2a7p4qk6n6yaihcznvyqpp7mabfadkd4
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657323639635/VnPxqXNou.png" alt="Filebase IPFS URL" /></p>
<h1 id="heading-whats-next">What’s Next</h1>
<p>Now that we can see that we can upload files directly to IPFS with Filebase, we can start to think about what we can do to built on top of this.</p>
<p>With IPFS in mind, here some articles that coming are:</p>
<ul>
<li>How to build a Frontend file uploader with React &amp; Filebase</li>
<li>Storing Your NFT Images Permanently On-Chain With IPFS</li>
</ul>
<p>Definitely look out for those when they are done being written.</p>
<p>If you got value from this, please like it, heart it, fire it, all of the emojis, and please also follow me on twitter (where I’m quite active) <a target="_blank" href="https://twitter.com/codingwithmant">@codingwithmanny</a> and on Discord as codingwithmanny 😉.</p>
<h1 id="heading-other-articles-to-read">Other Articles To Read</h1>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://ankr.hashnode.dev/configure-your-metamask-to-work-with-optimism">https://ankr.hashnode.dev/configure-your-metamask-to-work-with-optimism</a></div>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://ankr.hashnode.dev/build-and-deploy-your-own-erc20-token-on-optimism">https://ankr.hashnode.dev/build-and-deploy-your-own-erc20-token-on-optimism</a></div>
]]></content:encoded></item><item><title><![CDATA[Build & Deploy Your Own ERC20 Token On Optimism]]></title><description><![CDATA[What We're Building
If you have ever wanted to create your own type of currency or token that would be used as a means for an exchange of value or trading then you’re in the right place today. We’ll be building and deploying an ERC-20 Token to Optimi...]]></description><link>https://ankr.hashnode.dev/build-and-deploy-your-own-erc20-token-on-optimism</link><guid isPermaLink="true">https://ankr.hashnode.dev/build-and-deploy-your-own-erc20-token-on-optimism</guid><category><![CDATA[optimism]]></category><category><![CDATA[ERC20]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[hardhat]]></category><dc:creator><![CDATA[Manny]]></dc:creator><pubDate>Thu, 07 Jul 2022 15:46:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1657158345950/nm0sPZHhl.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-what-were-building">What We're Building</h1>
<p>If you have ever wanted to create your own type of currency or token that would be used as a means for an exchange of value or trading then you’re in the right place today. We’ll be building and deploying an <a target="_blank" href="https://eips.ethereum.org/EIPS/eip-20">ERC-20 Token</a> to Optimism Kovan Testnet.</p>
<p>We’ll be walking you through the entire process of coding, testing, setting up your network, adding tokens via a faucet, deploying the contract to the Optimism testnet, and interacting with it via a blockchain explorer.</p>
<h1 id="heading-wait-whats-optimism">Wait, What’s Optimism?</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657150950999/c8r6BWBuQ.png" alt="Optimism" /></p>
<p>Optimism is a fast and transactionally cheap L2 EVM Blockchain that lets developers build contracts on top of its chain with Solidity. If you’d like to read more about what Optimism is, there is a great article on <a target="_blank" href="https://coinmarketcap.com/alexandria/article/what-is-optimism-the-ultimate-guide-to-the-optimism-ecosystem">CoinMarketCap</a> explaining its advantages and differences.</p>
<h1 id="heading-requirements">Requirements</h1>
<p>Before we start, here is a list of things you’ll need on your computer:</p>
<ol>
<li>NVM or Node v16.15.1+</li>
<li>Yarn</li>
<li>VSCode</li>
<li>Metamask Wallet</li>
</ol>
<h1 id="heading-project-setup">Project Setup</h1>
<p>To start, we’re going to leverage <a target="_blank" href="https://hardhat.org/">Hardhat</a> to develop, compile, test, and deploy our contract locally. If you’re not familiar, this will be a good primer to start with.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657151103748/rTVWirrkB.png" alt="Hardhat" /></p>
<p>To start, we’re going to scaffold out a new project with TypeScript.</p>
<pre><code class="lang-bash">mkdir optimism-erc20;
<span class="hljs-built_in">cd</span> optimism-erc20;
npx hardhat;

<span class="hljs-comment"># PROMPT 1 - Choose base</span>
888    888                      888 888               888
888    888                      888 888               888
888    888                      888 888               888
8888888888  8888b.  888d888 .d88888 88888b.   8888b.  888888
888    888     <span class="hljs-string">"88b 888P"</span>  d88<span class="hljs-string">" 888 888 "</span>88b     <span class="hljs-string">"88b 888
888    888 .d888888 888    888  888 888  888 .d888888 888
888    888 888  888 888    Y88b 888 888  888 888  888 Y88b.
888    888 "</span>Y888888 888     <span class="hljs-string">"Y88888 888  888 "</span>Y888888  <span class="hljs-string">"Y888

👷 Welcome to Hardhat v2.9.9 👷‍

? What do you want to do? …
  Create a basic sample project
  Create an advanced sample project
❯ Create an advanced sample project that uses TypeScript
  Create an empty hardhat.config.js
  Quit

# PROMPT 2 - Confirm project root
✔ What do you want to do? · Create an advanced sample project that uses TypeScript
? Hardhat project root: › /path/to/optimism-erc20

# PROMPT 3 - Git Ignore
✔ What do you want to do? · Create an advanced sample project that uses TypeScript
✔ Hardhat project root: · /path/to/optimism-erc20
? Do you want to add a .gitignore? (Y/n) › y

# PROMPT 4 - Install Dependencies
✔ What do you want to do? · Create an advanced sample project that uses TypeScript
✔ Hardhat project root: · /Users/manny/Documents/github/optimism-erc20
✔ Do you want to add a .gitignore? (Y/n) · y
? Do you want to install this sample project's dependencies with npm (hardhat @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers ethers @nomiclabs/hardhat-etherscan dotenv eslint eslint-config-prettier eslint-config-standard eslint-plugin-import eslint-plugin-node eslint-plugin-prettier eslint-plugin-promise hardhat-gas-reporter prettier prettier-plugin-solidity solhint solidity-coverage @typechain/ethers-v5 @typechain/hardhat @typescript-eslint/eslint-plugin @typescript-eslint/parser @types/chai @types/node @types/mocha ts-node typechain typescript)? (Y/n) › y</span>
</code></pre>
<p>If we open up our project in VSCode we should see big list of files generated for us, but don’t worry we won’t need to use all of them.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657151274653/C2wDPA7xh.png" alt="VSCode" /></p>
<h1 id="heading-creating-our-contract">Creating Our Contract</h1>
<p>Now that we have all our files, we’re going to start off by modifying our current Solidity contract (<code>Greeter.sol</code>) in the <code>contracts</code> folder by renaming it to <code>Buidl.sol</code> and making the following modifications.</p>
<p><strong>File:</strong> <code>./contracts/Buidl.sol</code></p>
<pre><code class="lang-solidity"><span class="hljs-comment">//SPDX-License-Identifier: Unlicense</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">BuidlToken</span> </span>{
}
</code></pre>
<p>With that base in place, we’re now going to leverage some existing code to easily build our own ERC-20 token on top of a widely adopted standard. To do this, we’ll be using <a target="_blank" href="https://www.npmjs.com/package/@openzeppelin/contracts">OpenZeppelin’s contract npm package</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657151445727/rbbL8ro7j.png" alt="OpenZeppelin" /></p>
<pre><code class="lang-bash"><span class="hljs-comment"># /optimism-erc20</span>
yarn add @openzeppelin/contracts;
</code></pre>
<p>With this newly installed npm package, we can add it to our contract, extend the contract, and pass the default attributes needed to define the name and its symbol.</p>
<pre><code class="lang-solidity"><span class="hljs-comment">//SPDX-License-Identifier: Unlicense</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/ERC20.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">BuidlToken</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC20</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> initialSupply</span>) <span class="hljs-title">ERC20</span>(<span class="hljs-params"><span class="hljs-string">"BuidlToken"</span>, <span class="hljs-string">"BDL"</span></span>) </span>{
        _mint(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, initialSupply);
    }
}
</code></pre>
<p>That’s it! We have our ERC-20 token. The reason why our code is so short is because we’re using all the functions defined by the OpenZeppelin <code>ERC20.sol</code> file. The file provided by OpenZeppelin is an inherited set of functions from the ERC-20 contract, which you can more details on here. In VSCode, you can actually see the functions by doing <code>Command</code> (PC <code>CTRL</code>) + Click on the <code>ERC20.sol</code> part of the import.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657151561526/2GPJfTK3O.png" alt="Importing OpenZeppelin" /></p>
<p>This should open up the file located in your <code>node_modules</code> folder and show you the contents of the entire file we’re extending.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.1/contracts/token/ERC20/ERC20.sol">https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.1/contracts/token/ERC20/ERC20.sol</a></div>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657151759977/lM8jBQ5Xr.png" alt="ERC20.sol" /></p>
<p>There is one thing that we need to factor in with this default ERC-20 token and that is that the supply can only be defined once, at the time of the contract deployed. We’re going to make a slight modification to our contract to make it so that only the owner (the wallet that deployed the contract) can modify the supply after the contract has been deployed.</p>
<pre><code class="lang-solidity"><span class="hljs-comment">//SPDX-License-Identifier: Unlicense</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/ERC20.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/access/Ownable.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">BuidlToken</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC20</span>, <span class="hljs-title">Ownable</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> initialSupply</span>) <span class="hljs-title">ERC20</span>(<span class="hljs-params"><span class="hljs-string">"BuidlToken"</span>, <span class="hljs-string">"BDL"</span></span>) </span>{
        _mint(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, initialSupply);
    }

    <span class="hljs-comment">/**
     * Contract Owner - Increase the total supply and add it to their wallet
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mint</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">onlyOwner</span> </span>{
        _mint(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, amount);
    }

    <span class="hljs-comment">/**
     * User - Decrease their total supply
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">burn</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        _burn(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, amount);
    }
}
</code></pre>
<h1 id="heading-deploying-our-contract-locally">Deploying Our Contract Locally</h1>
<p>The next step is to deploy our contract to our local development environment to make sure things compile correctly. To do that we’ll need modify <code>deploy.ts</code>.</p>
<p><strong>File:</strong> <code>./scripts/deploy.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// We require the Hardhat Runtime Environment explicitly here. This is optional</span>
<span class="hljs-comment">// but useful for running the script in a standalone fashion through `node &lt;script&gt;`.</span>
<span class="hljs-comment">//</span>
<span class="hljs-comment">// When running the script with `npx hardhat run &lt;script&gt;` you'll find the Hardhat</span>
<span class="hljs-comment">// Runtime Environment's members available in the global scope.</span>
<span class="hljs-keyword">import</span> { ethers } <span class="hljs-keyword">from</span> <span class="hljs-string">"hardhat"</span>;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Hardhat always runs the compile task when running scripts with its command</span>
  <span class="hljs-comment">// line interface.</span>
  <span class="hljs-comment">//</span>
  <span class="hljs-comment">// If this script is run directly using `node` you may want to call compile</span>
  <span class="hljs-comment">// manually to make sure everything is compiled</span>
  <span class="hljs-comment">// await hre.run('compile');</span>

  <span class="hljs-comment">// We get the contract to deploy</span>
  <span class="hljs-keyword">const</span> Contract = <span class="hljs-keyword">await</span> ethers.getContractFactory(<span class="hljs-string">"BuidlToken"</span>);
  <span class="hljs-keyword">const</span> contract = <span class="hljs-keyword">await</span> Contract.deploy(<span class="hljs-number">1000</span>); <span class="hljs-comment">// Create 1000 initial tokens</span>

  <span class="hljs-keyword">await</span> contract.deployed();

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Contract deployed to:"</span>, contract.address);
}

<span class="hljs-comment">// We recommend this pattern to be able to use async/await everywhere</span>
<span class="hljs-comment">// and properly handle errors.</span>
main().catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.error(error);
  process.exitCode = <span class="hljs-number">1</span>;
});
</code></pre>
<p>After we’ve modified the file we’ll need to run two Terminals to get things deployed. The first one is to run the local development Ethereum Virtual Machine and the second is to deploy it to that environment.</p>
<p><strong>Terminal 1:</strong></p>
<pre><code class="lang-bash"><span class="hljs-comment"># TERMINAL 1</span>
<span class="hljs-comment"># /optimism-erc20</span>

./node_modules/.bin/hardhat node;

<span class="hljs-comment"># Expected Output</span>
<span class="hljs-comment"># Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/</span>
<span class="hljs-comment"># </span>
<span class="hljs-comment"># Accounts</span>
<span class="hljs-comment"># ========</span>
<span class="hljs-comment"># </span>
<span class="hljs-comment"># WARNING: These accounts, and their private keys, are publicly known.</span>
<span class="hljs-comment"># Any funds sent to them on Mainnet or any other live network WILL BE LOST.</span>
<span class="hljs-comment"># </span>
<span class="hljs-comment"># Account #0: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 (10000 ETH)</span>
<span class="hljs-comment"># Private Key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80</span>
<span class="hljs-comment"># </span>
<span class="hljs-comment"># Account #1: 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 (10000 ETH)</span>
<span class="hljs-comment"># Private Key: 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d</span>
<span class="hljs-comment"># </span>
<span class="hljs-comment"># ...</span>
<span class="hljs-comment"># </span>
<span class="hljs-comment"># WARNING: These accounts, and their private keys, are publicly known.</span>
<span class="hljs-comment"># Any funds sent to them on Mainnet or any other live network WILL BE LOST.</span>
</code></pre>
<p><strong>Terminal 2:</strong></p>
<pre><code class="lang-bash"><span class="hljs-comment"># TERMINAL 2</span>
<span class="hljs-comment"># /optimism-erc20</span>

./node_modules/.bin/hardhat run scripts/deploy.ts --network localhost;

<span class="hljs-comment"># Expected Output</span>
<span class="hljs-comment"># Generating typings for: 5 artifacts in dir: typechain for target: ethers-v5</span>
<span class="hljs-comment"># Successfully generated 11 typings!</span>
<span class="hljs-comment"># Compiled 5 Solidity files successfully</span>
<span class="hljs-comment"># Contract deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657151959452/LsPiAJsOm.png" alt="Deploy Script" /></p>
<h1 id="heading-testing-our-contract">Testing Our Contract</h1>
<p>A good habit is that when you have your contract code, is to create a series of tests to make sure that things are working as expected. As a brief overview of how I structure tests, the guideline I try to aim for is the following:</p>
<pre><code class="lang-bash">1 - Imports
2 - Configurations
3 - Helpers (Optional)
4 - Tests
    A - Function One Expected Failure(s)
    B - Function One Expected Success(es)
    C - Function Two ...
    D - Scenario(s)
</code></pre>
<p>Taking this guide into consideration, the main things we’re going to test for are:</p>
<ol>
<li><strong>Minting</strong> - Increasing the supply</li>
<li><strong>Burning</strong> - Decreasing the supply</li>
<li><strong>Approving</strong> - Giving another user permission to spend tokens on our behalf</li>
<li><strong>Transferring</strong> - Moving tokens from one user to another</li>
<li><strong>Scenario Insufficient Tokens</strong> - A user has the permission to spend tokens of another user but the tokens are already spent or burned</li>
</ol>
<p><strong>ℹ️ NOTE:</strong> This is a lot of code to read, but gives you some insight as to how tests are written. If you want to skip this part, just scroll through it, but if you want to test your code, I recommend just copying it for now.</p>
<p><strong>File:</strong> <code>./test/index.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Imports</span>
<span class="hljs-comment">// ========================================================</span>
<span class="hljs-keyword">import</span> { expect } <span class="hljs-keyword">from</span> <span class="hljs-string">"chai"</span>;
<span class="hljs-keyword">import</span> { ethers } <span class="hljs-keyword">from</span> <span class="hljs-string">"hardhat"</span>;
<span class="hljs-keyword">import</span> ContractABI <span class="hljs-keyword">from</span> <span class="hljs-string">"../artifacts/contracts/Buidl.sol/BuidlToken.json"</span>;

<span class="hljs-comment">// Config</span>
<span class="hljs-comment">// ========================================================</span>
<span class="hljs-comment">/**
 * Name of contract
 */</span>
<span class="hljs-keyword">const</span> CONTRACT_NAME = <span class="hljs-string">"BuidlToken"</span>;

<span class="hljs-comment">/**
 * @dev Account #0: First wallet address given when we run the hardhat node
 */</span>
<span class="hljs-keyword">const</span> OWNER_ADDRESS = <span class="hljs-string">"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"</span>;

<span class="hljs-comment">/**
 * @dev Account #1: Second wallet address given when we run the hardhat node
 */</span>
<span class="hljs-keyword">const</span> RANDOM_ADDRESS = <span class="hljs-string">"0x70997970C51812dc3A010C7d01b50e0d17dc79C8"</span>;

<span class="hljs-comment">/**
 * @dev Account #2: Third wallet address given when we run the hardhat node
 */</span>
<span class="hljs-keyword">const</span> ANOTHER_ADDRESS = <span class="hljs-string">"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC"</span>;

<span class="hljs-comment">// Tests</span>
<span class="hljs-comment">// ========================================================</span>
describe(<span class="hljs-string">`<span class="hljs-subst">${CONTRACT_NAME}</span> - Contract Tests`</span>, <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-comment">/**
   * mint
   */</span>
  it(<span class="hljs-string">"mint - should FAIL when minting -1"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// Setup</span>
    <span class="hljs-keyword">const</span> initialSupply = <span class="hljs-number">1000</span>;
    <span class="hljs-keyword">const</span> amountToMint = <span class="hljs-number">-1</span>;
    <span class="hljs-comment">// - Deploy contract</span>
    <span class="hljs-keyword">const</span> Contract = <span class="hljs-keyword">await</span> ethers.getContractFactory(<span class="hljs-string">`<span class="hljs-subst">${CONTRACT_NAME}</span>`</span>);
    <span class="hljs-keyword">const</span> deployedContract = <span class="hljs-keyword">await</span> Contract.deploy(initialSupply);
    <span class="hljs-keyword">await</span> deployedContract.deployed();
    <span class="hljs-comment">// - Setup wallet that will interact with the contract as a signer</span>
    <span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> ethers.providers.JsonRpcProvider();
    <span class="hljs-keyword">const</span> signer = provider.getSigner(OWNER_ADDRESS);
    <span class="hljs-comment">// - Get the contract linked with the signer</span>
    <span class="hljs-keyword">const</span> contract = <span class="hljs-keyword">new</span> ethers.Contract(
      (<span class="hljs-keyword">await</span> deployedContract.deployed()).address,
      ContractABI.abi,
      signer
    );

    <span class="hljs-keyword">try</span> {
      <span class="hljs-comment">// Init</span>
      <span class="hljs-keyword">await</span> contract.mint(amountToMint);
    } <span class="hljs-keyword">catch</span> (error: <span class="hljs-built_in">any</span>) {
      <span class="hljs-comment">// Expectations</span>
      expect(error?.reason).to.be.eq(<span class="hljs-string">"value out-of-bounds"</span>);
    }
  });

  <span class="hljs-comment">/**
   * mint
   */</span>
  it(<span class="hljs-string">"mint - should PASS when minting 10"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// Setup</span>
    <span class="hljs-keyword">const</span> initialSupply = <span class="hljs-number">1000</span>;
    <span class="hljs-keyword">const</span> amountToMint = <span class="hljs-number">10</span>;
    <span class="hljs-keyword">const</span> walletOwner = OWNER_ADDRESS;
    <span class="hljs-comment">// - Deploy contract</span>
    <span class="hljs-keyword">const</span> Contract = <span class="hljs-keyword">await</span> ethers.getContractFactory(<span class="hljs-string">`<span class="hljs-subst">${CONTRACT_NAME}</span>`</span>);
    <span class="hljs-keyword">const</span> deployedContract = <span class="hljs-keyword">await</span> Contract.deploy(initialSupply);
    <span class="hljs-keyword">await</span> deployedContract.deployed();
    <span class="hljs-comment">// - Setup wallet that will interact with the contract as a signer</span>
    <span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> ethers.providers.JsonRpcProvider();
    <span class="hljs-keyword">const</span> signer = provider.getSigner(walletOwner);
    <span class="hljs-comment">// - Get the contract linked with the signer</span>
    <span class="hljs-keyword">const</span> contract = <span class="hljs-keyword">new</span> ethers.Contract(
      (<span class="hljs-keyword">await</span> deployedContract.deployed()).address,
      ContractABI.abi,
      signer
    );

    <span class="hljs-comment">// Init</span>
    <span class="hljs-keyword">await</span> contract.mint(amountToMint);
    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> contract.totalSupply();

    <span class="hljs-comment">// Expectations</span>
    expect(result).to.be.eq(initialSupply + amountToMint);
  });

  <span class="hljs-comment">/**
   * burn
   */</span>
  it(<span class="hljs-string">"burn - should FAIL when burning -1"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// Setup</span>
    <span class="hljs-keyword">const</span> initialSupply = <span class="hljs-number">1000</span>;
    <span class="hljs-keyword">const</span> amountToBurn = <span class="hljs-number">-1</span>;
    <span class="hljs-keyword">const</span> walletOwner = OWNER_ADDRESS;
    <span class="hljs-comment">// - Deploy contract</span>
    <span class="hljs-keyword">const</span> Contract = <span class="hljs-keyword">await</span> ethers.getContractFactory(<span class="hljs-string">`<span class="hljs-subst">${CONTRACT_NAME}</span>`</span>);
    <span class="hljs-keyword">const</span> deployedContract = <span class="hljs-keyword">await</span> Contract.deploy(initialSupply);
    <span class="hljs-keyword">await</span> deployedContract.deployed();
    <span class="hljs-comment">// - Setup wallet that will interact with the contract as a signer</span>
    <span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> ethers.providers.JsonRpcProvider();
    <span class="hljs-keyword">const</span> signer = provider.getSigner(walletOwner);
    <span class="hljs-comment">// - Get the contract linked with the signer</span>
    <span class="hljs-keyword">const</span> contract = <span class="hljs-keyword">new</span> ethers.Contract(
      (<span class="hljs-keyword">await</span> deployedContract.deployed()).address,
      ContractABI.abi,
      signer
    );

    <span class="hljs-keyword">try</span> {
      <span class="hljs-comment">// Init</span>
      <span class="hljs-keyword">await</span> contract.burn(amountToBurn);
    } <span class="hljs-keyword">catch</span> (error: <span class="hljs-built_in">any</span>) {
      <span class="hljs-comment">// Expectations</span>
      expect(error?.reason).to.be.eq(<span class="hljs-string">"value out-of-bounds"</span>);
    }
  });

  <span class="hljs-comment">/**
   * burn
   */</span>
  it(<span class="hljs-string">"burn - should FAIL when burning tokens that aren't owned"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// Setup</span>
    <span class="hljs-keyword">const</span> initialSupply = <span class="hljs-number">1000</span>;
    <span class="hljs-keyword">const</span> amountToBurn = <span class="hljs-number">100</span>;
    <span class="hljs-keyword">const</span> walletOwner = RANDOM_ADDRESS;
    <span class="hljs-comment">// - Deploy contract</span>
    <span class="hljs-keyword">const</span> Contract = <span class="hljs-keyword">await</span> ethers.getContractFactory(<span class="hljs-string">`<span class="hljs-subst">${CONTRACT_NAME}</span>`</span>);
    <span class="hljs-keyword">const</span> deployedContract = <span class="hljs-keyword">await</span> Contract.deploy(initialSupply);
    <span class="hljs-keyword">await</span> deployedContract.deployed();
    <span class="hljs-comment">// - Setup wallet that will interact with the contract as a signer</span>
    <span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> ethers.providers.JsonRpcProvider();
    <span class="hljs-keyword">const</span> signer = provider.getSigner(walletOwner);
    <span class="hljs-comment">// - Get the contract linked with the signer</span>
    <span class="hljs-keyword">const</span> contract = <span class="hljs-keyword">new</span> ethers.Contract(
      (<span class="hljs-keyword">await</span> deployedContract.deployed()).address,
      ContractABI.abi,
      signer
    );

    <span class="hljs-keyword">try</span> {
      <span class="hljs-comment">// Init</span>
      <span class="hljs-keyword">await</span> contract.burn(amountToBurn);
    } <span class="hljs-keyword">catch</span> (error: <span class="hljs-built_in">any</span>) {
      <span class="hljs-comment">// Expectations</span>
      expect(error?.reason).to.be.eq(
        <span class="hljs-string">"Error: VM Exception while processing transaction: reverted with reason string 'ERC20: burn amount exceeds balance'"</span>
      );
    }
  });

  <span class="hljs-comment">/**
   * burn
   */</span>
  it(<span class="hljs-string">"burn - should PASS when burning tokens that exist/owned"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// Setup</span>
    <span class="hljs-keyword">const</span> initialSupply = <span class="hljs-number">1000</span>;
    <span class="hljs-keyword">const</span> amountToBurn = <span class="hljs-number">100</span>;
    <span class="hljs-keyword">const</span> walletOwner = OWNER_ADDRESS;
    <span class="hljs-comment">// - Deploy contract</span>
    <span class="hljs-keyword">const</span> Contract = <span class="hljs-keyword">await</span> ethers.getContractFactory(<span class="hljs-string">`<span class="hljs-subst">${CONTRACT_NAME}</span>`</span>);
    <span class="hljs-keyword">const</span> deployedContract = <span class="hljs-keyword">await</span> Contract.deploy(initialSupply);
    <span class="hljs-keyword">await</span> deployedContract.deployed();
    <span class="hljs-comment">// - Setup wallet that will interact with the contract as a signer</span>
    <span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> ethers.providers.JsonRpcProvider();
    <span class="hljs-keyword">const</span> signer = provider.getSigner(walletOwner);
    <span class="hljs-comment">// - Get the contract linked with the signer</span>
    <span class="hljs-keyword">const</span> contract = <span class="hljs-keyword">new</span> ethers.Contract(
      (<span class="hljs-keyword">await</span> deployedContract.deployed()).address,
      ContractABI.abi,
      signer
    );

    <span class="hljs-comment">// Init</span>
    <span class="hljs-keyword">await</span> contract.burn(amountToBurn);
    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> contract.totalSupply();

    <span class="hljs-comment">// Expectations</span>
    expect(result).to.be.eq(initialSupply - amountToBurn);
  });

  <span class="hljs-comment">/**
   * approve
   */</span>
  it(<span class="hljs-string">"approve - should FAIL when approving -1"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// Setup</span>
    <span class="hljs-keyword">const</span> initialSupply = <span class="hljs-number">1000</span>;
    <span class="hljs-keyword">const</span> amountToApprove = <span class="hljs-number">-1</span>;
    <span class="hljs-keyword">const</span> walletOwner = OWNER_ADDRESS;
    <span class="hljs-keyword">const</span> walletApproved = RANDOM_ADDRESS;
    <span class="hljs-comment">// - Deploy contract</span>
    <span class="hljs-keyword">const</span> Contract = <span class="hljs-keyword">await</span> ethers.getContractFactory(<span class="hljs-string">`<span class="hljs-subst">${CONTRACT_NAME}</span>`</span>);
    <span class="hljs-keyword">const</span> deployedContract = <span class="hljs-keyword">await</span> Contract.deploy(initialSupply);
    <span class="hljs-keyword">await</span> deployedContract.deployed();
    <span class="hljs-comment">// - Setup wallet that will interact with the contract as a signer</span>
    <span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> ethers.providers.JsonRpcProvider();
    <span class="hljs-keyword">const</span> signer = provider.getSigner(walletOwner);
    <span class="hljs-comment">// - Get the contract linked with the signer</span>
    <span class="hljs-keyword">const</span> contract = <span class="hljs-keyword">new</span> ethers.Contract(
      (<span class="hljs-keyword">await</span> deployedContract.deployed()).address,
      ContractABI.abi,
      signer
    );

    <span class="hljs-keyword">try</span> {
      <span class="hljs-comment">// Init</span>
      <span class="hljs-keyword">await</span> contract.approve(walletApproved, amountToApprove);
    } <span class="hljs-keyword">catch</span> (error: <span class="hljs-built_in">any</span>) {
      <span class="hljs-comment">// Expectations</span>
      expect(error?.reason).to.be.eq(<span class="hljs-string">"value out-of-bounds"</span>);
    }
  });

  <span class="hljs-comment">/**
   * approve
   */</span>
  it(<span class="hljs-string">"approve - should PASS when approving 10"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// Setup</span>
    <span class="hljs-keyword">const</span> initialSupply = <span class="hljs-number">1000</span>;
    <span class="hljs-keyword">const</span> amountToApprove = <span class="hljs-number">10</span>;
    <span class="hljs-keyword">const</span> walletOwner = OWNER_ADDRESS;
    <span class="hljs-keyword">const</span> walletApproved = RANDOM_ADDRESS;
    <span class="hljs-comment">// - Deploy contract</span>
    <span class="hljs-keyword">const</span> Contract = <span class="hljs-keyword">await</span> ethers.getContractFactory(<span class="hljs-string">`<span class="hljs-subst">${CONTRACT_NAME}</span>`</span>);
    <span class="hljs-keyword">const</span> deployedContract = <span class="hljs-keyword">await</span> Contract.deploy(initialSupply);
    <span class="hljs-keyword">await</span> deployedContract.deployed();
    <span class="hljs-comment">// - Setup wallet that will interact with the contract as a signer</span>
    <span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> ethers.providers.JsonRpcProvider();
    <span class="hljs-keyword">const</span> signer = provider.getSigner(walletOwner);
    <span class="hljs-comment">// - Get the contract linked with the signer</span>
    <span class="hljs-keyword">const</span> contract = <span class="hljs-keyword">new</span> ethers.Contract(
      (<span class="hljs-keyword">await</span> deployedContract.deployed()).address,
      ContractABI.abi,
      signer
    );

    <span class="hljs-comment">// Init</span>
    <span class="hljs-keyword">await</span> contract.approve(walletApproved, amountToApprove);
    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> contract.allowance(walletOwner, walletApproved);

    <span class="hljs-comment">// Expectations</span>
    expect(result.toNumber()).to.be.eq(amountToApprove);
  });

  <span class="hljs-comment">/**
   * transfer
   */</span>
  it(<span class="hljs-string">"transfer - should FAIL when transferring -1"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// Setup</span>
    <span class="hljs-keyword">const</span> initialSupply = <span class="hljs-number">1000</span>;
    <span class="hljs-keyword">const</span> amountToTransfer = <span class="hljs-number">-1</span>;
    <span class="hljs-keyword">const</span> walletOwner = OWNER_ADDRESS;
    <span class="hljs-keyword">const</span> walletReceiving = RANDOM_ADDRESS;
    <span class="hljs-comment">// - Deploy contract</span>
    <span class="hljs-keyword">const</span> Contract = <span class="hljs-keyword">await</span> ethers.getContractFactory(<span class="hljs-string">`<span class="hljs-subst">${CONTRACT_NAME}</span>`</span>);
    <span class="hljs-keyword">const</span> deployedContract = <span class="hljs-keyword">await</span> Contract.deploy(initialSupply);
    <span class="hljs-keyword">await</span> deployedContract.deployed();
    <span class="hljs-comment">// - Setup wallet that will interact with the contract as a signer</span>
    <span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> ethers.providers.JsonRpcProvider();
    <span class="hljs-keyword">const</span> signer = provider.getSigner(walletOwner);
    <span class="hljs-comment">// - Get the contract linked with the signer</span>
    <span class="hljs-keyword">const</span> contract = <span class="hljs-keyword">new</span> ethers.Contract(
      (<span class="hljs-keyword">await</span> deployedContract.deployed()).address,
      ContractABI.abi,
      signer
    );

    <span class="hljs-keyword">try</span> {
      <span class="hljs-comment">// Init</span>
      <span class="hljs-keyword">await</span> contract.transfer(walletReceiving, amountToTransfer);
    } <span class="hljs-keyword">catch</span> (error: <span class="hljs-built_in">any</span>) {
      <span class="hljs-comment">// Expectations</span>
      expect(error?.reason).to.be.eq(<span class="hljs-string">"value out-of-bounds"</span>);
    }
  });

  <span class="hljs-comment">/**
   * transfer
   */</span>
  it(<span class="hljs-string">"transfer - should FAIL when transferring more than owned"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// Setup</span>
    <span class="hljs-keyword">const</span> initialSupply = <span class="hljs-number">1000</span>;
    <span class="hljs-keyword">const</span> amountToTransfer = <span class="hljs-number">1001</span>;
    <span class="hljs-keyword">const</span> walletOwner = OWNER_ADDRESS;
    <span class="hljs-keyword">const</span> walletReceiving = RANDOM_ADDRESS;
    <span class="hljs-comment">// - Deploy contract</span>
    <span class="hljs-keyword">const</span> Contract = <span class="hljs-keyword">await</span> ethers.getContractFactory(<span class="hljs-string">`<span class="hljs-subst">${CONTRACT_NAME}</span>`</span>);
    <span class="hljs-keyword">const</span> deployedContract = <span class="hljs-keyword">await</span> Contract.deploy(initialSupply);
    <span class="hljs-keyword">await</span> deployedContract.deployed();
    <span class="hljs-comment">// - Setup wallet that will interact with the contract as a signer</span>
    <span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> ethers.providers.JsonRpcProvider();
    <span class="hljs-keyword">const</span> signer = provider.getSigner(walletOwner);
    <span class="hljs-comment">// - Get the contract linked with the signer</span>
    <span class="hljs-keyword">const</span> contract = <span class="hljs-keyword">new</span> ethers.Contract(
      (<span class="hljs-keyword">await</span> deployedContract.deployed()).address,
      ContractABI.abi,
      signer
    );

    <span class="hljs-keyword">try</span> {
      <span class="hljs-comment">// Init</span>
      <span class="hljs-keyword">await</span> contract.transfer(walletReceiving, amountToTransfer);
    } <span class="hljs-keyword">catch</span> (error: <span class="hljs-built_in">any</span>) {
      <span class="hljs-comment">// Expectations</span>
      expect(error?.reason).to.be.eq(
        <span class="hljs-string">"Error: VM Exception while processing transaction: reverted with reason string 'ERC20: transfer amount exceeds balance'"</span>
      );
    }
  });

  <span class="hljs-comment">/**
   * transfer
   */</span>
  it(<span class="hljs-string">"transfer - should PASS when transferring 10"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// Setup</span>
    <span class="hljs-keyword">const</span> initialSupply = <span class="hljs-number">1000</span>;
    <span class="hljs-keyword">const</span> amountToTransfer = <span class="hljs-number">10</span>;
    <span class="hljs-keyword">const</span> walletOwner = OWNER_ADDRESS;
    <span class="hljs-keyword">const</span> walletReceiving = RANDOM_ADDRESS;
    <span class="hljs-comment">// - Deploy contract</span>
    <span class="hljs-keyword">const</span> Contract = <span class="hljs-keyword">await</span> ethers.getContractFactory(<span class="hljs-string">`<span class="hljs-subst">${CONTRACT_NAME}</span>`</span>);
    <span class="hljs-keyword">const</span> deployedContract = <span class="hljs-keyword">await</span> Contract.deploy(initialSupply);
    <span class="hljs-keyword">await</span> deployedContract.deployed();
    <span class="hljs-comment">// - Setup wallet that will interact with the contract as a signer</span>
    <span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> ethers.providers.JsonRpcProvider();
    <span class="hljs-keyword">const</span> signer = provider.getSigner(walletOwner);
    <span class="hljs-comment">// - Get the contract linked with the signer</span>
    <span class="hljs-keyword">const</span> contract = <span class="hljs-keyword">new</span> ethers.Contract(
      (<span class="hljs-keyword">await</span> deployedContract.deployed()).address,
      ContractABI.abi,
      signer
    );

    <span class="hljs-comment">// Init</span>
    <span class="hljs-keyword">await</span> contract.transfer(walletReceiving, amountToTransfer);
    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> contract.balanceOf(walletReceiving);

    <span class="hljs-comment">// Expectations</span>
    expect(result.toNumber()).to.be.eq(amountToTransfer);
  });

  <span class="hljs-comment">/**
   * scenario transferFrom
   */</span>
  it(<span class="hljs-string">"scenario transferFrom - should FAIL when approved spender spends more than the owner has"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// Setup</span>
    <span class="hljs-keyword">const</span> initialSupply = <span class="hljs-number">1000</span>;
    <span class="hljs-keyword">const</span> amountToApprove = <span class="hljs-number">10</span>;
    <span class="hljs-keyword">const</span> walletOwner = OWNER_ADDRESS;
    <span class="hljs-keyword">const</span> walletApproved = RANDOM_ADDRESS;
    <span class="hljs-keyword">const</span> walletReceiving = ANOTHER_ADDRESS;
    <span class="hljs-comment">// - Deploy contract</span>
    <span class="hljs-keyword">const</span> Contract = <span class="hljs-keyword">await</span> ethers.getContractFactory(<span class="hljs-string">`<span class="hljs-subst">${CONTRACT_NAME}</span>`</span>);
    <span class="hljs-keyword">const</span> deployedContract = <span class="hljs-keyword">await</span> Contract.deploy(initialSupply);
    <span class="hljs-keyword">await</span> deployedContract.deployed();
    <span class="hljs-comment">// - Setup wallet that will interact with the contract as a signer</span>
    <span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> ethers.providers.JsonRpcProvider();
    <span class="hljs-keyword">const</span> signerOwner = provider.getSigner(walletOwner);
    <span class="hljs-keyword">const</span> signerSpender = provider.getSigner(walletApproved);
    <span class="hljs-comment">// - Get the contract linked with the signer</span>
    <span class="hljs-keyword">const</span> contractOwner = <span class="hljs-keyword">new</span> ethers.Contract(
      (<span class="hljs-keyword">await</span> deployedContract.deployed()).address,
      ContractABI.abi,
      signerOwner
    );
    <span class="hljs-comment">// - Get the contract linked with other signer</span>
    <span class="hljs-keyword">const</span> contractSpender = <span class="hljs-keyword">new</span> ethers.Contract(
      (<span class="hljs-keyword">await</span> deployedContract.deployed()).address,
      ContractABI.abi,
      signerSpender
    );

    <span class="hljs-comment">// Init</span>
    <span class="hljs-keyword">await</span> contractOwner.approve(walletApproved, amountToApprove);
    <span class="hljs-keyword">const</span> resultAllowance = <span class="hljs-keyword">await</span> contractOwner.allowance(
      walletOwner,
      walletApproved
    );
    <span class="hljs-keyword">await</span> contractOwner.burn(initialSupply);
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> contractSpender.transferFrom(
        walletOwner,
        walletReceiving,
        amountToApprove
      );
    } <span class="hljs-keyword">catch</span> (error: <span class="hljs-built_in">any</span>) {
      <span class="hljs-comment">// Expectations</span>
      expect(error?.reason).to.be.eq(
        <span class="hljs-string">"Error: VM Exception while processing transaction: reverted with reason string 'ERC20: transfer amount exceeds balance'"</span>
      );
      expect(resultAllowance.toNumber()).to.be.eq(amountToApprove);
    }
  });

  <span class="hljs-comment">/**
   * scenario transferFrom
   */</span>
  it(<span class="hljs-string">"scenario transferFrom - should PASS when approved spender spends what the owner has"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// Setup</span>
    <span class="hljs-keyword">const</span> initialSupply = <span class="hljs-number">1000</span>;
    <span class="hljs-keyword">const</span> amountToApprove = <span class="hljs-number">10</span>;
    <span class="hljs-keyword">const</span> walletOwner = OWNER_ADDRESS;
    <span class="hljs-keyword">const</span> walletApproved = RANDOM_ADDRESS;
    <span class="hljs-keyword">const</span> walletReceiving = ANOTHER_ADDRESS;
    <span class="hljs-comment">// - Deploy contract</span>
    <span class="hljs-keyword">const</span> Contract = <span class="hljs-keyword">await</span> ethers.getContractFactory(<span class="hljs-string">`<span class="hljs-subst">${CONTRACT_NAME}</span>`</span>);
    <span class="hljs-keyword">const</span> deployedContract = <span class="hljs-keyword">await</span> Contract.deploy(initialSupply);
    <span class="hljs-keyword">await</span> deployedContract.deployed();
    <span class="hljs-comment">// - Setup wallet that will interact with the contract as a signer</span>
    <span class="hljs-keyword">const</span> provider = <span class="hljs-keyword">new</span> ethers.providers.JsonRpcProvider();
    <span class="hljs-keyword">const</span> signerOwner = provider.getSigner(walletOwner);
    <span class="hljs-keyword">const</span> signerSpender = provider.getSigner(walletApproved);
    <span class="hljs-comment">// - Get the contract linked with the signer</span>
    <span class="hljs-keyword">const</span> contractOwner = <span class="hljs-keyword">new</span> ethers.Contract(
      (<span class="hljs-keyword">await</span> deployedContract.deployed()).address,
      ContractABI.abi,
      signerOwner
    );
    <span class="hljs-comment">// - Get the contract linked with other signer</span>
    <span class="hljs-keyword">const</span> contractSpender = <span class="hljs-keyword">new</span> ethers.Contract(
      (<span class="hljs-keyword">await</span> deployedContract.deployed()).address,
      ContractABI.abi,
      signerSpender
    );

    <span class="hljs-comment">// Init</span>
    <span class="hljs-keyword">await</span> contractOwner.approve(walletApproved, amountToApprove);
    <span class="hljs-keyword">const</span> resultAllowanceBefore = <span class="hljs-keyword">await</span> contractOwner.allowance(
      walletOwner,
      walletApproved
    );
    <span class="hljs-keyword">await</span> contractSpender.transferFrom(
      walletOwner,
      walletReceiving,
      amountToApprove
    );
    <span class="hljs-keyword">const</span> resultAllowanceAfter = <span class="hljs-keyword">await</span> contractOwner.allowance(
      walletOwner,
      walletApproved
    );
    <span class="hljs-keyword">const</span> resultBalanceReceiver = <span class="hljs-keyword">await</span> contractOwner.balanceOf(
      walletReceiving
    );
    <span class="hljs-keyword">const</span> resusltBalanceOwner = <span class="hljs-keyword">await</span> contractOwner.balanceOf(walletOwner);

    <span class="hljs-comment">// Expectations</span>
    expect(resultAllowanceBefore).to.be.eq(amountToApprove);
    expect(resultAllowanceAfter).to.be.eq(<span class="hljs-number">0</span>);
    expect(resultBalanceReceiver.toNumber()).to.be.eq(amountToApprove);
    expect(resusltBalanceOwner.toNumber()).to.be.eq(
      initialSupply - amountToApprove
    );
  });
});
</code></pre>
<p>ℹ️ <strong>NOTE:</strong> You might get this error in TypeScript</p>
<pre><code class="lang-bash"><span class="hljs-string">'ContractABI'</span> is declared but its value is never <span class="hljs-built_in">read</span>.
</code></pre>
<p>To fix this, add <code>resolveJsonModule</code> to your <code>tsconfig.json</code> file:</p>
<p><strong>File:</strong> <code>./tsconfig.json</code></p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"compilerOptions"</span>: {
    <span class="hljs-attr">"target"</span>: <span class="hljs-string">"es2018"</span>,
    <span class="hljs-attr">"module"</span>: <span class="hljs-string">"commonjs"</span>,
    <span class="hljs-attr">"strict"</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">"esModuleInterop"</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">"outDir"</span>: <span class="hljs-string">"dist"</span>,
    <span class="hljs-attr">"declaration"</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">"resolveJsonModule"</span>: <span class="hljs-literal">true</span>
  },
  <span class="hljs-attr">"include"</span>: [<span class="hljs-string">"./scripts"</span>, <span class="hljs-string">"./test"</span>, <span class="hljs-string">"./typechain"</span>],
  <span class="hljs-attr">"files"</span>: [<span class="hljs-string">"./hardhat.config.ts"</span>]
}
</code></pre>
<p>In another Terminal, if we run the tests, we should get the following results:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># /optimism-erc20</span>
./node_modules/.bin/hardhat --network localhost <span class="hljs-built_in">test</span>;

<span class="hljs-comment"># Expected Output</span>
<span class="hljs-comment"># No need to generate any newer typings.</span>
<span class="hljs-comment"># </span>
<span class="hljs-comment">#   BuidlToken - Contract Tests</span>
<span class="hljs-comment">#     ✔ mint - should FAIL when minting -1 (276ms)</span>
<span class="hljs-comment">#     ✔ mint - should PASS when minting 10 (192ms)</span>
<span class="hljs-comment">#     ✔ burn - should FAIL when burning -1 (75ms)</span>
<span class="hljs-comment">#     ✔ burn - should FAIL when burning tokens that aren't owned (122ms)</span>
<span class="hljs-comment">#     ✔ burn - should PASS when burning tokens that exist/owned (143ms)</span>
<span class="hljs-comment">#     ✔ approve - should FAIL when approving -1 (67ms)</span>
<span class="hljs-comment">#     ✔ approve - should PASS when approving 10 (144ms)</span>
<span class="hljs-comment">#     ✔ transfer - should FAIL when transferring -1 (65ms)</span>
<span class="hljs-comment">#     ✔ transfer - should FAIL when transferring more than owned (102ms)</span>
<span class="hljs-comment">#     ✔ transfer - should PASS when transferring 10 (147ms)</span>
<span class="hljs-comment">#     ✔ scenario transferFrom - should FAIL when approved spender spends more than the owner has (259ms)</span>
<span class="hljs-comment">#     ✔ scenario transferFrom - should PASS when approved spender spends what the owner has (339ms)</span>
<span class="hljs-comment"># </span>
<span class="hljs-comment">#   12 passing (2s)</span>
</code></pre>
<h1 id="heading-deploying-to-testnet">Deploying To Testnet</h1>
<p>Now that we have our code and our tests validate the different scenarios, we are ready to deploy our ERC-20 Token contract to Optimism’s Kovan Testnet. Before we start, we’ll need to <a target="_blank" href="https://ankr.hashnode.dev/configure-your-metamask-to-work-with-optimism">configure our Metamask wallet with Optimism’s Testnet</a> and then add native Optimism tokens to it with a faucet.</p>
<h2 id="heading-getting-testnet-tokens-from-a-faucet">Getting Testnet Tokens From A Faucet</h2>
<p>Once you have Optimism Testnet supported in your Metmask wallet is to get Testnet tokens. You can do this by going to <a target="_blank" href="https://faucet.paradigm.xyz/">https://faucet.paradigm.xyz/</a>. You will need a Twitter account, but once you sign in, you should be able to enter your wallet address and click claim.</p>
<p>⚠️ <strong>NOTE:</strong> Remember to click the checkbox for "Drip on additional networks"</p>
<p>If you don’t have a Twitter account, you can use some of these faucet options as alternatives:</p>
<ul>
<li><a target="_blank" href="https://kovan.optifaucet.com/">https://kovan.optifaucet.com</a></li>
<li><a target="_blank" href="https://optimismfaucet.xyz/">https://optimismfaucet.xyz</a></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657152292557/DBijURIW-.png" alt="Paradigm" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657152330518/5dYFHOWWv.png" alt="Paradigm Metamask" /></p>
<h2 id="heading-deployment-configuration">Deployment Configuration</h2>
<p>Now that we have the tokens in our wallet, we just need to need to create our environment variable file (<code>.env</code>) and modify our <code>hardhat.config.ts</code> to add the Optimism network to it.</p>
<p>Let’s first start by modifying our <code>.env.example</code> file:</p>
<p><strong>File:</strong> <code>./.env.example</code></p>
<pre><code class="lang-bash">ETHERSCAN_API_KEY=ABC123ABC123ABC123ABC123ABC123ABC1
OPTIMISM_KOVAN_URL=https://kovan.optimism.io
PRIVATE_KEY=0xabc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1
</code></pre>
<p>Next we’ll make a copy of it and paste our wallet private key to the <code>PRIVATE_KEY</code> section.</p>
<p>⚠️ <strong>REMEMBER:</strong> Never share this private key with anyone, not even your mom.</p>
<pre><code class="lang-bash">cp .env.example .env;
</code></pre>
<p>Next, we’ll need to get our wallet private key.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657152480048/u1ZTG3u4J.png" alt="Account Details" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657152543600/QFjlhRkS0.png" alt="Account Export Private" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657152590500/dZgJfym-D.png" alt="Password" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657152621298/pQHpLyko_.png" alt="Private Key" /></p>
<p>Once we have it, add it to our newly created <code>.env</code> file.</p>
<p><strong>File:</strong> <code>./.env</code></p>
<pre><code class="lang-bash">ETHERSCAN_API_KEY=ABC123ABC123ABC123ABC123ABC123ABC1
OPTIMISM_KOVAN_URL=https://kovan.optimism.io
PRIVATE_KEY=&lt;YOUR-WALLET-SECRET-PRIVATE-KEY&gt;
</code></pre>
<p>With these details entered, we just need to modify our <code>hardhat.config.ts</code> to support these new values and the Optimism Kovan testnet.</p>
<p><strong>File:</strong> <code>./hardhat.config.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> dotenv <span class="hljs-keyword">from</span> <span class="hljs-string">"dotenv"</span>;

<span class="hljs-keyword">import</span> { HardhatUserConfig, task } <span class="hljs-keyword">from</span> <span class="hljs-string">"hardhat/config"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@nomiclabs/hardhat-etherscan"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@nomiclabs/hardhat-waffle"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@typechain/hardhat"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"hardhat-gas-reporter"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"solidity-coverage"</span>;

dotenv.config();

<span class="hljs-comment">// This is a sample Hardhat task. To learn how to create your own go to</span>
<span class="hljs-comment">// https://hardhat.org/guides/create-task.html</span>
task(<span class="hljs-string">"accounts"</span>, <span class="hljs-string">"Prints the list of accounts"</span>, <span class="hljs-keyword">async</span> (taskArgs, hre) =&gt; {
  <span class="hljs-keyword">const</span> accounts = <span class="hljs-keyword">await</span> hre.ethers.getSigners();

  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> account <span class="hljs-keyword">of</span> accounts) {
    <span class="hljs-built_in">console</span>.log(account.address);
  }
});

<span class="hljs-comment">// You need to export an object to set up your config</span>
<span class="hljs-comment">// Go to https://hardhat.org/config/ to learn more</span>

<span class="hljs-keyword">const</span> config: HardhatUserConfig = {
  solidity: <span class="hljs-string">"0.8.4"</span>,
  networks: {
    <span class="hljs-comment">// ! START HERE - ADD THIS</span>
    optimismKovan: {
      url: process.env.OPTIMISM_KOVAN_URL || <span class="hljs-string">""</span>,
      accounts:
        process.env.PRIVATE_KEY !== <span class="hljs-literal">undefined</span> ? [process.env.PRIVATE_KEY] : [],
    },
        <span class="hljs-comment">// END HERE !</span>
  },
  gasReporter: {
    enabled: process.env.REPORT_GAS !== <span class="hljs-literal">undefined</span>,
    currency: <span class="hljs-string">"USD"</span>,
  },
  etherscan: {
    apiKey: process.env.ETHERSCAN_API_KEY,
  },
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> config;
</code></pre>
<h2 id="heading-finally-deploying-andamp-verifying-deployment">Finally Deploying &amp; Verifying Deployment</h2>
<p>Everything is now setup, now we can deploy our contract to the Optimism Kovan Testnet.</p>
<p>Run the following and enjoy the miracle of deploying to the blockchain.</p>
<pre><code class="lang-bash">./node_modules/.bin/hardhat run scripts/deploy.ts --network optimismKovan;

<span class="hljs-comment"># Expected Ouput</span>
<span class="hljs-comment"># No need to generate any newer typings.</span>
<span class="hljs-comment"># Contract deployed to: 0x375F01b156D9BdDDd41fd38c5CC74C514CB71f73</span>
</code></pre>
<p>Using <a target="_blank" href="https://kovan-optimistic.etherscan.io/">Etherscan’s Optimism Kovan Blockchain Explorer</a>, we can search for the deployed contract.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657152878363/yRxH7z_qa.png" alt="Etherscan" /></p>
<h1 id="heading-verifying-our-contract">Verifying Our Contract</h1>
<p>Now that we have our contract deployed, we want to be able to interact with it via the blockchain explorer and in order to do that we need to verify its source code. This part requires creating an account with <a target="_blank" href="https://optimistic.etherscan.io/register">Optimistic Etherscan</a> and generating an API key.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657152974360/C2yRmq9yu.png" alt="Deployed Contract" /></p>
<p>To do this, you’ll need to go to <a target="_blank" href="https://optimistic.etherscan.io/">https://optimistic.etherscan.io/</a>, sign up for a new account, and then make your way to the API Key section to generate a new key. With this key you’ll be pasting it into you <code>.env</code> file.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657153037395/weUkOGtKX.png" alt="Etherscan API" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657153081926/UUf5rKRtq.png" alt="Etherscan API Create Key" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657153132919/QXKJN3C_f.png" alt="Etherscan API Copy Key" /></p>
<p>With the newly created API key, copy it to this file.</p>
<p><strong>File:</strong> <code>./.env</code></p>
<pre><code class="lang-bash">ETHERSCAN_API_KEY=&lt;YOUR-OPTIMISTIC-ETHERSCAN-API-KEY&gt;
OPTIMISM_KOVAN_URL=https://kovan.optimism.io
PRIVATE_KEY=&lt;YOUR-WALLET-SECRET-PRIVATE-KEY&gt;
</code></pre>
<p>Now that we have all the right values, we can run the following to validate the contract.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># /optimism-erc20</span>
<span class="hljs-comment"># <span class="hljs-doctag">NOTE:</span></span>
<span class="hljs-comment"># 1 - 0x375... refers to the deployed contract address</span>
<span class="hljs-comment"># 2 - 1000 refers to the original 1000 supply parameter deployed in our deploy.ts file </span>
./node_modules/.bin/hardhat verify --network optimismKovan 0x375F01b156D9BdDDd41fd38c5CC74C514CB71f73 1000

<span class="hljs-comment"># Expected Output</span>
<span class="hljs-comment"># Nothing to compile</span>
<span class="hljs-comment"># No need to generate any newer typings.</span>
<span class="hljs-comment"># Successfully submitted source code for contract</span>
<span class="hljs-comment"># contracts/Buidl.sol:BuidlToken at 0x375F01b156D9BdDDd41fd38c5CC74C514CB71f73</span>
<span class="hljs-comment"># for verification on the block explorer. Waiting for verification result...</span>

<span class="hljs-comment"># Successfully verified contract BuidlToken on Etherscan.</span>
<span class="hljs-comment"># https://kovan-optimistic.etherscan.io/address/0x375F01b156D9BdDDd41fd38c5CC74C514CB71f73#code</span>
</code></pre>
<p>Now if we look on the test net we’ll see a bunch of functions that are available to us.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657153253251/AQAmipGq8.png" alt="Etherscan Wallet Interaction" /></p>
<h1 id="heading-minting-tokens">Minting Tokens</h1>
<p>Our final step is to increase the total supply by minting more token through the blockchain explorer. To do this you’ll head over to the <strong>Contract</strong> section and select <strong>Write Contract</strong>. From there you’ll need to connect your wallet (the wallet address which deployed the contract) and use the <code>mint</code> function.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657153360846/X4qxLJCR0.png" alt="Etherscan Write Contract" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657153432956/KXl4DfKYG.png" alt="Etherscan Write Interaction" /></p>
<p>Once the transaction is complete, you can verify the total supply by going back the <strong>Read Contract</strong> section and expanding the <code>totalSupply</code> section to see the new supply being reflected.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1657153490532/-wq0TVPlR.png" alt="Etherscan Read Contract" /></p>
<h1 id="heading-full-code-repository">Full Code Repository</h1>
<p>Congrats, you’ve completed a full deployment of an ERC-20 token to Optimism Kovan Testnet. If you want to take a look at the full source code, click the repository link below.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/codingwithmanny/optimism-erc20">https://github.com/codingwithmanny/optimism-erc20</a></div>
<h1 id="heading-whats-next">What’s Next?</h1>
<p>A fun project would also be to create an NFT marketplace that only accepts this new erc-20 token.</p>
<p>If you got value from this, please like it, heart it, fire it, all of the emojis, and please also follow me on Twitter (where I’m quite active) <a target="_blank" href="https://twitter.com/codingwithmant">@codingwithmanny</a> and on Discord as codingwithmanny :).</p>
<h1 id="heading-other-articles-to-read">Other Articles To Read</h1>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://ankr.hashnode.dev/configure-your-metamask-to-work-with-optimism">https://ankr.hashnode.dev/configure-your-metamask-to-work-with-optimism</a></div>
]]></content:encoded></item><item><title><![CDATA[Deploy and Mint a CryptoKitties-Like NFT with ERC-721 Smart Contract]]></title><description><![CDATA[Dawn of ERC-721
Mention NFT revolution and you will most likely stumble upon this project over and over again: CryptoKitties. Originally built on the Ethereum blockchain, CryptoKitties was the first non-fungible token (NFT) that allowed the creation ...]]></description><link>https://ankr.hashnode.dev/deploy-and-mint-a-cryptokitties-like-nft-with-erc-721-smart-contract</link><guid isPermaLink="true">https://ankr.hashnode.dev/deploy-and-mint-a-cryptokitties-like-nft-with-erc-721-smart-contract</guid><category><![CDATA[Smart Contracts]]></category><category><![CDATA[NFT]]></category><category><![CDATA[erc721]]></category><category><![CDATA[NFTcollectibles]]></category><category><![CDATA[Solidity]]></category><dc:creator><![CDATA[Krinza Momin]]></dc:creator><pubDate>Wed, 29 Jun 2022 08:46:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1656496459142/5REUr8i92.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-dawn-of-erc-721">Dawn of ERC-721</h3>
<p>Mention NFT revolution and you will most likely stumble upon this project over and over again: CryptoKitties. Originally built on the Ethereum blockchain, CryptoKitties was the first non-fungible token (NFT) that allowed the creation of unique digital collectibles as kitties, using the ERC-721 smart contract. Before the dawn of ERC-721, tokens on blockchain were only fungible, meaning they can be traded or exchanged with another identical one of the same value, much like a dollar bill. </p>
<p>We've already discussed how you can make a fungible token using <a target="_blank" href="https://ankr.hashnode.dev/how-to-deploy-your-own-erc-20-token-with-ankr-and-hardhat-on-eth-goerli-testnet">ERC20</a>↗, but what if you want to create tokens that are not alike at all?</p>
<h3 id="heading-what-we-are-building">What we are Building</h3>
<p>CryptoKitties really braced the growth and use case of NFTs we see today and in this tutorial, we will walk through creating and deploying an ERC-721 smart contract and minting the token on Optimism Kovan-Testnet using <a target="_blank" href="https://docs.soliditylang.org/en/v0.8.0/">Solidity</a>↗, <a target="_blank" href="https://hardhat.org/getting-started">Hardhat</a>↗ and <a target="_blank" href="https://www.pinata.cloud/">Pinata</a>↗. </p>
<p>By the end of this tutorial - you'll be able to mint an NFT and display it on <a target="_blank" href="https://testnet.quixotic.io/">Quixotic</a>↗ (an NFT marketplace on Optimism) from your deployed ERC721 contract. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1656491648455/rWcCRtwWU.png" alt="screenshot-rocks (8).png" /></p>
<hr />
<h2 id="heading-getting-started">Getting Started</h2>
<p>PS: I know I just threw a ton of new words at you in the previous section and if any of the above was confusing, don't worry as we'll discuss each one of them in detail. </p>
<p>But before we get our hands dirty, let's take a quick rundown on what Optimism is?</p>
<h3 id="heading-what-is-optimistic-ethereum">What is Optimistic Ethereum?</h3>
<p>Optimism is a layer 2 scaling solution for ETH, meaning it functions on top of the Ethereum mainnet (L1). It uses a technology called rollups, specifically Optimistic rollups, where the transactions are executed off the chain and get bundled into a single transaction before being pushed to the main blockchain. This increases the transaction speed and throughput and decreases the cost per transaction.</p>
<p>Pretty handy, right? Ready to give optimism a try?</p>
<hr />
<h3 id="heading-step-1-connect-metamask-to-optimism-kovan-testnet">Step 1: Connect Metamask to Optimism Kovan Testnet</h3>
<p>If you do not own a wallet, the first thing that needs to be done is to download and install the browser extension of <a target="_blank" href="https://metamask.io/download/">MetaMask</a>↗.</p>
<p>Once MetaMask is installed and running, follow these simple steps to connect with Optimism Kovan Testnet:</p>
<ul>
<li>Navigate to <a target="_blank" href="https://chainlist.org/">chainlist.org</a>↗</li>
<li>Enable the <code>Testnet</code> option and search for Optimism Kovan and connect your wallet with the given RPC.</li>
</ul>
<p>If you want to launch your ERC721 contract directly to mainnet, replace the RPC URL with Ankr's Public RPC -&gt; https://rpc.ankr.com/optimism</p>
<hr />
<h3 id="heading-step-2-add-test-ether-from-a-faucet">Step 2: Add Test Ether from a Faucet</h3>
<p>To request funds, go to <a target="_blank" href="https://optimismfaucet.xyz/">Optimism Kovan Faucet</a>↗ and sign in with GitHub to acquire some tokens. Wait a few moments and your wallet should be funded!</p>
<p>Note: ETH on testnets has no real value.</p>
<hr />
<h3 id="heading-step-3-set-up-your-development-environment">Step 3: Set Up Your Development Environment</h3>
<p>To get started with the hardhat installation, we first need to set up our dev environment. To do so, create a new directory called <code>erc721-token-mint</code>.</p>
<ul>
<li>Now, initialize your new npm project in the <code>erc721-token-mint</code> directory by running the following command in the terminal of your preferred code editor.</li>
</ul>
<pre><code>npm <span class="hljs-keyword">init</span>
</code></pre><pre><code><span class="hljs-built_in">npm</span> install dotenv
</code></pre><ul>
<li>Once your project is ready, install Hardhat, an Ethereum development environment for testing and deploying smart contracts to the blockchain.</li>
</ul>
<p>It might take a minute or two to install everything!</p>
<pre><code>npm install <span class="hljs-operator">-</span><span class="hljs-operator">-</span>save<span class="hljs-operator">-</span>dev hardhat
</code></pre><ul>
<li>Run <code>npx hardhat</code> and choose "create an empty hardhat.config.js".</li>
</ul>
<pre><code><span class="hljs-attribute">npx</span> hardhat
</code></pre><p>Your project should now contain the following files and folders: <code>hardhat.config.js</code>, <code>node_modules</code>, <code>package.json</code> and <code>package-lock.json</code>.</p>
<ul>
<li>Next, we are going to create two new directories to house our smart contract and deployment script. To do so, enter the following commands:</li>
</ul>
<pre><code><span class="hljs-keyword">mkdir</span> contracts
</code></pre><pre><code><span class="hljs-keyword">mkdir</span> scripts
</code></pre><ul>
<li>We will now install a Hardhat plugin that brings the Ethereum library ethers.js, which allows you to interact with the Ethereum blockchain in a simple way.</li>
</ul>
<pre><code>npm install <span class="hljs-operator">-</span><span class="hljs-operator">-</span>save<span class="hljs-operator">-</span>dev @nomiclabs<span class="hljs-operator">/</span>hardhat<span class="hljs-operator">-</span>ethers ethers
</code></pre><pre><code>npm install <span class="hljs-operator">-</span><span class="hljs-operator">-</span>save<span class="hljs-operator">-</span>dev @openzeppelin<span class="hljs-operator">/</span>hardhat<span class="hljs-operator">-</span>upgrades
</code></pre><ul>
<li>Create a <code>.env</code> file in your project’s root folder and set the environment variable as follows. This is the private key of the account you intend to use on the Optimism Network from MetaMask.</li>
</ul>
<pre><code><span class="hljs-attr">PRIVATE_KEY</span> = YOUR_PRIVATE_KEY
</code></pre><hr />
<h3 id="heading-step-4-setup-hardhat-configs">Step 4: Setup Hardhat Configs</h3>
<p>Before setting up the <code>hardhat.config.js</code> file, we will need a gateway to communicate to the Ethereum blockchain. For that, we will be using the Kovan testnet RPC <code>https://kovan.optimism.io/</code> provided by Optimism.</p>
<p>If you want to deploy your ERC-721 directly on the mainnet, you can use <a target="_blank" href="https://www.ankr.com/protocol/public/optimism/">Ankr's Public RPC</a>↗ for Optimism. Just copy the URL, no account or login is required!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1656513942082/THcPdzjEJ.png" alt="screenshot-rocks (11).png" /></p>
<p>Now you are ready to edit your <code>hardhat.config.js</code> with the following:</p>
<ul>
<li>Open the <code>hardhat.config.js</code> file</li>
<li>Delete the code inside, and copy-paste the code below:</li>
</ul>
<pre><code><span class="hljs-comment">/**
* @type import('hardhat/config').HardhatUserConfig
*/</span>
<span class="hljs-built_in">require</span>(<span class="hljs-string">'dotenv'</span>).config();
<span class="hljs-built_in">require</span>(<span class="hljs-string">"@nomiclabs/hardhat-ethers"</span>);

module.exports <span class="hljs-operator">=</span> {
   solidity: <span class="hljs-string">"0.8.1"</span>,
   defaultNetwork: <span class="hljs-string">"kovan"</span>,
   networks: {
      hardhat: {},
      kovan: {
         url: <span class="hljs-string">"https://kovan.optimism.io/"</span>,
         accounts: [`0x${process.env.PRIVATE_KEY}`]
      }
   },
}
</code></pre><p>Did you notice how we are sourcing the <code>PRIVATE_KEY</code> variable in this file? We are loading them up from <code>process.env</code> using the <code>dotenv</code> library we installed while setting up the dev environment.</p>
<hr />
<h3 id="heading-step-5-write-erc-721-smart-contract">Step 5: Write ERC-721 Smart Contract</h3>
<p>We will use an ERC-721 standard based on OpenZepplin. <a target="_blank" href="https://www.openzeppelin.com/">OpenZepplin</a>↗️ is an open-source standard for securing blockchain applications and provides security products to build, automate, and operate dApps.</p>
<ul>
<li>For this, we will install the OpenZepplin's contracts library.</li>
</ul>
<pre><code><span class="hljs-built_in">npm</span> install @openzeppelin/contracts
</code></pre><ul>
<li>Now navigate to the <code>contracts</code> folder and create a new file called <code>KittyMonster.sol</code></li>
<li>Below is our NFT smart contract code based on the OpenZeppelin's ERC721 implementation. Copy and paste the contents below into your <code>KittyMonster.sol</code> file.</li>
</ul>
<pre><code>
<span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-comment">//Declare the version of solidity to compile this contract. </span>
<span class="hljs-comment">//This must match the version of solidity in your hardhat.config.js file</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.1;</span>

<span class="hljs-comment">//inherits three OpenZepplin smart contract classes</span>

<span class="hljs-comment">//contains implementation of ERC721</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"</span>;

<span class="hljs-comment">//provides counters that can only be incremented or decremented by one</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/utils/Counters.sol"</span>;

<span class="hljs-comment">//implements ownership in the contracts</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/access/Ownable.sol"</span>;

<span class="hljs-comment">//This function instantiates the contract and </span>
<span class="hljs-comment">//classifies ERC721 for storage schema</span>
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">KittyMonster</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC721URIStorage</span>, <span class="hljs-title">Ownable</span> </span>{

    <span class="hljs-comment">//to keep track of the total number of NFTs minted </span>
    <span class="hljs-keyword">using</span> <span class="hljs-title">Counters</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title">Counters</span>.<span class="hljs-title">Counter</span>;
    Counters.Counter <span class="hljs-keyword">private</span> _tokenIds;

    <span class="hljs-comment">//sets contract's name and symbol</span>
    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) <span class="hljs-title">ERC721</span>(<span class="hljs-params"><span class="hljs-string">"KittyMonster"</span>, <span class="hljs-string">"KMON"</span></span>) </span>{}

    <span class="hljs-comment">//address recipient: address that will receive freshly minted NFT</span>
    <span class="hljs-comment">//tokenURI: describes the NFT's metadata</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mintNFT</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> recipient, <span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> tokenURI</span>)
        <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">onlyOwner</span>
        <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>)
    </span>{
        _tokenIds.increment();

        <span class="hljs-keyword">uint256</span> newItemId <span class="hljs-operator">=</span> _tokenIds.current();
        _mint(recipient, newItemId);
        _setTokenURI(newItemId, tokenURI);

        <span class="hljs-keyword">return</span> newItemId;
    }
}
</code></pre><ul>
<li>Save the file and compile your contract to make sure everything is good to deploy using the command below:</li>
</ul>
<pre><code><span class="hljs-attribute">npx</span> hardhat compile

<span class="hljs-comment"># output</span>
<span class="hljs-comment"># Compiled n Solidity file successfully</span>
</code></pre><hr />
<h3 id="heading-step-6-write-the-deploy-script">Step 6: Write the Deploy Script</h3>
<p>Now that we've got our ERC-721 contract set up, let's create the deployment script.</p>
<ul>
<li>Navigate to the <code>scripts</code> folder and create a new file called <code>deploy.js</code></li>
<li>Open the <code>deploy.js</code> file and copy-paste the following code:</li>
</ul>
<pre><code>async <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Grab the contract factory </span>
    <span class="hljs-comment">//used to deploy new smart contracts</span>
    const KittyMonster <span class="hljs-operator">=</span> await ethers.getContractFactory(<span class="hljs-string">"KittyMonster"</span>);

    <span class="hljs-comment">// Start deployment, returning a promise that resolves to a contract object</span>
    const KMONS <span class="hljs-operator">=</span> await KittyMonster.deploy(); <span class="hljs-comment">// Instance of the contract </span>
    console.log(<span class="hljs-string">"Contract deployed to address:"</span>, KMONS.<span class="hljs-built_in">address</span>);
 }

 main()
   .then(() <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> process.exit(<span class="hljs-number">0</span>))
   .catch(<span class="hljs-function"><span class="hljs-keyword">error</span> =&gt; </span>{
     console.error(<span class="hljs-function"><span class="hljs-keyword">error</span>)</span>;
     process.exit(<span class="hljs-number">1</span>);
   });
</code></pre><ul>
<li>Save and close the file</li>
<li>Run <code>npx hardhat run scripts/deploy.js --network kovan</code></li>
</ul>
<pre><code>npx hardhat run scripts<span class="hljs-operator">/</span>deploy.js <span class="hljs-operator">-</span><span class="hljs-operator">-</span>network kovan
</code></pre><p><code>Output: Contract deployed to address: 0xA2a736b9af8B2D3bb95F92d1cC015Bc6D0A2C0cB</code></p>
<p>Running the above command will compile the contract and deploy it to the Optimism Kovan Testnet.</p>
<ul>
<li>If you go to the <a target="_blank" href="https://kovan-optimistic.etherscan.io/">Kovan Optimism Etherscan</a>↗ and search for your contract address, you should be able to see that the contract has been successfully deployed. </li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1656513980889/SN0xRDthn.png" alt="screenshot-rocks (12).png" /></p>
<hr />
<h3 id="heading-step-7-flattening-the-solidity-file">Step 7: Flattening the Solidity File</h3>
<p>To update token information on Etherscan, the token contract address for the token must be verified. As contract owners, we can verify our contract by following the steps below. But before that, we will require to <strong>flatten the solidity file</strong> using Hardhat. </p>
<ul>
<li>To do so, within your project directory, run the following command on your terminal:<pre><code><span class="hljs-selector-tag">npx</span> <span class="hljs-selector-tag">hardhat</span> <span class="hljs-selector-tag">flatten</span> &gt; <span class="hljs-selector-tag">flattened</span><span class="hljs-selector-class">.sol</span>
</code></pre>This will generate a <code>flattened.sol</code> file which contains the contract(s) code and all its dependencies, which we will copy and paste to the etherscan when verifying the contract.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1656514000219/4qtOVayI8.png" alt="screenshot-rocks (13).png" /></p>
<p>Make sure in your <code>flattened.sol</code> file, <code>// SPDX-License-Identifier: MIT</code> is only mentioned one time. Otherwise, it will throw you an error. </p>
<hr />
<h3 id="heading-step-8-verifying-the-contract-on-optimism-kovan-etherscan">Step 8: Verifying the Contract on Optimism Kovan Etherscan</h3>
<p>To verify the contract on Optimism Kovan Etherscan, follow the steps below:</p>
<ul>
<li><p>Under the contract address, next to the <code>Transaction</code> tab, you will be able to find the “Contract” tab. Then click on “Verify And Publish” and you'll land on <code>Verify and Publish Contract Source Code</code> page.</p>
</li>
<li><p>From the drop-down for compiler type, version selection and license type, select the following configs: </p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1656514017337/9ZbOkkn0P.png" alt="screenshot-rocks (14).png" /></p>
<ul>
<li>Hit "continue" and under <code>Enter the Solidity Contract Code below</code> section, copy and paste the entire code from the <code>flattened.sol</code> file that we generated in step 7. </li>
<li>Click <code>Verify and Publish</code> and you be able to see that your contract is successfully verified on Optimism Kovan Etherscan.</li>
</ul>
<p>When the contract has been verified, the “Code” page will be filled with the contract details. The source code of the contract is now publicly available on Etherscan.</p>
<hr />
<h3 id="heading-step-9-adding-nft-asset-to-ipfs-or-pinata">Step 9: Adding NFT Asset to IPFS | Pinata</h3>
<p>We’re going to use Pinata to store our NFT asset and JSON metadata to IPFS so that we can pass it through to our token contract (remember <code>tokenURI</code> parameter from our <code>mintNFT</code> function in the smart contract?). </p>
<p>If you don’t have a Pinata account, <a target="_blank" href="https://app.pinata.cloud/">sign up</a>↗ for a free account here and complete the steps to verify your email.</p>
<ul>
<li>Once you have verified your account on the Pinata, navigate to the "My Files" page and click the "Upload" button.</li>
<li>Upload your NFT art and you'll see your image asset file under the <code>Files</code> page along with the CID column. </li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1656514143631/1Mte3mHbZ.png" alt="screenshot-rocks (16).png" /></p>
<ul>
<li>Copy the CID by clicking the copy button next to it and use it as a postfix to this URL "https://gateway.pinata.cloud/ipfs/" to view your NFT art. </li>
</ul>
<p>Here's the <a target="_blank" href="https://gateway.pinata.cloud/ipfs/QmY3AiXaCt9JFJ33GTR5U7YjXKrC5xbtjJDjEdUbN8QMVG">image</a>↗ that I used. </p>
<p>Now, we’re going to upload one more document to Pinata - JSON metadata. To do that, follow the steps below: </p>
<ul>
<li>In your code's root directory, make a new file called <code>monstermeta.json</code> and add the code given below to the JSON file.</li>
</ul>
<pre><code>{
    <span class="hljs-attr">"attributes"</span> : [ {
      <span class="hljs-attr">"trait_type"</span> : <span class="hljs-string">"Monster"</span>,
      <span class="hljs-attr">"value"</span> : <span class="hljs-string">"Dybbuk"</span>
    }, {
      <span class="hljs-attr">"trait_type"</span> : <span class="hljs-string">"Space"</span>,
      <span class="hljs-attr">"value"</span> : <span class="hljs-string">"Fire"</span>
    } ],
    <span class="hljs-attr">"description"</span> : <span class="hljs-string">"not cryptokitties."</span>,
    <span class="hljs-attr">"image"</span> : <span class="hljs-string">"https://gateway.pinata.cloud/ipfs/QmY3AiXaCt9JFJ33GTR5U7YjXKrC5xbtjJDjEdUbN8QMVG"</span>,
    <span class="hljs-attr">"name"</span> : <span class="hljs-string">"Kabbey"</span>
}
</code></pre><p>Feel free to add or remove the attributes. Also, make sure you are providing your IPFS image URL - otherwise, you will mint Kabbey too!! </p>
<ul>
<li>Once you’re done editing the JSON file, save it and upload it to Pinata, following the same steps we followed for uploading the image and copy the CID for the JSON file (we will need that in the next step).</li>
</ul>
<hr />
<h3 id="heading-step-10-minting-nft">Step 10: Minting NFT</h3>
<ul>
<li>To mint the NFT, navigate under the contract address page, next to the <code>Transaction</code> tab, you will find the “Contract” tab. </li>
<li>Click on “Write Contract” and "connect to Web3"</li>
<li>Under <code>mintNFT</code>, input your wallet's public address in <code>recipient (address)</code> and CID for the JSON file you uploaded to the Pinata. </li>
<li>Hit "write", and you can view your transaction successfully executed in the Optimism Kovan Etherscan.</li>
</ul>
<p>Now, we will head to <a target="_blank" href="https://testnet.quixotic.io/">Quixotic.io</a>↗, an NFT marketplace for Optimism. </p>
<ul>
<li>Connect your wallet to Quicotic's testnet marketplace and you'll be able to view your minted NFT there!</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1656514168389/v1o6tB1Jv.png" alt="screenshot-rocks (10).png" /></p>
<hr />
<h2 id="heading-check-the-github-repo">Check the GitHub Repo</h2>
<p>If you followed along with the tutorial, awesome! Here you can find the GitHub repository with the full code. </p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/kaymomin/erc721-token-mint">https://github.com/kaymomin/erc721-token-mint</a></div>
<p> </p>
<h3 id="heading-next-steps">Next Steps</h3>
<p>If you are up for a challenge, build a full-stack dApp to mint, display and transfer NFTs to your friends and make sure you drop the project links in the comments section. </p>
<p>If you have any cool idea you want to discuss, drop me a "👋" on Twitter <a target="_blank" href="https://twitter.com/kayprasla">@kayprasla</a> or find me in the Developer DAO discord!</p>
]]></content:encoded></item><item><title><![CDATA[How to deploy your own ERC-20 token with Ankr & Hardhat on ETH Goerli Testnet]]></title><description><![CDATA[If 'I wish I had my own token ' thought ever crossed your mind, then this article will serve to be your step-by-step guide for building and deploying your very own token (think of a name already). 
Getting Started
ERC-20 are widely used tokens on the...]]></description><link>https://ankr.hashnode.dev/how-to-deploy-your-own-erc-20-token-with-ankr-and-hardhat-on-eth-goerli-testnet</link><guid isPermaLink="true">https://ankr.hashnode.dev/how-to-deploy-your-own-erc-20-token-with-ankr-and-hardhat-on-eth-goerli-testnet</guid><category><![CDATA[Web3]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[Ankr]]></category><category><![CDATA[Ethereum]]></category><dc:creator><![CDATA[Krinza Momin]]></dc:creator><pubDate>Fri, 20 May 2022 13:00:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1652974130039/rXK7mS5cy.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If '<em>I wish I had my own token</em> ' thought ever crossed your mind, then this article will serve to be your step-by-step guide for building and deploying your very own token (think of a name already). </p>
<h3 id="heading-getting-started">Getting Started</h3>
<p>ERC-20 are widely used tokens on the Ethereum network. They are <strong>fungible</strong>, which means you don’t have to care which token you have since they’re all the same. And they are <strong>transferrable</strong>, meaning they can be sent from one address to another. This contrasts with non-fungible tokens (NFTs), which are unique and therefore not interchangeable.</p>
<p>Now that we briefly understand what ERC20 means, let's get started creating our very first ERC20 token.</p>
<h3 id="heading-step-1-create-a-metamask-account">Step 1: Create a MetaMask Account</h3>
<p>You will need MetaMask to access the testing networks on Ethereum. In this guide, we will use Goerli, an Ethereum test network that allows blockchain development testing before the deployment on Mainnet.</p>
<p>In your browser, go to <a target="_blank" href="https://metamask.io/">metamask.io</a> and install the plugin. Once MetaMask is installed and running, select the Goerli network. </p>
<h3 id="heading-step-2-acquire-goerli-eth">Step 2: Acquire Goerli ETH</h3>
<p>To request funds, go to <a target="_blank" href="https://faucets.chain.link/goerli">Goerli Faucet</a> and connect your metamask wallet with your newly-created test account into the UI. Wait a few moments and your wallet should be funded!</p>
<p>Note: ETH on testnets has no real value. </p>
<h3 id="heading-step-3-set-up-the-dev-environment">Step 3: Set up the Dev Environment</h3>
<p>To get started with the hardhat installation, we first need to set up our dev environment. To do so, create a new directory called <code>erc20-token-ankr</code>.</p>
<ul>
<li>Now, initialize your new npm project in the <code>erc20-token-ankr</code> directory by running the following command in the terminal.</li>
</ul>
<pre><code>npm <span class="hljs-keyword">init</span>
</code></pre><pre><code><span class="hljs-built_in">npm</span> install dotenv
</code></pre><ul>
<li>Once your project is ready, install Hardhat, an Ethereum development environment for testing and deploying smart contracts to the blockchain.</li>
</ul>
<pre><code>npm install <span class="hljs-operator">-</span><span class="hljs-operator">-</span>save<span class="hljs-operator">-</span>dev hardhat
</code></pre><ul>
<li>Run <code>npx hardhat</code>, choose "create a sample project" and say y to everything.</li>
</ul>
<p>It might take a minute or two to install everything!</p>
<pre><code><span class="hljs-attribute">npx</span> hardhat
</code></pre><p>Your project should now contain the following files and folders:
 <code>hardhat.config.js</code>,<code>node_modules</code>, <code>package.json</code>,  <code>package-lock.json</code>, <code>README.md</code>, <code>scripts</code>, and <code>contracts</code>.</p>
<ul>
<li><p>Go ahead and delete the <code>sample-script.js</code> in the <code>/scripts</code> directory and <code>Greeter.sol</code> in the <code>/contractsdirectory</code>.</p>
</li>
<li><p>We will now install a Hardhat plugin that brings the Ethereum library <a target="_blank" href="Link">ethers.js</a>, which allows you to interact with the Ethereum blockchain in a simple way.</p>
</li>
</ul>
<pre><code>npm install <span class="hljs-operator">-</span><span class="hljs-operator">-</span>save<span class="hljs-operator">-</span>dev @openzeppelin<span class="hljs-operator">/</span>hardhat<span class="hljs-operator">-</span>upgrades
</code></pre><pre><code>npm install <span class="hljs-operator">-</span><span class="hljs-operator">-</span>save<span class="hljs-operator">-</span>dev @nomiclabs<span class="hljs-operator">/</span>hardhat<span class="hljs-operator">-</span>ethers ethers
</code></pre><ul>
<li>Create a <code>.env</code> file in your project’s root folder and set the environment variable as follows. This is the private key of the account you intend to use on the Ethereum Network from MetaMask. </li>
</ul>
<pre><code><span class="hljs-attr">PRIVATE_KEY</span>=YOUR_PRIVATE_KEY
</code></pre><h3 id="heading-step-4-setup-hardhat">Step 4: Setup Hardhat</h3>
<p>Before setting up the <code>hardhat.config.js</code> file, we will need a gateway to communicate to Ethereum blockchain. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652553317904/XXYDUL60z.avif" alt="XA56QNi0d.avif" /></p>
<p>For that, we will be using <a target="_blank" href="https://www.ankr.com/protocol/public/eth/">Ankr's Public RPCs</a> to connect and send transactions on the Ethereum blockchain. Just copy the URL for the goerli testnet. No account or login is required!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652602906656/92QE1r-CE.png" alt="image.png" /></p>
<p>Now you are ready to edit your hardhat.config.js with the following:</p>
<ul>
<li>Open the <code>hardhat.config.js</code> file</li>
<li>Delete the code inside, and copy-paste the code below:</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-built_in">require</span>(<span class="hljs-string">"@nomiclabs/hardhat-waffle"</span>);
<span class="hljs-built_in">require</span>(<span class="hljs-string">'@openzeppelin/hardhat-upgrades'</span>);
<span class="hljs-comment">// Any file that has require('dotenv').config() statement </span>
<span class="hljs-comment">// will automatically load any variables in the root's .env file.</span>
<span class="hljs-built_in">require</span>(<span class="hljs-string">'dotenv'</span>).config();

<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">solidity</span>: <span class="hljs-string">"0.8.0"</span>,
  <span class="hljs-attr">networks</span>:{
    <span class="hljs-attr">goerli</span>:{
      <span class="hljs-comment">// Ankr's Public RPC URL</span>
      <span class="hljs-attr">url</span>: <span class="hljs-string">"https://rpc.ankr.com/eth_goerli"</span>,
     <span class="hljs-comment">// PRIVATE_KEY loaded from .env file</span>
      <span class="hljs-attr">accounts</span>: [<span class="hljs-string">`0x<span class="hljs-subst">${process.env.PRIVATE_KEY}</span>`</span>]
    }
  }
};
</code></pre>
<p>Did you notice how we are sourcing the <code>PRIVATE_KEY</code> variable in this file? We are loading them up from <code>process.env</code> using the <code>dotenv</code> library we installed while setting up the dev environment. </p>
<h3 id="heading-step-5-set-up-erc-20-contract">Step 5: Set Up ERC-20 Contract</h3>
<p>We will use an ERC-20 standard based on OpenZepplin. <a target="_blank" href="https://www.openzeppelin.com/">OpenZepplin</a>↗️ is an open-source standard for securing blockchain applications and provides security products to build, automate, and operate dApps.</p>
<p>For this, we will need the <code>@openzeppelin/contracts</code> package! </p>
<pre><code><span class="hljs-built_in">npm</span> install @openzeppelin/contracts
</code></pre><pre><code>npm install <span class="hljs-operator">-</span><span class="hljs-operator">-</span>save<span class="hljs-operator">-</span>dev @nomiclabs<span class="hljs-operator">/</span>hardhat<span class="hljs-operator">-</span>waffle
</code></pre><p>Now, it is time to name your token! </p>
<p>In the next steps, we will create a smart contract file (<strong>you must match the name of the file with the name of token</strong>). So if you're thinking to name your token <code>Buildoooor</code>, make sure to name the contract file exactly the same <code>Buildoooor.sol</code>.</p>
<ul>
<li><p><code>cd</code> into your <code>/contracts</code> folder (which should be empty right now), and run <code>touch Buildoooor.sol</code>.</p>
</li>
<li><p>Open the newly-create .sol file and copy-paste the following:</p>
</li>
</ul>
<pre><code><span class="hljs-comment">//SPDX-License-Identifier: Unlicense</span>
<span class="hljs-comment">//Declare the version of solidity to compile this contract. </span>
<span class="hljs-comment">//This must match the version of solidity in your hardhat.config.js file</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/ERC20.sol"</span>;

<span class="hljs-comment">//This function instantiates the contract and </span>
<span class="hljs-comment">//classifies ERC20 for storage schema</span>
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Buildoooor</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC20</span> </span>{

   <span class="hljs-comment">//Feel free to change the initial supply of 50 token </span>
   <span class="hljs-comment">//Keep the (10**18) unchanged as it multiplies the number we want as our supply to have 18 decimal</span>
    <span class="hljs-keyword">uint</span> <span class="hljs-keyword">constant</span> _initial_supply <span class="hljs-operator">=</span> <span class="hljs-number">50</span> <span class="hljs-operator">*</span> (<span class="hljs-number">10</span><span class="hljs-operator">*</span><span class="hljs-operator">*</span><span class="hljs-number">18</span>);

    <span class="hljs-comment">// make sure to replace the "Buildoooor" reference </span>
    <span class="hljs-comment">//with your own ERC-20 name</span>
    <span class="hljs-comment">//choose a token symbol, in our this case "FIRT"</span>
    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) <span class="hljs-title">ERC20</span>(<span class="hljs-params"><span class="hljs-string">"Buildoooor"</span>, <span class="hljs-string">"BUDL"</span></span>) </span>{

        _mint(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, _initial_supply);
    }
}
</code></pre><ul>
<li>Save and close this file</li>
<li>Compile your contract to make sure everything is good to deploy</li>
</ul>
<pre><code><span class="hljs-attribute">npx</span> hardhat compile

<span class="hljs-comment"># output</span>
<span class="hljs-comment"># Compiled n Solidity file successfully</span>
</code></pre><blockquote>
<p>Note: If you are on windows and getting "nothing to compile error" thrown at you, run <code>npm install glob@7.2.0</code> and rerun <code>npx hardhat compile</code>. This should solve the problem. Learn more <a target="_blank" href="https://github.com/NomicFoundation/hardhat/issues/2712#issuecomment-1126722588">here</a>!</p>
</blockquote>
<h3 id="heading-step-6-deploy-the-erc20-token">Step 6: Deploy the ERC20 Token</h3>
<p>Now that we've got our ERC20 contract set up, let's create the deployment script for it. </p>
<ul>
<li><code>cd ..</code> back into your project root directory</li>
<li><code>cd</code> into your scripts directory (which should be empty right now)</li>
<li>Run <code>touch deploy.js</code>, open the deploy.js file and copy-paste the following:</li>
</ul>
<pre><code>async <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
    const [deployer] <span class="hljs-operator">=</span> await ethers.getSigners();

    console.log(<span class="hljs-string">"Deploying contracts with the account:"</span>, deployer.<span class="hljs-built_in">address</span>);

    const weiAmount <span class="hljs-operator">=</span> (await deployer.getBalance()).toString();

    console.log(<span class="hljs-string">"Account balance:"</span>, (await ethers.utils.formatEther(weiAmount)));

   <span class="hljs-comment">// make sure to replace the "Buildoooor" reference </span>
   <span class="hljs-comment">//with your own ERC-20 name</span>
    const Token <span class="hljs-operator">=</span> await ethers.getContractFactory(<span class="hljs-string">"Buildoooor"</span>);
    const token <span class="hljs-operator">=</span> await Token.deploy();

  <span class="hljs-comment">// log the address of the Contract in our console</span>
    console.log(<span class="hljs-string">"Token address:"</span>, token.<span class="hljs-built_in">address</span>);
  }

<span class="hljs-comment">// run main, catch error, if any, and log in console</span>
  main()
    .then(() <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> process.exit(<span class="hljs-number">0</span>))
    .catch((<span class="hljs-function"><span class="hljs-keyword">error</span>) =&gt; </span>{
      console.error(<span class="hljs-function"><span class="hljs-keyword">error</span>)</span>;
      process.exit(<span class="hljs-number">1</span>);
  });
</code></pre><ul>
<li>Save and close the file</li>
<li><code>cd ..</code> back into your project root directory</li>
<li>Run <code>npx hardhat run scripts/deploy.js --network goerli</code></li>
</ul>
<pre><code><span class="hljs-attribute">npx</span> hardhat run scripts/deploy.js --network goerli

<span class="hljs-comment">#Deploying contracts with the account: 0x6d4779c3Dc002894C2E2108c75e6ef72C418E23f</span>
<span class="hljs-comment">#Account balance: 0.2</span>
<span class="hljs-comment">#Token address: 0x74d8C71a4aF1eBD7DA5B8eAAabe35b0D29478DF6</span>
</code></pre><p>Your contract will be compiled and deployed to the Goerli network! </p>
<ul>
<li>Now, go to <a target="_blank" href="https://goerli.etherscan.io/tx/0xc7d30c40475bb3d16bb9cac24a59fd02faf03d308d324b19061e8abed6c11241">goerli.etherscan.io/</a> and input your token address to see your deployed ERC-20 contract on Goerli Network.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652620208612/i-Zfqm2nI.png" alt="image.png" /></p>
<p>Buildoooors, great job deploying your own ERC-20 token on Goerli using Ankr, Hardhat, and OpenZeppelin ERC20 standard. Comment your contract addresses below and share them with the community!</p>
]]></content:encoded></item><item><title><![CDATA[Blockchain is Decentralized. What about access to it?]]></title><description><![CDATA[If advocates are to be believed, an idealistic third version of the web built for users must be truly decentralized. While the underlying architecture of blockchain itself is an attempt to democratize ownership, much of the infrastructure in practice...]]></description><link>https://ankr.hashnode.dev/blockchain-is-decentralized-what-about-access-to-it</link><guid isPermaLink="true">https://ankr.hashnode.dev/blockchain-is-decentralized-what-about-access-to-it</guid><category><![CDATA[Web3]]></category><category><![CDATA[infrastructure]]></category><category><![CDATA[Ankr]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[distributed system]]></category><dc:creator><![CDATA[Krinza Momin]]></dc:creator><pubDate>Thu, 19 May 2022 14:33:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1652970706502/HUOEYgpq5.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If advocates are to be believed, an idealistic third version of the web built for users must be truly decentralized. While the underlying architecture of blockchain itself is an attempt to democratize ownership, much of the infrastructure in practice is still the same as Web 2.0 — servers are owned by corporations which creates a centralized bottleneck in a decentralized system.</p>
<p>If you're an experienced blockchain developer, you will know how node infrastructure and developer tools are required to enable broader application development. If you're new here, having a rudimentary understanding of the concepts bandied around nodes and how they are an essential component of the blockchain stack might be beneficial. </p>
<p>Let’s begin by understanding what a blockchain node is.</p>
<h3 id="heading-node-in-a-blockchain-network">Node in a Blockchain Network</h3>
<p>A node is essentially a gateway to receive, store and send blockchain data along different routes through a distributed network. It acts as a connection point for transactions to be chronologically recorded and shared with a series of connected computers. These computers are called nodes. </p>
<p>Without nodes, a blockchain’s data would not be accessible. Therefore, one could easily say that nodes are the blockchain and all dApps need a way to communicate with it.  </p>
<h3 id="heading-accessing-the-blockchain">Accessing the Blockchain</h3>
<p>To do so, developers can either:</p>
<ul>
<li><strong>Run their own nodes</strong></li>
</ul>
<p>which can be resource-intensive from storage to bandwidth to valuable engineering time. </p>
<p>So, instead of manually setting up intricate infrastructure around a node, web3 developers often seek solutions that allow them to communicate with blockchains without needing to set aside time and focus for anything other than building their dApps. That's where <a target="_blank" href="https://kevin-dwyer.medium.com/centralized-vs-decentralized-web3-infrastructure-what-should-developers-choose-1a1d5f0715c7">node-as-a-service</a> provider comes in. </p>
<ul>
<li><strong>Or pay for centralized providers</strong></li>
</ul>
<p>relying heavily on AWS data centers to house their nodes and eventually falling prey to the government regulations, centralized censorship, control, and ofcourse single point of failure. So if AWS goes down — all of the dApps that depend on these nodes to communicate with the blockchain go down with it. </p>
<p>Now here comes the question of the day: if the blockchain is decentralized, should access to it be <a target="_blank" href="https://medium.com/ankr-network/why-you-shouldnt-rely-on-centralized-infrastructure-for-web3-b4d16cff22f4">centralized</a>?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652039144923/5RqN_7Spf.jpg" alt="FPP3WJ2XwBodDp7 (1).jpg" /></p>
<p>If your answer to the question is a "no", then you'll sure resonate with the third option. </p>
<ul>
<li><strong>Use a decentralized infrastructure provider</strong></li>
</ul>
<p>like <a target="_blank" href="https://www.ankr.com/">Ankr</a> offering multi-chain tools and node infrastructure to make Web3 development easy and prolific, all while doubling down on the true ethos of blockchain. Not only does Ankr Protocol come with a much smaller price tag, but it’s important to note that users are paying for more decentralized, geo-distributed infrastructure that affords them more reliability, less latency, and improved security. From free, public RPCs to advanced developer APIs, there’s something for every Web3 developer. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652038161339/pyEabowck.jpg" alt="FQIy5D8XsAEDCs-.jpg" /></p>
<h3 id="heading-build-with-ankr">Build with Ankr</h3>
<p>With Ankr, you can access a network of decentralized, independently run nodes with lower latency, more reliability, and high-performance standards while incentivizing node operators, users, and communities. </p>
<p>Ankr's public RPC endpoints can get you access to 15 blockchain networks including Polygon, Avalanche, Arbitrum, Solana, Celo, Near, Fantom, and Ethereum to name a few. <strong>No signups, no logins, just building.</strong></p>
<p>In addition to individual RPCs, Ankr operates a highly sophisticated multichain RPC that’s capable of interacting with multiple EVM-compatible blockchains at once. This tool works best with Ankr’s advanced developer APIs that allow dApps to scale cheaper, faster, and easier than ever before.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652038984533/MYXmnxEjT.jpg" alt="FQDVS9EWQAUEFtS (1).jpg" /></p>
<h3 id="heading-wrapping-it-up">Wrapping it up</h3>
<p>The more infrastructure for developers and Web3 applications remain relatively centralized, the more susceptible it is to censorship, control, and concentrated power. To realize the promise of web3, it's important for solutions to not be built on top of a centralized bottleneck. That's exactly where Ankr is disrupting itself, by providing developers and enterprises with tools and infrastructure that sit true to the vision of decentralization. </p>
]]></content:encoded></item></channel></rss>