<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aditya41205</title>
    <description>The latest articles on DEV Community by Aditya41205 (@aditya-alchemist).</description>
    <link>https://dev.to/aditya-alchemist</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1467887%2F6a84630f-3703-44e2-be91-712dda58b1a0.jpg</url>
      <title>DEV Community: Aditya41205</title>
      <link>https://dev.to/aditya-alchemist</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aditya-alchemist"/>
    <language>en</language>
    <item>
      <title>Uniswap V3 swapping functions</title>
      <dc:creator>Aditya41205</dc:creator>
      <pubDate>Wed, 16 Jul 2025 16:30:52 +0000</pubDate>
      <link>https://dev.to/aditya-alchemist/uniswap-v3-swapping-functions-5gc3</link>
      <guid>https://dev.to/aditya-alchemist/uniswap-v3-swapping-functions-5gc3</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faasuxswyl7tn14sm7qwg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faasuxswyl7tn14sm7qwg.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Uniswap V3 Swapping Functions Explained
&lt;/h2&gt;

&lt;p&gt;Uniswap V3 is the most advanced AMM (Automated Market Maker) on Ethereum, providing efficient on-chain swapping for ERC20 tokens. When working with Uniswap from a smart contract, you interact with the router interface—specifically, &lt;code&gt;ISwapRouter&lt;/code&gt;—to perform swaps programmatically.&lt;/p&gt;

&lt;p&gt;This blog will break down each major swap function (and their parameters!), so you can choose the right tool for your scenario and build powerful DeFi integrations.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Four Core Uniswap V3 Swapping Methods
&lt;/h2&gt;

