<?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[Jarrod Watts' Blog]]></title><description><![CDATA[Jarrod Watts Writes Technical Guides About Modern JavaScript Technologies and Web3. 

Check Out My Technical Blog Today!]]></description><link>https://blog.jarrodwatts.com</link><generator>RSS for Node</generator><lastBuildDate>Fri, 17 Apr 2026 18:11:00 GMT</lastBuildDate><atom:link href="https://blog.jarrodwatts.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[What is dev rel? (my perspective)]]></title><description><![CDATA[“What does dev rel do?” I see this question get asked surprisingly often.
Recently, I was given the opportunity to build a developer relations program from scratch and reflect on my 3 years of experience in this role to create a strategy.
I decided t...]]></description><link>https://blog.jarrodwatts.com/what-is-dev-rel-my-perspective</link><guid isPermaLink="true">https://blog.jarrodwatts.com/what-is-dev-rel-my-perspective</guid><category><![CDATA[DevRel]]></category><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Wed, 25 Sep 2024 06:10:13 GMT</pubDate><content:encoded><![CDATA[<p>“What does dev rel do?” I see this question get asked surprisingly often.</p>
<p>Recently, I was given the opportunity to build a developer relations program from scratch and reflect on my 3 years of experience in this role to create a strategy.</p>
<p>I decided to write these thoughts to document what I’ve learned from reading countless dev rel articles, several books on dev rel, and personal experiences on dev rel and how I’ve seen it done effectively.</p>
<p>A lot of the ideas in the post I have learned and expanded on from <a target="_blank" href="https://x.com/swyx">swyx</a>’s posts. They’re of course not necessarily correct, just my <em>current</em> opinions on things.</p>
<h2 id="heading-what-does-dev-rel-do">What does dev rel do?</h2>
<p><strong>Help developers be successful using your developer tool</strong> - this is dev rel.</p>
<p>You will often hear developer relations separated into different categories; developer relations, developer advocacy, developer education, developer experience, etc.</p>
<ul>
<li><p>Some companies will place these different teams on a spectrum from public-facing to internal-facing.</p>
</li>
<li><p>Some companies will move you around from engineering, marketing, and product (and back).</p>
</li>
<li><p><em>Some companies will just lay you off because they don’t know what you do.</em></p>
</li>
</ul>
<p>They’re basically the same thing with different areas of expertise/specialization.</p>
<p>All of these teams fit into the umbrella of developer relations, and a developer relations team has the goal of <strong>helping developers be successful using your developer tool</strong>.</p>
<p>This can be simplified into working on the <strong>developer experience</strong>; the level of ease a developer can successfully use your product to achieve their goal.</p>
<p>The <strong>developer experience</strong> is the most important aspect a developer tools company can have in the long term. I’ve written about why DX is so important in depth in the Tweet 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://twitter.com/jarrodWattsDev/status/1833716395122753538">https://twitter.com/jarrodWattsDev/status/1833716395122753538</a></div>
<p> </p>
<p>This goal might sound straightforward, but it’s multifaceted and <em>that</em> is the reason people are confused about what dev rel actually does.</p>
<h3 id="heading-breaking-down-the-dev-rel-goal">Breaking down the dev rel goal</h3>
<p>So why does every dev rel you speak to give you a different answer when asked what dev rel does? It’s because the goal <em>(help developers be successful using your tool)</em> is vague, broad, and difficult to measure.</p>
<p>This goal can be attacked in plenty of different ways, and depending on the stage of the company, the skillset of the person(s) you hired, and the goals &amp; culture of your company; the best strategy to do dev rel well is different.</p>
<p>Let’s interpret the goal (<em>Help developers be successful using your tool)</em> in different ways as an example of how things quickly get complicated:</p>
<ul>
<li><p><strong>Help developers</strong></p>
<ul>
<li><p>We don’t have any developers to help → Create awareness by creating content, attending developer conferences, and creating and sharing demos.</p>
</li>
<li><p>Developers aren’t opting to use our tool → Listen to the developer community and provide actionable feedback to the team internally.</p>
</li>
<li><p>Developers hate the experience of using our tool → Create better resources for developers; build documentation, starter kits, tutorials, etc.</p>
</li>
</ul>
</li>
<li><p><strong>Be successful using your developer tool</strong></p>
<ul>
<li><p>What does success mean for your customers and your business? Do you have thousands of individual developers or a handful of teams? The support you provide will be different.</p>
</li>
<li><p>How do you retain these successful developers and create a flywheel effect to bring onboard more developers to your tool?</p>
</li>
</ul>
</li>
</ul>
<p>These, among many other jobs I haven’t listed above, all fall under developer relations, and usually no one person is going to do all of it well; they have different skills, preferences, and ideas on how dev rel should be done.</p>
<p>The founders/managers will also have a big impact on what areas they want to see prioritized from the dev rel team (for better or worse).</p>
<p>So, with so much to cover for one role, what is a framework to approach developer relations with? What things should you prioritize, what things should you drop, and what things do I have no clue about?</p>
<h2 id="heading-a-framework-to-do-dev-rel">A framework to do dev rel</h2>
<p>After reading countless blog posts and several books, attending and participating in panels, discussing strategies with dev rel veterans, and trying these things myself… the best framework I have seen and try to apply myself is <a target="_blank" href="https://dx.tips/circles">radiating circles by Swyx</a>.</p>
<p>My interpretation of his framework is below.</p>
<h3 id="heading-radiating-circles-of-dx-by-swyx">Radiating circles of DX (by Swyx)</h3>
<p>In a nutshell, the framework follows this core idea:</p>
<ul>
<li><p>If your product was intuitive, you wouldn’t need docs.</p>
</li>
<li><p>If your docs covered everything clearly, you wouldn’t need supporting content.</p>
</li>
<li><p>If your content covered the hard parts or told a story hard to convey in the docs, you wouldn’t need 1-1 support in your community.</p>
</li>
<li><p>If all of the above was covered, you wouldn’t need to spend time helping developers in 1-1 chats like Discord, Slack, Telegram, etc.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1653867087999/dEkuiL4-x.png?auto=compress,format&amp;format=webp" alt="image.png" class="image--center mx-auto" /></p>
<p>Realistically, each of these areas is impossible to make perfect, and you should be doing all of it - but it provides a good guide of what the foundation should be when trying to improve your DX and priorities of what to work on.</p>
<ul>
<li><p>You can have a super intuitive product, but a strong getting started section and clear documentation helps a lot. This part is non-negotiable.</p>
</li>
<li><p>Your docs might be great, but content can help tie things together or make developers aware of what’s possible with your tool. They might check out your tool when they otherwise wouldn’t have done so thanks to your content.</p>
</li>
<li><p>Your resources might be great, but your customer support, community, events, and general <em>vibes</em> bring a love of using your tool and encourage developers to actively advocate for your tool to their peers.</p>
</li>
</ul>
<h4 id="heading-what-does-this-framework-mean">What does this framework mean?</h4>
<p><strong>You should prioritize improving the circles closer to the centre if you want the effort you put into those further from the centre to be effective.</strong></p>
<ul>
<li><p>You could have amazing content, docs, and community but if your product sucks to use or doesn’t solve their problem, then developers aren’t going to use it. You will still see some success, but the efforts you put into everything else suffer.</p>
<ul>
<li><p>Put simply: “You can't polish a turd”.</p>
</li>
<li><p>A good example is <a target="_blank" href="https://viem.sh/">viem</a>. Developers love it, a tonne of thought has been put into the product and the experience of using it. Nothing flashy - just a performant, typesafe library that developers love and recommend.</p>
</li>
</ul>
</li>
<li><p>You could have the worst docs, content, and community in the world but if your product is incredible with an amazing DX, <em>some</em> developers are probably still going to use it if it solves a problem for them. They just won’t like it, and move to something better when it exists.</p>
<ul>
<li><p>Put simply: “Good wine needs no bush”, but it certainly helps.</p>
</li>
<li><p>I’m not going to provide a specific example here - think of any product/company you have heard of N number of times but still have no idea what they even do or any reason to try it.</p>
</li>
</ul>
</li>
</ul>
<h4 id="heading-the-two-way-relationship-of-radiating-circles">The two-way relationship of radiating circles</h4>
<p>Swyx’s point here (at least as I interpreted it) was your product needs to be good first, your docs need to be good next, and so on.</p>
<ul>
<li><p>If your product is good and solves a problem, some people will use it.</p>
</li>
<li><p>If your docs are good, they’ll have a good experience using it, be able to achieve complex things more easily, be more likely to continue using your product and recommend using it to other people.</p>
</li>
<li><p>If your docs are not good enough, they’ll try to find out things in other ways, like YouTube videos, blog posts, or external sites like GitHub issues. This isn’t ideal.</p>
</li>
<li><p>If your tools are open source, they’ll dive into the code itself to see what’s going wrong or see how things work under the hood. It’s getting painful for them now.</p>
</li>
<li><p>As a last resort, they’ll join your support channels. Slack, Discord, Telegram. They don’t want to be in there. This is very annoying for most devs, especially if your support is no help at all.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726640937347/2a2d9cfe-825b-4534-bb3a-dc7ae139acb5.png" alt class="image--center mx-auto" /></p>
<p>These circles also provide a useful framework for understanding how to get developers to become aware of your product, which follows the reverse pattern.</p>
<ul>
<li><p>Developers are most likely to trust other developers in your community who are advocating for your product. It makes them aware of your product.</p>
</li>
<li><p>Developers can encounter your product being used to solve a problem in your content or at least become aware that your product exists from it.</p>
</li>
<li><p>Developers might check out your docs when they finally need to solve a problem and have a “what does this thing actually do?” moment.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726641578381/8c0077ea-e94b-486c-b8d8-6195a21ae0a6.png" alt class="image--center mx-auto" /></p>
<p>Once a developer is aware and willing to try your product, all of these efforts you put in so far lead into your product. This is where the reverse process (described above) begins - they will make their own assessment based on your product, and then read your docs, and go further out as they struggle with your DX.</p>
<p>This is why it’s important to get your fundamentals (things closer to the centre) right.</p>
<p>If you are pouring effort into your community and content, developers will come in to try your product. If you let them down when they arrive with a bad DX, you have wasted your efforts in the wider circles.</p>
<p>The wider circles provide more inflow of developers into your smaller circles, where it’s important for them to be successful. You can also think of this direction as a conversion funnel from awareness to success.</p>
<p>So, what do these circles actually involve? What tangible things can dev rel teams do to improve the developer experience in each of these aspects?</p>
<h3 id="heading-product">Product</h3>
<p>Your goal here is to make the product as intuitive as possible, by continually providing feedback (or directly contributing yourself) to the product itself and also external tools that developers are likely to integrate your tool with.</p>
<p>An exercise I like to try is - <strong>raw dog using your product</strong> and using only knowledge you can find publicly available from your existing resources (e.g. docs).</p>
<p>Mentally drop all prior knowledge of your tool and try to build something. Is it intuitive? Do things behave as you expect? Is it difficult to figure out how to do things? Are your AI tools able to provide helpful suggestions?</p>
<p>Provide any valuable feedback to your team to incrementally improve the product.</p>
<p>Everything else you make is a step away from your product. Your docs are an interpretation of your product, your content is piecing together parts of your docs to achieve something, etc.</p>
<h3 id="heading-docs">Docs</h3>
<p>I am struggling to write advice on writing good docs, but here is what I have:</p>
<ul>
<li><p>Your <strong>getting started</strong> flow is the most important.</p>
<ul>
<li>All developers will likely go through this and then disperse into the other parts of your docs when they get stuck on what to do next.</li>
</ul>
</li>
<li><p>Make them easily searchable and create good information architecture.</p>
<ul>
<li>Things should start simple and get progressively more complex (called “stair-stepping knowledge”) - this applies both on the sidebar and to the content of each page.</li>
</ul>
</li>
<li><p>Don’t repeat yourself. You don’t need to write the whole history of Ethereum to explain a concept. Assume some prior knowledge, or have a page that defines something clearly in the stair-stepping structure and then use links to that page wherever that pre-requisite knowledge is required.</p>
<ul>
<li>For example, assume your developers know the programming language; it is not your responsibility to teach them this in your documentation.</li>
</ul>
</li>
</ul>
<h3 id="heading-content">Content</h3>
<p>Sometimes it’s easier to explain something if you just hand developers the solution or a step-by-step guide on how to achieve something specific. This includes:</p>
<ul>
<li><p>GitHub Example repos - repositories that show best practices of using your tool to accomplish a given goal.</p>
</li>
<li><p>Step-by-step written &amp; video tutorials - same purpose as above.</p>
</li>
<li><p>Explainer content (Twitter threads, blog posts, short/long videos) - this helps bring awareness to your tool and its capabilities.</p>
</li>
<li><p>Build the brand of the individual dev rels in your company - people respect other people’s opinions more than they respect brands, and people associate your employees with your company.</p>
</li>
</ul>
<h3 id="heading-community">Community</h3>
<p>Community is more than just answering questions, but this part is where I lack the most knowledge. I don’t have good answers on how to build a community right now.</p>
<ul>
<li><p>Have a space where your team answers questions from developers like Discord.</p>
</li>
<li><p>Answer questions about your product on forums like GitHub issues.</p>
</li>
<li><p>Have less noisy dedicated chats for top-priority teams.</p>
</li>
</ul>
<h3 id="heading-what-should-i-do">What should I do?</h3>
<p>Identify what areas closer to the centre suck and start there. You can identify this yourself or speak to existing developers and learn from them.</p>
<p>If your product sucks, provide feedback or work on the product. If your docs suck, write better docs. If your content sucks, start creating good content; move outwards in the radiating circles as you feel things improving.</p>
<p>This doesn’t mean <em>just</em> doing that thing only; it is about balancing each of these areas among the members of your team and identifying what you should be prioritizing given your unique circumstances.</p>
<h4 id="heading-enjoyed-this">Enjoyed this?</h4>
<p>Follow me on Twitter: <a target="_blank" href="https://twitter.com/jarrodWattsDev">@jarrodwattsdev</a></p>
]]></content:encoded></item><item><title><![CDATA[Understanding the Commit Reveal Scheme (with Solidity examples)]]></title><description><![CDATA[Ever wanted to store a piece of information on-chain but keep it a secret until later? In this quick post, we'll explore the commit-reveal scheme and provide an example of how you can implement it within a smart contract using Solidity.
What is the C...]]></description><link>https://blog.jarrodwatts.com/understanding-the-commit-reveal-scheme-with-solidity-examples</link><guid isPermaLink="true">https://blog.jarrodwatts.com/understanding-the-commit-reveal-scheme-with-solidity-examples</guid><category><![CDATA[Solidity]]></category><category><![CDATA[Ethereum]]></category><category><![CDATA[Cryptography]]></category><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Sun, 30 Jun 2024 11:02:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1719745284817/6675f99e-eaec-44ad-977f-a20bc7347fbd.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Ever wanted to store a piece of information on-chain but keep it a secret until later? In this quick post, we'll explore the <strong>commit-reveal scheme</strong> and provide an example of how you can implement it within a smart contract using Solidity.</p>
<h2 id="heading-what-is-the-commit-reveal-scheme">What is the Commit Reveal Scheme?</h2>
<p>The commit-reveal scheme is a type of <a target="_blank" href="https://en.wikipedia.org/wiki/Commitment_scheme">commitment scheme</a> that can be used to store values in a smart contract and keep them secret until you choose to reveal them later.</p>
<p>One common example of this is <a target="_blank" href="https://portal.thirdweb.com/glossary/delayed-reveal">Delayed reveal NFT collections</a>; where users mint NFTs, but the underlying data (such as the image, name, traits, etc.) of those NFTs are not revealed until later.</p>
<p>In this post, we'll use the popular <a target="_blank" href="https://en.wikipedia.org/wiki/Rock_paper_scissors">rock paper scissors game</a> as an example of how and why you might want to implement this paradigm into your smart contracts.</p>
<h2 id="heading-how-does-the-commit-reveal-scheme-work">How Does the Commit Reveal Scheme Work?</h2>
<p>As the name suggests, the commit reveal scheme uses a two-step process:</p>
<ol>
<li><p><strong>Commit</strong>: write the data to the smart contract, but keep it <em>hidden</em>; by hashing the data itself along combined with a secret phrase, i.e. <code>hash(data, secret)</code>.</p>
</li>
<li><p><strong>Reveal</strong>: later, reveal the data by providing the same <code>data</code> and <code>secret</code> values. If the hash of the newly provided <code>data</code> and <code>secret</code> value is equal to the hash of the original <code>data</code> and <code>secret</code> value, then the data is revealed.</p>
</li>
</ol>
<p>For example, in a game of rock paper scissors, we want to submit our move inside a transaction without the other player knowing what move we made; otherwise, they could easily win every game by inspecting the move from our transaction.</p>
<p>Instead, we create a secret key or password and hash the combination of these two values. Using solidity, we can achieve this by using <code>keccak256</code> and <code>abi.encodePacked</code>:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// Generate a hash of the combination of the data and secret</span>
<span class="hljs-keyword">bytes32</span> hash <span class="hljs-operator">=</span> <span class="hljs-built_in">keccak256</span>(
    <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodePacked</span>(
        <span class="hljs-string">"scissors"</span> <span class="hljs-comment">// Our move</span>
        <span class="hljs-keyword">bytes32</span>(<span class="hljs-string">"player1-secret"</span>) <span class="hljs-comment">// Our secret key or password</span>
    )
);
</code></pre>
<p>Now, we can safely store this information inside of the smart contract. Other people will be able to see the <code>hash</code> value, however, they <em>won't</em> be able to decode it; as they don't know our secret value.</p>
<p>Only users who know both our original move and our secret key will be able to <strong>reveal</strong> our <strong>commitment</strong> at a later time; since the hash output of <code>data</code> and <code>secret</code> will always be the same value.</p>
<p>This also means we cannot change our <code>data</code> later; for example, we can't change our move from scissors to paper, since the output of <code>hash(paper,secret)</code> will be different to <code>hash(scissors,secret)</code>; i.e. we "committed" to our answer.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719735117444/2f16f13d-053a-4fae-9f7a-4132290f8aac.png" alt class="image--center mx-auto" /></p>
<p>Later, for example, when both players have committed their move in rock paper scissors, we can safely reveal our commitment; by providing both the original data and the secret key to produce the same hash, for example:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// Produce a new hash by providing the value and secret we did originally</span>
<span class="hljs-keyword">bytes32</span> newHash <span class="hljs-operator">=</span> <span class="hljs-built_in">keccak256</span>(
  <span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodePacked</span>(newMove, newSecret)
);

<span class="hljs-comment">// If hash(newMove, newSecret) == hash(originalMove, originalSecret), reveal!</span>
<span class="hljs-built_in">require</span>(
  hash <span class="hljs-operator">=</span><span class="hljs-operator">=</span> newHash, <span class="hljs-string">"Wrong move or wrong pasword: Hashes do not match."</span>
);
</code></pre>
<p>At this point, if the two hashes match, the move provided in the reveal phase <em>(</em><code>newMove</code> <em>in the code snippet above)</em> is the "revealed" data; the user has decoded their hash by proving that they know the secret as well as the original move.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719735150343/a04eb6e6-be3b-457c-ba00-70257a6e9da8.png" alt class="image--center mx-auto" /></p>
<p>To summarise, the commit-reveal scheme is a two-step process effective for storing data in a smart contract in a hidden manner that can be revealed later using hashing:</p>
<ol>
<li><p><strong>Commit:</strong> Store a hash of a combination of the data + a secret key</p>
</li>
<li><p><strong>Reveal:</strong> Provide the data and the secret key to recompute a new hash. If the hash is the same as the hash from the commit phase, the data is revealed.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719734599378/672230ae-3f4a-4487-ad73-0ae498d9d3c9.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>That's a quick introduction to the commit-reveal scheme. For a full code example in Solidity, check out the repository 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/jarrodwatts/rock-paper-scissors">https://github.com/jarrodwatts/rock-paper-scissors</a></div>
<p> </p>
<p>For any questions, feel free to reach out to me on Twitter <a target="_blank" href="https://twitter.com/jarrodWattsDev">@jarrodwattsdev</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Get Started with Coinbase Smart Wallet]]></title><description><![CDATA[In this tutorial, I'll walk you through the process of setting up Coinbase Smart Wallet inside a front-end application. By the end of the tutorial, we'll build a simple Next.js application where users can:

Connect to your application via Coinbase Sm...]]></description><link>https://blog.jarrodwatts.com/get-started-with-coinbase-smart-wallet</link><guid isPermaLink="true">https://blog.jarrodwatts.com/get-started-with-coinbase-smart-wallet</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[Web3]]></category><category><![CDATA[account abstraction]]></category><category><![CDATA[NFT]]></category><category><![CDATA[Cryptocurrency]]></category><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Fri, 07 Jun 2024 02:45:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1717727843664/431a5931-a570-4eab-b047-3854d644510c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this tutorial, I'll walk you through the process of setting up <a target="_blank" href="https://www.coinbase.com/en-au/wallet/smart-wallet">Coinbase Smart Wallet</a> inside a front-end application. By the end of the tutorial, we'll build a simple Next.js application where users can:</p>
<ol>
<li><p>Connect to your application via Coinbase Smart Wallet.</p>
</li>
<li><p>Perform transactions from their newly created wallet.</p>
</li>
<li><p>Pay no gas fees! Thanks to the power of paymasters to cover user's gas fees.</p>
</li>
</ol>
<p>Below is a quick demo video of what we'll build:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717642277559/d297f93c-9045-49b8-a85a-301307cea509.gif" alt="Coinbase Smart Wallet demo" class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">🤠</div>
<div data-node-type="callout-text">Try the live demo: <a target="_blank" href="https://polygon-coinbase-smart-wallet.vercel.app/">https://polygon-coinbase-smart-wallet.vercel.app/</a></div>
</div>

<p>If it sounds like you're in the right place, great! Let's get started!</p>
<h2 id="heading-setting-up-the-project">Setting Up the Project</h2>
<p>If you prefer to start from the complete code, the full source code is available on GitHub below, with instructions in the README on how to get started locally.</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/jarrodwatts/polygon-coinbase-smart-wallet">https://github.com/jarrodwatts/polygon-coinbase-smart-wallet</a></div>
<p> </p>
<p>For those starting from scratch, create a simple Next.js app using <code>npx create next-app</code>:</p>
<pre><code class="lang-bash">pnpm create next-app@latest coinbase-smart-wallet-demo --typescript --tailwind --eslint
</code></pre>
<p>Next, install the <a target="_blank" href="https://portal.thirdweb.com/typescript/v5">thirdweb React SDK</a> which includes the <a target="_blank" href="https://portal.thirdweb.com/typescript/v5/react/components/ConnectButton"><code>ConnectButton</code></a> component:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Ensure you run the command from the coinbase-smart-wallet-demo directory</span>
pnpm i thirdweb
</code></pre>
<h3 id="heading-thirdweb-api-key">thirdweb API Key</h3>
<p>To instantiate the thirdweb React SDK, you'll need a <a target="_blank" href="https://portal.thirdweb.com/account/api-keys">thirdweb API key</a> To get one:</p>
<ol>
<li><p>Head to the <strong>Settings</strong> tab on the <a target="_blank" href="https://thirdweb.com/dashboard/settings/api-keys">thirdweb dashboard</a>.</p>
</li>
<li><p>Click <strong>+ Create API Key</strong>.</p>
</li>
<li><p>Give your key a name and set the allowed domains.</p>
</li>
<li><p>Click <strong>Next</strong> and copy your app's <strong>Client ID</strong>.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717634294110/64c7741c-70fa-47ee-8dc2-21521cd4b9cb.png" alt="thirdweb API key setup demo" class="image--center mx-auto" /></p>
<p>To keep things brief for the tutorial, I'll store my thirdweb client ID in plain text, <strong>however, you should keep the values safe, using</strong> <a target="_blank" href="https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables"><strong>environment variables</strong></a><strong>.</strong></p>
<p>Nice! All our setup is done. This gives us everything we need to build our app.</p>
<h2 id="heading-integrating-coinbase-smart-wallet">Integrating Coinbase Smart Wallet</h2>
<p>We'll break down the Coinbase Smart Wallet integration into three steps:</p>
<ol>
<li><p>Wrapping our application in the <code>ThirdwebProvider</code>.</p>
</li>
<li><p>Adding the <code>ConnectButton</code> component.</p>
</li>
<li><p>Showcasing a simple test transaction with a <code>TransactionButton</code> component.</p>
</li>
</ol>
<h3 id="heading-wrapping-the-app-in-the-thirdwebprovider">Wrapping the App in the ThirdwebProvider</h3>
<p>The thirdweb SDK uses a <a target="_blank" href="https://react.dev/reference/react/createContext#provider">provider pattern</a>, meaning we wrap our application with a <code>ThirdwebProvider</code> component to use thirdweb SDK features throughout our code.</p>
<p>First, wrap your application in the <a target="_blank" href="https://portal.thirdweb.com/typescript/v5/react/ThirdwebProvider"><code>ThirdwebProvider</code></a> component like so:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// File: src/app/layout.tsx</span>
<span class="hljs-keyword">import</span> { ThirdwebProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"thirdweb/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">RootLayout</span>(<span class="hljs-params">{ children }</span>) </span>{
  <span class="hljs-keyword">return</span> (
      &lt;ThirdwebProvider&gt;
        &lt;body&gt;{children}&lt;/body&gt;
      &lt;/ThirdwebProvider&gt;
  );
}
</code></pre>
<h3 id="heading-adding-the-connect-wallet-button">Adding the Connect Wallet Button</h3>
<p>The thirdweb SDK includes a <a target="_blank" href="https://portal.thirdweb.com/typescript/v5/react/components/ConnectButton"><code>ConnectButton</code></a> component that opens a modal and allows users to connect their wallets. We'll use it to show the Coinbase Smart Wallet prompt.</p>
<p>Using the code below, we can render a "Connect Wallet" button that prompts the user to connect to our application using Coinbase Smart Wallet, by:</p>
<ol>
<li><p>Importing what chain we want to use from the <code>thirdweb/chains</code> package.</p>
</li>
<li><p>Rendering the <code>ConnectButton</code> from the thirdweb SDK.</p>
<ul>
<li><p>Providing your thirdweb client ID to the <code>createThirdwebClient</code> function.</p>
</li>
<li><p>Calling the <code>createWallet</code> function with <code>com.coinbase.wallet</code> (Coinbase Wallet).</p>
</li>
<li><p>Setting <code>smartWalletOnly</code> to disable the Coinbase Wallet Browser Extension.</p>
</li>
</ul>
</li>
</ol>
<pre><code class="lang-typescript"><span class="hljs-comment">// File: /src/app/page.tsx</span>
<span class="hljs-string">"use client"</span>; <span class="hljs-comment">// thirdweb SDK doesn't support server-side rendering yet.</span>

<span class="hljs-keyword">import</span> { createThirdwebClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"thirdweb"</span>; <span class="hljs-comment">// Create the thirdweb client with your client ID</span>
<span class="hljs-keyword">import</span> { ConnectButton } <span class="hljs-keyword">from</span> <span class="hljs-string">"thirdweb/react"</span>; <span class="hljs-comment">// The component we can prompt the user to connect their wallet with</span>
<span class="hljs-keyword">import</span> { createWallet } <span class="hljs-keyword">from</span> <span class="hljs-string">"thirdweb/wallets"</span>; <span class="hljs-comment">// Function to specify we want to use Coinbase smart wallet</span>
<span class="hljs-keyword">import</span> { polygon } <span class="hljs-keyword">from</span> <span class="hljs-string">"thirdweb/chains"</span>; <span class="hljs-comment">// Import the the blockchain you want to use</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> (
    &lt;&gt;
      &lt;ConnectButton
        client={createThirdwebClient({
          clientId: <span class="hljs-string">"your-thirdweb-client-id-goes-here"</span>,
        })}
        wallets={[
          createWallet(<span class="hljs-string">"com.coinbase.wallet"</span>, {
            walletConfig: {
              <span class="hljs-comment">// Specify we do not want coinbase wallet browser extension support, just smart wallet</span>
              options: <span class="hljs-string">"smartWalletOnly"</span>,
            },
            chains: [polygon],
          }),
        ]}
      /&gt;
    &lt;/&gt;
  );
}
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Ensure you replace the placeholder value with <strong><em>your </em></strong>thirdweb client ID!</div>
</div>

<p>That's all we need for our Coinbase Smart Wallet integration! 🎉 To see it in action, run <code>pnpm run dev</code> and visit <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a> in your browser and try it out:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717642277559/d297f93c-9045-49b8-a85a-301307cea509.gif" alt="Coinbase Smart Wallet demo" class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Depending on what device you are using (Windows, Mac, Android, etc.) the options to save your passkey will be different.</div>
</div>

<h3 id="heading-submitting-transactions-from-coinbase-smart-wallet">Submitting Transactions from Coinbase Smart Wallet</h3>
<p>Next, let's showcase a simple smart contract interaction with this connected wallet.</p>
<p>For this tutorial, I've deployed a simple <a target="_blank" href="https://thirdweb.com/thirdweb.eth/DropERC1155">Edition Drop smart contract</a> using the thirdweb dashboard. This <a target="_blank" href="https://docs.openzeppelin.com/contracts/3.x/erc1155">ERC-1155</a> NFT smart contract (<a target="_blank" href="https://thirdweb.com/polygon/0x04bE3B7a1a034297331A661c5b5E838264Ba0E58">deployed here</a>) allows users to mint NFTs for free; perfect for us to showcase Coinbase Smart Wallet.</p>
<p>If you want to follow the same steps, you can:</p>
<ol>
<li><p>Deploy an <a target="_blank" href="https://thirdweb.com/thirdweb.eth/DropERC1155">Edition Drop smart contract</a>.</p>
</li>
<li><p>Select the <strong>NFTs</strong> tab and <a target="_blank" href="https://portal.thirdweb.com/contracts/explore/pre-built-contracts/edition-drop#lazy-minting-nfts">lazy mint</a> metadata for an NFT.</p>
</li>
<li><p>Set up a free, public <a target="_blank" href="https://portal.thirdweb.com/contracts/explore/pre-built-contracts/edition-drop#setting-claim-phases"><strong>claim phase</strong></a> for your NFT.</p>
</li>
</ol>
<p>Beneath our <code>ConnectButton</code>, let's add a <a target="_blank" href="https://portal.thirdweb.com/references/typescript/v5/TransactionButton"><code>TransactionButton</code></a> so users can submit the transaction of minting an NFT from the drop from their Coinbase Smart Wallet.</p>
<p>First, import some relevant functions and components we'll be using from thirdweb:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { TransactionButton, useActiveAccount } <span class="hljs-keyword">from</span> <span class="hljs-string">"thirdweb/react"</span>;
<span class="hljs-keyword">import</span> { claimTo } <span class="hljs-keyword">from</span> <span class="hljs-string">"thirdweb/extensions/erc1155"</span>;
<span class="hljs-keyword">import</span> { getContract } <span class="hljs-keyword">from</span> <span class="hljs-string">"thirdweb"</span>;
</code></pre>
<p>Let's also abstract out the <strong>chain</strong> and <strong>thirdweb client</strong> into variables:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// You can safely place these *outside* of the component</span>
<span class="hljs-keyword">const</span> thirdwebClient = createThirdwebClient({
  clientId: <span class="hljs-string">"your-thirdweb-client-id-goes-here"</span>,
});

<span class="hljs-keyword">const</span> chainToUse = polygon;
</code></pre>
<p>Get the address of the connected Coinbase Smart Wallet using <code>useActiveAccount</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Place this *within* the component</span>
<span class="hljs-keyword">const</span> account = useActiveAccount();
</code></pre>
<p>Then, render the <code>TransactionButton</code> component <strong>beneath</strong> the existing <code>ConnectButton</code> component. We can use the <code>getContract</code> function to connect to our smart contract, and call the <code>claimTo</code> function to claim/mint an NFT from the drop:</p>
<pre><code class="lang-typescript">&lt;TransactionButton
  transaction={<span class="hljs-function">() =&gt;</span>
    claimTo({
      contract: getContract({
        client: thirdwebClient,
        chain: chainToUse,
        address: <span class="hljs-string">"0x-your-smart-contract-address-goes-here"</span>,
      }),
      quantity: BigInt(<span class="hljs-number">1</span>), <span class="hljs-comment">// Mint 1 NFT</span>
      to: account?.address, <span class="hljs-comment">// To the connected Coinbase Smart Wallet address</span>
      tokenId: BigInt(<span class="hljs-number">0</span>), <span class="hljs-comment">// Of NFT with token ID of 0</span>
    })
  }
  payModal={<span class="hljs-literal">false</span>} <span class="hljs-comment">// Disable the FIAT on-ramp dialogue (optional)</span>
&gt;
  Mint NFT
&lt;/TransactionButton&gt;
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">🤓</div>
<div data-node-type="callout-text">You can get your smart contract address from the thirdweb dashboard. Ensure you replace the placeholder value in the above code snippet.</div>
</div>

<p>Let's test out this transaction button on <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a> now:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717654836272/7ddf3912-dec3-4efd-8346-45aaaced4162.gif" alt="Account abstraction without a paymaster" class="image--center mx-auto" /></p>
<p>😱 Oh no! Our users don't have any funds in their wallets to pay for these gas fees... if only there was a way to cover our user's gas fees somehow! 😉</p>
<h2 id="heading-sponsoring-user-gas-fees-with-a-paymaster">Sponsoring User Gas Fees with a Paymaster</h2>
<p><a target="_blank" href="https://www.erc4337.io/docs/paymasters/introduction">Paymasters</a> are a feature of <a target="_blank" href="https://blog.jarrodwatts.com/what-is-account-abstraction-and-how-does-eip-4337-work"><strong>ERC-4337 account abstraction</strong></a><strong>,</strong> which is how Coinbase Smart Wallet works under the hood <em>(a topic for another blog post).</em></p>
<p>They allow the gas fee of a transaction to be "sponsored" (paid for) by a different wallet than the one submitting the transaction; typically, the developer of the application sponsors the gas fees of user transactions.</p>
<p>The thirdweb SDK provides specific <a target="_blank" href="https://blog.thirdweb.com/changelog/easy-coinbase-smart-wallet-integration-with-eip-5792-hooks/"><strong>EIP-5792</strong> hooks</a> for us to accomplish this sponsorship. Let's first import the one we're going to use, <a target="_blank" href="https://portal.thirdweb.com/references/typescript/v5/eip5792/useSendCalls"><code>useSendCalls</code></a>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useSendCalls } <span class="hljs-keyword">from</span> <span class="hljs-string">"thirdweb/wallets/eip5792"</span>;
</code></pre>
<p>Then, let's <strong>refactor</strong> the claiming code we wrote previously into a new, separate function, so we can include some paymaster logic:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendSponsoredTransaction</span>(<span class="hljs-params"></span>) </span>{

  <span class="hljs-comment">// Our existing claim code placed here in a claimTx variable</span>
  <span class="hljs-keyword">const</span> claimTx = claimTo({
    contract: getContract({
      client: thirdwebClient,
      chain: chainToUse,
      address: <span class="hljs-string">"0x-your-smart-contract-address-goes-here"</span>,
    }),
    quantity: BigInt(<span class="hljs-number">1</span>),
    to: account?.address,
    tokenId: BigInt(<span class="hljs-number">0</span>),
  });
  <span class="hljs-comment">// End existing code</span>

  <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> sendCalls({
    calls: [claimTx], <span class="hljs-comment">// We can even put multiple transactions here</span>
    capabilities: {
      <span class="hljs-comment">// We cover the gas fees of the transaction for the user!</span>
      paymasterService: {
        <span class="hljs-comment">// Docs: https://portal.thirdweb.com/connect/account-abstraction/infrastructure</span>
        url: <span class="hljs-string">`https://<span class="hljs-subst">${chainToUse.id}</span>.bundler.thirdweb.com/<span class="hljs-subst">${thirdwebClient.clientId}</span>`</span>,
      },
    },
  });
}
</code></pre>
<p>Finally, modify the <code>TransactionButton</code> from earlier to call the <code>sendSponderedTransaction</code> function, instead of directly calling the <code>claimTo</code> function, like so:</p>
<pre><code class="lang-typescript">&lt;TransactionButton transaction={<span class="hljs-function">() =&gt;</span> sendSponsoredTransaction()}&gt;
  Mint NFT
&lt;/TransactionButton&gt;
</code></pre>
<h3 id="heading-sponsoring-transactions-on-mainnet">Sponsoring Transactions on Mainnet</h3>
<p>On testnets such as Base Sepolia <em>(</em><code>baseSepolia</code><em>in the thirdweb chains package)</em>, it's free to cover the gas fees of users with the thirdweb SDK.</p>
<p>To sponsor transactions on mainnet environments, however, real funds are being used. Therefore, you need to provide a credit card on the <a target="_blank" href="https://thirdweb.com/dashboard/settings/billing">billing tab</a> of the thirdweb dashboard to pay for these fees. <em>Note</em>: <em>you</em> <strong><em>don't</em></strong> <em>need to upgrade to the growth tier.</em></p>
<p>You can read more details on <a target="_blank" href="https://portal.thirdweb.com/connect/account-abstraction/infrastructure">thirdweb's bundler documentation</a>.</p>
<h3 id="heading-configuring-sponsorship-rules">Configuring Sponsorship Rules</h3>
<p>When dealing with real funds (if you're using mainnet), you want to ensure you are only covering the fees of specific transactions that you want to sponsor, not just any transaction!</p>
<p>Thankfully, thirdweb makes this easy to configure from the dashboard within the <a target="_blank" href="https://thirdweb.com/dashboard/connect/account-abstraction">account abstraction configuration section</a>. This allows you to specify exactly what chains, smart contracts, and wallets you want to cover the gas fees for.</p>
<p>For example, I configured my sponsorship rules to:</p>
<ul>
<li><p>Only sponsor transactions on the Polygon chain.</p>
</li>
<li><p>Only sponsor transactions interacting with my NFT smart contract.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717657167204/1ad2184b-2702-4b7f-a9c9-cf940659059d.png" alt="thirdweb Account abstraction sponsorship rules" class="image--center mx-auto" /></p>
<p>Alright! We're finally done! Let's see the final demo in action:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717659617166/ba75a08e-ff10-407a-8cf0-5e3a8ae74fa4.gif" alt class="image--center mx-auto" /></p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>That's it! We've built a simple application where anybody can mint an NFT for free; without setting up a wallet, writing down seed phrases, or paying any gas fees!</p>
<p>Got questions or feedback? Reach out to me on Twitter <a target="_blank" href="https://x.com/jarrodWattsDev">@jarrodwattsdev</a></p>
]]></content:encoded></item><item><title><![CDATA[The Ultimate Guide to Sequencers in L2 Blockchains]]></title><description><![CDATA[As part of Ethereum's rollup-centric roadmap, rollups are taking away the heavy lifting from Ethereum and scaling its throughput by orders of magnitude, reflected in the $20B+ TVL stored in L2 chains today.

But, with great power, comes great respons...]]></description><link>https://blog.jarrodwatts.com/the-ultimate-guide-to-sequencers-in-l2-blockchains</link><guid isPermaLink="true">https://blog.jarrodwatts.com/the-ultimate-guide-to-sequencers-in-l2-blockchains</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Ethereum]]></category><category><![CDATA[zkevm]]></category><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Fri, 19 Jan 2024 00:36:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1705624450042/b9f7f3a3-cfd2-46d6-9d6c-6da714c11833.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As part of Ethereum's <a target="_blank" href="https://ethereum-magicians.org/t/a-rollup-centric-ethereum-roadmap/4698">rollup-centric roadmap</a>, rollups are taking away the heavy lifting from Ethereum and scaling its throughput by orders of magnitude, reflected in the $20B+ TVL stored in L2 chains today.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705448942535/28eca564-3c9a-45b5-a973-49337865d4b9.png" alt="l2beat L2 TVL over time" class="image--center mx-auto" /></p>
<p>But, with great power, comes great responsibility, and with the <a target="_blank" href="https://ethereum.org/en/roadmap/vision#:~:text=The%20challenge%20of%20decentralized%20scaling">blockchain trilemma</a> in mind, these L2 scalability gains currently come at the cost of weaker decentralization and security, along with added complexity.</p>
<p>In this post, we'll cover a key component of rollups called <strong>sequencers</strong>, how they work, the pros and cons of different kinds of sequencers, and finally explore a relatively new concept called <strong>shared</strong> <strong>sequencers</strong>. Let's dive in.</p>
<h2 id="heading-what-is-a-sequencer">What is a Sequencer?</h2>
<p>If you clicked on this post I'm going to assume you're already familiar with L2s, rollups, sequencers, and all the rest. But just so we're on the same page, let's do a quick definition of what we're talking about here.</p>
<p>If you're interested in a deep dive into a specific L2 and each of its components, check out my previous blog on zkEVMs:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://blog.jarrodwatts.com/how-zk-proofs-and-zkevms-work">https://blog.jarrodwatts.com/how-zk-proofs-and-zkevms-work</a></div>
<p> </p>
<p>Rollups consist of several components. While each of them is slightly different, each of them shares <strong>key</strong> components, such as the:</p>
<ul>
<li><p><strong>Sequencer</strong>: Picks up transactions from the L2 mempool, decides whether to execute or discard them and broadcasts this information to other nodes.</p>
</li>
<li><p><strong>Layer 1 Rollup Contract</strong>: A smart contract living on Ethereum, that receives batches of transaction data that occurred on L2. It also receives proofs (either fault proofs for optimistic rollups, or ZK proofs for ZK rollups) to verify batches.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705450383218/1fb4974a-5abb-4f5b-bf7a-5c97dc5f0f78.png" alt="simplified view of how rollup l2s work" class="image--center mx-auto" /></p>
<p>The above diagram is a simplified version of a rollup's architecture. At a high level, it's how rollups operate; arguably the most important component of the entire system is the <strong>sequencer</strong>, because of its two critical responsibilities:</p>
<ol>
<li><p>Read transactions from the mempool and execute or discard them. Without the sequencer, none of the rollup's transactions would be handled at all.</p>
</li>
<li><p>Batch transactions up together, and ship them to Ethereum. Without the sequencer, there would be no "rolling up"; it is responsible for sending all of the transaction data that occurred on L2 to Ethereum.</p>
</li>
</ol>
<p>Next, let's look closer at how these sequencers work in today's rollup landscape.</p>
<h2 id="heading-different-kinds-of-sequencers">Different Kinds of Sequencers</h2>
<p>Sequencers come in different shapes and sizes. Each rollup (Polygon zkEVM, Linea, Base, Optimism, etc.) utilizes its own unique sequencer. In this section, we're going to explore the different implementations of sequencers that exist today.</p>
<h3 id="heading-centralized-sequencers">Centralized Sequencers</h3>
<p>Centralized sequencers are the most common kind of sequencer that rollups use today. They're used by <a target="_blank" href="https://l2beat.com/scaling/projects/optimism#operator">Optimism</a>, <a target="_blank" href="https://l2beat.com/scaling/projects/arbitrum#operator">Abritrum One</a>, <a target="_blank" href="https://l2beat.com/scaling/projects/base#operator">Base</a>, <a target="_blank" href="https://l2beat.com/scaling/projects/zksync-era#operator">zkSync Era</a>, <a target="_blank" href="https://l2beat.com/scaling/projects/linea#operator">Linea</a>, <a target="_blank" href="https://l2beat.com/scaling/projects/polygonzkevm#operator">Polygon zkEVM</a>, <a target="_blank" href="https://l2beat.com/scaling/projects/scroll#operator">Scroll</a>, and more.</p>
<p>To simplify things, a centralized sequence is software that fetches transactions from the mempool, checks if they're valid, and then puts valid ones into a batch to send to Ethereum. This type of sequencer is labelled "centralized" because it:</p>
<ol>
<li><p>Is usually maintained by the core devs of the rollup team</p>
</li>
<li><p>Likely operates on a centralized server</p>
</li>
<li><p>Uses a single account to post batches to Ethereum</p>
</li>
</ol>
<h4 id="heading-the-benefits-of-centralized-sequencers">The Benefits of Centralized Sequencers</h4>
<p>Unlike blockchains or other decentralized systems, a centralized sequencer's only real concern is the efficiency of its software, and the hardware it's running on; it has no concern for how decentralized it is.</p>
<p>While "centralized" comes with negative connotations, a centralized sequencer provides the highest performance by providing users near-instant finality at the L2 level in a consistent manner and reliably submitting <strong>valid</strong> batches of transactions to Ethereum.</p>
<p>This arguably provides the best experience for users. It provides the fastest way to approve user transactions (which is a high priority for most people) and enables users to withdraw their funds more quickly from L2s in the case of zkEVMs; as the batches submitted by the trusted sequencer are likely going to be valid ones.</p>
<p>While centralized sequencers may provide a great UX, some people believe it undermines the benefits of building decentralized applications. If such an important component is centralized, then why even use a decentralized system in the first place?</p>
<h4 id="heading-the-downsides-to-centralized-sequencers">The Downsides to Centralized Sequencers</h4>
<p>With high scalability, comes the delicate balancing of decentralization and security, <em>or something like that</em>... As you can imagine, maxing out your scalability skill leaves you vulnerable to other downsides.</p>
<p>If a centralized sequencer goes down, the rollup effectively stops doing its job entirely. It stops handling transactions from users on the L2 and also stops sending batch data back to Ethereum.</p>
<p>This isn't a wild "what if" scenario either. This happened recently during the Inscriptions craze on Arbitrum's L2. The sequencer "stalled", and the network suffered <a target="_blank" href="https://cointelegraph.com/news/arbitrum-network-goes-offline-december-15">78 minutes</a> of downtime because of the centralized sequencer setup.</p>
<p>In addition, because the centralized sequencer handles all of a rollup's transactions, it's up to the centralized sequencer to determine what MEV is extracted and in what ways it benefits itself with the information of these incoming transactions (such as frontrunning for example).</p>
<p>With this level of power, you might also wonder what's stopping a sequencer from censoring transactions it doesn't want to go through. Most rollups have a mechanism that allows users to bypass the sequencer and "force" their transaction, however, at this point, these mechanisms are often disabled while the systems mature.</p>
<h3 id="heading-decentralized-sequencers">Decentralized Sequencers</h3>
<p>The distinction between centralized sequencers and decentralized sequencers is comparable to centralized networks and decentralized ones like blockchains <em>(which you've probably heard thousands of times by now).</em></p>
<p>As the name suggests, a decentralized sequencer uses a decentralized network of nodes to perform the responsibilities of the sequencer we discussed in the previous section.</p>
<p>An example of a layer 2 blockchain that implements a decentralized pool of sequencer nodes is <a target="_blank" href="https://docs.metis.io/meta/">Metis</a>. Metis implements this by tapping into its existing decentralized P2P validators and block producer network and <a target="_blank" href="https://docs.metis.io/dev/decentralized-sequencer/overview/selection-and-rotation">randomly selecting and rotating</a> what sequencer node performs these responsibilities.</p>
<p>Without being too verbose, this essentially has the reverse effects of centralized sequencers. Where centralized sequencers shine is where decentralized sequencers lack, and vice versa.</p>
<p>It is more time-consuming, less consistent, and likely more expensive to call upon a decentralized network of nodes to act as a sequencer, but does not have the single point of failure that centralized sequencers do.</p>
<h3 id="heading-shared-sequencers">Shared Sequencers</h3>
<p>Shared sequencers such as <a target="_blank" href="https://www.espressosys.com/">Espresso</a> and <a target="_blank" href="https://www.astria.org/">Astria</a> allow multiple rollups to share a single decentralized network of sequencers.</p>
<p>Shared sequencers are a network that sits in the middle between L2 and Ethereum L1 that anyone can permissionlessly utilize as a decentralized sequencer for their rollup. They're almost like a decentralized sequencer as a service.</p>
<p>A key differentiator here between decentralized sequencers and shared sequencers is that shared sequencers serve multiple blockchains rather than just one and shared sequencers are actually blockchain networks themselves.</p>
<p>For example, the Astria Shared Sequencer describes itself as <em>"a decentralized network of nodes utilizing CometBFT that come to a consensus on an ordered set of transactions (ie. it is a blockchain)".</em> <a target="_blank" href="https://docs.astria.org/docs/overview/architecture/the-astria-sequencer/">Source ↗</a></p>
<p>A key selling point for shared sequencers is that they introduce interoperability advantages between rollups, providing additional value to users using rollups that opt-in to a decentralized shared sequencing layer.</p>
<p>For example, <a target="_blank" href="https://hackmd.io/@EspressoSystems/EspressoSequencer#D-Decentralization-without-Fragmentation">Espresso</a> describes how users can express atomic dependencies between transactions across different rollups, enabling many new use cases such as cross-rollup DEX arbitrage.</p>
<h3 id="heading-based-rollups">Based Rollups</h3>
<p>Rollups such as <a target="_blank" href="https://taiko.xyz/">Taiko</a> are implementing an alternative strategy for decentralized sequencing which <a target="_blank" href="https://twitter.com/drakefjustin?lang=en">Justin Drake</a> coined "based" <em>(not to be confused with the Base rollup)</em> in <a target="_blank" href="https://ethresear.ch/t/based-rollups-superpowers-from-l1-sequencing/15016">this post</a>.</p>
<p>Based rollups or L1-sequenced rollups utilize Ethereum's decentralization by rolling up multiple transactions off-chain (as any L2 does) and sending them as a single transaction to Ethereum.</p>
<p>Imagine decentralized sequencing, but instead of a separate blockchain, it relies just uses Ethereum to handle both the secure recording of transaction data and the enforcement of consensus rules.</p>
<p>The downside to this approach is that most of the limitations that the L1 has, such as transaction confirmation delays (with <a target="_blank" href="https://taiko.mirror.xyz/7dfMydX1FqEx9_sOvhRt3V8hJksKSIWjzhCVu7FyMZU#:~:text=L1%20native%20token.-,Are%20based%20rollups%20limited%20to%20the%20L1%20block%20times%3F,-By%20default%2C%20yes">caveats</a> via restaking), block times, transaction ordering, and data availability throughput are all inherited as limitations in the based rollup.</p>
<h2 id="heading-so-whats-the-best">So, What's The Best...?</h2>
<p>TLDR: It's up to you. As either a user or developer (or both), you're going to have different preferences from others.</p>
<p>Some developers want their users to have the fast experiences that rollups like Base or Polygon zkEVM currently offer by utilizing centralized sequencers, whereas others may prefer to have stronger decentralization at the cost of speed.</p>
<p>In general, my opinion is that we're always going to see a trend where these solutions start by sacrificing decentralization for performance, and then over time become more decentralized while maintaining that level of performance. This is true more broadly in web3 than for just sequencers too.</p>
<p>It's valuable to know the tradeoffs that are being made to power your experience in the L2 world and make your own decisions based on your preferences.</p>
<h4 id="heading-want-more-content-like-this">Want more content like this?</h4>
<p>I usually post stuff like this on my Twitter first. If you enjoyed this content check out my Twitter <a target="_blank" href="https://twitter.com/jarrodWattsDev">@jarrodwattsdev</a> for more educational web3 content.</p>
]]></content:encoded></item><item><title><![CDATA[Create A Blockchain Indexer with Chain Indexer Framework]]></title><description><![CDATA[This guide will show you how to build your own indexer for an EVM-compatible blockchain such as Ethereum, Polygon Proof of Stake, and more!
By the end, you'll have a Docker container running Kafka that captures all blockchain events that you specify,...]]></description><link>https://blog.jarrodwatts.com/create-a-blockchain-indexer-with-chain-indexer-framework</link><guid isPermaLink="true">https://blog.jarrodwatts.com/create-a-blockchain-indexer-with-chain-indexer-framework</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[Web3]]></category><category><![CDATA[kafka]]></category><category><![CDATA[Docker]]></category><category><![CDATA[indexing]]></category><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Tue, 05 Dec 2023 12:55:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1701780908555/822882ee-7a7c-40d4-8f31-105c7c292e3d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This guide will show you how to build your own indexer for an EVM-compatible blockchain such as Ethereum, Polygon Proof of Stake, and more!</p>
<p>By the end, you'll have a <a target="_blank" href="https://www.docker.com/">Docker</a> container running <a target="_blank" href="https://kafka.apache.org/">Kafka</a> that captures all blockchain events that you specify, along with references for how to transform and consume this data inside applications!</p>
<p>Let's do this!</p>
<h2 id="heading-how-it-works">How It Works</h2>
<p>The architecture of the Chain Indexer Framework can be broken up into three parts:</p>
<ol>
<li><p><strong>Block Producers</strong>: Scan the blockchain and publish raw block data into Kafka.</p>
</li>
<li><p><strong>Transformers</strong>: Shape the raw data from Kafka into meaningful events.</p>
</li>
<li><p><strong>Consumers</strong>: Read the transformed data for various use cases such as from a frontend application or an API endpoint.</p>
</li>
</ol>
<p>We're going to first set up our Kafka instance inside a Docker container, then run one script written in TypeScript for each of the three components.</p>
<h3 id="heading-architecture-diagram">Architecture Diagram</h3>
<p>The producer reads data from the specified blockchain and publishes it into our Kafka instance running in a Docker container. At the same time, it also keeps the most recent blocks inside Mongo DB in case of <a target="_blank" href="https://www.alchemy.com/overviews/what-is-a-reorg">reorgs</a>.</p>
<p>Once it's stored in Kafka, we're able to transform it into more meaningful data, and also make it available for any consumer(s) to read; such as applications.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1701780140067/92ebbb2f-f336-4363-aece-24de1e8fbc28.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-setting-up-the-backend-infrastructure">Setting Up the Backend Infrastructure</h2>
<p>Before we create each of the three services (producer, transformer, consumer), we need to set up the infrastructure required to connect to the blockchain and store data. In this section, we'll set up the following services:</p>
<ol>
<li><p>An RPC to connect to the blockchain</p>
</li>
<li><p>A Docker container running Kafka to store raw data</p>
</li>
<li><p>A Mongo database for storing the most recent blocks.</p>
</li>
</ol>
<p>Let's first create a new directory to contain all of the work we're about to do:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Create our base directory</span>
mkdir chain-indexer-framework-guide

<span class="hljs-comment"># Change into this new directory</span>
<span class="hljs-built_in">cd</span> chain-indexer-framework-guide

<span class="hljs-comment"># Open in VS Code</span>
code .
</code></pre>
<h3 id="heading-creating-the-docker-compose-file">Creating the Docker Compose File</h3>
<p>Now we're here, let's set up our Docker container by creating a <a target="_blank" href="https://docs.docker.com/compose/compose-file/03-compose-file/">Docker Compose file</a>.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">You will need <a target="_blank" href="https://docs.docker.com/get-docker/">Docker</a> installed for this part of the guide. Follow the instructions on the <a target="_blank" href="https://docs.docker.com/get-docker/">Get Docker</a> page and verify your installation by running "docker --version" in the terminal.</div>
</div>

<p>The Docker Compose file allows us to define our app's environment. To create one, let's create a <code>docker-compose.yml</code> file within this current directory.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">If you're using <a target="_blank" href="https://code.visualstudio.com/">VS Code</a>, it's recommended to install the <a target="_blank" href="https://code.visualstudio.com/docs/containers/overview">Docker Extension</a>.</div>
</div>

<p>Within <code>docker-compose.yml</code>, set up the following compose file:</p>
<pre><code class="lang-yaml"><span class="hljs-meta">---</span>
<span class="hljs-attr">version:</span> <span class="hljs-string">"3"</span>
<span class="hljs-attr">services:</span>
  <span class="hljs-attr">zookeeper:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">confluentinc/cp-zookeeper:7.0.0</span>
    <span class="hljs-attr">hostname:</span> <span class="hljs-string">zookeeper</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">zookeeper</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-attr">ZOOKEEPER_CLIENT_PORT:</span> <span class="hljs-number">2181</span>
      <span class="hljs-attr">ZOOKEEPER_TICK_TIME:</span> <span class="hljs-number">2000</span>

  <span class="hljs-attr">broker:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">confluentinc/cp-kafka:7.0.0</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">broker</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"9092:9092"</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">zookeeper</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-attr">KAFKA_BROKER_ID:</span> <span class="hljs-number">1</span>
      <span class="hljs-attr">KAFKA_ZOOKEEPER_CONNECT:</span> <span class="hljs-string">"zookeeper:2181"</span>
      <span class="hljs-attr">KAFKA_LISTENER_SECURITY_PROTOCOL_MAP:</span> <span class="hljs-string">PLAINTEXT:PLAINTEXT,PLAINTEXT_INTERNAL:PLAINTEXT</span>
      <span class="hljs-attr">KAFKA_ADVERTISED_LISTENERS:</span> <span class="hljs-string">PLAINTEXT://localhost:9092,PLAINTEXT_INTERNAL://broker:29092</span>
      <span class="hljs-attr">KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR:</span> <span class="hljs-number">1</span>
      <span class="hljs-attr">KAFKA_TRANSACTION_STATE_LOG_MIN_ISR:</span> <span class="hljs-number">1</span>
      <span class="hljs-attr">KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR:</span> <span class="hljs-number">1</span>
</code></pre>
<p>We won't cover all of the fields in this guide (<a target="_blank" href="https://docs.docker.com/compose/compose-file/">learn more about compose files</a>), but this file will allow us to run a <a target="_blank" href="https://www.docker.com/resources/what-container/">Docker container</a> with <a target="_blank" href="https://zookeeper.apache.org/">Apache ZooKeeper</a> for maintaining configuration information and <a target="_blank" href="https://kafka.apache.org/">Apache Kafka</a> to store our raw data.</p>
<h3 id="heading-running-the-docker-container">Running the Docker Container</h3>
<p>Now we've defined our compose file, let's run the Docker container.</p>
<p>Use <a target="_blank" href="https://docs.docker.com/compose/">Docker Compose</a>'s "<a target="_blank" href="https://docs.docker.com/engine/reference/commandline/compose_up/">up</a>" command with the <code>-d</code> flag to run the container in detached mode.</p>
<pre><code class="lang-bash">docker-compose up -d
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>First time using Docker</strong>? Ensure you've <a target="_blank" href="https://stackoverflow.com/questions/40459280/docker-cannot-start-on-windows#:~:text=First%2C%20verify%20that%20Docker%20Desktop%20application%20is%20running.%20If%20not%2C%20launch%20it%3A%20that%20will%20run%20the%20docker%20daemon%20(just%20wait%20few%20minutes).">finalized the Docker installation</a>.</div>
</div>

<p>Run the <code>docker ps</code> command to view the status of all containers:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1701650719097/dd118c51-ce83-4fff-a01e-90b1ceedd16c.png" alt class="image--center mx-auto" /></p>
<p>You can also run <a target="_blank" href="https://www.docker.com/products/docker-desktop/">Docker Desktop</a> to see the container running:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1701650301712/832c41bf-9ecc-4a2a-b8d4-aee64313e84b.png" alt class="image--center mx-auto" /></p>
<p>Now our Kafka instance is up and running, we're ready to store raw data from the blockchain. However, to read blockchain data, we'll need a way of connecting to the chain itself; so let's create a new RPC node next.</p>
<h3 id="heading-creating-the-rpc-node">Creating the RPC Node</h3>
<p>There are <a target="_blank" href="https://ecosystem.polygon.technology/spn/explore/?search=&amp;competency=RPC+Provider&amp;chain=">many solution providers that provide RPC connections</a> to blockchains. In this guide, we'll use a popular RPC provider, <a target="_blank" href="https://docs.alchemy.com/">Alchemy</a> as our RPC provider as they provide a generous free tier.</p>
<p>To get started, head to the <a target="_blank" href="https://dashboard.alchemy.com/apps">Apps</a> page of your Alchemy Dashboard and click <strong>Create New App</strong>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1701651722493/297a1525-d9ff-4bd9-bcd0-f0bb8407465b.png" alt class="image--center mx-auto" /></p>
<p>Select the chain and network you want to read data from and click <strong>Create app</strong>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1701651818263/c2f79b52-bfc8-4d62-a5b9-3bfd8ca59b31.png" alt class="image--center mx-auto" /></p>
<p>We'll come back to this later to grab our RPC URL when we write the producer.</p>
<h3 id="heading-creating-a-mongo-db">Creating A Mongo DB</h3>
<p>Next, let's set up a database to do TODO.</p>
<p>In this guide, we'll use <a target="_blank" href="https://www.mongodb.com/">Mongo DB</a>, as the Chain Indexer Framework's <strong>Producer</strong> has a <code>mongoUrl</code> property we can easily plug this database into.</p>
<p><a target="_blank" href="https://www.mongodb.com/"><strong>Sign up to Mongo DB</strong></a> if you haven't already, and deploy a new database.</p>
<p>Below are the options that I chose; but you can customize this to your preferences:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1701653490008/57dbbf12-141f-4f03-a0c8-d929dfa4e180.png" alt class="image--center mx-auto" /></p>
<p>Once your database is provisioned, complete the setup process.</p>
<p>First, add an authentication method; in this guide, we're using a simple username and password that is auto-generated for us.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1701654085663/f5a76fd8-a1e2-45e9-9f9d-ac1503901a59.png" alt class="image--center mx-auto" /></p>
<p>Second, configure who can access your database. In this guide, we're simply adding our current machine's IP address. Finally, click <strong>Finish and Close</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1701654356586/bb65e7f8-8a6c-4d77-af07-880b975d2b38.png" alt class="image--center mx-auto" /></p>
<p>Finally, the infrastructure setup is complete! 🎉</p>
<h2 id="heading-setting-up-nodejs-typescript">Setting up Node.js + TypeScript</h2>
<p>Now we're ready to set up the three components of the Chain Indexer Framework.</p>
<p>Set up a simple TypeScript + Node.js project by running the following command:</p>
<pre><code class="lang-bash">npm init -y
</code></pre>
<p>To add TypeScript, create a <code>tsconfig.json</code> file with the following contents:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"compilerOptions"</span>: {
    <span class="hljs-attr">"module"</span>: <span class="hljs-string">"NodeNext"</span>,
    <span class="hljs-attr">"moduleResolution"</span>: <span class="hljs-string">"NodeNext"</span>,
    <span class="hljs-attr">"esModuleInterop"</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">"target"</span>: <span class="hljs-string">"ES2020"</span>,
    <span class="hljs-attr">"sourceMap"</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">"strict"</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">"include"</span>: [<span class="hljs-string">"src/**/*"</span>]
}
</code></pre>
<p>Set the <code>package.json</code> file to the following:</p>
<pre><code class="lang-bash">{
  <span class="hljs-string">"name"</span>: <span class="hljs-string">"producer"</span>,
  <span class="hljs-string">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
  <span class="hljs-string">"type"</span>: <span class="hljs-string">"module"</span>,
  <span class="hljs-string">"main"</span>: <span class="hljs-string">"index.js"</span>,
  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"build"</span>: <span class="hljs-string">"tsc"</span>,
    <span class="hljs-string">"start-producer"</span>: <span class="hljs-string">"npm run build &amp;&amp; node --experimental-import-meta-resolve --trace-warnings dist/producer.js"</span>,
    <span class="hljs-string">"start-transformer"</span>: <span class="hljs-string">"npm run build &amp;&amp; node --experimental-import-meta-resolve --trace-warnings dist/transformer.js"</span>,
    <span class="hljs-string">"start-consumer"</span>: <span class="hljs-string">"npm run build &amp;&amp; node --experimental-import-meta-resolve --trace-warnings dist/consumer.js"</span>
  },
}
</code></pre>
<p>Install the required TypeScript dependencies:</p>
<pre><code class="lang-bash">npm install -D typescript @types/node
</code></pre>
<p>Before installing further dependencies, you'll need to follow the installation instructions of <a target="_blank" href="https://github.com/nodejs/node-gyp"><code>node-gyp</code></a> as a pre-requisite to installing the <a target="_blank" href="https://github.com/0xPolygon/chain-indexer-framework"><code>@maticnetwork/chain-indexer-framework</code></a> package. If you're on Windows, this includes installing a current version of Python and the Visual C++ Build Environment in Visual Studio.</p>
<p>Next, install the <a target="_blank" href="https://github.com/0xPolygon/chain-indexer-framework"><code>@maticnetwork/chain-indexer-framework</code></a> package by running the following:</p>
<pre><code class="lang-bash">npm install @maticnetwork/chain-indexer-framework
</code></pre>
<p>Finally, create a <code>src</code> folder, containing three files:</p>
<ul>
<li><p><code>producer.ts</code></p>
</li>
<li><p><code>transformer.ts</code></p>
</li>
<li><p><code>consumer.ts</code></p>
</li>
</ul>
<p>Now we're ready to go. Let's start with the producer.</p>
<h2 id="heading-creating-the-producer">Creating the Producer</h2>
<p>Inside the <code>producer.ts</code> file, we're going to connect to the blockchain you selected in the RPC step and write raw data to Kafka.</p>
<p>Below is the barebones code to start storing raw data in Kafka. Mongo DB is used to store the most recent number of blocks (specified in the <code>maxReOrgDepth</code> field) before they become permanent inside Kafka.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { BlockPollerProducer } <span class="hljs-keyword">from</span> <span class="hljs-string">"@maticnetwork/chain-indexer-framework/block_producers/block_polling_producer"</span>;
<span class="hljs-keyword">import</span> { produce } <span class="hljs-keyword">from</span> <span class="hljs-string">"@maticnetwork/chain-indexer-framework/kafka/producer/produce"</span>;

<span class="hljs-keyword">const</span> producer = produce&lt;BlockPollerProducer&gt;({
  startBlock: <span class="hljs-number">50689834</span>, <span class="hljs-comment">// Pick any start block you want</span>
  rpcWsEndpoints: [<span class="hljs-string">"&lt;your-alchemy-rpc-url-here&gt;"</span>,],
  blockPollingTimeout: <span class="hljs-number">20000</span>,
  topic: <span class="hljs-string">"polygon.1442.blocks"</span>,
  maxReOrgDepth: <span class="hljs-number">256</span>, <span class="hljs-comment">// Maximum reorg depth on Polygon is 256</span>
  maxRetries: <span class="hljs-number">5</span>,
  mongoUrl: <span class="hljs-string">"mongodb+srv://&lt;your-mongo-username&gt;:&lt;your-mongo-password&gt;@chain-indexer.0ymaemb.mongodb.net/"</span>,
  <span class="hljs-string">"bootstrap.servers"</span>: <span class="hljs-string">"localhost:9092"</span>,
  <span class="hljs-string">"security.protocol"</span>: <span class="hljs-string">"plaintext"</span>,
  <span class="hljs-keyword">type</span>: <span class="hljs-string">"blocks:polling"</span>,
});

producer.on(<span class="hljs-string">"blockProducer.fatalError"</span>, <span class="hljs-function">(<span class="hljs-params">error: <span class="hljs-built_in">any</span></span>) =&gt;</span> {
  process.exit(<span class="hljs-number">1</span>); <span class="hljs-comment">//Exiting process on fatal error. Process manager needs to restart the process.</span>
});
</code></pre>
<p>Importantly, you need to:</p>
<ul>
<li><p>Add your HTTPS Alchemy RPC URL in the <code>rpcsWsEndpoints</code> field.</p>
</li>
<li><p>Add your Mongo URL connection string as the <code>mongoUrl</code>.</p>
</li>
<li><p>Optionally, configure the other properties to your preferences.</p>
</li>
</ul>
<p>When you're ready, you can run the following command to start the producer:</p>
<pre><code class="lang-typescript">npm run start-producer
</code></pre>
<p>If everything's working as expected, you should begin to see some data appear in Mongo DB, which you can find in the <strong>Database &gt; Collections</strong> section:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1701767515062/410a1c1b-7f53-469f-a569-6db0b7f40bd6.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-adding-logging">Adding Logging</h3>
<p>The Chain Indexer Framework also comes with logging capabilities to see what's happening behind the scenes. To add it to your producer, first import the Logger:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Logger } <span class="hljs-keyword">from</span> <span class="hljs-string">"@maticnetwork/chain-indexer-framework/logger"</span>;
</code></pre>
<p>And optionally add logs to any events emitted by the producer, for example:</p>
<pre><code class="lang-typescript">producer.on(<span class="hljs-string">"blockProducer.fatalError"</span>, <span class="hljs-function">(<span class="hljs-params">error: <span class="hljs-built_in">any</span></span>) =&gt;</span> {
  Logger.error(<span class="hljs-string">`Block producer exited. <span class="hljs-subst">${error.message}</span>`</span>);
  process.exit(<span class="hljs-number">1</span>); <span class="hljs-comment">//Exiting process on fatal error. Process manager needs to restart the process.</span>
});
</code></pre>
<h2 id="heading-transforming-amp-consuming-data">Transforming &amp; Consuming Data</h2>
<p>Now we have raw data available inside our Kafka instance! You're ready to begin transforming and consuming data in your applications.</p>
<p>Although there's a decent chunk of code to get started with these steps, we've already layed the foundation for everything, so it should be relatively simple!</p>
<p>Rather than dumping all the code for you to copy &amp; paste, we've made a few open-source <a target="_blank" href="https://github.com/0xPolygon/chain-indexer-framework/tree/main/examples">examples</a> of how to setup different kinds of transformers and producers on GitHub linked below.</p>
<ul>
<li><p><a target="_blank" href="https://github.com/0xPolygon/chain-indexer-framework/tree/main/examples/matic_transfer">MATIC Transfer Example</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/0xPolygon/chain-indexer-framework/tree/main/examples/nft_balancer">NFT Balance Example</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Build Your Own Layer 2 Blockchain (using Polygon CDK)]]></title><description><![CDATA[In this guide, I'll show you how you can create and operate your very own blockchain. More specifically, we'll walk through the process of creating a "ZK Validium". A layer 2 chain that utilizes zero-knowledge proofs to guarantee and verify the valid...]]></description><link>https://blog.jarrodwatts.com/build-your-own-layer-2-blockchain-using-polygon-cdk</link><guid isPermaLink="true">https://blog.jarrodwatts.com/build-your-own-layer-2-blockchain-using-polygon-cdk</guid><category><![CDATA[zkevm]]></category><category><![CDATA[zero-knowledge-proofs]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Polygon]]></category><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Tue, 03 Oct 2023 05:30:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1696308863457/1f67ab07-681e-475c-a5bf-f1cb8f4bb08e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this guide, I'll show you how you can create and operate your very own blockchain. More specifically, we'll walk through the process of creating a "ZK <a target="_blank" href="https://ethereum.org/en/developers/docs/scaling/validium/">Validium</a>". A layer 2 chain that utilizes zero-knowledge proofs to guarantee and verify the validity of batches of transactions.</p>
<p>If you're unfamiliar with ZK proofs or Validiums, I have also written blogs previously that will help you understand these topics in more depth, linked below:</p>
<ul>
<li><p><a target="_blank" href="https://blog.jarrodwatts.com/how-zk-proofs-and-zkevms-work">How do ZK Proofs and ZK-EVMs work</a>?</p>
</li>
<li><p><a target="_blank" href="https://blog.jarrodwatts.com/polygon-pos-is-becoming-a-zkevm-validium-explained#heading-what-are-validiums">What are Validiums</a>?</p>
</li>
</ul>
<p>By the end of this guide, you'll be operating your very own chain, including a faucet, block explorer, RPC, bridge, and more; powered by <a target="_blank" href="https://polygon.technology/polygon-cdk">Polygon CDK</a>.</p>
<p>As a bonus, I'll also showcase the process of deploying a smart contract to the chain, and finally, creating an application to interact with your smart contracts.</p>
<p>Let's do this!</p>
<h2 id="heading-what-is-polygon-cdk">What is Polygon CDK?</h2>
<p>Polygon Chain Development Kit (CDK) enables you to build your own ZK-powered Layer 2 blockchain that is custom-fitted to your needs. It provides a way for you to easily create and operate your own "app chain" <em>(application-specific chain)</em>.</p>
<p>The fastest way to do this is by using an <a target="_blank" href="https://polygon.technology/cdk/implementation-providers">implementation provider</a>; a platform that provides interfaces built on top of the CDK to help you configure and deploy a chain. In this guide, we'll use an IP called <a target="_blank" href="https://presto.gateway.fm">Presto</a> to easily ship our own chain.</p>
<p>Polygon CDK is already powering a number of companies by providing the infrastructure to launch ZK-powered L2s; including <a target="_blank" href="https://polygon.technology/blog/canto-to-migrate-to-a-zk-l2-powered-by-polygon-chain-development-kit">Canto</a>, <a target="_blank" href="https://polygon.technology/blog/immutable-zkevm-testnet-is-live-on-polygon">Immutable</a>, <a target="_blank" href="https://medium.com/@palmfdn/palm-foundation-chooses-polygon-technology-for-zkl2-upgrade-empowering-creators-sports-640a1bbd3e1f">Palm</a>, <a target="_blank" href="https://www.theblock.co/post/250505/astar-network-zkevm-ethereum-layer-2-polygon">Astar</a>, and <a target="_blank" href="https://twitter.com/0xMarcB/status/1707849304658899415">more</a>.</p>
<p>As part of the <a target="_blank" href="https://polygon.technology/blog/polygon-2-0-protocol-vision-and-architecture">Polygon 2.0</a> vision, the chains launched via the CDK will be connected via the interop layer, tapping into the existing ecosystems and liquidity available of all the other CDK-powered chains, including Polygon PoS and Polygon zkEVM.</p>
<p><img src="https://assets-global.website-files.com/637e2b6d602973ea0941d482/64ed4d6458993a014207eef2_image3.png" alt="Polygon CDK architecture" /></p>
<p><a target="_blank" href="https://polygon.technology/blog/introducing-polygon-chain-development-kit-launch-zk-l2s-on-demand-to-unlock-unified-liquidity">Learn More ↗</a></p>
<h2 id="heading-deploying-the-rollup">Deploying The Rollup</h2>
<p>In this guide, we'll use <a target="_blank" href="https://presto.gateway.fm/">Presto</a>, a <a target="_blank" href="https://www.alchemy.com/overviews/rollups-as-a-service-raas">RaaS</a> <em>(rollup-as-a-service)</em> platform utilizing Polygon CDK under the hood to deploy our chain with infrastructure deployed to AWS.</p>
<p>To get started, head to <a target="_blank" href="https://presto.gateway.fm/login">Presto</a> and sign up.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695907802643/b6504f13-8fd2-424f-a9b4-8acccca37092.png" alt="Presto Sign up page" class="image--center mx-auto" /></p>
<p>Once onboarded, Presto will take you to the dashboard page, where you can click "<strong>Add new"</strong> to kickstart the process of configuring and deploying your chain.</p>
<p>At the time of writing, the only available option is to deploy the ZK-Validium. However, CDK will soon support zkEVM rollups too! For now, let's select <strong>"Private zk-Validium"</strong>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695907721999/ff2ba592-70e5-494f-b3ce-2c6111a2f79e.png" alt="Presto plan select page" class="image--center mx-auto" /></p>
<p>Next, we need to decide how/where we want to deploy the infrastructure (such as the nodes, prover, aggregator, sequencer, etc.).</p>
<p>In this guide, we'll use the pre-configured option, "Stockholm", which handles all of the deployment steps for us and runs on AWS.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695907743305/f951d7a8-20de-4345-b7fb-1ee309a6a662.png" alt="Presto location select page" class="image--center mx-auto" /></p>
<p>The deployment process can take up to <em>a few hours</em> to fully complete; in the background, all of the infrastructure and compute resources are being deployed to AWS.</p>
<h3 id="heading-rpc-bridge-block-explorer-faucet-and-more">RPC, Bridge, Block Explorer, Faucet, and More</h3>
<p>All of the developer tooling required to utilize your rollup is also deployed for you! The RPC, chain ID, bridge, block explorer, and even a faucet are all deployed for you out of the box; making it super simple to get started developing on it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696286939433/589e7657-5cae-4efc-aff3-c3eaca6fcd99.png" alt="Presto RPC section" class="image--center mx-auto" /></p>
<p>You can also view the smart contracts that get deployed for data availability (DA), and the rollup smart contract where batches of transactions are sequenced and verified on Ethereum (layer 1).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696286927247/9aa456d7-55dd-49a1-a791-37c7fe3c49d5.png" alt="Presto diagnostics (smart contracts) section" class="image--center mx-auto" /></p>
<p>That's it for the deployment step!</p>
<p>Now, let's deploy our first smart contract to our newly created validium.</p>
<h3 id="heading-deploy-a-smart-contract-to-your-custom-chain">Deploy a Smart Contract to Your Custom Chain</h3>
<p>A big benefit of the CDK is that it allows you to create chains that are <a target="_blank" href="https://ethereum.org/en/developers/docs/evm/">EVM</a>-compatible; meaning you can use all of the methods you're already familiar with to develop your smart contracts, such as Hardhat, Solidity, MetaMask, etc.</p>
<p>The Presto dashboard provides you with the chain ID and RPC URL that you can connect your wallet with and deploy smart contracts to. If you've ever deployed to Polygon before, you're likely already equipped with the skills to deploy to your rollup.</p>
<p>In this guide, I'll show you my favourite way to deploy Solidity smart contracts, using <a target="_blank" href="https://thirdweb.com/">thirdweb</a> from a <a target="_blank" href="https://hardhat.org/">Hardhat</a> project.</p>
<h3 id="heading-create-a-new-solidity-project">Create a New Solidity Project</h3>
<p>First, let's create a new Solidity project by running the following command from the terminal:</p>
<pre><code class="lang-bash">npx thirdweb@latest create contract
</code></pre>
<p>This command allows you to configure and instantiate a new project with your preferences of tooling, such as Forge or Hardhat and sets us up with a simple smart contract to deploy. Below are the options I selected for the project:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696288627243/c99f7ece-444a-452b-9bb0-a71de03d4927.png" alt="npx thirdweb create contract" class="image--center mx-auto" /></p>
<p>Inside the project, you'll find a <code>Contract.sol</code> file that you can modify. For this guide, I've written a simple <code>Greeter</code> smart contract with the following contents:</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.11;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Greeter</span> </span>{
    <span class="hljs-keyword">string</span> <span class="hljs-keyword">private</span> greeting;

    <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> _greeting</span>) </span>{
        greeting <span class="hljs-operator">=</span> _greeting;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">greet</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">string</span> <span class="hljs-keyword">memory</span></span>) </span>{
        <span class="hljs-keyword">return</span> greeting;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setGreeting</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> _greeting</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        greeting <span class="hljs-operator">=</span> _greeting;
    }
}
</code></pre>
<h3 id="heading-deploy-the-smart-contract">Deploy the Smart Contract</h3>
<p>Let's go ahead and deploy this smart contract to the validium we just created. To do that, let's run the command below from the directory of our smart contract:</p>
<pre><code class="lang-bash">npx thirdweb@latest deploy
</code></pre>
<p>This will first prompt you to link your device to your thirdweb account, and then open a URL for you to configure the constructor parameters of your smart contract:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696289593341/1ee69c99-9f73-40fc-af83-aaef7e1fdd03.png" alt="deploy greeter smart contract" class="image--center mx-auto" /></p>
<p>We need to change the chain we're deploying on to be the validium we just deployed. Click on the network name (e.g. <code>Mumbai</code>) to open up the network modal and click <code>Add Custom Network</code>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696291870635/3ebd88a0-ab05-4dae-ab10-f90f5069e7d0.png" alt="add custom network" class="image--center mx-auto" /></p>
<p>This will allow you to add your validium's network details into the thirdweb dashboard. Map up the chain ID, URL and network name to the corresponding fields. In the screenshot below, I've color-coded each field to help you out:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696292181156/25a72042-0f47-460b-bac8-a452e9b7de1c.png" alt="custom network details section" class="image--center mx-auto" /></p>
<p>Ensure you set your custom network as the chain you'd like to deploy to, which will subsequently prompt your wallet to switch across to this network:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696292222159/9ebde643-cf7f-426a-b082-07808038eb83.png" alt="select your custom network" class="image--center mx-auto" /></p>
<p>We'll also need some funds on our validium so we can cover the gas fees of deploying our smart contract. On the Presto dashboard, you should see a URL for a <strong>faucet</strong>, where you can send funds to test with to your wallet:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696292331718/a7b9072f-842e-477d-9f18-826a74875ba7.png" alt="presto faucet URL section" class="image--center mx-auto" /></p>
<p>Open up the faucet website and paste your wallet address into the field like so:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696292367953/f728c253-608f-45cc-a6cf-6fb357cc324d.png" alt="CDK Faucet page" class="image--center mx-auto" /></p>
<p>Finally, click <code>Deploy Now</code> on the thirdweb dashboard to deploy your smart contract:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696292447182/ca22e498-99e7-4d20-9176-4eebcb227060.png" alt="Accept contract deployment transaction on thirdweb" class="image--center mx-auto" /></p>
<p>That's it! 🥳 We just shipped our smart contract! We can even use our own block explorer to confirm it. Go ahead and copy the address of our smart contract:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696293705855/539db809-9d1c-4020-b31d-8676309c037f.png" alt="Copy contract address from thirdweb dashbaord" class="image--center mx-auto" /></p>
<p>Open up the block explorer that was deployed for us from the Presto dashboard:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696293762306/54248aed-6c52-4130-a9af-f91796776346.png" alt="View block explorer URL presto dashboard" class="image--center mx-auto" /></p>
<p>And we can indeed see our contract was deployed successfully! 🚢🎉</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696293886880/1fcee801-de56-45d0-9c92-5c73d170eaff.png" alt="Blockscout contract creation transaction" class="image--center mx-auto" /></p>
<h2 id="heading-creating-a-dapp-on-your-custom-chain">Creating a dApp on your Custom Chain</h2>
<p>Now we've deployed our smart contract, let's see how we can create an application that interacts with the smart contract we just deployed.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Just want the source code? Check out the <a target="_blank" href="https://github.com/jarrodwatts/polygon-cdk-demo">GitHub repo</a>.</div>
</div>

<p>You can use any tools you like to do this, but in this guide, we'll use the <a target="_blank" href="https://portal.thirdweb.com/react">thirdweb React SDK</a> to easily connect to our custom chain from a front-end environment.</p>
<p>To create a new application with the thirdweb React SDK pre-configured, run the following command, <em>(from a new directory)</em>:</p>
<pre><code class="lang-bash">npx thirdweb@latest create app
</code></pre>
<p>This command allows you to interactively choose the frontend language and framework you prefer. Below are the options I selected for my app:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696294675812/8f53f173-95a3-49b7-a6de-218a336ca34c.png" alt="npx thirdweb create app" class="image--center mx-auto" /></p>
<h3 id="heading-setting-up-the-thirdweb-api-key">Setting Up the thirdweb API Key</h3>
<p>To use thirdweb's RPC infrastructure, you'll need to get a thirdweb API key from the <a target="_blank" href="https://thirdweb.com/dashboard/settings"><strong>Settings</strong></a> tab of the thirdweb dashboard. Click <code>Create API Key</code> to get started (free):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696294881782/95690dad-03a7-44ea-9b9d-f2b994672ded.png" alt class="image--center mx-auto" /></p>
<p>In the root of your project, create a new environment variables file (<code>.env.local</code>) and add the following:</p>
<pre><code class="lang-bash">NEXT_PUBLIC_TEMPLATE_CLIENT_ID=your-api-key-client-id-here
</code></pre>
<h3 id="heading-connect-to-your-custom-chain">Connect to your Custom Chain</h3>
<p>Now we've got our API key set, we can connect to our custom chain via the RPC.</p>
<p>Inside the <code>_app.tsx</code> file, you can see the active chain is currently set to <code>ethereum</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// This is the chain your dApp will work on.</span>
<span class="hljs-keyword">const</span> activeChain = <span class="hljs-string">"ethereum"</span>; <span class="hljs-comment">// &lt;------- Let's change this!</span>
</code></pre>
<p>We need to change this to be set to our own custom network details, which we can do by following the <a target="_blank" href="https://portal.thirdweb.com/react/react.thirdwebprovider#custom-evm-chains">custom EVM chains</a> section of the thirdweb docs. Let's change <code>ethereum</code> to a new object containing our network details, like so:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> activeChain = {
  <span class="hljs-comment">// Chain id from Presto</span>
  chainId: <span class="hljs-number">1571747963</span>,
  <span class="hljs-comment">// RPC URL from Presto</span>
  rpc: [<span class="hljs-string">"https://cranegeode-rpc.eu-north-2.gateway.fm"</span>],
  <span class="hljs-comment">// Name of your rollup in various forms that you want it to appear</span>
  shortName: <span class="hljs-string">"cranegeode"</span>,
  slug: <span class="hljs-string">"cranegeode"</span>,
  chain: <span class="hljs-string">"cranegeode"</span>,
  name: <span class="hljs-string">"Crane Geode"</span>,
  <span class="hljs-comment">// Testnet flag, set this to true!</span>
  testnet: <span class="hljs-literal">true</span>,
  <span class="hljs-comment">// Details of the token used for gas on your chain.</span>
  nativeCurrency: {
    name: <span class="hljs-string">"Ether"</span>,
    symbol: <span class="hljs-string">"ETH"</span>,
    decimals: <span class="hljs-number">18</span>,
  },
  <span class="hljs-comment">// Optional, the block explorer for wallets to view transactions.</span>
  explorers: [
    {
      name: <span class="hljs-string">"blockscout"</span>,
      <span class="hljs-comment">// Block Explorer, Explorer URL from Presto</span>
      url: <span class="hljs-string">"https://cranegeode-blockscout.eu-north-2.gateway.fm/"</span>,
      standard: <span class="hljs-string">"EIP3091"</span>,
    },
  ],
};
</code></pre>
<p>Now our application can interact with smart contracts deployed to our custom chain!</p>
<h3 id="heading-reading-amp-writing-data-on-the-smart-contract">Reading &amp; Writing Data on the Smart Contract</h3>
<p>Finally, we can demo interacting with the smart contract we deployed. On the homepage, (<code>index.tsx</code>), we can use the <a target="_blank" href="https://portal.thirdweb.com/react/react.web3button"><code>Web3Button</code></a> component to:</p>
<ol>
<li><p>Prompt users to connect their wallet</p>
</li>
<li><p>Prompt users to add &amp; connect to our custom chain</p>
</li>
<li><p>Call a function on our smart contract from the user's wallet.</p>
</li>
</ol>
<p>Below is some simple demo code to read and write data from the smart contract:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Web3Button, useContract, useContractRead } <span class="hljs-keyword">from</span> <span class="hljs-string">"@thirdweb-dev/react"</span>;

<span class="hljs-comment">// Your smart contract address (from the thirdweb dashboard)</span>
<span class="hljs-keyword">const</span> contractAddress = <span class="hljs-string">"0x33341719456e9d506bcFDbC3afcC5A6882230566"</span>;

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// Connect to your contract via the contract address</span>
  <span class="hljs-keyword">const</span> { contract } = useContract(contractAddress);
  <span class="hljs-comment">// Read the current greeting on the smart contract</span>
  <span class="hljs-keyword">const</span> { data, isLoading } = useContractRead(contract, <span class="hljs-string">"greet"</span>);

  <span class="hljs-keyword">return</span> (
    &lt;&gt;
      {isLoading ? ( &lt;p&gt;Loading...&lt;<span class="hljs-regexp">/p&gt; ) : ( &lt;h1&gt;{data}&lt;/</span>h1&gt; )}

      &lt;Web3Button
        contractAddress={contractAddress}
        action={<span class="hljs-function">(<span class="hljs-params">contract</span>) =&gt;</span>contract.call(<span class="hljs-string">"setGreeting"</span>, [<span class="hljs-string">"Hey!"</span>])}
      &gt;
        <span class="hljs-built_in">Set</span> Greeting
      &lt;/Web3Button&gt;
    &lt;/&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>Run <code>npm run dev</code> and visit <a target="_blank" href="http://localhost:3000/">localhost:3000</a> to preview your demo application:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696296591673/8a7f2713-682e-4390-b1fe-d71927412ee5.gif" alt class="image--center mx-auto" /></p>
<p>Voilà! 💅You just built a full-stack application on your own layer 2 blockchain.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Polygon CDK allows anyone to launch their own L2 chain, powered by the industry-leading ZK technology of Polygon.</p>
<p>In this guide, we've walked through the process of:</p>
<ul>
<li><p>Launching our own ZK-Validium L2 blockchain</p>
</li>
<li><p>Deploying a smart contract to our own custom chain</p>
</li>
<li><p>Building a dApp to interact with our custom chain smart contracts</p>
</li>
</ul>
<p>You can access the full source code of this demo on <a target="_blank" href="https://github.com/jarrodwatts/polygon-cdk-demo">GitHub</a>, and follow me on <a target="_blank" href="https://twitter.com/jarrodWattsDev">Twitter</a> for more content like this!</p>
]]></content:encoded></item><item><title><![CDATA[A Deep Dive: How Polygon zkEVM Proves Batches of Transactions]]></title><description><![CDATA[In my previous post, we discussed how ZK proofs work, and how the different non-interactive ZK proofs are utilized in ZK-EVMs such as Polygon zkEVM.
But how exactly does that work? What information gets sent back to Ethereum? And how does this enable...]]></description><link>https://blog.jarrodwatts.com/how-polygon-zkevm-proves-batches-of-transactions</link><guid isPermaLink="true">https://blog.jarrodwatts.com/how-polygon-zkevm-proves-batches-of-transactions</guid><category><![CDATA[zkevm]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[zero-knowledge-proofs]]></category><category><![CDATA[Polygon]]></category><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Fri, 11 Aug 2023 01:02:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691636973745/d8469b29-0e66-48f3-a5f7-bd29bb2f6192.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In my <a target="_blank" href="https://blog.jarrodwatts.com/how-zk-proofs-and-zkevms-work"><strong>previous post</strong></a>, we discussed how ZK proofs work, and how the different non-interactive ZK proofs are utilized in ZK-EVMs such as Polygon zkEVM.</p>
<p><em>But how exactly does that work?</em> What information gets sent back to Ethereum? And how does this enable Polygon zkEVM to inherit the security of Ethereum?</p>
<p>In this post, we'll take a closer look at exactly what is happening under the hood, covering how transactions:</p>
<ol>
<li><p>Get submitted to Polygon zkEVM.</p>
</li>
<li><p>Are executed almost instantly.</p>
</li>
<li><p>Are batched together using data encryption methods.</p>
</li>
<li><p>Get sequenced and sent to Ethereum L1.</p>
</li>
<li><p>Achieve consolidated finality on L1 with the power of ZK proofs.</p>
</li>
</ol>
<p>Let's do this!</p>
<h2 id="heading-submitting-transactions">Submitting Transactions</h2>
<p>As we explored in the <a target="_blank" href="https://blog.jarrodwatts.com/how-zk-proofs-and-zkevms-work">previous post</a>, users are constantly submitting their L2 transactions to the trusted sequencer's node via JSON-RPC interface <em>(typically through wallets like MetaMask).</em></p>
<p>This allows the Polygon zkEVM to look and feel exactly like Ethereum from the user's perspective when interacting with dApps. Example 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://twitter.com/jarrodWattsDev/status/1686304245539274753">https://twitter.com/jarrodWattsDev/status/1686304245539274753</a></div>
<p> </p>
<p>From the user's perspective, the transactions go through almost instantly, allowing them to continue using dApps immediately after submitting the transaction. This powerful UX benefit is possible because the state of the zkEVM is updated without any information being sent to Ethereum (L1) at first.</p>
<p>However, if users want to <strong>bridge funds</strong> from L2 (zkEVM) to L1 (Ethereum), essentially performing a withdrawal, the full transaction life-cycle needs to be complete. This requires the PolygonZkEVM smart contract to:</p>
<ol>
<li><p>Receive the batches from the sequencer (know what transactions to prove).</p>
</li>
<li><p>Receive the validity proof from the aggregator (prove the transactions).</p>
</li>
</ol>
<p><a target="_blank" href="https://blog.jarrodwatts.com/how-zk-proofs-and-zkevms-work#heading-flow-of-data-in-a-zkevm"><em>See the flow of data in a zkEVM diagram</em></a><em>.</em></p>
<p>From the user's POV at this point, the simplified flow looks like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691634316635/334f6935-6d98-492f-aa58-625e463863c9.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-executing-transactions">Executing Transactions</h2>
<p>After being submitted, the transactions are stored in a pending transactions pool, where they await the sequencer's selection for either execution or discard.</p>
<p>The sequencer makes a few checks to see if it can discard a transaction, based on:</p>
<ol>
<li><p>If the sender has enough funds to cover the transaction.</p>
</li>
<li><p>If the smart contract called exists and has valid/correct bytecode.</p>
</li>
<li><p>If the transaction isn't a duplicate.</p>
</li>
<li><p>If the transaction isn't a "<a target="_blank" href="https://en.wikipedia.org/wiki/Double-spending">double-spend</a>", to ensure the sender's funds haven't already been spent in another transaction.</p>
</li>
</ol>
<p>Once the transaction is considered to be valid, the sequencer updates the Polygon zkEVM state, at which point the user experiences the transaction going through almost instantly.</p>
<p>If we modify our diagram to explore under the hood, here's how it looks:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691634760659/8eb90795-de23-49de-8a21-e61df871b92a.png" alt class="image--center mx-auto" /></p>
<p>At this point in time, the user continues to interact with the state of the L2. Every step <em>after</em> this is related to posting transaction data back to Ethereum L1; which is only relevant to the user if they want to bridge funds <em>back</em> to Ethereum.</p>
<h2 id="heading-batching-transactions">Batching Transactions</h2>
<p>After being added to the L2 state, the transaction gets broadcast to all other zkEVM nodes on the network and is ready to be <strong>batched</strong> up with other transactions.</p>
<p>To batch transactions together, they are concatenated into a single set of bytes in binary form. On the <code>PolygonZkEVM</code> smart contract, a Solidity <a target="_blank" href="https://docs.soliditylang.org/en/v0.8.14/structure-of-a-contract.html"><code>struct</code></a> is defined, named <a target="_blank" href="https://github.com/0xPolygonHermez/zkevm-contracts/blob/main/contracts/PolygonZkEVM.sol#L27-L41"><code>BatchData</code></a>.</p>
<p>Within this struct, a <code>transactions</code> field of type <code>bytes</code> is defined, that contains the encoded batch of transactions concatenated together.</p>
<pre><code class="lang-solidity"><span class="hljs-comment">/**
 * @notice Struct which will be used to call sequenceBatches
 * @param transactions L2 ethereum transactions EIP-155 or pre-EIP-155 with signature:
 * EIP-155: rlp(nonce, gasprice, gasLimit, to, value, data, chainid, 0, 0,) || v || r || s
 * pre-EIP-155: rlp(nonce, gasprice, gasLimit, to, value, data) || v || r || s
 * @param globalExitRoot Global exit root of the batch
 * @param timestamp Sequenced timestamp of the batch
 * @param minForcedTimestamp Minimum timestamp of the force batch data, empty when non forced batch
 */</span>
<span class="hljs-keyword">struct</span> <span class="hljs-title">BatchData</span> {
    <span class="hljs-keyword">bytes</span> transactions;
    <span class="hljs-keyword">bytes32</span> globalExitRoot;
    <span class="hljs-keyword">uint64</span> timestamp;
    <span class="hljs-keyword">uint64</span> minForcedTimestamp;
}
</code></pre>
<p>As you can see in the comments above, the transactions are encoded using "RLP", and can be either EIP-155 or pre-EIP-155 transactions.</p>
<ul>
<li><p><a target="_blank" href="https://eips.ethereum.org/EIPS/eip-155">EIP-155</a> was a proposal created in 2016 by Vitalik to prevent replay attacks. It adds a <code>chainId</code> value to avoid transactions intended for one chain to also work on other chains.</p>
</li>
<li><p><code>rlp</code> stands for <a target="_blank" href="https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp">Recursive-Length Prefix Serialization</a>. It's a data serialization method that Ethereum uses to encode the structure of any arbitrarily nested arrays of data into binary.</p>
</li>
</ul>
<p>As for the other three fields:</p>
<ol>
<li><p><code>globalExitRoot</code>: The root of the global exit <em>(Merkle)</em> tree that stores information about asset transfers between L1 and L2. <a target="_blank" href="https://zkevm.polygon.technology/protocol/exit-tree/"><strong>Learn more</strong></a>.</p>
</li>
<li><p><code>timestamp</code>: The time the batch was created.</p>
</li>
<li><p><code>minForcedTimestamp</code>: Only relevant if the user is not using the trusted sequencer (helpful for censorship resistance). Typically set to <code>0</code>. <a target="_blank" href="https://zkevm.polygon.technology/docs/protocol/sequencer-resistance/">Learn more</a>.</p>
</li>
</ol>
<p>To update our diagram, let's zoom out and see what the sequencer is up to:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691635391815/81fab14f-0c72-4481-9acb-f1972605695a.png" alt class="image--center mx-auto" /></p>
<p>Multiple of these batches get created, according to some size rules that we'll define in the next section as defined on the L1 smart contract. So, let's see what happens with these batches next.</p>
<h2 id="heading-sequencing-batches-of-transactions">Sequencing Batches of Transactions</h2>
<p>Once we have batches of transactions, they're ready to be "sequenced". To do this, the sequencer calls the <code>PolygonZkEVM</code> smart contract's <code>sequenceBatches</code> function (on L1) and provides it with multiple batches of transactions.</p>
<p><a target="_blank" href="https://etherscan.io/tx/0x38ab7f8302722566b1262098418b322aa42f3353efbfa9569617c232c5e15ef3">This transaction</a> is an example of a <code>sequenceBatch</code> transaction on Ethereum mainnet. By inspecting the input data, we can see the <code>52</code> batches of transactions that got included in this particular function call:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691570911184/a156aed0-6c8e-4644-ae51-177c0ef2212a.png" alt class="image--center mx-auto" /></p>
<p>Each batch also contains the <code>transactions</code> field that we saw earlier (the concatenated bytes), which concatenates as many RLP encoded transactions as it can fit:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691571009307/3fe17b10-2ab6-4aff-9cbf-491ef000a9a6.png" alt class="image--center mx-auto" /></p>
<p>The <code>PolygonZkEVM</code> smart contract has a constant value called <code>_MAX_TRANSACTIONS_BYTE_LENGTH</code> that determines how many transactions can be concatenated together in that field. <a target="_blank" href="https://github.com/0xPolygonHermez/zkevm-contracts/blob/main/contracts/PolygonZkEVM.sol#L107-L119">Source code</a>:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// Max transactions bytes that can be added in a single batch</span>
<span class="hljs-comment">// Max keccaks circuit = (2**23 / 155286) * 44 = 2376</span>
<span class="hljs-comment">// Bytes per keccak = 136</span>
<span class="hljs-comment">// Minimum Static keccaks batch = 2</span>
<span class="hljs-comment">// Max bytes allowed = (2376 - 2) * 136 = 322864 bytes - 1 byte padding</span>
<span class="hljs-comment">// Rounded to 300000 bytes</span>
<span class="hljs-comment">// In order to process the transaction, the data is approximately hashed twice for ecrecover:</span>
<span class="hljs-comment">// 300000 bytes / 2 = 150000 bytes</span>
<span class="hljs-comment">// Since geth pool currently only accepts at maximum 128kb transactions:</span>
<span class="hljs-comment">// https://github.com/ethereum/go-ethereum/blob/master/core/txpool/txpool.go#L54</span>
<span class="hljs-comment">// We will limit this length to be compliant with the geth restrictions since our node will use it</span>
<span class="hljs-comment">// We let 8kb as a sanity margin</span>
<span class="hljs-keyword">uint256</span> <span class="hljs-keyword">internal</span> <span class="hljs-keyword">constant</span> _MAX_TRANSACTIONS_BYTE_LENGTH <span class="hljs-operator">=</span> <span class="hljs-number">120000</span>;
</code></pre>
<p>Similarly, there is a limit to how many batches can be sent as one transaction too, in a constant variable called <code>_MAX_VERIFY_BATCHES</code>. <a target="_blank" href="https://github.com/0xPolygonHermez/zkevm-contracts/blob/main/contracts/PolygonZkEVM.sol#L128-L130">Source code</a>:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// Maximum batches that can be verified in one call. It depends on our current metrics</span>
<span class="hljs-comment">// This should be a protection against someone that tries to generate huge chunk of invalid batches, and we can't prove otherwise before the pending timeout expires</span>
<span class="hljs-keyword">uint64</span> <span class="hljs-keyword">internal</span> <span class="hljs-keyword">constant</span> _MAX_VERIFY_BATCHES <span class="hljs-operator">=</span> <span class="hljs-number">1000</span>;
</code></pre>
<p>These batches are provided into a function called <a target="_blank" href="https://github.com/0xPolygonHermez/zkevm-contracts/blob/main/contracts/PolygonZkEVM.sol#L484-L487"><code>sequenceBatches</code></a>, which accepts:</p>
<ol>
<li><p>An array of <code>BatchData</code> structs called <code>batches</code>.</p>
</li>
<li><p>An address that fees for sequencing batches are sent called <code>l2Coinbase</code>.</p>
</li>
</ol>
<pre><code class="lang-solidity"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sequenceBatches</span>(<span class="hljs-params">
    BatchData[] <span class="hljs-keyword">calldata</span> batches,
    <span class="hljs-keyword">address</span> l2Coinbase
</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">ifNotEmergencyState</span> <span class="hljs-title">onlyTrustedSequencer</span> </span>{
  ...
}
</code></pre>
<p>This function iterates over each batch and ensures they are valid, before updating the <strong>virtual state</strong> on the L1 smart contract inside a <a target="_blank" href="https://docs.soliditylang.org/en/v0.8.7/types.html">mapping</a> called <a target="_blank" href="https://github.com/0xPolygonHermez/zkevm-contracts/blob/main/contracts/PolygonZkEVM.sol#L184-L186"><code>sequencedBatches</code></a>:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// Queue of batches that defines the virtual state</span>
<span class="hljs-comment">// SequenceBatchNum --&gt; SequencedBatchData</span>
<span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">uint64</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> SequencedBatchData) <span class="hljs-keyword">public</span> sequencedBatches;
</code></pre>
<p>In our diagram, here's where we are at:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691635720495/7eaae0a1-10dc-4bce-9b3f-5dc43a3ebe74.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-the-three-finality-states">The Three Finality States</h3>
<p>Now's a good time to introduce the different states a transaction can be in in the Polygon zkEVM. There are different phases of finality that transactions go through:</p>
<ol>
<li><p><strong>Trusted State</strong>: The state is updated on L2. Has not yet reached L1.</p>
<ul>
<li>Most of the time, this is what state users interact with.</li>
</ul>
</li>
<li><p><strong>Virtual State</strong>: Batches have been sequenced and data is available on L1.</p>
<ul>
<li>At this point, data is available on L1 for anyone to prove, but is not yet proven.</li>
</ul>
</li>
<li><p><strong>Consolidated State</strong>: A ZK proof has been posted on L1.</p>
<ul>
<li>At this point, the data is proven and inherits Ethereum's security.</li>
</ul>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691628675611/a985e7e8-39e3-4ecc-bceb-ade4816eee19.png" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://zkevm.polygon.technology/docs/protocol/state-management">Learn More ↗</a></p>
<p>So far, we've talked about the process up to trusted and virtual states, so let's jump into the final phase now, where ZK proofs of computational integrity are submitted to L1.</p>
<h2 id="heading-aggregating-sequenced-batches">Aggregating Sequenced Batches</h2>
<p>Once all of the sequenced batches have reached L1, the final step is to generate a ZK proof that verifies the validity of these transactions.</p>
<p>Aggregator nodes take the sequenced batches and provide them to the <a target="_blank" href="https://zkevm.polygon.technology/docs/zkProver/overview">ZK prover</a>, which produces a final <a target="_blank" href="https://blog.jarrodwatts.com/how-zk-proofs-and-zkevms-work#heading-what-are-zk-snarks">SNARK</a> using <code>fflonk</code> protocol. (Quick summary 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://twitter.com/jbaylina/status/1624116186861404188">https://twitter.com/jbaylina/status/1624116186861404188</a></div>
<p> </p>
<p>The end result is the aggregator receives a ZK proof that is succinct enough that it can be stored on the Ethereum L1. A simplified diagram of this flow is below:</p>
<p><img src="https://zkevm.polygon.technology/assets/images/fig4-zkProv-arch-337c7dd5cfc9f9c0c2e85024cc269904.png" alt="Skeletal Overview of zkProver" /></p>
<p>Once the aggregator node has the proof, it calls the PolygonZkEVM smart contract's <code>verifyBatchesTrustedAggregator</code> function, providing the proof it just received to the function, among other parameters, <a target="_blank" href="https://github.com/0xPolygonHermez/zkevm-contracts/blob/main/contracts/PolygonZkEVM.sol#L700-L716">source code</a>:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">/**
 * @notice Allows an aggregator to verify multiple batches
 * @param pendingStateNum Init pending state, 0 if consolidated state is used
 * @param initNumBatch Batch which the aggregator starts the verification
 * @param finalNewBatch Last batch aggregator intends to verify
 * @param newLocalExitRoot  New local exit root once the batch is processed
 * @param newStateRoot New State root once the batch is processed
 * @param proof fflonk proof
 */</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">verifyBatchesTrustedAggregator</span>(<span class="hljs-params">
    <span class="hljs-keyword">uint64</span> pendingStateNum,
    <span class="hljs-keyword">uint64</span> initNumBatch,
    <span class="hljs-keyword">uint64</span> finalNewBatch,
    <span class="hljs-keyword">bytes32</span> newLocalExitRoot,
    <span class="hljs-keyword">bytes32</span> newStateRoot,
    <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> proof
</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">onlyTrustedAggregator</span> </span>{
  ...
}
</code></pre>
<p>Let's inspect an example transaction again to see how this looks in the real world.</p>
<p><a target="_blank" href="https://etherscan.io/tx/0xdee359c60e068a4340d5b2d1f9a30cb2108810ecf5f9be843f76c25e999cbda0">This transaction</a> comes from the trusted aggregator and calls the <code>verifyBatchesTrustedAggregator</code> on the PolygonZkEVM smart contract with the proof:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691632283671/aa05cae7-51f8-416b-8850-ca973286bbc3.png" alt class="image--center mx-auto" /></p>
<p><em>Details on the other parameters can be found</em> <a target="_blank" href="https://zkevm.polygon.technology/docs/protocol/transaction-aggregation#aggregating-a-sequence-of-batches"><em>here</em></a><em>.</em></p>
<p>Within this function, another contract called the <code>rollupVerifier</code> has a function <a target="_blank" href="https://github.com/0xPolygonHermez/zkevm-contracts/blob/main/contracts/PolygonZkEVM.sol#L1510-L1513C10"><code>verifyProof</code></a> that gets called. This function is provided with the proof as well as an <code>inputSnark</code>; which is a cryptographic representation of all the L2 transactions of a specific L2 State transition.</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// Verify proof</span>
<span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>rollupVerifier.verifyProof(proof, [inputSnark])) {
    <span class="hljs-keyword">revert</span> InvalidProof();
}
</code></pre>
<p>If the proof is valid, <a target="_blank" href="https://github.com/0xPolygonHermez/zkevm-contracts/blob/main/contracts/PolygonZkEVM.sol#L726-L737">various states are updated</a> like the global exit root and the <code>batchNumToStateRoot</code> mapping containing the consolidated L2 state roots:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// State root mapping</span>
<span class="hljs-comment">// BatchNum --&gt; state root</span>
<span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">uint64</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> <span class="hljs-keyword">bytes32</span>) <span class="hljs-keyword">public</span> batchNumToStateRoot;
</code></pre>
<p>Posting and verifying this proof on L1, in this example, took ~350K gas:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691636320196/5af00f83-3e40-4e28-bc11-af0250accd0a.png" alt class="image--center mx-auto" /></p>
<p>With one final update to our diagram, we have achieved a consolidated state on L1!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1691636153930/34b1a6dd-7189-4b72-a8e2-dcc1d9d791da.png" alt class="image--center mx-auto" /></p>
<p>At this point, the batches of transactions are in the final "consolidated" state, and this is how Polygon zkEVM inherits the security of Ethereum; by posting and proving all transaction data back to Ethereum L1.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>When interacting with the Polygon zkEVM from a user perspective, transactions are confirmed almost instantaneously, while simultaneously inheriting the security of Ethereum as this entire process occurs under the hood.</p>
<p>This approach provides the best of both worlds, where users have both low gas fees and fast transaction speeds within seconds and can also bridge funds back to Ethereum within ~1 hour using the power of ZK proofs.</p>
<p>In this blog, we've covered the full life cycle of a transaction from the Polygon zkEVM, all the way through to being proved using zero-knowledge on Ethereum L1.</p>
<p>If you enjoyed this content, consider giving me a follow on <a target="_blank" href="https://twitter.com/jarrodWattsDev">Twitter</a>!</p>
]]></content:encoded></item><item><title><![CDATA[Create A Web3 App Store Using Polygon dApp Store Kit]]></title><description><![CDATA[In this guide, we'll cover how to use Polygon's dApp Store Kit to create a decentralized app store. We'll walk through the following topics:

What is Polygon dApp Store Kit?

Why was dApp Store Kit created?

How to create a web application built on t...]]></description><link>https://blog.jarrodwatts.com/create-a-web3-app-store-using-polygon-dapp-store-kit</link><guid isPermaLink="true">https://blog.jarrodwatts.com/create-a-web3-app-store-using-polygon-dapp-store-kit</guid><category><![CDATA[Web3]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[Polygon]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[dapps]]></category><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Thu, 03 Aug 2023 01:52:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1690792483735/62ddf933-32ba-4ef6-a84f-dca6c3b4274f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this guide, we'll cover how to use Polygon's <a target="_blank" href="https://polygon.technology/blog/dapp-store-kit-your-dapp-your-store-your-rules">dApp Store Kit</a> to create a decentralized app store. We'll walk through the following topics:</p>
<ul>
<li><p>What is Polygon dApp Store Kit?</p>
</li>
<li><p>Why was dApp Store Kit created?</p>
</li>
<li><p>How to create a web application built on top of the dApp Store Kit.</p>
</li>
</ul>
<p>By the end of the guide, we'll create a fully customizable decentralized app store with our own rules <em>(demo screenshot below)</em>. Let's do it!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690792623917/8a273f31-665b-4017-8fc9-8e9b84aebc97.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-what-is-dapp-store-kit">What Is dApp Store Kit?</h2>
<p>dApp Store Kit is an open-source development stack built by Polygon that uses <a target="_blank" href="https://meroku.org/">Meroku</a> under the hood; a decentralized app store protocol that acts as a registry for devs to create decentralized app stores on top of.</p>
<p>The registry comes with over 900 decentralized applications out of the box, meaning builders don't have to source and evaluate applications for their store but can instead filter and curate the ones within the registry.</p>
<h3 id="heading-why-dapp-store-kit">Why dApp Store Kit?</h3>
<p>Developers in web3 face a common challenge; it's difficult to have your dApp distributed and discovered by potential users/customers.</p>
<p>This is partially due to the restrictions that today's primary distribution channels have placed on blockchain-based applications and technology. Including:</p>
<ul>
<li><p><strong>Steam</strong>: Valve has placed a ban on selling blockchain-based games.</p>
</li>
<li><p><strong>Apple</strong>: Purchases must be made through the in-app purchase system.</p>
</li>
</ul>
<p>Although recent strides have been made in this space including Google Play Store announcing support for NFTs just last month (July 2023), distribution is a pain point for the web3 world.</p>
<p>Rather than release a centralized app store, Polygon created the dApp store kit as a protocol that allows anyone to freely create their own customized decentralized app stores that serve different purposes and have different incentives.</p>
<h2 id="heading-creating-a-decentralized-app-store">Creating A Decentralized App Store</h2>
<p>To create our decentralized app store, we're going to use <a target="_blank" href="https://nextjs.org/">Next.js</a>; a React framework for creating full-stack web applications, and the <code>@merokudao/storekit-sdk</code> package to use the Polygon dApp store kit.</p>
<p>To keep it short and sweet, I'll cut out the styles and fluff from this guide, but you can view the full source code for the project on GitHub linked below if you prefer.</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/jarrodwatts/dapp-store-kit-demo">https://github.com/jarrodwatts/dapp-store-kit-demo</a></div>
<p> </p>
<h3 id="heading-creating-the-project">Creating the Project</h3>
<p>To get started, create a new Next.js project using the <a target="_blank" href="https://nextjs.org/docs/pages/api-reference/create-next-app"><code>create-next-app</code></a> CLI:</p>
<pre><code class="lang-bash">npx create-next-app@latest
</code></pre>
<p>Below are the options that I chose, however, you can customize these as you prefer:</p>
<pre><code class="lang-bash">√ What is your project named? ... dapp-store
√ Would you like to use TypeScript? ... No / Yes
√ Would you like to use ESLint? ... No / Yes
√ Would you like to use Tailwind CSS? ... No / Yes
√ Would you like to use `src/` directory? ... No / Yes
√ Would you like to use App Router? (recommended) ... No / Yes
√ Would you like to customize the default import <span class="hljs-built_in">alias</span>? ... No / Yes
</code></pre>
<p>Next, change directories into your newly created project and install the <a target="_blank" href="https://www.npmjs.com/package/@merokudao/storekit-sdk">dApp store kit npm package</a>:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># First, change directories:</span>
<span class="hljs-built_in">cd</span> dapp-store

<span class="hljs-comment"># Install the dApp store kit package</span>
npm i @merokudao/storekit-sdk
</code></pre>
<p>Open the project in your text editor, run <code>npm run dev</code> and visit <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a> to preview your application.</p>
<h3 id="heading-getting-featured-dapps">Getting Featured dApps</h3>
<p>On our homepage, we're going to fetch the featured decentralized applications from the protocol and display them on the homepage. To do this, we'll:</p>
<ol>
<li><p>Instantiate the <code>DAppRegistryApi</code> from the <code>@merokudao/storekit-sdk</code> package.</p>
</li>
<li><p>Call the <code>getDAppV1</code> method on the <code>DAppRegistryApi</code> to get back an array of dApps.</p>
</li>
<li><p>Iterate over the returned array to display each dApp on the UI.</p>
</li>
</ol>
<p>Below is the code to achieve this:</p>
<pre><code class="lang-typescript"><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> { DAppRegistryApi, Dapp } <span class="hljs-keyword">from</span> <span class="hljs-string">"@merokudao/storekit-sdk"</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-comment">// State to store the list of dApps</span>
  <span class="hljs-keyword">const</span> [dapps, setDapps] = useState&lt;Dapp[]&gt;();

  <span class="hljs-comment">// useEffect to fetch the list of dApps and store them in the state</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    (<span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-comment">// Base URL for the mainnet API</span>
      <span class="hljs-keyword">const</span> baseURL = <span class="hljs-string">"https://api-a.meroku.store"</span>;

      <span class="hljs-comment">// Instantiate the dApp Registry API</span>
      <span class="hljs-keyword">const</span> dAppRegistryAPI = <span class="hljs-keyword">new</span> DAppRegistryApi({
        basePath: baseURL,
      });

      <span class="hljs-comment">// Get the dApps list, and store it in the state</span>
      <span class="hljs-keyword">const</span> dAppsRequest = <span class="hljs-keyword">await</span> dAppRegistryAPI.getDAppV1();
      <span class="hljs-keyword">const</span> dApps = dAppsRequest.data.response;
      setDapps(dApps);
    })();
  }, []);

  <span class="hljs-comment">// Display each dApp we stored in state</span>
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      {dapps?.map(<span class="hljs-function">(<span class="hljs-params">dapp</span>) =&gt;</span> (
        &lt;div key={dapp.dappId}&gt;
          &lt;img src={dapp.images?.logo?.toString() || <span class="hljs-string">""</span>} alt={dapp.name} /&gt;
          &lt;p&gt;{dapp.name}&lt;/p&gt;
        &lt;/div&gt;
      ))}
    &lt;/div&gt;
  );
}
</code></pre>
<p>With some added styles and some decoration, here's the application so far:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690781134946/02e0d124-5b31-46c6-81d2-3c02fb1818e3.png" alt class="image--center mx-auto" /></p>
<p>Each dApp returned from the method includes properties such as <code>name</code>, <code>categories</code>, <code>description</code>, <code>images</code>, <code>appUrl</code>, <code>chains</code>, and more. Using each of these properties, you can create fully customizable interfaces for your app store, such as mine below.</p>
<p><em>(You can copy the</em> <a target="_blank" href="https://github.com/jarrodwatts/dapp-store-kit-demo/blob/main/src/pages/index.tsx"><em>source code</em></a> <em>for this screenshot from the GitHub repo).</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690782010160/cca04114-730a-49ab-9f68-fd32e6e08811.png" alt class="image--center mx-auto" /></p>
<p>The <code>getDAppV1</code> method also comes with a large number of parameters that allow you to customize what dApps you want to serve in your application:</p>
<pre><code class="lang-typescript">getDAppV1(
   page?: <span class="hljs-built_in">number</span>,  
   limit?: <span class="hljs-built_in">number</span>,  
   search?: <span class="hljs-built_in">string</span>,  
   isListed?: <span class="hljs-built_in">boolean</span>,  
   chainId?: <span class="hljs-built_in">number</span>,  
   language?: <span class="hljs-built_in">string</span>,  
   availableOnPlatform?: <span class="hljs-built_in">Array</span>&lt;<span class="hljs-built_in">string</span>&gt;,  
   matureForAudience?: <span class="hljs-built_in">boolean</span>,  
   minAge?: <span class="hljs-built_in">number</span>,  
   listedOnOrAfter?: <span class="hljs-built_in">string</span>,  
   listedOnOrBefore?: <span class="hljs-built_in">string</span>,  
   allowedInCountries?: <span class="hljs-built_in">Array</span>&lt;<span class="hljs-built_in">string</span>&gt;,  
   blockedInCountries?: <span class="hljs-built_in">Array</span>&lt;<span class="hljs-built_in">string</span>&gt;,  
   categories?: <span class="hljs-built_in">Array</span>&lt;<span class="hljs-built_in">Array</span>&lt;<span class="hljs-built_in">string</span>&gt;&gt;,  
   orderBy?: <span class="hljs-built_in">string</span>,  
   subCategory?: <span class="hljs-built_in">Array</span>&lt;<span class="hljs-built_in">Array</span>&lt;<span class="hljs-built_in">string</span>&gt;&gt;,  
   options?: AxiosRequestConfig
): <span class="hljs-built_in">Promise</span>&lt;AxiosResponse&lt;InlineResponse200&gt;&gt;;
</code></pre>
<p>For example, if we want to limit what dApps we fetch to only show games only built on the Polygon chain, we could add the <code>games</code> filter to the <code>categories</code> parameter and <code>137</code> as the chain ID like so:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Get the dApps list, and store it in the state</span>
<span class="hljs-keyword">const</span> dAppsRequest = <span class="hljs-keyword">await</span> dAppRegistryAPI.getDAppV1(
  <span class="hljs-number">1</span>, <span class="hljs-comment">// page</span>
  <span class="hljs-number">10</span>, <span class="hljs-comment">// page size</span>
  <span class="hljs-literal">undefined</span>, <span class="hljs-comment">// search term</span>
  <span class="hljs-literal">true</span>, <span class="hljs-comment">// is dapp listed</span>
  <span class="hljs-number">137</span>, <span class="hljs-comment">// Polygon chain ID</span>
  <span class="hljs-literal">undefined</span>, <span class="hljs-comment">// language</span>
  <span class="hljs-literal">undefined</span>, <span class="hljs-comment">// availableOnPlatform</span>
  <span class="hljs-literal">undefined</span>, <span class="hljs-comment">// matureForAudience</span>
  <span class="hljs-literal">undefined</span>, <span class="hljs-comment">// minAge</span>
  <span class="hljs-literal">undefined</span>, <span class="hljs-comment">// listedOnOrAfter</span>
  <span class="hljs-literal">undefined</span>, <span class="hljs-comment">// listedOnOrBefore</span>
  <span class="hljs-literal">undefined</span>, <span class="hljs-comment">// allowedInCountries</span>
  <span class="hljs-literal">undefined</span>, <span class="hljs-comment">// blockedInCountries</span>
  [[<span class="hljs-string">"games"</span>]] <span class="hljs-comment">// categories</span>
);
</code></pre>
<p>This changes what dApps come back from the registry allowing us to fully customize our app store experience, for example, we now have a Polygon games store:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690782635036/83503ddf-879a-47b2-8c65-fdbdff12217b.png" alt class="image--center mx-auto" /></p>
<p>Let's convert each of these into a <a target="_blank" href="https://nextjs.org/docs/pages/api-reference/components/link"><code>Link</code></a> that points to the <code>/dapps/[id]</code> dynamic route so that when the user clicks on each dApp it takes them to the page for that dApp:</p>
<pre><code class="lang-typescript">{dapps?.map(<span class="hljs-function">(<span class="hljs-params">dapp</span>) =&gt;</span> (
  &lt;Link href={<span class="hljs-string">`/dapps/<span class="hljs-subst">${dapp.dappId}</span>`</span>} key={dapp.dappId}&gt;
    ...
  &lt;/Link&gt;
))}
</code></pre>
<h3 id="heading-creating-individual-dapp-pages">Creating Individual dApp Pages</h3>
<p>Create a new <a target="_blank" href="https://nextjs.org/docs/pages/building-your-application/routing/dynamic-routes">dynamic route</a> using Next.js by creating a new file at <code>/pages/dapps/[dappId].tsx</code> that renders each dApp in more detail.</p>
<p>Using a similar pattern as previously, we can call the <code>apiV1DappSearchDappIdGet</code> method on the <code>DAppRegistryApi</code> class to fetch a specific dApp using its ID, and render it on the UI. Below is a basic example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { DAppRegistryApi, Dapp } <span class="hljs-keyword">from</span> <span class="hljs-string">"@merokudao/storekit-sdk"</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/router"</span>;
<span class="hljs-keyword">import</span> React, { 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">DappPage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Get the dApp ID from the URL using Next router.</span>
  <span class="hljs-keyword">const</span> router = useRouter();
  <span class="hljs-keyword">const</span> { dappId } = router.query;

  <span class="hljs-keyword">const</span> [dapp, setDapp] = useState&lt;Dapp&gt;();

  <span class="hljs-comment">// useEffect to fetch the list of dApps and store them in the state</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    (<span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">if</span> (!dappId) <span class="hljs-keyword">return</span>;

      <span class="hljs-comment">// Base URL for the mainnet API</span>
      <span class="hljs-keyword">const</span> baseURL = <span class="hljs-string">"https://api-a.meroku.store"</span>;

      <span class="hljs-comment">// Instantiate the dApp Registry API</span>
      <span class="hljs-keyword">const</span> dAppRegistryAPI = <span class="hljs-keyword">new</span> DAppRegistryApi({
        basePath: baseURL,
      });

      <span class="hljs-comment">// Get dApp info by ID</span>
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> dAppRegistryAPI.apiV1DappSearchDappIdGet(
        dappId <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>
      );

      <span class="hljs-comment">// Get the dApp out of the response</span>
      <span class="hljs-keyword">const</span> result = response?.data?.data?.[<span class="hljs-number">0</span>];

      <span class="hljs-comment">// Store the dApp in the state</span>
      setDapp(result);
    })();
  }, [dappId]);

  <span class="hljs-comment">// Render dApp information</span>
  <span class="hljs-keyword">return</span> (
    &lt;main className=<span class="hljs-string">"container flex flex-col align-middle w-full min-h-screen py-2 pt-20"</span>&gt;
      &lt;h1&gt;{dapp?.name}&lt;/h1&gt;
      &lt;p&gt;{dapp?.description}&lt;/p&gt;
    &lt;/main&gt;
  );
}
</code></pre>
<p>Utilizing the metadata available and adding some styles, we can create an elegant page for each individual dApp like so <a target="_blank" href="https://github.com/jarrodwatts/dapp-store-kit-demo/blob/main/src/pages/dapps/%5BdappId%5D.tsx"><em>(source code)</em></a>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690790263375/75fd52fc-c101-4abe-b904-98d6a143a625.png" alt class="image--center mx-auto" /></p>
<p>That's it! We've created a discovery page and a detail page where users can find out more information and the URL to each app we curated on the home page.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>In this guide, we've covered the basics of understanding and getting started with Polygon's dApp store kit. Below, you'll find further resources to help you dive deeper into creating your own projects:</p>
<ul>
<li><p><a target="_blank" href="https://docs.meroku.org/api-docs/">dApp Store Kit API documentation</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/jarrodwatts/dapp-store-kit-demo/">Source code from this guide</a></p>
</li>
<li><p><a target="_blank" href="https://discord.gg/0xpolygondevs">Polygon Developer Discord</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[The Ultimate ZK-EVM Comparison Guide]]></title><description><![CDATA[All ZK-EVMs (Zero-knowledge Ethereum Virtual Machines) aim to achieve the same goal; make Ethereum more scalable and grow the adoption of web3.
As a developer, there are now several different options you have to create and deploy smart contracts onto...]]></description><link>https://blog.jarrodwatts.com/the-ultimate-zk-evm-comparison-guide</link><guid isPermaLink="true">https://blog.jarrodwatts.com/the-ultimate-zk-evm-comparison-guide</guid><category><![CDATA[zkevm]]></category><category><![CDATA[Ethereum]]></category><category><![CDATA[Smart Contracts]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Web3]]></category><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Sat, 15 Jul 2023 01:29:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1689314694483/fd46562f-c6f9-4da3-b0f8-23b939123061.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>All ZK-EVMs (Zero-knowledge Ethereum Virtual Machines) aim to achieve the same goal; make Ethereum more scalable and grow the adoption of web3.</p>
<p>As a developer, there are now several different options you have to create and deploy smart contracts onto a ZK-EVM, each with unique implementations, benefits, and drawbacks.</p>
<p>In this post, we'll cover the different kinds of ZK-EVMs as defined by <a target="_blank" href="https://vitalik.ca/general/2022/08/04/zkevm.html">Vitalik</a>, the pros and cons of each, discuss which companies are working on them, and deploy smart contracts to each one.</p>
<p>Let's dive into it!</p>
<h2 id="heading-recap-what-is-a-zk-evm">Recap: What Is A ZK-EVM?</h2>
<p>If you're reading this and you aren't already familiar with zero-knowledge proofs or ZK-EVMs, I'd encourage you to read two of my previous posts linked below.</p>
<p>First, a basic understanding of ZK-EVMs:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://blog.jarrodwatts.com/zkevms-and-the-race-to-scale-ethereum">https://blog.jarrodwatts.com/zkevms-and-the-race-to-scale-ethereum</a></div>
<p> </p>
<p>If you want to go deeper, I also made a post covering how zero-knowledge proofs work, without any of the math:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://blog.jarrodwatts.com/how-zk-proofs-and-zkevms-work">https://blog.jarrodwatts.com/how-zk-proofs-and-zkevms-work</a></div>
<p> </p>
<p><strong>TLDR</strong>: ZK-EVMs are Ethereum rollups that batch transactions together and post a "validity proof" of that batch back to the Ethereum blockchain + they're EVM-compatible, meaning you don't need specialized tools to work with them.</p>
<h2 id="heading-the-evm-opcodes-andamp-bytecode">The EVM, Opcodes &amp; Bytecode</h2>
<p>The Ethereum Virtual Machine (EVM) is the runtime environment for smart contracts on Ethereum. Ethereum not only stores all accounts and balances similarly to Bitcoin but additionally stores what's called a "machine state".</p>
<p>The machine state is stored in a <a target="_blank" href="https://ethereum.org/en/developers/docs/evm/#state">trie</a> data structure, and changes from block to block after executing the transactions contained within that block.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689129588055/d45e3924-a8ce-440e-96c0-927390ba84bd.png" alt class="image--center mx-auto" /></p>
<p>The EVM is deterministic, meaning a set of instructions performed on any given state will result in the same new state every time. A simple analogy for this is to imagine a game of chess.</p>
<p>The chess board (Ethereum) has a large (in Ethereum, infinite) number of states the game can be in. The game has rules on what moves (transactions) can be performed, and restrictions on who can perform what actions (using accounts, signatures, etc.).</p>
<p>Just like Ethereum, players make moves (submit transactions), and the game (Ethereum) dictates what rules are allowed, and executes them, resulting in a new board (world) state after each move (block).</p>
<p>The Ethereum documentation describes this as a mathematical function:</p>
<blockquote>
<p><a target="_blank" href="https://ethereum.org/en/developers/docs/evm/#:~:text=The%20EVM%20behaves%20as%20a%20mathematical%20function%20would%3A%20Given%20an%20input%2C%20it%20produces%20a%20deterministic%20output.%20It%20therefore%20is%20quite%20helpful%20to%20more%20formally%20describe%20Ethereum%20as%20having%20a%20state%20transition%20function%3A">Given an input, it produces a deterministic output. It therefore is quite helpful to more formally describe Ethereum as having a <strong>state transition function</strong>:</a></p>
<p><code>Y(S, T)= S'2</code></p>
<p>Given an old valid state <code>(S)</code> and a new set of valid transactions <code>(T)</code>, the Ethereum state transition function <code>Y(S, T)</code> produces a new valid output state <code>S'</code></p>
</blockquote>
<h3 id="heading-high-level-languages-andamp-bytecode-compilation">High-Level Languages &amp; Bytecode Compilation</h3>
<p>As a developer on Ethereum, or any other EVM-compatible blockchain you're usually writing smart contracts in Solidity (although other languages like Vyper and Yul exist).</p>
<p>As with all other <a target="_blank" href="https://en.wikipedia.org/wiki/High-level_programming_language">high-level languages</a>, they're intended to be easily readable for humans, so we don't have to worry about the hard stuff like <a target="_blank" href="https://en.wikipedia.org/wiki/High-level_programming_language#:~:text=registers%2C%20memory%20addresses%2C%20and%20call%20stacks%2C%20high%2Dlevel%20languages%20deal%20with%20variables%2C%20arrays%2C%20objects%2C%20complex%20arithmetic%20or%20boolean%20expressions%2C%20subroutines%20and%20functions%2C%20loops%2C%20threads%2C%20locks%2C%20and%20other%20abstract%20computer%20science%20concepts%2C">registers, memory addresses, and call stacks</a>, and instead focus on usability.</p>
<p>However, machines don't understand this Solidity nonsense; the EVM included. The EVM understands <strong>bytecode</strong>, which is binary; machine-readable code.</p>
<p>The bytecode represents a series of EVM <a target="_blank" href="https://ethereum.org/en/developers/docs/evm/opcodes/"><strong>opcodes</strong></a><strong>,</strong> each of which performs a specific operation in the EVM; sometimes these opcodes are concerned with stack operations like <code>PUSH</code> (add to the stack), or <code>POP</code> (remove from the stack) but also handles blockchain-specific operations like <code>ADDRESS</code> and <code>BALANCE</code>.</p>
<blockquote>
<p>Each item is a 256-bit word, which was chosen for the ease of use with 256-bit cryptography (such as Keccak-256 hashes or secp256k1 signatures).</p>
</blockquote>
<p>As developers, this means we need a way to convert our smart contract code from <strong>Solidity</strong> → <strong>Opcodes</strong> → <strong>Bytecode</strong> in order for it to be executable by the EVM.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689131974700/4b33a549-f9ad-4503-a6dd-65f59d219c9a.png" alt class="image--center mx-auto" /></p>
<p>Luckily for us, there are <a target="_blank" href="https://ethereum.org/en/developers/docs/smart-contracts/compiling/">compilers</a> that do this for us.</p>
<h3 id="heading-compiling-smart-contracts">Compiling Smart Contracts</h3>
<p>Let's look at an example. I've got a very basic smart contract written in Solidity:</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.11;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Greeter</span> </span>{
    <span class="hljs-comment">// Internal state to the contract</span>
    <span class="hljs-keyword">string</span> <span class="hljs-keyword">private</span> greeting;

    <span class="hljs-comment">// Constructor - run when contract is deployed</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> _greeting</span>) </span>{
        greeting <span class="hljs-operator">=</span> _greeting;
    }

    <span class="hljs-comment">// Read function (can be called without a transaction)</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">greet</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">string</span> <span class="hljs-keyword">memory</span></span>) </span>{
        <span class="hljs-keyword">return</span> greeting;
    }

    <span class="hljs-comment">// Write function (requires a transaction to be called)</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setGreeting</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> _greeting</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        greeting <span class="hljs-operator">=</span> _greeting;

        <span class="hljs-keyword">emit</span> GreetingChanged(_greeting);
    }

    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">GreetingChanged</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> newGreeting</span>)</span>;
}
</code></pre>
<p>But, I have a problem. The EVM can't understand this Solidity! It needs bytecode... So, I'm going to use a compiler to help me out here; more specifically, for example, I can use the built-in compiler in the <a target="_blank" href="https://remix.ethereum.org/">Remix IDE</a> to help me.</p>
<p>After I compile it, I can inspect the opcodes that get compiled, reflecting the contents of my smart contract.</p>
<p><strong>Opcode:</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689132237785/34baf417-41af-454b-835e-c10cfafb07e1.png" alt class="image--center mx-auto" /></p>
<p>I can also inspect the bytecode that gets compiled from those opcodes.</p>
<p><strong>Bytecode:</strong></p>
<pre><code class="lang-markdown">60806040523480156200001157600080fd5b5060405162000c2938038062000c298339818101604052810190620000379190620001e3565b80600090816200004891906200047f565b505062000566565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620000b9826200006e565b810181811067ffffffffffffffff82111715620000db57620000da6200007f565b5b80604052505050565b6000620000f062000050565b9050620000fe8282620000ae565b919050565b600067ffffffffffffffff8211156200012157620001206200007f565b5b6200012c826200006e565b9050602081019050919050565b60005b83811015620001595780820151818401526020810190506200013c565b60008484015250505050565b60006200017c620001768462000103565b620000e4565b9050828152602081018484840111156200019b576200019a62000069565b5b620001a884828562000139565b509392505050565b600082601f830112620001c857620001c762000064565b5b8151620001da84826020860162000165565b91505092915050565b600060208284031215620001fc57620001fb6200005a565b5b600082015167ffffffffffffffff8111156200021d576200021c6200005f565b5b6200022b84828501620001b0565b91505092915050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200028757607f821691505b6020821081036200029d576200029c6200023f565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620003077fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002c8565b620003138683620002c8565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620003606200035a62000354846200032b565b62000335565b6200032b565b9050919050565b6000819050919050565b6200037c836200033f565b620003946200038b8262000367565b848454620002d5565b825550505050565b600090565b620003ab6200039c565b620003b881848462000371565b505050565b5b81811015620003e057620003d4600082620003a1565b600181019050620003be565b5050565b601f8211156200042f57620003f981620002a3565b6200040484620002b8565b8101602085101562000414578190505b6200042c6200042385620002b8565b830182620003bd565b50505b505050565b600082821c905092915050565b6000620004546000198460080262000434565b1980831691505092915050565b60006200046f838362000441565b9150826002028217905092915050565b6200048a8262000234565b67ffffffffffffffff811115620004a657620004a56200007f565b5b620004b282546200026e565b620004bf828285620003e4565b600060209050601f831160018114620004f75760008415620004e2578287015190505b620004ee858262000461565b8655506200055e565b601f1984166200050786620002a3565b60005b8281101562000531578489015182556001820191506020850194506020810190506200050a565b868310156200055157848901516200054d601f89168262000441565b8355505b6001600288020188555050505b505050505050565b6106b380620005766000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063a41368621461003b578063cfae321714610057575b600080fd5b610055600480360381019061005091906102ab565b610075565b005b61005f6100bf565b60405161006c9190610373565b60405180910390f35b806000908161008491906105ab565b507f58c1144814f1df01a80f7347f945437a37cd818e027f87b0ade6db623ec41b57816040516100b49190610373565b60405180910390a150565b6060600080546100ce906103c4565b80601f01602080910402602001604051908101604052809291908181526020018280546100fa906103c4565b80156101475780601f1061011c57610100808354040283529160200191610147565b820191906000526020600020905b81548152906001019060200180831161012a57829003601f168201915b5050505050905090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6101b88261016f565b810181811067ffffffffffffffff821117156101d7576101d6610180565b5b80604052505050565b60006101ea610151565b90506101f682826101af565b919050565b600067ffffffffffffffff82111561021657610215610180565b5b61021f8261016f565b9050602081019050919050565b82818337600083830152505050565b600061024e610249846101fb565b6101e0565b90508281526020810184848401111561026a5761026961016a565b5b61027584828561022c565b509392505050565b600082601f83011261029257610291610165565b5b81356102a284826020860161023b565b91505092915050565b6000602082840312156102c1576102c061015b565b5b600082013567ffffffffffffffff8111156102df576102de610160565b5b6102eb8482850161027d565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561032e578082015181840152602081019050610313565b60008484015250505050565b6000610345826102f4565b61034f81856102ff565b935061035f818560208601610310565b6103688161016f565b840191505092915050565b6000602082019050818103600083015261038d818461033a565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806103dc57607f821691505b6020821081036103ef576103ee610395565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026104577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8261041a565b610461868361041a565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006104a86104a361049e84610479565b610483565b610479565b9050919050565b6000819050919050565b6104c28361048d565b6104d66104ce826104af565b848454610427565b825550505050565b600090565b6104eb6104de565b6104f68184846104b9565b505050565b5b8181101561051a5761050f6000826104e3565b6001810190506104fc565b5050565b601f82111561055f57610530816103f5565b6105398461040a565b81016020851015610548578190505b61055c6105548561040a565b8301826104fb565b50505b505050565b600082821c905092915050565b600061058260001984600802610564565b1980831691505092915050565b600061059b8383610571565b9150826002028217905092915050565b6105b4826102f4565b67ffffffffffffffff8111156105cd576105cc610180565b5b6105d782546103c4565b6105e282828561051e565b600060209050601f8311600181146106155760008415610603578287015190505b61060d858261058f565b865550610675565b601f198416610623866103f5565b60005b8281101561064b57848901518255600182019150602085019450602081019050610626565b868310156106685784890151610664601f891682610571565b8355505b6001600288020188555050505b50505050505056fea2646970667358221220a1f816fe7c07bf6a147b15ff4e1b591d0b43aca9fc57c8ddaecce27d5fe6f5fa64736f6c63430008120033
</code></pre>
<p>The final bytecode you see there is what would be understood by the EVM. So you can imagine why developers want to use high-level languages rather than write the bytecode themselves.</p>
<p>What we can do now is actually match up exactly what's happening in the bytecode to the opcodes. Let's take a look at the first three opcodes, <code>PUSH 80</code>, <code>PUSH 40</code>, and <code>MSTORE</code>.</p>
<p>I've matched up the first 10 hexadecimal values of the byte code to the first 3 opcodes we see below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689144063097/892c089e-a043-4db7-8e37-492ae0a7a95c.png" alt class="image--center mx-auto" /></p>
<ol>
<li><p><code>PUSH 80</code> / <code>6080</code>: Pushes the value 80 (hexadecimal) onto the stack.</p>
</li>
<li><p><code>PUSH 40</code> / <code>6040</code>: Pushes the value 40 (hexadecimal) onto the stack.</p>
</li>
<li><p><code>MSTORE</code> / 52: Stores the second stack item (40) at the memory location specified by the first stack item (80).</p>
</li>
</ol>
<p>We can do this matching process because Ethereum <a target="_blank" href="https://ethereum.org/en/developers/docs/evm/opcodes/">documents each opcode</a> corresponding to its bytecode value:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689133522647/cc1c71cf-aabb-4ee9-99c6-64d70ea14d70.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-why-do-opcodes-or-the-evm-matter">Why do Opcodes or the EVM Matter?</h3>
<p>The challenge of building an EVM-compatible rollup is that <a target="_blank" href="https://vitalik.ca/general/2022/08/04/zkevm.html#:~:text=Ethereum%20was%20not%20originally%20designed%20around%20ZK%2Dfriendliness%2C%20so%20there%20are%20many%20parts%20of%20the%20Ethereum%20protocol%20that%20take%20a%20large%20amount%20of%20computation%20to%20ZK%2Dprove">Ethereum was not originally designed around ZK-friendliness, so there are <em>many</em> parts of the Ethereum protocol that take a large amount of computation to ZK-prove</a>.</p>
<p>Specific opcodes executed by an EVM are more "ZK-unfriendly" than others, and this had led to variance in the level of EVM-compatibility companies have chosen to adopt in their ZK-EVM products.</p>
<p>For example, some have opted for full equivalency for every EVM opcode, some have slight modifications to some opcodes, and some actually embrace producing completely different bytecode while maintaining high-level-language equivalence.</p>
<p>Below, I'll explore the different approaches each ZK-EVM has made and the tradeoffs each of them makes between performance (how fast they can generate ZK proofs) and their level of EVM compatibility.</p>
<h2 id="heading-different-kinds-of-zk-evms">Different Kinds of ZK-EVMs</h2>
<p>Vitalik made a blog post in August 2022 categorizing ZK-EVMs into four (and a half) different categories, titled "<a target="_blank" href="https://vitalik.ca/general/2022/08/04/zkevm.html">The different kinds of zkEVMs</a>". I'll be summarising this information below, but I'd recommend reading the full post too.</p>
<p>In the post, Vitalik charts the different types according to their EVM compatibility and ZK-proof generation times (performance). <a target="_blank" href="https://vitalik.ca/general/2022/08/04/zkevm.html#:~:text=Overview%20(in%20chart%20form)">View original image</a>:</p>
<p><img src="https://vitalik.ca/images/zkevm/chart.png" alt /></p>
<p>To simplify this, in my opinion, we can place ZK-EVMs on a single line:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689143132612/9132e089-c71e-45f2-bf98-888d2ec339e1.png" alt class="image--center mx-auto" /></p>
<p>According to Vitalik, ZK-EVMs come in 4.5 different categorizations:</p>
<ul>
<li><p><strong>Type 1:</strong> Fully Ethereum equivalent, i.e. they do not change any part of the Ethereum system to make it easier to generate proofs. ZK proofs take several hours to generate in this kind of system.</p>
</li>
<li><p><strong>Type 2:</strong> Fully EVM-equivalent, but changes some different internal representations like how they store the state of the chain, for the purpose of improving ZK-proof generation times.</p>
</li>
<li><p><strong>Type 2.5:</strong> Fully EVM-equivalent, except they increase the gas costs of some operations to "significantly improve worst-case prover times".</p>
</li>
<li><p><strong>Type 3:</strong> Almost EVM-equivalent ZK-EVMs make sacrifices in exact equivalence to further enhance prover times and simplify EVM development.</p>
</li>
<li><p><strong>Type 4:</strong> High-level language equivalent ZK-EVMs compile smart contract source code written in a high-level language to a ZK-SNARK-friendly language, resulting in faster prover times but potentially introducing incompatibilities and limitations.</p>
</li>
</ul>
<h2 id="heading-companies-building-zk-evms">Companies Building ZK-EVMs</h2>
<p>Below, I'll show you the current landscape of all the different types of ZK-EVMs being built by various companies; including Taiko, Linea, Polygon, Scroll, and zkSync (plus a special bonus guest). I'll also be trying out each of the ZK-EVMs from a developer perspective.</p>
<p>For a fair test, I'll be using <a target="_blank" href="https://evmkit.com/">EVM Kit</a> as my starting point for each; a full-stack boilerplate setup for creating web3 applications (<a target="_blank" href="https://www.youtube.com/watch?v=smsAOtkM7nY">learn more</a>), including both smart contracts and web apps.</p>
<p>From a new EVM Kit project, I'll first deploy a <a target="_blank" href="https://github.com/jarrodwatts/evmkit/blob/main/template/contracts/contracts/Greeter.sol">basic smart contract</a> written in Solidity &amp; built in a <a target="_blank" href="https://hardhat.org/">Hardhat</a> environment to each of the different ZK-EVMs we have explored to review the developer experience of writing smart contracts.</p>
<p>Second, I'll deploy an <a target="_blank" href="https://thirdweb.com/thirdweb.eth/TokenERC721">NFT collection</a> smart contract to each, and mint some NFTs to see the gas price of interacting with common EIP standards on each chain as well.</p>
<p>We'll go through each in order of their "type", starting from type 1 and working our way up to type 4.</p>
<p>First up, we have Taiko at type 1.</p>
<h3 id="heading-taiko">Taiko</h3>
<p><em>Note: Taiko is currently in the testnet phase.</em></p>
<p>Taiko is a type 1 ZK-EVM, meaning it replicates all of Ethereum's behaviour exactly the same, using the same hash functions, gas prices, encryption algorithms, etc. <em>except</em> Taiko currently handles <a target="_blank" href="https://www.youtube.com/watch?v=cbAYOsp8CTA&amp;t=2717s"><strong>two Ethereum Improvement Proposals</strong></a> differently.</p>
<p>The primary <strong>benefits</strong> of this architecture are:</p>
<ul>
<li><p>The development process is identical to using Ethereum.</p>
</li>
<li><p>Taiko re-uses a lot of Ethereum infrastructure such as the node client software, making it very familiar to Ethereum users.</p>
</li>
<li><p>There are no changes to hash functions or gas costs.</p>
</li>
</ul>
<p>Taiko's approach is to fully optimize for EVM-equivalency, which comes at the cost of a large time to generate ZK proofs that get posted back to Ethereum.</p>
<p>The Taiko L2 uses the same rules of Ethereum to determine the new state of the rollup; <a target="_blank" href="https://taiko.xyz/docs/concepts/proposing">immediately and deterministically</a> after a block is proposed.</p>
<p>The drawback to this is slow ZK proof generation time, which is required to give <a target="_blank" href="https://taiko.xyz/docs/concepts/proving#:~:text=to%20give%20certainty%20to%20bridges%20about%20the%20execution%20that%20happened%20in%20the%20rollup">certainty about the execution that happened on the rollup</a> to bridges; meaning you won't be able to bridge funds back to Ethereum L1 until that proof is generated.</p>
<h4 id="heading-deploying-to-taiko-zk-evm-testnet">Deploying to Taiko ZK-EVM (Testnet)</h4>
<p>Since Taiko has not released their mainnet at the time of writing this, I'll be using the "Taiko Alpha-3 Testnet" throughout this process. First, I got myself some testnet funds from the <a target="_blank" href="https://sepoliafaucet.com/">Sepolia Faucet</a> and sent funds over to Taiko using <a target="_blank" href="https://bridge.test.taiko.xyz/#/">Taiko's Bridge</a>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688971650182/023cdc3d-aa43-412b-b9b7-81b29c5de3ee.png" alt class="image--center mx-auto" /></p>
<p>Once I'm across the bridge, the development process is identical to using Ethereum. The only change I make is to transform my RPC from an Ethereum RPC to the Taiko RPC. Below is the information about the chain ID and RPC I used for this process:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Chain ID</td><td>RPC</td></tr>
</thead>
<tbody>
<tr>
<td><strong>167005</strong></td><td><a target="_blank" href="https://taiko-alpha-3-testnet.rpc.thirdweb.com">https://taiko-alpha-3-testnet.rpc.thirdweb.com</a></td></tr>
</tbody>
</table>
</div><p>I was easily able to deploy my basic Solidity smart contract and perform both read and write operations on it as seen from the Taiko block explorer:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689037994640/f406ca8a-c8c7-4890-9821-f8b7efd7184e.png" alt class="image--center mx-auto" /></p>
<p>The process of deploying an <a target="_blank" href="https://thirdweb.com/taiko-alpha-3-testnet/0x9845b3d0907dF271ebeD2bd789DC9890D9f935a4/nfts">NFT collection</a> and minting my first Taiko NFT was also seamless, and worked exactly as I'd expect when working with Ethereum:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689038490328/e0b00e64-8756-44cf-9ae7-a31981c838c4.png" alt class="image--center mx-auto" /></p>
<p>As I mentioned previously, the drawback of Taiko is that the ZK proof generation process is very lengthy, which means I am unable to bridge my ETH back to Ethereum L1 for several hours:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689037757454/dc43b0e4-a399-4e2c-90ac-b83c8f1f5928.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>Your asset [<em>my ETH]</em> is not ready to be claimed. Taiko =&gt; Sepolia bridging can take several hours before being ready.</p>
</blockquote>
<p>Below is the summary of my interactions with Taiko:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Contract Interaction</strong></td><td><strong>Gas Fee (in ETH)</strong></td><td><strong>Gas Fee (USD)</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Deploy Greeter Solidity smart contract</td><td>0.000413119500275413</td><td>$0.78</td></tr>
<tr>
<td>Run "setGreeting" function</td><td>0.00004744500003163</td><td>$0.089</td></tr>
<tr>
<td>Deploy NFT Collection (via proxy)</td><td>0.001124796000749864</td><td>$2.12</td></tr>
<tr>
<td>Mint NFT</td><td>0.00030571500020381</td><td>$0.58</td></tr>
<tr>
<td>Bridge funds back to ETH L1</td><td>0.000194796000129864</td><td>$0.37</td></tr>
</tbody>
</table>
</div><p>Keep in mind, these were all on Taiko's testnet and these numbers will be different than when Taiko launches their mainnet in the future.</p>
<h3 id="heading-linea-consensys-zk-evm">Linea (Consensys ZK-EVM)</h3>
<p><em>Note: Linea is in the process of releasing</em> <a target="_blank" href="https://linea.mirror.xyz/7l9gKzYzKVOxEOnReavov467Ss_fsrkGzABvbRISPMY">their mainnet</a> later this month (July 2023)!</p>
<p>Linea's <a target="_blank" href="https://linea.mirror.xyz/qD18IaQ4BROn_Y40EBMTUTdJHYghUtdECscSWyMvm8M">original announcement</a> planned to release a <a target="_blank" href="https://linea.mirror.xyz/qD18IaQ4BROn_Y40EBMTUTdJHYghUtdECscSWyMvm8M#:~:text=of%20the%20cost.-,As%20a%20Type%202%20zkEVM,-%2C%20Linea%20prioritizes%20compatibility">type 2 ZK-EVM</a>, however, their current release is a type 3 ZK-EVM working towards a type 2. As outlined in their <a target="_blank" href="https://docs.linea.build/risk-disclosures">risk disclosure documentation</a>, Linea does not currently prove all EVM opcodes:</p>
<blockquote>
<p>The validity proofs used to verify the computation of Linea batches do not prove 100% of EVM opcodes and precompiles</p>
</blockquote>
<p>In addition, their documentation states the "<a target="_blank" href="https://docs.linea.build/decentralization-roadmap">proofs of computation for all EVM opcodes and precompiles</a>" will come in phase 1 of their improvements as outlined in their roadmap:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689146259692/7ae29645-91ef-440d-95fa-95cfeb257276.png" alt class="image--center mx-auto" /></p>
<p>Linea also deviates from Ethereum in how it <a target="_blank" href="https://youtu.be/W2f_GLEtobo?t=270">represents the state of the chain</a>. For instance, <a target="_blank" href="https://vitalik.ca/general/2022/08/04/zkevm.html#:~:text=Particularly%2C%20they%20might%20change%20Ethereum%27s%20Keccak">keccak</a>, a hashing function used by Ethereum has been changed for a more ZK-friendly alternative. Despite this internal difference, you're deploying the same smart contract bytecode to Linea that you would deploy if you were using Ethereum.</p>
<h4 id="heading-deploying-to-linea-testnet">Deploying to Linea (Testnet)</h4>
<p>Once I secured myself some Goerli testnet ETH <em>(which was a slight mission)</em>, I headed over to the <a target="_blank" href="https://bridge.goerli.linea.build/">Linea bridge</a> to bridge ETH to the Linea testnet.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689140230708/54631931-d915-4c24-8eca-7a9f9f4967a9.png" alt class="image--center mx-auto" /></p>
<p>Once I successfully bridge my funds across, the development process is the same as Ethereum. Everything worked as expected with my <a target="_blank" href="https://explorer.goerli.linea.build/address/0x33341719456e9d506bcFDbC3afcC5A6882230566">Greeter</a> smart contract:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689214749535/2aebc49f-8cac-4eb2-a2d0-4592ef75cf2a.png" alt class="image--center mx-auto" /></p>
<p>And I was easily able to deploy the <a target="_blank" href="https://explorer.goerli.linea.build/address/0x55176673F1D055E95891a5A954e6b2B0C5DEc067">NFT collection</a> and mint my first Linea NFT:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689214767106/ffe7caa1-075c-4277-a486-4e5d1f5ed491.png" alt class="image--center mx-auto" /></p>
<p>The bridge UI from Linea isn't currently available, but you can call the <code>sendMessage</code> function on their <a target="_blank" href="https://goerli.lineascan.build/address/0xC499a572640B64eA1C8c194c43Bc3E19940719dC#writeProxyContract">bridge smart contract</a> directly. According to the Linea documentation, the bridging of ETH from L2 back to L1 takes ~15 minutes, but it took several hours during my testing.</p>
<p>Below is the summary of my interactions with Linea:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Contract Interaction</strong></td><td><strong>Gas Fee (in ETH)</strong></td><td><strong>Gas Fee (USD)</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Deploy Greeter Solidity smart contract</td><td>0.000466914075602163</td><td>$0.87</td></tr>
<tr>
<td>Run "setGreeting" function</td><td>0.000053601071759034</td><td>$0.10</td></tr>
<tr>
<td>Deploy NFT Collection (via proxy)</td><td>0.001233567189763232</td><td>$2.31</td></tr>
<tr>
<td>Mint NFT</td><td>0.000096778500451633</td><td>$0.61</td></tr>
<tr>
<td>Bridge funds back to ETH L1</td><td>0.000096778500451633</td><td>$0.18</td></tr>
</tbody>
</table>
</div><p>These were all very similar prices to Taiko; but again, are testnet values!</p>
<h3 id="heading-polygon-zkevm">Polygon zkEVM</h3>
<p><em>Disclaimer: At the time of writing this, I currently work at Polygon Labs. There may be some unconscious bias for this reason.</em></p>
<p>Polygon zkEVM is currently a type 3 ZK-EVM, with a small number of changes required before transforming into a type 2 ZK-EVM. You can view the <a target="_blank" href="https://zkevm.polygon.technology/docs/protocol/evm-diff/#opcodes">opcodes</a>, <a target="_blank" href="https://zkevm.polygon.technology/docs/protocol/evm-diff/#precompiled-contracts">precompiled contracts</a>, and <a target="_blank" href="https://zkevm.polygon.technology/docs/protocol/evm-diff/#other-minor-differences">other minor differences</a> Polygon zkEVM transparently lists in the documentation that are different from the EVM's behaviour.</p>
<p>With these tradeoffs in equivalency to the EVM's behaviour, Polygon zkEVM is able to generate and post ZK proofs in just a few minutes; allowing you to bridge your funds back to Ethereum L1 in around <a target="_blank" href="https://twitter.com/jbaylina/status/1629352613178122240">~30 minutes</a> after interacting with the zkEVM.</p>
<p>With Polygon zkEVM, you're deploying the same bytecode as you would with Ethereum, however, the interpretation process of this bytecode is slightly different.</p>
<p>EVM Bytecodes are interpreted using a <strong>zero-knowledge Assembly language</strong> (zkASM), specially developed by the Polygon zkEVM team. In Vitalik's blog post, he mentions this:</p>
<blockquote>
<p>Polygon has a unique design where they are ZK-verifying their own internal language called <a target="_blank" href="https://github.com/0xPolygonHermez/zkevm-doc/blob/main/mkdocs/docs/zkEVM/zkASM/Introduction.md">zkASM</a>, and they interpret ZK-EVM code using the zkASM implementation. Despite this implementation detail, I would still call this a genuine Type 3 ZK-EVM; it can still verify EVM code, it just uses some different internal logic to do it.</p>
</blockquote>
<p>The polygon engineering team has also stated they'll complete the remaining precompiles to become type 2 in addition to improving the proof generation &amp; withdrawal times very soon.</p>
<h4 id="heading-deploying-to-polygon-zkevm">Deploying to Polygon zkEVM</h4>
<p>Polygon zkEVM mainnet beta launched in March 2023, so I'll be using mainnet funds for this process. First, I used the <a target="_blank" href="https://wallet.polygon.technology/zkEVM-Bridge/bridge">Polygon bridge</a> to ship my funds across to the zkEVM. The gas fee for this process was around $5 USD and took ~5 minutes for the funds to arrive on the L2.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689219034092/570e8a2d-e2bf-47bd-aa23-acd5b40652ee.png" alt class="image--center mx-auto" /></p>
<p>Just like the previous two chains, it's seamless and behaves as I'd expect Ethereum to. I was easily able to deploy my <a target="_blank" href="https://zkevm.polygonscan.com/address/0xf6e11008c1b42CD58Db567D576f1133604D79EeE">Greeter smart contract</a> and call the functions on it as well as deploy an <a target="_blank" href="https://zkevm.polygonscan.com/address/0xD9558758B72a98ec382889041CF5944e12257Cd3">NFT Collection</a> &amp; mint an NFT:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689219017062/4a1cd631-930c-4fc1-9ba7-3335b7303c44.png" alt class="image--center mx-auto" /></p>
<p>The bridging process back to Ethereum L1 took ~60 minutes and was another $5 to claim my funds back into Ethereum mainnet.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689221108313/ff1f5775-3cf0-47de-b85b-20eb46d985e0.png" alt class="image--center mx-auto" /></p>
<p>If you're looking to build on the Polygon zkEVM, consider checking out my guide below taking you through the full process in less than 10 minutes:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://blog.jarrodwatts.com/the-ultimate-guide-to-building-on-polygon-zkevm">https://blog.jarrodwatts.com/the-ultimate-guide-to-building-on-polygon-zkevm</a></div>
<p> </p>
<h3 id="heading-scroll">Scroll</h3>
<p><em>Note</em>: <em>Scroll is currently in the testnet phase.</em></p>
<p>Similar to Polygon zkEVM, Scroll is currently a type 3 ZK-EVM working towards being a type 2, with transparent documentation on the <a target="_blank" href="https://guide.scroll.io/developers/ethereum-and-alpha-testnet-differences#evm-opcodes">opcodes</a>, <a target="_blank" href="https://guide.scroll.io/developers/ethereum-and-alpha-testnet-differences#evm-precompiles">precompiles</a>, and <a target="_blank" href="https://guide.scroll.io/developers/ethereum-and-alpha-testnet-differences">other differences</a> from Ethereum defined in their documentation. The scroll docs outline:</p>
<blockquote>
<p>For the average Solidity developer, these details won't affect your development experience.</p>
</blockquote>
<p>On the Scroll blog, they have also listed the exact work remaining to release their mainnet - see <a target="_blank" href="https://hackmd.io/@haichen/ryukZaYAs"><strong>Scroll zkEVM next steps</strong></a>.</p>
<h4 id="heading-deploying-to-scroll">Deploying to Scroll</h4>
<p>Just like the previous chains we've explored so far, Scroll is able to execute the same native bytecode that you would deploy to Ethereum, meaning there's no change in the development process.</p>
<p>I'm easily able to bridge funds to the Scroll testnet via their <a target="_blank" href="https://scroll.io/bridge">bridge UI</a>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689221302569/5fcbec80-83a1-4d2b-b2c4-005901eb0e48.png" alt class="image--center mx-auto" /></p>
<p>The estimated time to bridge funds to the L2 is between <a target="_blank" href="https://guide.scroll.io/user-guide/bridge/deposit-from-goerli-to-scroll">8-14 minutes</a>, and it took 10 minutes for me to be able to use them on the L2.</p>
<p>Everything acts the same way as I'd expect Ethereum to, and I was easily able to deploy my <a target="_blank" href="https://blockscout.scroll.io/address/0x33341719456e9d506bcFDbC3afcC5A6882230566">Greeter smart contract</a> and my <a target="_blank" href="https://blockscout.scroll.io/address/0xAFaC6630050338c17F9765D40f35F4255dA5D599">NFT collection</a> again:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689222300172/15a76783-4223-4f03-928d-22bdc35badf8.png" alt class="image--center mx-auto" /></p>
<p>Bridging funds back to Ethereum L1 is estimated to take between <a target="_blank" href="https://guide.scroll.io/user-guide/bridge/withdraw-from-scroll-to-goerli#:~:text=10%20minutes%20to%20a%20few%20hours">10 minutes to a few hours</a> according to the Scroll documentation <em>(unfortunately I missed exactly how long it took in my case)</em>.</p>
<p>Below is the summary of my transactions on the Scroll testnet. During my testing, the gas fees seemed to be significantly cheaper than the previous chains we explored, although I'm not sure of the exact reason for why this was the case:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Contract Interaction</strong></td><td><strong>Gas Fee (in ETH)</strong></td><td><strong>Gas Fee (USD)</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Deploy Greeter Solidity smart contract</td><td>0.000000275329</td><td>$0.00051</td></tr>
<tr>
<td>Run "setGreeting" function</td><td>0.000000031618</td><td>$0.000059</td></tr>
<tr>
<td>Deploy NFT Collection (via proxy)</td><td>0.000000749896</td><td>$0.0014</td></tr>
<tr>
<td>Mint NFT</td><td>0.00000020381</td><td>$0.00038</td></tr>
<tr>
<td>Bridge funds back to ETH L1</td><td>0.000000261872</td><td>$0.00049</td></tr>
</tbody>
</table>
</div><h3 id="heading-zksync-era">zkSync Era</h3>
<p>zkSync Era is a type 4 ZK-EVM, and the experience is quite different from the other products we've explored so far.</p>
<p>Era embraces the fact that the smart contract bytecode that gets deployed for their zkEVM is not the same as Ethereum; and this large difference enables their product to have unique offerings, such as <a target="_blank" href="https://era.zksync.io/docs/reference/concepts/account-abstraction.html#account-abstraction">native account abstraction</a>.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://blog.jarrodwatts.com/what-is-account-abstraction-and-how-does-eip-4337-work">https://blog.jarrodwatts.com/what-is-account-abstraction-and-how-does-eip-4337-work</a></div>
<p> </p>
<p>These base changes in capability come with differences in developer experience, but as Vitalik defined; still allows you to work with the same high-level languages such as Solidity.</p>
<p>Era comes with a set of <a target="_blank" href="https://era.zksync.io/docs/dev/building-on-zksync/best-practices.html">best practices and considerations</a> for where you might run into different behaviours than when interacting with Ethereum and requires some slight adjustments in your development setup.</p>
<p>For example, I needed to install an additional Hardhat extension and add one additional flag to my Hardhat configuration to compile the required bytecode for the chain:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689223926120/29158774-947d-4a59-8c3b-b3a7803bed7e.png" alt class="image--center mx-auto" /></p>
<p>In the compilation process, the bytecode that gets generated for you to work with zkSync is different than the bytecode that gets generated by default:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689223999548/f8ecd67a-bd39-40af-9181-aa73a61bd5fe.png" alt class="image--center mx-auto" /></p>
<p>Existing deploy tooling like <a target="_blank" href="https://thirdweb.com/deploy">thirdweb deploy</a> (used in <a target="_blank" href="https://www.evmkit.com/">EVM Kit</a>) has support for this bytecode by providing the <code>--zksync</code> flag to the <code>deploy</code> command.</p>
<p>Overall, it's quite a small amount of changes required to use Solidity and my standard development environment to cooperate with zkSync.</p>
<h4 id="heading-deploying-to-zksync-era">Deploying to zkSync Era</h4>
<p>Using zkSync's <a target="_blank" href="https://bridge.zksync.io/">bridge</a>, it's estimated about ~15 minutes for the funds to arrive on L2.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689224304083/312923a6-81d6-4fd7-9840-cff681310107.png" alt class="image--center mx-auto" /></p>
<p>After this point, the process is the same! I'm able to deploy my <a target="_blank" href="https://explorer.zksync.io/address/0x4B4074312FEe60b6D88Aa650dB55a49055f9C0ed">Greeter smart contract</a>, as well as my usual <a target="_blank" href="https://explorer.zksync.io/address/0x19Ca6599D55606782a77A7f663101b61Cf9519De">NFT collection</a> with an NFT minted:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689244997861/06c275e6-ff42-46b7-8807-ca6365bd9df7.png" alt class="image--center mx-auto" /></p>
<p>Currently, bridging funds back to Ethereum L1 from zkSync Era has a 24-hour delay:</p>
<blockquote>
<p>To ensure security in the first days of the protocol, there is a 24 hour delay on withdrawals from zkSync Era (L2) to Ethereum (L1). See our <a target="_blank" href="https://blog.matter-labs.io/securing-zksync-era-execution-delay-ee32b11d6f9">blog post</a> for more details.</p>
</blockquote>
<p>Here's the summary of my interactions on zkSync Era:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td></td><td><strong>Gas Fee (in ETH)</strong></td><td><strong>Gas Fee (USD)</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Deploy Greeter Solidity smart contract</td><td>0.001839549</td><td>$3.47</td></tr>
<tr>
<td>Run "setGreeting" function</td><td>0.00007822825</td><td>$0.15</td></tr>
<tr>
<td>Deploy NFT Collection (via proxy)</td><td>0.0007640925</td><td>$1.44</td></tr>
<tr>
<td>Mint NFT</td><td>0.0002108245</td><td>$0.40</td></tr>
<tr>
<td>Bridge funds back to ETH L1</td><td>0.000140764</td><td>$0.27</td></tr>
</tbody>
</table>
</div><h3 id="heading-bonus-guest-kakarot">Bonus Guest: Kakarot</h3>
<p>Just last month, a new zkEVM called <a target="_blank" href="https://www.kakarot.org/">Kakarot</a> written in <a target="_blank" href="https://github.com/starkware-libs/cairo-lang">Cairo</a> was announced, which aims to <a target="_blank" href="https://book.starknet.io/chapter_2/kakarot.html">bring EVM compatibility to Starknet</a> as a type 2.5 ZK-EVM, however, is considered a type 3 in its current state.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689227897936/8c2bcf8a-26c3-441c-a432-f263833d10e1.png" alt class="image--center mx-auto" /></p>
<p>While it does has a very cool name and landing page, it also received funding from Vitalik himself, among others including Starkware.</p>
<p>The testnet has not yet been released but is planned to release later in 2023, and their development team has provided the <a target="_blank" href="https://book.starknet.io/chapter_2/kakarot.html">following update</a>:</p>
<blockquote>
<p>The Kakarot team achieved an impressive milestone (with the support of the Starknet Foundation and the collaborative efforts of over 40 unique contributors) by implementing 100% of EVM opcodes and 8 out of 9 EVM precompiles in just six months and with less than 5,000 lines of code!</p>
</blockquote>
<h2 id="heading-whats-the-future-will-one-chain-win">What's the future? Will One Chain Win?</h2>
<p>Rather than it being a battle about which chain is the best, it's overall good for the improvement of Ethereum and web3 that so many different approaches are being explored; each with their own pros and cons.</p>
<p>Vitalik also has explained his "multi-prover theory", where rollups could potentially collaborate together to enhance the security of the whole ecosystem, among other alternatives to the future of ZK-EVMs.</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=6hfVzCWT6YI">https://www.youtube.com/watch?v=6hfVzCWT6YI</a></div>
<p> </p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>That's the landscape of ZK-EVMs today, at least as I understand it!</p>
<p>You can find the summary below of the companies working in the space, and the types of ZK-EVM their respective products currently are:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689383613765/a3c7accc-e247-4754-8c7c-c4e45ebba554.png" alt class="image--center mx-auto" /></p>
<p>If you're looking to build on ZK-EVMs, consider checking out my guide to creating full-stack applications on the Polygon zkEVM 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://blog.jarrodwatts.com/the-ultimate-guide-to-building-on-polygon-zkevm">https://blog.jarrodwatts.com/the-ultimate-guide-to-building-on-polygon-zkevm</a></div>
<p> </p>
<p>Thanks for reading! Follow me on <a target="_blank" href="https://twitter.com/jarrodWattsDev">Twitter</a> for more!</p>
]]></content:encoded></item><item><title><![CDATA[How ZK Proofs & zkEVMs Work (without the math)]]></title><description><![CDATA[Zero-knowledge (ZK) proofs are powering the most recent innovations in web3. They're already being used in products such as Polygon's zkEVM to bring verifiable scalability to Ethereum, and Polygon ID to verify pieces of your identity without revealin...]]></description><link>https://blog.jarrodwatts.com/how-zk-proofs-and-zkevms-work</link><guid isPermaLink="true">https://blog.jarrodwatts.com/how-zk-proofs-and-zkevms-work</guid><category><![CDATA[Polygon]]></category><category><![CDATA[Ethereum]]></category><category><![CDATA[zero-knowledge-proofs]]></category><category><![CDATA[Cryptocurrency]]></category><category><![CDATA[Web3]]></category><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Wed, 28 Jun 2023 06:21:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1687923566261/704ae11a-ceb9-442b-9d10-c305ac5f5649.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Zero-knowledge (ZK) proofs are powering the most recent innovations in web3. They're already being used in products such as <a target="_blank" href="https://polygon.technology/polygon-zkevm">Polygon's zkEVM</a> to bring verifiable scalability to Ethereum, and <a target="_blank" href="https://polygon.technology/polygon-id">Polygon ID</a> to verify pieces of your identity without revealing any personal information.</p>
<p>In one sentence: <strong>ZK proofs allow you to prove something without revealing the thing itself</strong>. This has several real-world applications, such as verifying your age without providing your full license/passport information.</p>
<p>But how does this <em>actually</em> work? What's happening behind the scenes to make this possible? In this post, I'll cover everything you need to know about ZK proofs, but leave out the math.</p>
<p>Let's do it!</p>
<h2 id="heading-how-does-a-zk-proof-work">How Does a ZK Proof Work?</h2>
<p>To prove the validity of a statement without revealing the statement itself, there are two parties involved:</p>
<ol>
<li><p>The <strong>Prover</strong>: the person trying to prove something.</p>
</li>
<li><p>The <strong>Verifier</strong>: the person trying to validate the claim is "real".</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687824004048/f9e82d8f-5143-437c-9d22-9283ec70a266.png" alt class="image--center mx-auto" /></p>
<p>Sometimes, there is a third party involved, an <strong>issuer</strong>, who grants the prover a certificate (such as a license) to the prover, whom the verifier trusts as a source of information.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687824122301/b20178cf-6b58-4044-ba2b-a2ec59aee8ae.png" alt class="image--center mx-auto" /></p>
<p>Let's look at an example... I'd like to prove to a website that I am above the age of 18, <em>without</em> uploading a picture of my passport. In this situation, there are:</p>
<ul>
<li><p>The <strong>Prover:</strong> Me, the individual trying to prove I am of legal age.</p>
</li>
<li><p>The <strong>Verifier:</strong> The website owner, trying to verify that I am of legal age.</p>
</li>
<li><p>The <strong>Issuer</strong>: The government, that provides me with a passport; a document that the website owner trusts to prove my age.</p>
</li>
</ul>
<p>Typically, I'd need to upload screenshots of my entire passport to the website, (something I <em>really</em> don't want to do), just to prove that I'm over 18.</p>
<p>A fun example made by <a target="_blank" href="https://twitter.com/0ceans404">Steph</a> is applying this to Spongebob. Spongebob wants to prove that his name is in fact Spongebob, but in order to do that, he needs to provide his full license to the verifier (the police officer... or I guess, police fish).</p>
<p>His license contains sensitive information like his DOB, address, gender, and more; all of which isn't necessary to prove his name; but, alas, he has no other choice.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687824744966/2913aab9-f31e-4c1d-8aaa-bdb0bf1899de.png" alt class="image--center mx-auto" /></p>
<p>It would be so much better if Spongebob could prove his name, or if I could somehow prove that I'm over 18, <em>without</em> needing to hand over so much sensitive information.</p>
<p>This is a prime example of how ZK proofs provide real value to the world. With ZK proofs, I am now able to prove a part of my identity <em>(or anything else)</em> to a verifier without providing any aspect of my identity, or any supporting documents to prove that fact.</p>
<p>This way, I never transfer sensitive personal information to a third party to be stored in a database; vulnerable to attacks and leaks; something we currently risk almost every time we sign up for a website.</p>
<p>This all sounds great. But how do you prove something without revealing anything about it? For this, we can dive deeper into what ZK proofs are.</p>
<h2 id="heading-what-makes-up-a-zk-proof">What Makes Up A ZK Proof?</h2>
<p>So, we want to prove something, without revealing how we know that thing, or what that thing even is. How is that possible?</p>
<p>Before we can answer that, ZK proofs come in two broad categories:</p>
<ol>
<li><p>Interactive</p>
</li>
<li><p>Non-interactive</p>
</li>
</ol>
<p>The ones we care about in web3 are non-interactive, but let's quickly touch on what "interactivity" refers to in the context of ZK.</p>
<h3 id="heading-interactive-zk-proofs">Interactive ZK Proofs</h3>
<p>Imagine that there's a ring-shaped cave with a gate inside that requires a secret password to enter through.</p>
<p>Your goal, as the <strong>prover</strong> is to prove to your friend, <strong>the verifier</strong> that you know the secret password, called the "<strong>witness"</strong>, without telling them the actual password.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687826605348/6dd10dd7-de2c-4fb8-9752-af055f87cef6.png" alt class="image--center mx-auto" /></p>
<p>You don't want to tell your friend the password, so instead, you are going to prove you know it; by first, going into one side of the cave randomly; without them seeing.</p>
<p>At this point, your friend doesn't know which side you're on. But as a challenge, they shout out either "A!" or "B!"; requesting you to <strong>exit</strong> on either side <strong>A</strong> or side <strong>B</strong>.</p>
<p>In this simple example, this can lead to two outcomes:</p>
<ol>
<li>You entered side A, so you need the password to get through the gate to side B:</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687826964322/fdef1845-21d0-4f40-8773-343426ab3ee0.png" alt class="image--center mx-auto" /></p>
<ol>
<li>You entered side B, so you don't need the password; you can just walk back out:</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687827027133/40957851-bf55-4487-8a7f-9e6c3d63a066.png" alt class="image--center mx-auto" /></p>
<p><em>This is called the</em> <a target="_blank" href="https://en.wikipedia.org/wiki/Zero-knowledge_proof#The_Ali_Baba_cave"><em>Ali Baba Cave Story</em></a><em>, for reference.</em></p>
<p>This is a simple example because it's 50/50 whether or not you require the password to satisfy your friend's challenge; thus, doing this challenge only once is not enough to prove with certainty that you know the password.</p>
<p>This means you'd need to complete more iterations of the challenge, correctly exiting either side A or B until your friend is satisfied; or in the theoretical world, until it's impossible for you to have faked knowledge of the witness (the secret code).</p>
<p>Hence, this is <strong>interactive</strong>; you (the prover) and your friend (the verifier) interact back and forth. Your friend creates a <strong>challenge</strong>, and you create a <strong>response.</strong> This cycle repeats until the verifier is satisfied, at which point, the verifier has proven knowledge of the <strong>witness</strong>.</p>
<p>This makes up the three parts of an interactive ZK proof:</p>
<ol>
<li><p><strong>Witness</strong>: The secret information the prover wants to prove their knowledge of.</p>
</li>
<li><p><strong>Challenge</strong>: The question that only someone with knowledge of the witness would <em>likely</em> be capable of answering; although could be a lucky guess.</p>
</li>
<li><p><strong>Response</strong>: The prover's response to the challenge; containing the <em>(hopefully)</em> correct answer.</p>
</li>
</ol>
<p>Steps 2 and 3 are repeated until the verifier is satisfied.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687828387321/db3f2e9f-22bb-4538-bee5-af8d82a90342.png" alt class="image--center mx-auto" /></p>
<p>Eventually, once the verifier is satisfied, the cycle breaks; and instead of generating another challenge, the verifier accepts that the prover has knowledge of the witness.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687828497181/761ae3b3-101e-458d-aaaa-6d7b83e69ec1.png" alt class="image--center mx-auto" /></p>
<p>While this process works, it requires many rounds of communication between the prover and verifier; something that is inefficient and doesn't particularly work well in the context of blockchains.</p>
<p>Interactive proofs also have another big limitation; even after the verifier is satisfied, the proof would be <a target="_blank" href="https://ethereum.org/en/zero-knowledge-proofs/#non-interactive-zero-knowledge-proofs">unavailable for independent verification</a>; meaning only the party who verified it can trust it, not anyone else.</p>
<p>For these reasons, non-interactive ZK proofs were made.</p>
<h3 id="heading-non-interactive-zk-proofs">Non-Interactive ZK Proofs</h3>
<p>Non-interactive ZK proofs require only one round of communication from the prover to the verifier. The prover uses an algorithm to compute a ZK proof and sends it to the verifier, who also uses another algorithm to check it.</p>
<p>Another benefit to non-interactive ZK proofs is that they're available for anyone else to verify as well; meaning it's not just proven from the verifier's POV, but available for everyone to verify themselves; suitable for blockchains.</p>
<p>What are these "algorithms" that are capable of proving information and verifying proofs? Well, the answer is; it depends. <a target="_blank" href="https://en.wikipedia.org/wiki/Zero-knowledge_proof#:~:text=The%20most%20popular%20interactive%20or,Delegation%20(VPD)%2C%20and%20Succinct">There are quite a number of them</a>, but two ZKP systems are typically used in the context of blockchain; ZK-SNARKs and ZK-STARKs.</p>
<h3 id="heading-what-are-zk-snarks">What Are ZK-SNARKs?</h3>
<p>ZK-SNARK means Zero-Knowledge Succinct Non-Interactive Argument of Knowledge.</p>
<ul>
<li><p><strong>ZK:</strong> hopefully by now you can guess what this means (zero-knowledge).</p>
</li>
<li><p><strong>Succinct</strong>: they're small, and quickly verifiable by the verifier.</p>
</li>
<li><p><strong>Non-interactive</strong>: we discussed this previously. Only one round of communication between the prover and the verifier is required.</p>
</li>
<li><p><strong>Argument</strong>: It's theoretically extremely unlikely to be able to "fool" the system.</p>
</li>
<li><p><strong>(Of) Knowledge</strong>: It cannot be constructed without access to the secret information (the witness).</p>
</li>
</ul>
<p>They use a cryptographic primitive called <a target="_blank" href="https://medium.com/@VitalikButerin/exploring-elliptic-curve-pairings-c73c1864e627">elliptic curve pairing</a> as their method of creating and verifying these proofs (we won't go into the math here).</p>
<p>One key thing to note about ZK-SNARKs is that during the initial setup phase, the prover and the verifier must agree to use a "shared key", known as the Common Reference String (CRS). Anyone with access to this shared key can verify the proofs.</p>
<p>This shared key is what makes ZK-SNARKs possible; although this is also arguably their biggest drawback because it creates what is known as a "trusted environment".</p>
<p>The values used to create the CRS, sometimes called "toxic waste" need to be destroyed after the CRS is generated. If they are not, the entire system is at risk; as dishonest provers would be able to compute false proofs; hence, the users must trust that the value is destroyed.</p>
<p>Something also worth mentioning about ZK SNARKs is that they are not "quantum-resistant"; meaning they are vulnerable to attacks by quantum computers in the future; although they could potentially be upgraded in the future to become quantum-resistant.</p>
<h3 id="heading-what-are-zk-starks">What Are ZK-STARKs?</h3>
<p>ZK-STARK means Zero-Knowledge Scalable Transparent Argument of Knowledge.</p>
<ul>
<li><p><strong>Scalable</strong>: Rather than being "succinct", they're scalable; meaning they generate and verify proofs with larger witnesses more efficiently than ZK-SNARKs.</p>
</li>
<li><p><strong>Transparent</strong>: There's no trusted setup required. They rely on publicly verifiable randomness to generate the shared key.</p>
</li>
</ul>
<p>This improvement in transparency usually comes with a tradeoff of generating much larger proofs than the size of ZK-SNARKs; except when dealing with very large datasets. <a target="_blank" href="https://vitalik.ca/general/2017/11/09/starks_part_1.html#:~:text=the%20size%20of%20a%20proof%20goes%20up%20from%20288%20bytes%20to%20a%20few%20hundred%20kilobytes">The size of a proof goes up from 288 bytes to a few hundred kilobytes</a>.</p>
<p>Rather than using elliptic curves, they use <a target="_blank" href="https://vitalik.ca/general/2017/11/09/starks_part_1.html"><strong>polynomials</strong></a><strong>;</strong> something I am definitely not qualified to tell you about. Vitalik has a three-part series on this topic: <a target="_blank" href="https://vitalik.ca/general/2017/11/09/starks_part_1.html">1</a>, <a target="_blank" href="https://vitalik.ca/general/2017/11/22/starks_part_2.html">2</a>, <a target="_blank" href="https://vitalik.ca/general/2018/07/21/starks_part_3.html">3</a>.</p>
<p>ZK STARKs address both of the concerns we discussed with ZK-SNARKs, they:</p>
<ol>
<li><p>Don't require a "trusted environment".</p>
</li>
<li><p>Are plausibly post-quantum secure; meaning they won't be vulnerable to attacks from quantum computers in the future.</p>
</li>
</ol>
<p>ZK-STARKS are newer than ZK-SNARKs, and Vitalik calls them their "<a target="_blank" href="https://vitalik.ca/general/2017/11/09/starks_part_1.html#:~:text=a%20newer%2C%20shinier%20cousin">newer, shinier cousin</a>"! 🤠 So, as a quick recap:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td></td><td><strong>ZK-SNARK</strong></td><td><strong>ZK-STARK</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Size</strong></td><td>Succinct, quickly verifiable</td><td>Bigger, but scales more efficiently when proving larger witnesses</td></tr>
<tr>
<td><strong>Security</strong></td><td>Requires a trusted environment</td><td>Doesn't require a trusted environment</td></tr>
<tr>
<td><strong>Post-Quantum</strong></td><td>Not secure, although potentially upgradeable</td><td>Secure</td></tr>
</tbody>
</table>
</div><h2 id="heading-how-does-a-zkevm-work">How Does A zkEVM Work?</h2>
<p>Now that we've covered how zero-knowledge proofs work and the two common forms of ZKPs that appear in the web3 world, let's explore one of the recent innovations powered by ZKPs; the zkEVM (zero-knowledge Ethereum Virtual Machine).</p>
<p>zkEVMs come in a few different forms; as Vitalik outlines in his blog post "<a target="_blank" href="https://vitalik.ca/general/2022/08/04/zkevm.html">The different types of ZK-EVMs</a>". The one I'll be referencing in this post is the <a target="_blank" href="https://polygon.technology/polygon-zkevm">Polygon zkEVM</a>.</p>
<p>The goal of the zkEVM is to improve the scalability of the Ethereum blockchain while remaining secure, decentralized and <a target="_blank" href="https://ethereum.org/en/developers/docs/evm/">EVM</a>-compatible.</p>
<p>The details are complicated, but the core principles are the same as what we've discussed so far. As in all ZKP systems, there are:</p>
<ol>
<li><p>A <strong>Prover</strong>: Generates validity proofs representing the truthfulness of a batch of transactions submitted by users.</p>
<ul>
<li><p>First, it creates multiple ZK-STARK proofs.</p>
</li>
<li><p>It bundles the ZK-STARKs together using <a target="_blank" href="https://zkevm.polygon.technology/docs/zkProver/overview/#stark-recursion-component">STARK Recursion</a>, to create a single ZK-STARK.</p>
</li>
<li><p>This ZK-STARK is big, so it goes through the <a target="_blank" href="https://zkevm.polygon.technology/docs/zkProver/overview/#circom-library">CIRCOM component</a> which outputs to the SNARK builder.</p>
</li>
<li><p>As the name suggests, the SNARK builder generates a ZK-SNARK validity proof; this helps in reducing gas costs from 5M to 350K.</p>
</li>
</ul>
</li>
<li><p><strong>A Verifier</strong>: The <code>PolygonZkEVM</code> smart contract deployed on Ethereum is the verifier of the ZK proofs.</p>
</li>
</ol>
<h3 id="heading-flow-of-data-in-a-zkevm">Flow Of Data In A zkEVM</h3>
<p>Below, is a simplified flowchart of data in the Polygon zkEVM.</p>
<p>I've broken it up into chronological sections to help it be more digestible.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687918087863/1b5cb5f0-660b-4cf2-a9b2-17907521454f.png" alt class="image--center mx-auto" /></p>
<h4 id="heading-submitting-transactions">Submitting Transactions</h4>
<p>As a user, you submit transactions as you would normally with any other EVM chain such as Ethereum; by signing transactions and sending them through JSON RPC.</p>
<p>A sequencer node running zkEVM software picks these transactions up and decides which ones it wants to process, with some incentive mechanisms in place for doing so correctly.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687919433336/04ebef71-61f3-4e56-9c40-b12a42a1feb3.png" alt class="image--center mx-auto" /></p>
<h4 id="heading-batching-transactions">Batching Transactions</h4>
<p>The sequencer batches transactions together into one and submits them to the <code>PolygonZkEvm</code> smart contract, which is stored on Ethereum Mainnet (and a separate instance on Ethereum Goerli testnet).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687919535306/c27bf1c5-bf13-4967-b124-c83be6aba28b.png" alt class="image--center mx-auto" /></p>
<p>These batches aren't necessarily correct or verified at this point.</p>
<h4 id="heading-verifying-transactions">Verifying Transactions</h4>
<p>Using ZKPs, the <code>PolygonZkEVM</code> smart contract is acting as the verifier in this setup. It wants to verify that the batch it just received is valid; it does so by sending the batch to an aggregator node.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687919683002/548e5cac-5796-44a0-bb42-0e5b1ee8fd34.png" alt class="image--center mx-auto" /></p>
<h4 id="heading-generating-andamp-verifying-zk-proofs-validity-proofs">Generating &amp; Verifying ZK Proofs / Validity Proofs</h4>
<p>The <code>PolygonZkEVM</code> smart contract sends the batch it just received to an aggregator node, which is another machine running zkEVM software that communicates with a ZK prover. The flow is as follows:</p>
<ul>
<li><p>The aggregator receives the batch from smart contract</p>
</li>
<li><p>The Aggregator sends the batch to ZK Prover</p>
</li>
<li><p>The ZK Prover creates multiple ZK-STARKs -&gt; a single ZK-STARK -&gt; a ZK-SNARK</p>
</li>
<li><p>The ZK-SNARK (the validity proof) gets sent back to the aggregator</p>
</li>
<li><p>The aggregator sends back the validity proof to the <code>PolygonZkEVM</code> smart contract</p>
</li>
<li><p>The <code>PolygonZkEVM</code> Smart contract verifies the validity proof</p>
<ul>
<li><p>If the validity proof is valid, accept it.</p>
</li>
<li><p>If it is not valid, reject it.</p>
</li>
</ul>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687919773097/f8f8e097-2602-424b-8a37-26c4d5f3ccef.png" alt class="image--center mx-auto" /></p>
<h4 id="heading-reading-the-zk-evm">Reading The ZK EVM</h4>
<p>In order for the ZK EVM to be useful, decentralized applications (dApps) need to read information from it; which is where the <strong>synchronizer</strong> comes into play.</p>
<p>It reads in events from the Ethereum smart contract(s), storing knowledge of both the ZK validity proofs from the aggregator and the batches submitted from the sequencer.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687919935615/d98e32cb-94e2-47fd-a1cf-df4bf5648850.png" alt class="image--center mx-auto" /></p>
<p>This way, applications can easily get a view of the state of the rollup via JSON RPC.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Zero-knowledge proofs are real-world applications of cryptography that could be the foundation of a more privacy-oriented future; demonstrated in products like <a target="_blank" href="https://polygon.technology/polygon-id">Polygon ID</a>.</p>
<p>In the context of blockchain, ZKPs are being utilized to improve the scalability of Ethereum in products like <a target="_blank" href="https://polygon.technology/polygon-zkevm">Polygon's zkEVM</a>, by providing a new way to verify batches of transactions without the typical loss of security or EVM compatibility we see today with other rollup solutions.</p>
<p>In this post, we've covered:</p>
<ul>
<li><p>What ZK Proofs are, and why they're important.</p>
</li>
<li><p>How ZK proofs work, including ZK-SNARKs and ZK-STARKs.</p>
</li>
<li><p>How these proofs are being used in the blockchain world.</p>
</li>
</ul>
<p>If you'd like to learn how you can apply these concepts, I have a previous blog post covering how to build your first smart contract and decentralized application on Polygon zkEVM 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://blog.jarrodwatts.com/the-ultimate-guide-to-building-on-polygon-zkevm">https://blog.jarrodwatts.com/the-ultimate-guide-to-building-on-polygon-zkevm</a></div>
<p> </p>
<p>That's it for this post! Follow me on <a target="_blank" href="https://twitter.com/jarrodWattsDev">Twitter</a> to keep up to date with more educational content like this every week: <a target="_blank" href="https://twitter.com/jarrodWattsDev">My Twitter</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Polygon PoS Is Becoming A zkEVM Validium (Explained)]]></title><description><![CDATA[Polygon recently announced a roadmap of improvements to their products to become "the value layer of the internet".
The first announcement in the roadmap is a proposal to upgrade the Polygon PoS (proof-of-stake) chain we know and love to become a zkE...]]></description><link>https://blog.jarrodwatts.com/polygon-pos-is-becoming-a-zkevm-validium-explained</link><guid isPermaLink="true">https://blog.jarrodwatts.com/polygon-pos-is-becoming-a-zkevm-validium-explained</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[Web3]]></category><category><![CDATA[zkevm]]></category><category><![CDATA[Polygon]]></category><category><![CDATA[Cryptocurrency]]></category><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Thu, 22 Jun 2023 23:44:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1687393273169/e8319724-b37a-4be9-a91f-de57dfe5387a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Polygon recently announced a roadmap of improvements to their products to become "the value layer of the internet".</p>
<p>The <a target="_blank" href="https://polygon.technology/blog/polygon-2-0-polygon-pos-zk-layer-2">first announcement</a> in the roadmap is a proposal to upgrade the Polygon PoS (proof-of-stake) chain we know and love to become a zkEVM Validium.</p>
<p>I must admit... when I read that, I thought <em>"wtf is a zkEVM Validium?"</em>!</p>
<p>If you thought something similar, you're in the right place. I've done the research so you don't have to, and in this post, we're going to cover:</p>
<ul>
<li><p>What's changing about Polygon PoS?</p>
</li>
<li><p>What are Validiums? Why is Polygon PoS becoming one?</p>
</li>
<li><p>What about Polygon zkEVM? What's the difference between PoS and that?</p>
</li>
</ul>
<p>Let's do this!🫡👇</p>
<h2 id="heading-recap-sidechains-rollups-and-scaling">Recap: Sidechains, rollups, and scaling</h2>
<p>As a quick refresher, let's quickly explore why any of these scaling solutions exist in the first place. <em>You can safely skip this part if you're already a pro.</em></p>
<p>On Ethereum, users pay <a target="_blank" href="https://ethereum.org/en/developers/docs/gas/#priority-fee">fees</a> that validator nodes take as an incentive to include users' transactions in new blocks. Over time, Ethereum has reached "<a target="_blank" href="https://ethereum.org/en/developers/docs/scaling/#:~:text=certain%20capacity%20limitations">certain capability limitations</a>".</p>
<p>As the demand to write information to Ethereum, such as the desire to mint NFTs or transfer ETH rose, the fee required to have your transaction included in a block became very expensive <em>(sometimes hundreds of dollars per transaction).</em></p>
<p>This has led to many different scaling solutions developed by talented groups of people across the world, each with a unique way of accomplishing more scalability on Ethereum; including companies like <a target="_blank" href="https://polygon.technology/">Polygon</a>, <a target="_blank" href="https://www.optimism.io/">Optimism</a>, and <a target="_blank" href="https://arbitrum.io/">Arbitrum</a>.</p>
<p>These companies created implementations of <a target="_blank" href="https://ethereum.org/en/developers/docs/scaling/sidechains/">sidechains</a>, <a target="_blank" href="https://ethereum.org/en/developers/docs/scaling/#rollups">rollups</a>, <a target="_blank" href="https://ethereum.org/en/developers/docs/scaling/plasma/">plasma</a> chains, and more, to address the scalability problem that the Ethereum mainnet faces, and enable users to more easily create and experience decentralized applications.</p>
<p>You can learn more in-depth about each of these solutions in my previous blog post:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://blog.jarrodwatts.com/zkevms-and-the-race-to-scale-ethereum">https://blog.jarrodwatts.com/zkevms-and-the-race-to-scale-ethereum</a></div>
<p> </p>
<p>So that's why Polygon PoS was created initially, and more recently, Polygon zkEVM was also released. So why is Polygon PoS changing?</p>
<h2 id="heading-whats-changing-about-polygon-pos">What's changing about Polygon PoS?</h2>
<p>Polygon PoS (proof-of-stake) is, in its current state<em>,</em> a <a target="_blank" href="https://ethereum.org/en/developers/docs/scaling/sidechains/">sidechain</a>.</p>
<p>The main benefit of a sidechain is increased scalability; higher transactions per second and significantly lower gas fees per transaction.</p>
<p>Since Polygon PoS is EVM-compatible, you can perform the exact same development process you would if you were developing for Ethereum, and deploy to Polygon PoS instead, immediately granting your users a massively improved experience when interacting with your smart contracts, with no extra effort.</p>
<p>The downside to sidechains is that because they don't post back state changes or transaction data to Ethereum, they therefore don't inherit all of Ethereum's security properties; essentially making the tradeoff of more scalability for less security; as outlined in Ethereum's <a target="_blank" href="https://ethereum.org/en/roadmap/vision/#:~:text=The%20challenge%20of%20decentralized%20scaling">scalability trilemma</a>.</p>
<p>Polygon PoS powers the most popular brand web3 efforts in the world, like Reddit, Stripe, Starbucks, Bulgari, and more; giving it a powerful ecosystem and strong incentive for developers to launch their projects using this network.</p>
<p>However, Polygon's broader vision with Polygon 2.0 is to use the latest innovations in <a target="_blank" href="https://ethereum.org/en/zero-knowledge-proofs/">zero-knowledge proofs</a> to power all of their scaling solutions to Ethereum, and Polygon PoS in its current state is secured by its own validators; <strong><em>not</em></strong> by ZK proofs.</p>
<p>That's what's going to change; the <a target="_blank" href="https://polygon.technology/blog/polygon-2-0-polygon-pos-zk-layer-2">proposal</a> suggests Polygon PoS should upgrade to use ZK proofs to provide even more scalability and stronger security to the chain.</p>
<p>With this upgrade, Polygon PoS would become a <strong>zkEVM validium</strong>:</p>
<ul>
<li><p><strong>ZK</strong>: Utilizes zero-knowledge proofs to prove the result of transactions.</p>
</li>
<li><p><strong>EVM</strong>: It's Ethereum Virtual Machine (EVM) compatible, meaning it works out of the box with existing developer tools and user-facing apps such as wallets.</p>
</li>
<li><p><strong>Validium</strong>: This is a bit more complex; we'll explore this below.</p>
</li>
</ul>
<h2 id="heading-what-are-validiums">What are Validiums?</h2>
<p>By using zero-knowledge proofs instead of purely relying on validators to execute transactions, Polygon PoS is becoming a <a target="_blank" href="https://ethereum.org/en/developers/docs/scaling/validium/">validium</a>, and will no longer be a sidechain.</p>
<p>The proposal means that Polygon PoS will use zero-knowledge proofs to guarantee and verify the validity of batches of transactions, which are both executed and stored off-chain; leading to lead massive improvements in scalability.</p>
<p>According to <a target="_blank" href="https://ethereum.org/en/developers/docs/scaling/validium/#settlement">Ethereum's documentation</a>, validiums can process ~9,000 transactions, or more, per second; compared to Ethereum's roughly ~15 transactions per second.</p>
<p>Validiums are different from rollups and sidechains because they <strong><em>only</em></strong> post the validity proof (containing verified proof of the result of the transactions) back to Ethereum, <strong>not</strong> the actual <strong>transaction data</strong> of the executed transactions.</p>
<p>The way this works is by having a verifier smart contract deployed to Ethereum, which the validium submits validity proofs to. The validity proofs are zero-knowledge proofs that contain the result of the transactions, but not the data within them.</p>
<p>The verifier smart contract determines if the validity proof is valid, and if it's not, the batch submitted from the Validium is rejected and not stored on Ethereum.</p>
<p>The tradeoff to this process is that Validiums utilize an off-chain data availability model; transaction data is not stored on Ethereum, so the validators of the network must attest to data availability; which comes with its own set of <a target="_blank" href="https://ethereum.org/en/developers/docs/scaling/validium/#data-availability">potential risks</a>.</p>
<h3 id="heading-why-is-this-better-for-polygon-pos">Why is this better for Polygon PoS?</h3>
<p>Compared to sidechains, validiums are better in two key aspects:</p>
<ol>
<li><p>Scalability: The amount to which rollups and sidechains can scale is limited by the data bandwidth on Ethereum Mainnet. Since validiums reduce the amount of data Ethereum has to process, they <a target="_blank" href="https://ethereum.org/en/developers/docs/scaling/validium/#off-chain-data-storage">greatly extend throughput on Ethereum</a>.</p>
</li>
<li><p>Security: The use of validity proofs gives validiums higher security guarantees than sidechains.</p>
</li>
</ol>
<p>Typically, the downside to validiums is that they are not EVM-compatible, making them only suitable for simple applications like transferring tokens or minting NFTs, due to the <a target="_blank" href="https://ethereum.org/en/developers/docs/scaling/validium/#validiums-and-evm-compatibility">considerable overhead of proving EVM instructions in a zero-knowledge proof circuit</a>.</p>
<p>Over the past eighteen months, Polygon Labs has built "<a target="_blank" href="https://polygon.technology/blog/polygon-2-0-polygon-pos-zk-layer-2#:~:text=Over%20the%20past%20eighteen%20months%2C%20Polygon%20Labs%20has%20released%20the%20fastest%20ZK%20proving%20system%20in%20the%20industry%20and%20launched%20the%20only%20EVM%2Dequivalent%20zkEVM%20on%20mainnet">the fastest ZK proving system in the industry and launched the only EVM-equivalent zkEVM on mainnet</a>" to overcome this obstacle, meaning that a validium doesn't have to come with this limitation.</p>
<p>Creating an EVM-compatible validium is the best of both worlds; as it is flexible enough to perform all EVM operations and use all existing tools and applications in the EVM world, while also providing greater scalability and security to Polygon PoS; which has a massive community already.</p>
<p>Using zero-knowledge proofs for this process is the cherry on top; by proving the transactions upfront, it means there are no other limitations such as a challenge period that come with other scaling solutions.</p>
<h2 id="heading-what-about-polygon-zkevm">What about Polygon zkEVM?</h2>
<p>You might be asking, <em>didn't Polygon just release a zkEVM? What happened to that?</em></p>
<p>Polygon PoS and Polygon zkEVM currently co-exist as two separate chains, and they will continue to be separate chains moving forward; although Polygon 2.0's future announcements will include improved unity between the two.</p>
<p>The key difference here is that Polygon zkEVM is a zero-knowledge <strong>rollup</strong>, whereas Polygon PoS will become a zero-knowledge <strong>validium</strong>.</p>
<ul>
<li>Polygon zkEVM <em>does</em> post transaction data back to Ethereum mainnet. Meaning it will be comparatively less scalable, and more secure, making it suitable for projects such as high-value DeFi applications.</li>
</ul>
<ul>
<li>Polygon PoS (when upgraded) <em>does</em> <strong><em>not</em></strong> <em>post</em> transaction data back to Ethereum. Meaning it will be comparatively more scalable, and less secure, making it suitable for projects that have high transaction volume and require low transaction fees, e.g. gaming, social, and micro DeFi.</li>
</ul>
<p><img src="https://assets-global.website-files.com/637e2b6d602973ea0941d482/6491cb67a15313f153883a39_Blog%20cover%20(99).png" alt /></p>
<p><a target="_blank" href="https://polygon.technology/blog/polygon-2-0-polygon-pos-zk-layer-2"><em>Link to image</em> ↗</a></p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>TLDR: the big words are intimidating, but the proposed change to Polygon PoS will provide improvements to both the scalability and security of the chain.</p>
<p>Polygon's zkEVM will coexist, and be more suited to apps that require higher levels of security. Whereas Polygon PoS will be more suited towards apps demanding higher throughput; such as social apps built on <a target="_blank" href="https://www.lens.xyz/">Lens Protocol</a>.</p>
<p>It's clear to see the investments Polygon has made in zero-knowledge technology are powering massive innovations throughout its product suite, and I'm excited to see how this technology can be used more broadly.</p>
<p><a target="_blank" href="https://twitter.com/jarrodWattsDev">Follow me on Twitter</a> for more updates like this one!</p>
]]></content:encoded></item><item><title><![CDATA[You're (Probably) Wrong About Web3 Gaming]]></title><description><![CDATA[Last week, I saw this Twitter thread in my feed, which "predicts" a reality in the next five years where people don't play video games unless they earn cryptocurrency for doing so, and commends Axie Infinity as a leader in the space:

Within the next...]]></description><link>https://blog.jarrodwatts.com/youre-probably-wrong-about-web3-gaming</link><guid isPermaLink="true">https://blog.jarrodwatts.com/youre-probably-wrong-about-web3-gaming</guid><category><![CDATA[Web3]]></category><category><![CDATA[gaming]]></category><category><![CDATA[NFT]]></category><category><![CDATA[Cryptocurrency]]></category><category><![CDATA[Blockchain]]></category><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Thu, 08 Jun 2023 01:02:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1686185984944/fe50b238-19ed-4482-8e69-f8555f73bc39.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Last week, I saw <a target="_blank" href="https://twitter.com/alexisohanian/status/1663923368557420550">this Twitter thread</a> in my feed, which "predicts" a reality in the next five years where people don't play video games unless they earn cryptocurrency for doing so, and commends Axie Infinity as a leader in the space:</p>
<blockquote>
<p><em>Within the next 5 years, the majority of gamers won't play games unless they are being properly valued for that time. The model is called "play-to-earn" and it will become standard for video games in the future.</em></p>
</blockquote>
<p>Of course, this gathered the usual "scam", "crypto-bro", and "death of the industry" comments. It's an easy tweet to dunk on; and overall, felt very out of touch with what we've experienced in this space.</p>
<p>Despite working in web3 for a while now, I have to agree that it's completely delusional to think this is where gaming is headed <em>ever</em>; let alone in the next 5 years.</p>
<p>People don't play games to earn money and the play-to-earn games we've seen so far have been terrible, unfun messes that usually die out within months.</p>
<p><em>However</em>, I don't believe this is the death of NFTs in gaming, and I encourage you to try to read this with an open mind as I discuss points both for and against blockchain usage in gaming. I'll be talking about the following:</p>
<ol>
<li><p>Why do people <em>actually</em> play games?</p>
</li>
<li><p>Why web3 Gaming has (mostly) failed so far</p>
</li>
<li><p>Actual use-cases for the blockchain in gaming</p>
</li>
</ol>
<h2 id="heading-why-do-people-actually-play-games">Why Do People <em>Actually</em> Play Games?</h2>
<p>One of the quotes from this Twitter thread was as follows:</p>
<blockquote>
<p>Why would you keep playing the game for free when you could get paid for it?</p>
</blockquote>
<p>For many of us, working to make money is something we do to pay the bills and stay alive. This doesn't mean I don't enjoy work or that I am not a productive member of society; I take pride in my work and am consistently trying to improve my craft.</p>
<p>Gaming acts as an escape from this grind; and while I do think there are some deeper psychological natures of why games are played so often; I think I speak for a large percentage of the community when I say that I don't want gaming to become a thing I do to earn money, <em>especially</em> after spending most of my day doing something else for money.</p>
<p>I play games to dissociate from the other things going on in life; to relax, have fun, play with my friends, be competitive, improve and express my skill, and be part of an interactive story-telling experience.</p>
<p>Play-to-earn ignores this and replaces it with a monotonous grind of implementing the most optimized strategy to earn in-game currency in the hopes of making money.</p>
<p>I'm not jumping on Discord with the squad to earn digital currency to buy other digital assets in the game and hoping that someday I can retire from selling these to other players.</p>
<h2 id="heading-why-web3-gaming-has-failed-so-far">Why Web3 Gaming Has Failed (so far)</h2>
<p>Let's not sugarcoat it. Web3 games are (mostly) just not fun.</p>
<p>When your objective as a game developer is to pump the price of a digital token you printed in hopes of cashing out, your game's core mechanics revolve around getting players aligned with that same objective; so they too can "earn" by playing.</p>
<p>Let's look at another quote from the Twitter thread:</p>
<blockquote>
<p>Companies like <a target="_blank" href="https://twitter.com/AxieInfinity">@AxieInfinity</a> are already leading the way by letting players easily earn crypto and sell their in-game characters as NFTs.</p>
</blockquote>
<p>Bruh. Really... Axie Infinity is the one you're going with. Alright...</p>
<h3 id="heading-axie-infinity">Axie Infinity</h3>
<p>Axie Infinity is a game where you battle cute little "Axie" NFTs against each other to earn cryptocurrency called Smooth Love Potion (SLP).</p>
<p>Initially, you invest X amount of money to actually be able to play the game by purchasing a team of Axies, and over time, cash out the cryptocurrency you earned from playing the game to make a profit.</p>
<p>Since there is a limited supply of Axies, new players need to buy them from existing players in order to play the game, almost in a suspicious-looking triangle structure of onboarding new users. 🤔</p>
<p>The value of the Axie NFTs and the $SLP token you earn for playing the game depends on how much a new <s>investor</s> player is willing to spend to buy it; in hopes of earning a profit themselves.</p>
<p>Over time, it evolved into a dystopian capitalistic nightmare where people who could actually afford to buy the NFTs necessary to play the game outsourced the "fun" to people in the Philippines and Indonesia to actually play the game for them...</p>
<p>For Filipinos, it was a way to make a living through the pandemic, and for crypto-bros, an investment opportunity.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685946762727/a9745043-0bc6-4410-aade-815fd60567ec.png" alt class="image--center mx-auto" /></p>
<p><em>Source of image:</em> <a target="_blank" href="https://www.youtube.com/watch?v=Lg5C2EbYueo">PLAY-TO-EARN | NFT Gaming in the Philippines</a></p>
<p>As you'd expect, as the potential to earn money from Axie Infinity diminished, so did the player base. The price of the in-game token ($SLP) has dropped nearly 99% from its all-time high:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685947708501/859efb4e-c981-49b0-8846-0d2899cd4dc1.png" alt class="image--center mx-auto" /></p>
<p>This has led to a similar, sad-looking chart in activity on the game:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685947789205/11bba5a1-c2ed-4d8e-8456-e165ec9f6052.png" alt class="image--center mx-auto" /></p>
<p>The problem here is simple... when games are designed to make you money <em>(which usually actually</em> <em>means making the developers money),</em> it turns out they're usually not that fun. The developers aren't building it for fun, and people aren't playing it for fun.</p>
<p>This isn't to say there aren't <em>any</em> good games out there that incorporate NFTs; games built on chains like <a target="_blank" href="https://www.immutable.com/products/immutable-x">ImmutableX</a> such as <a target="_blank" href="https://godsunchained.com/">Gods Unchained</a> and <a target="_blank" href="https://www.crosstheages.com/">Cross The Ages</a> have real, human players that are playing the game for fun and trading their in-game assets as part of the game's economy.</p>
<h3 id="heading-the-problem-with-crypto-based-gaming">The Problem with Crypto-based Gaming</h3>
<p>Blockchains, digital collectables, cryptocurrencies, and "true ownership" aren't game mechanics. You can't make a game out of these concepts because they are inherently unfun.</p>
<p><em>Most</em> of the games we've seen that integrate these ideas use them as the <strong>core</strong> feature of the game itself; not something secondary to an <em>actual</em> fun game. Differing from the structure we see in popular games today like CS:GO or League of Legends.</p>
<p>This creates an environment where the only people interested in playing the game are those who want to do so to earn money, and once that opportunity is gone, the players leave too.</p>
<p>This is true in an even broader sense outside of just gaming. If you encourage any kind of behaviour with the reward of money, people are probably going to do that thing until that action is no longer worthwhile.</p>
<p>We see this in other parts of web3; with people performing on-chain actions to farm token airdrops, people engaging in Discord activity in the hopes of being whitelisted or scrawling Twitter "drop your ENS" posts in the hopes of hitting the next big project.</p>
<p>This strategy works because both developers and users benefit from the usage of their token, as it gathers the attention of other potential users to get on board.</p>
<p>So... we've dunked on web3 gaming a lot, let's quickly recap and shift tones a bit now.</p>
<h4 id="heading-quick-recap">Quick Recap</h4>
<ul>
<li><p>Web3 games often aren't even intended to be played for fun</p>
</li>
<li><p>Blockchain features are not something you can make a fun game around</p>
</li>
<li><p>There's little to no demand for "play-to-earn" in the gaming community</p>
</li>
</ul>
<p>So, with all this in mind, do NFTs have a place in gaming? Let's take a look.</p>
<h2 id="heading-why-blockchain">Why Blockchain?</h2>
<p>Despite the common saying that "blockchain is a solution looking for a problem", I think there is a pretty clear use case for where blockchain shines.</p>
<p>A blockchain is ideal for where there is some benefit for the data being separate from the application. Using a blockchain as the mechanism of data storage unlocks a way to give everyone read-level access to information while still controlling the rules of what can occur within that system.</p>
<p>That description is intentionally a little vague to cover all kinds of different use cases, so let's dive into what I think this looks like specifically in gaming.</p>
<p>To me, there is a clear trend that we see today in games. The game itself, and then the game's assets. Games usually have some kind of separate economies to them where players use in-game currencies to purchase in-game items, for example:</p>
<ul>
<li><p><strong>League</strong> <strong>of Legends</strong>: Use RP to buy champion skins, emotes, chromas, etc.</p>
</li>
<li><p><strong>CS:GO</strong>: Use dollars to buy weapon skins, stickers, cases, keys, etc.</p>
</li>
<li><p><strong>Fortnite</strong>: Use V-Bucks to buy skins, vehicle &amp; weapon wraps, and more.</p>
</li>
</ul>
<p><strong>Blockchains are not suitable to power the core features of fun games.</strong> Instead, it's these economies where a blockchain can provide value for both players and game developers, in the form of three different unique use cases:</p>
<ol>
<li><p>Access to in-game information outside of the game</p>
</li>
<li><p>Enabling of trading, buying, and selling of in-game items</p>
</li>
<li><p>Capability to use a shared identity across games and platforms</p>
</li>
</ol>
<p>In the following sections, I'll provide real scenarios where these could be used and the benefits of doing so for both game developers and players.</p>
<h3 id="heading-accessing-in-game-information-outside-the-game">Accessing In-Game Information Outside the Game</h3>
<p>If you're a gamer you're likely on several different platforms related to that game:</p>
<ol>
<li><p>The game itself</p>
</li>
<li><p>A community like Discord or Reddit to communicate with others about the game</p>
</li>
<li><p>Social platforms like Twitter, Twitch, and YouTube to view content of the game</p>
</li>
</ol>
<p>While these systems may have created integrations like <a target="_blank" href="https://gaming.amazon.com/">Prime Gaming</a> to communicate with each other, external platforms outside of the games ecosystem don't have access to information about your profile in-game* (<em>\</em>we'll talk about APIs shortly).*</p>
<p>Without a shared data layer to store in-game information such as what skins you own, or even taking it a step further to store information about your rank, your achievements, or your unique accomplishments, it's not possible to build seamless integrations across different platforms that read this information.</p>
<p>This affects two key parties in different ways; players and developers.</p>
<h4 id="heading-for-players">For Players...</h4>
<p>As a player, I'm proud of the accomplishments I've made in-game. I'm proud that I made it to Legend rank in Hearthstone, or got to Diamond rank in League, or that I have a high ranking for specific characters in my server.</p>
<p>For players, it's a flex to own the OG John Wick skin in Fortnite, and it's cool to own the Dragon Lore skin on your AWP in CS: GO.</p>
<p><img src="https://csgostash.com/storage/img/skin_sideview/s422.png?id=d0f53fa10778853316e953c55bdf5202" alt="AWP Dragon Lore" /></p>
<p>If this information was on a shared storage of data such as a blockchain, any external application would be able to pull in this information and utilize it on their platform outside of the game.</p>
<p>If I could showcase my in-game rank, or a rare item I own in social settings like Twitch, Discord, and Reddit, that brings added value to me as a player.</p>
<p>I'm passionate about being good at the games I play and I want other people to know that I am good at them. As a player, information being stored on the blockchain makes it available to any other platform that wishes to read this information; allowing me to show off my items, or even verify the accomplishments that I've made.</p>
<p>Some examples of this might be:</p>
<ul>
<li><p>On Twitter, setting my profile image as my Riot-issued Challenger NFT to show off and verify that I was one of the highest-ranked players on the server.</p>
<ul>
<li><em>Twitter already has built-in NFT integrations to verify the legitimacy of NFT profile pictures. Instagram recently shut down support for this, however.</em></li>
</ul>
</li>
<li><p>Opting into displaying a badge NFT next to my name in Twitch Chat that shows my rank or shows some item from my in-game profile.</p>
</li>
<li><p>Granting me restricted access to a Discord server where only the top players of a certain character are allowed to enter.</p>
</li>
</ul>
<h4 id="heading-for-developers">For Developers...</h4>
<p>A number of tools exist outside of the game's ecosystem that rely on in-game information. Some examples:</p>
<ul>
<li><p>League of Legends: <a target="_blank" href="https://www.op.gg/">op.gg</a> for in-game stats and rank progress</p>
</li>
<li><p>Hearthstone: <a target="_blank" href="https://hsreplay.net/">hsreplay.net</a> for the best decks and meta reports</p>
</li>
<li><p>Warzone: <a target="_blank" href="https://cod.tracker.gg/warzone">cod.tracker.gg</a> for your game history and rank</p>
</li>
</ul>
<p>These applications are powered by the game developer's API, such as the <a target="_blank" href="https://developer.riotgames.com/">Riot API</a>, and are essentially full-time businesses that are at the mercy of the company behind that API.</p>
<p>In recent months alone, we've seen several instances of why this structure <em>(where one company owns the data, and it is not public on a system like a blockchain)</em> is problematic:</p>
<ul>
<li><p><a target="_blank" href="https://www.wired.co.uk/article/twitter-data-api-prices-out-nearly-everyone">Twitter raised its API price to $42,000 per month</a>, killing many small businesses and third-party applications in the process.</p>
</li>
<li><p><a target="_blank" href="https://www.reddit.com/r/apolloapp/comments/13ws4w3/had_a_call_with_reddit_to_discuss_pricing_bad/">Reddit forcing third-party apps such as "Apollo" to pay $20 million per year</a> to keep running as-is.</p>
</li>
</ul>
<p>More specifically, in the gaming industry, Activision issued a cease-and-desist for the application "<a target="_blank" href="https://www.gamesindustry.biz/call-of-duty-warzone-stat-tracking-site-shuts-down-after-cease-and-desist-from-activision#:~:text=News-,Call%20of%20Duty%20Warzone%20stat%2Dtracking%20site%20shuts%20down,cease%20and%20desist%20from%20Activision&amp;text=A%20fan%20website%20that%20tracks,Activision%20and%20its%20legal%20representatives.">Warzone SBMM</a>"; an example of an application dependent on one of these APIs.</p>
<p>By using a decentralized data layer such as a blockchain, access to that data is granted to everyone out of the box. There's no requirement for the development team to maintain an API or built dedicated integrations with partners.</p>
<p>As a third-party developer, this setup would mean that you don't have a single point of failure (the API) in your business, as the data is available without having to trust anyone.</p>
<h3 id="heading-trading-buying-andamp-selling-in-game-items">Trading, Buying, &amp; Selling In-Game Items</h3>
<p>My most played game is League of Legends; a game I have spent hundreds of dollars on to purchase the in-game currency "RP" (Riot Points) I use to buy skins that make my characters look cooler in the game.</p>
<p>I spent this money because I get joy out of it, I can gift my friends skins for special occasions, or because I wanted to be involved in special events that Riot puts on. I didn't spend this money in the hopes of getting anything monetary in return.</p>
<p>When I buy skins in League, that money I spent is essentially gone and locked up in the ecosystem of League; I cannot do anything with the skin except use them in my games, and this is something I've accepted.</p>
<p>However, as a player, there are benefits for me if there were a method where I could buy, sell, and trade my in-game items to other players; so that I could sell my old skins I don't want, sell skins for characters I don't play, or buy a rare skin from another player that is no longer available from the store for my favourite character.</p>
<p>Having in-game items stored on the blockchain would enable this buying and selling of skins out of the box; allowing me to more actively participate in the game's economy; buying rare skins for my favourite champs, and selling ones that I don't want to other players. Something I can't currently do.</p>
<p>There's demand for this already. You can easily find <em>(illegal)</em> sites that sell League accounts with rare skins on them; a process that Riot (League's game developer) does not benefit from at all, and is actively trying to prevent.</p>
<p>For users, these websites are extremely sketchy and since you're performing something against the terms of service, there is no safety when it comes to buying them.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686023658926/652a20c7-f154-4ad2-93f8-754a7f806c7c.png" alt class="image--center mx-auto" /></p>
<p><em>Above: An example of accounts for sale with very rare skins on a third-party app</em></p>
<p>It's a lose-lose environment for both game developers and players, and something that a blockchain could be used to provide a potential solution.</p>
<p>By using NFTs to represent in-game items; they would come with standard features like being able to be transferred/sold on marketplaces, enabling third-party websites that already exist such as <a target="_blank" href="https://opensea.io/">OpenSea</a> to be used as a trusted environment for players to buy and sell these in-game items without additional effort from Riot (<em>if they made them NFTs from the start, which is not the case.)</em></p>
<p>All of this would be possible without any dedicated development to create or maintain this marketplace/economy; as these capabilities are standard features of tokens within <a target="_blank" href="https://ethereum.org/en/developers/docs/smart-contracts/">smart contracts</a>.</p>
<h4 id="heading-why-would-a-game-developer-like-riot-do-this">Why would a game developer like Riot do this?</h4>
<p>Money! Companies want money. Implementing this would help them get more money.</p>
<ol>
<li><p>As a player, I'm more willing to put money into the game's economy if I can get money out of it (anecdotal).</p>
</li>
<li><p>Game developers can take a percentage of the sales made between players in both royalty fees and platform fees whenever a skin is bought/sold/traded.</p>
</li>
</ol>
<p>An example of a game with an economy with a marketplace today is Counter Strike Global Offensive (<a target="_blank" href="https://store.steampowered.com/app/730/CounterStrike_Global_Offensive/">CS:GO</a>). Which has a centralized marketplace run by Valve; the creator of the game and of <a target="_blank" href="https://store.steampowered.com/">Steam</a>.</p>
<p>Despite playing CS:GO significantly less than I do League of Legends, I've spent a solid chunk of money buying skins in this game; because of this marketplace where I can sell these skins to other players willing to buy them.</p>
<p>Immediately, this creates a mindset shift; instead of "sinking money" into the game, I'm buying assets that I can later sell when I no longer want them, or trade for other skins if I don't get the ones I want.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686025380501/ca682bf0-7c59-4d9f-85f5-bf5c51948752.png" alt class="image--center mx-auto" /></p>
<p><em>Above: One example listing of an in-game CS:GO item on the Steam marketplace.</em></p>
<p>This marketplace proves there is a demand to buy &amp; sell in-game items between players, and there is a benefit for both the player and the game developer.</p>
<ul>
<li><p><strong>Players</strong>: Opportunity to buy skins that I want on my favourite weapons from other players that are not available for direct purchase, and potentially make a profit from selling/trading my own rare skins.</p>
</li>
<li><p><strong>Developers</strong>: Money. Steam <a target="_blank" href="https://help.steampowered.com/en/faqs/view/61F0-72B7-9A18-C70B#steamfee">takes a 10% fee of any CS:GO item transaction</a> on their marketplace.</p>
</li>
</ul>
<p>It's no easy task to hire a team of developers to build a marketplace that is almost a separate entity from your actual game, and this may be one of the reasons why Riot or other game developers choose to not build this infrastructure for their community.</p>
<p>The nature of the blockchain and standardized tokens such as NFTs enable this behaviour from the get-go, providing infrastructure to perform actions such as those that take place on the Steam marketplace both in and outside of the game.</p>
<p>By implementing this, game developers such as <a target="_blank" href="https://www.riotgames.com/en">Riot</a> could unlock an entirely new revenue stream for their business whenever players trade their League skins, Valorant skins, TFT Little Legends, and LoR cards.</p>
<p>Players would be able to purchase skins that are not directly available for sale anymore from other players; providing further reason for them to purchase the in-game currency in the process.</p>
<p>Anecdotally, as a player, this would also give my skins "value", as my skins in League are currently worth nothing other than personal joy, whereas my CS:GO skins <em>also</em> give me joy, but at the same time are exchangeable for actual money.</p>
<p>It's important to revisit the fact that these economies are completely separate from the fun, addictive games that these companies have developed. Players choose to opt-in to these economies and can still perform every action of the game without ever becoming involved with it.</p>
<h4 id="heading-ok-but-you-can-do-this-without-the-blockchain-already">Ok but... You can do this without the blockchain already?</h4>
<p>A valid argument against this point is "this is already possible <em>without</em> the blockchain".</p>
<p>This is true! As we just saw, Steam has already been enabling the buying &amp; selling of in-game items for over a decade; without ever touching the blockchain.</p>
<p>There are two counter-points I have to this:</p>
<p>1) By relying on a service such as Steam to facilitate this marketplace, Steam is the one profiting; not you (the developer).</p>
<p>There are incentives for the developer to control both the way that the assets work and the marketplace's conditions. For example, by implementing blockchain standard features such as royalty fees and platform fees, the game developer can ensure they are profiting whenever a buy/sell occurs from their community.</p>
<p>2) Building a marketplace takes time, effort, and money</p>
<p>For some game development companies, creating a marketplace from scratch is likely, not feasible; so the choice is either to use Steam or to not implement a marketplace at all; neither of which is beneficial to the development company.</p>
<h4 id="heading-that-doesnt-really-answer-the-question-though-why-wouldnt-the-game-development-company-could-just-create-their-own-marketplace-without-the-blockchain"><em>That doesn't really answer the question though. Why wouldn't the game development company could just create their own marketplace without the blockchain?</em></h4>
<p>I don't really have a good answer to this question.</p>
<p>Why would a company that <em>can</em> afford to create a marketplace for their game(s) opt to use the blockchain instead of a more traditional solution?</p>
<p>Realistically, for the company, it's more beneficial for them to have 100% control over the marketplace and the in-game items. Look at Steam, taking a 10% cut of every CS:GO transaction is crazy; but as players, there is no other option for us. It's either use the Steam marketplace or don't trade the items at all.</p>
<p>So really, it's up to us as players to set the expectations from companies. The benefits of using NFTs for in-game assets actually benefits us as a player, by providing us more freedom in what we can use them for, and how we can trade them amongst each other.</p>
<p>Maybe, with the features and benefits of NFTs that we've described earlier, gamers will start to perceive in-game items as more valuable if they can access them outside the game; slowly enticing game developers to follow suit.</p>
<p>Maybe, the success of a game implementing these strategies like <a target="_blank" href="https://midnightsociety.com/">Midnight Society</a> will encourage other game developers to explore NFTs &amp; blockchains as an option.</p>
<p>Maybe, some other web3 game uses the outside-of-the-game features to create an epic marketing campaign that game developers see and want to mimic.</p>
<p>Maybe, this never happens and NFTs are never widely adopted in gaming.</p>
<p>These are all possible realities, and the truth is no one knows what's going to happen in the next 5 years of gaming. However, the sentiment that NFTs are scams for crypto bros closes avenues that might benefit us as gamers, and I think shuts down some of the cool opportunities that this can enable for us.</p>
<p>Let's move on to one more use case before wrapping up; identity.</p>
<h3 id="heading-sharing-identity-across-games-andamp-platforms">Sharing Identity Across Games &amp; Platforms</h3>
<p>Something central to blockchains is the concept of <a target="_blank" href="https://ethereum.org/en/developers/docs/accounts/">accounts</a>.</p>
<p>An account is your profile for the blockchain. It is capable of storing fungible tokens such as cryptocurrencies which can represent in-game currencies, and non-fungible tokens (NFTS) which can represent in-game items.</p>
<p>The great thing about this is that you can use this wallet identity as your account for all applications on a blockchain. Allowing you to bring your account and the data within it along with you to whichever applications you want to use.</p>
<p>This is relevant for games too, meaning you could carry over your identity such as your gamer tag, profile picture, and bio with you to any game platform; Steam, Origin, EA, Riot, or any other individual game.</p>
<p>This would allow you to verify the authenticity of your account across any game you choose to play; valuable to you as a player for several reasons:</p>
<ul>
<li><p>Other players know it's the <em>real</em> you with on-chain verification</p>
</li>
<li><p>Other players can view your items/accomplishments from other games</p>
</li>
<li><p>You can tie your on-chain identity with your in-game information</p>
</li>
</ul>
<p>By linking your blockchain account with your in-game account, you could use this blockchain account to then sign into any other web3 application that supports connecting wallets; and have your in-game information available on these platforms too.</p>
<p>This is a built-in benefit of using blockchain infrastructure that we can already see today; for example, social applications built on the blockchain allows me to bring my profile and audience between applications; using the same profile for different apps like <a target="_blank" href="https://lenster.xyz/">Lenster</a> and <a target="_blank" href="https://orb.ac/">Orb</a>.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Overall, people, including myself love playing games for many reasons.</p>
<p>Earning money isn't anywhere near the top of that list... and I strongly disagree with the idea that that is going to change within the next five years.</p>
<p>This doesn't mean NFTs are dead, a scam, or something to shy away from. Blockchain technology has some real use cases that would add value to our lives and create deeper connections to the games we play.</p>
<p>With the right intentions, NFTs and other blockchain technologies have the potential to benefit both players and game developers alike.</p>
<p>Looking forward, I'm excited to see games like <a target="_blank" href="https://midnightsociety.com/">Midnight Society</a> integrate these ideas in a way that considers what gamers want first, and the in-game economy second.</p>
]]></content:encoded></item><item><title><![CDATA[I Fixed Web3 Onboarding]]></title><description><![CDATA[In this guide, I'll show you how to create a web3 onboarding experience that allows users to interact with your smart contracts without ever creating their own wallet.
I'll walk through how to:

Create a smart wallet factory contract (using EIP-4337 ...]]></description><link>https://blog.jarrodwatts.com/i-fixed-web3-onboarding</link><guid isPermaLink="true">https://blog.jarrodwatts.com/i-fixed-web3-onboarding</guid><category><![CDATA[Smart Contracts]]></category><category><![CDATA[Web3]]></category><category><![CDATA[account abstraction]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[React]]></category><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Tue, 09 May 2023 02:09:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1683598151486/e87ee7ed-d02c-4e8c-ad11-7f120c130b15.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this guide, I'll show you how to create a web3 onboarding experience that allows users to interact with your smart contracts <mark>without ever creating their own wallet.</mark></p>
<p>I'll walk through how to:</p>
<ul>
<li><p>Create a smart wallet factory contract (using EIP-4337 account abstraction)</p>
</li>
<li><p>Create new smart wallets on-demand for users from the factory</p>
</li>
<li><p>Allow users to interact with a smart contract from their created smart wallets</p>
</li>
<li><p>Bonus: generate EOA wallets for users under the hood - for a signless UX!</p>
</li>
</ul>
<p>Let's dive into it.</p>
<h2 id="heading-recap-whats-account-abstraction-again">Recap: what's account abstraction again?</h2>
<p>If you aren't already familiar with account abstraction or EIP-4337 in particular, check out my previous blog post for a beginner-friendly introduction:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://blog.jarrodwatts.com/what-is-account-abstraction-and-how-does-eip-4337-work">https://blog.jarrodwatts.com/what-is-account-abstraction-and-how-does-eip-4337-work</a></div>
<p> </p>
<p>TLDR: EIP-4337 adds several important features to better support smart wallets:</p>
<ol>
<li><p><code>UserOperation</code>: A new, special kind of operation that gets sent to a new mempool (a waiting zone to be picked up by nodes) called the "alt mempool".</p>
</li>
<li><p><code>Bundlers</code>: Nodes that bundle together <code>UserOperations</code> from the alt mempool, and send them to a <code>Entry Point</code> smart contract for them to be executed.</p>
</li>
<li><p><code>Entry Point</code>: A smart contract responsible for executing bundles of <code>UserOperations</code> that were submitted by bundlers.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1674449123541/87bef380-1733-4feb-bf6c-52edbef6f521.png?auto=compress,format&amp;format=webp" alt="summary of account abstraction in eip-4337" /></p>
<h2 id="heading-implementing-account-abstraction">Implementing Account Abstraction</h2>
<p>All this sounds great, but how do we implement this in a real-world application?</p>
<p>That's what we're going to cover in this guide, we'll break it into two parts:</p>
<ol>
<li><p>Creating &amp; deploying the smart wallet factory contract.</p>
</li>
<li><p>Building a web3 application that creates wallets for users under the hood and allows them to interact with our app from their generated wallets!</p>
</li>
</ol>
<p>Let's get started.</p>
<h2 id="heading-creating-a-smart-wallet-factory-contract">Creating a Smart Wallet Factory Contract</h2>
<p>The first thing we'll do is create a factory contract, responsible for the creation of new smart wallet contracts. By using a factory, we can deploy new smart wallets for users on demand; simply by asking the factory to create a new one.</p>
<p>To create a factory smart contract, head to the <a target="_blank" href="https://thirdweb.com/explore">thirdweb Explore page</a>, and scroll down to the "Smart Wallet" section:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683251044263/36315bca-1a39-40fe-b76f-4595669c13c7.png" alt class="image--center mx-auto" /></p>
<p>Select the <a target="_blank" href="https://thirdweb.com/thirdweb.eth/AccountFactory">Simple Wallet Factory</a> smart contract, and click <code>Deploy now</code>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683251184743/2eb14bc0-7ace-46ce-b56c-a43af7d8ddfd.png" alt class="image--center mx-auto" /></p>
<p>Leave the default value for the <code>_entrypoint</code> parameter, and click <code>Deploy Now</code> again!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683251246837/0e7655ae-195b-48b3-9e7b-7dc27178a4c9.png" alt class="image--center mx-auto" /></p>
<p>Deploy to one of the <a target="_blank" href="https://portal.thirdweb.com/wallet/smart-wallet#supported-chains">smart wallet supported chains</a> such as Mumbai or Goerli.</p>
<p><em>In the future, all EVM chains will be supported, but currently, only 6 have the smart wallet infrastructure available to use.</em></p>
<p>Once deployed, you'll be taken to the dashboard for your smart contract:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683251885167/05d8286e-1891-4a41-a229-3e350987a5b5.png" alt class="image--center mx-auto" /></p>
<p>Woo! 🥳 That's step one complete, we now have our own smart wallet factory contract deployed to the blockchain.</p>
<h3 id="heading-how-the-wallet-factory-works">How the Wallet Factory Works</h3>
<p>For those curious about how this smart contract works, this section is for you.</p>
<p>If you head to the <code>Sources</code> tab on your contract dashboard, you can see that the <a target="_blank" href="https://github.com/thirdweb-dev/contracts/blob/main/contracts/smart-wallet/non-upgradeable/AccountFactory.sol"><code>AccountFactory.sol</code></a> contract inherits the <a target="_blank" href="https://github.com/thirdweb-dev/contracts/blob/main/contracts/smart-wallet/utils/BaseAccountFactory.sol"><code>BaseAccountFactory.sol</code></a> contract; which is what provides us with the core functionality.</p>
<p>This contract includes features such as:</p>
<ul>
<li><p><code>createAccount</code>: To produce a new smart wallet contract.</p>
</li>
<li><p><code>addSigner</code> and <code>removeSigner</code>: To control which signers can act on behalf of a smart wallet.</p>
</li>
</ul>
<p>Each time <code>createAccount</code> is called, a new <a target="_blank" href="https://github.com/thirdweb-dev/contracts/blob/main/contracts/smart-wallet/non-upgradeable/Account.sol"><code>Account</code></a> contract is deployed and initialized.</p>
<p>The <code>Account.sol</code> smart contract is the contract that gets produced by the factory.</p>
<p>It contains the functions required to be an EIP-4337 compatible smart wallet such as <code>validateUserOp</code> to confirm the validity of the operation, and <code>execute</code> to run the logic defined in the operation.</p>
<h3 id="heading-whys-this-matter">Why's this Matter?</h3>
<p>What we're going to do with this factory is generate smart wallets for users under the hood. We'll perform a two-step process to easily onboard users into the application:</p>
<ol>
<li><p>Generate a new EOA wallet for the user and store it on their machine</p>
</li>
<li><p>Generate a smart wallet for the user, using the wallet from step 1's <strong>signer</strong> as a valid signer for the smart wallet.</p>
</li>
</ol>
<p>This way, the user will interact with our application from their generated smart wallet. By using the signer of the generated EOA to approve transactions, we can hide any prompts or approvals from the user.</p>
<h2 id="heading-creating-the-application">Creating the Application</h2>
<p>We'll be creating a Next.js + TypeScript application with the <a target="_blank" href="https://portal.thirdweb.com/react">thirdweb React SDK</a> installed to add our web3 features and capabilities.</p>
<p>To get started, create a new project with the SDK pre-configured by running the following command from your terminal:</p>
<pre><code class="lang-bash">npx thirdweb create app --evm --next --ts
</code></pre>
<p><em>You don't have to use Next.js or TypeScript, these are just my personal preferences.</em></p>
<p>Once the project is created, we're ready to start adding the connect wallet UI and integrate our account factory smart contract.</p>
<h3 id="heading-get-a-thirdweb-developer-api-key">Get a thirdweb Developer API Key</h3>
<p>From the <a target="_blank" href="https://thirdweb.com/dashboard/api-keys">thirdweb dashboard</a>, connect your wallet and sign a message to get an API key; we'll need it for the next step.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683260971182/ab431105-8944-4ae7-bae5-7129b8337efe.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-add-smart-wallet-support">Add Smart Wallet Support</h3>
<p>Back in our application, head to the <code>_app.tsx</code> page and change the <code>activeChain</code> to be <code>mumbai</code>, or one of the other <a target="_blank" href="https://portal.thirdweb.com/wallet/smart-wallet#supported-chains">currently supported chains</a>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { ThirdwebProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"@thirdweb-dev/react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { AppProps } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/app"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../styles/globals.css"</span>;

<span class="hljs-keyword">const</span> activeChain = <span class="hljs-string">"mumbai"</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> (
    &lt;ThirdwebProvider activeChain={activeChain}&gt;
      &lt;Component {...pageProps} /&gt;
    &lt;/ThirdwebProvider&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> MyApp;
</code></pre>
<p>The <a target="_blank" href="https://portal.thirdweb.com/react/react.thirdwebprovider"><code>ThirdwebProvider</code></a> component allows us to define a <code>supportedWallets</code> prop; to specify which <a target="_blank" href="https://portal.thirdweb.com/wallet">wallets</a> we want to support in the application. For us, we're going to specify that we want to support <a target="_blank" href="https://portal.thirdweb.com/wallet/smart-wallet">smart wallets</a>.</p>
<p>Your code should now looks like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { AppProps } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/app"</span>;
<span class="hljs-keyword">import</span> { smartWallet, ThirdwebProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"@thirdweb-dev/react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../styles/globals.css"</span>;

<span class="hljs-keyword">const</span> activeChain = <span class="hljs-string">"mumbai"</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> (
    &lt;ThirdwebProvider
      activeChain={activeChain}
      supportedWallets={[
        smartWallet({
          factoryAddress: <span class="hljs-string">"xxx"</span>, <span class="hljs-comment">// Address of your account factory smart contract</span>
          thirdwebApiKey: <span class="hljs-string">"xxx"</span>, <span class="hljs-comment">// The API key you got from the previous step</span>
          gasless: <span class="hljs-literal">true</span>,
        }),
      ]}
    &gt;
      &lt;Component {...pageProps} /&gt;
    &lt;/ThirdwebProvider&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> MyApp;
</code></pre>
<h3 id="heading-create-the-connect-wallet-button">Create the Connect Wallet Button</h3>
<p>On the <code>index.tsx</code> page, let's display a connect wallet button now. The thirdweb React SDK includes a <code>ConnectWallet</code> component, which reads the <code>supportedWallets</code> we just defined, and displays all of the supported options in a modal.</p>
<p>Simply import and render the <code>ConnectWallet</code> component on the home page:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { ConnectWallet } <span class="hljs-keyword">from</span> <span class="hljs-string">"@thirdweb-dev/react"</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">const</span> Home: NextPage = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> &lt;ConnectWallet /&gt;;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>Now let's preview our homepage by running <code>npm run dev</code> and visiting <a target="_blank" href="http://localhost:300/"><code>localhost:3000</code></a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683521024167/f163b224-2597-46f0-8ddb-e4525fa99e0c.png" alt class="image--center mx-auto" /></p>
<p>Voilà! Once we connect with a personal wallet (an EOA), we are connected to a smart wallet account. The address you see from the connect wallet button is the wallet address of your smart wallet account:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683521242042/c2daeaa8-560b-4ca2-8710-9f64ba5cb61c.png" alt class="image--center mx-auto" /></p>
<p><em>Note:</em> <em>This is a deterministic address; meaning this</em> <strong><em>will</em></strong> <em>be the address of the smart contract for this EOA/signer</em>, <em>but the actual contract is not deployed by the factory until a transaction is initiated by this smart wallet. We know the contract address ahead of time by using the</em> <a target="_blank" href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/Clones.sol#L61-L77"><em>predictDeterministicAddress</em></a> <em>function.</em></p>
<p>We can now interact with any smart contract such as an NFT drop directly from our smart contract wallet, and it will go through the full EIP-4337 flow.</p>
<p>I'll demo that process in the final section of this guide; showing you how our <code>UserOperation</code> gets picked up by the bundler, and sent to the entry point smart contract.</p>
<p>But first, let's talk about onboarding. With this setup, we still ask the user to provide an EOA before generating a smart wallet for them. Let's see how we can fix this.</p>
<h2 id="heading-improving-the-onboarding-experience">Improving the Onboarding Experience</h2>
<p>You might be saying something like "Isn't the point of account abstraction to improve onboarding? If users still need to have an EOA like MetaMask, what's the point of all this?"</p>
<p>The app we've built so far allows users to interact with our application using a smart wallet that gets generated for them. However, we still require users to connect a personal wallet / EOA beforehand.</p>
<p>This is because smart wallets still require a signature from one of the smart wallet's approved signers to confirm the action taking place on the smart contract.</p>
<p>Rather than asking users to provide their own wallet to act as a signer for the smart wallet we generate, let's also generate an EOA wallet, and use that generated wallet's signer as a signer for the smart wallet!</p>
<p>Introducing... local wallets!</p>
<h3 id="heading-local-wallets">Local Wallets</h3>
<p>The <a target="_blank" href="https://portal.thirdweb.com/wallet/local-wallet">local wallet</a> is a non-custodial solution that creates wallets for users under the hood and stores the wallet's private key on the device.</p>
<p>This way, as the app developer, we are creating wallets for the user under the hood without them knowing, and storing the wallet's private key on the user's device.</p>
<p>By combining the local wallet with the smart wallet, we can provide a smoother experience, that looks like this:</p>
<ol>
<li><p>We generate an EOA wallet for the user under the hood.</p>
</li>
<li><p>We <em>then</em> generate a smart wallet for the user under the hood (<em>again, it is not actually deployed until it is required).</em></p>
</li>
<li><p>The generated EOA is a signer for the generated smart wallet.</p>
</li>
<li><p>The user interacts with our app without ever signing messages or approving transactions since we (the app developer) have access to their local wallet signer.</p>
</li>
</ol>
<p>To replace the personal wallet step with this local wallet flow, we simply add an array of <code>personalWallets</code> to the <code>smartWallet</code> we set up earlier in the <code>_app.tsx</code> page, like so:</p>
<pre><code class="lang-typescript"><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> (
    &lt;ThirdwebProvider
      activeChain={activeChain}
      supportedWallets={[
        smartWallet({
          factoryAddress: <span class="hljs-string">"xxx"</span>,
          thirdwebApiKey: <span class="hljs-string">"xxx"</span>,
          gasless: <span class="hljs-literal">true</span>,
          <span class="hljs-comment">// Local wallet as the only option for EOA</span>
          personalWallets: [
            localWallet({
              persist: <span class="hljs-literal">true</span>,
            }),
          ],
        }),
      ]}
    &gt;
      &lt;Component {...pageProps} /&gt;
    &lt;/ThirdwebProvider&gt;
  );
}
</code></pre>
<p>Here, we're saying that the <em>only</em> option users have to connect with a personal wallet is a local wallet; one that we're going to generate for them.</p>
<p>On the UI, this shows the "Continue as guest" option to our users; which asks them to set up a password to secure their wallet on the device.</p>
<p>Users can re-enter this password next time they want to interact with our application to access the same wallet:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683524343441/bc72a9f2-6478-428b-9e7f-baa71b97c27d.png" alt class="image--center mx-auto" /></p>
<p>Now, we generate both the EOA <em>and</em> the smart wallet for the user. 🔥</p>
<p>When users interact with our contracts from within the application, they never see a "sign message" or "approve transaction" prompt!</p>
<p>The actions of the smart contract wallet are automatically signed by the generated EOA under the hood! Let's take a look.</p>
<h2 id="heading-final-demo">Final Demo</h2>
<p><em>View the demo:</em> <a target="_blank" href="https://twitter.com/jarrodWattsDev/status/1655460223413522434"><em>https://twitter.com/jarrodWattsDev/status/1655460223413522434</em></a></p>
<p>To showcase this process, I deployed a simple <a target="_blank" href="https://thirdweb.com/mumbai/0x5523B2CB564579aAf2947B8d08e2187ff35aE4b2">NFT Drop smart contract</a> to view how users can now interact with our app and perform an action such as minting an NFT without ever connecting a wallet or signing/approving a transaction.</p>
<p>Let's view the full flow from a user perspective.</p>
<ol>
<li><p>I click "Connect Wallet", type in a password, and the application generates an EOA wallet for me. Meaning I don't need to set up any browser extension/wallet.</p>
</li>
<li><p>A smart wallet gets generated for me under the hood. My EOA from step one is a valid signer for this smart wallet.</p>
</li>
<li><p>I click "Mint NFT", acting on behalf of my smart wallet.</p>
<ul>
<li><p>The app uses my generated EOA to sign the message under the hood.</p>
</li>
<li><p>This approves the transaction for the smart wallet (since my EOA signer is a valid signer for the smart wallet).</p>
</li>
</ul>
</li>
</ol>
<p>From here, we kick off the EIP-4337 account abstraction flow.</p>
<ol>
<li><p>After our EOA signs the message under the hood, a <code>UserOperation</code> is submitted to the alt mempool, containing the information that we want to mint an NFT to the smart wallet.</p>
</li>
<li><p>The bundler picks up this <code>UserOperation</code>, batches them together with other ones, and submits them to the entry point smart contract.</p>
</li>
<li><p>The entry point smart contract runs its <code>handleOps</code> function, which runs two functions on our smart wallet contract:</p>
<ul>
<li><p><code>validateUserOps</code>: Does this have a valid signature from one of my signers? (Yes, our app signs the message under the hood)</p>
</li>
<li><p><code>execute</code>: Since this looks legit, let's actually run the code.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-but-how-is-it-gasless">But... How is it Gasless?</h3>
<p>After the <code>execute</code> function is run by the smart wallet, typically this is the point that the smart wallet contract would pay the gas fee for the transaction to take place.</p>
<p>However, since we set the <code>gasless</code> flag to be <code>true</code> in our application, this enables thirdweb's <a target="_blank" href="https://eips.ethereum.org/EIPS/eip-4337#paymasters">paymaster</a> infrastructure to be utilized. Paymasters are smart contracts that can sponsor transactions for other users; AKA, pay the gas fee.</p>
<p>This allows our smart wallet to execute valid transactions without being pre-loaded with funds, and have the paymaster smart contract handle the gas fees; without using a centralized service such as a relayer!</p>
<p>You can view the full <a target="_blank" href="https://github.com/thirdweb-dev/contracts/blob/main/contracts/smart-wallet/interfaces/IPaymaster.sol"><code>IPaymaster.sol</code> interface on thirdweb's GitHub</a>.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>We've covered a lot in this guide, from generating EOA's, smart wallet factories, and EIP-4337 paymasters. I believe these will be important concepts for us to know in the coming months as we start to create better onboarding experiences for our users.</p>
<p>The bar to enter web3 applications is too high, and account abstraction offers a solution that is available to us now. It's up to us as developers to lower these gates and take the pain away from users by handling these complexities under the hood.</p>
<p>All of the resources I've referenced in this are open source and can be found below.</p>
<p>If you enjoy this kind of content, please consider <a target="_blank" href="https://blog.jarrodwatts.com/">following my blog</a> for more written content and follow me on <a target="_blank" href="https://twitter.com/jarrodWattsDev">Twitter</a> for video and short-form stuff.</p>
<p>Thank you for reading!</p>
<h3 id="heading-links-amp-resources">Links &amp; Resources</h3>
<p><strong>Smart Contracts</strong></p>
<ul>
<li><p><a target="_blank" href="https://github.com/thirdweb-dev/contracts/blob/main/contracts/smart-wallet/non-upgradeable/AccountFactory.sol">thirdweb AccountFactory.sol</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/thirdweb-dev/contracts/blob/main/contracts/smart-wallet/non-upgradeable/Account.sol">thirdweb Account.sol</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/thirdweb-dev/contracts/blob/main/contracts/smart-wallet/interfaces/IPaymaster.sol">thirdweb IPaymaster.sol</a></p>
</li>
</ul>
<p><strong>Application</strong></p>
<ul>
<li><p><a target="_blank" href="https://portal.thirdweb.com/react">thirdweb React SDK</a></p>
</li>
<li><p><a target="_blank" href="https://portal.thirdweb.com/wallet">thirdweb Wallet SDK</a></p>
</li>
</ul>
<p><strong>Other Tools</strong></p>
<ul>
<li><a target="_blank" href="https://portal.thirdweb.com/cli">thirdweb CLI</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[The Ultimate Guide to Building on Polygon zkEVM]]></title><description><![CDATA[In this guide, I'll show you how to create a full-stack web3 application on the Polygon zkEVM. By the end of the guide, we'll cover how to:

Set up our wallet to connect to the Polygon zkEVM

Create and deploy a smart contract to the Polygon zkEVM

B...]]></description><link>https://blog.jarrodwatts.com/the-ultimate-guide-to-building-on-polygon-zkevm</link><guid isPermaLink="true">https://blog.jarrodwatts.com/the-ultimate-guide-to-building-on-polygon-zkevm</guid><category><![CDATA[Web3]]></category><category><![CDATA[Ethereum]]></category><category><![CDATA[polygon zkEVM]]></category><category><![CDATA[thirdweb]]></category><category><![CDATA[Smart Contracts]]></category><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Mon, 27 Mar 2023 21:24:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1679895546481/8842582c-7ff5-47a4-a5d4-cbe1cd02bdb2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this guide, I'll show you how to create a full-stack web3 application on the <a target="_blank" href="https://wiki.polygon.technology/docs/zkEVM/">Polygon zkEVM</a>. By the end of the guide, we'll cover how to:</p>
<ul>
<li><p>Set up our wallet to connect to the Polygon zkEVM</p>
</li>
<li><p>Create and deploy a smart contract to the Polygon zkEVM</p>
</li>
<li><p>Build a React application to connect and interact with the smart contract</p>
</li>
</ul>
<p>Let's get started!</p>
<h2 id="heading-what-is-the-polygon-zkevm">What is the Polygon zkEVM?</h2>
<p>If you're not already familiar, Polygon zkEVM is an EVM-compatible zero-knowledge <a target="_blank" href="https://ethereum.org/en/developers/docs/scaling/#rollups">rollup</a>. This means it acts as a scaling solution to the <a target="_blank" href="https://ethereum.org/en/developers/docs/">Ethereum</a> blockchain; improving its scalability by enabling more transactions per second and significantly cheaper <a target="_blank" href="https://ethereum.org/en/developers/docs/gas/">gas fees</a>.</p>
<p>As developers, an important component of the Polygon zkEVM is its <a target="_blank" href="https://ethereum.org/en/developers/docs/evm/"><strong>EVM</strong></a> <strong>compatibility</strong>, which means we can use the same tooling we know and love such as <a target="_blank" href="https://docs.soliditylang.org/en/v0.8.19/">Solidity</a> to build smart contracts and deploy them to the network; something that was previously not possible with ZK rollups.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://blog.jarrodwatts.com/zkevms-and-the-race-to-scale-ethereum">https://blog.jarrodwatts.com/zkevms-and-the-race-to-scale-ethereum</a></div>
<p> </p>
<p>Now we've got the basics down, let's dive into the building.</p>
<h2 id="heading-setting-up-the-polygon-zkevm">Setting Up the Polygon zkEVM</h2>
<p>The Polygon zkEVM uses a <a target="_blank" href="https://ethereum.org/en/developers/docs/bridges/">bridge</a> to transfer ETH from Ethereum to the Polygon zkEVM rollup.</p>
<p>In this guide, we'll be using the <a target="_blank" href="https://ethereum.org/en/developers/docs/networks/#ethereum-testnets">testnet</a> to demonstrate the process, however the process is the same on mainnet, except you are dealing with real funds; I'll provide you with resources for both testnet and mainnet options.</p>
<p>Before we begin the bridging process, you'll need a wallet setup with some test <em>(or real) ETH loaded in</em>. I won't cover these topics as I'm assuming you likely already have this setup. Just in case you don't, below are some resources to help you:</p>
<ol>
<li><p><a target="_blank" href="https://support.metamask.io/hc/en-us/articles/360015489531-Getting-started-with-MetaMask">Getting started with MetaMask</a></p>
</li>
<li><p><a target="_blank" href="https://www.alchemy.com/overviews/goerli-faucet">How to get testnet ETH using a faucet</a></p>
</li>
</ol>
<h3 id="heading-bridge-funds-to-the-polygon-zkevm-network">Bridge Funds to the Polygon zkEVM Network</h3>
<p>With a wallet setup and either real ETH or testnet ETH in it, you're ready to begin the bridging process. Head over to the bridge URL below to get started <em>(pick either testnet or mainnet depending on which one you want)</em>:</p>
<ul>
<li><p><a target="_blank" href="https://public.zkevm-test.net/login?ref=blog.jarrodwatts.com">Testnet bridge</a></p>
</li>
<li><p><a target="_blank" href="https://bridge.zkevm-rpc.com/">Mainnet bridge</a></p>
</li>
</ul>
<p>On the bridge, click the "Add to MetaMask" button to add the network information about the zkEVM to your wallet. Click "Approve" and "Switch Network" as the prompts appear.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679874781768/e551a94b-db7d-4758-9227-89b00410b9a2.png" alt="Add polygon zkEVM network to wallet" class="image--center mx-auto" /></p>
<p>Next, connect your wallet to the bridge by clicking on the button below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679874892633/ddda7137-e646-4356-a151-583a436676db.png" alt="connect wallet to Polygon zkEVM bridge" class="image--center mx-auto" /></p>
<p>Select the Ethereum network as the "From" network; to specify you are bridging funds <em>from</em> Ethereum <em>to</em> the zkEVM.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679874965698/68020d56-3712-4782-b96c-08c60e790d94.png" alt="select Ethereum as the &quot;from&quot; network" class="image--center mx-auto" /></p>
<p>Enter the amount of ETH you want to bridge, e.g. <code>0.005 ETH</code>, and click "Continue", and "Bridge" in the confirmation step.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679875134642/01f1e76b-bbf2-42a6-b0fe-1697a17741cf.png" alt="bridge funds from eth to zkevm" class="image--center mx-auto" /></p>
<p>Approve the transaction to initiate the bridging process.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679875214070/28f4d02a-acbe-45b7-bf40-90e0c3d9670b.png" alt class="image--center mx-auto" /></p>
<p>Finally, click "Finalise" and approve the transaction to complete the bridging process.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679884286546/f2812fbb-90d5-4e6c-b523-11ae98b65689.png" alt class="image--center mx-auto" /></p>
<p>Once completed, you should see the funds available in your wallet:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679884371279/116bc2f9-ad56-4265-976f-e952711431f2.png" alt class="image--center mx-auto" /></p>
<p>Nice! Now we've got some funds to use on the zkEVM. Remember you can send funds back to Ethereum through the bridge at any time; one of the awesome benefits of ZK rollups!</p>
<h2 id="heading-creating-a-smart-contract-on-polygon-zkevm">Creating a Smart Contract on Polygon zkEVM</h2>
<p>Now we've got some funds setup, we're ready to start building! First, we're going to create a smart contract. In this guide, we'll build a simple <a target="_blank" href="https://eips.ethereum.org/EIPS/eip-721">ERC721</a> NFT smart contract; but you can create anything you like.</p>
<h3 id="heading-creating-the-hardhat-project">Creating the Hardhat project</h3>
<p>We'll use <a target="_blank" href="https://hardhat.org/">Hardhat</a> in this guide to keep it simple, but this process will also work for <a target="_blank" href="https://book.getfoundry.sh/forge/">Foundry/Forge</a> too.</p>
<p>To begin, let's create a new Solidity project by using the <a target="_blank" href="https://portal.thirdweb.com/cli">thirdweb CLI</a>.</p>
<p>Run the following command in your terminal to get started:</p>
<pre><code class="lang-bash">npx thirdweb create contract
</code></pre>
<p>This command kicks off an interactive set of questions to create your Solidity project with the framework and standards of your choice.</p>
<p>Below, I'm using Hardhat with a basic ERC721 NFT smart contract as a starting point:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679885174169/e4504d02-596a-4062-8d34-25600f85a721.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-creating-the-nft-collection-smart-contract">Creating the NFT Collection smart contract</h3>
<p>If we open this project in our text editor, we can see we have a barebones Hardhat project with a smart contract in the <code>/contracts/MyContract.sol</code> file, containing the following 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">"@thirdweb-dev/contracts/base/ERC721Base.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Contract</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC721Base</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> _name,
        <span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> _symbol,
        <span class="hljs-keyword">address</span> _royaltyRecipient,
        <span class="hljs-keyword">uint128</span> _royaltyBps
    </span>) <span class="hljs-title">ERC721Base</span>(<span class="hljs-params">_name, _symbol, _royaltyRecipient, _royaltyBps</span>) </span>{}
}
</code></pre>
<p>This is using thirdweb's <a target="_blank" href="https://portal.thirdweb.com/contractkit/base-contracts/erc-721/erc721base">ERC721 base contract</a> which provides code for us to implement all the features of the ERC721 NFT standard, along with the <a target="_blank" href="https://www.erc721a.org/">ERC721A</a> optimization to the standard.</p>
<p>Feel free to customize, override, or add any features you want to; or of course, build a completely different smart contract!</p>
<h2 id="heading-deploying-a-smart-contract-to-polygon-zkevm">Deploying a Smart Contract to Polygon zkEVM</h2>
<p>Now you've created the smart contract, you're ready to ship it to the zkEVM. To do this, we'll use <a target="_blank" href="https://portal.thirdweb.com/deploy">thirdweb deploy</a>.</p>
<p>Run the following command <em>(from the same directory as your smart contract)</em> to begin the deployment flow:</p>
<pre><code class="lang-bash">npx thirdweb deploy
</code></pre>
<p>This command completes all the steps required to prepare our contract:</p>
<ul>
<li><p>Compiles the smart contract using Hardhat</p>
</li>
<li><p>Uploads the smart contract ABI to IPFS.</p>
</li>
<li><p>Opens the <a target="_blank" href="https://thirdweb.com/dashboard">thirdweb dashboard</a> to deploy from your connected wallet.</p>
</li>
</ul>
<p>No private key, RPC URLs, or config required!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679885959755/46af549a-5177-46d0-8e2f-bd516da9fbf2.png" alt class="image--center mx-auto" /></p>
<p>Once this process is complete, open the URL that gets printed at the end of the command to be taken to the thirdweb dashboard.</p>
<h3 id="heading-populate-the-contracts-constructor-parameters">Populate the Contract's Constructor Parameters</h3>
<p>Connect your wallet to the dashboard, and provide values for any of your smart contract's <a target="_blank" href="https://www.tutorialspoint.com/solidity/solidity_constructors.htm">constructor parameters</a>. If you're following along with the NFT collection contract, the parameters are outlined below:</p>
<ul>
<li><p><strong>Name</strong>: the name of your smart contract</p>
</li>
<li><p><strong>Symbol</strong>: Ticker symbol for each token in the contract, e.g. ETH or BAYC</p>
</li>
<li><p><strong>Royalty Recipient</strong>: Wallet address that receives funds from royalty fees</p>
</li>
<li><p><strong>Royalty Bps</strong>: What percentage royalty fee to take, e.g. 500 = 5%</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679886102463/0e42d4af-d152-441f-90f4-bc71d20dc216.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-select-the-polygon-zkevm-network">Select the Polygon zkEVM Network</h3>
<p>To specify that we want to deploy to the Polygon zkEVM, click "Configure Networks":</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679886271150/d950b1e4-8161-4e50-9de7-b69a0b90136a.png" alt class="image--center mx-auto" /></p>
<p>Search for "Polygon zkEVM", and you'll see options for both the Polygon zkEVM Testnet and Polygon zkEVM Mainnet:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679947568679/2a7040e5-a131-4ffa-8f29-953490cea271.png" alt class="image--center mx-auto" /></p>
<p>Select the network and click "Add Network" to add the zkEVM as a deployment option. Close the modal and head back to the deploy page, and click "Deploy Now":</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679886457784/0c94f938-31eb-4ba9-9872-4a16e6a1a1f1.png" alt class="image--center mx-auto" /></p>
<p>Finally, approve the "Contract Deployment" transaction.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679886502891/e954470c-0d62-4165-a3d6-69a52981e730.png" alt class="image--center mx-auto" /></p>
<p>Nice! You just deployed a smart contract to the zkEVM! 🥳 Feel free to explore the dashboard, where you can view and execute all the functionality of your smart contract from the UI.</p>
<h2 id="heading-creating-a-web3-app-on-polygon-zkevm">Creating A Web3 App on Polygon zkEVM</h2>
<p>Now we've shipped our smart contract, let's create an application that can connect to users' wallets, and have them interact with our smart contract.</p>
<p>To do that, we'll again use the <a target="_blank" href="https://portal.thirdweb.com/cli">thirdweb CLI</a> to create a frontend application with the <a target="_blank" href="https://portal.thirdweb.com/react">thirdweb React SDK</a> installed.</p>
<p>Run the following command in your terminal to get started:</p>
<pre><code class="lang-bash">npx thirdweb create app
</code></pre>
<p>This will ask you a series of questions about the framework and languages you want to use to create your front-end application. In this guide, we'll use <a target="_blank" href="https://nextjs.org/">Next.js</a> and JavaScript; but feel free to use what you're comfortable with!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679887174369/20d4fcc5-19bd-43c9-a0a0-15c1858fb03e.png" alt class="image--center mx-auto" /></p>
<p>Open up the newly created application in your text editor.</p>
<h3 id="heading-connect-the-app-to-polygon-zkevm">Connect the App to Polygon zkEVM</h3>
<p>The first thing we'll need to do is configure the <a target="_blank" href="https://portal.thirdweb.com/react/react.thirdwebprovider"><code>ThirdwebProvider</code></a> to use the Polygon zkEVM network. We'll use the <a target="_blank" href="https://www.npmjs.com/package/@thirdweb-dev/chains"><code>@thirdweb-dev/chains</code></a> package to manage this connection for us.</p>
<p>From within your application, run the following command:</p>
<pre><code class="lang-bash">npm install @thirdweb-dev/chains@nightly
</code></pre>
<p>This package has over 700 chains for us to use and connect to, including the Polygon zkEVM testnet and mainnet.</p>
<p>Next, within the <code>_app.js</code> file, <em>(or</em> <code>Index.js</code> file <em>for CRA/vite)</em>, import the <code>PolygonZkevmTestnet</code> from the chains package and set it as the <a target="_blank" href="https://portal.thirdweb.com/react/react.thirdwebprovider#activechain-recommended"><code>activeChain</code></a> prop:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { ThirdwebProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"@thirdweb-dev/react"</span>;
<span class="hljs-comment">// Import the Polygon zkeVM chain and set it as the activeChain</span>
<span class="hljs-comment">// PolygonZkevmTestnet = testnet</span>
<span class="hljs-comment">// PolygonZkevmBeta = mainnet</span>
<span class="hljs-keyword">import</span> { PolygonZkevmTestnet, PolygonZkevmBeta } <span class="hljs-keyword">from</span> <span class="hljs-string">"@thirdweb-dev/chains"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../styles/globals.css"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyApp</span>(<span class="hljs-params">{ Component, pageProps }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ThirdwebProvider</span> <span class="hljs-attr">activeChain</span>=<span class="hljs-string">{PolygonZkevmTestnet}</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>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> MyApp;
</code></pre>
<p>This manages our connection to the blockchain with a free <a target="_blank" href="https://portal.thirdweb.com/glossary/rpc">RPC URL</a> out of the box.</p>
<h3 id="heading-connect-to-the-smart-contract">Connect to the Smart Contract</h3>
<p>Head to the home page at <code>index.js</code> <em>(or</em> <code>App.js</code><em>)</em> and connect to the smart contract you deployed using its contract address via the <a target="_blank" href="https://portal.thirdweb.com/react/react.usecontract"><code>useContract</code></a> hook.</p>
<p><em>Hint: you can get the contract address from the thirdweb dashboard.</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679887868121/b3a29e15-504d-4065-a14b-affc6c4392c1.png" alt class="image--center mx-auto" /></p>
<p>Here's how our code looks so far:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useContract } <span class="hljs-keyword">from</span> <span class="hljs-string">"@thirdweb-dev/react"</span>;

<span class="hljs-comment">// Place your smart contract address here!</span>
<span class="hljs-keyword">const</span> contractAddress = <span class="hljs-string">"0x66CC8aB6a3bFD1e1510d4ED2115b26E2f13fdcfC"</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-comment">// Connect to your smart contract with the useContract hook</span>
  <span class="hljs-keyword">const</span> { contract } = useContract(contractAddress);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Hello world!<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}
</code></pre>
<p>To add the capability to connect to users' wallets, we could use the <a target="_blank" href="https://portal.thirdweb.com/react/react.connectwallet"><code>ConnectWallet</code> UI component</a>, but we're going to use the <a target="_blank" href="https://portal.thirdweb.com/react/react.web3button"><code>Web3Button</code> UI Component</a> instead, to allow the contract admin to mint an NFT after they've connected.</p>
<h3 id="heading-mint-an-nft-using-the-react-sdk">Mint An NFT Using the React SDK</h3>
<p>The <code>Web3Button</code> connects to the user's wallets, switches them to the correct network (polygon zkeVM), and <em>then</em> calls some functionality on our smart contract when clicked.</p>
<p>First, import the button component from the <code>@thirdweb-dev/react</code> package, then provide the <a target="_blank" href="https://portal.thirdweb.com/react/react.web3button#contractaddress-required"><code>contractAddress</code></a> and <a target="_blank" href="https://portal.thirdweb.com/react/react.web3button#action-required"><code>action</code></a> props. The <code>action</code> is what occurs when the button is clicked; i.e. where we're going to mint our NFT.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useContract, Web3Button } <span class="hljs-keyword">from</span> <span class="hljs-string">"@thirdweb-dev/react"</span>;

<span class="hljs-keyword">const</span> contractAddress = <span class="hljs-string">"0x66CC8aB6a3bFD1e1510d4ED2115b26E2f13fdcfC"</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> { contract } = useContract(contractAddress);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Web3Button</span>
      <span class="hljs-attr">contractAddress</span>=<span class="hljs-string">{contractAddress}</span>
      <span class="hljs-attr">action</span>=<span class="hljs-string">{async</span> (<span class="hljs-attr">contract</span>) =&gt;</span> {
        return await contract.erc721.mint({
          name: "My zkEVM NFT",
          description: "I just minted an NFT on the Polygon zkEVM!",
          image: "your-image-url-here",
        });
      }}
    &gt;
      Mint NFT
    <span class="hljs-tag">&lt;/<span class="hljs-name">Web3Button</span>&gt;</span></span>
  );
}
</code></pre>
<p>Here, we provide the metadata of the NFT we want to mint and use the <a target="_blank" href="https://portal.thirdweb.com/typescript/sdk.erc721mintable#mint"><code>mint</code></a> function to upload and pin the metadata to IPFS before minting the NFT into the smart contract.</p>
<p>Run your application on your localhost to see the result, using <code>npm run dev</code> and visiting <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a>. Click the button and accept the transaction to mint your first NFT!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679892570325/d7c8f501-b26c-42d3-adff-b2713cc9ddd3.png" alt class="image--center mx-auto" /></p>
<p>On your contract dashboard, you can now see an NFT has been minted into the smart contract with the metadata you provided:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679892610387/87dcfbf0-3025-4313-83fd-a14ab9d0228d.png" alt class="image--center mx-auto" /></p>
<p>Awesome 🔥 we now have our very own NFT collection minted onto the polygon zkEVM network.</p>
<h3 id="heading-displaying-nfts-in-the-app">Displaying NFTs in the App</h3>
<p>Finally, we can use the thirdweb React SDK to read information from our smart contract too. In this example, we'll use the <a target="_blank" href="https://portal.thirdweb.com/react/react.usenfts"><code>useNFT</code></a> hook to read the metadata of the NFT we just minted, and the <a target="_blank" href="https://portal.thirdweb.com/react/react.thirdwebnftmedia">NFT Renderer</a> component to display it on the UI.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { ThirdwebNftMedia, useContract, useNFT } <span class="hljs-keyword">from</span> <span class="hljs-string">"@thirdweb-dev/react"</span>;

<span class="hljs-keyword">const</span> contractAddress = <span class="hljs-string">"0x66CC8aB6a3bFD1e1510d4ED2115b26E2f13fdcfC"</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> { contract } = useContract(contractAddress);
  <span class="hljs-keyword">const</span> { <span class="hljs-attr">data</span>: nft, isLoading } = useNFT(contract);

  <span class="hljs-keyword">return</span> isLoading ? (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
  ) : (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ThirdwebNftMedia</span> <span class="hljs-attr">metadata</span>=<span class="hljs-string">{nft.metadata}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{nft.metadata.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{nft.metadata.description}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Using a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">ternary operator</a>, we now display a loading state while the metadata loads from IPFS, and show the metadata of the NFT on the UI once it's loaded:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679892993891/2d015175-58b4-4f0d-97ce-0fc69d264e0e.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>That's it! We've covered everything you need to know when it comes to creating a full-stack application built on top of Polygon's new zkEVM; from setting up the network in your wallet to creating an app that allows users to connect their wallets and mint NFTs.</p>
]]></content:encoded></item><item><title><![CDATA[zkEVMs and the Race to Scale Ethereum]]></title><description><![CDATA[In the past week, the race to launch an EVM-compatible ZK rollup has been heating up:

Polygon announced the launch date for their zkEVM mainnet

zkSync launched their zkEVM mainnet (just two days later!)


Why's this happening? WTF is a zkEVM? How d...]]></description><link>https://blog.jarrodwatts.com/zkevms-and-the-race-to-scale-ethereum</link><guid isPermaLink="true">https://blog.jarrodwatts.com/zkevms-and-the-race-to-scale-ethereum</guid><category><![CDATA[Ethereum]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[zkevm]]></category><category><![CDATA[Blockchain technology]]></category><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Tue, 21 Feb 2023 00:54:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1676942739110/7e33c822-8bb3-4402-a98d-3bc267d4caf8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the past week, the race to launch an EVM-compatible ZK rollup has been heating up:</p>
<ul>
<li><p><a target="_blank" href="https://twitter.com/0xPolygon/status/1625529122561597440">Polygon announced the launch date for their zkEVM mainnet</a></p>
</li>
<li><p><a target="_blank" href="https://twitter.com/zksync/status/1626235292268240902">zkSync launched their zkEVM mainnet</a> <em>(just two days later!)</em></p>
</li>
</ul>
<p>Why's this happening? WTF is a zkEVM? How do I use one?</p>
<p>Let's dive into it.</p>
<h2 id="heading-wait-whats-wrong-with-ethereum">Wait, what's wrong with Ethereum?</h2>
<p>Ethereum Mainnet is able to process roughly <strong>15 transactions</strong> per second. We all know what this means; huge gas prices and long finality times, leading to a grim user experience.</p>
<p>Depending on how deep down the rabbit hole you are at this point, you may already be familiar with solutions to address this; sidechains, layer 2s, rollups... <em>all that good stuff</em>.</p>
<p>These were all built because Ethereum is <em>currently</em> too popular for what it is capable of handling. Despite this, the Ethereum Foundation has agreed they are not going to sacrifice security/decentralization to improve scalability.</p>
<p>This balance between decentralization, security, and scalability is known as the <a target="_blank" href="https://ethereum.org/en/upgrades/vision/">scalability trilemma</a>. The long-term vision of Ethereum is to achieve all three of these qualities.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676680857126/2bb5ac1f-96e2-4c75-9ece-67fe7afc286b.png" alt="blockchain scalability trilemma" class="image--center mx-auto" /></p>
<h2 id="heading-why-should-we-improve-scalability">Why should we improve scalability?</h2>
<p><a target="_blank" href="https://ethereum.org/en/developers/docs/scaling/">Scalability</a> refers to how well Ethereum can handle the demand for transactions to be processed. If more transactions can be processed faster, two things happen:</p>
<ol>
<li><p><a target="_blank" href="https://ethereum.org/en/developers/docs/gas/#top">Gas prices</a> go down</p>
</li>
<li><p><a target="_blank" href="https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/#finality">Finality</a> <em>(how fast your transactions are finalized)</em> gets faster</p>
</li>
</ol>
<p>So, if we're not going to sacrifice decentralization, how do we make Ethereum more scalable? There are multiple different solutions that are either already being used today, in the research/testing phase, or recently shipped to mainnet 😉.</p>
<p>Let's explore some of the existing solutions first, why they have problems of their own, and then dive into ZK EVMs as the potential "final boss" of scaling solutions.</p>
<h2 id="heading-whats-been-built-to-address-this-so-far">What's been built to address this so far?</h2>
<p>Most solutions built to address the scalability of Ethereum usually come with some kind of sacrifice in the other two qualities in the scalability trilemma.</p>
<p><em>"it scales better... buuuuuut &lt;insert downside here&gt;",</em> is usually how it goes<em>.</em></p>
<p>Let's take a closer look at each of them.</p>
<h3 id="heading-sidechains">Sidechains</h3>
<p>A sidechain is a completely separate blockchain from Ethereum, with different histories, roadmaps, and even <a target="_blank" href="https://ethereum.org/en/developers/docs/scaling/sidechains/#consensus-algorithms">consensus algorithms</a>.</p>
<p>In order for a side-chain to actually <em>be</em> a side-chain, it is required to have a two-way <a target="_blank" href="https://ethereum.org/en/bridges/">bridge</a> connecting it with Ethereum Mainnet, where data can be transferred between the two chains.</p>
<p><a target="_blank" href="https://polygon.technology/solutions/polygon-pos">Polygon's PoS</a> (<a target="_blank" href="https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/">proof-of-stake</a>) is the most popular example of a sidechain.</p>
<p>Polygon PoS boasts a ~10,000x lower gas fee per transaction, and ~450x increase in transactions per second than Ethereum. Polygon PoS is awesome. Some of the biggest brands in the world have chosen Polygon as their partner; Adidas, Meta, Stripe, Reddit, and more.</p>
<p><img src="https://pbs.twimg.com/media/FpLekSCXwAMbZec?format=jpg&amp;name=medium" alt="Partners of Polygon" /></p>
<p>However, sidechains sacrifice <em>some</em> measure of decentralization or security to achieve this higher throughput.</p>
<p>You can dive deeper into the risk assessment of scaling solutions on sites such as <a target="_blank" href="https://l2beat.com/scaling/risk">L2BEAT</a>. For example, if we take a look at Polygon PoS, we can see this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675941834613/af699227-f18e-4940-a37a-bb1cca4362ad.png" alt="Polygon PoS risk assessment L2BEAT" class="image--center mx-auto" /></p>
<p>In addition, despite these sacrifices, Polygon PoS has had struggles with scalability several times in the past.</p>
<p>For example, in 2022, a play-to-earn game called Sunflower Farmers sent gas prices skyrocketing after the game took up over 40% of the network's gas fees.</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/PhABCD/status/1478613172487602179">https://twitter.com/PhABCD/status/1478613172487602179</a></div>
<p> </p>
<p>More recently, transactions were failing from users' wallets due to incorrect gas estimations, as a result of the high demand on Polygon PoS.</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/moo9000/status/1626195644573425665">https://twitter.com/moo9000/status/1626195644573425665</a></div>
<p> </p>
<h2 id="heading-rollups">Rollups</h2>
<p>Rollups are different from sidechains in the sense that they're not "separate" from Ethereum. Instead, they publish transaction results onto Ethereum mainnet; allowing them to derive the full benefits of Ethereum's security in the process.</p>
<p>Rollups work by allowing operators to bundle multiple off-chain transactions together outside the main <a target="_blank" href="https://ethereum.org/en/developers/docs/evm/">EVM</a>, and then submit them all together to Ethereum; achieving 10 to 100 times improvements in terms of scalability.</p>
<p>On a technical level, these batches are submitted to a "rollup" smart contract that is stored on Ethereum mainnet; which keeps track of the rollup's state.</p>
<p>There are two kinds of rollups that exist today:</p>
<ol>
<li><p>Optimistic rollups</p>
</li>
<li><p>Zero Knowledge (ZK) Rollups</p>
</li>
</ol>
<p>A <a target="_blank" href="https://ethereum.org/en/developers/docs/bridges/">bridge</a> allows you to transfer funds or data between Ethereum mainnet and a rollup.</p>
<h3 id="heading-optimistic-rollups">Optimistic Rollups</h3>
<p>Optimistic rollups such as <a target="_blank" href="https://www.optimism.io/">Optimism</a> and <a target="_blank" href="https://arbitrum.io/">Arbitrum One</a> are called "optimistic" because they <strong>assume</strong> the transactions that they roll up are valid <strong>by default</strong>.</p>
<p>They don't post any proof that the transactions are valid to Ethereum. Instead, transactions are "innocent until proven guilty", which includes a fraud-proving scheme that enables the detection of invalid transactions.</p>
<p>A "challenge period" is available for parties to contest the results of a rollup transaction by submitting a <a target="_blank" href="https://ethereum.org/en/glossary/#fraud-proof"><strong>fraud-proof</strong></a> that can see whether or not a fraudulent transaction took place in that rollup.</p>
<p>If one is detected, the transactions are re-executed and the state of the rollup is updated. The party who submits the fraudulent transactions incur a penalty, creating an incentive mechanism within the ecosystem.</p>
<p><em>Okay, this sounds great. What's the downside?</em></p>
<p>Because of this challenge period, (usually around 7 days), you <strong>must wait</strong> until the challenge period is over before you can perform this withdrawal to Ethereum mainnet over the bridge.</p>
<p>There's also <em>some</em> level of reliance that at least <em>one</em> honest person is checking for fraudulent transactions to challenge the state of the rollup.</p>
<h3 id="heading-zk-rollups">ZK Rollups</h3>
<p>Alright, we're almost at the juicy part.</p>
<p>ZK rollups, unlike optimistic rollups, <strong>do</strong> post <a target="_blank" href="https://ethereum.org/en/glossary/#validity-proof">validity proofs</a> to prove the correctness of the changes they post to Ethereum mainnet.</p>
<p>These validity proofs are "zero-knowledge proofs"; meaning the details of the statement that the rollup provides can be proven as true, without revealing the actual contents of that statement, using either <a target="_blank" href="https://arxiv.org/abs/2202.06877">zk-SNARKs</a> or <a target="_blank" href="https://eprint.iacr.org/2018/046">zk-STARKs</a>.</p>
<p><a target="_blank" href="https://ethereum.org/en/developers/docs/scaling/zk-rollups/#validity-proofs-in-zk-rollups">Learn more about how validity proofs work in zk-rollups</a>.</p>
<p>This removes the requirement for a challenge period, as the transactions are provably true as soon as the rollup contract verifies the validity proof. This means you can withdraw funds from ZK rollups to Ethereum mainnet without waiting!</p>
<p><em>Awesome, but what's the catch?</em></p>
<p>Unlike the other solutions we've talked about so far, ZK Rollups are <strong>not</strong> compatible with the EVM. This means you can't just point your Solidity contract at a ZK Rollup and ship it, which you <em>can</em> do with all of the other solutions we've described.</p>
<p>Whereas, with other solutions, you can simply change the URL of your deployment script and deploy the exact same code to Ethereum, Polygon PoS, Optimism, Arbitrum, etc.</p>
<p>That's the catch. You <strong>cannot</strong> do this with ZK Rollups... <mark>Until now!</mark></p>
<p><strong>Enter, zkEVMs</strong>.</p>
<h2 id="heading-what-is-a-zkevm">What is a zkEVM?</h2>
<p>The main reason ZK rollups are not utilized is that they have not been EVM-compatible in the past, making it extremely difficult to actually build anything on them.</p>
<p>If I've done a good job explaining things so far, the name "zkEVM" is hopefully self-explanatory to you... <strong>A zkEVM is a zero-knowledge rollup, that <em>is</em> EVM compatible.</strong></p>
<p>zkEVMs enable all the benefits of a ZK Rollup, with the same developer experience of building on any other EVM chain like Polygon or Ethereum. Combining the best of both worlds, and potentially providing an answer to the scalability trilemma.</p>
<p>This technology unlocks all existing web3 dapps to simply change their deployment scripts to a different RPC URL and ship directly to the zkEVM, exactly the same way they do now.</p>
<p>zkEVMs handle the batching of transaction execution and post cryptographic proof that the result of those transactions is correct to Ethereum mainnet, all while maintaining EVM compatibility.</p>
<p>This means that every smart contract on Ethereum or Polygon PoS can now also be deployed to a zkEVM. Drastically improving the scalability of the smart contracts and the dapps that use them.</p>
<p><em>"In the medium to long term, ZK rollups will win out in all use cases as ZK-SNARK technology improves."</em> - <a target="_blank" href="https://vitalik.ca/general/2021/01/05/rollup.html">Vitalik Buterin</a></p>
<h3 id="heading-how-do-i-build-on-a-zk-evm">How do I build on a ZK EVM?</h3>
<p>With all of the hype and releases of ZK EVMs, how do you actually build on one?</p>
<p>At <a target="_blank" href="https://thirdweb.com/">thirdweb</a> <em>(where I currently work)</em>, we just shipped support for <em>any</em> EVM chain, including all the zkEVMs such as Polygon zkEVM, zkSync, Scroll and more.</p>
<p>Consider checking out the below guide I helped review by my awesome colleague and friend <a class="user-mention" href="https://hashnode.com/@avneesh0612">Avneesh Agarwal</a>, which shows you how to:</p>
<ul>
<li><p>Add a ZK EVM network to your wallet</p>
</li>
<li><p>Bridge funds from Ethereum to the ZK Rollup</p>
</li>
<li><p>Deploy your Solidity smart contract to a ZK EVM</p>
</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://blog.thirdweb.com/guides/how-to-deploy-a-smart-contract-to-polyon-zkevm-testnet/">https://blog.thirdweb.com/guides/how-to-deploy-a-smart-contract-to-polyon-zkevm-testnet/</a></div>
<p> </p>
<p>Or check out this 3-minute video to shipping an NFT collection on Polygon's zkEVM:</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/jarrodWattsDev/status/1627520959854022656">https://twitter.com/jarrodWattsDev/status/1627520959854022656</a></div>
<p> </p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>That's it! I've tried my best to condense the past few weeks of reading about Ethereum scaling solutions into a 5 minute read for you :)</p>
<p>What do you think? Are zkEVMs the holy grail for scaling Ethereum? Or are we just getting started? Let me know!</p>
<p>If you enjoyed this article, there'll be many more just like it coming soon. Consider following me to get notified when those are released!</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://hashnode.com/@JarrodWatts">https://hashnode.com/@JarrodWatts</a></div>
]]></content:encoded></item><item><title><![CDATA[How Account Abstraction Will Change Web3 UX Forever]]></title><description><![CDATA[In this post, we'll explore the issues with UX in the current web3 landscape, and dive deeper into how a proposal known as account abstraction provides a potential solution to several of the biggest problems we have today.
The reality is, a poor UX i...]]></description><link>https://blog.jarrodwatts.com/what-is-account-abstraction-and-how-does-eip-4337-work</link><guid isPermaLink="true">https://blog.jarrodwatts.com/what-is-account-abstraction-and-how-does-eip-4337-work</guid><category><![CDATA[Web3]]></category><category><![CDATA[Ethereum]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[Smart Contracts]]></category><category><![CDATA[decentralization]]></category><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Tue, 24 Jan 2023 01:04:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1674432949760/9c0506e0-bfb9-4970-a10e-2c32a7aa69fa.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this post, we'll explore the issues with UX in the current web3 landscape, and dive deeper into how a proposal known as <strong>account abstraction</strong> provides a potential solution to several of the biggest problems we have today.</p>
<p>The reality is, a poor UX is a significant drawback to building your application in a decentralized manner. While there are many solutions actively being worked on to address the issues, account abstraction is arguably the most promising.</p>
<p>It's an exciting paradigm that will allow anybody to interact with <a target="_blank" href="https://ethereum.org/en/developers/docs/dapps/">dapps</a>; not just web3 enthusiasts, and is coming to reality with the latest Ethereum Improvement Proposal <a target="_blank" href="https://eips.ethereum.org/EIPS/eip-4337">EIP-4337</a>.</p>
<p>Let's dive into it!</p>
<h2 id="heading-ethereum-accounts-andamp-transactions-recap">Ethereum Accounts &amp; Transactions Recap</h2>
<p>Let's get through the boring stuff first. To understand account abstraction, we first need to understand what an account actually <em>is</em> when talking about Ethereum.</p>
<h3 id="heading-what-are-ethereum-accounts">What Are Ethereum Accounts?</h3>
<p>Ethereum has two different types of "accounts":</p>
<ol>
<li><p>Contract Accounts</p>
</li>
<li><p>Externally Owned Accounts (EOAs)</p>
</li>
</ol>
<p>You can think of a contract account as <strong>code</strong> (smart contracts) living on the blockchain that defines how the account behaves, and think of EOAs as a <strong>person</strong> (<em>although a person could have many EOAs)</em>.</p>
<p>You probably are already familiar with EOAs. Your MetaMask wallet is an EOA. EOAs are made up of a cryptographic pair of keys: public and private keys that control account activities.</p>
<p>Contract accounts, however, don't have a private key. They're smart contracts that are controlled by the logic of the code within them; they're not controlled by a user.</p>
<p>The key takeaway here is that <em>code</em> defines what contract accounts do, and <em>users</em> control what EOAs do. This matters because smart contracts have the capability to do anything you can write in code, whereas EOAs can basically just sign transactions.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673397627141/f22cdc2c-7527-45e3-9d7f-291050a19adb.png" alt="contract accounts vs eoas" class="image--center mx-auto" /></p>
<h3 id="heading-what-are-ethereum-transactions">What Are Ethereum Transactions?</h3>
<p><em>Alright, so that's</em> <a target="_blank" href="https://ethereum.org/en/developers/docs/accounts/"><em>accounts</em></a><em>. What about</em> <a target="_blank" href="https://ethereum.org/en/developers/docs/transactions/"><em>transactions</em></a><em>?</em></p>
<p>Every time you want to write information to the blockchain, such as transfer tokens, or mint an NFT, a <strong>transaction</strong> needs to occur. <strong>Transactions</strong> need to be signed by an EOA, and an EOA also has to pay the associated gas fees.</p>
<p>A transaction is initiated <em>by</em> an EOA, and can be sent <em>to</em> either:</p>
<ul>
<li><p>Another EOA, for example, an EOA transferring ETH to another EOA.</p>
</li>
<li><p>A contract account, for example, minting an NFT from a drop.</p>
</li>
</ul>
<h3 id="heading-how-web3-works-today-eoas-andamp-a-poor-ux">How Web3 Works Today: EOAs &amp; A Poor UX</h3>
<p>Performing actions on the blockchain today is typically slow and tedious. Every time you want to write new information to the blockchain, you sign a transaction from your EOA to do so.</p>
<p>Once you're familiar with the process, this becomes the standard experience.</p>
<p><strong>For new users, however, it's a <em>nightmare</em>.</strong></p>
<p>The process of starting from scratch and interacting with a web3 application for the very first time is enough to put anyone off from entering the space, and that's <em>just</em> the beginning.</p>
<p>Here's a step-by-step experience that a new user goes through to perform their first action on a decentralized application from a fresh EOA:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673398370455/45c866dc-ec62-41e2-9468-f3cfcd07578e.png" alt="eoa onboarding flow for new users" class="image--center mx-auto" /></p>
<p>This experience is brutal for any new user, tech-savvy or not. But it doesn't stop there, the initial setup is just the beginning of the user's concerns when using EOAs.</p>
<h3 id="heading-eoas-are-extremely-risky">EOAs Are Extremely Risky</h3>
<p>You're likely already familiar with somebody you know losing access to their EOA by either accidentally sharing or losing access to their private key. Some examples:</p>
<ul>
<li><p><a target="_blank" href="https://www.independent.co.uk/tech/bitcoin-exchange-quadrigacx-password-cryptocurrency-scam-a8763676.html">Millions of dollars of cryptocurrency 'lost' after man <strong>dies</strong> with only password</a></p>
</li>
<li><p><a target="_blank" href="https://www.cbc.ca/radio/asithappens/as-it-happens-friday-edition-1.5875363/this-man-owns-321m-in-bitcoin-but-he-can-t-access-it-because-he-lost-his-password-1.5875366#:~:text=Back%20in%202011%2C%20he%20produced,wallet%20that%20holds%20his%20bitcoins.">Man owns $321M in bitcoin but he can't access it because he <strong>lost</strong> his password</a></p>
</li>
<li><p><a target="_blank" href="https://finbold.com/guy-locks-phone-with-potentially-6-million-in-crypto-heres-how-much-the-hacker-recovered/">Guy locks phone with potentially $6 million in crypto</a></p>
</li>
</ul>
<p>The level of responsibility you have with traditional EOAs is <strong>dangerously</strong> high.</p>
<p>There's even a saying for it: <strong>"not your keys, not your crypto"</strong>; referring to the fact that if somebody else ever has your private key at <em>any</em> point (such as a centralized exchange), they have the power to control your funds; this point has been proven countless times in the past.</p>
<p>The harsh reality is that <strong>private keys are easy to lose and impossible to recover</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673410563457/54b33450-2bbe-47bc-a532-3f8c1aaab3d1.gif" alt="with great power comes great responsibility gif" class="image--center mx-auto" /></p>
<h3 id="heading-eoas-have-limited-capabilities">EOAs Have Limited Capabilities</h3>
<p>As we touched on earlier, EOAs are very limited in their capabilities.</p>
<p>From your EOA, you're usually performing one of two typical actions:</p>
<ol>
<li><p>Submitting a transaction to transfer tokens to another EOA</p>
</li>
<li><p>Submitting a transaction that executes a function on a contract account</p>
</li>
</ol>
<p>Whoever has the private key can sign messages and initiate <em>any</em> transactions the EOA can handle. Knowing the private key of an EOA gives you the power to perform <strong>everything</strong> that an EOA is capable of. It's all or nothing.</p>
<h3 id="heading-eoas-will-never-enable-mainstream-adoption">EOAs Will Never Enable Mainstream Adoption</h3>
<p>In the real world, losing your credit card doesn't mean you are completely doomed.</p>
<p>There are rules in place that allow you to do things like set payment limits, stop transactions, detect fraud, change funds to a new account, only allow funds to be transferred under certain conditions, etc.</p>
<p>In web3, if you make <em>one</em> mistake, your <strong>entire</strong> account is compromised and unrecoverable. EOAs even compared to centralized stores of currency is... 💩.</p>
<p>We've dunked on EOAs enough, let's finally discuss the solution.</p>
<h2 id="heading-what-is-account-abstraction">What Is Account Abstraction?</h2>
<p><strong>Account abstraction is the proposal to allow users to use smart contract wallets instead of EOAs.</strong> This completely removes any need for users to use EOAs in order to perform transactions.</p>
<p><em>But why? What do contract accounts do that EOAs can't?</em></p>
<p>Smart contracts are infinitely more flexible in their capabilities than EOAs. Each smart contract can define different rules and configurations within its code.</p>
<p>Some examples of use cases can be seen below:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Use Case</strong></td><td><strong>EOAs</strong></td><td>Contract Accounts</td></tr>
</thead>
<tbody>
<tr>
<td>Permission controls</td><td>Private key grants full access to everything.</td><td>Define a list of tiered permission levels. e.g. Require 3 out of 5 signers to approve a transaction.</td></tr>
<tr>
<td>Batch transactions</td><td>Each individual action requires a separate signature.</td><td>Capable of batching transactions together; e.g. approving a token transfer and transferring a token in the same operation.</td></tr>
<tr>
<td>Account Recovery</td><td>Loss or exposure of private key means full loss of control over the wallet.</td><td>There is no private key. You can write any arbitrary logic in code that allows you to recover the funds in the wallet.</td></tr>
<tr>
<td>Transaction limits</td><td>Any transaction your wallet signs is what occurs. You cannot restrict anything.</td><td>Write any logic to control how funds can be transferred. E.g. a function to halt transactions to other addresses while you recover your account.</td></tr>
</tbody>
</table>
</div><p>These are just a few of the capabilities that contract accounts offer over traditional EOAs. The key thing is; <strong>contract accounts are code</strong>.</p>
<p>This means a<em>nything</em> you can write in code is therefore possible in a contract account.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673412340960/df7543a7-743f-4e75-b9ee-3c6c9f9db8dd.gif" alt="anything is possible gif" class="image--center mx-auto" /></p>
<h3 id="heading-history-of-account-abstraction-proposals">History of Account Abstraction Proposals</h3>
<p>Okay, this sounds great. Why aren't we already doing this today? Before we answer that, let's quickly give a brief overview of the history of account abstraction proposals dating back to 2016, and explore why EIP-4337 is different.</p>
<p><strong>2016:</strong> <a target="_blank" href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-86.md">EIP-86</a> - Proposal allowing users to create "account contracts" that perform any desired signature/nonce checks instead of using the mechanism that is currently hard-coded into transaction processing.</p>
<p><strong>2020:</strong> <a target="_blank" href="https://eips.ethereum.org/EIPS/eip-2938">EIP-2938</a> - Proposal to create a new transaction with type <code>AA_TX_TYPE</code>. Transactions of this type are referred to as “AA transactions”.</p>
<p><strong>2020:</strong> <a target="_blank" href="https://eips.ethereum.org/EIPS/eip-3074">EIP-3074</a> - Proposal allowing users to delegate control of their EOA to a smart contract. Would allow any EOA to act like a smart contract wallet without deploying a contract.</p>
<p><strong>None of these proposals have been merged into Ethereum</strong>. They are all currently in the "stagnant" category; meaning they have been inactive for a period of 6 months or greater.</p>
<p>Part of the reason for these proposals not being merged is that they require consensus-layer protocol changes to the Ethereum network.</p>
<p>Until 2021, when <a target="_blank" href="https://eips.ethereum.org/EIPS/eip-4337">EIP-4337</a> was proposed; account abstraction on Ethereum <em>without</em> a consensus layer change required!</p>
<h3 id="heading-eip-4337-account-abstraction-using-alt-mempool">EIP-4337: Account Abstraction Using Alt Mempool</h3>
<p><a target="_blank" href="https://eips.ethereum.org/EIPS/eip-4337">EIP-4337</a> introduces a <em>"</em>pseudo-transaction" object called a <code>UserOperation</code>; a structure that describes a transaction to be sent on behalf of a user.</p>
<p>User Operations go into an "alt mempool"; which is essentially a waiting room for storing information on unconfirmed transactions.</p>
<p>Nodes on the Ethereum network can choose to act as a "bundler". Bundlers pick up user operations from the mempool, and package multiple user operations into a single transaction known as a "bundle transaction".</p>
<p>Once they create a bundle transaction, they send it to a global "<a target="_blank" href="https://eips.ethereum.org/EIPS/eip-2470#:~:text=Some%20contracts%20are%20designed%20to,%2D1820%20and%20EIP%2D2429.">singleton</a>" smart contract known as the "EntryPoint". There is only one EntryPoint smart contract on the entire blockchain. The bundler calls a function on the EntryPoint smart contract called <code>handleOps</code>.</p>
<p>This function receives the bundle transaction, and calls a special function on each account: `<code>validateUserOp` </code>. Each smart contract wallet must implement this function.</p>
<p>`<code>validateUserOp` </code> should verify the operation’s signature, and pay the fee if the account considers the operation valid, before continuing to execute the operation.</p>
<p>Each smart contract wallet also must implement a second function: expected to be called "<code>execute</code>" to actually perform the operation that is sent in by the EntryPoint contract.</p>
<p>A simplified flow of this can be seen below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1674449123541/87bef380-1733-4feb-bf6c-52edbef6f521.png" alt="summary of account abstraction in eip-4337" class="image--center mx-auto" /></p>
<h3 id="heading-why-does-this-matter">Why Does This Matter?</h3>
<p>Contract accounts are the next evolution of wallets required to provide a much-needed improvement to the UX of web3.</p>
<p>The possibilities are really endless for what this change enables:</p>
<ul>
<li><p>Creating wallets for your users under the hood when they sign up for your app</p>
</li>
<li><p>Session keys for web3 games (allow any X transaction for Y amount of time without the need for signatures on each transaction)</p>
</li>
<li><p>Team wallets to use decentralized applications with tiered permissions</p>
</li>
</ul>
<p>A grandma could be collecting NFTs and not even know what the blockchain is. Account abstraction enables everybody to use web3; not just tech enthusiasts.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>In this post, we've outlined:</p>
<ul>
<li><p>The fundamental concepts of accounts and transactions on Ethereum.</p>
</li>
<li><p>How EOAs fall short in terms of web3 user experience.</p>
</li>
<li><p>What account abstraction does to solve it and how it works under the hood.</p>
</li>
</ul>
<p>Account abstraction is a game changer for web3 and bringing decentralized applications to a mainstream audience.</p>
<p>The power to use smart contracts as your wallet brings endless possibilities and EIP-4337 is the latest proposal of account abstraction that doesn't require a consensus-layer change.</p>
<h3 id="heading-thanks-for-reading">Thanks For Reading!</h3>
<p>I appreciate you making it this far! 🙏</p>
<p>If you enjoyed this content, consider following me on <a target="_blank" href="https://hashnode.com/@JarrodWatts"><strong>Hashnode</strong></a> for more!</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://hashnode.com/@JarrodWatts">https://hashnode.com/@JarrodWatts</a></div>
]]></content:encoded></item><item><title><![CDATA[How to ACTUALLY Become a Web3 Developer in 2023]]></title><description><![CDATA[This is an opinionated guide to becoming a web3 developer in 2023.
I'll outline the exact steps that I personally took to land a role as a developer relations engineer at thirdweb; a suite of developer tools for building in web3.
Unlike other roadmap...]]></description><link>https://blog.jarrodwatts.com/how-to-become-a-web3-developer-in-2023</link><guid isPermaLink="true">https://blog.jarrodwatts.com/how-to-become-a-web3-developer-in-2023</guid><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Fri, 06 Jan 2023 03:41:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1672973826693/70fea59a-9c5d-420d-b1da-4bcb33246e7d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is an <strong>opinionated</strong> guide to becoming a web3 developer in 2023.</p>
<p>I'll outline the exact steps that I personally took to land a role as a developer relations engineer at <a target="_blank" href="https://thirdweb.com/">thirdweb</a>; a suite of developer tools for building in web3.</p>
<p>Unlike other roadmaps, I'm not going to give you 300 things to learn and get you stuck in tutorial hell. This is an actionable, sequence of technologies for you to learn, including the exact resources I found most helpful throughout my journey.</p>
<p>Let's dive into it! Below is a preview of each layer of the stack we'll be covering.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672971332225/6458f265-cbe9-4116-a633-c38d9e6365a7.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-important-disclaimer-read-this">Important Disclaimer (READ THIS)</h2>
<p>Consuming resources alone will never teach you how to become a developer.</p>
<p>Every dev has to constantly fight their own battles on the journey to understanding how to code, and put together the pieces of the gigantic puzzle along the way.</p>
<p><strong>As soon as you know how to START building, exit the roadmap and go at it alone. Just <em>try</em> to build something. It's going to suck. And that's the point!</strong></p>
<p><strong>Come back to the resources to fill in the gaps in your knowledge as you get stuck; learn what tools are available for you to use that solve your problems with the resources in this guide.</strong></p>
<p>Every project you make will be better than the last, and you'll soon be embarrassed by your old code.</p>
<p>DO NOT <em>just</em> consume these resources, they are only there to help point you in the right direction in a logical order as you <strong>actually build your own projects.</strong></p>
<p><img src="https://media.giphy.com/media/l0Iy3tcRNXtp0jFXa/giphy.gif" alt="Buckle up" class="image--center mx-auto" /></p>
<p>It's not going to be easy, but it is worth it. Buckle up and let's get started!</p>
<h2 id="heading-the-roadmap">The Roadmap</h2>
<p>We're going to cover a lot of topics in this roadmap, and I'll provide you with resources that I personally used to develop my understanding at each step of the way. Here's a quick preview of some of the tools we'll cover:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672971234422/4625017c-13f0-4f27-a174-3b0b949e08cb.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-fundamentals-html-amp-css">The Fundamentals: HTML &amp; CSS</h2>
<p>Every website consists of three things:</p>
<p><strong>HTML</strong>: Structure of elements on the page</p>
<p><strong>CSS</strong>: Style of elements on the page</p>
<p><strong>JavaScript</strong>: Interactivity of elements on the page</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672894376521/43de96f2-0b10-4f63-82d3-b5841ade4b20.png" alt="html css and javascript" class="image--center mx-auto" /></p>
<p>Any application you build, no matter what technology you use, is eventually transformed into these three languages and served to a user on a web page.</p>
<p>Hence it's an important foundational piece of knowledge to understand the very basics of HTML and CSS first before diving into any "programming" (adding interactivity or logic to your application).</p>
<h3 id="heading-html-amp-css">HTML &amp; CSS</h3>
<p><a target="_blank" href="https://pll.harvard.edu/course/cs50-introduction-computer-science?delta=0">CS50</a> is Harvard's introductory course to computer science. It's an outstanding resource taught by the best lecturers in the world. I have taken multiple of their free online courses including their previous years' CS50 course and cannot recommend it enough.</p>
<p>Below is lecture number nine <em>(starting at index 0)</em> of the course that focuses on HTML, CSS and JavaScript. It teaches you the fundamentals of how web pages work and introduces how the three languages work together to create interactive websites.</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=fiR5QMZn3XA&amp;list=PLhQjrBD2T380F_inVRXMIHCqLaNUd7bN4&amp;index=9">https://www.youtube.com/watch?v=fiR5QMZn3XA&amp;list=PLhQjrBD2T380F_inVRXMIHCqLaNUd7bN4&amp;index=9</a></div>
<p> </p>
<p>Even if you already know HTML and CSS, you'll be surprised at how much you learn from these lectures by going back to basics and gaining a deeper understanding of the fundamentals.</p>
<h3 id="heading-javascript">JavaScript</h3>
<p>Picking up the basics of HTML and CSS is significantly easier than learning JavaScript; which is a behemoth in comparison; but also a lot more <strong>fun</strong>!</p>
<p>First, you need to learn the absolute basics of <strong>programming</strong> before diving deeper into JavaScript itself. This includes concepts key to any programming language; variables, functions, loops, and data structures.</p>
<p>A relatively concise resource that will teach you these basic fundamentals is the below video, "JavaScript Tutorial For Beginners".</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=W6NZfCO5SIk">https://www.youtube.com/watch?v=W6NZfCO5SIk</a></div>
<p> </p>
<p>The video above is just an example of beginner-friendly content to understand the basics of JavaScript. There are plenty of others out there and I encourage you to learn as much as you need before advancing further into this roadmap.</p>
<p>Here are some more great interactive resources that you can use to learn as a beginner:</p>
<ul>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=PkZNo7MFNFg">Free Code Camp: Full JavaScript Course for Beginners</a></p>
</li>
<li><p><a target="_blank" href="https://www.theodinproject.com/">The Odin Project</a></p>
</li>
<li><p><a target="_blank" href="https://javascript30.com/">Wes Bos - JavaScript30</a></p>
</li>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/">MDN Documentation</a></p>
</li>
</ul>
<h3 id="heading-optional-for-now-computer-science-fundamentals">Optional (For Now): Computer Science Fundamentals</h3>
<p>JavaScript is beginner-friendly and abstracts away many complexities of programming; it's designed so that you can hit the ground running quickly.</p>
<p>If you are willing to spend <strong>significantly</strong> more time learning the fundamentals of computer science, consider watching the <a target="_blank" href="https://www.youtube.com/playlist?list=PLhQjrBD2T380F_inVRXMIHCqLaNUd7bN4">full playlist of lectures for CS50 2022</a>; which is ~20 hours total.</p>
<p><em>My personal opinion</em> is that it's better to come back to these fundamentals later and <strong>start building something as soon as possible</strong>.</p>
<p><em>I personally didn't learn these computer science fundamentals in detail until 1-2 years into working as a professional software engineer (which might sound crazy, I know). Again, these are my personal opinions and others will disagree with this.</em></p>
<h3 id="heading-advanced-javascript">Advanced JavaScript</h3>
<p>Here's where the learning curve reached a steep point for me.</p>
<p>The resources I'm about to share may feel overwhelming at first; it took me several re-watches and many, many pages of notes to start to understand these concepts.</p>
<h4 id="heading-how-javascript-really-works">How JavaScript <em>Really Works</em></h4>
<p>The below video goes deep into the nuances of JavaScript and how the magic of the language works under the hood! 🧙</p>
<p>Topics like scope, closures, and prototypical inheritance are funnily enough the topics I've been asked about several times in job interviews over the past few years.</p>
<p>This is another CS50 lecture from 2018, and is still one of my personal favourite resources for learning JavaScript to this day!</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=X52b-8y2Hf4">https://www.youtube.com/watch?v=X52b-8y2Hf4</a></div>
<p> </p>
<h4 id="heading-asynchronous-javascript">Asynchronous JavaScript</h4>
<p>The subsequent lecture in this playlist is also quite complex but covers incredibly important topics for understanding JavaScript at a deeper level. You'll be introduced to some of the more modern features of JavaScript introduced in <a target="_blank" href="https://www.w3schools.com/js/js_es6.asp">ES6</a> such as callbacks, promises, and asynchronous functions.</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=3Ay2lS6tm4M">https://www.youtube.com/watch?v=3Ay2lS6tm4M</a></div>
<p> </p>
<h4 id="heading-optional-paid-course-es6-for-everyone-by-wes-bos">(Optional) Paid Course: "ES6 for Everyone!" by Wes Bos</h4>
<p>An additional resource I recommend (if you can afford it) is the "<a target="_blank" href="https://es6.io/">ES6 for Everyone!</a>" course by <a target="_blank" href="https://twitter.com/wesbos">Wes Bos</a>. It's an excellent interactive course that teaches you a variety of super helpful syntactic sugar that are part of the later releases of <a target="_blank" href="https://en.wikipedia.org/wiki/ECMAScript">ECMAScript</a>.</p>
<p>It's not essential, but Wes is a great teacher and the course is a fun way to learn the more efficient ways of doing things in JavaScript.</p>
<p>This course is very beginner friendly and will help you write more modern Javascript.</p>
<h4 id="heading-very-optional-paid-course-master-the-coding-interview">(VERY Optional) Paid Course: Master the Coding Interview</h4>
<p>As you're on your journey and are building your projects, some code you write is not going to be as efficient as it could be.</p>
<p>A paid course that taught me a tremendous amount about writing better code is the "<a target="_blank" href="https://www.udemy.com/course/master-the-coding-interview-big-tech-faang-interviews/">Master the Coding Interview: Big Tech (FAANG) Interviews</a>" course by <a target="_blank" href="https://twitter.com/andreineagoie">Andrei Neagoie</a>.</p>
<p>The title of the course is a bit clickbaity, but it teaches you almost everything there is to learn about data structures and algorithms; with 30 interactive questions for you to go through; all in JavaScript!</p>
<p>For me, this was extremely hard and took me many months to get through; which is why I put the "very optional" tag on this course. It's an amazing resource that I recommend you take at some point on your journey, but if you're a beginner it's likely going to be too hard for you.</p>
<h2 id="heading-react-building-user-interfaces">React - Building User Interfaces</h2>
<p>If you've started building your project by this point, you've probably realised that it is difficult to build an application by writing HTML, CSS, and JS alone.</p>
<p>Developers have come up with many different libraries and frameworks to address these issues over the past decade; <a target="_blank" href="https://jquery.com/">jQuery</a>, <a target="_blank" href="https://angular.io/">Angular</a>, <a target="_blank" href="https://svelte.dev/">Svelte</a>, <a target="_blank" href="https://vuejs.org/">Vue</a>... the list goes on!</p>
<p>One library has come out on top; <a target="_blank" href="https://reactjs.org/">React</a>, which is:</p>
<ul>
<li><p><a target="_blank" href="https://survey.stackoverflow.co/2022/#web-frameworks-and-technologies">The most used frontend JS framework of 2022</a>.</p>
</li>
<li><p><a target="_blank" href="https://survey.stackoverflow.co/2022/#web-frameworks-and-technologies">The framework that most developers "want" to use in 2022</a>.</p>
</li>
<li><p>The most in-demand frontend framework for landing a job <em>(too lazy to get a source for this stat, so... "probably"</em> 😄).</p>
</li>
</ul>
<p>React uses a syntax called <a target="_blank" href="https://reactjs.org/docs/introducing-jsx.html">JSX</a> to combine writing your UI structure and design with your "interactivity" in the same location:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672899546973/1b4fb682-c697-4d45-8678-1a71e9de6fa2.png" alt class="image--center mx-auto" /></p>
<p>A great resource to understand the "why" of React is this CS50W lecture on user interfaces:</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=jrBhi8wbzPw">https://www.youtube.com/watch?v=jrBhi8wbzPw</a></div>
<p> </p>
<p>This lecture outlines the problems of building applications without a framework or library and introduces React as the solution to some of the problems you might already be running into.</p>
<h4 id="heading-diving-deeper-into-react">Diving Deeper Into React</h4>
<p>The React core team have been iteratively releasing its new "beta" documentation over the past few months (<em>or years).</em></p>
<p>This new documentation is excellent and I strongly recommend you go through their <a target="_blank" href="https://beta.reactjs.org/learn">Quick Start</a> to learn all of the core concepts of React on one simple page.</p>
<p>You'll learn about the most common patterns of React like creating components, displaying data, and responding to events.</p>
<p>Before you dive too deep into building with React alone, I'll introduce you to another layer of abstraction on top of React, called <a target="_blank" href="https://nextjs.org/">Next.js</a>; which takes things to the next level.</p>
<h2 id="heading-nextjs-making-react-way-better">Next.js - Making React WAY Better</h2>
<p>I'll save you a lot of struggle: <strong>completely skip Create React App (CRA) and arguably even Vite. Start by using Next.js right from the get-go.</strong></p>
<p>Below is a great three-minute explainer of why CRA is no longer ideal for new projects using React:</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=o9TJWEPc0Lk">https://www.youtube.com/watch?v=o9TJWEPc0Lk</a></div>
<p> </p>
<h4 id="heading-get-started-with-nextjs">Get Started with Next.js</h4>
<p>Next.js documentation is absolutely brilliant. <a target="_blank" href="https://twitter.com/leeerob"><strong>Lee Robinson</strong></a> and his team of DX engineers have written fantastic, interactive documentation to help you learn Next.js and quiz your knowledge along the way.</p>
<p>For this reason, I recommend running through the interactive documentation first; and then diving into <a target="_blank" href="https://nextjs.org/docs#automatic-setup">creating your first Next.js application with their CLI</a>.</p>
<h2 id="heading-typescript">TypeScript</h2>
<p>Another hot take on this article 🌶️: Start using TypeScript ASAP! JavaScript is a great language for beginners, but this is a double-edged sword. Part of the reason it's good for beginners is that it gives you a lot of freedom to write 💩 code and it doesn't complain about it!</p>
<p>TypeScript can be a real pain in the 🍑 at first, but once it clicks, you'll never want to go back. More and more developers and developer tools are defaulting to TypeScript and for good reason; type safety makes your code significantly less likely to have bugs!</p>
<p>My suggestion: turn <a target="_blank" href="https://www.typescriptlang.org/tsconfig#strict">strict mode</a> off at the beginning. Use the <a target="_blank" href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#any"><code>any</code></a> type whenever you get completely stuck and don't know what to do. These are bad practices in reality, but will help you onboard to TypeScript without wanting to break your keyboard.</p>
<p>As you write more and more code with TypeScript and pick up more tricks, you'll feel comfortable enabling strict mode and using the <code>any</code> type more sparingly; until you eventually have complete type safety in your codebase and look at JavaScript in disgust!</p>
<h2 id="heading-styling">Styling</h2>
<p>There are a number of options for you to build out more beautiful applications that are ultimately just different ways of abstracting CSS so that it's ... well basically CSS but easier.</p>
<p>The general consensus going into 2023 is that <a target="_blank" href="https://tailwindcss.com/">Tailwind CSS</a> is the gold standard for adding styles to your application. I personally like to use a tool called <a target="_blank" href="https://mui.com/">Material UI</a> that comes with pre-built components; however, most people don't agree with me on this.</p>
<p>A great video weighing up the different options available and their pros and cons is "<a target="_blank" href="https://www.youtube.com/watch?v=CQuTF-bkOgc">The Best of CSS</a>" by <a target="_blank" href="https://twitter.com/t3dotgg">Theo</a>:</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=CQuTF-bkOgc">https://www.youtube.com/watch?v=CQuTF-bkOgc</a></div>
<p> </p>
<p>Short answer: If you don't already know and love a UI library, pick Tailwind CSS.</p>
<h2 id="heading-blockchain-fundamentals">Blockchain Fundamentals</h2>
<p>If you don't already have knowledge of what a blockchain or smart contract is, a helpful resource for beginners is <a target="_blank" href="https://twitter.com/PatrickAlphaC">Patrick Collins</a>' blockchain course.</p>
<p>I suggest you watch the <strong>first 2 hours</strong> of the 32-hour course which introduces the core concepts of blockchain, smart contracts and web3. You can pick and choose the other areas of the course that interest you as you wish!</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=gyMwXuJrbJQ">https://www.youtube.com/watch?v=gyMwXuJrbJQ</a></div>
<p> </p>
<h2 id="heading-understanding-the-web3-stack">Understanding the Web3 Stack</h2>
<p>An introductory video I recommend watching is "Defining the Web3 Stack", by <a class="user-mention" href="https://hashnode.com/@dabit3">Nader Dabit</a>; which outlines the equivalent web3 tech stack compared to a traditional "web2" application.</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=f9XRH7bjV8M">https://www.youtube.com/watch?v=f9XRH7bjV8M</a></div>
<p> </p>
<p>As an updated graphic to Nader's talk in 2021, I have provided my thoughts on the tech stack of a web3 application below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672959624469/748d9f53-b5ec-4b9a-9499-35086c394bc4.png" alt class="image--center mx-auto" /></p>
<p>There are a lot of moving pieces to consider when building a web3 application. There are a plethora of tools available to help you build different aspects of your decentralized application, and it's up to you to learn what you like best.</p>
<p>Of course, I'll provide my recommendations here that I have come to after experimenting with a number of these tools in the past year.</p>
<h3 id="heading-building-a-full-stack-web3-app-the-hard-way">Building a full stack web3 app "the hard way"</h3>
<p>Arguably the best resource I consumed when I was entering the web3 space was <a class="user-mention" href="https://hashnode.com/@dabit3">Nader Dabit</a>'s "<a target="_blank" href="https://www.youtube.com/watch?v=GKJBEEXUha0">Full Stack NFT Marketplace</a>" video tutorial. You'll learn how to build almost every aspect of a full-stack web3 application at a rapid pace, including:</p>
<ul>
<li><p>NFT Collection smart contract</p>
</li>
<li><p>NFT marketplace smart contract</p>
</li>
<li><p>Smart contract development environment and testing</p>
</li>
<li><p>IPFS file uploads and downloads</p>
</li>
<li><p>Frontend technologies &amp; Next.js to build a web3 application</p>
</li>
<li><p>RPC nodes and IPFS Gateways</p>
</li>
</ul>
<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=GKJBEEXUha0">https://www.youtube.com/watch?v=GKJBEEXUha0</a></div>
<p> </p>
<p>This might feel like quite the jump from the previous step, and you might not understand everything in this video immediately, and that's okay!</p>
<p>This resource taught me a tremendous amount about how the pieces of the web3 stack fit together and teach you how to build an epic project with modern technologies.</p>
<h4 id="heading-extending-naders-project">Extending Nader's Project</h4>
<p>Something that <em>really</em> made me understand what was happening was adding more functionality to Nader's NFT marketplace project; specifically, adding a function to get an individual listing's information on the marketplace smart contract.</p>
<p>Adding this capability to the project might sound easy, but it tests to see if you really understand how the project is functioning; and is a great step to add on top of the build itself.</p>
<h4 id="heading-why-is-this-the-hard-way">Why is this "the hard way"?</h4>
<p>This resource introduces you to what I'd argue is a low-level abstraction of building a full-stack web3 app; it shows you every step of the process which is super important to understand.</p>
<p>However, I'd argue that the purpose of the video isn't to build a "production-ready" application in 2023. I say this because there are a large number of tools that have been released since mid-2021 <em>(the time this video was made),</em> that has abstracted away the complexity of building full-stack web3 applications significantly.</p>
<p>Let's quickly cover a few other core concepts and then dive into the more modern tools available to build web3 apps with.</p>
<h2 id="heading-rpc-nodes">RPC Nodes</h2>
<p>To communicate to and from the blockchain, you need to use a node. Unless you want to run your own Node, you need to use a service provider such as Alchemy, Coinbase, or Moralis, <em>(or thirdweb as we'll explain in the next section)</em> to do so.</p>
<p>Below is a great resource outlining what an RPC Node is and why it's required to build web3 applications.</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.alchemy.com/overviews/rpc-node">https://www.alchemy.com/overviews/rpc-node</a></div>
<p> </p>
<h4 id="heading-interesting-project-lava-network">Interesting Project: Lava Network</h4>
<p>A project I am excited to see in 2023 is <a target="_blank" href="https://lavanet.xyz/">Lava Network</a>; which offers a decentralized alternative to the RPC Nodes. Check it out if you are interested!</p>
<h2 id="heading-decentralized-storage-solutions">Decentralized Storage Solutions</h2>
<p>Not all information needs to be stored on the blockchain. Storing data on the blockchain itself costs gas fees and has a significant storage limit; for this reason, a common pattern is to store your information "off-chain" and store the URL of that data on the blockchain instead.</p>
<p>Storage solutions exist that aren't stored "on-chain" but are still not controlled by a centralized service such as AWS or Google Cloud. The two prominent decentalized storage solutions solutions in 2023 are:</p>
<ol>
<li><p><a target="_blank" href="https://ipfs.tech/">IPFS</a></p>
</li>
<li><p><a target="_blank" href="https://www.arweave.org/">Arweave</a></p>
</li>
</ol>
<h3 id="heading-ipfs">IPFS</h3>
<p>Below is a concise summary of what IPFS is, how it works, and how you can integrate it into your applications using <a target="_blank" href="https://thirdweb.com/storage">thirdweb</a> (we'll talk more about this next).</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=4Nnu9Cy7SKc">https://www.youtube.com/watch?v=4Nnu9Cy7SKc</a></div>
<p> </p>
<p>To access data stored on IPFS on most browsers such as Google Chrome, you'll need to use an IPFS Gateway. There are a couple of options available for you here:</p>
<ol>
<li><p>Public gateway (available for everyone, not very reliable)</p>
</li>
<li><p>Private gateways - using services such as <a target="_blank" href="https://www.pinata.cloud/">Pinata</a> or <a target="_blank" href="http://nft.storage">nft.storage</a> for faster speed and higher availability, <em>(again, or just use thirdweb as we discuss next)</em>.</p>
</li>
</ol>
<h3 id="heading-arweave">Arweave</h3>
<p>Another excellent video by Nader Dabit is available for you to understand Arweave and other aspects of the Arweave ecosystem such as <a target="_blank" href="https://github.com/ArweaveTeam/SmartWeave">Smartweave</a> and <a target="_blank" href="https://warp.cc/">Warp</a>.</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=cGLMN5A2C4E">https://www.youtube.com/watch?v=cGLMN5A2C4E</a></div>
<p> </p>
<p>I should mention a lot of these technologies such as Arweave have <a target="_blank" href="https://www.arweave.org/get-involved/investment-funding">grant programs</a> if you are building with them; if you're looking for some funding this might be interesting to you.</p>
<h2 id="heading-thirdweb">thirdweb</h2>
<p><strong>Full disclosure: I work on the</strong> <a target="_blank" href="https://twitter.com/thirdweb"><strong>thirdweb</strong></a> <strong>team!</strong></p>
<p>I used Nader's NFT marketplace video as a starting point for a freelancing project I was working on as I began to increase my skills in web3 development. I came to the realisation that building smart contracts is HARD!</p>
<p>I didn't have the confidence at this point to write a fully-featured, gas-optimized, bug-free marketplace smart contract for my clients' requirements; so I started to ask myself: <em>"someone must have done this and open-sourced it somewhere RIGHT!?"</em></p>
<p><em>Well, turns out I was right!</em></p>
<p>I stumbled upon <a target="_blank" href="https://thirdweb.com/">thirdweb</a> shortly after it was released and discovered they had open-source smart contracts for NFT collections, marketplaces, and more.</p>
<p>I basically planned to just copy-paste their solidity smart contracts into my existing project and carry on my way 😂! <em>Here's proof (don't tell</em> <a target="_blank" href="https://twitter.com/FurqanR"><em>Furqan</em></a><em>):</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672961399204/028da489-f570-4cba-b1a4-85762b96eb26.png" alt class="image--center mx-auto" /></p>
<p>But as I explored the product more, I discovered they had an SDK! I didn't have to use ethers anymore! They also have tools to connect users' wallets, and manage my IPFS storage for me! I didn't even need my smart contract code in my project anymore as they had a dashboard I could deploy it with.</p>
<p>I was able to remove SO MUCH of the code I wrote for my marketplace project and replace them with thirdweb tools that I ended up falling in love with the product; <em>and applied for my current position at thirdweb a few months after completing my freelance work!</em></p>
<p><em>So, while I do get paid to advocate thirdweb's products, I do it from my heart, not from my ... wallet?</em> 🥲 I was really out here using their tools before I joined the team.</p>
<h3 id="heading-learning-thirdweb">Learning thirdweb</h3>
<p>I've spent a lot of time refining the <a target="_blank" href="https://portal.thirdweb.com/getting-started">Getting Started</a> flow of the thirdweb documentation to get you up and running from building a smart contract to building a front-end Next.js application in no time! So, my recommendation is to start there!</p>
<p>Alternatively, there is a getting started video that covers the same content:</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=fzsz-b2JV9U">https://www.youtube.com/watch?v=fzsz-b2JV9U</a></div>
<p> </p>
<p>Once you get the power of thirdweb's stack, you won't want to go back! 🤠 Since I joined, we have shipped even more features that make the web3 building process simpler:</p>
<ul>
<li><p>Free IPFS gateway and IPFS rendering components in the SDK.</p>
</li>
<li><p>Free RPC included directly in the SDK (which can be overridden).</p>
</li>
<li><p>IPFS upload and downloads in React hooks with <a target="_blank" href="https://portal.thirdweb.com/storage">Storage</a>.</p>
</li>
<li><p><a target="_blank" href="https://portal.thirdweb.com/react">React hooks</a> for everything you can imagine on the frontend; for both user wallets and interacting with smart contracts.</p>
</li>
<li><p>Full Solidity SDK called "<a target="_blank" href="https://portal.thirdweb.com/contractkit">ContractKit</a>" which is similar to OpenZeppelin.</p>
</li>
<li><p>An <a target="_blank" href="https://thirdweb.com/explore">Explore</a> page; for you to deploy the most popular smart contract standards.</p>
</li>
<li><p>Much more!</p>
</li>
</ul>
<p>Deploy a smart contract with thirdweb and connect to it in your Next.js application and I promise you'll never want to go back to your old stack.</p>
<h2 id="heading-other-web3-frontend-libraries">Other Web3 Frontend Libraries</h2>
<p>So that I'm not completely biased, I'll also recommend you some of the other modern libraries available for you to build more robust frontends for your web3 apps.</p>
<h3 id="heading-wagmi">wagmi</h3>
<p><a target="_blank" href="https://wagmi.sh/">wagmi</a> is a library of React Hooks for building EVM frontends. Much like the <a target="_blank" href="https://portal.thirdweb.com/react">thirdweb React SDK</a>, it has hooks for pretty much everything you can imagine and is significantly better than using ethers or web3.js alone.</p>
<p>The <a target="_blank" href="https://wagmi.sh/core/getting-started">documentation</a> is a great starting point for you to understand how to use it in your Next.js/React apps.</p>
<h3 id="heading-rainbow-kit">Rainbow Kit</h3>
<p><a target="_blank" href="https://www.rainbowkit.com/">RainbowKit</a> is an excellent library for adding connect wallet capabilities into your application and supporting a variety of different connection options for your users.</p>
<p>Their <a target="_blank" href="https://www.rainbowkit.com/docs/introduction">documentation</a> is concise and includes helpful short videos to get you up and running quickly.</p>
<h2 id="heading-indexing-solutions">Indexing Solutions</h2>
<p>Some web3 applications require information that isn't directly available from any smart contract; such as what NFTs a wallet owns, or how many times an NFT has been transferred.</p>
<p>When it comes to indexing solutions, you can use <a target="_blank" href="https://thegraph.com/en/">The Graph</a>; a decentralized solution, and again use Nader's resources to learn how to get started:</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=JpOLhkmtOak">https://www.youtube.com/watch?v=JpOLhkmtOak</a></div>
<p> </p>
<p>You might prefer to use SDKs or API endpoints to get your indexed information, and there are a number of popular solutions you can use, each with helpful resources and videos on their documentation:</p>
<ul>
<li><p><a target="_blank" href="https://www.alchemy.com/sdk">Alchemy</a></p>
</li>
<li><p><a target="_blank" href="https://docs.cloud.coinbase.com/node/docs/welcome-to-node">Coinbase Cloud</a></p>
</li>
<li><p><a target="_blank" href="https://moralis.io/">Moralis</a></p>
</li>
</ul>
<p>These tools have similar capabilities with various pros and cons, you can use their documentation to explore which tool is right for you.</p>
<h2 id="heading-smart-contracts">Smart Contracts</h2>
<p>This might seem crazy that the smart contracts section is all the way down here. 🤯</p>
<p>The reason I placed smart contracts after learning the full frontend tech stack is that you are often going to be building on top of smart contracts that <em>other</em> people have deployed already; such as <a target="_blank" href="https://www.lens.xyz/">Lens Protocol</a>, or deploying gas-optimized, audited smart contracts that suit your needs such as those available on <a target="_blank" href="https://thirdweb.com/explore">thirdweb Explore</a>.</p>
<p>To land a job in web3 you don't need to be an expert in writing your own smart contracts. At thirdweb, we have a team that is dedicated to writing Solidity smart contracts and building out our Solidity SDK; the rest of our engineers <em>understand</em> the Solidity code; but aren't actively writing smart contracts on a daily basis.</p>
<p>This might be a hot take 🌶️🥵 but you should learn the details of building smart contracts <em>after</em> learning how to actually <strong>build stuff people interact with</strong>; which <em>usually</em> means you need some kind of frontend application skills.</p>
<p>Some people will disagree with that; as almost everything in web3 depends on the foundational layer of decentralized applications; <strong>which is smart contracts</strong>. I'm not saying it's correct, this is just the path that I personally took to learn web3.</p>
<p>There are many resources you can use to learn Solidity itself, such as:</p>
<ul>
<li><p><a target="_blank" href="https://cryptozombies.io/">CryptoZombies</a> (interactive course)</p>
</li>
<li><p>Literally, just read the <a target="_blank" href="https://docs.soliditylang.org/en/v0.8.17/">Solidity documentation</a> 🥸</p>
</li>
</ul>
<h3 id="heading-object-oriented-programming">Object Oriented Programming</h3>
<p>OOP. <em>more like oof</em>, am I right? 😑</p>
<p>Solidity is an object-oriented programming language to build your own smart contracts. If you know OOP principles you are already most of the way there to be able to write basic Solidity.</p>
<p>Usually, you don't see JavaScript used for object-oriented programming; other languages like Java, C#, or Python are better suited for this style of writing code.</p>
<p>To get the basics of OOP down, I recommend you consume as many resources as you need to to get the basic principles down. Below is an introduction to OOP in JavaScript that will help you get the core concepts:</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=PFmuCDHHpwk">https://www.youtube.com/watch?v=PFmuCDHHpwk</a></div>
<p> </p>
<h4 id="heading-oop-in-solidity">OOP In Solidity</h4>
<p>Once you know what OOP is, I recommend you return back to Patrick's video at <a target="_blank" href="https://youtu.be/gyMwXuJrbJQ?t=11135">this timestamp</a> (chapter 3), to see how inheritance and overrides work in Solidity:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/gyMwXuJrbJQ?t=11135">https://youtu.be/gyMwXuJrbJQ?t=11135</a></div>
<p> </p>
<h3 id="heading-using-oss-smart-contracts">Using OSS Smart Contracts</h3>
<p>Usually, you'll want to build some variety of ERC standards such as ERC20 fungible tokens, ERC721 NFTs, or marketplaces, with a twist that makes your project unique.</p>
<p>Now that you know how to utilize inheritance in Solidity, you can make use of libraries such as <a target="_blank" href="https://www.openzeppelin.com/contracts">OpenZeppelin Contracts</a> and <a target="_blank" href="https://portal.thirdweb.com/contractkit">thirdweb ContractKit</a> to import core chunks of logic into your smart contracts; and customize them as you wish!</p>
<h4 id="heading-contractkit">ContractKit</h4>
<p>thirdweb's ContractKit has a vast array of plug-and-play smart contracts for you to extend, customize, and include in your own smart contracts; including ERC721, ERC1155, ERC20, staking, airdrop, and more 🤠!</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=G3IHeKhVtpQ">https://www.youtube.com/watch?v=G3IHeKhVtpQ</a></div>
<p> </p>
<h3 id="heading-smart-contract-security">Smart Contract Security</h3>
<p>It is important to know the most common vulnerabilities of smart contracts, which again Patrick covers thoroughly in his 32-hour Solidity course in Chapter 18 at <a target="_blank" href="https://youtu.be/gyMwXuJrbJQ?t=113313">this timestamp</a>.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/gyMwXuJrbJQ?t=113313">https://youtu.be/gyMwXuJrbJQ?t=113313</a></div>
<p> </p>
<p>There is also a detailed <a target="_blank" href="https://github.com/kadenzipfel/smart-contract-attack-vectors">open-source repository</a> outlining common attack vectors for smart contracts and historical exploits using these attacks:</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/kadenzipfel/smart-contract-attack-vectors">https://github.com/kadenzipfel/smart-contract-attack-vectors</a></div>
<p> </p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>That's it! These are the resources I personally used to develop my knowledge in web3 and land a job as a developer relations engineer at <a target="_blank" href="https://twitter.com/thirdweb">thirdweb</a>!</p>
<p>I'd like to reiterate that tutorials and resources alone will never be enough to become a dev. You need to get your hands dirty ASAP, come back to these resources as you run into problems in your project, and constantly fight battles on your own over many years to come.</p>
<p>The goal of this article isn't to give you months of resources to consume, it's here so you can come back to trusted sources of high-quality information as you build your own projects alone! 🦸</p>
<p>If you want to join a community of devs on your journey, jump into my community <a target="_blank" href="https://discord.com/invite/4eQBm7DDNS">Discord server</a> and introduce yourself! 👋</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://discord.com/invite/4eQBm7DDNS">https://discord.com/invite/4eQBm7DDNS</a></div>
]]></content:encoded></item><item><title><![CDATA[Build A Web3 Social Media App Using Lens & React Native]]></title><description><![CDATA[In this guide, I'll show you how to create a basic web3 social media app using Lens Protocol and Expo; a platform for building cross-platform apps.
By the end, you'll have a cross-platform app that looks like this:

Let's get started! 🤠
Create A Rea...]]></description><link>https://blog.jarrodwatts.com/build-a-web3-social-media-app-using-lens-react-native</link><guid isPermaLink="true">https://blog.jarrodwatts.com/build-a-web3-social-media-app-using-lens-react-native</guid><category><![CDATA[lensprotocol]]></category><category><![CDATA[Web3]]></category><category><![CDATA[React Native]]></category><category><![CDATA[social media]]></category><category><![CDATA[Expo]]></category><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Sat, 10 Dec 2022 07:21:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1670656559170/kO2h3jeLe.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this guide, I'll show you how to create a basic web3 social media app using <a target="_blank" href="https://www.lens.xyz/">Lens Protocol</a> and <a target="_blank" href="https://expo.dev/">Expo</a>; a platform for building cross-platform apps.</p>
<p>By the end, you'll have a cross-platform app that looks like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670655884051/_98f6dnFF.gif" alt class="image--center mx-auto" /></p>
<p>Let's get started! 🤠</p>
<h2 id="heading-create-a-react-native-app">Create A React Native App</h2>
<p>We'll be using <a target="_blank" href="https://docs.expo.dev/">Expo</a>, a platform for making mobile applications written in React Native to build our application.</p>
<h3 id="heading-create-a-project-with-the-expo-cli">Create a Project with the Expo CLI</h3>
<p>To get started, first, install the Expo CLI globally:</p>
<pre><code class="lang-bash">npm install --global expo-cli
</code></pre>
<p>Then, run the command below to create a new React Native project:</p>
<pre><code class="lang-bash">npx create-expo-app lens-react-native
</code></pre>
<p>Change directories into the newly created project and open it up in your text editor!</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> lens-react-native <span class="hljs-comment"># Change directories into your newly created project</span>
code . <span class="hljs-comment"># Open your project in Visual Studio Code</span>
</code></pre>
<h3 id="heading-optional-add-web-support">Optional: Add Web Support</h3>
<p>If you want to preview your application on your browser rather than your phone during development, run the command below:</p>
<pre><code class="lang-bash">npx expo install react-native-web@~0.18.9 react-dom@18.1.0 @expo/webpack-config@^0.17.2
</code></pre>
<p>This allows us to run <code>npm run web</code> to preview our application on <code>localhost</code> like so:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670646952731/mcH8HjXci.png" alt="localhost app preview" class="image--center mx-auto" /></p>
<h2 id="heading-setting-up-lens-protocol">Setting Up Lens Protocol</h2>
<p>We'll use the <a target="_blank" href="https://github.com/lens-protocol/react-native-lens-ui-kit">React Native Lens UI Kit</a> to integrate decentralized social media functionality into our app. The Lens UI Kit is a set of pre-made components that allow you to read data from the blockchain within a React Native app.</p>
<p>Install the UI Kit by running the following command:</p>
<pre><code class="lang-bash">npm install @lens-protocol/react-native-lens-ui-kit
</code></pre>
<p>I'll show you how to add a feed and a profile page, however, you can explore <em>all</em> of the components available in the <a target="_blank" href="https://github.com/lens-protocol/react-native-lens-ui-kit">README</a> file if you wish to explore further!</p>
<h3 id="heading-adding-navigation">Adding Navigation</h3>
<p>To allow navigation between pages, we'll install two more packages in our project:</p>
<pre><code class="lang-bash">npm i @react-navigation/native @react-navigation/native-stack
</code></pre>
<p>In your <code>App.js</code> file, create a <a target="_blank" href="https://reactnavigation.org/docs/getting-started/#wrapping-your-app-in-navigationcontainer">NavigationContainer</a> containing a <a target="_blank" href="https://reactnavigation.org/docs/native-stack-navigator/">Native Stack Navigator</a> with two screens; one for our home page and one for a user's profile:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { NavigationContainer } <span class="hljs-keyword">from</span> <span class="hljs-string">"@react-navigation/native"</span>;
<span class="hljs-keyword">import</span> { createNativeStackNavigator } <span class="hljs-keyword">from</span> <span class="hljs-string">"@react-navigation/native-stack"</span>;

<span class="hljs-keyword">import</span> Feed <span class="hljs-keyword">from</span> <span class="hljs-string">"./Feed"</span>;
<span class="hljs-keyword">import</span> Profile <span class="hljs-keyword">from</span> <span class="hljs-string">"./Profile"</span>;

<span class="hljs-keyword">const</span> Stack = createNativeStackNavigator();

<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">App</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">NavigationContainer</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Stack.Navigator</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Stack.Screen</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"Home"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Feed}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Stack.Screen</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"Profile"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Profile}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Stack.Navigator</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">NavigationContainer</span>&gt;</span></span>
  );
}
</code></pre>
<h3 id="heading-feed-page">Feed Page</h3>
<p>Create a new file at the root of your project called <code>Feed.js</code>.</p>
<p>We'll use the <code>Feed</code> component provided by the Lens UI Kit to show a feed of the latest posts on Lens:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Feed } <span class="hljs-keyword">from</span> <span class="hljs-string">"@lens-protocol/react-native-lens-ui-kit"</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">FeedPage</span>(<span class="hljs-params">{ navigation }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Feed</span>
      <span class="hljs-attr">onProfileImagePress</span>=<span class="hljs-string">{(press)</span> =&gt;</span>
        navigation.navigate("Profile", { profile: press.profile })
      }
    /&gt;</span>
  );
}
</code></pre>
<p>Here, we provide the <code>onProfileImagePress</code> prop, which navigates the user to the <code>Profile</code> page when they click one of the user's profile pictures on a post (example circled below).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670654767256/-3wc9RtEV.png" alt class="image--center mx-auto" /></p>
<p>This component creates a chronological order of posts for us like so:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670654885946/m-q0MRC5e.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-profile-page">Profile Page</h3>
<p>Using the <code>onProfileImagePress</code> prop, we navigate the user to that user's profile page.</p>
<p>Create another new file at the root of your project called <code>Profile.js</code> and populate it with the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Profile } <span class="hljs-keyword">from</span> <span class="hljs-string">"@lens-protocol/react-native-lens-ui-kit"</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">ProfilePage</span>(<span class="hljs-params">{ route }</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Profile</span> <span class="hljs-attr">profile</span>=<span class="hljs-string">{route.params.profile}</span> /&gt;</span></span>;
}
</code></pre>
<p>Here, we use the <code>Profile</code> component provided by Lens to render a feed of posts made by that user as well as their profile information:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1670655114190/fckd-rQi3.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-demo">Demo</h3>
<p>Run your application using one of the following commands to get a preview:</p>
<pre><code class="lang-bash">npm run web <span class="hljs-comment"># Open in your browser</span>
npm run ios <span class="hljs-comment"># Open on your iPhone</span>
npm run android <span class="hljs-comment"># Open on your Android phone</span>
</code></pre>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>The React Native Lens UI Kit is an incredible way to get started building social media apps on top of the Lens Protocol.</p>
<p>Currently, the kit is in an alpha release, meaning there are a lot of new features to come, outlined in their <a target="_blank" href="https://github.com/lens-protocol/react-native-lens-ui-kit#roadmap">beta roadmap</a>, such as:</p>
<ul>
<li><p>Authentication (signing in with Lens)</p>
</li>
<li><p>Custom styling and components</p>
</li>
<li><p>Support for GIFs and videos</p>
</li>
</ul>
<p>Most importantly 😉 TypeScript support is coming in their V1 release! 🎉</p>
]]></content:encoded></item><item><title><![CDATA[Level Up Your Full-Stack Development with React Query]]></title><description><![CDATA[Introduction
This guide will cover why React Query is an excellent tool to take your code to the next level when building full-stack applications.
Recently, I joined thirdweb and the React SDK uses React Query all over the place! But Why? What's all ...]]></description><link>https://blog.jarrodwatts.com/level-up-your-full-stack-development-with-react-query</link><guid isPermaLink="true">https://blog.jarrodwatts.com/level-up-your-full-stack-development-with-react-query</guid><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[ReactHooks]]></category><category><![CDATA[full stack]]></category><category><![CDATA[react-query]]></category><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Tue, 21 Jun 2022 01:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1655624979003/XCY11cMRO.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>This guide will cover why React Query is an excellent tool to take your code to the next level when building full-stack applications.</p>
<p>Recently, I joined <a target="_blank" href="https://thirdweb.com/">thirdweb</a> and the React SDK uses React Query all over the place! But Why? What's all the hype about?</p>
<p>This guide will cover:</p>
<ul>
<li>Why use React Query</li>
<li>Reading data with React Query queries</li>
<li>Writing data using React Query mutations</li>
<li>Using React Query in a Next.js project</li>
</ul>
<h2 id="heading-why-use-react-query">Why use React Query?</h2>
<p>If you've ever built an application that involves some kind of API or requesting data before, you're probably familiar with this pattern:</p>
<ol>
<li>Create some stateful variables using <code>useState</code>, like <code>data</code>, <code>isLoading</code>, <code>isError</code>.</li>
<li>A <code>useEffect</code> hook that fetches some data from an API, and updates these stateful variables accordingly</li>
<li>On the UI, show a loading state while the loading flag is true, or show the data or an error when it is available.</li>
<li>Another <code>useEffect</code>, that listens for updates and keeps the state variables up-to-date.</li>
</ol>
<p>Before you know it, you've got 50-100 lines of React code just to keep track of data for one page!</p>
<p>This still hasn't taken into account caching, memoization or performance optimizations like pagination!</p>
<p>What if you could use one hook, <code>useQuery</code> that handles all of this for you? And another hook, <code>useMutation</code> to keep your read and write operations in sync!</p>
<p>React Query is designed to help resolve these issues, and claims to "defeat and overcome the tricky challenges and hurdles of server state".</p>
<p>Let's explore it together and learn how we can improve our apps with this helpful library!</p>
<h2 id="heading-installation">Installation</h2>
<p>For this project I'll be using Next.js and TypeScript:</p>
<pre><code class="lang-bash">npx create-next-app@latest --ts
</code></pre>
<p>Then I'll install the react-query library</p>
<pre><code class="lang-bash">yarn add react-query
</code></pre>
<h2 id="heading-making-queries">Making Queries</h2>
<p>Querying refers to the process of <strong>fetching</strong> or "reading" data.</p>
<p>In React Query, a <code>query</code> is defined as:</p>
<blockquote>
<p>A declarative dependency on an asynchronous source of data that is tied to a <strong>unique key</strong>.</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1655623197635/C_bIz0Te1.gif" alt="i know some.gif" /></p>
<p>To break that sentence down:</p>
<ol>
<li>A query uses an asynchronous function that fetches some data, (e.g. <code>fetchPosts</code>)</li>
<li>Each query has a unique key that identifies itself, which is used for re-fetching and caching, (e.g. <code>posts</code>)</li>
</ol>
<p>For example, in step 1, you might have a function that fetches a list of todos from your database called <code>fetchTodoList</code>.</p>
<p>In step 2, you can use any name you like to define this query, let's say <code>todos</code> is the key to fetch all todos.</p>
<p>Combining them together, you end up with this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> result = useQuery(<span class="hljs-string">'todos'</span>, fetchTodoList)
</code></pre>
<p>Here, the <code>result</code> value contains a tonne of info, which you can de-structure as you please. It contains:</p>
<p><strong>Flags:</strong></p>
<ul>
<li><code>isLoading</code></li>
<li><code>isError</code></li>
<li><code>isSuccess</code></li>
<li><code>isIdle</code></li>
<li><code>isFetching</code></li>
</ul>
<p><strong>Data</strong></p>
<ul>
<li><code>error</code></li>
<li><code>data</code> 👈If your data fetching function ran successfully, the result is in here.</li>
</ul>
<p>Typically you might de-structure this <code>result</code> to look like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> { isLoading, isError, data, error } = useQuery(<span class="hljs-string">'todos'</span>, fetchTodoList)
</code></pre>
<p>And to take it a step further, you can re-name the <code>data</code> variable to be something meaningful:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> { <span class="hljs-attr">data</span>: todos } = useQuery(<span class="hljs-string">'todos'</span>, fetchTodoList)
</code></pre>
<p>Then, you can reflect all of these states on the UI, and show the data once it's loaded:</p>
<pre><code class="lang-jsx"> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Todos</span>(<span class="hljs-params"></span>) </span>{
   <span class="hljs-keyword">const</span> { isLoading, isError, data, error } = useQuery(<span class="hljs-string">'todos'</span>, fetchTodoList)

   <span class="hljs-keyword">if</span> (isLoading) {
     <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span></span>
   }

   <span class="hljs-keyword">if</span> (isError) {
     <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Error: {error.message}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span></span>
   }

   <span class="hljs-comment">// We can assume by this point that `isSuccess === true`</span>
   <span class="hljs-keyword">return</span> (
     <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
       {data.map(todo =&gt; (
         <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{todo.id}</span>&gt;</span>{todo.title}<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>
   )
 }
</code></pre>
<h3 id="heading-query-keys">Query Keys</h3>
<p>Okay, but why did we need that <code>key</code> called <code>todos</code>? Couldn't we have just used the function itself?</p>
<p>Here's where <strong>caching</strong> comes into play.</p>
<p>React Query is essentially building an object that contains a key-value pair for each query you make.</p>
<p>The key is the name of the query you made, <code>todos</code>. </p>
<p>The value is the result of that query (the data).</p>
<p>Let's break it down step-by-step and see why this is useful:</p>
<ol>
<li>You make a query to fetch all of your <code>todos</code> using the <code>fetchTodoList</code> function. Let's say you get two todos back in the result of this function.</li>
<li>React Query creates an entry into its mapping, saying "todo" is equal to those two queries.</li>
<li>Next time you need this <code>todos</code> data, you run the exact same query, using <code>fetchTodoList</code>, and the same key, <code>todos</code>.</li>
<li>React Query checks its mapping to see if it knows about this <code>todos</code> key, because <em>if</em> it does, then it can just return the data it kept knowledge of in step 2, rather than re-running the query again.</li>
</ol>
<p>This saves your application from re-fetching data that has already been calculated, because that data has been stored in a <strong>cache</strong>.</p>
<p>Now let's imagine the query to get fetch todos takes 2 seconds.</p>
<p>Your app just got a whole lot faster, saving 2 seconds every time you would have re-fetched these todos from the database.</p>
<h3 id="heading-technically">Technically...</h3>
<p>But wait, there's more!</p>
<p>Now let's imagine you have multiple users in your application.</p>
<p>The result of the <code>todos</code> query will be different for each user, this is why you can define the <code>key</code> to be an array, rather than just a string.</p>
<p>For example, currently, the key to identify our query is just "todos".</p>
<p>Behind the scenes, React query is actually converting this key to an array: <code>['todos']</code>.</p>
<p>If we wanted to have different cached results for different user we can use an array as a key instead:</p>
<p><strong>User One</strong>:</p>
<pre><code class="lang-jsx">useQuery([<span class="hljs-string">'todos'</span>, <span class="hljs-number">1</span>], fetchTodoListForUser(<span class="hljs-number">1</span>))
</code></pre>
<p><strong>User Two</strong>:</p>
<pre><code class="lang-jsx">useQuery([<span class="hljs-string">'todos'</span>, <span class="hljs-number">2</span>], fetchTodoListForUser(<span class="hljs-number">2</span>))
</code></pre>
<p>The array value here is serialized and used as the key value of the cache. The result? Different cached values for different users.</p>
<h3 id="heading-dependent-queries">Dependent Queries</h3>
<p>Often in our applications, we might have this pattern:</p>
<ol>
<li>Fetch some info</li>
<li>Fetch more info, but info that depends on info from step 1</li>
</ol>
<p>For example:</p>
<ol>
<li>Fetch a post by its ID</li>
<li>Fetch the user info for the user who posted this, using the result of step 1</li>
</ol>
<p>Without React Query, you'd likely:</p>
<ol>
<li>Fetch the post</li>
<li>Store it in a state variable, along with some loading and error flags, </li>
<li>Create a <code>useEffect</code> to listen for when that post has been loaded</li>
<li>If that post data came back successfully, <em>and</em> has a userId field, <em>then</em>, inside another <code>useEffect</code>; fetch the user. </li>
<li>Store the user in another state field (again, with loading and error flags)</li>
</ol>
<p>By this point, you've easily got 50 lines of code for two read operations!</p>
<p>Let's compare that to React Query's <strong>Dependent Queries</strong>:</p>
<pre><code class="lang-jsx"> <span class="hljs-comment">// Get the post by it's id</span>
 <span class="hljs-keyword">const</span> { <span class="hljs-attr">data</span>: post } = useQuery([<span class="hljs-string">'post'</span>, id], getUserByPost()

<span class="hljs-comment">// Get the user id of the user that posted this post</span>
 <span class="hljs-keyword">const</span> userId = post?.ownerId

 <span class="hljs-comment">// Then get the user information</span>
 <span class="hljs-keyword">const</span> { isIdle, <span class="hljs-attr">data</span>: user } = useQuery(
   [<span class="hljs-string">'user'</span>, userId],
   getUser,
   {
     <span class="hljs-comment">// The query will not execute until the userId is available</span>
     <span class="hljs-attr">enabled</span>: !!userId,
   }
 )
</code></pre>
<p>We've converted it down to less than 10 lines of code, gained caching, re-fetching, and a more error-safe way of reading multiple data sources just by implementing React Query!</p>
<h2 id="heading-mutations">Mutations</h2>
<p>Mutations are "write" operations (as opposed to "read" operations). </p>
<p>They're used to create, update, or delete data.</p>
<p>The real power of React Query's mutations comes with the <code>onSuccess</code> operation.</p>
<p>In a real-world application (without React Query), you might do something like this:</p>
<ol>
<li>Call a function that adds a piece of data</li>
<li>Once that function ran (if it succeeded), manually update the state with the new data</li>
<li>Let React re-render the page with the updated state</li>
</ol>
<p>Let's take a look at how we can solve this pattern using React Query.</p>
<p>A typical mutation in React Query looks like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> mutation = useMutation(postTodo)
</code></pre>
<p>Nothing special, but again, we can de-structure <code>mutation</code> to get meaningful flags and information about how our write operation is performing and where it's at.</p>
<ul>
<li><code>isIdle</code></li>
<li><code>isLoading</code></li>
<li><code>isError</code></li>
<li><code>isSuccess</code></li>
<li><code>error</code></li>
<li><code>data</code></li>
</ul>
<p>Let's say we have a function that allows a user to create a todo in the database called <code>addTodo</code>.</p>
<p>Whenever they add a todo, we need to update the query we have that fetches those todos, to let it know that there are new todos to fetch and that the result it currently has is invalid now.</p>
<p>To achieve this, we can combine:</p>
<ul>
<li><code>useQueryClient</code></li>
<li><code>invalidateQueries</code></li>
<li>the mutation's <code>onSuccess</code> event.</li>
</ul>
<pre><code class="lang-jsx"> <span class="hljs-keyword">import</span> { useMutation, useQueryClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-query'</span>

 <span class="hljs-keyword">const</span> queryClient = useQueryClient()

 <span class="hljs-comment">// When this mutation succeeds, invalidate any queries with the `todos` query key</span>
 <span class="hljs-keyword">const</span> mutation = useMutation(addTodo, {
   <span class="hljs-attr">onSuccess</span>: <span class="hljs-function">() =&gt;</span> {
     queryClient.invalidateQueries(<span class="hljs-string">'todos'</span>)
   },
 })
</code></pre>
<p>That's one way to do it. But this way, we're re-fetching ALL of that data again, when we really just want to let the query know that one new thing was added, so it's pretty inefficient.</p>
<p>For this case, we can use <code>setQueryData</code> instead, to tell our query that there has been an update, rather than telling it that the whole thing is invalid and re-fetch.</p>
<pre><code class="lang-jsx"> <span class="hljs-keyword">const</span> queryClient = useQueryClient()

 <span class="hljs-keyword">const</span> mutation = useMutation(editTodo, {
   <span class="hljs-attr">onSuccess</span>: <span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
     queryClient.setQueryData([<span class="hljs-string">'todo'</span>, { <span class="hljs-attr">id</span>: <span class="hljs-number">5</span> }], data)
   }
 })

 mutation.mutate({
   <span class="hljs-attr">id</span>: <span class="hljs-number">5</span>,
   <span class="hljs-attr">name</span>: <span class="hljs-string">'Do the laundry'</span>,
 })

 <span class="hljs-comment">// The query below will be updated with the response from the</span>
 <span class="hljs-comment">// successful mutation</span>
 <span class="hljs-keyword">const</span> { status, data, error } = useQuery([<span class="hljs-string">'todo'</span>, { <span class="hljs-attr">id</span>: <span class="hljs-number">5</span> }], fetchTodoById)
</code></pre>
<h2 id="heading-using-nextjs">Using Next.js</h2>
<p>We've only talked about client-side querying so far.</p>
<p>What about server-side rendering and static site generation?</p>
<p>Should you use React Query for that?</p>
<p>Short answer: yes!</p>
<p>Long answer: Yes, using <code>prefetchQuery</code>, <code>dehydrate</code>, and wrapping your application inside a <code>QueryClientProvider</code> a <code>Hydrate</code> components.</p>
<p><strong>Wrapping your <code>_app.tsx</code> file</strong>:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { Hydrate, QueryClient, QueryClientProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-query"</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> <span class="hljs-string">"../styles/globals.css"</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">const</span> [queryClient] = useState(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">new</span> QueryClient());

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">QueryClientProvider</span> <span class="hljs-attr">client</span>=<span class="hljs-string">{queryClient}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Hydrate</span> <span class="hljs-attr">state</span>=<span class="hljs-string">{pageProps.dehydratedState}</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">Hydrate</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">QueryClientProvider</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> MyApp;
</code></pre>
<p><strong>Fetch some data on the server-side</strong></p>
<pre><code class="lang-jsx">
 <span class="hljs-comment">// pages/posts.jsx</span>
 <span class="hljs-keyword">import</span> { dehydrate, QueryClient, useQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-query'</span>;

 <span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params"></span>) </span>{
   <span class="hljs-keyword">const</span> queryClient = <span class="hljs-keyword">new</span> QueryClient()

   <span class="hljs-keyword">await</span> queryClient.prefetchQuery(<span class="hljs-string">'posts'</span>, getPosts)

   <span class="hljs-keyword">return</span> {
     <span class="hljs-attr">props</span>: {
       <span class="hljs-attr">dehydratedState</span>: dehydrate(queryClient),
     },
   }
 }
</code></pre>
<p><strong>Hydrate the data on the client-side</strong>:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Home: NextPage = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// This useQuery could just as well happen in some deeper child to</span>
  <span class="hljs-comment">// the "Posts"-page, data will be available immediately either way</span>
  <span class="hljs-keyword">const</span> { data } = useQuery(<span class="hljs-string">"posts"</span>, getPosts);

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Data:"</span>, data);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>hello world<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};
</code></pre>
<p>This uses some intimidating terms like <code>dehydrate</code> and <code>prefetch</code>, but let's break it down.</p>
<p>Next.js pre-renders the DOM so that the user can view the information on the page quickly, without having to wait for the query to run (we do that at build-time when we statically generate the page).</p>
<p>At this point in time, we have a "dehydrated" state for React Query.</p>
<blockquote>
<p><code>dehydrate</code> creates a frozen representation of a cache that can later be hydrated with Hydrate, useHydrate, or hydrate. This is useful for passing prefetched queries from server to client or persisting queries to localStorage or other persistent locations. It only includes currently successful queries by default.</p>
</blockquote>
<p>You'll notice we are returning a <code>dehydratedState</code> variable on the server-side as props to our component. This is important for the next step.</p>
<p>We <code>hydrate</code> the query on the client-side, using the queries inside of the <code>dehydratedState</code> variable, and hydrate them.</p>
<blockquote>
<p>hydrate adds a previously dehydrated state into a cache. If the queries included in dehydration already exist in the queryCache, hydrate does not overwrite them.</p>
</blockquote>
<p>This way, we get all the benefits of the React Query library, like caching and re-fetching, but with data that originally came from the server-side.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>If you find yourself using <code>useState</code> and <code>useEffect</code> to manage your data, I'd suggest checking out this amazing tool, React Query!</p>
<p>React Query is an exciting, easy-to-implement library with excellent documentation to match. </p>
<p>It achieves its goal of overcoming the tricky challenges and hurdles of managing state on both client and server, and I will be integrating it into all of my projects going forward!</p>
<p>This guide discusses the basics of React Query and why you might want to use it, including:</p>
<ul>
<li>Why use React Query</li>
<li>Reading data using React Query's <code>queries</code></li>
<li>Writing data using React Query's <code>mutation</code>s</li>
<li>Real-world examples of server-side rendering and client-side hydration.</li>
</ul>
<h1 id="heading-follow-me">Follow Me</h1>
<p>If you enjoyed this article, follow me on Twitter for more thoughts on full-stack development particularly in the web3 space!</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/jarrodWattsDev">https://twitter.com/jarrodWattsDev</a></div>
]]></content:encoded></item><item><title><![CDATA[Create An NFT Staking Smart Contract with Solidity & thirdweb Deploy!]]></title><description><![CDATA[Introduction
In this guide, we will create:

An ERC-721 NFT Drop smart contract with lazy minted NFTs users can mint
Your own ERC-20 token smart contract
An NFT Staking Smart Contract where users can stake their NFTs, and earn tokens for doing so!

B...]]></description><link>https://blog.jarrodwatts.com/create-an-nft-staking-smart-contract-with-solidity-and-thirdweb-deploy</link><guid isPermaLink="true">https://blog.jarrodwatts.com/create-an-nft-staking-smart-contract-with-solidity-and-thirdweb-deploy</guid><category><![CDATA[thirdweb]]></category><category><![CDATA[Ethereum]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[Smart Contracts]]></category><dc:creator><![CDATA[Jarrod Watts]]></dc:creator><pubDate>Mon, 06 Jun 2022 16:00:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1654318833138/6KfkZnpcj.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>In this guide, we will create:</p>
<ol>
<li>An ERC-721 <strong>NFT Drop smart contract</strong> with <strong>lazy minted</strong> NFTs users can mint</li>
<li>Your own <strong>ERC-20</strong> token smart contract</li>
<li>An <strong>NFT Staking Smart Contract</strong> where users can stake their NFTs, and earn tokens for doing so!</li>
</ol>
<p>By the end, we'll have a full stack web application where users can see which NFTs they own, stake them onto the smart contract, and claim their rewards!</p>
<p>Let's do this!</p>
<h2 id="heading-what-well-build">What We'll Build</h2>
<p>You can check out a demo of the finished product below:</p>
<p>https://nft-staking-contract.thirdweb-example.com/</p>
<h3 id="heading-source-code">Source Code</h3>
<p>You can access the full source code from 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/thirdweb-example/nft-staking-app">https://github.com/thirdweb-example/nft-staking-app</a></div>
<p>Let's get started!</p>
<h1 id="heading-creating-the-nft-drop-smart-contract">Creating the NFT Drop Smart Contract</h1>
<p>Our objective with the NFT Drop is to upload all of our NFT metadata, and then allow users to come to our website and mint a random NFT from our collection.</p>
<p>We can do this using <a target="_blank" href="https://portal.thirdweb.com/pre-built-contracts/nft-drop">thirdweb's Pre-built NFT Drop Contract</a>!</p>
<blockquote>
<p>thirdweb's drop contracts lazy mint your NFTs and makes them available to be claimed by your users.</p>
</blockquote>
<p>That's exactly what we need! Alright, let's go ahead and create our NFT Drop!</p>
<h2 id="heading-creating-the-nft-drop-contract">Creating the NFT Drop Contract</h2>
<p>Head to the <a target="_blank" href="https://thirdweb.com/dashboard">thirdweb dashboard</a> and connect your wallet. </p>
<p>Then click on <strong>Deploy New Contract</strong>.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652495920499/Zqcuz0825.png" alt="image.png" class="image--center mx-auto" /></p>
<p>What we want is the <strong>NFT Drop</strong> contract, lets click <strong>Deploy Now</strong> on this one!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652496316402/0dbR60UFS.png" alt="image.png" class="image--center mx-auto" /></p>
<p>You can configure the <strong>Name</strong>, <strong>Symbol</strong>, <strong>Description</strong>, <strong>Image</strong>, and <strong>Royalty</strong> information in the settings before you deploy your NFT Drop.</p>
<p>I'll call my NFT Drop <code>Colored Shapes</code> and stick with the default values for the rest of the fields, but feel free to go wild and configure this to your liking!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652496501242/IMVq2FdFh.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Once you're happy, let's deploy this NFT Drop onto the <strong>Mumbai (MATIC) Test network.</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652496532723/K_fv48FTJ.png" alt="image.png" class="image--center mx-auto" /></p>
<p>This will prompt you to accept a transaction in MetaMask (or whatever wallet you connected with), and deploy your smart contract onto the Mumbai Test network!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652496588521/dBeR41BeQ.png" alt="image.png" class="image--center mx-auto" /></p>
<p>You might notice that the MetaMask transaction is requesting we <code>Deploy Proxy</code>. What on earth does that mean? Let's quickly explore what happens when we deploy a pre-built contract on thirdweb.</p>
<h3 id="heading-pre-built-contracts-and-deploying-a-proxy">Pre-built contracts and deploying a proxy</h3>
<p>thirdweb v2 introduced <strong>Proxy Contracts</strong>. For a full breakdown, you can check out the documentation on <a target="_blank" href="https://portal.thirdweb.com/pre-built-contracts#how-thirdweb-pre-built-contracts-work">how thirdweb pre-built contracts work</a>.</p>
<p>In a nutshell, the bulk of the smart contract logic has been created and deployed by thirdweb; you're just deploying a <strong>Proxy Contract</strong>, that stores information specific to <strong>YOUR</strong> smart contract. Such as the name, description, symbol, owner, and royalty configuration. </p>
<p>Since all of the NFT Contracts deployed on thirdweb have the same logic for things like minting and burning NFTs, we can simply <a target="_blank" href="https://docs.soliditylang.org/en/v0.8.13/introduction-to-smart-contracts.html#delegatecall-callcode-and-libraries">delegate</a> these function calls to the thirdweb base contracts; where the "real" logic lives.</p>
<p>This way, it is around <strong>10 times cheaper</strong> to deploy our smart contracts, since we deploy a lot less code, and let the thirdweb base contracts handle all the logic for us.</p>
<p>Here is a simple diagram to explain how this works:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652497081789/s2y1d0YVH.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Alright, now we know what we're deploying, lets's <strong>Confirm</strong> that transaction and continue!</p>
<h2 id="heading-setting-claim-phases">Setting Claim Phases</h2>
<p><a target="_blank" href="https://portal.thirdweb.com/pre-built-contracts/nft-drop#setting-claim-phases">Claim Phases</a> are conditions we can configure that define when and how users can claim NFTs from our collection.</p>
<p>A popular claim phase pattern is to have one claim phase where allow-listed wallets can claim, then another phase where <em>any</em> wallet can claim.</p>
<p>From the thirdweb dashboard, let's click <strong>Set Claim Phase</strong> and configure a simple claim phase where anyone can mint/claim our NFTs.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652497348036/rk0NpNoxN.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Click on <strong>Add Phase</strong>, and configure it to your liking! </p>
<p>I'm going to change the <code>How many NFTs can be claimed per transaction?</code> to be <code>1</code>, and accept the default values for the other fields.</p>
<p>Once you're happy with your claim phase(s), click <strong>Update Claim Phases</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652497437908/yDCCGD9sj.png" alt="image.png" class="image--center mx-auto" /></p>
<h2 id="heading-lazy-minting-nfts">Lazy Minting NFTs</h2>
<p>Awesome, now we have a claim phase set up, users can start claiming NFTs from our collection! So let's create those NFTs now.</p>
<p>thirdweb's <strong>Drop</strong> contracts <strong>Lazy Mint</strong> your NFTs. That means the user who <strong>claims</strong> the NFT is the one who actually does the minting of the NFT they claim.</p>
<blockquote>
<p>When you add NFTs to your drop contract, they are not minted at this point. You prepare everything for your users so that they can mint the NFT(s). This means the user who claims the NFT is the one who mints it, and it is minted into their wallet. By default, the user is the one who pays the gas fees.</p>
</blockquote>
<p>So now all we need to do is upload the metadata for our NFTs, such as the images, names, and descriptions of each NFT.</p>
<h3 id="heading-how-to-batch-upload-nft-metadata">How to Batch Upload NFT Metadata</h3>
<p>If you don't already have NFTs that you want to upload, you can use thirdweb's example files to create a dummy NFT Collection.  You can access either of those via the links below:</p>
<ul>
<li><a target="_blank" href="https://thirdweb.com/example.csv">Example CSV File</a></li>
<li><a target="_blank" href="https://thirdweb.com/example.json">Example JSON File</a></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652497911240/R_3Y6tsa_.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Upload your metadata file along with your images into the drag-n-drop area, and voilà!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652497974203/bybxk5bur.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Your NFTs will be ready for you to upload:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652498018610/LdUvVI4rk.png" alt="image.png" /></p>
<p>Make sure you're happy with how everything looks, then scroll to the bottom and click <strong>Next</strong>!</p>
<p>You'll then be given the option to add a <a target="_blank" href="https://portal.thirdweb.com/guides/nft-drop-with-delayed-reveal">Delayed Reveal</a>, which is up to you! For the purpose of this guide, I will choose <strong>Reveal upon mint</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652498085384/P5nG4_jbq.png" alt="image.png" /></p>
<p>Then I'll hit <strong>Upload 30 NFTs</strong>!</p>
<p>We're again prompted to approve a transaction, this time the name is a bit more obvious - we're <strong>Lazy Minting</strong> the NFTs we just uploaded, so I'll click <strong>Confirm</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652498259150/qDog0qHox.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Once the transaction is confirmed, we can see all of our NFTs that we just uploaded in the <strong>Overview</strong> tab of the NFT Drop.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652498353520/WeYbuUIki.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Awesome! Now our users are ready to start minting the NFTs from our collection.</p>
<p>Before we set that up, let's create our very own <strong>ERC-20 token</strong> too.</p>
<h1 id="heading-creating-the-erc-20-token">Creating the ERC-20 Token</h1>
<p>Creating our token is even easier than creating our NFT Drop, we'll follow the same path of clicking <strong>Deploy New Contract</strong> and <strong>Deploy Now</strong>, except this time we'll deploy a <a target="_blank" href="https://portal.thirdweb.com/pre-built-contracts/token">Token</a> contract rather than an NFT Drop.</p>
<p>I'll configure my Token with these settings, and click <strong>Deploy Now</strong>, once again deploying onto the <strong>Mumbai (MATIC)</strong> test network.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652499375532/y-53TBTRU.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Once we've created our token, let's mint the initial supply so that we can reward users later on for staking their NFTs. We can easily do that on the dashboard by clicking the <strong>Mint</strong> button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652499546413/pzPg94yT0.png" alt="image.png" class="image--center mx-auto" /></p>
<p>For simplicity, I'll initially create 100 of these tokens by clicking <strong>Mint Tokens</strong>, and approve the <strong>Mint To</strong> transaction in MetaMask.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652499611919/ZDIyqt7Vz.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Great! Now we have 100 tokens! In the next step, we'll be able to transfer these to our staking smart contract so that they can be sent out as rewards by the contract.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652499768187/BXlHLNdBB.png" alt="image.png" /></p>
<p>Let's build our Staking smart contract now!</p>
<h1 id="heading-building-the-staking-contract">Building the Staking Contract</h1>
<p>The purpose of our staking contract is to store users' NFTs from our NFT Drop contract and reward them with tokens from our token contract. </p>
<p>The longer the user stakes their NFT, the more tokens they will be rewarded.</p>
<p>To give credit where it's due, most of this code for this staking contract comes from this repo:</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/andreitoma8/ERC721-Staking/blob/master/contracts/ERC721Staking.sol">https://github.com/andreitoma8/ERC721-Staking/blob/master/contracts/ERC721Staking.sol</a></div>
<p>But we'll go through step by step how to build and understand the functions of this contract, and add <a target="_blank" href="https://portal.thirdweb.com/thirdweb-deploy">thirdweb deploy</a> to the contract so that we can:</p>
<ul>
<li>Configure and deploy it via the thirdweb dashboard</li>
<li>Generate TypeScript functions to interact with our contract</li>
<li>Use the thirdweb React and TypeScript SDKs to easily use the contract &amp; the blockchain.</li>
</ul>
<h2 id="heading-creating-the-project">Creating the Project</h2>
<p>For this guide, I'll be using <strong><a target="_blank" href="https://nextjs.org/">Next.js</a></strong> &amp; <strong>TypeScript</strong> to set up the project, and we'll create the smart contract directly in the project for simplicity.</p>
<p>Feel free to use the tools you're comfortable with, or follow along with the steps in this guide to end up with the same result!</p>
<h3 id="heading-initializing-the-nextjs-project-with-thirdweb">Initializing the Next.JS Project with thirdweb</h3>
<p>To create a new project using Next.JS, TypeScript and thirdweb, we can use thirdweb's <code>create-thirdweb-dapp</code> CLI tool:</p>
<pre><code class="lang-bash">npx create-thirdweb-dapp --next --ts
</code></pre>
<p>Change directory into the newly cloned repo:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> .\nft-staking-app\
</code></pre>
<p>Now we have a basic example of Next.JS + thirdweb + Typescript setup, where we can connect, disconnect, and view our MetaMask wallet on the homepage, using thirdweb's helpful hooks.</p>
<h2 id="heading-writing-the-staking-contract">Writing The Staking Contract</h2>
<p>We'll be using some of the [OpenZeppelin contracts] inside of our contract, so we'll need to install the <code>@openzeppelin/contracts</code> package into our project:</p>
<pre><code class="lang-bash">npm install @openzeppelin/contracts
</code></pre>
<p>To begin with, let's create a new file at the root of our project called <code>StakingContract.sol</code>, which is a Solidity file.</p>
<p>If you're new to Solidity, I'd recommend you install an Extension that provides syntax highlighting such as this one called <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=JuanBlanco.solidity">solidity</a> to make it a lot easier to read.</p>
<p>Let's define our license, imports, and contract in this file:</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.4;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/IERC20.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC721/IERC721.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts/security/ReentrancyGuard.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">ERC721Staking</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ReentrancyGuard</span> </span>{

}
</code></pre>
<p>Now let's walk through how the <a target="_blank" href="https://github.com/thirdweb-example/nft-staking-app/blob/main/StakingContract.sol">staking contract</a> is structured, and write it together step by step!</p>
<p>Firstly, let's make some variables for where we're going to store the contract address of the <code>NFT Collection</code> and <code>Token</code> that we created previously:</p>
<pre><code class="lang-solidity"><span class="hljs-comment">// We do this so we can use the safeTransfer function</span>
<span class="hljs-keyword">using</span> <span class="hljs-title">SafeERC20</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title">IERC20</span>;

<span class="hljs-comment">// Interfaces for ERC20 and ERC721</span>
IERC20 <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> rewardsToken;
IERC721 <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> nftCollection;
</code></pre>
<p>We can use a <code>struct</code> to store information about a staked token:</p>
<pre><code class="lang-solidity">    <span class="hljs-keyword">struct</span> <span class="hljs-title">StakedToken</span> {
        <span class="hljs-keyword">address</span> staker;
        <span class="hljs-keyword">uint256</span> tokenId;
    }
</code></pre>
<p>Now let's make a <code>struct</code> called <code>Staker</code>, which represents the information we need about a wallet that is going to stake its NFTs on our contract:</p>
<pre><code class="lang-solidity">    <span class="hljs-comment">// Staker info</span>
    <span class="hljs-keyword">struct</span> <span class="hljs-title">Staker</span> {
        <span class="hljs-comment">// Amount of tokens staked by the staker</span>
        <span class="hljs-keyword">uint256</span> amountStaked;

        <span class="hljs-comment">// Staked token ids</span>
        StakedToken[] stakedTokens;

        <span class="hljs-comment">// Last time of the rewards were calculated for this user</span>
        <span class="hljs-keyword">uint256</span> timeOfLastUpdate;

        <span class="hljs-comment">// Calculated, but unclaimed rewards for the User. The rewards are</span>
        <span class="hljs-comment">// calculated each time the user writes to the Smart Contract</span>
        <span class="hljs-keyword">uint256</span> unclaimedRewards;
    }
</code></pre>
<p>Next up, we'll configure how many tokens we want to reward per <strong>hour</strong> the NFT has been staked:</p>
<pre><code class="lang-solidity">    <span class="hljs-comment">// Rewards per hour per token deposited in wei.</span>
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">private</span> rewardsPerHour <span class="hljs-operator">=</span> <span class="hljs-number">100000</span>;
</code></pre>
<p>Some <code>mapping</code>s to store knowledge of:</p>
<ul>
<li>Wallet address to <code>Staker</code> (so we know which wallet is which staker)</li>
<li>Token ID to wallet address (so we know which NFT is staked by which wallet)</li>
</ul>
<pre><code class="lang-solidity">    <span class="hljs-comment">// Mapping of User Address to Staker info</span>
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> Staker) <span class="hljs-keyword">public</span> stakers;

    <span class="hljs-comment">// Mapping of Token Id to staker. Made for the SC to remeber</span>
    <span class="hljs-comment">// who to send back the ERC721 Token to.</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">address</span>) <span class="hljs-keyword">public</span> stakerAddress;
</code></pre>
<p>The <code>constructor</code>, which allows us to set the value of the NFT Collection contract address and the token contract address when we deploy the contract (we'll do this on the thirdweb dashboard);</p>
<pre><code class="lang-solidity">    <span class="hljs-comment">// Constructor function to set the rewards token and the NFT collection addresses</span>
    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params">IERC721 _nftCollection, IERC20 _rewardsToken</span>) </span>{
        nftCollection <span class="hljs-operator">=</span> _nftCollection;
        rewardsToken <span class="hljs-operator">=</span> _rewardsToken;
    }
</code></pre>
<p>Now to the functions!</p>
<p>First up, is a function that allows the user to <code>stake</code> their NFT. </p>
<p>This function also needs to store knowledge of which wallet address is staking which token IDs in the <code>mapping</code>s we created:</p>
<pre><code class="lang-solidity">    <span class="hljs-comment">// If address already has ERC721 Token/s staked, calculate the rewards.</span>
    <span class="hljs-comment">// Increment the amountStaked and map msg.sender to the Token Id of the staked</span>
    <span class="hljs-comment">// Token to later send back on withdrawal. Finally give timeOfLastUpdate the</span>
    <span class="hljs-comment">// value of now.</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">stake</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">nonReentrant</span> </span>{
        <span class="hljs-comment">// If wallet has tokens staked, calculate the rewards before adding the new token</span>
        <span class="hljs-keyword">if</span> (stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>].amountStaked <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span>) {
            <span class="hljs-keyword">uint256</span> rewards <span class="hljs-operator">=</span> calculateRewards(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>);
            stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>].unclaimedRewards <span class="hljs-operator">+</span><span class="hljs-operator">=</span> rewards;
        }

        <span class="hljs-comment">// Wallet must own the token they are trying to stake</span>
        <span class="hljs-built_in">require</span>(
            nftCollection.ownerOf(_tokenId) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>,
            <span class="hljs-string">"You don't own this token!"</span>
        );

        <span class="hljs-comment">// Transfer the token from the wallet to the Smart contract</span>
        nftCollection.transferFrom(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), _tokenId);

        <span class="hljs-comment">// Create StakedToken</span>
        StakedToken <span class="hljs-keyword">memory</span> stakedToken <span class="hljs-operator">=</span> StakedToken(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, _tokenId);

        <span class="hljs-comment">// Add the token to the stakedTokens array</span>
        stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>].stakedTokens.<span class="hljs-built_in">push</span>(stakedToken);

        <span class="hljs-comment">// Increment the amount staked for this wallet</span>
        stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>].amountStaked+<span class="hljs-operator">+</span>;

        <span class="hljs-comment">// Update the mapping of the tokenId to the staker's address</span>
        stakerAddress[_tokenId] <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;

        <span class="hljs-comment">// Update the timeOfLastUpdate for the staker   </span>
        stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>].timeOfLastUpdate <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>;
    }
</code></pre>
<p>A function that allows the user to <code>withdraw</code> the NFTs they have staked:</p>
<pre><code class="lang-solidity">    <span class="hljs-comment">// Check if user has any ERC721 Tokens Staked and if they tried to withdraw,</span>
    <span class="hljs-comment">// calculate the rewards and store them in the unclaimedRewards</span>
    <span class="hljs-comment">// decrement the amountStaked of the user and transfer the ERC721 token back to them</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</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">nonReentrant</span> </span>{
        <span class="hljs-comment">// Make sure the user has at least one token staked before withdrawing</span>
        <span class="hljs-built_in">require</span>(
            stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>].amountStaked <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span>,
            <span class="hljs-string">"You have no tokens staked"</span>
        );

        <span class="hljs-comment">// Wallet must own the token they are trying to withdraw</span>
        <span class="hljs-built_in">require</span>(stakerAddress[_tokenId] <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-string">"You don't own this token!"</span>);

        <span class="hljs-comment">// Update the rewards for this user, as the amount of rewards decreases with less tokens.</span>
        <span class="hljs-keyword">uint256</span> rewards <span class="hljs-operator">=</span> calculateRewards(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>);
        stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>].unclaimedRewards <span class="hljs-operator">+</span><span class="hljs-operator">=</span> rewards;

        <span class="hljs-comment">// Find the index of this token id in the stakedTokens array</span>
        <span class="hljs-keyword">uint256</span> index <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">uint256</span> i <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i <span class="hljs-operator">&lt;</span> stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>].stakedTokens.<span class="hljs-built_in">length</span>; i<span class="hljs-operator">+</span><span class="hljs-operator">+</span>) {
            <span class="hljs-keyword">if</span> (stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>].stakedTokens[i].tokenId <span class="hljs-operator">=</span><span class="hljs-operator">=</span> _tokenId
                <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span>
                stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>].stakedTokens[i].staker <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>)
            ) {
                index <span class="hljs-operator">=</span> i;
                <span class="hljs-keyword">break</span>;
            }
        }

        <span class="hljs-comment">// Set this token's .staker to be address 0 to mark it as no longer staked</span>
        stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>].stakedTokens[index].staker <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>);

        <span class="hljs-comment">// Decrement the amount staked for this wallet</span>
        stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>].amountStaked-<span class="hljs-operator">-</span>;

        <span class="hljs-comment">// Update the mapping of the tokenId to the be address(0) to indicate that the token is no longer staked</span>
        stakerAddress[_tokenId] <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>);

        <span class="hljs-comment">// Transfer the token back to the withdrawer</span>
        nftCollection.transferFrom(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, _tokenId);

        <span class="hljs-comment">// Update the timeOfLastUpdate for the withdrawer   </span>
        stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>].timeOfLastUpdate <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>;
    }
</code></pre>
<p>Finally, we have a function for the user to <code>claimRewards</code> so that they can be rewarded with the tokens we created for staking their NFT:</p>
<pre><code class="lang-solidity">    <span class="hljs-comment">// Calculate rewards for the msg.sender, check if there are any rewards</span>
    <span class="hljs-comment">// claim, set unclaimedRewards to 0 and transfer the ERC20 Reward token</span>
    <span class="hljs-comment">// to the user.</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">claimRewards</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">uint256</span> rewards <span class="hljs-operator">=</span> calculateRewards(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>) <span class="hljs-operator">+</span>
            stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>].unclaimedRewards;
        <span class="hljs-built_in">require</span>(rewards <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span>, <span class="hljs-string">"You have no rewards to claim"</span>);
        stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>].timeOfLastUpdate <span class="hljs-operator">=</span> <span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>;
        stakers[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>].unclaimedRewards <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
        rewardsToken.safeTransfer(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, rewards);
    }
</code></pre>
<p>These are the core pieces of our contract, but you might have noticed there is a function that we call named <code>calculateRewards</code>.</p>
<p>This function calculates the time that has passed since the contract last checked this <code>Staker</code>'s calculated rewards.</p>
<p>This function is <strong>internal</strong>, meaning it is not accessible by the public, only by other functions within this smart contract.</p>
<pre><code class="lang-solidity">    <span class="hljs-comment">// Calculate rewards for param _staker by calculating the time passed</span>
    <span class="hljs-comment">// since last update in hours and mulitplying it to ERC721 Tokens Staked</span>
    <span class="hljs-comment">// and rewardsPerHour.</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculateRewards</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _staker</span>)
        <span class="hljs-title"><span class="hljs-keyword">internal</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> _rewards</span>)
    </span>{
        <span class="hljs-keyword">return</span> (((
            ((<span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span> <span class="hljs-operator">-</span> stakers[_staker].timeOfLastUpdate) <span class="hljs-operator">*</span>
                stakers[_staker].amountStaked)
        ) <span class="hljs-operator">*</span> rewardsPerHour) <span class="hljs-operator">/</span> <span class="hljs-number">3600</span>);
    }
</code></pre>
<p>Amazing work! That's all the logic of our contract, now we just need to add some <code>view</code>s so that we can retrieve that information.</p>
<p>We'll add a view to read the token IDs a user currently has staked:</p>
<pre><code class="lang-solidity">    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStakedTokens</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _user</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">StakedToken[] <span class="hljs-keyword">memory</span></span>) </span>{
        <span class="hljs-comment">// Check if we know this user</span>
        <span class="hljs-keyword">if</span> (stakers[_user].amountStaked <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span>) {
            <span class="hljs-comment">// Return all the tokens in the stakedToken Array for this user that are not -1</span>
            StakedToken[] <span class="hljs-keyword">memory</span> _stakedTokens <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> StakedToken[](stakers[_user].amountStaked);
            <span class="hljs-keyword">uint256</span> _index <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;

            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">uint256</span> j <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; j <span class="hljs-operator">&lt;</span> stakers[_user].stakedTokens.<span class="hljs-built_in">length</span>; j<span class="hljs-operator">+</span><span class="hljs-operator">+</span>) {
                <span class="hljs-keyword">if</span> (stakers[_user].stakedTokens[j].staker <span class="hljs-operator">!</span><span class="hljs-operator">=</span> (<span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>))) {
                    _stakedTokens[_index] <span class="hljs-operator">=</span> stakers[_user].stakedTokens[j];
                    _index<span class="hljs-operator">+</span><span class="hljs-operator">+</span>;
                }
            }

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

        <span class="hljs-comment">// Otherwise, return empty array</span>
        <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> StakedToken[](<span class="hljs-number">0</span>);
        }
    }
</code></pre>
<p>Another to read the available rewards a user has:</p>
<pre><code class="lang-solidity">    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">availableRewards</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _staker</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">uint256</span> rewards <span class="hljs-operator">=</span> calculateRewards(_staker) <span class="hljs-operator">+</span>
            stakers[_staker].unclaimedRewards;
        <span class="hljs-keyword">return</span> rewards;
    }
</code></pre>
<p>That's it! Now we're ready to upload our contract to the thirdweb dashboard using thirdweb deploy.</p>
<h3 id="heading-uploading-the-contract-with-thirdweb-deploy">Uploading the contract with thirdweb deploy</h3>
<p>Now we're ready to upload our contract to thirdweb.</p>
<p>From the command line, let's run:</p>
<pre><code class="lang-bash">npx thirdweb deploy
</code></pre>
<p>The result you see should look like this:</p>
<pre><code class="lang-bash">💎 thirdweb-cli v0.4.53💎

WARN Unable to detect project <span class="hljs-built_in">type</span>, falling back to solc compilation
INFO  Detected thirdweb contracts: <span class="hljs-string">"ERC721Staking"</span>
INFO  Project compiled successfully
INFO  Uploading contract data...
INFO  Upload successful
INFO  Open this link to deploy your contracts:

https://thirdweb.com/contracts/deploy?ipfs=&lt;your-ipfs-url-here&gt;
</code></pre>
<p>If everything was successful, you can open that URL in your browser, which will take you to a page where you can deploy your contract. No private key is required!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652511939582/O5FfrBNAY.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Let's click on <strong>Deploy Now</strong> and deploy our staking contract onto the <strong>Mumbai (MATIC)</strong> test network.</p>
<p>Here, we'll need to populate the required fields we defined in our <code>constructor</code>. </p>
<p>If you go back to the dashboard you can access the contract addresses of your NFT Collection and your Token contracts, and paste them into the contract parameters here:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652512182988/lElXUXT0Q.png" alt="image.png" class="image--center mx-auto" /></p>
<p>You've just deployed your very own custom smart contract with the click of a few buttons!</p>
<p>Let's see how we can integrate it into our application now!</p>
<h3 id="heading-our-generated-sdk">Our Generated SDK</h3>
<p>If you take a look at the <strong>Code</strong> tab now on the thirdweb dashboard, you'll see a fully generated list of functions that we can interact with, just by simply using the thirdweb SDK!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652519052851/PPhGyfn7H.png" alt="image.png" class="image--center mx-auto" /></p>
<p>You can see all of the functions we wrote like <code>stake</code>, <code>withdraw</code>, and <code>claimRewards</code>. </p>
<p>The best part is, we don't have to use any other tools to interact with our smart contract, we can just use TypeScript! The thirdweb SDK's handle the rest. </p>
<p>Now let's build out the front-end of this application, so our users can claim and stake their NFTs, and start earning rewards!</p>
<h2 id="heading-creating-the-front-end-application">Creating the front-end application</h2>
<p>In this guide, I'll be using CSS modules to style the app, if you want to use the same styles as I am, feel free to create a file in <code>styles/Home.module.css</code> and <code>styles/globals.css</code> and use the files provided in this <a target="_blank" href="https://github.com/thirdweb-example/nft-staking-app/tree/main/styles">example repository</a>.</p>
<p>Remember to import these files wherever necessary.</p>
<p>To begin with, lets head to <code>_app.tsx</code> and configure the <code>activeChainId</code> to be set to <code>ChainId.Mumbai;</code>, like so:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> activeChainId = ChainId.Mumbai;
</code></pre>
<p>Then let's head over to our homepage at <code>index.tsx</code>, and create a simple page where users can navigate to two different pages:</p>
<ol>
<li>The <code>/mint</code> route, where they can use our NFT Collection contract to mint one of our lazy minted NFTs from the collection.</li>
<li>The <code>/stake</code> route, where they can view which NFTs they own from this collection, stake their NFT onto the contract, and claim their rewards.</li>
</ol>
<p>Here's how the code looks for this, with styling removed for simplicity:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/router"</span>;

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> router = useRouter();

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>thirdweb Deploy - Custom Staking Contract<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">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> router.push(`/mint`)}&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Mint a new NFT<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
            Use the NFT Drop Contract to claim an NFT from the collection.
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</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">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> router.push(`/stake`)}&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{</span>`/<span class="hljs-attr">icons</span>/<span class="hljs-attr">token.webp</span>`} <span class="hljs-attr">alt</span>=<span class="hljs-string">"drop"</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Stake Your NFTs<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
            Use the custom staking contract deployed via <span class="hljs-tag">&lt;<span class="hljs-name">b</span>&gt;</span>thirdweb Deploy<span class="hljs-tag">&lt;/<span class="hljs-name">b</span>&gt;</span>{" "}
            to stake your NFTs, and earn tokens from the <span class="hljs-tag">&lt;<span class="hljs-name">b</span>&gt;</span>Token<span class="hljs-tag">&lt;/<span class="hljs-name">b</span>&gt;</span> contract.
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</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> Home;
</code></pre>
<p>With some added styling and images, here's how it looks:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652572972841/m2DICNKUk.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Now we'll need to create these pages. In your <code>pages</code> folder, create two new files called <code>mint.tsx</code> and <code>stake.tsx</code>, these will be separate routes where we can handle the logic for minting and staking.</p>
<h3 id="heading-mint-page">Mint Page</h3>
<p>The mint page will show the user a button where they can claim the next available NFT in our NFT Drop. Since we lazy minted these NFTs, the user will be the one who <code>mint</code>s the NFT and pay the gas fee for minting.</p>
<p>Let's walk through the pieces of this claiming page now!</p>
<p>First up, let's create a functional component and import the necessary parts of the SDK to make this work:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { useAddress, useMetamask, useNFTDrop } <span class="hljs-keyword">from</span> <span class="hljs-string">"@thirdweb-dev/react"</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/router"</span>;

<span class="hljs-keyword">const</span> Mint = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> router = useRouter();

  <span class="hljs-keyword">return</span> (
    <span class="xml"><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> Mint;
</code></pre>
<p>Then, let's import the helpful hooks from the <code>@thirdweb-dev/react</code> package:</p>
<pre><code class="lang-jsx">  <span class="hljs-comment">// Get the currently connected wallet's address</span>
  <span class="hljs-keyword">const</span> address = useAddress();

  <span class="hljs-comment">// Function to connect to the user's Metamask wallet</span>
  <span class="hljs-keyword">const</span> connectWithMetamask = useMetamask();

  <span class="hljs-comment">// Get the NFT Collection contract</span>
  <span class="hljs-keyword">const</span> nftDropContract = useNFTDrop(
    <span class="hljs-string">"&lt;your-NFT-Drop-contract-address-here"</span>
  );
</code></pre>
<p>Now we have our NFT Drop contract stored in our <code>nftDropContract</code> variable, just by using one line of code! How cool is that!</p>
<p>We'll need a function to allow users to claim an NFT from our collection. This function will show an <code>alert</code> when the claim is successful, or if something goes wrong inside the <code>catch</code> block. Once the user closes the successful alert, we'll navigate them to the <code>/stake</code> route so they can stake their NFT if they choose to!</p>
<pre><code class="lang-js">  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">claimNft</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> tx = <span class="hljs-keyword">await</span> nftDropContract?.claim(<span class="hljs-number">1</span>);
      <span class="hljs-built_in">console</span>.log(tx);
      alert(<span class="hljs-string">"NFT Claimed!"</span>);
      router.push(<span class="hljs-string">`/stake`</span>);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(error);
      alert(error);
    }
  }
</code></pre>
<p>Now for the UI! We'll need to ensure the user is connected to the site with their wallet before they mint; otherwise the function won't work because there is no connected wallet.</p>
<p>To do this, we'll use a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">ternary operator</a> to show a <code>Connect Wallet</code> button if there is no connected wallet (using <code>address</code>), or show a <code>Claim An NFT</code> button if there <em>is</em> a connected wallet:</p>
<pre><code class="lang-jsx">    &lt;&gt;
      {!address ? (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{connectWithMetamask}</span>
        &gt;</span>
          Connect Wallet
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
      ) : (
          <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> claimNft()}&gt;
            Claim An NFT
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
      )}
    &lt;/div&gt;
</code></pre>
<p>Great! Now with some added styling, we can see both the <code>Connect Wallet</code> view:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652574247532/82WqTLi2m.png" alt="image.png" class="image--center mx-auto" /></p>
<p>And the <code>Claim An NFT</code> view:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652574269772/D5THgK3L_.png" alt="image.png" class="image--center mx-auto" /></p>
<p>When we click <strong>Connect Wallet</strong>, we'll be prompted to connect our MetaMask wallet with this website, and then be able to claim an NFT, and taken to the <code>/stake</code> route after approving the <code>claim</code> transaction.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1652574348357/tyrJ-nCnM.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Now we're on the <code>/stake</code> route, let's code this part up!</p>
<h3 id="heading-stake-page">Stake Page</h3>
<p>The stake page is going to have three sections:</p>
<ol>
<li>Information about the <code>Token</code></li>
<li>Staked NFTs</li>
<li>Unstaked NFTs</li>
</ol>
<p>Let's firstly import all of the required functionality for this page:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> {
  ThirdwebNftMedia,
  useAddress,
  useMetamask,
  useNFTDrop,
  useToken,
  useTokenBalance,
  useOwnedNFTs,
  useContract,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@thirdweb-dev/react"</span>;
<span class="hljs-keyword">import</span> { BigNumber, ethers } <span class="hljs-keyword">from</span> <span class="hljs-string">"ethers"</span>;
<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> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> styles <span class="hljs-keyword">from</span> <span class="hljs-string">"../styles/Home.module.css"</span>;
</code></pre>
<p>And we'll create some variables for our contract addresses so we can easily access them throughout this file:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> nftDropContractAddress = <span class="hljs-string">"&lt;your-nft-drop-contract-address&gt;"</span>;
<span class="hljs-keyword">const</span> tokenContractAddress = <span class="hljs-string">"&lt;your-token-contract-address&gt;"</span>;
<span class="hljs-keyword">const</span> stakingContractAddress = <span class="hljs-string">"&lt;your-staking-contract-address&gt;"</span>;
</code></pre>
<p>Now let's create the same structure using <code>useAddress</code> and <code>useMetamask</code> to ensure the user has their wallet connected before we attempt to fetch any information:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Stake: NextPage = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// Wallet Connection Hooks</span>
  <span class="hljs-keyword">const</span> address = useAddress();
  <span class="hljs-keyword">const</span> connectWithMetamask = useMetamask();
</code></pre>
<p>Connect to all of our contracts:</p>
<pre><code class="lang-jsx">  <span class="hljs-comment">// Contract Hooks</span>
  <span class="hljs-keyword">const</span> nftDropContract = useNFTDrop(nftDropContractAddress);
  <span class="hljs-keyword">const</span> tokenContract = useToken(tokenContractAddress);
  <span class="hljs-keyword">const</span> { contract, isLoading } = useContract(stakingContractAddress);
</code></pre>
<p>Utilise some helpful hooks to load the :</p>
<ol>
<li>Balance this user has of this token</li>
<li>The NFTs they have from this NFT collection:</li>
</ol>
<pre><code class="lang-jsx">  <span class="hljs-comment">// Load Balance of Token</span>
  <span class="hljs-keyword">const</span> { <span class="hljs-attr">data</span>: tokenBalance } = useTokenBalance(tokenContract, address);

  <span class="hljs-comment">// Load Unstaked NFTs</span>
  <span class="hljs-keyword">const</span> { <span class="hljs-attr">data</span>: ownedNfts } = useOwnedNFTs(nftDropContract, address);
</code></pre>
<p>You'll notice that we use the <code>.call</code> function to call any of the functions we wrote on the custom contract.</p>
<p>Load this user's staked NFTs if there is a connected wallet:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> [stakedNfts, setStakedNfts] = useState&lt;any[]&gt;([]);

useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (!contract) <span class="hljs-keyword">return</span>;

    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">loadStakedNfts</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">const</span> stakedTokens = <span class="hljs-keyword">await</span> contract?.call(<span class="hljs-string">"getStakedTokens"</span>, address);

      <span class="hljs-comment">// For each staked token, fetch metadata for the NFT </span>
      <span class="hljs-keyword">const</span> stakedNfts = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all(
        stakedTokens?.map(
          <span class="hljs-keyword">async</span> (stakedToken: { <span class="hljs-attr">staker</span>: string; tokenId: BigNumber }) =&gt; {
            <span class="hljs-keyword">const</span> nft = <span class="hljs-keyword">await</span> nftDropContract?.get(stakedToken.tokenId);
            <span class="hljs-keyword">return</span> nft;
          }
        )
      );

      setStakedNfts(stakedNfts);
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"setStakedNfts"</span>, stakedNfts);
    }

    <span class="hljs-keyword">if</span> (address) {
      loadStakedNfts();
    }
  }, [address, contract, nftDropContract]);
</code></pre>
<p>Load the available rewards for this user, again using <code>.call</code>:</p>
<pre><code class="lang-jsx">  <span class="hljs-keyword">const</span> [claimableRewards, setClaimableRewards] = useState&lt;BigNumber&gt;();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (!contract || !address) <span class="hljs-keyword">return</span>;

    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">loadClaimableRewards</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">const</span> cr = <span class="hljs-keyword">await</span> contract?.call(<span class="hljs-string">"availableRewards"</span>, address);
      setClaimableRewards(cr);
    }

    loadClaimableRewards();
  }, [address, contract]);
</code></pre>
<p><strong>Stake function call</strong>:</p>
<p>In order for the contract to <code>transfer</code> our NFTs, it needs to have the <code>approval</code> to do so.</p>
<p>Inside the <code>stake</code> function, we check to see if the smart contract has approval, and call <code>setApprovalForAll</code> if it doesn't already have the approval to transfer NFTs from this wallet for this collection.</p>
<pre><code class="lang-jsx">  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">stakeNft</span>(<span class="hljs-params">id: BigNumber</span>) </span>{
    <span class="hljs-keyword">if</span> (!address) <span class="hljs-keyword">return</span>;

    <span class="hljs-keyword">const</span> isApproved = <span class="hljs-keyword">await</span> nftDropContract?.isApproved(
      address,
      stakingContractAddress
    );
    <span class="hljs-comment">// If not approved, request approval</span>
    <span class="hljs-keyword">if</span> (!isApproved) {
      <span class="hljs-keyword">await</span> nftDropContract?.setApprovalForAll(stakingContractAddress, <span class="hljs-literal">true</span>);
    }
    <span class="hljs-keyword">const</span> stake = <span class="hljs-keyword">await</span> contract?.call(<span class="hljs-string">"stake"</span>, id);
  }
</code></pre>
<p>Withdraw function using <code>.call</code>:</p>
<pre><code class="lang-jsx">  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params">id: BigNumber</span>) </span>{
    <span class="hljs-keyword">const</span> withdraw = <span class="hljs-keyword">await</span> contract?.call(<span class="hljs-string">"withdraw"</span>, id);
  }
</code></pre>
<p>Claim Rewards function using <code>.call</code>:</p>
<pre><code class="lang-jsx">  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params">id: BigNumber</span>) </span>{
    <span class="hljs-keyword">const</span> withdraw = <span class="hljs-keyword">await</span> contract?.call(<span class="hljs-string">"withdraw"</span>, id);
  }
</code></pre>
<p>Now we can show all of the information we have fetched on the UI!</p>
<p>Loading state:</p>
<pre><code class="lang-jsx">  <span class="hljs-keyword">if</span> (isLoading) {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Loading<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
  }
</code></pre>
<p>Show a connect wallet button if there is no <code>address</code>:</p>
<pre><code class="lang-jsx"><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">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.h1}</span>&gt;</span>Stake Your NFTs<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">hr</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">styles.divider</span>} ${<span class="hljs-attr">styles.spacerTop</span>}`} /&gt;</span>

      {!address ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.mainButton}</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{connectWithMetamask}</span>&gt;</span>
          Connect Wallet
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      ) : (
        <span class="hljs-tag">&lt;&gt;</span>
          // ... next code blocks go here
        <span class="hljs-tag">&lt;/&gt;</span></span>
      )}
    &lt;/div&gt;
  );
</code></pre>
<p>Show connected wallet's claimable rewards and token balance</p>
<pre><code class="lang-jsx">          &lt;h2&gt;Your Tokens&lt;/h2&gt;

          <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.tokenGrid}</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.tokenItem}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.tokenLabel}</span>&gt;</span>Claimable Rewards<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.tokenValue}</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">b</span>&gt;</span>
                  {!claimableRewards
                    ? "Loading..."
                    : ethers.utils.formatUnits(claimableRewards, 18)}
                <span class="hljs-tag">&lt;/<span class="hljs-name">b</span>&gt;</span>{" "}
                {tokenBalance?.symbol}
              <span class="hljs-tag">&lt;/<span class="hljs-name">p</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">{styles.tokenItem}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.tokenLabel}</span>&gt;</span>Current Balance<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.tokenValue}</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">b</span>&gt;</span>{tokenBalance?.displayValue}<span class="hljs-tag">&lt;/<span class="hljs-name">b</span>&gt;</span> {tokenBalance?.symbol}
              <span class="hljs-tag">&lt;/<span class="hljs-name">p</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>
</code></pre>
<p>Button for users to claim their available rewards:</p>
<pre><code class="lang-jsx">          &lt;button
            className={<span class="hljs-string">`<span class="hljs-subst">${styles.mainButton}</span> <span class="hljs-subst">${styles.spacerTop}</span>`</span>}
            onClick={<span class="hljs-function">() =&gt;</span> claimRewards()}
          &gt;
            Claim Rewards
          &lt;/button&gt;
</code></pre>
<p>View all of their staked NFTs:</p>
<p>Each mapped div contains a <code>Withdraw</code> button to call the <code>withdraw</code> function and pass in the token ID of this item.</p>
<pre><code class="lang-jsx">          &lt;h2&gt;Your Staked NFTs&lt;/h2&gt;
          <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.nftBoxGrid}</span>&gt;</span>
            {stakedNfts?.map((nft) =&gt; (
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.nftBox}</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{nft.metadata.id.toString()}</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">ThirdwebNftMedia</span>
                  <span class="hljs-attr">metadata</span>=<span class="hljs-string">{nft.metadata}</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.nftMedia}</span>
                /&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{nft.metadata.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">styles.mainButton</span>} ${<span class="hljs-attr">styles.spacerBottom</span>}`}
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> withdraw(nft.metadata.id)}
                &gt;
                  Withdraw
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</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>
</code></pre>
<p>View all of their <strong>owned</strong> NFTs (NFTs from this collection that are not staked in the contract):</p>
<p>Each mapped div contains a button for the user to call the <code>stakeNft</code> function, again passing in the token ID as a parameter.</p>
<pre><code class="lang-jsx">          &lt;h2&gt;Your Unstaked NFTs&lt;/h2&gt;

          <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.nftBoxGrid}</span>&gt;</span>
            {ownedNfts?.map((nft) =&gt; (
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.nftBox}</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{nft.metadata.id.toString()}</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">ThirdwebNftMedia</span>
                  <span class="hljs-attr">metadata</span>=<span class="hljs-string">{nft.metadata}</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.nftMedia}</span>
                /&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{nft.metadata.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">styles.mainButton</span>} ${<span class="hljs-attr">styles.spacerBottom</span>}`}
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> stakeNft(nft.metadata.id)}
                &gt;
                  Stake
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</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>
</code></pre>
<p>You will also notice we are utilising the <a target="_blank" href="https://portal.thirdweb.com/react/react.thirdwebnftmedia"><code>ThirdwebNftMedia</code></a> component, which renders the media asset of the NFT differently depending on what kind of file type is resolved from the NFT.</p>
<p>That's it! Now users will be able to see any of the NFTs they claimed from the <code>/mint</code> route, click the <code>stake</code> button, and start earning rewards!</p>
<h2 id="heading-giving-the-staking-contract-some-funds">Giving the staking contract some funds</h2>
<p>One last thing, we'll need to transfer the NFT staking contract some of our tokens so that it can distribute them as rewards.</p>
<p>We can do this via the thirdweb CLI by going to our Token contract, and clicking on the <strong>Transfer</strong> button:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654395549358/Oc722npuc.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Then paste in your staking contract's address and send it some tokens!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654395568622/wHDpopQ4c.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Now it is capable of transferring tokens whenever somebody tries to call the <code>claimRewards</code> function!</p>
<p>🥳🎉</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>In this guide, we've made three smart contracts and combined them together to create a project that rewards users for holding the NFTs.</p>
<p>We have created all of this:</p>
<ul>
<li>ERC-721 NFT Drop contract</li>
<li>ERC-20 Token contract</li>
<li>An NFT Staking contract rewarding stakers with ERC-20 tokens</li>
</ul>
<p><strong>Disclaimer:</strong> This staking contract has not been audited and should not be trusted for use in production environments! Please do your own research and use it at your own risk.</p>
]]></content:encoded></item></channel></rss>