<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Site Name Blog</title>
  <subtitle>Blog</subtitle>
  <id>https://sveltekit-base.pages.dev/blog/feed</id>
  <link href="https://sveltekit-base.pages.dev/blog/feed" rel="self" type="application/atom+xml"/>
  <link href="https://sveltekit-base.pages.dev/blog" rel="alternate"/>
  <link href="https://pubsubhubbub.appspot.com" rel="hub"/>
  <icon>https://sveltekit-base.pages.dev/_app/immutable/assets/icon-512.-XfKluLk.png</icon>
  <rights>Copyright 2026. All rights reserved.</rights>
  <updated>2025-10-30T09:15:20.030Z</updated>
  <entry>
    <title>x402 Deep Dive: A Payment Standard for the Internet</title>
    <link href="https://blog.developerdao.com/x402-deep-dive-a-payment-standard-for-the-internet"/>
    <id>https://blog.developerdao.com/x402-deep-dive-a-payment-standard-for-the-internet</id>
    <updated>2025-10-30T09:15:20.030Z</updated>
    <author><name>David Ekete</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1761815604903/3ef97d76-2875-4e29-a0cc-7db715c0ae6b.jpeg?width=600&amp;format=auto"/>
    <summary>x402 is a new payment standard that enables micro payments on the web by leveraging blockchain technology. It leverages the existing 402 Payment Required status code to require payment before serving a response and uses crypto-native payments for spe...</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761815604903/3ef97d76-2875-4e29-a0cc-7db715c0ae6b.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761815604903/3ef97d76-2875-4e29-a0cc-7db715c0ae6b.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761815604903/3ef97d76-2875-4e29-a0cc-7db715c0ae6b.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761815604903/3ef97d76-2875-4e29-a0cc-7db715c0ae6b.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;p&gt;x402 is a new payment standard that enables micro payments on the web by leveraging blockchain technology. It leverages the existing 402 Payment Required status code to require payment before serving a response and uses crypto-native payments for speed, privacy, and efficiency, enabling micro payments.&lt;/p&gt;
&lt;p&gt;In this article, you will explore how x402 works for programmatic services and how you can integrate it into your existing workflows using a simple Express app as an example.&lt;/p&gt;
&lt;h2 id=&quot;heading-how-does-x402-work&quot;&gt;How Does x402 Work?&lt;/h2&gt;
&lt;p&gt;Every x402 workflow has three main components:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The buyer or client&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The seller or server&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The facilitator&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;heading-the-seller&quot;&gt;The Seller&lt;/h3&gt;
&lt;p&gt;In an x402 workflow, the seller, or server, refers to the entity that has paywalled a service using the x402 standard. The seller must define the payment requirements for the resource, including the amount, the blockchain network, the payment asset, and the payment destination (a wallet address).&lt;/p&gt;
&lt;p&gt;Note that x402 only supports payment assets that implement the EIP-3009 (&lt;code&gt;transferWithAuthorization&lt;/code&gt;) method, for example, USDC. This is because x402 sends a signed payment in a request header, so it needs a token that lets a relayer submit that signature on-chain without first setting allowances, and EIP-3009 &lt;code&gt;transferWithAuthorization&lt;/code&gt; is the standard that enables exactly this.&lt;/p&gt;
&lt;h3 id=&quot;heading-the-buyer&quot;&gt;The Buyer&lt;/h3&gt;
&lt;p&gt;In an x402 workflow, the buyer/client refers to the entity trying to access a paywalled service. A client can either be manually operated by a human, programmatically operated on behalf of a user, or autonomously operated using an AI agent.&lt;/p&gt;
&lt;p&gt;Regardless of the client type, the flow remains the same. After initiating a request to a 402 Payment Required protected endpoint, they read the payment details provided by the seller, construct a valid payment payload, and retry the request with an &lt;code&gt;X-PAYMENT&lt;/code&gt; header containing the signed payment payload.&lt;/p&gt;
&lt;h3 id=&quot;heading-the-facilitator&quot;&gt;The Facilitator&lt;/h3&gt;
&lt;p&gt;Although optional, a facilitator removes a lot of the overhead associated with verifying and settling payments between sellers and buyers.&lt;/p&gt;
&lt;p&gt;In a direct peer-to-peer x402 flow, the buyer requests a protected endpoint and receives a &lt;code&gt;402 Payment Required&lt;/code&gt; response with payment details (amount, blockchain network, wallet address). The buyer then creates and submits a blockchain transaction and retries the request with a &lt;code&gt;X-PAYMENT&lt;/code&gt; header containing the transaction proof.&lt;/p&gt;
&lt;p&gt;The seller must independently verify the payment on the blockchain before granting access. This requires both parties to handle blockchain interactions directly, including transaction submission and on-chain verification.&lt;/p&gt;
&lt;p&gt;A facilitator acts as a trusted intermediary for payment verification and settlement. Instead of sellers querying the blockchain directly, the facilitator provides a verification service that handles transaction broadcasting, confirmation monitoring, and issues cryptographically signed payment receipts.&lt;/p&gt;
&lt;p&gt;There are several facilitators available today, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://docs.cdp.coinbase.com/x402/docs/welcome&quot;&gt;CDP’s facilitator&lt;/a&gt; on Base mainnet, which offers fee-free USDC settlement on Base mainnet.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://docs.payai.network/x402&quot;&gt;PayAI’s facilitator&lt;/a&gt; on Solana, Base, Polygon, and more.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Custom facilitators such as &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/Dhaiwat10/x402-sovereign&quot;&gt;x402-sovereign&lt;/a&gt; by &lt;a target=&quot;_blank&quot; href=&quot;https://x.com/dhaiwat10&quot;&gt;dhai.eth&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The entire x402 flow is stateless. Clients do not need to manage accounts, credentials, or session tokens beyond their crypto wallet, and servers do not need to manage client identities or maintain session state.&lt;/p&gt;
&lt;p&gt;Everything is handled per request, making x402 well-suited for one-time or occasional access patterns, but potentially impractical for flows requiring frequent, continuous access to the protected resource due to per-request payment costs.&lt;/p&gt;
&lt;h2 id=&quot;heading-how-to-use-x402-in-your-apps&quot;&gt;How to Use x402 in Your Apps?&lt;/h2&gt;
&lt;p&gt;This section covers how you can use x402 in your current workflow.&lt;/p&gt;
&lt;p&gt;For this tutorial, we are going to use &lt;a target=&quot;_blank&quot; href=&quot;https://www.npmjs.com/package/x402-express&quot;&gt;x402-express&lt;/a&gt; and &lt;a target=&quot;_blank&quot; href=&quot;https://www.npmjs.com/package/x402-fetch&quot;&gt;x402-fetch&lt;/a&gt; to implement the flow for the seller and the buyer, respectively, because they already abstract most implementation details, allowing you to get started immediately. We are also going to &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/Dhaiwat10/x402-sovereign&quot;&gt;x402-sovereign&lt;/a&gt; as our facilitator because it doesn&apos;t require any setup or API keys like CDP’s or PayAI’s.&lt;/p&gt;
&lt;h3 id=&quot;heading-using-x402-as-seller&quot;&gt;Using x402 as Seller&lt;/h3&gt;
&lt;p&gt;To add an x402 paywall to a resource on an Express server or a similar server, you need to add the following packages to your existing app.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;x402-express:&lt;/strong&gt; Middleware for Express that handles x402 payment verification and responds with 402 Payment Required when payment is missing or invalid.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;viem:&lt;/strong&gt; TypeScript library for Ethereum interactions, used to verify blockchain transactions and interact with smart contracts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;x402-sovereign/core&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Install them by running the command below:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install @x402-sovereign/core viem x402-express
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You also need an EVM private key that will receive payments and pay gas.&lt;/p&gt;
&lt;div data-node-type=&quot;callout&quot;&gt;
&lt;div data-node-type=&quot;callout-emoji&quot;&gt;🚨&lt;/div&gt;
&lt;div data-node-type=&quot;callout-text&quot;&gt;Ensure you store your private key in an &lt;code&gt;.env&lt;/code&gt; file that is not tracked by version control!&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Next, you need to initialize your facilitator using your private key and specifying your supported networks:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { Facilitator } from &quot;@x402-sovereign/core&quot;;

const facilitator = new Facilitator({
  evmPrivateKey: process.env.EVM_PRIVATE_KEY as `0x${string}`,
  networks: [baseSepolia, sepolia],
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code block above initializes a custom facilitator using x402-sovereign supporting base sepolia and sepolia.&lt;/p&gt;
&lt;p&gt;x402-sovereign exposes an express adapter that you can register as a middleware to mount the facilitator endpoints your server will call for verification and settlement. Like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { createExpressAdapter } from &quot;@x402-sovereign/core&quot;;

createExpressAdapter(facilitator, app, &quot;/facilitator&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This mounts your local facilitator API onto your Express app under the &lt;code&gt;/facilitator&lt;/code&gt; path. It registers three routes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;GET /facilitator/supported&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;POST /facilitator/verify&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;POST /facilitator/settle&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It then forwards those requests to &lt;code&gt;facilitator.handleRequest({ method, path, body })&lt;/code&gt;: &lt;code&gt;/supported&lt;/code&gt; returns the facilitator’s capabilities and the networks you configured, &lt;code&gt;/verify&lt;/code&gt; decodes the &lt;code&gt;X-PAYMENT&lt;/code&gt; header and validates the EIP-712 signature, amount, asset, &lt;code&gt;payTo&lt;/code&gt;, resource URL, chain ID, and time/nonce, and &lt;code&gt;/settle&lt;/code&gt; Re-verifies and submits the EIP-3009 &lt;code&gt;transferWithAuthorization&lt;/code&gt; on chain using your &lt;code&gt;evmPrivateKey&lt;/code&gt;, returning success and a &lt;code&gt;txHash&lt;/code&gt;. The adapter adds no business logic or auth; it just relays the status and body from the facilitator, or returns a 500 if an error occurred.&lt;/p&gt;
&lt;p&gt;After configuring your facilitator, you can use the &lt;code&gt;paymentMiddleware&lt;/code&gt; provided by x402-express to register the routes you want to protect, along with their associated prices.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;app.use(
  paymentMiddleware(
    PAY_TO,
    {
      &quot;/add-badge&quot;: {
        price: &quot;$0.01&quot;,
        network: &quot;base-sepolia&quot;,
        config: {
          description: &quot;Grant Badge&quot;,
        },
      },
      &quot;/premium/*&quot;: {
        price: &quot;$0.10&quot;,
        network: &quot;base-sepolia&quot;,
        config: {
          description: &quot;Access to premium content&quot;,
        },
      },
    },
    {
      url: `${BASE_URL}/facilitator` as `${string}://${string}`,
    }
  )
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The middleware will return 402 Payment Required with a challenge (image below) when the request is missing/invalid, and will call your handler once a valid &lt;code&gt;X-PAYMENT&lt;/code&gt; header is supplied.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761815038924/69859e75-c4dd-40b4-89bc-fbe717f90f11.webp?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761815038924/69859e75-c4dd-40b4-89bc-fbe717f90f11.webp?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761815038924/69859e75-c4dd-40b4-89bc-fbe717f90f11.webp?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761815038924/69859e75-c4dd-40b4-89bc-fbe717f90f11.webp?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;You can find the full implementation for this section in this &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/davidekete/x402-demo/tree/main/server&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;heading-using-x402-as-buyer&quot;&gt;Using x402 as Buyer&lt;/h3&gt;
&lt;p&gt;To programmatically access routes protected by x402, you need the x402-fetch package, which provides utilities to wrap standard &lt;code&gt;fetch&lt;/code&gt; with automatic x402 payment handling, including signature creation and payment proof construction.&lt;/p&gt;
&lt;p&gt;You also need an EVM private key to sign and submit payments.&lt;/p&gt;
&lt;div data-node-type=&quot;callout&quot;&gt;
&lt;div data-node-type=&quot;callout-emoji&quot;&gt;🚨&lt;/div&gt;
&lt;div data-node-type=&quot;callout-text&quot;&gt;Store it securely in your &lt;code&gt;.env&lt;/code&gt; file that is not tracked by version control!&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;To make requests to x402-protected endpoints, you need to create a signer for your target network and wrap the standard &lt;code&gt;fetch&lt;/code&gt; function with payment capabilities:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { 
  wrapFetchWithPayment, 
  createSigner, 
  type Hex 
} from &quot;x402-fetch&quot;;

const privateKey = process.env.PRIVATE_KEY as Hex | string;
const signer = await createSigner(&quot;base-sepolia&quot;, privateKey);
const fetchWithPayment = wrapFetchWithPayment(fetch, signer);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;createSigner&lt;/code&gt; function initializes a signer for the specified network using your private key. The &lt;code&gt;wrapFetchWithPayment&lt;/code&gt; function returns an enhanced fetch that automatically handles the x402 payment flow.&lt;/p&gt;
&lt;p&gt;Now you can use &lt;code&gt;fetchWithPayment&lt;/code&gt; just like the standard &lt;code&gt;fetch&lt;/code&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const response = await fetchWithPayment(`${endpointBaseUrl}/add-badge`, {
  method: &quot;GET&quot;,
});

const body = await response.json();
console.log(body);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you request a protected endpoint, &lt;code&gt;fetchWithPayment&lt;/code&gt; automatically detects the 402 Payment Required response, reads the payment requirements from the challenge, constructs and signs the payment proof, and retries the request with the &lt;code&gt;X-PAYMENT&lt;/code&gt; header. From your perspective, it works seamlessly like a regular fetch call.&lt;/p&gt;
&lt;p&gt;Optionally, you can access payment details from the response headers:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { decodeXPaymentResponse } from &quot;x402-fetch&quot;;

const paymentResHeader = response.headers.get(&quot;x-payment-response&quot;);

if (paymentResHeader) {
  const paymentResponse = decodeXPaymentResponse(paymentResHeader);
  console.log(paymentResponse);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;x-payment-response&lt;/code&gt; header contains information about the payment transaction, including the transaction hash and settlement status.&lt;/p&gt;
&lt;p&gt;You can find the full implementation for this section in this &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/davidekete/x402-demo/tree/main/client&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;heading-conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The x402 standard provides practical developer tools for implementing &lt;a target=&quot;_blank&quot; href=&quot;https://eips.ethereum.org/EIPS/eip-8004&quot;&gt;ERC-8004&lt;/a&gt;, the protocol specification for blockchain-based HTTP payments. By abstracting the complexity of EIP-712 signatures and EIP-3009 settlements, x402 enables truly stateless, pay-per-use APIs without traditional authentication.&lt;/p&gt;
&lt;p&gt;To learn more about the underlying protocol, visit the &lt;a target=&quot;_blank&quot; href=&quot;https://eips.ethereum.org/EIPS/eip-8004&quot;&gt;ERC-8004 proposal&lt;/a&gt;. To explore the x402 ecosystem, check out &lt;a target=&quot;_blank&quot; href=&quot;https://www.x402.org/&quot;&gt;x402.org&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Using Arweave for AI Provenance</title>
    <link href="https://blog.developerdao.com/using-arweave-for-ai-provenance"/>
    <id>https://blog.developerdao.com/using-arweave-for-ai-provenance</id>
    <updated>2025-10-30T08:46:43.624Z</updated>
    <author><name>Rohit Pathare</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1761557773193/8aed01a1-328f-4269-9986-9271cfcfcfc8.jpeg?width=600&amp;format=auto"/>
    <summary>The so called AI slop all over the internet is getting less sloppy.

NBC News
We&apos;re living through an extraordinary moment in history. The rapid evolution of generative AI has unleashed an unprecedented creative boom. These tools have democratized co...</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761557773193/8aed01a1-328f-4269-9986-9271cfcfcfc8.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761557773193/8aed01a1-328f-4269-9986-9271cfcfcfc8.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761557773193/8aed01a1-328f-4269-9986-9271cfcfcfc8.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761557773193/8aed01a1-328f-4269-9986-9271cfcfcfc8.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;blockquote&gt;
&lt;p&gt;The so called AI slop all over the internet is getting less sloppy.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.youtube.com/watch?v=SRA4brHXBBQ&quot;&gt;NBC News&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We&apos;re living through an extraordinary moment in history. The rapid evolution of generative AI has unleashed an unprecedented creative boom. These tools have democratized content creation in ways unimaginable just a few years ago. With a few prompts, anyone can whip up stunning images or immersive videos, no special training required.&lt;/p&gt;
&lt;p&gt;AI is remarkable. AI is empowering. AI is also terrifying…&lt;/p&gt;
&lt;p&gt;Generative models are now producing images, videos, and text at a scale never seen before, and lately, they can be indistinguishable from human-made content. From social media feeds to news articles, AI’s creative “fingerprints” are everywhere. Photorealistic portraits, cinematic visuals, and engaging essays can all be churned out by AI in minutes.&lt;/p&gt;
&lt;p&gt;While it is empowering a single person with a laptop to achieve what once took teams, it poses a new question: How can we trust what we see and hear?&lt;/p&gt;
&lt;h2 id=&quot;heading-whats-real&quot;&gt;&lt;strong&gt;What&apos;s Real?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Recently, how often has your mum shown you an image or a reel and asked you if it’s real or AI-generated?&lt;/p&gt;
&lt;p&gt;The question is popping up more and more, and not without reason. As generative AI improves its output quality, the lines between reality and fiction continue to blur.&lt;/p&gt;
&lt;p&gt;Remember that image of Pope Francis walking on the streets of the Vatican in a designer coat fooled countless people online into thinking it was real?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761556283838/0527c62e-15b4-4f6c-99d6-d91bfbde6c9e.avif?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761556283838/0527c62e-15b4-4f6c-99d6-d91bfbde6c9e.avif?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761556283838/0527c62e-15b4-4f6c-99d6-d91bfbde6c9e.avif?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761556283838/0527c62e-15b4-4f6c-99d6-d91bfbde6c9e.avif?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Photo: r/midjourney subreddit&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Or when AI tools mimicked Studio Ghibli&apos;s distinctive art style?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761556395505/7f0695bc-db90-4a5b-9f32-48c4659ce0ae.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761556395505/7f0695bc-db90-4a5b-9f32-48c4659ce0ae.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761556395505/7f0695bc-db90-4a5b-9f32-48c4659ce0ae.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761556395505/7f0695bc-db90-4a5b-9f32-48c4659ce0ae.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Photo: ghibliai.ai&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;AI-generated content is flooding the internet, mimicking Hayao Miyazaki&apos;s painstaking hand-drawn aesthetic, appearing everywhere from fan art communities to brand moodboards and beyond. Even I wasn&apos;t immune to trying it out.&lt;/p&gt;
&lt;p&gt;While I do not want to get into &lt;a target=&quot;_blank&quot; href=&quot;https://www.tokyoweekender.com/japan-life/news-and-opinion/ghibli-style-ai-images-raise-ethical-concerns/&quot;&gt;the ethical discussion&lt;/a&gt; of replicating an art style in this article, I do feel that had anyone generated an entire book or film in this style, we might not have been able to tell it apart from the originals. There’s real concern about authenticity and trust in this AI-saturated landscape. The stakes can range from simple confusion to serious deception. Misleading AI-generated media can spread misinformation. I believe the trust in what we consume online is at stake. And we need a layer of transparency that helps us distinguish AI-generated media from authentic media.&lt;/p&gt;
&lt;h2 id=&quot;heading-proof-of-origin&quot;&gt;&lt;strong&gt;Proof of Origin&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;What if instead of trying to detect AI content after it&apos;s created, we could establish verifiable proof of origin at the moment of creation?&lt;/p&gt;
&lt;p&gt;This is where blockchain technology could come in. They are essentially ledgers that can store tamper-proof records, with multiple copies distributed across many nodes worldwide. If there&apos;s one thing blockchains are designed to excel at, it&apos;s &lt;strong&gt;preserving an immutable trail of information that anyone can verify&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;What if every AI-generated image, video, or text came with an unforgeable “receipt” describing how it was created?&lt;/p&gt;
&lt;p&gt;These receipts can serve as publicly auditable proofs of the origins of any AI-generated content.&lt;/p&gt;
&lt;h3 id=&quot;heading-arweave-and-hyperbeam&quot;&gt;&lt;strong&gt;Arweave and HyperBEAM&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;While I am yet to explore more technologies, something I will continue to do over the coming days, my familiarity with &lt;a target=&quot;_blank&quot; href=&quot;https://x.com/@ArweaveEco&quot;&gt;@ArweaveEco&lt;/a&gt; and &lt;a target=&quot;_blank&quot; href=&quot;https://hyperbeam.ar.io/build/introduction/what-is-hyperbeam.html&quot;&gt;HyperBEAM&lt;/a&gt; makes them potential good fits for this solution.&lt;/p&gt;
&lt;p&gt;HyperBEAM, built on the @aoTheComputer&apos;s spec, is a decentralized operating system that enables verifiable computation over HTTP. Inspired by the Erlang actor model, every interaction is handled as a message.&lt;/p&gt;
&lt;p&gt;And the cool part?&lt;/p&gt;
&lt;p&gt;It uses &lt;a target=&quot;_blank&quot; href=&quot;https://datatracker.ietf.org/doc/html/rfc9421&quot;&gt;RFC 9421,&lt;/a&gt; the latest HTTP message signature standard.&lt;/p&gt;
&lt;p&gt;Blockchains, for the most part, are known to be walled gardens that require specialized services, like oracles, to communicate with the traditional web. So, a system that can do so by default opens up very interesting possibilities.&lt;/p&gt;
&lt;p&gt;HyperBEAM includes devices that enable API requests with cryptographic receipts of those calls. In theory, every AI generation request could produce an immutable receipt stored permanently on Arweave, creating an unalterable record of origin.&lt;/p&gt;
&lt;h2 id=&quot;heading-how-could-it-work&quot;&gt;&lt;strong&gt;How Could it Work?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Imagine this workflow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;You generate an image with DALL-E.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The API request is signed using RFC 9421&apos;s HTTP message signature protocol.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The signature captures the request parameters, timestamps, the requester&apos;s identifier, and the model used.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;HyperBEAM&apos;s devices process this request and generate a cryptographic receipt.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The receipt gets stored permanently on Arweave.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now the generated image carries verifiable provenance. Anyone can trace it back to its moment of creation, verify who requested it, which AI model produced it, and when it was produced. The receipt is immutable. No one can alter this historical record. By adding cryptographic signatures to standard web requests, users can get a verifiable trail of truth. While this system doesn&apos;t prevent AI generation, it helps us embrace the benefits by establishing accountability and attribution.&lt;/p&gt;
&lt;h2 id=&quot;heading-what-are-the-use-cases&quot;&gt;&lt;strong&gt;What are the Use Cases?&lt;/strong&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Verification of news or user-generated content&lt;/strong&gt;: During breaking events like footage of natural disasters, celebrity sightings, etc., provenance lets platforms and audiences confirm whether a clip came from a verified source or an AI before it spreads.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Protecting artists &amp;amp; brands&lt;/strong&gt;: Creators and studios can register originals. Style-inspired pieces carry distinct receipts, enabling faster, fairer attribution, licensing, and takedown decisions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Legal evidence&lt;/strong&gt;: Courts handling deepfake cases could verify the authenticity of digital evidence through blockchain-backed provenance trails.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In general, while institutions like the Coalition for Content Provenance and Authenticity (C2PA) standard embed cryptographic signatures and metadata into digital assets, it has its limitations. Integrating this with blockchain technology could make these even more robust and perpetually accessible.&lt;/p&gt;
&lt;h2 id=&quot;heading-why-does-this-matter-now&quot;&gt;&lt;strong&gt;Why Does This Matter Now?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;We&apos;re at an inflection point. AI content generation is accelerating exponentially. By the end of 2025, estimates suggest 8 million deepfakes will be shared online, up from 500,000 in 2023. Europol estimates 90% of online content may eventually be generated synthetically.&lt;/p&gt;
&lt;p&gt;Trust could collapse without provenance. When we can&apos;t distinguish real from fake, we lose our shared basis for truth. Blockchain-based provenance isn&apos;t a silver bullet. It requires adoption by AI platform providers, integration into content creation tools, and cultural acceptance of transparency over anonymity.&lt;/p&gt;
&lt;h2 id=&quot;heading-the-bottom-line&quot;&gt;&lt;strong&gt;The Bottom Line&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;AI has genuinely been transformative. It&apos;s democratizing content creation, enabling new forms of expression, and augmenting human creativity in remarkable ways.&lt;/p&gt;
&lt;p&gt;We shouldn&apos;t fear this technology, but we should be wary and establish guardrails while it’s still young. Data provenance is one.&lt;/p&gt;
&lt;p&gt;We have infrastructure in place. HyperBEAM can provide signed receipts of API calls, which can then be stored on Arweave as an immutable proof of origin. At the very least, these give a path to experiment and establish a baseline for trust in this age of AI.&lt;/p&gt;
&lt;p&gt;If you think this post might resonate with someone you know, please share it with them!&lt;/p&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>An Introduction to Force Inclusion</title>
    <link href="https://blog.developerdao.com/an-introduction-to-force-inclusion"/>
    <id>https://blog.developerdao.com/an-introduction-to-force-inclusion</id>
    <updated>2025-10-21T14:32:00.132Z</updated>
    <author><name>Dhaiwat Pandya</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1761043304352/54481827-50e1-45ab-bc67-99e34f17bd7b.jpeg?width=600&amp;format=auto"/>
    <summary>In these last few years, layer two blockchains (L2) have become central to Ethereum&apos;s scaling efforts. L2s are fast, cheap, and inherit Ethereum&apos;s strong security guarantees. Ethereum serves as the settlement layer, and L2s serve as the execution lay...</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761043304352/54481827-50e1-45ab-bc67-99e34f17bd7b.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761043304352/54481827-50e1-45ab-bc67-99e34f17bd7b.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761043304352/54481827-50e1-45ab-bc67-99e34f17bd7b.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761043304352/54481827-50e1-45ab-bc67-99e34f17bd7b.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;p&gt;In these last few years, layer two blockchains (L2) have become central to Ethereum&apos;s scaling efforts. L2s are fast, cheap, and inherit Ethereum&apos;s strong security guarantees. Ethereum serves as the settlement layer, and L2s serve as the execution layer. This is great.&lt;/p&gt;
&lt;p&gt;It is important to pause here, though, and ask:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;What does it mean that these L2s inherit Ethereum&apos;s security guarantees?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What does it mean for an L2 to be secure?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This article won’t cover all the different L2 security details, but it will discuss one of the most important ones: &lt;strong&gt;censorship resistance&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;heading-what-is-censorship-resistance&quot;&gt;&lt;strong&gt;What is Censorship Resistance?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;An ideal L2 should be censorship-resistant. This means that no single entity or group (including the network operators, &lt;em&gt;especially&lt;/em&gt; the network operators) should be able to prevent users from accessing the network or using its services.&lt;/p&gt;
&lt;p&gt;Most L2s use highly centralised sequencer sets for speed, though. This is the usual lifecycle of an L2 transaction. For example, you send some ETH to a friend on Base:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761041026988/2221789b-a03c-47ba-9790-6925ff9750b1.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761041026988/2221789b-a03c-47ba-9790-6925ff9750b1.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761041026988/2221789b-a03c-47ba-9790-6925ff9750b1.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761041026988/2221789b-a03c-47ba-9790-6925ff9750b1.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;It is not hard to spot that there is a potential single point of failure in this system. The sequencer can censor your transaction and refuse to include it in the next batch.&lt;/p&gt;
&lt;p&gt;This is not good.&lt;/p&gt;
&lt;p&gt;But the cool thing about &lt;a target=&quot;_blank&quot; href=&quot;https://chatgpt.com/share/68f5abf0-3e9c-8008-836c-878f22e2654f&quot;&gt;real L2s&lt;/a&gt; is that this is not the end of the story. They are designed to protect users in exactly this scenario.&lt;/p&gt;
&lt;h2 id=&quot;heading-what-is-force-inclusion&quot;&gt;&lt;strong&gt;What is Force Inclusion?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;When you suspect that an L2 sequencer is misbehaving, you can bypass it entirely and get your transaction included anyway. Whether the sequencer likes it or not, it does not have a choice.&lt;/p&gt;
&lt;p&gt;This sequencer bypass is called &lt;strong&gt;force inclusion&lt;/strong&gt; and looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761041272330/f45ad2b1-40b6-4576-9733-3c12046c09c1.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761041272330/f45ad2b1-40b6-4576-9733-3c12046c09c1.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761041272330/f45ad2b1-40b6-4576-9733-3c12046c09c1.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761041272330/f45ad2b1-40b6-4576-9733-3c12046c09c1.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-how-is-force-inclusion-possible&quot;&gt;&lt;strong&gt;How is Force Inclusion Possible?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;In very simple terms, an Ethereum L2 is just a sophisticated set of smart contracts living on Ethereum L1. When you send a transaction on an L2, it is eventually posted to one of these smart contracts on Ethereum L1. The transaction is only considered truly &apos;final&apos; once that happens. Unless you are using an optimistic rollup, in which case the finality can take up to 7 days.&lt;/p&gt;
&lt;p&gt;This is why L2s inherit Ethereum&apos;s security. The source of truth for L2s is Ethereum L1, not the L2 sequencers or L2 nodes. The sequencer abstracts away the complexity of creating a valid L2 transaction and posting it properly to Ethereum. Any user can do this, too, but it is obviously more complicated.&lt;/p&gt;
&lt;p&gt;As an educational exercise, let&apos;s explore how you can actually send a transaction to an L2 without using the sequencer.&lt;/p&gt;
&lt;h2 id=&quot;heading-trying-out-force-inclusion&quot;&gt;&lt;strong&gt;Trying Out Force Inclusion&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Most major L2s support force inclusion. For this example, we will aim to get a transaction force-included on Base mainnet. To keep things simple, we will attempt to send some ETH from one address to another, but the same methods work for transactions of any level of complexity.&lt;/p&gt;
&lt;p&gt;I will be running a simple Bun script here. Let&apos;s initialize the project and install the one dependency we will need:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bun init

bun add ethers dotenv
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will also need a wallet&apos;s private key to send our transaction out. Note that this wallet needs to be funded on both Ethereum L1 and Base L2. We need ETH on L1 to pay the gas for the L1 transaction, and on L2 to pay for the ETH transfer.&lt;/p&gt;
&lt;div data-node-type=&quot;callout&quot;&gt;
&lt;div data-node-type=&quot;callout-emoji&quot;&gt;🚨&lt;/div&gt;
&lt;div data-node-type=&quot;callout-text&quot;&gt;&lt;strong&gt;Use a throwaway dev wallet for this exercise.&lt;/strong&gt; Do not use a wallet you use for anything else.&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Create an &lt;code&gt;.env&lt;/code&gt; file and paste the private key there:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WALLET_PRIVATE_KEY=0x...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s open up &lt;code&gt;index.ts&lt;/code&gt; and start setting up the script now.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;import&lt;/span&gt; { ethers } &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&quot;ethers&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; &lt;span&gt;&quot;dotenv/config&quot;&lt;/span&gt;;

&lt;span&gt;const&lt;/span&gt; l1Provider = &lt;span&gt;new&lt;/span&gt; ethers.JsonRpcProvider(&lt;span&gt;&quot;https://eth.llamarpc.com&quot;&lt;/span&gt;);
&lt;span&gt;const&lt;/span&gt; wallet = &lt;span&gt;new&lt;/span&gt; ethers.Wallet(process.env.WALLET_PRIVATE_KEY!, l1Provider);

&lt;span&gt;const&lt;/span&gt; portal = &lt;span&gt;new&lt;/span&gt; ethers.Contract(
  &lt;span&gt;&quot;0x49048044D57e1C92A77f79988d21Fa8fAF74E97e&quot;&lt;/span&gt;, &lt;span&gt;// OptimismPortal contract address on Ethereum (used by Base)&lt;/span&gt;
  [
    &lt;span&gt;&quot;function depositTransaction(address to,uint256 value,uint64 gasLimit,bool isCreation,bytes data) payable&quot;&lt;/span&gt;,
  ],
  wallet
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Base is an OP Stack rollup. This means that it uses a similar smart contract structure to Optimism and other OP Stack rollups.&lt;/p&gt;
&lt;p&gt;Remember how we discussed earlier that users have the ability to send transactions to one of the rollup contracts on Ethereum if they want to get a transaction force-included? This smart contract is called &lt;code&gt;OptimismPortal&lt;/code&gt; for Base. To put things very simply, any valid L2 transactions deposited to this contract will be force-included on Base L2. This mechanism is slightly different from other rollup stacks like Arbitrum, but the core idea is the same.&lt;/p&gt;
&lt;p&gt;If you are curious, you can check out the contract &lt;a target=&quot;_blank&quot; href=&quot;https://etherscan.io/address/0x49048044D57e1C92A77f79988d21Fa8fAF74E97e&quot;&gt;on Etherscan&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You might have also noticed the &lt;code&gt;depositTransaction&lt;/code&gt; function signature that we added to our contract initialization code. This is the function we will be calling to deposit our transaction to the rollup contract.&lt;/p&gt;
&lt;p&gt;The next step is to construct the actual transaction that we wish to send.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;const&lt;/span&gt; to = &lt;span&gt;&quot;0x0ED6Cec17F860fb54E21D154b49DAEFd9Ca04106&quot;&lt;/span&gt;;
&lt;span&gt;const&lt;/span&gt; value = ethers.parseEther(&lt;span&gt;&quot;0.001&quot;&lt;/span&gt;);
&lt;span&gt;const&lt;/span&gt; gasLimit = &lt;span&gt;200000n&lt;/span&gt;; &lt;span&gt;// conservative&lt;/span&gt;
&lt;span&gt;const&lt;/span&gt; data = &lt;span&gt;&quot;0x&quot;&lt;/span&gt;;

&lt;span&gt;const&lt;/span&gt; tx = &lt;span&gt;await&lt;/span&gt; portal.depositTransaction(
  to,
  value,
  gasLimit,
  &lt;span&gt;false&lt;/span&gt;,
  data,
  { value } &lt;span&gt;// pay ETH&lt;/span&gt;
);

&lt;span&gt;console&lt;/span&gt;.log(&lt;span&gt;&quot;L1 tx hash:&quot;&lt;/span&gt;, tx.hash);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We need to specify five properties:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;to&lt;/code&gt;: This is the address of the L2 wallet that we want to send the ETH to. If you were calling a smart contract, this would be the address of the contract you want to call.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;value&lt;/code&gt;: This is the amount of ETH we wish to send to the L2 wallet.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;gasLimit&lt;/code&gt;: This is the maximum amount of gas we are willing to pay for the transaction. Libraries like &lt;code&gt;viem&lt;/code&gt; provide helpers that can calculate this for you. For now, we will use a conservative estimate.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;isCreation&lt;/code&gt;: This is a boolean value that indicates whether the transaction is creating a new contract or not. If you are sending ETH to an existing contract, this should be set to &lt;code&gt;false&lt;/code&gt;. We have set this to &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;data&lt;/code&gt;: The calldata for the transaction. Since we are doing a simple ETH transfer, we can leave this as &lt;code&gt;0x&lt;/code&gt;. If you were interacting with a smart contract, this would be the encoded function call data.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Notice how we are not interacting with any Base RPC endpoints or contracts at all. Everything is being sent to Ethereum directly.&lt;/p&gt;
&lt;div data-node-type=&quot;callout&quot;&gt;
&lt;div data-node-type=&quot;callout-emoji&quot;&gt;💡&lt;/div&gt;
&lt;div data-node-type=&quot;callout-text&quot;&gt;Check that the private key you provided in the &lt;code&gt;.env&lt;/code&gt; &lt;strong&gt;is funded on both L1 and L2&lt;/strong&gt;, and check the receiving address on L2 (the &lt;code&gt;to&lt;/code&gt; field). This is the address that will receive the funds on Base.&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;For reference, you can find the complete code &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/Dhaiwat10/force-inclusion-script/blob/main/base.ts&quot;&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Run the script, and check the transaction hash on Etherscan:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bun run index.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the transaction is confirmed on L1, you might need to wait around 2 epochs (~13 minutes) for the Ethereum chain to be finalised before the transaction is included in an L2 block.&lt;/p&gt;
&lt;p&gt;After waiting, you should see a transaction pop up on Base L2 for the receiving address. You should receive the exact amount of ETH that you specified in the &lt;code&gt;value&lt;/code&gt; field.&lt;/p&gt;
&lt;p&gt;Congratulations!&lt;/p&gt;
&lt;p&gt;You just sent some ETH from one address to another on an Ethereum L2 without interacting with the L2 sequencer.&lt;/p&gt;
&lt;h2 id=&quot;heading-conclusion&quot;&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;I hope this article served as a very basic primer on why force inclusion is important and how you can use this security feature yourself if need be.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I am currently working on an SDK around this with some friends to make similar rollup security features more accessible to developers. &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/L2BombSquad/evm-force-inclusion&quot;&gt;You can check it out on GitHub&lt;/a&gt;!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Also, I’m currently looking for my next role in crypto. &lt;a target=&quot;_blank&quot; href=&quot;https://x.com/dhaiwat10&quot;&gt;My X DMs are open, hmu!&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>An Introduction to Blockchain RPC Nodes</title>
    <link href="https://blog.developerdao.com/an-introduction-to-blockchain-rpc-nodes"/>
    <id>https://blog.developerdao.com/an-introduction-to-blockchain-rpc-nodes</id>
    <updated>2025-10-21T14:31:21.360Z</updated>
    <author><name>David Ekete</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1761039384127/cf8f2689-52ea-4bad-ad3d-2f93fabf77e2.jpeg?width=600&amp;format=auto"/>
    <summary>A blockchain is a peer-to-peer (P2P) network of nodes that maintains a shared ledger. Every node communicates with other nodes in the network using specialized P2P protocols to verify blocks, transactions, store state, etc.
When you’re building an ap...</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761039384127/cf8f2689-52ea-4bad-ad3d-2f93fabf77e2.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761039384127/cf8f2689-52ea-4bad-ad3d-2f93fabf77e2.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761039384127/cf8f2689-52ea-4bad-ad3d-2f93fabf77e2.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761039384127/cf8f2689-52ea-4bad-ad3d-2f93fabf77e2.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;p&gt;A blockchain is a peer-to-peer (P2P) network of nodes that maintains a shared ledger. Every node communicates with other nodes in the network using specialized P2P protocols to verify blocks, transactions, store state, etc.&lt;/p&gt;
&lt;p&gt;When you’re building an app on a blockchain, you need a way to communicate with these nodes to read the current state of the blockchain (balances, contract/account data, logs) and write a new state.&lt;/p&gt;
&lt;p&gt;However, direct P2P communication is impractical because node-to-node communication is optimized for consensus and gossip, not for app developers. This is because they involve a lot of complex processes that browsers and typical backends aren’t designed to handle.&lt;/p&gt;
&lt;p&gt;Remote Procedural Call (RPC) nodes exist to abstract this complexity and provide a stable HTTP/WebSocket-friendly way to read and write blockchain data.&lt;/p&gt;
&lt;h2 id=&quot;heading-what-is-an-rpc-node&quot;&gt;&lt;strong&gt;What is an RPC Node?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;An RPC node is a blockchain node configured to expose this developer-friendly API&lt;/strong&gt;. Behind the scenes, it syncs the chain, validates data, and “&lt;a target=&quot;_blank&quot; href=&quot;https://medium.com/@sudhindra_saxena/understanding-gossip-protocol-how-it-really-works-dddb6b081626&quot;&gt;gossips&lt;/a&gt;” with peers; to you, it presents clear methods (read state, submit &lt;strong&gt;signed&lt;/strong&gt; transactions, subscribe to updates) accessible via an &lt;strong&gt;RPC endpoint&lt;/strong&gt; (the URL of the API).&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://en.wikipedia.org/wiki/Remote_procedure_call&quot;&gt;&lt;strong&gt;RPC&lt;/strong&gt;&lt;/a&gt; is a communication protocol that allows a program on one computer to execute a function on a different computer as if it were a local call. On blockchains, this commonly appears as JSON-RPC over HTTP or WebSocket so that you can call methods like &lt;code&gt;getBalance(address)&lt;/code&gt; which returns the balance of an address without handling low-level networking.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -X POST https://mainnet.infura.io/v3/YOUR_PROJECT_ID \
  -H &lt;span&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt; \
  -d &lt;span&gt;&apos;{
    &quot;jsonrpc&quot;: &quot;2.0&quot;,
    &quot;method&quot;: &quot;eth_getBalance&quot;,
    &quot;params&quot;: [
      &quot;0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe&quot;,
      &quot;latest&quot;
    ],
    &quot;id&quot;: 1
  }&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The request above fetches the address’s balance (in &lt;strong&gt;Wei&lt;/strong&gt;) using an RPC provider like Infura via an Ethereum JSON-RPC endpoint. In practice, apps use libraries like &lt;strong&gt;viem&lt;/strong&gt;, &lt;strong&gt;ethers.js&lt;/strong&gt;, or &lt;strong&gt;web3.js&lt;/strong&gt; to talk to RPC endpoints.&lt;/p&gt;
&lt;h2 id=&quot;heading-how-do-rpc-nodes-work&quot;&gt;&lt;strong&gt;How do RPC Nodes Work?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;RPC nodes are normal blockchain nodes with an exposed API surface. The node maintains chain state (syncs blocks, executes transactions, stores results). The &lt;strong&gt;RPC layer&lt;/strong&gt; maps your requests to the right internal components (state/execution, &lt;strong&gt;transaction pool&lt;/strong&gt;, or subscription engine).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761039134596/72ad6936-0105-48d5-9fe3-61d858bd362f.webp?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761039134596/72ad6936-0105-48d5-9fe3-61d858bd362f.webp?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761039134596/72ad6936-0105-48d5-9fe3-61d858bd362f.webp?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761039134596/72ad6936-0105-48d5-9fe3-61d858bd362f.webp?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;div data-node-type=&quot;callout&quot;&gt;
&lt;div data-node-type=&quot;callout-emoji&quot;&gt;💡&lt;/div&gt;
&lt;div data-node-type=&quot;callout-text&quot;&gt;The mechanisms explained below depict how RPC nodes on the Ethereum mainnet behave. It can vary from blockchain to blockchain.&lt;/div&gt;
&lt;/div&gt;

&lt;h3 id=&quot;heading-reading-data-from-a-blockchain&quot;&gt;&lt;strong&gt;Reading Data From a Blockchain&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;For a read (e.g., “get balance” or a contract view), the node selects the state at the &lt;strong&gt;block tag&lt;/strong&gt; (&lt;code&gt;latest&lt;/code&gt;, &lt;code&gt;pending&lt;/code&gt;, &lt;code&gt;safe&lt;/code&gt;, &lt;code&gt;finalized&lt;/code&gt;) you asked for, or a specific block number. If the method requires execution (for example, an &lt;code&gt;eth_call&lt;/code&gt; against a contract), the node runs the call against a sandboxed state at that height, without changing the chain. It then serializes the result and returns it.&lt;/p&gt;
&lt;h3 id=&quot;heading-writing-data-to-a-blockchain&quot;&gt;&lt;strong&gt;Writing Data to a Blockchain&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;For a write (i.e., submitting a &lt;strong&gt;signed&lt;/strong&gt; transaction), the node validates the format and signature (tx type, chainId, nonce, gas limits/fees, optional access list). If valid, your request enters the &lt;strong&gt;mempool&lt;/strong&gt; and is “gossiped” to peers. A block producer includes it, and after its execution, you can query receipts, logs, and confirmation depth.&lt;/p&gt;
&lt;h3 id=&quot;heading-subscribing-to-events-of-a-blockchain&quot;&gt;&lt;strong&gt;Subscribing to Events of a Blockchain&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Over WebSocket, Ethereum supports &lt;code&gt;eth_subscribe&lt;/code&gt; channels such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;newHeads&lt;/code&gt; (new block headers)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;logs&lt;/code&gt; (filtered by address/topics)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;newPendingTransactions&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The node manages buffers/backpressure; clients should handle reconnects and resume from the last seen block number to stay consistent.&lt;/p&gt;
&lt;h2 id=&quot;heading-how-to-use-an-rpc-node&quot;&gt;&lt;strong&gt;How to Use an RPC Node?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;To use an RPC node, you can either run your own private RPC node, use a public RPC node, or use an RPC node provider.&lt;/p&gt;
&lt;h3 id=&quot;heading-hosting-your-own-rpc-node&quot;&gt;&lt;strong&gt;Hosting Your Own RPC Node&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;If you need overall control over your own RPC node, you can install and run blockchain clients like &lt;a target=&quot;_blank&quot; href=&quot;https://geth.ethereum.org/&quot;&gt;Geth&lt;/a&gt;, &lt;a target=&quot;_blank&quot; href=&quot;https://www.nethermind.io/nethermind-client&quot;&gt;Nethermind&lt;/a&gt;, or &lt;a target=&quot;_blank&quot; href=&quot;https://reth.rs/&quot;&gt;Reth&lt;/a&gt; on your own hardware or virtual server and enable RPC on them.&lt;/p&gt;
&lt;div data-node-type=&quot;callout&quot;&gt;
&lt;div data-node-type=&quot;callout-emoji&quot;&gt;💡&lt;/div&gt;
&lt;div data-node-type=&quot;callout-text&quot;&gt;Running your own node requires a lot of maintenance on your end and is best for teams with special needs.&lt;/div&gt;
&lt;/div&gt;

&lt;h3 id=&quot;heading-using-a-public-rpc-node&quot;&gt;&lt;strong&gt;Using a Public RPC Node&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Most blockchains provide free public RPC endpoints that allow anybody to use RPC nodes. Due to their easy accessibility, they are usually overloaded and rate-limited, making them ideal for small DApps and testing. Additionally, they may not offer WebSocket support.&lt;/p&gt;
&lt;p&gt;Examples of popular public RPC nodes include the following:&lt;/p&gt;
&lt;div&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Chain&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Provider&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;RPC Endpoint&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ethereum&lt;/td&gt;&lt;td&gt;PublicNode&lt;/td&gt;&lt;td&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://ethereum-rpc.publicnode.com/&quot;&gt;https://ethereum-rpc.publicnode.com&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Solana (Mainnet-beta)&lt;/td&gt;&lt;td&gt;Anza (Solana Labs)&lt;/td&gt;&lt;td&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://api.mainnet-beta.solana.com/&quot;&gt;https://api.mainnet-beta.solana.com&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BNB Smart Chain&lt;/td&gt;&lt;td&gt;BNB Chain (official)&lt;/td&gt;&lt;td&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://bsc-dataseed.bnbchain.org/&quot;&gt;https://bsc-dataseed.bnbchain.org&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sui (Mainnet)&lt;/td&gt;&lt;td&gt;Mysten Labs&lt;/td&gt;&lt;td&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://fullnode.mainnet.sui.io/&quot;&gt;https://fullnode.mainnet.sui.io:443&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;&lt;h3 id=&quot;heading-using-an-rpc-node-provider&quot;&gt;&lt;strong&gt;Using an RPC Node Provider&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;This is the most popular option for most developers because using RPC node providers is cheaper than running your own RPC node, and you can scale your configuration as your usage increases. To use an RPC provider, you need to sign up on their platform, choose a plan, and start querying their endpoint. Some popular RPC Node providers include Alchemy &amp;amp; QuickNode.&lt;/p&gt;
&lt;div data-node-type=&quot;callout&quot;&gt;
&lt;div data-node-type=&quot;callout-emoji&quot;&gt;📡&lt;/div&gt;
&lt;div data-node-type=&quot;callout-text&quot;&gt;Another interesting RPC provider is the &lt;a target=&quot;_blank&quot; href=&quot;https://cloud.developerdao.com/&quot;&gt;D_D Cloud&lt;/a&gt;, which is built on the POKT Network and gives you access to 60+ chains with unbeatable uptime. You can join the D_D Cloud waitlist &lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/rpc-waitlist&quot;&gt;here&lt;/a&gt;.&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id=&quot;heading-conclusion&quot;&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;You can think of RPC nodes as the API layer of the blockchain. They abstract all the complexities associated with P2P communication between a node and a Dapp and expose a friendlier UI.&lt;/p&gt;
&lt;p&gt;You can access an RPC node via paid providers (often with free tiers), community/public endpoints, or by running your own dedicated node. Whichever route you choose, decide based on your needs for reliability, latency, and cost, and data/privacy requirements.&lt;/p&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Working With Solana Tokens Using Native Rust</title>
    <link href="https://blog.developerdao.com/working-with-solana-tokens-using-native-rust"/>
    <id>https://blog.developerdao.com/working-with-solana-tokens-using-native-rust</id>
    <updated>2025-10-21T14:30:40.478Z</updated>
    <author><name>David Ekete</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1761040465692/eda2aff9-51b1-408c-824c-4f88af6e9b23.jpeg?width=600&amp;format=auto"/>
    <summary>Tokens represent money-like assets, utility (such as governance or access), rewards and points, game items, tickets, and more. Most tokens on Solana follow the SPL token standard or Token-2022 with extensions, which define how tokens are created, tra...</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761040465692/eda2aff9-51b1-408c-824c-4f88af6e9b23.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761040465692/eda2aff9-51b1-408c-824c-4f88af6e9b23.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761040465692/eda2aff9-51b1-408c-824c-4f88af6e9b23.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761040465692/eda2aff9-51b1-408c-824c-4f88af6e9b23.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;p&gt;Tokens represent money-like assets, utility (such as governance or access), rewards and points, game items, tickets, and more. Most tokens on Solana follow the &lt;strong&gt;SPL token standard&lt;/strong&gt; or &lt;a target=&quot;_blank&quot; href=&quot;https://www.solana-program.com/docs/token-2022&quot;&gt;Token-2022&lt;/a&gt; with extensions, which define how tokens are created, transferred, and burned.&lt;/p&gt;
&lt;p&gt;This article covers how tokens work on Solana and how you can use them in your program. The examples in this article are in native Rust, but the concepts can be applied to any framework or library (Anchor, Pinocchio, Steel).&lt;/p&gt;
&lt;h2 id=&quot;heading-how-do-solana-tokens-work&quot;&gt;&lt;strong&gt;How do Solana Tokens Work?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Every token on Solana has a mint account. A mint account defines key information about the token, such as the decimals, authority (who can mint and optionally freeze), total supply, etc. However, the mint account only defines the token; it doesn’t store it.&lt;/p&gt;
&lt;p&gt;Token decimals describe the asset’s fractional precision. If a mint has &lt;code&gt;d&lt;/code&gt; decimals, then &lt;code&gt;1 token = 10^d&lt;/code&gt; base units. Because on-chain programs use &lt;strong&gt;integers only&lt;/strong&gt; to keep consensus deterministic (floating-point can round differently across machines), wallets and dapps convert to/from base units by multiplying or dividing by &lt;code&gt;10^d&lt;/code&gt;. For example, many fiat-like tokens (e.g., USDC) use &lt;strong&gt;six decimals&lt;/strong&gt;, so &lt;code&gt;1 USDC = 1,000,000&lt;/code&gt; base units.&lt;/p&gt;
&lt;p&gt;Tokens can exist as fungible or non-fungible (NFTs). Fungible tokens typically use decimals like &lt;code&gt;6&lt;/code&gt; or &lt;code&gt;9&lt;/code&gt; for divisibility, while NFTs use &lt;code&gt;0&lt;/code&gt; decimals and a supply of 1 (or small editions).&lt;/p&gt;
&lt;p&gt;The token balances live in associated token accounts (ATAs). ATAs are deterministically derived from a &lt;code&gt;(owner, mint, token_program_id)&lt;/code&gt; tuple. Names, symbols, and logos aren’t in the mint or token account. UIs read them from a Metaplex Token Metadata account linked to the mint.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761036910975/680e1b35-9d66-4220-9986-eb4f36408bf3.webp?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1761036910975/680e1b35-9d66-4220-9986-eb4f36408bf3.webp?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761036910975/680e1b35-9d66-4220-9986-eb4f36408bf3.webp?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1761036910975/680e1b35-9d66-4220-9986-eb4f36408bf3.webp?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Most resources on the web currently cover creating tokens on the client side with a CLI or SDK because it’s simpler, cheaper (no CPI), and fits one-off user-issued tokens or NFTs.&lt;/p&gt;
&lt;p&gt;This guide takes the other path, creating mints on-chain inside your program using PDAs and program-controlled authorities. That approach is crucial when the token is core to protocol safety or pricing, e.g., AMM LP shares, vault/receipt tokens, etc. As such, the examples in this tutorial are helper functions that can be part of a bigger program, not a standalone one.&lt;/p&gt;
&lt;h2 id=&quot;heading-setting-up-a-development-environment&quot;&gt;&lt;strong&gt;Setting Up a Development Environment&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;To follow along with this tutorial, you will need to set up a minimal Native Rust program.&lt;/p&gt;
&lt;p&gt;Start by running the command below to create a new project:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cargo init token-mints --lib
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then add the following crates by running the command below:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cargo add borsh@1.5.7 &amp;amp;&amp;amp; \
cargo add solana-program@2.3.0 &amp;amp;&amp;amp; \
cargo add solana-system-interface@1.0.0 --features bincode &amp;amp;&amp;amp; \
cargo add spl-associated-token-account@7.0.0 --features no-entrypoint &amp;amp;&amp;amp; \
cargo add spl-token@7.0.0 --features no-entrypoint
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The crates you added above include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;borsh&lt;/strong&gt; – Deterministic binary serialization/deserialization for your program/account data. Commonly used to (de)serialize instruction payloads and account state.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;solana-program&lt;/strong&gt;: types like &lt;code&gt;Pubkey&lt;/code&gt;, &lt;code&gt;AccountInfo&lt;/code&gt;, &lt;code&gt;ProgramResult&lt;/code&gt;, entrypoint glue, sysvars, and helpers to build/parse instructions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;solana-system-interface&lt;/strong&gt; (+ &lt;code&gt;bincode&lt;/code&gt; feature) – Stable interface types/IDL for the System Program (create accounts, transfers, etc.).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;spl-associated-token-account&lt;/strong&gt; (&lt;code&gt;no-entrypoint&lt;/code&gt;) – Instruction builders and CPI interface for the Associated Token Account (ATA) Program (create/find ATAs).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;spl-token&lt;/strong&gt; (&lt;code&gt;no-entrypoint&lt;/code&gt;) – Instruction builders, state types, and CPI interface for the SPL Token Program (mint, transfer, burn, etc.).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note: Ensure you install the exact versions in the command above, else this may not work as expected.&lt;/p&gt;
&lt;h2 id=&quot;heading-creating-and-initializing-a-token-mint&quot;&gt;&lt;strong&gt;Creating and Initializing a Token Mint&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;In this section, you’ll build a small helper, &lt;code&gt;create_and_init_mint&lt;/code&gt;, that allocates a mint account as a PDA, then initializes it so your program (via a PDA) controls minting. We’ll set the freeze authority to &lt;code&gt;None&lt;/code&gt; to keep the asset non-custodial by default.&lt;/p&gt;
&lt;p&gt;The function will accept the following inputs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Accounts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Payer (signer, writable)&lt;strong&gt;:&lt;/strong&gt; funds rent and signs the create account instruction.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Mint (PDA, writable, uninitialized)&lt;strong&gt;:&lt;/strong&gt; the account to become your mint.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;System Program*&lt;em&gt;:&lt;/em&gt;* required by the system &lt;code&gt;create_account&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;program_id&lt;/code&gt;: your program ID.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;token_decimals: u8&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;mint_authority: Pubkey&lt;/code&gt; (recommend a program PDA)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;mint_seeds: &amp;amp;[&amp;amp;[u8]]&lt;/code&gt; (the PDA seeds/bump for the mint)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before you proceed, ensure that you have the following imports at the top of your file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;use&lt;/span&gt; solana_program::account_info::{next_account_info, AccountInfo};
&lt;span&gt;use&lt;/span&gt; solana_program::entrypoint::ProgramResult;
&lt;span&gt;use&lt;/span&gt; solana_program::program::{invoke, invoke_signed};
&lt;span&gt;use&lt;/span&gt; solana_program::program_error::ProgramError;
&lt;span&gt;use&lt;/span&gt; solana_program::program_pack::Pack;
&lt;span&gt;use&lt;/span&gt; solana_program::pubkey::Pubkey;
&lt;span&gt;use&lt;/span&gt; solana_program::rent::Rent;
&lt;span&gt;use&lt;/span&gt; solana_program::sysvar::Sysvar;

&lt;span&gt;use&lt;/span&gt; spl_token::id &lt;span&gt;as&lt;/span&gt; spl_token_id;
&lt;span&gt;use&lt;/span&gt; spl_token::instruction &lt;span&gt;as&lt;/span&gt; token_instruction;
&lt;span&gt;use&lt;/span&gt; spl_token::state::{Account &lt;span&gt;as&lt;/span&gt; SplAccount, Mint &lt;span&gt;as&lt;/span&gt; SplMint};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that the imports from &lt;code&gt;spl_token&lt;/code&gt; are renamed to avoid conflicts with packages from &lt;code&gt;solana_program&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;heading-creating-the-token-mint&quot;&gt;&lt;strong&gt;Creating the Token Mint&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To create the mint, first, you allocate the mint account as a &lt;strong&gt;program-derived address (PDA)&lt;/strong&gt; and set its owner to the &lt;strong&gt;SPL Token program&lt;/strong&gt;. This ensures that, after creation, only the token program itself can mutate the mint’s data.&lt;/p&gt;
&lt;p&gt;Next, you set the &lt;strong&gt;mint authority&lt;/strong&gt; to a &lt;strong&gt;PDA controlled by your program&lt;/strong&gt;, so any future issuance must come through your on-chain logic (you’ll sign CPIs with &lt;code&gt;invoke_signed&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;You then intentionally leave the &lt;strong&gt;freeze authority&lt;/strong&gt; as &lt;code&gt;None&lt;/code&gt;, avoiding a built-in backdoor that could freeze user accounts. Finally, you choose the &lt;strong&gt;decimals&lt;/strong&gt; explicitly to set the asset’s precision up front (e.g., &lt;strong&gt;6&lt;/strong&gt; for fiat-like tokens, &lt;strong&gt;9&lt;/strong&gt; for Solana-style precision, &lt;strong&gt;0&lt;/strong&gt; for NFTs).&lt;/p&gt;
&lt;p&gt;Like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;pub&lt;/span&gt; &lt;span&gt;&lt;span&gt;fn&lt;/span&gt; &lt;span&gt;create_and_init_mint&lt;/span&gt;&lt;/span&gt;(
    program_id: &amp;amp;Pubkey,
    accounts: &amp;amp;[AccountInfo],
    mint_authority: &amp;amp;Pubkey,
    mint_seeds: &amp;amp;[&amp;amp;[&lt;span&gt;u8&lt;/span&gt;]],
    token_decimals: &lt;span&gt;u8&lt;/span&gt;,
) -&amp;gt; ProgramResult {
    &lt;span&gt;let&lt;/span&gt; acc_iter = &amp;amp;&lt;span&gt;mut&lt;/span&gt; accounts.iter();

    &lt;span&gt;//payer (signer), mint (writable), system program&lt;/span&gt;
    &lt;span&gt;let&lt;/span&gt; payer = next_account_info(acc_iter)?;
    &lt;span&gt;let&lt;/span&gt; token_mint = next_account_info(acc_iter)?;
    &lt;span&gt;let&lt;/span&gt; system_program = next_account_info(acc_iter)?;

    &lt;span&gt;if&lt;/span&gt; !payer.is_signer {
        &lt;span&gt;return&lt;/span&gt; &lt;span&gt;Err&lt;/span&gt;(ProgramError::MissingRequiredSignature);
    }

    &lt;span&gt;if&lt;/span&gt; !token_mint.is_writable {
        &lt;span&gt;return&lt;/span&gt; &lt;span&gt;Err&lt;/span&gt;(ProgramError::InvalidAccountData);
    }

    &lt;span&gt;// Ensure the passed mint is exactly the PDA we expect for these seeds.&lt;/span&gt;
    &lt;span&gt;let&lt;/span&gt; expected = Pubkey::create_program_address(mint_seeds, program_id)
        .map_err(|_| ProgramError::InvalidSeeds)?;
    &lt;span&gt;if&lt;/span&gt; *token_mint.key != expected {
        &lt;span&gt;return&lt;/span&gt; &lt;span&gt;Err&lt;/span&gt;(ProgramError::InvalidSeeds);
    }

    &lt;span&gt;let&lt;/span&gt; space = SplMint::LEN &lt;span&gt;as&lt;/span&gt; &lt;span&gt;u64&lt;/span&gt;;
    &lt;span&gt;let&lt;/span&gt; lamports = Rent::get()?.minimum_balance(space &lt;span&gt;as&lt;/span&gt; &lt;span&gt;usize&lt;/span&gt;);

    invoke_signed(
        &amp;amp;solana_system_interface::instruction::create_account(
            &amp;amp;payer.key,
            &amp;amp;token_mint.key,
            lamports,
            space,
            &amp;amp;spl_token_id(),
        ),
        &amp;amp;[payer.clone(), token_mint.clone(), system_program.clone()],
        &amp;amp;[mint_seeds],
    )?;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, you have created the token mint. Next, you will initialize it.&lt;/p&gt;
&lt;h3 id=&quot;heading-initializing-token-mints&quot;&gt;&lt;strong&gt;Initializing Token Mints&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To initialize the token mint, you need to invoke the &lt;code&gt;initialize_mint2&lt;/code&gt; instruction from the SPL token program. Pass the SPL program ID, the mint account’s public key, the mint_authority, the freeze authority, and the decimals into the instructions and invoke the instruction with the token mint account.&lt;/p&gt;
&lt;p&gt;Like so (this snippet is part of &lt;code&gt;create_and_init_mint&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &lt;span&gt;let&lt;/span&gt; initialize_ix = token_instruction::initialize_mint2(
        &amp;amp;spl_token_id(),
        token_mint.key,
        mint_authority,
        &lt;span&gt;None&lt;/span&gt;,
        token_decimals,
    )?;

    invoke(&amp;amp;initialize_ix, &amp;amp;[token_mint.clone()])?;

    &lt;span&gt;Ok&lt;/span&gt;(())

  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There’s an alternative to the &lt;code&gt;initialize_mint2&lt;/code&gt; instruction, which is the &lt;code&gt;initialize_mint&lt;/code&gt; function. Both set the same mint fields (decimals, mint authority, freeze authority).&lt;/p&gt;
&lt;p&gt;The difference is in the required accounts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;initialize_mint2&lt;/code&gt; does &lt;strong&gt;not&lt;/strong&gt; require the Rent sysvar; you pass only the mint account in the CPI account list.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;initialize_mint&lt;/code&gt; &lt;strong&gt;requires&lt;/strong&gt; the Rent sysvar and will read it during initialization.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After initialization, the mint’s total supply is 0. The SPL Token program does not enforce a cap; your supply policy is up to you.&lt;/p&gt;
&lt;p&gt;You create supply by calling &lt;code&gt;mint_to_checked&lt;/code&gt; from your mint authority (usually a PDA) into a token account (often a treasury ATA). However, if you want a fixed supply, mint the full amount and then revoke the mint authority by setting it to &lt;code&gt;None&lt;/code&gt; (This process is irreversible).&lt;/p&gt;
&lt;p&gt;Here’s an example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;// Mint initial supply to a treasury ATA, then lock the mint.&lt;/span&gt;
&lt;span&gt;let&lt;/span&gt; amount_base = ui_amount
    .checked_mul(&lt;span&gt;10u64&lt;/span&gt;.pow(token_decimals &lt;span&gt;as&lt;/span&gt; &lt;span&gt;u32&lt;/span&gt;))
    .ok_or(ProgramError::InvalidArgument)?;

&lt;span&gt;let&lt;/span&gt; ix = token_instruction::mint_to_checked(
    &amp;amp;spl_token_id(),
    token_mint.key,
    treasury_ata.key,
    mint_authority,      &lt;span&gt;// your PDA signs via invoke_signed&lt;/span&gt;
    &amp;amp;[],
    amount_base,
    token_decimals,
)?;
invoke(&amp;amp;ix, &amp;amp;[token_mint.clone(), treasury_ata.clone(), &lt;span&gt;/* + authority account */&lt;/span&gt;])?;

&lt;span&gt;// Later, make supply fixed:&lt;/span&gt;
&lt;span&gt;let&lt;/span&gt; ix_disable = token_instruction::set_authority(
    &amp;amp;spl_token_id(),
    token_mint.key,
    &lt;span&gt;None&lt;/span&gt;, &lt;span&gt;// new authority = None → revoke&lt;/span&gt;
    spl_token::instruction::AuthorityType::MintTokens,
    mint_authority,
    &amp;amp;[],
)?;
invoke(&amp;amp;ix_disable, &amp;amp;[token_mint.clone(), &lt;span&gt;/* + authority account */&lt;/span&gt;])?;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, you have created and initialized the token mint. Next, you will make associated token accounts for the mints.&lt;/p&gt;
&lt;h2 id=&quot;heading-creating-an-associated-token-account&quot;&gt;&lt;strong&gt;Creating an Associated Token Account&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;For any user to hold the token you just minted and initialized, they have to own an ATA for the mint. An ATA is a deterministic address derived from an &lt;code&gt;(owner, mint, token_program_id)&lt;/code&gt; tuple, so wallets and programs can compute it and fetch that single account.&lt;/p&gt;
&lt;p&gt;When creating ATAs, decide who pays the rent to initialize the account. You can sponsor creation from your program (great onboarding, but costs scale with users), or require the user to fund it themselves (adds a signature step and a bit of friction, but controls your spend). Anyone may pay the fee; payer and owner do not have to be the same, and the payer gains no control over the account.&lt;/p&gt;
&lt;p&gt;To create an ATA, invoke the &lt;code&gt;create_associated_token_account_idempotent&lt;/code&gt; instruction from the &lt;code&gt;spl_associated_token_account::instruction&lt;/code&gt; crate with the following accounts (in the same order): payer, owner, ATA account, token mint account, token program account, system program account.&lt;/p&gt;
&lt;p&gt;Like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;use&lt;/span&gt; spl_associated_token_account &lt;span&gt;as&lt;/span&gt; ata;

&lt;span&gt;pub&lt;/span&gt; &lt;span&gt;&lt;span&gt;fn&lt;/span&gt; &lt;span&gt;create_ata_for&lt;/span&gt;&lt;/span&gt;(accounts: &amp;amp;[AccountInfo]) -&amp;gt; ProgramResult {
    &lt;span&gt;let&lt;/span&gt; acc_iter = &amp;amp;&lt;span&gt;mut&lt;/span&gt; accounts.iter();

    &lt;span&gt;let&lt;/span&gt; payer = next_account_info(acc_iter)?; &lt;span&gt;//pays the fees for account creation&lt;/span&gt;
    &lt;span&gt;let&lt;/span&gt; owner = next_account_info(acc_iter)?; &lt;span&gt;//Owner of the ATA&lt;/span&gt;
    &lt;span&gt;let&lt;/span&gt; ata_acc = next_account_info(acc_iter)?;
    &lt;span&gt;let&lt;/span&gt; token_mint = next_account_info(acc_iter)?;
    &lt;span&gt;let&lt;/span&gt; token_program = next_account_info(acc_iter)?;
    &lt;span&gt;let&lt;/span&gt; system_program = next_account_info(acc_iter)?;

    &lt;span&gt;// Derive the expected ATA address and compare&lt;/span&gt;
    &lt;span&gt;let&lt;/span&gt; expected_ata = ata::get_associated_token_address_with_program_id(
        owner.key,
        token_mint.key,
        &amp;amp;spl_token_id(),
    );

    &lt;span&gt;// Sanity check: is the passed ATA the one we expect?&lt;/span&gt;
    &lt;span&gt;if&lt;/span&gt; ata_acc.key != &amp;amp;expected_ata {
        &lt;span&gt;return&lt;/span&gt; &lt;span&gt;Err&lt;/span&gt;(ProgramError::InvalidArgument);
    }

    &lt;span&gt;// Payer must sign&lt;/span&gt;
    &lt;span&gt;if&lt;/span&gt; !payer.is_signer {
        &lt;span&gt;return&lt;/span&gt; &lt;span&gt;Err&lt;/span&gt;(ProgramError::MissingRequiredSignature);
    }

    &lt;span&gt;// Create the ATA (idempotent)&lt;/span&gt;
    &lt;span&gt;let&lt;/span&gt; ata_instruction = ata::instruction::create_associated_token_account_idempotent(
        payer.key,
        owner.key,
        token_mint.key,
        &amp;amp;spl_token_id(),
    );

    &lt;span&gt;// Invoke the ATA creation instruction&lt;/span&gt;
    invoke(
        &amp;amp;ata_instruction,
        &amp;amp;[
            payer.clone(),
            ata_acc.clone(),
            owner.clone(),
            token_mint.clone(),
            system_program.clone(),
            token_program.clone(),
        ],
    )?;

    &lt;span&gt;Ok&lt;/span&gt;(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you can create ATAs for your mints. Next, you will learn how to burn tokens from the ATAs.&lt;/p&gt;
&lt;h2 id=&quot;heading-burning-tokens&quot;&gt;&lt;strong&gt;Burning Tokens&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Burning destroys tokens from a specific token account and reduces the mint’s total supply by the same amount. The SPL Token program enforces that only the token account owner (or an approved delegate) may burn from that account; you do not need the mint authority.&lt;/p&gt;
&lt;p&gt;To burn tokens, invoke the spl token programs &lt;code&gt;burn_checked&lt;/code&gt; instruction with the following accounts (in the same order): token mint account, ATA owner account, ATA.&lt;/p&gt;
&lt;p&gt;Like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;pub&lt;/span&gt; &lt;span&gt;&lt;span&gt;fn&lt;/span&gt; &lt;span&gt;burn_user_tokens&lt;/span&gt;&lt;/span&gt;(accounts: &amp;amp;[AccountInfo], amount_ui: &lt;span&gt;u64&lt;/span&gt;) -&amp;gt; ProgramResult {
    &lt;span&gt;let&lt;/span&gt; acc_iter = &amp;amp;&lt;span&gt;mut&lt;/span&gt; accounts.iter();

    &lt;span&gt;// 0 mint, 1 owner(signer), 2 token_account(ATA), 3 token_program&lt;/span&gt;
    &lt;span&gt;let&lt;/span&gt; mint_account = next_account_info(acc_iter)?;
    &lt;span&gt;let&lt;/span&gt; owner_account = next_account_info(acc_iter)?; &lt;span&gt;// authority, must sign&lt;/span&gt;
    &lt;span&gt;let&lt;/span&gt; ata_token_acc = next_account_info(acc_iter)?;

    &lt;span&gt;if&lt;/span&gt; !owner_account.is_signer {
        &lt;span&gt;return&lt;/span&gt; &lt;span&gt;Err&lt;/span&gt;(ProgramError::MissingRequiredSignature);
    }

    &lt;span&gt;// Sanity: token account belongs to owner and matches mint&lt;/span&gt;
    &lt;span&gt;let&lt;/span&gt; token_account = SplAccount::unpack(&amp;amp;ata_token_acc.try_borrow_data()?)?;
    &lt;span&gt;if&lt;/span&gt; token_account.mint != *mint_account.key || token_account.owner != *owner_account.key {
        &lt;span&gt;return&lt;/span&gt; &lt;span&gt;Err&lt;/span&gt;(ProgramError::InvalidAccountData);
    }

    &lt;span&gt;// Derive base units using mint decimals&lt;/span&gt;
    &lt;span&gt;let&lt;/span&gt; mint = SplMint::unpack(&amp;amp;mint_account.try_borrow_data()?)?;
    &lt;span&gt;let&lt;/span&gt; decimals = mint.decimals;
    &lt;span&gt;let&lt;/span&gt; amount_base = amount_ui
        .checked_mul(&lt;span&gt;10u64&lt;/span&gt;.pow(decimals &lt;span&gt;as&lt;/span&gt; &lt;span&gt;u32&lt;/span&gt;))
        .ok_or(ProgramError::InvalidArgument)?;

    &lt;span&gt;// Burn (checked) — accounts: [token_account, mint, authority]&lt;/span&gt;
    &lt;span&gt;let&lt;/span&gt; burn_ix = token_instruction::burn_checked(
        &amp;amp;spl_token_id(),
        ata_token_acc.key,
        mint_account.key,
        owner_account.key,
        &amp;amp;[],
        amount_base,
        decimals,
    )?;

    invoke(
        &amp;amp;burn_ix,
        &amp;amp;[
            ata_token_acc.clone(),
            mint_account.clone(),
            owner_account.clone(),
        ],
    )?;

    &lt;span&gt;Ok&lt;/span&gt;(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;heading-conclusion&quot;&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;With the core pieces in place, mints that define the assets, ATAs that hold balances, and a burn mechanism to control supply. You’ve learnt how to create a mint as a PDA, initialize it with explicit decimals and authorities, derive and fund ATAs, mint and transfer in base units, and burn safely.&lt;/p&gt;
&lt;p&gt;With these primitives, you can ship payments, points, or NFTs end-to-end in native Rust.&lt;/p&gt;
&lt;p&gt;You can find the code examples with associated tests in this &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/davidekete/token-mints&quot;&gt;GitHub repository&lt;/a&gt;. This is part one of a two-part series; the next part will cover Token-2022 extensions and hooks.&lt;/p&gt;
&lt;p&gt;To get notified when it drops, follow me on &lt;a target=&quot;_blank&quot; href=&quot;https://x.com/david_ekete&quot;&gt;X&lt;/a&gt; :).&lt;/p&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>BuildBear Tutorial:  Cross-Chain Bridge</title>
    <link href="https://blog.developerdao.com/buildbear-tutorial-cross-chain-bridge"/>
    <id>https://blog.developerdao.com/buildbear-tutorial-cross-chain-bridge</id>
    <updated>2025-10-07T11:37:38.946Z</updated>
    <author><name>Ϗ</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1760002075480/e6b31451-1286-4d30-81f0-6b6b3c07dbbd.jpeg?width=600&amp;format=auto"/>
    <summary>This is post was written by @0xJustUzair

BuildBear is a specialized platform for DApp development and testing. Developers can create a personalized private testnet sandbox for various EVM and EVM-compatible blockchain networks.
Key Features

Access ...</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1760002075480/e6b31451-1286-4d30-81f0-6b6b3c07dbbd.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1760002075480/e6b31451-1286-4d30-81f0-6b6b3c07dbbd.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1760002075480/e6b31451-1286-4d30-81f0-6b6b3c07dbbd.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1760002075480/e6b31451-1286-4d30-81f0-6b6b3c07dbbd.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;blockquote&gt;
&lt;p&gt;This is post was written by &lt;a target=&quot;_blank&quot; href=&quot;https://x.com/0xJustUzair&quot;&gt;@0xJustUzair&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;BuildBear is a specialized platform for DApp development and testing. Developers can create a personalized private testnet sandbox for various EVM and EVM-compatible blockchain networks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Features&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Access a private faucet for unlimited minting of native and ERC-20 tokens.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Experience lightning-fast transactions, completing in under three seconds.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Debug transactions effortlessly within your sandbox using the built-in explorer and transaction tracer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Leverage real-time testing and debugging tools, along with many other advanced features.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;heading-sign-in-to-the-buildbear-dashboard&quot;&gt;Sign in to the BuildBear Dashboard&lt;/h2&gt;
&lt;p&gt;Sign in using your GitHub, Google, or a Web3 wallet.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759747813501/0b2e5b22-015b-4631-99c6-7fd57600f87c.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759747813501/0b2e5b22-015b-4631-99c6-7fd57600f87c.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759747813501/0b2e5b22-015b-4631-99c6-7fd57600f87c.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759747813501/0b2e5b22-015b-4631-99c6-7fd57600f87c.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Once you&apos;re logged in, you&apos;ll see a page similar to the image below.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759747823747/7e920dbe-e9d7-4932-b268-7d4ad30522ec.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759747823747/7e920dbe-e9d7-4932-b268-7d4ad30522ec.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759747823747/7e920dbe-e9d7-4932-b268-7d4ad30522ec.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759747823747/7e920dbe-e9d7-4932-b268-7d4ad30522ec.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-create-a-sandbox&quot;&gt;Create a Sandbox&lt;/h2&gt;
&lt;p&gt;Discover how to set up a sandbox on BuildBear for seamless DApp development and testing. Customize your environment, fork from supported blockchains, and access essential tools for debugging and verification.&lt;/p&gt;
&lt;h3 id=&quot;heading-create-your-buildbear-sandbox&quot;&gt;Create Your BuildBear Sandbox&lt;/h3&gt;
&lt;p&gt;Click &lt;strong&gt;Create a Sandbox&lt;/strong&gt; to start configuring your test blockchain.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759747853748/c22abd0e-edc3-4595-8fc8-75c615814044.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759747853748/c22abd0e-edc3-4595-8fc8-75c615814044.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759747853748/c22abd0e-edc3-4595-8fc8-75c615814044.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759747853748/c22abd0e-edc3-4595-8fc8-75c615814044.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;heading-forking-options&quot;&gt;Forking Options&lt;/h3&gt;
&lt;p&gt;This feature enables you to create a sandbox, forked from the state of any supported blockchain, at any block number, with a randomly generated chain ID.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759747871108/f12d7511-d6af-4a27-a1bd-cd5b07ffe3d7.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759747871108/f12d7511-d6af-4a27-a1bd-cd5b07ffe3d7.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759747871108/f12d7511-d6af-4a27-a1bd-cd5b07ffe3d7.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759747871108/f12d7511-d6af-4a27-a1bd-cd5b07ffe3d7.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;You can also create a test blockchain without forking from an existing chain.&lt;/p&gt;
&lt;h4 id=&quot;heading-advanced-options&quot;&gt;Advanced Options&lt;/h4&gt;
&lt;p&gt;When creating a Sandbox, you can configure additional options to customize your environment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deploy Large Contracts&lt;/strong&gt;: Enable contracts larger than the default 24KB limit.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unlocked Accounts&lt;/strong&gt;: Access unlocked accounts for easier script execution.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mnemonic&lt;/strong&gt;: Generate a unique mnemonic phrase for your testnet.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Override Gas Estimation&lt;/strong&gt;: Detect and override gas estimation failures.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Impersonation Transactions&lt;/strong&gt;: Allow transactions to be sent from any address for testing purposes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Snapshots&lt;/strong&gt;: Take snapshots of the blockchain state for easy rollbacks.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Block Mining &amp;amp; Timestamp Manipulation&lt;/strong&gt;: Manually mine blocks and adjust timestamps.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759747888176/1b5171e6-f137-47f2-806f-218fecc280aa.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759747888176/1b5171e6-f137-47f2-806f-218fecc280aa.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759747888176/1b5171e6-f137-47f2-806f-218fecc280aa.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759747888176/1b5171e6-f137-47f2-806f-218fecc280aa.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Configure these options based on your development needs to optimize testing and debugging.&lt;/p&gt;
&lt;h3 id=&quot;heading-your-rpc-is-ready-for-use&quot;&gt;Your RPC Is Ready for Use&lt;/h3&gt;
&lt;p&gt;After clicking &lt;strong&gt;Create&lt;/strong&gt;, select &lt;strong&gt;Go to Dashboard&lt;/strong&gt; to access your newly created sandbox.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759747904876/dd30b476-2d18-49b0-8829-b4f3b8a42acb.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759747904876/dd30b476-2d18-49b0-8829-b4f3b8a42acb.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759747904876/dd30b476-2d18-49b0-8829-b4f3b8a42acb.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759747904876/dd30b476-2d18-49b0-8829-b4f3b8a42acb.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;On the &lt;strong&gt;Dashboard&lt;/strong&gt;, you’ll find essential details and tools to manage your test environment efficiently.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759747965110/ac3a726e-db88-4097-8ccd-493becc4ab31.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759747965110/ac3a726e-db88-4097-8ccd-493becc4ab31.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759747965110/ac3a726e-db88-4097-8ccd-493becc4ab31.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759747965110/ac3a726e-db88-4097-8ccd-493becc4ab31.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Each sandbox ships with a funded mnemonic. To extract the first account’s key:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759747982327/959cc7e3-726f-4f8a-8fbf-533c9092a502.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759747982327/959cc7e3-726f-4f8a-8fbf-533c9092a502.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759747982327/959cc7e3-726f-4f8a-8fbf-533c9092a502.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759747982327/959cc7e3-726f-4f8a-8fbf-533c9092a502.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748009170/fb24df82-333c-4815-9248-b8df7e562f22.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748009170/fb24df82-333c-4815-9248-b8df7e562f22.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748009170/fb24df82-333c-4815-9248-b8df7e562f22.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748009170/fb24df82-333c-4815-9248-b8df7e562f22.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cast wallet address PRIVATE_KEY&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748020929/ba9e0200-3b6a-407b-b3fc-879f738aa1cf.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748020929/ba9e0200-3b6a-407b-b3fc-879f738aa1cf.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748020929/ba9e0200-3b6a-407b-b3fc-879f738aa1cf.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748020929/ba9e0200-3b6a-407b-b3fc-879f738aa1cf.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Use the wallet address to obtain funds from your sandbox faucet.&lt;/p&gt;
&lt;h2 id=&quot;heading-faucet&quot;&gt;Faucet&lt;/h2&gt;
&lt;p&gt;The BuildBear Faucet provides an easy way to acquire native and ERC-20 tokens for your testnet sandbox. Whether you’re testing transactions or deploying smart contracts, you&apos;ll need tokens for gas fees. Use the faucet to mint both native tokens and ERC-20 tokens to fund your development efforts.&lt;/p&gt;
&lt;p&gt;Start by selecting the type of token you need (native or ERC-20), and you’ll receive the required tokens instantly. The faucet ensures a seamless experience for developers testing on BuildBear’s platform.&lt;/p&gt;
&lt;h2 id=&quot;heading-get-erc20-tokens&quot;&gt;Get ERC20 Tokens&lt;/h2&gt;
&lt;p&gt;The BuildBear Faucet allows you to request testnet tokens for your blockchain projects, enabling smooth testing and development.&lt;/p&gt;
&lt;h3 id=&quot;heading-add-erc-20-tokens&quot;&gt;Add ERC-20 Tokens&lt;/h3&gt;
&lt;p&gt;Click &lt;strong&gt;Faucet&lt;/strong&gt; in the left navigation pane.&lt;/p&gt;
&lt;p&gt;Use the faucet to mint ERC-20 tokens for your testing needs.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748111035/f4ffa87a-ee21-4568-9d21-08d090382e3d.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748111035/f4ffa87a-ee21-4568-9d21-08d090382e3d.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748111035/f4ffa87a-ee21-4568-9d21-08d090382e3d.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748111035/f4ffa87a-ee21-4568-9d21-08d090382e3d.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;The faucet provides a list of supported ERC-20 tokens. You can select the token you wish to mint from the list.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748114622/bb739789-7a8f-472b-9b5b-5432104a8c7b.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748114622/bb739789-7a8f-472b-9b5b-5432104a8c7b.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748114622/bb739789-7a8f-472b-9b5b-5432104a8c7b.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748114622/bb739789-7a8f-472b-9b5b-5432104a8c7b.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-get-native-tokens&quot;&gt;Get Native Tokens&lt;/h2&gt;
&lt;p&gt;The BuildBear Faucet allows you to request testnet tokens for your blockchain projects, enabling smooth testing and development.&lt;/p&gt;
&lt;h3 id=&quot;heading-add-native-tokens-or-erc-20-tokens&quot;&gt;Add Native Tokens or ERC-20 Tokens&lt;/h3&gt;
&lt;p&gt;Click &lt;strong&gt;Faucet&lt;/strong&gt; in the left Navigation Pane.&lt;/p&gt;
&lt;p&gt;To perform transactions on any sandbox, you’ll need native tokens for gas fees. Use the faucet to acquire them.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748136794/b09c4ce3-62cd-4df0-a804-113418c5e81a.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748136794/b09c4ce3-62cd-4df0-a804-113418c5e81a.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748136794/b09c4ce3-62cd-4df0-a804-113418c5e81a.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748136794/b09c4ce3-62cd-4df0-a804-113418c5e81a.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-plugins-installation&quot;&gt;Plugins Installation&lt;/h2&gt;
&lt;p&gt;Install the required plugins from the &lt;strong&gt;BuildBear Plugin Marketplace.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748150778/bc31e98b-74c5-4570-b618-b23db37e9d0a.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748150778/bc31e98b-74c5-4570-b618-b23db37e9d0a.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748150778/bc31e98b-74c5-4570-b618-b23db37e9d0a.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748150778/bc31e98b-74c5-4570-b618-b23db37e9d0a.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-contracts-verification-api&quot;&gt;Contracts Verification API&lt;/h2&gt;
&lt;p&gt;Verify your smart contracts and fetch verified contract artifacts via BuildBear’s unified verification endpoints.&lt;/p&gt;
&lt;h3 id=&quot;heading-supported-verification-types&quot;&gt;Supported Verification Types&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Foundry&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Etherscan&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sourcify&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Hardhat&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Etherscan&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sourcify&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Refer to the following doc to learn to Verify Contracts on BuildBear Sandboxes.&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.buildbear.io/docs/api-reference/contracts-verification-api?utm_source=devdao&amp;amp;utm_medium=blog&amp;amp;utm_campaign=blog-cross-chain-bridge&quot;&gt;Docs - Contracts Verification API - BuildBear Labs&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-buildbear-explorer&quot;&gt;BuildBear Explorer&lt;/h2&gt;
&lt;p&gt;BuildBear Explorer provides an &lt;strong&gt;intuitive and powerful interface&lt;/strong&gt; for monitoring blockchain transactions. Whether you’re debugging smart contracts or tracking transaction history, the explorer offers real-time insights and seamless navigation.&lt;/p&gt;
&lt;h3 id=&quot;heading-key-features&quot;&gt;Key Features&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Transaction Monitoring&lt;/strong&gt; – View pending and confirmed transactions across multiple explorers (&lt;strong&gt;BuildBear, BlockScout, and Ethernal&lt;/strong&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Detailed Transaction Insights&lt;/strong&gt; – Access transaction details, including hash, block number, sender/receiver addresses, and gas usage.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Advanced Debugging Tools&lt;/strong&gt; – Utilize &lt;strong&gt;Sentio Tracer, Sentio Debugger, and Simbolik Debugger&lt;/strong&gt; for in-depth contract execution analysis.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;External Explorer Support&lt;/strong&gt; – Open transactions in third-party explorers directly from BuildBear.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;heading-monitoring-transactions-on-buildbear-explorer&quot;&gt;Monitoring Transactions on BuildBear Explorer&lt;/h2&gt;
&lt;p&gt;Click &lt;strong&gt;Explorer&lt;/strong&gt; in the left Navigation Pane.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748175518/53488154-949f-4362-ad13-619b237e7170.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748175518/53488154-949f-4362-ad13-619b237e7170.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748175518/53488154-949f-4362-ad13-619b237e7170.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748175518/53488154-949f-4362-ad13-619b237e7170.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;A list of transactions will be displayed. You can filter the transactions by &lt;strong&gt;All&lt;/strong&gt;, &lt;strong&gt;Pending&lt;/strong&gt;, and &lt;strong&gt;Confirmed&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748184199/4d0fe3f2-21c5-40be-96d5-586b018bd0e6.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748184199/4d0fe3f2-21c5-40be-96d5-586b018bd0e6.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748184199/4d0fe3f2-21c5-40be-96d5-586b018bd0e6.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748184199/4d0fe3f2-21c5-40be-96d5-586b018bd0e6.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;You can also expand the &lt;strong&gt;Explorer&lt;/strong&gt; menu to select a default explorer from &lt;strong&gt;BuildBear&lt;/strong&gt;, &lt;strong&gt;BlockScout&lt;/strong&gt;, or &lt;strong&gt;Ethernal&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748195519/4ca37cfe-4733-4941-91ec-f2e00fbe522a.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748195519/4ca37cfe-4733-4941-91ec-f2e00fbe522a.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748195519/4ca37cfe-4733-4941-91ec-f2e00fbe522a.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748195519/4ca37cfe-4733-4941-91ec-f2e00fbe522a.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Click on a transaction to view its details. The transaction details page includes information such as the transaction hash, block number, sender and receiver addresses, etc.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748210100/9084edd0-18bf-4b35-9c25-8995677a1a39.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748210100/9084edd0-18bf-4b35-9c25-8995677a1a39.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748210100/9084edd0-18bf-4b35-9c25-8995677a1a39.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748210100/9084edd0-18bf-4b35-9c25-8995677a1a39.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;heading-transaction-debugging&quot;&gt;Transaction Debugging&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;Transaction Details&lt;/strong&gt; page provides essential debugging tools, including &lt;strong&gt;Sentio Tracer&lt;/strong&gt;, &lt;strong&gt;Sentio Debugger&lt;/strong&gt;, and &lt;strong&gt;Simbolik Debugger,&lt;/strong&gt; to analyze transaction execution.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748219960/b8a7b32d-6ef5-45b8-8841-0447c7ec4627.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748219960/b8a7b32d-6ef5-45b8-8841-0447c7ec4627.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748219960/b8a7b32d-6ef5-45b8-8841-0447c7ec4627.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748219960/b8a7b32d-6ef5-45b8-8841-0447c7ec4627.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;At the top, next to &lt;strong&gt;View all Transactions&lt;/strong&gt;, you’ll find a drop-down menu to open the current transaction’s details in an external explorer of your choice.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;heading-building-a-cross-chain-bridge-with-node-relayer-on-buildbear&quot;&gt;Building a Cross-Chain Bridge with Node Relayer on BuildBear&lt;/h2&gt;
&lt;p&gt;We will build a minimal, event-driven bridge that works end-to-end across two BuildBear Mainnet Sandboxes (Ethereum and Polygon).&lt;br /&gt;Instead of mocks, we will attach real Chainlink ETH/USD feeds via the BuildBear Data Feeds plugin, verify contracts with Sourcify, and debug transactions with Sentio, all in BuildBear&apos;s Sandboxes.&lt;/p&gt;
&lt;h3 id=&quot;heading-what-we-will-learn&quot;&gt;What We Will Learn&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Setting up two BuildBear Mainnet Sandboxes (ETH and Polygon)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Installing the Data Feeds plugin and attaching the WETH/USD feed on both Sandboxes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Preparing environment variables and Foundry configs&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deploying the Bridge with Foundry and verifying via Sourcify&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Running a bi-directional relayer to detect and release assets on the destination chain&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Interacting with the bridge (WETH ⇄ USDT) and inspecting results&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;End-to-End transaction debugging with Sentio and BuildBear explorer&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;heading-project-repository&quot;&gt;Project Repository&lt;/h2&gt;
&lt;p&gt;You can either use the repository provided by us or create your own &lt;code&gt;Foundry Project&lt;/code&gt;. Here, we will use the repository that we have provided.&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://github.com/BuildBearLabs/tutorial-buildbear-datafeed-bridge&quot;&gt;GitHub - BuildBearLabs/tutorial-buildbear-datafeed-bridge: Build a minimal event-driven bridge (WETH ⇄ USDT) using Foundry and Node relayer, fully built in BuildBear Mainnet Sandboxes with the Chainlink DataFeed Plugin.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;heading-how-it-works&quot;&gt;How it Works&lt;/h3&gt;
&lt;p&gt;The following snapshots provide a quick, visual understanding of the system before diving into the code. Add your rendered-mermaid images where indicated.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;High-level sequence&lt;/p&gt;
&lt;p&gt; &lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748249085/0abc574b-5692-4775-b1d7-29844df3e4d6.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748249085/0abc574b-5692-4775-b1d7-29844df3e4d6.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748249085/0abc574b-5692-4775-b1d7-29844df3e4d6.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748249085/0abc574b-5692-4775-b1d7-29844df3e4d6.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The user approves and calls &lt;code&gt;lockAndQuote&lt;/code&gt; on the source bridge.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The bridge pulls the source token, reads WETH/USD from the data feed, computes the destination amount, and emits &lt;code&gt;BridgeRequested&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The relayer observes that event on the source chain and calls &lt;code&gt;release&lt;/code&gt; on the destination bridge with the mapped token, amount, and nonce.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The destination bridge checks the nonce, transfers tokens to the recipient, and emits &lt;code&gt;TransferReleased&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The destination side is pre-funded, and the relayer must be running for events to be processed.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Contract internals&lt;/p&gt;
&lt;p&gt; &lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748260166/24d88d6c-33e3-47c6-82ee-22af7f7911af.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748260166/24d88d6c-33e3-47c6-82ee-22af7f7911af.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748260166/24d88d6c-33e3-47c6-82ee-22af7f7911af.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748260166/24d88d6c-33e3-47c6-82ee-22af7f7911af.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Lock-and-Quote&lt;/code&gt; Functionality&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Take custody of the source token via &lt;code&gt;safeTransferFrom&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Read WETH/USD from the data feed and normalize for math.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Handle decimals and calculate the destination amount.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Emit &lt;code&gt;BridgeRequested&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Increment &lt;code&gt;nonce&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Release&lt;/code&gt; Functionality&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Enforce admin-only access.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ensure the external nonce is unused and mark it processed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Transfer tokens out to the recipient.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Emit &lt;code&gt;TransferReleased&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;heading-directory-and-project-structure&quot;&gt;Directory and Project Structure&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748277426/401062b1-8631-484b-981f-7539bf002a16.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748277426/401062b1-8631-484b-981f-7539bf002a16.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748277426/401062b1-8631-484b-981f-7539bf002a16.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748277426/401062b1-8631-484b-981f-7539bf002a16.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-create-sandboxes-and-install-plugins&quot;&gt;Create Sandboxes and Install Plugins&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Create two Mainnet Sandboxes:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ethereum Mainnet&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Polygon Mainnet&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-node-type=&quot;callout&quot;&gt;
&lt;div data-node-type=&quot;callout-emoji&quot;&gt;💡&lt;/div&gt;
&lt;div data-node-type=&quot;callout-text&quot;&gt;&lt;strong&gt;Use the code &lt;/strong&gt;&lt;code&gt;DD-BB-BLOG&lt;/code&gt;&lt;strong&gt; to receive 1 month of free BuildBear Premium. Activate your premium access from &lt;/strong&gt;&lt;a target=&quot;_self&quot; href=&quot;https://app.buildbear.io/settings/billing/?utm_source=devdao&amp;amp;utm_medium=blog&amp;amp;utm_campaign=blog-cross-chain-bridge&quot;&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; and start enjoying the benefits immediately.&lt;/strong&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Install the following plugins on both Ethereum and Polygon Mainnet Sandboxes:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Installing and configuring the Chainlink Data Feed Plugin.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Install the &quot;Chainlink Data Feed&quot; Plugin from the Plugin Marketplace.&lt;/p&gt;
&lt;p&gt;  &lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748294780/7a4e7d37-c7b2-495e-8b4c-526541ccb2be.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748294780/7a4e7d37-c7b2-495e-8b4c-526541ccb2be.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748294780/7a4e7d37-c7b2-495e-8b4c-526541ccb2be.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748294780/7a4e7d37-c7b2-495e-8b4c-526541ccb2be.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Search and Subscribe to the &quot;ETH/USD&quot; feed.&lt;/p&gt;
&lt;p&gt;  &lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748306766/28018c45-ab09-49d8-afed-0c71e0c44ed4.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748306766/28018c45-ab09-49d8-afed-0c71e0c44ed4.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748306766/28018c45-ab09-49d8-afed-0c71e0c44ed4.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748306766/28018c45-ab09-49d8-afed-0c71e0c44ed4.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once you have installed the Data-Feeds on both the Sandboxes, verify that your feed addresses match the addresses below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ethereum Mainnet (ETH/USD Feed): &lt;code&gt;0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Polygon Mainnet (ETH/USD Feed): &lt;code&gt;0xF9680D99D6C9589e2a93a78A04A279e509205945&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;You can also visit &lt;a target=&quot;_blank&quot; href=&quot;https://app.buildbear.io/data-feeds?utm_source=devdao&amp;amp;utm_medium=blog&amp;amp;utm_campaign=blog-cross-chain-bridge&quot;&gt;Chainlink Data Feed Dashboard&lt;/a&gt; to see your subscribed feeds, and add/remove feeds.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Also, install &lt;code&gt;Sentio&lt;/code&gt;, &lt;code&gt;Simbolik&lt;/code&gt; &amp;amp; &lt;code&gt;Sourcify&lt;/code&gt; Plugins from BuildBear Plugin Marketplace.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Simbolik relies on &lt;strong&gt;Sourcify-verified&lt;/strong&gt; source code to debug contracts. It currently works best for &lt;strong&gt;unoptimized contracts&lt;/strong&gt; as there can be limited debugging information and inconsistencies, with optimized builds. Support for optimized contracts is improving with Solidity’s debugging tooling.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Before running any transactions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Go to your Sandbox&apos;s &lt;strong&gt;Plugins&lt;/strong&gt; tab&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Look for &lt;strong&gt;Sourcify,&lt;/strong&gt; &lt;strong&gt;Simbolik, and Sentio&lt;/strong&gt; plugins**.**&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;Install Plugin&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748321574/c0c2d05b-e82f-4270-b9aa-74b6744e291c.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748321574/c0c2d05b-e82f-4270-b9aa-74b6744e291c.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748321574/c0c2d05b-e82f-4270-b9aa-74b6744e291c.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748321574/c0c2d05b-e82f-4270-b9aa-74b6744e291c.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748331356/23ee69e2-b670-4226-b6d9-2aaae18fe6fd.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748331356/23ee69e2-b670-4226-b6d9-2aaae18fe6fd.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748331356/23ee69e2-b670-4226-b6d9-2aaae18fe6fd.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748331356/23ee69e2-b670-4226-b6d9-2aaae18fe6fd.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-environment-variables-amp-wallet-setuphttpswwwbuildbeariodocstutorialschainlink-datafeed-bridgeutmsourcedevdaoamputmmediumblogamputmcampaignblog-cross-chain-bridgestep-2-environment-variables-wallet-setup&quot;&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.buildbear.io/docs/tutorials/chainlink-datafeed-bridge?utm_source=devdao&amp;amp;utm_medium=blog&amp;amp;utm_campaign=blog-cross-chain-bridge#step-2-environment-variables--wallet-setup&quot;&gt;Environment Variables &amp;amp; Wallet Setup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Create a basic Foundry Project, and copy &lt;code&gt;.env.example&lt;/code&gt; to &lt;code&gt;.env&lt;/code&gt; and fill in values or use the env example below. We have some values pre-filled to save you some time sleuthing for addresses. These mirror Mainnet token addresses and price feed addresses that BuildBear exposes inside the Sandboxes after the plugins are installed and configured.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;# RPC endpoints (your BuildBear Sandbox RPC URLs) &lt;/span&gt;
ETH_MAINNET_SANDBOX=&amp;lt;YOUR_ETH_MAINNET_SANDBOX_URL&amp;gt; 
POL_MAINNET_SANDBOX=&amp;lt;YOUR_POLYGON_MAINNET_SANDBOX_URL&amp;gt; 

&lt;span&gt;# Deployer/admin key &amp;amp; address &lt;/span&gt;
PRIVATE_KEY= WALLET_ADDRESS= 

&lt;span&gt;# Chainlink WETH/USD feeds (mainnet addresses) &lt;/span&gt;
MAINNET_FEED_WETH_USD=0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419
POLYGON_FEED_WETH_USD=0xF9680D99D6C9589e2a93a78A04A279e509205945 

&lt;span&gt;# Token addresses (mainnet addresses; mirrored in BuildBear Sandboxes) &lt;/span&gt;
ETH_WETH_TOKEN=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 
ETH_USDT_TOKEN=0xdAC17F958D2ee523a2206206994597C13D831ec7 
POL_WETH_TOKEN=0x7ceb23fd6bc0add59e62ac25578270cff1b9f619 
POL_USDT_TOKEN=0xc2132D05D31c914a87C6611C10748AEb04B58e8F 

&lt;span&gt;# EOA used to perform lockAndQuote &lt;/span&gt;
RECEIVER_WALLET= 
RECEIVER_PRIVATE_KEY=
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;heading-foundrytoml&quot;&gt;&lt;code&gt;foundry.toml&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;[profile.default]&lt;/span&gt;
&lt;span&gt;src&lt;/span&gt; = &lt;span&gt;&quot;src&quot;&lt;/span&gt;
&lt;span&gt;out&lt;/span&gt; = &lt;span&gt;&quot;out&quot;&lt;/span&gt;
&lt;span&gt;libs&lt;/span&gt; = [&lt;span&gt;&quot;lib&quot;&lt;/span&gt;]
&lt;span&gt;# required to dynamically read and interact with latest bridge addresses&lt;/span&gt;
&lt;span&gt;fs_permissions&lt;/span&gt; = [{ access = &lt;span&gt;&quot;read&quot;&lt;/span&gt;, path = &lt;span&gt;&quot;./broadcast/DeployBridge.s.sol/&quot;&lt;/span&gt; }]
&lt;span&gt;remappings&lt;/span&gt; = [&lt;span&gt;&apos;@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts&apos;&lt;/span&gt;]
&lt;span&gt;[rpc_endpoints]&lt;/span&gt;
&lt;span&gt;eth_mainnet_sandbox&lt;/span&gt; = &lt;span&gt;&quot;${ETH_MAINNET_SANDBOX}&quot;&lt;/span&gt;
&lt;span&gt;pol_mainnet_sandbox&lt;/span&gt; = &lt;span&gt;&quot;${POL_MAINNET_SANDBOX}&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also need some &lt;code&gt;npm packages&lt;/code&gt; for the relayer to work, refer to the &lt;code&gt;package.json&lt;/code&gt; file or put the contents below in it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &lt;span&gt;&quot;scripts&quot;&lt;/span&gt;: {
    &lt;span&gt;&quot;start&quot;&lt;/span&gt;: &lt;span&gt;&quot;npm run start-relayer&quot;&lt;/span&gt;,
    &lt;span&gt;&quot;start-relayer&quot;&lt;/span&gt;: &lt;span&gt;&quot;tsx ./relayer/index.ts&quot;&lt;/span&gt;
  },
  &lt;span&gt;&quot;dependencies&quot;&lt;/span&gt;: {
    &lt;span&gt;&quot;dotenv&quot;&lt;/span&gt;: &lt;span&gt;&quot;^16.3.1&quot;&lt;/span&gt;,
    &lt;span&gt;&quot;ethers&quot;&lt;/span&gt;: &lt;span&gt;&quot;^6.13.5&quot;&lt;/span&gt;,
    &lt;span&gt;&quot;permissionless&quot;&lt;/span&gt;: &lt;span&gt;&quot;^0.2.47&quot;&lt;/span&gt;,
    &lt;span&gt;&quot;viem&quot;&lt;/span&gt;: &lt;span&gt;&quot;^2.30.0&quot;&lt;/span&gt;
  },
  &lt;span&gt;&quot;devDependencies&quot;&lt;/span&gt;: {
    &lt;span&gt;&quot;@types/node&quot;&lt;/span&gt;: &lt;span&gt;&quot;^20.11.10&quot;&lt;/span&gt;,
    &lt;span&gt;&quot;tsx&quot;&lt;/span&gt;: &lt;span&gt;&quot;^3.13.0&quot;&lt;/span&gt;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Need a new wallet keypair? Create one with&lt;/strong&gt; &lt;code&gt;cast&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cast wallet new
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3 id=&quot;heading-funding-your-deployer-amp-receiver-wallet&quot;&gt;Funding your Deployer &amp;amp; Receiver Wallet&lt;/h3&gt;
&lt;p&gt;Once you have configured your wallets, you will need to fund your wallets with enough funds to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Cover deployment and interaction gas costs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fund the bridges while deployment from &lt;code&gt;deployer&lt;/code&gt; to the Bridge&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Requires &lt;code&gt;deployer&lt;/code&gt; to hold more than &lt;code&gt;1000&lt;/code&gt; WETH and &lt;code&gt;25000&lt;/code&gt; USDT.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fund the receiver&apos;s wallet with some &lt;code&gt;WETH&lt;/code&gt; to allow interaction with Bridge.sol and bridge the assets.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why do we need to pre-fund wallet-addresses?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The relayer&apos;s call to release funds depends on the destination bridge already holding the mapped token. Without initial liquidity, &lt;code&gt;release&lt;/code&gt; would fail due to insufficient balance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;heading-creating-contracts-amp-scripts&quot;&gt;Creating Contracts &amp;amp; Scripts&lt;/h2&gt;
&lt;h3 id=&quot;heading-bridgesol-contract&quot;&gt;&lt;code&gt;Bridge.sol&lt;/code&gt; Contract&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Roles and Storage&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;admin&lt;/code&gt;: deployer; the only permitted caller to &lt;code&gt;release&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;nonce&lt;/code&gt;: increments per request; included in &lt;code&gt;BridgeRequested&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;processedNonces&lt;/code&gt;: marks opposite-chain nonces as used to prevent re-release.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;wethToken&lt;/code&gt;, &lt;code&gt;usdtToken&lt;/code&gt;: ERC-20s handled on this chain.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;wethUsdFeed&lt;/code&gt;: Chainlink WETH/USD aggregator.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Price &amp;amp; Quotes&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;_getWethPrice()&lt;/code&gt; reads Chainlink and normalizes the result to &lt;code&gt;1e8&lt;/code&gt; decimals for stable math.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pulls &lt;code&gt;srcAmount&lt;/code&gt; in via &lt;code&gt;safeTransferFrom&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gets WETH/USD price once &amp;amp; computes &lt;code&gt;dstAmount&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Emits &lt;code&gt;BridgeRequested(...)&lt;/code&gt; and increments &lt;code&gt;nonce&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Assets Release Post-Bridging&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Triggered by the relayer with &lt;code&gt;onlyAdmin&lt;/code&gt; restriction and check for unused &lt;code&gt;processedNonces[externalChainNonce]&lt;/code&gt;, and marks it used.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Transfers &lt;code&gt;amount&lt;/code&gt; of &lt;code&gt;token&lt;/code&gt; to &lt;code&gt;to&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Emits &lt;code&gt;TransferReleased(...)&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;// SPDX-License-Identifier: MIT&lt;/span&gt;
&lt;span&gt;&lt;span&gt;pragma&lt;/span&gt; &lt;span&gt;solidity&lt;/span&gt; ^0.8.24;&lt;/span&gt;

&lt;span&gt;import&lt;/span&gt; {&lt;span&gt;IERC20&lt;/span&gt;} &lt;span&gt;&lt;span&gt;from&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&quot;@openzeppelin/contracts/token/ERC20/IERC20.sol&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; {&lt;span&gt;SafeERC20&lt;/span&gt;} &lt;span&gt;&lt;span&gt;from&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&quot;@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol&quot;&lt;/span&gt;;

&lt;span&gt;&lt;span&gt;interface&lt;/span&gt; &lt;span&gt;AggregatorV3Interface&lt;/span&gt; &lt;/span&gt;{
    &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;decimals&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;span&gt;&lt;span&gt;external&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;view&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;returns&lt;/span&gt;&lt;/span&gt; (&lt;span&gt;&lt;span&gt;uint8&lt;/span&gt;&lt;/span&gt;)&lt;/span&gt;;
    &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;latestRoundData&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;span&gt;&lt;span&gt;external&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;view&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;returns&lt;/span&gt;&lt;/span&gt; (&lt;span&gt;&lt;span&gt;uint80&lt;/span&gt;, &lt;span&gt;int256&lt;/span&gt;, &lt;span&gt;uint256&lt;/span&gt;, &lt;span&gt;uint256&lt;/span&gt;, &lt;span&gt;uint80&lt;/span&gt;&lt;/span&gt;)&lt;/span&gt;;
}

&lt;span&gt;&lt;span&gt;contract&lt;/span&gt; &lt;span&gt;Bridge&lt;/span&gt; &lt;/span&gt;{
    &lt;span&gt;using&lt;/span&gt; &lt;span&gt;SafeERC20&lt;/span&gt; &lt;span&gt;&lt;span&gt;for&lt;/span&gt;&lt;/span&gt; &lt;span&gt;IERC20&lt;/span&gt;;

    &lt;span&gt;address&lt;/span&gt; &lt;span&gt;public&lt;/span&gt; admin;
    &lt;span&gt;uint256&lt;/span&gt; &lt;span&gt;public&lt;/span&gt; nonce;
    &lt;span&gt;mapping&lt;/span&gt;(&lt;span&gt;uint256&lt;/span&gt; &lt;span&gt;=&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt; &lt;span&gt;bool&lt;/span&gt;) &lt;span&gt;public&lt;/span&gt; processedNonces;

    &lt;span&gt;address&lt;/span&gt; &lt;span&gt;public&lt;/span&gt; wethToken;
    &lt;span&gt;address&lt;/span&gt; &lt;span&gt;public&lt;/span&gt; usdtToken;
    &lt;span&gt;address&lt;/span&gt; &lt;span&gt;public&lt;/span&gt; wethUsdFeed;

    &lt;span&gt;&lt;span&gt;event&lt;/span&gt; &lt;span&gt;BridgeRequested&lt;/span&gt;(&lt;span&gt; &lt;span&gt;// still present, but will be filled by relayer mapping&lt;/span&gt;
        &lt;span&gt;address&lt;/span&gt; &lt;span&gt;indexed&lt;/span&gt; &lt;span&gt;from&lt;/span&gt;,
        &lt;span&gt;address&lt;/span&gt; &lt;span&gt;indexed&lt;/span&gt; to,
        &lt;span&gt;address&lt;/span&gt; srcToken,
        &lt;span&gt;address&lt;/span&gt; dstToken,
        &lt;span&gt;uint256&lt;/span&gt; srcAmount,
        &lt;span&gt;uint256&lt;/span&gt; dstAmount,
        &lt;span&gt;uint256&lt;/span&gt; nonce,
        &lt;span&gt;uint256&lt;/span&gt; date
    &lt;/span&gt;)&lt;/span&gt;;

    &lt;span&gt;&lt;span&gt;event&lt;/span&gt; &lt;span&gt;TransferReleased&lt;/span&gt;(&lt;span&gt;&lt;span&gt;address&lt;/span&gt; &lt;span&gt;indexed&lt;/span&gt; to, &lt;span&gt;address&lt;/span&gt; token, &lt;span&gt;uint256&lt;/span&gt; amount, &lt;span&gt;uint256&lt;/span&gt; externalChainNonce, &lt;span&gt;uint256&lt;/span&gt; date&lt;/span&gt;)&lt;/span&gt;;

    &lt;span&gt;&lt;span&gt;modifier&lt;/span&gt; &lt;span&gt;onlyAdmin&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;/span&gt;{
        &lt;span&gt;require&lt;/span&gt;(&lt;span&gt;msg&lt;/span&gt;.&lt;span&gt;sender&lt;/span&gt; &lt;span&gt;=&lt;/span&gt;&lt;span&gt;=&lt;/span&gt; admin, &lt;span&gt;&quot;Not admin&quot;&lt;/span&gt;);
        &lt;span&gt;_&lt;/span&gt;;
    }

    &lt;span&gt;&lt;span&gt;constructor&lt;/span&gt;(&lt;span&gt;&lt;span&gt;address&lt;/span&gt; _weth, &lt;span&gt;address&lt;/span&gt; _usdt, &lt;span&gt;address&lt;/span&gt; _wethUsdFeed&lt;/span&gt;) &lt;/span&gt;{
        admin &lt;span&gt;=&lt;/span&gt; &lt;span&gt;msg&lt;/span&gt;.&lt;span&gt;sender&lt;/span&gt;;
        wethToken &lt;span&gt;=&lt;/span&gt; _weth;
        usdtToken &lt;span&gt;=&lt;/span&gt; _usdt;
        wethUsdFeed &lt;span&gt;=&lt;/span&gt; _wethUsdFeed;
    }

    &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;_getWethPrice&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;span&gt;&lt;span&gt;internal&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;view&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;returns&lt;/span&gt;&lt;/span&gt; (&lt;span&gt;&lt;span&gt;uint256&lt;/span&gt;&lt;/span&gt;) &lt;/span&gt;{
        AggregatorV3Interface feed &lt;span&gt;=&lt;/span&gt; AggregatorV3Interface(wethUsdFeed);
        (, &lt;span&gt;int256&lt;/span&gt; answer,,,) &lt;span&gt;=&lt;/span&gt; feed.latestRoundData();
        &lt;span&gt;require&lt;/span&gt;(answer &lt;span&gt;&amp;gt;&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;, &lt;span&gt;&quot;invalid answer&quot;&lt;/span&gt;);

        &lt;span&gt;uint8&lt;/span&gt; dec &lt;span&gt;=&lt;/span&gt; feed.decimals();
        &lt;span&gt;uint256&lt;/span&gt; price &lt;span&gt;=&lt;/span&gt; &lt;span&gt;uint256&lt;/span&gt;(answer);

        &lt;span&gt;if&lt;/span&gt; (dec &lt;span&gt;&amp;gt;&lt;/span&gt; &lt;span&gt;8&lt;/span&gt;) price &lt;span&gt;=&lt;/span&gt; price &lt;span&gt;/&lt;/span&gt; (&lt;span&gt;10&lt;/span&gt; &lt;span&gt;*&lt;/span&gt;&lt;span&gt;*&lt;/span&gt; (dec &lt;span&gt;-&lt;/span&gt; &lt;span&gt;8&lt;/span&gt;));
        &lt;span&gt;else&lt;/span&gt; &lt;span&gt;if&lt;/span&gt; (dec &lt;span&gt;&amp;lt;&lt;/span&gt; &lt;span&gt;8&lt;/span&gt;) price &lt;span&gt;=&lt;/span&gt; price &lt;span&gt;*&lt;/span&gt; (&lt;span&gt;10&lt;/span&gt; &lt;span&gt;*&lt;/span&gt;&lt;span&gt;*&lt;/span&gt; (&lt;span&gt;8&lt;/span&gt; &lt;span&gt;-&lt;/span&gt; dec));

        &lt;span&gt;return&lt;/span&gt; price; &lt;span&gt;// 1e8&lt;/span&gt;
    }

    &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;lockAndQuote&lt;/span&gt;(&lt;span&gt;&lt;span&gt;address&lt;/span&gt; srcFromToken, &lt;span&gt;address&lt;/span&gt; srcToToken, &lt;span&gt;uint256&lt;/span&gt; srcAmount, &lt;span&gt;address&lt;/span&gt; to&lt;/span&gt;) &lt;span&gt;&lt;span&gt;external&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;{
        IERC20(srcFromToken).safeTransferFrom(&lt;span&gt;msg&lt;/span&gt;.&lt;span&gt;sender&lt;/span&gt;, &lt;span&gt;address&lt;/span&gt;(&lt;span&gt;this&lt;/span&gt;), srcAmount);

        &lt;span&gt;uint256&lt;/span&gt; dstAmount;

        &lt;span&gt;uint256&lt;/span&gt; wethPrice &lt;span&gt;=&lt;/span&gt; _getWethPrice(); &lt;span&gt;// 1e8&lt;/span&gt;

        &lt;span&gt;if&lt;/span&gt; (srcFromToken &lt;span&gt;=&lt;/span&gt;&lt;span&gt;=&lt;/span&gt; wethToken &lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt; srcToToken &lt;span&gt;=&lt;/span&gt;&lt;span&gt;=&lt;/span&gt; usdtToken) {
            &lt;span&gt;// WETH → USDT&lt;/span&gt;
            dstAmount &lt;span&gt;=&lt;/span&gt; (srcAmount &lt;span&gt;*&lt;/span&gt; wethPrice) &lt;span&gt;/&lt;/span&gt; &lt;span&gt;1e8&lt;/span&gt; &lt;span&gt;/&lt;/span&gt; &lt;span&gt;1e12&lt;/span&gt;; &lt;span&gt;// adjust 18→6 decimals&lt;/span&gt;
        } &lt;span&gt;else&lt;/span&gt; &lt;span&gt;if&lt;/span&gt; (srcFromToken &lt;span&gt;=&lt;/span&gt;&lt;span&gt;=&lt;/span&gt; usdtToken &lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt; srcToToken &lt;span&gt;=&lt;/span&gt;&lt;span&gt;=&lt;/span&gt; wethToken) {
            &lt;span&gt;// USDT → WETH&lt;/span&gt;
            dstAmount &lt;span&gt;=&lt;/span&gt; (srcAmount &lt;span&gt;*&lt;/span&gt; &lt;span&gt;1e12&lt;/span&gt; &lt;span&gt;*&lt;/span&gt; &lt;span&gt;1e8&lt;/span&gt;) &lt;span&gt;/&lt;/span&gt; wethPrice; &lt;span&gt;// adjust 6→18 decimals&lt;/span&gt;
        } &lt;span&gt;else&lt;/span&gt; {
            &lt;span&gt;revert&lt;/span&gt;(&lt;span&gt;&quot;unsupported token pair&quot;&lt;/span&gt;);
        }

        &lt;span&gt;emit&lt;/span&gt; BridgeRequested(&lt;span&gt;msg&lt;/span&gt;.&lt;span&gt;sender&lt;/span&gt;, to, srcFromToken, srcToToken, srcAmount, dstAmount, nonce, &lt;span&gt;block&lt;/span&gt;.&lt;span&gt;timestamp&lt;/span&gt;);
        nonce&lt;span&gt;+&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;;
    }

    &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;release&lt;/span&gt;(&lt;span&gt;&lt;span&gt;address&lt;/span&gt; token, &lt;span&gt;address&lt;/span&gt; to, &lt;span&gt;uint256&lt;/span&gt; amount, &lt;span&gt;uint256&lt;/span&gt; externalChainNonce&lt;/span&gt;) &lt;span&gt;&lt;span&gt;external&lt;/span&gt;&lt;/span&gt; &lt;span&gt;onlyAdmin&lt;/span&gt; &lt;/span&gt;{
        &lt;span&gt;require&lt;/span&gt;(&lt;span&gt;!&lt;/span&gt;processedNonces[externalChainNonce], &lt;span&gt;&quot;already processed&quot;&lt;/span&gt;);
        processedNonces[externalChainNonce] &lt;span&gt;=&lt;/span&gt; &lt;span&gt;true&lt;/span&gt;;

        IERC20(token).safeTransfer(to, amount);

        &lt;span&gt;emit&lt;/span&gt; TransferReleased(to, token, amount, externalChainNonce, &lt;span&gt;block&lt;/span&gt;.&lt;span&gt;timestamp&lt;/span&gt;);
    }
}

&lt;span&gt;&lt;span&gt;interface&lt;/span&gt; &lt;span&gt;IERC20Metadata&lt;/span&gt; &lt;span&gt;is&lt;/span&gt; &lt;span&gt;IERC20&lt;/span&gt; &lt;/span&gt;{
    &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;decimals&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;span&gt;&lt;span&gt;external&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;returns&lt;/span&gt;&lt;/span&gt; (&lt;span&gt;&lt;span&gt;uint8&lt;/span&gt; decimals&lt;/span&gt;)&lt;/span&gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;heading-foundry-scripts-amp-their-usage&quot;&gt;Foundry Scripts &amp;amp; Their Usage&lt;/h3&gt;
&lt;h4 id=&quot;heading-helperconfigssol&quot;&gt;&lt;code&gt;HelperConfig.s.sol&lt;/code&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Defines a &lt;code&gt;NetworkConfig&lt;/code&gt; struct that carries:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;deployerKey&lt;/code&gt; (private key pulled from env),&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;wethToken&lt;/code&gt;, &lt;code&gt;usdtToken&lt;/code&gt;,&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;wethUsdFeed&lt;/code&gt;,&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;deployer&lt;/code&gt; (EOA that will pre-fund the bridge).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Chooses &lt;code&gt;activeNetworkConfig&lt;/code&gt; based on &lt;code&gt;block.chainid&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;1&lt;/code&gt; for the Ethereum Sandbox,&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;137&lt;/code&gt; for the Polygon Sandbox.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;All addresses and keys are read, &lt;code&gt;vm.env*&lt;/code&gt; so you configure once in &lt;code&gt;.env&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When to reference it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deployment and interaction scripts are used &lt;code&gt;HelperConfig&lt;/code&gt; to get chain-specific parameters without branching logic scattered across scripts.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;// SPDX-License-Identifier: MIT&lt;/span&gt;
&lt;span&gt;&lt;span&gt;pragma&lt;/span&gt; &lt;span&gt;solidity&lt;/span&gt; ^0.8.24;&lt;/span&gt;

&lt;span&gt;import&lt;/span&gt; {&lt;span&gt;Script&lt;/span&gt;} &lt;span&gt;&lt;span&gt;from&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&quot;forge-std/Script.sol&quot;&lt;/span&gt;;

&lt;span&gt;&lt;span&gt;contract&lt;/span&gt; &lt;span&gt;HelperConfig&lt;/span&gt; &lt;span&gt;is&lt;/span&gt; &lt;span&gt;Script&lt;/span&gt; &lt;/span&gt;{
    &lt;span&gt;struct&lt;/span&gt; &lt;span&gt;NetworkConfig&lt;/span&gt; {
        &lt;span&gt;uint256&lt;/span&gt; deployerKey;
        &lt;span&gt;address&lt;/span&gt; wethToken;
        &lt;span&gt;address&lt;/span&gt; usdtToken;
        &lt;span&gt;address&lt;/span&gt; wethUsdFeed;
        &lt;span&gt;address&lt;/span&gt; deployer;
    }

    NetworkConfig &lt;span&gt;public&lt;/span&gt; activeNetworkConfig;

    &lt;span&gt;&lt;span&gt;constructor&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;/span&gt;{
        &lt;span&gt;if&lt;/span&gt; (&lt;span&gt;block&lt;/span&gt;.&lt;span&gt;chainid&lt;/span&gt; &lt;span&gt;=&lt;/span&gt;&lt;span&gt;=&lt;/span&gt; &lt;span&gt;1&lt;/span&gt;) {
            activeNetworkConfig &lt;span&gt;=&lt;/span&gt; getEthMainnetConfig();
        } &lt;span&gt;else&lt;/span&gt; &lt;span&gt;if&lt;/span&gt; (&lt;span&gt;block&lt;/span&gt;.&lt;span&gt;chainid&lt;/span&gt; &lt;span&gt;=&lt;/span&gt;&lt;span&gt;=&lt;/span&gt; &lt;span&gt;137&lt;/span&gt;) {
            activeNetworkConfig &lt;span&gt;=&lt;/span&gt; getPolygonMainnetConfig();
        } &lt;span&gt;else&lt;/span&gt; {
            &lt;span&gt;revert&lt;/span&gt;(&lt;span&gt;&quot;Unsupported network&quot;&lt;/span&gt;);
        }
    }

    &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;getEthMainnetConfig&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;view&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;returns&lt;/span&gt;&lt;/span&gt; (&lt;span&gt;NetworkConfig &lt;span&gt;memory&lt;/span&gt;&lt;/span&gt;) &lt;/span&gt;{
        &lt;span&gt;return&lt;/span&gt; NetworkConfig({
            deployerKey: vm.envUint(&lt;span&gt;&quot;PRIVATE_KEY&quot;&lt;/span&gt;),
            wethToken: vm.envAddress(&lt;span&gt;&quot;ETH_WETH_TOKEN&quot;&lt;/span&gt;), &lt;span&gt;// BuildBear faucet weth token&lt;/span&gt;
            usdtToken: vm.envAddress(&lt;span&gt;&quot;ETH_USDT_TOKEN&quot;&lt;/span&gt;), &lt;span&gt;// BuildBear faucet USDT token&lt;/span&gt;
            wethUsdFeed: vm.envAddress(&lt;span&gt;&quot;MAINNET_FEED_WETH_USD&quot;&lt;/span&gt;),
            deployer: vm.envAddress(&lt;span&gt;&quot;WALLET_ADDRESS&quot;&lt;/span&gt;)
        });
    }

    &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;getPolygonMainnetConfig&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;view&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;returns&lt;/span&gt;&lt;/span&gt; (&lt;span&gt;NetworkConfig &lt;span&gt;memory&lt;/span&gt;&lt;/span&gt;) &lt;/span&gt;{
        &lt;span&gt;return&lt;/span&gt; NetworkConfig({
            deployerKey: vm.envUint(&lt;span&gt;&quot;PRIVATE_KEY&quot;&lt;/span&gt;),
            wethToken: vm.envAddress(&lt;span&gt;&quot;POL_WETH_TOKEN&quot;&lt;/span&gt;), &lt;span&gt;// BuildBear faucet weth token&lt;/span&gt;
            usdtToken: vm.envAddress(&lt;span&gt;&quot;POL_USDT_TOKEN&quot;&lt;/span&gt;), &lt;span&gt;// BuildBear faucet USDT token&lt;/span&gt;
            wethUsdFeed: vm.envAddress(&lt;span&gt;&quot;POLYGON_FEED_WETH_USD&quot;&lt;/span&gt;),
            deployer: vm.envAddress(&lt;span&gt;&quot;WALLET_ADDRESS&quot;&lt;/span&gt;)
        });
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;heading-deploybridgessol&quot;&gt;&lt;code&gt;DeployBridge.s.sol&lt;/code&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Starts a broadcast with &lt;code&gt;deployerKey&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deploys &lt;code&gt;Bridge(wethToken, usdtToken, wethUsdFeed)&lt;/code&gt;. The deployer becomes &lt;code&gt;admin&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pre-funding from &lt;code&gt;deployer&lt;/code&gt; to the deployed bridge:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Requires &lt;code&gt;deployer&lt;/code&gt; to hold more than &lt;code&gt;1000e18&lt;/code&gt; WETH and &lt;code&gt;25_000e6&lt;/code&gt; USDT.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Transfers a fixed seed amount to the bridge (&lt;code&gt;1000e18&lt;/code&gt; WETH and &lt;code&gt;25_000e6&lt;/code&gt; USDT).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Lower or remove the &lt;code&gt;require&lt;/code&gt; thresholds to demo with smaller balances.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add more tokens or feeds by extending constructor arguments and storage.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why the pre-funding check exists?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The relayer&apos;s call to release funds depends on the destination bridge already holding the mapped token. Without initial liquidity, &lt;code&gt;release&lt;/code&gt; would fail due to insufficient balance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;// SPDX-License-Identifier: MIT&lt;/span&gt;
&lt;span&gt;&lt;span&gt;pragma&lt;/span&gt; &lt;span&gt;solidity&lt;/span&gt; ^0.8.24;&lt;/span&gt;

&lt;span&gt;import&lt;/span&gt; {&lt;span&gt;Script&lt;/span&gt;} &lt;span&gt;&lt;span&gt;from&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&quot;forge-std/Script.sol&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; {&lt;span&gt;console2&lt;/span&gt;} &lt;span&gt;&lt;span&gt;from&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&quot;forge-std/console2.sol&quot;&lt;/span&gt;;

&lt;span&gt;import&lt;/span&gt; {&lt;span&gt;HelperConfig&lt;/span&gt;} &lt;span&gt;&lt;span&gt;from&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&quot;script/HelperConfig.s.sol&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; {&lt;span&gt;Bridge&lt;/span&gt;, &lt;span&gt;IERC20&lt;/span&gt;, &lt;span&gt;SafeERC20&lt;/span&gt;} &lt;span&gt;&lt;span&gt;from&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&quot;src/Bridge.sol&quot;&lt;/span&gt;;

&lt;span&gt;&lt;span&gt;contract&lt;/span&gt; &lt;span&gt;DeployBridge&lt;/span&gt; &lt;span&gt;is&lt;/span&gt; &lt;span&gt;Script&lt;/span&gt; &lt;/span&gt;{
    &lt;span&gt;using&lt;/span&gt; &lt;span&gt;SafeERC20&lt;/span&gt; &lt;span&gt;&lt;span&gt;for&lt;/span&gt;&lt;/span&gt; &lt;span&gt;IERC20&lt;/span&gt;;

    &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;run&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;span&gt;&lt;span&gt;external&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;{
        (&lt;span&gt;uint256&lt;/span&gt; deployerKey, &lt;span&gt;address&lt;/span&gt; wethToken, &lt;span&gt;address&lt;/span&gt; usdtToken, &lt;span&gt;address&lt;/span&gt; wethUsdFeed, &lt;span&gt;address&lt;/span&gt; deployer) &lt;span&gt;=&lt;/span&gt;
            &lt;span&gt;new&lt;/span&gt; HelperConfig().activeNetworkConfig();

        vm.startBroadcast(deployerKey);

        &lt;span&gt;// Deploy bridge&lt;/span&gt;
        Bridge bridge &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; Bridge(wethToken, usdtToken, wethUsdFeed);

        &lt;span&gt;// Optionally pre-fund bridge with WETH + USDT liquidity from deployer&lt;/span&gt;
        &lt;span&gt;uint256&lt;/span&gt; wethBal &lt;span&gt;=&lt;/span&gt; IERC20(wethToken).balanceOf(deployer);
        &lt;span&gt;uint256&lt;/span&gt; usdtBal &lt;span&gt;=&lt;/span&gt; IERC20(usdtToken).balanceOf(deployer);
        &lt;span&gt;require&lt;/span&gt;(wethBal &lt;span&gt;&amp;gt;&lt;/span&gt; &lt;span&gt;1000e18&lt;/span&gt;, &lt;span&gt;&quot;Fund your account with atleast 1000 WETH tokens&quot;&lt;/span&gt;);
        &lt;span&gt;require&lt;/span&gt;(usdtBal &lt;span&gt;&amp;gt;&lt;/span&gt; &lt;span&gt;25000e6&lt;/span&gt;, &lt;span&gt;&quot;Fund your account with atleast 25000 USDT tokens&quot;&lt;/span&gt;);

        &lt;span&gt;if&lt;/span&gt; (wethBal &lt;span&gt;&amp;gt;&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;) {
            &lt;span&gt;// IERC20(wethToken).approve(address(bridge), 1000e18);&lt;/span&gt;
            IERC20(wethToken).safeTransfer(&lt;span&gt;address&lt;/span&gt;(bridge), &lt;span&gt;1000e18&lt;/span&gt;);
        }
        &lt;span&gt;if&lt;/span&gt; (usdtBal &lt;span&gt;&amp;gt;&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;) {
            &lt;span&gt;// IERC20(usdtToken).approve(address(bridge), 25000e6);&lt;/span&gt;
            IERC20(usdtToken).safeTransfer(&lt;span&gt;address&lt;/span&gt;(bridge), &lt;span&gt;25000e6&lt;/span&gt;);
        }

        vm.stopBroadcast();

        console2.log(&lt;span&gt;&quot;Bridge deployed at:&quot;&lt;/span&gt;, &lt;span&gt;address&lt;/span&gt;(bridge));
        console2.log(&lt;span&gt;&quot;WETH/USD feed:&quot;&lt;/span&gt;, wethUsdFeed);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;heading-interactbridgessol&quot;&gt;&lt;code&gt;InteractBridge.s.sol&lt;/code&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Reads the deployed bridge address for the current &lt;code&gt;block.chainid&lt;/code&gt; from &lt;code&gt;broadcast/DeployBridge.s.sol/&amp;lt;chainId&amp;gt;/run-latest.json&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Loads &lt;code&gt;wethToken&lt;/code&gt; and &lt;code&gt;usdtToken&lt;/code&gt; from &lt;code&gt;HelperConfig&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Uses &lt;code&gt;RECEIVER_WALLET&lt;/code&gt; and &lt;code&gt;RECEIVER_PRIVATE_KEY&lt;/code&gt; to send the tx.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Approves the source token, then calls &lt;code&gt;lockAndQuote(wethToken, usdtToken, 1e18, receiver)&lt;/code&gt; to perform WETH → USDT on the current chain.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Emits &lt;code&gt;BridgeRequested&lt;/code&gt;, which the relayer observes to call &lt;code&gt;release&lt;/code&gt; on the opposite chain.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For USDT → WETH, swap the token params from before and use, 6-decimals (e.g., &lt;code&gt;1000e6&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Works on chain 1 and 137 since addresses come from &lt;code&gt;HelperConfig&lt;/code&gt; and broadcast files at runtime.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;// SPDX-License-Identifier: MIT&lt;/span&gt;
&lt;span&gt;&lt;span&gt;pragma&lt;/span&gt; &lt;span&gt;solidity&lt;/span&gt; ^0.8.24;&lt;/span&gt;

&lt;span&gt;import&lt;/span&gt; {&lt;span&gt;Script&lt;/span&gt;} &lt;span&gt;&lt;span&gt;from&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&quot;forge-std/Script.sol&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; {&lt;span&gt;console2&lt;/span&gt;} &lt;span&gt;&lt;span&gt;from&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&quot;forge-std/console2.sol&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; {&lt;span&gt;Bridge&lt;/span&gt;, &lt;span&gt;IERC20&lt;/span&gt;, &lt;span&gt;SafeERC20&lt;/span&gt;} &lt;span&gt;&lt;span&gt;from&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&quot;src/Bridge.sol&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; {&lt;span&gt;HelperConfig&lt;/span&gt;} &lt;span&gt;&lt;span&gt;from&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&quot;script/HelperConfig.s.sol&quot;&lt;/span&gt;;

&lt;span&gt;&lt;span&gt;contract&lt;/span&gt; &lt;span&gt;InteractBridge&lt;/span&gt; &lt;span&gt;is&lt;/span&gt; &lt;span&gt;Script&lt;/span&gt; &lt;/span&gt;{
    &lt;span&gt;using&lt;/span&gt; &lt;span&gt;SafeERC20&lt;/span&gt; &lt;span&gt;&lt;span&gt;for&lt;/span&gt;&lt;/span&gt; &lt;span&gt;IERC20&lt;/span&gt;;

    &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;run&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;span&gt;&lt;span&gt;external&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;{
        &lt;span&gt;// Load JSON from broadcast folder (network-specific)&lt;/span&gt;
        &lt;span&gt;string&lt;/span&gt; &lt;span&gt;memory&lt;/span&gt; path &lt;span&gt;=&lt;/span&gt; &lt;span&gt;string&lt;/span&gt;.concat(
            vm.projectRoot(), &lt;span&gt;&quot;/broadcast/DeployBridge.s.sol/&quot;&lt;/span&gt;, vm.toString(&lt;span&gt;block&lt;/span&gt;.&lt;span&gt;chainid&lt;/span&gt;), &lt;span&gt;&quot;/run-latest.json&quot;&lt;/span&gt;
        );
        &lt;span&gt;string&lt;/span&gt; &lt;span&gt;memory&lt;/span&gt; json &lt;span&gt;=&lt;/span&gt; vm.readFile(path);

        &lt;span&gt;// Parse contract address from broadcast&lt;/span&gt;
        &lt;span&gt;address&lt;/span&gt; bridgeAddr &lt;span&gt;=&lt;/span&gt; &lt;span&gt;abi&lt;/span&gt;.&lt;span&gt;decode&lt;/span&gt;(vm.parseJson(json, &lt;span&gt;&quot;.transactions[0].contractAddress&quot;&lt;/span&gt;), (&lt;span&gt;address&lt;/span&gt;));
        console2.log(&lt;span&gt;&quot;Bridge found at:&quot;&lt;/span&gt;, bridgeAddr);

        Bridge bridge &lt;span&gt;=&lt;/span&gt; Bridge(bridgeAddr);

        &lt;span&gt;// Load network config&lt;/span&gt;
        (, &lt;span&gt;address&lt;/span&gt; wethToken, &lt;span&gt;address&lt;/span&gt; usdtToken,,) &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; HelperConfig().activeNetworkConfig();

        &lt;span&gt;// Wallet for interaction&lt;/span&gt;
        &lt;span&gt;address&lt;/span&gt; receiver &lt;span&gt;=&lt;/span&gt; vm.envAddress(&lt;span&gt;&quot;RECEIVER_WALLET&quot;&lt;/span&gt;);
        &lt;span&gt;uint256&lt;/span&gt; receiverKey &lt;span&gt;=&lt;/span&gt; vm.envUint(&lt;span&gt;&quot;RECEIVER_PRIVATE_KEY&quot;&lt;/span&gt;);
        console2.log(&lt;span&gt;&quot;EOA Interacting with Bridge:&quot;&lt;/span&gt;, receiver);

        &lt;span&gt;// Interact: approve WETH and call lockAndQuote&lt;/span&gt;
        vm.startBroadcast(receiverKey);

        &lt;span&gt;uint256&lt;/span&gt; amount &lt;span&gt;=&lt;/span&gt; &lt;span&gt;1e18&lt;/span&gt;; &lt;span&gt;// 1 WETH&lt;/span&gt;
        IERC20(wethToken).approve(bridgeAddr, amount);

        bridge.lockAndQuote(wethToken, usdtToken, amount, receiver);

        vm.stopBroadcast();

        console2.log(&lt;span&gt;&quot;lockAndQuote called with&quot;&lt;/span&gt;, amount, &lt;span&gt;&quot;WETH -&amp;gt; expecting USDT&quot;&lt;/span&gt;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;heading-how-do-these-scripts-work-together&quot;&gt;How do these scripts work together?&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Deploy the bridge on both Sandboxes. Each bridge has its own admin and token/feed wiring.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pre-fund both bridges with the destination tokens you expect to release.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Start the relayer. It subscribes to &lt;code&gt;BridgeRequested&lt;/code&gt; on both chains, maps tokens for the opposite chain, and calls &lt;code&gt;release&lt;/code&gt; as the admin there.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run the interaction script on the source chain. It locks tokens and emits the event. The relayer fulfills on the destination chain.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This separation keeps on-chain logic minimal and pushes cross-chain coordination into the relayer, which is appropriate for an educational, event-driven demo.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;heading-relayer&quot;&gt;Relayer&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Purpose&lt;/code&gt;: watch &lt;code&gt;BridgeRequested&lt;/code&gt; on the source chain and call &lt;code&gt;release&lt;/code&gt; on the destination chain as the bridge admin.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Setup&lt;/code&gt;: loads bridge addresses from Foundry broadcasts, creates JSON-RPC providers, and builds a signer on the destination chain using &lt;code&gt;PRIVATE_KEY&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Flow&lt;/code&gt;: poll logs for &lt;code&gt;BridgeRequested&lt;/code&gt;, parse &lt;code&gt;{to, dstToken, dstAmount, nonce}&lt;/code&gt;, map &lt;code&gt;dstToken&lt;/code&gt; via &lt;code&gt;TOKEN_MAP&lt;/code&gt;, then send &lt;code&gt;release(mappedDstToken, to, dstAmount, nonce)&lt;/code&gt; on the destination bridge.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Safety&lt;/code&gt;: destination bridge enforces one-time processing with &lt;code&gt;processedNonces[nonce]&lt;/code&gt; to prevent replay.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Requirements&lt;/code&gt;: destination bridge must hold sufficient token liquidity; the signer must be the bridge admin.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Scope&lt;/code&gt;: the shown script is one-directional (ETH to POL). To support both directions, add a second poller for Polygon and call &lt;code&gt;release&lt;/code&gt; on Ethereum with an ETH-side admin signer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Limitation&lt;/code&gt;: processes only events observed while running; no backfill of past events.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;import&lt;/span&gt; &lt;span&gt;fs&lt;/span&gt; &lt;span&gt;&lt;span&gt;from&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&quot;fs&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; &lt;span&gt;path&lt;/span&gt; &lt;span&gt;&lt;span&gt;from&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&quot;path&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; { &lt;span&gt;ethers&lt;/span&gt; } &lt;span&gt;&lt;span&gt;from&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&quot;ethers&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; &lt;span&gt;BridgeAbi&lt;/span&gt; &lt;span&gt;&lt;span&gt;from&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&quot;../out/Bridge.sol/Bridge.json&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; &lt;span&gt;&quot;dotenv/config&quot;&lt;/span&gt;;

&lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;getLatestDeployment&lt;/span&gt;(&lt;span&gt;chainId: number&lt;/span&gt;) &lt;/span&gt;{
  const filePath &lt;span&gt;=&lt;/span&gt; path.join(
    __dirname,
    `../broadcast&lt;span&gt;/&lt;/span&gt;DeployBridge.s.sol/${chainId}&lt;span&gt;/&lt;/span&gt;run&lt;span&gt;-&lt;/span&gt;latest.json`
  );
  const raw &lt;span&gt;=&lt;/span&gt; fs.readFileSync(filePath, &lt;span&gt;&quot;utf-8&quot;&lt;/span&gt;);
  const json &lt;span&gt;=&lt;/span&gt; JSON.parse(raw);
  const &lt;span&gt;tx&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; json.transactions.find((t: any) &lt;span&gt;=&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt; t.transactionType &lt;span&gt;=&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;=&lt;/span&gt; &lt;span&gt;&quot;CREATE&quot;&lt;/span&gt;);
  &lt;span&gt;if&lt;/span&gt; (&lt;span&gt;!&lt;/span&gt;&lt;span&gt;tx&lt;/span&gt;) &lt;span&gt;throw&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; &lt;span&gt;Error&lt;/span&gt;(&lt;span&gt;&quot;No CREATE transaction in broadcast file&quot;&lt;/span&gt;);
  &lt;span&gt;return&lt;/span&gt; &lt;span&gt;tx&lt;/span&gt;.contractAddress;
}

const ETH_RPC &lt;span&gt;=&lt;/span&gt; process.env.ETH_MAINNET_SANDBOX!;
const POL_RPC &lt;span&gt;=&lt;/span&gt; process.env.POL_MAINNET_SANDBOX!;
const PK &lt;span&gt;=&lt;/span&gt; process.env.PRIVATE_KEY!;

&lt;span&gt;// cross-chain token mapping&lt;/span&gt;
const TOKEN_MAP: Record&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;, &lt;span&gt;string&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; {
  [process.env.ETH_USDT_TOKEN!]: process.env.POL_USDT_TOKEN!,
  [process.env.ETH_WETH_TOKEN!]: process.env.POL_WETH_TOKEN!,
  [process.env.POL_USDT_TOKEN!]: process.env.ETH_USDT_TOKEN!,
  [process.env.POL_WETH_TOKEN!]: process.env.ETH_WETH_TOKEN!,
};

async &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;main&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;/span&gt;{
  const ethProvider &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; ethers.JsonRpcProvider(ETH_RPC);
  const polProvider &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; ethers.JsonRpcProvider(POL_RPC);
  const wallet &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; ethers.Wallet(PK, polProvider);

  const ethBridgeAddr &lt;span&gt;=&lt;/span&gt; getLatestDeployment(&lt;span&gt;1&lt;/span&gt;);
  const polBridgeAddr &lt;span&gt;=&lt;/span&gt; getLatestDeployment(&lt;span&gt;137&lt;/span&gt;);

  console.log(&lt;span&gt;&quot;ETH Bridge:&quot;&lt;/span&gt;, ethBridgeAddr);
  console.log(&lt;span&gt;&quot;POL Bridge:&quot;&lt;/span&gt;, polBridgeAddr);

  const ethBridge &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; ethers.Contract(
    ethBridgeAddr,
    BridgeAbi.abi,
    ethProvider
  );
  const polBridge &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; ethers.Contract(polBridgeAddr, BridgeAbi.abi, wallet);

  const bridgeRequestedTopic &lt;span&gt;=&lt;/span&gt; ethers.id(
    &lt;span&gt;&quot;BridgeRequested(address,address,address,address,uint256,uint256,uint256,uint256)&quot;&lt;/span&gt;
  );

  let lastProcessed &lt;span&gt;=&lt;/span&gt; await ethProvider.getBlockNumber();
  console.log(&lt;span&gt;&quot;Relayer started. Watching new events...&quot;&lt;/span&gt;);

  setInterval(async () &lt;span&gt;=&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt; {
    &lt;span&gt;try&lt;/span&gt; {
      const latestBlock &lt;span&gt;=&lt;/span&gt; await ethProvider.getBlockNumber();
      &lt;span&gt;if&lt;/span&gt; (latestBlock &lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt; lastProcessed) &lt;span&gt;return&lt;/span&gt;;

      const logs &lt;span&gt;=&lt;/span&gt; await ethProvider.getLogs({
        fromBlock: lastProcessed &lt;span&gt;+&lt;/span&gt; &lt;span&gt;1&lt;/span&gt;,
        toBlock: latestBlock,
        &lt;span&gt;address&lt;/span&gt;: ethBridgeAddr,
        topics: [bridgeRequestedTopic],
      });

      &lt;span&gt;for&lt;/span&gt; (const log of logs) {
        const parsed &lt;span&gt;=&lt;/span&gt; ethBridge.interface.parseLog(log);
        let { &lt;span&gt;from&lt;/span&gt;, to, srcToken, dstToken, srcAmount, dstAmount, nonce } &lt;span&gt;=&lt;/span&gt;
          parsed.args;

        console.log(&lt;span&gt;&quot;Detected BridgeRequested:&quot;&lt;/span&gt;);
        console.log({
          &lt;span&gt;from&lt;/span&gt;,
          to,
          srcToken,
          dstToken,
          srcAmount,
          dstAmount,
          nonce,
        });

        &lt;span&gt;// map token for destination chain&lt;/span&gt;
        const mappedDstToken &lt;span&gt;=&lt;/span&gt; TOKEN_MAP[dstToken] &lt;span&gt;|&lt;/span&gt;&lt;span&gt;|&lt;/span&gt; dstToken;

        &lt;span&gt;try&lt;/span&gt; {
          const &lt;span&gt;tx&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; await polBridge.release(
            mappedDstToken,
            to,
            dstAmount,
            nonce
          );
          console.log(&lt;span&gt;&quot;Release tx sent:&quot;&lt;/span&gt;, &lt;span&gt;tx&lt;/span&gt;.hash);
          await &lt;span&gt;tx&lt;/span&gt;.wait();
          console.log(&lt;span&gt;&quot;Release confirmed.&quot;&lt;/span&gt;);
        } &lt;span&gt;catch&lt;/span&gt; (err) {
          console.error(&lt;span&gt;&quot;Release failed:&quot;&lt;/span&gt;, err);
        }
      }

      lastProcessed &lt;span&gt;=&lt;/span&gt; latestBlock;
    } &lt;span&gt;catch&lt;/span&gt; (err) {
      console.error(&lt;span&gt;&quot;Polling error:&quot;&lt;/span&gt;, err);
    }
  }, &lt;span&gt;10_000&lt;/span&gt;);
}

main().catch(err &lt;span&gt;=&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt; {
  console.error(err);
  process.exit(&lt;span&gt;1&lt;/span&gt;);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;heading-configuring-makefile&quot;&gt;Configuring Makefile&lt;/h2&gt;
&lt;p&gt;Now with the project set up, we can configure commands in a &lt;code&gt;Makefile&lt;/code&gt; to deploy, verify and interact with bridges on different sandboxes.&lt;/p&gt;
&lt;p&gt;Put this Makefile at the project root. It installs dependencies, deploys with Sourcify verification on both Sandboxes, and provides interaction targets. It basically takes away the overhead of writing commands again and again, working with complex commands and replacing them with simpler ones.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Remember to replace the placeholders in verifier-urls below with your actual BuildBear Sandbox ID&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;.PHONY&lt;/span&gt;: make-deploy install deploy-mainnet-sourcify deploy-pol-sourcify interact-mainnet-bridge interact-pol-bridge&lt;/span&gt;

&lt;span&gt;install:&lt;/span&gt;
    forge install &amp;amp;&amp;amp; npm i &amp;amp;&amp;amp; forge build


&lt;span&gt;deploy-mainnet-sourcify:&lt;/span&gt;
    forge script script/DeployBridge.s.sol \
     --rpc-url eth_mainnet_sandbox \
     --verifier sourcify \
     --verify \
     --verifier-url https://rpc.buildbear.io/verify/sourcify/server/&amp;lt;eth-mainnet-Sandbox-id&amp;gt; \
     --broadcast \


&lt;span&gt;deploy-pol-sourcify:&lt;/span&gt;
    forge script script/DeployBridge.s.sol \
     --rpc-url pol_mainnet_sandbox \
     --verifier sourcify \
     --verify \
     --verifier-url https://rpc.buildbear.io/verify/sourcify/server/&amp;lt;polygon-mainnet-Sandbox-id&amp;gt;  \
     --broadcast \


&lt;span&gt;interact-mainnet-bridge:&lt;/span&gt;
    forge script script/InteractBridge.s.sol \
     --rpc-url eth_mainnet_sandbox \
     --broadcast \


&lt;span&gt;interact-pol-bridge:&lt;/span&gt;
    forge script script/InteractBridge.s.sol \
     --rpc-url eth_mainnet_sandbox \
     --broadcast \
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;How it is set up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;install&lt;/code&gt; installs Foundry dependencies, Node packages, and builds contracts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;deploy-mainnet-sourcify&lt;/code&gt; deploys to the ETH Sandbox and verifies via the Sourcify plugin endpoint.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;deploy-pol-sourcify&lt;/code&gt; deploys to the Polygon Sandbox and verifies via the corresponding Sourcify plugin endpoint.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;interact-mainnet-bridge&lt;/code&gt; runs your interaction script against the ETH Sandbox to bridge assets.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;interact-pol-bridge&lt;/code&gt; runs your interaction script against the Polygon Sandbox to bridge assets.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;heading-install-and-build&quot;&gt;Install and Build&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;make install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This installs Foundry dependencies into &lt;code&gt;lib&lt;/code&gt;, installs &lt;code&gt;Node dependencies&lt;/code&gt; for the relayer, and compiles the contracts.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;heading-deploy-and-verify&quot;&gt;Deploy and Verify&lt;/h2&gt;
&lt;p&gt;Deploy both bridges:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;make deploy-mainnet-sourcify deploy-pol-sourcify
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your Foundry broadcast files will include the deployed addresses. Sourcify verification will be available in the Sandbox explorer.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748367729/c0b384a8-a1a2-4792-8c8c-c32871b72120.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748367729/c0b384a8-a1a2-4792-8c8c-c32871b72120.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748367729/c0b384a8-a1a2-4792-8c8c-c32871b72120.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748367729/c0b384a8-a1a2-4792-8c8c-c32871b72120.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pre-funding note from your deploy script&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Ensure the deployer wallet has sufficient WETH and USDT in both Sandboxes for the seed transfers. Adjust or remove the &lt;code&gt;require&lt;/code&gt; checks inside the script if you want smaller demo amounts.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;heading-start-the-relayer&quot;&gt;Start the Relayer&lt;/h2&gt;
&lt;p&gt;Remember to install the dependencies as mentioned before, and run the relayer:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748378634/e4b02aab-9584-4dff-913e-1d7122056b20.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748378634/e4b02aab-9584-4dff-913e-1d7122056b20.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748378634/e4b02aab-9584-4dff-913e-1d7122056b20.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748378634/e4b02aab-9584-4dff-913e-1d7122056b20.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This relayer processes only those events that occur while it is running. Backfill isn&apos;t supported, by the script for the purpose of simplicity and ease of implementation&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;heading-interact-and-bridge-the-assets&quot;&gt;Interact and Bridge the Assets&lt;/h2&gt;
&lt;p&gt;ETH to Polygon Bridging:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Remember to start the relayer before you call the Interact-Bridge Script on either of the Sandboxes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While the relayer is running, in another terminal, execute an interaction with the bridge&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;# This will emit a bridge request from ETH ---&amp;gt; Polygon for WETH to USDT&lt;/span&gt;
make interact-mainnet-bridge
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Script Broadcast&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748400850/77d1038c-7a1c-4ec3-b93d-91ab03ab017c.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748400850/77d1038c-7a1c-4ec3-b93d-91ab03ab017c.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748400850/77d1038c-7a1c-4ec3-b93d-91ab03ab017c.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748400850/77d1038c-7a1c-4ec3-b93d-91ab03ab017c.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tx on BuildBear Explorer&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748404632/781dcaff-6213-4c60-89a6-9ac1e44967aa.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748404632/781dcaff-6213-4c60-89a6-9ac1e44967aa.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748404632/781dcaff-6213-4c60-89a6-9ac1e44967aa.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748404632/781dcaff-6213-4c60-89a6-9ac1e44967aa.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Your interaction script reads the last deployment address from Foundry broadcasts, approves the source token, and calls &lt;code&gt;lockAndQuote&lt;/code&gt;. The relayer observes the &lt;code&gt;BridgeRequested&lt;/code&gt; event on the source chain and calls &lt;code&gt;release&lt;/code&gt; on the destination bridge.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In the output below, the relayer captured the &lt;code&gt;BridgeRequested(...)&lt;/code&gt; event and released the asset on the Polygon Mainnet Sandbox&lt;/p&gt;
&lt;p&gt;  &lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748425495/fefd66d6-56cf-4815-9c70-d2bf7be80fb2.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748425495/fefd66d6-56cf-4815-9c70-d2bf7be80fb2.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748425495/fefd66d6-56cf-4815-9c70-d2bf7be80fb2.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748425495/fefd66d6-56cf-4815-9c70-d2bf7be80fb2.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Asset release tx on Polygon Mainnet Sandbox&lt;/p&gt;
&lt;p&gt;  &lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748430314/f06f69fd-5479-4fc7-acc6-65d8bb7fc994.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748430314/f06f69fd-5479-4fc7-acc6-65d8bb7fc994.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748430314/f06f69fd-5479-4fc7-acc6-65d8bb7fc994.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748430314/f06f69fd-5479-4fc7-acc6-65d8bb7fc994.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;heading-transaction-debugging-with-the-sentio-plugin&quot;&gt;Transaction Debugging with the Sentio Plugin&lt;/h2&gt;
&lt;p&gt;This section is optional and shows how to inspect an end-to-end transfer using the explorer and Sentio. For the Sentio Debugger to work, you will need to install the &lt;code&gt;Sentio Plugin&lt;/code&gt; from BuildBear Plugin Marketplace&lt;/p&gt;
&lt;h3 id=&quot;heading-source-bridging-tx&quot;&gt;Source: Bridging Tx&lt;/h3&gt;
&lt;p&gt;Open the source Sandbox explorer.&lt;/p&gt;
&lt;p&gt;Find the tx hash for the interaction with &lt;code&gt;lockAndQuote&lt;/code&gt;, on the bridge contract.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748443542/09533b84-b044-47d6-8da4-063fb06134ec.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748443542/09533b84-b044-47d6-8da4-063fb06134ec.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748443542/09533b84-b044-47d6-8da4-063fb06134ec.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748443542/09533b84-b044-47d6-8da4-063fb06134ec.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Click on &lt;strong&gt;View Trace on Sentio&lt;/strong&gt;.&lt;/p&gt;
&lt;h4 id=&quot;heading-fund-flow&quot;&gt;Fund Flow&lt;/h4&gt;
&lt;p&gt;A visual map of token movement for the source transaction. Use it to confirm &lt;code&gt;transferFrom&lt;/code&gt; into the bridge and any intermediate ERC20 flows.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748454803/aec96bfe-390b-4052-bb53-6ce60a15aa15.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748454803/aec96bfe-390b-4052-bb53-6ce60a15aa15.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748454803/aec96bfe-390b-4052-bb53-6ce60a15aa15.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748454803/aec96bfe-390b-4052-bb53-6ce60a15aa15.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;heading-call-trace&quot;&gt;Call Trace&lt;/h4&gt;
&lt;p&gt;A step-by-step execution trace. Helpful to see the call into &lt;code&gt;lockAndQuote&lt;/code&gt;, the oracle read, and the event emission order.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748468216/cdb1a365-6bc7-47d9-a304-5c27c66a04b2.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748468216/cdb1a365-6bc7-47d9-a304-5c27c66a04b2.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748468216/cdb1a365-6bc7-47d9-a304-5c27c66a04b2.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748468216/cdb1a365-6bc7-47d9-a304-5c27c66a04b2.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;heading-call-graph&quot;&gt;Call Graph&lt;/h4&gt;
&lt;p&gt;Graph view of calls across contracts during the source transaction. Useful for understanding the sequence and flow of internal calls.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748491458/2a76827d-1c91-4123-9db0-502ec63af92b.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748491458/2a76827d-1c91-4123-9db0-502ec63af92b.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748491458/2a76827d-1c91-4123-9db0-502ec63af92b.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748491458/2a76827d-1c91-4123-9db0-502ec63af92b.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;heading-events-tab&quot;&gt;Events Tab&lt;/h4&gt;
&lt;p&gt;Structured list of emitted events. Verify &lt;code&gt;BridgeRequested&lt;/code&gt; fields such as &lt;code&gt;srcToken&lt;/code&gt;, &lt;code&gt;dstToken&lt;/code&gt;, &lt;code&gt;dstAmount&lt;/code&gt;, and &lt;code&gt;nonce&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748505106/a95bc41b-2187-4c99-aa4e-08eb584b8c6c.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748505106/a95bc41b-2187-4c99-aa4e-08eb584b8c6c.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748505106/a95bc41b-2187-4c99-aa4e-08eb584b8c6c.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748505106/a95bc41b-2187-4c99-aa4e-08eb584b8c6c.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;heading-state-tab&quot;&gt;State Tab&lt;/h4&gt;
&lt;p&gt;Storage and variable snapshots at key points. Useful for checking &lt;code&gt;nonce&lt;/code&gt; increments and any flags written during the call.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748523013/81f68a85-86c5-425b-b42e-38d2fde3aef8.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748523013/81f68a85-86c5-425b-b42e-38d2fde3aef8.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748523013/81f68a85-86c5-425b-b42e-38d2fde3aef8.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748523013/81f68a85-86c5-425b-b42e-38d2fde3aef8.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;heading-destination-release-tx&quot;&gt;Destination: Release Tx&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Open the destination Sandbox Explorer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Find the relayer &lt;code&gt;release&lt;/code&gt; transaction on the bridge contract that transfers assets from the bridge to the &lt;code&gt;receiver&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748546765/cea67143-2c1c-4b06-bf8f-4a5ddc2f276d.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748546765/cea67143-2c1c-4b06-bf8f-4a5ddc2f276d.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748546765/cea67143-2c1c-4b06-bf8f-4a5ddc2f276d.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748546765/cea67143-2c1c-4b06-bf8f-4a5ddc2f276d.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on &lt;strong&gt;View Trace on Sentio.&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;heading-fund-flow-1&quot;&gt;Fund Flow&lt;/h4&gt;
&lt;p&gt;Shows token movement out of the bridge to the receiver. Use it to confirm the final ERC20 transfer with the expected amount.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748570897/93415e47-140b-4c1f-a9d5-e7d224d67c45.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748570897/93415e47-140b-4c1f-a9d5-e7d224d67c45.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748570897/93415e47-140b-4c1f-a9d5-e7d224d67c45.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748570897/93415e47-140b-4c1f-a9d5-e7d224d67c45.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;heading-call-trace-1&quot;&gt;Call Trace&lt;/h4&gt;
&lt;p&gt;Execution path for the &lt;code&gt;release&lt;/code&gt; call by the relayer. Check the nonce processing and the order of effects before the transfer.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748599799/96480967-06fc-46d3-b327-fcb6f742fa60.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748599799/96480967-06fc-46d3-b327-fcb6f742fa60.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748599799/96480967-06fc-46d3-b327-fcb6f742fa60.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748599799/96480967-06fc-46d3-b327-fcb6f742fa60.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;heading-call-graph-1&quot;&gt;Call Graph&lt;/h4&gt;
&lt;p&gt;Graph view of the destination call sequence during &lt;code&gt;release&lt;/code&gt;. Helps verify checks, effects, interactions, ordering, and the final token transfer.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748620949/968faf41-86ff-42d0-b3fc-8b1ef9dac4be.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748620949/968faf41-86ff-42d0-b3fc-8b1ef9dac4be.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748620949/968faf41-86ff-42d0-b3fc-8b1ef9dac4be.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748620949/968faf41-86ff-42d0-b3fc-8b1ef9dac4be.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;heading-events-tab-1&quot;&gt;Events Tab&lt;/h4&gt;
&lt;p&gt;Verify &lt;code&gt;TransferReleased&lt;/code&gt; with the same external nonce used on the source chain, along with token and amount fields.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748634135/fba1f475-e218-4d1d-8bdc-585b04a1daad.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748634135/fba1f475-e218-4d1d-8bdc-585b04a1daad.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748634135/fba1f475-e218-4d1d-8bdc-585b04a1daad.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748634135/fba1f475-e218-4d1d-8bdc-585b04a1daad.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;heading-state-tab-1&quot;&gt;State Tab&lt;/h4&gt;
&lt;p&gt;Inspect &lt;code&gt;processedNonces&lt;/code&gt; and any relevant balances after the transfer to ensure idempotence and correct accounting.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748644668/4f03811c-094b-45a4-a3b7-166c83e0a512.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1759748644668/4f03811c-094b-45a4-a3b7-166c83e0a512.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748644668/4f03811c-094b-45a4-a3b7-166c83e0a512.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1759748644668/4f03811c-094b-45a4-a3b7-166c83e0a512.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;That’s it. You now have a minimal, event-driven cross-chain bridge running end-to-end in BuildBear Mainnet Sandboxes. You can extend this demo by adding multi-sig relayers, accounting, fees, slippage controls, and stronger verification models.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;You have now set up a minimal, event-driven bridge in BuildBear that uses BuildBear’s Data Feeds Plugin for price quoting, verifies via Sourcify Plugin, and can be traced and debugged in Sentio Plugin, all in BuildBear&apos;s Sandbox environment.&lt;/p&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Exploring Quantum Biology: A New Frontier in Science with Dr. Clarice D. Aiello</title>
    <link href="https://blog.developerdao.com/exploring-quantum-biology-a-new-frontier-in-science-with-dr-clarice-d-aiello"/>
    <id>https://blog.developerdao.com/exploring-quantum-biology-a-new-frontier-in-science-with-dr-clarice-d-aiello</id>
    <updated>2025-09-15T01:15:17.480Z</updated>
    <author><name>Narbeh Shahnazarian</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1757898656721/14334d87-c64b-4b83-8628-67afd2a975d5.png?width=600&amp;format=auto"/>
    <summary>In a world where science continuously pushes the boundaries of what we know, quantum biology emerges as a fascinating and profound field of study. In a recent episode of DevNTell, Narb introduced us to a captivating conversation with Dr. Clarice D. A...</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1757898656721/14334d87-c64b-4b83-8628-67afd2a975d5.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1757898656721/14334d87-c64b-4b83-8628-67afd2a975d5.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1757898656721/14334d87-c64b-4b83-8628-67afd2a975d5.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1757898656721/14334d87-c64b-4b83-8628-67afd2a975d5.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;p&gt;In a world where science continuously pushes the boundaries of what we know, quantum biology emerges as a fascinating and profound field of study. In a recent episode of DevNTell, Narb introduced us to a captivating conversation with Dr. Clarice D. Aiello from the Quantum Biology Institute. If you ever wondered about the possible intersections of quantum physics and biology, this episode provides remarkable insights.&lt;/p&gt;
&lt;h2 id=&quot;heading-intro-to-dr-aiellos-background&quot;&gt;Intro to Dr. Aiello’s Background&lt;/h2&gt;
&lt;p&gt;In the episode Dr. Aiello shared her journey from Brazil, through quantum physics training, to spearheading the Quantum Biology Institute in the United States. This multidisciplinary field probes the extent to which biology might utilize quantum mechanics. It&apos;s a thrilling consideration: tiny events at the molecular level could influence broader biological processes. The institute aims to prove or refute whether biology truly operates on quantum principles, potentially revolutionizing our understanding and approach to science and technology.&lt;/p&gt;
&lt;h2 id=&quot;heading-quantum-biology-bridging-disciplines&quot;&gt;&lt;strong&gt;Quantum Biology: Bridging Disciplines&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Quantum biology is not merely theoretical. The field explores how biological systems might harness quantum phenomena like superposition to function. Such ideas aren&apos;t entirely new, as they&apos;ve been suggested since 1978. Despite the intriguing possibilities, quantum biology has yet to hit the mainstream due to challenges in funding and research resources. Traditional evidence has been largely correlative, coming from either test tubes or broad biological observations.&lt;/p&gt;
&lt;p&gt;Dr. Aiello emphasized the need for advanced instruments to explore these phenomena at the cellular level. These instruments serve as &quot;glorified microscopes&quot; with quantum capabilities, aiming to provide causal data that could firmly establish quantum biology.&lt;/p&gt;
&lt;h2 id=&quot;heading-transformative-implications-of-quantum-biology&quot;&gt;&lt;strong&gt;Transformative Implications of Quantum Biology&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The applications for the research the institute is doing could be far-reaching. From medical therapies using weak magnetic fields to environmental and technological innovations, the potential impact is vast. Dr. Aiello envisions a future where treatments can be non-invasive and cost-effective, possibly accessed through something as ubiquitous as a smartphone. This approach could reshape medicine, offering solutions for conditions ranging from cancer to reproductive health.&lt;/p&gt;
&lt;p&gt;She also pointed to the implications for space exploration. As humanity looks to other planets like Mars, understanding how living organisms interact with magnetic fields becomes crucial. If life on Earth is attuned to our planet&apos;s magnetic field, what does that mean for biomagnets&apos; potential roles in other environments?&lt;/p&gt;
&lt;h2 id=&quot;heading-collaboration-and-innovation-the-future-of-quantum-biology&quot;&gt;&lt;strong&gt;Collaboration and Innovation: The Future of Quantum Biology&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Continuous collaboration among quantum physicists, chemists, and biologists is essential for progressing in this novel field. Despite obstacles like underfunding and skepticism, the Quantum Biology Institute is pioneering in its efforts, supported by a decentralized autonomous organization (DAO). They are set to launch a quantum biology incubator to further develop technology in this area.&lt;/p&gt;
&lt;p&gt;Dr. Aiello also highlighted a significant effort to share the institute&apos;s research openly online, which could democratize access to their groundbreaking work and inspire further collaboration worldwide.&lt;/p&gt;
&lt;h2 id=&quot;heading-closing-thoughts&quot;&gt;Closing Thoughts&lt;/h2&gt;
&lt;p&gt;Quantum biology stands as a beacon of scientific potential, aiming to illuminate unknown facets of how life operates. Dr. Aiello’s work at the Quantum Biology Institute invites us to rethink our understanding of life’s complexity. By probing the fundamental connections between quantum mechanics and biological processes, we may uncover new paradigms that drive future scientific and technological innovations.&lt;/p&gt;
&lt;h2 id=&quot;heading-links-and-resources&quot;&gt;Links and Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://open.spotify.com/episode/4pnFsiMtNghOv2foZwXlYV?si=e50b0a9c49f24bef&quot;&gt;Watch the full episode on Spotify&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://podcasts.apple.com/us/podcast/ep-185-decoding-life-through-quantum-science-with/id1773023025?i=1000726557060&quot;&gt;Listen to the full episode on Apple Podcasts&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.youtube.com/watch?v=NS4xIf5ZA1Y&quot;&gt;Watch the full episode on YouTube&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://pods.media/devntell/devntell-decoding-life-through-quantum-science-with-the-quantum-biology-institute-feat-dr-clarice-d-aiello?referrer=0x9934f8CcFdF5E008aC8c07bf00582A833cd33b99&quot;&gt;Mint the episode on Pods&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.quantumbiology.org/&quot;&gt;Quantum Biology Institute&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;http://bit.ly/MFEbiology&quot;&gt;Biological Effects on Magnetic Fields&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Announcing the D_D DevConnect Giveaway</title>
    <link href="https://blog.developerdao.com/announcing-the-dd-devconnect-giveaway"/>
    <id>https://blog.developerdao.com/announcing-the-dd-devconnect-giveaway</id>
    <updated>2025-09-12T17:40:44.749Z</updated>
    <author><name>Narbeh Shahnazarian</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1757622945890/8f8106e7-4a77-48be-ac0d-6af884895c8f.png?width=600&amp;format=auto"/>
    <summary>With the latest proposal passing in the DAO snapshot vote, we are locked, loaded and ready to revitalize what made Developer DAO great by helping send 3 active contributors to DevConnect with up to $2000 each. We wanted to bring back that “build web3...</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1757622945890/8f8106e7-4a77-48be-ac0d-6af884895c8f.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1757622945890/8f8106e7-4a77-48be-ac0d-6af884895c8f.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1757622945890/8f8106e7-4a77-48be-ac0d-6af884895c8f.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1757622945890/8f8106e7-4a77-48be-ac0d-6af884895c8f.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;p&gt;With the &lt;a target=&quot;_blank&quot; href=&quot;https://forum.developerdao.com/t/devconnect-funding-proposal/3371&quot;&gt;latest proposal&lt;/a&gt; passing in the DAO &lt;a target=&quot;_blank&quot; href=&quot;https://snapshot.box/#/s:devdao.eth/proposal/0xa777635e400e5f9bc63b46aa9ed5f008eb4ed66340fcc1c81b776c57ce3cbc11&quot;&gt;snapshot vote&lt;/a&gt;, we are locked, loaded and ready to revitalize what made Developer DAO great by helping send 3 active contributors to &lt;a target=&quot;_blank&quot; href=&quot;https://devconnect.org/&quot;&gt;DevConnect&lt;/a&gt; with up to $2000 each. We wanted to bring back that “build web3 with friends” vibe that arguably made D_D one of the best developer communities in the ecosystem. Many people who’ve come through the DAO have gone on to have incredible careers, founded multi-million dollar companies and most important of all, made great human connections along the way. Whether chilling in VC5 or hanging out at a global crypto conference, the vibes have always been immaculate which is why we’re looking to help send 3 of the most active members in the community to DevConnect. Who knows, maybe you’ll hack your way to a new job or start a new company 👀&lt;/p&gt;
&lt;h2 id=&quot;heading-important-dates&quot;&gt;Important Dates&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Giveaway Submission Deadline&lt;/strong&gt;: October 24th, 2025&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Winner Selection:&lt;/strong&gt; Winners will be announced and contacted the week of Oct 31st, 2025 and distribution of funds will follow&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Note&lt;/strong&gt;: Winners will need to submit proof they can attend and provide some level of KYC&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DevConnect&lt;/strong&gt;: November 17-22, 2025&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;D_D IRL event at DevConnect: TBA but be sure to &lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/events&quot;&gt;subscribe&lt;/a&gt; to our Luma Events page to hear about it first&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;heading-how-to-enter-the-giveaway&quot;&gt;How to Enter the Giveaway&lt;/h2&gt;
&lt;p&gt;Simply sign up for the giveaway using the following form:&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/devconnect-2025&quot;&gt;https://devdao.to/devconnect-2025&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;After you sign up you’ll see a unique referral link be shown to you which you can share with your friends to get you more points when they sign up for the giveaway. So be sure to reach out to your old D_D buddies to refer them to sign up as well! The more referrals you get, the more points you’ll collect which will be taken in consideration in our scoring system when we pick winners.&lt;/p&gt;
&lt;h2 id=&quot;heading-how-to-participate-and-win&quot;&gt;How to Participate and Win&lt;/h2&gt;
&lt;p&gt;While the referral points will help your case, it won’t be enough. To really solidify your odds you need to show that you’re an active member of the community with a curated list of D_D related participation activities (see below) that we’ll take into consideration. There is a scoring system behind all of this with all the activities listed below providing scoring points; however, there are some activities that are worth more points then others (e.g. creating tutorial content). In the same vein you don’t want lose out on points for low hanging fruit activities like following social accounts, subscribing to the newsletter, luma events page, minting DevNTell episodes, etc..&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The full points system will be revealed at a later date&lt;/p&gt;
&lt;p&gt;The more you participate, the more points you’ll earn and more likely it will be that you’ll get selected (past participation also counts)&lt;/p&gt;
&lt;h3 id=&quot;heading-participation-activities&quot;&gt;Participation Activities&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;General DAO participation&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Making &lt;strong&gt;high quality&lt;/strong&gt; tutorial content to help educate others (this is the embodiment of the DAO and what brought a lot of us together in the first place)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Doesn’t have to be web3/protocol specific, can span the broad range of tech (AI, infra, system design, etc…)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid strictly AI generated content; however, that’s not to say you can’t use AI to help refine/fine-tune your &lt;strong&gt;original&lt;/strong&gt; work&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Written (blog, X thread, etc…), Video format (YouTube, X video, etc…), GitHub repos, etc…&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once you’ve created the content be sure to share it on X and tag the &lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/twitter&quot;&gt;DAO’s X Account&lt;/a&gt; so we know about it (and can amplify it)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Being a D_D member (being a holder of CODE tokens and/or the D4R NFT)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Voting for snapshots&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/governance-forum&quot;&gt;Participating in proposals in our forum&lt;/a&gt; (writing them or providing useful feedback to others)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Following the &lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/twitter&quot;&gt;DAO’s X Account&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/newsletter&quot;&gt;Subscribing&lt;/a&gt; to the Probably Nothing Newsletter&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/youtube&quot;&gt;Subscribing&lt;/a&gt; to the DAO’s YouTube Channel&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://cloud.developerdao.com/&quot;&gt;&lt;strong&gt;D_D Cloud&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;Participation&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Signing up for the &lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/rpc-waitlist&quot;&gt;D_D Cloud waitlist&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Following the &lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/cloud-x&quot;&gt;Futex Labs account on X&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.devntell.com&quot;&gt;DevNTell&lt;/a&gt; Participation&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/dvt-pods&quot;&gt;Minting episodes for free&lt;/a&gt; on the Pods platform&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To mint an episode, visit the &lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/dvt-pods&quot;&gt;DevNTell profile on Pods&lt;/a&gt;, connect your wallet and choose the episode you want to mint. Mints are free except for a small platform fee charged by the Pods platform. Mint your favourite episodes and see where you rank on their native leaderboard!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/events&quot;&gt;Subscribing&lt;/a&gt; to on our Luma Events page&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Being a past (or future) guest on the podcast&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Follow the &lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/dvt-x&quot;&gt;DevNTell account on X&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Follow the DevNTell account on &lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/dvt-instagram&quot;&gt;Instagram&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Follow the DevNTell account on &lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/dvt-tiktok&quot;&gt;TikTok&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Good luck and looking forward to rekindling what made D_D such an amazing community to begin with!&lt;/p&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Building on Bitcoin Layers With the Hiro Platform</title>
    <link href="https://blog.developerdao.com/building-on-bitcoin-layers-with-the-hiro-platform"/>
    <id>https://blog.developerdao.com/building-on-bitcoin-layers-with-the-hiro-platform</id>
    <updated>2024-04-16T22:00:00.000Z</updated>
    <author><name>Ϗ</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1712227564078/85f5c303-d030-4057-b87f-63a3b28cb2ed.jpeg?width=600&amp;format=auto"/>
    <summary>Bitcoin is the highest-valued token on the planet, but building on the Bitcoin network was a hassle in the past; as the first blockchain, its support for smart contract development and apps was very basic. This changed with the rise of Bitcoin layer-...</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1712227564078/85f5c303-d030-4057-b87f-63a3b28cb2ed.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1712227564078/85f5c303-d030-4057-b87f-63a3b28cb2ed.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1712227564078/85f5c303-d030-4057-b87f-63a3b28cb2ed.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1712227564078/85f5c303-d030-4057-b87f-63a3b28cb2ed.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;p&gt;Bitcoin is the highest-valued token on the planet, but building on the Bitcoin network was a hassle in the past; as the first blockchain, its support for smart contract development and apps was very basic. This changed with the rise of Bitcoin layer-2 networks like &lt;a target=&quot;_blank&quot; href=&quot;https://www.stacks.co/&quot;&gt;Stacks&lt;/a&gt;, which come with powerful smart contract platforms. &lt;/p&gt;
&lt;p&gt;In the previous article, you learned the differences between Solidity and Clarity, the programming language used on Stacks. In this article, you will learn how to build smart contracts with Clarity on Stacks and send contract events to a web server with the Chainhook service. All powered by &lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/hiro-signup&quot;&gt;the Hiro Platform&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you prefer video, check out our workshop with Hiro &lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/hiro-ws-2&quot;&gt;on YouTube&lt;/a&gt;; it contains the same content.&lt;/p&gt;
&lt;h2 id=&quot;heading-prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/leather-wallet&quot;&gt;A Bitcoin wallet&lt;/a&gt; that can interact with the Stacks network.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://explorer.hiro.so/sandbox/faucet?chain=testnet&amp;amp;api=https://api.nakamoto.testnet.hiro.so&quot;&gt;Stacks testnet tokens&lt;/a&gt; to pay for the deployments.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/hiro-signup&quot;&gt;A Hiro account&lt;/a&gt; to use the Platform IDE.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://nodejs.org/en/download&quot;&gt;Node.js&lt;/a&gt; to run a server that can handle webhooks.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;heading-setting-up-a-hiro-platform-project&quot;&gt;Setting Up a Hiro Platform Project&lt;/h2&gt;
&lt;p&gt;To create a contract, you must create a new project on the Hiro Platform. To do so, &lt;a target=&quot;_blank&quot; href=&quot;https://platform.hiro.so/projects&quot;&gt;open the Platform&lt;/a&gt;, click “Create Project,” and select “Blank Project”. The Platform will automatically open the project after creation.&lt;/p&gt;
&lt;p&gt;The Hiro Platform is the Stacks equivalent to the Remix IDE for Ethereum. It comes preinstalled with all the CLI tools you need for development on Stacks and uses OpenVSCode Server, which is a familiar IDE to most developers.&lt;/p&gt;
&lt;h2 id=&quot;heading-building-smart-contracts-on-stacks&quot;&gt;Building Smart Contracts on Stacks&lt;/h2&gt;
&lt;p&gt;We will start with the smart contracts. You’ll build your own token, a swap contract for that token, and then leverage a chainhook to listen for contract deployments.&lt;/p&gt;
&lt;p&gt;The “Open in Web Editor” button will create a new contract for you and open it in a browser IDE.&lt;/p&gt;
&lt;h3 id=&quot;heading-creating-a-fungible-token-trait&quot;&gt;Creating a Fungible Token Trait&lt;/h3&gt;
&lt;p&gt;To create a token contract, we need a trait. This trait defines the function signatures our contract needs to implement to become a SIP-10 token contract (i.e., the Stacks equivalent of ERC-20 contracts on Ethereum). &lt;/p&gt;
&lt;p&gt;A trait in Clarity is like an interface in Solidity. In contrast to Solidity, which uses the NPM package manager to install libraries like OpenZeppelin, which helps with contract creation, you need to copy traits manually from templates. The code for SIP token standards is &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/stacksgov/sips/tree/main/sips&quot;&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To create the trait, you open a new terminal, as seen in Figure 1, and execute the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;clarinet contract new sip10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output should look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Created file contracts/sip10.clar
Created file tests/sip10.test.ts
Updated Clarinet.toml with contract sip10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://lh7-us.googleusercontent.com/rRaoFIRMeNx7tTPlhyreuGhxJtrF-UNKO-FVdXd8SL7ERAO0FG92u7W0849BgqI32wP_sdpAdgwj3RLgAx_w-X1AmTKQ4sS424Wdc9hJC1sIEcKeZicYUMtI_6xvES9ImPNzAY5i3rrLdE2i_W2QLyI?width=1400&amp;auto=format&quot; srcset=&quot;https://lh7-us.googleusercontent.com/rRaoFIRMeNx7tTPlhyreuGhxJtrF-UNKO-FVdXd8SL7ERAO0FG92u7W0849BgqI32wP_sdpAdgwj3RLgAx_w-X1AmTKQ4sS424Wdc9hJC1sIEcKeZicYUMtI_6xvES9ImPNzAY5i3rrLdE2i_W2QLyI?width=700&amp;auto=format&amp;dpr=1 1x, https://lh7-us.googleusercontent.com/rRaoFIRMeNx7tTPlhyreuGhxJtrF-UNKO-FVdXd8SL7ERAO0FG92u7W0849BgqI32wP_sdpAdgwj3RLgAx_w-X1AmTKQ4sS424Wdc9hJC1sIEcKeZicYUMtI_6xvES9ImPNzAY5i3rrLdE2i_W2QLyI?width=700&amp;auto=format&amp;dpr=2 2x, https://lh7-us.googleusercontent.com/rRaoFIRMeNx7tTPlhyreuGhxJtrF-UNKO-FVdXd8SL7ERAO0FG92u7W0849BgqI32wP_sdpAdgwj3RLgAx_w-X1AmTKQ4sS424Wdc9hJC1sIEcKeZicYUMtI_6xvES9ImPNzAY5i3rrLdE2i_W2QLyI?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 1: Open terminal&lt;/p&gt;
&lt;p&gt;After the command completes, you will have a new &lt;code&gt;contracts/sip10.clar&lt;/code&gt; file. Open it and replace its content with this code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;define-trait&lt;/span&gt; sip-010-trait
  (
    (&lt;span&gt;transfer&lt;/span&gt; (&lt;span&gt;uint&lt;/span&gt; principal principal (&lt;span&gt;optional&lt;/span&gt; (&lt;span&gt;buff&lt;/span&gt; &lt;span&gt;34&lt;/span&gt;))) (&lt;span&gt;response&lt;/span&gt; bool uint))
    (&lt;span&gt;get-name&lt;/span&gt; () (&lt;span&gt;response&lt;/span&gt; (&lt;span&gt;string-ascii&lt;/span&gt; &lt;span&gt;32&lt;/span&gt;) uint))
    (&lt;span&gt;get-symbol&lt;/span&gt; () (&lt;span&gt;response&lt;/span&gt; (&lt;span&gt;string-ascii&lt;/span&gt; &lt;span&gt;32&lt;/span&gt;) uint))
    (&lt;span&gt;get-decimals&lt;/span&gt; () (&lt;span&gt;response&lt;/span&gt; uint uint))
    (&lt;span&gt;get-balance&lt;/span&gt; (&lt;span&gt;principal&lt;/span&gt;) (&lt;span&gt;response&lt;/span&gt; uint uint))
    (&lt;span&gt;get-total-supply&lt;/span&gt; () (&lt;span&gt;response&lt;/span&gt; uint uint))
    (&lt;span&gt;get-token-uri&lt;/span&gt; () (&lt;span&gt;response&lt;/span&gt; (&lt;span&gt;optional&lt;/span&gt; (&lt;span&gt;string-utf8&lt;/span&gt; &lt;span&gt;256&lt;/span&gt;)) uint))
  )
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s similar to an interface definition in Solidity, as it defines functions a contract has to implement to be standard-conforming. It also enables static checks to validate your contract before deployment.&lt;/p&gt;
&lt;h3 id=&quot;heading-implementing-the-token-trait&quot;&gt;Implementing the Token Trait&lt;/h3&gt;
&lt;p&gt;To implement our trait, we create a new contract by running the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;clarinet contract new token
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It should output the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Created file contracts/token.clar
Created file tests/token.test.ts
Updated Clarinet.toml with contract token
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open the new &lt;code&gt;contracts/token.clar&lt;/code&gt; file and replace its content with this code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;impl-trait&lt;/span&gt; .sip10.sip-010-trait)

(&lt;span&gt;define-fungible-token&lt;/span&gt; clarity-token)

(&lt;span&gt;define-constant&lt;/span&gt; ERR_OWNER_ONLY (&lt;span&gt;err&lt;/span&gt; u100))
(&lt;span&gt;define-constant&lt;/span&gt; ERR_NOT_TOKEN_OWNER (&lt;span&gt;err&lt;/span&gt; u101))

(&lt;span&gt;define-constant&lt;/span&gt; CONTRACT_OWNER tx-sender)
(&lt;span&gt;define-constant&lt;/span&gt; TOKEN_URI u&lt;span&gt;&quot;https://clarity-lang.org&quot;&lt;/span&gt;)
(&lt;span&gt;define-constant&lt;/span&gt; TOKEN_NAME &lt;span&gt;&quot;Clarity Token&quot;&lt;/span&gt;)
(&lt;span&gt;define-constant&lt;/span&gt; TOKEN_SYMBOL &lt;span&gt;&quot;CT&quot;&lt;/span&gt;)
(&lt;span&gt;define-constant&lt;/span&gt; TOKEN_DECIMALS u6)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s go through it step by step.&lt;/p&gt;
&lt;p&gt;First, we tell Clarity that the token contract will implement a trait from the SIP-10 contract, allowing us to run a clarinet check to validate that implementation.&lt;/p&gt;
&lt;p&gt;Next, we tell Clarity that this contract will be a fungible token, so we can access built-in functions for checking balances and supply or transferring tokens.&lt;/p&gt;
&lt;p&gt;Then, we define several constants for error codes and token properties.&lt;/p&gt;
&lt;p&gt;Now, we didn’t implement any functions from the trait, so let’s run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;clarinet check
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output should look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;note: using deployments/default.simnet-plan.yaml
error: invalid signature &lt;span&gt;for&lt;/span&gt; method &lt;span&gt;&apos;get-balance&apos;&lt;/span&gt; regarding trait&lt;span&gt;&apos;s specification &amp;lt;sip-010-trait&amp;gt;
x 1 error detected&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It tells us we forgot to implement the &lt;code&gt;get-balance&lt;/code&gt; function defined by the &lt;code&gt;sip-010-trait&lt;/code&gt;.  &lt;/p&gt;
&lt;p&gt;The check command is helpful because we usually implement already deployed traits, meaning we can’t look at the file that defines the trait. If we run a check, it will tell us the next function we need to implement, and we can repeat this until we have implemented everything correctly.&lt;/p&gt;
&lt;p&gt;So, let’s add the missing functions at the bottom of the &lt;code&gt;contracts/token.clar&lt;/code&gt; file by pasting the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;define-read-only&lt;/span&gt; (&lt;span&gt;get-name&lt;/span&gt;)
    (&lt;span&gt;ok&lt;/span&gt; TOKEN_NAME)
)

(&lt;span&gt;define-read-only&lt;/span&gt; (&lt;span&gt;get-symbol&lt;/span&gt;)
    (&lt;span&gt;ok&lt;/span&gt; TOKEN_SYMBOL)
)

(&lt;span&gt;define-read-only&lt;/span&gt; (&lt;span&gt;get-decimals&lt;/span&gt;)
    (&lt;span&gt;ok&lt;/span&gt; TOKEN_DECIMALS)
)

(&lt;span&gt;define-read-only&lt;/span&gt; (&lt;span&gt;get-balance&lt;/span&gt; (&lt;span&gt;who&lt;/span&gt; principal))
    (&lt;span&gt;ok&lt;/span&gt; (&lt;span&gt;ft-get-balance&lt;/span&gt; clarity-token who))
)

(&lt;span&gt;define-read-only&lt;/span&gt; (&lt;span&gt;get-total-supply&lt;/span&gt;)
    (&lt;span&gt;ok&lt;/span&gt; (&lt;span&gt;ft-get-supply&lt;/span&gt; clarity-token))
)

(&lt;span&gt;define-read-only&lt;/span&gt; (&lt;span&gt;get-token-uri&lt;/span&gt;)
    (&lt;span&gt;ok&lt;/span&gt; (&lt;span&gt;some&lt;/span&gt; TOKEN_URI))
)

&lt;span&gt;;; #[allow(unchecked_data)]&lt;/span&gt;
(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;transfer&lt;/span&gt;
  (&lt;span&gt;amount&lt;/span&gt; uint)
  (&lt;span&gt;sender&lt;/span&gt; principal)
  (&lt;span&gt;recipient&lt;/span&gt; principal)
  (&lt;span&gt;memo&lt;/span&gt; (&lt;span&gt;optional&lt;/span&gt; (&lt;span&gt;buff&lt;/span&gt; &lt;span&gt;34&lt;/span&gt;)))
)
  (&lt;span&gt;begin&lt;/span&gt;
    &lt;span&gt;;; (asserts! (is-eq tx-sender sender) ERR_NOT_TOKEN_OWNER)&lt;/span&gt;
    (&lt;span&gt;try!&lt;/span&gt; (&lt;span&gt;ft-transfer&lt;/span&gt;? clarity-token amount sender recipient))
    (&lt;span&gt;match&lt;/span&gt; memo to-print (&lt;span&gt;print&lt;/span&gt; to-print) &lt;span&gt;0&lt;/span&gt;x)
    (&lt;span&gt;ok&lt;/span&gt; true)
  )
)

(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;mint&lt;/span&gt; 
    (&lt;span&gt;amount&lt;/span&gt; uint)
    (&lt;span&gt;recipient&lt;/span&gt; principal))
    (&lt;span&gt;begin&lt;/span&gt;
        (&lt;span&gt;asserts!&lt;/span&gt; (&lt;span&gt;is-eq&lt;/span&gt; tx-sender CONTRACT_OWNER) ERR_OWNER_ONLY)
        (&lt;span&gt;ft-mint&lt;/span&gt;? clarity-token amount recipient )
    )
))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, we have several read-only functions, similar to Ethereum&apos;s view functions. You can see the calls to the fungible token functions &lt;code&gt;ft-get-balance&lt;/code&gt; and &lt;code&gt;ft-get-supply&lt;/code&gt; we got by telling Clarity this is a fungible token at the top of the file. &lt;/p&gt;
&lt;p&gt;We have a transfer function, which usually checks that the &lt;code&gt;sender&lt;/code&gt; argument contains the same as the &lt;code&gt;tx-sender&lt;/code&gt;, but for this tutorial, we commented this line out. Then, there is a match function, which will put the &lt;code&gt;memo&lt;/code&gt; argument into a &lt;code&gt;to-print&lt;/code&gt; variable and pass it to print the memo argument if it exists. Calls to &lt;code&gt;print&lt;/code&gt; are the equivalent to &lt;code&gt;emit&lt;/code&gt; in Ethereum.&lt;/p&gt;
&lt;p&gt;Finally, we have a mint function that creates new tokens.&lt;/p&gt;
&lt;p&gt;This is a complete SIP-10-compliant token contract. Next, we implement a simple swap for it.&lt;/p&gt;
&lt;h3 id=&quot;heading-implementing-a-token-swap&quot;&gt;Implementing a Token Swap&lt;/h3&gt;
&lt;p&gt;For the swap, we create a new contract with the &lt;code&gt;clarinet&lt;/code&gt; CLI again:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;clarinet contract new swapper
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Created file contracts/swapper.clar
Created file tests/swapper.test.ts
Updated Clarinet.toml with contract swapper
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we add the following code into the new &lt;code&gt;contracts/swapper.clar&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;use-trait&lt;/span&gt; sip10-token .sip10.sip-010-trait)

(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;swap&lt;/span&gt; 
        (&lt;span&gt;from-token&lt;/span&gt; &amp;lt;sip10-token&amp;gt;) 
        (&lt;span&gt;to-token&lt;/span&gt; &amp;lt;sip10-token&amp;gt;) 
        (&lt;span&gt;amount&lt;/span&gt; uint)
    )
    (&lt;span&gt;begin&lt;/span&gt;
        (&lt;span&gt;try!&lt;/span&gt; (&lt;span&gt;contract-call&lt;/span&gt;? 
            from-token 
            transfer 
            amount  
            tx-sender 
            (&lt;span&gt;as-contract&lt;/span&gt; tx-sender) 
            none
        ))

        (&lt;span&gt;try!&lt;/span&gt; (&lt;span&gt;contract-call&lt;/span&gt;? 
            to-token 
            transfer 
            amount 
            (&lt;span&gt;as-contract&lt;/span&gt; tx-sender) 
            tx-sender 
            none
        ))
        (&lt;span&gt;ok&lt;/span&gt; true)  
    )
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a naive example of a swap that simply exchanges tokens at a 1:1 rate. It has only one function, which uses our &lt;code&gt;sip-010-trait&lt;/code&gt; and expects three arguments: two for the tokens and one for the number of tokens the contract should swap.&lt;/p&gt;
&lt;p&gt;To give the creator of a token and the swapper tokens, you must add the following code at the end of &lt;code&gt;contract/token.clar&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;mint&lt;/span&gt; u1000000 tx-sender)
(&lt;span&gt;mint&lt;/span&gt; u4200000 .swapper)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will be executed at the deployment of the token contract so that each new token deployed from our contract will give the swapper liquidity instantly.&lt;/p&gt;
&lt;h3 id=&quot;heading-deploying-the-contracts&quot;&gt;Deploying the Contracts&lt;/h3&gt;
&lt;p&gt;To deploy your project, &lt;a target=&quot;_blank&quot; href=&quot;https://platform.hiro.so/projects&quot;&gt;go to the Hiro Platform&lt;/a&gt;, open your project, and click the “Deploy Project” button on the top right. You have to connect your wallet and choose “Generate for Testnet”. &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://lh7-us.googleusercontent.com/RR5pB1atAJjIcGz0buNYq7CCV_17M-Er2klGN8QKgVSebiYtUO20EHtVwAzodTmUxbwIwVhfaHVGXM8QqvkbqIh9680gVnZpQ84rjGeHiKPS0lOb7Nyi1q266gwJsDskHLzJz7EO2uz5YMcAUyO3zG8?width=1400&amp;auto=format&quot; srcset=&quot;https://lh7-us.googleusercontent.com/RR5pB1atAJjIcGz0buNYq7CCV_17M-Er2klGN8QKgVSebiYtUO20EHtVwAzodTmUxbwIwVhfaHVGXM8QqvkbqIh9680gVnZpQ84rjGeHiKPS0lOb7Nyi1q266gwJsDskHLzJz7EO2uz5YMcAUyO3zG8?width=700&amp;auto=format&amp;dpr=1 1x, https://lh7-us.googleusercontent.com/RR5pB1atAJjIcGz0buNYq7CCV_17M-Er2klGN8QKgVSebiYtUO20EHtVwAzodTmUxbwIwVhfaHVGXM8QqvkbqIh9680gVnZpQ84rjGeHiKPS0lOb7Nyi1q266gwJsDskHLzJz7EO2uz5YMcAUyO3zG8?width=700&amp;auto=format&amp;dpr=2 2x, https://lh7-us.googleusercontent.com/RR5pB1atAJjIcGz0buNYq7CCV_17M-Er2klGN8QKgVSebiYtUO20EHtVwAzodTmUxbwIwVhfaHVGXM8QqvkbqIh9680gVnZpQ84rjGeHiKPS0lOb7Nyi1q266gwJsDskHLzJz7EO2uz5YMcAUyO3zG8?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 2: Deploy project.&lt;/p&gt;
&lt;p&gt;If you don’t have enough testnet STX, click the “Request STX” button. Receiving the testnet STX can take a few minutes. &lt;/p&gt;
&lt;p&gt;You should see the three contracts and click the “Deploy” button, which will trigger three signing requests to your wallet, one for each contract. Deploying the contracts can take a few minutes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://lh7-us.googleusercontent.com/rNYVX1yL0zPf44icMXWEHc_dKzjXZeVP-oNq2zeYs3E0w-gBoRQsqwd3KejwNZxN2Lirnt-DgT91CC2bY9vVXFId-XdvLjMymSWoYvMvfa5UFbyiVdecu1M7VlV8gZzzJFMIcL_mm5_QVKAgh58wgjg?width=1400&amp;auto=format&quot; srcset=&quot;https://lh7-us.googleusercontent.com/rNYVX1yL0zPf44icMXWEHc_dKzjXZeVP-oNq2zeYs3E0w-gBoRQsqwd3KejwNZxN2Lirnt-DgT91CC2bY9vVXFId-XdvLjMymSWoYvMvfa5UFbyiVdecu1M7VlV8gZzzJFMIcL_mm5_QVKAgh58wgjg?width=700&amp;auto=format&amp;dpr=1 1x, https://lh7-us.googleusercontent.com/rNYVX1yL0zPf44icMXWEHc_dKzjXZeVP-oNq2zeYs3E0w-gBoRQsqwd3KejwNZxN2Lirnt-DgT91CC2bY9vVXFId-XdvLjMymSWoYvMvfa5UFbyiVdecu1M7VlV8gZzzJFMIcL_mm5_QVKAgh58wgjg?width=700&amp;auto=format&amp;dpr=2 2x, https://lh7-us.googleusercontent.com/rNYVX1yL0zPf44icMXWEHc_dKzjXZeVP-oNq2zeYs3E0w-gBoRQsqwd3KejwNZxN2Lirnt-DgT91CC2bY9vVXFId-XdvLjMymSWoYvMvfa5UFbyiVdecu1M7VlV8gZzzJFMIcL_mm5_QVKAgh58wgjg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 3: Deployment plans&lt;/p&gt;
&lt;p&gt;After a successful deployment, you will see three “Deployed” links, as shown in Figure 4. &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://lh7-us.googleusercontent.com/UREqEx5bNKRNC3qeFnasn25WXGRGwp149dnySa__1usnr3pocYocsocWfhNff9dpP-YZRFVOMx3afcazEgI3kX00TIuhtmpnGgeUe9aXeJhXPK0Aw7Drewko2MATPPvGapUCDfwKQztSPug8lp3WqYI?width=1400&amp;auto=format&quot; srcset=&quot;https://lh7-us.googleusercontent.com/UREqEx5bNKRNC3qeFnasn25WXGRGwp149dnySa__1usnr3pocYocsocWfhNff9dpP-YZRFVOMx3afcazEgI3kX00TIuhtmpnGgeUe9aXeJhXPK0Aw7Drewko2MATPPvGapUCDfwKQztSPug8lp3WqYI?width=700&amp;auto=format&amp;dpr=1 1x, https://lh7-us.googleusercontent.com/UREqEx5bNKRNC3qeFnasn25WXGRGwp149dnySa__1usnr3pocYocsocWfhNff9dpP-YZRFVOMx3afcazEgI3kX00TIuhtmpnGgeUe9aXeJhXPK0Aw7Drewko2MATPPvGapUCDfwKQztSPug8lp3WqYI?width=700&amp;auto=format&amp;dpr=2 2x, https://lh7-us.googleusercontent.com/UREqEx5bNKRNC3qeFnasn25WXGRGwp149dnySa__1usnr3pocYocsocWfhNff9dpP-YZRFVOMx3afcazEgI3kX00TIuhtmpnGgeUe9aXeJhXPK0Aw7Drewko2MATPPvGapUCDfwKQztSPug8lp3WqYI?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 4: Deployed contracts&lt;/p&gt;
&lt;p&gt;Click on one for the token contract to open it in Hiro’s Stacks Explorer. &lt;strong&gt;Keep it open; we need it to copy a few values and call a function later&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://lh7-us.googleusercontent.com/FsSEwG7hXy33b8Ac91IuhcJ6XKUbEUTuYqp1stSeJQ1FohVyr6ytxKL54b0x4TSKTsQ1QbBAtPqf5hpAWQiras2spk1PyDRiYBGe7BmgoytruVYjaj2EKZBM2KrwqC_AOAH3Nw68W6sGNbK4ZdpneI8?width=1400&amp;auto=format&quot; srcset=&quot;https://lh7-us.googleusercontent.com/FsSEwG7hXy33b8Ac91IuhcJ6XKUbEUTuYqp1stSeJQ1FohVyr6ytxKL54b0x4TSKTsQ1QbBAtPqf5hpAWQiras2spk1PyDRiYBGe7BmgoytruVYjaj2EKZBM2KrwqC_AOAH3Nw68W6sGNbK4ZdpneI8?width=700&amp;auto=format&amp;dpr=1 1x, https://lh7-us.googleusercontent.com/FsSEwG7hXy33b8Ac91IuhcJ6XKUbEUTuYqp1stSeJQ1FohVyr6ytxKL54b0x4TSKTsQ1QbBAtPqf5hpAWQiras2spk1PyDRiYBGe7BmgoytruVYjaj2EKZBM2KrwqC_AOAH3Nw68W6sGNbK4ZdpneI8?width=700&amp;auto=format&amp;dpr=2 2x, https://lh7-us.googleusercontent.com/FsSEwG7hXy33b8Ac91IuhcJ6XKUbEUTuYqp1stSeJQ1FohVyr6ytxKL54b0x4TSKTsQ1QbBAtPqf5hpAWQiras2spk1PyDRiYBGe7BmgoytruVYjaj2EKZBM2KrwqC_AOAH3Nw68W6sGNbK4ZdpneI8?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 5: Stacks Explorer&lt;/p&gt;
&lt;h2 id=&quot;heading-sending-smart-contract-events-to-a-web-server&quot;&gt;Sending Smart Contract Events to a Web Server&lt;/h2&gt;
&lt;p&gt;Now that you have built a token and a simple exchange, the next step is letting off-chain applications, like web servers, react to events these contracts emit. For example, to notify you that someone deployed a new contract or to index the contract data off-chain. For this, Hiro created Chainhooks, a service that monitors the Bitcoin and Stacks networks for events and sends them to a web server via a webhook.&lt;/p&gt;
&lt;h3 id=&quot;heading-creating-a-web-server&quot;&gt;Creating a Web Server&lt;/h3&gt;
&lt;p&gt;First, we create a simple web server with Node.js. For this, we create a new Node.js project and add a dependency with the following commands:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir web-hook-server &amp;amp;&amp;amp; &lt;span&gt;cd&lt;/span&gt; web-hook-server
npm init -y
npm i -D localtunnel
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;localtunnel&lt;/code&gt; package lets us make the server accessible for the chainhook later.&lt;/p&gt;
&lt;p&gt;Create a &lt;code&gt;server.js&lt;/code&gt; file with this code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;const&lt;/span&gt; PORT = &lt;span&gt;8080&lt;/span&gt;

&lt;span&gt;require&lt;/span&gt;(&lt;span&gt;&quot;http&quot;&lt;/span&gt;)
  .createServer(&lt;span&gt;(&lt;span&gt;request, response&lt;/span&gt;) =&amp;gt;&lt;/span&gt; {
    &lt;span&gt;let&lt;/span&gt; body = &lt;span&gt;&quot;&quot;&lt;/span&gt;
    request.on(&lt;span&gt;&quot;data&quot;&lt;/span&gt;, &lt;span&gt;(&lt;span&gt;chunk&lt;/span&gt;) =&amp;gt;&lt;/span&gt; {
      body += chunk
    })

    request.on(&lt;span&gt;&quot;end&quot;&lt;/span&gt;, &lt;span&gt;() =&amp;gt;&lt;/span&gt; {
      &lt;span&gt;console&lt;/span&gt;.log(&lt;span&gt;JSON&lt;/span&gt;.parse(body))
      response.end()
    })
  })
  .listen(PORT)

&lt;span&gt;require&lt;/span&gt;(&lt;span&gt;&quot;localtunnel&quot;&lt;/span&gt;)({ &lt;span&gt;port&lt;/span&gt;: PORT }).then(&lt;span&gt;(&lt;span&gt;tunnel&lt;/span&gt;) =&amp;gt;&lt;/span&gt; {
  &lt;span&gt;console&lt;/span&gt;.log(tunnel.url)
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Start the server to get a public URL when creating the chainhook. &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node server.js
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Copy the URL for later, but &lt;strong&gt;remember you get a new public URL each time you restart the server!&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;heading-creating-a-chainhook-in-the-ui&quot;&gt;Creating a Chainhook in the UI&lt;/h3&gt;
&lt;p&gt;To create a chainhook, open your project in &lt;a target=&quot;_blank&quot; href=&quot;https://platform.hiro.so/projects&quot;&gt;the Hiro platform&lt;/a&gt;, select the “Chainhooks” tab, and click the “Create Hook” button. &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://lh7-us.googleusercontent.com/Sq5UcHp8IAGEHRUcfbFVWf0tUwLOXcnPzmoF2TxU5xDCCLZlW3jMuKAU9n6wz-OkIK57OrrPmpeRHUqc65ERLq7BTu3kq-vb1vEFw-zlPHHwaEpCuOLJsnvmFH2vFqRWYtnEEek0-3t0QA78lOsQsEg?width=1400&amp;auto=format&quot; srcset=&quot;https://lh7-us.googleusercontent.com/Sq5UcHp8IAGEHRUcfbFVWf0tUwLOXcnPzmoF2TxU5xDCCLZlW3jMuKAU9n6wz-OkIK57OrrPmpeRHUqc65ERLq7BTu3kq-vb1vEFw-zlPHHwaEpCuOLJsnvmFH2vFqRWYtnEEek0-3t0QA78lOsQsEg?width=700&amp;auto=format&amp;dpr=1 1x, https://lh7-us.googleusercontent.com/Sq5UcHp8IAGEHRUcfbFVWf0tUwLOXcnPzmoF2TxU5xDCCLZlW3jMuKAU9n6wz-OkIK57OrrPmpeRHUqc65ERLq7BTu3kq-vb1vEFw-zlPHHwaEpCuOLJsnvmFH2vFqRWYtnEEek0-3t0QA78lOsQsEg?width=700&amp;auto=format&amp;dpr=2 2x, https://lh7-us.googleusercontent.com/Sq5UcHp8IAGEHRUcfbFVWf0tUwLOXcnPzmoF2TxU5xDCCLZlW3jMuKAU9n6wz-OkIK57OrrPmpeRHUqc65ERLq7BTu3kq-vb1vEFw-zlPHHwaEpCuOLJsnvmFH2vFqRWYtnEEek0-3t0QA78lOsQsEg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 4: Chainhooks tab&lt;/p&gt;
&lt;p&gt;This will open a form where you must enter the chainhook’s configuration. In this example, we want to listen to new contract deployments, so the config should look like in Figure 5.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://lh7-us.googleusercontent.com/dB79Ml9OOQTlztHVZlIIfzQJRw4UO6fnKPfQgymZDVXe96xtX7zeV6kTeWfBB-xA6-xBSN88EWrYsZE9R8qIPY0pF1kiiyi4iCLKOhwbVMagpLZNUS9xT2vwsmhKl_8qql273vGxvLCWnfp1vnpap_A?width=1400&amp;auto=format&quot; srcset=&quot;https://lh7-us.googleusercontent.com/dB79Ml9OOQTlztHVZlIIfzQJRw4UO6fnKPfQgymZDVXe96xtX7zeV6kTeWfBB-xA6-xBSN88EWrYsZE9R8qIPY0pF1kiiyi4iCLKOhwbVMagpLZNUS9xT2vwsmhKl_8qql273vGxvLCWnfp1vnpap_A?width=700&amp;auto=format&amp;dpr=1 1x, https://lh7-us.googleusercontent.com/dB79Ml9OOQTlztHVZlIIfzQJRw4UO6fnKPfQgymZDVXe96xtX7zeV6kTeWfBB-xA6-xBSN88EWrYsZE9R8qIPY0pF1kiiyi4iCLKOhwbVMagpLZNUS9xT2vwsmhKl_8qql273vGxvLCWnfp1vnpap_A?width=700&amp;auto=format&amp;dpr=2 2x, https://lh7-us.googleusercontent.com/dB79Ml9OOQTlztHVZlIIfzQJRw4UO6fnKPfQgymZDVXe96xtX7zeV6kTeWfBB-xA6-xBSN88EWrYsZE9R8qIPY0pF1kiiyi4iCLKOhwbVMagpLZNUS9xT2vwsmhKl_8qql273vGxvLCWnfp1vnpap_A?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 5: Chainhook configuration&lt;/p&gt;
&lt;p&gt;Use the inputs as seen in Figure 5, but make the following changes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Replace “STX Address” with the “Deployed By” value from the Stacks Explorer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Replace the “Start Block” with the “Block Height” value from the Stacks Explorer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Replace the URL with the public URL printed by your web server.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you don’t set an “End Block”, the chainhook will continue listening to deployment events from your address indefinitely. &lt;/p&gt;
&lt;p&gt;Finally, you click the “Create Chainhook” button to deploy the hook. After a few seconds, the Hiro Platform should show the latest activity, as in Figure 6.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://lh7-us.googleusercontent.com/O_GA2YEUxQMGXQEVzzqKPbo1aFeJIb4Ch1M9eykU04LdymCo3sxAhwncjKYaZfJd3DXC2qf2pa5osNXsKnu5cWj5JL84fwpIfTWfjhuQNNXS7QycZdCWE_yXlkNpwcYo3wMlWFkHKq0K---eW7xH_ZM?width=1400&amp;auto=format&quot; srcset=&quot;https://lh7-us.googleusercontent.com/O_GA2YEUxQMGXQEVzzqKPbo1aFeJIb4Ch1M9eykU04LdymCo3sxAhwncjKYaZfJd3DXC2qf2pa5osNXsKnu5cWj5JL84fwpIfTWfjhuQNNXS7QycZdCWE_yXlkNpwcYo3wMlWFkHKq0K---eW7xH_ZM?width=700&amp;auto=format&amp;dpr=1 1x, https://lh7-us.googleusercontent.com/O_GA2YEUxQMGXQEVzzqKPbo1aFeJIb4Ch1M9eykU04LdymCo3sxAhwncjKYaZfJd3DXC2qf2pa5osNXsKnu5cWj5JL84fwpIfTWfjhuQNNXS7QycZdCWE_yXlkNpwcYo3wMlWFkHKq0K---eW7xH_ZM?width=700&amp;auto=format&amp;dpr=2 2x, https://lh7-us.googleusercontent.com/O_GA2YEUxQMGXQEVzzqKPbo1aFeJIb4Ch1M9eykU04LdymCo3sxAhwncjKYaZfJd3DXC2qf2pa5osNXsKnu5cWj5JL84fwpIfTWfjhuQNNXS7QycZdCWE_yXlkNpwcYo3wMlWFkHKq0K---eW7xH_ZM?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 6: Chainhook activity&lt;/p&gt;
&lt;p&gt;Your web server’s output should look similar to this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &lt;span&gt;apply&lt;/span&gt;: [
    {
      &lt;span&gt;block_identifier&lt;/span&gt;: [&lt;span&gt;Object&lt;/span&gt;],
      &lt;span&gt;metadata&lt;/span&gt;: [&lt;span&gt;Object&lt;/span&gt;],
      &lt;span&gt;parent_block_identifier&lt;/span&gt;: [&lt;span&gt;Object&lt;/span&gt;],
      &lt;span&gt;timestamp&lt;/span&gt;: &lt;span&gt;171.&lt;/span&gt;.&lt;span&gt;.939&lt;/span&gt;,
      &lt;span&gt;transactions&lt;/span&gt;: [&lt;span&gt;Array&lt;/span&gt;]
    }
  ],
  &lt;span&gt;chainhook&lt;/span&gt;: {
    &lt;span&gt;is_streaming_blocks&lt;/span&gt;: &lt;span&gt;false&lt;/span&gt;,
    &lt;span&gt;predicate&lt;/span&gt;: {
      &lt;span&gt;deployer&lt;/span&gt;: &lt;span&gt;&apos;ST3...3K3&apos;&lt;/span&gt;,
      &lt;span&gt;scope&lt;/span&gt;: &lt;span&gt;&apos;contract_deployment&apos;&lt;/span&gt;
    },
    &lt;span&gt;uuid&lt;/span&gt;: &lt;span&gt;&apos;44e...7c6&apos;&lt;/span&gt;
  },
  &lt;span&gt;rollback&lt;/span&gt;: []
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;heading-creating-a-chainhook-config-with-the-cli&quot;&gt;Creating a Chainhook Config With the CLI&lt;/h3&gt;
&lt;p&gt;Creating a chainhook configuration with the chainhook CLI in the Hiro Platform IDE is also possible. Run the following command to create a new file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;chainhook predicates new mint-hook.json --stacks
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will generate a &lt;code&gt;mint-hook.json&lt;/code&gt; file. To listen to the mint events of our token contract, you need to replace the &lt;code&gt;networks&lt;/code&gt; attribute in that file with the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&quot;networks&quot;&lt;/span&gt;: {
  &lt;span&gt;&quot;testnet&quot;&lt;/span&gt;: {
    &lt;span&gt;&quot;start_block&quot;&lt;/span&gt;: &lt;span&gt;152190&lt;/span&gt;,
    &lt;span&gt;&quot;if_this&quot;&lt;/span&gt;: {
      &lt;span&gt;&quot;scope&quot;&lt;/span&gt;: &lt;span&gt;&quot;contract_call&quot;&lt;/span&gt;,
      &lt;span&gt;&quot;contract_identifier&quot;&lt;/span&gt;: &lt;span&gt;&quot;ST3...3K3.token&quot;&lt;/span&gt;,
      &lt;span&gt;&quot;method&quot;&lt;/span&gt;: &lt;span&gt;&quot;mint&quot;&lt;/span&gt;
    },
    &lt;span&gt;&quot;then_that&quot;&lt;/span&gt;: {
      &lt;span&gt;&quot;http_post&quot;&lt;/span&gt;: {
        &lt;span&gt;&quot;url&quot;&lt;/span&gt;: &lt;span&gt;&quot;https://example.com/api/endpoint&quot;&lt;/span&gt;,
        &lt;span&gt;&quot;authorization_header&quot;&lt;/span&gt;: &lt;span&gt;&quot;&quot;&lt;/span&gt;
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make sure you replace the &lt;code&gt;contract_identifier&lt;/code&gt;, &lt;code&gt;start_block&lt;/code&gt;, and &lt;code&gt;url&lt;/code&gt; with the values from the Stacks Explorer after deploying your contracts. &lt;strong&gt;Use the Contract ID from the Stacks Explorer, not the Transaction ID.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Create the chainhook by uploading the &lt;code&gt;mint-hook.json&lt;/code&gt; file in &lt;a target=&quot;_blank&quot; href=&quot;https://platform.hiro.so/projects&quot;&gt;the Hiro Platform&lt;/a&gt; by opening your project, selecting the “Chainhooks” tab, and clicking the “Upload Chainhook” button on the top right.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://lh7-us.googleusercontent.com/xACMXaOuUnLpqcTnOmeXyP-ewu6VsGI52U9lWv6w8zOR8SkdyvWlFoOxoVtMGp9Qm1OZzbs80BY6nRmZ1roYhpKiV-AwDchzWna11lY_OHIxOvhCvQD7WqD_IMNXJT4Dzk9-tjph9tUA2qPHD_CsGlg?width=1400&amp;auto=format&quot; srcset=&quot;https://lh7-us.googleusercontent.com/xACMXaOuUnLpqcTnOmeXyP-ewu6VsGI52U9lWv6w8zOR8SkdyvWlFoOxoVtMGp9Qm1OZzbs80BY6nRmZ1roYhpKiV-AwDchzWna11lY_OHIxOvhCvQD7WqD_IMNXJT4Dzk9-tjph9tUA2qPHD_CsGlg?width=700&amp;auto=format&amp;dpr=1 1x, https://lh7-us.googleusercontent.com/xACMXaOuUnLpqcTnOmeXyP-ewu6VsGI52U9lWv6w8zOR8SkdyvWlFoOxoVtMGp9Qm1OZzbs80BY6nRmZ1roYhpKiV-AwDchzWna11lY_OHIxOvhCvQD7WqD_IMNXJT4Dzk9-tjph9tUA2qPHD_CsGlg?width=700&amp;auto=format&amp;dpr=2 2x, https://lh7-us.googleusercontent.com/xACMXaOuUnLpqcTnOmeXyP-ewu6VsGI52U9lWv6w8zOR8SkdyvWlFoOxoVtMGp9Qm1OZzbs80BY6nRmZ1roYhpKiV-AwDchzWna11lY_OHIxOvhCvQD7WqD_IMNXJT4Dzk9-tjph9tUA2qPHD_CsGlg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 7: Upload chainhook&lt;/p&gt;
&lt;p&gt;You can call the function with the Stacks Explorer. Copy the “Deployed by” address, scroll down to the “Available Functions”, and select the &lt;code&gt;mint&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://lh7-us.googleusercontent.com/g55KJVhMg8KERaf9dkKaGYqO3_CofbYCigkimqk9enJJL3vpz9ThW-aqIpo-FaPEG3zL16XS_adqcxOv3MS70I8vaLJiJw5yqGtUfW0_-UVqLV2GYJRnlwly3lNMdXNFzSrDmVNormcrLBt7hnjBhdM?width=1400&amp;auto=format&quot; srcset=&quot;https://lh7-us.googleusercontent.com/g55KJVhMg8KERaf9dkKaGYqO3_CofbYCigkimqk9enJJL3vpz9ThW-aqIpo-FaPEG3zL16XS_adqcxOv3MS70I8vaLJiJw5yqGtUfW0_-UVqLV2GYJRnlwly3lNMdXNFzSrDmVNormcrLBt7hnjBhdM?width=700&amp;auto=format&amp;dpr=1 1x, https://lh7-us.googleusercontent.com/g55KJVhMg8KERaf9dkKaGYqO3_CofbYCigkimqk9enJJL3vpz9ThW-aqIpo-FaPEG3zL16XS_adqcxOv3MS70I8vaLJiJw5yqGtUfW0_-UVqLV2GYJRnlwly3lNMdXNFzSrDmVNormcrLBt7hnjBhdM?width=700&amp;auto=format&amp;dpr=2 2x, https://lh7-us.googleusercontent.com/g55KJVhMg8KERaf9dkKaGYqO3_CofbYCigkimqk9enJJL3vpz9ThW-aqIpo-FaPEG3zL16XS_adqcxOv3MS70I8vaLJiJw5yqGtUfW0_-UVqLV2GYJRnlwly3lNMdXNFzSrDmVNormcrLBt7hnjBhdM?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 8: Available functions&lt;/p&gt;
&lt;p&gt;In the form, enter &lt;code&gt;100&lt;/code&gt; as the &lt;code&gt;amount&lt;/code&gt; and the copied address as the &lt;code&gt;recipient&lt;/code&gt;, and click “Call Function” to open your wallet, where you have to confirm the transaction.&lt;/p&gt;
&lt;p&gt;After a few minutes, your transaction is finalized on Stacks. Your chainhook will trigger, leading to the following output on your web server:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &lt;span&gt;apply&lt;/span&gt;: [
    {
      &lt;span&gt;block_identifier&lt;/span&gt;: [&lt;span&gt;Object&lt;/span&gt;],
      &lt;span&gt;metadata&lt;/span&gt;: [&lt;span&gt;Object&lt;/span&gt;],
      &lt;span&gt;parent_block_identifier&lt;/span&gt;: [&lt;span&gt;Object&lt;/span&gt;],
      &lt;span&gt;timestamp&lt;/span&gt;: &lt;span&gt;1711553905&lt;/span&gt;,
      &lt;span&gt;transactions&lt;/span&gt;: [&lt;span&gt;Array&lt;/span&gt;]
    }
  ],
  &lt;span&gt;chainhook&lt;/span&gt;: {
    &lt;span&gt;is_streaming_blocks&lt;/span&gt;: &lt;span&gt;true&lt;/span&gt;,
    &lt;span&gt;predicate&lt;/span&gt;: {
      &lt;span&gt;contract_identifier&lt;/span&gt;: &lt;span&gt;&apos;ST3...3K3.token&apos;&lt;/span&gt;,
      &lt;span&gt;method&lt;/span&gt;: &lt;span&gt;&apos;mint&apos;&lt;/span&gt;,
      &lt;span&gt;scope&lt;/span&gt;: &lt;span&gt;&apos;contract_call&apos;&lt;/span&gt;
    },
    &lt;span&gt;uuid&lt;/span&gt;: &lt;span&gt;&apos;906...43b6&apos;&lt;/span&gt;
  },
  &lt;span&gt;rollback&lt;/span&gt;: []
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this, you finally know how to relay smart contract events to an API of your choice. You can process it in any way you like. Use it to notify users of swaps or mints, index all token transactions for easy browsing, or even deploy new contracts in reaction to events!&lt;/p&gt;
&lt;h2 id=&quot;heading-summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;The Bitcoin ecosystem got a huge upgrade with the Stacks network, and Hiro makes it accessible for developers. With the Hiro Platform, it’s a matter of a few clicks to deploy Clarity smart contracts and listen to chain events&lt;/p&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Comparing Solidity With Clarity</title>
    <link href="https://blog.developerdao.com/comparing-solidity-with-clarity"/>
    <id>https://blog.developerdao.com/comparing-solidity-with-clarity</id>
    <updated>2024-04-10T08:54:05.022Z</updated>
    <author><name>Ϗ</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1712218211483/e641392a-484a-4fc6-9d98-826a286dbd39.jpeg?width=600&amp;format=auto"/>
    <summary>Writing smart contracts for Bitcoin was limited in the past, but with Stacks, this changed. Its Clarity programming language allows you to build Bitcoin smart contacts similar to those on the Ethereum network while being more secure than Solidity at ...</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1712218211483/e641392a-484a-4fc6-9d98-826a286dbd39.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1712218211483/e641392a-484a-4fc6-9d98-826a286dbd39.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1712218211483/e641392a-484a-4fc6-9d98-826a286dbd39.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1712218211483/e641392a-484a-4fc6-9d98-826a286dbd39.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;p&gt;Writing smart contracts for Bitcoin was limited in the past, but with Stacks, this changed. Its &lt;a target=&quot;_blank&quot; href=&quot;https://clarity-lang.org/&quot;&gt;Clarity&lt;/a&gt; programming language allows you to &lt;a target=&quot;_blank&quot; href=&quot;https://blog.developerdao.com/unleash-the-power-of-defi-on-bitcoin&quot;&gt;build Bitcoin smart contacts&lt;/a&gt; similar to those on the Ethereum network while being more secure than Solidity at the same time. At first glance, Clarity might seem a bit foreign, but the language has many similarities with Solidity, so don&apos;t get discouraged by its syntax.&lt;/p&gt;
&lt;p&gt;This article adds to &lt;a target=&quot;_blank&quot; href=&quot;https://www.youtube.com/watch?v=w5ZvGlv4gKY&quot;&gt;our first Stacks workshop&lt;/a&gt; with &lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/hiro-signup&quot;&gt;Hiro&lt;/a&gt;, where we compared the two languages.&lt;/p&gt;
&lt;h2 id=&quot;heading-what-is-stacks&quot;&gt;What is Stacks?&lt;/h2&gt;
&lt;p&gt;Stacks is a layer-2 blockchain network for Bitcoin that reads data from Bitcoin, settles on Bitcoin, and allows the creation of smart contracts similar to the ones on Ethereum.&lt;/p&gt;
&lt;p&gt;Besides being a smart contract platform, Stacks also offers several features and services you might know from the Ethereum ecosystem. For example, &lt;a target=&quot;_blank&quot; href=&quot;https://www.stackingdao.com/s&quot;&gt;Stacking DAO&lt;/a&gt; is a liquid staking service similar to Lido, and &lt;a target=&quot;_blank&quot; href=&quot;https://alexgo.io/&quot;&gt;ALEX&lt;/a&gt; is a DEX similar to Uniswap.&lt;/p&gt;
&lt;h2 id=&quot;heading-what-is-clarity&quot;&gt;What is Clarity?&lt;/h2&gt;
&lt;p&gt;Stacks smart contracts are written in &lt;a target=&quot;_blank&quot; href=&quot;https://clarity-lang.org/&quot;&gt;Clarity&lt;/a&gt;, a statically typed language with Lisp syntax that favors functional programming styles, including pure functions and immutable data. Its first release date is 2020, so it’s a rather young language, but it benefits from learning from Solidity’s mistakes.&lt;/p&gt;
&lt;p&gt;Clarity focuses on security and predictability. It is not Turing complete, which allows for more precise gas estimations and security checks. Conditional jumps or, in high-level languages, if-statements, loops, and recursion are often the cause of complexity in Turing complete languages. Clarity doesn’t support loops or recursion, so there is no way to run indefinitely, making it non-Turing complete. However, you can still review multiple elements with map, filter, and fold functions.&lt;/p&gt;
&lt;h2 id=&quot;heading-how-does-clarity-differ-from-solidity&quot;&gt;How Does Clarity Differ from Solidity?&lt;/h2&gt;
&lt;p&gt;Let&apos;s review Clarity and Solidity examples to highlight their differences. If you want a more concise visual comparison, &lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/hiro-comparsion-tool&quot;&gt;check out this site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We will touch on the following points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Syntax differences&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Immutable variables&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Function access&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;External function calls&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Event emission&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Token transfer&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;heading-syntax-differences&quot;&gt;Syntax Differences&lt;/h3&gt;
&lt;p&gt;Clarity’s syntax is inspired by Lisp, meaning you will see many parentheses. Clarity favors kebab-case instead of camelCase; everything is an expression since everything is done with functions. There are no statements like if or for that just define code blocks but don’t “return” a value.&lt;/p&gt;
&lt;p&gt;Take this example of a function call in Solidity:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;functionName(argument1, argument2, …, argumentN);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compared to the Clarity version:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;function-name&lt;/span&gt; argument1 argument2 … argumentN)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also, no commas or colons are needed.&lt;/p&gt;
&lt;h3 id=&quot;heading-assigning-variables&quot;&gt;Assigning Variables&lt;/h3&gt;
&lt;p&gt;By default, you can change variables directly in Solidity. In Clarity, you can’t; variables are immutable, and you must set them with a call to a built-in function.&lt;/p&gt;
&lt;p&gt;In the following Solidity example, we see the use of an assignment operator to change a contract variable.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;contract User {
  uint &lt;span&gt;public&lt;/span&gt; userAge = &lt;span&gt;42&lt;/span&gt;;
  &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;updateAge&lt;/span&gt;(&lt;span&gt;unit age&lt;/span&gt;) &lt;span&gt;public&lt;/span&gt; &lt;/span&gt;{
    userAge = age;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Clarity, no operator is involved; instead, you call the &lt;code&gt;define-data-var&lt;/code&gt; function for contract variables and override it with a &lt;code&gt;var-set&lt;/code&gt; function call.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;define-data-var&lt;/span&gt; userAge uint &lt;span&gt;42&lt;/span&gt;)
(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;update-age&lt;/span&gt; (&lt;span&gt;age&lt;/span&gt; uint))
  (&lt;span&gt;begin&lt;/span&gt;
    (&lt;span&gt;var-set&lt;/span&gt; userAge age)
    (&lt;span&gt;ok&lt;/span&gt; age)
  )
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;heading-working-with-variables&quot;&gt;Working With Variables&lt;/h3&gt;
&lt;p&gt;These variables are immutable; they get replaced by a new instance. This might not be obvious with primitive values like numbers, so let’s look at a more complex example with composite values.&lt;/p&gt;
&lt;p&gt;In Solidity, you can use structs to define composite values. The following example illustrates how to define a struct, create an instance, and mutate it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;contract UserContract {
  struct User {
    &lt;span&gt;string&lt;/span&gt; name;
    uint age;
  }

  User &lt;span&gt;public&lt;/span&gt; user = User(&lt;span&gt;&quot;Ryan&quot;&lt;/span&gt;, &lt;span&gt;42&lt;/span&gt;);

  &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;updateUser&lt;/span&gt;(&lt;span&gt;&lt;span&gt;string&lt;/span&gt; memory name, unit age&lt;/span&gt;) &lt;span&gt;public&lt;/span&gt; &lt;/span&gt;{
    user.name = name;
    user.age = age;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Clarity equivalent to a struct is the immutable tuple. Again, it’s created via a built-in function.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;tuple&lt;/span&gt; (&lt;span&gt;name&lt;/span&gt; &lt;span&gt;&quot;Ryan&quot;&lt;/span&gt;) (&lt;span&gt;age&lt;/span&gt; &lt;span&gt;42&lt;/span&gt;))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This time, some syntactic sugar allows you to define a tuple similar to object literals in JavaScript.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{name: &lt;span&gt;&quot;Ryan&quot;&lt;/span&gt;, age: &lt;span&gt;42&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To get data from a tuple, you use the get function. In the following example, we define variables local to the let block and set them to the content of our tuple stored in the &lt;code&gt;user&lt;/code&gt; reference.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;define-constant&lt;/span&gt; user {name: &lt;span&gt;&quot;Ryan&quot;&lt;/span&gt;, age: &lt;span&gt;42&lt;/span&gt;})
(&lt;span&gt;let&lt;/span&gt; 
  (
    (&lt;span&gt;userName&lt;/span&gt; (&lt;span&gt;get&lt;/span&gt; name user))
    (&lt;span&gt;userAge&lt;/span&gt; (&lt;span&gt;get&lt;/span&gt; age user))
  )
  (&lt;span&gt;print&lt;/span&gt; {name: userName, age: userAge})
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you want to change a tuple value, you have to replace the whole tuple with a new one. Maps can help here, allowing you to reference a tuple by key. This way, you can use a map and a key as a constant reference to a changing value.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;define-map&lt;/span&gt; users uint { name: (&lt;span&gt;string-ascii&lt;/span&gt; &lt;span&gt;50&lt;/span&gt;), age: uint })
(&lt;span&gt;define-public&lt;/span&gt; 
  (&lt;span&gt;add-or-update-user&lt;/span&gt; 
    (&lt;span&gt;userId&lt;/span&gt; uint) (&lt;span&gt;userName&lt;/span&gt; (&lt;span&gt;string-ascii&lt;/span&gt; &lt;span&gt;50&lt;/span&gt;)) (&lt;span&gt;userAge&lt;/span&gt; uint)
  )
  (&lt;span&gt;map-set&lt;/span&gt; users userId { name: userName, age: userAge })
  (&lt;span&gt;ok&lt;/span&gt; true)
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;heading-defining-function-access&quot;&gt;Defining Function Access&lt;/h3&gt;
&lt;p&gt;To define a function in Solidity, you use the &lt;code&gt;function&lt;/code&gt; keyword, followed by parenthesis with the arguments, a list of modifiers, and finally, the function body.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;contract UserManagement {
  uint &lt;span&gt;private&lt;/span&gt; age;

  &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;incrementAge&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;span&gt;private&lt;/span&gt; &lt;/span&gt;{
    age += &lt;span&gt;1&lt;/span&gt;;
  }

  &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;getAge&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;span&gt;public&lt;/span&gt; &lt;span&gt;view&lt;/span&gt; &lt;span&gt;returns&lt;/span&gt; (&lt;span&gt;uint&lt;/span&gt;) &lt;/span&gt;{
    &lt;span&gt;return&lt;/span&gt; age;
  }

  &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;setAge&lt;/span&gt;(&lt;span&gt;uint newAge&lt;/span&gt;) &lt;span&gt;public&lt;/span&gt; &lt;/span&gt;{
    age = newAge;
    incrementAge();
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Clarity, there are no modifiers but different built-in functions for function definition. Built-in functions define private, public, and view functions called read-only in Clarity. Also, Clarity doesn’t have external functions.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;define-data-var&lt;/span&gt; userAge uint u0)

(&lt;span&gt;define-private&lt;/span&gt; (&lt;span&gt;increment-age&lt;/span&gt;)
  (&lt;span&gt;var-set&lt;/span&gt; userAge (&lt;span&gt;+&lt;/span&gt; (&lt;span&gt;var-get&lt;/span&gt; userAge) u1))
)

(&lt;span&gt;define-read-only&lt;/span&gt; (&lt;span&gt;get-user-age&lt;/span&gt;)
  (&lt;span&gt;var-get&lt;/span&gt; userAge)
)

(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;set-user-age&lt;/span&gt; (&lt;span&gt;newAge&lt;/span&gt; uint))
  (&lt;span&gt;var-set&lt;/span&gt; userAge newAge)
  (&lt;span&gt;ok&lt;/span&gt; newAge)
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Solidity also allows for the definition of custom modifiers to enable you to manage access control.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;contract Owned {
  address &lt;span&gt;public&lt;/span&gt; owner;

  &lt;span&gt;constructor&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) {
    owner = msg.sender;
  }

  modifier onlyOwner() {
    &lt;span&gt;require&lt;/span&gt;(msg.sender == owner, &lt;span&gt;&quot;Not the owner&quot;&lt;/span&gt;);
    _;
  }

  &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;changeOwner&lt;/span&gt;(&lt;span&gt;address newOwner&lt;/span&gt;) &lt;span&gt;public&lt;/span&gt; &lt;span&gt;onlyOwner&lt;/span&gt; &lt;/span&gt;{
    owner = newOwner;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Clarity, you would use the built-in &lt;code&gt;asserts!&lt;/code&gt; function, which will revert your contract automatically if an assertion fails.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;define-data-var&lt;/span&gt; owner principal tx-sender)

(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;change-owner&lt;/span&gt; (&lt;span&gt;newOwner&lt;/span&gt; principal))
  (&lt;span&gt;begin&lt;/span&gt;
    (&lt;span&gt;asserts!&lt;/span&gt; (&lt;span&gt;is-eq&lt;/span&gt; tx-sender (&lt;span&gt;var-get&lt;/span&gt; owner)) (&lt;span&gt;err&lt;/span&gt; u1))
    (&lt;span&gt;var-set&lt;/span&gt; owner newOwner)
    (&lt;span&gt;ok&lt;/span&gt; true)
  )
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;heading-calling-functions-of-other-contracts&quot;&gt;Calling Functions of Other Contracts&lt;/h3&gt;
&lt;p&gt;To call a function of another contract in Solidity, you need the address of the contract you want to call and its definition or ABI.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;contract User {
  uint &lt;span&gt;public&lt;/span&gt; age;

  &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;setAge&lt;/span&gt;(&lt;span&gt;uint newAge&lt;/span&gt;) &lt;span&gt;public&lt;/span&gt; &lt;/span&gt;{
    age = newAge;
  }
}


contract Caller {
  &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;callSetAge&lt;/span&gt;(&lt;span&gt;address userAddress, uint newAge&lt;/span&gt;) &lt;span&gt;public&lt;/span&gt; &lt;/span&gt;{
    UserManagement user = User(userAddress);
    userManagement.setAge(newAge);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Clarity, you need the address (called &lt;code&gt;principal&lt;/code&gt;) since everything is handled with built-in functions; classes or contract definitions don’t exist.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;define-data-var&lt;/span&gt; age uint u20)

(&lt;span&gt;define-private&lt;/span&gt; (&lt;span&gt;increment-age&lt;/span&gt;)
  (&lt;span&gt;var-set&lt;/span&gt; age (&lt;span&gt;+&lt;/span&gt; (&lt;span&gt;var-get&lt;/span&gt; age) u1))
)

(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;update-age&lt;/span&gt;)
  (&lt;span&gt;increment-age&lt;/span&gt;) &lt;span&gt;;; Internal call&lt;/span&gt;
  (&lt;span&gt;ok&lt;/span&gt; (&lt;span&gt;var-get&lt;/span&gt; age))
)

(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;call-set-age&lt;/span&gt; (&lt;span&gt;contractA&lt;/span&gt; principal) (&lt;span&gt;newAge&lt;/span&gt; uint))
  (&lt;span&gt;contract-call&lt;/span&gt;? contractA set-age newAge)
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;heading-emitting-events&quot;&gt;Emitting Events&lt;/h3&gt;
&lt;p&gt;In Solidity, similar to structs, you have to define events up-front and explicitly &lt;code&gt;emit&lt;/code&gt; them.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;contract UserManagement {
  event UserUpdated(&lt;span&gt;string&lt;/span&gt; name, uint age);

  &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;updateUser&lt;/span&gt;(&lt;span&gt;&lt;span&gt;string&lt;/span&gt; memory name, uint age&lt;/span&gt;) &lt;span&gt;public&lt;/span&gt; &lt;/span&gt;{
    emit UserUpdated(_name, _age);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Clarity, you don’t need to define or emit events explicitly. Built-in functions like &lt;code&gt;stx-transfer&lt;/code&gt; emit events implicitly when called. However, if you want a custom event, you can call the &lt;code&gt;print&lt;/code&gt; function with a tuple, which will emit an event.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;update-user&lt;/span&gt; (&lt;span&gt;name&lt;/span&gt; (&lt;span&gt;string-ascii&lt;/span&gt; &lt;span&gt;32&lt;/span&gt;)) (&lt;span&gt;age&lt;/span&gt; uint))
  (&lt;span&gt;print&lt;/span&gt; { action: &lt;span&gt;&quot;User updated&quot;&lt;/span&gt;, name: name, age: age })
  (&lt;span&gt;stx-transfer&lt;/span&gt;? amount tx-sender recipient)
  (&lt;span&gt;ok&lt;/span&gt; true)
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;heading-transferring-native-tokens&quot;&gt;Transferring Native Tokens&lt;/h3&gt;
&lt;p&gt;To transfer ETH with Solidity, you’d call the transfer method of a payable address.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;contract SendETH {
  &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;sendViaTransfer&lt;/span&gt;(&lt;span&gt;address payable _to&lt;/span&gt;) &lt;span&gt;public&lt;/span&gt; &lt;span&gt;payable&lt;/span&gt; &lt;/span&gt;{
    _to.transfer(msg.value);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Clarity, you’d use the built-in &lt;code&gt;stx-transfer&lt;/code&gt; function to transfer the native token STX. It checks automatically if the sender has enough tokens.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;send-stx&lt;/span&gt; (&lt;span&gt;recipient&lt;/span&gt; principal) (&lt;span&gt;amount&lt;/span&gt; uint))
  (&lt;span&gt;stx-transfer&lt;/span&gt;? amount tx-sender recipient)
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;heading-transferring-non-native-tokens&quot;&gt;Transferring Non-Native Tokens&lt;/h3&gt;
&lt;p&gt;What would a smart contact-enabled blockchain be without custom tokens? Stacks’ ERC-20 equivalent is the SIP-010 standard.&lt;/p&gt;
&lt;p&gt;To transfer a custom (non-native) fungible token in Solidity, you need an interface and call its transfer method with an address and an amount.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;interface&lt;/span&gt; IERC20 {
  &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;transfer&lt;/span&gt;(&lt;span&gt;address to, uint256 amount&lt;/span&gt;) &lt;span&gt;external&lt;/span&gt; &lt;span&gt;returns&lt;/span&gt; (&lt;span&gt;bool&lt;/span&gt;)&lt;/span&gt;;
}

contract SendERC20 {
  &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;transferToken&lt;/span&gt;(&lt;span&gt;address tokenContract, address to, uint256 _amount&lt;/span&gt;) &lt;span&gt;public&lt;/span&gt; &lt;/span&gt;{
    IERC20 tokenContract = IERC20(_tokenContract);
    tokenContract.transfer(_to, _amount);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can do the same in Clarity by using the built-in &lt;code&gt;contract-call&lt;/code&gt; function. No interface is needed since Clarity is not object-oriented and doesn’t support inheritance.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;transfer-token&lt;/span&gt; (&lt;span&gt;recipient&lt;/span&gt; principal) (&lt;span&gt;amount&lt;/span&gt; uint))
  (&lt;span&gt;contract-call&lt;/span&gt;? .token transfer amount tx-sender recipient)
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Transferring non-fungible tokens in Solidity is similar to the fungible version; you just need an ID instead of an amount.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;interface&lt;/span&gt; IERC721 {
  &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;transferFrom&lt;/span&gt;(&lt;span&gt;address &lt;span&gt;from&lt;/span&gt;, address to, uint256 _tokenId&lt;/span&gt;) &lt;span&gt;external&lt;/span&gt;&lt;/span&gt;;
}


contract SendERC721 {
  &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;transferNFT&lt;/span&gt;(&lt;span&gt;address nftContract, address to, uint256 _tokenId&lt;/span&gt;) &lt;span&gt;public&lt;/span&gt; &lt;/span&gt;{
    IERC721 nftContract = IERC721(_nftContract);
    nftContract.transferFrom(msg.sender, to, tokenId);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same goes for Clarity, again a built-in function with no interface. Also, SIP-009 is Stacks’ equivalent of ERC-721 on Ethereum.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;transfer-nft&lt;/span&gt; (&lt;span&gt;nft-contract&lt;/span&gt; principal) (&lt;span&gt;token-id&lt;/span&gt; uint) (&lt;span&gt;recipient&lt;/span&gt; principal))
  (&lt;span&gt;contract-call&lt;/span&gt;? nft-contract transfer token-id tx-sender recipient)
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;heading-missing-features-of-clarity&quot;&gt;Missing Features of Clarity&lt;/h2&gt;
&lt;p&gt;While this might not be an issue in practice, some missing features make 1:1 ports of smart contracts from Solidity to Clarity a bit harder.&lt;/p&gt;
&lt;p&gt;First, &lt;strong&gt;Clarity contracts can’t directly modify the state of other contracts&lt;/strong&gt;, which means building contract factories isn’t possible.&lt;/p&gt;
&lt;p&gt;Second, &lt;strong&gt;Clarity does not have libraries&lt;/strong&gt;. In Solidity, you can import an ERC-20 library like OpenZeppelin and extend the interfaces. In Clarity, you would copy and modify code from a SIP-009 template.&lt;/p&gt;
&lt;h2 id=&quot;heading-hiro-development-tools-for-stacks&quot;&gt;Hiro Development Tools for Stacks&lt;/h2&gt;
&lt;p&gt;Hiro supplies you with all the tools you need to build smart contracts on Stacks.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://docs.hiro.so/clarinet&quot;&gt;Clarinet&lt;/a&gt;, a development environment similar to Hardhat, for building and testing Clarity contracts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://docs.hiro.so/stacks.js&quot;&gt;Stacks.js&lt;/a&gt;, a frontend library similar to web3.js, is used to access Stacks from a web application.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/hiro-signup&quot;&gt;The Hiro Platform&lt;/a&gt;, a cloud IDE similar to Remix, deploys and debugs Clarity smart contracts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://docs.hiro.so/chainhook&quot;&gt;Chainhook&lt;/a&gt;, an indexing service similar to the Graph, to get onchain data quickly.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;heading-summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;Clarity certainly is a unique language for smart contract development. It focuses on the functional programming paradigm and even ditches Turing completeness to make gas estimations and security checks straightforward.&lt;/p&gt;
&lt;p&gt;While Clarity might seem quite different at first glance, it still has many conceptual similarities with Solidity, so porting most contracts shouldn’t be a big deal.&lt;/p&gt;
&lt;p&gt;Finally, with the tools and services provided by Hiro, you should have your first contract deployed in no time! So, &lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/hiro-signup&quot;&gt;sign up to their platform&lt;/a&gt; and tap into the power of Bitcoin!&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://stacks.chat&quot;&gt;Ask Hiro on Discord&lt;/a&gt; if you have questions about Stacks or Hiro services.&lt;/p&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Creating a Token-Gated Web Page With Clarity</title>
    <link href="https://blog.developerdao.com/creating-a-token-gated-web-page-with-clarity"/>
    <id>https://blog.developerdao.com/creating-a-token-gated-web-page-with-clarity</id>
    <updated>2024-03-27T18:43:03.458Z</updated>
    <author><name>Osikhena Oshomah</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1711563528738/b3c252fc-f857-4428-8df5-59c72c4a20d1.jpeg?width=600&amp;format=auto"/>
    <summary>This tutorial shows how to create a token-gated website using Clarity as the smart contract language. A token-gated website serves content to users with a certain amount of tokens in their wallets.
In this tutorial, we will create two Clarity smart c...</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711563528738/b3c252fc-f857-4428-8df5-59c72c4a20d1.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711563528738/b3c252fc-f857-4428-8df5-59c72c4a20d1.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711563528738/b3c252fc-f857-4428-8df5-59c72c4a20d1.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711563528738/b3c252fc-f857-4428-8df5-59c72c4a20d1.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;p&gt;This tutorial shows how to create a token-gated website using Clarity as the smart contract language. A token-gated website serves content to users with a certain amount of tokens in their wallets.&lt;/p&gt;
&lt;p&gt;In this tutorial, we will create two Clarity smart contracts, &lt;code&gt;FanToken&lt;/code&gt; and &lt;code&gt;TokenGatedCommunity&lt;/code&gt;. Holders of the &lt;code&gt;FanToken&lt;/code&gt; can join a community on-chain in the &lt;code&gt;TokenGatedCommunity&lt;/code&gt; contract, and our frontend will serve users different content based on membership in the &lt;code&gt;TokenGatedCommunity&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The diagram below illustrates the functionalities of the smart contracts we will be creating.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711287438371/f97e536e-5074-4bc2-b122-1b58f5def53d.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711287438371/f97e536e-5074-4bc2-b122-1b58f5def53d.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711287438371/f97e536e-5074-4bc2-b122-1b58f5def53d.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711287438371/f97e536e-5074-4bc2-b122-1b58f5def53d.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;We will get up and running quickly on the front end by creating a NextJS application using a &lt;a target=&quot;_blank&quot; href=&quot;https://docs.hiro.so/stacksjs-starters&quot;&gt;Stack.js&lt;/a&gt; template.&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/blog-newsletter-1&quot;&gt;&lt;img src=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=1400&amp;auto=format&quot; srcset=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=1 1x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=2 2x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Subscribe to the Developer DAO Newsletter. Probably Nothing&quot; class=&quot;mx-auto&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;The author assumes the following prerequisites:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A beginner understanding of Clarity smart contract language&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The reader is familiar with the use of a CLI and can navigate between folders via the CLI&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Node is installed on the development machine of the reader&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Familiarity with React and NextJS&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;heading-installing-the-clarinet-cli&quot;&gt;Installing the Clarinet CLI&lt;/h3&gt;
&lt;p&gt;Clarinet provides a CLI package with a clarity runtime, a REPL, and a testing harness. Clarinet includes a Javascript library, a testing environment, and a browser-based Sandbox. With Clarinet, you can rigorously iterate on your smart contracts locally before moving into production. Install Clarinet &lt;a target=&quot;_blank&quot; href=&quot;https://docs.hiro.so/clarinet/getting-started&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;heading-installing-the-leather-wallet&quot;&gt;Installing the Leather wallet&lt;/h3&gt;
&lt;p&gt;In this tutorial, we will deploy the smart contracts we write to the testnet environment. To do so, we need to create a wallet and acquire some testnet STX. If you haven&apos;t already done so, visit &lt;a target=&quot;_blank&quot; href=&quot;https://leather.io/&quot;&gt;Hiro&apos;s wallet page&lt;/a&gt; to install the Leather wallet.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;After creating a new wallet, make sure to save your seed phrase somewhere safe. You will need it, along with the password you set when creating the wallet, every time you want to log into your wallet after logging out.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can request some testnet STX by navigating to &lt;a target=&quot;_blank&quot; href=&quot;https://explorer.hiro.so/sandbox/faucet?chain=testnet&quot;&gt;Hiro&apos;s testnet explorer sandbox&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711222495545/b4a7c32e-0813-48ca-87e4-75c914b60072.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711222495545/b4a7c32e-0813-48ca-87e4-75c914b60072.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711222495545/b4a7c32e-0813-48ca-87e4-75c914b60072.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711222495545/b4a7c32e-0813-48ca-87e4-75c914b60072.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-setting-up-the-project&quot;&gt;Setting up the project&lt;/h2&gt;
&lt;p&gt;Now that we have created a wallet let&apos;s proceed with the project. Create a new directory on your development machine to house the project. This directory will contain the smart contract and frontend application.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir tokenGateTutorial
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;cd&lt;/span&gt; tokenGateTutorial
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Clarity smart contract will be set up inside the project folder &lt;code&gt;tokenGateTutorial&lt;/code&gt;. The &lt;code&gt;clarinet&lt;/code&gt; command is used to scaffold a new Clarity project. This command becomes available after the successful installation of Clarity on our development machine.&lt;/p&gt;
&lt;p&gt;To scaffold a new Clarity project, run the command below from the location of the &lt;code&gt;tokenGateTutorial&lt;/code&gt; folder&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;clarinet new token-contracts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command scaffolds a new Clarity smart contract project inside a folder called &lt;code&gt;token-contracts&lt;/code&gt;. The folder name can be called anything you wish. Navigate into the &lt;code&gt;token-contracts&lt;/code&gt; folder to inspect the files and folders created by the &lt;code&gt;clarinet new folder-name&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711016799804/cfaf7518-eb20-4613-a681-b4cc15ae8181.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711016799804/cfaf7518-eb20-4613-a681-b4cc15ae8181.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711016799804/cfaf7518-eb20-4613-a681-b4cc15ae8181.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711016799804/cfaf7518-eb20-4613-a681-b4cc15ae8181.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;There is a&lt;code&gt;contracts&lt;/code&gt; folder where the &lt;code&gt;FanToken&lt;/code&gt; and &lt;code&gt;TokenGatedCommunity&lt;/code&gt; contracts will be stored. There is also a &lt;code&gt;settings&lt;/code&gt; folder that contains three files: &lt;code&gt;Devnet.toml&lt;/code&gt;, &lt;code&gt;Mainnet.toml&lt;/code&gt; and &lt;code&gt;Testnet.toml.&lt;/code&gt; These files contain the seed phrases of wallet accounts used for the deployment of contracts to the different environments of &lt;code&gt;Devnet&lt;/code&gt;, &lt;code&gt;Mainnet&lt;/code&gt; and &lt;code&gt;Testnet respectively&lt;/code&gt;. The project also contains the root &lt;code&gt;Clarinet.toml&lt;/code&gt; configuration file and our test folder for writing tests.&lt;/p&gt;
&lt;p&gt;Let&apos;s get to work and write our smart contract in the next section.&lt;/p&gt;
&lt;h2 id=&quot;heading-creating-the-fantoken-contract&quot;&gt;Creating the FanToken contract&lt;/h2&gt;
&lt;p&gt;Navigate into the &lt;code&gt;contracts&lt;/code&gt; folder and run the code below to create a new smart contract.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;clarinet contracts new FanToken
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command creates our actual Clarity file, &lt;code&gt;FanToken.clar&lt;/code&gt; inside the contracts directory. This is the location where we will write the &lt;code&gt;FanToken&lt;/code&gt; contract.&lt;/p&gt;
&lt;p&gt;Open the file FanToken.clar, delete the comments inside, and copy and replace the code below into the file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;;; traits&lt;/span&gt;
(&lt;span&gt;define-trait&lt;/span&gt; sip-010-trait
  (
    (&lt;span&gt;transfer&lt;/span&gt; (&lt;span&gt;uint&lt;/span&gt; principal principal (&lt;span&gt;optional&lt;/span&gt; (&lt;span&gt;buff&lt;/span&gt; &lt;span&gt;34&lt;/span&gt;))) (&lt;span&gt;response&lt;/span&gt; bool uint))
    (&lt;span&gt;get-name&lt;/span&gt; () (&lt;span&gt;response&lt;/span&gt; (&lt;span&gt;string-ascii&lt;/span&gt; &lt;span&gt;32&lt;/span&gt;) uint))
    (&lt;span&gt;get-symbol&lt;/span&gt; () (&lt;span&gt;response&lt;/span&gt; (&lt;span&gt;string-ascii&lt;/span&gt; &lt;span&gt;32&lt;/span&gt;) uint))
    (&lt;span&gt;get-decimals&lt;/span&gt; () (&lt;span&gt;response&lt;/span&gt; uint uint))
    (&lt;span&gt;get-balance&lt;/span&gt; (&lt;span&gt;principal&lt;/span&gt;) (&lt;span&gt;response&lt;/span&gt; uint uint))
    (&lt;span&gt;get-total-supply&lt;/span&gt; () (&lt;span&gt;response&lt;/span&gt; uint uint))
    (&lt;span&gt;get-token-uri&lt;/span&gt; () (&lt;span&gt;response&lt;/span&gt; (&lt;span&gt;optional&lt;/span&gt; (&lt;span&gt;string-utf8&lt;/span&gt; &lt;span&gt;256&lt;/span&gt;)) uint))
  )
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this snippet above, we are defining traits for a token. A trait is a standard or an interface to which an implementing token must conform. Top on the trait list is a&lt;code&gt;transfer&lt;/code&gt; function used to transfer tokens between principals. Addresses in Clarity are referred to as&lt;code&gt;principal&lt;/code&gt;. There are two types of &lt;code&gt;principal&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Standard Principal: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM&lt;/code&gt; :&lt;/p&gt;
&lt;p&gt;  &lt;code&gt;standard principal&lt;/code&gt; is backed by a corresponding private key used for the signing of transactions. This &lt;code&gt;principal&lt;/code&gt; starts with the letter ST, denoting that it can only be used in the testnet environment, while the mainnet principal begins with the letter SP and can be used in the mainnet environment.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Contract Principal: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.FanToken&lt;/code&gt; :&lt;/p&gt;
&lt;p&gt;  A &lt;code&gt;contract principal&lt;/code&gt; is the address of the deployed contract. It is a combination of the &lt;code&gt;standard principal&lt;/code&gt; who deployed the contract and the contract name.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&apos;s continue with the implementation of the token methods. Copy the code below and add it to the file &lt;code&gt;FanToken.clar&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&lt;span&gt;;;previous traits definition above&lt;/span&gt;

&lt;span&gt;;; token definitions &lt;/span&gt;
&lt;span&gt;;;one million tokens total supply&lt;/span&gt;
(&lt;span&gt;define-fungible-token&lt;/span&gt; fanToken u1000000000000) 
&lt;span&gt;;; constants&lt;/span&gt;
(&lt;span&gt;define-constant&lt;/span&gt; contract-owner tx-sender)
(&lt;span&gt;define-constant&lt;/span&gt; err-owner-only (&lt;span&gt;err&lt;/span&gt; u100))
(&lt;span&gt;define-constant&lt;/span&gt; err-not-token-owner (&lt;span&gt;err&lt;/span&gt; u101))
(&lt;span&gt;define-constant&lt;/span&gt; err-amount-less-than-zero (&lt;span&gt;err&lt;/span&gt; u102))

&lt;span&gt;;;#[allow(unchecked_data)]&lt;/span&gt;
(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;mint&lt;/span&gt; (&lt;span&gt;amount&lt;/span&gt; uint) (&lt;span&gt;recipient&lt;/span&gt; principal))
    (&lt;span&gt;begin&lt;/span&gt;
        (&lt;span&gt;asserts!&lt;/span&gt; (&lt;span&gt;&amp;gt;&lt;/span&gt; amount u0) err-amount-less-than-zero)
        (&lt;span&gt;ft-mint&lt;/span&gt;? fanToken amount recipient)
    )
)

&lt;span&gt;;;#[allow(unchecked_data)]&lt;/span&gt;
(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;transfer&lt;/span&gt; (&lt;span&gt;amount&lt;/span&gt; uint) (&lt;span&gt;sender&lt;/span&gt; principal) (&lt;span&gt;recipient&lt;/span&gt; principal) (&lt;span&gt;memo&lt;/span&gt; (&lt;span&gt;optional&lt;/span&gt; (&lt;span&gt;buff&lt;/span&gt; &lt;span&gt;34&lt;/span&gt;))))
    (&lt;span&gt;begin&lt;/span&gt;
        (&lt;span&gt;asserts!&lt;/span&gt; (&lt;span&gt;&amp;gt;&lt;/span&gt; amount u0) err-amount-less-than-zero)
        (&lt;span&gt;asserts!&lt;/span&gt; (&lt;span&gt;is-eq&lt;/span&gt; tx-sender sender) err-not-token-owner)
        (&lt;span&gt;try!&lt;/span&gt; (&lt;span&gt;ft-transfer&lt;/span&gt;? fanToken amount sender recipient))
        (&lt;span&gt;match&lt;/span&gt; memo to-print (&lt;span&gt;print&lt;/span&gt; to-print) &lt;span&gt;0&lt;/span&gt;x)
        (&lt;span&gt;ok&lt;/span&gt; true)
    )
)
&lt;span&gt;;; read only functions&lt;/span&gt;
(&lt;span&gt;define-read-only&lt;/span&gt; (&lt;span&gt;get-balance&lt;/span&gt; (&lt;span&gt;owner&lt;/span&gt; principal))
    (&lt;span&gt;ok&lt;/span&gt; (&lt;span&gt;ft-get-balance&lt;/span&gt; fanToken owner))
)
(&lt;span&gt;define-read-only&lt;/span&gt; (&lt;span&gt;get-total-supply&lt;/span&gt;)
    (&lt;span&gt;ok&lt;/span&gt; (&lt;span&gt;ft-get-supply&lt;/span&gt; fanToken))
)
(&lt;span&gt;define-read-only&lt;/span&gt; (&lt;span&gt;get-token-uri&lt;/span&gt;)
    (&lt;span&gt;ok&lt;/span&gt; none)
)
(&lt;span&gt;define-read-only&lt;/span&gt; (&lt;span&gt;get-name&lt;/span&gt;)
    (&lt;span&gt;ok&lt;/span&gt; &lt;span&gt;&quot;FanToken&quot;&lt;/span&gt;)
)
(&lt;span&gt;define-read-only&lt;/span&gt; (&lt;span&gt;get-symbol&lt;/span&gt;)
    (&lt;span&gt;ok&lt;/span&gt; &lt;span&gt;&quot;FT&quot;&lt;/span&gt;)
)
(&lt;span&gt;define-read-only&lt;/span&gt; (&lt;span&gt;get-decimals&lt;/span&gt;)
    (&lt;span&gt;ok&lt;/span&gt; u6)
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At the top of the code, a fungible token &lt;code&gt;FanToken&lt;/code&gt; is defined as Clarity has built-in support for fungible and non-fungible tokens (NFTs). The token has a decimal of 6 digits and a total supply of one million. &lt;code&gt;(define-fungible-token fanToken u1000000000000)&lt;/code&gt;. The &lt;code&gt;u&lt;/code&gt; in front of the digits represents an unsigned integer type.&lt;/p&gt;
&lt;p&gt;After the token definition, we have some declared constant values. The first is the &lt;code&gt;contract-owner&lt;/code&gt; which is equated to &lt;code&gt;tx-sender&lt;/code&gt;. &lt;code&gt;tx-sender&lt;/code&gt; refers to the &lt;code&gt;principal&lt;/code&gt; executing the transaction. In this instance, the &lt;code&gt;contract-owner&lt;/code&gt; will be the deployer of the contract. We also define other constants that denote different error messages.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;mint&lt;/code&gt; function is a public function that allocates tokens to a receiver. The function takes in two parameters of type &lt;code&gt;unit&lt;/code&gt; and &lt;code&gt;principal.&lt;/code&gt; Inside the function body, there&apos;s a&lt;code&gt;begin&lt;/code&gt; block used to combine different statements for execution.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;assert!&lt;/code&gt; block checks for the correctness or truthfulness of a statement. The &lt;code&gt;asserts!&lt;/code&gt; check is to see if the amount we want to mint exceeds 0. If the &lt;code&gt;asserts!&lt;/code&gt; block passes, the token amount is minted to the recipient &lt;code&gt;principal&lt;/code&gt; using the built-in mint function provided by Clarity. &lt;code&gt;(ft-mint? fanToken amount recipient)&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This token is set up this way for demonstration purpose as any &lt;code&gt;principal&lt;/code&gt; can mint the token.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;
(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;mint&lt;/span&gt; (&lt;span&gt;amount&lt;/span&gt; uint) (&lt;span&gt;recipient&lt;/span&gt; principal))
    (&lt;span&gt;begin&lt;/span&gt;
        (&lt;span&gt;asserts!&lt;/span&gt; (&lt;span&gt;&amp;gt;&lt;/span&gt; amount u0) err-amount-less-than-zero)
        (&lt;span&gt;ft-mint&lt;/span&gt;? fanToken amount recipient)
    )
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The&lt;code&gt;transfer&lt;/code&gt; function is used to move tokens between different accounts. The &lt;code&gt;transfer&lt;/code&gt; function takes four arguments, which are the &lt;code&gt;amount&lt;/code&gt; to transfer, the &lt;code&gt;sender&lt;/code&gt; (owner) of the token, the &lt;code&gt;recipient&lt;/code&gt; of the token, and an optional &lt;code&gt;bytes&lt;/code&gt; variable called &lt;code&gt;memo&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Inside the function body, we have a&lt;code&gt;begin&lt;/code&gt; block that contains other statements written inside it. The first&lt;code&gt;asserts!&lt;/code&gt; statement checks if the &lt;code&gt;amount&lt;/code&gt; being transferred is greater than 0, and the next &lt;code&gt;asserts!&lt;/code&gt; statement checks if &lt;code&gt;tx-sender&lt;/code&gt; is equal to the &lt;code&gt;sender&lt;/code&gt; arguments.&lt;/p&gt;
&lt;p&gt;If both &lt;code&gt;asserts!&lt;/code&gt; pass, we attempt to transfer the token using another built-in Clarity method,&lt;code&gt;ft-transfer&lt;/code&gt;. The transfer of the token is wrapped in a &lt;code&gt;try&lt;/code&gt; block. The &lt;code&gt;try&lt;/code&gt; block controls the flow of the program; if the transfer is unsuccessful, the execution halts.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;match&lt;/code&gt; block checks the provision of the optional parameter, &lt;code&gt;memo&lt;/code&gt;. If &lt;code&gt;memo&lt;/code&gt; is passed to the &lt;code&gt;transfer&lt;/code&gt; function, it binds the value &lt;code&gt;memo&lt;/code&gt; to the variable&lt;code&gt;to-print&lt;/code&gt;. The print statement emits the bonded variable. If &lt;code&gt;memo&lt;/code&gt; was not passed, we write 0x.&lt;/p&gt;
&lt;p&gt;At the end of the function, we return a response &lt;code&gt;(ok true)&lt;/code&gt; indicating that all went well and the changes made in the function can be committed to the blockchain. A public function must return a &lt;code&gt;response&lt;/code&gt; of either success or failure.&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;&lt;code&gt;
(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;transfer&lt;/span&gt; (&lt;span&gt;amount&lt;/span&gt; uint) (&lt;span&gt;sender&lt;/span&gt; principal) (&lt;span&gt;recipient&lt;/span&gt; principal) (&lt;span&gt;memo&lt;/span&gt; (&lt;span&gt;optional&lt;/span&gt; (&lt;span&gt;buff&lt;/span&gt; &lt;span&gt;34&lt;/span&gt;))))
    (&lt;span&gt;begin&lt;/span&gt;
        (&lt;span&gt;asserts!&lt;/span&gt; (&lt;span&gt;&amp;gt;&lt;/span&gt; amount u0) err-amount-less-than-zero)
        (&lt;span&gt;asserts!&lt;/span&gt; (&lt;span&gt;is-eq&lt;/span&gt; tx-sender sender) err-not-token-owner)
        (&lt;span&gt;try!&lt;/span&gt; (&lt;span&gt;ft-transfer&lt;/span&gt;? fanToken amount sender recipient))
        (&lt;span&gt;match&lt;/span&gt; memo to-print (&lt;span&gt;print&lt;/span&gt; to-print) &lt;span&gt;0&lt;/span&gt;x)
        (&lt;span&gt;ok&lt;/span&gt; true)
    )
)
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;We are done discussing the two main functions of the &lt;code&gt;FanToken&lt;/code&gt; contract, the other functions in the contract are &lt;code&gt;read-only&lt;/code&gt; that display the token data.&lt;/p&gt;
&lt;h3 id=&quot;heading-testing-fantoken-in-the-terminal&quot;&gt;Testing FanToken in the terminal&lt;/h3&gt;
&lt;p&gt;We have successfully created a contract, so let&apos;s deploy it for testing at the terminal. Navigate to the &lt;code&gt;contracts&lt;/code&gt; folder located inside the &lt;code&gt;token-contract&lt;/code&gt; folder. Run the code. This Clarinet CLI command loads and deploys contracts in the terminal environment.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;clarinet console
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a nice way of testing your contract manually before deploying. You can execute the contract&apos;s methods from the CLI.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711098799048/bf106b0c-6881-4cf6-b459-376966757897.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711098799048/bf106b0c-6881-4cf6-b459-376966757897.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711098799048/bf106b0c-6881-4cf6-b459-376966757897.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711098799048/bf106b0c-6881-4cf6-b459-376966757897.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;To test our &lt;code&gt;mint&lt;/code&gt; function, run the code below at the terminal.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;contract-call&lt;/span&gt;? .FanToken mint u4000000000 tx-sender)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We are calling a contract named; the dot in front of &lt;code&gt;FanToken&lt;/code&gt; it is a shorthand way of representing the &lt;code&gt;principal&lt;/code&gt; contract that was deployed. Remember, a contract &lt;code&gt;principal&lt;/code&gt; is a combination of the &lt;code&gt;standard principal&lt;/code&gt; that deployed the contract and the contract name. We are executing the contract in the context of the deployer account; that&apos;s why the shortcut.&lt;code&gt;FanToken&lt;/code&gt; works.&lt;/p&gt;
&lt;p&gt;The next parameter passed to the &lt;code&gt;contract-call?&lt;/code&gt; block after the contract name is the function name, which, in our case, is &lt;code&gt;mint&lt;/code&gt;. Then, the parameters of the function are passed after the function name. We are minting &lt;code&gt;4000 FT&lt;/code&gt; (FT token uses 6 digits) for the &lt;code&gt;principaltx-sender.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Execute the code, and you will get a similar output below. A print block was emitted as the tokens were minted and transferred to &lt;code&gt;tx-sender&lt;/code&gt;. A &lt;code&gt;response(ok true)&lt;/code&gt; was returned from the function, showing that the execution was successful.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711100177527/eb3f631a-7e3c-4ca5-890d-ada57b2149e2.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711100177527/eb3f631a-7e3c-4ca5-890d-ada57b2149e2.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711100177527/eb3f631a-7e3c-4ca5-890d-ada57b2149e2.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711100177527/eb3f631a-7e3c-4ca5-890d-ada57b2149e2.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;We can check the balance of &lt;code&gt;tx-sender&lt;/code&gt; by executing the &lt;code&gt;get-balance&lt;/code&gt; function.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;contract-call&lt;/span&gt;? .FanToken get-balance tx-sender)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711100581538/16f271bb-bf86-40ad-b575-e44bc16c20f4.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711100581538/16f271bb-bf86-40ad-b575-e44bc16c20f4.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711100581538/16f271bb-bf86-40ad-b575-e44bc16c20f4.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711100581538/16f271bb-bf86-40ad-b575-e44bc16c20f4.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-creating-the-tokengatedcommunity-contract&quot;&gt;Creating the TokenGatedCommunity contract&lt;/h2&gt;
&lt;p&gt;We shall proceed to create the second contract&lt;code&gt;TokenGatedCommunity&lt;/code&gt;. Copy the code below and post it in the &lt;code&gt;TokenGatedCommunity.char&lt;/code&gt; file located in the contracts folder.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&lt;span&gt;;; title: TokenGatedCommunity&lt;/span&gt;
&lt;span&gt;;; version: 1.0&lt;/span&gt;
&lt;span&gt;;; summary: &lt;/span&gt;
&lt;span&gt;;; description:&lt;/span&gt;


&lt;span&gt;;; constants&lt;/span&gt;
(&lt;span&gt;define-constant&lt;/span&gt; contract-owner tx-sender)
(&lt;span&gt;define-constant&lt;/span&gt; err-insufficient-token-balance (&lt;span&gt;err&lt;/span&gt; u1002))
(&lt;span&gt;define-constant&lt;/span&gt; err-getting-balance (&lt;span&gt;err&lt;/span&gt; u1003))
(&lt;span&gt;define-constant&lt;/span&gt; err-not-the-owner (&lt;span&gt;err&lt;/span&gt; u1004))
(&lt;span&gt;define-constant&lt;/span&gt; err-token-not-greaterThan-Zero (&lt;span&gt;err&lt;/span&gt; u1005))
(&lt;span&gt;define-constant&lt;/span&gt; err-unwrap-failed (&lt;span&gt;err&lt;/span&gt; u1006))
(&lt;span&gt;define-constant&lt;/span&gt; err-already-a-member (&lt;span&gt;err&lt;/span&gt; u1007))
(&lt;span&gt;define-constant&lt;/span&gt; err-not-a-member (&lt;span&gt;err&lt;/span&gt; u1008))

(&lt;span&gt;define-map&lt;/span&gt; tokenBalances principal uint)

&lt;span&gt;;; data vars&lt;/span&gt;
(&lt;span&gt;define-data-var&lt;/span&gt; entryTokenAmount uint u50000000) &lt;span&gt;;;50 FT&lt;/span&gt;


(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;joinCommunity&lt;/span&gt;) 
  (&lt;span&gt;begin&lt;/span&gt;
    (&lt;span&gt;if&lt;/span&gt; (&lt;span&gt;is-none&lt;/span&gt; (&lt;span&gt;userTokenBalance&lt;/span&gt; tx-sender))
       (&lt;span&gt;transferTokenAndJoinCommunity&lt;/span&gt; (&lt;span&gt;var-get&lt;/span&gt; entryTokenAmount))
      err-already-a-member
    )
  )
)

 (&lt;span&gt;define-private&lt;/span&gt; (&lt;span&gt;transferTokenAndJoinCommunity&lt;/span&gt; (&lt;span&gt;tokenAmount&lt;/span&gt; uint)) 
   (&lt;span&gt;begin&lt;/span&gt; 
    (&lt;span&gt;try!&lt;/span&gt; (&lt;span&gt;contract-call&lt;/span&gt;? .FanToken transfer tokenAmount tx-sender (&lt;span&gt;as-contract&lt;/span&gt; tx-sender) none))
    (&lt;span&gt;map-set&lt;/span&gt; tokenBalances tx-sender tokenAmount)
    (&lt;span&gt;ok&lt;/span&gt; true)
   )
 )

 (&lt;span&gt;define-private&lt;/span&gt; (&lt;span&gt;payoutTokens&lt;/span&gt; (&lt;span&gt;receiver&lt;/span&gt; principal) (&lt;span&gt;amount&lt;/span&gt; uint))
     (&lt;span&gt;begin&lt;/span&gt; 
        (&lt;span&gt;asserts!&lt;/span&gt; (&lt;span&gt;is-eq&lt;/span&gt; .TokenGatedCommunity (&lt;span&gt;as-contract&lt;/span&gt; tx-sender)) err-not-the-owner )
        (&lt;span&gt;try!&lt;/span&gt; (&lt;span&gt;as-contract&lt;/span&gt; (&lt;span&gt;contract-call&lt;/span&gt;? .FanToken transfer amount .TokenGatedCommunity receiver  none)))
        (&lt;span&gt;ok&lt;/span&gt; true)
      )
  )

 (&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;removeTokenAndExitCommunity&lt;/span&gt;)
     (
        &lt;span&gt;let&lt;/span&gt; (
            (&lt;span&gt;balance&lt;/span&gt; (&lt;span&gt;unwrap!&lt;/span&gt; (&lt;span&gt;userTokenBalance&lt;/span&gt; tx-sender) err-not-a-member))
        )

        (&lt;span&gt;try!&lt;/span&gt; (&lt;span&gt;payoutTokens&lt;/span&gt; tx-sender balance))
        (&lt;span&gt;map-delete&lt;/span&gt; tokenBalances tx-sender)
        (&lt;span&gt;ok&lt;/span&gt; true)
     )
 )

&lt;span&gt;;;public-function&lt;/span&gt;
(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;setEntryTokenAmount&lt;/span&gt; (&lt;span&gt;newEntryTokenAmount&lt;/span&gt; uint) ) 
    (&lt;span&gt;begin&lt;/span&gt;
        (&lt;span&gt;asserts!&lt;/span&gt; (&lt;span&gt;is-eq&lt;/span&gt; tx-sender contract-owner) err-not-the-owner)
        (&lt;span&gt;asserts!&lt;/span&gt; (&lt;span&gt;&amp;gt;&lt;/span&gt; newEntryTokenAmount u0) err-token-not-greaterThan-Zero)
        (&lt;span&gt;var-set&lt;/span&gt; entryTokenAmount newEntryTokenAmount)
        (&lt;span&gt;ok&lt;/span&gt; true)
     )
)

(&lt;span&gt;define-read-only&lt;/span&gt; (&lt;span&gt;userTokenBalance&lt;/span&gt; (&lt;span&gt;user&lt;/span&gt; principal)) 
   (&lt;span&gt;map-get&lt;/span&gt;? tokenBalances user)
)

(&lt;span&gt;define-read-only&lt;/span&gt; (&lt;span&gt;isUserACommunityMember&lt;/span&gt; (&lt;span&gt;user&lt;/span&gt; principal)) 
   (&lt;span&gt;match&lt;/span&gt; (&lt;span&gt;map-get&lt;/span&gt;? tokenBalances user) bal
     (&lt;span&gt;begin&lt;/span&gt; 
       bal
      (&lt;span&gt;ok&lt;/span&gt; true)
     )
     (&lt;span&gt;ok&lt;/span&gt; false)
   )
)

&lt;span&gt;;;read-only function&lt;/span&gt;
(&lt;span&gt;define-read-only&lt;/span&gt; (&lt;span&gt;getEntryTokenAmount&lt;/span&gt;)
     (&lt;span&gt;ok&lt;/span&gt; (&lt;span&gt;var-get&lt;/span&gt; entryTokenAmount))
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At the top of the contract, some useful constants are defined. The &lt;code&gt;contract-owner&lt;/code&gt; is set to the contract deployer. Some other declared constant variables are used to represent errors.&lt;/p&gt;
&lt;p&gt;A data variable &lt;code&gt;(define-data-var entryTokenAmount uint u50000000)&lt;/code&gt; called &lt;code&gt;entryToken&lt;/code&gt; is defined, and its initial value is set at 50 FT tokens.&lt;/p&gt;
&lt;p&gt;The functionality of this contract;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;users send &lt;code&gt;FanToken&lt;/code&gt; to the contract, and they are registered in the community; their principal is added to a &lt;code&gt;data-map&lt;/code&gt; variable &lt;code&gt;tokenBalances&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;users can withdraw their &lt;code&gt;FanToken&lt;/code&gt; from the &lt;code&gt;TokenGateCommunity&lt;/code&gt; contract, and their principal is deleted from the &lt;code&gt;data-map&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;heading-sending-tokens-to-the-tokengatecommunity-contract&quot;&gt;Sending tokens to the &lt;code&gt;TokenGateCommunity&lt;/code&gt; Contract&lt;/h3&gt;
&lt;p&gt;The public function &lt;code&gt;joinCommunity&lt;/code&gt; adds the user to the community if they are not already a member. Let&apos;s dissect the function to see how it works&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;joinCommunity&lt;/span&gt;) 
  (&lt;span&gt;begin&lt;/span&gt;
    (&lt;span&gt;if&lt;/span&gt; (&lt;span&gt;is-none&lt;/span&gt; (&lt;span&gt;userTokenBalance&lt;/span&gt; tx-sender))
      (&lt;span&gt;transferTokenAndJoinCommunity&lt;/span&gt; (&lt;span&gt;var-get&lt;/span&gt; entryTokenAmount))
      err-already-a-member
    )
  )
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The function accepts no parameter; inside the &lt;code&gt;begin&lt;/code&gt; block, a &lt;code&gt;read-only&lt;/code&gt; function &lt;code&gt;userTokenBalance&lt;/code&gt; returns a value of an &lt;code&gt;optional&lt;/code&gt; from the variable&lt;code&gt;tokenBalances&lt;/code&gt; of the user ( caller of the function ). The return value of &lt;code&gt;userTokenBalace&lt;/code&gt; could either be a &lt;code&gt;(some unit)&lt;/code&gt; if the user &lt;code&gt;principal&lt;/code&gt; is on the &lt;code&gt;data-map&lt;/code&gt; variable or&lt;code&gt;none&lt;/code&gt; if it is not on the data-map variable.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(&lt;span&gt;define-read-only&lt;/span&gt; (&lt;span&gt;userTokenBalance&lt;/span&gt; (&lt;span&gt;user&lt;/span&gt; principal)) 
   (&lt;span&gt;map-get&lt;/span&gt;? tokenBalances user)
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;if block&lt;/code&gt; checks the boolean value of the result from the &lt;code&gt;is-none&lt;/code&gt; block. If the result from &lt;code&gt;userTokenBalance&lt;/code&gt; is &lt;code&gt;noneis-none&lt;/code&gt; block returns &lt;code&gt;true&lt;/code&gt; and if the result is &lt;code&gt;(some unit)is-none&lt;/code&gt; block returns &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The if block runs when the user is not already a community member. The private function &lt;code&gt;transferTokenAndJoinCommunity&lt;/code&gt; is executed. The function is accepted as a parameter; this is the entry fee used to join the community.&lt;/p&gt;
&lt;p&gt;An external &lt;code&gt;contract-call?&lt;/code&gt; is made to the &lt;code&gt;.FanToken&lt;/code&gt; contract, calling its &lt;code&gt;transfer&lt;/code&gt; function. An amount of tokens equal to the parameter &lt;code&gt;tokenAmount&lt;/code&gt; is transferred from the user account to the &lt;code&gt;TokenGatedCommunity&lt;/code&gt; contract. This transfer is wrapped in a &lt;code&gt;try!&lt;/code&gt; block that halts contract execution if the token transfer fails.&lt;/p&gt;
&lt;p&gt;Next, the user is added to the &lt;code&gt;data-map&lt;/code&gt; , a &lt;code&gt;response&lt;/code&gt; of &lt;code&gt;ok&lt;/code&gt; is returned to the function caller. The token has been transferred successfully to the &lt;code&gt;TokenGatedCommunity&lt;/code&gt; contract, and the user is now a community member.&lt;/p&gt;
&lt;p&gt;The remaining portion left to dissect in the &lt;code&gt;joinCommunity&lt;/code&gt; function is the &lt;code&gt;else&lt;/code&gt; part of the &lt;code&gt;if&lt;/code&gt; block. This throws an error stating that the user is already a community member.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
(&lt;span&gt;define-private&lt;/span&gt; (&lt;span&gt;transferTokenAndJoinCommunity&lt;/span&gt; (&lt;span&gt;tokenAmount&lt;/span&gt; uint)) 
   (&lt;span&gt;begin&lt;/span&gt; 
    (&lt;span&gt;try!&lt;/span&gt; (&lt;span&gt;contract-call&lt;/span&gt;? .FanToken transfer tokenAmount tx-sender (&lt;span&gt;as-contract&lt;/span&gt; tx-sender) none))
    (&lt;span&gt;map-set&lt;/span&gt; tokenBalances tx-sender tokenAmount)
    (&lt;span&gt;ok&lt;/span&gt; true)
   )
 )
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;heading-withdrawing-tokens-from-the-tokengatecommunity-contract&quot;&gt;Withdrawing tokens from the &lt;code&gt;TokenGateCommunity&lt;/code&gt; Contract&lt;/h3&gt;
&lt;p&gt;This is when the user gets tired of the community and wants to leave. Ideally, they should get their tokens back from the &lt;code&gt;TokenGateCommunity&lt;/code&gt; contract and their &lt;code&gt;principal&lt;/code&gt; deleted from the &lt;code&gt;userTokenBalancesdata-map&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&apos;s see the implementation details:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; (&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;removeTokenAndExitCommunity&lt;/span&gt;)
     (
        &lt;span&gt;let&lt;/span&gt; (
            (&lt;span&gt;balance&lt;/span&gt; (&lt;span&gt;unwrap!&lt;/span&gt; (&lt;span&gt;userTokenBalance&lt;/span&gt; tx-sender) err-not-a-member))
        )
        (&lt;span&gt;try!&lt;/span&gt; (&lt;span&gt;payoutTokens&lt;/span&gt; tx-sender balance))
        (&lt;span&gt;map-delete&lt;/span&gt; tokenBalances tx-sender)
        (&lt;span&gt;ok&lt;/span&gt; true)
     )
 )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The public function &lt;code&gt;removeTokenAndExitCommunity&lt;/code&gt; is called by the user to exit the community and get paid their tokens. Inside the function, there&apos;s a &lt;code&gt;let&lt;/code&gt; block used to save values in a temporary data-binding variable called &lt;code&gt;balance&lt;/code&gt;. The &lt;code&gt;unwraps!&lt;/code&gt; function unwraps the &lt;code&gt;optional&lt;/code&gt; value returned from the read-only function &lt;code&gt;userTokenBalance.&lt;/code&gt; If unwrap was successful, the user token balance in the contract is stored in the temp variable &lt;code&gt;balance&lt;/code&gt; but if &lt;code&gt;unwrap!&lt;/code&gt; encounters a value of &lt;code&gt;none&lt;/code&gt; in the function, meaning the &lt;code&gt;principal&lt;/code&gt; is not in the &lt;code&gt;tokenBalancesdata-map&lt;/code&gt;, it throws an &lt;code&gt;err-not-a-member&lt;/code&gt; error.&lt;/p&gt;
&lt;p&gt;After retrieving the user token stored by the contract, the private function &lt;code&gt;payoutTokens&lt;/code&gt; is called with two parameters of the user &lt;code&gt;principal&lt;/code&gt; and the user token amount in the contract. Let&apos;s examine the &lt;code&gt;payoutTokens&lt;/code&gt; function below:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  (&lt;span&gt;define-private&lt;/span&gt; (&lt;span&gt;payoutTokens&lt;/span&gt; (&lt;span&gt;receiver&lt;/span&gt; principal) (&lt;span&gt;amount&lt;/span&gt; uint))
     (&lt;span&gt;begin&lt;/span&gt; 
        (&lt;span&gt;asserts!&lt;/span&gt; (&lt;span&gt;is-eq&lt;/span&gt; .TokenGatedCommunity (&lt;span&gt;as-contract&lt;/span&gt; tx-sender)) err-not-the-owner )
        (&lt;span&gt;try!&lt;/span&gt; (&lt;span&gt;as-contract&lt;/span&gt; (&lt;span&gt;contract-call&lt;/span&gt;? .FanToken transfer amount .TokenGatedCommunity receiver  none)))
        (&lt;span&gt;ok&lt;/span&gt; true)
      )
    )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The function starts with a &lt;code&gt;begin&lt;/code&gt; block, which contains three statements. The first is an &lt;code&gt;asserts!&lt;/code&gt; function that checks the equality of the &lt;code&gt;contract principal&lt;/code&gt; with the caller; the &lt;code&gt;(as-contract tx-sender)&lt;/code&gt; calls a function in the context of the contract and not the wallet &lt;code&gt;principal&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The next statement makes an external call to the &lt;code&gt;transfer&lt;/code&gt; function of &lt;code&gt;.FanToken&lt;/code&gt; contract in the context of the &lt;code&gt;.TokenGatedCommunity&lt;/code&gt; contract. This is necessary to transfer the tokens, as the tokens are owned by the &lt;code&gt;.TokenGatedCommunity&lt;/code&gt; contract at this point. We return a &lt;code&gt;response&lt;/code&gt; of &lt;code&gt;ok&lt;/code&gt; if the tokens were successfully transferred to the recipient.&lt;/p&gt;
&lt;p&gt;Finally in the &lt;code&gt;removeTokenAndExitCommunity&lt;/code&gt; function, the user is deleted from the &lt;code&gt;tokenBalancesdata-map&lt;/code&gt; and a &lt;code&gt;response&lt;/code&gt; of &lt;code&gt;ok&lt;/code&gt; is returned from the function.&lt;/p&gt;
&lt;h3 id=&quot;heading-setting-the-entrytokenamount-value&quot;&gt;Setting the &lt;code&gt;entryTokenAmount&lt;/code&gt; value&lt;/h3&gt;
&lt;p&gt;The function sets the value of the data variable &lt;code&gt;entryTokenAmount.&lt;/code&gt; The &lt;code&gt;setEntryToken&lt;/code&gt; function accepts a &lt;code&gt;newEntryTokenAmount&lt;/code&gt; as a parameter with a type of &lt;code&gt;unit&lt;/code&gt;. The first &lt;code&gt;asserts!&lt;/code&gt; checks that the &lt;code&gt;contract-ownerconstant&lt;/code&gt; is the same as the &lt;code&gt;principal&lt;/code&gt; calling the function. The next &lt;code&gt;asserts!&lt;/code&gt; performs data sanitation, ensuring that the passed parameter is greater than &lt;code&gt;0.&lt;/code&gt; The value of &lt;code&gt;entryTokenAmount&lt;/code&gt; is changed using the &lt;code&gt;var-set&lt;/code&gt; function. A &lt;code&gt;response&lt;/code&gt; of type &lt;code&gt;(ok true)&lt;/code&gt; is returned from the function.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;;;public-function&lt;/span&gt;
(&lt;span&gt;define-public&lt;/span&gt; (&lt;span&gt;setEntryTokenAmount&lt;/span&gt; (&lt;span&gt;newEntryTokenAmount&lt;/span&gt; uint) ) 
(&lt;span&gt;begin&lt;/span&gt;
    (&lt;span&gt;asserts!&lt;/span&gt; (&lt;span&gt;is-eq&lt;/span&gt; tx-sender contract-owner) err-not-the-owner)
    (&lt;span&gt;asserts!&lt;/span&gt; (&lt;span&gt;&amp;gt;&lt;/span&gt; newEntryTokenAmount u0) err-token-not-greaterThan-Zero)
    (&lt;span&gt;var-set&lt;/span&gt; entryTokenAmount newEntryTokenAmount)
    (&lt;span&gt;ok&lt;/span&gt; true)
)
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wooh! We have come to the end of creating the smart contracts. You can test this contract the same way we tested the &lt;code&gt;FanToken&lt;/code&gt; contract.&lt;/p&gt;
&lt;h2 id=&quot;heading-deploying-clarity-smart-contracts-to-testnet&quot;&gt;Deploying Clarity smart contracts to testnet&lt;/h2&gt;
&lt;p&gt;Navigate to the &lt;code&gt;settings&lt;/code&gt; folder in the Clarity project. The folder contains three files &lt;code&gt;Devnet.toml&lt;/code&gt;, &lt;code&gt;Testnet.toml&lt;/code&gt; and &lt;code&gt;Mainnet.toml&lt;/code&gt; contained inside the contracts folder. These files will contain the seed phrases for the wallet that will deploy the contract in the respective environment of &lt;code&gt;Devnet&lt;/code&gt;, &lt;code&gt;Testnet&lt;/code&gt; and &lt;code&gt;Mainnet&lt;/code&gt;. &lt;code&gt;Devnet.toml&lt;/code&gt; is already filled with different wallet seed phrases.&lt;/p&gt;
&lt;p&gt;Open the &lt;code&gt;Testnet.toml&lt;/code&gt; and replace &quot;&lt;code&gt;&amp;lt;YOUR PRIVATE TESTNET MNEMONIC HERE&amp;gt;&lt;/code&gt;&quot; with the seed phrase from the wallet we created earlier.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711223560574/07967f5b-4886-44ba-95a2-9ccbbfc6368b.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711223560574/07967f5b-4886-44ba-95a2-9ccbbfc6368b.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711223560574/07967f5b-4886-44ba-95a2-9ccbbfc6368b.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711223560574/07967f5b-4886-44ba-95a2-9ccbbfc6368b.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Move into the &lt;code&gt;contracts&lt;/code&gt; folder of the &lt;code&gt;Clarinet&lt;/code&gt; project and run the command below to generate a deployment file for the testnet environment.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;clarinet deployment generate --testnet --low-cost
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command generates a deployment file for &lt;code&gt;testnet&lt;/code&gt; using low-cost fees for the deployment. If we are deploying to &lt;code&gt;mainnet&lt;/code&gt;, we change &lt;code&gt;--testnet&lt;/code&gt; to &lt;code&gt;--mainnet&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After creating the deployment file, the next step is to apply the file and deploy the contract to the chosen environment. This command applies the deployment:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;clarinet deployment apply -p deployments/default.testnet-plan.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The smart contracts are broadcast and deployed to the network. Our contract name is a combination of the &lt;code&gt;principal&lt;/code&gt; that deployed the contract and the contract name.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711224388782/ed71c388-f4aa-43f2-8859-9b5734f2f130.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711224388782/ed71c388-f4aa-43f2-8859-9b5734f2f130.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711224388782/ed71c388-f4aa-43f2-8859-9b5734f2f130.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711224388782/ed71c388-f4aa-43f2-8859-9b5734f2f130.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;heading-deploying-to-devnet&quot;&gt;Deploying to devnet&lt;/h3&gt;
&lt;p&gt;We will also deploy the smart contracts to devnet. Hiro has a wonderful explorer that can be used to simulate and test the functionality of contracts on the devnet. Deploying to the devnet is straightforward. Before proceeding, you should install Docker on your system. If you haven&apos;t installed it yet, you can i&lt;a target=&quot;_blank&quot; href=&quot;https://docs.docker.com/get-docker/&quot;&gt;nstall it from the official page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If Docker has been installed, open the contracts folder of the Clarity projects at the terminal and run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;clarinet devnet start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Docker will download the containers needed to run the devnet the first time you run this command. It might take a little time, so be patient. Your terminal will look similar to the one below when the devnet is running. Stacks Devnet Explorer runs on &lt;code&gt;localhost:8000&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711395131165/0f6519a7-779f-44e7-804e-bcbd96e77935.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711395131165/0f6519a7-779f-44e7-804e-bcbd96e77935.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711395131165/0f6519a7-779f-44e7-804e-bcbd96e77935.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711395131165/0f6519a7-779f-44e7-804e-bcbd96e77935.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Keep the devnet terminal running, and let&apos;s proceed to the frontend to connect our application to the devnet blockchain.&lt;/p&gt;
&lt;h2 id=&quot;heading-creating-a-nextjs-frontend&quot;&gt;Creating a NextJS frontend&lt;/h2&gt;
&lt;p&gt;The smart contracts part of our application is ready. The next step is to create a NextJS frontend that will interact with the contracts. We will use &lt;a target=&quot;_blank&quot; href=&quot;https://docs.hiro.so/stacksjs-starters&quot;&gt;Hiro starter templates&lt;/a&gt; for fast iteration.&lt;/p&gt;
&lt;p&gt;Navigate to the root folder of your project and create a new folder named &lt;code&gt;frontend&lt;/code&gt;. &lt;code&gt;cd&lt;/code&gt; into the &lt;code&gt;frontend&lt;/code&gt; folder and run the code below to create the NextJS application.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm create stacks --template .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;stacks&lt;/code&gt; tool will walk you through creating a NextJS project. The period &lt;code&gt;(.)&lt;/code&gt; after the word &lt;code&gt;--template&lt;/code&gt; means we want the NextJS application to be installed in the current directory. Enter &lt;code&gt;frontend&lt;/code&gt; as the package name when prompted by the CLI and follow the other prompts to install a NextJS application.&lt;/p&gt;
&lt;p&gt;Next, install dependencies by running the command below to install the application dependencies.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The frontend application is started by running &lt;code&gt;npm run dev&lt;/code&gt;. The starter template makes our integration faster as it contains useful boilerplate code, which we can modify to suit our needs.&lt;/p&gt;
&lt;p&gt;Let&apos;s do a little bit of housekeeping. You can delete the &lt;code&gt;ContractVote.js&lt;/code&gt; file found in &lt;code&gt;src/components&lt;/code&gt; folder. Delete the content of &lt;code&gt;ConnectWallet.js&lt;/code&gt; file located in the components directory and replace it with the below code;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&quot;use client&quot;&lt;/span&gt;;

&lt;span&gt;import&lt;/span&gt; React, { useEffect, useState } &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&quot;react&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; { AppConfig, showConnect, UserSession } &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&quot;@stacks/connect&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; styles &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&quot;../app/page.module.css&quot;&lt;/span&gt;;

&lt;span&gt;const&lt;/span&gt; appConfig = &lt;span&gt;new&lt;/span&gt; AppConfig([&lt;span&gt;&quot;store_write&quot;&lt;/span&gt;, &lt;span&gt;&quot;publish_data&quot;&lt;/span&gt;]);

&lt;span&gt;export&lt;/span&gt; &lt;span&gt;const&lt;/span&gt; userSession = &lt;span&gt;new&lt;/span&gt; UserSession({ appConfig });

&lt;span&gt;const&lt;/span&gt; trimAddress = &lt;span&gt;(&lt;span&gt;address&lt;/span&gt;) =&amp;gt;&lt;/span&gt; {
  &lt;span&gt;if&lt;/span&gt; (address) {
    &lt;span&gt;const&lt;/span&gt; start = address.substr(&lt;span&gt;0&lt;/span&gt;, &lt;span&gt;6&lt;/span&gt;);
    &lt;span&gt;const&lt;/span&gt; middle = &lt;span&gt;&quot;.....&quot;&lt;/span&gt;;
    &lt;span&gt;const&lt;/span&gt; end = address.substr(address.length - &lt;span&gt;6&lt;/span&gt;, address.length)
    &lt;span&gt;return&lt;/span&gt; &lt;span&gt;`&lt;span&gt;${start}&lt;/span&gt;&lt;span&gt;${middle}&lt;/span&gt;&lt;span&gt;${end}&lt;/span&gt;`&lt;/span&gt;
  }
  &lt;span&gt;return&lt;/span&gt; &lt;span&gt;null&lt;/span&gt;;
}

&lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;authenticate&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;/span&gt;{
  showConnect({
    &lt;span&gt;appDetails&lt;/span&gt;: {
      &lt;span&gt;name&lt;/span&gt;: &lt;span&gt;&quot;Token Gated Demo&quot;&lt;/span&gt;,
      &lt;span&gt;icon&lt;/span&gt;: &lt;span&gt;window&lt;/span&gt;.location.origin + &lt;span&gt;&quot;/logo512.png&quot;&lt;/span&gt;,
    },
    &lt;span&gt;redirectTo&lt;/span&gt;: &lt;span&gt;&quot;/&quot;&lt;/span&gt;,
    &lt;span&gt;onFinish&lt;/span&gt;: &lt;span&gt;() =&amp;gt;&lt;/span&gt; {
      &lt;span&gt;window&lt;/span&gt;.location.reload();
    },
    userSession,
  });
}

&lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;disconnect&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;/span&gt;{
  userSession.signUserOut(&lt;span&gt;&quot;/&quot;&lt;/span&gt;);
}

&lt;span&gt;const&lt;/span&gt; ConnectWallet = &lt;span&gt;() =&amp;gt;&lt;/span&gt; {
  &lt;span&gt;const&lt;/span&gt; [mounted, setMounted] = useState(&lt;span&gt;false&lt;/span&gt;);
  useEffect(&lt;span&gt;() =&amp;gt;&lt;/span&gt; setMounted(&lt;span&gt;true&lt;/span&gt;), []);

  &lt;span&gt;if&lt;/span&gt; (mounted &amp;amp;&amp;amp; userSession.isUserSignedIn()) {
    &lt;span&gt;return&lt;/span&gt; (
      &lt;span&gt;&lt;span&gt;&amp;lt;&lt;span&gt;div&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;&quot;Container&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span&gt;&amp;lt;&lt;span&gt;button&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.buttonConnected}&lt;/span&gt; &lt;span&gt;onClick&lt;/span&gt;=&lt;span&gt;{disconnect}&lt;/span&gt;&amp;gt;&lt;/span&gt;
          Disconnect Wallet {trimAddress(userSession.loadUserData().profile.stxAddress.testnet)}
        &lt;span&gt;&amp;lt;/&lt;span&gt;button&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span&gt;&amp;lt;/&lt;span&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    );
  }

  &lt;span&gt;return&lt;/span&gt; (
    &lt;span&gt;&lt;span&gt;&amp;lt;&lt;span&gt;button&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.button}&lt;/span&gt; &lt;span&gt;onClick&lt;/span&gt;=&lt;span&gt;{authenticate}&lt;/span&gt;&amp;gt;&lt;/span&gt;
      Connect Wallet
    &lt;span&gt;&amp;lt;/&lt;span&gt;button&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  );
};

&lt;span&gt;export&lt;/span&gt; &lt;span&gt;default&lt;/span&gt; ConnectWallet;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The addition we made to the file is the &lt;code&gt;trimAddress&lt;/code&gt; function used to trim the connected wallet &lt;code&gt;principal&lt;/code&gt;. We won&apos;t be discussing any &lt;code&gt;CSS&lt;/code&gt; styles in this integration.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ConnectWallet&lt;/code&gt; component shows a button asking a user to connect their wallet. Most of the code is boilerplate, and we won&apos;t spend time discussing it. The meat of the &lt;code&gt;frontend&lt;/code&gt; application will be in the &lt;code&gt;page.js&lt;/code&gt; located in the app folder.&lt;/p&gt;
&lt;p&gt;Open the &lt;code&gt;page.js&lt;/code&gt; file and replace its content following code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&quot;use client&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; { useEffect, useState } &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&quot;react&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; styles &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&quot;./page.module.css&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; { Connect } &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&quot;@stacks/connect-react&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; ConnectWallet, { userSession } &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&quot;/../components/ConnectWallet&quot;&lt;/span&gt;;

&lt;span&gt;const&lt;/span&gt; deployer = &lt;span&gt;&quot;replace-with-the-account-that-deployed-the-project&quot;&lt;/span&gt; &lt;span&gt;//acount that deployed the contract&lt;/span&gt;
&lt;span&gt;export&lt;/span&gt; &lt;span&gt;default&lt;/span&gt; &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;Home&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;/span&gt;{
  &lt;span&gt;const&lt;/span&gt; [isClient, setIsClient] = useState(&lt;span&gt;false&lt;/span&gt;);
  &lt;span&gt;const&lt;/span&gt; [isQualified, setIsQualified] = useState(&lt;span&gt;false&lt;/span&gt;);
  &lt;span&gt;const&lt;/span&gt; [userTokenAmount, setUserTokenAmount] = useState(&lt;span&gt;0&lt;/span&gt;)
  &lt;span&gt;const&lt;/span&gt; [tokensToMint, setTokensToMint] = useState(&lt;span&gt;0&lt;/span&gt;);
  &lt;span&gt;const&lt;/span&gt; [tokenReceiver, setTokenReceiver] = useState(&lt;span&gt;null&lt;/span&gt;)


  useEffect(&lt;span&gt;() =&amp;gt;&lt;/span&gt; {
    setIsClient(&lt;span&gt;true&lt;/span&gt;);
  }, []);


  &lt;span&gt;if&lt;/span&gt; (!isClient) &lt;span&gt;return&lt;/span&gt; &lt;span&gt;null&lt;/span&gt;;

  &lt;span&gt;return&lt;/span&gt; (
    &lt;span&gt;&lt;span&gt;&amp;lt;&lt;span&gt;Connect&lt;/span&gt;
      &lt;span&gt;authOptions&lt;/span&gt;=&lt;span&gt;{{&lt;/span&gt;
        &lt;span&gt;appDetails:&lt;/span&gt; {
          &lt;span&gt;name:&lt;/span&gt; &quot;&lt;span&gt;Token&lt;/span&gt; &lt;span&gt;Gated&lt;/span&gt; &lt;span&gt;Community&lt;/span&gt;&quot;,
          &lt;span&gt;icon:&lt;/span&gt; &lt;span&gt;window.location.origin&lt;/span&gt; + &quot;/&lt;span&gt;logo.png&lt;/span&gt;&quot;,
        },
        &lt;span&gt;redirectTo:&lt;/span&gt; &quot;/&quot;,
        &lt;span&gt;onFinish:&lt;/span&gt; () =&amp;gt;&lt;/span&gt; {
          window.location.reload();
        },
        userSession,
      }}
    &amp;gt;
      &lt;span&gt;&amp;lt;&lt;span&gt;div&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.container}&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span&gt;&amp;lt;&lt;span&gt;header&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.header}&lt;/span&gt;&amp;gt;&lt;/span&gt;
          &lt;span&gt;&amp;lt;&lt;span&gt;h1&lt;/span&gt;&amp;gt;&lt;/span&gt;Token Gated Website&lt;span&gt;&amp;lt;/&lt;span&gt;h1&lt;/span&gt;&amp;gt;&lt;/span&gt;
          &lt;span&gt;&amp;lt;&lt;span&gt;nav&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.nav}&lt;/span&gt;&amp;gt;&lt;/span&gt;

            &lt;span&gt;&amp;lt;&lt;span&gt;ConnectWallet&lt;/span&gt; /&amp;gt;&lt;/span&gt;

          &lt;span&gt;&amp;lt;/&lt;span&gt;nav&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span&gt;&amp;lt;/&lt;span&gt;header&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span&gt;&amp;lt;&lt;span&gt;main&lt;/span&gt;&amp;gt;&lt;/span&gt;


          &lt;span&gt;&amp;lt;&lt;span&gt;div&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.inputContainerColumn}&lt;/span&gt;&amp;gt;&lt;/span&gt;
            &lt;span&gt;&amp;lt;&lt;span&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;Mint FT Tokens&lt;span&gt;&amp;lt;/&lt;span&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt; &lt;span&gt;&amp;amp;nbsp;&lt;/span&gt;
            &lt;span&gt;&amp;lt;&lt;span&gt;input&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.input}&lt;/span&gt; &lt;span&gt;value&lt;/span&gt;=&lt;span&gt;{tokensToMint}&lt;/span&gt;
              &lt;span&gt;onChange&lt;/span&gt;=&lt;span&gt;{(e)&lt;/span&gt; =&amp;gt;&lt;/span&gt; setTokensToMint(e.target.value)}
              type=&quot;number&quot; placeholder=&quot;00&quot;
            /&amp;gt;
            &lt;span&gt;&amp;lt;&lt;span&gt;input&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.input}&lt;/span&gt;
              &lt;span&gt;type&lt;/span&gt;=&lt;span&gt;&quot;text&quot;&lt;/span&gt;
              &lt;span&gt;placeholder&lt;/span&gt;=&lt;span&gt;&quot;principal to receive the token&quot;&lt;/span&gt;
              &lt;span&gt;value&lt;/span&gt;=&lt;span&gt;{tokenReceiver}&lt;/span&gt;
              &lt;span&gt;onChange&lt;/span&gt;=&lt;span&gt;{(e)&lt;/span&gt; =&amp;gt;&lt;/span&gt; setTokenReceiver(e.target.value)}

            /&amp;gt;
            &lt;span&gt;&amp;lt;&lt;span&gt;button&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.button}&lt;/span&gt;&amp;gt;&lt;/span&gt;Mint FT Tokens&lt;span&gt;&amp;lt;/&lt;span&gt;button&lt;/span&gt;&amp;gt;&lt;/span&gt;
          &lt;span&gt;&amp;lt;/&lt;span&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;


          {!isQualified &amp;amp;&amp;amp;
            &lt;span&gt;&amp;lt;&lt;span&gt;div&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.container}&lt;/span&gt;&amp;gt;&lt;/span&gt;
              &lt;span&gt;&amp;lt;&lt;span&gt;h3&lt;/span&gt;&amp;gt;&lt;/span&gt;Join Community&lt;span&gt;&amp;lt;/&lt;span&gt;h3&lt;/span&gt;&amp;gt;&lt;/span&gt;

              &lt;span&gt;&amp;lt;&lt;span&gt;button&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.button}&lt;/span&gt;
                &amp;gt;&lt;/span&gt;Join Community&lt;span&gt;&amp;lt;/&lt;span&gt;button&lt;/span&gt;&amp;gt;&lt;/span&gt;
            &lt;span&gt;&amp;lt;/&lt;span&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
          }



          {/*Token gated content */}

          {isQualified &amp;amp;&amp;amp;

            &lt;span&gt;&amp;lt;&lt;span&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
              &lt;span&gt;&amp;lt;&lt;span&gt;h1&lt;/span&gt;&amp;gt;&lt;/span&gt;Welcome to the community of dog lovers Premium content&lt;span&gt;&amp;lt;/&lt;span&gt;h1&lt;/span&gt;&amp;gt;&lt;/span&gt;
              &lt;span&gt;&amp;lt;&lt;span&gt;h3&lt;/span&gt;&amp;gt;&lt;/span&gt;This part of the website is token gated!&lt;span&gt;&amp;lt;/&lt;span&gt;h3&lt;/span&gt;&amp;gt;&lt;/span&gt;
              &lt;span&gt;&amp;lt;&lt;span&gt;div&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.card}&lt;/span&gt;&amp;gt;&lt;/span&gt;
                &lt;span&gt;&amp;lt;&lt;span&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;Send a transaction to change the entryTokenAmount variable&lt;span&gt;&amp;lt;/&lt;span&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;
                &lt;span&gt;&amp;lt;&lt;span&gt;div&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.inputContainer}&lt;/span&gt;&amp;gt;&lt;/span&gt;
                  &lt;span&gt;&amp;lt;&lt;span&gt;input&lt;/span&gt; &lt;span&gt;type&lt;/span&gt;=&lt;span&gt;&quot;number&quot;&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.input}&lt;/span&gt; &lt;span&gt;placeholder&lt;/span&gt;=&lt;span&gt;&quot;00&quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;
                  &lt;span&gt;&amp;lt;&lt;span&gt;button&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.button}&lt;/span&gt;&amp;gt;&lt;/span&gt;Change Entry Fee&lt;span&gt;&amp;lt;/&lt;span&gt;button&lt;/span&gt;&amp;gt;&lt;/span&gt;
                &lt;span&gt;&amp;lt;/&lt;span&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
              &lt;span&gt;&amp;lt;/&lt;span&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;



              &lt;span&gt;&amp;lt;&lt;span&gt;div&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.inputContainer}&lt;/span&gt;&amp;gt;&lt;/span&gt;
                &lt;span&gt;&amp;lt;&lt;span&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;Exit Community and claim back your tokens&lt;span&gt;&amp;lt;/&lt;span&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;

                &lt;span&gt;&amp;lt;&lt;span&gt;button&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.button}&lt;/span&gt;&amp;gt;&lt;/span&gt;Exit Community&lt;span&gt;&amp;lt;/&lt;span&gt;button&lt;/span&gt;&amp;gt;&lt;/span&gt;
              &lt;span&gt;&amp;lt;/&lt;span&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;

            &lt;span&gt;&amp;lt;/&lt;span&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;

          }


        &lt;span&gt;&amp;lt;/&lt;span&gt;main&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span&gt;&amp;lt;/&lt;span&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span&gt;&amp;lt;/&lt;span&gt;Connect&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The application should look like the one below. At the top of the file, we specified that the file will only run in the client environment, &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useEffect&lt;/code&gt; is imported from react.&lt;/p&gt;
&lt;p&gt;Some &lt;code&gt;react&lt;/code&gt; state is defined that will be used in the application. Look at the &lt;code&gt;deployer&lt;/code&gt; variable; replace this value with the account that deployed the contract. If working with devnet this will be the first account listed in the &lt;code&gt;Devnet.toml&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ConnectWallet&lt;/code&gt; button was imported, as well as a &lt;code&gt;Connect&lt;/code&gt; component from the package &lt;code&gt;@stacks/connect-react&lt;/code&gt;. The &lt;code&gt;Connect&lt;/code&gt; component manages the user session as they sign out and sign in via their wallets.&lt;/p&gt;
&lt;p&gt;The simple UI of the front end will allow a user to mint &lt;code&gt;FanToken&lt;/code&gt;, join the community, and exit the community. The &lt;code&gt;isQualified&lt;/code&gt; state renders the token-gated portion of the website if its value is &lt;code&gt;true&lt;/code&gt;. Let&apos;s see how to read contract value from a Clarity smart contract in the frontend application.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711397951218/140e8b8b-3298-4ef7-b7a4-39f9d5c1b858.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1711397951218/140e8b8b-3298-4ef7-b7a4-39f9d5c1b858.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711397951218/140e8b8b-3298-4ef7-b7a4-39f9d5c1b858.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1711397951218/140e8b8b-3298-4ef7-b7a4-39f9d5c1b858.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;heading-reading-values-from-clarity-smart-contracts-using-stacksjs&quot;&gt;Reading values from Clarity smart contracts using Stacks.js&lt;/h3&gt;
&lt;p&gt;The first function we shall implement reads the amount of FanToken owned by the signed-in user. Copy and paste the code below in the &lt;code&gt;page.js&lt;/code&gt; file after the useEffect function.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; &lt;span&gt;import&lt;/span&gt; { StacksTestnet, StacksDevnet } &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&quot;@stacks/network&quot;&lt;/span&gt;;
 &lt;span&gt;import&lt;/span&gt; { callReadOnlyFunction, standardPrincipalCV } &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&apos;@stacks/transactions&apos;&lt;/span&gt;;

&lt;span&gt;//code removed here&lt;/span&gt;

  useEffect(&lt;span&gt;() =&amp;gt;&lt;/span&gt; {
    setIsClient(&lt;span&gt;true&lt;/span&gt;);
  }, []);

&lt;span&gt;const&lt;/span&gt; getTokenBalance = &lt;span&gt;async&lt;/span&gt; () =&amp;gt; {
    &lt;span&gt;const&lt;/span&gt; userDevnetAddress = userSession.loadUserData().profile.stxAddress.testnet
    &lt;span&gt;console&lt;/span&gt;.log(&lt;span&gt;&quot;devNetAddress &quot;&lt;/span&gt;, userDevnetAddress)
    &lt;span&gt;try&lt;/span&gt; {
      &lt;span&gt;const&lt;/span&gt; contractName = &lt;span&gt;&apos;FanToken&apos;&lt;/span&gt;;
      &lt;span&gt;const&lt;/span&gt; functionName = &lt;span&gt;&apos;get-balance&apos;&lt;/span&gt;;
      &lt;span&gt;const&lt;/span&gt; network = &lt;span&gt;new&lt;/span&gt; StacksDevnet();
      &lt;span&gt;const&lt;/span&gt; senderAddress = userDevnetAddress;
      &lt;span&gt;const&lt;/span&gt; options = {
        &lt;span&gt;contractAddress&lt;/span&gt;: deployer,
        contractName,
        functionName,
        &lt;span&gt;functionArgs&lt;/span&gt;: [standardPrincipalCV(userDevnetAddress)],
        network,
        senderAddress,
      };
      &lt;span&gt;const&lt;/span&gt; result = &lt;span&gt;await&lt;/span&gt; callReadOnlyFunction(options);
      &lt;span&gt;const&lt;/span&gt; { &lt;span&gt;value&lt;/span&gt;: { value } } = result
      &lt;span&gt;const&lt;/span&gt; tokenAmount = +value.toString() / &lt;span&gt;1&lt;/span&gt;_000_000
      setUserTokenAmount(tokenAmount)
      &lt;span&gt;console&lt;/span&gt;.log(&lt;span&gt;&quot;result =&amp;gt; &quot;&lt;/span&gt;, tokenAmount + &lt;span&gt;&quot;FT&quot;&lt;/span&gt;)
    } &lt;span&gt;catch&lt;/span&gt; (error) {
      &lt;span&gt;console&lt;/span&gt;.log(&lt;span&gt;&quot;error =&amp;gt; &quot;&lt;/span&gt;, error);
    }
  };

&lt;span&gt;//code remove for brevity&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;getTokenBalance&lt;/code&gt; gets the balance of the user token. This is a read-only function, so we ain&apos;t making a transaction. We imported &lt;code&gt;StacksDevnet&lt;/code&gt; network from the &lt;code&gt;@stacks/network&lt;/code&gt;. If the contract we are working with is deployed on a &lt;code&gt;testnet&lt;/code&gt;, we will use the &lt;code&gt;StacksTestnet&lt;/code&gt; network constructor.&lt;/p&gt;
&lt;p&gt;The connected user wallet is retrieved from the &lt;code&gt;userSession&lt;/code&gt; object, and an options object that contains the following properties is constructed;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; &lt;span&gt;const&lt;/span&gt; options = {
        &lt;span&gt;contractAddress&lt;/span&gt;: deployer,
        contractName,
        functionName,
        &lt;span&gt;functionArgs&lt;/span&gt;: [standardPrincipalCV(userDevnetAddress)],
        network,
        senderAddress,
      };
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Function arguments have to be converted to &lt;code&gt;Clarity&lt;/code&gt; type. The &lt;code&gt;standardPrincipalCV&lt;/code&gt; converts the user address to a &lt;code&gt;Clarity principal&lt;/code&gt; type. Next, we call the contract, passing the &lt;code&gt;options&lt;/code&gt; object we have defined and &lt;code&gt;await&lt;/code&gt; the result of the call.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;const&lt;/span&gt; result = &lt;span&gt;await&lt;/span&gt; callReadOnlyFunction(options);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The result is an object that contains the user balance sent from the smart contract we just read. We destructure the result object and divide the value obtained by &lt;code&gt;100000&lt;/code&gt; to get the token amount, as the &lt;code&gt;FanToken&lt;/code&gt; operates internally with 6 digits. Lastly, we update the state using &lt;code&gt;setUserTokenAmount&lt;/code&gt; function.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;const&lt;/span&gt; { &lt;span&gt;value&lt;/span&gt;: { value } } = result
&lt;span&gt;const&lt;/span&gt; tokenAmount = +value.toString() / &lt;span&gt;1&lt;/span&gt;_000_000
setUserTokenAmount(tokenAmount)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The&lt;code&gt;getTokenBalance&lt;/code&gt; function is triggered in a &lt;code&gt;useEffect&lt;/code&gt; when the user sign in in with the wallet. Add this useEffect code;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  useEffect(&lt;span&gt;() =&amp;gt;&lt;/span&gt; {
    getTokenBalance()
    isUserACommunityMember()
  }, [userSession.isUserSignedIn()])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s define another read-only function that checks if the user is a community member, &lt;code&gt;isUserACommunityMember&lt;/code&gt;. Copy and paste the code below in the page.js file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;import&lt;/span&gt; {
  callReadOnlyFunction, standardPrincipalCV, ClarityType, AnchorMode,
  PostConditionMode, contractPrincipalCV, uintCV
} &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&apos;@stacks/transactions&apos;&lt;/span&gt;;
&lt;span&gt;//top of code removed. paste after the getTokenBalance function&lt;/span&gt;
 &lt;span&gt;const&lt;/span&gt; isUserACommunityMember = &lt;span&gt;async&lt;/span&gt; () =&amp;gt; {
    &lt;span&gt;const&lt;/span&gt; userDevnetAddress = userSession.loadUserData().profile.stxAddress.testnet
    &lt;span&gt;try&lt;/span&gt; {
      &lt;span&gt;const&lt;/span&gt; contractName = &lt;span&gt;&apos;TokenGatedCommunity&apos;&lt;/span&gt;;
      &lt;span&gt;const&lt;/span&gt; functionName = &lt;span&gt;&apos;isUserACommunityMember&apos;&lt;/span&gt;;
      &lt;span&gt;const&lt;/span&gt; network = &lt;span&gt;new&lt;/span&gt; StacksDevnet();
      &lt;span&gt;const&lt;/span&gt; senderAddress = userDevnetAddress;
      &lt;span&gt;const&lt;/span&gt; options = {
        &lt;span&gt;contractAddress&lt;/span&gt;: deployer,
        contractName,
        functionName,
        &lt;span&gt;functionArgs&lt;/span&gt;: [standardPrincipalCV(userDevnetAddress)],
        network,
        senderAddress,
      };
      &lt;span&gt;const&lt;/span&gt; result = &lt;span&gt;await&lt;/span&gt; callReadOnlyFunction(options);
      &lt;span&gt;if&lt;/span&gt; (result.value.type == ClarityType.BoolTrue) {
        setIsQualified(&lt;span&gt;true&lt;/span&gt;)
      } &lt;span&gt;else&lt;/span&gt; {
        setIsQualified(&lt;span&gt;false&lt;/span&gt;)
      }
    } &lt;span&gt;catch&lt;/span&gt; (error) {
      &lt;span&gt;console&lt;/span&gt;.log(&lt;span&gt;&quot;error =&amp;gt; &quot;&lt;/span&gt;, error);
    }
  };
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function calls the &lt;code&gt;isUserACommunityMember&lt;/code&gt; function of the &lt;code&gt;TokenGatedCommunity&lt;/code&gt; contract. The function returns a boolean indicating whether the user is a member. The state &lt;code&gt;isQualified&lt;/code&gt; is set based on the passed boolean result.&lt;/p&gt;
&lt;h3 id=&quot;heading-sending-transactions-to-a-clarity-contract-using-stacksjs&quot;&gt;Sending transactions to a Clarity contract using Stacks.js&lt;/h3&gt;
&lt;p&gt;We will examine how to send transactions to our smart contracts. Previously, we saw how to obtain values from the contract via read-only functions. This section will examine the &lt;code&gt;mintToken&lt;/code&gt; function to see how this is done. The mintFunction is used to mint tokens; it accepts a token amount and the receiver address as parameters. The user needs to have some tokens before joining the community, so the &lt;code&gt;mintToken&lt;/code&gt; function gives the user free tokens.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;const&lt;/span&gt; mintTokens = &lt;span&gt;async&lt;/span&gt; () =&amp;gt; {
    &lt;span&gt;let&lt;/span&gt; amount = tokensToMint * &lt;span&gt;1000&lt;/span&gt;_000; &lt;span&gt;//token is 6 digit&lt;/span&gt;
    amount = uintCV(amount);
    openContractCall({
      &lt;span&gt;network&lt;/span&gt;: &lt;span&gt;new&lt;/span&gt; StacksDevnet(), &lt;span&gt;//on testnet new StacksTestnet()&lt;/span&gt;
      &lt;span&gt;anchorMode&lt;/span&gt;: AnchorMode.Any,
      &lt;span&gt;contractAddress&lt;/span&gt;: deployer,
      &lt;span&gt;contractName&lt;/span&gt;: &lt;span&gt;&apos;FanToken&apos;&lt;/span&gt;,
      &lt;span&gt;functionName&lt;/span&gt;: &lt;span&gt;&apos;mint&apos;&lt;/span&gt;,
      &lt;span&gt;functionArgs&lt;/span&gt;: [amount, standardPrincipalCV(tokenReceiver)],
      &lt;span&gt;postConditionMode&lt;/span&gt;: PostConditionMode.Deny,
      &lt;span&gt;postConditions&lt;/span&gt;: [],
      &lt;span&gt;onFinish&lt;/span&gt;: &lt;span&gt;&lt;span&gt;data&lt;/span&gt; =&amp;gt;&lt;/span&gt; {
        &lt;span&gt;// WHEN user confirms pop-up&lt;/span&gt;
        setTokensToMint(&lt;span&gt;0&lt;/span&gt;)
        setTokenReceiver(&lt;span&gt;null&lt;/span&gt;)
        &lt;span&gt;//on testnet the url will be =&amp;gt; https://explorer.hiro.so/txid/${data.txId}?chain=testnet&lt;/span&gt;
        &lt;span&gt;window&lt;/span&gt;
          .open(
            &lt;span&gt;`http://localhost:8000/txid/&lt;span&gt;${data.txId}&lt;/span&gt;?chain=testnet&amp;amp;api=http://localhost:3999`&lt;/span&gt;,
            &lt;span&gt;&quot;_blank&quot;&lt;/span&gt;
          )
          .focus();
      },
      &lt;span&gt;onCancel&lt;/span&gt;: &lt;span&gt;() =&amp;gt;&lt;/span&gt; {
        &lt;span&gt;// WHEN user cancels/closes pop-up&lt;/span&gt;
        &lt;span&gt;console&lt;/span&gt;.log(&lt;span&gt;&quot;onCancel:&quot;&lt;/span&gt;, &lt;span&gt;&quot;Transaction was canceled&quot;&lt;/span&gt;);
      },
    });
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Transactions are sent using the &lt;code&gt;openContractCall&lt;/code&gt; Stacks.js function. The function accepts as an argument an object that contains the &lt;code&gt;functionName&lt;/code&gt;, &lt;code&gt;contractAddress&lt;/code&gt; like the &lt;code&gt;callReadOnlyFunction&lt;/code&gt; we used earlier to get the token balance. It also contains additional properties like &lt;code&gt;postConditionMode&lt;/code&gt;, &lt;code&gt;postCondition&lt;/code&gt; , &lt;code&gt;onFinish&lt;/code&gt; and &lt;code&gt;onCancel&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;postCondistionMode&lt;/code&gt; has a value of &lt;code&gt;PostConditionMode.Deny&lt;/code&gt; and &lt;code&gt;PostConditionMode.Allow&lt;/code&gt;. &lt;code&gt;PostConditionMode.Deny&lt;/code&gt;means that tokens will not be transferred from the user. This protects the user against malicious contracts, as the transaction will revert if any such token transfer is attempted. The &lt;code&gt;postCodition&lt;/code&gt; array sets conditions specifying how many tokens can be withdrawn from the user.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;onFinish&lt;/code&gt; function is triggered after the transaction has been created; in this example, we open the explorer to view the transaction. &lt;code&gt;onCancel&lt;/code&gt; is triggered if the user cancels the transaction. The value of the amount of token we are minting is retrieved from the &lt;code&gt;tokenToMint&lt;/code&gt; state, and it is converted to a &lt;code&gt;Clarity&lt;/code&gt; type of &lt;code&gt;uintCV,&lt;/code&gt; so also the token receiver value is converted to a &lt;code&gt;standardPrincipal&lt;/code&gt; and both values are passed to the &lt;code&gt;functionArgs&lt;/code&gt; array.&lt;/p&gt;
&lt;p&gt;After minting the tokens, we can refresh the page to see our minted token. There are two more transactions to define for this webpage: a transaction function to join the community and another function to exit the community.&lt;/p&gt;
&lt;h3 id=&quot;heading-finishing-the-frontend&quot;&gt;Finishing the frontend&lt;/h3&gt;
&lt;p&gt;The complete code of the &lt;code&gt;page.js&lt;/code&gt; function is given below. We define a function &lt;code&gt;joinTokenGatedCommunity&lt;/code&gt; and &lt;code&gt;exitTokenGatedCommunity&lt;/code&gt; and some other utility functions. The &lt;code&gt;isQualified&lt;/code&gt; state regulates access to the token-gated parts of the webpage. &lt;code&gt;isQualified&lt;/code&gt; is set based on the value returned from the &lt;code&gt;read-only&lt;/code&gt; function &lt;code&gt;isUserACommunityMember&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Adding the complete code to &lt;code&gt;page.js&lt;/code&gt;, we will see that there is some restricted parts of our webpage. We can build on this idea to create a more robust web application for token-gated users.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&quot;use client&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; { useEffect, useState } &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&quot;react&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; styles &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&quot;./page.module.css&quot;&lt;/span&gt;;

&lt;span&gt;import&lt;/span&gt; { Connect } &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&quot;@stacks/connect-react&quot;&lt;/span&gt;;

&lt;span&gt;import&lt;/span&gt; ConnectWallet, { userSession } &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&quot;../components/ConnectWallet&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; { StacksTestnet, StacksDevnet } &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&quot;@stacks/network&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; {
  callReadOnlyFunction, standardPrincipalCV, ClarityType, AnchorMode,
  PostConditionMode, contractPrincipalCV, uintCV
} &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&apos;@stacks/transactions&apos;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; { openContractCall } &lt;span&gt;from&lt;/span&gt; &lt;span&gt;&apos;@stacks/connect&apos;&lt;/span&gt;;


&lt;span&gt;const&lt;/span&gt; deployer = &lt;span&gt;&quot;ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM&quot;&lt;/span&gt; &lt;span&gt;//acount that deployed the contract&lt;/span&gt;

&lt;span&gt;export&lt;/span&gt; &lt;span&gt;default&lt;/span&gt; &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;Home&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;/span&gt;{
  &lt;span&gt;const&lt;/span&gt; [isClient, setIsClient] = useState(&lt;span&gt;false&lt;/span&gt;);
  &lt;span&gt;const&lt;/span&gt; [isQualified, setIsQualified] = useState(&lt;span&gt;false&lt;/span&gt;);
  &lt;span&gt;const&lt;/span&gt; [userTokenAmount, setUserTokenAmount] = useState(&lt;span&gt;0&lt;/span&gt;)
  &lt;span&gt;const&lt;/span&gt; [tokensToMint, setTokensToMint] = useState(&lt;span&gt;0&lt;/span&gt;);
  &lt;span&gt;const&lt;/span&gt; [tokenReceiver, setTokenReceiver] = useState(&lt;span&gt;null&lt;/span&gt;)

  &lt;span&gt;const&lt;/span&gt; mintTokens = &lt;span&gt;async&lt;/span&gt; () =&amp;gt; {
    &lt;span&gt;let&lt;/span&gt; amount = tokensToMint * &lt;span&gt;1000&lt;/span&gt;_000; &lt;span&gt;//token is 6 digit&lt;/span&gt;
    amount = uintCV(amount);
    openContractCall({
      &lt;span&gt;network&lt;/span&gt;: &lt;span&gt;new&lt;/span&gt; StacksDevnet(), &lt;span&gt;//on testnet new StacksTestnet()&lt;/span&gt;
      &lt;span&gt;anchorMode&lt;/span&gt;: AnchorMode.Any,
      &lt;span&gt;contractAddress&lt;/span&gt;: deployer,
      &lt;span&gt;contractName&lt;/span&gt;: &lt;span&gt;&apos;FanToken&apos;&lt;/span&gt;,
      &lt;span&gt;functionName&lt;/span&gt;: &lt;span&gt;&apos;mint&apos;&lt;/span&gt;,
      &lt;span&gt;functionArgs&lt;/span&gt;: [amount, standardPrincipalCV(tokenReceiver)],

      &lt;span&gt;postConditionMode&lt;/span&gt;: PostConditionMode.Deny,
      &lt;span&gt;postConditions&lt;/span&gt;: [],

      &lt;span&gt;onFinish&lt;/span&gt;: &lt;span&gt;&lt;span&gt;data&lt;/span&gt; =&amp;gt;&lt;/span&gt; {
        &lt;span&gt;// WHEN user confirms pop-up&lt;/span&gt;
        setTokensToMint(&lt;span&gt;0&lt;/span&gt;)
        setTokenReceiver(&lt;span&gt;null&lt;/span&gt;)
        &lt;span&gt;//on testnet the url will be =&amp;gt; https://explorer.hiro.so/txid/${data.txId}?chain=testnet&lt;/span&gt;
        &lt;span&gt;window&lt;/span&gt;
          .open(
            &lt;span&gt;`http://localhost:8000/txid/&lt;span&gt;${data.txId}&lt;/span&gt;?chain=testnet&amp;amp;api=http://localhost:3999`&lt;/span&gt;,
            &lt;span&gt;&quot;_blank&quot;&lt;/span&gt;
          )
          .focus();
      },
      &lt;span&gt;onCancel&lt;/span&gt;: &lt;span&gt;() =&amp;gt;&lt;/span&gt; {
        &lt;span&gt;// WHEN user cancels/closes pop-up&lt;/span&gt;
        &lt;span&gt;console&lt;/span&gt;.log(&lt;span&gt;&quot;onCancel:&quot;&lt;/span&gt;, &lt;span&gt;&quot;Transaction was canceled&quot;&lt;/span&gt;);
      },
    });

  }


  &lt;span&gt;const&lt;/span&gt; joinTokenGatedCommunity = &lt;span&gt;async&lt;/span&gt; () =&amp;gt; {
    &lt;span&gt;try&lt;/span&gt; {
      openContractCall({
        &lt;span&gt;network&lt;/span&gt;: &lt;span&gt;new&lt;/span&gt; StacksDevnet(), &lt;span&gt;//on testnet new StacksTestnet()&lt;/span&gt;
        &lt;span&gt;anchorMode&lt;/span&gt;: AnchorMode.Any,
        &lt;span&gt;contractAddress&lt;/span&gt;: deployer,
        &lt;span&gt;contractName&lt;/span&gt;: &lt;span&gt;&apos;TokenGatedCommunity&apos;&lt;/span&gt;,
        &lt;span&gt;functionName&lt;/span&gt;: &lt;span&gt;&apos;joinCommunity&apos;&lt;/span&gt;,
        &lt;span&gt;functionArgs&lt;/span&gt;: [],

        &lt;span&gt;postConditionMode&lt;/span&gt;: PostConditionMode.Allow,
        &lt;span&gt;postConditions&lt;/span&gt;: [],
        &lt;span&gt;onFinish&lt;/span&gt;: &lt;span&gt;&lt;span&gt;data&lt;/span&gt; =&amp;gt;&lt;/span&gt; {
          setTokenReceiver(&lt;span&gt;null&lt;/span&gt;);
          setTokensToMint(&lt;span&gt;0&lt;/span&gt;)
          &lt;span&gt;// WHEN user confirms pop-up&lt;/span&gt;
          &lt;span&gt;//on testnet the url will be =&amp;gt; https://explorer.hiro.so/txid/${data.txId}?chain=testnet&lt;/span&gt;
          &lt;span&gt;window&lt;/span&gt;
            .open(
              &lt;span&gt;`http://localhost:8000/txid/&lt;span&gt;${data.txId}&lt;/span&gt;?chain=testnet&amp;amp;api=http://localhost:3999`&lt;/span&gt;,
              &lt;span&gt;&quot;_blank&quot;&lt;/span&gt;
            )
            .focus();
        },
        &lt;span&gt;onCancel&lt;/span&gt;: &lt;span&gt;() =&amp;gt;&lt;/span&gt; {
          &lt;span&gt;// WHEN user cancels/closes pop-up&lt;/span&gt;
          &lt;span&gt;console&lt;/span&gt;.log(&lt;span&gt;&quot;onCancel:&quot;&lt;/span&gt;, &lt;span&gt;&quot;Transaction was canceled&quot;&lt;/span&gt;);
        },
      });
    } &lt;span&gt;catch&lt;/span&gt; (error) {
      &lt;span&gt;console&lt;/span&gt;.log(&lt;span&gt;&quot;error =&amp;gt; &quot;&lt;/span&gt;, error);
    }
  };

  &lt;span&gt;const&lt;/span&gt; exitTokenGatedCommunity = &lt;span&gt;async&lt;/span&gt; () =&amp;gt; {
    &lt;span&gt;try&lt;/span&gt; {
      openContractCall({
        &lt;span&gt;network&lt;/span&gt;: &lt;span&gt;new&lt;/span&gt; StacksDevnet(), &lt;span&gt;//on testnet new StacksTestnet()&lt;/span&gt;
        &lt;span&gt;anchorMode&lt;/span&gt;: AnchorMode.Any,
        &lt;span&gt;contractAddress&lt;/span&gt;: deployer,
        &lt;span&gt;contractName&lt;/span&gt;: &lt;span&gt;&apos;TokenGatedCommunity&apos;&lt;/span&gt;,
        &lt;span&gt;functionName&lt;/span&gt;: &lt;span&gt;&apos;removeTokenAndExitCommunity&apos;&lt;/span&gt;,
        &lt;span&gt;functionArgs&lt;/span&gt;: [],
        &lt;span&gt;postConditionMode&lt;/span&gt;: PostConditionMode.Allow,
        &lt;span&gt;postConditions&lt;/span&gt;: [],
        &lt;span&gt;onFinish&lt;/span&gt;: &lt;span&gt;&lt;span&gt;data&lt;/span&gt; =&amp;gt;&lt;/span&gt; {
          &lt;span&gt;// WHEN user confirms pop-up&lt;/span&gt;
          &lt;span&gt;//on testnet the url will be =&amp;gt; https://explorer.hiro.so/txid/${data.txId}?chain=testnet&lt;/span&gt;
          &lt;span&gt;window&lt;/span&gt;
            .open(
              &lt;span&gt;`http://localhost:8000/txid/&lt;span&gt;${data.txId}&lt;/span&gt;?chain=testnet&amp;amp;api=http://localhost:3999`&lt;/span&gt;,
              &lt;span&gt;&quot;_blank&quot;&lt;/span&gt;
            )
            .focus();
        },
        &lt;span&gt;onCancel&lt;/span&gt;: &lt;span&gt;() =&amp;gt;&lt;/span&gt; {
          &lt;span&gt;// WHEN user cancels/closes pop-up&lt;/span&gt;
          &lt;span&gt;console&lt;/span&gt;.log(&lt;span&gt;&quot;onCancel:&quot;&lt;/span&gt;, &lt;span&gt;&quot;Transaction was canceled&quot;&lt;/span&gt;);
        },
      });
    } &lt;span&gt;catch&lt;/span&gt; (error) {
      &lt;span&gt;console&lt;/span&gt;.log(&lt;span&gt;&quot;error =&amp;gt; &quot;&lt;/span&gt;, error);
    }
  };

  &lt;span&gt;const&lt;/span&gt; getTokenBalance = &lt;span&gt;async&lt;/span&gt; () =&amp;gt; {
    &lt;span&gt;const&lt;/span&gt; userDevnetAddress = userSession.loadUserData().profile.stxAddress.testnet
    &lt;span&gt;console&lt;/span&gt;.log(&lt;span&gt;&quot;devNetAddress &quot;&lt;/span&gt;, userDevnetAddress)
    &lt;span&gt;try&lt;/span&gt; {
      &lt;span&gt;const&lt;/span&gt; contractName = &lt;span&gt;&apos;FanToken&apos;&lt;/span&gt;;
      &lt;span&gt;const&lt;/span&gt; functionName = &lt;span&gt;&apos;get-balance&apos;&lt;/span&gt;;
      &lt;span&gt;const&lt;/span&gt; network = &lt;span&gt;new&lt;/span&gt; StacksDevnet();
      &lt;span&gt;const&lt;/span&gt; senderAddress = userDevnetAddress;
      &lt;span&gt;const&lt;/span&gt; options = {
        &lt;span&gt;contractAddress&lt;/span&gt;: deployer,
        contractName,
        functionName,
        &lt;span&gt;functionArgs&lt;/span&gt;: [standardPrincipalCV(userDevnetAddress)],
        network,
        senderAddress,
      };
      &lt;span&gt;const&lt;/span&gt; result = &lt;span&gt;await&lt;/span&gt; callReadOnlyFunction(options);
      &lt;span&gt;const&lt;/span&gt; { &lt;span&gt;value&lt;/span&gt;: { value } } = result
      &lt;span&gt;const&lt;/span&gt; tokenAmount = +value.toString() / &lt;span&gt;1&lt;/span&gt;_000_000
      setUserTokenAmount(tokenAmount)
      &lt;span&gt;console&lt;/span&gt;.log(&lt;span&gt;&quot;result =&amp;gt; &quot;&lt;/span&gt;, tokenAmount + &lt;span&gt;&quot;FT&quot;&lt;/span&gt;)
    } &lt;span&gt;catch&lt;/span&gt; (error) {
      &lt;span&gt;console&lt;/span&gt;.log(&lt;span&gt;&quot;error =&amp;gt; &quot;&lt;/span&gt;, error);
    }
  };

  &lt;span&gt;const&lt;/span&gt; isUserACommunityMember = &lt;span&gt;async&lt;/span&gt; () =&amp;gt; {
    &lt;span&gt;const&lt;/span&gt; userDevnetAddress = userSession.loadUserData().profile.stxAddress.testnet
    &lt;span&gt;try&lt;/span&gt; {
      &lt;span&gt;const&lt;/span&gt; contractName = &lt;span&gt;&apos;TokenGatedCommunity&apos;&lt;/span&gt;;
      &lt;span&gt;const&lt;/span&gt; functionName = &lt;span&gt;&apos;isUserACommunityMember&apos;&lt;/span&gt;;
      &lt;span&gt;const&lt;/span&gt; network = &lt;span&gt;new&lt;/span&gt; StacksDevnet();
      &lt;span&gt;const&lt;/span&gt; senderAddress = userDevnetAddress;
      &lt;span&gt;const&lt;/span&gt; options = {
        &lt;span&gt;contractAddress&lt;/span&gt;: deployer,
        contractName,
        functionName,
        &lt;span&gt;functionArgs&lt;/span&gt;: [standardPrincipalCV(userDevnetAddress)],
        network,
        senderAddress,
      };
      &lt;span&gt;const&lt;/span&gt; result = &lt;span&gt;await&lt;/span&gt; callReadOnlyFunction(options);
      &lt;span&gt;if&lt;/span&gt; (result.value.type == ClarityType.BoolTrue) {
        setIsQualified(&lt;span&gt;true&lt;/span&gt;)
      } &lt;span&gt;else&lt;/span&gt; {
        setIsQualified(&lt;span&gt;false&lt;/span&gt;)
      }

    } &lt;span&gt;catch&lt;/span&gt; (error) {
      &lt;span&gt;console&lt;/span&gt;.log(&lt;span&gt;&quot;error =&amp;gt; &quot;&lt;/span&gt;, error);
    }
  };


  useEffect(&lt;span&gt;() =&amp;gt;&lt;/span&gt; {
    setIsClient(&lt;span&gt;true&lt;/span&gt;);
  }, []);

  useEffect(&lt;span&gt;() =&amp;gt;&lt;/span&gt; {
    getTokenBalance()
    isUserACommunityMember()
  }, [userSession.isUserSignedIn()])

  &lt;span&gt;if&lt;/span&gt; (!isClient) &lt;span&gt;return&lt;/span&gt; &lt;span&gt;null&lt;/span&gt;;

  &lt;span&gt;return&lt;/span&gt; (
    &lt;span&gt;&lt;span&gt;&amp;lt;&lt;span&gt;Connect&lt;/span&gt;
      &lt;span&gt;authOptions&lt;/span&gt;=&lt;span&gt;{{&lt;/span&gt;
        &lt;span&gt;appDetails:&lt;/span&gt; {
          &lt;span&gt;name:&lt;/span&gt; &quot;&lt;span&gt;Token&lt;/span&gt; &lt;span&gt;Gated&lt;/span&gt; &lt;span&gt;Community&lt;/span&gt;&quot;,
          &lt;span&gt;icon:&lt;/span&gt; &lt;span&gt;window.location.origin&lt;/span&gt; + &quot;/&lt;span&gt;logo.png&lt;/span&gt;&quot;,
        },
        &lt;span&gt;redirectTo:&lt;/span&gt; &quot;/&quot;,
        &lt;span&gt;onFinish:&lt;/span&gt; () =&amp;gt;&lt;/span&gt; {
          window.location.reload();
        },
        userSession,
      }}
    &amp;gt;
      &lt;span&gt;&amp;lt;&lt;span&gt;div&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.container}&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span&gt;&amp;lt;&lt;span&gt;header&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.header}&lt;/span&gt;&amp;gt;&lt;/span&gt;
          &lt;span&gt;&amp;lt;&lt;span&gt;h1&lt;/span&gt;&amp;gt;&lt;/span&gt;Token Gated Website&lt;span&gt;&amp;lt;/&lt;span&gt;h1&lt;/span&gt;&amp;gt;&lt;/span&gt;
          &lt;span&gt;&amp;lt;&lt;span&gt;nav&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.nav}&lt;/span&gt;&amp;gt;&lt;/span&gt;

            &lt;span&gt;&amp;lt;&lt;span&gt;ConnectWallet&lt;/span&gt; /&amp;gt;&lt;/span&gt;

          &lt;span&gt;&amp;lt;/&lt;span&gt;nav&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span&gt;&amp;lt;/&lt;span&gt;header&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span&gt;&amp;lt;&lt;span&gt;main&lt;/span&gt;&amp;gt;&lt;/span&gt;

          &lt;span&gt;&amp;lt;&lt;span&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;
            User Fan Token Balance: {userTokenAmount} FT
          &lt;span&gt;&amp;lt;/&lt;span&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;


          &lt;span&gt;&amp;lt;&lt;span&gt;div&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.inputContainerColumn}&lt;/span&gt;&amp;gt;&lt;/span&gt;
            &lt;span&gt;&amp;lt;&lt;span&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;Mint FT Tokens&lt;span&gt;&amp;lt;/&lt;span&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt; &lt;span&gt;&amp;amp;nbsp;&lt;/span&gt;
            &lt;span&gt;&amp;lt;&lt;span&gt;input&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.input}&lt;/span&gt; &lt;span&gt;value&lt;/span&gt;=&lt;span&gt;{tokensToMint}&lt;/span&gt;
              &lt;span&gt;onChange&lt;/span&gt;=&lt;span&gt;{(e)&lt;/span&gt; =&amp;gt;&lt;/span&gt; setTokensToMint(e.target.value)}
              type=&quot;number&quot; placeholder=&quot;00&quot;
            /&amp;gt;
            &lt;span&gt;&amp;lt;&lt;span&gt;input&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.input}&lt;/span&gt;
              &lt;span&gt;type&lt;/span&gt;=&lt;span&gt;&quot;text&quot;&lt;/span&gt;
              &lt;span&gt;placeholder&lt;/span&gt;=&lt;span&gt;&quot;principal to receive the token&quot;&lt;/span&gt;
              &lt;span&gt;value&lt;/span&gt;=&lt;span&gt;{tokenReceiver}&lt;/span&gt;
              &lt;span&gt;onChange&lt;/span&gt;=&lt;span&gt;{(e)&lt;/span&gt; =&amp;gt;&lt;/span&gt; setTokenReceiver(e.target.value)}

            /&amp;gt;
            &lt;span&gt;&amp;lt;&lt;span&gt;button&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.button}&lt;/span&gt; &lt;span&gt;onClick&lt;/span&gt;=&lt;span&gt;{mintTokens}&lt;/span&gt;&amp;gt;&lt;/span&gt;Mint FT Tokens&lt;span&gt;&amp;lt;/&lt;span&gt;button&lt;/span&gt;&amp;gt;&lt;/span&gt;
          &lt;span&gt;&amp;lt;/&lt;span&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;


          {!isQualified &amp;amp;&amp;amp;
            &lt;span&gt;&amp;lt;&lt;span&gt;div&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.container}&lt;/span&gt;&amp;gt;&lt;/span&gt;
              &lt;span&gt;&amp;lt;&lt;span&gt;h3&lt;/span&gt;&amp;gt;&lt;/span&gt;Join Community&lt;span&gt;&amp;lt;/&lt;span&gt;h3&lt;/span&gt;&amp;gt;&lt;/span&gt;

              &lt;span&gt;&amp;lt;&lt;span&gt;button&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.button}&lt;/span&gt;
                &lt;span&gt;onClick&lt;/span&gt;=&lt;span&gt;{joinTokenGatedCommunity}&lt;/span&gt;&amp;gt;&lt;/span&gt;Join Community&lt;span&gt;&amp;lt;/&lt;span&gt;button&lt;/span&gt;&amp;gt;&lt;/span&gt;
            &lt;span&gt;&amp;lt;/&lt;span&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
          }

          {/*Token gated content */}

          {isQualified &amp;amp;&amp;amp;

            &lt;span&gt;&amp;lt;&lt;span&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
              &lt;span&gt;&amp;lt;&lt;span&gt;h1&lt;/span&gt;&amp;gt;&lt;/span&gt;Welcome to the community of dog lovers Premium content&lt;span&gt;&amp;lt;/&lt;span&gt;h1&lt;/span&gt;&amp;gt;&lt;/span&gt;
              &lt;span&gt;&amp;lt;&lt;span&gt;h3&lt;/span&gt;&amp;gt;&lt;/span&gt;This part of the website is token gated!&lt;span&gt;&amp;lt;/&lt;span&gt;h3&lt;/span&gt;&amp;gt;&lt;/span&gt;
              &lt;span&gt;&amp;lt;&lt;span&gt;div&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.card}&lt;/span&gt;&amp;gt;&lt;/span&gt;
                &lt;span&gt;&amp;lt;&lt;span&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;Send a transaction to change the entryTokenAmount variable&lt;span&gt;&amp;lt;/&lt;span&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;
                &lt;span&gt;&amp;lt;&lt;span&gt;div&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.inputContainer}&lt;/span&gt;&amp;gt;&lt;/span&gt;
                  &lt;span&gt;&amp;lt;&lt;span&gt;input&lt;/span&gt; &lt;span&gt;type&lt;/span&gt;=&lt;span&gt;&quot;number&quot;&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.input}&lt;/span&gt; &lt;span&gt;placeholder&lt;/span&gt;=&lt;span&gt;&quot;00&quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;
                  &lt;span&gt;&amp;lt;&lt;span&gt;button&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.button}&lt;/span&gt;&amp;gt;&lt;/span&gt;Change Entry Fee&lt;span&gt;&amp;lt;/&lt;span&gt;button&lt;/span&gt;&amp;gt;&lt;/span&gt;
                &lt;span&gt;&amp;lt;/&lt;span&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
              &lt;span&gt;&amp;lt;/&lt;span&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;



              &lt;span&gt;&amp;lt;&lt;span&gt;div&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.inputContainer}&lt;/span&gt;&amp;gt;&lt;/span&gt;
                &lt;span&gt;&amp;lt;&lt;span&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;Exit Community and claim back your tokens&lt;span&gt;&amp;lt;/&lt;span&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;

                &lt;span&gt;&amp;lt;&lt;span&gt;button&lt;/span&gt; &lt;span&gt;className&lt;/span&gt;=&lt;span&gt;{styles.button}&lt;/span&gt;
                  &lt;span&gt;onClick&lt;/span&gt;=&lt;span&gt;{exitTokenGatedCommunity}&lt;/span&gt;&amp;gt;&lt;/span&gt;Exit Community&lt;span&gt;&amp;lt;/&lt;span&gt;button&lt;/span&gt;&amp;gt;&lt;/span&gt;
              &lt;span&gt;&amp;lt;/&lt;span&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;

            &lt;span&gt;&amp;lt;/&lt;span&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;

          }
        &lt;span&gt;&amp;lt;/&lt;span&gt;main&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span&gt;&amp;lt;/&lt;span&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span&gt;&amp;lt;/&lt;span&gt;Connect&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/blog-newsletter-1&quot;&gt;&lt;img src=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=1400&amp;auto=format&quot; srcset=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=1 1x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=2 2x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Subscribe to the Developer DAO Newsletter. Probably Nothing&quot; class=&quot;mx-auto&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This example application could be built upon to solidify the knowledge gained in integrating &lt;code&gt;Clarity&lt;/code&gt; smart contracts with a frontend application.&lt;/p&gt;
&lt;p&gt;In this blog post, we learned how to create &lt;code&gt;Clarity&lt;/code&gt; smart contracts, fungible tokens, and how to token-gate a webpage using a token. We also learned how to deploy smart contracts to either the &lt;code&gt;testnet&lt;/code&gt; or &lt;code&gt;devnet&lt;/code&gt; and connect with a front-end to send transactions to the network. I hope you have learned a thing or two from this piece.&lt;/p&gt;
&lt;p&gt;Thank you for reading to the end. The source code can be found &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/jamiebones/clarity-token-gated-example&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Farcaster Frames Explained</title>
    <link href="https://blog.developerdao.com/farcaster-frames-explained"/>
    <id>https://blog.developerdao.com/farcaster-frames-explained</id>
    <updated>2024-02-16T14:33:50.652Z</updated>
    <author><name>Ϗ</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1708093430682/45c9d98e-94dd-4e72-a51b-7853498834c1.jpeg?width=600&amp;format=auto"/>
    <summary>Frames excited enough users to make Farcaster worth their time. To be honest, I wouldn’t say I liked Farcaster at first, as it required installing a native app on my phone. In 2024, when it’s called Web3; why would anyone install a native app?! 
At l...</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1708093430682/45c9d98e-94dd-4e72-a51b-7853498834c1.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1708093430682/45c9d98e-94dd-4e72-a51b-7853498834c1.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1708093430682/45c9d98e-94dd-4e72-a51b-7853498834c1.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1708093430682/45c9d98e-94dd-4e72-a51b-7853498834c1.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;p&gt;Frames excited enough users to make Farcaster worth their time. To be honest, I wouldn’t say I liked Farcaster at first, as it required installing a native app on my phone. In 2024, when it’s called &lt;strong&gt;Web&lt;/strong&gt;3; why would anyone install a native app?! &lt;/p&gt;
&lt;p&gt;At least the Warpcast app works in the browser after completing the registration process, so why not try it? Especially with all the hype around Frames. And when I’m already on it, why not write a few words about it?&lt;/p&gt;
&lt;p&gt;So, here it is, yet another Farcaster Frames explainer for you!&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/blog-newsletter-1&quot;&gt;&lt;img src=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=1400&amp;auto=format&quot; srcset=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=1 1x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=2 2x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Subscribe to the Developer DAO Newsletter. Probably Nothing&quot; class=&quot;mx-auto&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-what-are-farcaster-frames&quot;&gt;What are Farcaster Frames?&lt;/h2&gt;
&lt;p&gt;Technically, &lt;strong&gt;Frames are an extension of&lt;/strong&gt; &lt;a target=&quot;_blank&quot; href=&quot;https://ogp.me/&quot;&gt;&lt;strong&gt;the Open Graph protocol&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;(OGP)&lt;/strong&gt; but a peculiar one, as you can use OGP features just as a fallback and not mix them.&lt;/p&gt;
&lt;p&gt;In practice, you use the &lt;code&gt;fc:frame&lt;/code&gt; or the og: metatags. This is a bit strange, as it doesn’t allow Frames to re-use much of the OGP functionality (i.e., actually extending it). To be more precise, the only thing Frames has in common with OGP is that you can use both to embed preview images into other apps.&lt;/p&gt;
&lt;p&gt;In contrast to the static nature of OGP, &lt;strong&gt;Frames are interactive&lt;/strong&gt;. While they can’t play videos (yet, the protocol is still under development), they allow you to add &lt;strong&gt;up to four buttons and an input field&lt;/strong&gt; to the image. As Farcaster authenticates users with a crypto address, you can use Frames to perform crypto actions like minting NFTs directly from a Farcaster client.&lt;/p&gt;
&lt;h2 id=&quot;heading-how-do-farcaster-frames-work&quot;&gt;How Do Farcaster Frames Work?&lt;/h2&gt;
&lt;p&gt;For a Frames developer, Frames consists of the following parts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A frame definition&lt;/strong&gt; is like a Farcaster app widget that tells the app what to render and where to send the actions. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A frame server&lt;/strong&gt; handles the actions received from the app and can consult a Farcaster Hub for validation or additional Farcaster data. Let’s look at examples of both.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Figure 1 illustrates how they integrate with the Farcaster stack.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1708093537592/615c6dd3-ba79-43a7-bfa3-ba0c4868b3f9.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1708093537592/615c6dd3-ba79-43a7-bfa3-ba0c4868b3f9.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1708093537592/615c6dd3-ba79-43a7-bfa3-ba0c4868b3f9.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1708093537592/615c6dd3-ba79-43a7-bfa3-ba0c4868b3f9.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 1: Farcaster Frames Architecture&lt;/p&gt;
&lt;h3 id=&quot;heading-frame-definition&quot;&gt;Frame Definition&lt;/h3&gt;
&lt;p&gt;Like OGP, &lt;strong&gt;Frames are essentially HTML documents with special metatags&lt;/strong&gt;. Add at least the two required metatags to a document hosted on a public HTTP server to create a frame.&lt;/p&gt;
&lt;h4 id=&quot;heading-defining-a-minimal-frame&quot;&gt;Defining a Minimal Frame&lt;/h4&gt;
&lt;p&gt;This is a minimal frame-enabled HTML document:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&amp;lt;!doctype &lt;span&gt;html&lt;/span&gt;&amp;gt;&lt;/span&gt;

&lt;span&gt;&amp;lt;&lt;span&gt;title&lt;/span&gt;&amp;gt;&lt;/span&gt;Demo Frame&lt;span&gt;&amp;lt;/&lt;span&gt;title&lt;/span&gt;&amp;gt;&lt;/span&gt;

&lt;span&gt;&amp;lt;&lt;span&gt;meta&lt;/span&gt; &lt;span&gt;property&lt;/span&gt;=&lt;span&gt;&quot;fc:frame&quot;&lt;/span&gt; &lt;span&gt;content&lt;/span&gt;=&lt;span&gt;&quot;vNext&quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;
&lt;span&gt;&amp;lt;&lt;span&gt;meta&lt;/span&gt; &lt;span&gt;property&lt;/span&gt;=&lt;span&gt;&quot;fc:frame:image&quot;&lt;/span&gt; &lt;span&gt;content&lt;/span&gt;=&lt;span&gt;&quot;https://example.com/image.jpg&quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;
&lt;span&gt;&amp;lt;&lt;span&gt;meta&lt;/span&gt; &lt;span&gt;property&lt;/span&gt;=&lt;span&gt;&quot;og:image&quot;&lt;/span&gt; &lt;span&gt;content&lt;/span&gt;=&lt;span&gt;&quot;https://example.com/image.jpg&quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It only displays a preview image with a 1:1 or 1.91:1 aspect ratio. Putting the URL for that document into a Farcaster post or cast (the actual name of posts on Farcaster) will display the image inside any Farcaster client that supports Frames.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;og:image&lt;/code&gt; tag is required as a fallback for clients not supporting Frames.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1708093567339/2bdfaaad-dd58-4f85-82f6-c042a8c54261.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1708093567339/2bdfaaad-dd58-4f85-82f6-c042a8c54261.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1708093567339/2bdfaaad-dd58-4f85-82f6-c042a8c54261.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1708093567339/2bdfaaad-dd58-4f85-82f6-c042a8c54261.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 2: Simple Frame&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: The first frame is cached, so while you must host it on your server, you can’t change it after a user loads it the first time.&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;heading-defining-an-advanced-frame&quot;&gt;Defining an Advanced Frame&lt;/h4&gt;
&lt;p&gt;You can use some optional metatags to get the interactive part going. Let’s look at a more complex example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&amp;lt;!doctype &lt;span&gt;html&lt;/span&gt;&amp;gt;&lt;/span&gt;

&lt;span&gt;&amp;lt;&lt;span&gt;title&lt;/span&gt;&amp;gt;&lt;/span&gt;Demo Frame&lt;span&gt;&amp;lt;/&lt;span&gt;title&lt;/span&gt;&amp;gt;&lt;/span&gt;

&lt;span&gt;&amp;lt;&lt;span&gt;meta&lt;/span&gt; &lt;span&gt;property&lt;/span&gt;=&lt;span&gt;&quot;fc:frame&quot;&lt;/span&gt; &lt;span&gt;content&lt;/span&gt;=&lt;span&gt;&quot;vNext&quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;
&lt;span&gt;&amp;lt;&lt;span&gt;meta&lt;/span&gt; &lt;span&gt;property&lt;/span&gt;=&lt;span&gt;&quot;fc:frame:image&quot;&lt;/span&gt; &lt;span&gt;content&lt;/span&gt;=&lt;span&gt;&quot;https://example.com/image.jpg&quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;
&lt;span&gt;&amp;lt;&lt;span&gt;meta&lt;/span&gt; &lt;span&gt;property&lt;/span&gt;=&lt;span&gt;&quot;og:image&quot;&lt;/span&gt; &lt;span&gt;content&lt;/span&gt;=&lt;span&gt;&quot;https://example.com/image.jpg&quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;

&lt;span&gt;&amp;lt;&lt;span&gt;meta&lt;/span&gt; &lt;span&gt;property&lt;/span&gt;=&lt;span&gt;&quot;fc:frame:post_url&quot;&lt;/span&gt; &lt;span&gt;content&lt;/span&gt;=&lt;span&gt;&quot;https://example.com/api&quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;
&lt;span&gt;&amp;lt;&lt;span&gt;meta&lt;/span&gt; &lt;span&gt;property&lt;/span&gt;=&lt;span&gt;&quot;fc:frame:button:1&quot;&lt;/span&gt; &lt;span&gt;content&lt;/span&gt;=&lt;span&gt;&quot;Button 1&quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;
&lt;span&gt;&amp;lt;&lt;span&gt;meta&lt;/span&gt; &lt;span&gt;property&lt;/span&gt;=&lt;span&gt;&quot;fc:frame:button:2&quot;&lt;/span&gt; &lt;span&gt;content&lt;/span&gt;=&lt;span&gt;&quot;Button 2&quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;
&lt;span&gt;&amp;lt;&lt;span&gt;meta&lt;/span&gt; &lt;span&gt;property&lt;/span&gt;=&lt;span&gt;&quot;fc:frame:input:text&quot;&lt;/span&gt; &lt;span&gt;content&lt;/span&gt;=&lt;span&gt;&quot;Input&quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The top section is the same as before, but we have new metatags at the bottom.&lt;/p&gt;
&lt;p&gt;Let’s start with the &lt;code&gt;fc:frame:post_url&lt;/code&gt;, which brings us to the first crucial point. &lt;strong&gt;When a user clicks a button, the Farcaster client will send a POST request to the URL in this tag&lt;/strong&gt; and expects the response to contain an HTML document with a new frame definition. This allows you to change the content of a frame after it is rendered. After every button click, you can display a new frame with a new image, new buttons, and so on.&lt;/p&gt;
&lt;p&gt;The f&lt;code&gt;c:frame:button:1&lt;/code&gt; and &lt;code&gt;fc:frame:button:2&lt;/code&gt; tags define the buttons and their labels. Again, when a user clicks them, by default, the frame sends a POST request to the &lt;code&gt;FC:frame:post_url.&lt;/code&gt; This request will contain the index of the button.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;fc:frame:input:text&lt;/code&gt; tag lets you add a user input to the POST request.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1708093581895/0843fbf7-52ae-4f67-99f3-a4c157afd42d.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1708093581895/0843fbf7-52ae-4f67-99f3-a4c157afd42d.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1708093581895/0843fbf7-52ae-4f67-99f3-a4c157afd42d.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1708093581895/0843fbf7-52ae-4f67-99f3-a4c157afd42d.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 3: Advanced frame&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A frame can only have 4 buttons and 1 input field&lt;/strong&gt;; however, they can differ in every new frame your server sends in response to a POST request. Also, other metatags allow you to create different button types (e.g., links and redirects) and send each button click to a different server, giving you more flexibility. &lt;a target=&quot;_blank&quot; href=&quot;https://docs.farcaster.xyz/reference/frames/spec#optional-properties&quot;&gt;Find them in the Farcaster docs&lt;/a&gt;. &lt;/p&gt;
&lt;h3 id=&quot;heading-frame-server&quot;&gt;Frame Server&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;By default, every button click will issue a POST request&lt;/strong&gt;. Consequently, you must implement a frame server to handle these requests.&lt;/p&gt;
&lt;p&gt;The requirements for a frame server are the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Has a POST endpoint&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Accepts &lt;code&gt;application/json&lt;/code&gt; requests&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Responds with valid HTML containing Frames metatags&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Takes less than 5 seconds to respond&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The frame sends a POST request with JSON data that will look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &lt;span&gt;&quot;untrustedData&quot;&lt;/span&gt;: {
    &lt;span&gt;&quot;fid&quot;&lt;/span&gt;: &lt;span&gt;2&lt;/span&gt;,
    &lt;span&gt;&quot;url&quot;&lt;/span&gt;: &lt;span&gt;&quot;https://example.com/&quot;&lt;/span&gt;,
    &lt;span&gt;&quot;messageHash&quot;&lt;/span&gt;: &lt;span&gt;&quot;0xd2b…&quot;&lt;/span&gt;,
    &lt;span&gt;&quot;timestamp&quot;&lt;/span&gt;: &lt;span&gt;1706243218&lt;/span&gt;,
    &lt;span&gt;&quot;network&quot;&lt;/span&gt;: &lt;span&gt;1&lt;/span&gt;,
    &lt;span&gt;&quot;buttonIndex&quot;&lt;/span&gt;: &lt;span&gt;2&lt;/span&gt;,
    &lt;span&gt;&quot;inputText&quot;&lt;/span&gt;: &lt;span&gt;&quot;hello world&quot;&lt;/span&gt;,
    &lt;span&gt;&quot;castId&quot;&lt;/span&gt;: {
      &lt;span&gt;&quot;fid&quot;&lt;/span&gt;: &lt;span&gt;226&lt;/span&gt;,
      &lt;span&gt;&quot;hash&quot;&lt;/span&gt;: &lt;span&gt;&quot;0xa48…&quot;&lt;/span&gt;
    }
  },
  &lt;span&gt;&quot;trustedData&quot;&lt;/span&gt;: {
    &lt;span&gt;&quot;messageBytes&quot;&lt;/span&gt;: &lt;span&gt;&quot;...&quot;&lt;/span&gt;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Only use the object in&lt;/strong&gt; &lt;code&gt;untrustedData&lt;/code&gt; &lt;strong&gt;for uncritical interactions&lt;/strong&gt; (i.e., don’t mint an NFT) as attackers can change it.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;trustedData&lt;/code&gt; includes a Protocol Buffer encoded string you can use to check for authenticity. &lt;/p&gt;
&lt;h3 id=&quot;heading-using-untrusted-farcaster-frame-data&quot;&gt;Using Untrusted Farcaster Frame Data&lt;/h3&gt;
&lt;p&gt;A simple frame server that handles untrusted data, built with Express.js, could look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;const&lt;/span&gt; express = &lt;span&gt;require&lt;/span&gt;(&lt;span&gt;&quot;express&quot;&lt;/span&gt;)
&lt;span&gt;const&lt;/span&gt; app = express()

app.use(express.json())

app.get(&lt;span&gt;&quot;/frame&quot;&lt;/span&gt;, &lt;span&gt;(&lt;span&gt;request, response&lt;/span&gt;) =&amp;gt;&lt;/span&gt; {
  response.send(&lt;span&gt;`
    &amp;lt;!doctype html&amp;gt;

    &amp;lt;title&amp;gt;Frame 1&amp;lt;/title&amp;gt;

    &amp;lt;meta property=&quot;fc:frame&quot; content=&quot;vNext&quot;&amp;gt;
    &amp;lt;meta property=&quot;fc:frame:image&quot; content=&quot;https://example.com/image.jpg&quot;&amp;gt;
    &amp;lt;meta property=&quot;og:image&quot; content=&quot;https://example.com/image.jpg&quot;&amp;gt;
    &amp;lt;meta property=&quot;fc:frame:post_url&quot; content=&quot;https://example.com/frame&quot;&amp;gt;
    &amp;lt;meta property=&quot;fc:frame:button:1&quot; content=&quot;Next Frame&quot;&amp;gt;
  `&lt;/span&gt;)
})

app.post(&lt;span&gt;&quot;/frame&quot;&lt;/span&gt;, &lt;span&gt;(&lt;span&gt;request, response&lt;/span&gt;) =&amp;gt;&lt;/span&gt; {
  &lt;span&gt;const&lt;/span&gt; { fid } = request.body.untrustedData

  response.send(&lt;span&gt;`
    &amp;lt;!doctype html&amp;gt;

    &amp;lt;title&amp;gt;Frame 2&amp;lt;/title&amp;gt;

    &amp;lt;meta property=&quot;fc:frame&quot; content=&quot;vNext&quot;&amp;gt;
    &amp;lt;meta property=&quot;fc:frame:image&quot; content=&quot;https://example.com/image.jpg&quot;&amp;gt;
    &amp;lt;meta property=&quot;og:image&quot; content=&quot;https://example.com/image.jpg&quot;&amp;gt;
    &amp;lt;meta property=&quot;fc:frame:button:1&quot; content=&quot;Your FID is: &lt;span&gt;${fid}&lt;/span&gt;&quot;&amp;gt;
  `&lt;/span&gt;)

})

app.listen(&lt;span&gt;3333&lt;/span&gt;, &lt;span&gt;() =&amp;gt;&lt;/span&gt; 
  &lt;span&gt;console&lt;/span&gt;.log(&lt;span&gt;&quot;Server started on port 3333&quot;&lt;/span&gt;)
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The GET endpoint will deliver the first frame that shows an initial image and a button.&lt;/p&gt;
&lt;p&gt;The POST endpoint will use the &lt;code&gt;fid&lt;/code&gt; from the request as a label for the next button.&lt;/p&gt;
&lt;h3 id=&quot;heading-using-trusted-data-from-a-farcaster-frame&quot;&gt;Using Trusted Data from a Farcaster Frame&lt;/h3&gt;
&lt;p&gt;Here, things get a bit more involved. You should use the object inside &lt;code&gt;trustedData.messageBytes&lt;/code&gt; to perform critical interactions. It is encoded with &lt;a target=&quot;_blank&quot; href=&quot;https://protobuf.dev/&quot;&gt;Protocol Buffers&lt;/a&gt; to ensure integrity, and &lt;strong&gt;you must send it to a Farcaster hub for decoding and validation&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Farcaster Hubs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Farcaster hubs are the servers that make up the Farcaster network. They store and validate the off-chain data and store on-chain data on Optimism and Ethereum. &lt;strong&gt;You need a hub to validate your frame messages.&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Validating Farcaster Frame Data&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To use a hub for validation, send a POST request with the trusted data from your frame server to the /v1/validateMessage endpoint of a Farcaster hub.&lt;/p&gt;
&lt;p&gt;Inspired by &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/framesjs/frames.js/blob/main/packages/frames.js/src/validateFrameMessage.ts#L11&quot;&gt;the frames.js framework&lt;/a&gt;, a validation request in JavaScript could look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;const&lt;/span&gt; binaryData =  &lt;span&gt;new&lt;/span&gt; &lt;span&gt;Uint8Array&lt;/span&gt;(
  request.body.trustedData.messageBytes.match(&lt;span&gt;/.{1,2}/g&lt;/span&gt;)!.map(
    &lt;span&gt;(&lt;span&gt;byte&lt;/span&gt;) =&amp;gt;&lt;/span&gt; &lt;span&gt;parseInt&lt;/span&gt;(byte, &lt;span&gt;16&lt;/span&gt;)
  )
)

&lt;span&gt;const&lt;/span&gt; response = &lt;span&gt;await&lt;/span&gt; fetch(
  &lt;span&gt;&quot;http://example.com:2281/v1/validateMessage&quot;&lt;/span&gt;, {
  &lt;span&gt;method&lt;/span&gt;: &lt;span&gt;&quot;POST&quot;&lt;/span&gt;,
  &lt;span&gt;headers&lt;/span&gt;: {&lt;span&gt;&quot;Content-Type&quot;&lt;/span&gt;: &lt;span&gt;&quot;application/octet-stream&quot;&lt;/span&gt;},
  &lt;span&gt;body&lt;/span&gt;: binaryData
}).then(&lt;span&gt;&lt;span&gt;r&lt;/span&gt; =&amp;gt;&lt;/span&gt; r.json())
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, we convert the data into a format fetch understands, then send it to our Farcaster hub of choice, which will validate the content and convert it to JSON.&lt;/p&gt;
&lt;p&gt;The response from the hub looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &lt;span&gt;&quot;valid&quot;&lt;/span&gt;: &lt;span&gt;true&lt;/span&gt;,
  &lt;span&gt;&quot;message&quot;&lt;/span&gt;: {
    &lt;span&gt;&quot;data&quot;&lt;/span&gt;: {
      &lt;span&gt;&quot;type&quot;&lt;/span&gt;: &lt;span&gt;&quot;MESSAGE_TYPE_FRAME_ACTION&quot;&lt;/span&gt;,
      &lt;span&gt;&quot;fid&quot;&lt;/span&gt;: &lt;span&gt;2&lt;/span&gt;,
      &lt;span&gt;&quot;timestamp&quot;&lt;/span&gt;: &lt;span&gt;48994466&lt;/span&gt;,
      &lt;span&gt;&quot;network&quot;&lt;/span&gt;: &lt;span&gt;&quot;FARCASTER_NETWORK_MAINNET&quot;&lt;/span&gt;,
      &lt;span&gt;&quot;frameActionBody&quot;&lt;/span&gt;: {
        &lt;span&gt;&quot;url&quot;&lt;/span&gt;: &lt;span&gt;&quot;https://example.com/&quot;&lt;/span&gt;,
        &lt;span&gt;&quot;buttonIndex&quot;&lt;/span&gt;: &lt;span&gt;2&lt;/span&gt;,
        &lt;span&gt;&quot;inputText&quot;&lt;/span&gt;: &lt;span&gt;&quot;&quot;&lt;/span&gt;,
        &lt;span&gt;&quot;castId&quot;&lt;/span&gt;: {
          &lt;span&gt;&quot;fid&quot;&lt;/span&gt;: &lt;span&gt;226&lt;/span&gt;,
          &lt;span&gt;&quot;hash&quot;&lt;/span&gt;: &lt;span&gt;&quot;0xa48d...&quot;&lt;/span&gt;
        }
      }
    },
    &lt;span&gt;&quot;hash&quot;&lt;/span&gt;: &lt;span&gt;&quot;0xd2b...&quot;&lt;/span&gt;,
    &lt;span&gt;&quot;hashScheme&quot;&lt;/span&gt;: &lt;span&gt;&quot;HASH_SCHEME_BLAKE3&quot;&lt;/span&gt;,
    &lt;span&gt;&quot;signature&quot;&lt;/span&gt;: &lt;span&gt;&quot;3ms...PAA==&quot;&lt;/span&gt;,
    &lt;span&gt;&quot;signatureScheme&quot;&lt;/span&gt;: &lt;span&gt;&quot;SIGNATURE_SCHEME_ED25519&quot;&lt;/span&gt;,
    &lt;span&gt;&quot;signer&quot;&lt;/span&gt;: &lt;span&gt;&quot;0x78f...&quot;&lt;/span&gt;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;According to the Farcaster docs, the hub will validate the following properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;the &lt;code&gt;fid&lt;/code&gt; (i.e., the user FID) is registered&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the &lt;code&gt;signer&lt;/code&gt; is active and registered to the &lt;code&gt;fid&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the &lt;code&gt;messageHash&lt;/code&gt; is correct&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the &lt;code&gt;signature&lt;/code&gt; is valid and corresponds to the &lt;code&gt;signer&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Fetching Farcaster Casts&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Farcaster hub won’t check if the &lt;code&gt;castId&lt;/code&gt; belongs to an existing cast, or if the frame &lt;code&gt;url&lt;/code&gt; matches the embedded URL in that cast. You have to check it manually if needed (i.e., if a frame should only work when it is actually shared.&lt;/p&gt;
&lt;p&gt;To load the cast that issued the message, you can ask the trusty Farcaster hubs.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;const&lt;/span&gt; response = &lt;span&gt;await&lt;/span&gt; fetch(
  &lt;span&gt;&quot;http://example.com:2281/v1/castById?fid=&amp;lt;CAST_FID&amp;gt;&amp;amp;hash=&amp;lt;CAST_HASH&amp;gt;&quot;&lt;/span&gt;
).then(&lt;span&gt;&lt;span&gt;r&lt;/span&gt; =&amp;gt;&lt;/span&gt; r.json())
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The response looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &lt;span&gt;&quot;data&quot;&lt;/span&gt;: {
    &lt;span&gt;&quot;type&quot;&lt;/span&gt;: &lt;span&gt;&quot;MESSAGE_TYPE_CAST_ADD&quot;&lt;/span&gt;,
    &lt;span&gt;&quot;fid&quot;&lt;/span&gt;: &amp;lt;CAST_FID&amp;gt;,
    &lt;span&gt;&quot;timestamp&quot;&lt;/span&gt;: &lt;span&gt;48994466&lt;/span&gt;,
    &lt;span&gt;&quot;network&quot;&lt;/span&gt;: &lt;span&gt;&quot;FARCASTER_NETWORK_MAINNET&quot;&lt;/span&gt;,
    &lt;span&gt;&quot;castAddBody&quot;&lt;/span&gt;: {
      &lt;span&gt;&quot;embedsDeprecated&quot;&lt;/span&gt;: [],
      &lt;span&gt;&quot;mentions&quot;&lt;/span&gt;: [],
      &lt;span&gt;&quot;parentCastId&quot;&lt;/span&gt;: {
        &lt;span&gt;&quot;fid&quot;&lt;/span&gt;: &lt;span&gt;226&lt;/span&gt;,
        &lt;span&gt;&quot;hash&quot;&lt;/span&gt;: &lt;span&gt;&quot;0xa48d...&quot;&lt;/span&gt;
      },
      &lt;span&gt;&quot;text&quot;&lt;/span&gt;: &lt;span&gt;&quot;Cast Text&quot;&lt;/span&gt;,
      &lt;span&gt;&quot;mentionsPositions&quot;&lt;/span&gt;: [],
      &lt;span&gt;&quot;embeds&quot;&lt;/span&gt;: []
    }
  },
  &lt;span&gt;&quot;hash&quot;&lt;/span&gt;: &lt;span&gt;&quot;0xd2b...&quot;&lt;/span&gt;,
  &lt;span&gt;&quot;hashScheme&quot;&lt;/span&gt;: &lt;span&gt;&quot;HASH_SCHEME_BLAKE3&quot;&lt;/span&gt;,
  &lt;span&gt;&quot;signature&quot;&lt;/span&gt;: &lt;span&gt;&quot;3ms...PAA==&quot;&lt;/span&gt;,
  &lt;span&gt;&quot;signatureScheme&quot;&lt;/span&gt;: &lt;span&gt;&quot;SIGNATURE_SCHEME_ED25519&quot;&lt;/span&gt;,
  &lt;span&gt;&quot;signer&quot;&lt;/span&gt;: &lt;span&gt;&quot;0x78f...&quot;&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Fetching Farcaster User Data&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Getting user data might also be important for your frame; as you might expect, you get it from a hub.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;const&lt;/span&gt; response = &lt;span&gt;await&lt;/span&gt; fetch(
  &lt;span&gt;&quot;http://example.com:2281/v1/userDataByFid?fid=&amp;lt;USER_FID&amp;gt;&amp;amp;user_data_type=1&quot;&lt;/span&gt;
).then(&lt;span&gt;&lt;span&gt;r&lt;/span&gt; =&amp;gt;&lt;/span&gt; r.json())
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The response looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &lt;span&gt;&quot;data&quot;&lt;/span&gt;: {
    &lt;span&gt;&quot;type&quot;&lt;/span&gt;: &lt;span&gt;&quot;MESSAGE_TYPE_USER_DATA_ADD&quot;&lt;/span&gt;,
    &lt;span&gt;&quot;fid&quot;&lt;/span&gt;: &amp;lt;USER_FID&amp;gt;,
    &lt;span&gt;&quot;timestamp&quot;&lt;/span&gt;: &lt;span&gt;83433831&lt;/span&gt;,
    &lt;span&gt;&quot;network&quot;&lt;/span&gt;: &lt;span&gt;&quot;FARCASTER_NETWORK_MAINNET&quot;&lt;/span&gt;,
    &lt;span&gt;&quot;userDataBody&quot;&lt;/span&gt;: {
      &lt;span&gt;&quot;type&quot;&lt;/span&gt;: &lt;span&gt;&quot;USER_DATA_TYPE_PFP&quot;&lt;/span&gt;,
      &lt;span&gt;&quot;value&quot;&lt;/span&gt;: &lt;span&gt;&quot;https://i.imgur.com/HG54Hq6.png&quot;&lt;/span&gt;
    }
  },
  &lt;span&gt;&quot;hash&quot;&lt;/span&gt;: &lt;span&gt;&quot;0x327…&quot;&lt;/span&gt;,
  &lt;span&gt;&quot;hashScheme&quot;&lt;/span&gt;: &lt;span&gt;&quot;HASH_SCHEME_BLAKE3&quot;&lt;/span&gt;,
  &lt;span&gt;&quot;signature&quot;&lt;/span&gt;: &lt;span&gt;&quot;XIT..9Cg==&quot;&lt;/span&gt;,
  &lt;span&gt;&quot;signatureScheme&quot;&lt;/span&gt;: &lt;span&gt;&quot;SIGNATURE_SCHEME_ED25519&quot;&lt;/span&gt;,
  &lt;span&gt;&quot;signer&quot;&lt;/span&gt;: &lt;span&gt;&quot;0x085...&quot;&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are even more endpoints to fetch casts and their parents, so &lt;a target=&quot;_blank&quot; href=&quot;https://docs.farcaster.xyz/reference/hubble/httpapi/casts#castbyid&quot;&gt;check out the Farcaster docs&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: As you get all the information from Farcaster hubs, running your own might be a good idea.&lt;/em&gt; &lt;a target=&quot;_blank&quot; href=&quot;https://www.thehubble.xyz/intro/hubble.html&quot;&gt;&lt;em&gt;Check out the Hubble docs&lt;/em&gt;&lt;/a&gt; &lt;em&gt;to learn how.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-why-do-you-need-farcaster-frames&quot;&gt;Why Do You Need Farcaster Frames?&lt;/h2&gt;
&lt;p&gt;If you’ve used social media apps like Instagram (IG), you might have noticed the ads on that platform. They are integrated similarly to regular posts but come with a button allowing some interactions. Frames are similar; it&apos;s just that they are more powerful. In contrast to the IG ads, you can have more buttons and an input field, and the buttons can have any custom functionality a server can perform, not just the actions Meta allows. &lt;/p&gt;
&lt;p&gt;You can build rich social media embeds for your service that minimize the barriers for your users. While you can define buttons that open a website in a browser, you can use the default POST buttons to let them do interactions without leaving Farcaster. &lt;/p&gt;
&lt;p&gt;Since you have cryptographic account information, you can even let them perform authenticated actions on your service. In Web3 terms, that might mean minting or receiving tokens, but depending on how you link the Farcaster ID to your user accounts, this might include any action you could model with changing sets of up to 4 buttons, an input field, and an image. &lt;/p&gt;
&lt;p&gt;These limitations might seem drastic, but a command shell is also a limited yet powerful tool. &lt;/p&gt;
&lt;h2 id=&quot;heading-summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;Farcaster Frames are an exciting addition to the social media and Web3 landscape. They are more powerful than OGP but not too powerful, and constraints can fuel creativity.  &lt;/p&gt;
&lt;p&gt;Remember that you need an HTTP server to build frames, so while they might seem like a frontend technology, backend skills are required to get them working, including traffic considerations and hosting costs.&lt;/p&gt;
&lt;p&gt;Finally, remember that the Farcaster Frames specification is new and will change quite a bit. A few days ago, they added a limit for data URI images that broke several frames. So, if you consider using Farcaster Frames for critical tasks, ensure that you have a developer at hand who can keep them up-to-date!&lt;/p&gt;
&lt;h2 id=&quot;heading-additional-resources&quot;&gt;Additional Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://docs.farcaster.xyz/reference/frames/spec&quot;&gt;The Frames specification&lt;/a&gt; in the Farcaster docs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://github.com/framesjs/frames.js&quot;&gt;The frames.js framework&lt;/a&gt; helps you build frames quickly. &lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Phala offers an IPFS-based, decentralized hosting solution for Frames called &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/Phala-Network/framehub-template&quot;&gt;FrameHub&lt;/a&gt;. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Hubble docs explain &lt;a target=&quot;_blank&quot; href=&quot;https://www.thehubble.xyz/intro/hubble.html&quot;&gt;how to host a Farcaster Hub&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>What is Quadratic Funding, and How Does it Work?</title>
    <link href="https://blog.developerdao.com/what-is-quadratic-funding"/>
    <id>https://blog.developerdao.com/what-is-quadratic-funding</id>
    <updated>2024-02-14T13:49:00.118Z</updated>
    <author><name>Victor Fawole</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1707918392643/d8eb2433-1cb3-43f3-b8ae-4c64cf926d21.jpeg?width=600&amp;format=auto"/>
    <summary>Quadratic Funding: Voice of the masses. The community-centered way of raising funds in Web3</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1707918392643/d8eb2433-1cb3-43f3-b8ae-4c64cf926d21.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1707918392643/d8eb2433-1cb3-43f3-b8ae-4c64cf926d21.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1707918392643/d8eb2433-1cb3-43f3-b8ae-4c64cf926d21.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1707918392643/d8eb2433-1cb3-43f3-b8ae-4c64cf926d21.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;p&gt;The rich get richer every day, even when it comes to grant programs; however, Vitalik Buterin, the co-founder of Ethereum, thinks that for Web3 to be truly democratic, grant fundraising should also be democratic.&lt;/p&gt;
&lt;p&gt;That brought a new dawn, a new way of raising funds that prioritizes the voice and needs of the majority over the minority big-holder investor.&lt;/p&gt;
&lt;p&gt;Quadratic funding (QF) is the new way of fundraising in Web3. The time of crowdfunding is over!&lt;/p&gt;
&lt;p&gt;In this article, you will learn the aim behind QF and the potential opportunities embedded in it.&lt;/p&gt;
&lt;p&gt;Sit back and enjoy reading!&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/blog-newsletter-1&quot;&gt;&lt;img src=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=1400&amp;auto=format&quot; srcset=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=1 1x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=2 2x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Subscribe to the Developer DAO Newsletter. Probably Nothing&quot; class=&quot;mx-auto&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-history-of-quadratic-funding&quot;&gt;History of Quadratic Funding&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1707569971528/f9cd57bf-7eff-4679-b1bf-266866a1a0e6.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1707569971528/f9cd57bf-7eff-4679-b1bf-266866a1a0e6.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1707569971528/f9cd57bf-7eff-4679-b1bf-266866a1a0e6.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1707569971528/f9cd57bf-7eff-4679-b1bf-266866a1a0e6.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://unsplash.com/photos/brown-paper-and-black-pen-B6yDtYs2IgY?utm_content=creditShareLink&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash&quot;&gt;Unsplash: Joanna&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We must first trace its origins to understand QF (a.k.a plural funding). Ethereum co-founder Vitalik Buterin envisioned it in collaboration with Zoë Hitzig and E. Glen Weyl from the idea of quadratic voting.&lt;/p&gt;
&lt;p&gt;The driving force behind &lt;a target=&quot;_blank&quot; href=&quot;https://youtu.be/wXPxPBJCtoc?si=ZRV5Sf87FDe6BHuW&quot;&gt;this concept&lt;/a&gt; was democratizing the grant fundraising process, challenging the narrative that only the wealthy should dictate the flow of financial support.&lt;/p&gt;
&lt;p&gt;The journey began with a proposal paper laying the groundwork for a more democratic approach to crowdfunding. It aimed to address the rich-get-richer phenomenon in traditional grant programs, where major donors hold disproportionate influence.&lt;/p&gt;
&lt;h2 id=&quot;heading-what-is-quadratic-funding&quot;&gt;What is Quadratic Funding?&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://lh7-us.googleusercontent.com/Ce47nhzO_4HPr_XprTaR2L4ry-qK8S_PlbTrxIYxqyzdokJFPhV3XkdehHOK6YmyHJsrdOyF-p8_FT4FZEYmCMpP7PXU7AQe0a_lD8H_tcbIgmf5IYapea0uky1Nsb4742JLKNZJ7VE9mfEiQSdGdQc?width=1400&amp;auto=format&quot; srcset=&quot;https://lh7-us.googleusercontent.com/Ce47nhzO_4HPr_XprTaR2L4ry-qK8S_PlbTrxIYxqyzdokJFPhV3XkdehHOK6YmyHJsrdOyF-p8_FT4FZEYmCMpP7PXU7AQe0a_lD8H_tcbIgmf5IYapea0uky1Nsb4742JLKNZJ7VE9mfEiQSdGdQc?width=700&amp;auto=format&amp;dpr=1 1x, https://lh7-us.googleusercontent.com/Ce47nhzO_4HPr_XprTaR2L4ry-qK8S_PlbTrxIYxqyzdokJFPhV3XkdehHOK6YmyHJsrdOyF-p8_FT4FZEYmCMpP7PXU7AQe0a_lD8H_tcbIgmf5IYapea0uky1Nsb4742JLKNZJ7VE9mfEiQSdGdQc?width=700&amp;auto=format&amp;dpr=2 2x, https://lh7-us.googleusercontent.com/Ce47nhzO_4HPr_XprTaR2L4ry-qK8S_PlbTrxIYxqyzdokJFPhV3XkdehHOK6YmyHJsrdOyF-p8_FT4FZEYmCMpP7PXU7AQe0a_lD8H_tcbIgmf5IYapea0uky1Nsb4742JLKNZJ7VE9mfEiQSdGdQc?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;QF is a democratic crowdfunding mechanism designed to ensure fair and inclusive funding for public goods. This approach would benefit public goods such as open-source software, scientific research, and public art projects.&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://youtu.be/HJljTtLnymE?si=LPED3vDCxePXRNeI&quot;&gt;Gitcoin,&lt;/a&gt;, a leading QF platform, defines this method as combining modest individual contributions with larger matching sums from sponsors or contributors.&lt;/p&gt;
&lt;p&gt;It brings a novel perspective to crowdfunding by valuing widespread support over high donation amounts.&lt;/p&gt;
&lt;h2 id=&quot;heading-quadratic-funding-empowering-small-contributors&quot;&gt;Quadratic Funding: Empowering Small Contributors&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://lh7-us.googleusercontent.com/Hi5JEC9kJbhijxh7EJvtYRZBznZXkE9y4lRb5DWgfO1t6ZEwZCKFaBAsYQOjvlcbVduD9Nf9ganHIvq4iSJpKP4cNfV5QtAf3_Igffpt7rDy4iWtye0gTd-z-Ttk5fU5sRIz46wX16nMNJ6qeo4vMJ0?width=1400&amp;auto=format&quot; srcset=&quot;https://lh7-us.googleusercontent.com/Hi5JEC9kJbhijxh7EJvtYRZBznZXkE9y4lRb5DWgfO1t6ZEwZCKFaBAsYQOjvlcbVduD9Nf9ganHIvq4iSJpKP4cNfV5QtAf3_Igffpt7rDy4iWtye0gTd-z-Ttk5fU5sRIz46wX16nMNJ6qeo4vMJ0?width=700&amp;auto=format&amp;dpr=1 1x, https://lh7-us.googleusercontent.com/Hi5JEC9kJbhijxh7EJvtYRZBznZXkE9y4lRb5DWgfO1t6ZEwZCKFaBAsYQOjvlcbVduD9Nf9ganHIvq4iSJpKP4cNfV5QtAf3_Igffpt7rDy4iWtye0gTd-z-Ttk5fU5sRIz46wX16nMNJ6qeo4vMJ0?width=700&amp;auto=format&amp;dpr=2 2x, https://lh7-us.googleusercontent.com/Hi5JEC9kJbhijxh7EJvtYRZBznZXkE9y4lRb5DWgfO1t6ZEwZCKFaBAsYQOjvlcbVduD9Nf9ganHIvq4iSJpKP4cNfV5QtAf3_Igffpt7rDy4iWtye0gTd-z-Ttk5fU5sRIz46wX16nMNJ6qeo4vMJ0?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Unsplash: Hannah&lt;/p&gt;
&lt;p&gt;QF operates on a fundamental principle: it democratically matches funds to benefit small contributors considerably.&lt;/p&gt;
&lt;p&gt;This innovative model stands as a pillar of fairness and inclusivity, ensuring that resources for community projects are allocated based on collective support rather than the preferences of a privileged few.&lt;/p&gt;
&lt;p&gt;Why does this matter? &lt;/p&gt;
&lt;p&gt;QF is like the superhero of crowdfunding. It levels the playing field, ensuring even the smallest donor has a voice. No more one-size-fits-all matching – it&apos;s about amplifying community support.&lt;/p&gt;
&lt;p&gt;Parties Involved:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Every community member&lt;/li&gt;
&lt;li&gt;Large Donors&lt;/li&gt;
&lt;li&gt;Grantees (those seeking funding for a cause)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;heading-the-quadratic-funding-process-unveiled&quot;&gt;The Quadratic Funding Process Unveiled&lt;/h2&gt;
&lt;p&gt;Here&apos;s how QF works:&lt;/p&gt;
&lt;h3 id=&quot;heading-1-create-a-matching-pool&quot;&gt;1. Create a Matching Pool&lt;/h3&gt;
&lt;p&gt;Initiating the process involves setting aside a matching pool of funds. This pool catalyzes amplifying individual contributions.&lt;/p&gt;
&lt;h3 id=&quot;heading-2-community-support-for-donations&quot;&gt;2. Community Support for Donations&lt;/h3&gt;
&lt;p&gt;The heart of QF lies in community involvement. The platform encourages individuals to contribute to public goods they value, irrespective of the amount. This widens the participation net, making it accessible to diverse contributors.&lt;/p&gt;
&lt;h3 id=&quot;heading-3-quadratic-formula-in-action&quot;&gt;3. Quadratic Formula in Action&lt;/h3&gt;
&lt;p&gt;The unique aspect of QF is its application of a quadratic formula. This formula gives more weight to smaller contributions, leveling the playing field. It ensures that projects with more contributors receive more generous matching funds, even if each contributes modestly.&lt;/p&gt;
&lt;h3 id=&quot;heading-4-distribution-of-matching-funds&quot;&gt;4. Distribution of Matching Funds&lt;/h3&gt;
&lt;p&gt;The matching funds, determined by the quadratic formula, are then distributed to public goods. This mechanism guarantees a more equitable allocation of funds based on community preferences, fostering an environment where projects gain support not solely based on their size but on their broad appeal.&lt;/p&gt;
&lt;h2 id=&quot;heading-practical-example-marks-open-source-project&quot;&gt;Practical Example: Mark&apos;s Open-Source Project&lt;/h2&gt;
&lt;p&gt;Consider Mark, a developer with a vision for an open-source project enhancing online privacy. Launching his campaign on a QF platform (Gitcoin), Mark welcomes support from a diverse community.&lt;/p&gt;
&lt;p&gt;Even small contributors who believe in his vision significantly impact the project thanks to the quadratic incentives.&lt;/p&gt;
&lt;p&gt;For instance, a hundred contributors, each donating $1, could receive more matching funds than ten contributors, each donating $10.&lt;/p&gt;
&lt;p&gt;The quadratic formula&apos;s magic lies in recognizing the widespread support that Mark&apos;s project garners, irrespective of individual contribution size.&lt;/p&gt;
&lt;p&gt;This real-world example showcases how QF goes beyond the traditional fundraising model. It empowers projects like Mark&apos;s, which may lack backing from major funders, by democratizing the allocation of resources and emphasizing community-driven decision-making.&lt;/p&gt;
&lt;p&gt;This way, QF catalyzes innovation and supports projects that resonate with a broader audience.&lt;/p&gt;
&lt;h2 id=&quot;heading-how-does-quadratic-funding-improve-crowdfunding&quot;&gt;How Does Quadratic Funding Improve Crowdfunding?&lt;/h2&gt;
&lt;p&gt;QF improves crowding funding in many ways; here are a few.&lt;/p&gt;
&lt;h3 id=&quot;heading-democratizing-the-funding-landscape&quot;&gt;Democratizing the Funding Landscape&lt;/h3&gt;
&lt;p&gt;QF disrupts conventional crowdfunding norms by introducing a democratic and inclusive approach. Unlike traditional methods favoring large donors, this model places significance on the number of contributors.&lt;/p&gt;
&lt;p&gt;In essence, it shifts the power dynamic, ensuring that each voice, regardless of financial capacity, plays a crucial role in determining the allocation of funds.&lt;/p&gt;
&lt;h3 id=&quot;heading-incentivizing-modest-contributions&quot;&gt;Incentivizing Modest Contributions&lt;/h3&gt;
&lt;p&gt;The core strength of QF lies in its ability to incentivize a multitude of modest donations.&lt;/p&gt;
&lt;p&gt;Doing so breaks away from the trend observed in traditional fundraising, where a limited number of significant contributions from affluent individuals or organizations tend to dominate.&lt;/p&gt;
&lt;p&gt;This shift in focus encourages a broader spectrum of supporters, fostering a community-driven ethos where every contributor, irrespective of the donation size, contributes meaningfully to the cause.&lt;/p&gt;
&lt;h3 id=&quot;heading-countering-funding-concentration&quot;&gt;Countering Funding Concentration&lt;/h3&gt;
&lt;p&gt;Traditional crowdfunding often concentrates funds on well-known or already successful projects. QF disrupts this pattern by rewarding projects with widespread support. The quadratic formula matches contributions many people make more generously than those made by fewer individuals. This counteracts the rich-get-richer phenomenon, promoting diversity and inclusivity in the distribution of funds.&lt;/p&gt;
&lt;h3 id=&quot;heading-fostering-diversity-and-fairness&quot;&gt;Fostering Diversity and Fairness&lt;/h3&gt;
&lt;p&gt;QF places a premium on community support, resulting in a fairer distribution of resources for public goods. It inherently values diversity in terms of the number of contributors and the types of projects that receive support. Smaller projects, which might not have the backing of major funders but are nonetheless significant to the community, stand to benefit significantly.&lt;/p&gt;
&lt;p&gt;This emphasis on fairness and inclusivity sets QF apart as a transformative force in crowdfunding.&lt;/p&gt;
&lt;h3 id=&quot;heading-transparency-and-community-involvement&quot;&gt;Transparency and Community Involvement&lt;/h3&gt;
&lt;p&gt;QF aligns with the principles of decentralization and community involvement. The transparent nature of the process, coupled with visible fund allocation, builds trust and confidence among contributors. It ensures that decisions are made collaboratively, based on community preferences, rather than being swayed by the interests of a small group of affluent donors.&lt;/p&gt;
&lt;h2 id=&quot;heading-benefits-of-quadratic-funding&quot;&gt;Benefits of Quadratic Funding&lt;/h2&gt;
&lt;h3 id=&quot;heading-encourages-a-wide-variety-of-contributors&quot;&gt;Encourages a Wide Variety of Contributors&lt;/h3&gt;
&lt;p&gt;QF encourages diverse participation by providing matching funds for small contributions, irrespective of financial resources.&lt;/p&gt;
&lt;h3 id=&quot;heading-incentivizes-high-quality-work&quot;&gt;Incentivizes High-Quality Work&lt;/h3&gt;
&lt;p&gt;It motivates contributors to produce high-quality work, rewarding projects that generate positive feedback from the community.&lt;/p&gt;
&lt;h3 id=&quot;heading-reduces-influence-of-large-donors&quot;&gt;Reduces Influence of Large Donors&lt;/h3&gt;
&lt;p&gt;QF lessens the impact of wealthy donors, ensuring a more representative distribution of funds based on community support.&lt;/p&gt;
&lt;h3 id=&quot;heading-supports-transparency&quot;&gt;Supports Transparency&lt;/h3&gt;
&lt;p&gt;Platforms utilizing QF can enhance transparency by clearly illustrating how they distribute donations, building public confidence.&lt;/p&gt;
&lt;h3 id=&quot;heading-democratizes-decision-making&quot;&gt;Democratizes Decision-Making&lt;/h3&gt;
&lt;p&gt;The democratic nature of QF ensures that decisions are made based on widespread community support rather than the preferences of a few affluent individuals.&lt;/p&gt;
&lt;h2 id=&quot;heading-demerits-of-quadratic-funding-you-should-know&quot;&gt;Demerits of Quadratic Funding You Should Know&lt;/h2&gt;
&lt;h3 id=&quot;heading-difficulty-in-measuring-impact&quot;&gt;Difficulty in Measuring Impact&lt;/h3&gt;
&lt;p&gt;Measuring impact can be challenging and arbitrary, making it difficult to distribute resources wisely.&lt;/p&gt;
&lt;h3 id=&quot;heading-possibility-for-abuse&quot;&gt;Possibility for Abuse&lt;/h3&gt;
&lt;p&gt;Dishonest individuals may use the system through forged donations or collusion.&lt;/p&gt;
&lt;h3 id=&quot;heading-lack-of-diversity&quot;&gt;Lack of Diversity&lt;/h3&gt;
&lt;p&gt;Biases and preferences of the larger community may still influence public goods funded through QF.&lt;/p&gt;
&lt;h3 id=&quot;heading-need-for-infrastructure-and-resources&quot;&gt;Need for Infrastructure and Resources&lt;/h3&gt;
&lt;p&gt;Establishing a QF system requires significant infrastructure and investment, limiting accessibility.&lt;/p&gt;
&lt;h3 id=&quot;heading-impact-determination-challenges&quot;&gt;Impact Determination Challenges&lt;/h3&gt;
&lt;p&gt;The system may need help accurately determining the impact of funded projects, which could make assessing success difficult.&lt;/p&gt;
&lt;h2 id=&quot;heading-blockchain-technology-and-the-future-of-quadratic-funding&quot;&gt;Blockchain Technology and the Future of Quadratic Funding&lt;/h2&gt;
&lt;p&gt;Looking ahead, blockchain technology is poised to play a major role in improving the effectiveness and efficiency of QF.&lt;/p&gt;
&lt;p&gt;Blockchain offers a secure, open, unchangeable record of donations and funding distributions. Smart contracts can automate the funding process, ensuring equitable and transparent distribution of funds.&lt;/p&gt;
&lt;p&gt;The decentralization enabled by blockchain can increase the accessibility of QF, supporting smaller, less-resourced groups and fostering the participation of diverse communities.&lt;/p&gt;
&lt;p&gt;Tokens representing contributions can streamline fund tracking and transfer, giving donors a tangible representation of their commitment to a project.&lt;/p&gt;
&lt;p&gt;List of projects using QF:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gitcoin&lt;/li&gt;
&lt;li&gt;Ethereum&lt;/li&gt;
&lt;li&gt;Pomelo&lt;/li&gt;
&lt;li&gt;Giveth&lt;/li&gt;
&lt;li&gt;Supermodular&lt;/li&gt;
&lt;li&gt;Endaoment&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;heading-final-thought&quot;&gt;Final Thought&lt;/h2&gt;
&lt;p&gt;QF is a transformative force in crowdfunding, championing community involvement, fairness, and inclusivity. Gitcoin Grants is already rocking this, raising over &lt;a target=&quot;_blank&quot; href=&quot;https://youtu.be/HJljTtLnymE?si=LPED3vDCxePXRNeI&quot;&gt;$4 Million&lt;/a&gt; in Ethereum communities. As it continues to gain traction, its potential impact on public goods projects. While challenges exist, the innovative nature of QF positions it as a dynamic and evolving model with promising prospects. Its uniqueness lies in prioritizing the number of supporters rather than the highest monetary value.&lt;/p&gt;
&lt;p&gt;Say goodbye to traditional crowdfunding: QF is the innovative way forward in Web3.&lt;/p&gt;
&lt;h2 id=&quot;heading-frequently-asked-questions-faqs&quot;&gt;Frequently Asked Questions (FAQs)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What principle underpins QF?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;QF prioritizes widespread support over substantial donations, fostering a democratized crowdfunding process where community participation takes precedence.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How does blockchain technology enhance the effectiveness of QF?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Blockchain is the cornerstone by providing a secure and transparent ledger for recording donations.&lt;/p&gt;
&lt;p&gt;Simultaneously, smart contracts automate the intricate funding distribution process, thereby increasing operational efficiency and mitigating the risks associated with potential abuse.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What are the primary advantages associated with QF?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;QF offers a multifaceted array of benefits. It encourages a diverse spectrum of contributors and acts as a catalyst for high-quality work.&lt;/p&gt;
&lt;p&gt;Additionally, it diminishes the disproportionate influence of large donors, promotes transparency in fund allocation, and embodies a democratic decision-making approach.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What challenges does QF encounter?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The challenges encompass measuring impact, mitigating the potential for abuse, addressing the lack of diversity in funded projects, securing the necessary infrastructure and resources, and accurately determining the effect of funded initiatives. Each presents a nuanced aspect contributing to QF&apos;s complexities in its implementation and sustainability.&lt;/p&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Crafting Beautiful Light Art with Figma and Midjourney</title>
    <link href="https://blog.developerdao.com/crafting-beautiful-light-art-with-figma-and-midjourney"/>
    <id>https://blog.developerdao.com/crafting-beautiful-light-art-with-figma-and-midjourney</id>
    <updated>2024-01-22T09:03:25.962Z</updated>
    <author><name>Erik Knobl</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1705913981276/9ed107a6-5d9a-4a16-9128-af4025696943.jpeg?width=600&amp;format=auto"/>
    <summary>Learn how to use sketches to guide your prompts in Midjourney to craft amazing Generative AI images.</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705913981276/9ed107a6-5d9a-4a16-9128-af4025696943.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705913981276/9ed107a6-5d9a-4a16-9128-af4025696943.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705913981276/9ed107a6-5d9a-4a16-9128-af4025696943.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705913981276/9ed107a6-5d9a-4a16-9128-af4025696943.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;p&gt;One of the most overlooked features of Midjourney is the ability to include images in your &lt;code&gt;/imagine&lt;/code&gt; prompt. This gives you the power to influence a prompt&apos;s basic visual structure. The more details this image has, the more it will influence your result.&lt;/p&gt;
&lt;p&gt;Recently, I have been using very simple sketches created in Figma to influence my Midjourney prompts, and the results are amazing.&lt;/p&gt;
&lt;p&gt;First, you can do this with Photoshop, Illustration, Canva, or other tools—even drawn sketches. However, for this tutorial, we&apos;ll be using Figma. If you want to learn more about Midjourney, check out my &lt;a target=&quot;_blank&quot; href=&quot;https://medium.com/@Erik_Knobl/mastering-midjourney-beginners-guide-f6d4087a2b40&quot;&gt;Beginner&apos;s Guide&lt;/a&gt; and &lt;a target=&quot;_blank&quot; href=&quot;https://medium.com/@Erik_Knobl/mastering-midjourney-complete-guide-to-image-effects-68cf5c70e45c&quot;&gt;Complete Guide to Image Effects&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;heading-step-1-background&quot;&gt;Step 1: Background&lt;/h2&gt;
&lt;p&gt;Let&apos;s get started by creating a frame in Figma with the same shape as the image we want to make. In this case, we are using the 16:9 format and painting it with a dark tone, as we want our future image to be set during the night.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705584458851/b9240e00-fc44-4e9b-abc2-edd292dcf510.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705584458851/b9240e00-fc44-4e9b-abc2-edd292dcf510.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705584458851/b9240e00-fc44-4e9b-abc2-edd292dcf510.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705584458851/b9240e00-fc44-4e9b-abc2-edd292dcf510.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Figma screen creating a frame&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-step-2-shapes&quot;&gt;Step 2: Shapes&lt;/h2&gt;
&lt;p&gt;Then, draw a shape - a line, circle, square, or anything you like!&lt;/p&gt;
&lt;p&gt;As we want to create an image of a light portal for this guide, we draw a shape that looks like an uneven circle. You can do that by using two circles and the &quot;Subtract&quot; feature, or just make a circle of one color and add another on top with the same color as your background.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705584480038/86a7d97e-37aa-4f20-9c34-be6424dcc92b.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705584480038/86a7d97e-37aa-4f20-9c34-be6424dcc92b.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705584480038/86a7d97e-37aa-4f20-9c34-be6424dcc92b.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705584480038/86a7d97e-37aa-4f20-9c34-be6424dcc92b.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Firgma screenshot of two circles&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-step-3-effects&quot;&gt;Step 3: Effects&lt;/h2&gt;
&lt;p&gt;Let&apos;s add a cool glow effect. Add layer blurs to the shape. You can duplicate the shape a few times and use blurs with different values to make it look 3D. Once you&apos;re happy with its appearance, export the image as a PNG and bring it to the Discord of Midjourney.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705584496166/3a740da1-7c5d-4783-b0c5-09547b808e85.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705584496166/3a740da1-7c5d-4783-b0c5-09547b808e85.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705584496166/3a740da1-7c5d-4783-b0c5-09547b808e85.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705584496166/3a740da1-7c5d-4783-b0c5-09547b808e85.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Figma screenshot of two circles with blur effect&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-step-4-prompting&quot;&gt;Step 4: Prompting&lt;/h2&gt;
&lt;p&gt;Now, let&apos;s start building the prompt in Midjourney (for the basics, &lt;a target=&quot;_blank&quot; href=&quot;https://medium.com/@Erik_Knobl/mastering-midjourney-beginners-guide-f6d4087a2b40&quot;&gt;check out this guide&lt;/a&gt;.) Start by adding the image link. Midjourney allows you to add images to a prompt by pasting in a URL. Then, describe what you want the light to do in the picture. You can design the rest of the prompt however you like. In this example, we will be using the following prompt:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Cinematic Medium Shot, mysterious human, circular portal in an alien wasteland leading towards a nebula, in the style of biblical drama, monumental figures, voluminous mass --ar 16:9 --iw 0.5 --v 6 --style raw&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;heading-what-is-the-iw-in-midjourney&quot;&gt;What is the IW in Midjourney?&lt;/h3&gt;
&lt;p&gt;It&apos;s the image weight parameter --iw. It&apos;s used to &lt;strong&gt;adjust the importance of the image vs. text portion of a prompt&lt;/strong&gt;. The default value is used when no --iw is specified. Let&apos;s try playing with three different values (0.9, 0.5, and 0.9) and see the results:&lt;/p&gt;
&lt;p&gt;![Cinematic Medium Shot, mysterious human, circular portal in an alien wasteland leading towards a nebula, in the style of biblical drama, monumental figures, voluminous mass Midjourney](https://cdn.hashnode.com/res/hashnode/image/upload/v1705584550255/7e5d9281-b42c-4335-8ac2-a6c10ba3af18.png align= &quot;center&quot;)&lt;/p&gt;
&lt;p&gt;A weight of 0.9 is very heavy in our prompt. Let&apos;s reduce it a little bit.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705584828304/593a43dd-851a-4f8a-bf17-59fff0f6049b.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705584828304/593a43dd-851a-4f8a-bf17-59fff0f6049b.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705584828304/593a43dd-851a-4f8a-bf17-59fff0f6049b.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705584828304/593a43dd-851a-4f8a-bf17-59fff0f6049b.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Cinematic Medium Shot, mysterious human, circular portal in an alien wasteland leading towards a nebula, in the style of biblical drama, monumental figures, voluminous mass Midjourney&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Weight 0.5 is better. Maybe we can push it a little bit more?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705584921071/8ae114c1-944b-4153-a4d0-ccbbb9d8211b.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705584921071/8ae114c1-944b-4153-a4d0-ccbbb9d8211b.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705584921071/8ae114c1-944b-4153-a4d0-ccbbb9d8211b.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705584921071/8ae114c1-944b-4153-a4d0-ccbbb9d8211b.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Cinematic Medium Shot, mysterious human, circular portal in an alien wasteland leading towards a nebula, in the style of biblical drama, monumental figures, voluminous mass Midjourney&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Weight 0.1 is so much better.&lt;/p&gt;
&lt;p&gt;That&apos;s it! You&apos;re done!&lt;/p&gt;
&lt;p&gt;You can use the same technique to experiment with different shapes, colors of light, or even &lt;a target=&quot;_blank&quot; href=&quot;https://erikknobl.gumroad.com/l/PromptCore-BasicGuidetoMidjourney-CameraAngles&quot;&gt;camera angles&lt;/a&gt; and combine them with various prompts.&lt;/p&gt;
&lt;p&gt;I hope this tutorial has been helpful and has given you a new set of tools to explore.&lt;/p&gt;
&lt;p&gt;As mentioned before, there are many tools out there for creating these light shapes, but Figma is my favorite, and the best part is it&apos;s free for anyone to use!&lt;/p&gt;
&lt;p&gt;Thanks for reading!&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/blog-newsletter-1&quot;&gt;&lt;img src=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=1400&amp;auto=format&quot; srcset=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=1 1x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=2 2x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Subscribe to the Developer DAO Newsletter. Probably Nothing&quot; class=&quot;mx-auto&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;Hi👋 I&apos;m Erik, a product designer by day and AI storyteller by night.&lt;br /&gt;I&apos;ve always been crafting stories in my dreams, and now I feel powered by Generative AI tools to make them a reality.&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>NEAR Chain Abstraction Explained</title>
    <link href="https://blog.developerdao.com/near-chain-abstraction-explained"/>
    <id>https://blog.developerdao.com/near-chain-abstraction-explained</id>
    <updated>2024-01-19T09:03:25.382Z</updated>
    <author><name>Ϗ</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1705489484539/540e01c0-aa61-448a-aa7c-3934f5ff9138.jpeg?width=600&amp;format=auto"/>
    <summary>Web3 gives users more control over their data and payments. Still, we pay for these benefits with increased technical and UX complexity. In recent years, blockchain ecosystems have tried to improve onboarding to get a hold of the UX part, but as many...</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705489484539/540e01c0-aa61-448a-aa7c-3934f5ff9138.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705489484539/540e01c0-aa61-448a-aa7c-3934f5ff9138.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705489484539/540e01c0-aa61-448a-aa7c-3934f5ff9138.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705489484539/540e01c0-aa61-448a-aa7c-3934f5ff9138.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;p&gt;Web3 gives users more control over their data and payments. Still, we pay for these benefits with increased technical and UX complexity. In recent years, blockchain ecosystems have tried to improve onboarding to get a hold of the UX part, but as many new chains sprouted, the technical complexities grew with them.&lt;/p&gt;
&lt;p&gt;Account abstraction solves key management quite nicely. When a smart contract can decide when TXs are valid, nobody needs to juggle keys anymore, but wouldn’t it be nice if we could abstract away the different chains altogether? NEAR leverages account abstraction, modular data availability, cross-chain liquidity networks, and composable decentralized frontends for chain interoperability—one account for all chains.&lt;/p&gt;
&lt;p&gt;This article explains what chain abstraction means in practice and how NEAR achieves it.&lt;/p&gt;
&lt;h2 id=&quot;heading-what-is-chain-abstraction&quot;&gt;What is Chain Abstraction?&lt;/h2&gt;
&lt;p&gt;Chain abstraction lets you &lt;strong&gt;sign and transact on multiple blockchains with one NEAR account&lt;/strong&gt;. Instead of creating an account for each chain and managing multiple seed phrases or keys, you create one NEAR account and let it take care of the keys and sign for you. NEAR calls the storage of keys for multiple chains in one NEAR account “Account Aggregation”.&lt;/p&gt;
&lt;p&gt;NEAR even allows you to &lt;strong&gt;hide all blockchain-related information from users&lt;/strong&gt;. As NEAR supports linking OpenID Connect accounts to NEAR accounts, account abstraction allows using a simple email login to transact on multiple chains simultaneously.&lt;/p&gt;
&lt;p&gt;The unique selling point is that no bridge smart contracts are involved; you do all your transactions on the target chain. For example, a DEX that uses chain abstraction could swap Bitcoin to Ethereum directly since the DEX’s keys that manage the funds on their respective chain are all part of a single NEAR account.&lt;/p&gt;
&lt;p&gt;Check out our chain abstraction introduction workshop!&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=IjRUYxioZLo&quot;&gt;https://www.youtube.com/watch?v=IjRUYxioZLo&lt;/a&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2 id=&quot;heading-how-do-near-accounts-work&quot;&gt;How Do NEAR Accounts Work?&lt;/h2&gt;
&lt;p&gt;Before diving into chain abstraction, you should understand NEAR’s account system, as everything flows from there.&lt;/p&gt;
&lt;h3 id=&quot;heading-one-account-many-keys&quot;&gt;One Account - Many Keys&lt;/h3&gt;
&lt;p&gt;Each big layer 1 blockchain network has its specialty. NEAR’s killer feature is its account system, which allows you to manage and rotate multiple keys in one account with a human-readable name.&lt;/p&gt;
&lt;p&gt;Your account name or “address” could be &lt;em&gt;example.near&lt;/em&gt;, so everyone who knows it can send you tokens. However, you could create a key for every smart contract you use to limit the damage if one of these keys gets stolen. As only keys that are currently active in your account can sign new transactions, you can replace one key for one smart contract, keep the keys for all the safe smart contracts, and keep using your account name. Figure 1 illustrates the difference between EVM and NEAR accounts.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705488985429/088935ce-ad5c-426d-9b6f-e1709f4ed796.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705488985429/088935ce-ad5c-426d-9b6f-e1709f4ed796.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705488985429/088935ce-ad5c-426d-9b6f-e1709f4ed796.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705488985429/088935ce-ad5c-426d-9b6f-e1709f4ed796.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Figure 1: EVM and NEAR account comparison&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Figure 1: EVM and NEAR account comparison&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;On EVM chains, &lt;strong&gt;you derive an address from a public key&lt;/strong&gt;, which, in turn, is derived from a private key. Private keys are usually deterministically generated from a seed phrase, so a user doesn’t have to remember all keys.&lt;/p&gt;
&lt;p&gt;As EVM chains handle all assets via an address and &lt;strong&gt;each address only has one key pair&lt;/strong&gt;, you can’t rotate these keys easily. A new key pair means a new address and a new address requires moving all assets from the old address to the new one.&lt;/p&gt;
&lt;p&gt;NEAR uses account IDs like addresses on EVM chains. NEAR supports implicit accounts, which work similarly to the EVM addresses. Yet, named accounts are where NEAR shines. In the case of named accounts, &lt;strong&gt;you don’t derive these IDs from public keys; you store the public keys in the account&lt;/strong&gt;. Seed phrases are also supported to generate keys. Think of it as ENS built into the protocol.&lt;/p&gt;
&lt;p&gt;NEAR handles all assets via an account ID, but since it isn’t directly related to a key pair, &lt;strong&gt;you can rotate keys without changing your “address”&lt;/strong&gt;—no need to move your assets to the new address when you get a new key.&lt;/p&gt;
&lt;p&gt;There are two types of keys in a NEAR account:&lt;/p&gt;
&lt;h4 id=&quot;heading-1-fullaccess-keys&quot;&gt;1. FullAccess Keys&lt;/h4&gt;
&lt;p&gt;You use them to &lt;strong&gt;manage the account&lt;/strong&gt; by creating and deleting keys, calling smart contract functions, and even deleting the whole account. A FullAccess key gives admin access to an account.&lt;/p&gt;
&lt;h4 id=&quot;heading-2-functioncall-keys&quot;&gt;2. FunctionCall Keys&lt;/h4&gt;
&lt;p&gt;They are light versions of FullAccess keys. A FunctionCall key can &lt;strong&gt;call the functions of one smart contract&lt;/strong&gt;. You can also limit which functions a key can call and set an allowance of funds the key can transfer. If a FunctionCall key gets leaked, you can replace it with a new one.&lt;/p&gt;
&lt;h3 id=&quot;heading-support-for-openid-connect-and-recovery&quot;&gt;Support for OpenID Connect and Recovery&lt;/h3&gt;
&lt;p&gt;Another nice feature (albeit not part of the account system but built on top) is the support for OIDC accounts. With the &lt;a target=&quot;_blank&quot; href=&quot;https://docs.near.org/tools/fastauth-sdk#introduction&quot;&gt;FastAuth SDK&lt;/a&gt;, you can &lt;strong&gt;build an email-based authentication flow&lt;/strong&gt; that creates NEAR accounts in the background and relays transactions via &lt;a target=&quot;_blank&quot; href=&quot;https://docs.near.org/develop/relayers/build-relayer&quot;&gt;your server&lt;/a&gt;. The SDK generates a FullAccess key (controlled by NEAR MPC nodes) to manage and recover the account.&lt;/p&gt;
&lt;p&gt;Human-readable account names, key rotation, email logins, and account recovery make NEAR a powerful platform. Consequently, leveraging these features on other blockchain networks would greatly improve the Web3 space.&lt;/p&gt;
&lt;h2 id=&quot;heading-how-does-near-chain-abstraction-work&quot;&gt;How Does NEAR Chain Abstraction Work?&lt;/h2&gt;
&lt;p&gt;Now that you understand NEAR’s account model let’s look at chain abstraction.&lt;/p&gt;
&lt;p&gt;As mentioned, chain abstraction lets you sign and transact on multiple chains with one NEAR account. If required, you can even hide all blockchain information from a user.&lt;/p&gt;
&lt;p&gt;These are the five features that enable this marvel:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;OIDC accounts can control NEAR accounts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Relay servers can subsidize gas fees.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Accounts on NEAR can hold multiple keys.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Support for MPC key generation functions for other chains (i.e., account aggregation)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A frontend hosting platform that connects the keys on NEAR with libraries that connect to other chain networks.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Since you already learned about &lt;a target=&quot;_blank&quot; href=&quot;https://docs.near.org/concepts/basics/accounts/model&quot;&gt;the account model&lt;/a&gt; and &lt;a target=&quot;_blank&quot; href=&quot;https://docs.near.org/tools/fastauth-sdk#introduction&quot;&gt;the FastAuth SDK&lt;/a&gt;, we will check out points 4 and 5.&lt;/p&gt;
&lt;h3 id=&quot;heading-mpc-key-generation-for-multiple-chains&quot;&gt;MPC Key Generation for Multiple Chains&lt;/h3&gt;
&lt;p&gt;NEAR allows the storage of multiple keys in one account, but obviously, only the public keys are stored there to enable the network to verify your signatures. The private keys are usually stored locally; &lt;strong&gt;you should never upload private keys anywhere!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;NEAR wanted to go beyond abstracting multi-chain interactions; they &lt;strong&gt;tri&lt;/strong&gt;ed to hide all blockchain complexity from users. They created a multi-party computation (MPC) node network for private keys. These nodes use threshold cryptography to hold only parts of each key and can sign messages for the user without one node knowing the full key. This shared custody &lt;strong&gt;prevents nodes from using your private key without the consent of multiple other nodes&lt;/strong&gt; in the network. This feature is called Chain Signatures.&lt;/p&gt;
&lt;p&gt;When a user wants to sign a message, each node can use a part of the private key to create a partial signature and send it to the user, who then assembles it into a full signature. You can see the process in Figure 2; each node only has a part of the private key and only generates a part of the signature.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705489296909/fad3d173-43d1-434c-9fa1-ac57f9368ca7.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705489296909/fad3d173-43d1-434c-9fa1-ac57f9368ca7.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705489296909/fad3d173-43d1-434c-9fa1-ac57f9368ca7.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705489296909/fad3d173-43d1-434c-9fa1-ac57f9368ca7.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Figure 2: NEAR MPC signing process&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Figure 2: NEAR MPC signing process&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;These MPC nodes got a recent update that allows them to generate keys for EVM chains and Bitcoin, enabling users to sign transactions outside of NEAR.&lt;/p&gt;
&lt;h3 id=&quot;heading-layer-2-data-availability&quot;&gt;Layer 2 Data Availability&lt;/h3&gt;
&lt;p&gt;To verify any proof, you need to see when the transactions happened and be able to reconstruct the state. With NEAR’s &lt;a target=&quot;_blank&quot; href=&quot;https://near.org/data-availability&quot;&gt;Data Availability layer&lt;/a&gt;, you can publish your data on decentralized infrastructure for a fraction of the costs on chains like Ethereum or Celestia. See Figure 3 for a cost comparison.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705489362865/b9671b53-83a5-40db-b2fb-b4ef29ecc9d4.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705489362865/b9671b53-83a5-40db-b2fb-b4ef29ecc9d4.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705489362865/b9671b53-83a5-40db-b2fb-b4ef29ecc9d4.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705489362865/b9671b53-83a5-40db-b2fb-b4ef29ecc9d4.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Figure 3: Data availability cost comparison&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Figure 3: Data availability cost comparison&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Part 3 of our chain abstraction workshop is about data availability.&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=kpwAi0YMhv4&quot;&gt;https://www.youtube.com/watch?v=kpwAi0YMhv4&lt;/a&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h3 id=&quot;heading-frontend-component-hosting&quot;&gt;Frontend Component Hosting&lt;/h3&gt;
&lt;p&gt;Now that all the pieces are in place, we must connect them. That’s where &lt;a target=&quot;_blank&quot; href=&quot;https://docs.near.org/bos/overview&quot;&gt;the Blockchain Operating System&lt;/a&gt; (BOS) comes into play. Figure 3 illustrates how the BOS fits into the picture.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705489405606/12a1b2eb-0403-4406-8725-cf5696b56235.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1705489405606/12a1b2eb-0403-4406-8725-cf5696b56235.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705489405606/12a1b2eb-0403-4406-8725-cf5696b56235.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1705489405606/12a1b2eb-0403-4406-8725-cf5696b56235.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Figure 3: The BOS architecture&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The BOS platform manages onchain frontend components.&lt;/p&gt;
&lt;p&gt;With the &lt;a target=&quot;_blank&quot; href=&quot;https://docs.near.org/bos/dev/bos-loader&quot;&gt;BOS Loader&lt;/a&gt;, you can &lt;strong&gt;fetch&lt;/strong&gt; &lt;a target=&quot;_blank&quot; href=&quot;https://docs.near.org/bos/components&quot;&gt;&lt;strong&gt;built-in components&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;stored on the NEAR chain and reuse them in your application&lt;/strong&gt;. You can also &lt;strong&gt;create your own components and store them on NEAR&lt;/strong&gt;; there is &lt;a target=&quot;_blank&quot; href=&quot;https://near.org/sandbox&quot;&gt;a handy online IDE&lt;/a&gt; to get you started. Each component can access website and blockchain data via &lt;a target=&quot;_blank&quot; href=&quot;https://docs.near.org/bos/api/home&quot;&gt;the BOS API&lt;/a&gt;. A nice extra here: When building a NEAR component, you have components from &lt;a target=&quot;_blank&quot; href=&quot;https://www.radix-ui.com/primitives/docs/overview/introduction&quot;&gt;the Radix library&lt;/a&gt; implicitly available, so you don’t have to start from scratch.&lt;/p&gt;
&lt;p&gt;NEAR components and the FastAuth SDK form the glue between your users and the blockchain ecosystem. Login with email, let MPC nodes sign transactions for your chain of choice, and then submit them via a relay server.&lt;/p&gt;
&lt;p&gt;Part 2 of our chain abstraction workshop series is about building composable and decentralized frontends!&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=pk8QkBqafm4&quot;&gt;https://www.youtube.com/watch?v=pk8QkBqafm4&lt;/a&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2 id=&quot;heading-future-outlook&quot;&gt;Future Outlook&lt;/h2&gt;
&lt;p&gt;NEAR has some exciting features in the pipeline that will enable smart contracts to serve even more use cases.&lt;/p&gt;
&lt;h3 id=&quot;heading-encrypted-onchain-content&quot;&gt;Encrypted Onchain Content&lt;/h3&gt;
&lt;p&gt;Chain signatures (i.e., signing with MPC nodes) allow anyone to communicate securely with a smart contract by &lt;a target=&quot;_blank&quot; href=&quot;https://youtu.be/rLTSBLbePLU?t=616&quot;&gt;depositing an encrypted payload&lt;/a&gt; and then having that content re-encrypted and sent to a third party.&lt;/p&gt;
&lt;p&gt;In theory, this can be used for MEV mitigation, assuming we can have encrypted pools of transactions that miners can’t see before they need to be executed. Users send encrypted bids to the chain, and when the bid closes, the network nodes will decrypt the bids and evaluate them synchronously. This enables private Dutch auctions and more efficient trading with less frontrunning or slippage.&lt;/p&gt;
&lt;h3 id=&quot;heading-smart-contract-owned-domains&quot;&gt;Smart Contract Owned Domains&lt;/h3&gt;
&lt;p&gt;DNSSEC can verify that &lt;a target=&quot;_blank&quot; href=&quot;https://youtu.be/rLTSBLbePLU?t=793&quot;&gt;a smart contract approved everything served from your domain&lt;/a&gt;. This gives users the transparency to ensure that a genuine frontend serves the application and the ability to vote on the changes to the frontend rather than just the backend. Everything is versioned.&lt;/p&gt;
&lt;h3 id=&quot;heading-omnichain-liquidity&quot;&gt;Omnichain Liquidity&lt;/h3&gt;
&lt;p&gt;Efficient decentralized economies need efficient and liquid markets so users don’t suffer from random slippage when transacting. &lt;a target=&quot;_blank&quot; href=&quot;https://orderly.network/blog/orderly-network-liquidation-engine-a-deep-dive-&quot;&gt;Orderly’s decentralized liquidation engine&lt;/a&gt; improves the security of derivative trading.&lt;/p&gt;
&lt;h3 id=&quot;heading-zero-knowledge-wasm-prover&quot;&gt;Zero-Knowledge WASM Prover&lt;/h3&gt;
&lt;p&gt;To push the boundaries of computing beyond blockchains, the NEAR Foundation and Polygon Labs are embarking on a journey to build &lt;a target=&quot;_blank&quot; href=&quot;https://polygon.technology/blog/polygon-labs-and-near-foundation-collaborate-to-build-a-zkwasm-prover-as-a-component-for-polygon-cdk&quot;&gt;a zero-knowledge prover for WebAssembly blockchains&lt;/a&gt;. This project is still in development.&lt;/p&gt;
&lt;h3 id=&quot;heading-chain-signatures-bounty&quot;&gt;Chain Signatures Bounty&lt;/h3&gt;
&lt;p&gt;Do you have an idea for an awesome use of chain signatures?&lt;/p&gt;
&lt;p&gt;NEAR &lt;a target=&quot;_blank&quot; href=&quot;https://banyan-collective.notion.site/Pagoda-s-Chain-Signatures-089368fa56e74f1a8494dbb8dc5643ff&quot;&gt;offers a 2,000 USDC bounty&lt;/a&gt; for the best implementation of chain signatures!&lt;/p&gt;
&lt;h2 id=&quot;heading-summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;NEAR wants to be the blockchain operating system, and they are on a good trajectory. With account aggregation, their account model is superior to that of EVM chains, and bringing it to other chains is a boon for the whole blockchain ecosystem. If they can pull chain abstraction off, they could become valuable partners for every DApp creator.&lt;/p&gt;
&lt;p&gt;With their onchain component hosting with several built-in components out-of-the-box, they already save developers quite some time, but with FastAuth, MPC key management, and relayers, they could make chain bridging a thing of the past.&lt;/p&gt;
&lt;h2 id=&quot;heading-additional-resources&quot;&gt;Additional Resources&lt;/h2&gt;
&lt;p&gt;Our chain abstraction workshop series&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.youtube.com/watch?v=IjRUYxioZLo&quot;&gt;Part 1: Introduction to Chain Abstraction&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.youtube.com/watch?v=pk8QkBqafm4&quot;&gt;Part 2: Building Composable &amp;amp; Decentralized Frontends&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.youtube.com/watch?v=kpwAi0YMhv4&quot;&gt;Part 3: Data Availability &amp;amp; Account Aggregation&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;NEAR Tutorials&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://docs.near.org/develop/integrate/quickstart-frontend&quot;&gt;DApp Quickstart&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://docs.near.org/develop/contracts/quickstart&quot;&gt;Smart Contract Quickstart&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://docs.near.org/develop/relayers/build-relayer&quot;&gt;Building a Meta Transaction Relayer&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;NEAR Tools&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://docs.near.org/tools/wallet-selector&quot;&gt;Wallet Selector&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://docs.near.org/tools/fastauth-sdk&quot;&gt;FastAuth SDK&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://docs.near.org/bos/dev/vscode&quot;&gt;VS Code Extension&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://jutsu.ai/editor&quot;&gt;BOS Web IDE&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://docs.welldonestudio.io/code/getting-started/&quot;&gt;Remix IDE Plugin&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://github.com/near/awesome-near&quot;&gt;Awesome List of NEAR resources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Unleash the Power of DeFi on Bitcoin</title>
    <link href="https://blog.developerdao.com/unleash-the-power-of-defi-on-bitcoin"/>
    <id>https://blog.developerdao.com/unleash-the-power-of-defi-on-bitcoin</id>
    <updated>2023-12-05T15:40:01.333Z</updated>
    <author><name>Max Efremov</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1701770355419/629acf5a-d7ef-4477-ac40-3f238d81daa5.jpeg?width=600&amp;format=auto"/>
    <summary>If you&apos;ve been building on Ethereum and EVM-compatible chains and yet are intrigued by the potential of Bitcoin, this post is for you. We will talk about Stacks, a Bitcoin layer 2, and how it will unlock $500B+ of Bitcoin liquidity for everyday apps....</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1701770355419/629acf5a-d7ef-4477-ac40-3f238d81daa5.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1701770355419/629acf5a-d7ef-4477-ac40-3f238d81daa5.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1701770355419/629acf5a-d7ef-4477-ac40-3f238d81daa5.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1701770355419/629acf5a-d7ef-4477-ac40-3f238d81daa5.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;p&gt;If you&apos;ve been building on Ethereum and EVM-compatible chains and yet are intrigued by the potential of Bitcoin, this post is for you. We will talk about &lt;a target=&quot;_blank&quot; href=&quot;https://www.stacks.co/&quot;&gt;Stacks&lt;/a&gt;, a Bitcoin layer 2, and how it will unlock $500B+ of Bitcoin liquidity for everyday apps.&lt;/p&gt;
&lt;p&gt;Since 2020’s DeFi Summer, we have seen an explosion of smart contract-enabled applications and user experiences—DEXs, AMMs, lending protocols, NFT marketplaces, and more—that now define Web3 and crypto.&lt;/p&gt;
&lt;p&gt;However, Bitcoin has not seen this innovation because &lt;a target=&quot;_blank&quot; href=&quot;https://www.hiro.so/blog/bitcoin-economy-the-challenges-of-bitcoin-defi&quot;&gt;building on Bitcoin is hard&lt;/a&gt;. Bitcoin Script is an incredibly limited language. That makes Bitcoin very secure—great for a store of value and digital currency—but it comes at the cost of programmability. You can&apos;t build apps and smart contracts directly on Bitcoin, but that is changing.&lt;/p&gt;
&lt;p&gt;We&apos;ve seen a renewed interest in building on Bitcoin in the past year. From the &lt;a target=&quot;_blank&quot; href=&quot;https://www.hiro.so/blog/what-are-bitcoin-ordinals&quot;&gt;ordinals protocol&lt;/a&gt; introducing Bitcoin-native NFTs to &lt;a target=&quot;_blank&quot; href=&quot;https://www.hiro.so/blog/creating-new-fungible-tokens-on-bitcoin-with-brc-20-tokens&quot;&gt;BRC-20&lt;/a&gt; bringing fungible tokens, a wave of innovation is happening on the Bitcoin blockchain, and that doesn&apos;t even touch on the innovation happening on &lt;a target=&quot;_blank&quot; href=&quot;https://www.hiro.so/blog/building-on-bitcoin-project-comparison&quot;&gt;Bitcoin layers&lt;/a&gt;, ranging from rollups to sidechains to Lightning payment channels to Stacks, the largest Web3 project on Bitcoin. The Bitcoin Halving is just around April 2024, and there’s never been a better time to start building on Stacks.&lt;/p&gt;
&lt;h2 id=&quot;heading-stacks-a-bitcoin-layer-2-network&quot;&gt;Stacks: A Bitcoin Layer 2 Network&lt;/h2&gt;
&lt;p&gt;Stacks is a layer 2 network for Bitcoin with a unique consensus mechanism called &lt;a target=&quot;_blank&quot; href=&quot;https://www.hiro.so/blog/securing-web3-apps-through-bitcoin-an-overview-of-stacks-consensus-mechanism&quot;&gt;Proof of Transfer&lt;/a&gt;, enabling it to settle on Bitcoin periodically. Stacks builds on Bitcoin’s security while allowing smart contracts to leverage the same. And coming in 2024, the ecosystem is working on a major upgrade that will bring sBTC, a decentralized, 1:1 Bitcoin-backed, and fully programmable BTC asset, to the ecosystem.&lt;/p&gt;
&lt;p&gt;Stacks is a blockchain that extends the functionality of Bitcoin without modifying its core protocol. Satoshi Nakamoto once described this &lt;a target=&quot;_blank&quot; href=&quot;https://bitcointalk.org/index.php?topic=1790.msg28696#msg28696&quot;&gt;in a forum post&lt;/a&gt;: “a completely separate network and separate blockchain, yet shares computational power with Bitcoin,” increasing the total strength and capabilities of the Bitcoin network.&lt;/p&gt;
&lt;h2 id=&quot;heading-the-stacks-opportunity-for-early-builders&quot;&gt;The Stacks Opportunity for Early Builders&lt;/h2&gt;
&lt;p&gt;Stacks has already brought the innovation of Web3, NFTs, and DeFi to Bitcoin by creating a smart contract layer 2. With the Stacks &lt;a target=&quot;_blank&quot; href=&quot;https://sbtc.tech/#roadmap&quot;&gt;blockchain upgrade coinciding with the Bitcoin Halving&lt;/a&gt; in spring 2024, the Stacks network will soon have a decentralized, programmatic Bitcoin asset: sBTC. You will be able to do everything you can on Ethereum on the Stacks layer 2 with BTC.&lt;/p&gt;
&lt;p&gt;Stacks features include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Moving BTC in and out of the Stacks layer 2 in a decentralized way.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unlocking BTC for billions of users that can’t use the Bitcoin layer 1.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;BTC deployed into many DeFi applications that can’t use layer 1.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can be one of the pioneers since it&apos;s still early—around 200 devs are building in Stacks today, a far cry from Ethereum’s 5,700. However, you&apos;re building on the strongest foundation in crypto: the most secure, largest, oldest, and decentralized blockchain that enables you to tap into over $500B of Bitcoin liquidity. This early stage presents a &lt;a target=&quot;_blank&quot; href=&quot;https://www.hiro.so/blog/attention-bitcoin-developers-theres-a-trillion-dollar-opportunity-waiting-for-you&quot;&gt;one-of-a-kind opportunity&lt;/a&gt; for developers.&lt;/p&gt;
&lt;h2 id=&quot;heading-clarity-the-smart-contract-language-for-stacks&quot;&gt;Clarity: The Smart Contract Language for Stacks&lt;/h2&gt;
&lt;p&gt;Stacks uses &lt;a target=&quot;_blank&quot; href=&quot;https://clarity-lang.org/&quot;&gt;the Clarity smart contract language&lt;/a&gt; to build the next generation of Bitcoin apps.&lt;/p&gt;
&lt;p&gt;Clarity is a LISP-like language that gives Stacks developers a direct way to read and, with sBTC next year, &lt;em&gt;write&lt;/em&gt; transactions to Bitcoin, unlocking countless additional use cases. It&apos;s predictable and secure, making it an ideal choice for high-stakes code where a single bug can cost users billions. Clarity is deterministic—you know where your code will terminate before you execute it, and you can statically analyze your work as you go.&lt;/p&gt;
&lt;p&gt;In the diagram below, you can inspect the two languages executing the same functionality, a simple counter smart contract, side-by-side:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://lh7-us.googleusercontent.com/_L6ZTLzvOk9sA6x5eug0wZqksI22kRbc5CY7rrJg1cdNOINPG20lX5MdKp7Tb1ZVWpmePWyhZmQ0Oek0doPOp1OXMDwQzTccw-h8Y9Uk42q0qk4bQWOC7KXYXeNtcjR5dHom-ykq-wdPIbN1gaqC3eY?width=1400&amp;auto=format&quot; srcset=&quot;https://lh7-us.googleusercontent.com/_L6ZTLzvOk9sA6x5eug0wZqksI22kRbc5CY7rrJg1cdNOINPG20lX5MdKp7Tb1ZVWpmePWyhZmQ0Oek0doPOp1OXMDwQzTccw-h8Y9Uk42q0qk4bQWOC7KXYXeNtcjR5dHom-ykq-wdPIbN1gaqC3eY?width=700&amp;auto=format&amp;dpr=1 1x, https://lh7-us.googleusercontent.com/_L6ZTLzvOk9sA6x5eug0wZqksI22kRbc5CY7rrJg1cdNOINPG20lX5MdKp7Tb1ZVWpmePWyhZmQ0Oek0doPOp1OXMDwQzTccw-h8Y9Uk42q0qk4bQWOC7KXYXeNtcjR5dHom-ykq-wdPIbN1gaqC3eY?width=700&amp;auto=format&amp;dpr=2 2x, https://lh7-us.googleusercontent.com/_L6ZTLzvOk9sA6x5eug0wZqksI22kRbc5CY7rrJg1cdNOINPG20lX5MdKp7Tb1ZVWpmePWyhZmQ0Oek0doPOp1OXMDwQzTccw-h8Y9Uk42q0qk4bQWOC7KXYXeNtcjR5dHom-ykq-wdPIbN1gaqC3eY?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;We compare the two languages more thoroughly &lt;a target=&quot;_blank&quot; href=&quot;https://www.hiro.so/blog/web3-programming-languages-clarity-vs-solidity&quot;&gt;on the Hiro blog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Fear not if you aren’t keen on learning a new programming language. With the network’s next upgrade coming in 2024, Stacks allows devs to use other popular smart contract languages like Solidity and Rust alongside Clarity in the future.&lt;/p&gt;
&lt;h2 id=&quot;heading-the-future-sbtc&quot;&gt;The Future: sBTC&lt;/h2&gt;
&lt;p&gt;The next billion users need help to onboard onto Bitcoin currently. Fees are too high, blocktimes are too long, and BTC is not programmable. That’s why there have been many attempts at making a “wrapped Bitcoin” asset.&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.hiro.so/blog/sbtc-vs-wbtc-a-comparison-of-tokenized-bitcoin&quot;&gt;There is a long history of these wrapped Bitcoin assets&lt;/a&gt;. sBTC is different, leveraging Stacks’ unique design to create a decentralized, open-membership set of signers that power deposits and withdrawals of Bitcoin to the Stacks blockchain—instead of a closed-membership set of custodians like &lt;a target=&quot;_blank&quot; href=&quot;https://www.bitgo.com/newsroom/press-releases/wbtc-brings-bitcoin-to-ethereum/&quot;&gt;a single company&lt;/a&gt; or a &lt;a target=&quot;_blank&quot; href=&quot;https://support.avax.network/en/articles/5462271-what-is-the-role-of-the-avalanche-bridge-nodes#:~:text=Within%20the%20enclave%2C%20the%20secret,collection%20of%208%20Bridge%20Nodes.&quot;&gt;handful of “bridge nodes”&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://sbtc.tech/&quot;&gt;Read here about sBTC&lt;/a&gt; and how it fulfills its trust-minimized, decentralized promise of a programmatic Bitcoin asset.&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://learn.stacks.org/&quot;&gt;Learn to build on Stacks with Clarity today!&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Stacks represents a unique opportunity for DeFi and Web3 developers. It allows you to leverage the security and decentralization of Bitcoin while enjoying the flexibility and programmability of smart contracts on a Bitcoin layer 2 network.&lt;/p&gt;
&lt;p&gt;With Stacks, you&apos;re not just building on any blockchain; you&apos;re building on Bitcoin, the most secure, largest, and decentralized entity in crypto. So why wait? Start building on Stacks today and be part of the future of DeFi.&lt;/p&gt;
&lt;p&gt;Join the &lt;a target=&quot;_blank&quot; href=&quot;https://discord.gg/5DJaBrf&quot;&gt;Stacks Discord&lt;/a&gt; and sign up for the Stacks DevNTell on December 15th—see you then!&lt;/p&gt;
&lt;h2 id=&quot;heading-devntell&quot;&gt;Dev&apos;n&apos;Tell&lt;/h2&gt;
&lt;p&gt;We&apos;re also live on Dev&apos;n&apos;Tell, December 15th at 16:30 UTC!&lt;/p&gt;
&lt;p&gt;So, &lt;a target=&quot;_blank&quot; href=&quot;https://lu.ma/peh41nlb&quot;&gt;sign up!&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>My Journey from Newbie to Hackathon Champion</title>
    <link href="https://blog.developerdao.com/my-journey-from-newbie-to-hackathon-champion"/>
    <id>https://blog.developerdao.com/my-journey-from-newbie-to-hackathon-champion</id>
    <updated>2023-11-01T12:26:19.754Z</updated>
    <author><name>Vedant Chainani</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1698839296306/90565158-5e72-4774-b4f1-1302b704ee67.jpeg?width=600&amp;format=auto"/>
    <summary>I was sitting in my bedroom, watching Silicon Valley, episode S4E1, when Russ asked Richard what the one thing he would build if he had unlimited time and resources. His answer was &quot;a decentralized internet.&quot; And I was like, what the heck is that? Th...</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1698839296306/90565158-5e72-4774-b4f1-1302b704ee67.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1698839296306/90565158-5e72-4774-b4f1-1302b704ee67.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1698839296306/90565158-5e72-4774-b4f1-1302b704ee67.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1698839296306/90565158-5e72-4774-b4f1-1302b704ee67.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;p&gt;I was sitting in my bedroom, watching Silicon Valley, episode S4E1, when Russ asked Richard what the one thing he would build if he had unlimited time and resources. His answer was &quot;a decentralized internet.&quot; And I was like, what the heck is that? That would be your reaction when you first heard about this fancy term.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1698838379115/96302a73-9052-43d7-846c-782c92148f01.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1698838379115/96302a73-9052-43d7-846c-782c92148f01.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1698838379115/96302a73-9052-43d7-846c-782c92148f01.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1698838379115/96302a73-9052-43d7-846c-782c92148f01.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;I had always been interested in computers and coding, and I had built all sorts of things, from Discord bots to Python scripts to simple WordPress sites and games. But after hearing about the decentralized internet, I knew that&apos;s what I wanted to focus on.&lt;/p&gt;
&lt;p&gt;Gm gm! My name is Vedant, and I&apos;m a developer and technical writer. From the beginning, I&apos;ve been passionate about creating things, just going out there and building stuff. Still, I never thought I could do something as ambitious as making a &quot;decentralized internet&quot;.&lt;/p&gt;
&lt;p&gt;I started reading books and articles about blockchain technology and building small projects from various boot camps. The more I learned and built, the more excited I became. Then, one day, I had an epiphany: &lt;strong&gt;I wanted to be a Web3 developer.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here we are now; I&apos;ve been building in the Web3 space for about a year. However, as I realized it takes a lot of work to keep up with the ever-growing number of new product launches, I wanted to join a developer community where I could learn from experienced developers.&lt;/p&gt;
&lt;p&gt;I heard many good things about Developer DAO through Lens Protocol and Nader Dabit. I was particularly impressed by the DAO&apos;s vast developer community and its Dev-n-Tell sessions.&lt;/p&gt;
&lt;p&gt;I immediately got some CODE tokens and joined the DAO 🚀&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1698838408174/17f4a540-b3c1-4c27-bb18-c70d9a0e230d.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1698838408174/17f4a540-b3c1-4c27-bb18-c70d9a0e230d.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1698838408174/17f4a540-b3c1-4c27-bb18-c70d9a0e230d.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1698838408174/17f4a540-b3c1-4c27-bb18-c70d9a0e230d.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-how-i-started-with-hackathons&quot;&gt;How I Started With Hackathons&lt;/h2&gt;
&lt;p&gt;I&apos;m unsure if it&apos;s my competitive spirit or my love of free pizza, but I&apos;ve always been drawn to hackathons. My first hackathon was Ethos, a completely offline event mostly oriented toward cybersecurity but also had a blockchain track. Me and my friend went there as a team, and to my surprise, we were the only team building in our track.&lt;/p&gt;
&lt;p&gt;That&apos;s when we questioned ourselves: &lt;strong&gt;Are we too early? Is there any point in doing all this?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;But we persevered and built a simple crowdfunding application with NFT rewards. We won that track, but the experience could have been better. I didn&apos;t learn much from the hackathon and started discovering developer clubs. This was the time when I joined Developer DAO, and my hackathon journey began.&lt;/p&gt;
&lt;p&gt;Not all hackathons go as smoothly as you might have thought; they can also be challenging, especially if you&apos;re new to hackathons or coding.&lt;/p&gt;
&lt;p&gt;One of the biggest challenges I faced when I first started participating in hackathons was the documentation. The documentation for new technologies and products can be confusing, especially if you&apos;re unfamiliar with them. Sometimes, the documentation is outdated and doesn&apos;t match the current version of the technology or product. This can lead to a lot of frustration and wasted time.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1698838441497/b0c222c7-81a2-4075-ae06-bfc37e192604.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1698838441497/b0c222c7-81a2-4075-ae06-bfc37e192604.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1698838441497/b0c222c7-81a2-4075-ae06-bfc37e192604.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1698838441497/b0c222c7-81a2-4075-ae06-bfc37e192604.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Another challenge I faced was the need for developer support. Not all hackathons have a large developer community. This can make it difficult to get help when you get stuck. And when you&apos;re on a tight deadline, every minute counts.&lt;/p&gt;
&lt;p&gt;Finally, bugs are always a challenge in software development, but they are especially frustrating during a hackathon. When you&apos;re under pressure to deliver a working product in a short amount of time, every bug feels like a major setback.&lt;/p&gt;
&lt;h2 id=&quot;heading-how-i-got-better-at-hackathons&quot;&gt;How I Got Better at Hackathons&lt;/h2&gt;
&lt;p&gt;I remember the first project I made for a Developer DAO hackathon: a simple newsletter service that sent Web3 onboarding emails using Mailchain. It was a really simple project, but after seeing other people&apos;s projects, I asked myself, &lt;strong&gt;&quot;How do these people build such amazing things?&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I felt like I was in a bad situation. I didn&apos;t know how to learn how to make those types of things. But then I realized that the obvious path was to check out their projects and see how they had implemented things. I could understand their thought process while they were doing those projects.&lt;/p&gt;
&lt;p&gt;My major takeaway from that hackathon was: &lt;strong&gt;Learn from other people&apos;s projects. It gives you a great idea of how to make amazing projects yourself.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For example, if you&apos;ve participated in an ETH Global Hackathon after the results are declared, you can see all their projects on their showcase page with source code and live demo. Just try them out and see what interests you. Play around with them. This will give you more creative thinking ideas for projects, and you will also learn how to do things that you thought were previously not doable.&lt;/p&gt;
&lt;p&gt;Another thing I learned after giving hackathons is that most people don&apos;t continue with their projects after hackathons. This was the same thing for me at first. It&apos;s like the meme of half-eaten apples and my uneaten projects.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1698838465315/44beee1b-02b6-403a-ab83-34373a8a5c48.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1698838465315/44beee1b-02b6-403a-ab83-34373a8a5c48.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1698838465315/44beee1b-02b6-403a-ab83-34373a8a5c48.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1698838465315/44beee1b-02b6-403a-ab83-34373a8a5c48.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But if you believe in your project, continue it!&lt;/strong&gt; This is a great thing to do after a hackathon. Just rewrite things and make your hackathon project more optimized, more organized, and better in general. You&apos;ll learn various new things just by thinking of alternative approaches to implement a single feature.&lt;/p&gt;
&lt;h3 id=&quot;heading-writing-technical-articles-for-hackathons&quot;&gt;Writing Technical Articles for Hackathons&lt;/h3&gt;
&lt;p&gt;If you have a simple hackathon project or you don&apos;t feel like building a full-fledged project, writing a technical article is a great option. Some hackathons offer a separate track for technical articles, such as the Mailchain, MINA, and Phala tracks at Developer DAO hackathons. They are a great way to grab some additional prizes and recognition.&lt;/p&gt;
&lt;p&gt;To write a technical article for a hackathon, simply choose a topic related to your hackathon project and write a concise tutorial on how to build it.&lt;/p&gt;
&lt;p&gt;I&apos;ve written a few technical articles for hackathons, and it&apos;s a great way to learn the product on a much deeper level. When you write a technical article, you have to explain the product to your audience, which forces you to research it and understand how it works. This can be helpful, especially if you&apos;re new to the product or technology.&lt;/p&gt;
&lt;p&gt;Another benefit of writing technical articles is that it&apos;s a great way to share your knowledge. I&apos;ve received a lot of positive feedback from people who read my articles and found them helpful. It&apos;s a great way to connect with other developers and learn from them.&lt;/p&gt;
&lt;p&gt;At one hackathon, I decided to write an article about how to use a new blockchain platform called Mina Protocol. I had never used Mina before, so I had to do much research. I wrote an article on &quot;&lt;a target=&quot;_blank&quot; href=&quot;https://blog.vedantc.dev/build-a-zk-airdrop-app-with-mina-protocol&quot;&gt;How to Build a zk-Airdrop App with Mina Protocol&lt;/a&gt;&quot;, and I won a prize for the best technical article at the hackathon!&lt;/p&gt;
&lt;p&gt;So, If you&apos;re looking for a way to contribute to a hackathon without building a full-fledged project, writing a technical article is a great way to learn new things, share your knowledge with others, and even win prizes!&lt;/p&gt;
&lt;h2 id=&quot;heading-highlights-from-the-hackathons-i-won&quot;&gt;Highlights from the Hackathons I Won&lt;/h2&gt;
&lt;p&gt;I&apos;ve been in Developer DAO for almost six months and have participated in three hackathons. It&apos;s been a great experience, and I&apos;m proud to say I&apos;ve won prizes in all of them. Here&apos;s a small overview of each hackathon and my experience.&lt;/p&gt;
&lt;h3 id=&quot;heading-mailchain-hackathon&quot;&gt;Mailchain Hackathon&lt;/h3&gt;
&lt;p&gt;This was my first Web3 hackathon and my first DAO hackathon. I built a simple Web3 newsletter mail sender where once a person joins a newsletter, they are sent a welcome Web3 mail using Mailchain directly to their Ethereum address.&lt;/p&gt;
&lt;p&gt;While doing the project, I also wrote a &lt;a target=&quot;_blank&quot; href=&quot;https://blog.vedantc.dev/create-a-web3-newsletter-with-mailchain&quot;&gt;technical article&lt;/a&gt; on the implementation and how to use Mailchain. It&apos;s a great way to learn more about the technology and share your knowledge.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1698838494424/e47268a8-8a01-4da2-a797-9bf8fa7dba5d.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1698838494424/e47268a8-8a01-4da2-a797-9bf8fa7dba5d.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1698838494424/e47268a8-8a01-4da2-a797-9bf8fa7dba5d.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1698838494424/e47268a8-8a01-4da2-a797-9bf8fa7dba5d.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;heading-mina-hackathon&quot;&gt;Mina Hackathon&lt;/h3&gt;
&lt;p&gt;My second hackathon was the Mina Hackathon. This time, I was hacking with a friend, &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/peteruche21&quot;&gt;Peter&lt;/a&gt;, a Developer DAO member. This hackathon was more challenging because Mina doesn’t use EVM but utilizes zkSNARKs to maintain a constant-sized blockchain. So, we needed to familiarize ourselves with a new stack.&lt;/p&gt;
&lt;p&gt;In that hackathon, Peter and I tried to build a job credential verifier called &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/Envoy-VC/zkTalents&quot;&gt;zkTalents&lt;/a&gt; with GitHub activity and other off-chain data using oracles. We could implement the logic and SnarkyJS contracts and run them successfully, but we failed to integrate them with our front end because of the complexities with web workers.&lt;/p&gt;
&lt;p&gt;Despite this setback, we still managed to secure third place in the hackathon for the implementation we did. Apart from that, we both won prizes for technical articles.&lt;/p&gt;
&lt;p&gt;The takeaway from this is that it&apos;s okay to fail or not do things that you had planned earlier. It happens as hackathons are limited-timed events. Just try your best and learn from your mistakes.&lt;/p&gt;
&lt;h3 id=&quot;heading-phala-hackathon&quot;&gt;Phala Hackathon&lt;/h3&gt;
&lt;p&gt;The Phala Hackathon was the most recent hackathon I participated in. This hackathon was divided into two parts: the &lt;strong&gt;Early Lens Hackathon&lt;/strong&gt; and the &lt;strong&gt;Main Phala Functions Hackathon&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;For the first part of the hackathon, I made a threshold-based roles website using Lens API and OpenZeppelin roles. It lets you have different roles based on your Lens followers, similar to Discord roles but on-chain. I even won second place for that!&lt;/p&gt;
&lt;p&gt;For the second hackathon, I was feeling a little creative. For a long time, I wanted to build a Web3 game, and this hackathon let us do that. We could use any data worldwide, so I thought, &lt;strong&gt;&quot;Let&apos;s make a game!&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After some brainstorming, I came up with the idea of making a crypto betting game using real-time crypto data. We&apos;re all amazed by the real-time ticking charts for different tokens, so I recreated them using Binance WebSockets and built an entire game. I won the &quot;Phat&quot; sub-prize for the project.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1698838516093/3484068b-8f03-4971-a08c-aa7a9d253955.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1698838516093/3484068b-8f03-4971-a08c-aa7a9d253955.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1698838516093/3484068b-8f03-4971-a08c-aa7a9d253955.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1698838516093/3484068b-8f03-4971-a08c-aa7a9d253955.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;So, sometimes, you should have fun in hackathons. Build what you want and push your limits.&lt;/p&gt;
&lt;h2 id=&quot;heading-my-strategy-for-winning-hackathons&quot;&gt;My Strategy for Winning Hackathons&lt;/h2&gt;
&lt;p&gt;There is no one-size-fits-all strategy for winning hackathons, but the one I&apos;m about to share has served me well so far. I call it &lt;strong&gt;the 3 a.m. Process&lt;/strong&gt; because I mostly come up with my best ideas late at night.&lt;/p&gt;
&lt;h3 id=&quot;heading-1-brainstorming-the-idea&quot;&gt;1. Brainstorming the Idea&lt;/h3&gt;
&lt;p&gt;The first step is to brainstorm ideas. Think about the basic features you want your product to have. Start with some basic ideas that you can build quickly. Then, think about what you use in real life, like messaging, social media, or payments, and how your product could improve them.&lt;/p&gt;
&lt;p&gt;The more you discover other people&apos;s ideas and research the product, the better your creative juices will flow. So, go to other hackathon pages and see what other people have already built to take inspiration for projects. Think about something that you could implement based on them.&lt;/p&gt;
&lt;h3 id=&quot;heading-2-validating-the-ideas-feasibility&quot;&gt;2. Validating the Idea’s Feasibility&lt;/h3&gt;
&lt;p&gt;The most important step in the process is validating your idea. Once you have brainstormed a project idea and are happy with it, you must ensure the implementation is feasible. You have to think about every interaction in your project and think, &quot;Is it possible?&quot;&lt;/p&gt;
&lt;p&gt;When validating your idea, be sure to think outside the box. Don&apos;t be afraid to challenge the status quo.&lt;/p&gt;
&lt;p&gt;I like to use FigJam or some other flowcharting program to make a user flow for my project. This lays out the entire flow of my project and gives me a clear path to follow. For individual actions, I can see if they&apos;re possible or not. I can also use this to decide my tech stack and plan out my features in the app.&lt;/p&gt;
&lt;h3 id=&quot;heading-3-how-to-start-hacking&quot;&gt;3. How to Start Hacking&lt;/h3&gt;
&lt;p&gt;Once you have everything planned out, you need to start working on your idea. Hackathons are typically short-timed events, ranging from 36 hours to a week, so you must use your time efficiently.&lt;/p&gt;
&lt;h4 id=&quot;heading-leverage-starter-kits-sdks-and-frameworks&quot;&gt;Leverage Starter Kits, SDKs, and Frameworks&lt;/h4&gt;
&lt;p&gt;Starter kits are a great way to save time and get started quickly. They provide you with a pre-built foundation that you can use to develop your app. I have a specially set-up starter kit that I use for myself, which has certain technologies and UI libraries that I&apos;m most comfortable with. Everyone should have a similar starter kit for themselves because everyone has different interests in tech stacks and different preferences.&lt;/p&gt;
&lt;p&gt;Another tip is to use well-known SDKs and frameworks in your projects. This way, if you get stuck, the answer is already out there on the internet.&lt;/p&gt;
&lt;h4 id=&quot;heading-take-regular-breaks&quot;&gt;Take Regular Breaks&lt;/h4&gt;
&lt;p&gt;If you feel lost or drained during the hackathon, don&apos;t be afraid to take a break. Go outside, touch some grass, have coffee, and clear your head or talk to a friend. Hackathons can be stressful at times, but they can also teach you a lot about how to build things quickly and test your patience.&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/blog-newsletter-1&quot;&gt;&lt;img src=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=1400&amp;auto=format&quot; srcset=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=1 1x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=2 2x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Subscribe to the Developer DAO Newsletter. Probably Nothing&quot; class=&quot;mx-auto&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-wrapping-up&quot;&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;Wooh! That was a long journey, but we made it. We covered a lot of ground, from what hackathons are to how to win them and everything in between.&lt;/p&gt;
&lt;p&gt;New chains and protocols are popping up every day, and new ERC standards are coming out all the time. It can be tough to keep up with it all. But hackathons can be a great way to learn about new protocols and products and to stay ahead of the curve.&lt;/p&gt;
&lt;p&gt;And let&apos;s be honest, who doesn&apos;t love fat prizes and swag? Hackathons are a great way to challenge yourself, build something cool, win a prize, and make precious memories.&lt;/p&gt;
&lt;p&gt;If you&apos;re new to hackathons, Developer DAO is a great place to start. Hackathons are happening constantly, and the community is incredibly supportive and welcoming.&lt;/p&gt;
&lt;p&gt;Until next time...and remember, &lt;strong&gt;WAGMI forever!&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>How to Deploy Your Own Hyperlane on Polygon zkEVM</title>
    <link href="https://blog.developerdao.com/how-to-deploy-your-own-hyperlane-on-polygon-zkevm"/>
    <id>https://blog.developerdao.com/how-to-deploy-your-own-hyperlane-on-polygon-zkevm</id>
    <updated>2023-10-02T09:40:51.605Z</updated>
    <author><name>megabyte</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1696239581849/14022650-206f-47ef-865b-c13d4bfed913.jpeg?width=600&amp;format=auto"/>
    <summary>gm gm gm!!!  
New chains are popping up by the minute, so getting liquidity there is a burning issue. Hyperlane tries to solve this with permissionless bridges. Hyperlane is a permissionless protocol, which means you can deploy your own Hyperlane on ...</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1696239581849/14022650-206f-47ef-865b-c13d4bfed913.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1696239581849/14022650-206f-47ef-865b-c13d4bfed913.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1696239581849/14022650-206f-47ef-865b-c13d4bfed913.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1696239581849/14022650-206f-47ef-865b-c13d4bfed913.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;p&gt;gm gm gm!!!  &lt;/p&gt;
&lt;p&gt;New chains are popping up by the minute, so getting liquidity there is a burning issue. Hyperlane tries to solve this with permissionless bridges. Hyperlane is a permissionless protocol, which means you can deploy your own Hyperlane on any chain without asking the core team. In this guide, you will learn how to deploy Hyperlane on &lt;a target=&quot;_blank&quot; href=&quot;https://wiki.polygon.technology/docs/zkevm/&quot;&gt;Polygon zkEVM&lt;/a&gt; Testnet, &lt;a target=&quot;_blank&quot; href=&quot;https://wiki.polygon.technology/docs/pos/getting-started/&quot;&gt;Polygon&lt;/a&gt; Mumbai Testnet and Sepolia.&lt;/p&gt;
&lt;p&gt;There are five steps we need to follow so LFG🚀&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/blog-newsletter-1&quot;&gt;&lt;img src=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=1400&amp;auto=format&quot; srcset=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=1 1x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=2 2x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Subscribe to the Developer DAO Newsletter. Probably Nothing&quot; class=&quot;mx-auto&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://classic.yarnpkg.com/lang/en/docs/cli/install/&quot;&gt;Yarn&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://github.com/&quot;&gt;Git and GitHub knowledge&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Understanding of blockchain&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Optional: Solidity experience&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;heading-1-setting-up-the-keys&quot;&gt;1. Setting Up the Keys&lt;/h2&gt;
&lt;p&gt;Deploying Hyperlane includes smart contracts, validators, and relayers, each requiring a key pair.&lt;/p&gt;
&lt;h3 id=&quot;heading-the-deployment-keys&quot;&gt;The Deployment Keys&lt;/h3&gt;
&lt;p&gt;To deploy smart contracts, you must have a key pair with the funds for all the chains you will be deploying.&lt;/p&gt;
&lt;p&gt;To create the keys, follow these steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Open your Terminal and enter the following command&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  cast wallet new
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;  This will generate new keys for you, which will look something like this 👇🏻&lt;/p&gt;
&lt;p&gt;  &lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1695271307360/af69b0d0-75a9-421b-b7c2-53147bc13899.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1695271307360/af69b0d0-75a9-421b-b7c2-53147bc13899.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1695271307360/af69b0d0-75a9-421b-b7c2-53147bc13899.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1695271307360/af69b0d0-75a9-421b-b7c2-53147bc13899.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
  &lt;div data-node-type=&quot;callout&quot;&gt;
  &lt;div data-node-type=&quot;callout-emoji&quot;&gt;⚠&lt;/div&gt;
  &lt;div data-node-type=&quot;callout-text&quot;&gt;THIS IS A TESTING WALLET.&lt;/div&gt;
  &lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Save your public address and private key.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fund your address with the tokens of all the networks.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;For tokens on Polygon zkEVM Testnet and Polygon Mumbai Testnet, use &lt;a target=&quot;_blank&quot; href=&quot;https://faucet.polygon.technology/&quot;&gt;Polygon faucet.&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For tokens on Sepolia, you can use the &lt;a target=&quot;_blank&quot; href=&quot;https://sepoliafaucet.com/&quot;&gt;Alchemy faucet&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;heading-the-validator-keys&quot;&gt;The Validator Keys&lt;/h3&gt;
&lt;p&gt;This tutorial will use the default &lt;a target=&quot;_blank&quot; href=&quot;https://docs.hyperlane.xyz/docs/protocol/sovereign-consensus/multisig-ism&quot;&gt;Hyperlane&apos;s Multisig ISM&lt;/a&gt;. Multisig ISM is a module that takes several signatures from validators before completing the transaction. We use 4 addresses with the threshold 1.&lt;/p&gt;
&lt;p&gt;Copy any 4 of your public addresses for later use.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: Make sure to have a private key secured for the public addresses you use. You can generate key pairs using the above method.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;heading-2-cloning-the-deploy-repository&quot;&gt;2. Cloning the Deploy Repository&lt;/h2&gt;
&lt;p&gt;The Hyperlane team provides you with a repository that you can use to deploy Hyperlane on your preferred chain.&lt;/p&gt;
&lt;p&gt;Follow these steps to set up the Hyperlane deployment repo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Open your terminal at your preferred directory.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;pre&gt;&lt;code&gt;    git &lt;span&gt;clone&lt;/span&gt; https://github.com/hyperlane-xyz/hyperlane-deploy.git
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;pre&gt;&lt;code&gt;    &lt;span&gt;cd&lt;/span&gt; hyperlane-deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;pre&gt;&lt;code&gt;    yarn install
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;heading-3-adding-a-custom-chain-to-hyperlane&quot;&gt;3. Adding a Custom Chain to Hyperlane&lt;/h2&gt;
&lt;p&gt;Hyperlane provided a &lt;a target=&quot;_blank&quot; href=&quot;https://docs.hyperlane.xyz/docs/resources/addresses&quot;&gt;few chains in the SDK&lt;/a&gt;. To add a chain missing from this list, follow these steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Open &lt;code&gt;config/chains.ts&lt;/code&gt;, where you will find the configuration example for adding new chains.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the following configuration for the Polygon zkEVM Testnet:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    polygonzkevmtestnet: {
      name: &lt;span&gt;&apos;polygonzkevmtestnet&apos;&lt;/span&gt;,
      chainId: &lt;span&gt;1442&lt;/span&gt;,
      protocol: ProtocolType.Ethereum,
      nativeToken: {
        name: &lt;span&gt;&apos;ether&apos;&lt;/span&gt;,
        symbol: &lt;span&gt;&apos;ETH&apos;&lt;/span&gt;,
        decimals: &lt;span&gt;18&lt;/span&gt;,
      },
      rpcUrls: [
        {
          http: &lt;span&gt;&apos;https://rpc.public.zkevm-test.net&apos;&lt;/span&gt;,
        },
      ],
      blockExplorers: [
        {
          name: &lt;span&gt;&apos;Polygon Scan&apos;&lt;/span&gt;,
          url: &lt;span&gt;&apos;https://testnet-zkevm.polygonscan.com&apos;&lt;/span&gt;,
          apiUrl: &lt;span&gt;&apos;https://api-zkevm.polygonscan.com/api&apos;&lt;/span&gt;,
        },
      ],
      isTestnet: &lt;span&gt;true&lt;/span&gt;,
    },
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;heading-4-adding-the-validator-keys&quot;&gt;4. Adding the Validator Keys&lt;/h2&gt;
&lt;p&gt;We will use the default &lt;a target=&quot;_blank&quot; href=&quot;https://docs.hyperlane.xyz/docs/protocol/sovereign-consensus/multisig-ism&quot;&gt;Multisig&lt;/a&gt; as our Interchain Security Module.&lt;/p&gt;
&lt;p&gt;Follow these steps to set up the keys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Open &lt;code&gt;config/multisig_ism.ts&lt;/code&gt;. You will find the configuration example for adding new chains and their keys there.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the keys for your validator:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    polygonzkevmtestnet: {
      threshold: &lt;span&gt;1&lt;/span&gt;,
      &lt;span&gt;type&lt;/span&gt;: ModuleType.LEGACY_MULTISIG,
      validators: [
        &lt;span&gt;&apos;0xabcabcabcabcabcabcabcabcabcabcabcabcabca&apos;&lt;/span&gt;,
        &lt;span&gt;&apos;0xabcabcabcabcabcabcabcabcabcabcabcabcabca&apos;&lt;/span&gt;,
        &lt;span&gt;&apos;0xabcabcabcabcabcabcabcabcabcabcabcabcabca&apos;&lt;/span&gt;,
        &lt;span&gt;&apos;0xabcabcabcabcabcabcabcabcabcabcabcabcabca&apos;&lt;/span&gt;,
      ],
    },
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;threshold&lt;/code&gt; is 1, which means only one of the validator&apos;s signatures is required.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Woohoooo!!!&lt;/strong&gt; You are done setting up the Hyperlane deployment on Polygon zkEVM testnet with remotes Mumbai and Sepolia.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;heading-5-deploying-your-hyperlane&quot;&gt;5. Deploying Your Hyperlane&lt;/h2&gt;
&lt;p&gt;To deploy Hyperlane, run the following command on your terminal.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DEBUG=hyperlane* yarn ts-node scripts/deploy-hyperlane.ts --&lt;span&gt;local&lt;/span&gt; polygonzkevmtestnet \
  --remotes mumbai sepolia \
  --key 0xbeda2b3910bae7dbfb4e65e9c0931f001066d4f0df257b77ad55093fa271bde2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above command,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;we are running the &lt;code&gt;deploy-hyperlane.ts&lt;/code&gt; script&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;with &lt;code&gt;polygonzkevmtestnet&lt;/code&gt; as &lt;code&gt;local&lt;/code&gt; chain and&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;mumbai&lt;/code&gt; and &lt;code&gt;sepolia&lt;/code&gt; as remotes. Since &lt;code&gt;mumbai&lt;/code&gt; and &lt;code&gt;sepolia&lt;/code&gt; are already provided by the Hyperlane SDK we don&apos;t need to add the configurations again.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the value after &lt;code&gt;key&lt;/code&gt; param is your private key to the address that contains funds for all the networks.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After running the command, wait for a few minutes till your terminal looks like this 👇🏻&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Congrats!!! You just deployed Hyperlane on Polygon zkEVM Testnet.&lt;/p&gt;
&lt;p&gt;To test this deployment, you must run validators and relayers for all the chains you deployed (local + remote). To learn how to set up validators and relayers, check out these guides on the Hyperlane blog 👇🏻&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;a href=&quot;https://blog.hyperlaneindia.xyz/hyperlane-relayers-setup-guide&quot;&gt;https://blog.hyperlaneindia.xyz/hyperlane-relayers-setup-guide&lt;/a&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;a href=&quot;https://blog.hyperlaneindia.xyz/hyperlane-validators-setup-guide&quot;&gt;https://blog.hyperlaneindia.xyz/hyperlane-validators-setup-guide&lt;/a&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Thanks for reading this article; I hope you learned something today.&lt;/p&gt;
&lt;div data-node-type=&quot;callout&quot;&gt;
&lt;div data-node-type=&quot;callout-emoji&quot;&gt;💡&lt;/div&gt;
&lt;div data-node-type=&quot;callout-text&quot;&gt;If you wanna explore more check out the &lt;a target=&quot;_blank&quot; href=&quot;https://docs.hyperlane.xyz&quot;&gt;Hyperlane Docs&lt;/a&gt;, and if you have any queries get them resolved in &lt;a target=&quot;_blank&quot; href=&quot;http://t.me/c/1264208834/1&quot;&gt;Hyperlane India Telegram Channel.&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Let me know if you have any doubts on &lt;a target=&quot;_blank&quot; href=&quot;https://twitter.com/megabyte0x&quot;&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a target=&quot;_blank&quot; href=&quot;https://lenster.xyz/u/megabyte0x&quot;&gt;&lt;em&gt;Lenster&lt;/em&gt;&lt;/a&gt; &lt;em&gt;or&lt;/em&gt; &lt;a target=&quot;_blank&quot; href=&quot;https://linkedin.com/in/megabyte0x&quot;&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Happy Learning 🙌🏻&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Keep Building 🧱🚀&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Hyperlane from A to Z</title>
    <link href="https://blog.developerdao.com/hyperlane-from-a-to-z"/>
    <id>https://blog.developerdao.com/hyperlane-from-a-to-z</id>
    <updated>2023-09-15T10:58:18.882Z</updated>
    <author><name>megabyte</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1694607113803/ccebbcf4-ef39-485f-a0c6-f4c2fb9400c9.jpeg?width=600&amp;format=auto"/>
    <summary>Permissionless Interoperability Layer for web3</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1694607113803/ccebbcf4-ef39-485f-a0c6-f4c2fb9400c9.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1694607113803/ccebbcf4-ef39-485f-a0c6-f4c2fb9400c9.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1694607113803/ccebbcf4-ef39-485f-a0c6-f4c2fb9400c9.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1694607113803/ccebbcf4-ef39-485f-a0c6-f4c2fb9400c9.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;p&gt;gm gm gm!!!&lt;/p&gt;
&lt;p&gt;Even in a vast blockchain network with countless nodes and layers, users need help utilizing the decentralized network&apos;s complete potential because DApps use different chains. Some use Ethereum, some Polygon, some Gnosis, and so on!&lt;/p&gt;
&lt;p&gt;In this environment, developers should build chain-agnostic applications—no dependency on one chain and no restriction for any user.&lt;/p&gt;
&lt;p&gt;Now, solving this interoperability issue between different chains requires devs to build robust and, more importantly, secure designs, which is a highly technical and resourceful process, and to save devs from going through such pain &lt;a target=&quot;_blank&quot; href=&quot;https://www.hyperlane.xyz&quot;&gt;Hyperlane&lt;/a&gt; comes into the picture.&lt;/p&gt;
&lt;p&gt;This article will explain almost all about Hyperlane and how it works, so grab a coffee ☕️ and LFG 🚀&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/blog-newsletter-1&quot;&gt;&lt;img src=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=1400&amp;auto=format&quot; srcset=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=1 1x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=2 2x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;D_D Newsletter CTA&quot; class=&quot;mx-auto&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-what-is-hyperlane&quot;&gt;What is Hyperlane?&lt;/h2&gt;
&lt;p&gt;Hyperlane is a permissionless interoperability protocol that helps devs send arbitrary data across chains⛓&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;a href=&quot;https://twitter.com/megabyte0x/status/1686628441888804864&quot;&gt;https://twitter.com/megabyte0x/status/1686628441888804864&lt;/a&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Permissionless means no one requires any permission from the Hyperlane team to use Hyperlane SDK, contracts, or even while deploying on new chains as I did👇🏻&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;a href=&quot;https://twitter.com/megabyte0x/status/1651938319570456577&quot;&gt;https://twitter.com/megabyte0x/status/1651938319570456577&lt;/a&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Interoperability means sending between different chains. Imagine initiating a transaction on Ethereum to close a position on Polygon.&lt;/p&gt;
&lt;p&gt;Hyperlane is a complete modular protocol that helps devs to customize it according to their application requirements.&lt;/p&gt;
&lt;p&gt;The following are the key components of Hyperlane:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Mailbox&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Interchain Security Module (ISM)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Interchain Gas Payment (IGP)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Agents&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This article will explain each of them. You can either learn about them in depth one by one or go directly to the example.&lt;/p&gt;
&lt;h2 id=&quot;heading-what-is-a-hyperlane-mailbox&quot;&gt;What is a Hyperlane Mailbox?&lt;/h2&gt;
&lt;p&gt;Mailbox is an on-chain API to send and receive interchain messages.&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;a href=&quot;https://twitter.com/megabyte0x/status/1686979539291762688&quot;&gt;https://twitter.com/megabyte0x/status/1686979539291762688&lt;/a&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Mailbox is the middleman that helps devs connect different chains and leverage them to build something new.&lt;/p&gt;
&lt;p&gt;Hyperlane deployed a Mailbox contract on each of its &lt;a target=&quot;_blank&quot; href=&quot;https://docs.hyperlane.xyz/docs/resources/addresses&quot;&gt;supported chains&lt;/a&gt;. The contract interface defines two functions that must be present in these cross-chain contracts, &lt;code&gt;dispatch&lt;/code&gt; and &lt;code&gt;process&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;heading-how-does-the-dispatch-function-work&quot;&gt;How Does the &lt;code&gt;dispatch&lt;/code&gt; Function Work?&lt;/h3&gt;
&lt;p&gt;This function lets you send data from the origin to the destination chain.&lt;/p&gt;
&lt;p&gt;It accepts several params:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1693564023609/bc6ce931-e81f-49df-80a3-e962ee166066.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1693564023609/bc6ce931-e81f-49df-80a3-e962ee166066.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1693564023609/bc6ce931-e81f-49df-80a3-e962ee166066.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1693564023609/bc6ce931-e81f-49df-80a3-e962ee166066.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;_destinationDomain (uint32)&lt;/code&gt;: The domain of the destination chain or the deployer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;_recipient Address (bytes32)&lt;/code&gt;: The recipient&apos;s address.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;_messageBody (bytes)&lt;/code&gt;: The content of the message as raw bytes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The function works by following these steps:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1693564190795/f026d50f-6fe4-43d5-bdf6-070f91c4f8ac.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1693564190795/f026d50f-6fe4-43d5-bdf6-070f91c4f8ac.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1693564190795/f026d50f-6fe4-43d5-bdf6-070f91c4f8ac.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1693564190795/f026d50f-6fe4-43d5-bdf6-070f91c4f8ac.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;It checks whether the message length exceeds the 2KiB length.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It formats the &lt;code&gt;_messageBody&lt;/code&gt; using &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/hyperlane-xyz/hyperlane-monorepo/blob/main/solidity/contracts/libs/Message.sol&quot;&gt;&lt;code&gt;Message.sol&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://github.com/hyperlane-xyz/hyperlane-monorepo/blob/main/solidity/contracts/libs/Message.sol&quot;&gt;Message.sol&lt;/a&gt; provides an &lt;code&gt;id&lt;/code&gt; function that returns a KECCAK256 hash of &lt;code&gt;_message&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This hash becomes the &lt;code&gt;_id&lt;/code&gt; and is saved into an &lt;a target=&quot;_blank&quot; href=&quot;https://medium.com/@josephdelong/ethereum-2-0-deposit-merkle-tree-13ec8404ca4f&quot;&gt;incremental Merkle tree&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The function uses the Merkle tree to verify fraud proofs in Hyperlane&apos;s staking and slashing protocol.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;heading-how-does-the-process-function-work&quot;&gt;How Does the &lt;code&gt;process&lt;/code&gt; Function Work?&lt;/h3&gt;
&lt;p&gt;The function is called on the destination chain to receive the message. It accepts the following two params:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1693564279003/2b1971f7-4392-4c37-8af9-5b7aa9374df9.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1693564279003/2b1971f7-4392-4c37-8af9-5b7aa9374df9.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1693564279003/2b1971f7-4392-4c37-8af9-5b7aa9374df9.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1693564279003/2b1971f7-4392-4c37-8af9-5b7aa9374df9.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;It works by following these steps:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1693593889185/09afb654-cf53-4afd-9fb4-8c843424fa5e.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1693593889185/09afb654-cf53-4afd-9fb4-8c843424fa5e.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1693593889185/09afb654-cf53-4afd-9fb4-8c843424fa5e.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1693593889185/09afb654-cf53-4afd-9fb4-8c843424fa5e.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;_message&lt;/code&gt; argument is the one the &lt;code&gt;dispatch&lt;/code&gt; function formatted with &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/hyperlane-xyz/hyperlane-monorepo/blob/main/solidity/contracts/libs/Message.sol&quot;&gt;&lt;code&gt;Message.sol&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;_metadata&lt;/code&gt; argument is metadata provided by the &lt;a target=&quot;_blank&quot; href=&quot;https://docs.hyperlane.xyz/docs/protocol/sovereign-consensus&quot;&gt;ISM&lt;/a&gt; relayer to verify &lt;code&gt;_message&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The function checks whether the &lt;code&gt;_id&lt;/code&gt; is in the array of delivered messages. If it is, it reverts with &lt;code&gt;delivered&lt;/code&gt;; if not, it adds it to that array.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The function gets the ISM address for the &lt;code&gt;recepientAddress&lt;/code&gt;. If the recipient has defined a specific ISM, it uses that; otherwise, it uses the default ISM for the chain.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It uses the ISM address to verify messages received by the Mailbox.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After verification, it emits the message received event using the &lt;code&gt;IMessageRecepient.sol&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://docs.hyperlane.xyz/docs/protocol/messaging&quot;&gt;You can learn more about Mailbox in the Hyperlane docs.&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;heading-what-are-hyperlane-interchain-security-modules&quot;&gt;What are Hyperlane Interchain Security Modules?&lt;/h2&gt;
&lt;p&gt;An ISM verifies that the messages delivered on the destination chain come from the origin chain.&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;a href=&quot;https://twitter.com/megabyte0x/status/1687471625724383232&quot;&gt;https://twitter.com/megabyte0x/status/1687471625724383232&lt;/a&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Mailbox uses the ISM to verify the message Mailbox received from a relayer before executing transactions.&lt;/p&gt;
&lt;p&gt;Devs can define their own ISM for their application or can use default ISMs provided by the team, using the &lt;code&gt;ISpecifiesInterchainSecurityModule.sol&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/F2sYYrcbsAA_Zii?format=png&amp;amp;name=900x900&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://pbs.twimg.com/media/F2sYYrcbsAA_Zii?format=png&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://pbs.twimg.com/media/F2sYYrcbsAA_Zii?format=png&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://pbs.twimg.com/media/F2sYYrcbsAA_Zii?format=png&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Image&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;ISM can be configured per the application requirements, with all the additional parameters required by the application.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Devs can use more than one ISM in their application to increase security and work according to the chain&apos;s consensus.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Devs can use IInterfaceSecurityModule.sol and build a custom ISM according to their needs.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each ISM comes with two main functions:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/F2sYjIaboAENMUY?format=jpg&amp;amp;name=900x900&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://pbs.twimg.com/media/F2sYjIaboAENMUY?format=jpg&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://pbs.twimg.com/media/F2sYjIaboAENMUY?format=jpg&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://pbs.twimg.com/media/F2sYjIaboAENMUY?format=jpg&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Image&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/blog-newsletter-1&quot;&gt;&lt;img src=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=1400&amp;auto=format&quot; srcset=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=1 1x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=2 2x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;D_D Newsletter CTA&quot; class=&quot;mx-auto&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;heading-how-does-the-verify-function-work&quot;&gt;How Does the &lt;code&gt;verify&lt;/code&gt; Function Work?&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/F2sYnasaIAAJ47k?format=jpg&amp;amp;name=900x900&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://pbs.twimg.com/media/F2sYnasaIAAJ47k?format=jpg&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://pbs.twimg.com/media/F2sYnasaIAAJ47k?format=jpg&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://pbs.twimg.com/media/F2sYnasaIAAJ47k?format=jpg&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Image&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;This function takes two params:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;message(bytes)&lt;/code&gt;: Message that needs to be verified.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;metadata(bytes)&lt;/code&gt;: Off-chain bytes provided by the relayers.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;heading-how-does-the-moduletype-function-work&quot;&gt;How Does the &lt;code&gt;moduleType&lt;/code&gt; Function Work?&lt;/h3&gt;
&lt;p&gt;This function signals relayers about the module type to include in the metadata.&lt;/p&gt;
&lt;h3 id=&quot;heading-how-to-implement-an-interchain-security-module&quot;&gt;How to Implement an Interchain Security Module?&lt;/h3&gt;
&lt;p&gt;You can use the &lt;code&gt;ISpecifiesInterchainSecurityModule.sol&lt;/code&gt; module to implement a custom ISM for your application.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/F2sYwiQaoAAeO6b?format=jpg&amp;amp;name=900x900&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://pbs.twimg.com/media/F2sYwiQaoAAeO6b?format=jpg&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://pbs.twimg.com/media/F2sYwiQaoAAeO6b?format=jpg&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://pbs.twimg.com/media/F2sYwiQaoAAeO6b?format=jpg&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Image&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;The team provides different prebuilt ISMs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;MultisigISM&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;RoutingISM&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AggregationISM&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;OptimisticISM&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;WormholeISM&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;HookISM&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can find more details about ISMs &lt;a target=&quot;_blank&quot; href=&quot;https://docs.hyperlane.xyz/docs/protocol/sovereign-consensus&quot;&gt;in the Hyperlane docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;heading-what-is-the-hyperlane-interchain-gas-paymaster&quot;&gt;What is the Hyperlane Interchain Gas Paymaster?&lt;/h2&gt;
&lt;p&gt;The IGP is an on-chain API to pay relayers that deliver the message on the destination chain.&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;a href=&quot;https://twitter.com/megabyte0x/status/1687818750635261954&quot;&gt;https://twitter.com/megabyte0x/status/1687818750635261954&lt;/a&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;An interchain message requires two transactions: one on the origin chain to send the message and one on the destination chain to receive it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/F2xWNzRboAEXST_?format=png&amp;amp;name=900x900&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://pbs.twimg.com/media/F2xWNzRboAEXST_?format=png&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://pbs.twimg.com/media/F2xWNzRboAEXST_?format=png&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://pbs.twimg.com/media/F2xWNzRboAEXST_?format=png&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Image&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;When users send the message via a Mailbox contract on the origin chain to a relayer, they must include the gas fee to cover the gas fee on the destination chain. The IGP calculates the gas fee and sends the amount to the relayer.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/F2xWONJbYAAw1XU?format=png&amp;amp;name=small&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://pbs.twimg.com/media/F2xWONJbYAAw1XU?format=png&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://pbs.twimg.com/media/F2xWONJbYAAw1XU?format=png&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://pbs.twimg.com/media/F2xWONJbYAAw1XU?format=png&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Image&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;IGP provides two functions:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/F2xWOp5aIAAVYqF?format=png&amp;amp;name=small&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://pbs.twimg.com/media/F2xWOp5aIAAVYqF?format=png&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://pbs.twimg.com/media/F2xWOp5aIAAVYqF?format=png&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://pbs.twimg.com/media/F2xWOp5aIAAVYqF?format=png&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Image&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;payGasFor()&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;quoteGasPayment()&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;heading-how-does-the-payforgas-function-work&quot;&gt;How does the &lt;code&gt;payForGas&lt;/code&gt; Function Work?&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/F2xWPEsbkAATs-U?format=jpg&amp;amp;name=small&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://pbs.twimg.com/media/F2xWPEsbkAATs-U?format=jpg&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://pbs.twimg.com/media/F2xWPEsbkAATs-U?format=jpg&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://pbs.twimg.com/media/F2xWPEsbkAATs-U?format=jpg&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Image&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;This function takes four parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;_messageId&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;destinationDomain&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;gasAmount&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;refundAddress&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When the user sends the above parameters, the following steps happen:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/F2xWPhAbYAAoOdW?format=jpg&amp;amp;name=small&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://pbs.twimg.com/media/F2xWPhAbYAAoOdW?format=jpg&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://pbs.twimg.com/media/F2xWPhAbYAAoOdW?format=jpg&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://pbs.twimg.com/media/F2xWPhAbYAAoOdW?format=jpg&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Image&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The function gets the gas fee required on the destination chain by calling &lt;code&gt;quoteGasPayment()&lt;/code&gt;. It reverts if the required amount exceeds the &lt;code&gt;msg.value&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It calculates the overpaid amount; if it exceeds 0, it sends the amount to the &lt;code&gt;refundAddress&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It emits a GasPayment event.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;heading-how-does-the-quotegaspayment-function-work&quot;&gt;How does the &lt;code&gt;quoteGasPayment&lt;/code&gt; Function Work?&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/F2xWQUJawAAO1bE?format=png&amp;amp;name=small&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://pbs.twimg.com/media/F2xWQUJawAAO1bE?format=png&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://pbs.twimg.com/media/F2xWQUJawAAO1bE?format=png&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://pbs.twimg.com/media/F2xWQUJawAAO1bE?format=png&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Image&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;This function takes the following parameters: &lt;code&gt;_destinationDomain&lt;/code&gt; and &lt;code&gt;_gasAmount&lt;/code&gt;. It works like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/F2xWQusbYAEBM5_?format=jpg&amp;amp;name=small&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://pbs.twimg.com/media/F2xWQusbYAEBM5_?format=jpg&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://pbs.twimg.com/media/F2xWQusbYAEBM5_?format=jpg&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://pbs.twimg.com/media/F2xWQusbYAEBM5_?format=jpg&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Image&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The function gets the token exchange rate and the gas price for the destination chain.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It calculates the gas fee on the destination chain.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It calculates the number of native tokens required on the origin chain and returns it.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;heading-the-igp-workflow&quot;&gt;The IGP Workflow&lt;/h3&gt;
&lt;p&gt;Let&apos;s look at a complete workflow of IGP on the origin chain to deliver the message on the destination chain:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1693593387030/9e0f9d6d-a728-46ec-9c5d-8efe81f9253f.png?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1693593387030/9e0f9d6d-a728-46ec-9c5d-8efe81f9253f.png?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1693593387030/9e0f9d6d-a728-46ec-9c5d-8efe81f9253f.png?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1693593387030/9e0f9d6d-a728-46ec-9c5d-8efe81f9253f.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://docs.hyperlane.xyz/docs/protocol/interchain-gas-payments&quot;&gt;The Hyperlane docs&lt;/a&gt; have additional details if you want to learn more about IGP.&lt;/p&gt;
&lt;h2 id=&quot;heading-what-are-hyperlane-agents&quot;&gt;What are Hyperlane Agents?&lt;/h2&gt;
&lt;p&gt;Agents are the off-chain actors that power Hyperlane.&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;a href=&quot;https://twitter.com/megabyte0x/status/1688514083287678977&quot;&gt;https://twitter.com/megabyte0x/status/1688514083287678977&lt;/a&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;There are three agents in the Hyperlane protocol: Validators, relayers, and watchtowers.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/F27OnUSbEAAjnPk?format=jpg&amp;amp;name=900x900&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://pbs.twimg.com/media/F27OnUSbEAAjnPk?format=jpg&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://pbs.twimg.com/media/F27OnUSbEAAjnPk?format=jpg&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://pbs.twimg.com/media/F27OnUSbEAAjnPk?format=jpg&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Image&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Since Hyperlane is a permissionless interoperability protocol, you can take the role of any agent and contribute to the network&apos;s security.&lt;/p&gt;
&lt;h3 id=&quot;heading-what-are-hyperlane-validators&quot;&gt;What are Hyperlane Validators?&lt;/h3&gt;
&lt;p&gt;They sign the current Merkle root, which they receive from the &lt;code&gt;Mailbox.latestCheckpoint()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/F27OnzdbMAEA2Os?format=jpg&amp;amp;name=900x900&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://pbs.twimg.com/media/F27OnzdbMAEA2Os?format=jpg&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://pbs.twimg.com/media/F27OnzdbMAEA2Os?format=jpg&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://pbs.twimg.com/media/F27OnzdbMAEA2Os?format=jpg&amp;amp;name=900x900&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Image&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Validators are supposed to sign the checkpoint after it reaches the finality to maintain the network&apos;s security.&lt;/p&gt;
&lt;p&gt;After signing the checkpoint, validators post signatures on the available storage so that the Relayers can aggregate them.&lt;/p&gt;
&lt;h3 id=&quot;heading-what-are-hyperlane-relayers&quot;&gt;What are Hyperlane Relayers?&lt;/h3&gt;
&lt;p&gt;Relayers are responsible for delivering messages to the recipient.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/F27OocLaAAAXIDS?format=png&amp;amp;name=small&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://pbs.twimg.com/media/F27OocLaAAAXIDS?format=png&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://pbs.twimg.com/media/F27OocLaAAAXIDS?format=png&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://pbs.twimg.com/media/F27OocLaAAAXIDS?format=png&amp;amp;name=small&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Image&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;It works as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Observe Mailbox for new messages.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use Mailbox to get the ISM implemented by the recipient.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Aggregate the metadata for the ISM.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deliver the message.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Relayers can also have configurations for the messages they want to deliver:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A sender/recipient allowlist.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A sender/recipient denylist&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Getting paid on-chain after delivering.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The relayers get rewarded when they process the message with the gas fee.&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/blog-newsletter-1&quot;&gt;&lt;img src=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=1400&amp;auto=format&quot; srcset=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=1 1x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=2 2x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;D_D Newsletter CTA&quot; class=&quot;mx-auto&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;heading-what-are-hyperlane-watchtowers&quot;&gt;What are Hyperlane Watchtowers?&lt;/h3&gt;
&lt;p&gt;They are the police of the Hyperlane protocol. They look for fraudulent validators in the network and slash their stake. Watchtowers get rewarded when they submit the correct report of fraud.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can learn more about agents &lt;a target=&quot;_blank&quot; href=&quot;https://docs.hyperlane.xyz/docs/protocol/agents&quot;&gt;in the Hyperlane docs&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;heading-example-how-to-send-a-message-from-polygon-zkevm-to-ethereum&quot;&gt;Example: How to Send a Message from Polygon zkEVM to Ethereum?&lt;/h2&gt;
&lt;p&gt;Let&apos;s use an example to understand how Hyperlane&apos;s components work together.&lt;/p&gt;
&lt;p&gt;Jim wants to send a message data to Dwight from Polygon zkEVM to Ethereum with Hyperlane.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/F3AXEMZb0AEz0Df?format=jpg&amp;amp;name=medium&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://pbs.twimg.com/media/F3AXEMZb0AEz0Df?format=jpg&amp;amp;name=medium&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://pbs.twimg.com/media/F3AXEMZb0AEz0Df?format=jpg&amp;amp;name=medium&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://pbs.twimg.com/media/F3AXEMZb0AEz0Df?format=jpg&amp;amp;name=medium&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Image&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;a href=&quot;https://twitter.com/megabyte0x/status/1688875226745253888?s=20&quot;&gt;https://twitter.com/megabyte0x/status/1688875226745253888?s=20&lt;/a&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;The following steps are required to transfer the message:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://pbs.twimg.com/media/F3AXE5EbkAAfJJA?format=jpg&amp;amp;name=medium&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://pbs.twimg.com/media/F3AXE5EbkAAfJJA?format=jpg&amp;amp;name=medium&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://pbs.twimg.com/media/F3AXE5EbkAAfJJA?format=jpg&amp;amp;name=medium&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://pbs.twimg.com/media/F3AXE5EbkAAfJJA?format=jpg&amp;amp;name=medium&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;Image&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Jim sends the message data, recipient address, and destination chain to the Maibox contract on the Polygon zkEVM chain.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Mailbox emits an event that gets indexed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Validators sign the latest checkpoint.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The signature gets stored in the database.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Jim pays the gas fee using IGP during the process.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When the relayer receives the gas fee, it relays the message and metadata on the Ethereum chain.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;messageBody&lt;/code&gt; is sent to the ISM for verification.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The message gets delivered to Dwight on the Ethereum chain.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/blog-newsletter-1&quot;&gt;&lt;img src=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=1400&amp;auto=format&quot; srcset=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=1 1x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=2 2x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;D_D Newsletter CTA&quot; class=&quot;mx-auto&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;Whoo!!🤩 This was quite a lot of workflow and solidity contracts understanding.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div data-node-type=&quot;callout&quot;&gt;
&lt;div data-node-type=&quot;callout-emoji&quot;&gt;💡&lt;/div&gt;
&lt;div data-node-type=&quot;callout-text&quot;&gt;If you wanna explore more check out the &lt;a target=&quot;_blank&quot; href=&quot;https://docs.hyperlane.xyz&quot;&gt;Hyperlane Docs&lt;/a&gt;, and if you have any queries get them resolved in &lt;a target=&quot;_blank&quot; href=&quot;http://t.me/c/1264208834/1&quot;&gt;Hyperlane India Telegram Channel.&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;You can connect with me on &lt;a target=&quot;_blank&quot; href=&quot;https://twitter.com/megabyte0x&quot;&gt;Twitter&lt;/a&gt;, &lt;a target=&quot;_blank&quot; href=&quot;https://lenster.xyz/u/megabyte0x&quot;&gt;Lenster&lt;/a&gt; or &lt;a target=&quot;_blank&quot; href=&quot;https://linkedin.com/in/megabyte0x&quot;&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy Learning 🙌🏻&lt;/p&gt;
&lt;p&gt;Keep Building 🧱🚀&lt;/p&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>Build Your Own NFT Collection with QuickNode and Optimism</title>
    <link href="https://blog.developerdao.com/build-your-own-nft-collection-with-quicknode-and-optimism"/>
    <id>https://blog.developerdao.com/build-your-own-nft-collection-with-quicknode-and-optimism</id>
    <updated>2023-09-04T12:34:58.700Z</updated>
    <author><name>Aayush Gupta</name></author>
    <link rel="enclosure" href="https://cdn.hashnode.com/res/hashnode/image/upload/v1693830816842/6ba52adb-550f-4ac8-866f-a1cda6c26afd.jpeg?width=600&amp;format=auto"/>
    <summary>Building and deploying your own NFT collection can be time and money-consuming, especially with the gas prices on Ethereum. With the rise of layer-2 solutions and cheap RPCs, this doesn&apos;t have to be the case! This tutorial will explain building an NF...</summary>
    <content type="html">&lt;div&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1693830816842/6ba52adb-550f-4ac8-866f-a1cda6c26afd.jpeg?width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1693830816842/6ba52adb-550f-4ac8-866f-a1cda6c26afd.jpeg?width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1693830816842/6ba52adb-550f-4ac8-866f-a1cda6c26afd.jpeg?width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1693830816842/6ba52adb-550f-4ac8-866f-a1cda6c26afd.jpeg?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;p&gt;Building and deploying your own NFT collection can be time and money-consuming, especially with the gas prices on Ethereum. With the rise of layer-2 solutions and cheap RPCs, this doesn&apos;t have to be the case! This tutorial will explain building an NFT Collection using the &lt;a target=&quot;_blank&quot; href=&quot;https://ethereum.org/en/developers/docs/standards/tokens/erc-721/&quot;&gt;ERC-721&lt;/a&gt; token standard. You will store all NFT assets and metadata on IPFS with &lt;a target=&quot;_blank&quot; href=&quot;https://dashboard.quicknode.com/storage&quot;&gt;QuickNode&lt;/a&gt; and deploy the smart contract on &lt;a target=&quot;_blank&quot; href=&quot;https://www.optimism.io/&quot;&gt;Optimism&lt;/a&gt; Goerli Testnet.&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/blog-newsletter-1&quot;&gt;&lt;img src=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=1400&amp;auto=format&quot; srcset=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=1 1x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=2 2x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;D_D Newsletter CTA&quot; class=&quot;mx-auto&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-requirements&quot;&gt;Requirements&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A basic understanding of &lt;a target=&quot;_blank&quot; href=&quot;https://www.quicknode.com/guides/ethereum-development/smart-contracts/how-to-create-a-hello-world-smart-contract-with-solidity&quot;&gt;Solidity development&lt;/a&gt; will be helpful but is not required.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A basic understanding of the &lt;a target=&quot;_blank&quot; href=&quot;https://ethereum.org/en/developers/docs/standards/tokens/erc-721/&quot;&gt;ERC-721&lt;/a&gt; token standard will be helpful but is not required.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A basic understanding of the &lt;a target=&quot;_blank&quot; href=&quot;https://remix.ethereum.org/&quot;&gt;Remix&lt;/a&gt; IDE will be helpful but is not required.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Image assets and metadata of the NFT collections.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MetaMask or any other wallet and a small amount of Goerli test ETH.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A free &lt;a target=&quot;_blank&quot; href=&quot;https://www.quicknode.com/&quot;&gt;QuickNode&lt;/a&gt; account.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;heading-what-is-quicknode-ipfs&quot;&gt;What is QuickNode IPFS?&lt;/h2&gt;
&lt;p&gt;The QuickNode IPFS service lets you store data decentralized using IPFS. Your files are automatically spread and replicated across global data centers, ensuring redundancy and distribution throughout the network. &lt;/p&gt;
&lt;h2 id=&quot;heading-what-is-optimism&quot;&gt;What is Optimism?&lt;/h2&gt;
&lt;p&gt;Optimism is a layer-2 scaling solution that Ethereum developers choose for its speed and low transaction costs while maintaining full compatibility with the EVM.&lt;/p&gt;
&lt;h2 id=&quot;heading-what-are-the-steps&quot;&gt;What are the Steps?&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Store NFT assets and metadata on QuickNode IPFS.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create and deploy an ERC-721 contract on the Optimism Goerli Testnet.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Interact with the Smart Contract to mint NFTs&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;View your NFTs on OpenSea.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;heading-storing-files-on-ipfs&quot;&gt;Storing Files on IPFS&lt;/h2&gt;
&lt;p&gt;First, you upload your images and metadata via &lt;a target=&quot;_blank&quot; href=&quot;https://dashboard.quicknode.com/storage&quot;&gt;QuickNode&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.quicknode.com/&quot;&gt;Open the QuickNode website&lt;/a&gt; and navigate to the &quot;Storage&quot; section. Click the &lt;strong&gt;Add a file&lt;/strong&gt; button and select the file from your local machine.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692864842685/265225f1-fdff-4a0f-bf08-10df2ca1353c.png?auto=compress,format&amp;amp;format=webp&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692864842685/265225f1-fdff-4a0f-bf08-10df2ca1353c.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692864842685/265225f1-fdff-4a0f-bf08-10df2ca1353c.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692864842685/265225f1-fdff-4a0f-bf08-10df2ca1353c.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;After you upload the file, it will appear like this, showing the file name, CID, status, and other information about the file.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692865232027/369a9abb-568a-4e1d-ac3a-2c2e61eef173.png?auto=compress,format&amp;amp;format=webp&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692865232027/369a9abb-568a-4e1d-ac3a-2c2e61eef173.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692865232027/369a9abb-568a-4e1d-ac3a-2c2e61eef173.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692865232027/369a9abb-568a-4e1d-ac3a-2c2e61eef173.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Upload images for each of the NFTs. &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/AAYUSH-GUPTA-coder/NFT-COLLECTION-QUICKNODE-TUTORIAL/tree/main/images&quot;&gt;You&apos;ll find all the images on GitHub&lt;/a&gt;. The outcome will look similar to this.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692867518088/2ac00c65-2f3e-49b4-a368-baf62c1a4226.png?auto=compress,format&amp;amp;format=webp&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692867518088/2ac00c65-2f3e-49b4-a368-baf62c1a4226.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692867518088/2ac00c65-2f3e-49b4-a368-baf62c1a4226.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692867518088/2ac00c65-2f3e-49b4-a368-baf62c1a4226.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Create three JSON metadata files to store information about our NFT collections.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;0.json&lt;/code&gt;: Agra collection&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;1.json&lt;/code&gt;: Delhi collection&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;2.json&lt;/code&gt;: Goa collection&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;0.json&lt;/code&gt; file should look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &lt;span&gt;&quot;name&quot;&lt;/span&gt;: &lt;span&gt;&quot;Agra&quot;&lt;/span&gt;,
  &lt;span&gt;&quot;description&quot;&lt;/span&gt;: &lt;span&gt;&quot;Agra is a historic city in northern India, renowned for the iconic Taj Mahal, a marble mausoleum. It&apos;s a UNESCO World Heritage site and symbolizes love and architectural splendor. Agra also boasts Agra Fort and Fatehpur Sikri, both reflecting the city&apos;s Mughal heritage and attracting countless tourists for their cultural significance.&quot;&lt;/span&gt;,
  &lt;span&gt;&quot;image&quot;&lt;/span&gt;: &lt;span&gt;&quot;ipfs://Qmdr1zPumimEFKRkszo3nfFhGQ3UwofQXMbfDy1wd1gdLQ&quot;&lt;/span&gt;,
  &lt;span&gt;&quot;properties&quot;&lt;/span&gt;: {
    &lt;span&gt;&quot;rarity&quot;&lt;/span&gt;: &lt;span&gt;&quot;a bit rare&quot;&lt;/span&gt;,
    &lt;span&gt;&quot;fanciness&quot;&lt;/span&gt;: &lt;span&gt;8&lt;/span&gt;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;name&lt;/strong&gt;: Contains the name of the NFT.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;description&lt;/strong&gt;: Contains the description of the NFT.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;image&lt;/strong&gt;: Includes the link to the previously obtained image (IPFS URL).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;properties&lt;/strong&gt;: Encompasses the various attributes of the NFT.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Create the remaining JSON files, &lt;code&gt;1.json&lt;/code&gt; and &lt;code&gt;2.json&lt;/code&gt;, for the Delhi and Goa collections. &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/AAYUSH-GUPTA-coder/NFT-COLLECTION-QUICKNODE-TUTORIAL/tree/main/metadata&quot;&gt;You&apos;ll find the Metadata example on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Similarly, upload your metadata folder to QuickNode IPFS. Once successfully uploaded, it will appear as shown:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692874812751/79aa6d1d-7d71-4df8-8257-6beac718ed0a.png?auto=compress,format&amp;amp;format=webp&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692874812751/79aa6d1d-7d71-4df8-8257-6beac718ed0a.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692874812751/79aa6d1d-7d71-4df8-8257-6beac718ed0a.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692874812751/79aa6d1d-7d71-4df8-8257-6beac718ed0a.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;You can view the JSON file by clicking on the filename in the QuickNode IPFS dashboard.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692875218884/4fda8d2e-8f92-4ae4-8944-268330d2c3c6.png?auto=compress,format&amp;amp;format=webp&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692875218884/4fda8d2e-8f92-4ae4-8944-268330d2c3c6.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692875218884/4fda8d2e-8f92-4ae4-8944-268330d2c3c6.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692875218884/4fda8d2e-8f92-4ae4-8944-268330d2c3c6.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now, click &quot;COPY IPFS URL&quot; to copy the CID and the gateway link, allowing you to access the file. For example, this is the link to the &lt;code&gt;0.json&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://quicknode.quicknode-ipfs.com/ipfs/QmQQEjRjhUQPgJ51U2PKkwyRLgktzGWmX95vgUzWfBj5gb&quot;&gt;&lt;strong&gt;https://quicknode.quicknode-ipfs.com/ipfs/QmQQEjRjhUQPgJ51U2PKkwyRLgktzGWmX95vgUzWfBj5gb&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692875496119/12994666-7593-4e14-b459-95f67d3bc825.png?auto=compress,format&amp;amp;format=webp&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692875496119/12994666-7593-4e14-b459-95f67d3bc825.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692875496119/12994666-7593-4e14-b459-95f67d3bc825.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692875496119/12994666-7593-4e14-b459-95f67d3bc825.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-creating-andamp-deploying-the-nft-smart-contract&quot;&gt;&lt;strong&gt;Creating &amp;amp; Deploying the NFT Smart Contract&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Use the OpenZeppelin contracts library to create an &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC721&quot;&gt;ERC-721 contract&lt;/a&gt; and &lt;a target=&quot;_blank&quot; href=&quot;https://remix.ethereum.org/&quot;&gt;deploy it on the Optimism Goerli Testnet using the Remix IDE&lt;/a&gt;. Ensure you have some Goerli Ether, which you can &lt;a target=&quot;_blank&quot; href=&quot;https://faucet.quicknode.com/optimism/goerli&quot;&gt;get from the Quicknode Optimism Faucet&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Create a new file named &lt;code&gt;QuickNft.sol&lt;/code&gt; in Remix IDE and paste the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;// SPDX-License-Identifier: MIT&lt;/span&gt;
&lt;span&gt;&lt;span&gt;pragma&lt;/span&gt; &lt;span&gt;solidity&lt;/span&gt; 0.8.17;&lt;/span&gt;

&lt;span&gt;import&lt;/span&gt; &lt;span&gt;&quot;@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; &lt;span&gt;&quot;@openzeppelin/contracts/access/Ownable.sol&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; &lt;span&gt;&quot;@openzeppelin/contracts/utils/Strings.sol&quot;&lt;/span&gt;;

&lt;span&gt;&lt;span&gt;error&lt;/span&gt; &lt;span&gt;NFT_NOT_EXIST&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;)&lt;/span&gt;;
&lt;span&gt;&lt;span&gt;error&lt;/span&gt; &lt;span&gt;YOU_ALREADY_MINTED_NFT&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;)&lt;/span&gt;;
&lt;span&gt;&lt;span&gt;error&lt;/span&gt; &lt;span&gt;ALL_NFTS_ARE_MINTED&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;)&lt;/span&gt;;

&lt;span&gt;&lt;span&gt;contract&lt;/span&gt; &lt;span&gt;QuickNft&lt;/span&gt; &lt;span&gt;is&lt;/span&gt; &lt;span&gt;ERC721Enumerable&lt;/span&gt;, &lt;span&gt;Ownable&lt;/span&gt; &lt;/span&gt;{
    &lt;span&gt;uint256&lt;/span&gt; &lt;span&gt;public&lt;/span&gt; supplies &lt;span&gt;=&lt;/span&gt; &lt;span&gt;500&lt;/span&gt;;
    &lt;span&gt;uint256&lt;/span&gt; &lt;span&gt;public&lt;/span&gt; minted;
    &lt;span&gt;string&lt;/span&gt;[] &lt;span&gt;public&lt;/span&gt; cid &lt;span&gt;=&lt;/span&gt; [
        &lt;span&gt;&quot;ipfs://QmQQEjRjhUQPgJ51U2PKkwyRLgktzGWmX95vgUzWfBj5gb&quot;&lt;/span&gt;,
        &lt;span&gt;&quot;ipfs://Qmch5VaqXCc5ZbwKuL2awac1vrBXBBPiB5h7WxtYKDZ7DS&quot;&lt;/span&gt;,
        &lt;span&gt;&quot;ipfs://QmQg5wf1KHLDA1pEg51wK44UqPa6wJztTxppgb92VyPEbR&quot;&lt;/span&gt;
    ];

    &lt;span&gt;&lt;span&gt;constructor&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;span&gt;ERC721&lt;/span&gt;(&lt;span&gt;&lt;span&gt;&quot;QuickNft&quot;&lt;/span&gt;, &lt;span&gt;&quot;QNN&quot;&lt;/span&gt;&lt;/span&gt;) &lt;/span&gt;{}

    &lt;span&gt;/**
     * @notice function to put NFT on Opensea
     * @param _cidId ID of the metadata of NFT we want to mint
     * @dev tokenURI overrides the Openzeppelin&apos;s ERC721 implementation for tokenURI function
     * This function returns the URI from where we can extract the metadata for a given tokenId
     */&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;tokenURI&lt;/span&gt;(&lt;span&gt;
        &lt;span&gt;uint256&lt;/span&gt; _cidId
    &lt;/span&gt;) &lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;view&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;virtual&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;override&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;returns&lt;/span&gt;&lt;/span&gt; (&lt;span&gt;&lt;span&gt;string&lt;/span&gt; &lt;span&gt;memory&lt;/span&gt;&lt;/span&gt;) &lt;/span&gt;{
        &lt;span&gt;if&lt;/span&gt; (_cidId &lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt; cid.&lt;span&gt;length&lt;/span&gt;) &lt;span&gt;revert&lt;/span&gt; NFT_NOT_EXIST();
        &lt;span&gt;return&lt;/span&gt; &lt;span&gt;string&lt;/span&gt;(&lt;span&gt;abi&lt;/span&gt;.&lt;span&gt;encodePacked&lt;/span&gt;(cid[_cidId]));
    }

    &lt;span&gt;/**
     * @notice function to mint the NFT
     * @param _cidId CID ID to select the metadata of your choice
     */&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;mint&lt;/span&gt;(&lt;span&gt;&lt;span&gt;uint256&lt;/span&gt; _cidId&lt;/span&gt;) &lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;{
        &lt;span&gt;if&lt;/span&gt; (_cidId &lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt; cid.&lt;span&gt;length&lt;/span&gt;) &lt;span&gt;revert&lt;/span&gt; NFT_NOT_EXIST();
        &lt;span&gt;if&lt;/span&gt; (minted &lt;span&gt;+&lt;/span&gt; &lt;span&gt;1&lt;/span&gt; &lt;span&gt;&amp;gt;&lt;/span&gt; supplies) &lt;span&gt;revert&lt;/span&gt; ALL_NFTS_ARE_MINTED();
        _safeMint(&lt;span&gt;msg&lt;/span&gt;.&lt;span&gt;sender&lt;/span&gt;, minted);
        &lt;span&gt;unchecked&lt;/span&gt; {
            &lt;span&gt;+&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;minted;
        }
    }

    &lt;span&gt;/**
     * @notice function to get total number of NFTs minted
     */&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;totalNftMinted&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;view&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;returns&lt;/span&gt;&lt;/span&gt; (&lt;span&gt;&lt;span&gt;uint256&lt;/span&gt;&lt;/span&gt;) &lt;/span&gt;{
        &lt;span&gt;return&lt;/span&gt; minted;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s break down the above Solidity smart contract code line by line:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;// SPDX-License-Identifier: MIT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This line specifies the license identifier for the contract. In this case, it&apos;s indicating that the contract is under the MIT License.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;pragma&lt;/span&gt; &lt;span&gt;solidity&lt;/span&gt; 0.8.17;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This pragma sets the version of Solidity. In this case, the compiler will use version 0.8.17 of Solidity for the compilation.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;import&lt;/span&gt; &lt;span&gt;&quot;@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; &lt;span&gt;&quot;@openzeppelin/contracts/access/Ownable.sol&quot;&lt;/span&gt;;
&lt;span&gt;import&lt;/span&gt; &lt;span&gt;&quot;@openzeppelin/contracts/utils/Strings.sol&quot;&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These lines are importing necessary contracts from the OpenZeppelin library. The the &lt;code&gt;ERC721Enumerable&lt;/code&gt; contract helps to create an ERC-721 token that supports enumeration (listing tokens), the &lt;code&gt;Ownable&lt;/code&gt; contract will provide basic ownership functionality and the &lt;code&gt;Strings&lt;/code&gt; contract is used for manipulating strings.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;error&lt;/span&gt; &lt;span&gt;NFT_NOT_EXIST&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;)&lt;/span&gt;;
&lt;span&gt;&lt;span&gt;error&lt;/span&gt; &lt;span&gt;YOU_ALREADY_MINTED_NFT&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;)&lt;/span&gt;;
&lt;span&gt;&lt;span&gt;error&lt;/span&gt; &lt;span&gt;ALL_NFTS_ARE_MINTED&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;)&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These lines define custom error messages that we used in the contract.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;contract&lt;/span&gt; &lt;span&gt;QuickNft&lt;/span&gt; &lt;span&gt;is&lt;/span&gt; &lt;span&gt;ERC721Enumerable&lt;/span&gt;, &lt;span&gt;Ownable&lt;/span&gt; &lt;/span&gt;{
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This line defines the &lt;code&gt;QuickNft&lt;/code&gt; contract, which inherits from &lt;code&gt;ERC721Enumerable&lt;/code&gt; and &lt;code&gt;Ownable&lt;/code&gt;,  so the contract will be both an ERC-721 token (with enumeration capabilities) and have ownership functionality.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;uint256&lt;/span&gt; &lt;span&gt;public&lt;/span&gt; supply &lt;span&gt;=&lt;/span&gt; &lt;span&gt;500&lt;/span&gt;;
&lt;span&gt;uint256&lt;/span&gt; &lt;span&gt;public&lt;/span&gt; minted;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These lines declare two state variables. &lt;code&gt;supply&lt;/code&gt; represents the total number of NFTs available for minting, and &lt;code&gt;minted&lt;/code&gt; keeps track of how many NFTs people minted so far.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;string&lt;/span&gt;[] &lt;span&gt;public&lt;/span&gt; cid &lt;span&gt;=&lt;/span&gt; [
    &lt;span&gt;&quot;ipfs://QmQQEjRjhUQPgJ51U2PKkwyRLgktzGWmX95vgUzWfBj5gb&quot;&lt;/span&gt;,
    &lt;span&gt;&quot;ipfs://Qmch5VaqXCc5ZbwKuL2awac1vrBXBBPiB5h7WxtYKDZ7DS&quot;&lt;/span&gt;,
    &lt;span&gt;&quot;ipfs://QmQg5wf1KHLDA1pEg51wK44UqPa6wJztTxppgb92VyPEbR&quot;&lt;/span&gt;
];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An array &lt;code&gt;cid&lt;/code&gt; is defined, containing three IPFS URLs that represent the metadata of the NFTs.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;constructor&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;span&gt;ERC721&lt;/span&gt;(&lt;span&gt;&lt;span&gt;&quot;QuickNft&quot;&lt;/span&gt;, &lt;span&gt;&quot;QNN&quot;&lt;/span&gt;&lt;/span&gt;) &lt;/span&gt;{}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The contract&apos;s constructor initializes the ERC-721 token with &quot;QuickNft&quot; as the name and &quot;QNN&quot; as the symbol.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;tokenURI&lt;/span&gt;(&lt;span&gt;&lt;span&gt;uint256&lt;/span&gt; _cidId&lt;/span&gt;) &lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;view&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;virtual&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;override&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;returns&lt;/span&gt;&lt;/span&gt; (&lt;span&gt;&lt;span&gt;string&lt;/span&gt; &lt;span&gt;memory&lt;/span&gt;&lt;/span&gt;) &lt;/span&gt;{
    &lt;span&gt;if&lt;/span&gt; (_cidId &lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt; cid.&lt;span&gt;length&lt;/span&gt;) &lt;span&gt;revert&lt;/span&gt; NFT_NOT_EXIST();
    &lt;span&gt;return&lt;/span&gt; &lt;span&gt;string&lt;/span&gt;(&lt;span&gt;abi&lt;/span&gt;.&lt;span&gt;encodePacked&lt;/span&gt;(cid[_cidId]));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function, &lt;code&gt;tokenURI&lt;/code&gt;, overrides the default ERC721 behavior and returns the IPFS URL (metadata URI) associated with the given &lt;code&gt;_cidId&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;mint&lt;/span&gt;(&lt;span&gt;&lt;span&gt;uint256&lt;/span&gt; _cidId&lt;/span&gt;) &lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;{
    &lt;span&gt;if&lt;/span&gt; (_cidId &lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt; cid.&lt;span&gt;length&lt;/span&gt;) &lt;span&gt;revert&lt;/span&gt; NFT_NOT_EXIST();
    &lt;span&gt;if&lt;/span&gt; (minted &lt;span&gt;+&lt;/span&gt; &lt;span&gt;1&lt;/span&gt; &lt;span&gt;&amp;gt;&lt;/span&gt; supplies) &lt;span&gt;revert&lt;/span&gt; ALL_NFTS_ARE_MINTED();
    _safeMint(&lt;span&gt;msg&lt;/span&gt;.&lt;span&gt;sender&lt;/span&gt;, minted);
    &lt;span&gt;unchecked&lt;/span&gt; {
        &lt;span&gt;+&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;minted;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;mint&lt;/code&gt; function allows users to mint NFTs. It checks if the &lt;code&gt;_cidId&lt;/code&gt; is valid and the total number of minted NFTs is within the available supply. If this is the case, it mints a new NFT for the caller and increments the &lt;code&gt;minted&lt;/code&gt; count.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;function&lt;/span&gt; &lt;span&gt;totalNftMinted&lt;/span&gt;(&lt;span&gt;&lt;/span&gt;) &lt;span&gt;&lt;span&gt;public&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;view&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;returns&lt;/span&gt;&lt;/span&gt; (&lt;span&gt;&lt;span&gt;uint256&lt;/span&gt;&lt;/span&gt;) &lt;/span&gt;{
    &lt;span&gt;return&lt;/span&gt; minted;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;totalNftMinted&lt;/code&gt; function returns the total count of minted NFTs.&lt;/p&gt;
&lt;p&gt;In case you don&apos;t have the Optimism Goerli Testnet set up in your wallet, follow these steps:&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/blog-newsletter-1&quot;&gt;&lt;img src=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=1400&amp;auto=format&quot; srcset=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=1 1x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=2 2x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;D_D Newsletter CTA&quot; class=&quot;mx-auto&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-creating-an-optimism-endpoint-on-quicknode&quot;&gt;Creating an Optimism Endpoint on QuickNode&lt;/h2&gt;
&lt;p&gt;To deploy a smart contract to Optimism&apos;s test blockchain, Goerli, you&apos;ll need an API endpoint to communicate with the network. &lt;a target=&quot;_blank&quot; href=&quot;https://dashboard.quicknode.com/endpoints&quot;&gt;Go to the QuickNode Dashboard to configure it.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once logged in, click the &quot;Create an endpoint&quot; button, then select the &quot;Optimism&quot; chain and &quot;Goerli&quot; network.&lt;/p&gt;
&lt;p&gt;After creating your endpoint, copy the HTTP provider link and keep it handy, as you&apos;ll need it next.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692972974293/6532afd7-8c99-4fec-b026-76ddf2f3f989.png?auto=compress,format&amp;amp;format=webp&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692972974293/6532afd7-8c99-4fec-b026-76ddf2f3f989.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692972974293/6532afd7-8c99-4fec-b026-76ddf2f3f989.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692972974293/6532afd7-8c99-4fec-b026-76ddf2f3f989.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-configuring-your-web3-wallet-with-quicknode&quot;&gt;Configuring Your Web3 Wallet with QuickNode&lt;/h2&gt;
&lt;p&gt;Configure your RPC settings if you&apos;re using MetaMask to deploy this contract. Some compatible wallets are &lt;a target=&quot;_blank&quot; href=&quot;https://www.coinbase.com/es/wallet&quot;&gt;Coinbase Wallet&lt;/a&gt;, &lt;a target=&quot;_blank&quot; href=&quot;https://rainbow.me/&quot;&gt;Rainbow Wallet&lt;/a&gt; and &lt;a target=&quot;_blank&quot; href=&quot;https://trustwallet.com/es/&quot;&gt;TrustWallet&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Open up MetaMask and click the network dropdown at the top. After, click the &quot;Add Network&quot; button.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692981270357/8cf1c8c2-1026-48e8-b20a-f594a2555de8.png?auto=compress,format&amp;amp;format=webp&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692981270357/8cf1c8c2-1026-48e8-b20a-f594a2555de8.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692981270357/8cf1c8c2-1026-48e8-b20a-f594a2555de8.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692981270357/8cf1c8c2-1026-48e8-b20a-f594a2555de8.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;At the bottom of the page, click &quot;Add a network manually&quot; and fill out the following details:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Network name: Optimism Goerli Testnet&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;New RPC URL: Enter the QuickNode HTTP URL you retrieved earlier&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Chain ID: 420&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Currency symbol: ETH&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Block Explorer URL: &lt;a target=&quot;_blank&quot; href=&quot;https://optimism-goerli.blockscout.com&quot;&gt;&lt;strong&gt;https://optimism-goerli.blockscout.com&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It should end up looking similar to this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692981515517/200fa9cf-1449-4b1e-8b2c-f6c49309ece1.png?auto=compress,format&amp;amp;format=webp&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692981515517/200fa9cf-1449-4b1e-8b2c-f6c49309ece1.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692981515517/200fa9cf-1449-4b1e-8b2c-f6c49309ece1.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692981515517/200fa9cf-1449-4b1e-8b2c-f6c49309ece1.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-compiling-the-smart-contract&quot;&gt;Compiling the Smart Contract&lt;/h2&gt;
&lt;p&gt;Open Remix IDE, copy and paste the above code, and navigate to the Deploy section. Select &apos;Injected Web3&apos; as the environment, and deploy it by choosing the correct contract name. You need to select the chain on your MetaMask wallet. In our case, we are deploying it on the Optimism Goerli Testnet with chain ID 420. Click the Deploy button&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692972641112/35e866c5-6d16-4580-9b37-870718c7b240.png?auto=compress,format&amp;amp;format=webp&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692972641112/35e866c5-6d16-4580-9b37-870718c7b240.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692972641112/35e866c5-6d16-4580-9b37-870718c7b240.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692972641112/35e866c5-6d16-4580-9b37-870718c7b240.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Approve the transaction on MetaMask by clicking the Confirm button. Once the transaction is complete, your contract will be deployed.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692982135567/08bd8aae-c524-4765-9397-60925a641940.png?auto=compress,format&amp;amp;format=webp&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692982135567/08bd8aae-c524-4765-9397-60925a641940.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692982135567/08bd8aae-c524-4765-9397-60925a641940.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692982135567/08bd8aae-c524-4765-9397-60925a641940.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now you can perform functions like mint NFT by entering CID ID. We can also retrieve the NFT URI by entering the CID ID.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692984714894/6918f5a7-9f13-4b2a-9d22-bb5e9f2e53c5.png?auto=compress,format&amp;amp;format=webp&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692984714894/6918f5a7-9f13-4b2a-9d22-bb5e9f2e53c5.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692984714894/6918f5a7-9f13-4b2a-9d22-bb5e9f2e53c5.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692984714894/6918f5a7-9f13-4b2a-9d22-bb5e9f2e53c5.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-minting-an-nft&quot;&gt;Minting an NFT&lt;/h2&gt;
&lt;p&gt;Enter the CID ID of the NFT you want to mint and click on the Confirm Button.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692985097616/de40d378-da01-44f9-a5a9-cd2d348b4a8b.png?auto=compress,format&amp;amp;format=webp&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692985097616/de40d378-da01-44f9-a5a9-cd2d348b4a8b.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692985097616/de40d378-da01-44f9-a5a9-cd2d348b4a8b.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692985097616/de40d378-da01-44f9-a5a9-cd2d348b4a8b.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;p&gt;After some time, you can see the NFT on &lt;a target=&quot;_blank&quot; href=&quot;https://testnets.opensea.io/collection/quicknft-1&quot;&gt;OpenSea&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692985680055/e4293a0d-8a57-4b6d-a5db-301137afd99e.png?auto=compress,format&amp;amp;format=webp&amp;width=1400&amp;auto=format&quot; srcset=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1692985680055/e4293a0d-8a57-4b6d-a5db-301137afd99e.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=1 1x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692985680055/e4293a0d-8a57-4b6d-a5db-301137afd99e.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=2 2x, https://cdn.hashnode.com/res/hashnode/image/upload/v1692985680055/e4293a0d-8a57-4b6d-a5db-301137afd99e.png?auto=compress,format&amp;amp;format=webp&amp;width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;&quot; class=&quot;mx-auto&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;heading-boom&quot;&gt;🎉BOOM 🎉&lt;/h2&gt;
&lt;p&gt;You&apos;ve completed the entire tutorial. Give yourself a well-deserved pat on the back. You&apos;ve learned how to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create an NFT Collection using the ERC-721 Token standard.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Store NFT Metadata in a decentralized manner using QuickNode IPFS.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compile and deploy a Smart Contract on the Optimism Goerli Testnet.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Interact with the smart contract using Remix.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;🎉&lt;/strong&gt; Bonus for sticking till the end: use code &lt;strong&gt;BUILD-AMB-15&lt;/strong&gt;. This coupon gives you 1 month of the QuickNode Build ($49) plan for free &lt;strong&gt;🎉&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://devdao.to/blog-newsletter-1&quot;&gt;&lt;img src=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=1400&amp;auto=format&quot; srcset=&quot;https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=1 1x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=2 2x, https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png?width=700&amp;auto=format&amp;dpr=3 3x&quot; alt=&quot;D_D Newsletter CTA&quot; class=&quot;mx-auto&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;###💥 Simply WOW 💥&lt;/p&gt;
&lt;p&gt;If you found this tutorial helpful and enjoyable, consider sharing it with your friends. I hope you&apos;ve gained new insights or even solved a challenge. Thank you for reading, and have a great time!&lt;/p&gt;
&lt;p&gt;Feel free to connect with me on &lt;a target=&quot;_blank&quot; href=&quot;https://twitter.com/Aayush_gupta_ji&quot;&gt;Twitter&lt;/a&gt;, &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/AAYUSH-GUPTA-coder&quot;&gt;GitHub&lt;/a&gt;, and &lt;a target=&quot;_blank&quot; href=&quot;https://www.linkedin.com/in/aayush-gupta-20023b183/&quot;&gt;LinkedIn&lt;/a&gt;. I welcome your suggestions and comments!&lt;/p&gt;
&lt;p&gt;WAGMI 🚀🚀&lt;/p&gt;
&lt;/div&gt;</content>
  </entry>
</feed>