&lt;p&gt;Uniswap V3's &lt;code&gt;ISwapRouter&lt;/code&gt; exposes four primary ways to swap tokens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;exactInputSingle&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;exactInput&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;exactOutputSingle&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;exactOutput&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s explain each in detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;code&gt;exactInputSingle&lt;/code&gt;: Single Pool, Exact Input Amount
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Swap a &lt;strong&gt;known amount of &lt;code&gt;tokenIn&lt;/code&gt;&lt;/strong&gt; for &lt;em&gt;as much&lt;/em&gt; &lt;code&gt;tokenOut&lt;/code&gt; as possible, all via a &lt;em&gt;single&lt;/em&gt; Uniswap V3 pool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signature:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Parameters (packed in a struct):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tokenIn&lt;/code&gt;: Address of input token (e.g., DAI).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tokenOut&lt;/code&gt;: Address of output token (e.g., WETH).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fee&lt;/code&gt;: Pool fee (500, 3000, or 10000 for 0.05%, 0.3%, 1%).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;recipient&lt;/code&gt;: Where to send the output tokens.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;amountIn&lt;/code&gt;: The fixed amount of &lt;code&gt;tokenIn&lt;/code&gt; to swap.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;amountOutMinimum&lt;/code&gt;: Minimum amount of &lt;code&gt;tokenOut&lt;/code&gt; you will accept (&lt;em&gt;prevents frontrunning/slippage&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sqrtPriceLimitX96&lt;/code&gt;: Optional. Sets a price boundary for the swap (0 for no limit).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Usage in Practice:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Simple swaps (DAI↔WETH, USDC↔USDT, etc.) without routing through multiple pairs.&lt;br&gt;&lt;br&gt;
&lt;em&gt;Example scenario:&lt;/em&gt; Swap exactly 1000 DAI to receive the maximum possible amount of WETH.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. &lt;code&gt;exactInput&lt;/code&gt;: Multi-hop, Exact Input Amount
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Swap a &lt;strong&gt;known amount of &lt;code&gt;tokenIn&lt;/code&gt;&lt;/strong&gt; for &lt;em&gt;as much as possible&lt;/em&gt; of a final &lt;code&gt;tokenOut&lt;/code&gt;, possibly routing through several pools (multi-hop swap).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signature:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Parameters (in a struct):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;path&lt;/code&gt;: Bytes data encoding token and fee sequence, e.g., &lt;code&gt;tokenA, feeAB, tokenB, feeBC, tokenC&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;recipient&lt;/code&gt;: Who receives the output tokens.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;amountIn&lt;/code&gt;: The fixed amount of &lt;code&gt;tokenIn&lt;/code&gt; for the whole route.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;amountOutMinimum&lt;/code&gt;: Minimum acceptable output.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Path Example (DAI → WETH → WBTC):&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;abi.encodePacked(DAI, uint24(3000), WETH, uint24(3000), WBTC)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Usage in Practice:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
For swaps not directly supported in a single pool (e.g., DAI→WETH→WBTC), or to find the best route through intermediary assets.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. &lt;code&gt;exactOutputSingle&lt;/code&gt;: Single Pool, Exact Output Amount
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Receive an &lt;strong&gt;exact amount of &lt;code&gt;tokenOut&lt;/code&gt;&lt;/strong&gt; while spending &lt;em&gt;as little as possible&lt;/em&gt; of &lt;code&gt;tokenIn&lt;/code&gt;, via a single Uniswap pool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signature:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Parameters:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tokenIn&lt;/code&gt;: Address of input token.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tokenOut&lt;/code&gt;: Address of output token.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fee&lt;/code&gt;: Pool fee.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;recipient&lt;/code&gt;: Recipient of the output tokens.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;amountOut&lt;/code&gt;: The desired, exact output amount of &lt;code&gt;tokenOut&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;amountInMaximum&lt;/code&gt;: The most input tokens you’ll allow to be spent (slippage protection).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sqrtPriceLimitX96&lt;/code&gt;: Optional price boundary (set to 0 for no limit).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Usage in Practice:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You need exactly e.g. 1 ETH, but want to spend the minimum DAI possible, and you're willing to cap total input due to price impact or slippage.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. &lt;code&gt;exactOutput&lt;/code&gt;: Multi-hop, Exact Output Amount
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Receive an &lt;strong&gt;exact amount of &lt;code&gt;tokenOut&lt;/code&gt;&lt;/strong&gt; via multiple pools, spending as little input as needed (but no more than your set maximum).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signature:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Parameters:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;path&lt;/code&gt;: Bytes encoding the swap route &lt;strong&gt;from output to input&lt;/strong&gt; (i.e., reversed compared to &lt;code&gt;exactInput&lt;/code&gt;!).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;recipient&lt;/code&gt;: Who gets the output.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;amountOut&lt;/code&gt;: The precise amount of output tokens you want.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;amountInMaximum&lt;/code&gt;: The maximum input tokens you’re willing to spend.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Example path for WBTC (output) ← WETH ← DAI (input):&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;abi.encodePacked(WBTC, uint24(3000), WETH, uint24(3000), DAI)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Note: Multi-hop exactOutput paths are reversed!)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usage in Practice:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Useful for use-cases where you need to guarantee a specific payment amount in the output token (e.g., for NFT or fixed-price purchases), optimizing how little input you spend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Struct Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;th&gt;Parameter Struct Name&lt;/th&gt;
&lt;th&gt;Path Format&lt;/th&gt;
&lt;th&gt;Guarantees&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;exactInputSingle&lt;/td&gt;
&lt;td&gt;ExactInputSingleParams&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;Exact input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;exactInput&lt;/td&gt;
&lt;td&gt;ExactInputParams&lt;/td&gt;
&lt;td&gt;[tokenIn, fee, tokenMid, ...]&lt;/td&gt;
&lt;td&gt;Exact input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;exactOutputSingle&lt;/td&gt;
&lt;td&gt;ExactOutputSingleParams&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;Exact output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;exactOutput&lt;/td&gt;
&lt;td&gt;ExactOutputParams&lt;/td&gt;
&lt;td&gt;[tokenOut, fee, tokenMid, ...] &lt;strong&gt;reverse!&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Exact output&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Key Design Patterns and Safety
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Always fill in &lt;code&gt;amountOutMinimum&lt;/code&gt;/&lt;code&gt;amountInMaximum&lt;/code&gt; to guard against front-running and sandwich attacks.&lt;/li&gt;
&lt;li&gt;Approve the router contract for any tokens you supply (&lt;code&gt;IERC20(tokenIn).approve(...)&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sqrtPriceLimitX96&lt;/code&gt; is almost always safe at 0 unless you want to enforce a strict price boundary.&lt;/li&gt;
&lt;li&gt;For multi-hop routes, ensure each pool (each hop) has liquidity!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Uniswap V3's router gives you immense flexibility :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;exactInputSingle&lt;/code&gt; for simple, one-hop max-output swaps.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;exactInput&lt;/code&gt; for complex swaps through several pools with a fixed input.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;exactOutputSingle&lt;/code&gt; and &lt;code&gt;exactOutput&lt;/code&gt; when you know exactly what you want to receive and want to cap your spending.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this understanding, you can integrate efficient, robust DeFi swaps into your own contracts and dApps!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Further Reading:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.uniswap.org/contracts/v3/reference/periphery/interfaces/ISwapRouter" rel="noopener noreferrer"&gt;Uniswap V3 Periphery Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.uniswap.org/contracts/v3/guides/swaps/" rel="noopener noreferrer"&gt;Uniswap V3 Swaps Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy swapping!&lt;/p&gt;

</description>
      <category>uniswapv3</category>
      <category>decentralizedexchange</category>
      <category>defi</category>
      <category>foundry</category>
    </item>
    <item>
      <title>Uniswap V2 Decoded: A Complete Guide with Code Examples</title>
      <dc:creator>Aditya41205</dc:creator>
      <pubDate>Sun, 29 Jun 2025 07:35:53 +0000</pubDate>
      <link>https://dev.to/aditya-alchemist/uniswap-v2-decoded-a-complete-guide-with-code-examples-2lpd</link>
      <guid>https://dev.to/aditya-alchemist/uniswap-v2-decoded-a-complete-guide-with-code-examples-2lpd</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9cm9j0zz8q7yw7ufrwhc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9cm9j0zz8q7yw7ufrwhc.png" alt="Uniswap" width="780" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Uniswap V2 revolutionized decentralized trading by introducing automated market makers (AMMs) that enable permissionless token swapping and liquidity provision. In this comprehensive guide, we'll decode the core mechanics of Uniswap V2 with practical code examples that you can implement today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Uniswap V2 Architecture
&lt;/h2&gt;

&lt;p&gt;Uniswap V2 implements a &lt;strong&gt;core/periphery architecture&lt;/strong&gt; that separates essential functionality from user-friendly interfaces. The core contracts handle the fundamental trading logic and secure liquidity pools, while periphery contracts like the Router provide safety checks and ease-of-use features.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core vs Periphery Design
&lt;/h3&gt;

&lt;p&gt;The minimalist core contracts contain only logic strictly necessary to secure liquidity, while periphery contracts handle trader security and user experience. This modular approach allows external helpers to be improved and replaced without migrating liquidity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Core: Minimal, secure, immutable
contract UniswapV2Pair {
    // Essential trading logic only
}

// Periphery: User-friendly, upgradeable
contract UniswapV2Router02 {
    // Safety checks and convenience functions
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting Up Your Contract
&lt;/h2&gt;

&lt;p&gt;To interact with Uniswap V2, you need to create an instance of the router contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pragma solidity ^0.8.0;

import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract UniswapV2Integration {
    address private constant ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
    IUniswapV2Router02 public uniswapV2Router;

    constructor() {
        uniswapV2Router = IUniswapV2Router02(ROUTER);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Components:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Router Address&lt;/strong&gt;: The official Ethereum mainnet address of UniswapV2Router02&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interface Declaration&lt;/strong&gt;: Defines all available router functions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instance Creation&lt;/strong&gt;: Enables calling router functions in your contract&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Adding Liquidity: Becoming a Liquidity Provider
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;addLiquidity()&lt;/code&gt; function allows you to provide liquidity to trading pairs and earn fees from every trade.&lt;/p&gt;

&lt;h3&gt;
  
  
  Function Signature
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function addLiquidity(
    address tokenA,
    address tokenB,
    uint amountADesired,
    uint amountBDesired,
    uint amountAMin,
    uint amountBMin,
    address to,
    uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Parameter Breakdown
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;tokenA/tokenB&lt;/code&gt;&lt;/strong&gt;: Contract addresses of the tokens to pair&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;amountADesired/amountBDesired&lt;/code&gt;&lt;/strong&gt;: Your preferred deposit amounts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;amountAMin/amountBMin&lt;/code&gt;&lt;/strong&gt;: Minimum amounts (slippage protection)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;to&lt;/code&gt;&lt;/strong&gt;: Address receiving LP tokens&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;deadline&lt;/code&gt;&lt;/strong&gt;: Transaction expiration timestamp&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Practical Implementation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function addLiquidityToPool(
    address tokenA,
    address tokenB,
    uint256 amountA,
    uint256 amountB
) external {
    // Approve router to spend tokens
    IERC20(tokenA).approve(address(uniswapV2Router), amountA);
    IERC20(tokenB).approve(address(uniswapV2Router), amountB);

    // Add liquidity with 5% slippage tolerance
    uniswapV2Router.addLiquidity(
        tokenA,
        tokenB,
        amountA,
        amountB,
        amountA * 95 / 100,  // 5% slippage protection
        amountB * 95 / 100,  // 5% slippage protection
        msg.sender,          // LP tokens to caller
        block.timestamp + 300 // 5 minute deadline
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Internal Mechanics: How addLiquidity() Works
&lt;/h2&gt;

&lt;p&gt;Understanding the internal &lt;code&gt;_addLiquidity()&lt;/code&gt; function reveals the sophisticated logic behind liquidity provision:&lt;/p&gt;

&lt;h3&gt;
  
  
  Pair Creation Check
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) {
    IUniswapV2Factory(factory).createPair(tokenA, tokenB);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Reserve-Based Calculations
&lt;/h3&gt;

&lt;p&gt;For existing pairs, the function maintains price ratios:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;amountBOptimal = amountADesired.mul(reserveB) / reserveA;

if (amountBOptimal &amp;lt;= amountBDesired) {
    (amountA, amountB) = (amountADesired, amountBOptimal);
} else {
    amountAOptimal = amountBDesired.mul(reserveA) / reserveB;
    (amountA, amountB) = (amountAOptimal, amountBDesired);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CREATE2 Address Calculation
&lt;/h3&gt;

&lt;p&gt;Uniswap V2 uses deterministic addresses for gas efficiency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pair = address(uint(keccak256(abi.encodePacked(
    hex'ff',
    factory,
    keccak256(abi.encodePacked(token0, token1)),
    hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f'
))));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Removing Liquidity: Exiting Your Position
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;removeLiquidity()&lt;/code&gt; function allows you to withdraw your tokens by burning LP tokens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function removeLiquidity(
    address tokenA,
    address tokenB,
    uint liquidity,
    uint amountAMin,
    uint amountBMin,
    address to,
    uint deadline
) external returns (uint amountA, uint amountB);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Implementation Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function removeLiquidityFromPool(
    address tokenA,
    address tokenB,
    uint256 liquidityAmount
) external {
    address pair = IUniswapV2Factory(factory).getPair(tokenA, tokenB);

    // Approve router to spend LP tokens
    IERC20(pair).approve(address(uniswapV2Router), liquidityAmount);

    // Remove liquidity
    uniswapV2Router.removeLiquidity(
        tokenA,
        tokenB,
        liquidityAmount,
        0, // Accept any amount of tokenA
        0, // Accept any amount of tokenB
        msg.sender,
        block.timestamp + 300
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Token Swapping: The Heart of DeFi Trading
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;swapExactTokensForTokens()&lt;/code&gt; function enables precise token exchanges:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function swapExactTokensForTokens(
    uint amountIn,
    uint amountOutMin,
    address[] calldata path,
    address to,
    uint deadline
) external returns (uint[] memory amounts);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Advanced Swap Implementation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function swapTokens(
    address tokenIn,
    address tokenOut,
    uint256 amountIn,
    uint256 slippagePercent
) external {
    // Approve router
    IERC20(tokenIn).approve(address(uniswapV2Router), amountIn);

    // Calculate minimum output with slippage
    address[] memory path = new address[](2);
    path[0] = tokenIn;
    path[1] = tokenOut;

    uint[] memory amountsOut = uniswapV2Router.getAmountsOut(amountIn, path);
    uint amountOutMin = amountsOut[1] * (100 - slippagePercent) / 100;

    // Execute swap
    uniswapV2Router.swapExactTokensForTokens(
        amountIn,
        amountOutMin,
        path,
        msg.sender,
        block.timestamp + 300
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Multi-Hop Swapping
&lt;/h3&gt;

&lt;p&gt;For tokens without direct pairs, Uniswap routes through intermediate tokens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function multiHopSwap(uint256 amountIn) external {
    address[] memory path = new address[](3);
    path[0] = USDC_ADDRESS;  // Start with USDC
    path[1] = WETH_ADDRESS;  // Route through WETH
    path[2] = DAI_ADDRESS;   // End with DAI

    IERC20(USDC_ADDRESS).approve(address(uniswapV2Router), amountIn);

    uniswapV2Router.swapExactTokensForTokens(
        amountIn,
        0, // Calculate proper minimum in production
        path,
        msg.sender,
        block.timestamp + 300
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  LP Token Economics: Understanding Your Returns
&lt;/h2&gt;

&lt;p&gt;When you provide liquidity, you receive ERC-20 LP tokens representing your pool share:&lt;/p&gt;

&lt;h3&gt;
  
  
  LP Token Characteristics
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Proportional ownership&lt;/strong&gt; of the entire pool&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fee accumulation&lt;/strong&gt; from every trade (0.3% in V2)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redeemable&lt;/strong&gt; for underlying tokens plus earned fees&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Profitability Factors
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Your share calculation
uint256 yourPoolShare = (yourLPTokens * 100) / totalLPSupply;
uint256 yourTokenAShare = (poolReserveA * yourPoolShare) / 100;
uint256 yourTokenBShare = (poolReserveB * yourPoolShare) / 100;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Security Considerations and Best Practices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Always Use Slippage Protection
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Bad: No slippage protection
uniswapV2Router.swapExactTokensForTokens(amountIn, 0, path, to, deadline);

// Good: Proper slippage protection
uint256 amountOutMin = expectedAmount * 95 / 100; // 5% slippage
uniswapV2Router.swapExactTokensForTokens(amountIn, amountOutMin, path, to, deadline);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Implement Proper Deadlines
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Bad: No deadline
uint deadline = type(uint).max;

// Good: Reasonable deadline
uint deadline = block.timestamp + 300; // 5 minutes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Handle Approvals Securely
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function safeApprove(address token, address spender, uint256 amount) internal {
    IERC20(token).approve(spender, 0); // Reset to 0 first
    IERC20(token).approve(spender, amount);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Complete Integration Example
&lt;/h2&gt;

&lt;p&gt;Here's a comprehensive contract that demonstrates all major Uniswap V2 interactions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pragma solidity ^0.8.0;

import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract UniswapV2Manager {
    IUniswapV2Router02 public immutable uniswapV2Router;
    IUniswapV2Factory public immutable uniswapV2Factory;

    constructor() {
        uniswapV2Router = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
        uniswapV2Factory = IUniswapV2Factory(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f);
    }

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint256 amountA,
        uint256 amountB,
        uint256 slippage
    ) external returns (uint256, uint256, uint256) {
        IERC20(tokenA).transferFrom(msg.sender, address(this), amountA);
        IERC20(tokenB).transferFrom(msg.sender, address(this), amountB);

        IERC20(tokenA).approve(address(uniswapV2Router), amountA);
        IERC20(tokenB).approve(address(uniswapV2Router), amountB);

        uint256 amountAMin = amountA * (100 - slippage) / 100;
        uint256 amountBMin = amountB * (100 - slippage) / 100;

        return uniswapV2Router.addLiquidity(
            tokenA,
            tokenB,
            amountA,
            amountB,
            amountAMin,
            amountBMin,
            msg.sender,
            block.timestamp + 300
        );
    }

    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint256 liquidity,
        uint256 slippage
    ) external returns (uint256, uint256) {
        address pair = uniswapV2Factory.getPair(tokenA, tokenB);
        IERC20(pair).transferFrom(msg.sender, address(this), liquidity);
        IERC20(pair).approve(address(uniswapV2Router), liquidity);

        // Get current reserves to calculate minimums
        (uint256 reserveA, uint256 reserveB,) = IUniswapV2Pair(pair).getReserves();
        uint256 totalSupply = IERC20(pair).totalSupply();

        uint256 amountAMin = (reserveA * liquidity / totalSupply) * (100 - slippage) / 100;
        uint256 amountBMin = (reserveB * liquidity / totalSupply) * (100 - slippage) / 100;

        return uniswapV2Router.removeLiquidity(
            tokenA,
            tokenB,
            liquidity,
            amountAMin,
            amountBMin,
            msg.sender,
            block.timestamp + 300
        );
    }

    function swapExactTokensForTokens(
        address tokenIn,
        address tokenOut,
        uint256 amountIn,
        uint256 slippage
    ) external returns (uint256[] memory) {
        IERC20(tokenIn).transferFrom(msg.sender, address(this), amountIn);
        IERC20(tokenIn).approve(address(uniswapV2Router), amountIn);

        address[] memory path = new address[](2);
        path[0] = tokenIn;
        path[1] = tokenOut;

        uint256[] memory amountsOut = uniswapV2Router.getAmountsOut(amountIn, path);
        uint256 amountOutMin = amountsOut[1] * (100 - slippage) / 100;

        return uniswapV2Router.swapExactTokensForTokens(
            amountIn,
            amountOutMin,
            path,
            msg.sender,
            block.timestamp + 300
        );
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Uniswap V2's elegant design combines simplicity with powerful functionality. By understanding the core mechanics of liquidity provision, token swapping, and the underlying mathematical models, developers can build sophisticated DeFi applications that leverage automated market makers.&lt;/p&gt;

&lt;p&gt;The key to successful Uniswap V2 integration lies in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Proper slippage protection&lt;/strong&gt; to prevent unfavorable trades&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure token approvals&lt;/strong&gt; to maintain user fund safety
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Efficient routing&lt;/strong&gt; for optimal swap execution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Understanding LP economics&lt;/strong&gt; for sustainable liquidity provision&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whether you're building a DEX aggregator, yield farming protocol, or simple token swap interface, Uniswap V2's battle-tested infrastructure provides the foundation for reliable decentralized trading.&lt;/p&gt;

&lt;p&gt;Remember to always test your implementations thoroughly on testnets before deploying to mainnet, and consider the gas costs and user experience implications of your design choices.&lt;/p&gt;

</description>
      <category>uniswapv2</category>
      <category>web3</category>
      <category>blockchain</category>
      <category>solidity</category>
    </item>
    <item>
      <title>Freelancing in Web3</title>
      <dc:creator>Aditya41205</dc:creator>
      <pubDate>Mon, 16 Jun 2025 05:53:48 +0000</pubDate>
      <link>https://dev.to/aditya-alchemist/freelancing-in-web3-31p5</link>
      <guid>https://dev.to/aditya-alchemist/freelancing-in-web3-31p5</guid>
      <description>&lt;h2&gt;
  
  
  How I Got Paid to Freelance in Web3 — Without Selling My Soul
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Freelancing in Web3&lt;/strong&gt; sounds like a dream: paid in crypto, working async, and building on bleeding-edge tech. But the reality? It’s chaotic, fast-paced, and full of noise.&lt;/p&gt;

&lt;p&gt;Here’s what I learned from landing and completing my first serious freelance project in the space — no hype, just signal.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Why Web3 Freelancing Is Different
&lt;/h2&gt;

&lt;p&gt;In Web2, freelancing is mostly about shipping interfaces. In Web3, you're often shipping protocol logic, smart contracts, and dApps — things that directly move value and can't afford to break.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You're not just a developer — you're an engineer with a kill switch.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clients are more careful (or should be).&lt;/li&gt;
&lt;li&gt;Security matters more than speed.&lt;/li&gt;
&lt;li&gt;Your code can literally be part of a live economy.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔍 How I Landed My First Gig
&lt;/h2&gt;

&lt;p&gt;I didn’t spam job boards. Here’s what worked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Build in Public&lt;/strong&gt;: I was posting my dev progress — no fluff, just commits and testnet links.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Niche Down&lt;/strong&gt;: I focused hard on smart contracts and dApps, not just “blockchain dev”.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DM-Ready Profile&lt;/strong&gt;: My pinned post showed what I’d built. No need for fancy portfolios.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Eventually, someone reached out who needed a trustless game mechanic built. Perfect fit.&lt;/p&gt;




&lt;h2&gt;
  
  
  💸 The Deal
&lt;/h2&gt;

&lt;p&gt;Without going into specifics (NDA), here’s how we structured it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fixed Price&lt;/strong&gt; — for scope clarity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crypto Payment&lt;/strong&gt; — stablecoins. Fast, no middlemen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart Contract Audit Light&lt;/strong&gt; — I did my own internal review before handing it over.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Long Meetings&lt;/strong&gt; — everything async. Purely technical comms.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is how freelancing &lt;em&gt;should&lt;/em&gt; be.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 Lessons Learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Don’t Work Without a Wallet Address&lt;/strong&gt;&lt;br&gt;
Get 50% up front or agree to escrow. Trustless doesn’t mean naive.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Contracts Are Law&lt;/strong&gt;&lt;br&gt;
Code is literally law in Web3. One bug = client loses funds = your fault. Test, then test again.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clarity &amp;gt; Everything&lt;/strong&gt;&lt;br&gt;
Scope creep kills Web3 projects. Define &lt;em&gt;exactly&lt;/em&gt; what you’re building, down to the contract methods.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Post-Delivery ≠ Ghosting&lt;/strong&gt;&lt;br&gt;
Stick around a few days for bugfixes. It builds reputation.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🛠️ Tech Stack (Generalized)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Solidity / Cairo for contracts&lt;/li&gt;
&lt;li&gt;React + Wagmi / StarkNet.js for frontend&lt;/li&gt;
&lt;li&gt;Testnets + Faucet-fu&lt;/li&gt;
&lt;li&gt;Hardhat / Foundry / Protostar for dev workflow&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧭 Where I'm Headed Next
&lt;/h2&gt;

&lt;p&gt;Freelancing in Web3 is viable — but only if you're selective. I’m now focusing more on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building my own zk-integrated dApps&lt;/li&gt;
&lt;li&gt;Taking on fewer, higher-impact contracts&lt;/li&gt;
&lt;li&gt;Contributing to open source where possible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re looking to start freelancing in Web3, here's my advice:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build something weird and real. Show it. Stay curious. Be trustworthy.&lt;/strong&gt; The work will find you.&lt;/p&gt;




&lt;h2&gt;
  
  
  💬 DM-Friendly
&lt;/h2&gt;

&lt;p&gt;I'm open to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Collaborating on side projects&lt;/li&gt;
&lt;li&gt;Giving advice to new devs entering Web3&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to reach out.&lt;/p&gt;

</description>
      <category>freelance</category>
      <category>blockchain</category>
      <category>gigs</category>
      <category>web3</category>
    </item>
    <item>
      <title>🧠 Deep Dive Into DAOs: The Next Evolution of Human Coordination</title>
      <dc:creator>Aditya41205</dc:creator>
      <pubDate>Tue, 10 Jun 2025 16:12:42 +0000</pubDate>
      <link>https://dev.to/aditya-alchemist/deep-dive-into-daos-the-next-evolution-of-human-coordination-38k2</link>
      <guid>https://dev.to/aditya-alchemist/deep-dive-into-daos-the-next-evolution-of-human-coordination-38k2</guid>
      <description>&lt;p&gt;In 2015, Ethereum launched with a vision: to be the "world computer" — a decentralized platform where anyone can deploy code that no single party controls. Out of that vision emerged one of the most powerful constructs in the crypto ecosystem: &lt;strong&gt;DAOs&lt;/strong&gt;, or &lt;strong&gt;Decentralized Autonomous Organizations&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;More than just buzzwords, DAOs are reshaping how we collaborate, govern, and build shared value. Let’s explore what DAOs are, how they work, real-world examples, their underlying tech, challenges, and the immense potential they hold.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏠 What Is a DAO?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;DAO&lt;/strong&gt; is a digital, community-led organization governed by rules encoded as smart contracts. Unlike traditional companies that rely on CEOs, boards, and middle managers, DAOs operate without centralized leadership.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Traits of a DAO:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decentralized&lt;/strong&gt;: No single entity controls the organization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autonomous&lt;/strong&gt;: Rules and operations are automated through smart contracts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transparent&lt;/strong&gt;: All actions (votes, transactions) are recorded on-chain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token-governed&lt;/strong&gt;: Governance tokens give members voting power.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;In essence: DAOs are like cooperatives built in code — trustless, borderless, and self-executing.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🛠️ How DAOs Work
&lt;/h2&gt;

&lt;p&gt;The architecture of a DAO is typically composed of:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Smart Contracts&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;These enforce rules, manage funds, execute votes, and perform tasks autonomously. On Ethereum, Solidity is most common. On StarkNet, DAOs may be built using &lt;strong&gt;Cairo&lt;/strong&gt;, leveraging zk-rollups for scalability and privacy.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Governance Tokens&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Members receive ERC-20 tokens (like \$UNI or \$COMP) representing voting power. These tokens can be earned, bought, or distributed.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Proposal Mechanism&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Anyone can submit proposals (e.g., to fund a project, change rules). Each proposal has a voting period and quorum requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Voting Systems&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1 Token = 1 Vote&lt;/strong&gt; (common, but plutocratic)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quadratic Voting&lt;/strong&gt; (weights small holders more fairly)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delegated Voting&lt;/strong&gt; (token holders delegate votes to active participants)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;Treasury Management&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;DAO treasuries hold crypto assets and disburse funds via proposals. Tools like &lt;strong&gt;Gnosis Safe&lt;/strong&gt; or on-chain escrow contracts are common.&lt;/p&gt;




&lt;h2&gt;
  
  
  🌐 Why DAOs Matter
&lt;/h2&gt;

&lt;p&gt;DAOs aren't just a new governance model — they offer a &lt;strong&gt;paradigm shift&lt;/strong&gt; in how people organize, build, and make decisions together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Trustless Coordination&lt;/strong&gt;: Replace backroom deals with open, transparent processes.&lt;/li&gt;
&lt;li&gt;🌍 &lt;strong&gt;Global &amp;amp; Permissionless&lt;/strong&gt;: Anyone with an internet connection can contribute.&lt;/li&gt;
&lt;li&gt;☁️ &lt;strong&gt;Composability&lt;/strong&gt;: DAOs can integrate directly with DeFi, NFTs, identity layers, and more.&lt;/li&gt;
&lt;li&gt;🩏 &lt;strong&gt;Incentive Alignment&lt;/strong&gt;: Tokenomics ensure that contributors benefit when the DAO succeeds.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 Real-World DAOs in Action
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Uniswap DAO&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Controls the Uniswap protocol and its \$3B treasury. Holders of \$UNI propose and vote on changes like fee toggles, new features, and grants.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;MakerDAO&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Manages DAI, the most used decentralized stablecoin. Votes on risk parameters, collateral assets, and protocol changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Gitcoin DAO&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Coordinates funding for open-source public goods. Uses &lt;strong&gt;quadratic funding&lt;/strong&gt; to maximize impact.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;ENS DAO&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Governs the Ethereum Name Service, which maps readable names like &lt;code&gt;vitalik.eth&lt;/code&gt; to wallet addresses.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;Nouns DAO&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A cultural experiment where 1 NFT = 1 vote. Funds public goods, art, and open web initiatives.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Tech Stack Behind DAOs
&lt;/h2&gt;

&lt;p&gt;DAOs leverage an ecosystem of decentralized infrastructure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smart Contracts&lt;/strong&gt;: Solidity, Cairo, Move&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontends&lt;/strong&gt;: React + ethers.js / starknet.js&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Governance Platforms&lt;/strong&gt;: Snapshot, Tally, Agora, JokeRace&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treasury Tools&lt;/strong&gt;: Gnosis Safe, Zodiac Modules&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identity/Delegation&lt;/strong&gt;: ENS, Gitcoin Passport, EAS (Ethereum Attestation Service)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On &lt;strong&gt;StarkNet&lt;/strong&gt;, Cairo-based DAOs may use zk-based voting or rollup-native execution logic to improve scalability and reduce costs.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚡ DAO Challenges
&lt;/h2&gt;

&lt;p&gt;Despite their promise, DAOs face several issues:&lt;/p&gt;

&lt;h3&gt;
  
  
  ❌ Voter Apathy
&lt;/h3&gt;

&lt;p&gt;Most token holders don’t vote. Low participation can lead to governance capture by whales or insiders.&lt;/p&gt;

&lt;h3&gt;
  
  
  📅 Governance Gridlock
&lt;/h3&gt;

&lt;p&gt;Without strong leadership, decision-making can stall. DAOs need clear processes and proposal templates.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚪 Legal Uncertainty
&lt;/h3&gt;

&lt;p&gt;DAOs exist in a regulatory gray zone. Some states (like Wyoming) recognize them legally; most don’t.&lt;/p&gt;

&lt;h3&gt;
  
  
  🪨 Security Risks
&lt;/h3&gt;

&lt;p&gt;Bugs in contracts or governance logic (see: The DAO hack of 2016) can cause catastrophic losses.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔁 Forkability
&lt;/h3&gt;

&lt;p&gt;Because DAOs are open-source and on-chain, factions can fork away (e.g., Sushi from Uniswap). This can fragment communities.&lt;/p&gt;




&lt;h2&gt;
  
  
  🌧️ The Future of DAOs
&lt;/h2&gt;

&lt;p&gt;We are still in the early days of DAO design. But exciting trends are emerging:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ZK Governance&lt;/strong&gt;: Voting with privacy using zero-knowledge proofs (StarkNet, Semaphore)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reputation-based Voting&lt;/strong&gt;: Weigh votes by merit, not wealth (e.g., soulbound tokens)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-chain DAOs&lt;/strong&gt;: Operating across multiple chains via bridges or Layer 0s&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI x DAOs&lt;/strong&gt;: Using agents to draft proposals, summarize debates, or manage operations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DAO2DAO Coordination&lt;/strong&gt;: DAOs collaborating like nations or companies do&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💼 Should You Join or Build a DAO?
&lt;/h2&gt;

&lt;p&gt;Yes — if you want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contribute meaningfully to a mission you care about&lt;/li&gt;
&lt;li&gt;Learn how decentralized coordination works&lt;/li&gt;
&lt;li&gt;Help build better governance systems&lt;/li&gt;
&lt;li&gt;Experiment with incentive design, tokenomics, and power distribution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don’t need permission. You just need initiative.&lt;/p&gt;




&lt;h2&gt;
  
  
  📄 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;DAOs are not just tools — they’re social revolutions encoded into smart contracts. They challenge our assumptions about leadership, ownership, and accountability.&lt;/p&gt;

&lt;p&gt;While imperfect today, they are evolving fast. The next wave of DAOs may govern not just crypto protocols, but universities, art collectives, cities, and even nation-states.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The future won’t be built by CEOs in boardrooms. It will be coded by communities on-chain.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you're curious, start by joining a DAO, voting on a proposal, or contributing to one. If you're bold, build one yourself.&lt;/p&gt;

&lt;p&gt;The era of decentralized organizations has just begun.&lt;/p&gt;




</description>
    </item>
    <item>
      <title>L2 &lt;-&gt; L1 Tokens Bridging</title>
      <dc:creator>Aditya41205</dc:creator>
      <pubDate>Sat, 24 May 2025 17:14:06 +0000</pubDate>
      <link>https://dev.to/aditya-alchemist/l2-l1-tokens-bridging-4bfp</link>
      <guid>https://dev.to/aditya-alchemist/l2-l1-tokens-bridging-4bfp</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4gaigal8jyb5myu6r492.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4gaigal8jyb5myu6r492.png" alt="Mint/lock burn bridge" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Complete Guide to Token Bridging: L1 ↔ L2
&lt;/h1&gt;

&lt;h2&gt;
  
  
  What is Bridging?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bridging&lt;/strong&gt; is the process of moving tokens or assets between different blockchain networks. In the context of Ethereum and Starknet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;L1 (Layer 1)&lt;/strong&gt;: Ethereum mainnet - the main blockchain&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L2 (Layer 2)&lt;/strong&gt;: Starknet - a scaling solution built on top of Ethereum&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why Do We Need Bridging?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: L2 networks like Starknet offer faster and cheaper transactions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interoperability&lt;/strong&gt;: Users want to move assets between different networks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ecosystem Access&lt;/strong&gt;: Different DeFi applications exist on different layers&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  How Bridging Works
&lt;/h3&gt;

&lt;p&gt;Bridging doesn't actually "move" tokens between chains. Instead, it uses a &lt;strong&gt;lock-and-mint&lt;/strong&gt; mechanism:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;L1 → L2 (Deposit)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lock/burn tokens on L1&lt;/li&gt;
&lt;li&gt;Send a message to L2&lt;/li&gt;
&lt;li&gt;Mint equivalent tokens on L2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;L2 → L1 (Withdrawal)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Burn tokens on L2&lt;/li&gt;
&lt;li&gt;Send a message to L1&lt;/li&gt;
&lt;li&gt;Unlock/mint tokens on L1&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────┐    Message     ┌─────────────────┐
│   Ethereum L1   │ ◄────────────► │   Starknet L2   │
│                 │                │                 │
│ TokenBridge.sol │                │ TokenBridge.cairo│
│ MintableToken   │                │ MintableToken   │
└─────────────────┘                └─────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key Components
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Token Contracts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;L1 Token&lt;/strong&gt;: ERC20-like contract on Ethereum that can mint/burn&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L2 Token&lt;/strong&gt;: Starknet contract that can mint/burn&lt;/li&gt;
&lt;li&gt;Both represent the same asset on different layers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Bridge Contracts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;L1 Bridge&lt;/strong&gt;: Ethereum contract that handles L1 operations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L2 Bridge&lt;/strong&gt;: Starknet contract that handles L2 operations&lt;/li&gt;
&lt;li&gt;Both communicate via cross-chain messaging&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Messaging System
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;L1 → L2&lt;/strong&gt;: Uses Starknet's &lt;code&gt;sendMessageToL2&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L2 → L1&lt;/strong&gt;: Uses Starknet's &lt;code&gt;send_message_to_l1_syscall&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation Deep Dive
&lt;/h2&gt;

&lt;h3&gt;
  
  
  L2 (Starknet) Implementation
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Token Interface
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#[starknet::interface]
pub trait IMintableToken&amp;lt;TContractState&amp;gt; {
    fn mint(ref self: TContractState, account: ContractAddress, amount: u256);
    fn burn(ref self: TContractState, account: ContractAddress, amount: u256);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Bridge Interface
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#[starknet::interface]
pub trait ITokenBridge&amp;lt;TContractState&amp;gt; {
    fn bridge_to_l1(ref self: TContractState, l1_recipient: EthAddress, amount: u256);
    fn set_l1_bridge(ref self: TContractState, l1_bridge_address: EthAddress);
    fn set_token(ref self: TContractState, l2_token_address: ContractAddress);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Key Functions
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Bridging to L1 (Withdrawal)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fn bridge_to_l1(ref self: ContractState, l1_recipient: EthAddress, amount: u256) {
    // 1. Burn tokens on L2
    IMintableTokenDispatcher { contract_address: self.l2_token.read() }
        .burn(caller_address, amount);

    // 2. Send message to L1
    let mut payload: Array&amp;lt;felt252&amp;gt; = array![
        l1_recipient.into(), amount.low.into(), amount.high.into(),
    ];
    syscalls::send_message_to_l1_syscall(self.l1_bridge.read(), payload.span())
        .unwrap_syscall();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Handling Deposits from L1&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#[l1_handler]
pub fn handle_deposit(
    ref self: ContractState, 
    from_address: felt252, 
    account: ContractAddress, 
    amount: u256,
) {
    // 1. Verify message came from L1 bridge
    assert(from_address == self.l1_bridge.read(), Errors::EXPECTED_FROM_BRIDGE_ONLY);

    // 2. Mint tokens on L2
    IMintableTokenDispatcher { contract_address: self.l2_token.read() }
        .mint(account, amount);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  L1 (Ethereum) Implementation
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Key Functions
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Bridging to L2 (Deposit)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function bridgeToL2(uint256 recipientAddress, uint256 amount) external payable {
    // 1. Burn tokens on L1
    token.burn(msg.sender, amount);

    // 2. Split uint256 for Cairo compatibility
    (uint128 low, uint128 high) = splitUint256(amount);
    uint256[] memory payload = new uint256[](3);
    payload[0] = recipientAddress;
    payload[1] = low;
    payload[2] = high;

    // 3. Send message to L2
    snMessaging.sendMessageToL2{value: msg.value}(
        l2Bridge,
        l2HandlerSelector,
        payload
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Consuming Withdrawals from L2&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function consumeWithdrawal(
    uint256 fromAddress,
    address recipient,
    uint128 low,
    uint128 high
) external {
    // 1. Recreate payload
    uint256[] memory payload = new uint256[](3);
    payload[0] = uint256(uint160(recipient));
    payload[1] = uint256(low);
    payload[2] = uint256(high);

    // 2. Consume message from L2
    snMessaging.consumeMessageFromL2(fromAddress, payload);

    // 3. Mint tokens on L1
    uint256 amount = (uint256(high) &amp;lt;&amp;lt; 128) | uint256(low);
    token.mint(recipient, amount);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Data Serialization
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Split uint256?
&lt;/h3&gt;

&lt;p&gt;Cairo uses &lt;code&gt;felt252&lt;/code&gt; (252-bit field elements), while Solidity uses &lt;code&gt;uint256&lt;/code&gt;. To bridge a &lt;code&gt;uint256&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function splitUint256(uint256 value) private pure returns (uint128 low, uint128 high) {
    low = uint128(value &amp;amp; 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
    high = uint128(value &amp;gt;&amp;gt; 128);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Starknet side:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Received as amount.low and amount.high
// Automatically reconstructed as u256
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Transaction Flow Examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Depositing (L1 → L2)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;User calls&lt;/strong&gt; &lt;code&gt;bridgeToL2(starknet_address, 100)&lt;/code&gt; on L1&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L1 Bridge&lt;/strong&gt; burns 100 tokens from user&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L1 Bridge&lt;/strong&gt; sends message to L2: &lt;code&gt;[starknet_address, 100_low, 100_high]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Starknet Sequencer&lt;/strong&gt; automatically calls &lt;code&gt;handle_deposit&lt;/code&gt; on L2&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L2 Bridge&lt;/strong&gt; mints 100 tokens to user's Starknet address&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Withdrawing (L2 → L1)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;User calls&lt;/strong&gt; &lt;code&gt;bridge_to_l1(ethereum_address, 50)&lt;/code&gt; on L2&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L2 Bridge&lt;/strong&gt; burns 50 tokens from user&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L2 Bridge&lt;/strong&gt; sends message to L1: &lt;code&gt;[ethereum_address, 50_low, 50_high]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User manually calls&lt;/strong&gt; &lt;code&gt;consumeWithdrawal(l2_bridge, ethereum_address, 50_low, 50_high)&lt;/code&gt; on L1&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L1 Bridge&lt;/strong&gt; mints 50 tokens to user's Ethereum address&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Security Considerations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Access Control
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Only bridge contracts can mint/burn tokens&lt;/li&gt;
&lt;li&gt;Only governors can update bridge addresses&lt;/li&gt;
&lt;li&gt;Validate all message sources&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Message Validation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Always verify message source
assert(from_address == self.l1_bridge.read(), Errors::EXPECTED_FROM_BRIDGE_ONLY);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Amount Validation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Prevent zero amounts
assert(amount.is_non_zero(), Errors::INVALID_AMOUNT);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Timing and Gas Costs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  L1 → L2 (Deposits)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Time&lt;/strong&gt;: ~10-20 minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost&lt;/strong&gt;: Ethereum gas + L2 message fee&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic&lt;/strong&gt;: Sequencer calls L1 handler automatically&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  L2 → L1 (Withdrawals)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Time&lt;/strong&gt;: ~2-8 hours (state proof generation)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost&lt;/strong&gt;: L2 gas + Ethereum gas for consumption&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual&lt;/strong&gt;: User must call &lt;code&gt;consumeWithdrawal&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testing Strategy
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Unit Tests
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Test token minting/burning&lt;/li&gt;
&lt;li&gt;Test message payload construction&lt;/li&gt;
&lt;li&gt;Test access control&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Integration Tests
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Test full deposit flow&lt;/li&gt;
&lt;li&gt;Test full withdrawal flow&lt;/li&gt;
&lt;li&gt;Test edge cases and failures&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Mock Contracts
&lt;/h3&gt;

&lt;p&gt;Use simple mock tokens that emit events instead of managing balances:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fn mint(ref self: ContractState, account: ContractAddress, amount: u256) {
    self.emit(Minted { account, amount });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Pitfalls
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Wrong Selector&lt;/strong&gt;: L2 handler selector must match exactly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Serialization&lt;/strong&gt;: uint256 must be split for Cairo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Message Source&lt;/strong&gt;: Always validate message sender&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timing&lt;/strong&gt;: L2→L1 messages need manual consumption&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gas Estimation&lt;/strong&gt;: L1→L2 requires payment for L2 execution&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use Events&lt;/strong&gt;: Emit detailed events for off-chain tracking&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate Inputs&lt;/strong&gt;: Check addresses and amounts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access Control&lt;/strong&gt;: Implement proper governance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Handling&lt;/strong&gt;: Provide clear error messages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation&lt;/strong&gt;: Document selector calculations and message formats&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This architecture provides a secure, efficient way to bridge tokens between Ethereum and Starknet, enabling users to access applications on both layers while maintaining asset security.&lt;/p&gt;

</description>
      <category>bridging</category>
      <category>solidity</category>
      <category>starknet</category>
      <category>ethereum</category>
    </item>
    <item>
      <title>Building a Merkle Tree Airdrop System on Starknet: A Complete Guide</title>
      <dc:creator>Aditya41205</dc:creator>
      <pubDate>Fri, 23 May 2025 19:33:18 +0000</pubDate>
      <link>https://dev.to/aditya-alchemist/building-a-merkle-tree-airdrop-system-on-starknet-a-complete-guide-5ga4</link>
      <guid>https://dev.to/aditya-alchemist/building-a-merkle-tree-airdrop-system-on-starknet-a-complete-guide-5ga4</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F90sd4m6bfy2lxc2r5eyt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F90sd4m6bfy2lxc2r5eyt.png" alt="Image description" width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Building a Merkle Tree Airdrop System on Starknet: A Complete Guide
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Learn how to create an efficient, gas-optimized airdrop system using Merkle trees with JavaScript and Cairo smart contracts&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Airdrops have become a cornerstone of Web3 projects for distributing tokens to communities. However, traditional airdrop mechanisms can be extremely gas-intensive when dealing with thousands of recipients. Enter &lt;strong&gt;Merkle trees&lt;/strong&gt; – a cryptographic data structure that allows us to verify membership in a large dataset with minimal on-chain storage and computation.&lt;/p&gt;

&lt;p&gt;In this comprehensive guide, we'll build a complete Merkle tree-based airdrop system on Starknet, covering everything from generating proofs off-chain to verifying them on-chain with Cairo smart contracts.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are Merkle Trees and Why Use Them?
&lt;/h2&gt;

&lt;p&gt;A Merkle tree is a binary tree where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each leaf represents a data element (in our case, an airdrop recipient)&lt;/li&gt;
&lt;li&gt;Each internal node contains the hash of its children&lt;/li&gt;
&lt;li&gt;The root represents the entire dataset&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Benefits for airdrops:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Gas Efficiency&lt;/strong&gt;: Store only the root hash on-chain instead of all recipient data&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Scalability&lt;/strong&gt;: Handle millions of recipients with minimal on-chain footprint&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Privacy&lt;/strong&gt;: Recipients' data isn't publicly visible until they claim&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Flexibility&lt;/strong&gt;: Easy to update or modify recipient lists&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Project Architecture
&lt;/h2&gt;

&lt;p&gt;Our system consists of three main components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript Generator&lt;/strong&gt;: Creates Merkle trees and generates proofs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cairo Smart Contract&lt;/strong&gt;: Verifies proofs and handles claims on-chain&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration Layer&lt;/strong&gt;: Connects off-chain computation with on-chain verification&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setting Up the Development Environment
&lt;/h2&gt;

&lt;p&gt;First, let's set up our project structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;starknet-merkle-airdrop
&lt;span class="nb"&gt;cd &lt;/span&gt;starknet-merkle-airdrop
npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;starknet-merkle-tree starknet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update your &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"generate-tree"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node generate-tree.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test-verification"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node test-verification.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"starknet-merkle-tree"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"starknet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^6.0.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Building the Off-Chain Merkle Tree Generator
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;generate-tree.js&lt;/code&gt; to handle tree generation and proof creation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Merkle&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;starknet-merkle-tree&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Define airdrop recipients with their allocation data&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;airdropData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// 1 ETH&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x53c615080d35defd55569488bc48c1a91d82f2d2ce6199463e095b4a4ead551&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2000000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// 2 ETH&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;500000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  &lt;span class="c1"&gt;// 0.5 ETH&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0x5678901234567890abcdef1234567890abcdef1234567890abcdef1234567890&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;750000000000000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="c1"&gt;// 0.75 ETH&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;🌳 Generating Merkle tree...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Create tree using Poseidon hash (optimized for Starknet)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Merkle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StarknetMerkleTree&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;airdropData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Merkle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HashType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Poseidon&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`✅ Tree created with &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;airdropData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; leaves`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`📋 Merkle Root: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Generate and store proofs for all recipients&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;proofs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;claims&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;verify_proof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;TContractState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;leaf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;felt252&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;verify_claim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;TContractState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ContractAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;u256&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;additional_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;felt252&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;get_merkle_root&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;TContractState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;felt252&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;set_merkle_root&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TContractState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;new_root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;felt252&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;starknet&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nx"&gt;mod&lt;/span&gt; &lt;span class="nx"&gt;MerkleVerifier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;use&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;IMerkleVerifier&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;starknet&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nx"&gt;ContractAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;get_caller_address&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nx"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;poseidon&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;poseidon_hash_span&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;ArrayTrait&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;starknet&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nx"&gt;StoragePointerReadAccess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StoragePointerWriteAccess&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;struct&lt;/span&gt; &lt;span class="nx"&gt;Storage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;merkle_root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;felt252&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ContractAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;derive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Drop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;starknet&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;Event&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;ProofVerified&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ProofVerified&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;RootUpdated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RootUpdated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;derive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Drop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;starknet&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="nx"&gt;struct&lt;/span&gt; &lt;span class="nx"&gt;ProofVerified&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="nx"&gt;leaf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;felt252&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;verified&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;derive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Drop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;starknet&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="nx"&gt;struct&lt;/span&gt; &lt;span class="nx"&gt;RootUpdated&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;old_root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;felt252&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;new_root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;felt252&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ContractState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ContractAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;merkle_root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;felt252&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;merkle_root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;merkle_root&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;embed_v0&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="nx"&gt;impl&lt;/span&gt; &lt;span class="nx"&gt;MerkleVerifierImpl&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;IMerkleVerifier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;verify_proof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ContractState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;leaf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;felt252&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;merkle_root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_verify_merkle_proof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;span&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;leaf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;verify_claim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ContractState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ContractAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;u256&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;additional_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;felt252&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;leaf_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_compute_leaf_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;additional_data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify_proof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;leaf_hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;get_merkle_root&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ContractState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;felt252&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;merkle_root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;set_merkle_root&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ContractState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;new_root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;felt252&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;caller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_caller_address&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;caller&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Only owner can update root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;old_root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;merkle_root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;merkle_root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;new_root&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;RootUpdated&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;old_root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;new_root&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;generate_trait&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;impl&lt;/span&gt; &lt;span class="nx"&gt;InternalImpl&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;InternalTrait&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;_verify_merkle_proof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ContractState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;leaf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;felt252&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;felt252&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;mut&lt;/span&gt; &lt;span class="nx"&gt;computed_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;leaf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;mut&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;  &lt;span class="nx"&gt;felt252&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Hash format: [address, amount_low, amount_high, additional_data]&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;mut&lt;/span&gt; &lt;span class="nx"&gt;hash_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ArrayTrait&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nx"&gt;hash_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;into&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
            &lt;span class="nx"&gt;hash_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;low&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;into&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
            &lt;span class="nx"&gt;hash_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;high&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;into&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
            &lt;span class="nx"&gt;hash_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;additional_data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="nf"&gt;poseidon_hash_span&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hash_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;span&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;_is_left_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ContractState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;felt252&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;felt252&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;a_u256&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;u256&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;into&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;b_u256&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;u256&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;into&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nx"&gt;a_u256&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;b_u256&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing the Integration
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;test-verification.js&lt;/code&gt; to test our complete system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Contract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RpcProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;starknet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;testMerkleVerification&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Load generated data&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;proofs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./proofs.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;treeData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./merkle_tree.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🧪 Testing Merkle verification...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`📋 Root: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;treeData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Test data&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testProof&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;proofs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;testAddress&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;testProof&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;❌ No proof found for test address&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`🎯 Testing address: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;testAddress&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`💰 Amount: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;testProof&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`🔐 Proof: [&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;testProof&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;]`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Here you would call your deployed contract&lt;/span&gt;
    &lt;span class="c1"&gt;// const result = await contract.verify_claim(&lt;/span&gt;
    &lt;span class="c1"&gt;//     testProof.proof,&lt;/span&gt;
    &lt;span class="c1"&gt;//     testAddress,&lt;/span&gt;
    &lt;span class="c1"&gt;//     { low: testProof.amount, high: "0x0" },&lt;/span&gt;
    &lt;span class="c1"&gt;//     testProof.additionalData&lt;/span&gt;
    &lt;span class="c1"&gt;// );&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;✅ Test data prepared for contract verification&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;testMerkleVerification&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deployment and Usage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Generate Your Merkle Tree
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run generate-tree
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Deploy the Contract
&lt;/h3&gt;

&lt;p&gt;Use the generated root hash when deploying your Cairo contract.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Verify Claims
&lt;/h3&gt;

&lt;p&gt;Users can now claim their airdrops by providing their proof, which the contract will verify against the stored root.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features and Benefits
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🚀 &lt;strong&gt;Gas Efficiency&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Only stores a single 32-byte root hash on-chain&lt;/li&gt;
&lt;li&gt;Verification requires minimal computation&lt;/li&gt;
&lt;li&gt;Scales to millions of recipients without increasing gas costs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔒 &lt;strong&gt;Security&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Cryptographically secure proof system&lt;/li&gt;
&lt;li&gt;Impossible to forge valid proofs without the original data&lt;/li&gt;
&lt;li&gt;Owner-controlled root updates for flexibility&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🎯 &lt;strong&gt;User Experience&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Recipients only need their proof to claim&lt;/li&gt;
&lt;li&gt;No need to submit all recipient data on-chain&lt;/li&gt;
&lt;li&gt;Fast verification process&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real-World Applications
&lt;/h2&gt;

&lt;p&gt;This Merkle tree system can be used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Token Airdrops&lt;/strong&gt;: Distribute governance or utility tokens&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NFT Allowlists&lt;/strong&gt;: Manage whitelist access for minting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reward Systems&lt;/strong&gt;: Distribute rewards based on participation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access Control&lt;/strong&gt;: Gate access to exclusive features or content&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Optimization Tips
&lt;/h2&gt;

&lt;h3&gt;
  
  
  For Large Datasets
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use batch processing for tree generation&lt;/li&gt;
&lt;li&gt;Implement pagination for proof distribution&lt;/li&gt;
&lt;li&gt;Consider using IPFS for storing large proof sets&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  For Gas Optimization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use Poseidon hashing (optimized for Starknet)&lt;/li&gt;
&lt;li&gt;Minimize proof verification loops&lt;/li&gt;
&lt;li&gt;Batch multiple claims when possible&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Merkle trees provide an elegant solution for scalable, gas-efficient airdrops on Starknet. By combining off-chain computation with on-chain verification, we can handle massive recipient lists while maintaining security and minimizing costs.&lt;/p&gt;

&lt;p&gt;The system we've built demonstrates the power of cryptographic data structures in solving real-world blockchain challenges. Whether you're launching a new token or rewarding your community, this Merkle tree implementation provides a robust foundation for your airdrop needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;Consider extending this system with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-token support&lt;/strong&gt; for complex airdrop scenarios&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time-based claiming&lt;/strong&gt; with expiration dates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delegation mechanisms&lt;/strong&gt; for third-party claiming&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration with frontend dApps&lt;/strong&gt; for seamless user experience&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>starknet</category>
      <category>merkle</category>
      <category>merkletrees</category>
      <category>cairo</category>
    </item>
    <item>
      <title>🚀 Building and Interacting with a StarkNet Contract using React and StarkNet.js</title>
      <dc:creator>Aditya41205</dc:creator>
      <pubDate>Sun, 18 May 2025 18:35:36 +0000</pubDate>
      <link>https://dev.to/aditya-alchemist/building-and-interacting-with-a-starknet-contract-using-react-and-starknetjs-3lfa</link>
      <guid>https://dev.to/aditya-alchemist/building-and-interacting-with-a-starknet-contract-using-react-and-starknetjs-3lfa</guid>
      <description>&lt;h2&gt;
  
  
  🧠 Introduction
&lt;/h2&gt;

&lt;p&gt;As blockchain scalability becomes increasingly important, Layer 2 solutions are gaining momentum. Among them, &lt;strong&gt;StarkNet&lt;/strong&gt; stands out due to its use of zero-knowledge proofs (ZK-STARKs) to enable scalable and secure computations. However, StarkNet development involves a unique stack — from Cairo smart contracts to frontend integration via StarkNet.js.&lt;/p&gt;

&lt;p&gt;In this article, you'll learn how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write a &lt;strong&gt;Cairo 1.0 smart contract&lt;/strong&gt; with access control.&lt;/li&gt;
&lt;li&gt;Deploy it on the &lt;strong&gt;StarkNet testnet&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Build a frontend using &lt;strong&gt;React&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Connect it to wallets like &lt;strong&gt;Argent X&lt;/strong&gt; or &lt;strong&gt;Braavos&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Interact with the contract using &lt;strong&gt;StarkNet.js&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧱 Writing the Cairo Smart Contract
&lt;/h2&gt;

&lt;p&gt;Let’s start with a simple secure counter contract.&lt;/p&gt;

&lt;p&gt;Only the &lt;strong&gt;contract owner&lt;/strong&gt; can increment the counter, while anyone can view it.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧾 Contract Code (Cairo 1.0)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[starknet::interface]&lt;/span&gt;
&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;ICounterContract&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TContractState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;get_counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;TContractState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;increase_counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TContractState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[starknet::contract]&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;starknet&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;StoragePointerReadAccess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StoragePointerWriteAccess&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;starknet&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;get_caller_address&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;starknet&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ContractAddress&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;#[storage]&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Storage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ContractAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;#[constructor]&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ContractState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ContractAddress&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.counter&lt;/span&gt;&lt;span class="nf"&gt;.write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.owner&lt;/span&gt;&lt;span class="nf"&gt;.write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;#[abi(embed_v0)]&lt;/span&gt;
    &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;abc&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ICounterContract&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ContractState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;get_counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;ContractState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.counter&lt;/span&gt;&lt;span class="nf"&gt;.read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;increase_counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ContractState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;caller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_caller_address&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.owner&lt;/span&gt;&lt;span class="nf"&gt;.read&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;caller&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;'Owner&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="n"&gt;only&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.counter&lt;/span&gt;&lt;span class="nf"&gt;.read&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.counter&lt;/span&gt;&lt;span class="nf"&gt;.write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔍 Key Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Access Control&lt;/strong&gt;: &lt;code&gt;increase_counter&lt;/code&gt; is restricted to the owner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;View Function&lt;/strong&gt;: &lt;code&gt;get_counter&lt;/code&gt; is publicly accessible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constructor&lt;/strong&gt;: Initializes counter value and sets the contract owner.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can compile this with &lt;strong&gt;Scarb&lt;/strong&gt;, and deploy using tools like &lt;strong&gt;starkli&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🌐 Building the React Frontend
&lt;/h2&gt;

&lt;p&gt;Now, let’s build a minimal React frontend to interact with the smart contract.&lt;/p&gt;

&lt;h3&gt;
  
  
  🛠 Tools Used
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React&lt;/strong&gt; for UI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;StarkNet.js&lt;/strong&gt; for smart contract interactions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RpcProvider&lt;/strong&gt; to read blockchain state&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;window.starknet&lt;/strong&gt; to connect wallet extensions like Argent X or Braavos&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  📁 1. Setting Up the Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app starknet-dapp
&lt;span class="nb"&gt;cd &lt;/span&gt;starknet-dapp
npm &lt;span class="nb"&gt;install &lt;/span&gt;starknet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🧩 2. Complete React Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RpcProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Contract&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;starknet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CONTRACT_ADDRESS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0xYOUR_CONTRACT_ADDRESS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Replace with actual deployed address&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ABI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="cm"&gt;/* ABI JSON here */&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RpcProvider&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;nodeUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_8/YOUR_API_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;walletConnected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setWalletConnected&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCounter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setContract&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUserAddress&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;connectWallet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;starknet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Install Argent X or Braavos&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;starknet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;starknet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ctr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Contract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ABI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CONTRACT_ADDRESS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setContract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setWalletConnected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setUserAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Wallet connection failed:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchCounter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;readContract&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Contract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ABI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CONTRACT_ADDRESS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rpc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;readContract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_counter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nf"&gt;setCounter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Failed to fetch counter:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;increaseCounter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increase_counter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;rpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transaction_hash&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;fetchCounter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Transaction failed:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;StarkNet Counter&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;walletConnected&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;connectWallet&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Connect Wallet&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Connected: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userAddress&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;fetchCounter&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Get Counter&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Counter: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Not fetched&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;increaseCounter&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Increase Counter&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔄 Interaction Flow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Connect Wallet&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Uses &lt;code&gt;window.starknet.enable()&lt;/code&gt; to initiate connection.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Read Counter&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Uses &lt;code&gt;RpcProvider&lt;/code&gt; and a read-only &lt;code&gt;Contract&lt;/code&gt; instance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Write to Counter&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Uses &lt;code&gt;Contract&lt;/code&gt; with the connected wallet account to call &lt;code&gt;increase_counter()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✅ Deployment &amp;amp; Testing
&lt;/h2&gt;

&lt;p&gt;Once your contract is deployed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;Voyager&lt;/strong&gt; to inspect it.&lt;/li&gt;
&lt;li&gt;Interact using your React dApp.&lt;/li&gt;
&lt;li&gt;Refer to &lt;strong&gt;StarkNet.js&lt;/strong&gt; docs for more interaction patterns.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;starkli&lt;/strong&gt; for testing locally.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧠 Learnings and Best Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Split Read/Write Logic&lt;/strong&gt;: Use &lt;code&gt;RpcProvider&lt;/code&gt; for reads, and wallet &lt;code&gt;account&lt;/code&gt; for writes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Clean ABIs&lt;/strong&gt;: Flatten or manually simplify ABI if needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wallet Support&lt;/strong&gt;: Ensure compatibility with Argent X &amp;amp; Braavos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handle Errors&lt;/strong&gt;: Wrap all async calls with &lt;code&gt;try/catch&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Interactions:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bpx1fm6p78m638za7as.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bpx1fm6p78m638za7as.png" alt="Wallet connection" width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                   Wallet connection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3o1wcxwimi1xna21w693.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3o1wcxwimi1xna21w693.png" alt="Interface" width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                        Interface
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fez1f7jy7fzwslt7zeeds.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fez1f7jy7fzwslt7zeeds.png" alt="Invoking Read function" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                   Invoking Read function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhyn2y1sxnlmy3m06duwb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhyn2y1sxnlmy3m06duwb.png" alt="Invoking Write function" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                  Invoking Write function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h2&gt;
  
  
  🧾 Conclusion
&lt;/h2&gt;

&lt;p&gt;With the rise of ZK-powered Layer 2s, &lt;strong&gt;StarkNet&lt;/strong&gt; offers a powerful and developer-friendly ecosystem for writing scalable dApps.&lt;/p&gt;

&lt;p&gt;You just:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wrote a secure Cairo contract ✅&lt;/li&gt;
&lt;li&gt;Deployed it on StarkNet testnet ✅&lt;/li&gt;
&lt;li&gt;Built a full React frontend ✅&lt;/li&gt;
&lt;li&gt;Integrated wallet connectivity ✅&lt;/li&gt;
&lt;li&gt;Interacted with it using StarkNet.js ✅&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>daaps</category>
      <category>starknet</category>
      <category>zkrollups</category>
      <category>cairo</category>
    </item>
    <item>
      <title>Using OpenZeppelin in StarkNet contracts</title>
      <dc:creator>Aditya41205</dc:creator>
      <pubDate>Sat, 17 May 2025 05:46:52 +0000</pubDate>
      <link>https://dev.to/aditya-alchemist/how-to-use-openzeppelin-contracts-in-starknet-with-cairo-a-practical-example-59fg</link>
      <guid>https://dev.to/aditya-alchemist/how-to-use-openzeppelin-contracts-in-starknet-with-cairo-a-practical-example-59fg</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;StarkNet is rapidly becoming a go-to Layer 2 scaling solution for Ethereum, bringing massive scalability and low fees to decentralized applications. At its core, StarkNet uses Cairo — a powerful new language designed specifically for writing provable, efficient smart contracts.&lt;/p&gt;

&lt;p&gt;But writing smart contracts from scratch is time-consuming and error-prone. That’s where OpenZeppelin comes in. OpenZeppelin is widely trusted for providing battle-tested, reusable contract components on Ethereum. Now, OpenZeppelin is bringing the same security and modularity to StarkNet with a growing set of Cairo contracts.&lt;/p&gt;

&lt;p&gt;In this post, I’ll show you how to build an ERC20 token on StarkNet by leveraging OpenZeppelin’s Cairo components. We’ll walk through an example contract step-by-step, highlighting key StarkNet concepts along the way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Use OpenZeppelin on StarkNet?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;OpenZeppelin contracts help you:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Save Development Time&lt;/strong&gt;: You don’t need to reinvent the wheel or debug low-level logic like token transfers or storage management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Increase Security&lt;/strong&gt;: The code is audited and battle-tested by a huge community.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Follow Best Practices&lt;/strong&gt;: OpenZeppelin enforces standards, reducing subtle bugs and ensuring interoperability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Write Modular Code&lt;/strong&gt;: Components can be composed and extended easily, which fits perfectly with StarkNet’s contract architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Breakdown&lt;/strong&gt;: Your ERC20 Token Contract&lt;/p&gt;

&lt;p&gt;Here’s a simplified example of an ERC20 token contract that uses OpenZeppelin Cairo components:&lt;/p&gt;

&lt;p&gt;You should include openzeppelin in Scarb.toml.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[dependencies]
openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git" }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Contract:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#[starknet::interface]
trait IERC&amp;lt;ContractState&amp;gt; {

fn minting(
        ref self: ContractState,
        recipient: starknet::ContractAddress,
        amount: u256
    );
}
#[starknet::contract]
mod MyERC20Token {
    use openzeppelin::token::erc20::{ERC20Component, ERC20HooksEmptyImpl};
    use starknet::ContractAddress;
    component!(path: ERC20Component, storage: erc20, event: ERC20Event);
    #[abi(embed_v0)]
    impl ERC20MixinImpl = ERC20Component::ERC20Impl&amp;lt;ContractState&amp;gt;;

    impl ERC20InternalImpl = ERC20Component::InternalImpl&amp;lt;ContractState&amp;gt;;
    #[storage]
    struct Storage {
        #[substorage(v0)]
        erc20: ERC20Component::Storage,
    }
    #[event]
    #[derive(Drop, starknet::Event)]
    enum Event {
        #[flat]
        ERC20Event: ERC20Component::Event,
    }
    #[constructor]
    fn constructor(
        ref self: ContractState,
        fixed_supply: u256,
        recipient: ContractAddress
    ) {
        let name = "Test";
        let symbol = "TST";
        self.erc20.initializer(name, symbol);
        self.erc20.mint(recipient, fixed_supply);
    }
    #[abi(embed_v0)]
    impl t of super::IERC&amp;lt;ContractState&amp;gt; {
        fn minting(
            ref self: ContractState,
            recipient: ContractAddress,
            amount: u256
        ) {
            self.erc20.mint(recipient, amount);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Breaking Down the Contract&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Defining the Interface IERC&lt;/strong&gt;&lt;br&gt;
The IERC trait defines an interface for minting tokens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#[starknet::interface]
trait IERC&amp;lt;ContractState&amp;gt; {

    fn minting(
        ref self: ContractState,
        recipient: starknet::ContractAddress,
        amount: u256
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The minting function lets external callers mint tokens to a specified recipient address.&lt;br&gt;
The #[abi(embed_v0)] macro generates ABI code so this function can be called externally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contract Module and Imports&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Inside the MyERC20Token module, we import OpenZeppelin’s ERC20 component and StarkNet address utilities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use openzeppelin::token::erc20::{ERC20Component, ERC20HooksEmptyImpl};

use starknet::ContractAddress;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Composing with component!&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;component!(path: ERC20Component, storage: erc20, event: ERC20Event);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This macro pulls in OpenZeppelin’s ERC20 logic, storage, and events into your contract under the name erc20.&lt;br&gt;
It helps modularize your contract by reusing battle-tested components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Storage Definition&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#[storage]
struct Storage {
    #[substorage(v0)]
    erc20: ERC20Component::Storage,
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The contract’s storage embeds OpenZeppelin’s ERC20 storage.&lt;br&gt;
The #[substorage(v0)] attribute allows versioned, modular storage management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Event Wrapping&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#[event]
#[derive(Drop, starknet::Event)]
enum Event {
    #[flat]
    ERC20Event: ERC20Component::Event,
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your contract wraps OpenZeppelin’s ERC20 events so it can emit them properly on StarkNet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Constructor: Initialize and Mint&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#[constructor]
fn constructor(
    ref self: ContractState,
    fixed_supply: u256,
    recipient: ContractAddress
) {
    let name = "Test";
    let symbol = "TST";
    self.erc20.initializer(name, symbol);
    self.erc20.mint(recipient, fixed_supply);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On deployment, the contract sets the token name and symbol.&lt;br&gt;
It immediately mints the entire fixed_supply to the recipient address.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Minting Implementation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#[abi(embed_v0)]
impl t of super::IERC&amp;lt;ContractState&amp;gt; {
    fn minting(
        ref self: ContractState,
        recipient: ContractAddress,
        amount: u256
    ) {
        self.erc20.mint(recipient, amount);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This implements the minting method from the IERC interface.&lt;br&gt;
It calls the OpenZeppelin mint function to mint tokens after deployment.&lt;/p&gt;

&lt;p&gt;Deploying and Interacting with the Contract&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To deploy:&lt;/strong&gt;&lt;br&gt;
Compile the contract with the Cairo compiler targeting StarkNet.&lt;/p&gt;

&lt;p&gt;Deploy the contract to StarkNet testnet or a local devnet.&lt;br&gt;
Call the constructor with your fixed supply and recipient address.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To interact&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Use the minting function to mint additional tokens to any address after deployment.&lt;/p&gt;

&lt;p&gt;Use standard ERC20 calls (transfer, approve, balanceOf) inherited from OpenZeppelin’s ERC20 component.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using OpenZeppelin’s Cairo components on StarkNet significantly speeds up development of secure, standard-compliant smart contracts. This example shows how easily you can compose and extend OpenZeppelin’s battle-tested ERC20 token implementation on StarkNet.&lt;/p&gt;

&lt;p&gt;If you want to build robust Layer 2 dApps, leveraging OpenZeppelin on StarkNet is a smart choice. Feel free to check out the OpenZeppelin Cairo repository and experiment with the components.&lt;/p&gt;

&lt;p&gt;Drop a comment if you have questions or want more tutorials on StarkNet Cairo smart contracts!&lt;/p&gt;

</description>
      <category>starknet</category>
      <category>cairo</category>
      <category>zkrollups</category>
      <category>blockchain</category>
    </item>
  </channel>
</rss>
